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