2
* gsdlg.c - Simple GTK dialog wrapper
4
* Copyright 2007-2008 Jeff Pohlmeyer <yetanothergeek(at)gmail(dot)com>
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.
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.
18
* You should have received a copy of the GNU General Public License along
19
* with this program; if not, write to the Free Software Foundation, Inc.,
20
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24
#ifndef GSDLG_ALL_IN_ONE
28
#include <glib/gi18n.h>
32
#define realpath(src,dst) _fullpath((dst),(src),_MAX_PATH)
36
#define TextKey "gsdlg_TextKey_bc4871f4e3478ab5234e28432460a6b8"
37
#define DataKey "gsdlg_DataKey_bc4871f4e3478ab5234e28432460a6b8"
40
static void destroy_slist_and_data(gpointer list)
43
for (p=list; p ; p=p->next) {
44
if (p->data) g_free(p->data);
52
void gsdlg_textarea(GtkDialog *dlg, GsDlgStr key, GsDlgStr value, GsDlgStr label)
57
g_return_if_fail(dlg);
58
tv=gtk_text_view_new();
59
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tv),GTK_WRAP_WORD_CHAR);
60
gtk_text_view_set_accepts_tab(GTK_TEXT_VIEW(tv),FALSE);
62
GtkTextBuffer *tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tv));
63
gtk_text_buffer_set_text (tb, value, -1);
65
sw=gtk_scrolled_window_new(NULL, NULL);
66
gtk_widget_set_usize(sw, gdk_screen_get_width(gdk_screen_get_default())/3,
67
gdk_screen_get_height(gdk_screen_get_default())/10);
68
gtk_container_add(GTK_CONTAINER(sw),tv);
69
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
70
frm=gtk_frame_new(label);
71
gtk_frame_set_shadow_type(GTK_FRAME(frm), GTK_SHADOW_ETCHED_IN);
72
gtk_container_add(GTK_CONTAINER(frm),sw);
73
gtk_container_add(GTK_CONTAINER(dlg->vbox),frm);
74
g_object_set_data_full(G_OBJECT(tv), TextKey, g_strdup(key), g_free);
79
static void make_modal(GtkWidget *w, GtkWidget*p)
81
gtk_window_set_modal(GTK_WINDOW(w), TRUE);
82
gtk_window_set_transient_for(GTK_WINDOW(w),GTK_WINDOW(p));
87
static void file_dlg_map(GtkWidget *w, gpointer user_data)
89
GtkWidget* entry=gtk_window_get_focus (GTK_WINDOW(w));
90
if (entry && GTK_IS_ENTRY(entry)) {
91
gtk_entry_set_text(GTK_ENTRY(entry), (gchar*)user_data);
97
static void file_btn_clicked(GtkButton *button, gpointer user_data)
100
const gchar *fn=NULL;
103
dlg=gtk_file_chooser_dialog_new(_("Open file"),
104
gsdlg_toplevel, GTK_FILE_CHOOSER_ACTION_OPEN,
105
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
106
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
107
gtk_window_set_title(GTK_WINDOW(dlg), _("Select file"));
108
make_modal(dlg, gtk_widget_get_toplevel(GTK_WIDGET(user_data)));
109
fn=gtk_entry_get_text(GTK_ENTRY(user_data));
111
if (g_file_test(fn,G_FILE_TEST_IS_REGULAR)) {
112
gchar *rp=realpath(fn,NULL);
113
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dlg), rp);
116
if (g_file_test(fn,G_FILE_TEST_IS_DIR)) {
117
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dlg), fn);
119
gchar *dn=g_path_get_dirname(fn);
120
if (g_file_test(dn,G_FILE_TEST_IS_DIR)) {
121
gchar *rp=realpath(dn,NULL);
122
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dlg), rp);
124
bn=g_path_get_basename(fn);
125
g_signal_connect(G_OBJECT(dlg), "map", G_CALLBACK(file_dlg_map), bn);
131
resp=gtk_dialog_run(GTK_DIALOG(dlg));
132
if (resp == GTK_RESPONSE_ACCEPT) {
133
gchar *fcfn=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg));
135
gtk_entry_set_text(GTK_ENTRY(user_data), fcfn);
139
gtk_widget_destroy(dlg);
140
if (bn) { g_free(bn); }
145
void gsdlg_file(GtkDialog *dlg, GsDlgStr key, GsDlgStr value, GsDlgStr label)
151
g_return_if_fail(dlg);
152
input=gtk_entry_new();
153
if (value) { gtk_entry_set_text(GTK_ENTRY(input),value); }
154
btn=gtk_button_new_with_label(_("Browse..."));
155
g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(file_btn_clicked), input);
156
hbox=gtk_hbox_new(FALSE,FALSE);
157
gtk_box_pack_start(GTK_BOX(hbox), input,TRUE,TRUE,1);
158
gtk_box_pack_start(GTK_BOX(hbox), btn,FALSE,FALSE,1);
159
frm=gtk_frame_new(label);
160
gtk_frame_set_shadow_type(GTK_FRAME(frm), GTK_SHADOW_ETCHED_IN);
161
gtk_container_add(GTK_CONTAINER(frm),hbox);
162
gtk_container_add(GTK_CONTAINER(dlg->vbox),frm);
163
g_object_set_data_full(G_OBJECT(input), TextKey, g_strdup(key), g_free);
168
static void color_btn_clicked(GtkButton *button, gpointer user_data)
171
const gchar *cn=NULL;
175
dlg=gtk_color_selection_dialog_new (_("Select Color"));
176
make_modal(dlg, gtk_widget_get_toplevel(GTK_WIDGET(user_data)));
177
cn=gtk_entry_get_text(GTK_ENTRY(user_data));
178
if (cn && *cn && gdk_color_parse(cn,&rgb)) {
179
gtk_color_selection_set_current_color(
180
GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(dlg)->colorsel), &rgb);
182
resp=gtk_dialog_run(GTK_DIALOG(dlg));
183
if (resp == GTK_RESPONSE_OK) {
185
gtk_color_selection_get_current_color(
186
GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(dlg)->colorsel), &rgb);
187
rv=g_strdup_printf("#%2.2X%2.2X%2.2X",rgb.red/256,rgb.green/256,rgb.blue/256);
188
gtk_entry_set_text(GTK_ENTRY(user_data), rv);
191
gtk_widget_destroy(dlg);
196
void gsdlg_color(GtkDialog *dlg, GsDlgStr key, GsDlgStr value, GsDlgStr prompt)
202
g_return_if_fail(dlg);
203
input=gtk_entry_new();
204
if (value) { gtk_entry_set_text(GTK_ENTRY(input),value); }
205
btn=gtk_button_new_with_label(_("Choose..."));
206
g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(color_btn_clicked), input);
207
hbox=gtk_hbox_new(FALSE,FALSE);
209
label=gtk_label_new(prompt);
210
gtk_box_pack_start(GTK_BOX(hbox), label,FALSE,FALSE,1);
212
gtk_box_pack_start(GTK_BOX(hbox), input,TRUE,TRUE,1);
213
gtk_box_pack_start(GTK_BOX(hbox), btn,FALSE,FALSE,1);
214
gtk_container_add(GTK_CONTAINER(dlg->vbox),hbox);
215
g_object_set_data_full(G_OBJECT(input), TextKey, g_strdup(key), g_free);
220
static void font_btn_clicked(GtkButton *button, gpointer user_data)
223
const gchar *fn=NULL;
225
fn=gtk_entry_get_text(GTK_ENTRY(user_data));
226
dlg=gtk_font_selection_dialog_new(_("Select Font"));
227
make_modal(dlg, gtk_widget_get_toplevel(GTK_WIDGET(user_data)));
229
gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(dlg),fn);
231
resp=gtk_dialog_run(GTK_DIALOG(dlg));
232
if (resp==GTK_RESPONSE_OK) {
233
gchar *gfn=gtk_font_selection_dialog_get_font_name(GTK_FONT_SELECTION_DIALOG(dlg));
235
gtk_entry_set_text(GTK_ENTRY(user_data), gfn);
239
gtk_widget_destroy(dlg);
244
void gsdlg_font(GtkDialog *dlg, GsDlgStr key, GsDlgStr value, GsDlgStr prompt)
250
g_return_if_fail(dlg);
251
input=gtk_entry_new();
252
if (value) { gtk_entry_set_text(GTK_ENTRY(input),value); }
253
btn=gtk_button_new_with_label(_("Select..."));
254
g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(font_btn_clicked), input);
255
hbox=gtk_hbox_new(FALSE,FALSE);
257
label=gtk_label_new(prompt);
258
gtk_box_pack_start(GTK_BOX(hbox), label,FALSE,FALSE,1);
260
gtk_box_pack_start(GTK_BOX(hbox), input,TRUE,TRUE,1);
261
gtk_box_pack_start(GTK_BOX(hbox), btn,FALSE,FALSE,1);
262
gtk_container_add(GTK_CONTAINER(dlg->vbox),hbox);
263
g_object_set_data_full(G_OBJECT(input), TextKey, g_strdup(key), g_free);
268
static void gsdlg_entry(GtkDialog *dlg, GsDlgStr key, GsDlgStr value, GsDlgStr prompt, gboolean masked)
273
g_return_if_fail(dlg);
274
input=gtk_entry_new();
275
if (value) { gtk_entry_set_text(GTK_ENTRY(input),value); }
276
label=gtk_label_new(prompt);
277
hbox=gtk_hbox_new(FALSE,FALSE);
278
gtk_box_pack_start(GTK_BOX(hbox), label,FALSE,FALSE,1);
279
gtk_box_pack_start(GTK_BOX(hbox), input,TRUE,TRUE,1);
280
gtk_entry_set_visibility(GTK_ENTRY(input), !masked);
281
gtk_container_add(GTK_CONTAINER(dlg->vbox),hbox);
282
g_object_set_data_full(G_OBJECT(input), TextKey, g_strdup(key), g_free);
286
void gsdlg_text(GtkDialog *dlg, GsDlgStr key, GsDlgStr value, GsDlgStr label)
288
gsdlg_entry(dlg, key, value, label, FALSE);
293
void gsdlg_password(GtkDialog *dlg, GsDlgStr key, GsDlgStr value, GsDlgStr label)
295
gsdlg_entry(dlg, key, value, label, TRUE);
299
void gsdlg_checkbox(GtkDialog *dlg, GsDlgStr key, gboolean value, GsDlgStr label)
302
g_return_if_fail(dlg);
303
cb=gtk_check_button_new_with_label(label);
304
g_object_set_data_full(G_OBJECT(cb),TextKey,g_strdup(key), g_free);
305
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb),value);
306
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dlg)->vbox),cb);
311
typedef struct _KeySearchData {
319
static void find_widget_by_key_cb(GtkWidget *w, gpointer p)
322
if (kv->value) {return;}
324
if (G_OBJECT_TYPE(G_OBJECT(w)) == kv->type) {
325
gchar*key=g_object_get_data(G_OBJECT(w), TextKey);
326
if (key && g_str_equal(kv->key,key)) { kv->value=w; }
331
static GtkWidget *find_widget_by_key(GtkDialog *dlg, GType type, GsDlgStr key)
333
KeySearchData kv={NULL,0,NULL};
334
g_return_val_if_fail(dlg, NULL);
337
gtk_container_foreach(GTK_CONTAINER(GTK_DIALOG(dlg)->vbox),find_widget_by_key_cb,&kv);
342
static void select_radio(GtkWidget*parent, GsDlgStr value)
344
GList *kids=gtk_container_get_children(GTK_CONTAINER(parent));
345
if (!kids) { return;}
346
if (kids->data && GTK_IS_RADIO_BUTTON(kids->data)) {
348
for (kid=kids; kid; kid=kid->next) {
349
if (kid->data && GTK_IS_RADIO_BUTTON(kid->data)) {
350
gchar*kval=g_object_get_data(G_OBJECT(kid->data),TextKey);
351
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(kid->data),
352
kval && g_str_equal(kval,value));
360
void gsdlg_group(GtkDialog *dlg, GsDlgStr key, GsDlgStr value, GsDlgStr label)
365
g_return_if_fail(dlg);
366
frm=find_widget_by_key(dlg,GTK_TYPE_FRAME,key);
368
vbox=gtk_bin_get_child(GTK_BIN(frm));
369
gtk_frame_set_label(GTK_FRAME(frm), label);
371
frm=gtk_frame_new(label);
372
vbox=gtk_vbox_new(FALSE,FALSE);
373
gtk_container_add(GTK_CONTAINER(frm),vbox);
374
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dlg)->vbox),frm);
377
/* Frame holds keyname, vbox holds default value */
378
g_object_set_data_full(G_OBJECT(frm), TextKey, g_strdup(key), g_free);
379
g_object_set_data_full(G_OBJECT(vbox), TextKey, g_strdup(value), g_free);
380
select_radio(vbox,value);
386
void gsdlg_radio(GtkDialog *dlg, GsDlgStr key, GsDlgStr value, GsDlgStr label)
389
GtkWidget *vbox=NULL;
393
g_return_if_fail(dlg);
394
frm=find_widget_by_key(dlg,GTK_TYPE_FRAME,key);
396
vbox=gtk_bin_get_child(GTK_BIN(frm));
398
kids=gtk_container_get_children(GTK_CONTAINER(vbox));
401
gsdlg_group(dlg,key,value,NULL);
402
frm=find_widget_by_key(dlg,GTK_TYPE_FRAME,key);
403
vbox=gtk_bin_get_child(GTK_BIN(frm));
406
rb=gtk_radio_button_new_with_label_from_widget (kids->data,label);
409
rb=gtk_radio_button_new_with_label(NULL, label);
411
g_object_set_data_full(G_OBJECT(rb),TextKey, g_strdup(value), g_free);
412
gtk_container_add(GTK_CONTAINER(vbox), rb);
413
defval=g_object_get_data(G_OBJECT(vbox),TextKey);
414
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb),
415
value && defval && g_str_equal(defval,value));
421
static void select_combo(GtkWidget*parent, GsDlgStr value)
424
GSList*values=g_object_get_data(G_OBJECT(parent), DataKey);
426
for (v=values; v; v=v->next) {
427
if (v->data && g_str_equal(v->data, value)) {break;}
430
gtk_combo_box_set_active(GTK_COMBO_BOX(parent), n);
434
typedef struct _ComboWidgets {
440
void gsdlg_select(GtkDialog *dlg, GsDlgStr key, GsDlgStr value, GsDlgStr label)
442
GtkWidget *hbox=NULL;
443
ComboWidgets*cw=NULL;
444
g_return_if_fail(dlg);
445
hbox=find_widget_by_key(dlg,GTK_TYPE_HBOX, key);
447
cw=g_object_get_data(G_OBJECT(hbox), DataKey);
448
gtk_label_set(GTK_LABEL(cw->label), label);
450
hbox=gtk_hbox_new(FALSE,FALSE);
451
cw=g_malloc0(sizeof(ComboWidgets));
452
g_object_set_data_full(G_OBJECT(hbox),DataKey,cw,g_free);
453
cw->combo=gtk_combo_box_new_text();
454
cw->label=gtk_label_new(label);
455
gtk_box_pack_start(GTK_BOX(hbox), cw->label,FALSE,FALSE,4);
456
gtk_box_pack_start(GTK_BOX(hbox), cw->combo,TRUE,TRUE,1);
457
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dlg)->vbox),hbox);
459
/* Hbox holds keyname, combo holds default value */
460
g_object_set_data_full(G_OBJECT(hbox), TextKey, g_strdup(key), g_free);
461
g_object_set_data_full(G_OBJECT(cw->combo), TextKey, g_strdup(value), g_free);
462
select_combo(cw->combo,value);
467
void gsdlg_option(GtkDialog *dlg, GsDlgStr key, GsDlgStr value, GsDlgStr label)
469
GtkWidget *hbox=NULL;
471
ComboWidgets*cw=NULL;
473
g_return_if_fail(dlg);
475
hbox=find_widget_by_key(dlg,GTK_TYPE_HBOX, key);
477
gsdlg_select(dlg,key,value,NULL);
478
hbox=find_widget_by_key(dlg,GTK_TYPE_HBOX, key);
480
cw=g_object_get_data(G_OBJECT(hbox), DataKey);
481
values=g_object_steal_data(G_OBJECT(cw->combo), DataKey);
482
values=g_slist_append(values, g_strdup(value));
483
g_object_set_data_full(G_OBJECT(cw->combo), DataKey, values, destroy_slist_and_data);
484
gtk_combo_box_append_text(GTK_COMBO_BOX(cw->combo), label);
485
defval=g_object_get_data(G_OBJECT(cw->combo), TextKey);
486
if (value && defval && g_str_equal(value,defval)) {
487
select_combo(cw->combo,value);
494
void gsdlg_label(GtkDialog *dlg, GsDlgStr text)
497
g_return_if_fail(dlg);
498
lab=gtk_label_new(text);
499
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dlg)->vbox), lab);
500
gtk_misc_set_alignment(GTK_MISC(lab), 0.0f, 0.0f);
505
void gsdlg_hr(GtkDialog *dlg)
507
g_return_if_fail(dlg);
508
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dlg)->vbox), gtk_hseparator_new());
513
void gsdlg_heading(GtkDialog *dlg, GsDlgStr text)
515
g_return_if_fail(dlg);
517
gsdlg_label(dlg,text);
520
GSDLG_API GtkWindow* gsdlg_toplevel=NULL;
524
GtkDialog *gsdlg_new(GsDlgStr title, GsDlgStr*btns)
528
dlg=GTK_DIALOG(gtk_dialog_new());
529
if (gsdlg_toplevel) {
530
gtk_window_set_destroy_with_parent(GTK_WINDOW(dlg), TRUE);
531
gtk_window_set_transient_for(GTK_WINDOW(dlg),gsdlg_toplevel);
532
gtk_window_set_modal(GTK_WINDOW(dlg), TRUE);
534
for (i=0; btns[i]; i++) {
535
gtk_dialog_add_button(GTK_DIALOG(dlg),btns[i],i);
537
gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dlg)->vbox), 4);
538
gtk_container_set_border_width(GTK_CONTAINER(dlg), 4);
539
gtk_window_set_title(GTK_WINDOW(dlg),title);
545
static void widgets_foreach(GtkWidget *w, gpointer p)
547
gchar*key=g_object_get_data(G_OBJECT(w),TextKey);
549
const gchar*value=NULL;
550
if (GTK_IS_ENTRY(w)) {
551
value=gtk_entry_get_text(GTK_ENTRY(w));
552
} else if (GTK_IS_RADIO_BUTTON(w)) {
553
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))){
555
key=g_object_get_data(
556
G_OBJECT(gtk_widget_get_parent(gtk_widget_get_parent(w))), TextKey);
558
} else if (GTK_IS_CHECK_BUTTON(w)) {
559
value=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))?"1":"0";
560
} else if (GTK_IS_COMBO_BOX(w)) {
561
GSList*values=g_object_get_data(G_OBJECT(w),DataKey);
562
key=g_object_get_data(G_OBJECT(gtk_widget_get_parent(w)), TextKey);
564
gint n=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
565
if (n>=0) { value=g_slist_nth_data(values, n); }
567
} else if (GTK_IS_TEXT_VIEW(w)) {
568
GtkTextBuffer *tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(w));
570
gtk_text_buffer_get_start_iter(tb,&a);
571
gtk_text_buffer_get_end_iter(tb,&z);
572
value=gtk_text_buffer_get_text (tb,&a,&z,TRUE);
576
g_hash_table_insert(h,g_strdup(key),g_strdup(value));
579
if (GTK_IS_CONTAINER(w)) {
580
gtk_container_foreach(GTK_CONTAINER(w),widgets_foreach,p);
585
static GsDlgRunHook gsdlg_run_hook=NULL;
589
void gsdlg_set_run_hook(GsDlgRunHook cb)
596
GHashTable* gsdlg_run(GtkDialog *dlg, gint *btn, gpointer user_data)
598
GHashTable* results=NULL;
600
g_return_val_if_fail(dlg, NULL);
601
gtk_widget_show_all(GTK_WIDGET(dlg));
602
if (!btn) { btn=&dummy; }
603
if (gsdlg_run_hook) { gsdlg_run_hook(TRUE,user_data); }
604
*btn=gtk_dialog_run(GTK_DIALOG(dlg));
605
if (gsdlg_run_hook) { gsdlg_run_hook(FALSE,user_data); }
607
results=g_hash_table_new_full(g_str_hash,g_str_equal,g_free,g_free);
608
gtk_container_foreach(GTK_CONTAINER(GTK_DIALOG(dlg)->vbox),widgets_foreach,results);
609
gtk_widget_hide(GTK_WIDGET(dlg));