Mercurial > geeqie.yaz
annotate src/ui_utildlg.c @ 454:57459cf0952c
Prefix editor entries in the main menu with numbers.
It allows Alt+E+number as shortcut to start an editor.
author | zas_ |
---|---|
date | Sun, 20 Apr 2008 22:29:23 +0000 |
parents | ddabc4873a3f |
children | 48c8e49b571c |
rev | line source |
---|---|
9 | 1 /* |
2 * (SLIK) SimpLIstic sKin functions | |
3 * (C) 2004 John Ellis | |
4 * | |
5 * Author: John Ellis | |
6 * | |
7 * This software is released under the GNU General Public License (GNU GPL). | |
8 * Please read the included file COPYING for more information. | |
9 * This software comes with no warranty of any kind, use at your own risk! | |
10 */ | |
11 | |
12 #ifdef HAVE_CONFIG_H | |
13 # include "config.h" | |
14 #endif | |
15 #include "intl.h" | |
16 | |
17 #include <stdio.h> | |
18 #include <stdlib.h> | |
19 #include <string.h> | |
20 #include <sys/types.h> | |
21 #include <gtk/gtk.h> | |
22 | |
23 #include <gdk/gdkkeysyms.h> /* for keyboard values */ | |
24 | |
281 | 25 #include "main.h" |
9 | 26 #include "ui_utildlg.h" |
27 | |
232 | 28 #include "filelist.h" |
9 | 29 #include "ui_fileops.h" |
30 #include "ui_misc.h" | |
31 #include "ui_pathsel.h" | |
32 #include "ui_tabcomp.h" | |
33 | |
34 | |
35 /* | |
36 *----------------------------------------------------------------------------- | |
37 * generic dialog | |
38 *----------------------------------------------------------------------------- | |
442 | 39 */ |
9 | 40 |
41 void generic_dialog_close(GenericDialog *gd) | |
42 { | |
43 gtk_widget_destroy(gd->dialog); | |
44 g_free(gd); | |
45 } | |
46 | |
47 static void generic_dialog_click_cb(GtkWidget *widget, gpointer data) | |
48 { | |
49 GenericDialog *gd = data; | |
50 void (*func)(GenericDialog *, gpointer); | |
51 gint auto_close; | |
52 | |
53 func = g_object_get_data(G_OBJECT(widget), "dialog_function"); | |
54 auto_close = gd->auto_close; | |
55 | |
56 if (func) func(gd, gd->data); | |
57 if (auto_close) generic_dialog_close(gd); | |
58 } | |
59 | |
60 static gint generic_dialog_default_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) | |
61 { | |
62 GenericDialog *gd = data; | |
63 | |
64 if (event->keyval == GDK_Return && GTK_WIDGET_HAS_FOCUS(widget) | |
65 && gd->default_cb) | |
66 { | |
67 gint auto_close; | |
68 | |
69 auto_close = gd->auto_close; | |
70 gd->default_cb(gd, gd->data); | |
71 if (auto_close) generic_dialog_close(gd); | |
72 | |
73 return TRUE; | |
74 } | |
75 return FALSE; | |
76 } | |
77 | |
78 void generic_dialog_attach_default(GenericDialog *gd, GtkWidget *widget) | |
79 { | |
80 if (!gd || !widget) return; | |
81 g_signal_connect(G_OBJECT(widget), "key_press_event", | |
82 G_CALLBACK(generic_dialog_default_key_press_cb), gd); | |
83 } | |
84 | |
85 static gint generic_dialog_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) | |
86 { | |
87 GenericDialog *gd = data; | |
88 | |
89 if (event->keyval == GDK_Escape) | |
90 { | |
91 if (gd->cancel_cb) gd->cancel_cb(gd, gd->data); | |
92 if (gd->auto_close) generic_dialog_click_cb(widget, data); | |
93 return TRUE; | |
94 } | |
95 return FALSE; | |
96 } | |
97 | |
98 static gint generic_dialog_delete_cb(GtkWidget *w, GdkEventAny *event, gpointer data) | |
99 { | |
100 GenericDialog *gd = data; | |
101 gint auto_close; | |
102 | |
103 auto_close = gd->auto_close; | |
104 | |
105 if (gd->cancel_cb) gd->cancel_cb(gd, gd->data); | |
106 if (auto_close) generic_dialog_close(gd); | |
107 | |
108 return TRUE; | |
109 } | |
110 | |
111 static void generic_dialog_show_cb(GtkWidget *widget, gpointer data) | |
112 { | |
113 GenericDialog *gd = data; | |
114 if (gd->cancel_button) | |
442 | 115 { |
9 | 116 gtk_box_reorder_child(GTK_BOX(gd->hbox), gd->cancel_button, -1); |
117 } | |
118 | |
119 g_signal_handlers_disconnect_by_func(G_OBJECT(widget), | |
120 G_CALLBACK(generic_dialog_show_cb), gd); | |
121 } | |
122 | |
123 gint generic_dialog_get_alternative_button_order(GtkWidget *widget) | |
124 { | |
125 GtkSettings *settings; | |
126 GObjectClass *klass; | |
127 gint alternative_order = FALSE; | |
128 | |
129 settings = gtk_settings_get_for_screen(gtk_widget_get_screen(widget)); | |
130 klass = G_OBJECT_CLASS(GTK_SETTINGS_GET_CLASS(settings)); | |
131 if (g_object_class_find_property(klass, "gtk-alternative-button-order")) | |
132 { | |
133 g_object_get(settings, "gtk-alternative-button-order", &alternative_order, NULL); | |
134 } | |
135 | |
136 return alternative_order; | |
137 } | |
138 | |
139 GtkWidget *generic_dialog_add_button(GenericDialog *gd, const gchar *stock_id, const gchar *text, | |
140 void (*func_cb)(GenericDialog *, gpointer), gint is_default) | |
141 { | |
142 GtkWidget *button; | |
143 gint alternative_order; | |
144 | |
145 button = pref_button_new(NULL, stock_id, text, FALSE, | |
146 G_CALLBACK(generic_dialog_click_cb), gd); | |
147 | |
148 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); | |
149 g_object_set_data(G_OBJECT(button), "dialog_function", func_cb); | |
150 | |
151 gtk_container_add(GTK_CONTAINER(gd->hbox), button); | |
152 | |
153 alternative_order = generic_dialog_get_alternative_button_order(gd->hbox); | |
154 | |
155 if (is_default) | |
156 { | |
157 gtk_widget_grab_default(button); | |
158 gtk_widget_grab_focus(button); | |
159 gd->default_cb = func_cb; | |
160 | |
161 if (!alternative_order) gtk_box_reorder_child(GTK_BOX(gd->hbox), button, -1); | |
162 } | |
163 else | |
164 { | |
165 if (!alternative_order) gtk_box_reorder_child(GTK_BOX(gd->hbox), button, 0); | |
166 } | |
167 | |
168 gtk_widget_show(button); | |
169 | |
170 return button; | |
171 } | |
172 | |
173 GtkWidget *generic_dialog_add_message(GenericDialog *gd, const gchar *icon_stock_id, | |
174 const gchar *heading, const gchar *text) | |
175 { | |
176 GtkWidget *hbox; | |
177 GtkWidget *vbox; | |
178 GtkWidget *label; | |
179 | |
180 hbox = pref_box_new(gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE); | |
181 if (icon_stock_id) | |
182 { | |
183 GtkWidget *image; | |
184 | |
185 image = gtk_image_new_from_stock(icon_stock_id, GTK_ICON_SIZE_DIALOG); | |
186 gtk_misc_set_alignment(GTK_MISC(image), 0.5, 0.0); | |
187 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0); | |
188 gtk_widget_show(image); | |
189 } | |
190 | |
191 vbox = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE); | |
192 if (heading) | |
193 { | |
194 label = pref_label_new(vbox, heading); | |
195 pref_label_bold(label, TRUE, TRUE); | |
196 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); | |
197 } | |
198 if (text) | |
199 { | |
200 label = pref_label_new(vbox, text); | |
201 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); | |
15
3263965d5f9e
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
202 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); |
9 | 203 } |
204 | |
205 return vbox; | |
206 } | |
207 | |
208 static void generic_dialog_setup(GenericDialog *gd, | |
209 const gchar *title, | |
210 const gchar *wmclass, const gchar *wmsubclass, | |
211 GtkWidget *parent, gint auto_close, | |
212 void (*cancel_cb)(GenericDialog *, gpointer), gpointer data) | |
213 { | |
214 GtkWidget *vbox; | |
215 | |
216 gd->auto_close = auto_close; | |
217 gd->data = data; | |
218 gd->cancel_cb = cancel_cb; | |
219 | |
289
6a7298988a7a
Simplify and unify gtk_window creation with the help of
zas_
parents:
281
diff
changeset
|
220 gd->dialog = window_new(GTK_WINDOW_TOPLEVEL, wmsubclass, NULL, NULL, title); |
9 | 221 gtk_window_set_type_hint(GTK_WINDOW(gd->dialog), GDK_WINDOW_TYPE_HINT_DIALOG); |
289
6a7298988a7a
Simplify and unify gtk_window creation with the help of
zas_
parents:
281
diff
changeset
|
222 |
9 | 223 if (parent) |
224 { | |
225 GtkWindow *window = NULL; | |
226 | |
227 if (GTK_IS_WINDOW(parent)) | |
228 { | |
229 window = GTK_WINDOW(parent); | |
230 } | |
231 else | |
232 { | |
233 GtkWidget *top; | |
234 | |
235 top = gtk_widget_get_toplevel(parent); | |
236 if (GTK_IS_WINDOW(top) && GTK_WIDGET_TOPLEVEL(top)) window = GTK_WINDOW(top); | |
237 } | |
238 | |
239 if (window) gtk_window_set_transient_for(GTK_WINDOW(gd->dialog), window); | |
240 } | |
241 | |
242 g_signal_connect(G_OBJECT(gd->dialog), "delete_event", | |
243 G_CALLBACK(generic_dialog_delete_cb), gd); | |
244 g_signal_connect(G_OBJECT(gd->dialog), "key_press_event", | |
245 G_CALLBACK(generic_dialog_key_press_cb), gd); | |
246 | |
247 gtk_window_set_resizable(GTK_WINDOW(gd->dialog), TRUE); | |
248 gtk_container_set_border_width(GTK_CONTAINER(gd->dialog), PREF_PAD_BORDER); | |
249 | |
250 vbox = gtk_vbox_new(FALSE, PREF_PAD_BUTTON_SPACE); | |
251 gtk_container_add(GTK_CONTAINER(gd->dialog), vbox); | |
252 gtk_widget_show(vbox); | |
253 | |
254 gd->vbox = gtk_vbox_new(FALSE, PREF_PAD_GAP); | |
255 gtk_box_pack_start(GTK_BOX(vbox), gd->vbox, TRUE, TRUE, 0); | |
256 gtk_widget_show(gd->vbox); | |
257 | |
258 gd->hbox = gtk_hbutton_box_new(); | |
259 gtk_button_box_set_layout(GTK_BUTTON_BOX(gd->hbox), GTK_BUTTONBOX_END); | |
260 gtk_box_set_spacing(GTK_BOX(gd->hbox), PREF_PAD_BUTTON_GAP); | |
261 gtk_box_pack_start(GTK_BOX(vbox), gd->hbox, FALSE, FALSE, 0); | |
262 gtk_widget_show(gd->hbox); | |
263 | |
264 if (gd->cancel_cb) | |
442 | 265 { |
9 | 266 gd->cancel_button = generic_dialog_add_button(gd, GTK_STOCK_CANCEL, NULL, gd->cancel_cb, TRUE); |
267 } | |
268 else | |
269 { | |
270 gd->cancel_button = NULL; | |
271 } | |
272 | |
273 if (generic_dialog_get_alternative_button_order(gd->hbox)) | |
274 { | |
275 g_signal_connect(G_OBJECT(gd->dialog), "show", | |
276 G_CALLBACK(generic_dialog_show_cb), gd); | |
277 } | |
278 | |
279 gd->default_cb = NULL; | |
280 } | |
281 | |
282 GenericDialog *generic_dialog_new(const gchar *title, | |
283 const gchar *wmclass, const gchar *wmsubclass, | |
284 GtkWidget *parent, gint auto_close, | |
285 void (*cancel_cb)(GenericDialog *, gpointer), gpointer data) | |
286 { | |
287 GenericDialog *gd; | |
288 | |
289 gd = g_new0(GenericDialog, 1); | |
290 generic_dialog_setup(gd, title, wmclass, wmsubclass, | |
291 parent, auto_close, cancel_cb, data); | |
292 return gd; | |
293 } | |
294 /* | |
295 *----------------------------------------------------------------------------- | |
296 * simple warning dialog | |
297 *----------------------------------------------------------------------------- | |
442 | 298 */ |
9 | 299 |
300 static void warning_dialog_ok_cb(GenericDialog *gd, gpointer data) | |
301 { | |
302 /* no op */ | |
303 } | |
304 | |
305 GenericDialog *warning_dialog(const gchar *heading, const gchar *text, | |
306 const gchar *icon_stock_id, GtkWidget *parent) | |
307 { | |
308 GenericDialog *gd; | |
309 | |
254
9faf34f047b1
Make the wmclass value unique among the code by defining
zas_
parents:
232
diff
changeset
|
310 gd = generic_dialog_new(heading, GQ_WMCLASS, "warning", parent, TRUE, NULL, NULL); |
9 | 311 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, warning_dialog_ok_cb, TRUE); |
312 | |
313 generic_dialog_add_message(gd, icon_stock_id, heading, text); | |
314 | |
315 gtk_widget_show(gd->dialog); | |
316 | |
317 return gd; | |
318 } | |
319 | |
320 /* | |
321 *----------------------------------------------------------------------------- | |
322 * generic file ops dialog routines | |
323 *----------------------------------------------------------------------------- | |
442 | 324 */ |
9 | 325 |
138 | 326 void file_dialog_close(FileDialog *fdlg) |
9 | 327 { |
138 | 328 file_data_unref(fdlg->source_fd); |
329 g_free(fdlg->dest_path); | |
330 if (fdlg->source_list) filelist_free(fdlg->source_list); | |
9 | 331 |
138 | 332 generic_dialog_close(GENERIC_DIALOG(fdlg)); |
9 | 333 } |
334 | |
335 FileDialog *file_dialog_new(const gchar *title, | |
336 const gchar *wmclass, const gchar *wmsubclass, | |
337 GtkWidget *parent, | |
338 void (*cancel_cb)(FileDialog *, gpointer), gpointer data) | |
339 { | |
138 | 340 FileDialog *fdlg = NULL; |
9 | 341 |
138 | 342 fdlg = g_new0(FileDialog, 1); |
9 | 343 |
138 | 344 generic_dialog_setup(GENERIC_DIALOG(fdlg), title, |
9 | 345 wmclass, wmsubclass, parent, FALSE, |
346 (void *)cancel_cb, data); | |
347 | |
138 | 348 return fdlg; |
9 | 349 } |
350 | |
138 | 351 GtkWidget *file_dialog_add_button(FileDialog *fdlg, const gchar *stock_id, const gchar *text, |
9 | 352 void (*func_cb)(FileDialog *, gpointer), gint is_default) |
353 { | |
138 | 354 return generic_dialog_add_button(GENERIC_DIALOG(fdlg), stock_id, text, |
9 | 355 (void *)func_cb, is_default); |
356 } | |
357 | |
358 static void file_dialog_entry_cb(GtkWidget *widget, gpointer data) | |
359 { | |
138 | 360 FileDialog *fdlg = data; |
361 g_free(fdlg->dest_path); | |
362 fdlg->dest_path = remove_trailing_slash(gtk_entry_get_text(GTK_ENTRY(fdlg->entry))); | |
9 | 363 } |
364 | |
365 static void file_dialog_entry_enter_cb(const gchar *path, gpointer data) | |
366 { | |
367 GenericDialog *gd = data; | |
368 | |
369 file_dialog_entry_cb(NULL, data); | |
370 | |
371 if (gd->default_cb) gd->default_cb(gd, gd->data); | |
372 } | |
373 | |
138 | 374 void file_dialog_add_path_widgets(FileDialog *fdlg, const gchar *default_path, const gchar *path, |
9 | 375 const gchar *history_key, const gchar *filter, const gchar *filter_desc) |
376 { | |
377 GtkWidget *tabcomp; | |
378 GtkWidget *list; | |
379 | |
138 | 380 if (fdlg->entry) return; |
9 | 381 |
138 | 382 tabcomp = tab_completion_new_with_history(&fdlg->entry, NULL, |
383 history_key, -1, file_dialog_entry_enter_cb, fdlg); | |
384 gtk_box_pack_end(GTK_BOX(GENERIC_DIALOG(fdlg)->vbox), tabcomp, FALSE, FALSE, 0); | |
385 generic_dialog_attach_default(GENERIC_DIALOG(fdlg), fdlg->entry); | |
9 | 386 gtk_widget_show(tabcomp); |
387 | |
388 if (path && path[0] == '/') | |
389 { | |
138 | 390 fdlg->dest_path = g_strdup(path); |
9 | 391 } |
392 else | |
393 { | |
394 const gchar *base; | |
395 | |
138 | 396 base = tab_completion_set_to_last_history(fdlg->entry); |
9 | 397 |
398 if (!base) base = default_path; | |
399 if (!base) base = homedir(); | |
400 | |
401 if (path) | |
402 { | |
138 | 403 fdlg->dest_path = concat_dir_and_file(base, path); |
9 | 404 } |
405 else | |
406 { | |
138 | 407 fdlg->dest_path = g_strdup(base); |
9 | 408 } |
409 } | |
410 | |
138 | 411 list = path_selection_new_with_files(fdlg->entry, fdlg->dest_path, filter, filter_desc); |
412 path_selection_add_select_func(fdlg->entry, file_dialog_entry_enter_cb, fdlg); | |
413 gtk_box_pack_end(GTK_BOX(GENERIC_DIALOG(fdlg)->vbox), list, TRUE, TRUE, 0); | |
9 | 414 gtk_widget_show(list); |
415 | |
138 | 416 gtk_widget_grab_focus(fdlg->entry); |
417 if (fdlg->dest_path) | |
9 | 418 { |
138 | 419 gtk_entry_set_text(GTK_ENTRY(fdlg->entry), fdlg->dest_path); |
420 gtk_editable_set_position(GTK_EDITABLE(fdlg->entry), strlen(fdlg->dest_path)); | |
9 | 421 } |
422 | |
138 | 423 g_signal_connect(G_OBJECT(fdlg->entry), "changed", |
424 G_CALLBACK(file_dialog_entry_cb), fdlg); | |
9 | 425 } |
426 | |
138 | 427 void file_dialog_add_filter(FileDialog *fdlg, const gchar *filter, const gchar *filter_desc, gint set) |
9 | 428 { |
138 | 429 if (!fdlg->entry) return; |
430 path_selection_add_filter(fdlg->entry, filter, filter_desc, set); | |
9 | 431 } |
432 | |
138 | 433 void file_dialog_clear_filter(FileDialog *fdlg) |
9 | 434 { |
138 | 435 if (!fdlg->entry) return; |
436 path_selection_clear_filter(fdlg->entry); | |
9 | 437 } |
438 | |
138 | 439 void file_dialog_sync_history(FileDialog *fdlg, gint dir_only) |
9 | 440 { |
138 | 441 if (!fdlg->dest_path) return; |
9 | 442 |
443 if (!dir_only || | |
138 | 444 (dir_only && isdir(fdlg->dest_path)) ) |
9 | 445 { |
138 | 446 tab_completion_append_to_history(fdlg->entry, fdlg->dest_path); |
9 | 447 } |
448 else | |
449 { | |
138 | 450 gchar *buf = remove_level_from_path(fdlg->dest_path); |
451 tab_completion_append_to_history(fdlg->entry, buf); | |
9 | 452 g_free(buf); |
453 } | |
454 } |