1 /*
2  * This is a plug-in for GIMP.
3  *
4  * Generates clickable image maps.
5  *
6  * Copyright (C) 1998-2005 Maurits Rijk  m.rijk@chello.nl
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #include "config.h"
24 
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include <glib/gstdio.h>
29 
30 #include "libgimp/gimp.h"
31 #include "libgimp/gimpui.h"
32 
33 #include "imap_command.h"
34 #include "imap_file.h"
35 #include "imap_main.h"
36 #include "imap_menu.h"
37 #include "imap_misc.h"
38 #include "imap_mru.h"
39 #include "imap_preferences.h"
40 #include "imap_table.h"
41 
42 #include "libgimp/stdplugins-intl.h"
43 
44 typedef struct {
45    DefaultDialog_t      *dialog;
46    GtkWidget            *notebook;
47    GtkWidget            *ncsa;
48    GtkWidget            *cern;
49    GtkWidget            *csim;
50    GtkWidget            *prompt_for_area_info;
51    GtkWidget            *require_default_url;
52    GtkWidget            *show_area_handle;
53    GtkWidget            *keep_circles_round;
54    GtkWidget            *show_url_tip;
55    GtkWidget            *use_doublesized;
56 
57    GtkWidget            *undo_levels;
58    GtkWidget            *mru_size;
59 
60    GtkWidget            *normal_fg;
61    GtkWidget            *normal_bg;
62    GtkWidget            *selected_fg;
63    GtkWidget            *selected_bg;
64    GtkWidget            *interactive_fg;
65    GtkWidget            *interactive_bg;
66 
67    GtkWidget            *threshold;
68    GtkWidget            *auto_convert;
69 
70    PreferencesData_t    *old_data;
71 } PreferencesDialog_t;
72 
73 static void get_button_colors (PreferencesDialog_t *dialog,
74                                ColorSelData_t *colors);
75 
76 static gint
parse_map_type(void)77 parse_map_type(void)
78 {
79    char *token = strtok(NULL, " )");
80    if (!strcmp(token, "ncsa"))
81       return NCSA;
82    else if (!strcmp(token, "cern"))
83       return CERN;
84    return CSIM;
85 }
86 
87 static gint
parse_yes_no(void)88 parse_yes_no(void)
89 {
90    char *token = strtok(NULL, " )");
91    return (gint) strcmp(token, "no");
92 }
93 
94 static gint
parse_int(void)95 parse_int(void)
96 {
97    char *token = strtok(NULL, " )");
98    return (gint) atoi(token);
99 }
100 
101 static void
parse_color(GdkColor * gdk_color)102 parse_color(GdkColor *gdk_color)
103 {
104    gdk_color->red = (guint16) parse_int();
105    gdk_color->green = (guint16) parse_int();
106    gdk_color->blue = (guint16) parse_int();
107 }
108 
109 static void
parse_mru_entry(void)110 parse_mru_entry(void)
111 {
112    char *filename = strtok(NULL, " )");
113    mru_add(get_mru(), filename);
114 }
115 
116 static void
parse_line(PreferencesData_t * data,char * line)117 parse_line(PreferencesData_t *data, char *line)
118 {
119    char *token;
120    ColorSelData_t *colors = &data->colors;
121 
122    line++;                      /* Skip '(' */
123    token = strtok(line, " ");
124 
125    if (!strcmp(token, "default-map-type")) {
126       data->default_map_type = parse_map_type();
127    }else if (!strcmp(token, "prompt-for-area-info")) {
128       data->prompt_for_area_info = parse_yes_no();
129    } else if (!strcmp(token, "require-default-url")) {
130       data->require_default_url = parse_yes_no();
131    } else if (!strcmp(token, "show-area-handle")) {
132       data->show_area_handle = parse_yes_no();
133    } else if (!strcmp(token, "keep-circles-round")) {
134       data->keep_circles_round = parse_yes_no();
135    } else if (!strcmp(token, "show-url-tip")) {
136       data->show_url_tip = parse_yes_no();
137    } else if (!strcmp(token, "use-doublesized")) {
138       data->use_doublesized = parse_yes_no();
139    } else if (!strcmp(token, "mru-size")) {
140       data->mru_size = parse_int();
141       if (data->mru_size < 1)
142         data->mru_size = 1;
143    } else if (!strcmp(token, "undo-levels")) {
144       data->undo_levels = parse_int();
145       if (data->undo_levels < 1)
146         data->undo_levels = 1;
147    } else if (!strcmp(token, "normal-fg-color")) {
148       parse_color(&colors->normal_fg);
149    } else if (!strcmp(token, "normal-bg-color")) {
150       parse_color(&colors->normal_bg);
151    } else if (!strcmp(token, "selected-fg-color")) {
152       parse_color(&colors->selected_fg);
153    } else if (!strcmp(token, "selected-bg-color")) {
154       parse_color(&colors->selected_bg);
155    } else if (!strcmp(token, "interactive-fg-color")) {
156       parse_color(&colors->interactive_fg);
157    } else if (!strcmp(token, "interactive-bg-color")) {
158       parse_color(&colors->interactive_bg);
159    } else if (!strcmp(token, "mru-entry")) {
160       parse_mru_entry();
161    } else {
162       /* Unrecognized, just ignore rest of line */
163    }
164 }
165 
166 gboolean
preferences_load(PreferencesData_t * data)167 preferences_load(PreferencesData_t *data)
168 {
169    FILE *in;
170    char buf[256];
171    gchar *filename;
172 
173    filename = gimp_personal_rc_file ("imagemaprc");
174 
175    in = g_fopen(filename, "rb");
176    g_free(filename);
177    if (in) {
178       while (fgets(buf, sizeof(buf), in)) {
179          if (*buf != '\n' && *buf != '#') {
180             parse_line(data, buf);
181          }
182       }
183       fclose(in);
184       return TRUE;
185    }
186    return FALSE;
187 }
188 
189 void
preferences_save(PreferencesData_t * data)190 preferences_save(PreferencesData_t *data)
191 {
192    FILE *out;
193    gchar *filename;
194    ColorSelData_t *colors = &data->colors;
195 
196    filename = gimp_personal_rc_file ("imagemaprc");
197 
198    out = g_fopen(filename, "wb");
199    if (out) {
200       fprintf(out, "# Image map plug-in resource file\n\n");
201       if (data->default_map_type == NCSA)
202          fprintf(out, "(default-map-type ncsa)\n");
203       else if (data->default_map_type == CERN)
204          fprintf(out, "(default-map-type cern)\n");
205       else
206          fprintf(out, "(default-map-type csim)\n");
207 
208       fprintf(out, "(prompt-for-area-info %s)\n",
209               (data->prompt_for_area_info) ? "yes" : "no");
210       fprintf(out, "(require-default-url %s)\n",
211               (data->require_default_url) ? "yes" : "no");
212       fprintf(out, "(show-area-handle %s)\n",
213               (data->show_area_handle) ? "yes" : "no");
214       fprintf(out, "(keep-circles-round %s)\n",
215               (data->keep_circles_round) ? "yes" : "no");
216       fprintf(out, "(show-url-tip %s)\n",
217               (data->show_url_tip) ? "yes" : "no");
218       fprintf(out, "(use-doublesized %s)\n",
219               (data->use_doublesized) ? "yes" : "no");
220 
221       fprintf(out, "(undo-levels %d)\n", data->undo_levels);
222       fprintf(out, "(mru-size %d)\n", data->mru_size);
223 
224       fprintf(out, "(normal-fg-color %d %d %d)\n",
225               colors->normal_fg.red, colors->normal_fg.green,
226               colors->normal_fg.blue);
227       fprintf(out, "(normal-bg-color %d %d %d)\n",
228               colors->normal_bg.red, colors->normal_bg.green,
229               colors->normal_bg.blue);
230       fprintf(out, "(selected-fg-color %d %d %d)\n",
231               colors->selected_fg.red, colors->selected_fg.green,
232               colors->selected_fg.blue);
233       fprintf(out, "(selected-bg-color %d %d %d)\n",
234               colors->selected_bg.red, colors->selected_bg.green,
235               colors->selected_bg.blue);
236       fprintf(out, "(interactive-fg-color %d %d %d)\n",
237               colors->interactive_fg.red, colors->interactive_fg.green,
238               colors->interactive_fg.blue);
239       fprintf(out, "(interactive-bg-color %d %d %d)\n",
240               colors->interactive_bg.red, colors->interactive_bg.green,
241               colors->interactive_bg.blue);
242 
243       mru_write(get_mru(), out);
244 
245       fclose(out);
246    } else {
247       do_file_error_dialog( _("Couldn't save resource file:"), filename);
248    }
249    g_free(filename);
250 }
251 
252 static void
preferences_ok_cb(gpointer data)253 preferences_ok_cb(gpointer data)
254 {
255    PreferencesDialog_t *param = (PreferencesDialog_t*) data;
256    PreferencesData_t *old_data = param->old_data;
257    ColorSelData_t *colors = &old_data->colors;
258    MRU_t *mru = get_mru();
259 
260    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(param->cern)))
261       old_data->default_map_type = CERN;
262    else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(param->ncsa)))
263       old_data->default_map_type = NCSA;
264    else
265       old_data->default_map_type = CSIM;
266 
267    old_data->prompt_for_area_info = gtk_toggle_button_get_active(
268       GTK_TOGGLE_BUTTON(param->prompt_for_area_info));
269    old_data->require_default_url = gtk_toggle_button_get_active(
270       GTK_TOGGLE_BUTTON(param->require_default_url));
271    old_data->show_area_handle = gtk_toggle_button_get_active(
272       GTK_TOGGLE_BUTTON(param->show_area_handle));
273    old_data->keep_circles_round = gtk_toggle_button_get_active(
274       GTK_TOGGLE_BUTTON(param->keep_circles_round));
275    old_data->show_url_tip = gtk_toggle_button_get_active(
276       GTK_TOGGLE_BUTTON(param->show_url_tip));
277    old_data->use_doublesized = gtk_toggle_button_get_active(
278       GTK_TOGGLE_BUTTON(param->use_doublesized));
279 
280    old_data->mru_size =
281       gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->mru_size));
282    old_data->undo_levels =
283       gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->undo_levels));
284    mru_set_size(mru, old_data->mru_size);
285    menu_build_mru_items(mru);
286    command_list_set_undo_level(old_data->undo_levels);
287 
288    get_button_colors (param, colors);
289 
290    set_sash_size(old_data->use_doublesized);
291    preview_redraw();
292 }
293 
294 static void
get_button_color(GtkWidget * button,GdkColor * color)295 get_button_color (GtkWidget *button, GdkColor *color)
296 {
297   GimpRGB rgb;
298   gimp_color_button_get_color (GIMP_COLOR_BUTTON (button), &rgb);
299   color->red = rgb.r * 0xffff;
300   color->green = rgb.g * 0xffff;
301   color->blue = rgb.b * 0xffff;
302 }
303 
304 static void
get_button_colors(PreferencesDialog_t * dialog,ColorSelData_t * colors)305 get_button_colors(PreferencesDialog_t *dialog, ColorSelData_t *colors)
306 {
307   get_button_color (dialog->normal_fg, &colors->normal_fg);
308   get_button_color (dialog->normal_bg, &colors->normal_bg);
309   get_button_color (dialog->selected_fg, &colors->selected_fg);
310   get_button_color (dialog->selected_bg, &colors->selected_bg);
311   get_button_color (dialog->interactive_fg, &colors->interactive_fg);
312   get_button_color (dialog->interactive_bg, &colors->interactive_bg);
313 }
314 
315 static void
set_button_color(GtkWidget * button,GdkColor * color)316 set_button_color (GtkWidget *button, GdkColor *color)
317 {
318   GimpRGB rgb;
319   gimp_rgb_set (&rgb, color->red, color->green, color->blue);
320   gimp_rgb_multiply (&rgb, 1.0 / 0xffff);
321   gimp_color_button_set_color (GIMP_COLOR_BUTTON (button), &rgb);
322 }
323 
324 static void
set_button_colors(PreferencesDialog_t * dialog,ColorSelData_t * colors)325 set_button_colors(PreferencesDialog_t *dialog, ColorSelData_t *colors)
326 {
327   set_button_color (dialog->normal_fg, &colors->normal_fg);
328   set_button_color (dialog->normal_bg, &colors->normal_bg);
329   set_button_color (dialog->selected_fg, &colors->selected_fg);
330   set_button_color (dialog->selected_bg, &colors->selected_bg);
331   set_button_color (dialog->interactive_fg, &colors->interactive_fg);
332   set_button_color (dialog->interactive_bg, &colors->interactive_bg);
333 }
334 
335 static GtkWidget*
create_tab(GtkWidget * notebook,const gchar * label,gint rows,gint cols)336 create_tab(GtkWidget *notebook, const gchar *label, gint rows, gint cols)
337 {
338    GtkWidget *table;
339    GtkWidget *vbox;
340 
341    vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 1);
342    gtk_widget_show(vbox);
343 
344    table = gtk_table_new(rows, cols, FALSE);
345    gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
346    gtk_container_set_border_width(GTK_CONTAINER(table), 12);
347    gtk_table_set_row_spacings(GTK_TABLE(table), 6);
348    gtk_table_set_col_spacings(GTK_TABLE(table), 6);
349    gtk_widget_show(table);
350 
351    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox,
352                             gtk_label_new_with_mnemonic(label));
353 
354    return table;
355 }
356 
357 static void
create_general_tab(PreferencesDialog_t * data,GtkWidget * notebook)358 create_general_tab(PreferencesDialog_t *data, GtkWidget *notebook)
359 {
360    GtkWidget *table = create_tab(notebook, _("General"), 7, 2);
361    GtkWidget *frame;
362    GtkWidget *hbox;
363 
364    frame = gimp_frame_new( _("Default Map Type"));
365    gtk_widget_show(frame);
366    gtk_table_attach_defaults(GTK_TABLE(table), frame, 0, 2, 0, 1);
367    hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1);
368    gtk_container_add(GTK_CONTAINER(frame), hbox);
369    gtk_widget_show(hbox);
370    data->ncsa = gtk_radio_button_new_with_mnemonic_from_widget(NULL, "_NCSA");
371    gtk_box_pack_start(GTK_BOX(hbox), data->ncsa, TRUE, TRUE, 10);
372    gtk_widget_show(data->ncsa);
373    data->cern = gtk_radio_button_new_with_mnemonic_from_widget(
374       GTK_RADIO_BUTTON(data->ncsa), "C_ERN");
375    gtk_box_pack_start(GTK_BOX(hbox), data->cern, TRUE, TRUE, 10);
376    gtk_widget_show(data->cern);
377    data->csim = gtk_radio_button_new_with_mnemonic_from_widget(
378       GTK_RADIO_BUTTON(data->cern), "C_SIM");
379    gtk_box_pack_start(GTK_BOX(hbox), data->csim, TRUE, TRUE, 10);
380    gtk_widget_show(data->csim);
381 
382    data->prompt_for_area_info =
383       create_check_button_in_table(table, 1, 0, _("_Prompt for area info"));
384    data->require_default_url =
385       create_check_button_in_table(table, 2, 0, _("_Require default URL"));
386    data->show_area_handle =
387       create_check_button_in_table(table, 3, 0, _("Show area _handles"));
388    data->keep_circles_round =
389       create_check_button_in_table(table, 4, 0, _("_Keep NCSA circles true"));
390    data->show_url_tip =
391       create_check_button_in_table(table, 5, 0, _("Show area URL _tip"));
392    data->use_doublesized =
393       create_check_button_in_table(table, 6, 0,
394                                    _("_Use double-sized grab handles"));
395    gtk_widget_show(frame);
396 }
397 
398 static void
create_menu_tab(PreferencesDialog_t * data,GtkWidget * notebook)399 create_menu_tab(PreferencesDialog_t *data, GtkWidget *notebook)
400 {
401    GtkWidget *table = create_tab(notebook, _("Menu"), 2, 2);
402    GtkWidget *label;
403 
404    label = create_label_in_table(table, 0, 0,
405                                  _("Number of _undo levels (1 - 99):"));
406    data->undo_levels = create_spin_button_in_table(table, label, 0, 1, 1, 1,
407                                                    99);
408 
409    label = create_label_in_table(table, 1, 0,
410                                  _("Number of M_RU entries (1 - 16):"));
411    data->mru_size = create_spin_button_in_table(table, label, 1, 1, 1, 1, 16);
412 }
413 
414 static GtkWidget*
create_color_field(PreferencesDialog_t * data,GtkWidget * table,gint row,gint col)415 create_color_field(PreferencesDialog_t *data, GtkWidget *table, gint row,
416                    gint col)
417 {
418    GimpRGB color = {0.0, 0.0, 0.0, 1.0};
419    GtkWidget *area = gimp_color_button_new (_("Select Color"), 16, 8, &color,
420                                             GIMP_COLOR_AREA_FLAT);
421    gimp_color_button_set_update (GIMP_COLOR_BUTTON (area), TRUE);
422    gtk_table_attach_defaults (GTK_TABLE (table), area, col, col + 1, row,
423                               row + 1);
424    gtk_widget_show (area);
425 
426    return area;
427 }
428 
429 static void
create_colors_tab(PreferencesDialog_t * data,GtkWidget * notebook)430 create_colors_tab(PreferencesDialog_t *data, GtkWidget *notebook)
431 {
432    GtkWidget *table = create_tab(notebook, _("Colors"), 3, 3);
433 
434    create_label_in_table(table, 0, 0, _("Normal:"));
435    data->normal_fg = create_color_field(data, table, 0, 1);
436    data->normal_bg = create_color_field(data, table, 0, 2);
437 
438    create_label_in_table(table, 1, 0, _("Selected:"));
439    data->selected_fg = create_color_field(data, table, 1, 1);
440    data->selected_bg = create_color_field(data, table, 1, 2);
441 
442    create_label_in_table(table, 2, 0, _("Interaction:"));
443    data->interactive_fg = create_color_field(data, table, 2, 1);
444    data->interactive_bg = create_color_field(data, table, 2, 2);
445 }
446 
447 #ifdef _NOT_READY_YET_
448 static void
create_contiguous_regions_tab(PreferencesDialog_t * data,GtkWidget * notebook)449 create_contiguous_regions_tab(PreferencesDialog_t *data, GtkWidget *notebook)
450 {
451    GtkWidget *table = create_tab(notebook, _("Co_ntiguous Region"), 2, 2);
452    GtkWidget *label;
453 
454    label = create_label_in_table(table, 0, 0,
455                                  _("_Threshold:"));
456    data->auto_convert =
457       create_check_button_in_table(table, 1, 0, _("_Automatically convert"));
458 }
459 #endif
460 
461 static PreferencesDialog_t*
create_preferences_dialog(void)462 create_preferences_dialog(void)
463 {
464    PreferencesDialog_t *data = g_new(PreferencesDialog_t, 1);
465    DefaultDialog_t *dialog;
466    GtkWidget *notebook;
467 
468    data->dialog = dialog = make_default_dialog( _("General Preferences"));
469    default_dialog_set_ok_cb(dialog, preferences_ok_cb, (gpointer) data);
470 
471    data->notebook = notebook = gtk_notebook_new();
472    gtk_box_pack_start (GTK_BOX (data->dialog->vbox), notebook, TRUE, TRUE, 0);
473    create_general_tab(data, notebook);
474    create_menu_tab(data, notebook);
475    create_colors_tab(data, notebook);
476 #ifdef _NOT_READY_YET_
477    create_contiguous_regions_tab(data, notebook);
478 #endif
479    gtk_widget_show(notebook);
480 
481    return data;
482 }
483 
484 void
do_preferences_dialog(void)485 do_preferences_dialog(void)
486 {
487    static PreferencesDialog_t *dialog;
488    PreferencesData_t *old_data;
489    GtkWidget *map_type;
490 
491    if (!dialog) {
492       dialog = create_preferences_dialog();
493    }
494    gtk_notebook_set_current_page(GTK_NOTEBOOK(dialog->notebook), 0);
495    dialog->old_data = old_data = get_preferences();
496 
497    if (old_data->default_map_type == CERN)
498       map_type = dialog->cern;
499    else if (old_data->default_map_type == NCSA)
500       map_type = dialog->ncsa;
501    else
502       map_type = dialog->csim;
503    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(map_type), TRUE);
504 
505    gtk_toggle_button_set_active(
506       GTK_TOGGLE_BUTTON(dialog->prompt_for_area_info),
507       old_data->prompt_for_area_info);
508    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->require_default_url),
509                                 old_data->require_default_url);
510    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->show_area_handle),
511                                 old_data->show_area_handle);
512    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->keep_circles_round),
513                                 old_data->keep_circles_round);
514    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->show_url_tip),
515                                 old_data->show_url_tip);
516    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->use_doublesized),
517                                 old_data->use_doublesized);
518 
519    gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->undo_levels),
520                              old_data->undo_levels);
521    gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->mru_size),
522                              old_data->mru_size);
523 
524    set_button_colors(dialog, &old_data->colors);
525 
526    default_dialog_show(dialog->dialog);
527 }
528