~ubuntu-branches/ubuntu/karmic/gimp/karmic-security

« back to all changes in this revision

Viewing changes to plug-ins/common/value-propagate.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2008-10-06 13:30:41 UTC
  • mfrom: (1.1.15 upstream)
  • Revision ID: james.westby@ubuntu.com-20081006133041-axco233xt49jobn7
Tags: 2.6.0-1ubuntu1
* Sync on debian and new version (lp: #276839)
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch:
  - updated some strings for ubuntu
* debian/rules:
  - updated translation templates

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vpropagate.c -- This is a plug-in for GIMP (1.0's API)
 
2
 * Author: Shuji Narazaki <narazaki@InetQ.or.jp>
 
3
 * Time-stamp: <2000-01-09 15:50:46 yasuhiro>
 
4
 * Version: 0.89a
 
5
 *
 
6
 * Copyright (C) 1996-1997 Shuji Narazaki <narazaki@InetQ.or.jp>
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License as published by
 
10
 * the Free Software Foundation; either version 2 of the License, or
 
11
 * (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 * GNU General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program; if not, write to the Free Software
 
20
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
21
 */
 
22
 
 
23
/* memo
 
24
   the initial value of each pixel is the value of the pixel itself.
 
25
   To determine whether it is an isolated local peak point, use:
 
26
   (self == min && (! modified_flag))   ; modified_flag holds history of update
 
27
   In other word, pixel itself is not a neighbor of it.
 
28
*/
 
29
/*
 
30
   in response to bug #156545, after lengthy discussion, the meanings
 
31
   of "dilate" and "erode" are being swapped -- 19 May 2006.
 
32
*/
 
33
 
 
34
#include "config.h"
 
35
 
 
36
#include <stdlib.h>
 
37
#include <string.h>
 
38
 
 
39
#include <libgimp/gimp.h>
 
40
#include <libgimp/gimpui.h>
 
41
 
 
42
#include "libgimp/stdplugins-intl.h"
 
43
 
 
44
 
 
45
#define VPROPAGATE_PROC      "plug-in-vpropagate"
 
46
#define ERODE_PROC           "plug-in-erode"
 
47
#define DILATE_PROC          "plug-in-dilate"
 
48
#define PLUG_IN_BINARY       "value-propagate"
 
49
#define PLUG_IN_IMAGE_TYPES  "RGB*, GRAY*"
 
50
 
 
51
#define VP_RGB          (1 << 0)
 
52
#define VP_GRAY         (1 << 1)
 
53
#define VP_WITH_ALPHA   (1 << 2)
 
54
#define VP_WO_ALPHA     (1 << 3)
 
55
#define num_direction   4
 
56
#define Right2Left      0
 
57
#define Bottom2Top      1
 
58
#define Left2Right      2
 
59
#define Top2Bottom      3
 
60
 
 
61
static void         query                      (void);
 
62
static void         run                        (const gchar       *name,
 
63
                                                gint               nparams,
 
64
                                                const GimpParam   *param,
 
65
                                                gint              *nreturn_vals,
 
66
                                                GimpParam        **return_vals);
 
67
 
 
68
static GimpPDBStatusType  value_propagate      (GimpDrawable  *drawable);
 
69
static void         value_propagate_body       (GimpDrawable  *drawable,
 
70
                                                GimpPreview   *preview);
 
71
static gboolean     vpropagate_dialog          (GimpDrawable  *drawable);
 
72
static void         prepare_row                (GimpPixelRgn  *pixel_rgn,
 
73
                                                guchar        *data,
 
74
                                                gint           x,
 
75
                                                gint           y,
 
76
                                                gint           w);
 
77
 
 
78
static void    vpropagate_toggle_button_update (GtkWidget     *widget,
 
79
                                                gpointer       data);
 
80
static GtkWidget *  gtk_table_add_toggle       (GtkWidget     *table,
 
81
                                                const gchar   *name,
 
82
                                                gint           x1,
 
83
                                                gint           x2,
 
84
                                                gint           y,
 
85
                                                GCallback      update,
 
86
                                                gint          *value);
 
87
 
 
88
static int          value_difference_check  (guchar *, guchar *, int);
 
89
static void         set_value               (GimpImageBaseType,
 
90
                                             int, guchar *, guchar *, guchar *,
 
91
                                             void *);
 
92
static void         initialize_white        (GimpImageBaseType,
 
93
                                             int, guchar *, guchar *,
 
94
                                             void **);
 
95
static void         propagate_white         (GimpImageBaseType,
 
96
                                             int, guchar *, guchar *, guchar *,
 
97
                                             void *);
 
98
static void         initialize_black        (GimpImageBaseType,
 
99
                                             int, guchar *, guchar *,
 
100
                                             void **);
 
101
static void         propagate_black         (GimpImageBaseType,
 
102
                                             int, guchar *, guchar *, guchar *,
 
103
                                             void *);
 
104
static void         initialize_middle       (GimpImageBaseType,
 
105
                                             int, guchar *, guchar *,
 
106
                                             void **);
 
107
static void         propagate_middle        (GimpImageBaseType,
 
108
                                             int, guchar *, guchar *, guchar *,
 
109
                                             void *);
 
110
static void         set_middle_to_peak      (GimpImageBaseType,
 
111
                                             int, guchar *, guchar *, guchar *,
 
112
                                             void *);
 
113
static void         set_foreground_to_peak  (GimpImageBaseType,
 
114
                                             int, guchar *, guchar *, guchar *,
 
115
                                             void *);
 
116
static void         initialize_foreground   (GimpImageBaseType,
 
117
                                             int, guchar *, guchar *,
 
118
                                             void **);
 
119
static void         initialize_background   (GimpImageBaseType,
 
120
                                             int, guchar *, guchar *,
 
121
                                             void **);
 
122
static void         propagate_a_color       (GimpImageBaseType,
 
123
                                             int, guchar *, guchar *, guchar *,
 
124
                                             void *);
 
125
static void         propagate_opaque        (GimpImageBaseType,
 
126
                                             int, guchar *, guchar *, guchar *,
 
127
                                             void *);
 
128
static void         propagate_transparent   (GimpImageBaseType,
 
129
                                             int, guchar *, guchar *, guchar *,
 
130
                                             void *);
 
131
 
 
132
const GimpPlugInInfo PLUG_IN_INFO =
 
133
{
 
134
  NULL,  /* init_proc  */
 
135
  NULL,  /* quit_proc  */
 
136
  query, /* query_proc */
 
137
  run,   /* run_proc   */
 
138
};
 
139
 
 
140
#define SCALE_WIDTH        100
 
141
#define PROPAGATING_VALUE  (1 << 0)
 
142
#define PROPAGATING_ALPHA  (1 << 1)
 
143
 
 
144
/* parameters */
 
145
typedef struct
 
146
{
 
147
  gint     propagate_mode;
 
148
  gint     propagating_channel;
 
149
  gdouble  propagating_rate;
 
150
  gint     direction_mask;
 
151
  gint     lower_limit;
 
152
  gint     upper_limit;
 
153
} VPValueType;
 
154
 
 
155
static VPValueType vpvals =
 
156
{
 
157
  0,        /* propagate_mode                        */
 
158
  3,        /* PROPAGATING_VALUE + PROPAGATING_ALPHA */
 
159
  1.0,      /* [0.0:1.0]                             */
 
160
  15,       /* propagate to all 4 directions         */
 
161
  0,        /* lower_limit                           */
 
162
  255       /* upper_limit                           */
 
163
};
 
164
 
 
165
/* dialog variables */
 
166
static gint       propagate_alpha;
 
167
static gint       propagate_value;
 
168
static gint       direction_mask_vec[4];
 
169
static gint       channel_mask[] = { 1, 1, 1 };
 
170
static gint       peak_max = 1;
 
171
static gint       peak_min = 1;
 
172
static gint       peak_includes_equals = 1;
 
173
static guchar     fore[3];
 
174
static GtkWidget *preview;
 
175
 
 
176
typedef struct
 
177
{
 
178
  gint    applicable_image_type;
 
179
  gchar  *name;
 
180
  void  (*initializer) (GimpImageBaseType, gint, guchar *, guchar *, gpointer *);
 
181
  void  (*updater) (GimpImageBaseType, gint, guchar *, guchar *, guchar *, gpointer);
 
182
  void  (*finalizer) (GimpImageBaseType, gint, guchar *, guchar *, guchar *, gpointer);
 
183
} ModeParam;
 
184
 
 
185
#define num_mode 8
 
186
static ModeParam modes[num_mode] =
 
187
{
 
188
  { VP_RGB | VP_GRAY | VP_WITH_ALPHA | VP_WO_ALPHA,
 
189
    N_("More _white (larger value)"),
 
190
    initialize_white,      propagate_white,       set_value },
 
191
  { VP_RGB | VP_GRAY | VP_WITH_ALPHA | VP_WO_ALPHA,
 
192
    N_("More blac_k (smaller value)"),
 
193
    initialize_black,      propagate_black,       set_value },
 
194
  { VP_RGB | VP_GRAY | VP_WITH_ALPHA | VP_WO_ALPHA,
 
195
    N_("_Middle value to peaks"),
 
196
    initialize_middle,     propagate_middle,      set_middle_to_peak },
 
197
  { VP_RGB | VP_GRAY | VP_WITH_ALPHA | VP_WO_ALPHA,
 
198
    N_("_Foreground to peaks"),
 
199
    initialize_middle,     propagate_middle,      set_foreground_to_peak },
 
200
  { VP_RGB | VP_WITH_ALPHA | VP_WO_ALPHA,
 
201
    N_("O_nly foreground"),
 
202
    initialize_foreground, propagate_a_color,     set_value },
 
203
  { VP_RGB | VP_WITH_ALPHA | VP_WO_ALPHA,
 
204
    N_("Only b_ackground"),
 
205
    initialize_background, propagate_a_color,     set_value },
 
206
  { VP_RGB | VP_GRAY | VP_WITH_ALPHA,
 
207
    N_("Mor_e opaque"),
 
208
    NULL,                  propagate_opaque,      set_value },
 
209
  { VP_RGB | VP_GRAY | VP_WITH_ALPHA,
 
210
    N_("More t_ransparent"),
 
211
    NULL,                  propagate_transparent, set_value },
 
212
};
 
213
 
 
214
MAIN ()
 
215
 
 
216
static void
 
217
query (void)
 
218
{
 
219
  static const GimpParamDef args[] =
 
220
  {
 
221
    { GIMP_PDB_INT32,    "run-mode",            "Interactive, non-interactive" },
 
222
    { GIMP_PDB_IMAGE,    "image",               "Input image (not used)" },
 
223
    { GIMP_PDB_DRAWABLE, "drawable",            "Input drawable" },
 
224
    { GIMP_PDB_INT32,    "propagate-mode",      "propagate 0:white, 1:black, 2:middle value 3:foreground to peak, 4:foreground, 5:background, 6:opaque, 7:transparent" },
 
225
    { GIMP_PDB_INT32,    "propagating-channel", "channels which values are propagated" },
 
226
    { GIMP_PDB_FLOAT,    "propagating-rate",    "0.0 <= propagatating_rate <= 1.0" },
 
227
    { GIMP_PDB_INT32,    "direction-mask",      "0 <= direction-mask <= 15" },
 
228
    { GIMP_PDB_INT32,    "lower-limit",         "0 <= lower-limit <= 255" },
 
229
    { GIMP_PDB_INT32,    "upper-limit",         "0 <= upper-limit <= 255" }
 
230
  };
 
231
 
 
232
  gimp_install_procedure (VPROPAGATE_PROC,
 
233
                          N_("Propagate certain colors to neighboring pixels"),
 
234
                          "Propagate values of the layer",
 
235
                          "Shuji Narazaki (narazaki@InetQ.or.jp)",
 
236
                          "Shuji Narazaki",
 
237
                          "1996-1997",
 
238
                          N_("_Value Propagate..."),
 
239
                          PLUG_IN_IMAGE_TYPES,
 
240
                          GIMP_PLUGIN,
 
241
                          G_N_ELEMENTS (args), 0,
 
242
                          args, NULL);
 
243
 
 
244
  gimp_install_procedure (ERODE_PROC,
 
245
                          N_("Shrink lighter areas of the image"),
 
246
                          "Erode image",
 
247
                          "Shuji Narazaki (narazaki@InetQ.or.jp)",
 
248
                          "Shuji Narazaki",
 
249
                          "1996-1997",
 
250
                          N_("E_rode"),
 
251
                          PLUG_IN_IMAGE_TYPES,
 
252
                          GIMP_PLUGIN,
 
253
                          G_N_ELEMENTS (args), 0,
 
254
                          args, NULL);
 
255
 
 
256
  gimp_install_procedure (DILATE_PROC,
 
257
                          N_("Grow lighter areas of the image"),
 
258
                          "Dilate image",
 
259
                          "Shuji Narazaki (narazaki@InetQ.or.jp)",
 
260
                          "Shuji Narazaki",
 
261
                          "1996-1997",
 
262
                          N_("_Dilate"),
 
263
                          PLUG_IN_IMAGE_TYPES,
 
264
                          GIMP_PLUGIN,
 
265
                          G_N_ELEMENTS (args), 0,
 
266
                          args, NULL);
 
267
 
 
268
  gimp_plugin_menu_register (VPROPAGATE_PROC, "<Image>/Filters/Distorts");
 
269
  gimp_plugin_menu_register (ERODE_PROC,      "<Image>/Filters/Generic");
 
270
  gimp_plugin_menu_register (DILATE_PROC,     "<Image>/Filters/Generic");
 
271
}
 
272
 
 
273
static void
 
274
run (const gchar      *name,
 
275
     gint              nparams,
 
276
     const GimpParam  *param,
 
277
     gint             *nreturn_vals,
 
278
     GimpParam       **return_vals)
 
279
{
 
280
  static GimpParam   values[1];
 
281
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
 
282
  GimpRunMode        run_mode;
 
283
  GimpDrawable      *drawable;
 
284
 
 
285
  run_mode = param[0].data.d_int32;
 
286
  drawable = gimp_drawable_get (param[2].data.d_int32);
 
287
 
 
288
  INIT_I18N ();
 
289
 
 
290
  *nreturn_vals = 1;
 
291
  *return_vals  = values;
 
292
 
 
293
  values[0].type          = GIMP_PDB_STATUS;
 
294
  values[0].data.d_status = status;
 
295
 
 
296
  switch (run_mode)
 
297
    {
 
298
    case GIMP_RUN_INTERACTIVE:
 
299
      if (strcmp (name, VPROPAGATE_PROC) == 0)
 
300
        {
 
301
          gimp_get_data (VPROPAGATE_PROC, &vpvals);
 
302
          /* building the values of dialog variables from vpvals. */
 
303
          propagate_alpha =
 
304
            (vpvals.propagating_channel & PROPAGATING_ALPHA) ? TRUE : FALSE;
 
305
          propagate_value =
 
306
            (vpvals.propagating_channel & PROPAGATING_VALUE) ? TRUE : FALSE;
 
307
 
 
308
          {
 
309
            gint i;
 
310
            for (i = 0; i < 4; i++)
 
311
              direction_mask_vec[i] =
 
312
                (vpvals.direction_mask & (1 << i)) ? TRUE : FALSE;
 
313
          }
 
314
 
 
315
          if (! vpropagate_dialog (drawable))
 
316
            return;
 
317
        }
 
318
      else if (strcmp (name, ERODE_PROC) == 0 ||
 
319
               strcmp (name, DILATE_PROC) == 0)
 
320
        {
 
321
          vpvals.propagating_channel = PROPAGATING_VALUE;
 
322
          vpvals.propagating_rate    = 1.0;
 
323
          vpvals.direction_mask      = 15;
 
324
          vpvals.lower_limit         = 0;
 
325
          vpvals.upper_limit         = 255;
 
326
 
 
327
          if (strcmp (name, ERODE_PROC) == 0)
 
328
            vpvals.propagate_mode = 1;
 
329
          else if (strcmp (name, DILATE_PROC) == 0)
 
330
            vpvals.propagate_mode = 0;
 
331
        }
 
332
      break;
 
333
 
 
334
    case GIMP_RUN_NONINTERACTIVE:
 
335
      if (strcmp (name, VPROPAGATE_PROC) == 0)
 
336
        {
 
337
          vpvals.propagate_mode      = param[3].data.d_int32;
 
338
          vpvals.propagating_channel = param[4].data.d_int32;
 
339
          vpvals.propagating_rate    = param[5].data.d_float;
 
340
          vpvals.direction_mask      = param[6].data.d_int32;
 
341
          vpvals.lower_limit         = param[7].data.d_int32;
 
342
          vpvals.upper_limit         = param[8].data.d_int32;
 
343
        }
 
344
      else if (strcmp (name, ERODE_PROC) == 0 ||
 
345
               strcmp (name, DILATE_PROC) == 0)
 
346
        {
 
347
          vpvals.propagating_channel = PROPAGATING_VALUE;
 
348
          vpvals.propagating_rate    = 1.0;
 
349
          vpvals.direction_mask      = 15;
 
350
          vpvals.lower_limit         = 0;
 
351
          vpvals.upper_limit         = 255;
 
352
 
 
353
          if (strcmp (name, ERODE_PROC) == 0)
 
354
            vpvals.propagate_mode = 1;
 
355
          else if (strcmp (name, DILATE_PROC) == 0)
 
356
            vpvals.propagate_mode = 0;
 
357
        }
 
358
      break;
 
359
 
 
360
    case GIMP_RUN_WITH_LAST_VALS:
 
361
      gimp_get_data (name, &vpvals);
 
362
      break;
 
363
    }
 
364
 
 
365
  status = value_propagate (drawable);
 
366
 
 
367
  if (status == GIMP_PDB_SUCCESS)
 
368
    {
 
369
      if (run_mode != GIMP_RUN_NONINTERACTIVE)
 
370
        gimp_displays_flush ();
 
371
 
 
372
      if (run_mode == GIMP_RUN_INTERACTIVE)
 
373
        gimp_set_data (name, &vpvals, sizeof (VPValueType));
 
374
    }
 
375
 
 
376
  values[0].type = GIMP_PDB_STATUS;
 
377
  values[0].data.d_status = status;
 
378
}
 
379
 
 
380
/* registered function entry */
 
381
static GimpPDBStatusType
 
382
value_propagate (GimpDrawable *drawable)
 
383
{
 
384
  /* check the validness of parameters */
 
385
  if (!(vpvals.propagating_channel & (PROPAGATING_VALUE | PROPAGATING_ALPHA)))
 
386
    {
 
387
      /* gimp_message ("No channel selected."); */
 
388
      return GIMP_PDB_EXECUTION_ERROR;
 
389
    }
 
390
  if (vpvals.direction_mask == 0)
 
391
    {
 
392
      /* gimp_message ("No direction selected."); */
 
393
      return GIMP_PDB_EXECUTION_ERROR;
 
394
    }
 
395
  if ((vpvals.lower_limit < 0) || (255 < vpvals.lower_limit) ||
 
396
       (vpvals.upper_limit < 0) || (255 < vpvals.lower_limit) ||
 
397
       (vpvals.upper_limit < vpvals.lower_limit))
 
398
    {
 
399
      /* gimp_message ("Limit values are not valid."); */
 
400
      return GIMP_PDB_EXECUTION_ERROR;
 
401
    }
 
402
  value_propagate_body (drawable, NULL);
 
403
  return GIMP_PDB_SUCCESS;
 
404
}
 
405
 
 
406
static void
 
407
value_propagate_body (GimpDrawable *drawable,
 
408
                      GimpPreview  *preview)
 
409
{
 
410
  GimpImageBaseType  dtype;
 
411
  ModeParam          operation;
 
412
  GimpPixelRgn       srcRgn, destRgn;
 
413
  guchar            *here, *best, *dest;
 
414
  guchar            *dest_row, *prev_row, *cur_row, *next_row;
 
415
  guchar            *pr, *cr, *nr, *swap;
 
416
  gint               width, height, bytes, index;
 
417
  gint               begx, begy, endx, endy, x, y, dx;
 
418
  gint               left_index, right_index, up_index, down_index;
 
419
  gpointer           tmp;
 
420
  GimpRGB            foreground;
 
421
 
 
422
  /* calculate neighbors' indexes */
 
423
  left_index  = (vpvals.direction_mask & (1 << Left2Right)) ? -1 : 0;
 
424
  right_index = (vpvals.direction_mask & (1 << Right2Left)) ?  1 : 0;
 
425
  up_index    = (vpvals.direction_mask & (1 << Top2Bottom)) ? -1 : 0;
 
426
  down_index  = (vpvals.direction_mask & (1 << Bottom2Top)) ?  1 : 0;
 
427
  operation   = modes[vpvals.propagate_mode];
 
428
  tmp         = NULL;
 
429
 
 
430
  dtype = gimp_drawable_type (drawable->drawable_id);
 
431
  bytes = drawable->bpp;
 
432
 
 
433
  /* Here I use the algorithm of blur.c . */
 
434
  if (preview)
 
435
    {
 
436
       gimp_preview_get_position (preview, &begx, &begy);
 
437
       gimp_preview_get_size (preview, &width, &height);
 
438
       endx = begx + width;
 
439
       endy = begy + height;
 
440
    }
 
441
  else
 
442
    {
 
443
      gimp_drawable_mask_bounds (drawable->drawable_id,
 
444
                                 &begx, &begy, &endx, &endy);
 
445
      width  = endx - begx;
 
446
      height = endy - begy;
 
447
    }
 
448
 
 
449
  gimp_tile_cache_ntiles (2 * ((width) / gimp_tile_width () + 1));
 
450
 
 
451
  prev_row = g_new (guchar, (width + 2) * bytes);
 
452
  cur_row  = g_new (guchar, (width + 2) * bytes);
 
453
  next_row = g_new (guchar, (width + 2) * bytes);
 
454
  dest_row = g_new (guchar, width * bytes);
 
455
 
 
456
  gimp_pixel_rgn_init (&srcRgn, drawable,
 
457
                       begx, begy, width, height,
 
458
                       FALSE, FALSE);
 
459
  gimp_pixel_rgn_init (&destRgn, drawable,
 
460
                       begx, begy, width, height,
 
461
                       (preview == NULL), TRUE);
 
462
 
 
463
  pr = prev_row + bytes;
 
464
  cr = cur_row + bytes;
 
465
  nr = next_row + bytes;
 
466
 
 
467
  prepare_row (&srcRgn, pr, begx, (0 < begy) ? begy : begy - 1, endx-begx);
 
468
  prepare_row (&srcRgn, cr, begx, begy, endx-begx);
 
469
 
 
470
  best = g_new (guchar, bytes);
 
471
 
 
472
  if (!preview)
 
473
    gimp_progress_init (_("Value Propagate"));
 
474
 
 
475
  gimp_context_get_foreground (&foreground);
 
476
  gimp_rgb_get_uchar (&foreground, fore+0, fore+1, fore+2);
 
477
 
 
478
  /* start real job */
 
479
  for (y = begy ; y < endy ; y++)
 
480
    {
 
481
      prepare_row (&srcRgn, nr, begx, ((y+1) < endy) ? y+1 : endy, endx-begx);
 
482
 
 
483
      for (index = 0; index < (endx - begx) * bytes; index++)
 
484
        dest_row[index] = cr[index];
 
485
 
 
486
      for (x = 0 ; x < endx - begx; x++)
 
487
        {
 
488
          dest = dest_row + (x * bytes);
 
489
          here = cr + (x * bytes);
 
490
 
 
491
          /* *** copy source value to best value holder *** */
 
492
          memcpy (best, here, bytes);
 
493
 
 
494
          if (operation.initializer)
 
495
            (* operation.initializer)(dtype, bytes, best, here, &tmp);
 
496
 
 
497
          /* *** gather neighbors' values: loop-unfolded version *** */
 
498
          if (up_index == -1)
 
499
            for (dx = left_index ; dx <= right_index ; dx++)
 
500
              (* operation.updater)(dtype, bytes, here, pr+((x+dx)*bytes), best, tmp);
 
501
          for (dx = left_index ; dx <= right_index ; dx++)
 
502
            if (dx != 0)
 
503
              (* operation.updater)(dtype, bytes, here, cr+((x+dx)*bytes), best, tmp);
 
504
          if (down_index == 1)
 
505
            for (dx = left_index ; dx <= right_index ; dx++)
 
506
              (* operation.updater)(dtype, bytes, here, nr+((x+dx)*bytes), best, tmp);
 
507
          /* *** store it to dest_row*** */
 
508
          (* operation.finalizer)(dtype, bytes, best, here, dest, tmp);
 
509
        }
 
510
 
 
511
      /* now store destline to destRgn */
 
512
      gimp_pixel_rgn_set_row (&destRgn, dest_row, begx, y, endx - begx);
 
513
 
 
514
      /* shift the row pointers  */
 
515
      swap = pr;
 
516
      pr = cr;
 
517
      cr = nr;
 
518
      nr = swap;
 
519
 
 
520
 
 
521
      if (((y % 16) == 0) && !preview)
 
522
        gimp_progress_update ((gdouble) y / (gdouble) (endy - begy));
 
523
    }
 
524
 
 
525
  if (preview)
 
526
    {
 
527
      gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview),
 
528
                                         &destRgn);
 
529
    }
 
530
  else
 
531
    {
 
532
      /*  update the region  */
 
533
      gimp_progress_update (1.0);
 
534
      gimp_drawable_flush (drawable);
 
535
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
 
536
      gimp_drawable_update (drawable->drawable_id, begx, begy, endx-begx, endy-begy);
 
537
    }
 
538
}
 
539
 
 
540
static void
 
541
prepare_row (GimpPixelRgn *pixel_rgn,
 
542
             guchar       *data,
 
543
             gint          x,
 
544
             gint          y,
 
545
             gint          w)
 
546
{
 
547
  gint b;
 
548
 
 
549
  if (y <= 0)
 
550
    gimp_pixel_rgn_get_row (pixel_rgn, data, x, (y + 1), w);
 
551
  else if (y >= pixel_rgn->h)
 
552
    gimp_pixel_rgn_get_row (pixel_rgn, data, x, (y - 1), w);
 
553
  else
 
554
    gimp_pixel_rgn_get_row (pixel_rgn, data, x, y, w);
 
555
 
 
556
  /*  Fill in edge pixels  */
 
557
  for (b = 0; b < pixel_rgn->bpp; b++)
 
558
    {
 
559
      data[-(gint)pixel_rgn->bpp + b] = data[b];
 
560
      data[w * pixel_rgn->bpp + b] = data[(w - 1) * pixel_rgn->bpp + b];
 
561
    }
 
562
}
 
563
 
 
564
static void
 
565
set_value (GimpImageBaseType  dtype,
 
566
           gint               bytes,
 
567
           guchar            *best,
 
568
           guchar            *here,
 
569
           guchar            *dest,
 
570
           void              *tmp)
 
571
{
 
572
  gint  value_chs = 0;
 
573
  gint  alpha = 0;
 
574
  gint  ch;
 
575
 
 
576
  switch (dtype)
 
577
    {
 
578
    case GIMP_RGB_IMAGE:
 
579
      value_chs = 3;
 
580
      break;
 
581
    case GIMP_RGBA_IMAGE:
 
582
      value_chs = 3;
 
583
      alpha = 3;
 
584
      break;
 
585
    case GIMP_GRAY_IMAGE:
 
586
      value_chs = 1;
 
587
      break;
 
588
    case GIMP_GRAYA_IMAGE:
 
589
      value_chs = 1;
 
590
      alpha = 1;
 
591
      break;
 
592
    default:
 
593
      break;
 
594
    }
 
595
  for (ch = 0; ch < value_chs; ch++)
 
596
    {
 
597
      if (vpvals.propagating_channel & PROPAGATING_VALUE) /* value channel */
 
598
        *dest++ = (guchar)(vpvals.propagating_rate * best[ch]
 
599
                       + (1.0 - vpvals.propagating_rate) * here[ch]);
 
600
      else
 
601
        *dest++ = here[ch];
 
602
    }
 
603
  if (alpha)
 
604
    {
 
605
      if (vpvals.propagating_channel & PROPAGATING_ALPHA) /* alpha channel */
 
606
        *dest++ = (guchar)(vpvals.propagating_rate * best[alpha]
 
607
                       + (1.0 - vpvals.propagating_rate) * here[alpha]);
 
608
      else
 
609
        *dest++ = here[alpha];
 
610
    }
 
611
}
 
612
 
 
613
static inline int
 
614
value_difference_check (guchar *pos1,
 
615
                        guchar *pos2,
 
616
                        gint   ch)
 
617
{
 
618
  gint  index;
 
619
  int   diff;
 
620
 
 
621
  for (index = 0 ; index < ch; index++)
 
622
    if (channel_mask[index] != 0)
 
623
      {
 
624
        diff = abs(pos1[index] - pos2[index]);
 
625
        if (! ((vpvals.lower_limit <= diff) && (diff <= vpvals.upper_limit)))
 
626
          return 0;
 
627
      }
 
628
  return 1;
 
629
}
 
630
 
 
631
/* mothods for each mode */
 
632
static void
 
633
initialize_white (GimpImageBaseType   dtype,
 
634
                  gint                bytes,
 
635
                  guchar             *best,
 
636
                  guchar             *here,
 
637
                  void              **tmp)
 
638
{
 
639
 
 
640
  switch (dtype)
 
641
    {
 
642
    case GIMP_RGB_IMAGE:
 
643
    case GIMP_RGBA_IMAGE:
 
644
      if (*tmp == NULL)
 
645
        *tmp = (void *) g_new (gfloat, 1);
 
646
      **(float **)tmp = channel_mask[0] * here[0] * here[0]
 
647
                     + channel_mask[1] * here[1] * here[1]
 
648
                     + channel_mask[2] * here[2] * here[2];
 
649
      break;
 
650
    case GIMP_GRAYA_IMAGE:
 
651
    case GIMP_GRAY_IMAGE:
 
652
      break;
 
653
    default:
 
654
      break;
 
655
    }
 
656
}
 
657
 
 
658
static void
 
659
propagate_white (GimpImageBaseType  dtype,
 
660
                 gint               bytes,
 
661
                 guchar            *orig,
 
662
                 guchar            *here,
 
663
                 guchar            *best,
 
664
                 void              *tmp)
 
665
{
 
666
  float v_here;
 
667
 
 
668
  switch (dtype)
 
669
    {
 
670
    case GIMP_RGB_IMAGE:
 
671
    case GIMP_RGBA_IMAGE:
 
672
      v_here = channel_mask[0] * here[0] * here[0]
 
673
                     + channel_mask[1] * here[1] * here[1]
 
674
                     + channel_mask[2] * here[2] * here[2];
 
675
     if (*(float *)tmp < v_here && value_difference_check(orig, here, 3))
 
676
        {
 
677
          *(float *)tmp = v_here;
 
678
          memcpy(best, here, 3 * sizeof(guchar)); /* alpha channel holds old value */
 
679
        }
 
680
      break;
 
681
    case GIMP_GRAYA_IMAGE:
 
682
    case GIMP_GRAY_IMAGE:
 
683
      if (*best < *here && value_difference_check(orig, here, 1))
 
684
        *best = *here;
 
685
      break;
 
686
    default:
 
687
      break;
 
688
    }
 
689
}
 
690
 
 
691
static void
 
692
initialize_black (GimpImageBaseType   dtype,
 
693
                  gint                channels,
 
694
                  guchar             *best,
 
695
                  guchar             *here,
 
696
                  void              **tmp)
 
697
{
 
698
  switch (dtype)
 
699
    {
 
700
    case GIMP_RGB_IMAGE:
 
701
    case GIMP_RGBA_IMAGE:
 
702
      if (*tmp == NULL)
 
703
        *tmp = (void *) g_new (gfloat, 1);
 
704
      **(float **)tmp = (channel_mask[0] * here[0] * here[0]
 
705
                     + channel_mask[1] * here[1] * here[1]
 
706
                     + channel_mask[2] * here[2] * here[2]);
 
707
      break;
 
708
    case GIMP_GRAYA_IMAGE:
 
709
    case GIMP_GRAY_IMAGE:
 
710
      break;
 
711
    default:
 
712
      break;
 
713
    }
 
714
}
 
715
 
 
716
static void
 
717
propagate_black (GimpImageBaseType  image_type,
 
718
                 gint               channels,
 
719
                 guchar            *orig,
 
720
                 guchar            *here,
 
721
                 guchar            *best,
 
722
                 void              *tmp)
 
723
{
 
724
  float v_here;
 
725
 
 
726
  switch (image_type)
 
727
    {
 
728
    case GIMP_RGB_IMAGE:
 
729
    case GIMP_RGBA_IMAGE:
 
730
      v_here = (channel_mask[0] * here[0] * here[0]
 
731
                     + channel_mask[1] * here[1] * here[1]
 
732
                     + channel_mask[2] * here[2] * here[2]);
 
733
      if (v_here < *(float *)tmp && value_difference_check(orig, here, 3))
 
734
        {
 
735
          *(float *)tmp = v_here;
 
736
          memcpy (best, here, 3 * sizeof(guchar)); /* alpha channel holds old value */
 
737
        }
 
738
      break;
 
739
    case GIMP_GRAYA_IMAGE:
 
740
    case GIMP_GRAY_IMAGE:
 
741
      if (*here < *best && value_difference_check(orig, here, 1))
 
742
        *best = *here;
 
743
      break;
 
744
    default:
 
745
      break;
 
746
    }
 
747
}
 
748
 
 
749
typedef struct
 
750
{
 
751
  gshort min_modified;
 
752
  gshort max_modified;
 
753
  glong  original_value;
 
754
  glong  minv;
 
755
  guchar min[3];
 
756
  glong  maxv;
 
757
  guchar max[3];
 
758
} MiddlePacket;
 
759
 
 
760
static void
 
761
initialize_middle (GimpImageBaseType   image_type,
 
762
                   gint                channels,
 
763
                   guchar             *best,
 
764
                   guchar             *here,
 
765
                   void              **tmp)
 
766
{
 
767
  int index;
 
768
  MiddlePacket *data;
 
769
 
 
770
  if (*tmp == NULL)
 
771
    *tmp = (void *) g_new (MiddlePacket, 1);
 
772
  data = (MiddlePacket *)*tmp;
 
773
  for (index = 0; index < channels; index++)
 
774
    data->min[index] = data->max[index] = here[index];
 
775
  switch (image_type)
 
776
    {
 
777
    case GIMP_RGB_IMAGE:
 
778
    case GIMP_RGBA_IMAGE:
 
779
      data->original_value = (channel_mask[0] * here[0] * here[0]
 
780
                                   + channel_mask[1] * here[1] * here[1]
 
781
                                   + channel_mask[2] * here[2] * here[2]);
 
782
      break;
 
783
    case GIMP_GRAYA_IMAGE:
 
784
    case GIMP_GRAY_IMAGE:
 
785
      data->original_value = *here;
 
786
      break;
 
787
    default:
 
788
      break;
 
789
    }
 
790
  data->minv = data->maxv = data->original_value;
 
791
  data->min_modified = data->max_modified = 0;
 
792
}
 
793
 
 
794
static void
 
795
propagate_middle (GimpImageBaseType  image_type,
 
796
                  gint               channels,
 
797
                  guchar            *orig,
 
798
                  guchar            *here,
 
799
                  guchar            *best,
 
800
                  void              *tmp)
 
801
{
 
802
  float v_here;
 
803
  MiddlePacket *data;
 
804
 
 
805
  data = (MiddlePacket *)tmp;
 
806
 
 
807
  switch (image_type)
 
808
    {
 
809
    case GIMP_RGB_IMAGE:
 
810
    case GIMP_RGBA_IMAGE:
 
811
      v_here = (channel_mask[0] * here[0] * here[0]
 
812
                     + channel_mask[1] * here[1] * here[1]
 
813
                     + channel_mask[2] * here[2] * here[2]);
 
814
      if ((v_here <= data->minv) && value_difference_check(orig, here, 3))
 
815
        {
 
816
          data->minv = v_here;
 
817
          memcpy (data->min, here, 3*sizeof(guchar));
 
818
          data->min_modified = 1;
 
819
        }
 
820
      if (data->maxv <= v_here && value_difference_check(orig, here, 3))
 
821
        {
 
822
          data->maxv = v_here;
 
823
          memcpy (data->max, here, 3*sizeof(guchar));
 
824
          data->max_modified = 1;
 
825
        }
 
826
      break;
 
827
    case GIMP_GRAYA_IMAGE:
 
828
    case GIMP_GRAY_IMAGE:
 
829
      if ((*here <= data->min[0]) && value_difference_check(orig, here, 1))
 
830
        {
 
831
          data->min[0] = *here;
 
832
          data->min_modified = 1;
 
833
        }
 
834
      if ((data->max[0] <= *here) && value_difference_check(orig, here, 1))
 
835
        {
 
836
          data->max[0] = *here;
 
837
          data->max_modified = 1;
 
838
        }
 
839
      break;
 
840
    default:
 
841
      break;
 
842
    }
 
843
}
 
844
 
 
845
static void
 
846
set_middle_to_peak (GimpImageBaseType  image_type,
 
847
                    gint               channels,
 
848
                    guchar            *here,
 
849
                    guchar            *best,
 
850
                    guchar            *dest,
 
851
                    void              *tmp)
 
852
{
 
853
  gint  value_chs = 0;
 
854
  gint  alpha = 0;
 
855
  gint  ch;
 
856
  MiddlePacket  *data;
 
857
 
 
858
  data = (MiddlePacket *)tmp;
 
859
  if (! ((peak_min & (data->minv == data->original_value))
 
860
         || (peak_max & (data->maxv == data->original_value))))
 
861
    return;
 
862
  if ((! peak_includes_equals)
 
863
      && ((peak_min & (! data->min_modified))
 
864
          || (peak_max & (! data->max_modified))))
 
865
      return;
 
866
 
 
867
  switch (image_type)
 
868
    {
 
869
    case GIMP_RGB_IMAGE:
 
870
      value_chs = 3;
 
871
      break;
 
872
    case GIMP_RGBA_IMAGE:
 
873
      value_chs = 3;
 
874
      alpha = 3;
 
875
      break;
 
876
    case GIMP_GRAY_IMAGE:
 
877
      value_chs = 1;
 
878
      break;
 
879
    case GIMP_GRAYA_IMAGE:
 
880
      value_chs = 1;
 
881
      alpha = 1;
 
882
      break;
 
883
    default:
 
884
      break;
 
885
    }
 
886
  for (ch = 0; ch < value_chs; ch++)
 
887
    {
 
888
      if (vpvals.propagating_channel & PROPAGATING_VALUE) /* value channel */
 
889
        *dest++ = (guchar)(vpvals.propagating_rate * 0.5 * (data->min[ch] + data->max[ch])
 
890
                       + (1.0 - vpvals.propagating_rate) * here[ch]);
 
891
      else
 
892
        *dest++ = here[ch];
 
893
    }
 
894
  if (alpha)
 
895
    {
 
896
      if (vpvals.propagating_channel & PROPAGATING_ALPHA) /* alpha channel */
 
897
        *dest++ = (guchar)(vpvals.propagating_rate * best[alpha]
 
898
                       + (1.0 - vpvals.propagating_rate) * here[alpha]);
 
899
      else
 
900
        *dest++ = here[alpha];
 
901
    }
 
902
}
 
903
 
 
904
static void
 
905
set_foreground_to_peak (GimpImageBaseType  image_type,
 
906
                        gint               channels,
 
907
                        guchar            *here,
 
908
                        guchar            *best,
 
909
                        guchar            *dest,
 
910
                        void              *tmp)
 
911
{
 
912
  gint  value_chs = 0;
 
913
  gint  alpha = 0;
 
914
  gint  ch;
 
915
  MiddlePacket  *data;
 
916
 
 
917
  data = (MiddlePacket *)tmp;
 
918
  if (! ((peak_min & (data->minv == data->original_value))
 
919
         || (peak_max & (data->maxv == data->original_value))))
 
920
    return;
 
921
  if (peak_includes_equals
 
922
      && ((peak_min & (! data->min_modified))
 
923
          || (peak_max & (! data->max_modified))))
 
924
      return;
 
925
 
 
926
  switch (image_type)
 
927
    {
 
928
    case GIMP_RGB_IMAGE:
 
929
      value_chs = 3;
 
930
      break;
 
931
    case GIMP_RGBA_IMAGE:
 
932
      value_chs = 3;
 
933
      alpha = 3;
 
934
      break;
 
935
    case GIMP_GRAY_IMAGE:
 
936
      value_chs = 1;
 
937
      break;
 
938
    case GIMP_GRAYA_IMAGE:
 
939
      value_chs = 1;
 
940
      alpha = 1;
 
941
      break;
 
942
    default:
 
943
      break;
 
944
    }
 
945
  for (ch = 0; ch < value_chs; ch++)
 
946
    {
 
947
      if (vpvals.propagating_channel & PROPAGATING_VALUE) /* value channel */
 
948
        *dest++ = (guchar)(vpvals.propagating_rate*fore[ch]
 
949
                       + (1.0 - vpvals.propagating_rate)*here[ch]);
 
950
      else
 
951
        *dest++ = here[ch];
 
952
    }
 
953
}
 
954
 
 
955
static void
 
956
initialize_foreground (GimpImageBaseType   image_type,
 
957
                       gint                channels,
 
958
                       guchar             *here,
 
959
                       guchar             *best,
 
960
                       void              **tmp)
 
961
{
 
962
  GimpRGB  foreground;
 
963
  guchar  *ch;
 
964
 
 
965
  if (*tmp == NULL)
 
966
    {
 
967
      *tmp = (void *) g_new (guchar, 3);
 
968
      ch = (guchar *)*tmp;
 
969
      gimp_context_get_foreground (&foreground);
 
970
      gimp_rgb_get_uchar (&foreground, &ch[0], &ch[1], &ch[2]);
 
971
    }
 
972
}
 
973
 
 
974
static void
 
975
initialize_background (GimpImageBaseType   image_type,
 
976
                       gint                channels,
 
977
                       guchar             *here,
 
978
                       guchar             *best,
 
979
                       void              **tmp)
 
980
{
 
981
  GimpRGB  background;
 
982
  guchar  *ch;
 
983
 
 
984
  if (*tmp == NULL)
 
985
    {
 
986
      *tmp = (void *) g_new (guchar, 3);
 
987
      ch = (guchar *)*tmp;
 
988
      gimp_context_get_background (&background);
 
989
      gimp_rgb_get_uchar (&background, &ch[0], &ch[1], &ch[2]);
 
990
    }
 
991
}
 
992
 
 
993
static void
 
994
propagate_a_color (GimpImageBaseType  image_type,
 
995
                   gint               channels,
 
996
                   guchar            *orig,
 
997
                   guchar            *here,
 
998
                   guchar            *best,
 
999
                   void              *tmp)
 
1000
{
 
1001
  guchar *fg = (guchar *)tmp;
 
1002
 
 
1003
  switch (image_type)
 
1004
    {
 
1005
    case GIMP_RGB_IMAGE:
 
1006
    case GIMP_RGBA_IMAGE:
 
1007
      if (here[0] == fg[0] && here[1] == fg[1] && here[2] == fg[2] &&
 
1008
          value_difference_check(orig, here, 3))
 
1009
        {
 
1010
          memcpy (best, here, 3 * sizeof(guchar)); /* alpha channel holds old value */
 
1011
        }
 
1012
      break;
 
1013
    case GIMP_GRAYA_IMAGE:
 
1014
    case GIMP_GRAY_IMAGE:
 
1015
      break;
 
1016
    default:
 
1017
      break;
 
1018
    }
 
1019
}
 
1020
 
 
1021
static void
 
1022
propagate_opaque (GimpImageBaseType  image_type,
 
1023
                  gint               channels,
 
1024
                  guchar            *orig,
 
1025
                  guchar            *here,
 
1026
                  guchar            *best,
 
1027
                  void              *tmp)
 
1028
{
 
1029
  switch (image_type)
 
1030
    {
 
1031
    case GIMP_RGBA_IMAGE:
 
1032
      if (best[3] < here[3] && value_difference_check(orig, here, 3))
 
1033
        memcpy(best, here, channels * sizeof(guchar));
 
1034
      break;
 
1035
    case GIMP_GRAYA_IMAGE:
 
1036
      if (best[1] < here[1] && value_difference_check(orig, here, 1))
 
1037
        memcpy(best, here, channels * sizeof(guchar));
 
1038
      break;
 
1039
    default:
 
1040
      break;
 
1041
    }
 
1042
}
 
1043
 
 
1044
static void
 
1045
propagate_transparent (GimpImageBaseType  image_type,
 
1046
                       gint               channels,
 
1047
                       guchar            *orig,
 
1048
                       guchar            *here,
 
1049
                       guchar            *best,
 
1050
                       void              *tmp)
 
1051
{
 
1052
  switch (image_type)
 
1053
    {
 
1054
    case GIMP_RGBA_IMAGE:
 
1055
      if (here[3] < best[3] && value_difference_check(orig, here, 3))
 
1056
        memcpy(best, here, channels * sizeof(guchar));
 
1057
      break;
 
1058
    case GIMP_GRAYA_IMAGE:
 
1059
      if (here[1] < best[1] && value_difference_check(orig, here, 1))
 
1060
        memcpy(best, here, channels * sizeof(guchar));
 
1061
      break;
 
1062
    default:
 
1063
      break;
 
1064
    }
 
1065
}
 
1066
 
 
1067
/* dialog stuff */
 
1068
 
 
1069
static gboolean
 
1070
vpropagate_dialog (GimpDrawable *drawable)
 
1071
{
 
1072
  GtkWidget *dialog;
 
1073
  GtkWidget *main_vbox;
 
1074
  GtkWidget *hbox;
 
1075
  GtkWidget *frame;
 
1076
  GtkWidget *table;
 
1077
  GtkWidget *toggle_vbox;
 
1078
  GtkWidget *button;
 
1079
  GtkObject *adj;
 
1080
  GSList    *group = NULL;
 
1081
  gint       index = 0;
 
1082
  gboolean   run;
 
1083
 
 
1084
  gimp_ui_init (PLUG_IN_BINARY, FALSE);
 
1085
 
 
1086
  dialog = gimp_dialog_new (_("Value Propagate"), PLUG_IN_BINARY,
 
1087
                            NULL, 0,
 
1088
                            gimp_standard_help_func, VPROPAGATE_PROC,
 
1089
 
 
1090
                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 
1091
                            GTK_STOCK_OK,     GTK_RESPONSE_OK,
 
1092
 
 
1093
                            NULL);
 
1094
 
 
1095
  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
 
1096
                                           GTK_RESPONSE_OK,
 
1097
                                           GTK_RESPONSE_CANCEL,
 
1098
                                           -1);
 
1099
 
 
1100
  gimp_window_set_transient (GTK_WINDOW (dialog));
 
1101
 
 
1102
  main_vbox = gtk_vbox_new (FALSE, 12);
 
1103
  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
 
1104
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
 
1105
  gtk_widget_show (main_vbox);
 
1106
 
 
1107
  preview = gimp_drawable_preview_new (drawable, NULL);
 
1108
  gtk_box_pack_start (GTK_BOX (main_vbox), preview, TRUE, TRUE, 0);
 
1109
  gtk_widget_show (preview);
 
1110
 
 
1111
  g_signal_connect_swapped (preview, "invalidated",
 
1112
                            G_CALLBACK (value_propagate_body),
 
1113
                            drawable);
 
1114
 
 
1115
  hbox = gtk_hbox_new (FALSE, 12);
 
1116
  gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
 
1117
  gtk_widget_show (hbox);
 
1118
 
 
1119
  /* Propagate Mode */
 
1120
  frame = gimp_frame_new (_("Mode"));
 
1121
  gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
 
1122
  gtk_widget_show (frame);
 
1123
 
 
1124
  toggle_vbox = gtk_vbox_new (FALSE, 2);
 
1125
  gtk_container_add (GTK_CONTAINER (frame), toggle_vbox);
 
1126
  gtk_widget_show (toggle_vbox);
 
1127
 
 
1128
  for (index = 0; index < num_mode; index++)
 
1129
    {
 
1130
      button =
 
1131
        gtk_radio_button_new_with_mnemonic (group,
 
1132
                                            gettext (modes[index].name));
 
1133
      group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
 
1134
      gtk_box_pack_start (GTK_BOX (toggle_vbox), button, FALSE, FALSE, 0);
 
1135
      gtk_widget_show (button);
 
1136
 
 
1137
      g_object_set_data (G_OBJECT (button), "gimp-item-data",
 
1138
                         GINT_TO_POINTER (index));
 
1139
 
 
1140
      g_signal_connect (button, "toggled",
 
1141
                        G_CALLBACK (gimp_radio_button_update),
 
1142
                        &vpvals.propagate_mode);
 
1143
      g_signal_connect_swapped (button, "toggled",
 
1144
                                G_CALLBACK (gimp_preview_invalidate),
 
1145
                                preview);
 
1146
 
 
1147
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
 
1148
                                    index == vpvals.propagate_mode);
 
1149
    }
 
