1 /* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */
2 
3 /*
4  * GImageView
5  * Copyright (C) 2001-2002 Takuro Ashie
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 3S30, Boston, MA 02111-1307, USA.
20  *
21  * $Id: gimv_prefs_ui_utils.c,v 1.2 2003/06/13 09:43:32 makeinu Exp $
22  */
23 
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "gimv_prefs_ui_utils.h"
28 
29 #include "charset.h"
30 #include "gimv_dlist.h"
31 #include "gimv_elist.h"
32 #include "gtkutils.h"
33 #include "intl.h"
34 #include "prefs.h"
35 #include "gimv_prefs_win.h"
36 
37 /*******************************************************************************
38  *
39  *  Mouse button preference
40  *
41  *******************************************************************************/
42 static void
cb_mouse_button(GtkWidget * menu_item,gpointer user_data)43 cb_mouse_button (GtkWidget *menu_item, gpointer user_data)
44 {
45    gchar **src = user_data, *dest, *tempstr, buf[128], *defval;
46    gchar **buttons, **mods;
47    gpointer bid_p, mid_p, num_p;
48    gint i, j, bid, mid, num, data[4];
49    GtkToggleButton *pressed, *released;
50 
51    g_return_if_fail (menu_item);
52    g_return_if_fail (src && *src && **src);
53 
54    bid_p    = gtk_object_get_data (GTK_OBJECT (menu_item), "button-id");
55    mid_p    = gtk_object_get_data (GTK_OBJECT (menu_item), "mod-id");
56    num_p    = gtk_object_get_data (GTK_OBJECT (menu_item), "num");
57    defval   = gtk_object_get_data (GTK_OBJECT (menu_item), "prefs-prechanged");
58    pressed  = gtk_object_get_data (GTK_OBJECT (menu_item), "pressed");
59    released = gtk_object_get_data (GTK_OBJECT (menu_item), "released");
60 
61    bid = GPOINTER_TO_INT (bid_p);
62    mid = GPOINTER_TO_INT (mid_p);
63    num = GPOINTER_TO_INT (num_p);
64 
65    if (!*src) return;
66    buttons = g_strsplit (*src, ";", 6);
67    if (!buttons) return;
68    dest = g_strdup ("");
69 
70    for (i = 0; i < 6; i++) {
71       mods = g_strsplit (buttons[i], ",", 4);
72       if (!mods) {
73          g_strfreev (buttons);
74          g_free (dest);
75          return;
76       }
77       for (j = 0; j < 4; j++) {
78          if (i == bid && j == mid) {
79             if (released && released->active)
80                data[j] = 0 - num;
81             else
82                data[j] = num;
83          } else{
84             g_strstrip (mods[j]);
85             data[j] = atoi (mods[j]);
86          }
87       }
88       g_snprintf (buf, 128, "%d,%d,%d,%d; ",
89                   data[0], data[1], data[2], data[3]);
90       tempstr = g_strconcat (dest, buf, NULL);
91       g_free (dest);
92       dest = tempstr;
93       g_strfreev (mods);
94    }
95 
96    if (defval != *src)
97       g_free (*src);
98 
99    *src = dest;
100 
101    g_strfreev (buttons);
102 }
103 
104 
105 static void
cb_mouse_prefs_pressed_radio(GtkWidget * radio,gpointer data)106 cb_mouse_prefs_pressed_radio (GtkWidget *radio, gpointer data)
107 {
108    GtkOptionMenu *option_menu = data;
109 
110    g_return_if_fail (option_menu);
111 
112    if (option_menu->menu_item)
113       gtk_signal_emit_by_name (GTK_OBJECT (option_menu->menu_item),
114                                "activate");
115 }
116 
117 
118 GtkWidget *
gimv_prefs_ui_mouse_prefs(const gchar ** items,const gchar * defval,gchar ** dest)119 gimv_prefs_ui_mouse_prefs (const gchar **items,
120                            const gchar  *defval,
121                            gchar       **dest)
122 {
123    const gchar *mod_keys[] = {
124       N_("Normal"),
125       N_("Shift"),
126       N_("Control"),
127       N_("Mod1")
128    };
129    gint mod_keys_num = sizeof (mod_keys) / sizeof (gchar *);
130 
131    GtkWidget *main_vbox, *vbox, *hbox, *vbox1, *vbox2, *temp_vbox;
132    GtkWidget *frame1, *frame_vbox1;
133    GtkWidget *label, *notebook, *option_menu, *menu, *menu_item;
134    GtkWidget *radio0, *radio1;
135    gchar buf[128], **temp = NULL, *buttons[6], **mods;
136    gint id, num, i, j, k, def;
137 
138    g_return_val_if_fail (items, NULL);
139    g_return_val_if_fail (defval, NULL);
140    g_return_val_if_fail (dest, NULL);
141 
142    main_vbox = gtk_vbox_new (FALSE, 0);
143    gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 5);
144 
145    hbox = gtk_hbox_new (TRUE, 0);
146    gtk_box_pack_start(GTK_BOX(main_vbox), hbox, FALSE, TRUE, 0);
147    vbox1 = gtk_vbox_new (FALSE, 0);
148    gtk_box_pack_start(GTK_BOX(hbox), vbox1, FALSE, TRUE, 0);
149    vbox2 = gtk_vbox_new (FALSE, 0);
150    gtk_box_pack_start(GTK_BOX(hbox), vbox2, FALSE, TRUE, 0);
151 
152    if (defval)
153       temp = g_strsplit (defval, ";", 6);
154    if (temp) {
155       buttons[0] = temp[1];
156       buttons[1] = temp[2];
157       buttons[2] = temp[3];
158       buttons[3] = temp[0];
159       buttons[4] = temp[4];
160       buttons[5] = temp[5];
161    } else {
162       for (i = 0; i < 6; i++)
163          buttons[i] = NULL;
164    }
165 
166    /* create frames */
167    for (i = 0; i < 6; i++) {
168       if (i < 3) {
169          num = i + 1;
170          id = num;
171       } else if (i == 3) {
172          num = 1;
173          id = 0;
174       } else {
175          num = i;
176          id = num;
177       }
178 
179       if (i / 3 < 1) {
180          temp_vbox = vbox1;
181       } else {
182          temp_vbox = vbox2;
183       }
184 
185       /**********************************************
186        * Mouse Button X Frame
187        **********************************************/
188       if (num == 4) {
189          g_snprintf (buf, 128, _("Mouse Button %d (Wheel up)"), num);
190       } else if (num == 5) {
191          g_snprintf (buf, 128, _("Mouse Button %d (Wheel down)"), num);
192       } else if (i == 3) {
193          g_snprintf (buf, 128, _("Mouse Button %d Double Click"), num);
194       } else {
195          const gchar *button_num_str[] = {
196             NULL, N_("Left"), N_("Middle"), N_("Right")
197          };
198          g_snprintf (buf, 128, _("Mouse Button %d (%s)"),
199                      num, _(button_num_str[num]));
200       }
201       frame1 = gtk_frame_new (buf);
202       gtk_container_set_border_width(GTK_CONTAINER(frame1), 5);
203       gtk_box_pack_start(GTK_BOX(temp_vbox), frame1, FALSE, TRUE, 5);
204       frame_vbox1 = gtk_vbox_new (FALSE, 0);
205       gtk_container_set_border_width(GTK_CONTAINER(frame1), 5);
206       gtk_container_add (GTK_CONTAINER (frame1), frame_vbox1);
207 
208       notebook = gtk_notebook_new ();
209       gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
210       gtk_box_pack_start(GTK_BOX(frame_vbox1), notebook, FALSE, FALSE, 5);
211       gtk_widget_show (notebook);
212 
213       if (buttons[i] && *buttons[i]) {
214          mods = g_strsplit (buttons[i], ",", 4);
215       } else {
216          mods = NULL;
217       }
218 
219       /* create notebook pages */
220       for (j = 0; j < mod_keys_num; j++) {
221          label = gtk_label_new (_(mod_keys[j]));
222          gtk_widget_show (label);
223          vbox = gtk_vbox_new (FALSE, 0);
224          gtk_widget_show (vbox);
225          gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
226                                    vbox, label);
227 
228          if (mods[j] && *mods[j]) {
229             g_strstrip (mods[j]);
230             def = atoi (mods[j]);
231          } else {
232             def = 0;
233          }
234 
235          option_menu = gtk_option_menu_new();
236          menu = gtk_menu_new();
237 
238          gtk_box_pack_start(GTK_BOX(vbox), option_menu, FALSE, FALSE, 5);
239 
240          hbox = gtk_hbox_new (FALSE, 0);
241          gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
242 
243          radio0 = gtk_radio_button_new_with_label (NULL, _("Pressed"));
244          gtk_box_pack_start (GTK_BOX (hbox), radio0, FALSE, FALSE, 0);
245          radio1 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (radio0),
246                                                                _("Released"));
247          gtk_box_pack_start (GTK_BOX (hbox), radio1, FALSE, FALSE, 0);
248          gtk_signal_connect (GTK_OBJECT (radio0), "toggled",
249                              GTK_SIGNAL_FUNC (cb_mouse_prefs_pressed_radio),
250                              option_menu);
251          gtk_signal_connect (GTK_OBJECT (radio1), "toggled",
252                              GTK_SIGNAL_FUNC (cb_mouse_prefs_pressed_radio),
253                              option_menu);
254 
255          if (def < 0)
256             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio1), TRUE);
257          else
258             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio0), TRUE);
259 
260          if (id == 0) {
261             gtk_widget_set_sensitive (radio0, FALSE);
262             gtk_widget_set_sensitive (radio1, FALSE);
263          }
264 
265          /* create option menu items */
266          for (k = 0; items[k]; k++) {
267             menu_item = gtk_menu_item_new_with_label (_(items[k]));
268             gtk_object_set_data (GTK_OBJECT (menu_item),
269                                  "button-id",
270                                  GINT_TO_POINTER(id));
271             gtk_object_set_data (GTK_OBJECT (menu_item),
272                                  "mod-id",
273                                  GINT_TO_POINTER(j));
274             gtk_object_set_data (GTK_OBJECT (menu_item),
275                                  "num",
276                                  GINT_TO_POINTER(k));
277             gtk_object_set_data (GTK_OBJECT (menu_item),
278                                  "prefs-prechanged",
279                                  (gpointer) defval);
280             gtk_signal_connect(GTK_OBJECT(menu_item), "activate",
281                                GTK_SIGNAL_FUNC(cb_mouse_button),
282                                dest);
283 
284             gtk_object_set_data (GTK_OBJECT (menu_item),
285                                  "pressed",
286                                  (gpointer) radio0);
287             gtk_object_set_data (GTK_OBJECT (menu_item),
288                                  "released",
289                                  (gpointer) radio1);
290             gtk_menu_append (GTK_MENU(menu), menu_item);
291             gtk_widget_show (menu_item);
292          }
293          gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
294          gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), abs (def));
295       }
296 
297       g_strfreev (mods);
298    }
299 
300    g_strfreev (temp);
301 
302    return main_vbox;
303 }
304 
305 
306 
307 /*******************************************************************************
308  *
309  *  Directory list preference
310  *
311  *******************************************************************************/
312 typedef struct DirListPrefs_Tag {
313    GtkWidget *editlist, *entry, *select_button;
314    const gchar *defval;
315    gchar **prefsval;
316    gchar sepchar;
317    const gchar *dialog_title;
318 } DirListPrefs;
319 
320 
321 static void
set_default_dir_list(DirListPrefs * dirprefs)322 set_default_dir_list (DirListPrefs *dirprefs)
323 {
324    gchar **strs;
325    gint i;
326 
327    if (!dirprefs->defval) return;
328 
329    strs = g_strsplit (dirprefs->defval, &dirprefs->sepchar, -1);
330    for (i = 0; strs && strs[i]; i++) {
331       gchar *text[1];
332 
333       text[0] = charset_to_internal (strs[i],
334                                      conf.charset_filename,
335                                      conf.charset_auto_detect_fn,
336                                      conf.charset_filename_mode);
337 
338       gimv_elist_append_row (GIMV_ELIST (dirprefs->editlist), text);
339 
340       g_free (text[0]);
341    }
342    g_strfreev (strs);
343 }
344 
345 
346 static void
cb_dirprefs_editlist_updated(GimvEList * editlist,gpointer data)347 cb_dirprefs_editlist_updated (GimvEList *editlist, gpointer data)
348 {
349    DirListPrefs *dirprefs = data;
350    gchar *string = NULL;
351    gint i;
352 
353    for (i = 0; i < editlist->rows; i++) {
354       gchar **text, *text_locale, *tmpstr;
355 
356       text = gimv_elist_get_row_text (editlist, i);
357       if (!text) continue;
358 
359       if (string) {
360          tmpstr = string;
361          string = g_strconcat (string, &dirprefs->sepchar, NULL);
362          g_free (tmpstr);
363       } else {
364          string = g_strdup ("");
365       }
366 
367       tmpstr = string;
368       text_locale = charset_internal_to_locale (text[0]);
369       string = g_strconcat (tmpstr, text_locale, NULL);
370       g_free (text_locale);
371       g_free (tmpstr);
372    }
373 
374    if (dirprefs->defval != *dirprefs->prefsval) {
375       g_free (*dirprefs->prefsval);
376    }
377    *dirprefs->prefsval = string;
378 }
379 
380 
381 static void
cb_dirprefs_dirsel_pressed(GtkButton * button,gpointer data)382 cb_dirprefs_dirsel_pressed (GtkButton *button, gpointer data)
383 {
384    DirListPrefs *dirprefs = data;
385    gchar *path;
386    const gchar *default_path, *dialog_title = _("Select directory");
387 
388    if (dirprefs->dialog_title)
389       dialog_title = dirprefs->dialog_title;
390 
391    default_path = gtk_entry_get_text (GTK_ENTRY (dirprefs->entry));
392    path = gtkutil_modal_file_dialog (dialog_title,
393                                      default_path,
394                                      MODAL_FILE_DIALOG_DIR_ONLY,
395                                      GTK_WINDOW (gimv_prefs_win_get ()));
396    if (path)
397       gtk_entry_set_text (GTK_ENTRY (dirprefs->entry), path);
398    g_free (path);
399 }
400 
401 
402 static void
cb_dirprefs_destroy(GtkWidget * widget,gpointer data)403 cb_dirprefs_destroy (GtkWidget *widget, gpointer data)
404 {
405    g_free (data);
406 }
407 
408 
409 GtkWidget *
gimv_prefs_ui_dir_list_prefs(const gchar * title,const gchar * dialog_title,const gchar * defval,gchar ** prefsval,gchar sepchar)410 gimv_prefs_ui_dir_list_prefs (const gchar *title,
411                               const gchar *dialog_title,
412                               const gchar *defval,
413                               gchar **prefsval,
414                               gchar sepchar)
415 {
416    DirListPrefs *dirprefs = g_new0 (DirListPrefs, 1);
417    GtkWidget *frame, *frame_vbox, *hbox;
418    GtkWidget *editlist, *label, *entry, *button;
419    gchar *titles[] = {
420       N_("Directory"),
421    };
422    gint titles_num = sizeof (titles)/ sizeof (gchar *);
423 
424    g_return_val_if_fail (prefsval, NULL);
425 
426    dirprefs->defval = defval;
427    dirprefs->prefsval = prefsval;
428    dirprefs->sepchar = sepchar;
429    dirprefs->dialog_title = dialog_title;
430 
431    /* frame */
432    frame = gtk_frame_new (title);
433    gtk_container_set_border_width(GTK_CONTAINER (frame), 0);
434    frame_vbox = gtk_vbox_new (FALSE, 0);
435    gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
436    gtk_container_add (GTK_CONTAINER (frame), frame_vbox);
437 
438    gtk_signal_connect (GTK_OBJECT (frame),"destroy",
439                        GTK_SIGNAL_FUNC (cb_dirprefs_destroy),
440                        dirprefs);
441 
442    /* clist */
443    dirprefs->editlist = editlist
444       = gimv_elist_new_with_titles (titles_num, titles);
445    gimv_elist_set_column_title_visible (GIMV_ELIST (editlist), FALSE);
446    gtk_box_pack_start (GTK_BOX (frame_vbox), editlist, TRUE, TRUE, 0);
447    set_default_dir_list (dirprefs);
448    gtk_signal_connect (GTK_OBJECT (editlist), "list_updated",
449                        GTK_SIGNAL_FUNC (cb_dirprefs_editlist_updated), dirprefs);
450 
451    /* entry area */
452    hbox = GIMV_ELIST (editlist)->edit_area;
453 
454    label = gtk_label_new (_("Directory to add : "));
455    gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
456    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
457 
458    entry = dirprefs->entry
459       = gimv_elist_create_entry (GIMV_ELIST (editlist), 0,
460                                  NULL, FALSE);
461    gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
462 
463    button = dirprefs->select_button = gtk_button_new_with_label (_("Select"));
464    gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
465    gtk_signal_connect (GTK_OBJECT (button),"clicked",
466                        GTK_SIGNAL_FUNC (cb_dirprefs_dirsel_pressed), dirprefs);
467 
468    return frame;
469 }
470 
471 
472 
473 /*******************************************************************************
474  *
475  *  Double Stack List.
476  *
477  *******************************************************************************/
478 typedef struct GimvDListData_Tag
479 {
480    GtkWidget *dslist;
481    const gchar *defval;
482    gchar **prefsval;
483    gchar sepchar;
484 } GimvDListData;
485 
486 
487 static void
cb_dslist_destroy(GtkWidget * dslist,gpointer data)488 cb_dslist_destroy (GtkWidget *dslist, gpointer data)
489 {
490    GimvDListData *dsdata = data;
491    g_free (dsdata);
492 }
493 
494 
495 static void
cb_gimv_dlist_updated(GimvDList * dslist,GimvDListData * dsdata)496 cb_gimv_dlist_updated (GimvDList *dslist, GimvDListData *dsdata)
497 {
498    gchar *string = NULL, *tmpstr;
499    gint i, rows;
500 
501    g_return_if_fail (dsdata);
502 
503    rows = gimv_dlist_get_n_enabled_items (dslist);
504 
505    for (i = 0; i < rows; i++) {
506       gchar *text;
507       text = gimv_dlist_get_enabled_row_text (dslist, i);
508       if (!text) continue;
509 
510       if (string) {
511          tmpstr = string;
512          string = g_strconcat (tmpstr, &dsdata->sepchar, NULL);
513          g_free (tmpstr);
514       } else {
515          string = g_strdup ("");
516       }
517       tmpstr = string;
518       string = g_strconcat (tmpstr, text, NULL);
519       g_free (tmpstr);
520    }
521 
522    if (!dsdata->prefsval) return;
523 
524    if (*dsdata->prefsval != dsdata->defval) {
525       g_free (*dsdata->prefsval);
526    }
527    *dsdata->prefsval = string;
528 }
529 
530 
531 GtkWidget *
gimv_prefs_ui_double_clist(const gchar * title,const gchar * clist1_title,const gchar * clist2_title,GList * available_list,const gchar * defval,gchar ** prefsval,gchar sepchar)532 gimv_prefs_ui_double_clist (const gchar *title,
533                             const gchar *clist1_title,
534                             const gchar *clist2_title,
535                             GList *available_list,
536                             const gchar *defval,
537                             gchar **prefsval,
538                             gchar sepchar)
539 {
540    GimvDListData *dsdata;
541    GtkWidget *frame, *frame_vbox, *dslist;
542    GList *node;
543    gchar **titles;
544    gint i;
545 
546    g_return_val_if_fail (prefsval, NULL);
547 
548    dsdata = g_new0 (GimvDListData, 1);
549    dsdata->defval = defval;
550    dsdata->prefsval = prefsval;
551    dsdata->sepchar = sepchar;
552 
553    /* frame */
554    frame = gtk_frame_new (title);
555    gtk_container_set_border_width(GTK_CONTAINER (frame), 0);
556    frame_vbox = gtk_vbox_new (FALSE, 0);
557    gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
558    gtk_container_add (GTK_CONTAINER (frame), frame_vbox);
559 
560 
561    /* double stack list */
562    dslist = gimv_dlist_new (clist1_title, clist2_title);
563    gtk_box_pack_start (GTK_BOX (frame_vbox), dslist, TRUE, TRUE, 0);
564    gtk_widget_show (dslist);
565 
566    /* set available list */
567    for (node = available_list; node; node = g_list_next (node)) {
568       const gchar *text = node->data;
569       gimv_dlist_append_available_item (GIMV_DLIST (dslist), text);
570    }
571 
572    /* set default data */
573    if (dsdata->defval) {
574       titles = g_strsplit (dsdata->defval, &dsdata->sepchar, -1);
575       for (i = 0; titles[i]; i++) {
576          gimv_dlist_column_add_by_label (GIMV_DLIST (dslist), titles[i]);
577       }
578       g_strfreev (titles);
579    }
580 
581    gtk_signal_connect (GTK_OBJECT (dslist), "destroy",
582                        GTK_SIGNAL_FUNC (cb_dslist_destroy), dsdata);
583    gtk_signal_connect (GTK_OBJECT (dslist), "enabled_list_updated",
584                        GTK_SIGNAL_FUNC (cb_gimv_dlist_updated),
585                        dsdata);
586 
587    return frame;
588 }
589