1 /*
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This is a plug-in for GIMP.
5  *
6  * Copyright (C) Pavel Grinfeld (pavel@ml.com)
7  *
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
21  */
22 
23 #include "config.h"
24 
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include <libgimp/gimp.h>
29 #include <libgimp/gimpui.h>
30 
31 #include "libgimp/stdplugins-intl.h"
32 
33 
34 #define PLUG_IN_PROC       "plug-in-filter-pack"
35 #define PLUG_IN_BINARY     "filter-pack"
36 #define PLUG_IN_ROLE       "gimp-filter-pack"
37 
38 #define MAX_PREVIEW_SIZE   125
39 #define MAX_ROUGHNESS      128
40 #define RANGE_HEIGHT       15
41 #define PR_BX_BRDR         4
42 #define MARGIN             4
43 
44 #define RANGE_ADJUST_MASK (GDK_EXPOSURE_MASK       | \
45                            GDK_ENTER_NOTIFY_MASK   | \
46                            GDK_BUTTON_PRESS_MASK   | \
47                            GDK_BUTTON_RELEASE_MASK | \
48                            GDK_BUTTON1_MOTION_MASK | \
49                            GDK_POINTER_MOTION_HINT_MASK)
50 
51 
52 typedef struct
53 {
54   gboolean run;
55 } fpInterface;
56 
57 typedef struct
58 {
59   gint       width;
60   gint       height;
61   guchar    *rgb;
62   gdouble   *hsv;
63   guchar    *mask;
64 } ReducedImage;
65 
66 typedef enum
67 {
68   SHADOWS,
69   MIDTONES,
70   HIGHLIGHTS,
71   INTENSITIES
72 } FPIntensity;
73 
74 enum
75 {
76   NONEATALL  = 0,
77   CURRENT    = 1,
78   HUE        = 2,
79   SATURATION = 4,
80   VALUE      = 8
81 };
82 
83 enum
84 {
85   BY_HUE,
86   BY_SAT,
87   BY_VAL,
88   JUDGE_BY
89 };
90 
91 enum
92 {
93   RED,
94   GREEN,
95   BLUE,
96   CYAN,
97   YELLOW,
98   MAGENTA,
99   ALL_PRIMARY
100 };
101 
102 enum
103 {
104   DOWN = -1,
105   UP   =  1
106 };
107 
108 typedef struct
109 {
110   GtkWidget *window;
111   GtkWidget *range_preview;
112   GtkWidget *aliasing_preview;
113   GtkWidget *aliasing_graph;
114 } AdvancedWindow;
115 
116 
117 typedef struct
118 {
119   gdouble       roughness;
120   gdouble       aliasing;
121   gdouble       preview_size;
122   FPIntensity   intensity_range;
123   gint          value_by;
124   gint          selection_only;
125   guchar        offset;
126   guchar        visible_frames;
127   guchar        cutoff[INTENSITIES];
128   gboolean      touched[JUDGE_BY];
129   gint          red_adjust[JUDGE_BY][256];
130   gint          blue_adjust[JUDGE_BY][256];
131   gint          green_adjust[JUDGE_BY][256];
132   gint          sat_adjust[JUDGE_BY][256];
133 } FPValues;
134 
135 typedef struct
136 {
137   GtkWidget    *roughness_scale;
138   GtkWidget    *aliasing_scale;
139   GtkWidget    *preview_size_scale;
140   GtkWidget    *range_label[12];
141 } FPWidgets;
142 
143 static void           fp_show_hide_frame          (GtkWidget     *button,
144                                                    GtkWidget     *frame);
145 
146 static ReducedImage * fp_reduce_image             (GimpDrawable  *drawable,
147                                                    GimpDrawable  *mask,
148                                                    gint           longer_size,
149                                                    gint           selection);
150 
151 static void           fp_render_preview           (GtkWidget     *preview,
152                                                    gint           change_what,
153                                                    gint           change_which);
154 
155 static void           update_current_fp           (gint           change_what,
156                                                    gint           change_which);
157 
158 static void           fp_create_nudge             (gint          *adj_array);
159 
160 static gboolean       fp_dialog                   (void);
161 static void           fp_advanced_dialog          (GtkWidget     *parent);
162 
163 static void           fp_selection_made           (GtkWidget     *widget,
164                                                    gpointer       data);
165 static void           fp_scale_update             (GtkAdjustment *adjustment,
166                                                    gdouble        *scale_val);
167 static void           fp_reset_filter_packs       (void);
168 
169 static void           fp_create_smoothness_graph  (GtkWidget     *preview);
170 
171 static void           fp_range_preview_spill      (GtkWidget     *preview,
172                                                    gint           type);
173 static void           fp_adjust_preview_sizes     (gint           width,
174                                                    gint           height);
175 static void           fp_redraw_all_windows       (void);
176 static void           fp_refresh_previews         (gint           which);
177 static void           fp_init_filter_packs        (void);
178 
179 static void           fp_preview_scale_update     (GtkAdjustment *adjustment,
180                                                    gdouble       *scale_val);
181 
182 static void           fp                          (GimpDrawable  *drawable);
183 static GtkWidget *    fp_create_bna               (void);
184 static GtkWidget *    fp_create_rough             (void);
185 static GtkWidget *    fp_create_range             (void);
186 static GtkWidget *    fp_create_circle_palette    (GtkWidget     *parent);
187 static GtkWidget *    fp_create_lnd               (GtkWidget     *parent);
188 static GtkWidget *    fp_create_show              (void);
189 static GtkWidget *    fp_create_msnls             (GtkWidget     *parent);
190 static GtkWidget *    fp_create_pixels_select_by  (void);
191 static void           update_range_labels         (void);
192 static gboolean       fp_range_change_events      (GtkWidget     *widget,
193                                                    GdkEvent      *event,
194                                                    FPValues      *current);
195 
196 static void           fp_create_preview           (GtkWidget    **preview,
197                                                    GtkWidget    **frame,
198                                                    gint           preview_width,
199                                                    gint           preview_height);
200 
201 static void           fp_create_table_entry      (GtkWidget     **box,
202                                                   GtkWidget      *smaller_frame,
203                                                   const gchar    *description);
204 
205 static void         fp_frames_checkbutton_in_box (GtkWidget      *vbox,
206                                                   const gchar    *label,
207                                                   GCallback       func,
208                                                   GtkWidget      *frame,
209                                                   gboolean        clicked);
210 
211 static void             fp_preview_size_allocate (GtkWidget      *widget,
212                                                   GtkAllocation  *allocation);
213 
214 #define RESPONSE_RESET 1
215 
216 /* These values are translated for the GUI but also used internally
217    to figure out which button the user pushed, etc.
218    Not my design, please don't blame me -- njl */
219 
220 static const gchar *hue_red     = N_("Red:");
221 static const gchar *hue_green   = N_("Green:");
222 static const gchar *hue_blue    = N_("Blue:");
223 static const gchar *hue_cyan    = N_("Cyan:");
224 static const gchar *hue_yellow  = N_("Yellow:");
225 static const gchar *hue_magenta = N_("Magenta:");
226 
227 static const gchar *val_darker  = N_("Darker:");
228 static const gchar *val_lighter = N_("Lighter:");
229 
230 static const gchar *sat_more    = N_("More Sat:");
231 static const gchar *sat_less    = N_("Less Sat:");
232 
233 static const gchar *current_val = N_("Current:");
234 
235 static const gint colorSign[3][ALL_PRIMARY]=
236 {{1,-1,-1,-1,1,1},{-1,1,-1,1,1,-1},{-1,-1,1,1,-1,1}};
237 
238 static AdvancedWindow AW = { NULL, NULL, NULL, NULL };
239 
240 static FPWidgets fp_widgets = { NULL, NULL, NULL };
241 
242 static gint nudgeArray[256];
243 
244 static GtkWidget *origPreview, *curPreview;
245 static GtkWidget *rPreview, *gPreview, *bPreview;
246 static GtkWidget *cPreview, *yPreview, *mPreview;
247 static GtkWidget *centerPreview;
248 static GtkWidget *darkerPreview, *lighterPreview, *middlePreview;
249 static GtkWidget *dlg;
250 static GtkWidget *plusSatPreview, *SatPreview, *minusSatPreview;
251 
252 static struct
253 {
254   GtkWidget *bna;
255   GtkWidget *palette;
256   GtkWidget *rough;
257   GtkWidget *range;
258   GtkWidget *show;
259   GtkWidget *lnd;
260   GtkWidget *pixelsBy;
261   GtkWidget *frameSelect;
262   GtkWidget *satur;
263 } fp_frames;
264 
265 static fpInterface FPint =
266 {
267   FALSE   /*  run  */
268 };
269 
270 static ReducedImage *reduced;
271 
272 static FPValues fpvals =
273 {
274   .25,                    /* Initial Roughness */
275   .6,                     /* Initial Degree of Aliasing */
276   80,                     /* Initial preview size */
277   MIDTONES,               /* Initial Range */
278   BY_VAL,                 /* Initial God knows what */
279   TRUE,                   /* Selection Only */
280   0,                      /* Offset */
281   0,                      /* Visible frames */
282   { 32, 224, 255 },       /* cutoffs */
283   { FALSE, FALSE, FALSE } /* touched */
284 };
285 
286 static GimpDrawable *drawable = NULL;
287 static GimpDrawable *mask     = NULL;
288 
289 static void      query  (void);
290 static void      run    (const gchar      *name,
291                          gint              nparams,
292                          const GimpParam  *param,
293                          gint             *nreturn_vals,
294                          GimpParam       **return_vals);
295 
296 const GimpPlugInInfo PLUG_IN_INFO =
297 {
298   NULL,  /* init_proc  */
299   NULL,  /* quit_proc  */
300   query, /* query_proc */
301   run,   /* run_proc   */
302 };
303 
MAIN()304 MAIN()
305 
306 static void
307 query (void)
308 {
309   GimpParamDef args[] =
310   {
311     { GIMP_PDB_INT32,    "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }"          },
312     { GIMP_PDB_IMAGE,    "image",    "Input image (used for indexed images)" },
313     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable"                        }
314   };
315 
316   gimp_install_procedure (PLUG_IN_PROC,
317                           N_("Interactively modify the image colors"),
318                           "Interactively modify the image colors.",
319                           "Pavel Grinfeld (pavel@ml.com)",
320                           "Pavel Grinfeld (pavel@ml.com)",
321                           "27th March 1997",
322                           N_("_Filter Pack..."),
323                           "RGB*",
324                           GIMP_PLUGIN,
325                           G_N_ELEMENTS (args), 0,
326                           args, NULL);
327 }
328 
329 /********************************STANDARD RUN*************************/
330 
331 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)332 run (const gchar      *name,
333      gint              nparams,
334      const GimpParam  *param,
335      gint             *nreturn_vals,
336      GimpParam       **return_vals)
337 {
338   static GimpParam  values[1];
339   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
340   GimpRunMode       run_mode;
341 
342   *nreturn_vals = 1;
343   *return_vals = values;
344 
345   run_mode = param[0].data.d_int32;
346 
347   INIT_I18N ();
348 
349   values[0].type = GIMP_PDB_STATUS;
350   values[0].data.d_status = status;
351 
352   fp_init_filter_packs();
353 
354   drawable = gimp_drawable_get (param[2].data.d_drawable);
355 
356   if (gimp_selection_is_empty (param[1].data.d_image))
357     mask = NULL;
358   else
359     mask = gimp_drawable_get (gimp_image_get_selection (param[1].data.d_image));
360 
361   switch (run_mode)
362     {
363     case GIMP_RUN_INTERACTIVE:
364       /*  Possibly retrieve data  */
365       gimp_get_data (PLUG_IN_PROC, &fpvals);
366 
367       if (gimp_drawable_is_indexed (drawable->drawable_id) ||
368           gimp_drawable_is_gray (drawable->drawable_id) )
369         {
370           gimp_message (_("FP can only be used on RGB images."));
371           status = GIMP_PDB_EXECUTION_ERROR;
372         }
373       else if (! fp_dialog())
374         {
375           status = GIMP_PDB_CANCEL;
376         }
377       break;
378 
379     case GIMP_RUN_NONINTERACTIVE:
380       gimp_message (_("FP can only be run interactively."));
381       status = GIMP_PDB_CALLING_ERROR;
382       break;
383 
384     case GIMP_RUN_WITH_LAST_VALS:
385       /*  Possibly retrieve data  */
386       gimp_get_data (PLUG_IN_PROC, &fpvals);
387       break;
388 
389     default:
390       break;
391     }
392 
393   if (status == GIMP_PDB_SUCCESS)
394     {
395       /*  Make sure that the drawable is gray or RGB color  */
396       if (gimp_drawable_is_rgb (drawable->drawable_id))
397         {
398           gimp_progress_init (_("Applying filter pack"));
399           gimp_tile_cache_ntiles (2 * (drawable->width /
400                                        gimp_tile_width () + 1));
401           fp (drawable);
402 
403           /*  Store data  */
404           if (run_mode == GIMP_RUN_INTERACTIVE)
405             gimp_set_data (PLUG_IN_PROC, &fpvals, sizeof (FPValues));
406 
407           gimp_displays_flush ();
408         }
409       else
410         {
411           status = GIMP_PDB_EXECUTION_ERROR;
412         }
413     }
414 
415   gimp_drawable_detach (drawable);
416   if (mask)
417     gimp_drawable_detach (mask);
418 
419   values[0].data.d_status = status;
420 }
421 
422 static void
fp_func(const guchar * src,guchar * dest,gint bpp,gpointer data)423 fp_func (const guchar *src,
424          guchar       *dest,
425          gint          bpp,
426          gpointer      data)
427 {
428   gint    bytenum, k;
429   gint    JudgeBy, Intensity = 0, P[3];
430   GimpRGB rgb;
431   GimpHSV hsv;
432   gint    M, m, middle;
433 
434   P[0] = src[0];
435   P[1] = src[1];
436   P[2] = src[2];
437 
438   gimp_rgb_set_uchar (&rgb, (guchar) P[0], (guchar) P[1], (guchar) P[2]);
439   gimp_rgb_to_hsv (&rgb, &hsv);
440 
441   for (JudgeBy = BY_HUE; JudgeBy < JUDGE_BY; JudgeBy++)
442     {
443       if (!fpvals.touched[JudgeBy])
444         continue;
445 
446       switch (JudgeBy)
447         {
448         case BY_HUE:
449           Intensity = 255 * hsv.h;
450           break;
451 
452         case BY_SAT:
453           Intensity = 255 * hsv.s;
454           break;
455 
456         case BY_VAL:
457           Intensity = 255 * hsv.v;
458           break;
459         }
460 
461 
462       /* It's important to take care of Saturation first!!! */
463 
464       m = MIN (MIN (P[0], P[1]), P[2]);
465       M = MAX (MAX (P[0], P[1]), P[2]);
466       middle = (M + m) / 2;
467 
468       for (k = 0; k < 3; k++)
469         if (P[k] != m && P[k] != M)
470           middle = P[k];
471 
472       for (k = 0; k < 3; k++)
473         if (M != m)
474           {
475             if (P[k] == M)
476               P[k] = MAX (P[k] + fpvals.sat_adjust[JudgeBy][Intensity], middle);
477             else if (P[k] == m)
478               P[k] = MIN (P[k] - fpvals.sat_adjust[JudgeBy][Intensity], middle);
479           }
480 
481       P[0] += fpvals.red_adjust[JudgeBy][Intensity];
482       P[1] += fpvals.green_adjust[JudgeBy][Intensity];
483       P[2] += fpvals.blue_adjust[JudgeBy][Intensity];
484 
485       P[0]  = CLAMP0255(P[0]);
486       P[1]  = CLAMP0255(P[1]);
487       P[2]  = CLAMP0255(P[2]);
488     }
489 
490   dest[0] = P[0];
491   dest[1] = P[1];
492   dest[2] = P[2];
493 
494   for (bytenum = 3; bytenum < bpp; bytenum++)
495     dest[bytenum] = src[bytenum];
496 }
497 
498 static void
fp(GimpDrawable * drawable)499 fp (GimpDrawable *drawable)
500 {
501   GimpPixelRgn  srcPR, destPR;
502   gint          x1, y1, x2, y2;
503   gpointer      pr;
504   gint          total_area;
505   gint          area_so_far;
506   gint          count;
507 
508   g_return_if_fail (drawable != NULL);
509 
510   gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
511 
512   total_area  = (x2 - x1) * (y2 - y1);
513   area_so_far = 0;
514 
515   if (total_area <= 0)
516     return;
517 
518   /* Initialize the pixel regions. */
519   gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, (x2 - x1), (y2 - y1),
520                        FALSE, FALSE);
521   gimp_pixel_rgn_init (&destPR, drawable, x1, y1, (x2 - x1), (y2 - y1),
522                        TRUE, TRUE);
523 
524   for (pr = gimp_pixel_rgns_register (2, &srcPR, &destPR), count = 0;
525        pr != NULL;
526        pr = gimp_pixel_rgns_process (pr), count++)
527     {
528       const guchar *src  = srcPR.data;
529       guchar       *dest = destPR.data;
530       gint          row;
531 
532       for (row = 0; row < srcPR.h; row++)
533         {
534           const guchar *s      = src;
535           guchar       *d      = dest;
536           gint          pixels = srcPR.w;
537 
538           while (pixels--)
539             {
540               fp_func (s, d, srcPR.bpp, NULL);
541 
542               s += srcPR.bpp;
543               d += destPR.bpp;
544             }
545 
546           src  += srcPR.rowstride;
547           dest += destPR.rowstride;
548         }
549 
550       area_so_far += srcPR.w * srcPR.h;
551 
552       if ((count % 16) == 0)
553         gimp_progress_update ((gdouble) area_so_far / (gdouble) total_area);
554     }
555 
556   /*  update the processed region  */
557   gimp_drawable_flush (drawable);
558   gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
559   gimp_drawable_update (drawable->drawable_id, x1, y1, (x2 - x1), (y2 - y1));
560 }
561 
562 /***********************************************************/
563 /************   Main Dialog Window   ******************/
564 /***********************************************************/
565 
566 static GtkWidget *
fp_create_bna(void)567 fp_create_bna (void)
568 {
569   GtkWidget *table;
570   GtkWidget *label;
571   GtkWidget *bframe, *aframe;
572 
573   fp_create_preview (&origPreview, &bframe, reduced->width, reduced->height);
574   fp_create_preview (&curPreview, &aframe, reduced->width, reduced->height);
575 
576   table = gtk_table_new (2, 2, FALSE);
577   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
578   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
579 
580   label = gtk_label_new (_("Original:"));
581   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
582                     GTK_SHRINK, GTK_SHRINK, 0, 0);
583   gtk_widget_show (label);
584 
585   gtk_table_attach (GTK_TABLE (table), bframe, 0, 1, 1, 2,
586                     GTK_EXPAND, 0, 0, 0);
587 
588   label = gtk_label_new (_("Current:"));
589   gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
590                     GTK_SHRINK, GTK_SHRINK, 0, 0);
591   gtk_widget_show (label);
592 
593   gtk_table_attach (GTK_TABLE (table), aframe, 1, 2, 1, 2,
594                     GTK_EXPAND, 0, 0, 0);
595 
596   gtk_widget_show (table);
597 
598   return table;
599 }
600 
601 /* close a sub dialog (from window manager) by simulating toggle click */
602 static gboolean
sub_dialog_destroy(GtkWidget * dialog,GdkEvent * ev,gpointer dummy)603 sub_dialog_destroy (GtkWidget *dialog,
604                     GdkEvent  *ev,
605                     gpointer   dummy)
606 {
607   GtkWidget *button =
608     GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), "ctrlButton"));
609 
610   gtk_button_clicked (GTK_BUTTON (button));
611 
612   return TRUE;
613 }
614 
615 static GtkWidget *
fp_create_circle_palette(GtkWidget * parent)616 fp_create_circle_palette (GtkWidget *parent)
617 {
618   GtkWidget *table;
619   GtkWidget *rVbox, *rFrame;
620   GtkWidget *gVbox, *gFrame;
621   GtkWidget *bVbox, *bFrame;
622   GtkWidget *cVbox, *cFrame;
623   GtkWidget *yVbox, *yFrame;
624   GtkWidget *mVbox, *mFrame;
625   GtkWidget *centerVbox, *centerFrame;
626   GtkWidget *win;
627 
628   win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
629 
630   gimp_help_connect (win, gimp_standard_help_func, PLUG_IN_PROC, NULL);
631 
632   gtk_window_set_title (GTK_WINDOW (win), _("Hue Variations"));
633   gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (parent));
634 
635   g_signal_connect (win, "delete-event",
636                     G_CALLBACK (sub_dialog_destroy),
637                     NULL);
638 
639   table = gtk_table_new (11, 11, FALSE);
640   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
641   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
642   gtk_container_set_border_width (GTK_CONTAINER (table), 12);
643   gtk_container_add (GTK_CONTAINER (win), table);
644   gtk_widget_show (table);
645 
646   fp_create_preview (&rPreview, &rFrame, reduced->width, reduced->height);
647   fp_create_preview (&gPreview, &gFrame, reduced->width, reduced->height);
648   fp_create_preview (&bPreview, &bFrame, reduced->width, reduced->height);
649   fp_create_preview (&cPreview, &cFrame, reduced->width, reduced->height);
650   fp_create_preview (&yPreview, &yFrame, reduced->width, reduced->height);
651   fp_create_preview (&mPreview, &mFrame, reduced->width, reduced->height);
652   fp_create_preview (&centerPreview, &centerFrame,
653                      reduced->width, reduced->height);
654 
655   fp_create_table_entry (&rVbox, rFrame, hue_red);
656   fp_create_table_entry (&gVbox, gFrame, hue_green);
657   fp_create_table_entry (&bVbox, bFrame, hue_blue);
658   fp_create_table_entry (&cVbox, cFrame, hue_cyan);
659   fp_create_table_entry (&yVbox, yFrame, hue_yellow);
660   fp_create_table_entry (&mVbox, mFrame, hue_magenta);
661   fp_create_table_entry (&centerVbox, centerFrame, current_val);
662 
663   gtk_table_attach (GTK_TABLE (table), rVbox, 8, 11 ,4 , 7,
664                     GTK_EXPAND , GTK_EXPAND, 0 ,0);
665   gtk_table_attach (GTK_TABLE (table), gVbox, 2, 5, 0, 3,
666                     GTK_EXPAND, GTK_EXPAND, 0, 0);
667   gtk_table_attach (GTK_TABLE (table), bVbox, 2, 5, 8, 11,
668                     GTK_EXPAND, GTK_EXPAND,0,0);
669   gtk_table_attach (GTK_TABLE (table), cVbox, 0, 3, 4, 7,
670                     GTK_EXPAND, GTK_EXPAND, 0 ,0);
671   gtk_table_attach (GTK_TABLE (table), yVbox, 6, 9, 0, 3,
672                     GTK_EXPAND, GTK_EXPAND, 0 ,0);
673   gtk_table_attach (GTK_TABLE (table), mVbox, 6, 9, 8, 11,
674                     GTK_EXPAND, GTK_EXPAND, 0 ,0);
675   gtk_table_attach (GTK_TABLE (table), centerVbox, 4, 7, 4, 7,
676                     GTK_EXPAND, GTK_EXPAND, 0 ,0);
677 
678   return win;
679 }
680 
681 static GtkWidget *
fp_create_rough(void)682 fp_create_rough (void)
683 {
684   GtkWidget     *frame, *vbox, *scale;
685   GtkAdjustment *data;
686 
687   frame = gimp_frame_new (_("Roughness"));
688   gtk_widget_show (frame);
689 
690   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
691   gtk_container_add (GTK_CONTAINER (frame), vbox);
692   gtk_widget_show (vbox);
693 
694   data = (GtkAdjustment *)
695     gtk_adjustment_new (fpvals.roughness, 0, 1.0, 0.05, 0.01, 0.0);
696   fp_widgets.roughness_scale = scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL,
697                                                       data);
698 
699   gtk_widget_set_size_request (scale, 60, -1);
700   gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
701   gtk_scale_set_digits (GTK_SCALE (scale), 2);
702   gtk_widget_show (scale);
703 
704   g_signal_connect (data, "value-changed",
705                     G_CALLBACK (fp_scale_update),
706                     &fpvals.roughness);
707 
708   gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
709 
710   return frame;
711 }
712 
713 static void
fp_change_current_range(GtkWidget * widget,gpointer data)714 fp_change_current_range (GtkWidget *widget,
715                          gpointer   data)
716 {
717   gimp_radio_button_update (widget, data);
718 
719   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
720     {
721       fp_refresh_previews (fpvals.visible_frames);
722       if (AW.window && gtk_widget_get_visible (AW.window))
723         fp_create_smoothness_graph (AW.aliasing_preview);
724     }
725 }
726 
727 static GtkWidget *
fp_create_range(void)728 fp_create_range (void)
729 {
730   GtkWidget *frame;
731 
732   frame = gimp_int_radio_group_new (TRUE, _("Affected Range"),
733                                     G_CALLBACK (fp_change_current_range),
734                                     &fpvals.intensity_range, fpvals.intensity_range,
735 
736                                     _("Sha_dows"),    SHADOWS,    NULL,
737                                     _("_Midtones"),   MIDTONES,   NULL,
738                                     _("H_ighlights"), HIGHLIGHTS, NULL,
739 
740                                     NULL);
741 
742   gtk_widget_show (frame);
743 
744   return frame;
745 }
746 
747 static GtkWidget *
fp_create_control(void)748 fp_create_control (void)
749 {
750   GtkWidget *frame, *box;
751 
752   frame = gimp_frame_new (_("Windows"));
753 
754   box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
755   gtk_container_add (GTK_CONTAINER (frame), box);
756   gtk_widget_show (box);
757 
758   fp_frames_checkbutton_in_box (box, _("_Hue"),
759                                 G_CALLBACK (fp_show_hide_frame),
760                                 fp_frames.palette,
761                                 fpvals.visible_frames & HUE);
762   fp_frames_checkbutton_in_box (box, _("_Saturation"),
763                                 G_CALLBACK (fp_show_hide_frame),
764                                 fp_frames.satur,
765                                 fpvals.visible_frames & SATURATION);
766   fp_frames_checkbutton_in_box (box, _("_Value"),
767                                 G_CALLBACK (fp_show_hide_frame),
768                                 fp_frames.lnd,
769                                 fpvals.visible_frames & VALUE);
770   fp_frames_checkbutton_in_box (box, _("A_dvanced"),
771                                 G_CALLBACK (fp_show_hide_frame),
772                                 AW.window,
773                                 FALSE);
774   gtk_widget_show (frame);
775 
776   return frame;
777 }
778 
779 static GtkWidget *
fp_create_lnd(GtkWidget * parent)780 fp_create_lnd (GtkWidget *parent)
781 {
782   GtkWidget *table, *lighterFrame, *middleFrame, *darkerFrame;
783   GtkWidget *lighterVbox, *middleVbox, *darkerVbox;
784   GtkWidget *win;
785 
786   win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
787 
788   gimp_help_connect (win, gimp_standard_help_func, PLUG_IN_PROC, NULL);
789 
790   gtk_window_set_title (GTK_WINDOW (win), _("Value Variations"));
791   gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (parent));
792 
793   g_signal_connect (win, "delete-event",
794                     G_CALLBACK (sub_dialog_destroy),
795                     NULL);
796 
797   fp_create_preview (&lighterPreview, &lighterFrame,
798                     reduced->width, reduced->height);
799   fp_create_preview (&middlePreview, &middleFrame,
800                     reduced->width, reduced->height);
801   fp_create_preview (&darkerPreview, &darkerFrame,
802                     reduced->width, reduced->height);
803 
804   fp_create_table_entry (&lighterVbox, lighterFrame, val_lighter);
805   fp_create_table_entry (&middleVbox, middleFrame, current_val);
806   fp_create_table_entry (&darkerVbox, darkerFrame, val_darker);
807 
808   table = gtk_table_new (1, 11, FALSE);
809   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
810   gtk_container_set_border_width (GTK_CONTAINER (table), 12);
811   gtk_container_add (GTK_CONTAINER (win), table);
812   gtk_widget_show (table);
813 
814   gtk_table_attach (GTK_TABLE (table), lighterVbox, 0, 3, 0, 1,
815                     GTK_EXPAND , GTK_EXPAND, 0, 0);
816   gtk_table_attach (GTK_TABLE (table), middleVbox, 4, 7, 0, 1,
817                     GTK_EXPAND, GTK_EXPAND, 0, 0);
818   gtk_table_attach (GTK_TABLE (table), darkerVbox, 8, 11, 0, 1,
819                     GTK_EXPAND, GTK_EXPAND, 0, 0);
820 
821   return win;
822 }
823 
824 static GtkWidget *
fp_create_msnls(GtkWidget * parent)825 fp_create_msnls (GtkWidget *parent)
826 {
827   GtkWidget *table, *lessFrame, *middleFrame, *moreFrame;
828   GtkWidget *lessVbox, *middleVbox, *moreVbox;
829   GtkWidget *win;
830 
831   win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
832 
833   gimp_help_connect (win, gimp_standard_help_func, PLUG_IN_PROC, NULL);
834 
835   gtk_window_set_title (GTK_WINDOW (win), _("Saturation Variations"));
836   gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (parent));
837 
838   g_signal_connect (win, "delete-event",
839                     G_CALLBACK (sub_dialog_destroy),
840                     NULL);
841 
842   fp_create_preview (&minusSatPreview, &lessFrame,
843                     reduced->width, reduced->height);
844   fp_create_preview (&SatPreview, &middleFrame,
845                     reduced->width, reduced->height);
846   fp_create_preview (&plusSatPreview, &moreFrame,
847                     reduced->width, reduced->height);
848 
849   fp_create_table_entry (&moreVbox, moreFrame, sat_more);
850   fp_create_table_entry (&middleVbox, middleFrame, current_val);
851   fp_create_table_entry (&lessVbox, lessFrame, sat_less);
852 
853   table = gtk_table_new (1, 11, FALSE);
854   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
855   gtk_container_set_border_width (GTK_CONTAINER (table), 12);
856   gtk_container_add (GTK_CONTAINER (win), table);
857   gtk_widget_show (table);
858 
859   gtk_table_attach (GTK_TABLE (table), moreVbox, 0, 3, 0, 1,
860                     GTK_EXPAND, GTK_EXPAND, 0, 0);
861   gtk_table_attach (GTK_TABLE (table), middleVbox, 4, 7, 0, 1,
862                     GTK_EXPAND, GTK_EXPAND, 0, 0);
863   gtk_table_attach (GTK_TABLE (table), lessVbox, 8, 11, 0, 1,
864                     GTK_EXPAND, GTK_EXPAND, 0, 0);
865 
866   return win;
867 }
868 
869 static void
fp_change_current_pixels_by(GtkWidget * widget,gpointer data)870 fp_change_current_pixels_by (GtkWidget *widget,
871                              gpointer   data)
872 {
873   gimp_radio_button_update (widget, data);
874 
875   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
876     {
877       fp_refresh_previews (fpvals.visible_frames);
878       if (AW.window && gtk_widget_get_visible (AW.window) && AW.range_preview)
879         fp_range_preview_spill (AW.range_preview,fpvals.value_by);
880     }
881 }
882 
883 static GtkWidget *
fp_create_pixels_select_by(void)884 fp_create_pixels_select_by (void)
885 {
886   GtkWidget *frame;
887 
888   frame = gimp_int_radio_group_new (TRUE, _("Select Pixels By"),
889                                     G_CALLBACK (fp_change_current_pixels_by),
890                                     &fpvals.value_by,
891                                     fpvals.value_by,
892 
893                                     _("H_ue"),  0, NULL,
894                                     _("Satu_ration"), 1, NULL,
895                                     _("V_alue"), 2, NULL,
896 
897                                     NULL);
898 
899   gtk_widget_show (frame);
900 
901   return frame;
902 }
903 
904 static void
fp_change_selection(GtkWidget * widget,gpointer data)905 fp_change_selection (GtkWidget *widget,
906                      gpointer   data)
907 {
908   gimp_radio_button_update (widget, data);
909 
910   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
911     {
912       fp_redraw_all_windows ();
913     }
914 }
915 
916 static GtkWidget *
fp_create_show(void)917 fp_create_show (void)
918 {
919   GtkWidget *frame;
920 
921   frame = gimp_int_radio_group_new (TRUE, _("Show"),
922                                     G_CALLBACK (fp_change_selection),
923                                     &fpvals.selection_only,
924                                     fpvals.selection_only,
925 
926                                     _("_Entire image"),  0, NULL,
927                                     _("Se_lection only"), 1, NULL,
928                                     _("Selec_tion in context"), 2, NULL,
929 
930                                     NULL);
931 
932   gtk_widget_show (frame);
933 
934   return frame;
935 }
936 
937 static void
fp_create_preview(GtkWidget ** preview,GtkWidget ** frame,gint preview_width,gint preview_height)938 fp_create_preview (GtkWidget **preview,
939                   GtkWidget  **frame,
940                   gint         preview_width,
941                   gint         preview_height)
942 {
943   *frame = gtk_frame_new (NULL);
944   gtk_frame_set_shadow_type (GTK_FRAME (*frame), GTK_SHADOW_IN);
945   gtk_widget_show (*frame);
946 
947   *preview = gimp_preview_area_new ();
948   gtk_widget_set_size_request (*preview, preview_width, preview_height);
949   g_signal_connect (*preview, "size-allocate",
950                     G_CALLBACK (fp_preview_size_allocate), NULL);
951   gtk_widget_show (*preview);
952   gtk_container_add (GTK_CONTAINER (*frame), *preview);
953 }
954 
955 static void
fp_frames_checkbutton_in_box(GtkWidget * vbox,const gchar * label,GCallback function,GtkWidget * frame,gboolean clicked)956 fp_frames_checkbutton_in_box (GtkWidget     *vbox,
957                               const gchar   *label,
958                               GCallback      function,
959                               GtkWidget     *frame,
960                               gboolean       clicked)
961 {
962   GtkWidget *button;
963 
964   button = gtk_check_button_new_with_mnemonic (label);
965   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
966   g_object_set_data (G_OBJECT (frame), "ctrlButton", (gpointer) button);
967   gtk_widget_show (button);
968 
969   g_signal_connect (button, "clicked",
970                     function,
971                     frame);
972 
973   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), clicked);
974 }
975 
976 static void
fp_create_table_entry(GtkWidget ** box,GtkWidget * smaller_frame,const gchar * description)977 fp_create_table_entry (GtkWidget   **box,
978                       GtkWidget    *smaller_frame,
979                       const gchar  *description)
980 {
981   GtkWidget *label;
982   GtkWidget *button;
983   GtkWidget *table;
984 
985   *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 1);
986   gtk_container_set_border_width (GTK_CONTAINER (*box), PR_BX_BRDR);
987   gtk_widget_show (*box);
988 
989   /* Delayed translation applied here */
990   label = gtk_label_new (gettext (description));
991 
992   gtk_label_set_xalign (GTK_LABEL (label), 0.0);
993   gtk_widget_show (label);
994 
995   table = gtk_table_new (2, 1, FALSE);
996   gtk_widget_show (table);
997 
998   gtk_box_pack_start (GTK_BOX (*box), table, TRUE, TRUE, 0);
999 
1000   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
1001                     0, 0, 0, 0);
1002 
1003   if (description != current_val)
1004     {
1005       button = gtk_button_new ();
1006       gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2,
1007                         0, 0, 0, 4);
1008       gtk_widget_show (button);
1009 
1010       gtk_container_add (GTK_CONTAINER (button), smaller_frame);
1011 
1012       g_signal_connect (button, "clicked",
1013                         G_CALLBACK (fp_selection_made),
1014                         (gchar *) description);
1015     }
1016   else
1017     {
1018       gtk_table_attach (GTK_TABLE (table), smaller_frame, 0, 1, 1, 2,
1019                         0, 0, 0, 4);
1020     }
1021 }
1022 
1023 static void
fp_redraw_all_windows(void)1024 fp_redraw_all_windows (void)
1025 {
1026   if (reduced)
1027     {
1028       g_free (reduced->rgb);
1029       g_free (reduced->hsv);
1030       g_free (reduced->mask);
1031 
1032       g_free (reduced);
1033     }
1034 
1035   reduced = fp_reduce_image (drawable, mask,
1036                              fpvals.preview_size,
1037                              fpvals.selection_only);
1038 
1039   fp_adjust_preview_sizes (reduced->width, reduced->height);
1040 
1041   gtk_widget_queue_draw (fp_frames.palette);
1042   gtk_widget_queue_draw (fp_frames.satur);
1043   gtk_widget_queue_draw (fp_frames.lnd);
1044   gtk_widget_queue_draw (dlg);
1045 
1046   fp_refresh_previews (fpvals.visible_frames);
1047 }
1048 
1049 static void
fp_show_hide_frame(GtkWidget * button,GtkWidget * frame)1050 fp_show_hide_frame (GtkWidget *button,
1051                     GtkWidget *frame)
1052 {
1053   gint prev = fpvals.visible_frames;
1054 
1055   if (frame == NULL)
1056     return;
1057 
1058   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
1059     {
1060       if (! gtk_widget_get_visible (frame))
1061         {
1062           gtk_widget_show (frame);
1063 
1064           if (frame==fp_frames.palette)
1065             fpvals.visible_frames |= HUE;
1066           else if (frame==fp_frames.satur)
1067             fpvals.visible_frames |= SATURATION;
1068           else if (frame==fp_frames.lnd)
1069             fpvals.visible_frames |= VALUE;
1070 
1071           fp_refresh_previews (fpvals.visible_frames & ~prev);
1072           fp_create_smoothness_graph (AW.aliasing_preview);
1073           fp_range_preview_spill (AW.range_preview,fpvals.value_by);
1074         }
1075     }
1076   else
1077     {
1078       if (gtk_widget_get_visible (frame))
1079         {
1080           gtk_widget_hide (frame);
1081 
1082           if (frame==fp_frames.palette)
1083             fpvals.visible_frames &= ~HUE;
1084           else if (frame==fp_frames.satur)
1085             fpvals.visible_frames &= ~SATURATION;
1086           else if (frame==fp_frames.lnd)
1087             fpvals.visible_frames &= ~VALUE;
1088         }
1089     }
1090 }
1091 
1092 static void
fp_adjust_preview_sizes(gint width,gint height)1093 fp_adjust_preview_sizes (gint width,
1094                          gint height)
1095 {
1096   gtk_widget_set_size_request (origPreview,     width, height);
1097   gtk_widget_set_size_request (curPreview,      width, height);
1098   gtk_widget_set_size_request (rPreview,        width, height);
1099   gtk_widget_set_size_request (gPreview,        width, height);
1100   gtk_widget_set_size_request (bPreview,        width, height);
1101   gtk_widget_set_size_request (cPreview,        width, height);
1102   gtk_widget_set_size_request (yPreview,        width, height);
1103   gtk_widget_set_size_request (mPreview,        width, height);
1104   gtk_widget_set_size_request (centerPreview,   width, height);
1105   gtk_widget_set_size_request (lighterPreview,  width, height);
1106   gtk_widget_set_size_request (darkerPreview,   width, height);
1107   gtk_widget_set_size_request (middlePreview,   width, height);
1108   gtk_widget_set_size_request (minusSatPreview, width, height);
1109   gtk_widget_set_size_request (SatPreview,      width, height);
1110   gtk_widget_set_size_request (plusSatPreview,  width, height);
1111 
1112 }
1113 
1114 static void
fp_selection_made(GtkWidget * widget,gpointer data)1115 fp_selection_made (GtkWidget *widget,
1116                    gpointer   data)
1117 {
1118   fpvals.touched[fpvals.value_by] = TRUE;
1119 
1120   if (data == (gpointer) hue_red)
1121     {
1122       update_current_fp (HUE, RED);
1123     }
1124   else if (data == (gpointer) hue_green)
1125     {
1126       update_current_fp (HUE, GREEN);
1127     }
1128   else if (data == (gpointer) hue_blue)
1129     {
1130       update_current_fp (HUE, BLUE);
1131     }
1132   else if (data == (gpointer) hue_cyan)
1133     {
1134       update_current_fp (HUE, CYAN);
1135     }
1136   else if (data == (gpointer) hue_yellow)
1137     {
1138       update_current_fp (HUE, YELLOW);
1139     }
1140   else if (data == (gpointer) hue_magenta)
1141     {
1142       update_current_fp (HUE, MAGENTA);
1143     }
1144   else if (data == (gpointer) val_darker)
1145     {
1146       update_current_fp (VALUE, DOWN);
1147     }
1148   else if (data == (gpointer) val_lighter)
1149     {
1150       update_current_fp (VALUE, UP);
1151     }
1152   else if (data == (gpointer) sat_more)
1153     {
1154       update_current_fp (SATURATION, UP);
1155     }
1156   else if (data == (gpointer) sat_less)
1157     {
1158       update_current_fp (SATURATION, DOWN);
1159     }
1160 
1161   fp_refresh_previews (fpvals.visible_frames);
1162 }
1163 
1164 static void
fp_refresh_previews(gint which)1165 fp_refresh_previews (gint which)
1166 {
1167   fp_create_nudge (nudgeArray);
1168   fp_render_preview (origPreview, NONEATALL, 0);
1169   fp_render_preview (curPreview, CURRENT, 0);
1170 
1171   if (which & HUE)
1172     {
1173       fp_render_preview (rPreview,        HUE,        RED);
1174       fp_render_preview (gPreview,        HUE,        GREEN);
1175       fp_render_preview (bPreview,        HUE,        BLUE);
1176       fp_render_preview (cPreview,        HUE,        CYAN);
1177       fp_render_preview (yPreview,        HUE,        YELLOW);
1178       fp_render_preview (mPreview,        HUE,        MAGENTA);
1179       fp_render_preview (centerPreview,   CURRENT,    0);
1180     }
1181 
1182   if (which & VALUE)
1183     {
1184       fp_render_preview (lighterPreview,  VALUE,      UP);
1185       fp_render_preview (middlePreview,   CURRENT,    0);
1186       fp_render_preview (darkerPreview,   VALUE,      DOWN);
1187     }
1188 
1189   if (which & SATURATION)
1190     {
1191       fp_render_preview (plusSatPreview,  SATURATION, UP);
1192       fp_render_preview (SatPreview,      CURRENT,    0);
1193       fp_render_preview (minusSatPreview, SATURATION, DOWN);
1194     }
1195 }
1196 
1197 static void
fp_response(GtkWidget * widget,gint response_id,gpointer data)1198 fp_response (GtkWidget *widget,
1199              gint       response_id,
1200              gpointer   data)
1201 {
1202   switch (response_id)
1203     {
1204     case RESPONSE_RESET:
1205       fp_reset_filter_packs ();
1206       break;
1207 
1208     case GTK_RESPONSE_OK:
1209       FPint.run = TRUE;
1210       gtk_widget_destroy (widget);
1211       break;
1212 
1213     default:
1214       gtk_widget_destroy (widget);
1215       break;
1216     }
1217 }
1218 
1219 static void
fp_scale_update(GtkAdjustment * adjustment,gdouble * scale_val)1220 fp_scale_update (GtkAdjustment *adjustment,
1221                  gdouble       *scale_val)
1222 {
1223   static gdouble prevValue = 0.25;
1224 
1225   *scale_val = gtk_adjustment_get_value (adjustment);
1226 
1227   if (prevValue != gtk_adjustment_get_value (adjustment))
1228     {
1229       fp_create_nudge (nudgeArray);
1230       fp_refresh_previews (fpvals.visible_frames);
1231 
1232       if (AW.window != NULL && gtk_widget_get_visible (AW.window))
1233         fp_create_smoothness_graph (AW.aliasing_preview);
1234 
1235       prevValue = gtk_adjustment_get_value (adjustment);
1236     }
1237 }
1238 
1239 static gboolean
fp_dialog(void)1240 fp_dialog (void)
1241 {
1242   GtkWidget *bna;
1243   GtkWidget *palette;
1244   GtkWidget *lnd;
1245   GtkWidget *show;
1246   GtkWidget *rough;
1247   GtkWidget *range;
1248   GtkWidget *pixelsBy;
1249   GtkWidget *satur;
1250   GtkWidget *control;
1251   GtkWidget *table;
1252 
1253   reduced = fp_reduce_image (drawable, mask,
1254                              fpvals.preview_size,
1255                              fpvals.selection_only);
1256 
1257   gimp_ui_init (PLUG_IN_BINARY, FALSE);
1258 
1259   dlg = gimp_dialog_new (_("Filter Pack Simulation"), PLUG_IN_ROLE,
1260                          NULL, 0,
1261                          gimp_standard_help_func, PLUG_IN_PROC,
1262 
1263                          _("_Reset"),  RESPONSE_RESET,
1264                          _("_Cancel"), GTK_RESPONSE_CANCEL,
1265                          _("_OK"),     GTK_RESPONSE_OK,
1266 
1267                          NULL);
1268 
1269   gtk_dialog_set_alternative_button_order (GTK_DIALOG (dlg),
1270                                            RESPONSE_RESET,
1271                                            GTK_RESPONSE_OK,
1272                                            GTK_RESPONSE_CANCEL,
1273                                            -1);
1274 
1275   gimp_window_set_transient (GTK_WINDOW (dlg));
1276 
1277   g_signal_connect (dlg, "response",
1278                     G_CALLBACK (fp_response),
1279                     dlg);
1280 
1281   g_signal_connect (dlg, "destroy",
1282                     G_CALLBACK (gtk_main_quit),
1283                     NULL);
1284 
1285   fp_advanced_dialog (dlg);
1286 
1287   fp_frames.bna          = bna          = fp_create_bna ();
1288   fp_frames.rough        = rough        = fp_create_rough ();
1289   fp_frames.range        = range        = fp_create_range ();
1290   fp_frames.palette      = palette      = fp_create_circle_palette (dlg);
1291   fp_frames.lnd          = lnd          = fp_create_lnd (dlg);
1292   fp_frames.show         = show         = fp_create_show ();
1293   fp_frames.satur        = satur        = fp_create_msnls (dlg);
1294   fp_frames.pixelsBy     = pixelsBy     = fp_create_pixels_select_by ();
1295                            control      = fp_create_control ();
1296   /********************************************************************/
1297   /********************   PUT EVERYTHING TOGETHER    ******************/
1298 
1299   table = gtk_table_new (4, 2, FALSE);
1300   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1301   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1302   gtk_container_set_border_width (GTK_CONTAINER (table), 12);
1303   gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
1304                       table, TRUE, TRUE, 0);
1305   gtk_widget_show (table);
1306 
1307   gtk_table_attach (GTK_TABLE (table), bna, 0, 2, 0, 1,
1308                     GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
1309 
1310   gtk_table_attach (GTK_TABLE (table), control, 1, 2, 1, 3,
1311                     GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
1312 
1313   gtk_table_attach (GTK_TABLE (table), rough, 1, 2, 3, 4,
1314                     GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
1315 
1316   gtk_table_attach (GTK_TABLE (table), show, 0, 1, 1, 2,
1317                     GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
1318 
1319   gtk_table_attach (GTK_TABLE (table), range, 0, 1, 2, 3,
1320                     GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
1321 
1322   gtk_table_attach (GTK_TABLE (table), pixelsBy, 0, 1, 3, 4,
1323                     GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
1324 
1325   gtk_widget_show (dlg);
1326 
1327   fp_refresh_previews (fpvals.visible_frames);
1328 
1329   gtk_main ();
1330 
1331   return FPint.run;
1332 }
1333 
1334 /***********************************************************/
1335 /************   Advanced Options Window   ******************/
1336 /***********************************************************/
1337 
1338 static void
fp_preview_scale_update(GtkAdjustment * adjustment,gdouble * scale_val)1339 fp_preview_scale_update (GtkAdjustment *adjustment,
1340                          gdouble        *scale_val)
1341 {
1342   fpvals.preview_size = gtk_adjustment_get_value (adjustment);
1343   fp_redraw_all_windows();
1344 }
1345 
1346 static void
fp_advanced_dialog(GtkWidget * parent)1347 fp_advanced_dialog (GtkWidget *parent)
1348 {
1349   const gchar *rangeNames[] = { N_("Shadows:"),
1350                                 N_("Midtones:"),
1351                                 N_("Highlights:") };
1352   GtkWidget     *frame, *hbox;
1353   GtkAdjustment *smoothnessData;
1354   GtkWidget     *graphFrame, *scale;
1355   GtkWidget     *vbox, *label, *labelTable, *alignment;
1356   GtkWidget     *inner_vbox, *innermost_vbox;
1357   gint           i;
1358 
1359   AW.window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1360 
1361   gimp_help_connect (AW.window, gimp_standard_help_func, PLUG_IN_PROC, NULL);
1362 
1363   gtk_window_set_title (GTK_WINDOW (AW.window),
1364                         _("Advanced Filter Pack Options"));
1365   gtk_window_set_transient_for (GTK_WINDOW (AW.window), GTK_WINDOW (parent));
1366 
1367   g_signal_connect (AW.window, "delete-event",
1368                     G_CALLBACK (sub_dialog_destroy),
1369                     NULL);
1370 
1371   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1372   gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
1373   gtk_container_add (GTK_CONTAINER (AW.window), hbox);
1374   gtk_widget_show (hbox);
1375 
1376   frame = gimp_frame_new (_("Affected Range"));
1377   gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
1378   gtk_widget_show (frame);
1379 
1380   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1381   gtk_container_add (GTK_CONTAINER (frame), vbox);
1382   gtk_widget_show (vbox);
1383 
1384   graphFrame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1, TRUE);
1385   gtk_frame_set_shadow_type (GTK_FRAME (graphFrame), GTK_SHADOW_IN);
1386   gtk_container_set_border_width (GTK_CONTAINER (graphFrame), 0);
1387   gtk_box_pack_start (GTK_BOX (vbox), graphFrame, FALSE, FALSE, 0);
1388   gtk_widget_show (graphFrame);
1389 
1390   inner_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1391   gtk_container_add (GTK_CONTAINER (graphFrame), inner_vbox);
1392   gtk_widget_show (inner_vbox);
1393 
1394   alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1395   gtk_box_pack_start (GTK_BOX (inner_vbox), alignment, TRUE, TRUE, 0);
1396   gtk_widget_show (alignment);
1397 
1398   innermost_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1399   gtk_container_add (GTK_CONTAINER (alignment), innermost_vbox);
1400   gtk_widget_show (innermost_vbox);
1401 
1402   AW.aliasing_preview = gimp_preview_area_new ();
1403   gtk_widget_set_size_request (AW.aliasing_preview, 256, MAX_ROUGHNESS);
1404   gtk_box_pack_start (GTK_BOX (innermost_vbox),
1405                       AW.aliasing_preview, TRUE, TRUE, 0);
1406   gtk_widget_show (AW.aliasing_preview);
1407 
1408   fp_create_smoothness_graph (AW.aliasing_preview);
1409 
1410   AW.range_preview = gimp_preview_area_new ();
1411   gtk_widget_set_size_request (AW.range_preview, 256, RANGE_HEIGHT);
1412   gtk_box_pack_start(GTK_BOX (innermost_vbox),
1413                      AW.range_preview, TRUE, TRUE, 0);
1414   gtk_widget_show (AW.range_preview);
1415 
1416   fp_range_preview_spill (AW.range_preview, fpvals.value_by);
1417 
1418   labelTable = gtk_table_new (3, 4, FALSE);
1419   gtk_table_set_col_spacings (GTK_TABLE (labelTable), 6);
1420   gtk_table_set_row_spacings (GTK_TABLE (labelTable), 6);
1421   gtk_box_pack_start (GTK_BOX (vbox), labelTable, FALSE, FALSE, 0);
1422   gtk_widget_show (labelTable);
1423 
1424   /************************************************************/
1425 
1426   AW.aliasing_graph = gtk_drawing_area_new ();
1427   gtk_widget_set_size_request (AW.aliasing_graph,
1428                                2 * MARGIN + 256,
1429                                RANGE_HEIGHT);
1430   gtk_box_pack_start (GTK_BOX (inner_vbox), AW.aliasing_graph, TRUE, TRUE, 0);
1431   gtk_widget_show (AW.aliasing_graph);
1432   gtk_widget_set_events (AW.aliasing_graph, RANGE_ADJUST_MASK);
1433 
1434   g_signal_connect (AW.aliasing_graph, "event",
1435                     G_CALLBACK (fp_range_change_events),
1436                     &fpvals);
1437 
1438   /************************************************************/
1439 
1440   for (i = 0; i < 12; i++)
1441     {
1442       label = fp_widgets.range_label[i] = gtk_label_new ("-");
1443 
1444       if (!(i % 4))
1445         {
1446           gtk_label_set_text (GTK_LABEL(label), gettext (rangeNames[i/4]));
1447           gimp_label_set_attributes (GTK_LABEL (label),
1448                                      PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
1449                                      -1);
1450           gtk_label_set_xalign (GTK_LABEL (label), 1.0);
1451           gtk_label_set_yalign (GTK_LABEL (label), 1.0);
1452         }
1453 
1454       gtk_widget_show (label);
1455       gtk_table_attach (GTK_TABLE (labelTable), label, i%4, i%4+1, i/4, i/4+1,
1456                         GTK_EXPAND | GTK_FILL, 0, 0, 0);
1457     }
1458 
1459   smoothnessData = (GtkAdjustment *)
1460     gtk_adjustment_new (fpvals.aliasing,
1461                         0, 1.0, 0.05, 0.01, 0.0);
1462 
1463   fp_widgets.aliasing_scale = scale =
1464     gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, smoothnessData);
1465   gtk_widget_set_size_request (scale, 200, -1);
1466   gtk_scale_set_digits (GTK_SCALE (scale), 2);
1467   gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
1468   gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
1469   gtk_widget_show (scale);
1470 
1471   g_signal_connect (smoothnessData, "value-changed",
1472                     G_CALLBACK (fp_scale_update),
1473                     &fpvals.aliasing);
1474 
1475   /******************* MISC OPTIONS ***************************/
1476 
1477   frame = gimp_frame_new (_("Preview Size"));
1478   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
1479   gtk_widget_show (frame);
1480 
1481   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1482   gtk_container_add (GTK_CONTAINER (frame), vbox);
1483   gtk_widget_show (vbox);
1484 
1485   smoothnessData = (GtkAdjustment *)
1486     gtk_adjustment_new (fpvals.preview_size,
1487                         50, MAX_PREVIEW_SIZE,
1488                         5, 5, 0.0);
1489 
1490   fp_widgets.preview_size_scale = scale =
1491     gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, smoothnessData);
1492   gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
1493   gtk_widget_set_size_request (scale, 100, -1);
1494   gtk_scale_set_digits (GTK_SCALE (scale), 0);
1495   gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
1496   gtk_widget_show (scale);
1497 
1498   g_signal_connect (smoothnessData, "value-changed",
1499                     G_CALLBACK (fp_preview_scale_update),
1500                     &fpvals.preview_size);
1501 
1502   update_range_labels ();
1503 }
1504 
1505 static void
slider_erase(GdkWindow * window,int xpos)1506 slider_erase (GdkWindow *window,
1507               int        xpos)
1508 {
1509   gdk_window_clear_area (window, MARGIN + xpos - (RANGE_HEIGHT - 1) / 2, 0,
1510                          RANGE_HEIGHT, RANGE_HEIGHT);
1511 }
1512 
1513 static void
draw_slider(cairo_t * cr,GdkColor * border_color,GdkColor * fill_color,gint xpos)1514 draw_slider (cairo_t  *cr,
1515              GdkColor *border_color,
1516              GdkColor *fill_color,
1517              gint      xpos)
1518 {
1519   cairo_move_to (cr, MARGIN + xpos, 0);
1520   cairo_line_to (cr, MARGIN + xpos - (RANGE_HEIGHT - 1) / 2, RANGE_HEIGHT - 1);
1521   cairo_line_to (cr, MARGIN + xpos + (RANGE_HEIGHT - 1) / 2, RANGE_HEIGHT - 1);
1522   cairo_line_to (cr, MARGIN + xpos, 0);
1523 
1524   gdk_cairo_set_source_color (cr, fill_color);
1525   cairo_fill_preserve (cr);
1526 
1527   gdk_cairo_set_source_color (cr, border_color);
1528   cairo_stroke (cr);
1529 }
1530 
1531 static void
draw_it(GtkWidget * widget)1532 draw_it (GtkWidget *widget)
1533 {
1534   GtkStyle *style = gtk_widget_get_style (AW.aliasing_graph);
1535   cairo_t  *cr    = gdk_cairo_create (gtk_widget_get_window (AW.aliasing_graph));
1536 
1537   cairo_translate (cr, 0.5, 0.5);
1538   cairo_set_line_width (cr, 1.0);
1539 
1540   draw_slider (cr,
1541                &style->black,
1542                &style->dark[GTK_STATE_NORMAL],
1543                fpvals.cutoff[SHADOWS]);
1544 
1545   draw_slider (cr,
1546                &style->black,
1547                &style->dark[GTK_STATE_NORMAL],
1548                fpvals.cutoff[MIDTONES]);
1549 
1550   draw_slider (cr,
1551                &style->black,
1552                &style->dark[GTK_STATE_SELECTED],
1553                fpvals.offset);
1554 
1555   cairo_destroy (cr);
1556 }
1557 
1558 static gboolean
fp_range_change_events(GtkWidget * widget,GdkEvent * event,FPValues * current)1559 fp_range_change_events (GtkWidget *widget,
1560                         GdkEvent  *event,
1561                         FPValues *current)
1562 {
1563   GdkEventButton *bevent;
1564   GdkEventMotion *mevent;
1565   gint shad, mid, offset, min;
1566   static guchar  *new;
1567   gint  x;
1568 
1569   switch (event->type)
1570     {
1571     case GDK_EXPOSE:
1572       draw_it (NULL);
1573       break;
1574 
1575     case GDK_BUTTON_PRESS:
1576       bevent= (GdkEventButton *) event;
1577 
1578       shad   =  abs (bevent->x - fpvals.cutoff[SHADOWS]);
1579       mid    =  abs (bevent->x - fpvals.cutoff[MIDTONES]);
1580       offset =  abs (bevent->x - fpvals.offset);
1581 
1582       min = MIN (MIN (shad, mid), offset);
1583 
1584       if (bevent->x >0 && bevent->x<256)
1585         {
1586           if (min == shad)
1587             new = &fpvals.cutoff[SHADOWS];
1588           else if (min == mid)
1589             new = &fpvals.cutoff[MIDTONES];
1590           else
1591             new = &fpvals.offset;
1592 
1593           slider_erase (gtk_widget_get_window (AW.aliasing_graph), *new);
1594           *new = bevent->x;
1595         }
1596 
1597       draw_it (NULL);
1598 
1599       fp_range_preview_spill (AW.range_preview, fpvals.value_by);
1600       update_range_labels ();
1601       fp_create_smoothness_graph (AW.aliasing_preview);
1602       break;
1603 
1604     case GDK_BUTTON_RELEASE:
1605       fp_refresh_previews (fpvals.visible_frames);
1606       break;
1607 
1608     case GDK_MOTION_NOTIFY:
1609       mevent = (GdkEventMotion *) event;
1610       x = mevent->x;
1611 
1612       if (x >= 0 && x < 256)
1613         {
1614           slider_erase (gtk_widget_get_window (AW.aliasing_graph), *new);
1615           *new = x;
1616           draw_it (NULL);
1617           fp_range_preview_spill (AW.range_preview, fpvals.value_by);
1618           update_range_labels ();
1619           fp_create_smoothness_graph (AW.aliasing_preview);
1620         }
1621 
1622       gdk_event_request_motions (mevent);
1623       break;
1624 
1625     default:
1626       break;
1627     }
1628 
1629   return FALSE;
1630 }
1631 
1632 static void
update_range_labels(void)1633 update_range_labels (void)
1634 {
1635   gchar buffer[4];
1636 
1637   gtk_label_set_text (GTK_LABEL(fp_widgets.range_label[1]), "0");
1638 
1639   g_snprintf (buffer, sizeof (buffer), "%d", fpvals.cutoff[SHADOWS]);
1640   gtk_label_set_text (GTK_LABEL (fp_widgets.range_label[3]), buffer);
1641   gtk_label_set_text (GTK_LABEL (fp_widgets.range_label[5]), buffer);
1642 
1643   g_snprintf (buffer, sizeof (buffer), "%d", fpvals.cutoff[MIDTONES]);
1644   gtk_label_set_text (GTK_LABEL (fp_widgets.range_label[7]), buffer);
1645   gtk_label_set_text (GTK_LABEL (fp_widgets.range_label[9]), buffer);
1646 
1647   gtk_label_set_text (GTK_LABEL(fp_widgets.range_label[11]), "255");
1648 }
1649 
1650 static void
fp_init_filter_packs(void)1651 fp_init_filter_packs (void)
1652 {
1653   gint i, j;
1654 
1655   for (i = 0; i < 256; i++)
1656     for (j = BY_HUE; j < JUDGE_BY; j++)
1657       {
1658         fpvals.red_adjust   [j][i] = 0;
1659         fpvals.green_adjust [j][i] = 0;
1660         fpvals.blue_adjust  [j][i] = 0;
1661         fpvals.sat_adjust   [j][i] = 0;
1662       }
1663 }
1664 
1665 static void
fp_reset_filter_packs(void)1666 fp_reset_filter_packs (void)
1667 {
1668   fp_init_filter_packs ();
1669   fp_refresh_previews (fpvals.visible_frames);
1670 }
1671 
1672 static ReducedImage *
fp_reduce_image(GimpDrawable * drawable,GimpDrawable * mask,gint longer_size,gint selection)1673 fp_reduce_image (GimpDrawable *drawable,
1674                  GimpDrawable *mask,
1675                  gint          longer_size,
1676                  gint          selection)
1677 {
1678   gint          RH, RW, bytes = drawable->bpp;
1679   gint          x, y, width, height;
1680   ReducedImage *temp = g_new0 (ReducedImage, 1);
1681   guchar       *tempRGB, *src_row, *tempmask, *src_mask_row, R, G, B;
1682   gint          i, j, whichcol, whichrow;
1683   GimpPixelRgn  srcPR, srcMask;
1684   gdouble      *tempHSV;
1685   GimpRGB       rgb;
1686   GimpHSV       hsv;
1687 
1688   switch (selection)
1689     {
1690     case 0:
1691       x      = 0;
1692       width  = drawable->width;
1693       y      = 0;
1694       height = drawable->height;
1695       break;
1696 
1697     case 1:
1698       if (! gimp_drawable_mask_intersect (drawable->drawable_id,
1699                                           &x, &y, &width, &height))
1700         return temp;
1701       break;
1702 
1703     case 2:
1704       if (! gimp_drawable_mask_intersect (drawable->drawable_id,
1705                                           &x, &y, &width, &height) ||
1706           ! gimp_rectangle_intersect (x - width / 2, y - height / 2,
1707                                       2 * width, 2 * height,
1708                                       0, 0, drawable->width, drawable->height,
1709                                       &x, &y, &width, &height))
1710         return temp;
1711       break;
1712 
1713     default:
1714       return temp;
1715     }
1716 
1717   if (width > height)
1718     {
1719       RW = longer_size;
1720       RH = (gdouble) height * (gdouble) longer_size / (gdouble) width;
1721     }
1722   else
1723     {
1724       RH = longer_size;
1725       RW = (gdouble) width * (gdouble) longer_size / (gdouble) height;
1726     }
1727 
1728   tempRGB  = g_new (guchar, RW * RH * bytes);
1729   tempHSV  = g_new (gdouble, RW * RH * bytes);
1730   tempmask = g_new (guchar, RW * RH);
1731 
1732   src_row      = g_new (guchar, width * bytes);
1733   src_mask_row = g_new (guchar, width);
1734 
1735   gimp_pixel_rgn_init (&srcPR, drawable, x, y, width, height, FALSE, FALSE);
1736 
1737   if (mask)
1738     {
1739       gimp_pixel_rgn_init (&srcMask, mask, x, y, width, height, FALSE, FALSE);
1740     }
1741   else
1742     {
1743       memset (src_mask_row, 255, width);
1744     }
1745 
1746   for (i = 0; i < RH; i++)
1747     {
1748       whichrow = (gdouble) i * (gdouble) height / (gdouble) RH;
1749 
1750       gimp_pixel_rgn_get_row (&srcPR, src_row, x, y + whichrow, width);
1751 
1752       if (mask)
1753         gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x, y + whichrow, width);
1754 
1755       for (j = 0; j < RW; j++)
1756         {
1757           whichcol = (gdouble) j * (gdouble) width / (gdouble) RW;
1758 
1759           tempmask[i * RW + j] = src_mask_row[whichcol];
1760 
1761           R = src_row[whichcol * bytes + 0];
1762           G = src_row[whichcol * bytes + 1];
1763           B = src_row[whichcol * bytes + 2];
1764 
1765           gimp_rgb_set_uchar (&rgb, R, G, B);
1766           gimp_rgb_to_hsv (&rgb, &hsv);
1767 
1768           tempRGB[i * RW * bytes + j * bytes + 0] = R;
1769           tempRGB[i * RW * bytes + j * bytes + 1] = G;
1770           tempRGB[i * RW * bytes + j * bytes + 2] = B;
1771 
1772           tempHSV[i * RW * bytes + j * bytes + 0] = hsv.h;
1773           tempHSV[i * RW * bytes + j * bytes + 1] = hsv.s;
1774           tempHSV[i * RW * bytes + j * bytes + 2] = hsv.v;
1775 
1776           if (bytes == 4)
1777             {
1778               tempRGB[i * RW * bytes + j * bytes + 3] =
1779                 src_row[whichcol * bytes + 3];
1780             }
1781         }
1782     }
1783 
1784   g_free (src_row);
1785   g_free (src_mask_row);
1786 
1787   temp->width  = RW;
1788   temp->height = RH;
1789   temp->rgb    = tempRGB;
1790   temp->hsv    = tempHSV;
1791   temp->mask   = tempmask;
1792 
1793   return temp;
1794 }
1795 
1796 static void
fp_render_preview(GtkWidget * preview,gint change_what,gint change_which)1797 fp_render_preview (GtkWidget *preview,
1798                    gint       change_what,
1799                    gint       change_which)
1800 {
1801   guchar *a;
1802   gint    Inten;
1803   gint    bytes = drawable->bpp;
1804   gint    i, j, k, nudge, M, m, middle, JudgeBy;
1805   gdouble partial;
1806   gint    RW = reduced->width;
1807   gint    RH = reduced->height;
1808   gint    backupP[3];
1809   gint    P[3];
1810   gint    tempSat[JUDGE_BY][256];
1811 
1812   a = g_new (guchar, 4 * RW * RH);
1813 
1814   if (change_what == SATURATION)
1815     for (k = 0; k < 256; k++)
1816       {
1817         for (JudgeBy = BY_HUE; JudgeBy < JUDGE_BY; JudgeBy++)
1818           tempSat[JudgeBy][k] = 0;
1819 
1820         tempSat[fpvals.value_by][k] +=
1821           change_which * nudgeArray[(k + fpvals.offset) % 256];
1822       }
1823 
1824   for (i = 0; i < RH; i++)
1825     {
1826       for (j = 0; j < RW; j++)
1827         {
1828           backupP[0] = P[0] = reduced->rgb[i * RW * bytes + j * bytes + 0];
1829           backupP[1] = P[1] = reduced->rgb[i * RW * bytes + j * bytes + 1];
1830           backupP[2] = P[2] = reduced->rgb[i * RW * bytes + j * bytes + 2];
1831 
1832           m = MIN (MIN (P[0], P[1]), P[2]);
1833           M = MAX (MAX (P[0], P[1]), P[2]);
1834 
1835           middle = (M + m) / 2;
1836 
1837           for (k = 0; k < 3; k++)
1838             if (P[k] != m && P[k] != M) middle = P[k];
1839 
1840           partial = reduced->mask[i * RW + j] / 255.0;
1841 
1842           for (JudgeBy = BY_HUE; JudgeBy < JUDGE_BY; JudgeBy++)
1843             {
1844               if (!fpvals.touched[JudgeBy])
1845                 continue;
1846 
1847               Inten =
1848                 reduced->hsv[i * RW * bytes + j * bytes + JudgeBy] * 255.0;
1849 
1850               /*DO SATURATION FIRST*/
1851               if (change_what != NONEATALL)
1852                 {
1853                   gint adjust = partial * fpvals.sat_adjust[JudgeBy][Inten];
1854 
1855                   if (M != m)
1856                     {
1857                       for (k = 0; k < 3; k++)
1858                         if (backupP[k] == M)
1859                           {
1860                             P[k] = MAX (P[k] + adjust, middle);
1861                           }
1862                         else if (backupP[k] == m)
1863                           {
1864                             P[k] = MIN (P[k] - adjust, middle);
1865                           }
1866                     }
1867 
1868                   P[0] += partial * fpvals.red_adjust[JudgeBy][Inten];
1869                   P[1] += partial * fpvals.green_adjust[JudgeBy][Inten];
1870                   P[2] += partial * fpvals.blue_adjust[JudgeBy][Inten];
1871                 }
1872             }
1873 
1874           Inten =
1875             reduced->hsv[i * RW * bytes + j * bytes + fpvals.value_by] * 255.0;
1876           nudge = partial * nudgeArray[(Inten + fpvals.offset) % 256];
1877 
1878           switch (change_what)
1879             {
1880             case HUE:
1881               P[0] += colorSign[RED][change_which]   * nudge;
1882               P[1] += colorSign[GREEN][change_which] * nudge;
1883               P[2] += colorSign[BLUE][change_which]  * nudge;
1884               break;
1885 
1886             case SATURATION:
1887               for (JudgeBy = BY_HUE; JudgeBy < JUDGE_BY; JudgeBy++)
1888                 {
1889                   gint adjust = partial * tempSat[JudgeBy][Inten];
1890 
1891                   for (k = 0; k < 3; k++)
1892                     if (M != m)
1893                       {
1894                         if (backupP[k] == M)
1895                           {
1896                             P[k] = MAX (P[k] + adjust, middle);
1897                           }
1898                         else if (backupP[k] == m)
1899                           {
1900                             P[k] = MIN (P[k] - adjust, middle);
1901                           }
1902                       }
1903                 }
1904               break;
1905 
1906             case VALUE:
1907               P[0] += change_which * nudge;
1908               P[1] += change_which * nudge;
1909               P[2] += change_which * nudge;
1910               break;
1911 
1912             default:
1913               break;
1914             }
1915 
1916           a[(i * RW + j) * 4 + 0] = CLAMP0255 (P[0]);
1917           a[(i * RW + j) * 4 + 1] = CLAMP0255 (P[1]);
1918           a[(i * RW + j) * 4 + 2] = CLAMP0255 (P[2]);
1919 
1920           if (bytes == 4)
1921             a[(i * RW + j) * 4 + 3] = reduced->rgb[i * RW * bytes + j * bytes + 3];
1922           else
1923             a[(i * RW + j) * 4 + 3] = 255;
1924         }
1925     }
1926 
1927   gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
1928                           0, 0, RW, RH,
1929                           GIMP_RGBA_IMAGE,
1930                           a,
1931                           RW * 4);
1932   g_free (a);
1933 }
1934 
1935 static void
update_current_fp(gint change_what,gint change_which)1936 update_current_fp (gint change_what,
1937                    gint change_which)
1938 {
1939   gint i;
1940 
1941   for (i = 0; i < 256; i++)
1942     {
1943       gint nudge;
1944 
1945       fp_create_nudge (nudgeArray);
1946       nudge = nudgeArray[(i + fpvals.offset) % 256];
1947 
1948       switch (change_what) {
1949       case HUE:
1950         fpvals.red_adjust[fpvals.value_by][i] +=
1951           colorSign[RED][change_which] * nudge;
1952 
1953         fpvals.green_adjust[fpvals.value_by][i] +=
1954           colorSign[GREEN][change_which] * nudge;
1955 
1956         fpvals.blue_adjust[fpvals.value_by][i] +=
1957           colorSign[BLUE][change_which]  * nudge;
1958         break;
1959 
1960       case SATURATION:
1961         fpvals.sat_adjust[fpvals.value_by][i] += change_which * nudge;
1962         break;
1963 
1964       case VALUE:
1965         fpvals.red_adjust[fpvals.value_by][i]   += change_which * nudge;
1966         fpvals.green_adjust[fpvals.value_by][i] += change_which * nudge;
1967         fpvals.blue_adjust[fpvals.value_by][i]  += change_which * nudge;
1968         break;
1969 
1970       default:
1971         break;
1972       }
1973     }
1974 }
1975 
1976 static void
fp_create_smoothness_graph(GtkWidget * preview)1977 fp_create_smoothness_graph (GtkWidget *preview)
1978 {
1979   guchar data[256 * MAX_ROUGHNESS * 3];
1980   gint nArray[256];
1981   gint i, j;
1982   gboolean toBeBlack;
1983 
1984   fp_create_nudge(nArray);
1985 
1986   for (i = 0; i < MAX_ROUGHNESS; i++)
1987     {
1988       gint coor = MAX_ROUGHNESS - i;
1989 
1990       for (j = 0; j < 256; j++)
1991         {
1992           data[3 * (i * 256 + j) + 0] = 255;
1993           data[3 * (i * 256 + j) + 1] = 255;
1994           data[3 * (i * 256 + j) + 2] = 255;
1995 
1996           if (!(i % (MAX_ROUGHNESS / 4)))
1997             {
1998               data[3 * (i * 256 + j) + 0] = 255;
1999               data[3 * (i * 256 + j) + 1] = 128;
2000               data[3 * (i * 256 + j) + 2] = 128;
2001             }
2002 
2003           if (!((j + 1) % 32))
2004             {
2005               data[3 * (i * 256 + j) + 0] = 255;
2006               data[3 * (i * 256 + j) + 1] = 128;
2007               data[3 * (i * 256 + j) + 2] = 128;
2008             }
2009 
2010           toBeBlack = FALSE;
2011 
2012           if (nArray[j] == coor)
2013             toBeBlack = TRUE;
2014 
2015           if (j < 255)
2016             {
2017               gint jump = abs (nArray[j] - nArray[j+1]);
2018 
2019               if (abs (coor - nArray[j]) < jump  &&
2020                   abs (coor - nArray[j + 1]) < jump)
2021                 toBeBlack = TRUE;
2022             }
2023 
2024           if (toBeBlack)
2025             {
2026               data[3 * (i * 256 + j) + 0] = 0;
2027               data[3 * (i * 256 + j) + 1] = 0;
2028               data[3 * (i * 256 + j) + 2] = 0;
2029             }
2030         }
2031     }
2032 
2033   gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
2034                           0, 0, 256, MAX_ROUGHNESS,
2035                           GIMP_RGB_IMAGE,
2036                           data,
2037                           256 * 3);
2038 }
2039 
2040 static void
fp_range_preview_spill(GtkWidget * preview,gint type)2041 fp_range_preview_spill (GtkWidget *preview,
2042                         gint       type)
2043 {
2044   gint   i, j;
2045   guchar data[256 * RANGE_HEIGHT * 3];
2046 
2047   for (i = 0; i < RANGE_HEIGHT; i++)
2048     {
2049       for (j = 0; j < 256; j++)
2050         {
2051           GimpRGB rgb;
2052           GimpHSV hsv;
2053 
2054           if (! ((j + 1) % 32))
2055             {
2056               data[3 * (i * 256 + j) + 0] = 255;
2057               data[3 * (i * 256 + j) + 1] = 128;
2058               data[3 * (i * 256 + j) + 2] = 128;
2059             }
2060           else
2061             {
2062               switch (type)
2063                 {
2064                 case BY_VAL:
2065                   data[3 * (i * 256 + j) + 0] = j - fpvals.offset;
2066                   data[3 * (i * 256 + j) + 1] = j - fpvals.offset;
2067                   data[3 * (i * 256 + j) + 2] = j - fpvals.offset;
2068                   break;
2069 
2070                 case BY_HUE:
2071                   gimp_hsv_set (&hsv,
2072                                 ((j - fpvals.offset + 256) % 256) / 255.0,
2073                                 1.0,
2074                                 0.5);
2075                   gimp_hsv_to_rgb (&hsv, &rgb);
2076                   gimp_rgb_get_uchar (&rgb,
2077                                       &data[3 * (i * 256 + j) + 0],
2078                                       &data[3 * (i * 256 + j) + 1],
2079                                       &data[3 * (i * 256 + j) + 2]);
2080                   break;
2081 
2082                 case BY_SAT:
2083                   gimp_hsv_set (&hsv,
2084                                 0.5,
2085                                 ((j - (gint) fpvals.offset + 256) % 256) / 255.0,
2086                                 0.5);
2087                   gimp_hsv_to_rgb (&hsv, &rgb);
2088                   gimp_rgb_get_uchar (&rgb,
2089                                       &data[3 * (i * 256 + j) + 0],
2090                                       &data[3 * (i * 256 + j) + 1],
2091                                       &data[3 * (i * 256 + j) + 2]);
2092                   break;
2093                 }
2094             }
2095         }
2096     }
2097 
2098   gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
2099                           0, 0, 256, RANGE_HEIGHT,
2100                           GIMP_RGB_IMAGE,
2101                           data,
2102                           256 * 3);
2103 }
2104 
2105 static void
fp_create_nudge(gint * adj_array)2106 fp_create_nudge (gint *adj_array)
2107 {
2108   gint left, right, middle,i;
2109   /* The following function was determined by trial and error */
2110   gdouble Steepness = pow (1 - fpvals.aliasing, 4) * .8;
2111 
2112   left = (fpvals.intensity_range == SHADOWS) ? 0 : fpvals.cutoff[fpvals.intensity_range - 1];
2113   right = fpvals.cutoff[fpvals.intensity_range];
2114   middle = (left + right)/2;
2115 
2116   if (fpvals.aliasing)
2117     for (i = 0; i < 256; i++)
2118       if (i <= middle)
2119         adj_array[i] = MAX_ROUGHNESS *
2120           fpvals.roughness * (1 + tanh (Steepness * (i - left))) / 2;
2121       else
2122         adj_array[i] = MAX_ROUGHNESS *
2123           fpvals.roughness * (1 + tanh (Steepness * (right - i))) / 2;
2124   else
2125     for (i = 0; i < 256; i++)
2126       adj_array[i] = (left <= i && i <= right)
2127         ? MAX_ROUGHNESS * fpvals.roughness : 0;
2128 }
2129 
2130 static void
fp_preview_size_allocate(GtkWidget * widget,GtkAllocation * allocation)2131 fp_preview_size_allocate (GtkWidget     *widget,
2132                           GtkAllocation *allocation)
2133 {
2134   gint which = fpvals.visible_frames;
2135 
2136   if (widget == origPreview)
2137     fp_render_preview (origPreview, NONEATALL, 0);
2138   else if (widget == curPreview)
2139     fp_render_preview (curPreview, CURRENT, 0);
2140 
2141   if (which & HUE)
2142     {
2143       if (widget == rPreview)
2144         fp_render_preview (rPreview,        HUE,        RED);
2145       else if (widget == gPreview)
2146         fp_render_preview (gPreview,        HUE,        GREEN);
2147       else if (widget == bPreview)
2148         fp_render_preview (bPreview,        HUE,        BLUE);
2149       else if (widget == cPreview)
2150         fp_render_preview (cPreview,        HUE,        CYAN);
2151       else if (widget == yPreview)
2152         fp_render_preview (yPreview,        HUE,        YELLOW);
2153       else if (widget == mPreview)
2154         fp_render_preview (mPreview,        HUE,        MAGENTA);
2155       else if (widget == centerPreview)
2156         fp_render_preview (centerPreview,   CURRENT,    0);
2157     }
2158 
2159   if (which & VALUE)
2160     {
2161       if (widget == lighterPreview)
2162         fp_render_preview (lighterPreview,  VALUE,      UP);
2163       else if (widget == middlePreview)
2164         fp_render_preview (middlePreview,   CURRENT,    0);
2165       else if (widget == darkerPreview)
2166         fp_render_preview (darkerPreview,   VALUE,      DOWN);
2167     }
2168 
2169   if (which & SATURATION)
2170     {
2171       if (widget == plusSatPreview)
2172         fp_render_preview (plusSatPreview,  SATURATION, UP);
2173       else if (widget == SatPreview)
2174         fp_render_preview (SatPreview,      CURRENT,    0);
2175       else if (widget == minusSatPreview)
2176         fp_render_preview (minusSatPreview, SATURATION, DOWN);
2177     }
2178 }
2179