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                         &copy_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                         &copy_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                     &param->function);
1611 
1612   CML_explorer_menu_entry_init (&widget_pointers[channel_id][index],
1613                                 combo, &param->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                     &param->composition);
1627 
1628   CML_explorer_menu_entry_init (&widget_pointers[channel_id][index],
1629                                 combo, &param->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                     &param->arrange);
1641 
1642   CML_explorer_menu_entry_init (&widget_pointers[channel_id][index],
1643                                 combo, &param->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, &param->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, &param->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, &param->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, &param->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, &param->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, &param->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, &param->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, &param->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, &param->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, &param->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, &param->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, &param->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