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 <string.h>
21 #include <stdlib.h>
22
23 #include <sys/stat.h>
24 #include <sys/types.h>
25
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29
30 #include <glib/gstdio.h>
31
32 #include <libgimp/gimp.h>
33 #include <libgimp/gimpui.h>
34
35 #include "gimpressionist.h"
36 #include "presets.h"
37
38 #include "color.h"
39 #include "general.h"
40 #include "orientation.h"
41 #include "placement.h"
42 #include "size.h"
43
44
45 #include "libgimp/stdplugins-intl.h"
46
47 #ifdef G_OS_WIN32
48 #include "libgimpbase/gimpwin32-io.h"
49 #endif
50
51 #define PRESETMAGIC "Preset"
52
53 static GtkWidget *presetnameentry = NULL;
54 static GtkWidget *presetlist = NULL;
55 static GtkWidget *presetdesclabel = NULL;
56 static GtkWidget *presetsavebutton = NULL;
57 static GtkWidget *delete_button = NULL;
58 static GtkListStore *store = NULL;
59 static gchar *selected_preset_orig_name = NULL;
60 static gchar *selected_preset_filename = NULL;
61
62 static gboolean
can_delete_preset(const gchar * abs)63 can_delete_preset (const gchar *abs)
64 {
65 gchar *user_data_dir;
66 gboolean ret;
67
68 user_data_dir = g_strconcat (gimp_directory (),
69 G_DIR_SEPARATOR_S,
70 NULL);
71
72
73 ret = (!strncmp (abs, user_data_dir, strlen (user_data_dir)));
74
75 g_free (user_data_dir);
76
77 return ret;
78 }
79
80 void
preset_save_button_set_sensitive(gboolean s)81 preset_save_button_set_sensitive (gboolean s)
82 {
83 if (GTK_IS_WIDGET (presetsavebutton))
84 gtk_widget_set_sensitive (GTK_WIDGET (presetsavebutton), s);
85 }
86
87 void
preset_free(void)88 preset_free (void)
89 {
90 g_free (selected_preset_orig_name);
91 g_free (selected_preset_filename);
92 }
93
set_preset_description_text(const gchar * text)94 static void set_preset_description_text (const gchar *text)
95 {
96 gtk_label_set_text (GTK_LABEL (presetdesclabel), text);
97 }
98
99 static char presetdesc[4096] = "";
100
101 static const char *factory_defaults = "<Factory defaults>";
102
103 static gchar *
get_early_line_from_preset(gchar * full_path,const gchar * prefix)104 get_early_line_from_preset (gchar *full_path, const gchar *prefix)
105 {
106 FILE *f;
107 gchar line[4096];
108 gint prefix_len, line_idx;
109
110 prefix_len = strlen (prefix);
111 f = g_fopen (full_path, "rt");
112 if (f)
113 {
114 /* Skip the preset magic. */
115 fgets (line, 10, f);
116 if (!strncmp (line, PRESETMAGIC, 4))
117 {
118 for (line_idx = 0; line_idx < 5; line_idx++)
119 {
120 if (!fgets (line, sizeof (line), f))
121 break;
122 g_strchomp (line);
123 if (!strncmp (line, prefix, prefix_len))
124 {
125 fclose(f);
126 return g_strdup (line+prefix_len);
127 }
128 }
129 }
130 fclose (f);
131 }
132 return NULL;
133 }
134
135 static gchar *
get_object_name(const gchar * dir,gchar * filename,void * context)136 get_object_name (const gchar *dir,
137 gchar *filename,
138 void *context)
139 {
140 gchar *ret = NULL, *unprocessed_line = NULL;
141 gchar *full_path = NULL;
142
143 /* First try to extract the object's name (= user-friendly description)
144 * from the preset file
145 * */
146
147 full_path = g_build_filename (dir, filename, NULL);
148
149 unprocessed_line = get_early_line_from_preset (full_path, "name=");
150 if (unprocessed_line)
151 {
152 ret = g_strcompress (unprocessed_line);
153 g_free (unprocessed_line);
154 }
155 else
156 {
157 /* The object name defaults to a filename-derived description */
158 ret = g_filename_display_basename (full_path);
159 }
160
161 g_free (full_path);
162
163 return ret;
164 }
165
166
167 static void
preset_read_dir_into_list(void)168 preset_read_dir_into_list (void)
169 {
170 readdirintolist_extended ("Presets", presetlist, NULL, TRUE,
171 get_object_name, NULL);
172 }
173
174 static gchar *
preset_create_filename(const gchar * basename,const gchar * dest_dir)175 preset_create_filename (const gchar *basename,
176 const gchar *dest_dir)
177 {
178 gchar *fullpath;
179 gchar *safe_name;
180 gint i;
181 gint unum = 1;
182
183 g_return_val_if_fail (basename != NULL, NULL);
184 g_return_val_if_fail (dest_dir != NULL, NULL);
185 g_return_val_if_fail (g_path_is_absolute (dest_dir), NULL);
186
187 safe_name = g_filename_from_utf8 (basename, -1, NULL, NULL, NULL);
188
189 if (safe_name[0] == '.')
190 safe_name[0] = '-';
191
192 for (i = 0; safe_name[i]; i++)
193 if (safe_name[i] == G_DIR_SEPARATOR || g_ascii_isspace (safe_name[i]))
194 safe_name[i] = '-';
195
196 fullpath = g_build_filename (dest_dir, safe_name, NULL);
197
198 while (g_file_test (fullpath, G_FILE_TEST_EXISTS))
199 {
200 gchar *filename;
201
202 g_free (fullpath);
203
204 filename = g_strdup_printf ("%s-%d", safe_name, unum++);
205
206 fullpath = g_build_filename (dest_dir, filename, NULL);
207
208 g_free (filename);
209 }
210
211 g_free (safe_name);
212
213 return fullpath;
214 }
215
216
217 static void
add_factory_defaults(void)218 add_factory_defaults (void)
219 {
220 GtkTreeIter iter;
221
222 gtk_list_store_append (store, &iter);
223 /* Set the filename. */
224 gtk_list_store_set (store, &iter, PRESETS_LIST_COLUMN_FILENAME,
225 factory_defaults, -1);
226 /* Set the object name. */
227 gtk_list_store_set (store, &iter, PRESETS_LIST_COLUMN_OBJECT_NAME,
228 factory_defaults, -1);
229
230 }
231
232 static void
preset_refresh_presets(void)233 preset_refresh_presets (void)
234 {
235 gtk_list_store_clear (store);
236 add_factory_defaults ();
237 preset_read_dir_into_list ();
238 }
239
240 static int
load_old_preset(const gchar * fname)241 load_old_preset (const gchar *fname)
242 {
243 FILE *f;
244 int len;
245
246 f = g_fopen (fname, "rb");
247 if (!f)
248 {
249 g_printerr ("Error opening file \"%s\" for reading!\n",
250 gimp_filename_to_utf8 (fname));
251 return -1;
252 }
253 len = fread (&pcvals, 1, sizeof (pcvals), f);
254 fclose (f);
255
256 return (len != sizeof (pcvals)) ? -1 : 0;
257 }
258
259 static unsigned int
hexval(char c)260 hexval (char c)
261 {
262 c = g_ascii_tolower (c);
263 if ((c >= 'a') && (c <= 'f'))
264 return c - 'a' + 10;
265 if ((c >= '0') && (c <= '9'))
266 return c - '0';
267 return 0;
268 }
269
270 static char *
parse_rgb_string(const gchar * s)271 parse_rgb_string (const gchar *s)
272 {
273 static char col[3];
274 col[0] = (hexval (s[0]) << 4) | hexval (s[1]);
275 col[1] = (hexval (s[2]) << 4) | hexval (s[3]);
276 col[2] = (hexval (s[4]) << 4) | hexval (s[5]);
277 return col;
278 }
279
280 static void
set_orient_vector(const gchar * str)281 set_orient_vector (const gchar *str)
282 {
283 const gchar *tmps = str;
284 int n;
285
286 n = atoi (tmps);
287
288 if (!(tmps = strchr (tmps, ',')))
289 return;
290 pcvals.orient_vectors[n].x = g_ascii_strtod (++tmps, NULL);
291
292 if (!(tmps = strchr (tmps, ',')))
293 return;
294 pcvals.orient_vectors[n].y = g_ascii_strtod (++tmps, NULL);
295
296 if (!(tmps = strchr (tmps, ',')))
297 return;
298 pcvals.orient_vectors[n].dir = g_ascii_strtod (++tmps, NULL);
299
300 if (!(tmps = strchr (tmps, ',')))
301 return;
302 pcvals.orient_vectors[n].dx = g_ascii_strtod (++tmps, NULL);
303
304 if (!(tmps = strchr (tmps, ',')))
305 return;
306 pcvals.orient_vectors[n].dy = g_ascii_strtod (++tmps, NULL);
307
308 if (!(tmps = strchr (tmps, ',')))
309 return;
310 pcvals.orient_vectors[n].str = g_ascii_strtod (++tmps, NULL);
311
312 if (!(tmps = strchr (tmps, ',')))
313 return;
314 pcvals.orient_vectors[n].type = atoi (++tmps);
315
316 }
317
set_size_vector(const gchar * str)318 static void set_size_vector (const gchar *str)
319 {
320 const gchar *tmps = str;
321 int n;
322
323 n = atoi (tmps);
324
325 if (!(tmps = strchr (tmps, ',')))
326 return;
327 pcvals.size_vectors[n].x = g_ascii_strtod (++tmps, NULL);
328
329 if (!(tmps = strchr (tmps, ',')))
330 return;
331 pcvals.size_vectors[n].y = g_ascii_strtod (++tmps, NULL);
332
333 if (!(tmps = strchr (tmps, ',')))
334 return;
335 pcvals.size_vectors[n].siz = g_ascii_strtod (++tmps, NULL);
336
337 if (!(tmps = strchr (tmps, ',')))
338 return;
339 pcvals.size_vectors[n].str = g_ascii_strtod (++tmps, NULL);
340
341 }
342
343 static void
parse_desc(const gchar * str,gchar * d,gssize d_len)344 parse_desc (const gchar *str, gchar *d, gssize d_len)
345 {
346 gchar *dest = g_strcompress (str);
347
348 g_strlcpy (d, dest, d_len);
349
350 g_free (dest);
351 }
352
353 static void
set_values(const gchar * key,const gchar * val)354 set_values (const gchar *key, const gchar *val)
355 {
356 if (!strcmp (key, "desc"))
357 parse_desc (val, presetdesc, sizeof (presetdesc));
358 else if (!strcmp (key, "orientnum"))
359 pcvals.orient_num = atoi (val);
360 else if (!strcmp (key, "orientfirst"))
361 pcvals.orient_first = g_ascii_strtod (val, NULL);
362 else if (!strcmp (key, "orientlast"))
363 pcvals.orient_last = g_ascii_strtod (val, NULL);
364 else if (!strcmp (key, "orienttype"))
365 pcvals.orient_type = orientation_type_input (atoi (val));
366
367 else if (!strcmp (key, "sizenum"))
368 pcvals.size_num = atoi (val);
369 else if (!strcmp (key, "sizefirst"))
370 pcvals.size_first = g_ascii_strtod (val, NULL);
371 else if (!strcmp (key, "sizelast"))
372 pcvals.size_last = g_ascii_strtod (val, NULL);
373 else if (!strcmp (key, "sizetype"))
374 pcvals.size_type = size_type_input (atoi (val));
375
376 else if (!strcmp (key, "brushrelief"))
377 pcvals.brush_relief = g_ascii_strtod (val, NULL);
378 else if (!strcmp (key, "brushscale"))
379 {
380 /* For compatibility */
381 pcvals.size_num = 1;
382 pcvals.size_first = pcvals.size_last = g_ascii_strtod (val, NULL);
383 }
384 else if (!strcmp (key, "brushdensity"))
385 pcvals.brush_density = g_ascii_strtod (val, NULL);
386 else if (!strcmp (key, "brushgamma"))
387 pcvals.brushgamma = g_ascii_strtod (val, NULL);
388 else if (!strcmp (key, "brushaspect"))
389 pcvals.brush_aspect = g_ascii_strtod (val, NULL);
390
391 else if (!strcmp (key, "generalbgtype"))
392 pcvals.general_background_type = general_bg_type_input (atoi (val));
393 else if (!strcmp (key, "generaldarkedge"))
394 pcvals.general_dark_edge = g_ascii_strtod (val, NULL);
395 else if (!strcmp (key, "generalpaintedges"))
396 pcvals.general_paint_edges = atoi (val);
397 else if (!strcmp (key, "generaltileable"))
398 pcvals.general_tileable = atoi (val);
399 else if (!strcmp (key, "generaldropshadow"))
400 pcvals.general_drop_shadow = atoi (val);
401 else if (!strcmp (key, "generalshadowdarkness"))
402 pcvals.general_shadow_darkness = g_ascii_strtod (val, NULL);
403 else if (!strcmp (key, "generalshadowdepth"))
404 pcvals.general_shadow_depth = atoi (val);
405 else if (!strcmp (key, "generalshadowblur"))
406 pcvals.general_shadow_blur = atoi (val);
407 else if (!strcmp (key, "devthresh"))
408 pcvals.devthresh = g_ascii_strtod (val, NULL);
409
410 else if (!strcmp (key, "paperrelief"))
411 pcvals.paper_relief = g_ascii_strtod (val, NULL);
412 else if (!strcmp (key, "paperscale"))
413 pcvals.paper_scale = g_ascii_strtod (val, NULL);
414 else if (!strcmp (key, "paperinvert"))
415 pcvals.paper_invert = atoi (val);
416 else if (!strcmp (key, "paperoverlay"))
417 pcvals.paper_overlay = atoi (val);
418
419 else if (!strcmp (key, "placetype"))
420 pcvals.place_type = place_type_input (atoi (val));
421 else if (!strcmp (key, "placecenter"))
422 pcvals.placement_center = atoi (val);
423
424 else if (!strcmp (key, "selectedbrush"))
425 g_strlcpy (pcvals.selected_brush, val, sizeof (pcvals.selected_brush));
426 else if (!strcmp (key, "selectedpaper"))
427 g_strlcpy (pcvals.selected_paper, val, sizeof (pcvals.selected_paper));
428
429 else if (!strcmp (key, "color"))
430 {
431 char *c = parse_rgb_string (val);
432 gimp_rgba_set_uchar (&pcvals.color, c[0], c[1], c[2], 255);
433 }
434
435 else if (!strcmp (key, "numorientvector"))
436 pcvals.num_orient_vectors = atoi (val);
437 else if (!strcmp (key, "orientvector"))
438 set_orient_vector (val);
439 else if (!strcmp (key, "orientangoff"))
440 pcvals.orient_angle_offset = g_ascii_strtod (val, NULL);
441 else if (!strcmp (key, "orientstrexp"))
442 pcvals.orient_strength_exponent = g_ascii_strtod (val, NULL);
443 else if (!strcmp (key, "orientvoronoi"))
444 pcvals.orient_voronoi = atoi (val);
445
446 else if (!strcmp (key, "numsizevector"))
447 pcvals.num_size_vectors = atoi (val);
448 else if (!strcmp (key, "sizevector"))
449 set_size_vector (val);
450 else if (!strcmp (key, "sizestrexp"))
451 pcvals.size_strength_exponent = g_ascii_strtod (val, NULL);
452 else if (!strcmp (key, "sizevoronoi"))
453 pcvals.size_voronoi = atoi (val);
454
455 else if (!strcmp (key, "colortype"))
456 pcvals.color_type = color_type_input (atoi (val));
457 else if (!strcmp (key, "colornoise"))
458 pcvals.color_noise = g_ascii_strtod (val, NULL);
459 }
460
461 static int
load_preset(const gchar * fn)462 load_preset (const gchar *fn)
463 {
464 char line[1024] = "";
465 FILE *f;
466
467 f = g_fopen (fn, "rt");
468 if (!f)
469 {
470 g_printerr ("Error opening file \"%s\" for reading!\n",
471 gimp_filename_to_utf8 (fn));
472 return -1;
473 }
474 fgets (line, 10, f);
475 if (strncmp (line, PRESETMAGIC, 4))
476 {
477 fclose (f);
478 return load_old_preset (fn);
479 }
480
481 restore_default_values ();
482
483 while (!feof (f))
484 {
485 char *tmps;
486
487 if (!fgets (line, 1024, f))
488 break;
489 g_strchomp (line);
490 tmps = strchr (line, '=');
491 if (!tmps)
492 continue;
493 *tmps = '\0';
494 tmps++;
495 set_values (line, tmps);
496 }
497 fclose (f);
498 return 0;
499 }
500
501 int
select_preset(const gchar * preset)502 select_preset (const gchar *preset)
503 {
504 int ret = SELECT_PRESET_OK;
505 /* I'm copying this behavior as is. As it seems applying the
506 * factory_defaults preset does nothing, which I'm not sure
507 * if that was what the author intended.
508 * -- Shlomi Fish
509 */
510 if (strcmp (preset, factory_defaults))
511 {
512 gchar *rel = g_build_filename ("Presets", preset, NULL);
513 gchar *abs = findfile (rel);
514
515 g_free (rel);
516
517 if (abs)
518 {
519 if (load_preset (abs))
520 ret = SELECT_PRESET_LOAD_FAILED;
521
522 g_free (abs);
523 }
524 else
525 {
526 ret = SELECT_PRESET_FILE_NOT_FOUND;
527 }
528 }
529 if (ret == SELECT_PRESET_OK)
530 {
531 /* This is so the colorbrushes param (that is not stored in the
532 * preset will be set correctly upon the preset loading.
533 * */
534 set_colorbrushes (pcvals.selected_brush);
535 }
536
537 return ret;
538 }
539
540 static void
apply_preset(GtkWidget * w,GtkTreeSelection * selection)541 apply_preset (GtkWidget *w, GtkTreeSelection *selection)
542 {
543 GtkTreeIter iter;
544 GtkTreeModel *model;
545
546 if (gtk_tree_selection_get_selected (selection, &model, &iter))
547 {
548 gchar *preset;
549
550 gtk_tree_model_get (model, &iter, PRESETS_LIST_COLUMN_FILENAME,
551 &preset, -1);
552
553 select_preset (preset);
554
555 restore_values ();
556
557 /* g_free (preset); */
558 g_free (selected_preset_filename);
559 selected_preset_filename = preset;
560 }
561 }
562
563 static void
delete_preset(GtkWidget * w,GtkTreeSelection * selection)564 delete_preset (GtkWidget *w, GtkTreeSelection *selection)
565 {
566 GtkTreeIter iter;
567 GtkTreeModel *model;
568
569 if (gtk_tree_selection_get_selected (selection, &model, &iter))
570 {
571 gchar *preset;
572
573 gtk_tree_model_get (model, &iter, PRESETS_LIST_COLUMN_FILENAME,
574 &preset, -1);
575
576 if (preset)
577 {
578 gchar *rel = g_build_filename ("Presets", preset, NULL);
579 gchar *abs = findfile (rel);
580
581 g_free (rel);
582
583 if (abs)
584 {
585 /* Don't delete global presets - bug # 147483 */
586 if (can_delete_preset (abs))
587 g_unlink (abs);
588
589 g_free (abs);
590 }
591
592 preset_refresh_presets ();
593
594 g_free (preset);
595 }
596 }
597 }
598
599 static void save_preset (void);
600
601 static void
preset_desc_callback(GtkTextBuffer * buffer,gpointer data)602 preset_desc_callback (GtkTextBuffer *buffer, gpointer data)
603 {
604 char *str;
605 GtkTextIter start, end;
606
607 gtk_text_buffer_get_bounds (buffer, &start, &end);
608 str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
609 g_strlcpy (presetdesc, str, sizeof (presetdesc));
610 g_free (str);
611 }
612
613 static void
save_preset_response(GtkWidget * widget,gint response_id,gpointer data)614 save_preset_response (GtkWidget *widget,
615 gint response_id,
616 gpointer data)
617 {
618 gtk_widget_destroy (widget);
619
620 if (response_id == GTK_RESPONSE_OK)
621 save_preset ();
622 }
623
624 static void
create_save_preset(GtkWidget * parent)625 create_save_preset (GtkWidget *parent)
626 {
627 static GtkWidget *window = NULL;
628 GtkWidget *box, *label;
629 GtkWidget *swin, *text;
630 GtkTextBuffer *buffer;
631
632 if (window)
633 {
634 gtk_window_present (GTK_WINDOW (window));
635 return;
636 }
637
638 window = gimp_dialog_new (_("Save Current"), PLUG_IN_ROLE,
639 gtk_widget_get_toplevel (parent), 0,
640 gimp_standard_help_func, PLUG_IN_PROC,
641
642 _("_Cancel"), GTK_RESPONSE_CANCEL,
643 _("_OK"), GTK_RESPONSE_OK,
644
645 NULL);
646
647 gtk_dialog_set_alternative_button_order (GTK_DIALOG (window),
648 GTK_RESPONSE_OK,
649 GTK_RESPONSE_CANCEL,
650 -1);
651
652 g_signal_connect (window, "response",
653 G_CALLBACK (save_preset_response),
654 NULL);
655 g_signal_connect (window, "destroy",
656 G_CALLBACK (gtk_widget_destroyed),
657 &window);
658
659 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
660 gtk_container_set_border_width (GTK_CONTAINER (box), 12);
661 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
662 box, TRUE, TRUE, 0);
663 gtk_widget_show (box);
664
665 label = gtk_label_new (_("Description:"));
666 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
667 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
668 gtk_widget_show (label);
669
670 swin = gtk_scrolled_window_new (NULL, NULL);
671 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
672 GTK_SHADOW_IN);
673 gtk_box_pack_start (GTK_BOX (box), swin, TRUE, TRUE, 0);
674 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
675 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
676 gtk_widget_show (swin);
677
678 buffer = gtk_text_buffer_new (NULL);
679 g_signal_connect (buffer, "changed",
680 G_CALLBACK (preset_desc_callback), NULL);
681 gtk_text_buffer_set_text (buffer, presetdesc, -1);
682
683 text = gtk_text_view_new_with_buffer (buffer);
684 gtk_widget_set_size_request (text, -1, 192);
685 gtk_container_add (GTK_CONTAINER (swin), text);
686 gtk_widget_show (text);
687
688 gtk_widget_show (window);
689 }
690
691 static void
save_preset(void)692 save_preset (void)
693 {
694 const gchar *preset_name;
695
696 gchar *fname, *presets_dir_path;
697 FILE *f;
698 GList *thispath;
699 gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
700 gchar vbuf[6][G_ASCII_DTOSTR_BUF_SIZE];
701 guchar color[3];
702 gint i;
703 gchar *desc_escaped, *preset_name_escaped;
704
705 preset_name = gtk_entry_get_text (GTK_ENTRY (presetnameentry));
706 thispath = parsepath ();
707 store_values ();
708
709 if (!thispath)
710 {
711 g_printerr ("Internal error: (save_preset) thispath == NULL\n");
712 return;
713 }
714
715 /* Create the ~/.gimp-$VER/gimpressionist/Presets directory if
716 * it doesn't already exists.
717 *
718 */
719 presets_dir_path = g_build_filename ((const gchar *) thispath->data,
720 "Presets",
721 NULL);
722
723 if (! g_file_test (presets_dir_path, G_FILE_TEST_IS_DIR))
724 {
725 if (g_mkdir (presets_dir_path,
726 S_IRUSR | S_IWUSR | S_IXUSR |
727 S_IRGRP | S_IXGRP |
728 S_IROTH | S_IXOTH) == -1)
729 {
730 g_printerr ("Error creating folder \"%s\"!\n",
731 gimp_filename_to_utf8 (presets_dir_path));
732 g_free (presets_dir_path);
733 return;
734 }
735 }
736
737 /* Check if the user-friendly name has changed. If so, then save it
738 * under a new file. If not - use the same file name.
739 */
740 if (selected_preset_orig_name &&
741 strcmp (preset_name, selected_preset_orig_name) == 0)
742 {
743 fname = g_build_filename (presets_dir_path,
744 selected_preset_filename,
745 NULL);
746 }
747 else
748 {
749 fname = preset_create_filename (preset_name, presets_dir_path);
750 }
751
752 g_free (presets_dir_path);
753
754 if (!fname)
755 {
756 g_printerr ("Error building a filename for preset \"%s\"!\n",
757 preset_name);
758 return;
759 }
760
761 f = g_fopen (fname, "wt");
762 if (!f)
763 {
764 g_printerr ("Error opening file \"%s\" for writing!\n",
765 gimp_filename_to_utf8 (fname));
766 g_free (fname);
767 return;
768 }
769
770 fprintf (f, "%s\n", PRESETMAGIC);
771 desc_escaped = g_strescape (presetdesc, NULL);
772 fprintf (f, "desc=%s\n", desc_escaped);
773 g_free (desc_escaped);
774 preset_name_escaped = g_strescape (preset_name, NULL);
775 fprintf (f, "name=%s\n", preset_name_escaped);
776 g_free (preset_name_escaped);
777 fprintf (f, "orientnum=%d\n", pcvals.orient_num);
778 fprintf (f, "orientfirst=%s\n",
779 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_first));
780 fprintf (f, "orientlast=%s\n",
781 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_last));
782 fprintf (f, "orienttype=%d\n", pcvals.orient_type);
783
784 fprintf (f, "sizenum=%d\n", pcvals.size_num);
785 fprintf (f, "sizefirst=%s\n",
786 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.size_first));
787 fprintf (f, "sizelast=%s\n",
788 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.size_last));
789 fprintf (f, "sizetype=%d\n", pcvals.size_type);
790
791 fprintf (f, "brushrelief=%s\n",
792 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.brush_relief));
793 fprintf (f, "brushdensity=%s\n",
794 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.brush_density));
795 fprintf (f, "brushgamma=%s\n",
796 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.brushgamma));
797 fprintf (f, "brushaspect=%s\n",
798 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.brush_aspect));
799
800 fprintf (f, "generalbgtype=%d\n", pcvals.general_background_type);
801 fprintf (f, "generaldarkedge=%s\n",
802 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.general_dark_edge));
803 fprintf (f, "generalpaintedges=%d\n", pcvals.general_paint_edges);
804 fprintf (f, "generaltileable=%d\n", pcvals.general_tileable);
805 fprintf (f, "generaldropshadow=%d\n", pcvals.general_drop_shadow);
806 fprintf (f, "generalshadowdarkness=%s\n",
807 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.general_shadow_darkness));
808 fprintf (f, "generalshadowdepth=%d\n", pcvals.general_shadow_depth);
809 fprintf (f, "generalshadowblur=%d\n", pcvals.general_shadow_blur);
810 fprintf (f, "devthresh=%s\n",
811 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.devthresh));
812
813 fprintf (f, "paperrelief=%s\n",
814 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.paper_relief));
815 fprintf (f, "paperscale=%s\n",
816 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.paper_scale));
817 fprintf (f, "paperinvert=%d\n", pcvals.paper_invert);
818 fprintf (f, "paperoverlay=%d\n", pcvals.paper_overlay);
819
820 fprintf (f, "selectedbrush=%s\n", pcvals.selected_brush);
821 fprintf (f, "selectedpaper=%s\n", pcvals.selected_paper);
822
823 gimp_rgb_get_uchar (&pcvals.color, &color[0], &color[1], &color[2]);
824 fprintf (f, "color=%02x%02x%02x\n", color[0], color[1], color[2]);
825
826 fprintf (f, "placetype=%d\n", pcvals.place_type);
827 fprintf (f, "placecenter=%d\n", pcvals.placement_center);
828
829 fprintf (f, "numorientvector=%d\n", pcvals.num_orient_vectors);
830 for (i = 0; i < pcvals.num_orient_vectors; i++)
831 {
832 g_ascii_dtostr (vbuf[0], G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_vectors[i].x);
833 g_ascii_dtostr (vbuf[1], G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_vectors[i].y);
834 g_ascii_dtostr (vbuf[2], G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_vectors[i].dir);
835 g_ascii_dtostr (vbuf[3], G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_vectors[i].dx);
836 g_ascii_dtostr (vbuf[4], G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_vectors[i].dy);
837 g_ascii_dtostr (vbuf[5], G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_vectors[i].str);
838
839 fprintf (f, "orientvector=%d,%s,%s,%s,%s,%s,%s,%d\n", i,
840 vbuf[0], vbuf[1], vbuf[2], vbuf[3], vbuf[4], vbuf[5],
841 pcvals.orient_vectors[i].type);
842 }
843
844 fprintf (f, "orientangoff=%s\n",
845 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE,
846 pcvals.orient_angle_offset));
847 fprintf (f, "orientstrexp=%s\n",
848 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE,
849 pcvals.orient_strength_exponent));
850 fprintf (f, "orientvoronoi=%d\n", pcvals.orient_voronoi);
851
852 fprintf (f, "numsizevector=%d\n", pcvals.num_size_vectors);
853 for (i = 0; i < pcvals.num_size_vectors; i++)
854 {
855 g_ascii_dtostr (vbuf[0], G_ASCII_DTOSTR_BUF_SIZE, pcvals.size_vectors[i].x);
856 g_ascii_dtostr (vbuf[1], G_ASCII_DTOSTR_BUF_SIZE, pcvals.size_vectors[i].y);
857 g_ascii_dtostr (vbuf[2], G_ASCII_DTOSTR_BUF_SIZE, pcvals.size_vectors[i].siz);
858 g_ascii_dtostr (vbuf[3], G_ASCII_DTOSTR_BUF_SIZE, pcvals.size_vectors[i].str);
859 fprintf (f, "sizevector=%d,%s,%s,%s,%s\n", i,
860 vbuf[0], vbuf[1], vbuf[2], vbuf[3]);
861 }
862 fprintf (f, "sizestrexp=%s\n",
863 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.size_strength_exponent));
864 fprintf (f, "sizevoronoi=%d\n", pcvals.size_voronoi);
865
866 fprintf (f, "colortype=%d\n", pcvals.color_type);
867 fprintf (f, "colornoise=%s\n",
868 g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.color_noise));
869
870 fclose (f);
871 preset_refresh_presets ();
872 reselect (presetlist, fname);
873
874 g_free (fname);
875 }
876
877 static void
read_description(const char * fn)878 read_description (const char *fn)
879 {
880 char *rel_fname;
881 char *fname;
882 gchar *unprocessed_line;
883
884 rel_fname = g_build_filename ("Presets", fn, NULL);
885 fname = findfile (rel_fname);
886 g_free (rel_fname);
887
888 if (!fname)
889 {
890 if (!strcmp (fn, factory_defaults))
891 {
892 gtk_widget_set_sensitive (delete_button, FALSE);
893 set_preset_description_text (_("Gimpressionist Defaults"));
894 }
895 else
896 {
897 set_preset_description_text ("");
898 }
899 return;
900 }
901
902 /* Don't delete global presets - bug # 147483 */
903 gtk_widget_set_sensitive (delete_button, can_delete_preset (fname));
904
905 unprocessed_line = get_early_line_from_preset (fname, "desc=");
906 g_free (fname);
907
908 if (unprocessed_line)
909 {
910 char tmplabel[4096];
911 parse_desc (unprocessed_line, tmplabel, sizeof (tmplabel));
912 g_free (unprocessed_line);
913 set_preset_description_text (tmplabel);
914 }
915 else
916 {
917 set_preset_description_text ("");
918 }
919 }
920
921 static void
presets_list_select_preset(GtkTreeSelection * selection,gpointer data)922 presets_list_select_preset (GtkTreeSelection *selection,
923 gpointer data)
924 {
925 GtkTreeIter iter;
926 GtkTreeModel *model;
927
928 if (gtk_tree_selection_get_selected (selection, &model, &iter))
929 {
930 gchar *preset_name;
931 gchar *preset_filename;
932
933 gtk_tree_model_get (model, &iter, PRESETS_LIST_COLUMN_OBJECT_NAME,
934 &preset_name, -1);
935 gtk_tree_model_get (model, &iter, PRESETS_LIST_COLUMN_FILENAME,
936 &preset_filename, -1);
937
938 /* TODO : Maybe make the factory defaults behavior in regards
939 * to the preset's object name and filename more robust?
940 *
941 */
942 if (strcmp (preset_filename, factory_defaults))
943 {
944 gtk_entry_set_text (GTK_ENTRY (presetnameentry), preset_name);
945 g_free (selected_preset_orig_name);
946 g_free (selected_preset_filename);
947 selected_preset_orig_name = g_strdup (preset_name);
948 selected_preset_filename = g_strdup (selected_preset_filename);
949 }
950
951 read_description (preset_filename);
952
953 g_free (preset_name);
954 g_free (preset_filename);
955 }
956 }
957
958 static GtkWidget *
create_presets_list(GtkWidget * parent)959 create_presets_list (GtkWidget *parent)
960 {
961 GtkListStore *store;
962 GtkTreeSelection *selection;
963 GtkCellRenderer *renderer;
964 GtkTreeViewColumn *column;
965 GtkWidget *swin, *view;
966
967 swin = gtk_scrolled_window_new (NULL, NULL);
968 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
969 GTK_POLICY_AUTOMATIC,
970 GTK_POLICY_AUTOMATIC);
971 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
972 GTK_SHADOW_IN);
973 gtk_box_pack_start (GTK_BOX (parent), swin, FALSE, FALSE, 0);
974 gtk_widget_show (swin);
975 gtk_widget_set_size_request (swin, 200, -1);
976
977 store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
978 view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
979
980 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
981 g_object_unref (store);
982 gtk_widget_show (view);
983
984 renderer = gtk_cell_renderer_text_new ();
985
986 column =
987 gtk_tree_view_column_new_with_attributes ("Preset", renderer,
988 "text",
989 PRESETS_LIST_COLUMN_OBJECT_NAME,
990 NULL);
991 gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
992
993
994 gtk_container_add (GTK_CONTAINER (swin), view);
995
996 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
997 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
998 g_signal_connect (selection, "changed",
999 G_CALLBACK (presets_list_select_preset),
1000 NULL);
1001
1002 return view;
1003 }
1004
1005 void
create_presetpage(GtkNotebook * notebook)1006 create_presetpage (GtkNotebook *notebook)
1007 {
1008 GtkWidget *vbox, *hbox, *box1, *box2, *thispage;
1009 GtkWidget *view;
1010 GtkWidget *tmpw;
1011 GtkWidget *label;
1012 GtkTreeSelection *selection;
1013
1014 label = gtk_label_new_with_mnemonic (_("_Presets"));
1015
1016 thispage = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1017 gtk_container_set_border_width (GTK_CONTAINER (thispage), 12);
1018 gtk_widget_show (thispage);
1019
1020 box1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1021 gtk_box_pack_start (GTK_BOX (thispage), box1, FALSE, FALSE, 0);
1022 gtk_widget_show (box1);
1023
1024 presetnameentry = tmpw = gtk_entry_new ();
1025 gtk_box_pack_start (GTK_BOX (box1), tmpw, FALSE, FALSE, 0);
1026 gtk_widget_set_size_request (tmpw, 200, -1);
1027 gtk_widget_show (tmpw);
1028
1029 presetsavebutton = tmpw = gtk_button_new_with_label ( _("Save Current..."));
1030 gtk_button_set_image (GTK_BUTTON (presetsavebutton),
1031 gtk_image_new_from_icon_name (GIMP_ICON_DOCUMENT_SAVE,
1032 GTK_ICON_SIZE_BUTTON));
1033 gtk_box_pack_start (GTK_BOX (box1), tmpw, FALSE, FALSE, 0);
1034 gtk_widget_show (tmpw);
1035 g_signal_connect (tmpw, "clicked", G_CALLBACK (create_save_preset), NULL);
1036 gimp_help_set_help_data
1037 (tmpw, _("Save the current settings to the specified file"), NULL);
1038
1039 box1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1040 gtk_box_pack_start (GTK_BOX (thispage), box1, TRUE, TRUE, 0);
1041 gtk_widget_show (box1);
1042
1043 presetlist = view = create_presets_list (box1);
1044 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view)));
1045 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
1046 add_factory_defaults ();
1047
1048 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1049 gtk_box_pack_start (GTK_BOX (box1), vbox, FALSE, FALSE, 0);
1050 gtk_widget_show (vbox);
1051
1052 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1053 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1054 gtk_widget_show (hbox);
1055
1056 box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1057 gtk_box_pack_start (GTK_BOX (hbox), box2, FALSE, FALSE, 0);
1058 gtk_widget_show (box2);
1059
1060 tmpw = gtk_button_new_with_mnemonic (_("_Apply"));
1061 gtk_box_pack_start (GTK_BOX (box2), tmpw, FALSE, FALSE, 0);
1062 gtk_widget_show (tmpw);
1063 g_signal_connect (tmpw, "clicked", G_CALLBACK (apply_preset), selection);
1064 gimp_help_set_help_data
1065 (tmpw, _("Reads the selected Preset into memory"), NULL);
1066
1067 tmpw = delete_button = gtk_button_new_with_mnemonic (_("_Delete"));
1068 gtk_box_pack_start (GTK_BOX (box2), tmpw, FALSE, FALSE,0);
1069 gtk_widget_show (tmpw);
1070 g_signal_connect (tmpw, "clicked", G_CALLBACK (delete_preset), selection);
1071 gimp_help_set_help_data (tmpw, _("Deletes the selected Preset"), NULL);
1072
1073 tmpw = gtk_button_new_with_mnemonic (_("_Refresh"));
1074 gtk_box_pack_start (GTK_BOX (box2), tmpw, FALSE, FALSE,0);
1075 gtk_widget_show (tmpw);
1076 g_signal_connect (tmpw, "clicked", G_CALLBACK (preset_refresh_presets), NULL);
1077 gimp_help_set_help_data (tmpw, _("Reread the folder of Presets"), NULL);
1078
1079 presetdesclabel = tmpw = gtk_label_new (NULL);
1080 gimp_label_set_attributes (GTK_LABEL (tmpw),
1081 PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
1082 -1);
1083 gtk_label_set_line_wrap (GTK_LABEL (tmpw), TRUE);
1084 /*
1085 * Make sure the label's width is reasonable and it won't stretch
1086 * the dialog more than its width.
1087 * */
1088 gtk_widget_set_size_request (tmpw, 240, -1);
1089
1090 gtk_label_set_xalign (GTK_LABEL (tmpw), 0.0);
1091 gtk_label_set_yalign (GTK_LABEL (tmpw), 0.0);
1092 gtk_box_pack_start (GTK_BOX (vbox), tmpw, TRUE, TRUE, 0);
1093 gtk_widget_show (tmpw);
1094
1095 preset_read_dir_into_list ();
1096
1097 gtk_notebook_append_page_menu (notebook, thispage, label, NULL);
1098 }
1099