1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * CML_explorer.c
5 * Time-stamp: <2000-02-13 18:18:37 yasuhiro>
6 * Copyright (C) 1997 Shuji Narazaki <narazaki@InetQ.or.jp>
7 * Version: 1.0.11
8 * URL: http://www.inetq.or.jp/~narazaki/TheGIMP/
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 *
23 * Comment:
24 * CML is the abbreviation of Coupled-Map Lattice that is a model of
25 * complex systems, proposed by a physicist[1,2].
26 *
27 * Similar models are summaried as follows:
28 *
29 * Value Time Space
30 * Coupled-Map Lattice cont. discrete discrete
31 * Celluar Automata discrete discrete discrete
32 * Differential Eq. cont. cont. cont.
33 *
34 * (But this program uses a parameter: hold-rate to avoid very fast changes.
35 * Thus time is rather continuous than discrete.
36 * Yes, this change to model changes the output completely.)
37 *
38 * References:
39 * 1. Kunihiko Kaneko, Period-doubling of kind-antikink patterns,
40 * quasi-periodicity in antiferro-like structures and spatial
41 * intermittency in coupled map lattices -- Toward a prelude to a
42 * "field theory of chaos", Prog. Theor. Phys. 72 (1984) 480.
43 *
44 * 2. Kunihiko Kaneko ed., Theory and Applications of Coupled Map
45 * Lattices (Wiley, 1993).
46 *
47 * About Parameter File:
48 * I assume that the possible longest line in CMP parameter file is 1023.
49 * Please read CML_save_to_file_callback if you want know details of syntax.
50 *
51 * Format version 1.0 starts with:
52 * ; This is a parameter file for CML_explorer
53 * ; File format version: 1.0
54 * ;
55 * Hue
56 *
57 * The old format for CML_explorer included in gimp-0.99.[89] is:
58 * ; CML parameter file (version: 1.0)
59 * ; Hue
60 *
61 * (This file format is interpreted as format version 0.99 now.)
62 *
63 * Thanks:
64 * This version contains patches from:
65 * Tim Mooney <mooney@dogbert.cc.ndsu.NoDak.edu>
66 * Sean P Cier <scier@andrew.cmu.edu>
67 * David Mosberger-Tang <davidm@azstarnet.com>
68 * Michael Sweet <mike@easysw.com>
69 *
70 */
71 #include "config.h"
72
73 #include <errno.h>
74 #include <stdlib.h>
75 #include <string.h>
76
77 #include <glib/gstdio.h>
78
79 #include <libgimp/gimp.h>
80 #include <libgimp/gimpui.h>
81
82 #include "libgimp/stdplugins-intl.h"
83
84 #define PARAM_FILE_FORMAT_VERSION 1.0
85 #define PLUG_IN_PROC "plug-in-cml-explorer"
86 #define PLUG_IN_BINARY "cml-explorer"
87 #define PLUG_IN_ROLE "gimp-cml-explorer"
88 #define VALS CML_explorer_vals
89 #define PROGRESS_UPDATE_NUM 100
90 #define CML_LINE_SIZE 1024
91 #define TILE_CACHE_SIZE 32
92 #define SCALE_WIDTH 130
93 #define PREVIEW_WIDTH 64
94 #define PREVIEW_HEIGHT 220
95
96 #define CANNONIZE(p, x) (255*(((p).range_h - (p).range_l)*(x) + (p).range_l))
97 #define HCANNONIZE(p, x) (254*(((p).range_h - (p).range_l)*(x) + (p).range_l))
98 #define POS_IN_TORUS(i,size) ((i < 0) ? size + i : ((size <= i) ? i - size : i))
99
100 typedef struct _WidgetEntry WidgetEntry;
101
102 struct _WidgetEntry
103 {
104 GtkWidget *widget;
105 gpointer value;
106 void (*updater) (WidgetEntry *);
107 };
108
109 enum
110 {
111 CML_KEEP_VALUES,
112 CML_KEEP_FIRST,
113 CML_FILL,
114 CML_LOGIST,
115 CML_LOGIST_STEP,
116 CML_POWER,
117 CML_POWER_STEP,
118 CML_REV_POWER,
119 CML_REV_POWER_STEP,
120 CML_DELTA,
121 CML_DELTA_STEP,
122 CML_SIN_CURVE,
123 CML_SIN_CURVE_STEP,
124 CML_NUM_VALUES
125 };
126
127 static const gchar *function_names[CML_NUM_VALUES] =
128 {
129 N_("Keep image's values"),
130 N_("Keep the first value"),
131 N_("Fill with parameter k"),
132 N_("k{x(1-x)}^p"),
133 N_("k{x(1-x)}^p stepped"),
134 N_("kx^p"),
135 N_("kx^p stepped"),
136 N_("k(1-x^p)"),
137 N_("k(1-x^p) stepped"),
138 N_("Delta function"),
139 N_("Delta function stepped"),
140 N_("sin^p-based function"),
141 N_("sin^p, stepped")
142 };
143
144 enum
145 {
146 COMP_NONE,
147 COMP_MAX_LINEAR,
148 COMP_MAX_LINEAR_P1,
149 COMP_MAX_LINEAR_M1,
150 COMP_MIN_LINEAR,
151 COMP_MIN_LINEAR_P1,
152 COMP_MIN_LINEAR_M1,
153 COMP_MAX_LINEAR_P1L,
154 COMP_MAX_LINEAR_P1U,
155 COMP_MAX_LINEAR_M1L,
156 COMP_MAX_LINEAR_M1U,
157 COMP_MIN_LINEAR_P1L,
158 COMP_MIN_LINEAR_P1U,
159 COMP_MIN_LINEAR_M1L,
160 COMP_MIN_LINEAR_M1U,
161 COMP_NUM_VALUES
162 };
163
164 static const gchar *composition_names[COMP_NUM_VALUES] =
165 {
166 NC_("cml-composition", "None"),
167 N_("Max (x, -)"),
168 N_("Max (x+d, -)"),
169 N_("Max (x-d, -)"),
170 N_("Min (x, -)"),
171 N_("Min (x+d, -)"),
172 N_("Min (x-d, -)"),
173 N_("Max (x+d, -), (x < 0.5)"),
174 N_("Max (x+d, -), (0.5 < x)"),
175 N_("Max (x-d, -), (x < 0.5)"),
176 N_("Max (x-d, -), (0.5 < x)"),
177 N_("Min (x+d, -), (x < 0.5)"),
178 N_("Min (x+d, -), (0.5 < x)"),
179 N_("Min (x-d, -), (x < 0.5)"),
180 N_("Min (x-d, -), (0.5 < x)")
181 };
182
183 enum
184 {
185 STANDARD,
186 AVERAGE,
187 ANTILOG,
188 RAND_POWER0,
189 RAND_POWER1,
190 RAND_POWER2,
191 MULTIPLY_RANDOM0,
192 MULTIPLY_RANDOM1,
193 MULTIPLY_GRADIENT,
194 RAND_AND_P,
195 ARRANGE_NUM_VALUES
196 };
197
198 static const gchar *arrange_names[ARRANGE_NUM_VALUES] =
199 {
200 N_("Standard"),
201 N_("Use average value"),
202 N_("Use reverse value"),
203 N_("With random power (0,10)"),
204 N_("With random power (0,1)"),
205 N_("With gradient power (0,1)"),
206 N_("Multiply rand. value (0,1)"),
207 N_("Multiply rand. value (0,2)"),
208 N_("Multiply gradient (0,1)"),
209 N_("With p and random (0,1)"),
210 };
211
212 enum
213 {
214 CML_INITIAL_RANDOM_INDEPENDENT = 6,
215 CML_INITIAL_RANDOM_SHARED,
216 CML_INITIAL_RANDOM_FROM_SEED,
217 CML_INITIAL_RANDOM_FROM_SEED_SHARED,
218 CML_INITIAL_NUM_VALUES
219 };
220
221 static const gchar *initial_value_names[CML_INITIAL_NUM_VALUES] =
222 {
223 N_("All black"),
224 N_("All gray"),
225 N_("All white"),
226 N_("The first row of the image"),
227 N_("Continuous gradient"),
228 N_("Continuous grad. w/o gap"),
229 N_("Random, ch. independent"),
230 N_("Random shared"),
231 N_("Randoms from seed"),
232 N_("Randoms from seed (shared)")
233 };
234
235 #define CML_PARAM_NUM 15
236
237 typedef struct
238 {
239 gint function;
240 gint composition;
241 gint arrange;
242 gint cyclic_range;
243 gdouble mod_rate; /* diff / old-value */
244 gdouble env_sensitivity; /* self-diff : env-diff */
245 gint diffusion_dist;
246 gdouble ch_sensitivity;
247 gint range_num;
248 gdouble power;
249 gdouble parameter_k;
250 gdouble range_l;
251 gdouble range_h;
252 gdouble mutation_rate;
253 gdouble mutation_dist;
254 } CML_PARAM;
255
256 typedef struct
257 {
258 CML_PARAM hue;
259 CML_PARAM sat;
260 CML_PARAM val;
261 gint initial_value;
262 gint scale;
263 gint start_offset;
264 gint seed;
265 gchar last_file_name[256];
266 } ValueType;
267
268 static ValueType VALS =
269 {
270 /* function composition arra
271 cyc chng sens diff cor n pow k (l,h) rnd dist */
272 {
273 CML_SIN_CURVE, COMP_NONE, STANDARD,
274 1, 0.5, 0.7, 2, 0.0, 1, 1.0, 1.0, 0, 1, 0.0, 0.1
275 },
276 {
277 CML_FILL, COMP_NONE, STANDARD,
278 0, 0.6, 0.1, 2, 0.0, 1, 1.4, 0.9, 0, 0.9, 0.0, 0.1
279 },
280 {
281 CML_FILL, COMP_NONE, STANDARD,
282 0, 0.5, 0.2, 2, 0.0, 1, 2.0, 1.0, 0, 0.9, 0.0, 0.1
283 },
284 6, /* random value 1 */
285 1, /* scale */
286 0, /* start_offset */
287 0, /* seed */
288 "" /* last filename */
289 };
290
291 static CML_PARAM *channel_params[] =
292 {
293 &VALS.hue,
294 &VALS.sat,
295 &VALS.val
296 };
297
298 static const gchar *channel_names[] =
299 {
300 N_("Hue"),
301 N_("Saturation"),
302 N_("Value")
303 };
304
305 static const gchar *load_channel_names[] =
306 {
307 N_("(None)"),
308 N_("Hue"),
309 N_("Saturation"),
310 N_("Value")
311 };
312
313 static void query (void);
314 static void run (const gchar *name,
315 gint nparams,
316 const GimpParam *param,
317 gint *nreturn_vals,
318 GimpParam **return_vals);
319
320 static GimpPDBStatusType CML_main_function (gboolean preview_p);
321 static void CML_compute_next_step (gint size,
322 gdouble **h,
323 gdouble **s,
324 gdouble **v,
325 gdouble **hn,
326 gdouble **sn,
327 gdouble **vn,
328 gdouble **haux,
329 gdouble **saux,
330 gdouble **vaux);
331 static gdouble CML_next_value (gdouble *vec,
332 gint pos,
333 gint size,
334 gdouble c1,
335 gdouble c2,
336 CML_PARAM *param,
337 gdouble aux);
338 static gdouble logistic_function (CML_PARAM *param,
339 gdouble x,
340 gdouble power);
341
342
343 static gint CML_explorer_dialog (void);
344 static GtkWidget * CML_dialog_channel_panel_new (CML_PARAM *param,
345 gint channel_id);
346 static GtkWidget * CML_dialog_advanced_panel_new (void);
347
348 static void CML_explorer_toggle_entry_init (WidgetEntry *widget_entry,
349 GtkWidget *widget,
350 gpointer value_ptr);
351
352 static void CML_explorer_int_entry_init (WidgetEntry *widget_entry,
353 GtkObject *object,
354 gpointer value_ptr);
355
356 static void CML_explorer_double_entry_init (WidgetEntry *widget_entry,
357 GtkObject *object,
358 gpointer value_ptr);
359
360 static void CML_explorer_menu_update (GtkWidget *widget,
361 gpointer data);
362 static void CML_initial_value_menu_update (GtkWidget *widget,
363 gpointer data);
364 static void CML_explorer_menu_entry_init (WidgetEntry *widget_entry,
365 GtkWidget *widget,
366 gpointer value_ptr);
367
368 static void preview_update (void);
369 static void function_graph_new (GtkWidget *widget,
370 gpointer *data);
371 static void CML_set_or_randomize_seed_callback (GtkWidget *widget,
372 gpointer data);
373 static void CML_copy_parameters_callback (GtkWidget *widget,
374 gpointer data);
375 static void CML_initial_value_sensitives_update (void);
376
377 static void CML_save_to_file_callback (GtkWidget *widget,
378 gpointer data);
379 static void CML_save_to_file_response (GtkWidget *dialog,
380 gint response_id,
381 gpointer data);
382
383 static void CML_preview_update_callback (GtkWidget *widget,
384 gpointer data);
385 static void CML_load_from_file_callback (GtkWidget *widget,
386 gpointer data);
387 static gboolean CML_load_parameter_file (const gchar *filename,
388 gboolean interactive_mode);
389 static void CML_load_from_file_response (GtkWidget *dialog,
390 gint response_id,
391 gpointer data);
392 static gint parse_line_to_gint (FILE *file,
393 gboolean *flag);
394 static gdouble parse_line_to_gdouble (FILE *file,
395 gboolean *flag);
396
397
398 const GimpPlugInInfo PLUG_IN_INFO =
399 {
400 NULL, /* init_proc */
401 NULL, /* quit_proc */
402 query, /* query_proc */
403 run, /* run_proc */
404 };
405
406 static GtkWidget *preview;
407 static WidgetEntry widget_pointers[4][CML_PARAM_NUM];
408
409 static guchar *img;
410 static gint img_stride;
411 static cairo_surface_t *buffer;
412
413 typedef struct
414 {
415 GtkWidget *widget;
416 gint logic;
417 } CML_sensitive_widget_table;
418
419 #define RANDOM_SENSITIVES_NUM 5
420 #define GRAPHSIZE 256
421
422 static CML_sensitive_widget_table random_sensitives[RANDOM_SENSITIVES_NUM] =
423 {
424 { NULL, 0 },
425 { NULL, 0 },
426 { NULL, 0 },
427 { NULL, 0 },
428 { NULL, 0 }
429 };
430
431 static GRand *gr;
432 static gint drawable_id = 0;
433 static gint copy_source = 0;
434 static gint copy_destination = 0;
435 static gint selective_load_source = 0;
436 static gint selective_load_destination = 0;
437 static gboolean CML_preview_defer = FALSE;
438
439 static gdouble *mem_chank0 = NULL;
440 static gint mem_chank0_size = 0;
441 static guchar *mem_chank1 = NULL;
442 static gint mem_chank1_size = 0;
443 static guchar *mem_chank2 = NULL;
444 static gint mem_chank2_size = 0;
445
MAIN()446 MAIN ()
447
448 static void
449 query (void)
450 {
451 static const GimpParamDef args [] =
452 {
453 { GIMP_PDB_INT32, "ru-_mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
454 { GIMP_PDB_IMAGE, "image", "Input image (not used)" },
455 { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
456 { GIMP_PDB_STRING, "parameter-filename", "The name of parameter file. CML_explorer makes an image with its settings." }
457 };
458
459 gimp_install_procedure (PLUG_IN_PROC,
460 N_("Create abstract Coupled-Map Lattice patterns"),
461 "Make an image of Coupled-Map Lattice (CML). CML is "
462 "a kind of Cellula Automata on continuous (value) "
463 "domain. In GIMP_RUN_NONINTERACTIVE, the name of a "
464 "parameter file is passed as the 4th arg. You can "
465 "control CML_explorer via parameter file.",
466 /* Or do you want to call me with over 50 args? */
467 "Shuji Narazaki (narazaki@InetQ.or.jp); "
468 "http://www.inetq.or.jp/~narazaki/TheGIMP/",
469 "Shuji Narazaki",
470 "1997",
471 N_("CML _Explorer..."),
472 "RGB*, GRAY*",
473 GIMP_PLUGIN,
474 G_N_ELEMENTS (args), 0,
475 args, NULL);
476
477 gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Filters/Render/Pattern");
478 }
479
480 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)481 run (const gchar *name,
482 gint nparams,
483 const GimpParam *param,
484 gint *nreturn_vals,
485 GimpParam **return_vals)
486 {
487 static GimpParam values[1];
488 GimpPDBStatusType status = GIMP_PDB_EXECUTION_ERROR;
489 GimpRunMode run_mode;
490
491 run_mode = param[0].data.d_int32;
492 drawable_id = param[2].data.d_drawable;
493
494 INIT_I18N ();
495 gegl_init (NULL, NULL);
496
497 *nreturn_vals = 1;
498 *return_vals = values;
499
500 values[0].type = GIMP_PDB_STATUS;
501 values[0].data.d_status = status;
502
503 switch (run_mode)
504 {
505 case GIMP_RUN_INTERACTIVE:
506 gimp_get_data (PLUG_IN_PROC, &VALS);
507 if (! CML_explorer_dialog ())
508 return;
509 break;
510 case GIMP_RUN_NONINTERACTIVE:
511 {
512 gchar *filename = param[3].data.d_string;
513
514 if (! CML_load_parameter_file (filename, FALSE))
515 return;
516 break;
517 }
518 case GIMP_RUN_WITH_LAST_VALS:
519 gimp_get_data (PLUG_IN_PROC, &VALS);
520 break;
521 }
522
523 status = CML_main_function (FALSE);
524
525 if (run_mode != GIMP_RUN_NONINTERACTIVE)
526 gimp_displays_flush();
527 if (run_mode == GIMP_RUN_INTERACTIVE && status == GIMP_PDB_SUCCESS)
528 gimp_set_data (PLUG_IN_PROC, &VALS, sizeof (ValueType));
529
530 g_free (mem_chank0);
531 g_free (mem_chank1);
532 g_free (mem_chank2);
533
534 values[0].type = GIMP_PDB_STATUS;
535 values[0].data.d_status = status;
536 }
537
538 static GimpPDBStatusType
CML_main_function(gboolean preview_p)539 CML_main_function (gboolean preview_p)
540 {
541 GeglBuffer *src_buffer;
542 GeglBuffer *dest_buffer;
543 const Babl *src_format;
544 const Babl *dest_format;
545 guchar *dest_buf = NULL;
546 guchar *src_buf = NULL;
547 gint x, y;
548 gint dx, dy;
549 gboolean dest_has_alpha = FALSE;
550 gboolean dest_is_gray = FALSE;
551 gboolean src_has_alpha = FALSE;
552 gboolean src_is_gray = FALSE;
553 gint total, processed = 0;
554 gint keep_height = 1;
555 gint cell_num, width_by_pixel, height_by_pixel;
556 gint index;
557 gint src_bpp, src_bpl;
558 gint dest_bpp, dest_bpl;
559 gdouble *hues, *sats, *vals;
560 gdouble *newh, *news, *newv;
561 gdouble *haux, *saux, *vaux;
562
563 if (! gimp_drawable_mask_intersect (drawable_id,
564 &x, &y,
565 &width_by_pixel, &height_by_pixel))
566 return GIMP_PDB_SUCCESS;
567
568 src_has_alpha = dest_has_alpha = gimp_drawable_has_alpha (drawable_id);
569 src_is_gray = dest_is_gray = gimp_drawable_is_gray (drawable_id);
570
571 if (src_is_gray)
572 {
573 if (src_has_alpha)
574 src_format = babl_format ("Y'A u8");
575 else
576 src_format = babl_format ("Y' u8");
577 }
578 else
579 {
580 if (src_has_alpha)
581 src_format = babl_format ("R'G'B'A u8");
582 else
583 src_format = babl_format ("R'G'B' u8");
584 }
585
586 dest_format = src_format;
587
588 src_bpp = dest_bpp = babl_format_get_bytes_per_pixel (src_format);
589
590 if (preview_p)
591 {
592 dest_format = babl_format ("R'G'B' u8");
593
594 dest_has_alpha = FALSE;
595 dest_bpp = 3;
596
597 if (width_by_pixel > PREVIEW_WIDTH) /* preview < drawable (selection) */
598 width_by_pixel = PREVIEW_WIDTH;
599 if (height_by_pixel > PREVIEW_HEIGHT)
600 height_by_pixel = PREVIEW_HEIGHT;
601 }
602
603 dest_bpl = width_by_pixel * dest_bpp;
604 src_bpl = width_by_pixel * src_bpp;
605 cell_num = (width_by_pixel - 1)/ VALS.scale + 1;
606 total = height_by_pixel * width_by_pixel;
607
608 if (total < 1)
609 return GIMP_PDB_EXECUTION_ERROR;
610
611 keep_height = VALS.scale;
612
613 /* configure reusable memories */
614 if (mem_chank0_size < 9 * cell_num * sizeof (gdouble))
615 {
616 g_free (mem_chank0);
617 mem_chank0_size = 9 * cell_num * sizeof (gdouble);
618 mem_chank0 = (gdouble *) g_malloc (mem_chank0_size);
619 }
620
621 hues = mem_chank0;
622 sats = mem_chank0 + cell_num;
623 vals = mem_chank0 + 2 * cell_num;
624 newh = mem_chank0 + 3 * cell_num;
625 news = mem_chank0 + 4 * cell_num;
626 newv = mem_chank0 + 5 * cell_num;
627 haux = mem_chank0 + 6 * cell_num;
628 saux = mem_chank0 + 7 * cell_num;
629 vaux = mem_chank0 + 8 * cell_num;
630
631 if (mem_chank1_size < src_bpl * keep_height)
632 {
633 g_free (mem_chank1);
634 mem_chank1_size = src_bpl * keep_height;
635 mem_chank1 = (guchar *) g_malloc (mem_chank1_size);
636 }
637 src_buf = mem_chank1;
638
639 if (mem_chank2_size < dest_bpl * keep_height)
640 {
641 g_free (mem_chank2);
642 mem_chank2_size = dest_bpl * keep_height;
643 mem_chank2 = (guchar *) g_malloc (mem_chank2_size);
644 }
645 dest_buf = mem_chank2;
646
647 if (! preview_p)
648 dest_buffer = gimp_drawable_get_shadow_buffer (drawable_id);
649
650 src_buffer = gimp_drawable_get_buffer (drawable_id);
651
652 gr = g_rand_new ();
653 if (VALS.initial_value == CML_INITIAL_RANDOM_FROM_SEED)
654 g_rand_set_seed (gr, VALS.seed);
655
656 for (index = 0; index < cell_num; index++)
657 {
658 switch (VALS.hue.arrange)
659 {
660 case RAND_POWER0:
661 haux [index] = g_rand_double_range (gr, 0, 10);
662 break;
663 case RAND_POWER2:
664 case MULTIPLY_GRADIENT:
665 haux [index] = (gdouble) abs ((index % 511) - 255) / (gdouble) 256;
666 break;
667 case RAND_POWER1:
668 case MULTIPLY_RANDOM0:
669 haux [index] = g_rand_double (gr);
670 break;
671 case MULTIPLY_RANDOM1:
672 haux [index] = g_rand_double_range (gr, 0, 2);
673 break;
674 case RAND_AND_P:
675 haux [index] = ((index % (2 * VALS.hue.diffusion_dist) == 0) ?
676 g_rand_double (gr) : VALS.hue.power);
677 break;
678 default:
679 haux [index] = VALS.hue.power;
680 break;
681 }
682
683 switch (VALS.sat.arrange)
684 {
685 case RAND_POWER0:
686 saux [index] = g_rand_double_range (gr, 0, 10);
687 break;
688 case RAND_POWER2:
689 case MULTIPLY_GRADIENT:
690 saux [index] = (gdouble) abs ((index % 511) - 255) / (gdouble) 256;
691 break;
692 case RAND_POWER1:
693 case MULTIPLY_RANDOM0:
694 saux [index] = g_rand_double (gr);
695 break;
696 case MULTIPLY_RANDOM1:
697 saux [index] = g_rand_double_range (gr, 0, 2);
698 break;
699 case RAND_AND_P:
700 saux [index] = ((index % (2 * VALS.sat.diffusion_dist) == 0) ?
701 g_rand_double (gr) : VALS.sat.power);
702 break;
703 default:
704 saux [index] = VALS.sat.power;
705 break;
706 }
707
708 switch (VALS.val.arrange)
709 {
710 case RAND_POWER0:
711 vaux [index] = g_rand_double_range (gr, 0, 10);
712 break;
713 case RAND_POWER2:
714 case MULTIPLY_GRADIENT:
715 vaux [index] = (gdouble) abs ((index % 511) - 255) / (gdouble) 256;
716 break;
717 case RAND_POWER1:
718 case MULTIPLY_RANDOM0:
719 vaux [index] = g_rand_double (gr);
720 break;
721 case MULTIPLY_RANDOM1:
722 vaux [index] = g_rand_double_range (gr, 0, 2);
723 break;
724 case RAND_AND_P:
725 vaux [index] = ((index % (2 * VALS.val.diffusion_dist) == 0) ?
726 g_rand_double (gr) : VALS.val.power);
727 break;
728 default:
729 vaux [index] = VALS.val.power;
730 break;
731 }
732
733 switch (VALS.initial_value)
734 {
735 case 0:
736 case 1:
737 case 2:
738 hues[index] = sats[index] = vals[index] = 0.5 * (VALS.initial_value);
739 break;
740 case 3: /* use the values of the image (drawable) */
741 break; /* copy from the drawable after this loop */
742 case 4: /* grandient 1 */
743 hues[index] = sats[index] = vals[index]
744 = (gdouble) (index % 256) / (gdouble) 256;
745 break; /* gradinet 2 */
746 case 5:
747 hues[index] = sats[index] = vals[index]
748 = (gdouble) abs ((index % 511) - 255) / (gdouble) 256;
749 break;
750 case CML_INITIAL_RANDOM_INDEPENDENT:
751 case CML_INITIAL_RANDOM_FROM_SEED:
752 hues[index] = g_rand_double (gr);
753 sats[index] = g_rand_double (gr);
754 vals[index] = g_rand_double (gr);
755 break;
756 case CML_INITIAL_RANDOM_SHARED:
757 case CML_INITIAL_RANDOM_FROM_SEED_SHARED:
758 hues[index] = sats[index] = vals[index] = g_rand_double (gr);
759 break;
760 }
761 }
762
763 if (VALS.initial_value == 3)
764 {
765 int index;
766
767 for (index = 0;
768 index < MIN (cell_num, width_by_pixel / VALS.scale);
769 index++)
770 {
771 guchar buffer[4];
772 int rgbi[3];
773 int i;
774
775 gegl_buffer_sample (src_buffer, x + (index * VALS.scale), y, NULL,
776 buffer, src_format,
777 GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
778
779 for (i = 0; i < 3; i++) rgbi[i] = buffer[i];
780 gimp_rgb_to_hsv_int (rgbi, rgbi + 1, rgbi + 2);
781 hues[index] = (gdouble) rgbi[0] / (gdouble) 255;
782 sats[index] = (gdouble) rgbi[1] / (gdouble) 255;
783 vals[index] = (gdouble) rgbi[2] / (gdouble) 255;
784 }
785 }
786
787 if (! preview_p)
788 gimp_progress_init (_("CML Explorer: evoluting"));
789
790 /* rolling start */
791 for (index = 0; index < VALS.start_offset; index++)
792 CML_compute_next_step (cell_num, &hues, &sats, &vals, &newh, &news, &newv,
793 &haux, &saux, &vaux);
794
795 /* rendering */
796 for (dy = 0; dy < height_by_pixel; dy += VALS.scale)
797 {
798 gint r, g, b, h, s, v;
799 gint offset_x, offset_y, dest_offset;
800
801 if (height_by_pixel < dy + keep_height)
802 keep_height = height_by_pixel - dy;
803
804 if ((VALS.hue.function == CML_KEEP_VALUES) ||
805 (VALS.sat.function == CML_KEEP_VALUES) ||
806 (VALS.val.function == CML_KEEP_VALUES))
807 {
808 gegl_buffer_get (src_buffer,
809 GEGL_RECTANGLE (x, y + dy,
810 width_by_pixel, keep_height), 1.0,
811 src_format, src_buf,
812 GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
813 }
814
815 CML_compute_next_step (cell_num,
816 &hues, &sats, &vals,
817 &newh, &news, &newv,
818 &haux, &saux, &vaux);
819
820 for (dx = 0; dx < cell_num; dx++)
821 {
822 h = r = HCANNONIZE (VALS.hue, hues[dx]);
823 s = g = CANNONIZE (VALS.sat, sats[dx]);
824 v = b = CANNONIZE (VALS.val, vals[dx]);
825
826 if (! dest_is_gray)
827 gimp_hsv_to_rgb_int (&r, &g, &b);
828
829 /* render destination */
830 for (offset_y = 0;
831 (offset_y < VALS.scale) && (dy + offset_y < height_by_pixel);
832 offset_y++)
833 for (offset_x = 0;
834 (offset_x < VALS.scale) && (dx * VALS.scale + offset_x < width_by_pixel);
835 offset_x++)
836 {
837 if ((VALS.hue.function == CML_KEEP_VALUES) ||
838 (VALS.sat.function == CML_KEEP_VALUES) ||
839 (VALS.val.function == CML_KEEP_VALUES))
840 {
841 int rgbi[3];
842 int i;
843
844 for (i = 0; i < src_bpp; i++)
845 rgbi[i] = src_buf[offset_y * src_bpl
846 + (dx * VALS.scale + offset_x) * src_bpp + i];
847 if (src_is_gray && (VALS.val.function == CML_KEEP_VALUES))
848 {
849 b = rgbi[0];
850 }
851 else
852 {
853 gimp_rgb_to_hsv_int (rgbi, rgbi + 1, rgbi + 2);
854
855 r = (VALS.hue.function == CML_KEEP_VALUES) ? rgbi[0] : h;
856 g = (VALS.sat.function == CML_KEEP_VALUES) ? rgbi[1] : s;
857 b = (VALS.val.function == CML_KEEP_VALUES) ? rgbi[2] : v;
858 gimp_hsv_to_rgb_int (&r, &g, &b);
859 }
860 }
861
862 dest_offset = (offset_y * dest_bpl +
863 (dx * VALS.scale + offset_x) * dest_bpp);
864
865 if (dest_is_gray)
866 {
867 dest_buf[dest_offset++] = b;
868 if (preview_p)
869 {
870 dest_buf[dest_offset++] = b;
871 dest_buf[dest_offset++] = b;
872 }
873 }
874 else
875 {
876 dest_buf[dest_offset++] = r;
877 dest_buf[dest_offset++] = g;
878 dest_buf[dest_offset++] = b;
879 }
880 if (dest_has_alpha)
881 dest_buf[dest_offset] = 255;
882
883 if ((!preview_p) &&
884 (++processed % (total / PROGRESS_UPDATE_NUM + 1)) == 0)
885 gimp_progress_update ((gdouble) processed / (gdouble) total);
886 }
887 }
888
889 if (preview_p)
890 {
891 gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
892 0, dy,
893 width_by_pixel, keep_height,
894 GIMP_RGB_IMAGE,
895 dest_buf,
896 dest_bpl);
897 }
898 else
899 {
900 gegl_buffer_set (dest_buffer,
901 GEGL_RECTANGLE (x, y + dy,
902 width_by_pixel, keep_height), 0,
903 dest_format, dest_buf,
904 GEGL_AUTO_ROWSTRIDE);
905 }
906 }
907
908 g_object_unref (src_buffer);
909
910 if (preview_p)
911 {
912 gtk_widget_queue_draw (preview);
913 }
914 else
915 {
916 gimp_progress_update (1.0);
917
918 g_object_unref (dest_buffer);
919
920 gimp_drawable_merge_shadow (drawable_id, TRUE);
921 gimp_drawable_update (drawable_id,
922 x, y, width_by_pixel, height_by_pixel);
923 }
924
925 g_rand_free (gr);
926
927 return GIMP_PDB_SUCCESS;
928 }
929
930 static void
CML_compute_next_step(gint size,gdouble ** h,gdouble ** s,gdouble ** v,gdouble ** hn,gdouble ** sn,gdouble ** vn,gdouble ** haux,gdouble ** saux,gdouble ** vaux)931 CML_compute_next_step (gint size,
932 gdouble **h,
933 gdouble **s,
934 gdouble **v,
935 gdouble **hn,
936 gdouble **sn,
937 gdouble **vn,
938 gdouble **haux,
939 gdouble **saux,
940 gdouble **vaux)
941 {
942 gint index;
943
944 for (index = 0; index < size; index++)
945 (*hn)[index] = CML_next_value (*h, index, size,
946 (*s)[POS_IN_TORUS (index, size)],
947 (*v)[POS_IN_TORUS (index, size)],
948 &VALS.hue,
949 (*haux)[POS_IN_TORUS (index , size)]);
950 for (index = 0; index < size; index++)
951 (*sn)[index] = CML_next_value (*s, index, size,
952 (*v)[POS_IN_TORUS (index , size)],
953 (*h)[POS_IN_TORUS (index , size)],
954 &VALS.sat,
955 (*saux)[POS_IN_TORUS (index , size)]);
956 for (index = 0; index < size; index++)
957 (*vn)[index] = CML_next_value (*v, index, size,
958 (*h)[POS_IN_TORUS (index , size)],
959 (*s)[POS_IN_TORUS (index , size)],
960 &VALS.val,
961 (*vaux)[POS_IN_TORUS (index , size)]);
962
963 #define GD_SWAP(x, y) { gdouble *tmp = *x; *x = *y; *y = tmp; }
964 GD_SWAP (h, hn);
965 GD_SWAP (s, sn);
966 GD_SWAP (v, vn);
967 #undef SWAP
968 }
969
970 #define LOGISTICS(x) logistic_function (param, x, power)
971 #define ENV_FACTOR(x) (param->env_sensitivity * LOGISTICS (x))
972 #define CHN_FACTOR(x) (param->ch_sensitivity * LOGISTICS (x))
973
974 static gdouble
CML_next_value(gdouble * vec,gint pos,gint size,gdouble c1,gdouble c2,CML_PARAM * param,gdouble power)975 CML_next_value (gdouble *vec,
976 gint pos,
977 gint size,
978 gdouble c1,
979 gdouble c2,
980 CML_PARAM *param,
981 gdouble power)
982 {
983 gdouble val = vec[pos];
984 gdouble diff = 0;
985 gdouble self_diff = 0;
986 gdouble by_env = 0;
987 gdouble self_mod_rate = 0;
988 gdouble hold_rate = 1 - param->mod_rate;
989 gdouble env_factor = 0;
990 gint index;
991
992 self_mod_rate = (1 - param->env_sensitivity - param->ch_sensitivity);
993
994 switch (param->arrange)
995 {
996 case ANTILOG:
997 self_diff = self_mod_rate * LOGISTICS (1 - vec[pos]);
998 for (index = 1; index <= param->diffusion_dist / 2; index++)
999 env_factor += ENV_FACTOR (1 - vec[POS_IN_TORUS (pos + index, size)])
1000 + ENV_FACTOR (1 - vec[POS_IN_TORUS (pos - index, size)]);
1001 if ((param->diffusion_dist % 2) == 1)
1002 env_factor += (ENV_FACTOR (1 - vec[POS_IN_TORUS (pos + index, size)])
1003 + ENV_FACTOR (1 - vec[POS_IN_TORUS (pos - index, size)])) / 2;
1004 env_factor /= (gdouble) param->diffusion_dist;
1005 by_env = env_factor + (CHN_FACTOR (1 - c1) + CHN_FACTOR (1 - c2)) / 2;
1006 diff = param->mod_rate * (self_diff + by_env);
1007 val = hold_rate * vec[pos] + diff;
1008 break;
1009 case AVERAGE:
1010 self_diff = self_mod_rate * LOGISTICS (vec[pos]);
1011 for (index = 1; index <= param->diffusion_dist / 2; index++)
1012 env_factor += vec[POS_IN_TORUS (pos + index, size)] + vec[POS_IN_TORUS (pos - index, size)];
1013 if ((param->diffusion_dist % 2) == 1)
1014 env_factor += (vec[POS_IN_TORUS (pos + index, size)] + vec[POS_IN_TORUS (pos - index, size)]) / 2;
1015 env_factor /= (gdouble) param->diffusion_dist;
1016 by_env = ENV_FACTOR (env_factor) + (CHN_FACTOR (c1) + CHN_FACTOR (c2)) / 2;
1017 diff = param->mod_rate * (self_diff + by_env);
1018 val = hold_rate * vec[pos] + diff;
1019 break;
1020 case MULTIPLY_RANDOM0:
1021 case MULTIPLY_RANDOM1:
1022 case MULTIPLY_GRADIENT:
1023 {
1024 gdouble tmp;
1025
1026 tmp = power;
1027 power = param->power;
1028 self_diff = self_mod_rate * LOGISTICS (vec[pos]);
1029 for (index = 1; index <= param->diffusion_dist / 2; index++)
1030 env_factor += ENV_FACTOR (vec[POS_IN_TORUS (pos + index, size)])
1031 + ENV_FACTOR (vec[POS_IN_TORUS (pos - index, size)]);
1032 if ((param->diffusion_dist % 2) == 1)
1033 env_factor += (ENV_FACTOR (vec[POS_IN_TORUS (pos + index, size)])
1034 + ENV_FACTOR (vec[POS_IN_TORUS (pos - index, size)])) / 2;
1035 env_factor /= (gdouble) param->diffusion_dist;
1036 by_env = (env_factor + CHN_FACTOR (c1) + CHN_FACTOR (c2)) / 2;
1037 diff = pow (param->mod_rate * (self_diff + by_env), tmp);
1038 val = hold_rate * vec[pos] + diff;
1039 break;
1040 }
1041 case STANDARD:
1042 case RAND_POWER0:
1043 case RAND_POWER1:
1044 case RAND_POWER2:
1045 case RAND_AND_P:
1046 default:
1047 self_diff = self_mod_rate * LOGISTICS (vec[pos]);
1048
1049 for (index = 1; index <= param->diffusion_dist / 2; index++)
1050 env_factor += ENV_FACTOR (vec[POS_IN_TORUS (pos + index, size)])
1051 + ENV_FACTOR (vec[POS_IN_TORUS (pos - index, size)]);
1052 if ((param->diffusion_dist % 2) == 1)
1053 env_factor += (ENV_FACTOR (vec[POS_IN_TORUS (pos + index, size)])
1054 + ENV_FACTOR (vec[POS_IN_TORUS (pos - index, size)])) / 2;
1055 env_factor /= (gdouble) param->diffusion_dist;
1056 by_env = env_factor + (CHN_FACTOR (c1) + CHN_FACTOR (c2)) / 2;
1057 diff = param->mod_rate * (self_diff + by_env);
1058 val = hold_rate * vec[pos] + diff;
1059 break;
1060 }
1061 /* finalize */
1062 if (g_rand_double (gr) < param->mutation_rate)
1063 {
1064 val += ((g_rand_double (gr) < 0.5) ? -1.0 : 1.0) * param->mutation_dist * g_rand_double (gr);
1065 }
1066 if (param->cyclic_range)
1067 {
1068 if (1.0 < val)
1069 val = val - (int) val;
1070 else if (val < 0.0)
1071 val = val - floor (val);
1072 }
1073 else
1074 /* The range of val should be [0,1], not [0,1).
1075 Cannonization shuold be done in color mapping phase. */
1076 val = CLAMP (val, 0.0, 1);
1077
1078 return val;
1079 }
1080 #undef LOGISTICS
1081 #undef ENV_FACTOR
1082 #undef CHN_FACTOR
1083
1084
1085 static gdouble
logistic_function(CML_PARAM * param,gdouble x,gdouble power)1086 logistic_function (CML_PARAM *param,
1087 gdouble x,
1088 gdouble power)
1089 {
1090 gdouble x1 = x;
1091 gdouble result = 0;
1092 gint n = param->range_num;
1093 gint step;
1094
1095 step = (int) (x * (gdouble) n);
1096 x1 = (x - ((gdouble) step / (gdouble) n)) * n;
1097 switch (param->function)
1098 {
1099 case CML_KEEP_VALUES:
1100 case CML_KEEP_FIRST:
1101 result = x;
1102 return result;
1103 break;
1104 case CML_FILL:
1105 result = CLAMP (param->parameter_k, 0.0, 1.0);
1106 return result;
1107 break;
1108 case CML_LOGIST:
1109 result = param->parameter_k * pow (4 * x1 * (1.0 - x1), power);
1110 break;
1111 case CML_LOGIST_STEP:
1112 result = param->parameter_k * pow (4 * x1 * (1.0 - x1), power);
1113 result = (result + step) / (gdouble) n;
1114 break;
1115 case CML_POWER:
1116 result = param->parameter_k * pow (x1, power);
1117 break;
1118 case CML_POWER_STEP:
1119 result = param->parameter_k * pow (x1, power);
1120 result = (result + step) / (gdouble) n;
1121 break;
1122 case CML_REV_POWER:
1123 result = param->parameter_k * (1 - pow (x1, power));
1124 break;
1125 case CML_REV_POWER_STEP:
1126 result = param->parameter_k * (1 - pow (x1, power));
1127 result = (result + step) / (gdouble) n;
1128 break;
1129 case CML_DELTA:
1130 result = param->parameter_k * 2 * ((x1 < 0.5) ? x1 : (1.0 - x1));
1131 break;
1132 case CML_DELTA_STEP:
1133 result = param->parameter_k * 2 * ((x1 < 0.5) ? x1 : (1.0 - x1));
1134 result = (result + step) / (gdouble) n;
1135 break;
1136 case CML_SIN_CURVE:
1137 if (1.0 < power)
1138 result = 0.5 * (sin (G_PI * ABS (x1 - 0.5) / power) / sin (G_PI * 0.5 / power) + 1);
1139 else
1140 result = 0.5 * (pow (sin (G_PI * ABS (x1 - 0.5)), power) + 1);
1141 if (x1 < 0.5) result = 1 - result;
1142 break;
1143 case CML_SIN_CURVE_STEP:
1144 if (1.0 < power)
1145 result = 0.5 * (sin (G_PI * ABS (x1 - 0.5) / power) / sin (G_PI * 0.5 / power) + 1);
1146 else
1147 result = 0.5 * (pow (sin (G_PI * ABS (x1 - 0.5)), power) + 1);
1148 if (x1 < 0.5) result = 1 - result;
1149 result = (result + step) / (gdouble) n;
1150 break;
1151 }
1152 switch (param->composition)
1153 {
1154 case COMP_NONE:
1155 break;
1156 case COMP_MAX_LINEAR:
1157 result = MAX ((gdouble) x, (gdouble) result);
1158 break;
1159 case COMP_MAX_LINEAR_P1:
1160 result = MAX ((gdouble) x + (gdouble) 1 / (gdouble) 256, (gdouble) result);
1161 break;
1162 case COMP_MAX_LINEAR_P1L:
1163 if (x < 0.5)
1164 result = MAX ((gdouble) x + (gdouble) 1 / (gdouble) 256, (gdouble) result);
1165 break;
1166 case COMP_MAX_LINEAR_P1U:
1167 if (0.5 < x)
1168 result = MAX ((gdouble) x + (gdouble) 1 / (gdouble) 256, (gdouble) result);
1169 break;
1170 case COMP_MAX_LINEAR_M1:
1171 result = MAX ((gdouble) x - (gdouble) 1 / (gdouble) 256, (gdouble) result);
1172 break;
1173 case COMP_MAX_LINEAR_M1L:
1174 if (x < 0.5)
1175 result = MAX ((gdouble) x - (gdouble) 1 / (gdouble) 256, (gdouble) result);
1176 break;
1177 case COMP_MAX_LINEAR_M1U:
1178 if (0.5 < x)
1179 result = MAX ((gdouble) x - (gdouble) 1 / (gdouble) 256, (gdouble) result);
1180 break;
1181 case COMP_MIN_LINEAR:
1182 result = MIN ((gdouble) x, (gdouble) result);
1183 break;
1184 case COMP_MIN_LINEAR_P1:
1185 result = MIN ((gdouble) x + (gdouble) 1 / (gdouble) 256, (gdouble) result);
1186 break;
1187 case COMP_MIN_LINEAR_P1L:
1188 if (x < 0.5)
1189 result = MIN ((gdouble) x + (gdouble) 1 / (gdouble) 256, (gdouble) result);
1190 break;
1191 case COMP_MIN_LINEAR_P1U:
1192 if (0.5 < x)
1193 result = MIN ((gdouble) x + (gdouble) 1 / (gdouble) 256, (gdouble) result);
1194 break;
1195 case COMP_MIN_LINEAR_M1:
1196 result = MIN ((gdouble) x - (gdouble) 1 / (gdouble) 256, (gdouble) result);
1197 break;
1198 case COMP_MIN_LINEAR_M1L:
1199 if (x < 0.5)
1200 result = MIN ((gdouble) x - (gdouble) 1 / (gdouble) 256, (gdouble) result);
1201 break;
1202 case COMP_MIN_LINEAR_M1U:
1203 if (0.5 < x)
1204 result = MIN ((gdouble) x - (gdouble) 1 / (gdouble) 256, (gdouble) result);
1205 break;
1206 }
1207 return result;
1208 }
1209
1210 /* dialog stuff */
1211 static gint
CML_explorer_dialog(void)1212 CML_explorer_dialog (void)
1213 {
1214 GtkWidget *dialog;
1215 GtkWidget *hbox;
1216 GtkWidget *vbox;
1217 GtkWidget *frame;
1218 GtkWidget *abox;
1219 GtkWidget *bbox;
1220 GtkWidget *button;
1221 gboolean run;
1222
1223 gimp_ui_init (PLUG_IN_BINARY, TRUE);
1224
1225 dialog = gimp_dialog_new (_("Coupled-Map-Lattice Explorer"), PLUG_IN_ROLE,
1226 NULL, 0,
1227 gimp_standard_help_func, PLUG_IN_PROC,
1228
1229 _("_Cancel"), GTK_RESPONSE_CANCEL,
1230 _("_OK"), GTK_RESPONSE_OK,
1231
1232 NULL);
1233
1234 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
1235 GTK_RESPONSE_OK,
1236 GTK_RESPONSE_CANCEL,
1237 -1);
1238
1239 gimp_window_set_transient (GTK_WINDOW (dialog));
1240
1241 CML_preview_defer = TRUE;
1242
1243 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1244 gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
1245 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
1246 hbox, FALSE, FALSE, 0);
1247 gtk_widget_show (hbox);
1248
1249 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1250 gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
1251 gtk_widget_show (vbox);
1252
1253 abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1254 gtk_box_pack_start (GTK_BOX (vbox), abox, FALSE, FALSE, 0);
1255 gtk_widget_show (abox);
1256
1257 frame = gtk_frame_new (NULL);
1258 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
1259 gtk_container_add (GTK_CONTAINER (abox), frame);
1260 gtk_widget_show (frame);
1261
1262 preview = gimp_preview_area_new ();
1263 gtk_widget_set_size_request (preview,
1264 PREVIEW_WIDTH, PREVIEW_HEIGHT);
1265 gtk_container_add (GTK_CONTAINER (frame), preview);
1266 gtk_widget_show (preview);
1267
1268 bbox = gtk_button_box_new (GTK_ORIENTATION_VERTICAL);
1269 gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
1270 gtk_widget_show (bbox);
1271
1272 button = gtk_button_new_with_label (_("New Seed"));
1273 gtk_container_add (GTK_CONTAINER (bbox), button);
1274 gtk_widget_show (button);
1275
1276 g_signal_connect (button, "clicked",
1277 G_CALLBACK (CML_preview_update_callback),
1278 &VALS);
1279
1280 random_sensitives[0].widget = button;
1281 random_sensitives[0].logic = TRUE;
1282
1283 button = gtk_button_new_with_label (_("Fix Seed"));
1284 gtk_container_add (GTK_CONTAINER (bbox), button);
1285 gtk_widget_show (button);
1286
1287 g_signal_connect (button, "clicked",
1288 G_CALLBACK (CML_set_or_randomize_seed_callback),
1289 &VALS);
1290
1291 random_sensitives[1].widget = button;
1292 random_sensitives[1].logic = TRUE;
1293
1294 button = gtk_button_new_with_label (_("Random Seed"));
1295 gtk_container_add (GTK_CONTAINER (bbox), button);
1296 gtk_widget_show (button);
1297
1298 g_signal_connect (button, "clicked",
1299 G_CALLBACK (CML_set_or_randomize_seed_callback),
1300 &VALS);
1301
1302 random_sensitives[2].widget = button;
1303 random_sensitives[2].logic = FALSE;
1304
1305 bbox = gtk_button_box_new (GTK_ORIENTATION_VERTICAL);
1306 gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
1307 gtk_widget_show (bbox);
1308
1309 button = gtk_button_new_with_mnemonic (_("_Open"));
1310 gtk_container_add (GTK_CONTAINER (bbox), button);
1311 gtk_widget_show (button);
1312
1313 g_signal_connect (button, "clicked",
1314 G_CALLBACK (CML_load_from_file_callback),
1315 &VALS);
1316
1317 button = gtk_button_new_with_mnemonic (_("_Save"));
1318 gtk_container_add (GTK_CONTAINER (bbox), button);
1319 gtk_widget_show (button);
1320
1321 g_signal_connect (button, "clicked",
1322 G_CALLBACK (CML_save_to_file_callback),
1323 &VALS);
1324
1325 {
1326 GtkWidget *notebook;
1327 GtkWidget *page;
1328
1329 notebook = gtk_notebook_new ();
1330 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
1331 gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
1332 gtk_widget_show (notebook);
1333
1334 page = CML_dialog_channel_panel_new (&VALS.hue, 0);
1335 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page,
1336 gtk_label_new_with_mnemonic (_("_Hue")));
1337
1338 page = CML_dialog_channel_panel_new (&VALS.sat, 1);
1339 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page,
1340 gtk_label_new_with_mnemonic (_("Sat_uration")));
1341
1342 page = CML_dialog_channel_panel_new (&VALS.val, 2);
1343 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page,
1344 gtk_label_new_with_mnemonic (_("_Value")));
1345
1346 page = CML_dialog_advanced_panel_new ();
1347 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page,
1348 gtk_label_new_with_mnemonic (_("_Advanced")));
1349
1350 {
1351 GtkSizeGroup *group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
1352 GtkWidget *table;
1353 GtkWidget *label;
1354 GtkWidget *combo;
1355 GtkWidget *frame;
1356 GtkWidget *vbox;
1357 GtkObject *adj;
1358
1359 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1360 gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
1361 gtk_widget_show (vbox);
1362
1363 frame = gimp_frame_new (_("Channel Independent Parameters"));
1364 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
1365 gtk_widget_show (frame);
1366
1367 table = gtk_table_new (3, 3, FALSE);
1368 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1369 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1370 gtk_container_add (GTK_CONTAINER (frame), table);
1371 gtk_widget_show (table);
1372
1373 combo = gimp_int_combo_box_new_array (CML_INITIAL_NUM_VALUES,
1374 initial_value_names);
1375 gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo),
1376 VALS.initial_value);
1377
1378 g_signal_connect (combo, "changed",
1379 G_CALLBACK (CML_initial_value_menu_update),
1380 &VALS.initial_value);
1381
1382 CML_explorer_menu_entry_init (&widget_pointers[3][0],
1383 combo, &VALS.initial_value);
1384 label = gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
1385 _("Initial value:"), 0.0, 0.5,
1386 combo, 2, FALSE);
1387 gtk_size_group_add_widget (group, label);
1388 g_object_unref (group);
1389
1390 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
1391 _("Zoom scale:"), SCALE_WIDTH, 3,
1392 VALS.scale, 1, 10, 1, 2, 0,
1393 TRUE, 0, 0,
1394 NULL, NULL);
1395 gtk_size_group_add_widget (group, GIMP_SCALE_ENTRY_LABEL (adj));
1396 CML_explorer_int_entry_init (&widget_pointers[3][1],
1397 adj, &VALS.scale);
1398
1399 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
1400 _("Start offset:"), SCALE_WIDTH, 3,
1401 VALS.start_offset, 0, 100, 1, 10, 0,
1402 TRUE, 0, 0,
1403 NULL, NULL);
1404 gtk_size_group_add_widget (group, GIMP_SCALE_ENTRY_LABEL (adj));
1405 CML_explorer_int_entry_init (&widget_pointers[3][2],
1406 adj, &VALS.start_offset);
1407
1408 frame =
1409 gimp_frame_new (_("Seed of Random (only for \"From Seed\" Modes)"));
1410 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
1411 gtk_widget_show (frame);
1412
1413 table = gtk_table_new (2, 3, FALSE);
1414 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1415 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1416 gtk_container_add (GTK_CONTAINER (frame), table);
1417 gtk_widget_show (table);
1418
1419 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
1420 _("Seed:"), SCALE_WIDTH, 0,
1421 VALS.seed, 0, (guint32) -1, 1, 10, 0,
1422 TRUE, 0, 0,
1423 NULL, NULL);
1424 gtk_size_group_add_widget (group, GIMP_SCALE_ENTRY_LABEL (adj));
1425 CML_explorer_int_entry_init (&widget_pointers[3][3],
1426 adj, &VALS.seed);
1427
1428 random_sensitives[3].widget = table;
1429 random_sensitives[3].logic = FALSE;
1430
1431 button =
1432 gtk_button_new_with_label
1433 (_("Switch to \"From seed\" With the Last Seed"));
1434 gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 3, 1, 2);
1435 gtk_widget_show (button);
1436
1437 g_signal_connect (button, "clicked",
1438 G_CALLBACK (CML_set_or_randomize_seed_callback),
1439 &VALS);
1440
1441 random_sensitives[4].widget = button;
1442 random_sensitives[4].logic = TRUE;
1443
1444 gimp_help_set_help_data (button,
1445 _("\"Fix seed\" button is an alias of me.\n"
1446 "The same seed produces the same image, "
1447 "if (1) the widths of images are same "
1448 "(this is the reason why image on drawable "
1449 "is different from preview), and (2) all "
1450 "mutation rates equal to zero."), NULL);
1451
1452 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox,
1453 gtk_label_new_with_mnemonic (_("O_thers")));
1454 }
1455
1456 {
1457 GtkSizeGroup *group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
1458 GtkWidget *table;
1459 GtkWidget *frame;
1460 GtkWidget *label;
1461 GtkWidget *combo;
1462 GtkWidget *vbox;
1463
1464 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1465 gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
1466 gtk_widget_show (vbox);
1467
1468 frame = gimp_frame_new (_("Copy Settings"));
1469 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
1470 gtk_widget_show (frame);
1471
1472 table = gtk_table_new (3, 2, FALSE);
1473 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1474 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1475 gtk_container_add (GTK_CONTAINER (frame), table);
1476 gtk_widget_show (table);
1477
1478 combo = gimp_int_combo_box_new_array (G_N_ELEMENTS (channel_names),
1479 channel_names);
1480 gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), copy_source);
1481
1482 g_signal_connect (combo, "changed",
1483 G_CALLBACK (gimp_int_combo_box_get_active),
1484 ©_source);
1485
1486 label = gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
1487 _("Source channel:"), 0.0, 0.5,
1488 combo, 1, FALSE);
1489 gtk_size_group_add_widget (group, label);
1490 g_object_unref (group);
1491
1492 combo = gimp_int_combo_box_new_array (G_N_ELEMENTS (channel_names),
1493 channel_names);
1494 gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo),
1495 copy_destination);
1496
1497 g_signal_connect (combo, "changed",
1498 G_CALLBACK (gimp_int_combo_box_get_active),
1499 ©_destination);
1500
1501 label = gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
1502 _("Destination channel:"), 0.0, 0.5,
1503 combo, 1, FALSE);
1504 gtk_size_group_add_widget (group, label);
1505
1506 button = gtk_button_new_with_label (_("Copy Parameters"));
1507 gtk_table_attach (GTK_TABLE (table), button, 0, 2, 2, 3,
1508 GTK_SHRINK | GTK_FILL, GTK_SHRINK, 0, 0);
1509 gtk_widget_show (button);
1510
1511 g_signal_connect (button, "clicked",
1512 G_CALLBACK (CML_copy_parameters_callback),
1513 &VALS);
1514
1515 frame = gimp_frame_new (_("Selective Load Settings"));
1516 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
1517 gtk_widget_show (frame);
1518
1519 table = gtk_table_new (2, 2, FALSE);
1520 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1521 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1522 gtk_container_add (GTK_CONTAINER (frame), table);
1523 gtk_widget_show (table);
1524
1525 combo = gimp_int_combo_box_new_array (G_N_ELEMENTS (load_channel_names),
1526 load_channel_names);
1527 gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo),
1528 selective_load_source);
1529
1530 g_signal_connect (combo, "changed",
1531 G_CALLBACK (gimp_int_combo_box_get_active),
1532 &selective_load_source);
1533
1534 label = gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
1535 _("Source channel in file:"),
1536 0.0, 0.5,
1537 combo, 1, FALSE);
1538 gtk_size_group_add_widget (group, label);
1539
1540 combo = gimp_int_combo_box_new_array (G_N_ELEMENTS (load_channel_names),
1541 load_channel_names);
1542 gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo),
1543 selective_load_destination);
1544
1545 g_signal_connect (combo, "changed",
1546 G_CALLBACK (gimp_int_combo_box_get_active),
1547 &selective_load_destination);
1548
1549 label = gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
1550 _("Destination channel:"),
1551 0.0, 0.5,
1552 combo, 1, FALSE);
1553 gtk_size_group_add_widget (group, label);
1554
1555 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox,
1556 gtk_label_new_with_mnemonic (_("_Misc Ops.")));
1557 }
1558 }
1559
1560 CML_initial_value_sensitives_update ();
1561
1562 gtk_widget_show (dialog);
1563
1564 img_stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, GRAPHSIZE);
1565 img = g_malloc0 (img_stride * GRAPHSIZE);
1566
1567 buffer = cairo_image_surface_create_for_data (img, CAIRO_FORMAT_RGB24,
1568 GRAPHSIZE,
1569 GRAPHSIZE,
1570 img_stride);
1571
1572 /* Displaying preview might takes a long time. Thus, first, dialog itself
1573 * should be shown before making preview in it.
1574 */
1575 CML_preview_defer = FALSE;
1576 preview_update ();
1577
1578 run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
1579
1580 gtk_widget_destroy (dialog);
1581 g_free (img);
1582 cairo_surface_destroy (buffer);
1583
1584 return run;
1585 }
1586
1587 static GtkWidget *
CML_dialog_channel_panel_new(CML_PARAM * param,gint channel_id)1588 CML_dialog_channel_panel_new (CML_PARAM *param,
1589 gint channel_id)
1590 {
1591 GtkWidget *table;
1592 GtkWidget *combo;
1593 GtkWidget *toggle;
1594 GtkWidget *button;
1595 GtkObject *adj;
1596 gpointer *chank;
1597 gint index = 0;
1598
1599 table = gtk_table_new (13, 3, FALSE);
1600 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1601 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1602 gtk_container_set_border_width (GTK_CONTAINER (table), 12);
1603 gtk_widget_show (table);
1604
1605 combo = gimp_int_combo_box_new_array (CML_NUM_VALUES, function_names);
1606 gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), param->function);
1607
1608 g_signal_connect (combo, "changed",
1609 G_CALLBACK (CML_explorer_menu_update),
1610 ¶m->function);
1611
1612 CML_explorer_menu_entry_init (&widget_pointers[channel_id][index],
1613 combo, ¶m->function);
1614 gimp_table_attach_aligned (GTK_TABLE (table), 0, index,
1615 _("Function type:"), 0.0, 0.5,
1616 combo, 2, FALSE);
1617 index++;
1618
1619 combo = gimp_int_combo_box_new_array (COMP_NUM_VALUES, composition_names);
1620
1621 gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo),
1622 param->composition);
1623
1624 g_signal_connect (combo, "changed",
1625 G_CALLBACK (CML_explorer_menu_update),
1626 ¶m->composition);
1627
1628 CML_explorer_menu_entry_init (&widget_pointers[channel_id][index],
1629 combo, ¶m->composition);
1630 gimp_table_attach_aligned (GTK_TABLE (table), 0, index,
1631 _("Composition:"), 0.0, 0.5,
1632 combo, 2, FALSE);
1633 index++;
1634
1635 combo = gimp_int_combo_box_new_array (ARRANGE_NUM_VALUES, arrange_names);
1636 gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), param->arrange);
1637
1638 g_signal_connect (combo, "changed",
1639 G_CALLBACK (CML_explorer_menu_update),
1640 ¶m->arrange);
1641
1642 CML_explorer_menu_entry_init (&widget_pointers[channel_id][index],
1643 combo, ¶m->arrange);
1644 gimp_table_attach_aligned (GTK_TABLE (table), 0, index,
1645 _("Misc arrange:"), 0.0, 0.5,
1646 combo, 2, FALSE);
1647 index++;
1648
1649 toggle = gtk_check_button_new_with_label (_("Use cyclic range"));
1650 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
1651 param->cyclic_range);
1652 gtk_table_attach_defaults (GTK_TABLE (table), toggle, 0, 3, index, index + 1);
1653 CML_explorer_toggle_entry_init (&widget_pointers[channel_id][index],
1654 toggle, ¶m->cyclic_range);
1655 gtk_widget_show (toggle);
1656 index++;
1657
1658 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, index,
1659 _("Mod. rate:"), SCALE_WIDTH, 5,
1660 param->mod_rate, 0.0, 1.0, 0.01, 0.1, 2,
1661 TRUE, 0, 0,
1662 NULL, NULL);
1663 CML_explorer_double_entry_init (&widget_pointers[channel_id][index],
1664 adj, ¶m->mod_rate);
1665 index++;
1666
1667 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, index,
1668 _("Env. sensitivity:"), SCALE_WIDTH, 5,
1669 param->env_sensitivity, 0.0, 1.0, 0.01, 0.1, 2,
1670 TRUE, 0, 0,
1671 NULL, NULL);
1672 CML_explorer_double_entry_init (&widget_pointers[channel_id][index],
1673 adj, ¶m->env_sensitivity);
1674 index++;
1675
1676 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, index,
1677 _("Diffusion dist.:"), SCALE_WIDTH, 5,
1678 param->diffusion_dist, 2, 10, 1, 2, 0,
1679 TRUE, 0, 0,
1680 NULL, NULL);
1681 CML_explorer_int_entry_init (&widget_pointers[channel_id][index],
1682 adj, ¶m->diffusion_dist);
1683 index++;
1684
1685 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, index,
1686 _("# of subranges:"), SCALE_WIDTH, 5,
1687 param->range_num, 1, 10, 1, 2, 0,
1688 TRUE, 0, 0,
1689 NULL, NULL);
1690 CML_explorer_int_entry_init (&widget_pointers[channel_id][index],
1691 adj, ¶m->range_num);
1692 index++;
1693
1694 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, index,
1695 _("P(ower factor):"), SCALE_WIDTH, 5,
1696 param->power, 0.0, 10.0, 0.1, 1.0, 2,
1697 TRUE, 0, 0,
1698 NULL, NULL);
1699 CML_explorer_double_entry_init (&widget_pointers[channel_id][index],
1700 adj, ¶m->power);
1701 index++;
1702
1703 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, index,
1704 _("Parameter k:"), SCALE_WIDTH, 5,
1705 param->parameter_k, 0.0, 10.0, 0.1, 1.0, 2,
1706 TRUE, 0, 0,
1707 NULL, NULL);
1708 CML_explorer_double_entry_init (&widget_pointers[channel_id][index],
1709 adj, ¶m->parameter_k);
1710 index++;
1711
1712 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, index,
1713 _("Range low:"), SCALE_WIDTH, 5,
1714 param->range_l, 0.0, 1.0, 0.01, 0.1, 2,
1715 TRUE, 0, 0,
1716 NULL, NULL);
1717 CML_explorer_double_entry_init (&widget_pointers[channel_id][index],
1718 adj, ¶m->range_l);
1719 index++;
1720
1721 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, index,
1722 _("Range high:"), SCALE_WIDTH, 5,
1723 param->range_h, 0.0, 1.0, 0.01, 0.1, 2,
1724 TRUE, 0, 0,
1725 NULL, NULL);
1726 CML_explorer_double_entry_init (&widget_pointers[channel_id][index],
1727 adj, ¶m->range_h);
1728 index++;
1729
1730 chank = g_new (gpointer, 2);
1731 chank[0] = GINT_TO_POINTER (channel_id);
1732 chank[1] = param;
1733
1734 button = gtk_button_new_with_label (_("Plot a Graph of the Settings"));
1735 gtk_table_attach_defaults (GTK_TABLE (table), button,
1736 0, 3, index, index + 1);
1737 gtk_widget_show (button);
1738
1739 g_signal_connect (button, "clicked",
1740 G_CALLBACK (function_graph_new),
1741 chank);
1742 return table;
1743 }
1744
1745 static GtkWidget *
CML_dialog_advanced_panel_new(void)1746 CML_dialog_advanced_panel_new (void)
1747 {
1748 GtkWidget *vbox;
1749 GtkWidget *subframe;
1750 GtkWidget *table;
1751 GtkObject *adj;
1752
1753 gint index = 0;
1754 gint widget_offset = 12;
1755 gint channel_id;
1756 CML_PARAM *param;
1757
1758 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1759 gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
1760 gtk_widget_show (vbox);
1761
1762 for (channel_id = 0; channel_id < 3; channel_id++)
1763 {
1764 param = (CML_PARAM *)&VALS + channel_id;
1765
1766 subframe = gimp_frame_new (gettext (channel_names[channel_id]));
1767 gtk_box_pack_start (GTK_BOX (vbox), subframe, FALSE, FALSE, 0);
1768 gtk_widget_show (subframe);
1769
1770 table = gtk_table_new (3, 3, FALSE);
1771 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1772 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1773 gtk_container_add (GTK_CONTAINER (subframe), table);
1774 gtk_widget_show (table);
1775
1776 index = 0;
1777
1778 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, index,
1779 _("Ch. sensitivity:"), SCALE_WIDTH, 0,
1780 param->ch_sensitivity, 0.0, 1.0, 0.01, 0.1, 2,
1781 TRUE, 0, 0,
1782 NULL, NULL);
1783 CML_explorer_double_entry_init (&widget_pointers[channel_id][index +
1784 widget_offset],
1785 adj, ¶m->ch_sensitivity);
1786 index++;
1787
1788 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, index,
1789 _("Mutation rate:"), SCALE_WIDTH, 0,
1790 param->mutation_rate, 0.0, 1.0, 0.01, 0.1, 2,
1791 TRUE, 0, 0,
1792 NULL, NULL);
1793 CML_explorer_double_entry_init (&widget_pointers[channel_id][index +
1794 widget_offset],
1795 adj, ¶m->mutation_rate);
1796 index++;
1797
1798 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, index,
1799 _("Mutation dist.:"), SCALE_WIDTH, 0,
1800 param->mutation_dist, 0.0, 1.0, 0.01, 0.1, 2,
1801 TRUE, 0, 0,
1802 NULL, NULL);
1803 CML_explorer_double_entry_init (&widget_pointers[channel_id][index +
1804 widget_offset],
1805 adj, ¶m->mutation_dist);
1806 }
1807 return vbox;
1808 }
1809
1810 static void
preview_update(void)1811 preview_update (void)
1812 {
1813 if (! CML_preview_defer)
1814 CML_main_function (TRUE);
1815 }
1816
1817 static gboolean
function_graph_expose(GtkWidget * widget,GdkEventExpose * event,gpointer * data)1818 function_graph_expose (GtkWidget *widget,
1819 GdkEventExpose *event,
1820 gpointer *data)
1821 {
1822 GtkStyle *style = gtk_widget_get_style (widget);
1823 gint x, y;
1824 gint rgbi[3];
1825 gint channel_id = GPOINTER_TO_INT (data[0]);
1826 CML_PARAM *param = data[1];
1827 cairo_t *cr;
1828
1829 cr = gdk_cairo_create (gtk_widget_get_window (widget));
1830
1831 gdk_cairo_region (cr, event->region);
1832 cairo_clip (cr);
1833
1834 cairo_set_line_width (cr, 1.0);
1835
1836 cairo_surface_flush (buffer);
1837
1838 for (x = 0; x < GRAPHSIZE; x++)
1839 {
1840 /* hue */
1841 rgbi[0] = rgbi[1] = rgbi[2] = 127;
1842 if ((0 <= channel_id) && (channel_id <= 2))
1843 rgbi[channel_id] = CANNONIZE ((*param), ((gdouble) x / (gdouble) 255));
1844 gimp_hsv_to_rgb_int (rgbi, rgbi+1, rgbi+2);
1845 for (y = 0; y < GRAPHSIZE; y++)
1846 {
1847 GIMP_CAIRO_RGB24_SET_PIXEL((img+(y*img_stride+x*4)),
1848 rgbi[0],
1849 rgbi[1],
1850 rgbi[2]);
1851 }
1852 }
1853
1854 cairo_surface_mark_dirty (buffer);
1855
1856 cairo_set_source_surface (cr, buffer, 0.0, 0.0);
1857
1858 cairo_paint (cr);
1859 cairo_translate (cr, 0.5, 0.5);
1860
1861 cairo_move_to (cr, 0, 255);
1862 cairo_line_to (cr, 255, 0);
1863 gdk_cairo_set_source_color (cr, &style->white);
1864 cairo_stroke (cr);
1865
1866 y = 255 * CLAMP (logistic_function (param, 0, param->power),
1867 0, 1.0);
1868 cairo_move_to (cr, 0, 255-y);
1869 for (x = 0; x < GRAPHSIZE; x++)
1870 {
1871 /* curve */
1872 y = 255 * CLAMP (logistic_function (param, x/(gdouble)255, param->power),
1873 0, 1.0);
1874 cairo_line_to (cr, x, 255-y);
1875 }
1876
1877 gdk_cairo_set_source_color (cr, &style->black);
1878 cairo_stroke (cr);
1879 cairo_destroy (cr);
1880
1881 return TRUE;
1882 }
1883
1884 static void
function_graph_new(GtkWidget * widget,gpointer * data)1885 function_graph_new (GtkWidget *widget,
1886 gpointer *data)
1887 {
1888 GtkWidget *dialog;
1889 GtkWidget *frame;
1890 GtkWidget *preview;
1891
1892 dialog = gimp_dialog_new (_("Graph of the Current Settings"), PLUG_IN_ROLE,
1893 gtk_widget_get_toplevel (widget), 0,
1894 gimp_standard_help_func, PLUG_IN_PROC,
1895
1896 _("_Close"), GTK_RESPONSE_CLOSE,
1897
1898 NULL);
1899
1900 frame = gtk_frame_new (NULL);
1901 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
1902 gtk_container_set_border_width (GTK_CONTAINER (frame), 12);
1903 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
1904 frame, FALSE, FALSE, 0);
1905 gtk_widget_show (frame);
1906
1907 preview = gtk_drawing_area_new ();
1908 gtk_widget_set_size_request (preview, GRAPHSIZE, GRAPHSIZE);
1909 gtk_container_add (GTK_CONTAINER (frame), preview);
1910 gtk_widget_show (preview);
1911 g_signal_connect (preview, "expose-event",
1912 G_CALLBACK (function_graph_expose), data);
1913
1914 gtk_widget_show (dialog);
1915
1916 gimp_dialog_run (GIMP_DIALOG (dialog));
1917
1918 gtk_widget_destroy (dialog);
1919 }
1920
1921 static void
CML_set_or_randomize_seed_callback(GtkWidget * widget,gpointer data)1922 CML_set_or_randomize_seed_callback (GtkWidget *widget,
1923 gpointer data)
1924 {
1925 CML_preview_defer = TRUE;
1926
1927 switch (VALS.initial_value)
1928 {
1929 case CML_INITIAL_RANDOM_INDEPENDENT:
1930 VALS.initial_value = CML_INITIAL_RANDOM_FROM_SEED;
1931 break;
1932 case CML_INITIAL_RANDOM_SHARED:
1933 VALS.initial_value = CML_INITIAL_RANDOM_FROM_SEED_SHARED;
1934 break;
1935 case CML_INITIAL_RANDOM_FROM_SEED:
1936 VALS.initial_value = CML_INITIAL_RANDOM_INDEPENDENT;
1937 break;
1938 case CML_INITIAL_RANDOM_FROM_SEED_SHARED:
1939 VALS.initial_value = CML_INITIAL_RANDOM_SHARED;
1940 break;
1941 default:
1942 break;
1943 }
1944 if (widget_pointers[3][3].widget && widget_pointers[3][3].updater)
1945 (widget_pointers[3][3].updater) (widget_pointers[3]+3);
1946 if (widget_pointers[3][0].widget && widget_pointers[3][0].updater)
1947 (widget_pointers[3][0].updater) (widget_pointers[3]);
1948
1949 CML_initial_value_sensitives_update ();
1950
1951 CML_preview_defer = FALSE;
1952 }
1953
1954 static void
CML_copy_parameters_callback(GtkWidget * widget,gpointer data)1955 CML_copy_parameters_callback (GtkWidget *widget,
1956 gpointer data)
1957 {
1958 gint index;
1959 WidgetEntry *widgets;
1960
1961 if (copy_source == copy_destination)
1962 {
1963 g_message (_("Warning: the source and the destination are the same channel."));
1964 return;
1965 }
1966 *channel_params[copy_destination] = *channel_params[copy_source];
1967 CML_preview_defer = TRUE;
1968 widgets = widget_pointers[copy_destination];
1969
1970 for (index = 0; index < CML_PARAM_NUM; index++)
1971 if (widgets[index].widget && widgets[index].updater)
1972 (widgets[index].updater) (widgets + index);
1973
1974 CML_preview_defer = FALSE;
1975 preview_update ();
1976 }
1977
1978 static void
CML_initial_value_sensitives_update(void)1979 CML_initial_value_sensitives_update (void)
1980 {
1981 gint i = 0;
1982 gint flag1, flag2;
1983
1984 flag1 = (CML_INITIAL_RANDOM_INDEPENDENT <= VALS.initial_value)
1985 & (VALS.initial_value <= CML_INITIAL_RANDOM_FROM_SEED_SHARED);
1986 flag2 = (CML_INITIAL_RANDOM_INDEPENDENT <= VALS.initial_value)
1987 & (VALS.initial_value <= CML_INITIAL_RANDOM_SHARED);
1988
1989 for (; i < G_N_ELEMENTS (random_sensitives) ; i++)
1990 if (random_sensitives[i].widget)
1991 gtk_widget_set_sensitive (random_sensitives[i].widget,
1992 flag1 & (random_sensitives[i].logic == flag2));
1993 }
1994
1995 static void
CML_preview_update_callback(GtkWidget * widget,gpointer data)1996 CML_preview_update_callback (GtkWidget *widget,
1997 gpointer data)
1998 {
1999 WidgetEntry seed_widget = widget_pointers[3][3];
2000
2001 preview_update ();
2002
2003 CML_preview_defer = TRUE;
2004
2005 if (seed_widget.widget && seed_widget.updater)
2006 seed_widget.updater (&seed_widget);
2007
2008 CML_preview_defer = FALSE;
2009 }
2010
2011 /* parameter file saving functions */
2012
2013 static void
CML_save_to_file_callback(GtkWidget * widget,gpointer data)2014 CML_save_to_file_callback (GtkWidget *widget,
2015 gpointer data)
2016 {
2017 static GtkWidget *dialog = NULL;
2018
2019 if (! dialog)
2020 {
2021 dialog =
2022 gtk_file_chooser_dialog_new (_("Save CML Explorer Parameters"),
2023 GTK_WINDOW (gtk_widget_get_toplevel (widget)),
2024 GTK_FILE_CHOOSER_ACTION_SAVE,
2025
2026 _("_Cancel"), GTK_RESPONSE_CANCEL,
2027 _("_Save"), GTK_RESPONSE_OK,
2028
2029 NULL);
2030
2031 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
2032 GTK_RESPONSE_OK,
2033 GTK_RESPONSE_CANCEL,
2034 -1);
2035 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2036
2037 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
2038 TRUE);
2039
2040 g_signal_connect (dialog, "response",
2041 G_CALLBACK (CML_save_to_file_response),
2042 NULL);
2043 g_signal_connect (dialog, "delete-event",
2044 G_CALLBACK (gtk_true),
2045 NULL);
2046 }
2047
2048 if (strlen (VALS.last_file_name))
2049 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog),
2050 VALS.last_file_name);
2051
2052 gtk_window_present (GTK_WINDOW (dialog));
2053 }
2054
2055 static void
CML_save_to_file_response(GtkWidget * dialog,gint response_id,gpointer data)2056 CML_save_to_file_response (GtkWidget *dialog,
2057 gint response_id,
2058 gpointer data)
2059 {
2060 gchar *filename;
2061 FILE *file;
2062 gint channel_id;
2063
2064 if (response_id != GTK_RESPONSE_OK)
2065 {
2066 gtk_widget_hide (dialog);
2067 return;
2068 }
2069
2070 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
2071 if (! filename)
2072 return;
2073
2074 file = g_fopen (filename, "wb");
2075
2076 if (! file)
2077 {
2078 g_message (_("Could not open '%s' for writing: %s"),
2079 gimp_filename_to_utf8 (filename), g_strerror (errno));
2080 g_free (filename);
2081 return;
2082 }
2083
2084 fprintf (file, "; This is a parameter file for CML_explorer\n");
2085 fprintf (file, "; File format version: %1.1f\n", PARAM_FILE_FORMAT_VERSION);
2086 fprintf (file, ";\n");
2087
2088 for (channel_id = 0; channel_id < 3; channel_id++)
2089 {
2090 gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
2091
2092 CML_PARAM param = *(CML_PARAM *)(channel_params[channel_id]);
2093
2094 fprintf (file, "\t%s\n", channel_names[channel_id]);
2095 fprintf (file, "Function_type : %d (%s)\n",
2096 param.function, function_names[param.function]);
2097 fprintf (file, "Compostion_type : %d (%s)\n",
2098 param.composition, composition_names[param.composition]);
2099 fprintf (file, "Arrange : %d (%s)\n",
2100 param.arrange, arrange_names[param.arrange]);
2101 fprintf (file, "Cyclic_range : %d (%s)\n",
2102 param.cyclic_range, (param.cyclic_range ? "TRUE" : "FALSE"));
2103 fprintf (file, "Mod. rate : %s\n",
2104 g_ascii_dtostr (buf, sizeof (buf), param.mod_rate));
2105 fprintf (file, "Env_sensitivtiy : %s\n",
2106 g_ascii_dtostr (buf, sizeof (buf), param.env_sensitivity));
2107 fprintf (file, "Diffusion dist. : %d\n", param.diffusion_dist);
2108 fprintf (file, "Ch. sensitivity : %s\n",
2109 g_ascii_dtostr (buf, sizeof (buf), param.ch_sensitivity));
2110 fprintf (file, "Num. of Subranges: %d\n", param.range_num);
2111 fprintf (file, "Power_factor : %s\n",
2112 g_ascii_dtostr (buf, sizeof (buf), param.power));
2113 fprintf (file, "Parameter_k : %s\n",
2114 g_ascii_dtostr (buf, sizeof (buf), param.parameter_k));
2115 fprintf (file, "Range_low : %s\n",
2116 g_ascii_dtostr (buf, sizeof (buf), param.range_l));
2117 fprintf (file, "Range_high : %s\n",
2118 g_ascii_dtostr (buf, sizeof (buf), param.range_h));
2119 fprintf (file, "Mutation_rate : %s\n",
2120 g_ascii_dtostr (buf, sizeof (buf), param.mutation_rate));
2121 fprintf (file, "Mutation_distance: %s\n",
2122 g_ascii_dtostr (buf, sizeof (buf), param.mutation_dist));
2123 }
2124
2125 fprintf (file, "\n");
2126 fprintf (file, "Initial value : %d (%s)\n",
2127 VALS.initial_value, initial_value_names[VALS.initial_value]);
2128 fprintf (file, "Zoom scale : %d\n", VALS.scale);
2129 fprintf (file, "Start offset : %d\n", VALS.start_offset);
2130 fprintf (file, "Random seed : %d\n", VALS.seed);
2131 fclose(file);
2132
2133 g_message (_("Parameters were saved to '%s'"),
2134 gimp_filename_to_utf8 (filename));
2135
2136 strncpy (VALS.last_file_name, filename,
2137 sizeof (VALS.last_file_name) - 1);
2138
2139 g_free (filename);
2140
2141 gtk_widget_hide (dialog);
2142 }
2143
2144 /* parameter file loading functions */
2145
2146 static void
CML_load_from_file_callback(GtkWidget * widget,gpointer data)2147 CML_load_from_file_callback (GtkWidget *widget,
2148 gpointer data)
2149 {
2150 static GtkWidget *dialog = NULL;
2151
2152 if (! dialog)
2153 {
2154 dialog =
2155 gtk_file_chooser_dialog_new (_("Load CML Explorer Parameters"),
2156 GTK_WINDOW (gtk_widget_get_toplevel (widget)),
2157 GTK_FILE_CHOOSER_ACTION_OPEN,
2158
2159 _("_Cancel"), GTK_RESPONSE_CANCEL,
2160 _("_Open"), GTK_RESPONSE_OK,
2161
2162 NULL);
2163
2164 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
2165 GTK_RESPONSE_OK,
2166 GTK_RESPONSE_CANCEL,
2167 -1);
2168
2169 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2170
2171 g_signal_connect (dialog, "response",
2172 G_CALLBACK (CML_load_from_file_response),
2173 NULL);
2174 g_signal_connect (dialog, "delete-event",
2175 G_CALLBACK (gtk_true),
2176 NULL);
2177 }
2178
2179 if (strlen (VALS.last_file_name) > 0)
2180 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog),
2181 VALS.last_file_name);
2182
2183 gtk_window_present (GTK_WINDOW (dialog));
2184 }
2185
2186 static void
CML_load_from_file_response(GtkWidget * dialog,gint response_id,gpointer data)2187 CML_load_from_file_response (GtkWidget *dialog,
2188 gint response_id,
2189 gpointer data)
2190 {
2191 if (response_id == GTK_RESPONSE_OK)
2192 {
2193 gchar *filename;
2194 gint channel_id;
2195 gboolean flag = TRUE;
2196
2197 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
2198
2199 gtk_widget_set_sensitive (dialog, FALSE);
2200 flag = CML_load_parameter_file (filename, TRUE);
2201
2202 g_free (filename);
2203
2204 if (flag)
2205 {
2206 WidgetEntry *widgets;
2207 gint index;
2208
2209 CML_preview_defer = TRUE;
2210
2211 for (channel_id = 0; channel_id < 3; channel_id++)
2212 {
2213 widgets = widget_pointers[channel_id];
2214 for (index = 0; index < CML_PARAM_NUM; index++)
2215 if (widgets[index].widget && widgets[index].updater)
2216 (widgets[index].updater) (widgets + index);
2217 }
2218 /* channel independent parameters */
2219 widgets = widget_pointers[3];
2220 for (index = 0; index < 4; index++)
2221 if (widgets[index].widget && widgets[index].updater)
2222 (widgets[index].updater) (widgets + index);
2223
2224 CML_preview_defer = FALSE;
2225
2226 preview_update ();
2227 }
2228 }
2229
2230 gtk_widget_hide (GTK_WIDGET (dialog));
2231 }
2232
2233 static gboolean
CML_load_parameter_file(const gchar * filename,gboolean interactive_mode)2234 CML_load_parameter_file (const gchar *filename,
2235 gboolean interactive_mode)
2236 {
2237 FILE *file;
2238 gint channel_id;
2239 gboolean flag = TRUE;
2240 CML_PARAM ch[3];
2241 gint initial_value = 0;
2242 gint scale = 1;
2243 gint start_offset = 0;
2244 gint seed = 0;
2245 gint old2new_function_id[] = { 3, 4, 5, 6, 7, 9, 10, 11, 1, 2 };
2246
2247 file = g_fopen (filename, "rb");
2248
2249 if (!file)
2250 {
2251 g_message (_("Could not open '%s' for reading: %s"),
2252 gimp_filename_to_utf8 (filename), g_strerror (errno));
2253 return FALSE;
2254 }
2255 else
2256 {
2257 gchar line[CML_LINE_SIZE];
2258 gdouble version = 0.99;
2259
2260 version = parse_line_to_gdouble (file, &flag); /* old format returns 1 */
2261 if (version == 1.0)
2262 version = 0.99;
2263 else if (! flag)
2264 {
2265 flag = TRUE;
2266 version = parse_line_to_gdouble (file, &flag); /* maybe new format */
2267 if (flag)
2268 fgets (line, CML_LINE_SIZE - 1, file); /* one more comment line */
2269 }
2270 if (version == 0)
2271 {
2272 if (interactive_mode)
2273 gimp_message (_("Error: it's not CML parameter file."));
2274 fclose(file);
2275 return FALSE;
2276 }
2277 if (interactive_mode)
2278 {
2279 if (version < PARAM_FILE_FORMAT_VERSION)
2280 g_message (_("Warning: '%s' is an old format file."),
2281 gimp_filename_to_utf8 (filename));
2282
2283 if (PARAM_FILE_FORMAT_VERSION < version)
2284 g_message (_("Warning: '%s' is a parameter file for a newer "
2285 "version of CML Explorer."),
2286 gimp_filename_to_utf8 (filename));
2287 }
2288 for (channel_id = 0; flag && (channel_id < 3); channel_id++)
2289 {
2290 /* patched by Tim Mooney <mooney@dogbert.cc.ndsu.NoDak.edu> */
2291 if (fgets (line, CML_LINE_SIZE - 1, file) == NULL) /* skip channel name */
2292 {
2293 flag = FALSE;
2294 break;
2295 }
2296 ch[channel_id].function = parse_line_to_gint (file, &flag);
2297 if (version < 1.0)
2298 ch[channel_id].function = old2new_function_id [ch[channel_id].function];
2299 if (1.0 <= version)
2300 ch[channel_id].composition = parse_line_to_gint (file, &flag);
2301 else
2302 ch[channel_id].composition = COMP_NONE;
2303 ch[channel_id].arrange = parse_line_to_gint (file, &flag);
2304 ch[channel_id].cyclic_range = parse_line_to_gint (file, &flag);
2305 ch[channel_id].mod_rate = parse_line_to_gdouble (file, &flag);
2306 ch[channel_id].env_sensitivity = parse_line_to_gdouble (file, &flag);
2307 if (1.0 <= version)
2308 ch[channel_id].diffusion_dist = parse_line_to_gint (file, &flag);
2309 else
2310 ch[channel_id].diffusion_dist = 2;
2311 ch[channel_id].ch_sensitivity = parse_line_to_gdouble (file, &flag);
2312 ch[channel_id].range_num = parse_line_to_gint (file, &flag);
2313 ch[channel_id].power = parse_line_to_gdouble (file, &flag);
2314 ch[channel_id].parameter_k = parse_line_to_gdouble (file, &flag);
2315 ch[channel_id].range_l = parse_line_to_gdouble (file, &flag);
2316 ch[channel_id].range_h = parse_line_to_gdouble (file, &flag);
2317 ch[channel_id].mutation_rate = parse_line_to_gdouble (file, &flag);
2318 ch[channel_id].mutation_dist = parse_line_to_gdouble (file, &flag);
2319 }
2320 if (flag)
2321 {
2322 gint dummy;
2323
2324 if (fgets (line, CML_LINE_SIZE - 1, file) == NULL) /* skip a line */
2325 dummy = 1;
2326 else
2327 {
2328 initial_value = parse_line_to_gint (file, &dummy);
2329 scale = parse_line_to_gint (file, &dummy);
2330 start_offset = parse_line_to_gint (file, &dummy);
2331 seed = parse_line_to_gint (file, &dummy);
2332 }
2333 if (! dummy)
2334 {
2335 initial_value = 0;
2336 scale = 1;
2337 start_offset = 0;
2338 seed = 0;
2339 }
2340 }
2341 fclose (file);
2342 }
2343
2344 if (! flag)
2345 {
2346 if (interactive_mode)
2347 gimp_message (_("Error: failed to load parameters"));
2348 }
2349 else
2350 {
2351 if ((selective_load_source == 0) || (selective_load_destination == 0))
2352 {
2353 VALS.hue = ch[0];
2354 VALS.sat = ch[1];
2355 VALS.val = ch[2];
2356
2357 VALS.initial_value = initial_value;
2358 VALS.scale = scale;
2359 VALS.start_offset = start_offset;
2360 VALS.seed = seed;
2361 }
2362 else
2363 {
2364 memcpy ((CML_PARAM *)&VALS + (selective_load_destination - 1),
2365 (void *)&ch[selective_load_source - 1],
2366 sizeof (CML_PARAM));
2367 }
2368
2369 strncpy (VALS.last_file_name, filename,
2370 sizeof (VALS.last_file_name) - 1);
2371 }
2372 return flag;
2373 }
2374
2375 static gint
parse_line_to_gint(FILE * file,gboolean * flag)2376 parse_line_to_gint (FILE *file,
2377 gboolean *flag)
2378 {
2379 gchar line[CML_LINE_SIZE];
2380 gchar *str;
2381
2382 if (! *flag)
2383 return 0;
2384 if (fgets (line, CML_LINE_SIZE - 1, file) == NULL)
2385 {
2386 *flag = FALSE; /* set FALSE if fail to parse */
2387 return 0;
2388 }
2389 str = &line[0];
2390 while (*str != ':')
2391 if (*str == '\000')
2392 {
2393 *flag = FALSE;
2394 return 0;
2395 }
2396 else
2397 {
2398 str++;
2399 }
2400
2401 return atoi (str + 1);
2402 }
2403
2404 static gdouble
parse_line_to_gdouble(FILE * file,gboolean * flag)2405 parse_line_to_gdouble (FILE *file,
2406 gboolean *flag)
2407 {
2408 gchar line[CML_LINE_SIZE];
2409 gchar *str;
2410
2411 if (! *flag)
2412 return 0.0;
2413
2414 if (fgets (line, CML_LINE_SIZE - 1, file) == NULL)
2415 {
2416 *flag = FALSE; /* set FALSE if fail to parse */
2417 return 0.0;
2418 }
2419 str = &line[0];
2420 while (*str != ':')
2421 if (*str == '\000')
2422 {
2423 *flag = FALSE;
2424 return 0.0;
2425 }
2426 else
2427 {
2428 str++;
2429 }
2430
2431 return g_ascii_strtod (str + 1, NULL);
2432 }
2433
2434
2435 /* toggle button functions */
2436
2437 static void
CML_explorer_toggle_update(GtkWidget * widget,gpointer data)2438 CML_explorer_toggle_update (GtkWidget *widget,
2439 gpointer data)
2440 {
2441 gimp_toggle_button_update (widget, data);
2442
2443 preview_update ();
2444 }
2445
2446 static void
CML_explorer_toggle_entry_change_value(WidgetEntry * widget_entry)2447 CML_explorer_toggle_entry_change_value (WidgetEntry *widget_entry)
2448 {
2449 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget_entry->widget),
2450 *(gint *) (widget_entry->value));
2451 }
2452
2453 static void
CML_explorer_toggle_entry_init(WidgetEntry * widget_entry,GtkWidget * widget,gpointer value_ptr)2454 CML_explorer_toggle_entry_init (WidgetEntry *widget_entry,
2455 GtkWidget *widget,
2456 gpointer value_ptr)
2457 {
2458 g_signal_connect (widget, "toggled",
2459 G_CALLBACK (CML_explorer_toggle_update),
2460 value_ptr);
2461
2462 widget_entry->widget = widget;
2463 widget_entry->value = value_ptr;
2464 widget_entry->updater = CML_explorer_toggle_entry_change_value;
2465 }
2466
2467 /* int adjustment functions */
2468
2469 static void
CML_explorer_int_adjustment_update(GtkAdjustment * adjustment,gpointer data)2470 CML_explorer_int_adjustment_update (GtkAdjustment *adjustment,
2471 gpointer data)
2472 {
2473 gimp_int_adjustment_update (adjustment, data);
2474
2475 preview_update ();
2476 }
2477
2478 static void
CML_explorer_int_entry_change_value(WidgetEntry * widget_entry)2479 CML_explorer_int_entry_change_value (WidgetEntry *widget_entry)
2480 {
2481 GtkAdjustment *adjustment = (GtkAdjustment *) (widget_entry->widget);
2482
2483 gtk_adjustment_set_value (adjustment, *(gint *) (widget_entry->value));
2484 }
2485
2486 static void
CML_explorer_int_entry_init(WidgetEntry * widget_entry,GtkObject * adjustment,gpointer value_ptr)2487 CML_explorer_int_entry_init (WidgetEntry *widget_entry,
2488 GtkObject *adjustment,
2489 gpointer value_ptr)
2490 {
2491 g_signal_connect (adjustment, "value-changed",
2492 G_CALLBACK (CML_explorer_int_adjustment_update),
2493 value_ptr);
2494
2495 widget_entry->widget = (GtkWidget *) adjustment;
2496 widget_entry->value = value_ptr;
2497 widget_entry->updater = CML_explorer_int_entry_change_value;
2498 }
2499
2500 /* double adjustment functions */
2501
2502 static void
CML_explorer_double_adjustment_update(GtkAdjustment * adjustment,gpointer data)2503 CML_explorer_double_adjustment_update (GtkAdjustment *adjustment,
2504 gpointer data)
2505 {
2506 gimp_double_adjustment_update (adjustment, data);
2507
2508 preview_update ();
2509 }
2510
2511 static void
CML_explorer_double_entry_change_value(WidgetEntry * widget_entry)2512 CML_explorer_double_entry_change_value (WidgetEntry *widget_entry)
2513 {
2514 GtkAdjustment *adjustment = (GtkAdjustment *) (widget_entry->widget);
2515
2516 gtk_adjustment_set_value (adjustment, *(gdouble *) (widget_entry->value));
2517 }
2518
2519 static void
CML_explorer_double_entry_init(WidgetEntry * widget_entry,GtkObject * adjustment,gpointer value_ptr)2520 CML_explorer_double_entry_init (WidgetEntry *widget_entry,
2521 GtkObject *adjustment,
2522 gpointer value_ptr)
2523 {
2524 g_signal_connect (adjustment, "value-changed",
2525 G_CALLBACK (CML_explorer_double_adjustment_update),
2526 value_ptr);
2527
2528 widget_entry->widget = (GtkWidget *) adjustment;
2529 widget_entry->value = value_ptr;
2530 widget_entry->updater = CML_explorer_double_entry_change_value;
2531 }
2532
2533 /* menu functions */
2534
2535 static void
CML_explorer_menu_update(GtkWidget * widget,gpointer data)2536 CML_explorer_menu_update (GtkWidget *widget,
2537 gpointer data)
2538 {
2539 gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), (gint *) data);
2540
2541 preview_update ();
2542 }
2543
2544 static void
CML_initial_value_menu_update(GtkWidget * widget,gpointer data)2545 CML_initial_value_menu_update (GtkWidget *widget,
2546 gpointer data)
2547 {
2548 gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), (gint *) data);
2549
2550 CML_initial_value_sensitives_update ();
2551 preview_update ();
2552 }
2553
2554 static void
CML_explorer_menu_entry_change_value(WidgetEntry * widget_entry)2555 CML_explorer_menu_entry_change_value (WidgetEntry *widget_entry)
2556 {
2557 gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (widget_entry->widget),
2558 *(gint *) (widget_entry->value));
2559 }
2560
2561 static void
CML_explorer_menu_entry_init(WidgetEntry * widget_entry,GtkWidget * widget,gpointer value_ptr)2562 CML_explorer_menu_entry_init (WidgetEntry *widget_entry,
2563 GtkWidget *widget,
2564 gpointer value_ptr)
2565 {
2566 widget_entry->widget = widget;
2567 widget_entry->value = value_ptr;
2568 widget_entry->updater = CML_explorer_menu_entry_change_value;
2569 }
2570