1150
 
 
1151
  /* Parameter settings */
 
1152
  frame = gimp_frame_new (_("Propagate"));
 
1153
  gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
 
1154
  gtk_widget_show (frame);
 
1155
 
 
1156
  table = gtk_table_new (8, 3, FALSE); /* 4 raw, 2 columns(name and value) */
 
1157
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
1158
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
 
1159
  gtk_table_set_row_spacing (GTK_TABLE (table), 2, 12);
 
1160
  gtk_table_set_row_spacing (GTK_TABLE (table), 5, 12);
 
1161
  gtk_container_add (GTK_CONTAINER (frame), table);
 
1162
  gtk_widget_show (table);
 
1163
 
 
1164
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
 
1165
                              _("Lower t_hreshold:"), SCALE_WIDTH, 4,
 
1166
                              vpvals.lower_limit, 0, 255, 1, 8, 0,
 
1167
                              TRUE, 0, 0,
 
1168
                              NULL, NULL);
 
1169
  g_signal_connect (adj, "value-changed",
 
1170
                    G_CALLBACK (gimp_int_adjustment_update),
 
1171
                    &vpvals.lower_limit);
 
1172
  g_signal_connect_swapped (adj, "value-changed",
 
1173
                            G_CALLBACK (gimp_preview_invalidate),
 
1174
                            preview);
 
