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 (¢erPreview, ¢erFrame,
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 (¢erVbox, 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