';
}
$output .= '';
return $output;
}
/**
* Add the necessary CSS for a stylizer plugin to the page.
*
* This will check to see if the images directory and the cached CSS
* exists and, if not, will regenerate everything needed.
*/
function ctools_stylizer_add_css($plugin, $settings) {
if (!file_exists(ctools_stylizer_get_image_path($plugin, $settings, FALSE))) {
ctools_stylizer_build_style($plugin, $settings, TRUE);
return;
}
ctools_include('css');
$filename = ctools_css_retrieve(ctools_stylizer_get_css_id($plugin, $settings));
if (!$filename) {
ctools_stylizer_build_style($plugin, $settings, TRUE);
}
else {
ctools_css_add_css($filename);
}
}
/**
* Build the files for a stylizer given the proper settings.
*/
function ctools_stylizer_build_style($plugin, $settings, $add_css = FALSE) {
$path = ctools_stylizer_get_image_path($plugin, $settings);
if (!$path) {
return;
}
$replacements = array();
// Set up palette conversions
foreach ($settings['palette'] as $key => $color) {
$replacements['%' . $key ] = $color;
}
// Process image actions:
if (!empty($plugin['actions'])) {
$processor = new ctools_stylizer_image_processor;
$processor->execute($path, $plugin, $settings);
// @todo -- there needs to be an easier way to get at this.
// dsm($processor->message_log);
// Add filenames to our conversions.
}
// Convert and write the CSS file.
$css = file_get_contents($plugin['path'] . '/' . $plugin['css']);
// Replace %style keyword with our generated class name.
// @todo We need one more unique identifier I think.
$class = ctools_stylizer_get_css_class($plugin, $settings);
$replacements['%style'] = '.' . $class;
if (!empty($processor) && !empty($processor->paths)) {
foreach ($processor->paths as $file => $image) {
$replacements[$file] = file_create_url($image);
}
}
if (!empty($plugin['build']) && function_exists($plugin['build'])) {
$plugin['build']($plugin, $settings, $css, $replacements);
}
$css = strtr($css, $replacements);
ctools_include('css');
$filename = ctools_css_store(ctools_stylizer_get_css_id($plugin, $settings), $css, FALSE);
if ($add_css) {
ctools_css_add_css($filename);
}
}
/**
* Clean up no longer used files.
*
* To prevent excess clutter in the files directory, this should be called
* whenever a style is going out of use. When being deleted, but also when
* the palette is being changed.
*/
function ctools_stylizer_cleanup_style($plugin, $settings) {
ctools_include('css');
$path = ctools_stylizer_get_image_path($plugin, $settings, FALSE);
if ($path) {
ctools_stylizer_recursive_delete($path);
}
ctools_css_clear(ctools_stylizer_get_css_id($plugin, $settings));
}
/**
* Recursively delete all files and folders in the specified filepath, then
* delete the containing folder.
*
* Note that this only deletes visible files with write permission.
*
* @param string $path
* A filepath relative to file_directory_path.
*/
function ctools_stylizer_recursive_delete($path) {
if (empty($path)) {
return;
}
$listing = $path . '/*';
foreach (glob($listing) as $file) {
if (is_file($file) === TRUE) {
@unlink($file);
}
elseif (is_dir($file) === TRUE) {
ctools_stylizer_recursive_delete($file);
}
}
@rmdir($path);
}
/**
* Get the path where images will be stored for a given style plugin and settings.
*
* This function will make sure the path exists.
*/
function ctools_stylizer_get_image_path($plugin, $settings, $check = TRUE) {
$file = 'ctools/style/' . $settings['name'] . '/' . md5(serialize($settings['palette']));
$path = file_create_path($file);
if ($check && !ctools_file_check_directory($path)) {
$base = '';
foreach (explode('/', $file) as $bit) {
$base .= '/' . $bit;
$path = file_directory_path() . $base;
if (!ctools_file_check_directory($path, FILE_CREATE_DIRECTORY)) {
drupal_set_message(t('Unable to create CTools styles cache directory @path. Check the permissions on your files directory.', array('@path' => $path)), 'error');
return;
}
}
}
return $path;
}
/**
* Get the id used to cache CSS for a given style plugin and settings.
*/
function ctools_stylizer_get_css_id($plugin, $settings) {
return 'ctools-stylizer:' . $settings['name'] . ':' . md5(serialize($settings['palette']));
}
/**
* Get the class to use for a stylizer plugin.
*/
function ctools_stylizer_get_css_class($plugin, $settings) {
ctools_include('cleanstring');
return ctools_cleanstring($plugin['name'] . '-' . $settings['name']);
}
class ctools_stylizer_image_processor {
var $workspace = NULL;
var $name = NULL;
var $workspaces = array();
var $message_log = array();
var $error_log = array();
function execute($path, $plugin, $settings) {
$this->path = $path;
$this->plugin = $plugin;
$this->settings = $settings;
$this->palette = $settings['palette'];
if (is_string($plugin['actions']) && function_exists($plugin['actions'])) {
$actions = $plugin['actions']($plugin, $settings);
}
else if (is_array($plugin['actions'])) {
$actions = $plugin['actions'];
}
if (!empty($actions) && is_array($actions)) {
foreach ($plugin['actions'] as $action) {
$command = 'command_' . array_shift($action);
if (method_exists($this, $command)) {
call_user_func_array(array($this, $command), $action);
}
}
}
// Clean up buffers.
foreach ($this->workspaces as $name => $workspace) {
imagedestroy($this->workspaces[$name]);
}
}
function log($message, $type = 'normal') {
$this->message_log[] = $message;
if ($type == 'error') {
$this->error_log[] = $message;
}
}
function set_current_workspace($workspace) {
$this->log("Set current workspace: $workspace");
$this->workspace = &$this->workspaces[$workspace];
$this->name = $workspace;
}
/**
* Create a new workspace.
*/
function command_new($name, $width, $height) {
$this->log("New workspace: $name ($width x $height)");
// Clean up if there was already a workspace there.
if (isset($this->workspaces[$name])) {
imagedestroy($this->workspaces[$name]);
}
$this->workspaces[$name] = imagecreatetruecolor($width, $height);
$this->set_current_workspace($name);
// Make sure the new workspace has a transparent color.
// Turn off transparency blending (temporarily)
imagealphablending($this->workspace, FALSE);
// Create a new transparent color for image
$color = imagecolorallocatealpha($this->workspace, 0, 0, 0, 127);
// Completely fill the background of the new image with allocated color.
imagefill($this->workspace, 0, 0, $color);
// Restore transparency blending
imagesavealpha($this->workspace, TRUE);
}
/**
* Create a new workspace a file.
*
* This will make the new workspace the current workspace.
*/
function command_load($name, $file) {
$this->log("New workspace: $name (from $file)");
if (!file_exists($file)) {
// Try it relative to the plugin
$file = $this->plugin['path'] . '/' . $file;
if (!file_exists($file)) {
$this->log("Unable to open $file");
return;
}
}
// Clean up if there was already a workspace there.
if (isset($this->workspaces[$name])) {
imagedestroy($this->workspaces[$name]);
}
$this->workspaces[$name] = imagecreatefrompng($file);
$this->set_current_workspace($name);
}
/**
* Create a new workspace using the properties of an existing workspace
*/
function command_new_from($name, $workspace) {
$this->log("New workspace: $name from existing $workspace");
if (empty($this->workspaces[$workspace])) {
$this->log("Workspace $name does not exist.", 'error');
return;
}
// Clean up if there was already a workspace there.
if (isset($this->workspaces[$name])) {
imagedestroy($this->workspaces[$name]);
}
$this->workspaces[$name] = $this->new_image($this->workspace[$workspace]);
$this->set_current_workspace($name);
}
/**
* Set the current workspace.
*/
function command_workspace($name) {
$this->log("Set workspace: $name");
if (empty($this->workspaces[$name])) {
$this->log("Workspace $name does not exist.", 'error');
return;
}
$this->set_current_workspace($name);
}
/**
* Copy the contents of one workspace into the current workspace.
*/
function command_merge_from($workspace, $x = 0, $y = 0) {
$this->log("Merge from: $workspace ($x, $y)");
if (empty($this->workspaces[$workspace])) {
$this->log("Workspace $name does not exist.", 'error');
return;
}
$this->merge($this->workspaces[$workspace], $this->workspace, $x, $y);
}
function command_merge_to($workspace, $x = 0, $y = 0) {
$this->log("Merge to: $workspace ($x, $y)");
if (empty($this->workspaces[$workspace])) {
$this->log("Workspace $name does not exist.", 'error');
return;
}
$this->merge($this->workspace, $this->workspaces[$workspace], $x, $y);
$this->set_current_workspace($workspace);
}
/**
* Blend an image into the current workspace.
*/
function command_merge_from_file($file, $x = 0, $y = 0) {
$this->log("Merge from file: $file ($x, $y)");
if (!file_exists($file)) {
// Try it relative to the plugin
$file = $this->plugin['path'] . '/' . $file;
if (!file_exists($file)) {
$this->log("Unable to open $file");
return;
}
}
$source = imagecreatefrompng($file);
$this->merge($source, $this->workspace, $x, $y);
imagedestroy($source);
}
function command_fill($color, $x, $y, $width, $height) {
$this->log("Fill: $color ($x, $y, $width, $height)");
imagefilledrectangle($this->workspace, $x, $y, $x + $width, $y + $height, _color_gd($this->workspace, $this->palette[$color]));
}
function command_gradient($from, $to, $x, $y, $width, $height, $direction = 'down') {
$this->log("Gradient: $from to $to ($x, $y, $width, $height) $direction");
if ($direction == 'down') {
for ($i = 0; $i < $height; ++$i) {
$color = _color_blend($this->workspace, $this->palette[$from], $this->palette[$to], $i / ($height - 1));
imagefilledrectangle($this->workspace, $x, $y + $i, $x + $width, $y + $i + 1, $color);
}
}
else {
for ($i = 0; $i < $width; ++$i) {
$color = _color_blend($this->workspace, $this->palette[$from], $this->palette[$to], $i / ($width - 1));
imagefilledrectangle($this->workspace, $x + $i, $y, $x + $i + 1, $y + $height, $color);
}
}
}
/**
* Colorize the current workspace with the given location.
*
* This uses simple color blending to colorize the image.
*
* @todo it is possible that this colorize could allow different methods for
* determining how to blend colors?
*/
function command_colorize($color, $x = NULL, $y = NULL, $width = NULL, $height = NULL) {
if (!isset($x)) {
$whole_image = TRUE;
$x = $y = 0;
$width = imagesx($this->workspace);
$height = imagesy($this->workspace);
}
$this->log("Colorize: $color ($x, $y, $width, $height)");
$c = _color_unpack($this->palette[$color]);
imagealphablending($this->workspace, FALSE);
imagesavealpha($this->workspace, TRUE);
// If PHP 5 use the nice imagefilter which is faster.
if (!empty($whole_image) && version_compare(phpversion(), '5.2.5', '>=') && function_exists('imagefilter')) {
imagefilter($this->workspace, IMG_FILTER_COLORIZE, $c[0], $c[1], $c[2]);
}
else {
// Otherwise we can do it the brute force way.
for ($j = 0; $j < $height; $j++) {
for ($i = 0; $i < $width; $i++) {
$current = imagecolorsforindex($this->workspace, imagecolorat($this->workspace, $i, $j));
$new_index = imagecolorallocatealpha($this->workspace, $c[0], $c[1], $c[2], $current['alpha']);
imagesetpixel($this->workspace, $i, $j, $new_index);
}
}
}
}
/**
* Colorize the current workspace with the given location.
*
* This uses a color replacement algorithm that retains luminosity but
* turns replaces all color with the specified color.
*/
function command_hue($color, $x = NULL, $y = NULL, $width = NULL, $height = NULL) {
if (!isset($x)) {
$whole_image = TRUE;
$x = $y = 0;
$width = imagesx($this->workspace);
$height = imagesy($this->workspace);
}
$this->log("Hue: $color ($x, $y, $width, $height)");
list($red, $green, $blue) = _color_unpack($this->palette[$color]);
// We will create a monochromatic palette based on the input color
// which will go from black to white.
// Input color luminosity: this is equivalent to the position of the
// input color in the monochromatic palette
$luminosity_input = round(255 * ($red + $green + $blue) / 765); // 765 = 255 * 3
// We fill the palette entry with the input color at itscorresponding position
$palette[$luminosity_input]['red'] = $red;
$palette[$luminosity_input]['green'] = $green;
$palette[$luminosity_input]['blue'] = $blue;
// Now we complete the palette, first we'll do it tothe black, and then to
// the white.
// From input to black
$steps_to_black = $luminosity_input;
// The step size for each component
if ($steps_to_black) {
$step_size_red = $red / $steps_to_black;
$step_size_green = $green / $steps_to_black;
$step_size_blue = $blue / $steps_to_black;
for ($i = $steps_to_black; $i >= 0; $i--) {
$palette[$steps_to_black-$i]['red'] = $red - round($step_size_red * $i);
$palette[$steps_to_black-$i]['green'] = $green - round($step_size_green * $i);
$palette[$steps_to_black-$i]['blue'] = $blue - round($step_size_blue * $i);
}
}
// From input to white
$steps_to_white = 255 - $luminosity_input;
if ($steps_to_white) {
$step_size_red = (255 - $red) / $steps_to_white;
$step_size_green = (255 - $green) / $steps_to_white;
$step_size_blue = (255 - $blue) / $steps_to_white;
}
else {
$step_size_red=$step_size_green=$step_size_blue=0;
}
// The step size for each component
for($i = ($luminosity_input + 1); $i <= 255; $i++) {
$palette[$i]['red'] = $red + round($step_size_red * ($i - $luminosity_input));
$palette[$i]['green'] = $green + round($step_size_green * ($i - $luminosity_input));
$palette[$i]['blue']= $blue + round($step_size_blue * ($i - $luminosity_input));
}
// Go over the specified area of the image and update the colors.
for ($j = $x; $j < $height; $j++) {
for ($i = $y; $i < $width; $i++) {
$color = imagecolorsforindex($this->workspace, imagecolorat($this->workspace, $i, $j));
$luminosity = round(255 * ($color['red'] + $color['green'] + $color['blue']) / 765);
$new_color = imagecolorallocatealpha($this->workspace, $palette[$luminosity]['red'], $palette[$luminosity]['green'], $palette[$luminosity]['blue'], $color['alpha']);
imagesetpixel($this->workspace, $i, $j, $new_color);
}
}
}
/**
* Take a slice out of the current workspace and save it as an image.
*/
function command_slice($file, $x = NULL, $y = NULL, $width = NULL, $height = NULL) {
if (!isset($x)) {
$x = $y = 0;
$width = imagesx($this->workspace);
$height = imagesy($this->workspace);
}
$this->log("Slice: $file ($x, $y, $width, $height)");
$base = basename($file);
$image = $this->path . '/' . $base;
$slice = $this->new_image($this->workspace, $width, $height);
imagecopy($slice, $this->workspace, 0, 0, $x, $y, $width, $height);
// Make sure alphas are saved:
imagealphablending($slice, FALSE);
imagesavealpha($slice, TRUE);
// Save image.
imagepng($slice, $image);
imagedestroy($slice);
// Set standard file permissions for webserver-generated files
@chmod(realpath($image), 0664);
$this->paths[$file] = $image;
}
/**
* Prepare a new image for being copied or worked on, preserving transparency.
*/
function &new_image(&$source, $width = NULL, $height = NULL) {
if (!isset($width)) {
$width = imagesx($source);
}
if (!isset($height)) {
$height = imagesy($source);
}
$target = imagecreatetruecolor($width, $height);
imagealphablending($target, FALSE);
imagesavealpha($target, TRUE);
$transparency_index = imagecolortransparent($source);
// If we have a specific transparent color
if ($transparency_index >= 0) {
// Get the original image's transparent color's RGB values
$transparent_color = imagecolorsforindex($source, $transparency_index);
// Allocate the same color in the new image resource
$transparency_index = imagecolorallocate($target, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
// Completely fill the background of the new image with allocated color.
imagefill($target, 0, 0, $transparency_index);
// Set the background color for new image to transparent
imagecolortransparent($target, $transparency_index);
}
// Always make a transparent background color for PNGs that don't have one allocated already
else {
// Create a new transparent color for image
$color = imagecolorallocatealpha($target, 0, 0, 0, 127);
// Completely fill the background of the new image with allocated color.
imagefill($target, 0, 0, $color);
}
return $target;
}
/**
* Merge two images together, preserving alpha transparency.
*/
function merge(&$from, &$to, $x, $y) {
// Blend over template.
$width = imagesx($from);
$height = imagesy($from);
// Re-enable alpha blending to make sure transparency merges.
imagealphablending($to, TRUE);
imagecopy($to, $from, $x, $y, 0, 0, $width, $height);
imagealphablending($to, FALSE);
}
}
/**
* Get the cached changes to a given task handler.
*/
function ctools_stylizer_get_settings_cache($name) {
ctools_include('object-cache');
return ctools_object_cache_get('ctools_stylizer_settings', $name);
}
/**
* Store changes to a task handler in the object cache.
*/
function ctools_stylizer_set_settings_cache($name, $settings) {
ctools_include('object-cache');
ctools_object_cache_set('ctools_stylizer_settings', $name, $settings);
}
/**
* Remove an item from the object cache.
*/
function ctools_stylizer_clear_settings_cache($name) {
ctools_include('object-cache');
ctools_object_cache_clear('ctools_stylizer_settings', $name);
}
/**
* Add a new style of the specified type.
*/
function ctools_stylizer_edit_style(&$info, $js, $step = NULL) {
$name = '::new';
$form_info = array(
'id' => 'ctools_stylizer_edit_style',
'path' => $info['path'],
'show trail' => TRUE,
'show back' => TRUE,
'show return' => FALSE,
'next callback' => 'ctools_stylizer_edit_style_next',
'finish callback' => 'ctools_stylizer_edit_style_finish',
'return callback' => 'ctools_stylizer_edit_style_finish',
'cancel callback' => 'ctools_stylizer_edit_style_cancel',
'forms' => array(
'choose' => array(
'form id' => 'ctools_stylizer_edit_style_form_choose',
),
),
);
if (empty($info['settings'])) {
$form_info['order'] = array(
'choose' => t('Select base style'),
);
if (empty($step)) {
$step = 'choose';
}
if ($step != 'choose') {
$cache = ctools_stylizer_get_settings_cache($name);
if (!$cache) {
return t('Missing settings cache.');
}
if (!empty($cache['owner settings'])) {
$info['owner settings'] = $cache['owner settings'];
}
$settings = $cache['settings'];
}
else {
$settings = array(
'name' => '_temporary',
'style_base' => NULL,
'palette' => array(),
);
ctools_stylizer_clear_settings_cache($name);
}
$form_type = 'add';
}
else {
$cache = ctools_stylizer_get_settings_cache($info['settings']['name']);
if (!empty($cache)) {
if (!empty($cache['owner settings'])) {
$info['owner settings'] = $cache['owner settings'];
}
$settings = $cache['settings'];
}
else {
$settings = $info['settings'];
}
$form_type = 'edit';
}
$plugin = NULL;
if (!empty($settings['style_base'])) {
$plugin = ctools_get_style_base($settings['style_base']);
// Add in forms specific to the plugin. The plugin can store forms
// either as a simple 'edit form' => 'form callback' or if it needs
// the more complicated wizard functionality, it can set 'forms'
// and 'order' with values suitable for the wizard $form_info
// array.
$info['type'] = $plugin['type'];
if (empty($plugin['forms'])) {
if ($form_type == 'add' && isset($plugin['add form'])) {
$id = $plugin['add form'];
}
else if (isset($plugin['edit form'])) {
$id = $plugin['edit form'];
}
else {
$id = 'ctools_stylizer_edit_style_form_default';
}
$form_info['forms']['settings'] = array(
'form id' => $id,
);
$form_info['order']['settings'] = t('Settings');
}
else {
$form_info['forms'] += $plugin['forms'];
$form_info['order'] += $plugin['order'];
}
}
else {
// This is here so the 'finish' button does not show up, but because
// we don't have the selected style we don't know what the next form(s)
// will be.
$form_info['order']['next'] = t('A meaningless second page');
}
if (count($form_info['order']) < 2 || $step == 'choose') {
$form_info['show trail'] = FALSE;
}
$form_state = array(
'module' => $info['module'],
'type' => $info['type'],
'owner info' => &$info,
'plugin' => $plugin,
'name' => $name,
'step' => $step,
'settings' => $settings,
'ajax' => $js,
'form_type' => $form_type,
);
if (!empty($info['modal'])) {
$form_state['modal'] = TRUE;
$form_state['title'] = $info['modal'];
$form_state['modal return'] = TRUE;
}
ctools_include('wizard');
$output = ctools_wizard_multistep_form($form_info, $step, $form_state);
if (!empty($form_state['complete'])) {
$info['complete'] = TRUE;
$info['settings'] = $form_state['settings'];
}
if ($js && !$output && !empty($form_state['clicked_button']['#next'])) {
// We have to do a separate redirect here because the formula that adds
// stuff to the wizard after being chosen hasn't happened. The wizard
// tried to go to the next step which did not exist.
return ctools_stylizer_edit_style($info, $js, $form_state['clicked_button']['#next']);
}
return $output;
}
/**
* Callback generated when the add style process is finished.
*/
function ctools_stylizer_edit_style_finish(&$form_state) {
$form_state['complete'] = TRUE;
ctools_stylizer_clear_settings_cache($form_state['name']);
if (isset($form_state['settings']['old_settings'])) {
unset($form_state['settings']['old_settings']);
}
}
/**
* Callback generated when the 'next' button is clicked.
*/
function ctools_stylizer_edit_style_next(&$form_state) {
$form_state['form_info']['path'] = str_replace('%name', $form_state['name'], $form_state['form_info']['path']);
$form_state['redirect'] = ctools_wizard_get_path($form_state['form_info'], $form_state['clicked_button']['#next']);
// Update the cache with changes.
$cache = array('settings' => $form_state['settings']);
if (!empty($form_state['owner info']['owner settings'])) {
$cache['owner settings'] = $form_state['owner info']['owner settings'];
}
ctools_stylizer_set_settings_cache($form_state['name'], $cache);
}
/**
* Callback generated when the 'cancel' button is clicked.
*
* We might have some temporary data lying around. We must remove it.
*/
function ctools_stylizer_edit_style_cancel(&$form_state) {
if (!empty($form_state['name'])) {
ctools_stylizer_clear_settings_cache($form_state['name']);
}
}
/**
* Choose which plugin to use to create a new style.
*/
function ctools_stylizer_edit_style_form_choose(&$form, &$form_state) {
$plugins = ctools_get_style_bases();
$options = array();
$categories = array();
foreach ($plugins as $name => $plugin) {
if ($form_state['module'] == $plugin['module'] && $form_state['type'] == $plugin['type']) {
$categories[$plugin['category']] = $plugin['category'];
$unsorted_options[$plugin['category']][$name] = ctools_stylizer_print_style_icon($plugin, TRUE);
}
}
asort($categories);
foreach ($categories as $category) {
$options[$category] = $unsorted_options[$category];
}
$form['style_base'] = array(
'#prefix' => '
',
);
foreach ($radios as $key => $choice) {
// Generate the parents as the autogenerator does, so we will have a
// unique id for each radio button.
$form['style_base'][$cat][$key] = array(
'#type' => 'radio',
'#title' => $choice,
'#parents' => array('style_base'),
'#id' => form_clean_id('edit-style-base-' . $key),
'#return_value' => check_plain($key),
);
}
}
}
function ctools_stylizer_edit_style_form_choose_submit(&$form, &$form_state) {
$form_state['settings']['style_base'] = $form_state['values']['style_base'];
// The 'next' form will show up as 'next' but that's not accurate now that
// we have a style. Figure out what next really is and update.
$plugin = ctools_get_style_base($form_state['settings']['style_base']);
if (empty($plugin['forms'])) {
$form_state['clicked_button']['#next'] = 'settings';
}
else {
$forms = array_keys($form_info['forms']);
$form_state['clicked_button']['#next'] = array_shift($forms);
}
// Fill in the defaults for the settings.
if (!empty($plugin['defaults'])) {
// @todo allow a callback
$form_state['settings'] += $plugin['defaults'];
}
}
/**
* The default stylizer style editing form.
*
* Even when not using this, styles should call through to this form in
* their own edit forms.
*/
function ctools_stylizer_edit_style_form_default(&$form, &$form_state) {
ctools_add_js('stylizer');
ctools_add_css('stylizer');
drupal_add_js('misc/farbtastic/farbtastic.js');
drupal_add_css('misc/farbtastic/farbtastic.css');
$plugin = &$form_state['plugin'];
$settings = &$form_state['settings'];
$form['top box'] = array(
'#prefix' => '
'; // color form
return $output;
}
/**
* Theme the stylizer preview form.
*/
function theme_ctools_stylizer_preview_form($form) {
$plugin = $form['#form_state']['plugin'];
$settings = $form['#form_state']['settings'];
if (!empty($form['#form_state']['settings']['old_settings'])) {
ctools_stylizer_cleanup_style($plugin, $form['#form_state']['settings']['old_settings']);
}
if (!empty($plugin['preview']) && function_exists($plugin['preview'])) {
$output = '';
return $output;
}
}
function ctools_stylizer_edit_style_form_default_validate($form, &$form_state) {
if (!empty($form_state['owner info']['owner form validate']) && function_exists($form_state['owner info']['owner form validate'])) {
$form_state['owner info']['owner form validate']($form, $form_state);
}
if (!empty($form_state['plugin']['settings form validate']) && function_exists($form_state['plugin']['settings form validate'])) {
$form_state['plugin']['settings form validate']($form, $form_state);
}
}
function ctools_stylizer_edit_style_form_default_submit($form, &$form_state) {
// Store old settings for the purposes of cleaning up.
$form_state['settings']['old_settings'] = $form_state['settings'];
$form_state['settings']['palette'] = $form_state['values']['palette'];
if (!empty($form_state['owner info']['owner form submit']) && function_exists($form_state['owner info']['owner form submit'])) {
$form_state['owner info']['owner form submit']($form, $form_state);
}
if (!empty($form_state['plugin']['settings form submit']) && function_exists($form_state['plugin']['settings form submit'])) {
$form_state['plugin']['settings form submit']($form, $form_state);
}
if ($form_state['clicked_button']['#value'] == t('Preview')) {
$form_state['rerender'] = TRUE;
// Update the cache with changes.
$cache = array('settings' => $form_state['settings']);
if (!empty($form_state['owner info']['owner settings'])) {
$cache['owner settings'] = $form_state['owner info']['owner settings'];
}
ctools_stylizer_set_settings_cache($form_state['name'], $cache);
}
}
// --------------------------------------------------------------------------
// CSS forms and tools that plugins can use.
/**
* Font selector form
*/
function ctools_stylizer_font_selector_form(&$form, &$form_state, $label, $settings) {
// Family
$form['#prefix'] = '