1175
 
 
1176
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
 
1177
                              _("_Upper threshold:"), SCALE_WIDTH, 4,
 
1178
                              vpvals.upper_limit, 0, 255, 1, 8, 0,
 
1179
                              TRUE, 0, 0,
 
1180
                              NULL, NULL);
 
1181
  g_signal_connect (adj, "value-changed",
 
1182
                    G_CALLBACK (gimp_int_adjustment_update),
 
1183
                    &vpvals.upper_limit);
 
1184
  g_signal_connect_swapped (adj, "value-changed",
 
1185
                            G_CALLBACK (gimp_preview_invalidate),
 
1186
                            preview);
 
1187
 
 
1188
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
 
1189
                              _("_Propagating rate:"), SCALE_WIDTH, 4,
 
1190
                              vpvals.propagating_rate, 0, 1, 0.01, 0.1, 2,
 
1191
                              TRUE, 0, 0,
 
1192
                              NULL, NULL);
 
1193
  g_signal_connect (adj, "value-changed",
 
1194
                    G_CALLBACK (gimp_double_adjustment_update),
 
1195
                    &vpvals.propagating_rate);
 
1196
  g_signal_connect_swapped (adj, "value-changed",
 
1197
                            G_CALLBACK (gimp_preview_invalidate),
 
1198
                            preview);
 
