[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/modules/ctools/includes/ -> stylizer.inc (source)

   1  <?php
   2  // $Id: stylizer.inc,v 1.1.2.12 2010/10/15 20:52:02 merlinofchaos Exp $
   3  /**
   4   * @file
   5   * Create customized CSS and images from palettes created by user input.
   6   */
   7  
   8  /**
   9   * Fetch metadata on a specific style_base plugin.
  10   *
  11   * @param $content type
  12   *   Name of a panel content type.
  13   *
  14   * @return
  15   *   An array with information about the requested stylizer style base.
  16   */
  17  function ctools_get_style_base($style_base) {
  18    ctools_include('plugins');
  19    return ctools_get_plugins('ctools', 'style_bases', $style_base);
  20  }
  21  
  22  /**
  23   * Fetch metadata for all style_base plugins.
  24   *
  25   * @return
  26   *   An array of arrays with information about all available styleizer style bases.
  27   */
  28  function ctools_get_style_bases() {
  29    ctools_include('plugins');
  30    return ctools_get_plugins('ctools', 'style_bases');
  31  }
  32  
  33  /**
  34   * Fetch metadata about all of the style base types that are available.
  35   */
  36  function ctools_get_style_base_types() {
  37    $types = array();
  38    foreach (module_implements('ctools_style_base_types') as $module) {
  39      $types[$module] = module_invoke($module, 'ctools_style_base_types');
  40    }
  41  
  42    return $types;
  43  }
  44  
  45  /**
  46   * Render the icon for a style base.
  47   */
  48  function ctools_stylizer_print_style_icon($plugin, $print_title = TRUE) {
  49    $file = $plugin['path'] . '/' . $plugin['icon'];
  50    $title = $print_title ? $plugin['title'] : '';
  51    return theme('ctools_style_icon', theme('image', $file), $title);
  52  }
  53  
  54  /**
  55   * Theme the style icon image
  56   */
  57  function theme_ctools_style_icon($image, $title = NULL) {
  58    ctools_add_css('stylizer');
  59    ctools_add_js('stylizer');
  60    $output = '<div class="ctools-style-icon">';
  61    $output .= $image;
  62    if ($title) {
  63      $output .= '<div class="caption">' . $title . '</div>';
  64    }
  65    $output .= '</div>';
  66    return $output;
  67  }
  68  
  69  /**
  70   * Add the necessary CSS for a stylizer plugin to the page.
  71   *
  72   * This will check to see if the images directory and the cached CSS
  73   * exists and, if not, will regenerate everything needed.
  74   */
  75  function ctools_stylizer_add_css($plugin, $settings) {
  76    if (!file_exists(ctools_stylizer_get_image_path($plugin, $settings, FALSE))) {
  77      ctools_stylizer_build_style($plugin, $settings, TRUE);
  78      return;
  79    }
  80  
  81    ctools_include('css');
  82    $filename = ctools_css_retrieve(ctools_stylizer_get_css_id($plugin, $settings));
  83    if (!$filename) {
  84      ctools_stylizer_build_style($plugin, $settings, TRUE);
  85    }
  86    else {
  87      ctools_css_add_css($filename);
  88    }
  89  }
  90  
  91  /**
  92   * Build the files for a stylizer given the proper settings.
  93   */
  94  function ctools_stylizer_build_style($plugin, $settings, $add_css = FALSE) {
  95    $path = ctools_stylizer_get_image_path($plugin, $settings);
  96    if (!$path) {
  97      return;
  98    }
  99  
 100    $replacements = array();
 101  
 102    // Set up palette conversions
 103    foreach ($settings['palette'] as $key => $color) {
 104      $replacements['%' . $key ] = $color;
 105    }
 106  
 107    // Process image actions:
 108    if (!empty($plugin['actions'])) {
 109      $processor = new ctools_stylizer_image_processor;
 110      $processor->execute($path, $plugin, $settings);
 111  
 112  // @todo -- there needs to be an easier way to get at this.
 113  //  dsm($processor->message_log);
 114      // Add filenames to our conversions.
 115    }
 116  
 117    // Convert and write the CSS file.
 118    $css = file_get_contents($plugin['path'] . '/' . $plugin['css']);
 119  
 120    // Replace %style keyword with our generated class name.
 121    // @todo We need one more unique identifier I think.
 122    $class = ctools_stylizer_get_css_class($plugin, $settings);
 123    $replacements['%style'] = '.' . $class;
 124  
 125    if (!empty($processor) && !empty($processor->paths)) {
 126      foreach ($processor->paths as $file => $image) {
 127        $replacements[$file] = file_create_url($image);
 128      }
 129    }
 130  
 131    if (!empty($plugin['build']) && function_exists($plugin['build'])) {
 132      $plugin['build']($plugin, $settings, $css, $replacements);
 133    }
 134  
 135    $css = strtr($css, $replacements);
 136    ctools_include('css');
 137    $filename = ctools_css_store(ctools_stylizer_get_css_id($plugin, $settings), $css, FALSE);
 138  
 139    if ($add_css) {
 140      ctools_css_add_css($filename);
 141    }
 142  }
 143  
 144  /**
 145   * Clean up no longer used files.
 146   *
 147   * To prevent excess clutter in the files directory, this should be called
 148   * whenever a style is going out of use. When being deleted, but also when
 149   * the palette is being changed.
 150   */
 151  function ctools_stylizer_cleanup_style($plugin, $settings) {
 152    ctools_include('css');
 153    $path = ctools_stylizer_get_image_path($plugin, $settings, FALSE);
 154    if ($path) {
 155      ctools_stylizer_recursive_delete($path);
 156    }
 157  
 158    ctools_css_clear(ctools_stylizer_get_css_id($plugin, $settings));
 159  }
 160  
 161  /**
 162   * Recursively delete all files and folders in the specified filepath, then
 163   * delete the containing folder.
 164   *
 165   * Note that this only deletes visible files with write permission.
 166   *
 167   * @param string $path
 168   *   A filepath relative to file_directory_path.
 169   */
 170  function ctools_stylizer_recursive_delete($path) {
 171    if (empty($path)) {
 172      return;
 173    }
 174  
 175    $listing = $path . '/*';
 176  
 177    foreach (glob($listing) as $file) {
 178      if (is_file($file) === TRUE) {
 179        @unlink($file);
 180      }
 181      elseif (is_dir($file) === TRUE) {
 182        ctools_stylizer_recursive_delete($file);
 183      }
 184    }
 185  
 186    @rmdir($path);
 187  }
 188  
 189  /**
 190   * Get a safe name for the settings.
 191   *
 192   * This uses an md5 of the palette if the name is temporary so
 193   * that multiple temporary styles on the same page can coexist
 194   * safely.
 195   */
 196  function ctools_stylizer_get_settings_name($settings) {
 197    if ($settings['name'] != '_temporary') {
 198      return $settings['name'];
 199    }
 200  
 201    return $settings['name'] . '-' . md5(serialize($settings['palette']));
 202  }
 203  
 204  /**
 205   * Get the path where images will be stored for a given style plugin and settings.
 206   *
 207   * This function will make sure the path exists.
 208   */
 209  function ctools_stylizer_get_image_path($plugin, $settings, $check = TRUE) {
 210    $file = 'ctools/style/' . $settings['name'] . '/' . md5(serialize($settings['palette']));
 211    $path = file_create_path($file);
 212  
 213    if ($check && !ctools_file_check_directory($path)) {
 214      $base = '';
 215      foreach (explode('/', $file) as $bit) {
 216        $base .= '/' . $bit;
 217        $path = file_directory_path() . $base;
 218        if (!ctools_file_check_directory($path, FILE_CREATE_DIRECTORY)) {
 219          drupal_set_message(t('Unable to create CTools styles cache directory @path. Check the permissions on your files directory.', array('@path' => $path)), 'error');
 220          return;
 221        }
 222      }
 223    }
 224  
 225    return $path;
 226  }
 227  
 228  /**
 229   * Get the id used to cache CSS for a given style plugin and settings.
 230   */
 231  function ctools_stylizer_get_css_id($plugin, $settings) {
 232    return 'ctools-stylizer:' . $settings['name'] . ':' . md5(serialize($settings['palette']));
 233  }
 234  
 235  /**
 236   * Get the class to use for a stylizer plugin.
 237   */
 238  function ctools_stylizer_get_css_class($plugin, $settings) {
 239    ctools_include('cleanstring');
 240    return ctools_cleanstring($plugin['name'] . '-' . ctools_stylizer_get_settings_name($settings));
 241  }
 242  
 243  class ctools_stylizer_image_processor {
 244    var $workspace = NULL;
 245    var $name = NULL;
 246  
 247    var $workspaces = array();
 248  
 249    var $message_log = array();
 250    var $error_log = array();
 251  
 252    function execute($path, $plugin, $settings) {
 253      $this->path = $path;
 254      $this->plugin = $plugin;
 255      $this->settings = $settings;
 256      $this->palette = $settings['palette'];
 257  
 258      if (is_string($plugin['actions']) && function_exists($plugin['actions'])) {
 259        $actions = $plugin['actions']($plugin, $settings);
 260      }
 261      else if (is_array($plugin['actions'])) {
 262        $actions = $plugin['actions'];
 263      }
 264  
 265      if (!empty($actions) && is_array($actions)) {
 266        foreach ($plugin['actions'] as $action) {
 267          $command = 'command_' . array_shift($action);
 268          if (method_exists($this, $command)) {
 269            call_user_func_array(array($this, $command), $action);
 270          }
 271        }
 272      }
 273  
 274      // Clean up buffers.
 275      foreach ($this->workspaces as $name => $workspace) {
 276        imagedestroy($this->workspaces[$name]);
 277      }
 278    }
 279  
 280    function log($message, $type = 'normal') {
 281      $this->message_log[] = $message;
 282      if ($type == 'error') {
 283        $this->error_log[] = $message;
 284      }
 285    }
 286  
 287    function set_current_workspace($workspace) {
 288      $this->log("Set current workspace: $workspace");
 289      $this->workspace = &$this->workspaces[$workspace];
 290      $this->name = $workspace;
 291    }
 292  
 293    /**
 294     * Create a new workspace.
 295     */
 296    function command_new($name, $width, $height) {
 297      $this->log("New workspace: $name ($width x $height)");
 298      // Clean up if there was already a workspace there.
 299      if (isset($this->workspaces[$name])) {
 300        imagedestroy($this->workspaces[$name]);
 301      }
 302  
 303      $this->workspaces[$name] = imagecreatetruecolor($width, $height);
 304      $this->set_current_workspace($name);
 305  
 306      // Make sure the new workspace has a transparent color.
 307  
 308      // Turn off transparency blending (temporarily)
 309      imagealphablending($this->workspace, FALSE);
 310  
 311      // Create a new transparent color for image
 312      $color = imagecolorallocatealpha($this->workspace, 0, 0, 0, 127);
 313  
 314      // Completely fill the background of the new image with allocated color.
 315      imagefill($this->workspace, 0, 0, $color);
 316  
 317      // Restore transparency blending
 318      imagesavealpha($this->workspace, TRUE);
 319  
 320    }
 321  
 322    /**
 323     * Create a new workspace a file.
 324     *
 325     * This will make the new workspace the current workspace.
 326     */
 327    function command_load($name, $file) {
 328      $this->log("New workspace: $name (from $file)");
 329      if (!file_exists($file)) {
 330        // Try it relative to the plugin
 331        $file = $this->plugin['path'] . '/' . $file;
 332        if (!file_exists($file)) {
 333          $this->log("Unable to open $file");
 334          return;
 335        }
 336      }
 337  
 338      // Clean up if there was already a workspace there.
 339      if (isset($this->workspaces[$name])) {
 340        imagedestroy($this->workspaces[$name]);
 341      }
 342  
 343      $this->workspaces[$name] = imagecreatefrompng($file);
 344      $this->set_current_workspace($name);
 345    }
 346  
 347    /**
 348     * Create a new workspace using the properties of an existing workspace
 349     */
 350    function command_new_from($name, $workspace) {
 351      $this->log("New workspace: $name from existing $workspace");
 352      if (empty($this->workspaces[$workspace])) {
 353        $this->log("Workspace $name does not exist.", 'error');
 354        return;
 355      }
 356  
 357      // Clean up if there was already a workspace there.
 358      if (isset($this->workspaces[$name])) {
 359        imagedestroy($this->workspaces[$name]);
 360      }
 361  
 362      $this->workspaces[$name] = $this->new_image($this->workspace[$workspace]);
 363      $this->set_current_workspace($name);
 364    }
 365  
 366    /**
 367     * Set the current workspace.
 368     */
 369    function command_workspace($name) {
 370      $this->log("Set workspace: $name");
 371      if (empty($this->workspaces[$name])) {
 372        $this->log("Workspace $name does not exist.", 'error');
 373        return;
 374      }
 375      $this->set_current_workspace($name);
 376    }
 377  
 378    /**
 379     * Copy the contents of one workspace into the current workspace.
 380     */
 381    function command_merge_from($workspace, $x = 0, $y = 0) {
 382      $this->log("Merge from: $workspace ($x, $y)");
 383      if (empty($this->workspaces[$workspace])) {
 384        $this->log("Workspace $name does not exist.", 'error');
 385        return;
 386      }
 387  
 388      $this->merge($this->workspaces[$workspace], $this->workspace, $x, $y);
 389    }
 390  
 391    function command_merge_to($workspace, $x = 0, $y = 0) {
 392      $this->log("Merge to: $workspace ($x, $y)");
 393      if (empty($this->workspaces[$workspace])) {
 394        $this->log("Workspace $name does not exist.", 'error');
 395        return;
 396      }
 397  
 398      $this->merge($this->workspace, $this->workspaces[$workspace], $x, $y);
 399      $this->set_current_workspace($workspace);
 400    }
 401  
 402    /**
 403     * Blend an image into the current workspace.
 404     */
 405    function command_merge_from_file($file, $x = 0, $y = 0) {
 406      $this->log("Merge from file: $file ($x, $y)");
 407      if (!file_exists($file)) {
 408        // Try it relative to the plugin
 409        $file = $this->plugin['path'] . '/' . $file;
 410        if (!file_exists($file)) {
 411          $this->log("Unable to open $file");
 412          return;
 413        }
 414      }
 415  
 416      $source = imagecreatefrompng($file);
 417  
 418      $this->merge($source, $this->workspace, $x, $y);
 419  
 420      imagedestroy($source);
 421    }
 422  
 423    function command_fill($color, $x, $y, $width, $height) {
 424      $this->log("Fill: $color ($x, $y, $width, $height)");
 425      imagefilledrectangle($this->workspace, $x, $y, $x + $width, $y + $height, ctools_color_gd($this->workspace, $this->palette[$color]));
 426    }
 427  
 428    function command_gradient($from, $to, $x, $y, $width, $height, $direction = 'down') {
 429      $this->log("Gradient: $from to $to ($x, $y, $width, $height) $direction");
 430  
 431      if ($direction == 'down') {
 432        for ($i = 0; $i < $height; ++$i) {
 433          $color = ctools_color_blend($this->workspace, $this->palette[$from], $this->palette[$to], $i / ($height - 1));
 434          imagefilledrectangle($this->workspace, $x, $y + $i, $x + $width, $y + $i + 1, $color);
 435        }
 436      }
 437      else {
 438        for ($i = 0; $i < $width; ++$i) {
 439          $color = ctools_color_blend($this->workspace, $this->palette[$from], $this->palette[$to], $i / ($width - 1));
 440          imagefilledrectangle($this->workspace, $x + $i, $y, $x + $i + 1, $y + $height, $color);
 441        }
 442      }
 443    }
 444  
 445    /**
 446     * Colorize the current workspace with the given location.
 447     *
 448     * This uses simple color blending to colorize the image.
 449     *
 450     * @todo it is possible that this colorize could allow different methods for
 451     * determining how to blend colors?
 452     */
 453    function command_colorize($color, $x = NULL, $y = NULL, $width = NULL, $height = NULL) {
 454      if (!isset($x)) {
 455        $whole_image = TRUE;
 456        $x = $y = 0;
 457        $width = imagesx($this->workspace);
 458        $height = imagesy($this->workspace);
 459      }
 460      $this->log("Colorize: $color ($x, $y, $width, $height)");
 461  
 462      $c = ctools_color_unpack($this->palette[$color]);
 463  
 464      imagealphablending($this->workspace, FALSE);
 465      imagesavealpha($this->workspace, TRUE);
 466  
 467      // If PHP 5 use the nice imagefilter which is faster.
 468      if (!empty($whole_image) && version_compare(phpversion(), '5.2.5', '>=') && function_exists('imagefilter')) {
 469        imagefilter($this->workspace, IMG_FILTER_COLORIZE, $c[0], $c[1], $c[2]);
 470      }
 471      else {
 472        // Otherwise we can do it the brute force way.
 473        for ($j = 0; $j < $height; $j++) {
 474          for ($i = 0; $i < $width; $i++) {
 475            $current = imagecolorsforindex($this->workspace, imagecolorat($this->workspace, $i, $j));
 476            $new_index = imagecolorallocatealpha($this->workspace, $c[0], $c[1], $c[2], $current['alpha']);
 477            imagesetpixel($this->workspace, $i, $j, $new_index);
 478          }
 479        }
 480      }
 481    }
 482  
 483    /**
 484     * Colorize the current workspace with the given location.
 485     *
 486     * This uses a color replacement algorithm that retains luminosity but
 487     * turns replaces all color with the specified color.
 488     */
 489    function command_hue($color, $x = NULL, $y = NULL, $width = NULL, $height = NULL) {
 490      if (!isset($x)) {
 491        $whole_image = TRUE;
 492        $x = $y = 0;
 493        $width = imagesx($this->workspace);
 494        $height = imagesy($this->workspace);
 495      }
 496      $this->log("Hue: $color ($x, $y, $width, $height)");
 497  
 498      list($red, $green, $blue) = ctools_color_unpack($this->palette[$color]);
 499  
 500      // We will create a monochromatic palette based on the input color
 501      // which will go from black to white.
 502  
 503      // Input color luminosity: this is equivalent to the position of the
 504      // input color in the monochromatic palette
 505      $luminosity_input = round(255 * ($red + $green + $blue) / 765); // 765 = 255 * 3
 506  
 507      // We fill the palette entry with the input color at itscorresponding position
 508      $palette[$luminosity_input]['red'] = $red;
 509      $palette[$luminosity_input]['green'] = $green;
 510      $palette[$luminosity_input]['blue'] = $blue;
 511  
 512      // Now we complete the palette, first we'll do it tothe black, and then to
 513      // the white.
 514  
 515      // From input to black
 516      $steps_to_black = $luminosity_input;
 517  
 518      // The step size for each component
 519      if ($steps_to_black) {
 520        $step_size_red = $red / $steps_to_black;
 521        $step_size_green = $green / $steps_to_black;
 522        $step_size_blue = $blue / $steps_to_black;
 523  
 524        for ($i = $steps_to_black; $i >= 0; $i--) {
 525          $palette[$steps_to_black-$i]['red'] = $red - round($step_size_red * $i);
 526          $palette[$steps_to_black-$i]['green'] = $green - round($step_size_green * $i);
 527          $palette[$steps_to_black-$i]['blue'] = $blue - round($step_size_blue * $i);
 528        }
 529      }
 530  
 531      // From input to white
 532      $steps_to_white = 255 - $luminosity_input;
 533  
 534      if ($steps_to_white) {
 535        $step_size_red = (255 - $red) / $steps_to_white;
 536        $step_size_green = (255 - $green) / $steps_to_white;
 537        $step_size_blue = (255 - $blue) / $steps_to_white;
 538      }
 539      else {
 540        $step_size_red=$step_size_green=$step_size_blue=0;
 541      }
 542  
 543      // The step size for each component
 544      for($i = ($luminosity_input + 1); $i <= 255; $i++) {
 545        $palette[$i]['red'] = $red + round($step_size_red * ($i - $luminosity_input));
 546        $palette[$i]['green'] = $green + round($step_size_green * ($i - $luminosity_input));
 547        $palette[$i]['blue']= $blue + round($step_size_blue * ($i - $luminosity_input));
 548      }
 549  
 550      // Go over the specified area of the image and update the colors.
 551      for ($j = $x; $j < $height; $j++) {
 552        for ($i = $y; $i < $width; $i++) {
 553          $color = imagecolorsforindex($this->workspace, imagecolorat($this->workspace, $i, $j));
 554          $luminosity = round(255 * ($color['red'] + $color['green'] + $color['blue']) / 765);
 555          $new_color = imagecolorallocatealpha($this->workspace, $palette[$luminosity]['red'], $palette[$luminosity]['green'], $palette[$luminosity]['blue'], $color['alpha']);
 556          imagesetpixel($this->workspace, $i, $j, $new_color);
 557        }
 558      }
 559    }
 560  
 561    /**
 562     * Take a slice out of the current workspace and save it as an image.
 563     */
 564    function command_slice($file, $x = NULL, $y = NULL, $width = NULL, $height = NULL) {
 565      if (!isset($x)) {
 566        $x = $y = 0;
 567        $width = imagesx($this->workspace);
 568        $height = imagesy($this->workspace);
 569      }
 570  
 571      $this->log("Slice: $file ($x, $y, $width, $height)");
 572  
 573      $base = basename($file);
 574      $image = $this->path . '/' . $base;
 575  
 576      $slice = $this->new_image($this->workspace, $width, $height);
 577      imagecopy($slice, $this->workspace, 0, 0, $x, $y, $width, $height);
 578  
 579      // Make sure alphas are saved:
 580      imagealphablending($slice, FALSE);
 581      imagesavealpha($slice, TRUE);
 582  
 583      // Save image.
 584      imagepng($slice, $image);
 585      imagedestroy($slice);
 586  
 587      // Set standard file permissions for webserver-generated files
 588      @chmod(realpath($image), 0664);
 589  
 590      $this->paths[$file] = $image;
 591    }
 592  
 593    /**
 594     * Prepare a new image for being copied or worked on, preserving transparency.
 595     */
 596    function &new_image(&$source, $width = NULL, $height = NULL) {
 597      if (!isset($width)) {
 598        $width = imagesx($source);
 599      }
 600  
 601      if (!isset($height)) {
 602        $height = imagesy($source);
 603      }
 604  
 605      $target = imagecreatetruecolor($width, $height);
 606      imagealphablending($target, FALSE);
 607        imagesavealpha($target, TRUE);
 608  
 609      $transparency_index = imagecolortransparent($source);
 610  
 611      // If we have a specific transparent color
 612      if ($transparency_index >= 0) {
 613        // Get the original image's transparent color's RGB values
 614        $transparent_color = imagecolorsforindex($source, $transparency_index);
 615  
 616        // Allocate the same color in the new image resource
 617        $transparency_index = imagecolorallocate($target, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
 618  
 619        // Completely fill the background of the new image with allocated color.
 620        imagefill($target, 0, 0, $transparency_index);
 621  
 622        // Set the background color for new image to transparent
 623        imagecolortransparent($target, $transparency_index);
 624      }
 625      // Always make a transparent background color for PNGs that don't have one allocated already
 626      else {
 627        // Create a new transparent color for image
 628        $color = imagecolorallocatealpha($target, 0, 0, 0, 127);
 629  
 630        // Completely fill the background of the new image with allocated color.
 631        imagefill($target, 0, 0, $color);
 632      }
 633  
 634      return $target;
 635    }
 636  
 637    /**
 638     * Merge two images together, preserving alpha transparency.
 639     */
 640    function merge(&$from, &$to, $x, $y) {
 641      // Blend over template.
 642      $width = imagesx($from);
 643      $height = imagesy($from);
 644  
 645      // Re-enable alpha blending to make sure transparency merges.
 646      imagealphablending($to, TRUE);
 647      imagecopy($to, $from, $x, $y, 0, 0, $width, $height);
 648      imagealphablending($to, FALSE);
 649    }
 650  }
 651  
 652  /**
 653   * Get the cached changes to a given task handler.
 654   */
 655  function ctools_stylizer_get_settings_cache($name) {
 656    ctools_include('object-cache');
 657    return ctools_object_cache_get('ctools_stylizer_settings', $name);
 658  }
 659  
 660  /**
 661   * Store changes to a task handler in the object cache.
 662   */
 663  function ctools_stylizer_set_settings_cache($name, $settings) {
 664    ctools_include('object-cache');
 665    ctools_object_cache_set('ctools_stylizer_settings', $name, $settings);
 666  }
 667  
 668  /**
 669   * Remove an item from the object cache.
 670   */
 671  function ctools_stylizer_clear_settings_cache($name) {
 672    ctools_include('object-cache');
 673    ctools_object_cache_clear('ctools_stylizer_settings', $name);
 674  }
 675  
 676  /**
 677   * Add a new style of the specified type.
 678   */
 679  function ctools_stylizer_edit_style(&$info, $js, $step = NULL) {
 680    $name = '::new';
 681    $form_info = array(
 682      'id' => 'ctools_stylizer_edit_style',
 683      'path' => $info['path'],
 684      'show trail' => TRUE,
 685      'show back' => TRUE,
 686      'show return' => FALSE,
 687      'next callback' => 'ctools_stylizer_edit_style_next',
 688      'finish callback' => 'ctools_stylizer_edit_style_finish',
 689      'return callback' => 'ctools_stylizer_edit_style_finish',
 690      'cancel callback' => 'ctools_stylizer_edit_style_cancel',
 691      'forms' => array(
 692        'choose' => array(
 693          'form id' => 'ctools_stylizer_edit_style_form_choose',
 694        ),
 695      ),
 696    );
 697  
 698    if (empty($info['settings'])) {
 699      $form_info['order'] = array(
 700        'choose' => t('Select base style'),
 701      );
 702      if (empty($step)) {
 703        $step = 'choose';
 704      }
 705  
 706      if ($step != 'choose') {
 707        $cache = ctools_stylizer_get_settings_cache($name);
 708        if (!$cache) {
 709          $output = t('Missing settings cache.');
 710          if ($js) {
 711            return ctools_modal_form_render($form_state, $output);
 712          }
 713          else {
 714            return $output;
 715          }
 716        }
 717  
 718        if (!empty($cache['owner settings'])) {
 719          $info['owner settings'] = $cache['owner settings'];
 720        }
 721        $settings = $cache['settings'];
 722      }
 723      else {
 724        $settings = array(
 725          'name' => '_temporary',
 726          'style_base' => NULL,
 727          'palette' => array(),
 728        );
 729        ctools_stylizer_clear_settings_cache($name);
 730      }
 731      $op = 'add';
 732    }
 733    else {
 734      $cache = ctools_stylizer_get_settings_cache($info['settings']['name']);
 735  
 736      if (!empty($cache)) {
 737        if (!empty($cache['owner settings'])) {
 738          $info['owner settings'] = $cache['owner settings'];
 739        }
 740        $settings = $cache['settings'];
 741      }
 742      else {
 743        $settings = $info['settings'];
 744      }
 745      $op = 'edit';
 746    }
 747  
 748    if (!empty($info['op'])) {
 749      // Allow this to override. Necessary to allow cloning properly.
 750      $op = $info['op'];
 751    }
 752  
 753    $plugin = NULL;
 754    if (!empty($settings['style_base'])) {
 755      $plugin = ctools_get_style_base($settings['style_base']);
 756      $info['type'] = $plugin['type'];
 757      ctools_stylizer_add_plugin_forms($form_info, $plugin, $op);
 758    }
 759    else {
 760      // This is here so the 'finish' button does not show up, and because
 761      // we don't have the selected style we don't know what the next form(s)
 762      // will be.
 763      $form_info['order']['next'] = t('Configure style');
 764    }
 765  
 766    if (count($form_info['order']) < 2 || $step == 'choose') {
 767      $form_info['show trail'] = FALSE;
 768    }
 769  
 770    $form_state = array(
 771      'module' => $info['module'],
 772      'type' => $info['type'],
 773      'owner info' => &$info,
 774      'plugin' => $plugin,
 775      'name' => $name,
 776      'step' => $step,
 777      'settings' => $settings,
 778      'ajax' => $js,
 779      'op' => $op,
 780    );
 781  
 782    if (!empty($info['modal'])) {
 783      $form_state['modal'] = TRUE;
 784      $form_state['title'] = $info['modal'];
 785      $form_state['modal return'] = TRUE;
 786    }
 787  
 788    ctools_include('wizard');
 789    $output = ctools_wizard_multistep_form($form_info, $step, $form_state);
 790  
 791    if (!empty($form_state['complete'])) {
 792      $info['complete'] = TRUE;
 793      $info['settings'] = $form_state['settings'];
 794    }
 795  
 796    if ($js && !$output && !empty($form_state['clicked_button']['#next'])) {
 797      // We have to do a separate redirect here because the formula that adds
 798      // stuff to the wizard after being chosen hasn't happened. The wizard
 799      // tried to go to the next step which did not exist.
 800      return ctools_stylizer_edit_style($info, $js, $form_state['clicked_button']['#next']);
 801    }
 802  
 803    if ($js) {
 804      return ctools_modal_form_render($form_state, $output);
 805    }
 806    else {
 807      return $output;
 808    }
 809  }
 810  
 811  /**
 812   * Add wizard forms specific to a style base plugin.
 813   *
 814   * The plugin can store forms either as a simple 'edit form'
 815   * => 'form callback' or if it needs the more complicated wizard
 816   * functionality, it can set 'forms' and 'order' with values suitable
 817   * for the wizard $form_info array.
 818   *
 819   * @param &$form_info
 820   *   The form info to modify.
 821   * @param $plugin
 822   *   The plugin to use.
 823   * @param $op
 824   *   Either 'add' or 'edit' so we can get the right forms.
 825   */
 826  function ctools_stylizer_add_plugin_forms(&$form_info, $plugin, $op) {
 827    if (empty($plugin['forms'])) {
 828      if ($op == 'add' && isset($plugin['add form'])) {
 829        $id = $plugin['add form'];
 830      }
 831      else if (isset($plugin['edit form'])) {
 832        $id = $plugin['edit form'];
 833      }
 834      else {
 835        $id = 'ctools_stylizer_edit_style_form_default';
 836      }
 837  
 838      $form_info['forms']['settings'] = array(
 839        'form id' => $id,
 840      );
 841      $form_info['order']['settings'] = t('Settings');
 842    }
 843    else {
 844      $form_info['forms'] += $plugin['forms'];
 845      $form_info['order'] += $plugin['order'];
 846    }
 847  }
 848  
 849  /**
 850   * Callback generated when the add style process is finished.
 851   */
 852  function ctools_stylizer_edit_style_finish(&$form_state) {
 853    $form_state['complete'] = TRUE;
 854    ctools_stylizer_clear_settings_cache($form_state['name']);
 855  
 856    if (isset($form_state['settings']['old_settings'])) {
 857      unset($form_state['settings']['old_settings']);
 858    }
 859  }
 860  
 861  /**
 862   * Callback generated when the 'next' button is clicked.
 863   */
 864  function ctools_stylizer_edit_style_next(&$form_state) {
 865    $form_state['form_info']['path'] = str_replace('%name', $form_state['name'], $form_state['form_info']['path']);
 866    $form_state['redirect'] = ctools_wizard_get_path($form_state['form_info'], $form_state['clicked_button']['#next']);
 867  
 868    // Update the cache with changes.
 869    $cache = array('settings' => $form_state['settings']);
 870    if (!empty($form_state['owner info']['owner settings'])) {
 871      $cache['owner settings'] = $form_state['owner info']['owner settings'];
 872    }
 873    ctools_stylizer_set_settings_cache($form_state['name'], $cache);
 874  }
 875  
 876  /**
 877   * Callback generated when the 'cancel' button is clicked.
 878   *
 879   * We might have some temporary data lying around. We must remove it.
 880   */
 881  function ctools_stylizer_edit_style_cancel(&$form_state) {
 882    if (!empty($form_state['name'])) {
 883      ctools_stylizer_clear_settings_cache($form_state['name']);
 884    }
 885  }
 886  
 887  /**
 888   * Choose which plugin to use to create a new style.
 889   */
 890  function ctools_stylizer_edit_style_form_choose(&$form, &$form_state) {
 891    $plugins = ctools_get_style_bases();
 892    $options = array();
 893  
 894    $categories = array();
 895    foreach ($plugins as $name => $plugin) {
 896      if ($form_state['module'] == $plugin['module'] && $form_state['type'] == $plugin['type']) {
 897        $categories[$plugin['category']] = $plugin['category'];
 898        $unsorted_options[$plugin['category']][$name] = ctools_stylizer_print_style_icon($plugin, TRUE);
 899      }
 900    }
 901  
 902    asort($categories);
 903  
 904    foreach ($categories as $category) {
 905      $options[$category] = $unsorted_options[$category];
 906    }
 907  
 908    $form['style_base'] = array(
 909      '#prefix' => '<div class="ctools-style-icons clear-block">',
 910      '#suffix' => '</div>',
 911    );
 912  
 913    ctools_include('cleanstring');
 914    foreach ($options as $category => $radios) {
 915      $cat = ctools_cleanstring($category);
 916      $form['style_base'][$cat] = array(
 917        '#prefix' => '<div class="ctools-style-category clear-block"><label>' . $category . '</label>',
 918        '#suffix' => '</div>',
 919      );
 920  
 921      foreach ($radios as $key => $choice) {
 922        // Generate the parents as the autogenerator does, so we will have a
 923        // unique id for each radio button.
 924        $form['style_base'][$cat][$key] = array(
 925          '#type' => 'radio',
 926          '#title' => $choice,
 927          '#parents' => array('style_base'),
 928          '#id' => form_clean_id('edit-style-base-' . $key),
 929          '#return_value' => check_plain($key),
 930        );
 931      }
 932    }
 933  }
 934  
 935  function ctools_stylizer_edit_style_form_choose_submit(&$form, &$form_state) {
 936    $form_state['settings']['style_base'] = $form_state['values']['style_base'];
 937  
 938    // The 'next' form will show up as 'next' but that's not accurate now that
 939    // we have a style. Figure out what next really is and update.
 940    $plugin = ctools_get_style_base($form_state['settings']['style_base']);
 941    if (empty($plugin['forms'])) {
 942      $form_state['clicked_button']['#next'] = 'settings';
 943    }
 944    else {
 945      $forms = array_keys($form_info['forms']);
 946      $form_state['clicked_button']['#next'] = array_shift($forms);
 947    }
 948  
 949    // Fill in the defaults for the settings.
 950    if (!empty($plugin['defaults'])) {
 951      // @todo allow a callback
 952      $form_state['settings'] += $plugin['defaults'];
 953    }
 954  }
 955  
 956  /**
 957   * The default stylizer style editing form.
 958   *
 959   * Even when not using this, styles should call through to this form in
 960   * their own edit forms.
 961   */
 962  function ctools_stylizer_edit_style_form_default(&$form, &$form_state) {
 963    ctools_add_js('stylizer');
 964    ctools_add_css('stylizer');
 965    drupal_add_js('misc/farbtastic/farbtastic.js');
 966    drupal_add_css('misc/farbtastic/farbtastic.css');
 967  
 968    $plugin = &$form_state['plugin'];
 969    $settings = &$form_state['settings'];
 970  
 971    $form['top box'] = array(
 972      '#prefix' => '<div id="ctools-stylizer-top-box" class="clear-block">',
 973      '#suffix' => '</div>',
 974    );
 975    $form['top box']['left'] = array(
 976      '#prefix' => '<div id="ctools-stylizer-left-box">',
 977      '#suffix' => '</div>',
 978    );
 979    $form['top box']['preview'] = array(
 980      // We have a copy of the $form_state on $form because form theme functions
 981      // do not get $form_state.
 982      '#theme' => 'ctools_stylizer_preview_form',
 983      '#form_state' => &$form_state,
 984    );
 985  
 986    $form['top box']['preview']['submit'] = array(
 987      '#type' => 'submit',
 988      '#value' => t('Preview'),
 989    );
 990  
 991    if (!empty($plugin['palette'])) {
 992      $form['top box']['color'] = array(
 993        '#type' => 'fieldset',
 994        '#title' => t('Color scheme'),
 995        '#attributes' => array('id' => 'ctools_stylizer_color_scheme_form', 'class' => 'ctools-stylizer-color-edit'),
 996        '#theme' => 'ctools_stylizer_color_scheme_form',
 997      );
 998  
 999      $form['top box']['color']['palette']['#tree'] = true;
1000  
1001      foreach ($plugin['palette'] as $key => $color) {
1002        if (empty($settings['palette'][$key])) {
1003          $settings['palette'][$key] = $color['default_value'];
1004        }
1005  
1006        $form['top box']['color']['palette'][$key] = array(
1007          '#type' => 'textfield',
1008          '#title' => $color['label'],
1009          '#default_value' => $settings['palette'][$key],
1010          '#size' => 8,
1011        );
1012      }
1013    }
1014  
1015    if (!empty($plugin['settings form']) && function_exists($plugin['settings form'])) {
1016      $plugin['settings form']($form, $form_state);
1017    }
1018  
1019    if (!empty($form_state['owner info']['owner form']) && function_exists($form_state['owner info']['owner form'])) {
1020      $form_state['owner info']['owner form']($form, $form_state);
1021    }
1022  }
1023  
1024  /**
1025   * Theme the stylizer color scheme form.
1026   */
1027  function theme_ctools_stylizer_color_scheme_form($form) {
1028    $output = '';
1029  
1030    // Wrapper
1031    $output .= '<div class="color-form clear-block">';
1032  
1033    // Color schemes
1034  //  $output .= drupal_render($form['scheme']);
1035  
1036    // Palette
1037    $output .= '<div id="palette" class="clear-block">';
1038    foreach (element_children($form['palette']) as $name) {
1039      $output .= drupal_render($form['palette'][$name]);
1040    }
1041    $output .= '</div>'; // palette
1042  
1043    $output .= '</div>'; // color form
1044  
1045    return $output;
1046  }
1047  
1048  /**
1049   * Theme the stylizer preview form.
1050   */
1051  function theme_ctools_stylizer_preview_form($form) {
1052    $plugin = $form['#form_state']['plugin'];
1053    $settings = $form['#form_state']['settings'];
1054  
1055    if (!empty($form['#form_state']['settings']['old_settings'])) {
1056      ctools_stylizer_cleanup_style($plugin, $form['#form_state']['settings']['old_settings']);
1057    }
1058    $preview = '';
1059    if (!empty($plugin['preview'])) {
1060      $preview = $plugin['preview'];
1061    }
1062    else {
1063      $base_types = ctools_get_style_base_types();
1064      if (!empty($base_types[$plugin['module']][$plugin['type']]['preview'])) {
1065        $preview = $base_types[$plugin['module']][$plugin['type']]['preview'];
1066      }
1067    }
1068  
1069    if (!empty($preview) && function_exists($preview)) {
1070      $output = '<fieldset id="preview"><legend>' . t('Preview') . '</legend>';
1071      $output .= $preview($plugin, $settings);
1072      $output .= drupal_render($form);
1073      $output .= '</fieldset>';
1074  
1075      return $output;
1076    }
1077  }
1078  
1079  function ctools_stylizer_edit_style_form_default_validate($form, &$form_state) {
1080    if (!empty($form_state['owner info']['owner form validate']) && function_exists($form_state['owner info']['owner form validate'])) {
1081      $form_state['owner info']['owner form validate']($form, $form_state);
1082    }
1083  
1084    if (!empty($form_state['plugin']['settings form validate']) && function_exists($form_state['plugin']['settings form validate'])) {
1085      $form_state['plugin']['settings form validate']($form, $form_state);
1086    }
1087  }
1088  
1089  function ctools_stylizer_edit_style_form_default_submit($form, &$form_state) {
1090    // Store old settings for the purposes of cleaning up.
1091    $form_state['settings']['old_settings'] = $form_state['settings'];
1092    $form_state['settings']['palette'] = $form_state['values']['palette'];
1093  
1094    if (!empty($form_state['owner info']['owner form submit']) && function_exists($form_state['owner info']['owner form submit'])) {
1095      $form_state['owner info']['owner form submit']($form, $form_state);
1096    }
1097  
1098    if (!empty($form_state['plugin']['settings form submit']) && function_exists($form_state['plugin']['settings form submit'])) {
1099      $form_state['plugin']['settings form submit']($form, $form_state);
1100    }
1101  
1102    if ($form_state['clicked_button']['#value'] == t('Preview')) {
1103      $form_state['rerender'] = TRUE;
1104      // Update the cache with changes.
1105      if (!empty($form_state['name'])) {
1106        $cache = array('settings' => $form_state['settings']);
1107        if (!empty($form_state['owner info']['owner settings'])) {
1108          $cache['owner settings'] = $form_state['owner info']['owner settings'];
1109        }
1110        ctools_stylizer_set_settings_cache($form_state['name'], $cache);
1111      }
1112    }
1113  }
1114  
1115  // --------------------------------------------------------------------------
1116  // CSS forms and tools that plugins can use.
1117  
1118  /**
1119   * Font selector form
1120   */
1121  function ctools_stylizer_font_selector_form(&$form, &$form_state, $label, $settings) {
1122    // Family
1123    $form['#prefix'] = '<div class="ctools-stylizer-spacing-form clear-block">';
1124    $form['#type'] = 'fieldset';
1125    $form['#title'] = $label;
1126    $form['#suffix'] = '</div>';
1127    $form['#tree'] = TRUE;
1128  
1129    $form['font'] = array(
1130      '#title' => t('Font family'),
1131      '#type' => 'select',
1132      '#default_value' => isset($settings['font']) ? $settings['font'] : '',
1133      '#options' => array(
1134        '' => '',
1135        'Arial, Helvetica, sans-serif' => t('Arial, Helvetica, sans-serif'),
1136        'Times New Roman, Times, serif' => t('Times New Roman, Times, serif'),
1137        'Courier New, Courier, monospace' => t('Courier New, Courier, monospace'),
1138        'Georgia, Times New Roman, Times, serif' => t('Georgia, Times New Roman, Times, serif'),
1139        'Verdana, Arial, Helvetica, sans-serif' => t('Verdana, Arial, Helvetica, sans-serif'),
1140        'Geneva, Arial, Helvetica, sans-serif' => t('Geneva, Arial, Helvetica, sans-serif'),
1141        'Trebuchet MS, Trebuchet, Verdana, sans-serif' => t('Trebuchet MS, Trebuchet, Verdana, sans-serif'),
1142      ),
1143    );
1144  
1145    // size
1146    $form['size'] = array(
1147      '#title' => t('Size'),
1148      '#type' => 'select',
1149      '#default_value' => isset($settings['size']) ? $settings['size'] : '',
1150      '#options' => array(
1151        '' => '',
1152        'xx-small' => t('XX-Small'),
1153        'x-small' => t('X-Small'),
1154        'small' => t('Small'),
1155        'medium' => t('Medium'),
1156        'large' => t('Large'),
1157        'x-large' => t('X-Large'),
1158        'xx-large' => t('XX-Large'),
1159      ),
1160    );
1161  
1162    // letter spacing
1163    $form['letter_spacing'] = array(
1164      '#title' => t('Letter spacing'),
1165      '#type' => 'select',
1166      '#default_value' => isset($settings['letter_spacing']) ? $settings['letter_spacing'] : '',
1167      '#options' => array(
1168        '' => '',
1169        "-10px" => '10px',
1170        "-9px" => '9px',
1171        "-8px" => '8px',
1172        "-7px" => '7px',
1173        "-6px" => '6px',
1174        "-5px" => '5px',
1175        "-4px" => '4px',
1176        "-3px" => '3px',
1177        "-2px" => '2px',
1178        "-1px" => '1px',
1179        "0" => '0',
1180        "1px" => '1px',
1181        "2px" => '2px',
1182        "3px" => '3px',
1183        "4px" => '4px',
1184        "5px" => '5px',
1185        "6px" => '6px',
1186        "7px" => '7px',
1187        "8px" => '8px',
1188        "9px" => '9px',
1189        "10px" => '10px',
1190        "11px" => '11px',
1191        "12px" => '12px',
1192        "13px" => '13px',
1193        "14px" => '14px',
1194        "15px" => '15px',
1195        "16px" => '16px',
1196        "17px" => '17px',
1197        "18px" => '18px',
1198        "19px" => '19px',
1199        "20px" => '20px',
1200        "21px" => '21px',
1201        "22px" => '22px',
1202        "23px" => '23px',
1203        "24px" => '24px',
1204        "25px" => '25px',
1205        "26px" => '26px',
1206        "27px" => '27px',
1207        "28px" => '28px',
1208        "29px" => '29px',
1209        "30px" => '30px',
1210        "31px" => '31px',
1211        "32px" => '32px',
1212        "33px" => '33px',
1213        "34px" => '34px',
1214        "35px" => '35px',
1215        "36px" => '36px',
1216        "37px" => '37px',
1217        "38px" => '38px',
1218        "39px" => '39px',
1219        "40px" => '40px',
1220        "41px" => '41px',
1221        "42px" => '42px',
1222        "43px" => '43px',
1223        "44px" => '44px',
1224        "45px" => '45px',
1225        "46px" => '46px',
1226        "47px" => '47px',
1227        "48px" => '48px',
1228        "49px" => '49px',
1229        "50px" => '50px',
1230      ),
1231    );
1232  
1233    // word space
1234    $form['word_spacing'] = array(
1235      '#title' => t('Word spacing'),
1236      '#type' => 'select',
1237      '#default_value' => isset($settings['word_spacing']) ? $settings['word_spacing'] : '',
1238      '#options' => array(
1239        '' => '',
1240        "-1em" => '-1em',
1241        "-0.95em" => '-0.95em',
1242        "-0.9em" => '-0.9em',
1243        "-0.85em" => '-0.85em',
1244        "-0.8em" => '-0.8em',
1245        "-0.75em" => '-0.75em',
1246        "-0.7em" => '-0.7em',
1247        "-0.65em" => '-0.65em',
1248        "-0.6em" => '-0.6em',
1249        "-0.55em" => '-0.55em',
1250        "-0.5em" => '-0.5em',
1251        "-0.45em" => '-0.45em',
1252        "-0.4em" => '-0.4em',
1253        "-0.35em" => '-0.35em',
1254        "-0.3em" => '-0.3em',
1255        "-0.25em" => '-0.25em',
1256        "-0.2em" => '-0.2em',
1257        "-0.15em" => '-0.15em',
1258        "-0.1em" => '-0.1em',
1259        "-0.05em" => '-0.05em',
1260        "normal" => 'normal',
1261        "0.05em" => '0.05em',
1262        "0.1em" => '0.1em',
1263        "0.15em" => '0.15em',
1264        "0.2em" => '0.2em',
1265        "0.25em" => '0.25em',
1266        "0.3em" => '0.3em',
1267        "0.35em" => '0.35em',
1268        "0.4em" => '0.4em',
1269        "0.45em" => '0.45em',
1270        "0.5em" => '0.5em',
1271        "0.55em" => '0.55em',
1272        "0.6em" => '0.6em',
1273        "0.65em" => '0.65em',
1274        "0.7em" => '0.7em',
1275        "0.75em" => '0.75em',
1276        "0.8em" => '0.8em',
1277        "0.85em" => '0.85em',
1278        "0.9em" => '0.9em',
1279        "0.95em" => '0.95em',
1280        "1em" => '1em',
1281      ),
1282    );
1283  
1284    // decoration
1285    $form['decoration'] = array(
1286      '#title' => t('Decoration'),
1287      '#type' => 'select',
1288      '#default_value' => isset($settings['decoration']) ? $settings['decoration'] : '',
1289      '#options' => array(
1290        '' => '',
1291        'none' => t('None'),
1292        'underline' => t('Underline'),
1293        'overline' => t('Overline'),
1294        'line-through' => t('Line-through'),
1295      ),
1296    );
1297  
1298    // weight
1299    $form['weight'] = array(
1300      '#title' => t('Weight'),
1301      '#type' => 'select',
1302      '#default_value' => isset($settings['weight']) ? $settings['weight'] : '',
1303      '#options' => array(
1304        '' => '',
1305        'normal' => t('Normal'),
1306        'bold' => t('Bold'),
1307        'bolder' => t('Bolder'),
1308        'lighter' => t('Lighter'),
1309      ),
1310    );
1311  
1312    // style
1313    $form['style'] = array(
1314      '#title' => t('Style'),
1315      '#type' => 'select',
1316      '#default_value' => isset($settings['style']) ? $settings['style'] : '',
1317      '#options' => array(
1318        '' => '',
1319        'normal' => t('Normal'),
1320        'italic' => t('Italic'),
1321        'oblique' => t('Oblique'),
1322      ),
1323    );
1324  
1325    // variant
1326    $form['variant'] = array(
1327      '#title' => t('Variant'),
1328      '#type' => 'select',
1329      '#default_value' => isset($settings['variant']) ? $settings['variant'] : '',
1330      '#options' => array(
1331        '' => '',
1332        'normal' => t('Normal'),
1333        'small-caps' => t('Small-caps'),
1334      ),
1335    );
1336  
1337    // case
1338    $form['case'] = array(
1339      '#title' => t('Case'),
1340      '#type' => 'select',
1341      '#default_value' => isset($settings['case']) ? $settings['case'] : '',
1342      '#options' => array(
1343        '' => '',
1344        'capitalize' => t('Capitalize'),
1345        'uppercase' => t('Uppercase'),
1346        'lowercase' => t('Lowercase'),
1347        'none' => t('None'),
1348      ),
1349    );
1350  
1351    // alignment
1352    $form['alignment'] = array(
1353      '#title' => t('Align'),
1354      '#type' => 'select',
1355      '#default_value' => isset($settings['alignment']) ? $settings['alignment'] : '',
1356      '#options' => array(
1357        '' => '',
1358        'justify' => t('Justify'),
1359        'left' => t('Left'),
1360        'right' => t('Right'),
1361        'center' => t('Center'),
1362      ),
1363    );
1364  }
1365  
1366  /**
1367   * Copy font selector information into the settings
1368   */
1369  function ctools_stylizer_font_selector_form_submit(&$form, &$form_state, &$values, &$settings) {
1370    $settings = $values;
1371  }
1372  
1373  function ctools_stylizer_font_apply_style(&$stylesheet, $selector, $settings) {
1374    $css = '';
1375    if (isset($settings['font']) && $settings['font'] !== '') {
1376      $css .= '  font-family: ' . $settings['font'] . ";\n";
1377    }
1378  
1379    if (isset($settings['size']) && $settings['size'] !== '') {
1380      $css .= '  font-size: ' . $settings['size'] . ";\n";
1381    }
1382  
1383    if (isset($settings['weight']) && $settings['weight'] !== '') {
1384      $css .= '  font-weight: ' . $settings['weight'] . ";\n";
1385    }
1386  
1387    if (isset($settings['style']) && $settings['style'] !== '') {
1388      $css .= '  font-style: ' . $settings['style'] . ";\n";
1389    }
1390  
1391    if (isset($settings['variant']) && $settings['variant'] !== '') {
1392      $css .= '  font-variant: ' . $settings['variant'] . ";\n";
1393    }
1394  
1395    if (isset($settings['case']) && $settings['case'] !== '') {
1396      $css .= '  text-transform: ' . $settings['case'] . ";\n";
1397    }
1398  
1399    if (isset($settings['decoration']) && $settings['decoration'] !== '') {
1400      $css .= '  text-decoration: ' . $settings['decoration'] . ";\n";
1401    }
1402  
1403    if (isset($settings['alignment']) && $settings['alignment'] !== '') {
1404      $css .= '  text-align: ' . $settings['alignment'] . ";\n";
1405    }
1406  
1407    if (isset($settings['letter_spacing']) && $settings['letter_spacing'] !== '') {
1408      $css .= '  letter-spacing: ' . $settings['letter_spacing'] . ";\n";
1409    }
1410  
1411    if (isset($settings['word_spacing']) && $settings['word_spacing'] !== '') {
1412      $css .= '  word-spacing: ' . $settings['word_spacing'] . ";\n";
1413    }
1414  
1415    if ($css) {
1416      $stylesheet .= $selector . " {\n" . $css . "}\n";
1417    }
1418  }
1419  
1420  /**
1421   * Border selector form
1422   */
1423  function ctools_stylizer_border_selector_form(&$form, &$form_state, $label, $settings) {
1424    // Family
1425    $form['#prefix'] = '<div class="ctools-stylizer-spacing-form clear-block">';
1426    $form['#type'] = 'fieldset';
1427    $form['#title'] = $label;
1428    $form['#suffix'] = '</div>';
1429    $form['#tree'] = TRUE;
1430  
1431    $form['thickness'] = array(
1432      '#title' => t('Thickness'),
1433      '#type' => 'select',
1434      '#default_value' => isset($settings['thickness']) ? $settings['thickness'] : '',
1435      '#options' => array(
1436        '' => '',
1437        "none" => t('None'),
1438        "1px" => '1px',
1439        "2px" => '2px',
1440        "3px" => '3px',
1441        "4px" => '4px',
1442        "5px" => '5px',
1443      ),
1444    );
1445  
1446    $form['style'] = array(
1447      '#title' => t('style'),
1448      '#type' => 'select',
1449      '#default_value' => isset($settings['style']) ? $settings['style'] : '',
1450      '#options' => array(
1451        '' => '',
1452        'solid' => t('Solid'),
1453        'dotted' => t('Dotted'),
1454        'dashed' => t('Dashed'),
1455        'double' => t('Double'),
1456        'groove' => t('Groove'),
1457        'ridge' => t('Ridge'),
1458        'inset' => t('Inset'),
1459        'outset' => t('Outset'),
1460      ),
1461    );
1462  }
1463  
1464  /**
1465   * Copy border selector information into the settings
1466   */
1467  function ctools_stylizer_border_selector_form_submit(&$form, &$form_state, &$values, &$settings) {
1468    $settings = $values;
1469  }
1470  
1471  function ctools_stylizer_border_apply_style(&$stylesheet, $selector, $settings, $color, $which = NULL) {
1472    $border = 'border';
1473    if ($which) {
1474      $border .= '-' . $which;
1475    }
1476  
1477    $css = '';
1478    if (isset($settings['thickness']) && $settings['thickness'] !== '') {
1479      if ($settings['thickness'] == 'none') {
1480        $css .= '  ' . $border . ': none';
1481      }
1482      else {
1483        $css .= '  ' . $border . '-width: ' . $settings['thickness'] . ";\n";
1484  
1485        if (isset($settings['style']) && $settings['style'] !== '') {
1486          $css .= '  ' . $border . '-style: ' . $settings['style'] . ";\n";
1487        }
1488  
1489        $css .= '  ' . $border . '-color: ' . $color . ";\n";
1490      }
1491    }
1492  
1493    if ($css) {
1494      $stylesheet .= $selector . " {\n" . $css . "}\n";
1495    }
1496  
1497  }
1498  
1499  /**
1500   * padding selector form
1501   */
1502  function ctools_stylizer_padding_selector_form(&$form, &$form_state, $label, $settings) {
1503    // Family
1504    $form['#prefix'] = '<div class="ctools-stylizer-spacing-form clear-block">';
1505    $form['#type'] = 'fieldset';
1506    $form['#title'] = $label;
1507    $form['#suffix'] = '</div>';
1508    $form['#tree'] = TRUE;
1509  
1510    $options = array(
1511      '' => '',
1512      "0.05em" => '0.05em',
1513      "0.1em" => '0.1em',
1514      "0.15em" => '0.15em',
1515      "0.2em" => '0.2em',
1516      "0.25em" => '0.25em',
1517      "0.3em" => '0.3em',
1518      "0.35em" => '0.35em',
1519      "0.4em" => '0.4em',
1520      "0.45em" => '0.45em',
1521      "0.5em" => '0.5em',
1522      "0.55em" => '0.55em',
1523      "0.6em" => '0.6em',
1524      "0.65em" => '0.65em',
1525      "0.7em" => '0.7em',
1526      "0.75em" => '0.75em',
1527      "0.8em" => '0.8em',
1528      "0.85em" => '0.85em',
1529      "0.9em" => '0.9em',
1530      "0.95em" => '0.95em',
1531      "1.0em" => '1.0em',
1532      "1.05em" => '1.05em',
1533      "1.1em" => '1.1em',
1534      "1.15em" => '1.15em',
1535      "1.2em" => '1.2em',
1536      "1.25em" => '1.25em',
1537      "1.3em" => '1.3em',
1538      "1.35em" => '1.35em',
1539      "1.4em" => '1.4em',
1540      "1.45em" => '1.45em',
1541      "1.5em" => '1.5em',
1542      "1.55em" => '1.55em',
1543      "1.6em" => '1.6em',
1544      "1.65em" => '1.65em',
1545      "1.7em" => '1.7em',
1546      "1.75em" => '1.75em',
1547      "1.8em" => '1.8em',
1548      "1.85em" => '1.85em',
1549      "1.9em" => '1.9em',
1550      "1.95em" => '1.95em',
1551      "2.0em" => '2.0em',
1552      "2.05em" => '2.05em',
1553      "2.1em" => '2.1em',
1554      "2.15em" => '2.15em',
1555      "2.2em" => '2.2em',
1556      "2.25em" => '2.25em',
1557      "2.3em" => '2.3em',
1558      "2.35em" => '2.35em',
1559      "2.4em" => '2.4em',
1560      "2.45em" => '2.45em',
1561      "2.5em" => '2.5em',
1562      "2.55em" => '2.55em',
1563      "2.6em" => '2.6em',
1564      "2.65em" => '2.65em',
1565      "2.7em" => '2.7em',
1566      "2.75em" => '2.75em',
1567      "2.8em" => '2.8em',
1568      "2.85em" => '2.85em',
1569      "2.9em" => '2.9em',
1570      "2.95em" => '2.95em',
1571      "3.0em" => '3.0em',
1572      "3.05em" => '3.05em',
1573      "3.1em" => '3.1em',
1574      "3.15em" => '3.15em',
1575      "3.2em" => '3.2em',
1576      "3.25em" => '3.25em',
1577      "3.3em" => '3.3em',
1578      "3.35em" => '3.35em',
1579      "3.4em" => '3.4em',
1580      "3.45em" => '3.45em',
1581      "3.5em" => '3.5em',
1582      "3.55em" => '3.55em',
1583      "3.6em" => '3.6em',
1584      "3.65em" => '3.65em',
1585      "3.7em" => '3.7em',
1586      "3.75em" => '3.75em',
1587      "3.8em" => '3.8em',
1588      "3.85em" => '3.85em',
1589      "3.9em" => '3.9em',
1590      "3.95em" => '3.95em',
1591    );
1592  
1593    $form['top'] = array(
1594      '#title' => t('Top'),
1595      '#type' => 'select',
1596      '#default_value' => isset($settings['top']) ? $settings['top'] : '',
1597      '#options' => $options,
1598    );
1599  
1600    $form['right'] = array(
1601      '#title' => t('Right'),
1602      '#type' => 'select',
1603      '#default_value' => isset($settings['right']) ? $settings['right'] : '',
1604      '#options' => $options,
1605    );
1606  
1607    $form['bottom'] = array(
1608      '#title' => t('Bottom'),
1609      '#type' => 'select',
1610      '#default_value' => isset($settings['bottom']) ? $settings['bottom'] : '',
1611      '#options' => $options,
1612    );
1613  
1614    $form['left'] = array(
1615      '#title' => t('Left'),
1616      '#type' => 'select',
1617      '#default_value' => isset($settings['left']) ? $settings['left'] : '',
1618      '#options' => $options,
1619    );
1620  }
1621  
1622  /**
1623   * Copy padding selector information into the settings
1624   */
1625  function ctools_stylizer_padding_selector_form_submit(&$form, &$form_state, &$values, &$settings) {
1626    $settings = $values;
1627  }
1628  
1629  function ctools_stylizer_padding_apply_style(&$stylesheet, $selector, $settings) {
1630    $css = '';
1631  
1632    if (isset($settings['top']) && $settings['top'] !== '') {
1633      $css .= '  padding-top: ' . $settings['top'] . ";\n";
1634    }
1635  
1636    if (isset($settings['right']) && $settings['right'] !== '') {
1637      $css .= '  padding-right: ' . $settings['right'] . ";\n";
1638    }
1639  
1640    if (isset($settings['bottom']) && $settings['bottom'] !== '') {
1641      $css .= '  padding-bottom: ' . $settings['bottom'] . ";\n";
1642    }
1643  
1644    if (isset($settings['left']) && $settings['left'] !== '') {
1645      $css .= '  padding-left: ' . $settings['left'] . ";\n";
1646    }
1647  
1648    if ($css) {
1649      $stylesheet .= $selector . " {\n" . $css . "}\n";
1650    }
1651  
1652  }
1653  
1654  /**
1655   * Check to see that a directory exists.
1656   *
1657   * This is an exact copy of core's, but without the stupid drupal_set_message
1658   * because we need this to be silent.
1659   *
1660   * @todo this should probably be in another file.
1661   */
1662  function ctools_file_check_directory(&$directory, $mode = 0, $form_item = NULL) {
1663    $directory = rtrim($directory, '/\\');
1664  
1665    // Check if directory exists.
1666    if (!is_dir($directory)) {
1667      if (($mode & FILE_CREATE_DIRECTORY) && @mkdir($directory)) {
1668        @chmod($directory, 0775); // Necessary for non-webserver users.
1669      }
1670      else {
1671        if ($form_item) {
1672          form_set_error($form_item, t('The directory %directory does not exist.', array('%directory' => $directory)));
1673        }
1674        return FALSE;
1675      }
1676    }
1677  
1678    // Check to see if the directory is writable.
1679    if (!is_writable($directory)) {
1680      if (($mode & FILE_MODIFY_PERMISSIONS) && @chmod($directory, 0775)) {
1681        drupal_set_message(t('The permissions of directory %directory have been changed to make it writable.', array('%directory' => $directory)));
1682      }
1683      else {
1684        form_set_error($form_item, t('The directory %directory is not writable', array('%directory' => $directory)));
1685        watchdog('file system', 'The directory %directory is not writable, because it does not have the correct permissions set.', array('%directory' => $directory), WATCHDOG_ERROR);
1686        return FALSE;
1687      }
1688    }
1689  
1690    if ((file_directory_path() == $directory || file_directory_temp() == $directory) && !is_file("$directory/.htaccess")) {
1691      $htaccess_lines = "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nOptions None\nOptions +FollowSymLinks";
1692      if (($fp = fopen("$directory/.htaccess", 'w')) && fputs($fp, $htaccess_lines)) {
1693        fclose($fp);
1694        chmod($directory .'/.htaccess', 0664);
1695      }
1696      else {
1697        $variables = array('%directory' => $directory, '!htaccess' => '<br />'. nl2br(check_plain($htaccess_lines)));
1698        form_set_error($form_item, t("Security warning: Couldn't write .htaccess file. Please create a .htaccess file in your %directory directory which contains the following lines: <code>!htaccess</code>", $variables));
1699        watchdog('security', "Security warning: Couldn't write .htaccess file. Please create a .htaccess file in your %directory directory which contains the following lines: <code>!htaccess</code>", $variables, WATCHDOG_ERROR);
1700      }
1701    }
1702  
1703    return TRUE;
1704  }
1705  
1706  /**
1707   * Blend two hex colors and return the GD color.
1708   */
1709  function ctools_color_blend($img, $hex1, $hex2, $alpha) {
1710    $in1 = ctools_color_unpack($hex1);
1711    $in2 = ctools_color_unpack($hex2);
1712    $out = array($img);
1713    for ($i = 0; $i < 3; ++$i) {
1714      $out[] = $in1[$i] + ($in2[$i] - $in1[$i]) * $alpha;
1715    }
1716    return call_user_func_array('imagecolorallocate', $out);
1717  }
1718  
1719  /**
1720   * Convert a hex color into an RGB triplet.
1721   */
1722  function ctools_color_unpack($hex, $normalize = false) {
1723    if (strlen($hex) == 4) {
1724      $hex = $hex[1] . $hex[1] . $hex[2] . $hex[2] . $hex[3] . $hex[3];
1725    }
1726    $c = hexdec($hex);
1727    for ($i = 16; $i >= 0; $i -= 8) {
1728      $out[] = (($c >> $i) & 0xFF) / ($normalize ? 255 : 1);
1729    }
1730    return $out;
1731  }
1732  
1733  /**
1734   * Convert a hex triplet into a GD color.
1735   */
1736  function ctools_color_gd($img, $hex) {
1737    $c = array_merge(array($img), ctools_color_unpack($hex));
1738    return call_user_func_array('imagecolorallocate', $c);
1739  }
1740  


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7