diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:30:19 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:30:19 +0000 |
commit | 5c1676dfe6d2f3c837a5e074117b45613fd29a72 (patch) | |
tree | cbffb45144febf451e54061db2b21395faf94bfe /plug-ins/gimpressionist/presets.c | |
parent | Initial commit. (diff) | |
download | gimp-5c1676dfe6d2f3c837a5e074117b45613fd29a72.tar.xz gimp-5c1676dfe6d2f3c837a5e074117b45613fd29a72.zip |
Adding upstream version 2.10.34.upstream/2.10.34upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | plug-ins/gimpressionist/presets.c | 1098 |
1 files changed, 1098 insertions, 0 deletions
diff --git a/plug-ins/gimpressionist/presets.c b/plug-ins/gimpressionist/presets.c new file mode 100644 index 0000000..3db9715 --- /dev/null +++ b/plug-ins/gimpressionist/presets.c @@ -0,0 +1,1098 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <string.h> +#include <stdlib.h> + +#include <sys/stat.h> +#include <sys/types.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <glib/gstdio.h> + +#include <libgimp/gimp.h> +#include <libgimp/gimpui.h> + +#include "gimpressionist.h" +#include "presets.h" + +#include "color.h" +#include "general.h" +#include "orientation.h" +#include "placement.h" +#include "size.h" + + +#include "libgimp/stdplugins-intl.h" + +#ifdef G_OS_WIN32 +#include "libgimpbase/gimpwin32-io.h" +#endif + +#define PRESETMAGIC "Preset" + +static GtkWidget *presetnameentry = NULL; +static GtkWidget *presetlist = NULL; +static GtkWidget *presetdesclabel = NULL; +static GtkWidget *presetsavebutton = NULL; +static GtkWidget *delete_button = NULL; +static GtkListStore *store = NULL; +static gchar *selected_preset_orig_name = NULL; +static gchar *selected_preset_filename = NULL; + +static gboolean +can_delete_preset (const gchar *abs) +{ + gchar *user_data_dir; + gboolean ret; + + user_data_dir = g_strconcat (gimp_directory (), + G_DIR_SEPARATOR_S, + NULL); + + + ret = (!strncmp (abs, user_data_dir, strlen (user_data_dir))); + + g_free (user_data_dir); + + return ret; +} + +void +preset_save_button_set_sensitive (gboolean s) +{ + if (GTK_IS_WIDGET (presetsavebutton)) + gtk_widget_set_sensitive (GTK_WIDGET (presetsavebutton), s); +} + +void +preset_free (void) +{ + g_free (selected_preset_orig_name); + g_free (selected_preset_filename); +} + +static void set_preset_description_text (const gchar *text) +{ + gtk_label_set_text (GTK_LABEL (presetdesclabel), text); +} + +static char presetdesc[4096] = ""; + +static const char *factory_defaults = "<Factory defaults>"; + +static gchar * +get_early_line_from_preset (gchar *full_path, const gchar *prefix) +{ + FILE *f; + gchar line[4096]; + gint prefix_len, line_idx; + + prefix_len = strlen (prefix); + f = g_fopen (full_path, "rt"); + if (f) + { + /* Skip the preset magic. */ + fgets (line, 10, f); + if (!strncmp (line, PRESETMAGIC, 4)) + { + for (line_idx = 0; line_idx < 5; line_idx++) + { + if (!fgets (line, sizeof (line), f)) + break; + g_strchomp (line); + if (!strncmp (line, prefix, prefix_len)) + { + fclose(f); + return g_strdup (line+prefix_len); + } + } + } + fclose (f); + } + return NULL; +} + +static gchar * +get_object_name (const gchar *dir, + gchar *filename, + void *context) +{ + gchar *ret = NULL, *unprocessed_line = NULL; + gchar *full_path = NULL; + + /* First try to extract the object's name (= user-friendly description) + * from the preset file + * */ + + full_path = g_build_filename (dir, filename, NULL); + + unprocessed_line = get_early_line_from_preset (full_path, "name="); + if (unprocessed_line) + { + ret = g_strcompress (unprocessed_line); + g_free (unprocessed_line); + } + else + { + /* The object name defaults to a filename-derived description */ + ret = g_filename_display_basename (full_path); + } + + g_free (full_path); + + return ret; +} + + +static void +preset_read_dir_into_list (void) +{ + readdirintolist_extended ("Presets", presetlist, NULL, TRUE, + get_object_name, NULL); +} + +static gchar * +preset_create_filename (const gchar *basename, + const gchar *dest_dir) +{ + gchar *fullpath; + gchar *safe_name; + gint i; + gint unum = 1; + + g_return_val_if_fail (basename != NULL, NULL); + g_return_val_if_fail (dest_dir != NULL, NULL); + g_return_val_if_fail (g_path_is_absolute (dest_dir), NULL); + + safe_name = g_filename_from_utf8 (basename, -1, NULL, NULL, NULL); + + if (safe_name[0] == '.') + safe_name[0] = '-'; + + for (i = 0; safe_name[i]; i++) + if (safe_name[i] == G_DIR_SEPARATOR || g_ascii_isspace (safe_name[i])) + safe_name[i] = '-'; + + fullpath = g_build_filename (dest_dir, safe_name, NULL); + + while (g_file_test (fullpath, G_FILE_TEST_EXISTS)) + { + gchar *filename; + + g_free (fullpath); + + filename = g_strdup_printf ("%s-%d", safe_name, unum++); + + fullpath = g_build_filename (dest_dir, filename, NULL); + + g_free (filename); + } + + g_free (safe_name); + + return fullpath; +} + + +static void +add_factory_defaults (void) +{ + GtkTreeIter iter; + + gtk_list_store_append (store, &iter); + /* Set the filename. */ + gtk_list_store_set (store, &iter, PRESETS_LIST_COLUMN_FILENAME, + factory_defaults, -1); + /* Set the object name. */ + gtk_list_store_set (store, &iter, PRESETS_LIST_COLUMN_OBJECT_NAME, + factory_defaults, -1); + +} + +static void +preset_refresh_presets (void) +{ + gtk_list_store_clear (store); + add_factory_defaults (); + preset_read_dir_into_list (); +} + +static int +load_old_preset (const gchar *fname) +{ + FILE *f; + int len; + + f = g_fopen (fname, "rb"); + if (!f) + { + g_printerr ("Error opening file \"%s\" for reading!\n", + gimp_filename_to_utf8 (fname)); + return -1; + } + len = fread (&pcvals, 1, sizeof (pcvals), f); + fclose (f); + + return (len != sizeof (pcvals)) ? -1 : 0; +} + +static unsigned int +hexval (char c) +{ + c = g_ascii_tolower (c); + if ((c >= 'a') && (c <= 'f')) + return c - 'a' + 10; + if ((c >= '0') && (c <= '9')) + return c - '0'; + return 0; +} + +static char * +parse_rgb_string (const gchar *s) +{ + static char col[3]; + col[0] = (hexval (s[0]) << 4) | hexval (s[1]); + col[1] = (hexval (s[2]) << 4) | hexval (s[3]); + col[2] = (hexval (s[4]) << 4) | hexval (s[5]); + return col; +} + +static void +set_orient_vector (const gchar *str) +{ + const gchar *tmps = str; + int n; + + n = atoi (tmps); + + if (!(tmps = strchr (tmps, ','))) + return; + pcvals.orient_vectors[n].x = g_ascii_strtod (++tmps, NULL); + + if (!(tmps = strchr (tmps, ','))) + return; + pcvals.orient_vectors[n].y = g_ascii_strtod (++tmps, NULL); + + if (!(tmps = strchr (tmps, ','))) + return; + pcvals.orient_vectors[n].dir = g_ascii_strtod (++tmps, NULL); + + if (!(tmps = strchr (tmps, ','))) + return; + pcvals.orient_vectors[n].dx = g_ascii_strtod (++tmps, NULL); + + if (!(tmps = strchr (tmps, ','))) + return; + pcvals.orient_vectors[n].dy = g_ascii_strtod (++tmps, NULL); + + if (!(tmps = strchr (tmps, ','))) + return; + pcvals.orient_vectors[n].str = g_ascii_strtod (++tmps, NULL); + + if (!(tmps = strchr (tmps, ','))) + return; + pcvals.orient_vectors[n].type = atoi (++tmps); + +} + +static void set_size_vector (const gchar *str) +{ + const gchar *tmps = str; + int n; + + n = atoi (tmps); + + if (!(tmps = strchr (tmps, ','))) + return; + pcvals.size_vectors[n].x = g_ascii_strtod (++tmps, NULL); + + if (!(tmps = strchr (tmps, ','))) + return; + pcvals.size_vectors[n].y = g_ascii_strtod (++tmps, NULL); + + if (!(tmps = strchr (tmps, ','))) + return; + pcvals.size_vectors[n].siz = g_ascii_strtod (++tmps, NULL); + + if (!(tmps = strchr (tmps, ','))) + return; + pcvals.size_vectors[n].str = g_ascii_strtod (++tmps, NULL); + +} + +static void +parse_desc (const gchar *str, gchar *d, gssize d_len) +{ + gchar *dest = g_strcompress (str); + + g_strlcpy (d, dest, d_len); + + g_free (dest); +} + +static void +set_values (const gchar *key, const gchar *val) +{ + if (!strcmp (key, "desc")) + parse_desc (val, presetdesc, sizeof (presetdesc)); + else if (!strcmp (key, "orientnum")) + pcvals.orient_num = atoi (val); + else if (!strcmp (key, "orientfirst")) + pcvals.orient_first = g_ascii_strtod (val, NULL); + else if (!strcmp (key, "orientlast")) + pcvals.orient_last = g_ascii_strtod (val, NULL); + else if (!strcmp (key, "orienttype")) + pcvals.orient_type = orientation_type_input (atoi (val)); + + else if (!strcmp (key, "sizenum")) + pcvals.size_num = atoi (val); + else if (!strcmp (key, "sizefirst")) + pcvals.size_first = g_ascii_strtod (val, NULL); + else if (!strcmp (key, "sizelast")) + pcvals.size_last = g_ascii_strtod (val, NULL); + else if (!strcmp (key, "sizetype")) + pcvals.size_type = size_type_input (atoi (val)); + + else if (!strcmp (key, "brushrelief")) + pcvals.brush_relief = g_ascii_strtod (val, NULL); + else if (!strcmp (key, "brushscale")) + { + /* For compatibility */ + pcvals.size_num = 1; + pcvals.size_first = pcvals.size_last = g_ascii_strtod (val, NULL); + } + else if (!strcmp (key, "brushdensity")) + pcvals.brush_density = g_ascii_strtod (val, NULL); + else if (!strcmp (key, "brushgamma")) + pcvals.brushgamma = g_ascii_strtod (val, NULL); + else if (!strcmp (key, "brushaspect")) + pcvals.brush_aspect = g_ascii_strtod (val, NULL); + + else if (!strcmp (key, "generalbgtype")) + pcvals.general_background_type = general_bg_type_input (atoi (val)); + else if (!strcmp (key, "generaldarkedge")) + pcvals.general_dark_edge = g_ascii_strtod (val, NULL); + else if (!strcmp (key, "generalpaintedges")) + pcvals.general_paint_edges = atoi (val); + else if (!strcmp (key, "generaltileable")) + pcvals.general_tileable = atoi (val); + else if (!strcmp (key, "generaldropshadow")) + pcvals.general_drop_shadow = atoi (val); + else if (!strcmp (key, "generalshadowdarkness")) + pcvals.general_shadow_darkness = g_ascii_strtod (val, NULL); + else if (!strcmp (key, "generalshadowdepth")) + pcvals.general_shadow_depth = atoi (val); + else if (!strcmp (key, "generalshadowblur")) + pcvals.general_shadow_blur = atoi (val); + else if (!strcmp (key, "devthresh")) + pcvals.devthresh = g_ascii_strtod (val, NULL); + + else if (!strcmp (key, "paperrelief")) + pcvals.paper_relief = g_ascii_strtod (val, NULL); + else if (!strcmp (key, "paperscale")) + pcvals.paper_scale = g_ascii_strtod (val, NULL); + else if (!strcmp (key, "paperinvert")) + pcvals.paper_invert = atoi (val); + else if (!strcmp (key, "paperoverlay")) + pcvals.paper_overlay = atoi (val); + + else if (!strcmp (key, "placetype")) + pcvals.place_type = place_type_input (atoi (val)); + else if (!strcmp (key, "placecenter")) + pcvals.placement_center = atoi (val); + + else if (!strcmp (key, "selectedbrush")) + g_strlcpy (pcvals.selected_brush, val, sizeof (pcvals.selected_brush)); + else if (!strcmp (key, "selectedpaper")) + g_strlcpy (pcvals.selected_paper, val, sizeof (pcvals.selected_paper)); + + else if (!strcmp (key, "color")) + { + char *c = parse_rgb_string (val); + gimp_rgba_set_uchar (&pcvals.color, c[0], c[1], c[2], 255); + } + + else if (!strcmp (key, "numorientvector")) + pcvals.num_orient_vectors = atoi (val); + else if (!strcmp (key, "orientvector")) + set_orient_vector (val); + else if (!strcmp (key, "orientangoff")) + pcvals.orient_angle_offset = g_ascii_strtod (val, NULL); + else if (!strcmp (key, "orientstrexp")) + pcvals.orient_strength_exponent = g_ascii_strtod (val, NULL); + else if (!strcmp (key, "orientvoronoi")) + pcvals.orient_voronoi = atoi (val); + + else if (!strcmp (key, "numsizevector")) + pcvals.num_size_vectors = atoi (val); + else if (!strcmp (key, "sizevector")) + set_size_vector (val); + else if (!strcmp (key, "sizestrexp")) + pcvals.size_strength_exponent = g_ascii_strtod (val, NULL); + else if (!strcmp (key, "sizevoronoi")) + pcvals.size_voronoi = atoi (val); + + else if (!strcmp (key, "colortype")) + pcvals.color_type = color_type_input (atoi (val)); + else if (!strcmp (key, "colornoise")) + pcvals.color_noise = g_ascii_strtod (val, NULL); +} + +static int +load_preset (const gchar *fn) +{ + char line[1024] = ""; + FILE *f; + + f = g_fopen (fn, "rt"); + if (!f) + { + g_printerr ("Error opening file \"%s\" for reading!\n", + gimp_filename_to_utf8 (fn)); + return -1; + } + fgets (line, 10, f); + if (strncmp (line, PRESETMAGIC, 4)) + { + fclose (f); + return load_old_preset (fn); + } + + restore_default_values (); + + while (!feof (f)) + { + char *tmps; + + if (!fgets (line, 1024, f)) + break; + g_strchomp (line); + tmps = strchr (line, '='); + if (!tmps) + continue; + *tmps = '\0'; + tmps++; + set_values (line, tmps); + } + fclose (f); + return 0; +} + +int +select_preset (const gchar *preset) +{ + int ret = SELECT_PRESET_OK; + /* I'm copying this behavior as is. As it seems applying the + * factory_defaults preset does nothing, which I'm not sure + * if that was what the author intended. + * -- Shlomi Fish + */ + if (strcmp (preset, factory_defaults)) + { + gchar *rel = g_build_filename ("Presets", preset, NULL); + gchar *abs = findfile (rel); + + g_free (rel); + + if (abs) + { + if (load_preset (abs)) + ret = SELECT_PRESET_LOAD_FAILED; + + g_free (abs); + } + else + { + ret = SELECT_PRESET_FILE_NOT_FOUND; + } + } + if (ret == SELECT_PRESET_OK) + { + /* This is so the colorbrushes param (that is not stored in the + * preset will be set correctly upon the preset loading. + * */ + set_colorbrushes (pcvals.selected_brush); + } + + return ret; +} + +static void +apply_preset (GtkWidget *w, GtkTreeSelection *selection) +{ + GtkTreeIter iter; + GtkTreeModel *model; + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gchar *preset; + + gtk_tree_model_get (model, &iter, PRESETS_LIST_COLUMN_FILENAME, + &preset, -1); + + select_preset (preset); + + restore_values (); + + /* g_free (preset); */ + g_free (selected_preset_filename); + selected_preset_filename = preset; + } +} + +static void +delete_preset (GtkWidget *w, GtkTreeSelection *selection) +{ + GtkTreeIter iter; + GtkTreeModel *model; + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gchar *preset; + + gtk_tree_model_get (model, &iter, PRESETS_LIST_COLUMN_FILENAME, + &preset, -1); + + if (preset) + { + gchar *rel = g_build_filename ("Presets", preset, NULL); + gchar *abs = findfile (rel); + + g_free (rel); + + if (abs) + { + /* Don't delete global presets - bug # 147483 */ + if (can_delete_preset (abs)) + g_unlink (abs); + + g_free (abs); + } + + preset_refresh_presets (); + + g_free (preset); + } + } +} + +static void save_preset (void); + +static void +preset_desc_callback (GtkTextBuffer *buffer, gpointer data) +{ + char *str; + GtkTextIter start, end; + + gtk_text_buffer_get_bounds (buffer, &start, &end); + str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); + g_strlcpy (presetdesc, str, sizeof (presetdesc)); + g_free (str); +} + +static void +save_preset_response (GtkWidget *widget, + gint response_id, + gpointer data) +{ + gtk_widget_destroy (widget); + + if (response_id == GTK_RESPONSE_OK) + save_preset (); +} + +static void +create_save_preset (GtkWidget *parent) +{ + static GtkWidget *window = NULL; + GtkWidget *box, *label; + GtkWidget *swin, *text; + GtkTextBuffer *buffer; + + if (window) + { + gtk_window_present (GTK_WINDOW (window)); + return; + } + + window = gimp_dialog_new (_("Save Current"), PLUG_IN_ROLE, + gtk_widget_get_toplevel (parent), 0, + gimp_standard_help_func, PLUG_IN_PROC, + + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_OK"), GTK_RESPONSE_OK, + + NULL); + + gtk_dialog_set_alternative_button_order (GTK_DIALOG (window), + GTK_RESPONSE_OK, + GTK_RESPONSE_CANCEL, + -1); + + g_signal_connect (window, "response", + G_CALLBACK (save_preset_response), + NULL); + g_signal_connect (window, "destroy", + G_CALLBACK (gtk_widget_destroyed), + &window); + + box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); + gtk_container_set_border_width (GTK_CONTAINER (box), 12); + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))), + box, TRUE, TRUE, 0); + gtk_widget_show (box); + + label = gtk_label_new (_("Description:")); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + swin = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin), + GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (box), swin, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_widget_show (swin); + + buffer = gtk_text_buffer_new (NULL); + g_signal_connect (buffer, "changed", + G_CALLBACK (preset_desc_callback), NULL); + gtk_text_buffer_set_text (buffer, presetdesc, -1); + + text = gtk_text_view_new_with_buffer (buffer); + gtk_widget_set_size_request (text, -1, 192); + gtk_container_add (GTK_CONTAINER (swin), text); + gtk_widget_show (text); + + gtk_widget_show (window); +} + +static void +save_preset (void) +{ + const gchar *preset_name; + + gchar *fname, *presets_dir_path; + FILE *f; + GList *thispath; + gchar buf[G_ASCII_DTOSTR_BUF_SIZE]; + gchar vbuf[6][G_ASCII_DTOSTR_BUF_SIZE]; + guchar color[3]; + gint i; + gchar *desc_escaped, *preset_name_escaped; + + preset_name = gtk_entry_get_text (GTK_ENTRY (presetnameentry)); + thispath = parsepath (); + store_values (); + + if (!thispath) + { + g_printerr ("Internal error: (save_preset) thispath == NULL\n"); + return; + } + + /* Create the ~/.gimp-$VER/gimpressionist/Presets directory if + * it doesn't already exists. + * + */ + presets_dir_path = g_build_filename ((const gchar *) thispath->data, + "Presets", + NULL); + + if (! g_file_test (presets_dir_path, G_FILE_TEST_IS_DIR)) + { + if (g_mkdir (presets_dir_path, + S_IRUSR | S_IWUSR | S_IXUSR | + S_IRGRP | S_IXGRP | + S_IROTH | S_IXOTH) == -1) + { + g_printerr ("Error creating folder \"%s\"!\n", + gimp_filename_to_utf8 (presets_dir_path)); + g_free (presets_dir_path); + return; + } + } + + /* Check if the user-friendly name has changed. If so, then save it + * under a new file. If not - use the same file name. + */ + if (selected_preset_orig_name && + strcmp (preset_name, selected_preset_orig_name) == 0) + { + fname = g_build_filename (presets_dir_path, + selected_preset_filename, + NULL); + } + else + { + fname = preset_create_filename (preset_name, presets_dir_path); + } + + g_free (presets_dir_path); + + if (!fname) + { + g_printerr ("Error building a filename for preset \"%s\"!\n", + preset_name); + return; + } + + f = g_fopen (fname, "wt"); + if (!f) + { + g_printerr ("Error opening file \"%s\" for writing!\n", + gimp_filename_to_utf8 (fname)); + g_free (fname); + return; + } + + fprintf (f, "%s\n", PRESETMAGIC); + desc_escaped = g_strescape (presetdesc, NULL); + fprintf (f, "desc=%s\n", desc_escaped); + g_free (desc_escaped); + preset_name_escaped = g_strescape (preset_name, NULL); + fprintf (f, "name=%s\n", preset_name_escaped); + g_free (preset_name_escaped); + fprintf (f, "orientnum=%d\n", pcvals.orient_num); + fprintf (f, "orientfirst=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_first)); + fprintf (f, "orientlast=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_last)); + fprintf (f, "orienttype=%d\n", pcvals.orient_type); + + fprintf (f, "sizenum=%d\n", pcvals.size_num); + fprintf (f, "sizefirst=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.size_first)); + fprintf (f, "sizelast=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.size_last)); + fprintf (f, "sizetype=%d\n", pcvals.size_type); + + fprintf (f, "brushrelief=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.brush_relief)); + fprintf (f, "brushdensity=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.brush_density)); + fprintf (f, "brushgamma=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.brushgamma)); + fprintf (f, "brushaspect=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.brush_aspect)); + + fprintf (f, "generalbgtype=%d\n", pcvals.general_background_type); + fprintf (f, "generaldarkedge=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.general_dark_edge)); + fprintf (f, "generalpaintedges=%d\n", pcvals.general_paint_edges); + fprintf (f, "generaltileable=%d\n", pcvals.general_tileable); + fprintf (f, "generaldropshadow=%d\n", pcvals.general_drop_shadow); + fprintf (f, "generalshadowdarkness=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.general_shadow_darkness)); + fprintf (f, "generalshadowdepth=%d\n", pcvals.general_shadow_depth); + fprintf (f, "generalshadowblur=%d\n", pcvals.general_shadow_blur); + fprintf (f, "devthresh=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.devthresh)); + + fprintf (f, "paperrelief=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.paper_relief)); + fprintf (f, "paperscale=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.paper_scale)); + fprintf (f, "paperinvert=%d\n", pcvals.paper_invert); + fprintf (f, "paperoverlay=%d\n", pcvals.paper_overlay); + + fprintf (f, "selectedbrush=%s\n", pcvals.selected_brush); + fprintf (f, "selectedpaper=%s\n", pcvals.selected_paper); + + gimp_rgb_get_uchar (&pcvals.color, &color[0], &color[1], &color[2]); + fprintf (f, "color=%02x%02x%02x\n", color[0], color[1], color[2]); + + fprintf (f, "placetype=%d\n", pcvals.place_type); + fprintf (f, "placecenter=%d\n", pcvals.placement_center); + + fprintf (f, "numorientvector=%d\n", pcvals.num_orient_vectors); + for (i = 0; i < pcvals.num_orient_vectors; i++) + { + g_ascii_dtostr (vbuf[0], G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_vectors[i].x); + g_ascii_dtostr (vbuf[1], G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_vectors[i].y); + g_ascii_dtostr (vbuf[2], G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_vectors[i].dir); + g_ascii_dtostr (vbuf[3], G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_vectors[i].dx); + g_ascii_dtostr (vbuf[4], G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_vectors[i].dy); + g_ascii_dtostr (vbuf[5], G_ASCII_DTOSTR_BUF_SIZE, pcvals.orient_vectors[i].str); + + fprintf (f, "orientvector=%d,%s,%s,%s,%s,%s,%s,%d\n", i, + vbuf[0], vbuf[1], vbuf[2], vbuf[3], vbuf[4], vbuf[5], + pcvals.orient_vectors[i].type); + } + + fprintf (f, "orientangoff=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, + pcvals.orient_angle_offset)); + fprintf (f, "orientstrexp=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, + pcvals.orient_strength_exponent)); + fprintf (f, "orientvoronoi=%d\n", pcvals.orient_voronoi); + + fprintf (f, "numsizevector=%d\n", pcvals.num_size_vectors); + for (i = 0; i < pcvals.num_size_vectors; i++) + { + g_ascii_dtostr (vbuf[0], G_ASCII_DTOSTR_BUF_SIZE, pcvals.size_vectors[i].x); + g_ascii_dtostr (vbuf[1], G_ASCII_DTOSTR_BUF_SIZE, pcvals.size_vectors[i].y); + g_ascii_dtostr (vbuf[2], G_ASCII_DTOSTR_BUF_SIZE, pcvals.size_vectors[i].siz); + g_ascii_dtostr (vbuf[3], G_ASCII_DTOSTR_BUF_SIZE, pcvals.size_vectors[i].str); + fprintf (f, "sizevector=%d,%s,%s,%s,%s\n", i, + vbuf[0], vbuf[1], vbuf[2], vbuf[3]); + } + fprintf (f, "sizestrexp=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.size_strength_exponent)); + fprintf (f, "sizevoronoi=%d\n", pcvals.size_voronoi); + + fprintf (f, "colortype=%d\n", pcvals.color_type); + fprintf (f, "colornoise=%s\n", + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, pcvals.color_noise)); + + fclose (f); + preset_refresh_presets (); + reselect (presetlist, fname); + + g_free (fname); +} + +static void +read_description (const char *fn) +{ + char *rel_fname; + char *fname; + gchar *unprocessed_line; + + rel_fname = g_build_filename ("Presets", fn, NULL); + fname = findfile (rel_fname); + g_free (rel_fname); + + if (!fname) + { + if (!strcmp (fn, factory_defaults)) + { + gtk_widget_set_sensitive (delete_button, FALSE); + set_preset_description_text (_("Gimpressionist Defaults")); + } + else + { + set_preset_description_text (""); + } + return; + } + + /* Don't delete global presets - bug # 147483 */ + gtk_widget_set_sensitive (delete_button, can_delete_preset (fname)); + + unprocessed_line = get_early_line_from_preset (fname, "desc="); + g_free (fname); + + if (unprocessed_line) + { + char tmplabel[4096]; + parse_desc (unprocessed_line, tmplabel, sizeof (tmplabel)); + g_free (unprocessed_line); + set_preset_description_text (tmplabel); + } + else + { + set_preset_description_text (""); + } +} + +static void +presets_list_select_preset (GtkTreeSelection *selection, + gpointer data) +{ + GtkTreeIter iter; + GtkTreeModel *model; + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gchar *preset_name; + gchar *preset_filename; + + gtk_tree_model_get (model, &iter, PRESETS_LIST_COLUMN_OBJECT_NAME, + &preset_name, -1); + gtk_tree_model_get (model, &iter, PRESETS_LIST_COLUMN_FILENAME, + &preset_filename, -1); + + /* TODO : Maybe make the factory defaults behavior in regards + * to the preset's object name and filename more robust? + * + */ + if (strcmp (preset_filename, factory_defaults)) + { + gtk_entry_set_text (GTK_ENTRY (presetnameentry), preset_name); + g_free (selected_preset_orig_name); + g_free (selected_preset_filename); + selected_preset_orig_name = g_strdup (preset_name); + selected_preset_filename = g_strdup (selected_preset_filename); + } + + read_description (preset_filename); + + g_free (preset_name); + g_free (preset_filename); + } +} + +static GtkWidget * +create_presets_list (GtkWidget *parent) +{ + GtkListStore *store; + GtkTreeSelection *selection; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkWidget *swin, *view; + + swin = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin), + GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (parent), swin, FALSE, FALSE, 0); + gtk_widget_show (swin); + gtk_widget_set_size_request (swin, 200, -1); + + store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); + + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE); + g_object_unref (store); + gtk_widget_show (view); + + renderer = gtk_cell_renderer_text_new (); + + column = + gtk_tree_view_column_new_with_attributes ("Preset", renderer, + "text", + PRESETS_LIST_COLUMN_OBJECT_NAME, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (view), column); + + + gtk_container_add (GTK_CONTAINER (swin), view); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); + g_signal_connect (selection, "changed", + G_CALLBACK (presets_list_select_preset), + NULL); + + return view; +} + +void +create_presetpage (GtkNotebook *notebook) +{ + GtkWidget *vbox, *hbox, *box1, *box2, *thispage; + GtkWidget *view; + GtkWidget *tmpw; + GtkWidget *label; + GtkTreeSelection *selection; + + label = gtk_label_new_with_mnemonic (_("_Presets")); + + thispage = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); + gtk_container_set_border_width (GTK_CONTAINER (thispage), 12); + gtk_widget_show (thispage); + + box1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); + gtk_box_pack_start (GTK_BOX (thispage), box1, FALSE, FALSE, 0); + gtk_widget_show (box1); + + presetnameentry = tmpw = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX (box1), tmpw, FALSE, FALSE, 0); + gtk_widget_set_size_request (tmpw, 200, -1); + gtk_widget_show (tmpw); + + presetsavebutton = tmpw = gtk_button_new_with_label ( _("Save Current...")); + gtk_button_set_image (GTK_BUTTON (presetsavebutton), + gtk_image_new_from_icon_name (GIMP_ICON_DOCUMENT_SAVE, + GTK_ICON_SIZE_BUTTON)); + gtk_box_pack_start (GTK_BOX (box1), tmpw, FALSE, FALSE, 0); + gtk_widget_show (tmpw); + g_signal_connect (tmpw, "clicked", G_CALLBACK (create_save_preset), NULL); + gimp_help_set_help_data + (tmpw, _("Save the current settings to the specified file"), NULL); + + box1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); + gtk_box_pack_start (GTK_BOX (thispage), box1, TRUE, TRUE, 0); + gtk_widget_show (box1); + + presetlist = view = create_presets_list (box1); + store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view))); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); + add_factory_defaults (); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); + gtk_box_pack_start (GTK_BOX (box1), vbox, FALSE, FALSE, 0); + gtk_widget_show (vbox); + + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + gtk_widget_show (hbox); + + box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); + gtk_box_pack_start (GTK_BOX (hbox), box2, FALSE, FALSE, 0); + gtk_widget_show (box2); + + tmpw = gtk_button_new_with_mnemonic (_("_Apply")); + gtk_box_pack_start (GTK_BOX (box2), tmpw, FALSE, FALSE, 0); + gtk_widget_show (tmpw); + g_signal_connect (tmpw, "clicked", G_CALLBACK (apply_preset), selection); + gimp_help_set_help_data + (tmpw, _("Reads the selected Preset into memory"), NULL); + + tmpw = delete_button = gtk_button_new_with_mnemonic (_("_Delete")); + gtk_box_pack_start (GTK_BOX (box2), tmpw, FALSE, FALSE,0); + gtk_widget_show (tmpw); + g_signal_connect (tmpw, "clicked", G_CALLBACK (delete_preset), selection); + gimp_help_set_help_data (tmpw, _("Deletes the selected Preset"), NULL); + + tmpw = gtk_button_new_with_mnemonic (_("_Refresh")); + gtk_box_pack_start (GTK_BOX (box2), tmpw, FALSE, FALSE,0); + gtk_widget_show (tmpw); + g_signal_connect (tmpw, "clicked", G_CALLBACK (preset_refresh_presets), NULL); + gimp_help_set_help_data (tmpw, _("Reread the folder of Presets"), NULL); + + presetdesclabel = tmpw = gtk_label_new (NULL); + gimp_label_set_attributes (GTK_LABEL (tmpw), + PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC, + -1); + gtk_label_set_line_wrap (GTK_LABEL (tmpw), TRUE); + /* + * Make sure the label's width is reasonable and it won't stretch + * the dialog more than its width. + * */ + gtk_widget_set_size_request (tmpw, 240, -1); + + gtk_label_set_xalign (GTK_LABEL (tmpw), 0.0); + gtk_label_set_yalign (GTK_LABEL (tmpw), 0.0); + gtk_box_pack_start (GTK_BOX (vbox), tmpw, TRUE, TRUE, 0); + gtk_widget_show (tmpw); + + preset_read_dir_into_list (); + + gtk_notebook_append_page_menu (notebook, thispage, label, NULL); +} |