1199
 
 
1200
  gtk_table_add_toggle (table, _("To l_eft"), 0, 1, 4,
 
1201
                        G_CALLBACK (vpropagate_toggle_button_update),
 
1202
                        &direction_mask_vec[Right2Left]);
 
1203
  gtk_table_add_toggle (table, _("To _right"), 2, 3, 4,
 
1204
                        G_CALLBACK (vpropagate_toggle_button_update),
 
1205
                        &direction_mask_vec[Left2Right]);
 
1206
  gtk_table_add_toggle (table, _("To _top"), 1, 2, 3,
 
1207
                        G_CALLBACK (vpropagate_toggle_button_update),
 
1208
                        &direction_mask_vec[Bottom2Top]);
 
1209
  gtk_table_add_toggle (table, _("To _bottom"), 1, 2, 5,
 
1210
                        G_CALLBACK (vpropagate_toggle_button_update),
 
1211
                        &direction_mask_vec[Top2Bottom]);
 
1212
 
 
1213
  if (gimp_drawable_has_alpha (drawable->drawable_id))
 
1214
    {
 
1215
      GtkWidget *toggle;
 
1216
 
 
1217
      toggle =
 
1218
        gtk_table_add_toggle (table, _("Propagating _alpha channel"),
 
1219
                              0, 3, 6,
 
1220
                              G_CALLBACK (vpropagate_toggle_button_update),
 
1221
                              &propagate_alpha);
 
1222
 
 
1223
      if (gimp_layer_get_lock_alpha (drawable->drawable_id))
 
1224
        {
 
1225
          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), 0);
 
