Mercurial > geeqie
annotate src/ui_utildlg.c @ 196:f6e307c7bad6
rename GQview -> Geeqie over the code
author | nadvornik |
---|---|
date | Sun, 23 Mar 2008 20:38:54 +0000 |
parents | 71e1ebee420e |
children | 985a9a09c9d1 |
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 | |
138 | 25 #include "gqview.h" |
9 | 26 #include "ui_utildlg.h" |
27 | |
28 #include "ui_fileops.h" | |
29 #include "ui_misc.h" | |
30 #include "ui_pathsel.h" | |
31 #include "ui_tabcomp.h" | |
32 | |
33 | |
34 /* | |
35 *----------------------------------------------------------------------------- | |
36 * generic dialog | |
37 *----------------------------------------------------------------------------- | |
38 */ | |
39 | |
40 void generic_dialog_close(GenericDialog *gd) | |
41 { | |
42 gtk_widget_destroy(gd->dialog); | |
43 g_free(gd); | |
44 } | |
45 | |
46 static void generic_dialog_click_cb(GtkWidget *widget, gpointer data) | |
47 { | |
48 GenericDialog *gd = data; | |
49 void (*func)(GenericDialog *, gpointer); | |
50 gint auto_close; | |
51 | |
52 func = g_object_get_data(G_OBJECT(widget), "dialog_function"); | |
53 auto_close = gd->auto_close; | |
54 | |
55 if (func) func(gd, gd->data); | |
56 if (auto_close) generic_dialog_close(gd); | |
57 } | |
58 | |
59 static gint generic_dialog_default_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) | |
60 { | |
61 GenericDialog *gd = data; | |
62 | |
63 if (event->keyval == GDK_Return && GTK_WIDGET_HAS_FOCUS(widget) | |
64 && gd->default_cb) | |
65 { | |
66 gint auto_close; | |
67 | |
68 auto_close = gd->auto_close; | |
69 gd->default_cb(gd, gd->data); | |
70 if (auto_close) generic_dialog_close(gd); | |
71 | |
72 return TRUE; | |
73 } | |
74 return FALSE; | |
75 } | |
76 | |
77 void generic_dialog_attach_default(GenericDialog *gd, GtkWidget *widget) | |
78 { | |
79 if (!gd || !widget) return; | |
80 g_signal_connect(G_OBJECT(widget), "key_press_event", | |
81 G_CALLBACK(generic_dialog_default_key_press_cb), gd); | |
82 } | |
83 | |
84 static gint generic_dialog_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) | |
85 { | |
86 GenericDialog *gd = data; | |
87 | |
88 if (event->keyval == GDK_Escape) | |
89 { | |
90 if (gd->cancel_cb) gd->cancel_cb(gd, gd->data); | |
91 if (gd->auto_close) generic_dialog_click_cb(widget, data); | |
92 return TRUE; | |
93 } | |
94 return FALSE; | |
95 } | |
96 | |
97 static gint generic_dialog_delete_cb(GtkWidget *w, GdkEventAny *event, gpointer data) | |
98 { | |
99 GenericDialog *gd = data; | |
100 gint auto_close; | |
101 | |
102 auto_close = gd->auto_close; | |
103 | |
104 if (gd->cancel_cb) gd->cancel_cb(gd, gd->data); | |
105 if (auto_close) generic_dialog_close(gd); | |
106 | |
107 return TRUE; | |
108 } | |
109 | |
110 static void generic_dialog_show_cb(GtkWidget *widget, gpointer data) | |
111 { | |
112 GenericDialog *gd = data; | |
113 if (gd->cancel_button) | |
114 { | |
115 gtk_box_reorder_child(GTK_BOX(gd->hbox), gd->cancel_button, -1); | |
116 } | |
117 | |
118 g_signal_handlers_disconnect_by_func(G_OBJECT(widget), | |
119 G_CALLBACK(generic_dialog_show_cb), gd); | |
120 } | |
121 | |
122 gint generic_dialog_get_alternative_button_order(GtkWidget *widget) | |
123 { | |
124 GtkSettings *settings; | |
125 GObjectClass *klass; | |
126 gint alternative_order = FALSE; | |
127 | |
128 settings = gtk_settings_get_for_screen(gtk_widget_get_screen(widget)); | |
129 klass = G_OBJECT_CLASS(GTK_SETTINGS_GET_CLASS(settings)); | |
130 if (g_object_class_find_property(klass, "gtk-alternative-button-order")) | |
131 { | |
132 g_object_get(settings, "gtk-alternative-button-order", &alternative_order, NULL); | |
133 } | |
134 | |
135 return alternative_order; | |
136 } | |
137 | |
138 GtkWidget *generic_dialog_add_button(GenericDialog *gd, const gchar *stock_id, const gchar *text, | |
139 void (*func_cb)(GenericDialog *, gpointer), gint is_default) | |
140 { | |
141 GtkWidget *button; | |
142 gint alternative_order; | |
143 | |
144 button = pref_button_new(NULL, stock_id, text, FALSE, | |
145 G_CALLBACK(generic_dialog_click_cb), gd); | |
146 | |
147 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); | |
148 g_object_set_data(G_OBJECT(button), "dialog_function", func_cb); | |
149 | |
150 gtk_container_add(GTK_CONTAINER(gd->hbox), button); | |
151 | |
152 alternative_order = generic_dialog_get_alternative_button_order(gd->hbox); | |
153 | |
154 if (is_default) | |
155 { | |
156 gtk_widget_grab_default(button); | |
157 gtk_widget_grab_focus(button); | |
158 gd->default_cb = func_cb; | |
159 | |
160 if (!alternative_order) gtk_box_reorder_child(GTK_BOX(gd->hbox), button, -1); | |
161 } | |
162 else | |
163 { | |
164 if (!alternative_order) gtk_box_reorder_child(GTK_BOX(gd->hbox), button, 0); | |
165 } | |
166 | |
167 gtk_widget_show(button); | |
168 | |
169 return button; | |
170 } | |
171 | |
172 GtkWidget *generic_dialog_add_message(GenericDialog *gd, const gchar *icon_stock_id, | |
173 const gchar *heading, const gchar *text) | |
174 { | |
175 GtkWidget *hbox; | |
176 GtkWidget *vbox; | |
177 GtkWidget *label; | |
178 | |
179 hbox = pref_box_new(gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE); | |
180 if (icon_stock_id) | |
181 { | |
182 GtkWidget *image; | |
183 | |
184 image = gtk_image_new_from_stock(icon_stock_id, GTK_ICON_SIZE_DIALOG); | |
185 gtk_misc_set_alignment(GTK_MISC(image), 0.5, 0.0); | |
186 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0); | |
187 gtk_widget_show(image); | |
188 } | |
189 | |
190 vbox = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE); | |
191 if (heading) | |
192 { | |
193 label = pref_label_new(vbox, heading); | |
194 pref_label_bold(label, TRUE, TRUE); | |
195 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); | |
196 } | |
197 if (text) | |
198 { | |
199 label = pref_label_new(vbox, text); | |
200 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
|
201 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); |
9 | 202 } |
203 | |
204 return vbox; | |
205 } | |
206 | |
207 static void generic_dialog_setup(GenericDialog *gd, | |
208 const gchar *title, | |
209 const gchar *wmclass, const gchar *wmsubclass, | |
210 GtkWidget *parent, gint auto_close, | |
211 void (*cancel_cb)(GenericDialog *, gpointer), gpointer data) | |
212 { | |
213 GtkWidget *vbox; | |
214 | |
215 gd->auto_close = auto_close; | |
216 gd->data = data; | |
217 gd->cancel_cb = cancel_cb; | |
218 | |
219 gd->dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
220 gtk_window_set_type_hint(GTK_WINDOW(gd->dialog), GDK_WINDOW_TYPE_HINT_DIALOG); | |
221 gtk_window_set_wmclass(GTK_WINDOW(gd->dialog), wmsubclass, wmclass); | |
222 if (parent) | |
223 { | |
224 GtkWindow *window = NULL; | |
225 | |
226 if (GTK_IS_WINDOW(parent)) | |
227 { | |
228 window = GTK_WINDOW(parent); | |
229 } | |
230 else | |
231 { | |
232 GtkWidget *top; | |
233 | |
234 top = gtk_widget_get_toplevel(parent); | |
235 if (GTK_IS_WINDOW(top) && GTK_WIDGET_TOPLEVEL(top)) window = GTK_WINDOW(top); | |
236 } | |
237 | |
238 if (window) gtk_window_set_transient_for(GTK_WINDOW(gd->dialog), window); | |
239 } | |
240 | |
241 g_signal_connect(G_OBJECT(gd->dialog), "delete_event", | |
242 G_CALLBACK(generic_dialog_delete_cb), gd); | |
243 g_signal_connect(G_OBJECT(gd->dialog), "key_press_event", | |
244 G_CALLBACK(generic_dialog_key_press_cb), gd); | |
245 | |
246 gtk_window_set_resizable(GTK_WINDOW(gd->dialog), TRUE); | |
247 gtk_window_set_title(GTK_WINDOW (gd->dialog), title); | |
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) | |
265 { | |
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 *----------------------------------------------------------------------------- | |
298 */ | |
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 | |
310 gd = generic_dialog_new(heading, PACKAGE, "warning", parent, TRUE, NULL, NULL); | |
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 *----------------------------------------------------------------------------- | |
324 */ | |
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 } | |
455 | |
456 |