home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / CML_explorer.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-28  |  80.5 KB  |  2,704 lines

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