1226
          gtk_widget_set_sensitive (toggle, FALSE);
 
1227
        }
 
1228
 
 
1229
      gtk_table_add_toggle (table, _("Propagating value channel"), 0, 3, 7,
 
1230
                            G_CALLBACK (vpropagate_toggle_button_update),
 
1231
                            &propagate_value);
 
1232
    }
 
1233
 
 
1234
  gtk_widget_show (dialog);
 
1235
 
 
1236
  run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
 
1237
 
 
1238
  if (run)
 
1239
    {
 
1240
      gint i, result;
 
1241
 
 
1242
      for (i = result = 0; i < 4; i++)
 
1243
        result |= (direction_mask_vec[i] ? 1 : 0) << i;
 
1244
      vpvals.direction_mask = result;
 
1245
 
 
1246
      vpvals.propagating_channel = ((propagate_alpha ? PROPAGATING_ALPHA : 0) |
 
1247
                                    (propagate_value ? PROPAGATING_VALUE : 0));
 
1248
    }
 
1249
 
 
1250
  gtk_widget_destroy (dialog);
 
1251
 
 
1252
  return run;
 
1253
}
 
1254
 
 
1255
static void
 
1256
vpropagate_toggle_button_update (GtkWidget *widget,
 
1257
                                 gpointer   data)
 
