f0bff26a0ded4bb7b46650adfd162686d01250ec
[geeqie.git] / src / ui-misc.cc
1 /*
2  * Copyright (C) 2004 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * Author: John Ellis
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 along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "main.h"
26 #include "ui-misc.h"
27
28 #include "history-list.h"
29
30 #include <langinfo.h>
31
32 /*
33  *-----------------------------------------------------------------------------
34  * widget and layout utilities
35  *-----------------------------------------------------------------------------
36  */
37
38 GtkWidget *pref_box_new(GtkWidget *parent_box, gboolean fill,
39                         GtkOrientation orientation, gboolean padding)
40 {
41         GtkWidget *box;
42
43         if (orientation == GTK_ORIENTATION_HORIZONTAL)
44                 {
45                 box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, padding);
46                 }
47         else
48                 {
49                 box = gtk_box_new(GTK_ORIENTATION_VERTICAL, padding);
50                 }
51
52         gtk_box_pack_start(GTK_BOX(parent_box), box, fill, fill, 0);
53         gtk_widget_show(box);
54
55         return box;
56 }
57
58 GtkWidget *pref_group_new(GtkWidget *parent_box, gboolean fill,
59                           const gchar *text, GtkOrientation orientation)
60 {
61         GtkWidget *box;
62         GtkWidget *vbox;
63         GtkWidget *hbox;
64         GtkWidget *label;
65
66         vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
67
68         /* add additional spacing if necessary */
69         if (GTK_IS_VBOX(parent_box))
70                 {
71                 GList *list = gtk_container_get_children(GTK_CONTAINER(parent_box));
72                 if (list)
73                         {
74                         pref_spacer(vbox, PREF_PAD_GROUP - PREF_PAD_GAP);
75                         }
76                 g_list_free(list);
77                 }
78
79         gtk_box_pack_start(GTK_BOX(parent_box), vbox, fill, fill, 0);
80         gtk_widget_show(vbox);
81
82         label = gtk_label_new(text);
83         gtk_label_set_xalign(GTK_LABEL(label), 0.0);
84         gtk_label_set_yalign(GTK_LABEL(label), 0.5);
85         pref_label_bold(label, TRUE, FALSE);
86
87         gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
88         gtk_widget_show(label);
89
90         hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PREF_PAD_INDENT);
91         gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
92         gtk_widget_show(hbox);
93
94         /* indent using empty box */
95         pref_spacer(hbox, 0);
96
97         if (orientation == GTK_ORIENTATION_HORIZONTAL)
98                 {
99                 box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
100                 }
101         else
102                 {
103                 box = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
104                 }
105         gtk_box_pack_start(GTK_BOX(hbox), box, TRUE, TRUE, 0);
106         gtk_widget_show(box);
107
108         g_object_set_data(G_OBJECT(box), "pref_group", vbox);
109
110         return box;
111 }
112
113 GtkWidget *pref_group_parent(GtkWidget *child)
114 {
115         GtkWidget *parent;
116
117         parent = child;
118         while (parent)
119                 {
120                 GtkWidget *group;
121
122                 group = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(parent), "pref_group"));
123                 if (group && GTK_IS_WIDGET(group)) return group;
124
125                 parent = gtk_widget_get_parent(parent);
126                 }
127
128         return child;
129 }
130
131 GtkWidget *pref_frame_new(GtkWidget *parent_box, gboolean fill,
132                           const gchar *text,
133                           GtkOrientation orientation, gboolean padding)
134 {
135         GtkWidget *box;
136         GtkWidget *frame = NULL;
137
138         frame = gtk_frame_new(text);
139         gtk_box_pack_start(GTK_BOX(parent_box), frame, fill, fill, 0);
140         gtk_widget_show(frame);
141
142         if (orientation == GTK_ORIENTATION_HORIZONTAL)
143                 {
144                 box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, padding);
145                 }
146         else
147                 {
148                 box = gtk_box_new(GTK_ORIENTATION_VERTICAL, padding);
149                 }
150         gtk_container_add(GTK_CONTAINER(frame), box);
151         gtk_container_set_border_width(GTK_CONTAINER(box), PREF_PAD_BORDER);
152         gtk_widget_show(box);
153
154         return box;
155 }
156
157 GtkWidget *pref_spacer(GtkWidget *parent_box, gboolean padding)
158 {
159         GtkWidget *spacer;
160
161         spacer = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
162         gtk_box_pack_start(GTK_BOX(parent_box), spacer, FALSE, FALSE, padding / 2);
163         gtk_widget_show(spacer);
164
165         return spacer;
166 }
167
168 GtkWidget *pref_line(GtkWidget *parent_box, gboolean padding)
169 {
170         GtkWidget *spacer;
171
172         if (GTK_IS_HBOX(parent_box))
173                 {
174                 spacer = gtk_vseparator_new();
175                 }
176         else
177                 {
178                 spacer = gtk_hseparator_new();
179                 }
180
181         gtk_box_pack_start(GTK_BOX(parent_box), spacer, FALSE, FALSE, padding / 2);
182         gtk_widget_show(spacer);
183
184         return spacer;
185 }
186
187 GtkWidget *pref_label_new(GtkWidget *parent_box, const gchar *text)
188 {
189         GtkWidget *label;
190
191         label = gtk_label_new(text);
192         gtk_box_pack_start(GTK_BOX(parent_box), label, FALSE, FALSE, 0);
193         gtk_widget_show(label);
194
195         return label;
196 }
197
198 GtkWidget *pref_label_new_mnemonic(GtkWidget *parent_box, const gchar *text, GtkWidget *widget)
199 {
200         GtkWidget *label;
201
202         label = gtk_label_new_with_mnemonic(text);
203         gtk_label_set_mnemonic_widget(GTK_LABEL(label), widget);
204         gtk_box_pack_start(GTK_BOX(parent_box), label, FALSE, FALSE, 0);
205         gtk_widget_show(label);
206
207         return label;
208 }
209
210 void pref_label_bold(GtkWidget *label, gboolean bold, gboolean increase_size)
211 {
212         PangoAttrList *pal;
213         PangoAttribute *pa;
214
215         if (!bold && !increase_size) return;
216
217         pal = pango_attr_list_new();
218
219         if (bold)
220                 {
221                 pa = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
222                 pa->start_index = 0;
223                 pa->end_index = G_MAXINT;
224                 pango_attr_list_insert(pal, pa);
225                 }
226
227         if (increase_size)
228                 {
229                 pa = pango_attr_scale_new(PANGO_SCALE_LARGE);
230                 pa->start_index = 0;
231                 pa->end_index = G_MAXINT;
232                 pango_attr_list_insert(pal, pa);
233                 }
234
235         gtk_label_set_attributes(GTK_LABEL(label), pal);
236         pango_attr_list_unref(pal);
237 }
238
239 GtkWidget *pref_button_new(GtkWidget *parent_box, const gchar *stock_id,
240                            const gchar *text, gboolean hide_stock_text,
241                            GCallback func, gpointer data)
242 {
243         GtkWidget *button;
244
245         if (stock_id && !text && !hide_stock_text)
246                 {
247                 button = gtk_button_new_from_stock(stock_id);
248                 }
249         else
250                 {
251                 GtkWidget *image = NULL;
252                 GtkWidget *label = NULL;
253
254                 button = gtk_button_new();
255
256                 if (stock_id) image = gtk_image_new_from_icon_name(stock_id, GTK_ICON_SIZE_BUTTON);
257                 if (text)
258                         {
259                         label = gtk_label_new_with_mnemonic(text);
260                         gtk_label_set_xalign(GTK_LABEL(label), 0.5);
261                         gtk_label_set_yalign(GTK_LABEL(label), 0.5);
262                         gtk_label_set_mnemonic_widget(GTK_LABEL(label), button);
263                         }
264
265                 if (image && label)
266                         {
267                         GtkWidget *align;
268                         GtkWidget *hbox;
269
270                         hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_ICON_GAP);
271
272                         align = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
273                         gtk_container_add(GTK_CONTAINER(button), align);
274                         gtk_widget_show(align);
275
276                         gtk_container_add(GTK_CONTAINER(align), hbox);
277                         gtk_widget_show(hbox);
278
279                         gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
280                         gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0);
281                         }
282                 else
283                         {
284                         if (image)
285                                 {
286                                 gtk_container_add(GTK_CONTAINER(button), image);
287                                 }
288                         else if (label)
289                                 {
290                                 gtk_container_add(GTK_CONTAINER(button), label);
291                                 }
292                         }
293
294                 if (image) gtk_widget_show(image);
295                 if (label) gtk_widget_show(label);
296                 }
297
298         if (func) g_signal_connect(G_OBJECT(button), "clicked", func, data);
299
300         if (parent_box)
301                 {
302                 gtk_box_pack_start(GTK_BOX(parent_box), button, FALSE, FALSE, 0);
303                 gtk_widget_show(button);
304                 }
305
306         return button;
307 }
308
309 static GtkWidget *real_pref_checkbox_new(GtkWidget *parent_box, const gchar *text, gboolean mnemonic_text,
310                                          gboolean active, GCallback func, gpointer data)
311 {
312         GtkWidget *button;
313
314         if (mnemonic_text)
315                 {
316                 button = gtk_check_button_new_with_mnemonic(text);
317                 }
318         else
319                 {
320                 button = gtk_check_button_new_with_label(text);
321                 }
322         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
323         if (func) g_signal_connect(G_OBJECT(button), "clicked", func, data);
324
325         gtk_box_pack_start(GTK_BOX(parent_box), button, FALSE, FALSE, 0);
326         gtk_widget_show(button);
327
328         return button;
329 }
330
331 GtkWidget *pref_checkbox_new(GtkWidget *parent_box, const gchar *text, gboolean active,
332                              GCallback func, gpointer data)
333 {
334         return real_pref_checkbox_new(parent_box, text, FALSE, active, func, data);
335 }
336
337 //GtkWidget *pref_checkbox_new_mnemonic(GtkWidget *parent_box, const gchar *text, gboolean active,
338                                       //GCallback func, gpointer data)
339 //{
340         //return real_pref_checkbox_new(parent_box, text, TRUE, active, func, data);
341 //}
342
343 static void pref_checkbox_int_cb(GtkWidget *widget, gpointer data)
344 {
345         gboolean *result = static_cast<gboolean *>(data);
346
347         *result = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
348 }
349
350 GtkWidget *pref_checkbox_new_int(GtkWidget *parent_box, const gchar *text, gboolean active,
351                                  gboolean *result)
352 {
353         GtkWidget *button;
354
355         button = pref_checkbox_new(parent_box, text, active,
356                                    G_CALLBACK(pref_checkbox_int_cb), result);
357         *result = active;
358
359         return button;
360 }
361
362 static void pref_checkbox_link_sensitivity_cb(GtkWidget *button, gpointer data)
363 {
364         GtkWidget *widget = static_cast<GtkWidget *>(data);
365
366         gtk_widget_set_sensitive(widget, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
367 }
368
369 void pref_checkbox_link_sensitivity(GtkWidget *button, GtkWidget *widget)
370 {
371         g_signal_connect(G_OBJECT(button), "toggled",
372                          G_CALLBACK(pref_checkbox_link_sensitivity_cb), widget);
373
374         pref_checkbox_link_sensitivity_cb(button, widget);
375 }
376
377 //static void pref_checkbox_link_sensitivity_swap_cb(GtkWidget *button, gpointer data)
378 //{
379         //GtkWidget *widget = static_cast<GtkWidget *>(data);
380
381         //gtk_widget_set_sensitive(widget, !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
382 //}
383
384 //void pref_checkbox_link_sensitivity_swap(GtkWidget *button, GtkWidget *widget)
385 //{
386         //g_signal_connect(G_OBJECT(button), "toggled",
387                          //G_CALLBACK(pref_checkbox_link_sensitivity_swap_cb), widget);
388
389         //pref_checkbox_link_sensitivity_swap_cb(button, widget);
390 //}
391
392 static GtkWidget *real_pref_radiobutton_new(GtkWidget *parent_box, GtkWidget *sibling,
393                                             const gchar *text, gboolean mnemonic_text, gboolean active,
394                                             GCallback func, gpointer data)
395 {
396         GtkWidget *button;
397         GSList *group;
398
399         if (sibling)
400                 {
401                 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(sibling));
402                 }
403         else
404                 {
405                 group = NULL;
406                 }
407
408         if (mnemonic_text)
409                 {
410                 button = gtk_radio_button_new_with_mnemonic(group, text);
411                 }
412         else
413                 {
414                 button = gtk_radio_button_new_with_label(group, text);
415                 }
416
417         if (active) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
418         if (func) g_signal_connect(G_OBJECT(button), "clicked", func, data);
419
420         gtk_box_pack_start(GTK_BOX(parent_box), button, FALSE, FALSE, 0);
421         gtk_widget_show(button);
422
423         return button;
424 }
425
426 GtkWidget *pref_radiobutton_new(GtkWidget *parent_box, GtkWidget *sibling,
427                                 const gchar *text, gboolean active,
428                                 GCallback func, gpointer data)
429 {
430         return real_pref_radiobutton_new(parent_box, sibling, text, FALSE, active, func, data);
431 }
432
433 //GtkWidget *pref_radiobutton_new_mnemonic(GtkWidget *parent_box, GtkWidget *sibling,
434                                          //const gchar *text, gboolean active,
435                                          //GCallback func, gpointer data)
436 //{
437         //return real_pref_radiobutton_new(parent_box, sibling, text, TRUE, active, func, data);
438 //}
439
440 #define PREF_RADIO_VALUE_KEY "pref_radio_value"
441
442 //static void pref_radiobutton_int_cb(GtkWidget *widget, gpointer data)
443 //{
444         //gboolean *result = static_cast<gboolean *>(data);
445
446         //if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
447                 //{
448                 //*result = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), PREF_RADIO_VALUE_KEY));
449                 //}
450 //}
451
452 //GtkWidget *pref_radiobutton_new_int(GtkWidget *parent_box, GtkWidget *sibling,
453                                     //const gchar *text, gboolean active,
454                                     //gboolean *result, gboolean value,
455                                     //GCallback UNUSED(func), gpointer UNUSED(data))
456 //{
457         //GtkWidget *button;
458
459         //button = pref_radiobutton_new(parent_box, sibling, text, active,
460                                       //G_CALLBACK(pref_radiobutton_int_cb), result);
461         //g_object_set_data(G_OBJECT(button), PREF_RADIO_VALUE_KEY, GINT_TO_POINTER(value));
462         //if (active) *result = value;
463
464         //return button;
465 //}
466
467 static GtkWidget *real_pref_spin_new(GtkWidget *parent_box, const gchar *text, const gchar *suffix,
468                                      gboolean mnemonic_text,
469                                      gdouble min, gdouble max, gdouble step, gint digits,
470                                      gdouble value,
471                                      GCallback func, gpointer data)
472 {
473         GtkWidget *spin;
474         GtkWidget *box;
475         GtkWidget *label;
476
477         box = pref_box_new(parent_box, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
478
479         spin = gtk_spin_button_new_with_range(min, max, step);
480         gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), digits);
481         gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), value);
482
483         if (func)
484                 {
485                 g_signal_connect(G_OBJECT(spin), "value_changed", G_CALLBACK(func), data);
486                 }
487
488         if (text)
489                 {
490                 if (mnemonic_text)
491                         {
492                         label = pref_label_new_mnemonic(box, text, spin);
493                         }
494                 else
495                         {
496                         label = pref_label_new(box, text);
497                         }
498                 pref_link_sensitivity(label, spin);
499                 }
500
501         gtk_box_pack_start(GTK_BOX(box), spin, FALSE, FALSE, 0);
502         gtk_widget_show(spin);
503
504         /* perhaps this should only be PREF_PAD_GAP distance from spinbutton ? */
505         if (suffix)
506                 {
507                 label =  pref_label_new(box, suffix);
508                 pref_link_sensitivity(label, spin);
509                 }
510
511         return spin;
512 }
513
514 GtkWidget *pref_spin_new(GtkWidget *parent_box, const gchar *text, const gchar *suffix,
515                          gdouble min, gdouble max, gdouble step, gint digits,
516                          gdouble value,
517                          GCallback func, gpointer data)
518 {
519         return real_pref_spin_new(parent_box, text, suffix, FALSE,
520                                   min, max, step, digits, value, func, data);
521 }
522
523 //GtkWidget *pref_spin_new_mnemonic(GtkWidget *parent_box, const gchar *text, const gchar *suffix,
524                                   //gdouble min, gdouble max, gdouble step, gint digits,
525                                   //gdouble value,
526                                   //GCallback func, gpointer data)
527 //{
528         //return real_pref_spin_new(parent_box, text, suffix, TRUE,
529                                   //min, max, step, digits, value, func, data);
530 //}
531
532 static void pref_spin_int_cb(GtkWidget *widget, gpointer data)
533 {
534         gint *var = static_cast<gint *>(data);
535         *var = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
536 }
537
538 GtkWidget *pref_spin_new_int(GtkWidget *parent_box, const gchar *text, const gchar *suffix,
539                              gint min, gint max, gint step,
540                              gint value, gint *value_var)
541 {
542         *value_var = value;
543         return pref_spin_new(parent_box, text, suffix,
544                              (gdouble)min, (gdouble)max, (gdouble)step, 0,
545                              value,
546                              G_CALLBACK(pref_spin_int_cb), value_var);
547 }
548
549 static void pref_link_sensitivity_cb(GtkWidget *watch, GtkStateType UNUSED(prev_state), gpointer data)
550 {
551         GtkWidget *widget = static_cast<GtkWidget *>(data);
552
553         gtk_widget_set_sensitive(widget, gtk_widget_is_sensitive(watch));
554 }
555
556 void pref_link_sensitivity(GtkWidget *widget, GtkWidget *watch)
557 {
558         g_signal_connect(G_OBJECT(watch), "state_changed",
559                          G_CALLBACK(pref_link_sensitivity_cb), widget);
560 }
561
562 void pref_signal_block_data(GtkWidget *widget, gpointer data)
563 {
564         g_signal_handlers_block_matched(widget, G_SIGNAL_MATCH_DATA,
565                                         0, 0, NULL, NULL, data);
566 }
567
568 void pref_signal_unblock_data(GtkWidget *widget, gpointer data)
569 {
570         g_signal_handlers_unblock_matched(widget, G_SIGNAL_MATCH_DATA,
571                                           0, 0, NULL, NULL, data);
572 }
573
574 GtkWidget *pref_table_new(GtkWidget *parent_box, gint columns, gint rows,
575                           gboolean homogeneous, gboolean fill)
576 {
577         GtkWidget *table;
578
579         table = gtk_table_new(rows, columns, homogeneous);
580         gtk_table_set_row_spacings(GTK_TABLE(table), PREF_PAD_GAP);
581         gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_SPACE);
582
583         if (parent_box)
584                 {
585                 gtk_box_pack_start(GTK_BOX(parent_box), table, fill, fill, 0);
586                 gtk_widget_show(table);
587                 }
588
589         return table;
590 }
591
592 GtkWidget *pref_table_box(GtkWidget *table, gint column, gint row,
593                           GtkOrientation orientation, const gchar *text)
594 {
595         GtkWidget *box;
596         GtkWidget *shell;
597
598         if (text)
599                 {
600                 shell = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
601                 box = pref_group_new(shell, TRUE, text, orientation);
602                 }
603         else
604                 {
605                 if (orientation == GTK_ORIENTATION_HORIZONTAL)
606                         {
607                         box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
608                         }
609                 else
610                         {
611                         box = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
612                         }
613                 shell = box;
614                 }
615
616         gtk_table_attach(GTK_TABLE(table), shell, column, column + 1, row, row + 1,
617                          static_cast<GtkAttachOptions>(GTK_EXPAND | GTK_FILL), static_cast<GtkAttachOptions>(0), 0, 0);
618
619         gtk_widget_show(shell);
620
621         return box;
622 }
623
624 GtkWidget *pref_table_label(GtkWidget *table, gint column, gint row,
625                             const gchar *text, gfloat alignment)
626 {
627         GtkWidget *label;
628         GtkWidget *align;
629
630         align = gtk_alignment_new(alignment, 0.50, 0.0, 0.0);
631         gtk_table_attach(GTK_TABLE(table), align, column, column + 1, row, row + 1,
632                          GTK_FILL, static_cast<GtkAttachOptions>(0), 0, 0);
633         gtk_widget_show(align);
634         label = gtk_label_new(text);
635         gtk_container_add(GTK_CONTAINER(align), label);
636         gtk_widget_show(label);
637
638         return label;
639 }
640
641 GtkWidget *pref_table_button(GtkWidget *table, gint column, gint row,
642                              const gchar *stock_id, const gchar *text, gboolean hide_stock_text,
643                              GCallback func, gpointer data)
644 {
645         GtkWidget *button;
646
647         button = pref_button_new(NULL, stock_id, text, hide_stock_text, func, data);
648         gtk_table_attach(GTK_TABLE(table), button, column, column + 1, row, row + 1,
649                          GTK_FILL, static_cast<GtkAttachOptions>(0), 0, 0);
650         gtk_widget_show(button);
651
652         return button;
653 }
654
655 GtkWidget *pref_table_spin(GtkWidget *table, gint column, gint row,
656                            const gchar *text, const gchar *suffix,
657                            gdouble min, gdouble max, gdouble step, gint digits,
658                            gdouble value,
659                            GCallback func, gpointer data)
660 {
661         GtkWidget *spin;
662         GtkWidget *box;
663         GtkWidget *label;
664
665         spin = gtk_spin_button_new_with_range(min, max, step);
666         gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), digits);
667         gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), value);
668         if (func)
669                 {
670                 g_signal_connect(G_OBJECT(spin), "value_changed", G_CALLBACK(func), data);
671                 }
672
673         if (text)
674                 {
675                 label = pref_table_label(table, column, row, text, 1.0);
676                 pref_link_sensitivity(label, spin);
677                 column++;
678                 }
679
680         if (suffix)
681                 {
682                 box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
683                 gtk_box_pack_start(GTK_BOX(box), spin, FALSE, FALSE, 0);
684                 gtk_widget_show(spin);
685
686                 label = pref_label_new(box, suffix);
687                 pref_link_sensitivity(label, spin);
688                 }
689         else
690                 {
691                 box = spin;
692                 }
693
694         gtk_table_attach(GTK_TABLE(table), box, column, column + 1, row, row + 1,
695                          static_cast<GtkAttachOptions>(GTK_EXPAND | GTK_FILL), static_cast<GtkAttachOptions>(GTK_EXPAND | GTK_FILL), 0, 0);
696         gtk_widget_show(box);
697
698         return spin;
699 }
700
701 GtkWidget *pref_table_spin_new_int(GtkWidget *table, gint column, gint row,
702                                    const gchar *text, const gchar *suffix,
703                                    gint min, gint max, gint step,
704                                    gint value, gint *value_var)
705 {
706         *value_var = value;
707         return pref_table_spin(table, column, row,
708                                text, suffix,
709                                (gdouble)min, (gdouble)max, (gdouble)step, 0,
710                                value,
711                                G_CALLBACK(pref_spin_int_cb), value_var);
712 }
713
714
715 GtkWidget *pref_toolbar_new(GtkWidget *parent_box, GtkToolbarStyle style)
716 {
717         GtkWidget *tbar;
718
719         tbar = gtk_toolbar_new();
720         gtk_toolbar_set_style(GTK_TOOLBAR(tbar), style);
721
722         if (parent_box)
723                 {
724                 gtk_box_pack_start(GTK_BOX(parent_box), tbar, FALSE, FALSE, 0);
725                 gtk_widget_show(tbar);
726                 }
727         return tbar;
728 }
729
730 GtkWidget *pref_toolbar_button(GtkWidget *toolbar,
731                                const gchar *stock_id, const gchar *label, gboolean toggle,
732                                const gchar *description,
733                                GCallback func, gpointer data)
734 {
735         GtkWidget *item;
736
737         if (toggle)
738                 {
739                 if (stock_id)
740                         {
741                         item = GTK_WIDGET(gtk_toggle_tool_button_new_from_stock(stock_id));
742                         }
743                 else
744                         {
745                         item = GTK_WIDGET(gtk_toggle_tool_button_new());
746                         }
747                 }
748         else
749                 {
750                 if (stock_id)
751                         {
752                         item = GTK_WIDGET(gtk_tool_button_new_from_stock(stock_id));
753                         }
754                 else
755                         {
756                         item = GTK_WIDGET(gtk_tool_button_new(NULL, NULL));
757                         }
758                 }
759         gtk_tool_button_set_use_underline(GTK_TOOL_BUTTON(item), TRUE);
760
761         if (label) gtk_tool_button_set_label(GTK_TOOL_BUTTON(item), label);
762
763         if (func) g_signal_connect(item, "clicked", func, data);
764         gtk_container_add(GTK_CONTAINER(toolbar), item);
765         gtk_widget_show(item);
766
767         if (description)
768                 {
769                 gtk_widget_set_tooltip_text(item, description);
770                 }
771
772         return item;
773 }
774
775 //void pref_toolbar_button_set_icon(GtkWidget *button, GtkWidget *widget, const gchar *stock_id)
776 //{
777         //if (widget)
778                 //{
779                 //gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(button), widget);
780                 //}
781         //else if (stock_id)
782                 //{
783                 //gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(button), stock_id);
784                 //}
785 //}
786
787 //GtkWidget *pref_toolbar_spacer(GtkWidget *toolbar)
788 //{
789         //GtkWidget *item;
790
791         //item = GTK_WIDGET(gtk_separator_tool_item_new());
792         //gtk_container_add(GTK_CONTAINER(toolbar), item);
793         //gtk_widget_show(item);
794
795         //return item;
796 //}
797
798
799 /*
800  *-----------------------------------------------------------------------------
801  * date selection entry
802  *-----------------------------------------------------------------------------
803  */
804
805 #define DATE_SELECION_KEY "date_selection_data"
806
807
808 typedef struct _DateSelection DateSelection;
809 struct _DateSelection
810 {
811         GtkWidget *box;
812
813         GtkWidget *spin_d;
814         GtkWidget *spin_m;
815         GtkWidget *spin_y;
816
817         GtkWidget *button;
818
819         GtkWidget *window;
820         GtkWidget *calendar;
821 };
822
823
824 static void date_selection_popup_hide(DateSelection *ds)
825 {
826         if (!ds->window) return;
827
828         if (gtk_widget_has_grab(ds->window))
829                 {
830                 gtk_grab_remove(ds->window);
831                 gdk_keyboard_ungrab(GDK_CURRENT_TIME);
832                 gdk_pointer_ungrab(GDK_CURRENT_TIME);
833                 }
834
835         gtk_widget_hide(ds->window);
836
837         gtk_widget_destroy(ds->window);
838         ds->window = NULL;
839         ds->calendar = NULL;
840
841         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ds->button), FALSE);
842 }
843
844 static gboolean date_selection_popup_release_cb(GtkWidget *UNUSED(widget), GdkEventButton *UNUSED(event), gpointer data)
845 {
846         DateSelection *ds = static_cast<DateSelection *>(data);
847
848         date_selection_popup_hide(ds);
849         return TRUE;
850 }
851
852 static gboolean date_selection_popup_press_cb(GtkWidget *UNUSED(widget), GdkEventButton *event, gpointer data)
853 {
854         DateSelection *ds = static_cast<DateSelection *>(data);
855         gint x, y;
856         gint w, h;
857         gint xr, yr;
858         GdkWindow *window;
859
860         xr = (gint)event->x_root;
861         yr = (gint)event->y_root;
862
863         window = gtk_widget_get_window(ds->window);
864         gdk_window_get_origin(window, &x, &y);
865         w = gdk_window_get_width(window);
866         h = gdk_window_get_height(window);
867
868         if (xr < x || yr < y || xr > x + w || yr > y + h)
869                 {
870                 g_signal_connect(G_OBJECT(ds->window), "button_release_event",
871                                  G_CALLBACK(date_selection_popup_release_cb), ds);
872                 return TRUE;
873                 }
874
875         return FALSE;
876 }
877
878 static void date_selection_popup_sync(DateSelection *ds)
879 {
880         guint day, month, year;
881
882         gtk_calendar_get_date(GTK_CALENDAR(ds->calendar), &year, &month, &day);
883         date_selection_set(ds->box, day, month + 1, year);
884 }
885
886 static gboolean date_selection_popup_keypress_cb(GtkWidget *UNUSED(widget), GdkEventKey *event, gpointer data)
887 {
888         DateSelection *ds = static_cast<DateSelection *>(data);
889
890         switch (event->keyval)
891                 {
892                 case GDK_KEY_Return:
893                 case GDK_KEY_KP_Enter:
894                 case GDK_KEY_Tab:
895                 case GDK_KEY_ISO_Left_Tab:
896                         date_selection_popup_sync(ds);
897                         date_selection_popup_hide(ds);
898                         break;
899                 case GDK_KEY_Escape:
900                         date_selection_popup_hide(ds);
901                         break;
902                 default:
903                         break;
904                 }
905
906         return FALSE;
907 }
908
909 static void date_selection_day_cb(GtkWidget *UNUSED(widget), gpointer data)
910 {
911         DateSelection *ds = static_cast<DateSelection *>(data);
912
913         date_selection_popup_sync(ds);
914 }
915
916 static void date_selection_doubleclick_cb(GtkWidget *UNUSED(widget), gpointer data)
917 {
918         DateSelection *ds = static_cast<DateSelection *>(data);
919
920         date_selection_popup_hide(ds);
921 }
922
923 static void date_selection_popup(DateSelection *ds)
924 {
925         gint x, y;
926         gint wx, wy;
927         gint day, month, year;
928         GtkAllocation button_allocation;
929         GtkAllocation window_allocation;
930
931         if (ds->window) return;
932
933         ds->window = gtk_window_new(GTK_WINDOW_POPUP);
934         gtk_window_set_resizable(GTK_WINDOW(ds->window), FALSE);
935         g_signal_connect(G_OBJECT(ds->window), "button_press_event",
936                          G_CALLBACK(date_selection_popup_press_cb), ds);
937         g_signal_connect(G_OBJECT(ds->window), "key_press_event",
938                          G_CALLBACK(date_selection_popup_keypress_cb), ds);
939
940         ds->calendar = gtk_calendar_new();
941         gtk_container_add(GTK_CONTAINER(ds->window), ds->calendar);
942         gtk_widget_show(ds->calendar);
943
944         date_selection_get(ds->box, &day, &month, &year);
945         gtk_calendar_select_month(GTK_CALENDAR(ds->calendar), month - 1, year);
946         gtk_calendar_select_day(GTK_CALENDAR(ds->calendar), day);
947
948         g_signal_connect(G_OBJECT(ds->calendar), "day_selected",
949                          G_CALLBACK(date_selection_day_cb), ds);
950         g_signal_connect(G_OBJECT(ds->calendar), "day_selected_double_click",
951                         G_CALLBACK(date_selection_doubleclick_cb), ds);
952
953         gtk_widget_realize(ds->window);
954
955         gdk_window_get_origin(gtk_widget_get_window(ds->button), &wx, &wy);
956
957         gtk_widget_get_allocation(ds->button, &button_allocation);
958         gtk_widget_get_allocation(ds->window, &window_allocation);
959
960         x = wx + button_allocation.x + button_allocation.width - window_allocation.width;
961         y = wy + button_allocation.y + button_allocation.height;
962
963         if (y + window_allocation.height > gdk_screen_height())
964                 {
965                 y = wy + button_allocation.y - window_allocation.height;
966                 }
967         if (x < 0) x = 0;
968         if (y < 0) y = 0;
969
970         gtk_window_move(GTK_WINDOW(ds->window), x, y);
971         gtk_widget_show(ds->window);
972
973         gtk_widget_grab_focus(ds->calendar);
974         gdk_pointer_grab(gtk_widget_get_window(ds->window), TRUE,
975                          static_cast<GdkEventMask>(GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK),
976                          NULL, NULL, GDK_CURRENT_TIME);
977         gdk_keyboard_grab(gtk_widget_get_window(ds->window), TRUE, GDK_CURRENT_TIME);
978         gtk_grab_add(ds->window);
979
980         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ds->button), TRUE);
981 }
982
983 static void date_selection_button_cb(GtkWidget *UNUSED(widget), gpointer data)
984 {
985         DateSelection *ds = static_cast<DateSelection *>(data);
986
987         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ds->button)) == (!ds->window))
988                 {
989                 date_selection_popup(ds);
990                 }
991 }
992
993 static void button_size_allocate_cb(GtkWidget *button, GtkAllocation *allocation, gpointer data)
994 {
995         GtkWidget *spin = static_cast<GtkWidget *>(data);
996         GtkRequisition spin_requisition;
997         gtk_widget_get_requisition(spin, &spin_requisition);
998
999         if (allocation->height > spin_requisition.height)
1000                 {
1001                 GtkAllocation button_allocation;
1002                 GtkAllocation spin_allocation;
1003
1004                 gtk_widget_get_allocation(button, &button_allocation);
1005                 gtk_widget_get_allocation(spin, &spin_allocation);
1006                 button_allocation.height = spin_requisition.height;
1007                 button_allocation.y = spin_allocation.y +
1008                         (spin_allocation.height - spin_requisition.height) / 2;
1009                 gtk_widget_size_allocate(button, &button_allocation);
1010                 }
1011 }
1012
1013 static void spin_increase(GtkWidget *spin, gint value)
1014 {
1015         GtkRequisition req;
1016
1017         gtk_widget_size_request(spin, &req);
1018         gtk_widget_set_size_request(spin, req.width + value, -1);
1019 }
1020
1021 static void date_selection_destroy_cb(GtkWidget *UNUSED(widget), gpointer data)
1022 {
1023         DateSelection *ds = static_cast<DateSelection *>(data);
1024
1025         date_selection_popup_hide(ds);
1026
1027         g_free(ds);
1028 }
1029
1030 GtkWidget *date_selection_new(void)
1031 {
1032         DateSelection *ds;
1033         GtkWidget *arrow;
1034
1035         ds = g_new0(DateSelection, 1);
1036         gchar *date_format;
1037         gint i;
1038
1039         ds->box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
1040         g_signal_connect(G_OBJECT(ds->box), "destroy",
1041                          G_CALLBACK(date_selection_destroy_cb), ds);
1042
1043         date_format = nl_langinfo(D_FMT);
1044
1045         if (strlen(date_format) == 8)
1046                 {
1047                 for (i=1; i<8; i=i+3)
1048                         {
1049                         switch (date_format[i])
1050                                 {
1051                                 case 'd':
1052                                         ds->spin_d = pref_spin_new(ds->box, NULL, NULL, 1, 31, 1, 0, 1, NULL, NULL);
1053                                         break;
1054                                 case 'm':
1055                                         ds->spin_m = pref_spin_new(ds->box, NULL, NULL, 1, 12, 1, 0, 1, NULL, NULL);
1056                                         break;
1057                                 case 'y': case 'Y':
1058                                         ds->spin_y = pref_spin_new(ds->box, NULL, NULL, 1900, 9999, 1, 0, 1900, NULL, NULL);
1059                                         break;
1060                                 default:
1061                                         log_printf("Warning: Date locale %s is unknown", date_format);
1062                                         break;
1063                                 }
1064                         }
1065                 }
1066         else
1067                 {
1068                 ds->spin_m = pref_spin_new(ds->box, NULL, NULL, 1, 12, 1, 0, 1, NULL, NULL);
1069                 ds->spin_d = pref_spin_new(ds->box, NULL, NULL, 1, 31, 1, 0, 1, NULL, NULL);
1070                 ds->spin_y = pref_spin_new(ds->box, NULL, NULL, 1900, 9999, 1, 0, 1900, NULL, NULL);
1071                 }
1072
1073         spin_increase(ds->spin_y, 5);
1074
1075         ds->button = gtk_toggle_button_new();
1076         g_signal_connect(G_OBJECT(ds->button), "size_allocate",
1077                          G_CALLBACK(button_size_allocate_cb), ds->spin_y);
1078
1079         arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1080         gtk_container_add(GTK_CONTAINER(ds->button), arrow);
1081         gtk_widget_show(arrow);
1082
1083         gtk_box_pack_start(GTK_BOX(ds->box), ds->button, FALSE, FALSE, 0);
1084         g_signal_connect(G_OBJECT(ds->button), "clicked",
1085                          G_CALLBACK(date_selection_button_cb), ds);
1086         gtk_widget_show(ds->button);
1087
1088         g_object_set_data(G_OBJECT(ds->box), DATE_SELECION_KEY, ds);
1089
1090         return ds->box;
1091 }
1092
1093 void date_selection_set(GtkWidget *widget, gint day, gint month, gint year)
1094 {
1095         DateSelection *ds;
1096
1097         ds = static_cast<DateSelection *>(g_object_get_data(G_OBJECT(widget), DATE_SELECION_KEY));
1098         if (!ds) return;
1099
1100         gtk_spin_button_set_value(GTK_SPIN_BUTTON(ds->spin_d), (gdouble)day);
1101         gtk_spin_button_set_value(GTK_SPIN_BUTTON(ds->spin_m), (gdouble)month);
1102         gtk_spin_button_set_value(GTK_SPIN_BUTTON(ds->spin_y), (gdouble)year);
1103 }
1104
1105
1106 void date_selection_get(GtkWidget *widget, gint *day, gint *month, gint *year)
1107 {
1108         DateSelection *ds;
1109
1110         ds = static_cast<DateSelection *>(g_object_get_data(G_OBJECT(widget), DATE_SELECION_KEY));
1111         if (!ds) return;
1112
1113         if (day) *day = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ds->spin_d));
1114         if (month) *month = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ds->spin_m));
1115         if (year) *year = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ds->spin_y));
1116 }
1117
1118 void date_selection_time_set(GtkWidget *widget, time_t t)
1119 {
1120         struct tm *lt;
1121
1122         lt = localtime(&t);
1123         if (!lt) return;
1124
1125         date_selection_set(widget, lt->tm_mday, lt->tm_mon + 1, lt->tm_year + 1900);
1126 }
1127
1128 //time_t date_selection_time_get(GtkWidget *widget)
1129 //{
1130         //struct tm lt;
1131         //gint day = 0;
1132         //gint month = 0;
1133         //gint year = 0;
1134
1135         //date_selection_get(widget, &day, &month ,&year);
1136
1137         //lt.tm_sec = 0;
1138         //lt.tm_min = 0;
1139         //lt.tm_hour = 0;
1140         //lt.tm_mday = day;
1141         //lt.tm_mon = month - 1;
1142         //lt.tm_year = year - 1900;
1143         //lt.tm_isdst = 0;
1144
1145         //return mktime(&lt);
1146 //}
1147
1148 /*
1149  *-----------------------------------------------------------------------------
1150  * storing data in a history list with key,data pairs
1151  *-----------------------------------------------------------------------------
1152  */
1153
1154 #define PREF_LIST_MARKER_INT "[INT]:"
1155 #define PREF_LIST_MARKER_DOUBLE "[DOUBLE]:"
1156 #define PREF_LIST_MARKER_STRING "[STRING]:"
1157
1158 static GList *pref_list_find(const gchar *group, const gchar *token)
1159 {
1160         GList *work;
1161         gint l;
1162
1163         l = strlen(token);
1164
1165         work = history_list_get_by_key(group);
1166         while (work)
1167                 {
1168                 const gchar *text = static_cast<const gchar *>(work->data);
1169
1170                 if (strncmp(text, token, l) == 0) return work;
1171
1172                 work = work->next;
1173                 }
1174
1175         return NULL;
1176 }
1177
1178 static gboolean pref_list_get(const gchar *group, const gchar *key, const gchar *marker, const gchar **result)
1179 {
1180         gchar *token;
1181         GList *work;
1182         gboolean ret;
1183
1184         if (!group || !key || !marker)
1185                 {
1186                 *result = NULL;
1187                 return FALSE;
1188                 }
1189
1190         token = g_strconcat(key, marker, NULL);
1191
1192         work = pref_list_find(group, token);
1193         if (work)
1194                 {
1195                 *result = (const gchar *)work->data + strlen(token);
1196                 if (strlen(*result) == 0) *result = NULL;
1197                 ret = TRUE;
1198                 }
1199         else
1200                 {
1201                 *result = NULL;
1202                 ret = FALSE;
1203                 }
1204
1205         g_free(token);
1206
1207         return ret;
1208 }
1209
1210 static void pref_list_set(const gchar *group, const gchar *key, const gchar *marker, const gchar *text)
1211 {
1212         gchar *token;
1213         gchar *path;
1214         GList *work;
1215
1216         if (!group || !key || !marker) return;
1217
1218         token = g_strconcat(key, marker, NULL);
1219         path = g_strconcat(token, text, NULL);
1220
1221         work = pref_list_find(group, token);
1222         if (work)
1223                 {
1224                 gchar *old_path = static_cast<gchar *>(work->data);
1225
1226                 if (text)
1227                         {
1228                         work->data = path;
1229                         path = NULL;
1230
1231                         g_free(old_path);
1232                         }
1233                 else
1234                         {
1235                         history_list_item_remove(group, old_path);
1236                         }
1237                 }
1238         else if (text)
1239                 {
1240                 history_list_add_to_key(group, path, 0);
1241                 }
1242
1243         g_free(path);
1244         g_free(token);
1245 }
1246
1247 void pref_list_int_set(const gchar *group, const gchar *key, gint value)
1248 {
1249         gchar *text;
1250
1251         text = g_strdup_printf("%d", value);
1252         pref_list_set(group, key, PREF_LIST_MARKER_INT, text);
1253         g_free(text);
1254 }
1255
1256 gboolean pref_list_int_get(const gchar *group, const gchar *key, gint *result)
1257 {
1258         const gchar *text;
1259
1260         if (!group || !key)
1261                 {
1262                 *result = 0;
1263                 return FALSE;
1264                 }
1265
1266         if (pref_list_get(group, key, PREF_LIST_MARKER_INT, &text) && text)
1267                 {
1268                 *result = (gint)strtol(text, NULL, 10);
1269                 return TRUE;
1270                 }
1271
1272         *result = 0;
1273         return FALSE;
1274 }
1275
1276 //void pref_list_double_set(const gchar *group, const gchar *key, gdouble value)
1277 //{
1278         //gchar text[G_ASCII_DTOSTR_BUF_SIZE];
1279
1280         //g_ascii_dtostr(text, sizeof(text), value);
1281         //pref_list_set(group, key, PREF_LIST_MARKER_DOUBLE, text);
1282 //}
1283
1284 //gboolean pref_list_double_get(const gchar *group, const gchar *key, gdouble *result)
1285 //{
1286         //const gchar *text;
1287
1288         //if (!group || !key)
1289                 //{
1290                 //*result = 0;
1291                 //return FALSE;
1292                 //}
1293
1294         //if (pref_list_get(group, key, PREF_LIST_MARKER_DOUBLE, &text) && text)
1295                 //{
1296                 //*result = g_ascii_strtod(text, NULL);
1297                 //return TRUE;
1298                 //}
1299
1300         //*result = 0;
1301         //return FALSE;
1302 //}
1303
1304 //void pref_list_string_set(const gchar *group, const gchar *key, const gchar *value)
1305 //{
1306         //pref_list_set(group, key, PREF_LIST_MARKER_STRING, value);
1307 //}
1308
1309 //gboolean pref_list_string_get(const gchar *group, const gchar *key, const gchar **result)
1310 //{
1311         //return pref_list_get(group, key, PREF_LIST_MARKER_STRING, result);
1312 //}
1313
1314
1315 void pref_color_button_set_cb(GtkWidget *widget, gpointer data)
1316 {
1317         GdkColor *color = static_cast<GdkColor *>(data);
1318
1319         gtk_color_button_get_color(GTK_COLOR_BUTTON(widget), color);
1320 }
1321
1322 GtkWidget *pref_color_button_new(GtkWidget *parent_box,
1323                                  const gchar *title, const GdkColor *color,
1324                                  GCallback func, gpointer data)
1325 {
1326         GtkWidget *button;
1327
1328         if (color)
1329                 {
1330                 button = gtk_color_button_new_with_color(color);
1331                 }
1332         else
1333                 {
1334                 button = gtk_color_button_new();
1335                 }
1336
1337         if (func) g_signal_connect(G_OBJECT(button), "color-set", func, data);
1338
1339         if (title)
1340                 {
1341                 GtkWidget *label;
1342                 GtkWidget *hbox;
1343
1344                 gtk_color_button_set_title(GTK_COLOR_BUTTON(button), title);
1345                 label = gtk_label_new(title);
1346
1347                 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1348                 gtk_box_pack_start(GTK_BOX(parent_box), hbox, TRUE, TRUE, 0);
1349
1350                 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
1351                 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
1352
1353                 gtk_widget_show_all(hbox);
1354                 }
1355         else
1356                 {
1357                 gtk_widget_show(button);
1358                 }
1359
1360         return button;
1361 }
1362
1363 /*
1364  *-----------------------------------------------------------------------------
1365  * text widget
1366  *-----------------------------------------------------------------------------
1367  */
1368
1369 gchar *text_widget_text_pull(GtkWidget *text_widget)
1370 {
1371         if (GTK_IS_TEXT_VIEW(text_widget))
1372                 {
1373                 GtkTextBuffer *buffer;
1374                 GtkTextIter start, end;
1375
1376                 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_widget));
1377                 gtk_text_buffer_get_bounds(buffer, &start, &end);
1378
1379                 return gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
1380                 }
1381         else if (GTK_IS_ENTRY(text_widget))
1382                 {
1383                 return g_strdup(gtk_entry_get_text(GTK_ENTRY(text_widget)));
1384                 }
1385         else
1386                 {
1387                 return NULL;
1388                 }
1389
1390 }
1391
1392 gchar *text_widget_text_pull_selected(GtkWidget *text_widget)
1393 {
1394         if (GTK_IS_TEXT_VIEW(text_widget))
1395                 {
1396                 GtkTextBuffer *buffer;
1397                 GtkTextIter start, end;
1398
1399                 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_widget));
1400                 gtk_text_buffer_get_bounds(buffer, &start, &end);
1401
1402                 if (gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
1403                         {
1404                         gtk_text_iter_set_line_offset(&start, 0);
1405                         gtk_text_iter_forward_to_line_end(&end);
1406                         }
1407
1408                 return gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
1409                 }
1410         else if (GTK_IS_ENTRY(text_widget))
1411                 {
1412                 return g_strdup(gtk_entry_get_text(GTK_ENTRY(text_widget)));
1413                 }
1414         else
1415                 {
1416                 return NULL;
1417                 }
1418 }
1419
1420 gboolean defined_mouse_buttons(GtkWidget *UNUSED(widget), GdkEventButton *event, gpointer data)
1421 {
1422         LayoutWindow *lw = static_cast<LayoutWindow *>(data);
1423         GtkAction *action;
1424         gboolean ret = FALSE;
1425
1426         switch (event->button)
1427                 {
1428                 case MOUSE_BUTTON_8:
1429                         if (options->mouse_button_8)
1430                                 {
1431                                 action = gtk_action_group_get_action(lw->action_group, options->mouse_button_8);
1432                                 if (action)
1433                                         {
1434                                         gtk_action_activate(action);
1435                                         }
1436                                 ret = TRUE;
1437                                 }
1438                                 break;
1439                 case MOUSE_BUTTON_9:
1440                         if (options->mouse_button_9)
1441                                 {
1442                                 action = gtk_action_group_get_action(lw->action_group, options->mouse_button_9);
1443                                 if (action)
1444                                         {
1445                                         gtk_action_activate(action);
1446                                         }
1447                                 ret = TRUE;
1448                                 }
1449                         break;
1450                 default:
1451                         break;
1452                 }
1453
1454         return ret;
1455 }
1456
1457 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */