1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <gtk/gtk.h>
21 
22 #include <libgimp/gimp.h>
23 #include <libgimp/gimpui.h>
24 
25 #include "gimpressionist.h"
26 #include "ppmtool.h"
27 #include "size.h"
28 #include "infile.h"
29 
30 #include "preview.h"
31 
32 #include "libgimp/stdplugins-intl.h"
33 
34 
35 #define RESPONSE_APPLY 1
36 
37 #define MAPFILE "data.out"
38 
39 static GtkWidget *smwindow;
40 static GtkWidget *smvectorprev;
41 static GtkWidget *smpreviewprev;
42 static GtkWidget *prev_button;
43 static GtkWidget *next_button;
44 static GtkWidget *add_button;
45 static GtkWidget *kill_button;
46 
47 static GtkAdjustment *smvectprevbrightadjust = NULL;
48 
49 static GtkAdjustment *sizadjust = NULL;
50 static GtkAdjustment *smstradjust = NULL;
51 static GtkAdjustment *smstrexpadjust = NULL;
52 static GtkWidget     *size_voronoi = NULL;
53 
54 #define OMWIDTH 150
55 #define OMHEIGHT 150
56 
57 static smvector_t smvector[MAXSIZEVECT];
58 static int numsmvect = 0;
59 
60 static double
getsiz_from_gui(double x,double y)61 getsiz_from_gui (double x, double y)
62 {
63   return getsiz_proto (x,y, numsmvect, smvector,
64                        gtk_adjustment_get_value (smstrexpadjust),
65                        gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (size_voronoi)));
66 }
67 
68 static void
updatesmpreviewprev(void)69 updatesmpreviewprev (void)
70 {
71   gint         x, y;
72   static ppm_t nsbuffer;
73   guchar       black[3] = {0, 0, 0};
74   guchar       gray[3]  = {120, 120, 120};
75 
76   if (! PPM_IS_INITED (&nsbuffer))
77     {
78       ppm_new (&nsbuffer, OMWIDTH, OMHEIGHT);
79     }
80   fill (&nsbuffer, black);
81 
82   for (y = 6; y < OMHEIGHT-4; y += 10)
83     {
84       for (x = 6; x < OMWIDTH-4; x += 10)
85          {
86            gdouble siz = 5 * getsiz_from_gui (x / (double)OMWIDTH,
87                                               y / (double)OMHEIGHT);
88            ppm_drawline (&nsbuffer, x-siz, y-siz, x+siz, y-siz, gray);
89            ppm_drawline (&nsbuffer, x+siz, y-siz, x+siz, y+siz, gray);
90            ppm_drawline (&nsbuffer, x+siz, y+siz, x-siz, y+siz, gray);
91            ppm_drawline (&nsbuffer, x-siz, y+siz, x-siz, y-siz, gray);
92          }
93     }
94 
95 
96   gimp_preview_area_draw (GIMP_PREVIEW_AREA (smpreviewprev),
97                           0, 0, OMWIDTH, OMHEIGHT,
98                           GIMP_RGB_IMAGE,
99                           nsbuffer.col,
100                           OMWIDTH * 3);
101 }
102 
103 static gint selectedsmvector = 0;
104 static ppm_t update_vector_preview_backup = {0,0,NULL};
105 static ppm_t update_vector_preview_sbuffer = {0,0,NULL};
106 
107 static void
updatesmvectorprev(void)108 updatesmvectorprev (void)
109 {
110   static int     ok = 0;
111   gint           i, x, y;
112   gdouble        val;
113   static gdouble last_val = 0.0;
114   guchar         gray[3]  = {120, 120, 120};
115   guchar         red[3]   = {255, 0, 0};
116   guchar         white[3] = {255, 255, 255};
117 
118   if (smvectprevbrightadjust)
119     val = 1.0 - gtk_adjustment_get_value (smvectprevbrightadjust) / 100.0;
120   else
121     val = 0.5;
122 
123   if (!ok || (val != last_val))
124     {
125 #if 0
126       if (!PPM_IS_INITED (&infile))
127          updatepreview (NULL, (void *)2); /* Force grabarea () */
128       ppm_copy (&infile, &update_vector_preview_backup);
129 #else
130       infile_copy_to_ppm (&update_vector_preview_backup);
131 #endif
132       ppm_apply_brightness (&update_vector_preview_backup, val, 1,1,1);
133 
134       if (update_vector_preview_backup.width != OMWIDTH ||
135           update_vector_preview_backup.height != OMHEIGHT)
136          resize_fast (&update_vector_preview_backup, OMWIDTH, OMHEIGHT);
137 
138       ok = 1;
139   }
140   ppm_copy (&update_vector_preview_backup, &update_vector_preview_sbuffer);
141 
142   for (i = 0; i < numsmvect; i++)
143     {
144       x = smvector[i].x * OMWIDTH;
145       y = smvector[i].y * OMHEIGHT;
146       if (i == selectedsmvector)
147       {
148          ppm_drawline (&update_vector_preview_sbuffer, x-5, y, x+5, y, red);
149          ppm_drawline (&update_vector_preview_sbuffer, x, y-5, x, y+5, red);
150       }
151       else
152       {
153          ppm_drawline (&update_vector_preview_sbuffer, x-5, y, x+5, y, gray);
154          ppm_drawline (&update_vector_preview_sbuffer, x, y-5, x, y+5, gray);
155       }
156       ppm_put_rgb (&update_vector_preview_sbuffer, x, y, white);
157   }
158 
159   gimp_preview_area_draw (GIMP_PREVIEW_AREA (smvectorprev),
160                           0, 0, OMWIDTH, OMHEIGHT,
161                           GIMP_RGB_IMAGE,
162                           update_vector_preview_sbuffer.col,
163                           OMWIDTH * 3);
164 
165   gtk_widget_set_sensitive (prev_button, (numsmvect > 1));
166   gtk_widget_set_sensitive (next_button, (numsmvect > 1));
167   gtk_widget_set_sensitive (add_button, (numsmvect < MAXORIENTVECT));
168   gtk_widget_set_sensitive (kill_button, (numsmvect > 1));
169 }
170 
171 void
size_map_free_resources(void)172 size_map_free_resources (void)
173 {
174   ppm_kill (&update_vector_preview_backup);
175   ppm_kill (&update_vector_preview_sbuffer);
176 }
177 
178 static gboolean smadjignore = FALSE;
179 
180 static void
updatesmsliders(void)181 updatesmsliders (void)
182 {
183   smadjignore = TRUE;
184   gtk_adjustment_set_value (sizadjust, smvector[selectedsmvector].siz);
185   gtk_adjustment_set_value (smstradjust, smvector[selectedsmvector].str);
186   smadjignore = FALSE;
187 }
188 
189 static void
smprevclick(GtkWidget * w,gpointer data)190 smprevclick (GtkWidget *w, gpointer data)
191 {
192   selectedsmvector--;
193   if (selectedsmvector < 0)
194     selectedsmvector = numsmvect-1;
195   updatesmsliders ();
196   updatesmvectorprev ();
197 }
198 
199 static void
smnextclick(GtkWidget * w,gpointer data)200 smnextclick (GtkWidget *w, gpointer data)
201 {
202   selectedsmvector++;
203 
204   if (selectedsmvector == numsmvect)
205     selectedsmvector = 0;
206   updatesmsliders ();
207   updatesmvectorprev ();
208 }
209 
210 static void
smaddclick(GtkWidget * w,gpointer data)211 smaddclick (GtkWidget *w, gpointer data)
212 {
213   smvector[numsmvect].x = 0.5;
214   smvector[numsmvect].y = 0.5;
215   smvector[numsmvect].siz = 50.0;
216   smvector[numsmvect].str = 1.0;
217   selectedsmvector = numsmvect;
218   numsmvect++;
219   updatesmsliders ();
220   updatesmvectorprev ();
221   updatesmpreviewprev ();
222 }
223 
224 static void
smdeleteclick(GtkWidget * w,gpointer data)225 smdeleteclick (GtkWidget *w, gpointer data)
226 {
227   int i;
228 
229   for (i = selectedsmvector; i < numsmvect-1; i++)
230     {
231       smvector[i] = smvector[i+1];
232     }
233   numsmvect--;
234   if (selectedsmvector >= numsmvect)
235     selectedsmvector = 0;
236   updatesmsliders ();
237   updatesmvectorprev ();
238   updatesmpreviewprev ();
239 }
240 
241 static void
smmapclick(GtkWidget * w,GdkEventButton * event)242 smmapclick (GtkWidget *w, GdkEventButton *event)
243 {
244   if (event->button == 1)
245     {
246       smvector[selectedsmvector].x = event->x / (double)OMWIDTH;
247       smvector[selectedsmvector].y = event->y / (double)OMHEIGHT;
248     }
249   else if (event->button == 2)
250     {
251       if (numsmvect + 1 == MAXSIZEVECT)
252         return;
253       smvector[numsmvect].x = event->x / (double)OMWIDTH;
254       smvector[numsmvect].y = event->y / (double)OMHEIGHT;
255       smvector[numsmvect].siz = 0.0;
256       smvector[numsmvect].str = 1.0;
257       selectedsmvector = numsmvect;
258       numsmvect++;
259       updatesmsliders ();
260     }
261 #if 0
262   else if (event->button == 3)
263     {
264       double d;
265       d = atan2 (OMWIDTH * smvector[selectedsmvector].x - event->x,
266                  OMHEIGHT * smvector[selectedsmvector].y - event->y);
267       smvector[selectedsmvector].dir = radtodeg (d);
268       updatesmsliders ();
269     */
270   }
271 #endif
272   updatesmvectorprev ();
273   updatesmpreviewprev ();
274 }
275 
276 static void
angsmadjmove(GtkWidget * w,gpointer data)277 angsmadjmove (GtkWidget *w, gpointer data)
278 {
279   if (!smadjignore)
280     {
281       smvector[selectedsmvector].siz = gtk_adjustment_get_value (sizadjust);
282       updatesmvectorprev ();
283       updatesmpreviewprev ();
284     }
285 }
286 
287 static void
strsmadjmove(GtkWidget * w,gpointer data)288 strsmadjmove (GtkWidget *w, gpointer data)
289 {
290   if (!smadjignore)
291     {
292       smvector[selectedsmvector].str = gtk_adjustment_get_value (smstradjust);
293       updatesmvectorprev ();
294       updatesmpreviewprev ();
295     }
296 }
297 
298 static void
smstrexpsmadjmove(GtkWidget * w,gpointer data)299 smstrexpsmadjmove (GtkWidget *w, gpointer data)
300 {
301   if (!smadjignore)
302     {
303       updatesmvectorprev ();
304       updatesmpreviewprev ();
305     }
306 }
307 
308 static void
smresponse(GtkWidget * widget,gint response_id,gpointer data)309 smresponse (GtkWidget *widget,
310             gint       response_id,
311             gpointer   data)
312 {
313   switch (response_id)
314     {
315     case RESPONSE_APPLY:
316     case GTK_RESPONSE_OK:
317       {
318         gint i;
319 
320         for (i = 0; i < numsmvect; i++)
321           pcvals.size_vectors[i] = smvector[i];
322 
323         pcvals.num_size_vectors = numsmvect;
324         pcvals.size_strength_exponent  = gtk_adjustment_get_value (smstrexpadjust);
325         pcvals.size_voronoi = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (size_voronoi));
326       }
327       break;
328     }
329 
330   if (response_id != RESPONSE_APPLY)
331     gtk_widget_hide (widget);
332 }
333 
334 static void
initsmvectors(void)335 initsmvectors (void)
336 {
337   if (pcvals.num_size_vectors)
338     {
339       gint i;
340 
341       numsmvect = pcvals.num_size_vectors;
342       for (i = 0; i < numsmvect; i++)
343          {
344            smvector[i] = pcvals.size_vectors[i];
345          }
346     }
347   else
348     {
349       /* Shouldn't happen */
350       numsmvect = 1;
351       smvector[0].x = 0.5;
352       smvector[0].y = 0.5;
353       smvector[0].siz = 0.0;
354       smvector[0].str = 1.0;
355     }
356   if (selectedsmvector >= numsmvect)
357      selectedsmvector = numsmvect-1;
358 }
359 
360 #if 0
361 static void
362 update_sizemap_dialog (void)
363 {
364   if (smwindow)
365     {
366       initsmvectors ();
367 
368       gtk_adjustment_set_value (smstrexpadjust, pcvals.size_strength_exponent);
369       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (size_voronoi),
370                                     pcvals.size_voronoi);
371 
372       updatesmvectorprev ();
373       updatesmpreviewprev ();
374     }
375 }
376 #endif
377 
378 void
create_sizemap_dialog(GtkWidget * parent)379 create_sizemap_dialog (GtkWidget *parent)
380 {
381   GtkWidget *tmpw, *tmpw2;
382   GtkWidget *table1;
383   GtkWidget *table2;
384   GtkWidget *hbox;
385 
386   initsmvectors ();
387 
388   if (smwindow)
389     {
390       updatesmvectorprev ();
391       updatesmpreviewprev ();
392       gtk_window_present (GTK_WINDOW (smwindow));
393       return;
394     }
395 
396   smwindow = gimp_dialog_new (_("Size Map Editor"), PLUG_IN_ROLE,
397                               gtk_widget_get_toplevel (parent), 0,
398                               gimp_standard_help_func, PLUG_IN_PROC,
399 
400                               _("_Apply"),  RESPONSE_APPLY,
401                               _("_Cancel"), GTK_RESPONSE_CANCEL,
402                               _("_OK"),     GTK_RESPONSE_OK,
403 
404                               NULL);
405 
406   gtk_dialog_set_alternative_button_order (GTK_DIALOG (smwindow),
407                                            GTK_RESPONSE_OK,
408                                            RESPONSE_APPLY,
409                                            GTK_RESPONSE_CANCEL,
410                                            -1);
411 
412   g_signal_connect (smwindow, "response",
413                     G_CALLBACK (smresponse),
414                     NULL);
415   g_signal_connect (smwindow, "destroy",
416                     G_CALLBACK (gtk_widget_destroyed),
417                     &smwindow);
418 
419   table1 = gtk_table_new (2, 5, FALSE);
420   gtk_container_set_border_width (GTK_CONTAINER (table1), 6);
421   gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (smwindow))),
422                       table1, TRUE, TRUE, 0);
423   gtk_widget_show (table1);
424 
425   tmpw2 = tmpw = gtk_frame_new (_("Smvectors"));
426   gtk_container_set_border_width (GTK_CONTAINER (tmpw), 2);
427   gtk_table_attach (GTK_TABLE (table1), tmpw, 0,1,0,1,GTK_EXPAND,GTK_EXPAND,0,0);
428   gtk_widget_show (tmpw);
429 
430   tmpw = hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL,0);
431   gtk_container_add (GTK_CONTAINER (tmpw2), tmpw);
432   gtk_widget_show (tmpw);
433 
434   tmpw = gtk_event_box_new ();
435   gimp_help_set_help_data (tmpw, _("The smvector-field. Left-click to move selected smvector, Right-click to point it towards mouse, Middle-click to add a new smvector."), NULL);
436   gtk_box_pack_start (GTK_BOX (hbox), tmpw, FALSE, FALSE, 0);
437   tmpw2 = tmpw;
438 
439   tmpw = smvectorprev = gimp_preview_area_new ();
440   gtk_widget_set_size_request (tmpw, OMWIDTH, OMHEIGHT);
441   gtk_container_add (GTK_CONTAINER (tmpw2), tmpw);
442   gtk_widget_show (tmpw);
443   gtk_widget_add_events (tmpw2, GDK_BUTTON_PRESS_MASK);
444   g_signal_connect (tmpw2, "button-press-event",
445                     G_CALLBACK (smmapclick), NULL);
446   gtk_widget_show (tmpw2);
447 
448   smvectprevbrightadjust = (GtkAdjustment *)
449     gtk_adjustment_new (50.0, 0.0, 100.0, 1.0, 1.0, 1.0);
450   tmpw = gtk_scale_new (GTK_ORIENTATION_VERTICAL, smvectprevbrightadjust);
451   gtk_scale_set_draw_value (GTK_SCALE (tmpw), FALSE);
452   gtk_box_pack_start (GTK_BOX (hbox), tmpw,FALSE,FALSE,0);
453   gtk_widget_show (tmpw);
454   g_signal_connect (smvectprevbrightadjust, "value-changed",
455                     G_CALLBACK (updatesmvectorprev), NULL);
456   gimp_help_set_help_data (tmpw, _("Adjust the preview's brightness"), NULL);
457 
458   tmpw2 = tmpw = gtk_frame_new (_("Preview"));
459   gtk_container_set_border_width (GTK_CONTAINER (tmpw), 2);
460   gtk_table_attach (GTK_TABLE (table1), tmpw, 1,2,0,1,GTK_EXPAND,GTK_EXPAND,0,0);
461   gtk_widget_show (tmpw);
462 
463   tmpw = smpreviewprev = gimp_preview_area_new ();
464   gtk_widget_set_size_request (tmpw, OMWIDTH, OMHEIGHT);
465   gtk_container_add (GTK_CONTAINER (tmpw2), tmpw);
466   gtk_widget_show (tmpw);
467 
468   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
469   gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
470   gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
471   gtk_table_attach_defaults (GTK_TABLE (table1), hbox, 0, 1, 1, 2);
472   gtk_widget_show (hbox);
473 
474   prev_button = tmpw = gtk_button_new_with_mnemonic ("_<<");
475   gtk_box_pack_start (GTK_BOX (hbox), tmpw, FALSE, TRUE, 0);
476   gtk_widget_show (tmpw);
477   g_signal_connect (tmpw, "clicked",
478                     G_CALLBACK (smprevclick), NULL);
479   gimp_help_set_help_data (tmpw, _("Select previous smvector"), NULL);
480 
481   next_button = tmpw = gtk_button_new_with_mnemonic ("_>>");
482   gtk_box_pack_start (GTK_BOX (hbox),tmpw,FALSE,TRUE,0);
483   gtk_widget_show (tmpw);
484   g_signal_connect (tmpw, "clicked",
485                     G_CALLBACK (smnextclick), NULL);
486   gimp_help_set_help_data (tmpw, _("Select next smvector"), NULL);
487 
488   add_button = tmpw = gtk_button_new_with_mnemonic ( _("A_dd"));
489   gtk_box_pack_start (GTK_BOX (hbox),tmpw,FALSE,TRUE,0);
490   gtk_widget_show (tmpw);
491   g_signal_connect (tmpw, "clicked",
492                     G_CALLBACK (smaddclick), NULL);
493   gimp_help_set_help_data (tmpw, _("Add new smvector"), NULL);
494 
495   kill_button = tmpw = gtk_button_new_with_mnemonic (_("_Kill"));
496   gtk_box_pack_start (GTK_BOX (hbox),tmpw,FALSE,TRUE,0);
497   gtk_widget_show (tmpw);
498   g_signal_connect (tmpw, "clicked",
499                     G_CALLBACK (smdeleteclick), NULL);
500   gimp_help_set_help_data (tmpw, _("Delete selected smvector"), NULL);
501 
502   table2 = gtk_table_new (3, 4, FALSE);
503   gtk_table_set_col_spacings (GTK_TABLE (table2), 4);
504   gtk_table_attach_defaults (GTK_TABLE (table1), table2, 0, 2, 2, 3);
505   gtk_widget_show (table2);
506 
507   sizadjust = (GtkAdjustment *)
508     gimp_scale_entry_new (GTK_TABLE (table2), 0, 0,
509                           _("_Size:"),
510                           150, 6, 50.0,
511                           0.0, 100.0, 1.0, 10.0, 1,
512                           TRUE, 0, 0,
513                           _("Change the angle of the selected smvector"),
514                           NULL);
515   g_signal_connect (sizadjust, "value-changed",
516                     G_CALLBACK (angsmadjmove), NULL);
517 
518   smstradjust = (GtkAdjustment *)
519     gimp_scale_entry_new (GTK_TABLE (table2), 0, 1,
520                           _("S_trength:"),
521                           150, 6, 1.0,
522                           0.1, 5.0, 0.1, 0.5, 1,
523                           TRUE, 0, 0,
524                           _("Change the strength of the selected smvector"),
525                           NULL);
526   g_signal_connect (smstradjust, "value-changed",
527                     G_CALLBACK (strsmadjmove), NULL);
528 
529   smstrexpadjust = (GtkAdjustment *)
530     gimp_scale_entry_new (GTK_TABLE (table2), 0, 2,
531                           _("St_rength exp.:"),
532                           150, 6, 1.0,
533                           0.1, 10.9, 0.1, 0.5, 1,
534                           TRUE, 0, 0,
535                           _("Change the exponent of the strength"),
536                           NULL);
537   g_signal_connect (smstrexpadjust, "value-changed",
538                     G_CALLBACK (smstrexpsmadjmove), NULL);
539 
540   size_voronoi = tmpw = gtk_check_button_new_with_mnemonic ( _("_Voronoi"));
541   gtk_table_attach_defaults (GTK_TABLE (table2), tmpw, 3, 4, 0, 1);
542   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (tmpw), FALSE);
543   gtk_widget_show (tmpw);
544   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (tmpw), pcvals.size_voronoi);
545   g_signal_connect (tmpw, "clicked",
546                     G_CALLBACK (smstrexpsmadjmove), NULL);
547   gimp_help_set_help_data (tmpw, _("Voronoi-mode makes only the smvector closest to the given point have any influence"), NULL);
548 
549   gtk_widget_show (smwindow);
550 
551   updatesmvectorprev ();
552   updatesmpreviewprev ();
553 }
554