1258
{
 
1259
  gint i, result;
 
1260
 
 
1261
  gimp_toggle_button_update (widget, data);
 
1262
 
 
1263
  for (i = result = 0; i < 4; i++)
 
1264
    result |= (direction_mask_vec[i] ? 1 : 0) << i;
 
1265
  vpvals.direction_mask = result;
 
1266
 
 
1267
  vpvals.propagating_channel = ((propagate_alpha ? PROPAGATING_ALPHA : 0) |
 
1268
                                (propagate_value ? PROPAGATING_VALUE : 0));
 
1269
  gimp_preview_invalidate (GIMP_PREVIEW (preview));
 
1270
}
 
1271
 
 
1272
static GtkWidget *
 
1273
gtk_table_add_toggle (GtkWidget   *table,
 
1274
                      const gchar *name,
 
1275
                      gint         x1,
 
1276
                      gint         x2,
 
1277
                      gint         y,
 
1278
                      GCallback    update,
 
1279
                      gint        *value)
 
1280
{
 
1281
  GtkWidget *toggle;
 
1282
 
 
1283
  toggle = gtk_check_button_new_with_mnemonic(name);
 
1284
  gtk_table_attach (GTK_TABLE (table), toggle, x1, x2, y, y+1,
 
1285
                    GTK_FILL|GTK_EXPAND, 0, 0, 0);
 
1286
  gtk_widget_show (toggle);
 
1287
 
 
1288
  g_signal_connect (toggle, "toggled",
 
1289
                    G_CALLBACK (update),
 
1290
                    value);
 
1291
 
 
1292
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), *value);
 
1293
 
 
1294
  return toggle;
 
1295
}