Projet

Général

Profil

Paste
Télécharger (48,2 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ctools / includes / stylizer.inc @ 560c3060

1
<?php
2
/**
3
 * @file
4
 * Create customized CSS and images from palettes created by user input.
5
 */
6

    
7
/**
8
 * Fetch metadata on a specific style_base plugin.
9
 *
10
 * @param $content type
11
 *   Name of a panel content type.
12
 *
13
 * @return
14
 *   An array with information about the requested stylizer style base.
15
 */
16
function ctools_get_style_base($style_base) {
17
  ctools_include('plugins');
18
  return ctools_get_plugins('stylizer', 'style_bases', $style_base);
19
}
20

    
21
/**
22
 * Fetch metadata for all style_base plugins.
23
 *
24
 * @return
25
 *   An array of arrays with information about all available styleizer style bases.
26
 */
27
function ctools_get_style_bases() {
28
  ctools_include('plugins');
29
  return ctools_get_plugins('stylizer', 'style_bases');
30
}
31

    
32
/**
33
 * Fetch metadata about all of the style base types that are available.
34
 */
35
function ctools_get_style_base_types() {
36
  $types = array();
37
  foreach (module_implements('ctools_style_base_types') as $module) {
38
    $types[$module] = module_invoke($module, 'ctools_style_base_types');
39
  }
40

    
41
  return $types;
42
}
43

    
44
/**
45
 * Render the icon for a style base.
46
 */
47
function ctools_stylizer_print_style_icon($plugin, $print_title = TRUE) {
48
  $file = $plugin['path'] . '/' . $plugin['icon'];
49
  $title = $print_title ? $plugin['title'] : '';
50
  return theme('ctools_style_icon', array('image' => theme('image', array('path' => $file)), 'title' => $title));
51
}
52

    
53
/**
54
 * Theme the style icon image
55
 */
56
function theme_ctools_style_icon($vars) {
57
  $image = $vars['image'];
58
  ctools_add_css('stylizer');
59
  ctools_add_js('stylizer');
60
  $output = '<div class="ctools-style-icon">';
61
  $output .= $vars['image'];
62
  if ($vars['title']) {
63
    $output .= '<div class="caption">' . $vars['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
    drupal_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
    drupal_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
  $path = 'public://ctools/style/' . $settings['name'] . '/' . md5(serialize($settings['palette']));
211
  if (!file_prepare_directory($path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
212
    drupal_set_message(t('Unable to create CTools styles cache directory @path. Check the permissions on your files directory.', array('@path' => $path)), 'error');
213
    return;
214
  }
215

    
216
  return $path;
217
}
218

    
219
/**
220
 * Get the id used to cache CSS for a given style plugin and settings.
221
 */
222
function ctools_stylizer_get_css_id($plugin, $settings) {
223
  return 'ctools-stylizer:' . $settings['name'] . ':' . md5(serialize($settings['palette']));
224
}
225

    
226
/**
227
 * Get the class to use for a stylizer plugin.
228
 */
229
function ctools_stylizer_get_css_class($plugin, $settings) {
230
  ctools_include('cleanstring');
231
  return ctools_cleanstring($plugin['name'] . '-' . ctools_stylizer_get_settings_name($settings));
232
}
233

    
234
class ctools_stylizer_image_processor {
235
  var $workspace = NULL;
236
  var $name = NULL;
237

    
238
  var $workspaces = array();
239

    
240
  var $message_log = array();
241
  var $error_log = array();
242

    
243
  function execute($path, $plugin, $settings) {
244
    $this->path = $path;
245
    $this->plugin = $plugin;
246
    $this->settings = $settings;
247
    $this->palette = $settings['palette'];
248

    
249
    if (is_string($plugin['actions']) && function_exists($plugin['actions'])) {
250
      $actions = $plugin['actions']($plugin, $settings);
251
    }
252
    else if (is_array($plugin['actions'])) {
253
      $actions = $plugin['actions'];
254
    }
255

    
256
    if (!empty($actions) && is_array($actions)) {
257
      foreach ($plugin['actions'] as $action) {
258
        $command = 'command_' . array_shift($action);
259
        if (method_exists($this, $command)) {
260
          call_user_func_array(array($this, $command), $action);
261
        }
262
      }
263
    }
264

    
265
    // Clean up buffers.
266
    foreach ($this->workspaces as $name => $workspace) {
267
      imagedestroy($this->workspaces[$name]);
268
    }
269
  }
270

    
271
  function log($message, $type = 'normal') {
272
    $this->message_log[] = $message;
273
    if ($type == 'error') {
274
      $this->error_log[] = $message;
275
    }
276
  }
277

    
278
  function set_current_workspace($workspace) {
279
    $this->log("Set current workspace: $workspace");
280
    $this->workspace = &$this->workspaces[$workspace];
281
    $this->name = $workspace;
282
  }
283

    
284
  /**
285
   * Create a new workspace.
286
   */
287
  function command_new($name, $width, $height) {
288
    $this->log("New workspace: $name ($width x $height)");
289
    // Clean up if there was already a workspace there.
290
    if (isset($this->workspaces[$name])) {
291
      imagedestroy($this->workspaces[$name]);
292
    }
293

    
294
    $this->workspaces[$name] = imagecreatetruecolor($width, $height);
295
    $this->set_current_workspace($name);
296

    
297
    // Make sure the new workspace has a transparent color.
298

    
299
    // Turn off transparency blending (temporarily)
300
    imagealphablending($this->workspace, FALSE);
301

    
302
    // Create a new transparent color for image
303
    $color = imagecolorallocatealpha($this->workspace, 0, 0, 0, 127);
304

    
305
    // Completely fill the background of the new image with allocated color.
306
    imagefill($this->workspace, 0, 0, $color);
307

    
308
    // Restore transparency blending
309
    imagesavealpha($this->workspace, TRUE);
310

    
311
  }
312

    
313
  /**
314
   * Create a new workspace a file.
315
   *
316
   * This will make the new workspace the current workspace.
317
   */
318
  function command_load($name, $file) {
319
    $this->log("New workspace: $name (from $file)");
320
    if (!file_exists($file)) {
321
      // Try it relative to the plugin
322
      $file = $this->plugin['path'] . '/' . $file;
323
      if (!file_exists($file)) {
324
        $this->log("Unable to open $file");
325
        return;
326
      }
327
    }
328

    
329
    // Clean up if there was already a workspace there.
330
    if (isset($this->workspaces[$name])) {
331
      imagedestroy($this->workspaces[$name]);
332
    }
333

    
334
    $this->workspaces[$name] = imagecreatefrompng($file);
335
    $this->set_current_workspace($name);
336
  }
337

    
338
  /**
339
   * Create a new workspace using the properties of an existing workspace
340
   */
341
  function command_new_from($name, $workspace) {
342
    $this->log("New workspace: $name from existing $workspace");
343
    if (empty($this->workspaces[$workspace])) {
344
      $this->log("Workspace $name does not exist.", 'error');
345
      return;
346
    }
347

    
348
    // Clean up if there was already a workspace there.
349
    if (isset($this->workspaces[$name])) {
350
      imagedestroy($this->workspaces[$name]);
351
    }
352

    
353
    $this->workspaces[$name] = $this->new_image($this->workspace[$workspace]);
354
    $this->set_current_workspace($name);
355
  }
356

    
357
  /**
358
   * Set the current workspace.
359
   */
360
  function command_workspace($name) {
361
    $this->log("Set workspace: $name");
362
    if (empty($this->workspaces[$name])) {
363
      $this->log("Workspace $name does not exist.", 'error');
364
      return;
365
    }
366
    $this->set_current_workspace($name);
367
  }
368

    
369
  /**
370
   * Copy the contents of one workspace into the current workspace.
371
   */
372
  function command_merge_from($workspace, $x = 0, $y = 0) {
373
    $this->log("Merge from: $workspace ($x, $y)");
374
    if (empty($this->workspaces[$workspace])) {
375
      $this->log("Workspace $name does not exist.", 'error');
376
      return;
377
    }
378

    
379
    $this->merge($this->workspaces[$workspace], $this->workspace, $x, $y);
380
  }
381

    
382
  function command_merge_to($workspace, $x = 0, $y = 0) {
383
    $this->log("Merge to: $workspace ($x, $y)");
384
    if (empty($this->workspaces[$workspace])) {
385
      $this->log("Workspace $name does not exist.", 'error');
386
      return;
387
    }
388

    
389
    $this->merge($this->workspace, $this->workspaces[$workspace], $x, $y);
390
    $this->set_current_workspace($workspace);
391
  }
392

    
393
  /**
394
   * Blend an image into the current workspace.
395
   */
396
  function command_merge_from_file($file, $x = 0, $y = 0) {
397
    $this->log("Merge from file: $file ($x, $y)");
398
    if (!file_exists($file)) {
399
      // Try it relative to the plugin
400
      $file = $this->plugin['path'] . '/' . $file;
401
      if (!file_exists($file)) {
402
        $this->log("Unable to open $file");
403
        return;
404
      }
405
    }
406

    
407
    $source = imagecreatefrompng($file);
408

    
409
    $this->merge($source, $this->workspace, $x, $y);
410

    
411
    imagedestroy($source);
412
  }
413

    
414
  function command_fill($color, $x, $y, $width, $height) {
415
    $this->log("Fill: $color ($x, $y, $width, $height)");
416
    imagefilledrectangle($this->workspace, $x, $y, $x + $width, $y + $height, _color_gd($this->workspace, $this->palette[$color]));
417
  }
418

    
419
  function command_gradient($from, $to, $x, $y, $width, $height, $direction = 'down') {
420
    $this->log("Gradient: $from to $to ($x, $y, $width, $height) $direction");
421

    
422
    if ($direction == 'down') {
423
      for ($i = 0; $i < $height; ++$i) {
424
        $color = _color_blend($this->workspace, $this->palette[$from], $this->palette[$to], $i / ($height - 1));
425
        imagefilledrectangle($this->workspace, $x, $y + $i, $x + $width, $y + $i + 1, $color);
426
      }
427
    }
428
    else {
429
      for ($i = 0; $i < $width; ++$i) {
430
        $color = _color_blend($this->workspace, $this->palette[$from], $this->palette[$to], $i / ($width - 1));
431
        imagefilledrectangle($this->workspace, $x + $i, $y, $x + $i + 1, $y + $height, $color);
432
      }
433
    }
434
  }
435

    
436
  /**
437
   * Colorize the current workspace with the given location.
438
   *
439
   * This uses simple color blending to colorize the image.
440
   *
441
   * @todo it is possible that this colorize could allow different methods for
442
   * determining how to blend colors?
443
   */
444
  function command_colorize($color, $x = NULL, $y = NULL, $width = NULL, $height = NULL) {
445
    if (!isset($x)) {
446
      $whole_image = TRUE;
447
      $x = $y = 0;
448
      $width = imagesx($this->workspace);
449
      $height = imagesy($this->workspace);
450
    }
451
    $this->log("Colorize: $color ($x, $y, $width, $height)");
452

    
453
    $c = _color_unpack($this->palette[$color]);
454

    
455
    imagealphablending($this->workspace, FALSE);
456
    imagesavealpha($this->workspace, TRUE);
457

    
458
    // If PHP 5 use the nice imagefilter which is faster.
459
    if (!empty($whole_image) && version_compare(phpversion(), '5.2.5', '>=') && function_exists('imagefilter')) {
460
      imagefilter($this->workspace, IMG_FILTER_COLORIZE, $c[0], $c[1], $c[2]);
461
    }
462
    else {
463
      // Otherwise we can do it the brute force way.
464
      for ($j = 0; $j < $height; $j++) {
465
        for ($i = 0; $i < $width; $i++) {
466
          $current = imagecolorsforindex($this->workspace, imagecolorat($this->workspace, $i, $j));
467
          $new_index = imagecolorallocatealpha($this->workspace, $c[0], $c[1], $c[2], $current['alpha']);
468
          imagesetpixel($this->workspace, $i, $j, $new_index);
469
        }
470
      }
471
    }
472
  }
473

    
474
  /**
475
   * Colorize the current workspace with the given location.
476
   *
477
   * This uses a color replacement algorithm that retains luminosity but
478
   * turns replaces all color with the specified color.
479
   */
480
  function command_hue($color, $x = NULL, $y = NULL, $width = NULL, $height = NULL) {
481
    if (!isset($x)) {
482
      $whole_image = TRUE;
483
      $x = $y = 0;
484
      $width = imagesx($this->workspace);
485
      $height = imagesy($this->workspace);
486
    }
487
    $this->log("Hue: $color ($x, $y, $width, $height)");
488

    
489
    list($red, $green, $blue) = _color_unpack($this->palette[$color]);
490

    
491
    // We will create a monochromatic palette based on the input color
492
    // which will go from black to white.
493

    
494
    // Input color luminosity: this is equivalent to the position of the
495
    // input color in the monochromatic palette
496
    $luminosity_input = round(255 * ($red + $green + $blue) / 765); // 765 = 255 * 3
497

    
498
    // We fill the palette entry with the input color at itscorresponding position
499
    $palette[$luminosity_input]['red'] = $red;
500
    $palette[$luminosity_input]['green'] = $green;
501
    $palette[$luminosity_input]['blue'] = $blue;
502

    
503
    // Now we complete the palette, first we'll do it to the black, and then to
504
    // the white.
505

    
506
    // From input to black
507
    $steps_to_black = $luminosity_input;
508

    
509
    // The step size for each component
510
    if ($steps_to_black) {
511
      $step_size_red = $red / $steps_to_black;
512
      $step_size_green = $green / $steps_to_black;
513
      $step_size_blue = $blue / $steps_to_black;
514

    
515
      for ($i = $steps_to_black; $i >= 0; $i--) {
516
        $palette[$steps_to_black-$i]['red'] = $red - round($step_size_red * $i);
517
        $palette[$steps_to_black-$i]['green'] = $green - round($step_size_green * $i);
518
        $palette[$steps_to_black-$i]['blue'] = $blue - round($step_size_blue * $i);
519
      }
520
    }
521

    
522
    // From input to white
523
    $steps_to_white = 255 - $luminosity_input;
524

    
525
    if ($steps_to_white) {
526
      $step_size_red = (255 - $red) / $steps_to_white;
527
      $step_size_green = (255 - $green) / $steps_to_white;
528
      $step_size_blue = (255 - $blue) / $steps_to_white;
529
    }
530
    else {
531
      $step_size_red=$step_size_green=$step_size_blue=0;
532
    }
533

    
534
    // The step size for each component
535
    for ($i = ($luminosity_input + 1); $i <= 255; $i++) {
536
      $palette[$i]['red'] = $red + round($step_size_red * ($i - $luminosity_input));
537
      $palette[$i]['green'] = $green + round($step_size_green * ($i - $luminosity_input));
538
      $palette[$i]['blue']= $blue + round($step_size_blue * ($i - $luminosity_input));
539
    }
540

    
541
    // Go over the specified area of the image and update the colors.
542
    for ($j = $x; $j < $height; $j++) {
543
      for ($i = $y; $i < $width; $i++) {
544
        $color = imagecolorsforindex($this->workspace, imagecolorat($this->workspace, $i, $j));
545
        $luminosity = round(255 * ($color['red'] + $color['green'] + $color['blue']) / 765);
546
        $new_color = imagecolorallocatealpha($this->workspace, $palette[$luminosity]['red'], $palette[$luminosity]['green'], $palette[$luminosity]['blue'], $color['alpha']);
547
        imagesetpixel($this->workspace, $i, $j, $new_color);
548
      }
549
    }
550
  }
551

    
552
  /**
553
   * Take a slice out of the current workspace and save it as an image.
554
   */
555
  function command_slice($file, $x = NULL, $y = NULL, $width = NULL, $height = NULL) {
556
    if (!isset($x)) {
557
      $x = $y = 0;
558
      $width = imagesx($this->workspace);
559
      $height = imagesy($this->workspace);
560
    }
561

    
562
    $this->log("Slice: $file ($x, $y, $width, $height)");
563

    
564
    $base = basename($file);
565
    $image = $this->path . '/' . $base;
566

    
567
    $slice = $this->new_image($this->workspace, $width, $height);
568
    imagecopy($slice, $this->workspace, 0, 0, $x, $y, $width, $height);
569

    
570
    // Make sure alphas are saved:
571
    imagealphablending($slice, FALSE);
572
    imagesavealpha($slice, TRUE);
573

    
574
    // Save image.
575
    $temp_name = drupal_tempnam('temporary://', 'file');
576

    
577
    imagepng($slice, drupal_realpath($temp_name));
578
    file_unmanaged_move($temp_name, $image);
579
    imagedestroy($slice);
580

    
581
    // Set standard file permissions for webserver-generated files
582
    @chmod(realpath($image), 0664);
583

    
584
    $this->paths[$file] = $image;
585
  }
586

    
587
  /**
588
   * Prepare a new image for being copied or worked on, preserving transparency.
589
   */
590
  function &new_image(&$source, $width = NULL, $height = NULL) {
591
    if (!isset($width)) {
592
      $width = imagesx($source);
593
    }
594

    
595
    if (!isset($height)) {
596
      $height = imagesy($source);
597
    }
598

    
599
    $target = imagecreatetruecolor($width, $height);
600
    imagealphablending($target, FALSE);
601
      imagesavealpha($target, TRUE);
602

    
603
    $transparency_index = imagecolortransparent($source);
604

    
605
    // If we have a specific transparent color
606
    if ($transparency_index >= 0) {
607
      // Get the original image's transparent color's RGB values
608
      $transparent_color = imagecolorsforindex($source, $transparency_index);
609

    
610
      // Allocate the same color in the new image resource
611
      $transparency_index = imagecolorallocate($target, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
612

    
613
      // Completely fill the background of the new image with allocated color.
614
      imagefill($target, 0, 0, $transparency_index);
615

    
616
      // Set the background color for new image to transparent
617
      imagecolortransparent($target, $transparency_index);
618
    }
619
    // Always make a transparent background color for PNGs that don't have one allocated already
620
    else {
621
      // Create a new transparent color for image
622
      $color = imagecolorallocatealpha($target, 0, 0, 0, 127);
623

    
624
      // Completely fill the background of the new image with allocated color.
625
      imagefill($target, 0, 0, $color);
626
    }
627

    
628
    return $target;
629
  }
630

    
631
  /**
632
   * Merge two images together, preserving alpha transparency.
633
   */
634
  function merge(&$from, &$to, $x, $y) {
635
    // Blend over template.
636
    $width = imagesx($from);
637
    $height = imagesy($from);
638

    
639
    // Re-enable alpha blending to make sure transparency merges.
640
    imagealphablending($to, TRUE);
641
    imagecopy($to, $from, $x, $y, 0, 0, $width, $height);
642
    imagealphablending($to, FALSE);
643
  }
644
}
645

    
646
/**
647
 * Get the cached changes to a given task handler.
648
 */
649
function ctools_stylizer_get_settings_cache($name) {
650
  ctools_include('object-cache');
651
  return ctools_object_cache_get('ctools_stylizer_settings', $name);
652
}
653

    
654
/**
655
 * Store changes to a task handler in the object cache.
656
 */
657
function ctools_stylizer_set_settings_cache($name, $settings) {
658
  ctools_include('object-cache');
659
  ctools_object_cache_set('ctools_stylizer_settings', $name, $settings);
660
}
661

    
662
/**
663
 * Remove an item from the object cache.
664
 */
665
function ctools_stylizer_clear_settings_cache($name) {
666
  ctools_include('object-cache');
667
  ctools_object_cache_clear('ctools_stylizer_settings', $name);
668
}
669

    
670
/**
671
 * Add a new style of the specified type.
672
 */
673
function ctools_stylizer_edit_style(&$info, $js, $step = NULL) {
674
  $name = '::new';
675
  $form_info = array(
676
    'id' => 'ctools_stylizer_edit_style',
677
    'path' => $info['path'],
678
    'show trail' => TRUE,
679
    'show back' => TRUE,
680
    'show return' => FALSE,
681
    'next callback' => 'ctools_stylizer_edit_style_next',
682
    'finish callback' => 'ctools_stylizer_edit_style_finish',
683
    'return callback' => 'ctools_stylizer_edit_style_finish',
684
    'cancel callback' => 'ctools_stylizer_edit_style_cancel',
685
    'forms' => array(
686
      'choose' => array(
687
        'form id' => 'ctools_stylizer_edit_style_form_choose',
688
      ),
689
    ),
690
  );
691

    
692
  if (empty($info['settings'])) {
693
    $form_info['order'] = array(
694
      'choose' => t('Select base style'),
695
    );
696
    if (empty($step)) {
697
      $step = 'choose';
698
    }
699

    
700
    if ($step != 'choose') {
701
      $cache = ctools_stylizer_get_settings_cache($name);
702
      if (!$cache) {
703
        $output = t('Missing settings cache.');
704
        if ($js) {
705
          return ctools_modal_form_render($form_state, $output);
706
        }
707
        else {
708
          return $output;
709
        }
710
      }
711

    
712
      if (!empty($cache['owner settings'])) {
713
        $info['owner settings'] = $cache['owner settings'];
714
      }
715
      $settings = $cache['settings'];
716
    }
717
    else {
718
      $settings = array(
719
        'name' => '_temporary',
720
        'style_base' => NULL,
721
        'palette' => array(),
722
      );
723
      ctools_stylizer_clear_settings_cache($name);
724
    }
725
    $op = 'add';
726
  }
727
  else {
728
    $cache = ctools_stylizer_get_settings_cache($info['settings']['name']);
729

    
730
    if (!empty($cache)) {
731
      if (!empty($cache['owner settings'])) {
732
        $info['owner settings'] = $cache['owner settings'];
733
      }
734
      $settings = $cache['settings'];
735
    }
736
    else {
737
      $settings = $info['settings'];
738
    }
739
    $op = 'edit';
740
  }
741

    
742
  if (!empty($info['op'])) {
743
    // Allow this to override. Necessary to allow cloning properly.
744
    $op = $info['op'];
745
  }
746

    
747
  $plugin = NULL;
748
  if (!empty($settings['style_base'])) {
749
    $plugin = ctools_get_style_base($settings['style_base']);
750
    $info['type'] = $plugin['type'];
751
    ctools_stylizer_add_plugin_forms($form_info, $plugin, $op);
752
  }
753
  else {
754
    // This is here so the 'finish' button does not show up, and because
755
    // we don't have the selected style we don't know what the next form(s)
756
    // will be.
757
    $form_info['order']['next'] = t('Configure style');
758
  }
759

    
760
  if (count($form_info['order']) < 2 || $step == 'choose') {
761
    $form_info['show trail'] = FALSE;
762
  }
763

    
764
  $form_state = array(
765
    'module' => $info['module'],
766
    'type' => $info['type'],
767
    'owner info' => &$info,
768
    'base_style_plugin' => $plugin,
769
    'name' => $name,
770
    'step' => $step,
771
    'settings' => $settings,
772
    'ajax' => $js,
773
    'op' => $op,
774
  );
775

    
776
  if (!empty($info['modal'])) {
777
    $form_state['modal'] = TRUE;
778
    $form_state['title'] = $info['modal'];
779
    $form_state['modal return'] = TRUE;
780
  }
781

    
782
  ctools_include('wizard');
783
  $output = ctools_wizard_multistep_form($form_info, $step, $form_state);
784

    
785
  if (!empty($form_state['complete'])) {
786
    $info['complete'] = TRUE;
787
    $info['settings'] = $form_state['settings'];
788
  }
789

    
790
  if ($js && !$output && !empty($form_state['clicked_button']['#next'])) {
791
    // We have to do a separate redirect here because the formula that adds
792
    // stuff to the wizard after being chosen hasn't happened. The wizard
793
    // tried to go to the next step which did not exist.
794
    return ctools_stylizer_edit_style($info, $js, $form_state['clicked_button']['#next']);
795
  }
796

    
797
  if ($js) {
798
    return ctools_modal_form_render($form_state, $output);
799
  }
800
  else {
801
    return $output;
802
  }
803
}
804

    
805
/**
806
 * Add wizard forms specific to a style base plugin.
807
 *
808
 * The plugin can store forms either as a simple 'edit form'
809
 * => 'form callback' or if it needs the more complicated wizard
810
 * functionality, it can set 'forms' and 'order' with values suitable
811
 * for the wizard $form_info array.
812
 *
813
 * @param &$form_info
814
 *   The form info to modify.
815
 * @param $plugin
816
 *   The plugin to use.
817
 * @param $op
818
 *   Either 'add' or 'edit' so we can get the right forms.
819
 */
820
function ctools_stylizer_add_plugin_forms(&$form_info, $plugin, $op) {
821
  if (empty($plugin['forms'])) {
822
    if ($op == 'add' && isset($plugin['add form'])) {
823
      $id = $plugin['add form'];
824
    }
825
    else if (isset($plugin['edit form'])) {
826
      $id = $plugin['edit form'];
827
    }
828
    else {
829
      $id = 'ctools_stylizer_edit_style_form_default';
830
    }
831

    
832
    $form_info['forms']['settings'] = array(
833
      'form id' => $id,
834
    );
835
    $form_info['order']['settings'] = t('Settings');
836
  }
837
  else {
838
    $form_info['forms'] += $plugin['forms'];
839
    $form_info['order'] += $plugin['order'];
840
  }
841
}
842

    
843
/**
844
 * Callback generated when the add style process is finished.
845
 */
846
function ctools_stylizer_edit_style_finish(&$form_state) {
847
  $form_state['complete'] = TRUE;
848
  ctools_stylizer_clear_settings_cache($form_state['name']);
849

    
850
  if (isset($form_state['settings']['old_settings'])) {
851
    unset($form_state['settings']['old_settings']);
852
  }
853
}
854

    
855
/**
856
 * Callback generated when the 'next' button is clicked.
857
 */
858
function ctools_stylizer_edit_style_next(&$form_state) {
859
  $form_state['form_info']['path'] = str_replace('%name', $form_state['name'], $form_state['form_info']['path']);
860
  $form_state['redirect'] = ctools_wizard_get_path($form_state['form_info'], $form_state['clicked_button']['#next']);
861

    
862
  // Update the cache with changes.
863
  $cache = array('settings' => $form_state['settings']);
864
  if (!empty($form_state['owner info']['owner settings'])) {
865
    $cache['owner settings'] = $form_state['owner info']['owner settings'];
866
  }
867
  ctools_stylizer_set_settings_cache($form_state['name'], $cache);
868
}
869

    
870
/**
871
 * Callback generated when the 'cancel' button is clicked.
872
 *
873
 * We might have some temporary data lying around. We must remove it.
874
 */
875
function ctools_stylizer_edit_style_cancel(&$form_state) {
876
  if (!empty($form_state['name'])) {
877
    ctools_stylizer_clear_settings_cache($form_state['name']);
878
  }
879
}
880

    
881
/**
882
 * Choose which plugin to use to create a new style.
883
 */
884
function ctools_stylizer_edit_style_form_choose($form, &$form_state) {
885
  $plugins = ctools_get_style_bases();
886
  $options = array();
887

    
888
  $categories = array();
889
  foreach ($plugins as $name => $plugin) {
890
    if ($form_state['module'] == $plugin['module'] && $form_state['type'] == $plugin['type']) {
891
      $categories[$plugin['category']] = $plugin['category'];
892
      $unsorted_options[$plugin['category']][$name] = ctools_stylizer_print_style_icon($plugin, TRUE);
893
    }
894
  }
895

    
896
  asort($categories);
897

    
898
  foreach ($categories as $category) {
899
    $options[$category] = $unsorted_options[$category];
900
  }
901

    
902
  $form['style_base'] = array(
903
    '#prefix' => '<div class="ctools-style-icons clearfix">',
904
    '#suffix' => '</div>',
905
  );
906

    
907
  ctools_include('cleanstring');
908
  foreach ($options as $category => $radios) {
909
    $cat = ctools_cleanstring($category);
910
    $form['style_base'][$cat] = array(
911
      '#prefix' => '<div class="ctools-style-category clearfix"><label>' . $category . '</label>',
912
      '#suffix' => '</div>',
913
    );
914

    
915
    foreach ($radios as $key => $choice) {
916
      // Generate the parents as the autogenerator does, so we will have a
917
      // unique id for each radio button.
918
      $form['style_base'][$cat][$key] = array(
919
        '#type' => 'radio',
920
        '#title' => $choice,
921
        '#parents' => array('style_base'),
922
        '#id' => drupal_clean_css_identifier('edit-style-base-' . $key),
923
        '#return_value' => check_plain($key),
924
      );
925
    }
926
  }
927

    
928
  return $form;
929
}
930

    
931
function ctools_stylizer_edit_style_form_choose_submit($form, &$form_state) {
932
  $form_state['settings']['style_base'] = $form_state['values']['style_base'];
933

    
934
  // The 'next' form will show up as 'next' but that's not accurate now that
935
  // we have a style. Figure out what next really is and update.
936
  $plugin = ctools_get_style_base($form_state['settings']['style_base']);
937
  if (empty($plugin['forms'])) {
938
    $form_state['clicked_button']['#next'] = 'settings';
939
  }
940
  else {
941
    $forms = array_keys($form_info['forms']);
942
    $form_state['clicked_button']['#next'] = array_shift($forms);
943
  }
944

    
945
  // Fill in the defaults for the settings.
946
  if (!empty($plugin['defaults'])) {
947
    // @todo allow a callback
948
    $form_state['settings'] += $plugin['defaults'];
949
  }
950

    
951
  return $form;
952
}
953

    
954
/**
955
 * The default stylizer style editing form.
956
 *
957
 * Even when not using this, styles should call through to this form in
958
 * their own edit forms.
959
 */
960
function ctools_stylizer_edit_style_form_default($form, &$form_state) {
961
  ctools_add_js('stylizer');
962
  ctools_add_css('stylizer');
963
  drupal_add_library('system', 'farbtastic');
964

    
965
  $plugin = &$form_state['base_style_plugin'];
966
  $settings = &$form_state['settings'];
967

    
968
  $form['top box'] = array(
969
    '#prefix' => '<div id="ctools-stylizer-top-box" class="clearfix">',
970
    '#suffix' => '</div>',
971
  );
972
  $form['top box']['left'] = array(
973
    '#prefix' => '<div id="ctools-stylizer-left-box">',
974
    '#suffix' => '</div>',
975
  );
976
  $form['top box']['preview'] = array(
977
    // We have a copy of the $form_state on $form because form theme functions
978
    // do not get $form_state.
979
    '#theme' => 'ctools_stylizer_preview_form',
980
    '#form_state' => &$form_state,
981
  );
982

    
983
  $form['top box']['preview']['submit'] = array(
984
    '#type' => 'submit',
985
    '#value' => t('Preview'),
986
  );
987

    
988
  if (!empty($plugin['palette'])) {
989
    $form['top box']['color'] = array(
990
      '#type' => 'fieldset',
991
      '#title' => t('Color scheme'),
992
      '#attributes' => array('id' => 'ctools_stylizer_color_scheme_form', 'class' => array('ctools-stylizer-color-edit')),
993
      '#theme' => 'ctools_stylizer_color_scheme_form',
994
    );
995

    
996
    $form['top box']['color']['palette']['#tree'] = TRUE;
997

    
998
    foreach ($plugin['palette'] as $key => $color) {
999
      if (empty($settings['palette'][$key])) {
1000
        $settings['palette'][$key] = $color['default_value'];
1001
      }
1002

    
1003
      $form['top box']['color']['palette'][$key] = array(
1004
        '#type' => 'textfield',
1005
        '#title' => $color['label'],
1006
        '#default_value' => $settings['palette'][$key],
1007
        '#size' => 8,
1008
      );
1009
    }
1010
  }
1011

    
1012
  if (!empty($plugin['settings form']) && function_exists($plugin['settings form'])) {
1013
    $plugin['settings form']($form, $form_state);
1014
  }
1015

    
1016
  if (!empty($form_state['owner info']['owner form']) && function_exists($form_state['owner info']['owner form'])) {
1017
    $form_state['owner info']['owner form']($form, $form_state);
1018
  }
1019

    
1020
  return $form;
1021
}
1022

    
1023
/**
1024
 * Theme the stylizer color scheme form.
1025
 */
1026
function theme_ctools_stylizer_color_scheme_form($vars) {
1027
  $form = &$vars['form'];
1028
  $output = '';
1029

    
1030
  // Wrapper
1031
  $output .= '<div class="color-form clearfix">';
1032

    
1033
  // Color schemes
1034
//  $output .= drupal_render($form['scheme']);
1035

    
1036
  // Palette
1037
  $output .= '<div id="palette" class="clearfix">';
1038
  foreach (element_children($form['palette']) as $name) {
1039
    $output .= 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($vars) {
1052
  $form = &$vars['form'];
1053

    
1054
  $plugin = $form['#form_state']['base_style_plugin'];
1055
  $settings = $form['#form_state']['settings'];
1056

    
1057
  if (!empty($form['#form_state']['settings']['old_settings'])) {
1058
    ctools_stylizer_cleanup_style($plugin, $form['#form_state']['settings']['old_settings']);
1059
  }
1060
  $preview = '';
1061
  if (!empty($plugin['preview'])) {
1062
    $preview = $plugin['preview'];
1063
  }
1064
  else {
1065
    $base_types = ctools_get_style_base_types();
1066
    if (!empty($base_types[$plugin['module']][$plugin['type']]['preview'])) {
1067
      $preview = $base_types[$plugin['module']][$plugin['type']]['preview'];
1068
    }
1069
  }
1070

    
1071
  if (!empty($preview) && function_exists($preview)) {
1072
    $output = '<fieldset id="preview"><legend>' . t('Preview') . '</legend>';
1073
    $output .= $preview($plugin, $settings);
1074
    $output .= drupal_render_children($form);
1075
    $output .= '</fieldset>';
1076

    
1077
    return $output;
1078
  }
1079
}
1080

    
1081
function ctools_stylizer_edit_style_form_default_validate($form, &$form_state) {
1082
  if (!empty($form_state['owner info']['owner form validate']) && function_exists($form_state['owner info']['owner form validate'])) {
1083
    $form_state['owner info']['owner form validate']($form, $form_state);
1084
  }
1085

    
1086
  if (!empty($form_state['base_style_plugin']['settings form validate']) && function_exists($form_state['base_style_plugin']['settings form validate'])) {
1087
    $form_state['base_style_plugin']['settings form validate']($form, $form_state);
1088
  }
1089
}
1090

    
1091
function ctools_stylizer_edit_style_form_default_submit($form, &$form_state) {
1092
  // Store old settings for the purposes of cleaning up.
1093
  $form_state['settings']['old_settings'] = $form_state['settings'];
1094
  $form_state['settings']['palette'] = $form_state['values']['palette'];
1095

    
1096
  if (!empty($form_state['owner info']['owner form submit']) && function_exists($form_state['owner info']['owner form submit'])) {
1097
    $form_state['owner info']['owner form submit']($form, $form_state);
1098
  }
1099

    
1100
  if (!empty($form_state['base_style_plugin']['settings form submit']) && function_exists($form_state['base_style_plugin']['settings form submit'])) {
1101
    $form_state['base_style_plugin']['settings form submit']($form, $form_state);
1102
  }
1103

    
1104
  if ($form_state['clicked_button']['#value'] == t('Preview')) {
1105
    $form_state['rerender'] = TRUE;
1106
    // Update the cache with changes.
1107
    if (!empty($form_state['name'])) {
1108
      $cache = array('settings' => $form_state['settings']);
1109
      if (!empty($form_state['owner info']['owner settings'])) {
1110
        $cache['owner settings'] = $form_state['owner info']['owner settings'];
1111
      }
1112
      ctools_stylizer_set_settings_cache($form_state['name'], $cache);
1113
    }
1114
  }
1115
}
1116

    
1117
// --------------------------------------------------------------------------
1118
// CSS forms and tools that plugins can use.
1119

    
1120
/**
1121
 * Font selector form
1122
 */
1123
function ctools_stylizer_font_selector_form(&$form, &$form_state, $label, $settings) {
1124
  // Family
1125
  $form['#prefix'] = '<div class="ctools-stylizer-spacing-form clearfix">';
1126
  $form['#type'] = 'fieldset';
1127
  $form['#title'] = $label;
1128
  $form['#suffix'] = '</div>';
1129
  $form['#tree'] = TRUE;
1130

    
1131
  $form['font'] = array(
1132
    '#title' => t('Font family'),
1133
    '#type' => 'select',
1134
    '#default_value' => isset($settings['font']) ? $settings['font'] : '',
1135
    '#options' => array(
1136
      '' => '',
1137
      'Arial, Helvetica, sans-serif' => t('Arial, Helvetica, sans-serif'),
1138
      'Times New Roman, Times, serif' => t('Times New Roman, Times, serif'),
1139
      'Courier New, Courier, monospace' => t('Courier New, Courier, monospace'),
1140
      'Georgia, Times New Roman, Times, serif' => t('Georgia, Times New Roman, Times, serif'),
1141
      'Verdana, Arial, Helvetica, sans-serif' => t('Verdana, Arial, Helvetica, sans-serif'),
1142
      'Geneva, Arial, Helvetica, sans-serif' => t('Geneva, Arial, Helvetica, sans-serif'),
1143
      'Trebuchet MS, Trebuchet, Verdana, sans-serif' => t('Trebuchet MS, Trebuchet, Verdana, sans-serif'),
1144
    ),
1145
  );
1146

    
1147
  // size
1148
  $form['size'] = array(
1149
    '#title' => t('Size'),
1150
    '#type' => 'select',
1151
    '#default_value' => isset($settings['size']) ? $settings['size'] : '',
1152
    '#options' => array(
1153
      '' => '',
1154
      'xx-small' => t('XX-Small'),
1155
      'x-small' => t('X-Small'),
1156
      'small' => t('Small'),
1157
      'medium' => t('Medium'),
1158
      'large' => t('Large'),
1159
      'x-large' => t('X-Large'),
1160
      'xx-large' => t('XX-Large'),
1161
    ),
1162
  );
1163

    
1164
  // letter spacing
1165
  $form['letter_spacing'] = array(
1166
    '#title' => t('Letter spacing'),
1167
    '#type' => 'select',
1168
    '#default_value' => isset($settings['letter_spacing']) ? $settings['letter_spacing'] : '',
1169
    '#options' => array(
1170
      '' => '',
1171
      "-10px" => '10px',
1172
      "-9px" => '9px',
1173
      "-8px" => '8px',
1174
      "-7px" => '7px',
1175
      "-6px" => '6px',
1176
      "-5px" => '5px',
1177
      "-4px" => '4px',
1178
      "-3px" => '3px',
1179
      "-2px" => '2px',
1180
      "-1px" => '1px',
1181
      "0" => '0',
1182
      "1px" => '1px',
1183
      "2px" => '2px',
1184
      "3px" => '3px',
1185
      "4px" => '4px',
1186
      "5px" => '5px',
1187
      "6px" => '6px',
1188
      "7px" => '7px',
1189
      "8px" => '8px',
1190
      "9px" => '9px',
1191
      "10px" => '10px',
1192
      "11px" => '11px',
1193
      "12px" => '12px',
1194
      "13px" => '13px',
1195
      "14px" => '14px',
1196
      "15px" => '15px',
1197
      "16px" => '16px',
1198
      "17px" => '17px',
1199
      "18px" => '18px',
1200
      "19px" => '19px',
1201
      "20px" => '20px',
1202
      "21px" => '21px',
1203
      "22px" => '22px',
1204
      "23px" => '23px',
1205
      "24px" => '24px',
1206
      "25px" => '25px',
1207
      "26px" => '26px',
1208
      "27px" => '27px',
1209
      "28px" => '28px',
1210
      "29px" => '29px',
1211
      "30px" => '30px',
1212
      "31px" => '31px',
1213
      "32px" => '32px',
1214
      "33px" => '33px',
1215
      "34px" => '34px',
1216
      "35px" => '35px',
1217
      "36px" => '36px',
1218
      "37px" => '37px',
1219
      "38px" => '38px',
1220
      "39px" => '39px',
1221
      "40px" => '40px',
1222
      "41px" => '41px',
1223
      "42px" => '42px',
1224
      "43px" => '43px',
1225
      "44px" => '44px',
1226
      "45px" => '45px',
1227
      "46px" => '46px',
1228
      "47px" => '47px',
1229
      "48px" => '48px',
1230
      "49px" => '49px',
1231
      "50px" => '50px',
1232
    ),
1233
  );
1234

    
1235
  // word space
1236
  $form['word_spacing'] = array(
1237
    '#title' => t('Word spacing'),
1238
    '#type' => 'select',
1239
    '#default_value' => isset($settings['word_spacing']) ? $settings['word_spacing'] : '',
1240
    '#options' => array(
1241
      '' => '',
1242
      "-1em" => '-1em',
1243
      "-0.95em" => '-0.95em',
1244
      "-0.9em" => '-0.9em',
1245
      "-0.85em" => '-0.85em',
1246
      "-0.8em" => '-0.8em',
1247
      "-0.75em" => '-0.75em',
1248
      "-0.7em" => '-0.7em',
1249
      "-0.65em" => '-0.65em',
1250
      "-0.6em" => '-0.6em',
1251
      "-0.55em" => '-0.55em',
1252
      "-0.5em" => '-0.5em',
1253
      "-0.45em" => '-0.45em',
1254
      "-0.4em" => '-0.4em',
1255
      "-0.35em" => '-0.35em',
1256
      "-0.3em" => '-0.3em',
1257
      "-0.25em" => '-0.25em',
1258
      "-0.2em" => '-0.2em',
1259
      "-0.15em" => '-0.15em',
1260
      "-0.1em" => '-0.1em',
1261
      "-0.05em" => '-0.05em',
1262
      "normal" => 'normal',
1263
      "0.05em" => '0.05em',
1264
      "0.1em" => '0.1em',
1265
      "0.15em" => '0.15em',
1266
      "0.2em" => '0.2em',
1267
      "0.25em" => '0.25em',
1268
      "0.3em" => '0.3em',
1269
      "0.35em" => '0.35em',
1270
      "0.4em" => '0.4em',
1271
      "0.45em" => '0.45em',
1272
      "0.5em" => '0.5em',
1273
      "0.55em" => '0.55em',
1274
      "0.6em" => '0.6em',
1275
      "0.65em" => '0.65em',
1276
      "0.7em" => '0.7em',
1277
      "0.75em" => '0.75em',
1278
      "0.8em" => '0.8em',
1279
      "0.85em" => '0.85em',
1280
      "0.9em" => '0.9em',
1281
      "0.95em" => '0.95em',
1282
      "1em" => '1em',
1283
    ),
1284
  );
1285

    
1286
  // decoration
1287
  $form['decoration'] = array(
1288
    '#title' => t('Decoration'),
1289
    '#type' => 'select',
1290
    '#default_value' => isset($settings['decoration']) ? $settings['decoration'] : '',
1291
    '#options' => array(
1292
      '' => '',
1293
      'none' => t('None'),
1294
      'underline' => t('Underline'),
1295
      'overline' => t('Overline'),
1296
      'line-through' => t('Line-through'),
1297
    ),
1298
  );
1299

    
1300
  // weight
1301
  $form['weight'] = array(
1302
    '#title' => t('Weight'),
1303
    '#type' => 'select',
1304
    '#default_value' => isset($settings['weight']) ? $settings['weight'] : '',
1305
    '#options' => array(
1306
      '' => '',
1307
      'normal' => t('Normal'),
1308
      'bold' => t('Bold'),
1309
      'bolder' => t('Bolder'),
1310
      'lighter' => t('Lighter'),
1311
    ),
1312
  );
1313

    
1314
  // style
1315
  $form['style'] = array(
1316
    '#title' => t('Style'),
1317
    '#type' => 'select',
1318
    '#default_value' => isset($settings['style']) ? $settings['style'] : '',
1319
    '#options' => array(
1320
      '' => '',
1321
      'normal' => t('Normal'),
1322
      'italic' => t('Italic'),
1323
      'oblique' => t('Oblique'),
1324
    ),
1325
  );
1326

    
1327
  // variant
1328
  $form['variant'] = array(
1329
    '#title' => t('Variant'),
1330
    '#type' => 'select',
1331
    '#default_value' => isset($settings['variant']) ? $settings['variant'] : '',
1332
    '#options' => array(
1333
      '' => '',
1334
      'normal' => t('Normal'),
1335
      'small-caps' => t('Small-caps'),
1336
    ),
1337
  );
1338

    
1339
  // case
1340
  $form['case'] = array(
1341
    '#title' => t('Case'),
1342
    '#type' => 'select',
1343
    '#default_value' => isset($settings['case']) ? $settings['case'] : '',
1344
    '#options' => array(
1345
      '' => '',
1346
      'capitalize' => t('Capitalize'),
1347
      'uppercase' => t('Uppercase'),
1348
      'lowercase' => t('Lowercase'),
1349
      'none' => t('None'),
1350
    ),
1351
  );
1352

    
1353
  // alignment
1354
  $form['alignment'] = array(
1355
    '#title' => t('Align'),
1356
    '#type' => 'select',
1357
    '#default_value' => isset($settings['alignment']) ? $settings['alignment'] : '',
1358
    '#options' => array(
1359
      '' => '',
1360
      'justify' => t('Justify'),
1361
      'left' => t('Left'),
1362
      'right' => t('Right'),
1363
      'center' => t('Center'),
1364
    ),
1365
  );
1366
}
1367

    
1368
/**
1369
 * Copy font selector information into the settings
1370
 */
1371
function ctools_stylizer_font_selector_form_submit(&$form, &$form_state, &$values, &$settings) {
1372
  $settings = $values;
1373
}
1374

    
1375
function ctools_stylizer_font_apply_style(&$stylesheet, $selector, $settings) {
1376
  $css = '';
1377
  if (isset($settings['font']) && $settings['font'] !== '') {
1378
    $css .= '  font-family: ' . $settings['font'] . ";\n";
1379
  }
1380

    
1381
  if (isset($settings['size']) && $settings['size'] !== '') {
1382
    $css .= '  font-size: ' . $settings['size'] . ";\n";
1383
  }
1384

    
1385
  if (isset($settings['weight']) && $settings['weight'] !== '') {
1386
    $css .= '  font-weight: ' . $settings['weight'] . ";\n";
1387
  }
1388

    
1389
  if (isset($settings['style']) && $settings['style'] !== '') {
1390
    $css .= '  font-style: ' . $settings['style'] . ";\n";
1391
  }
1392

    
1393
  if (isset($settings['variant']) && $settings['variant'] !== '') {
1394
    $css .= '  font-variant: ' . $settings['variant'] . ";\n";
1395
  }
1396

    
1397
  if (isset($settings['case']) && $settings['case'] !== '') {
1398
    $css .= '  text-transform: ' . $settings['case'] . ";\n";
1399
  }
1400

    
1401
  if (isset($settings['decoration']) && $settings['decoration'] !== '') {
1402
    $css .= '  text-decoration: ' . $settings['decoration'] . ";\n";
1403
  }
1404

    
1405
  if (isset($settings['alignment']) && $settings['alignment'] !== '') {
1406
    $css .= '  text-align: ' . $settings['alignment'] . ";\n";
1407
  }
1408

    
1409
  if (isset($settings['letter_spacing']) && $settings['letter_spacing'] !== '') {
1410
    $css .= '  letter-spacing: ' . $settings['letter_spacing'] . ";\n";
1411
  }
1412

    
1413
  if (isset($settings['word_spacing']) && $settings['word_spacing'] !== '') {
1414
    $css .= '  word-spacing: ' . $settings['word_spacing'] . ";\n";
1415
  }
1416

    
1417
  if ($css) {
1418
    $stylesheet .= $selector . " {\n" . $css . "}\n";
1419
  }
1420
}
1421

    
1422
/**
1423
 * Border selector form
1424
 */
1425
function ctools_stylizer_border_selector_form(&$form, &$form_state, $label, $settings) {
1426
  // Family
1427
  $form['#prefix'] = '<div class="ctools-stylizer-spacing-form clearfix">';
1428
  $form['#type'] = 'fieldset';
1429
  $form['#title'] = $label;
1430
  $form['#suffix'] = '</div>';
1431
  $form['#tree'] = TRUE;
1432

    
1433
  $form['thickness'] = array(
1434
    '#title' => t('Thickness'),
1435
    '#type' => 'select',
1436
    '#default_value' => isset($settings['thickness']) ? $settings['thickness'] : '',
1437
    '#options' => array(
1438
      '' => '',
1439
      "none" => t('None'),
1440
      "1px" => '1px',
1441
      "2px" => '2px',
1442
      "3px" => '3px',
1443
      "4px" => '4px',
1444
      "5px" => '5px',
1445
    ),
1446
  );
1447

    
1448
  $form['style'] = array(
1449
    '#title' => t('style'),
1450
    '#type' => 'select',
1451
    '#default_value' => isset($settings['style']) ? $settings['style'] : '',
1452
    '#options' => array(
1453
      '' => '',
1454
      'solid' => t('Solid'),
1455
      'dotted' => t('Dotted'),
1456
      'dashed' => t('Dashed'),
1457
      'double' => t('Double'),
1458
      'groove' => t('Groove'),
1459
      'ridge' => t('Ridge'),
1460
      'inset' => t('Inset'),
1461
      'outset' => t('Outset'),
1462
    ),
1463
  );
1464
}
1465

    
1466
/**
1467
 * Copy border selector information into the settings
1468
 */
1469
function ctools_stylizer_border_selector_form_submit(&$form, &$form_state, &$values, &$settings) {
1470
  $settings = $values;
1471
}
1472

    
1473
function ctools_stylizer_border_apply_style(&$stylesheet, $selector, $settings, $color, $which = NULL) {
1474
  $border = 'border';
1475
  if ($which) {
1476
    $border .= '-' . $which;
1477
  }
1478

    
1479
  $css = '';
1480
  if (isset($settings['thickness']) && $settings['thickness'] !== '') {
1481
    if ($settings['thickness'] == 'none') {
1482
      $css .= '  ' . $border . ': none';
1483
    }
1484
    else {
1485
      $css .= '  ' . $border . '-width: ' . $settings['thickness'] . ";\n";
1486

    
1487
      if (isset($settings['style']) && $settings['style'] !== '') {
1488
        $css .= '  ' . $border . '-style: ' . $settings['style'] . ";\n";
1489
      }
1490

    
1491
      $css .= '  ' . $border . '-color: ' . $color . ";\n";
1492
    }
1493
  }
1494

    
1495
  if ($css) {
1496
    $stylesheet .= $selector . " {\n" . $css . "}\n";
1497
  }
1498

    
1499
}
1500

    
1501
/**
1502
 * padding selector form
1503
 */
1504
function ctools_stylizer_padding_selector_form(&$form, &$form_state, $label, $settings) {
1505
  // Family
1506
  $form['#prefix'] = '<div class="ctools-stylizer-spacing-form clearfix">';
1507
  $form['#type'] = 'fieldset';
1508
  $form['#title'] = $label;
1509
  $form['#suffix'] = '</div>';
1510
  $form['#tree'] = TRUE;
1511

    
1512
  $options = array(
1513
    '' => '',
1514
    "0.05em" => '0.05em',
1515
    "0.1em" => '0.1em',
1516
    "0.15em" => '0.15em',
1517
    "0.2em" => '0.2em',
1518
    "0.25em" => '0.25em',
1519
    "0.3em" => '0.3em',
1520
    "0.35em" => '0.35em',
1521
    "0.4em" => '0.4em',
1522
    "0.45em" => '0.45em',
1523
    "0.5em" => '0.5em',
1524
    "0.55em" => '0.55em',
1525
    "0.6em" => '0.6em',
1526
    "0.65em" => '0.65em',
1527
    "0.7em" => '0.7em',
1528
    "0.75em" => '0.75em',
1529
    "0.8em" => '0.8em',
1530
    "0.85em" => '0.85em',
1531
    "0.9em" => '0.9em',
1532
    "0.95em" => '0.95em',
1533
    "1.0em" => '1.0em',
1534
    "1.05em" => '1.05em',
1535
    "1.1em" => '1.1em',
1536
    "1.15em" => '1.15em',
1537
    "1.2em" => '1.2em',
1538
    "1.25em" => '1.25em',
1539
    "1.3em" => '1.3em',
1540
    "1.35em" => '1.35em',
1541
    "1.4em" => '1.4em',
1542
    "1.45em" => '1.45em',
1543
    "1.5em" => '1.5em',
1544
    "1.55em" => '1.55em',
1545
    "1.6em" => '1.6em',
1546
    "1.65em" => '1.65em',
1547
    "1.7em" => '1.7em',
1548
    "1.75em" => '1.75em',
1549
    "1.8em" => '1.8em',
1550
    "1.85em" => '1.85em',
1551
    "1.9em" => '1.9em',
1552
    "1.95em" => '1.95em',
1553
    "2.0em" => '2.0em',
1554
    "2.05em" => '2.05em',
1555
    "2.1em" => '2.1em',
1556
    "2.15em" => '2.15em',
1557
    "2.2em" => '2.2em',
1558
    "2.25em" => '2.25em',
1559
    "2.3em" => '2.3em',
1560
    "2.35em" => '2.35em',
1561
    "2.4em" => '2.4em',
1562
    "2.45em" => '2.45em',
1563
    "2.5em" => '2.5em',
1564
    "2.55em" => '2.55em',
1565
    "2.6em" => '2.6em',
1566
    "2.65em" => '2.65em',
1567
    "2.7em" => '2.7em',
1568
    "2.75em" => '2.75em',
1569
    "2.8em" => '2.8em',
1570
    "2.85em" => '2.85em',
1571
    "2.9em" => '2.9em',
1572
    "2.95em" => '2.95em',
1573
    "3.0em" => '3.0em',
1574
    "3.05em" => '3.05em',
1575
    "3.1em" => '3.1em',
1576
    "3.15em" => '3.15em',
1577
    "3.2em" => '3.2em',
1578
    "3.25em" => '3.25em',
1579
    "3.3em" => '3.3em',
1580
    "3.35em" => '3.35em',
1581
    "3.4em" => '3.4em',
1582
    "3.45em" => '3.45em',
1583
    "3.5em" => '3.5em',
1584
    "3.55em" => '3.55em',
1585
    "3.6em" => '3.6em',
1586
    "3.65em" => '3.65em',
1587
    "3.7em" => '3.7em',
1588
    "3.75em" => '3.75em',
1589
    "3.8em" => '3.8em',
1590
    "3.85em" => '3.85em',
1591
    "3.9em" => '3.9em',
1592
    "3.95em" => '3.95em',
1593
  );
1594

    
1595
  $form['top'] = array(
1596
    '#title' => t('Top'),
1597
    '#type' => 'select',
1598
    '#default_value' => isset($settings['top']) ? $settings['top'] : '',
1599
    '#options' => $options,
1600
  );
1601

    
1602
  $form['right'] = array(
1603
    '#title' => t('Right'),
1604
    '#type' => 'select',
1605
    '#default_value' => isset($settings['right']) ? $settings['right'] : '',
1606
    '#options' => $options,
1607
  );
1608

    
1609
  $form['bottom'] = array(
1610
    '#title' => t('Bottom'),
1611
    '#type' => 'select',
1612
    '#default_value' => isset($settings['bottom']) ? $settings['bottom'] : '',
1613
    '#options' => $options,
1614
  );
1615

    
1616
  $form['left'] = array(
1617
    '#title' => t('Left'),
1618
    '#type' => 'select',
1619
    '#default_value' => isset($settings['left']) ? $settings['left'] : '',
1620
    '#options' => $options,
1621
  );
1622
}
1623

    
1624
/**
1625
 * Copy padding selector information into the settings
1626
 */
1627
function ctools_stylizer_padding_selector_form_submit(&$form, &$form_state, &$values, &$settings) {
1628
  $settings = $values;
1629
}
1630

    
1631
function ctools_stylizer_padding_apply_style(&$stylesheet, $selector, $settings) {
1632
  $css = '';
1633

    
1634
  if (isset($settings['top']) && $settings['top'] !== '') {
1635
    $css .= '  padding-top: ' . $settings['top'] . ";\n";
1636
  }
1637

    
1638
  if (isset($settings['right']) && $settings['right'] !== '') {
1639
    $css .= '  padding-right: ' . $settings['right'] . ";\n";
1640
  }
1641

    
1642
  if (isset($settings['bottom']) && $settings['bottom'] !== '') {
1643
    $css .= '  padding-bottom: ' . $settings['bottom'] . ";\n";
1644
  }
1645

    
1646
  if (isset($settings['left']) && $settings['left'] !== '') {
1647
    $css .= '  padding-left: ' . $settings['left'] . ";\n";
1648
  }
1649

    
1650
  if ($css) {
1651
    $stylesheet .= $selector . " {\n" . $css . "}\n";
1652
  }
1653

    
1654
}