Mercurial > geeqie
comparison src/ui_utildlg.c @ 9:d907d608745f
Sync to GQview 1.5.9 release.
########
DO NOT BASE ENHANCEMENTS OR TRANSLATION UPDATES ON CODE IN THIS CVS!
This CVS is never up to date with current development and is provided
solely for reference purposes, please use the latest official release
package when making any changes or translation updates.
########
author | gqview |
---|---|
date | Sat, 26 Feb 2005 00:13:35 +0000 |
parents | |
children | 3263965d5f9e |
comparison
equal
deleted
inserted
replaced
8:e0d0593d519e | 9:d907d608745f |
---|---|
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 | |
25 #include "ui_utildlg.h" | |
26 | |
27 #include "ui_fileops.h" | |
28 #include "ui_misc.h" | |
29 #include "ui_pathsel.h" | |
30 #include "ui_tabcomp.h" | |
31 | |
32 | |
33 /* | |
34 *----------------------------------------------------------------------------- | |
35 * generic dialog | |
36 *----------------------------------------------------------------------------- | |
37 */ | |
38 | |
39 void generic_dialog_close(GenericDialog *gd) | |
40 { | |
41 gtk_widget_destroy(gd->dialog); | |
42 g_free(gd); | |
43 } | |
44 | |
45 static void generic_dialog_click_cb(GtkWidget *widget, gpointer data) | |
46 { | |
47 GenericDialog *gd = data; | |
48 void (*func)(GenericDialog *, gpointer); | |
49 gint auto_close; | |
50 | |
51 func = g_object_get_data(G_OBJECT(widget), "dialog_function"); | |
52 auto_close = gd->auto_close; | |
53 | |
54 if (func) func(gd, gd->data); | |
55 if (auto_close) generic_dialog_close(gd); | |
56 } | |
57 | |
58 static gint generic_dialog_default_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) | |
59 { | |
60 GenericDialog *gd = data; | |
61 | |
62 if (event->keyval == GDK_Return && GTK_WIDGET_HAS_FOCUS(widget) | |
63 && gd->default_cb) | |
64 { | |
65 gint auto_close; | |
66 | |
67 auto_close = gd->auto_close; | |
68 gd->default_cb(gd, gd->data); | |
69 if (auto_close) generic_dialog_close(gd); | |
70 | |
71 return TRUE; | |
72 } | |
73 return FALSE; | |
74 } | |
75 | |
76 void generic_dialog_attach_default(GenericDialog *gd, GtkWidget *widget) | |
77 { | |
78 if (!gd || !widget) return; | |
79 g_signal_connect(G_OBJECT(widget), "key_press_event", | |
80 G_CALLBACK(generic_dialog_default_key_press_cb), gd); | |
81 } | |
82 | |
83 static gint generic_dialog_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) | |
84 { | |
85 GenericDialog *gd = data; | |
86 | |
87 if (event->keyval == GDK_Escape) | |
88 { | |
89 if (gd->cancel_cb) gd->cancel_cb(gd, gd->data); | |
90 if (gd->auto_close) generic_dialog_click_cb(widget, data); | |
91 return TRUE; | |
92 } | |
93 return FALSE; | |
94 } | |
95 | |
96 static gint generic_dialog_delete_cb(GtkWidget *w, GdkEventAny *event, gpointer data) | |
97 { | |
98 GenericDialog *gd = data; | |
99 gint auto_close; | |
100 | |
101 auto_close = gd->auto_close; | |
102 | |
103 if (gd->cancel_cb) gd->cancel_cb(gd, gd->data); | |
104 if (auto_close) generic_dialog_close(gd); | |
105 | |
106 return TRUE; | |
107 } | |
108 | |
109 static void generic_dialog_show_cb(GtkWidget *widget, gpointer data) | |
110 { | |
111 GenericDialog *gd = data; | |
112 if (gd->cancel_button) | |
113 { | |
114 gtk_box_reorder_child(GTK_BOX(gd->hbox), gd->cancel_button, -1); | |
115 } | |
116 | |
117 g_signal_handlers_disconnect_by_func(G_OBJECT(widget), | |
118 G_CALLBACK(generic_dialog_show_cb), gd); | |
119 } | |
120 | |
121 gint generic_dialog_get_alternative_button_order(GtkWidget *widget) | |
122 { | |
123 GtkSettings *settings; | |
124 GObjectClass *klass; | |
125 gint alternative_order = FALSE; | |
126 | |
127 settings = gtk_settings_get_for_screen(gtk_widget_get_screen(widget)); | |
128 klass = G_OBJECT_CLASS(GTK_SETTINGS_GET_CLASS(settings)); | |
129 if (g_object_class_find_property(klass, "gtk-alternative-button-order")) | |
130 { | |
131 g_object_get(settings, "gtk-alternative-button-order", &alternative_order, NULL); | |
132 } | |
133 | |
134 return alternative_order; | |
135 } | |
136 | |
137 GtkWidget *generic_dialog_add_button(GenericDialog *gd, const gchar *stock_id, const gchar *text, | |
138 void (*func_cb)(GenericDialog *, gpointer), gint is_default) | |
139 { | |
140 GtkWidget *button; | |
141 gint alternative_order; | |
142 | |
143 button = pref_button_new(NULL, stock_id, text, FALSE, | |
144 G_CALLBACK(generic_dialog_click_cb), gd); | |
145 | |
146 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); | |
147 g_object_set_data(G_OBJECT(button), "dialog_function", func_cb); | |
148 | |
149 gtk_container_add(GTK_CONTAINER(gd->hbox), button); | |
150 | |
151 alternative_order = generic_dialog_get_alternative_button_order(gd->hbox); | |
152 | |
153 if (is_default) | |
154 { | |
155 gtk_widget_grab_default(button); | |
156 gtk_widget_grab_focus(button); | |
157 gd->default_cb = func_cb; | |
158 | |
159 if (!alternative_order) gtk_box_reorder_child(GTK_BOX(gd->hbox), button, -1); | |
160 } | |
161 else | |
162 { | |
163 if (!alternative_order) gtk_box_reorder_child(GTK_BOX(gd->hbox), button, 0); | |
164 } | |
165 | |
166 gtk_widget_show(button); | |
167 | |
168 return button; | |
169 } | |
170 | |
171 GtkWidget *generic_dialog_add_message(GenericDialog *gd, const gchar *icon_stock_id, | |
172 const gchar *heading, const gchar *text) | |
173 { | |
174 GtkWidget *hbox; | |
175 GtkWidget *vbox; | |
176 GtkWidget *label; | |
177 | |
178 hbox = pref_box_new(gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE); | |
179 if (icon_stock_id) | |
180 { | |
181 GtkWidget *image; | |
182 | |
183 image = gtk_image_new_from_stock(icon_stock_id, GTK_ICON_SIZE_DIALOG); | |
184 gtk_misc_set_alignment(GTK_MISC(image), 0.5, 0.0); | |
185 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0); | |
186 gtk_widget_show(image); | |
187 } | |
188 | |
189 vbox = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE); | |
190 if (heading) | |
191 { | |
192 label = pref_label_new(vbox, heading); | |
193 pref_label_bold(label, TRUE, TRUE); | |
194 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); | |
195 } | |
196 if (text) | |
197 { | |
198 label = pref_label_new(vbox, text); | |
199 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); | |
200 } | |
201 | |
202 return vbox; | |
203 } | |
204 | |
205 static void generic_dialog_setup(GenericDialog *gd, | |
206 const gchar *title, | |
207 const gchar *wmclass, const gchar *wmsubclass, | |
208 GtkWidget *parent, gint auto_close, | |
209 void (*cancel_cb)(GenericDialog *, gpointer), gpointer data) | |
210 { | |
211 GtkWidget *vbox; | |
212 | |
213 gd->auto_close = auto_close; | |
214 gd->data = data; | |
215 gd->cancel_cb = cancel_cb; | |
216 | |
217 gd->dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
218 gtk_window_set_type_hint(GTK_WINDOW(gd->dialog), GDK_WINDOW_TYPE_HINT_DIALOG); | |
219 gtk_window_set_wmclass(GTK_WINDOW(gd->dialog), wmsubclass, wmclass); | |
220 if (parent) | |
221 { | |
222 GtkWindow *window = NULL; | |
223 | |
224 if (GTK_IS_WINDOW(parent)) | |
225 { | |
226 window = GTK_WINDOW(parent); | |
227 } | |
228 else | |
229 { | |
230 GtkWidget *top; | |
231 | |
232 top = gtk_widget_get_toplevel(parent); | |
233 if (GTK_IS_WINDOW(top) && GTK_WIDGET_TOPLEVEL(top)) window = GTK_WINDOW(top); | |
234 } | |
235 | |
236 if (window) gtk_window_set_transient_for(GTK_WINDOW(gd->dialog), window); | |
237 } | |
238 | |
239 g_signal_connect(G_OBJECT(gd->dialog), "delete_event", | |
240 G_CALLBACK(generic_dialog_delete_cb), gd); | |
241 g_signal_connect(G_OBJECT(gd->dialog), "key_press_event", | |
242 G_CALLBACK(generic_dialog_key_press_cb), gd); | |
243 | |
244 gtk_window_set_resizable(GTK_WINDOW(gd->dialog), TRUE); | |
245 gtk_window_set_title(GTK_WINDOW (gd->dialog), title); | |
246 gtk_container_set_border_width(GTK_CONTAINER(gd->dialog), PREF_PAD_BORDER); | |
247 | |
248 vbox = gtk_vbox_new(FALSE, PREF_PAD_BUTTON_SPACE); | |
249 gtk_container_add(GTK_CONTAINER(gd->dialog), vbox); | |
250 gtk_widget_show(vbox); | |
251 | |
252 gd->vbox = gtk_vbox_new(FALSE, PREF_PAD_GAP); | |
253 gtk_box_pack_start(GTK_BOX(vbox), gd->vbox, TRUE, TRUE, 0); | |
254 gtk_widget_show(gd->vbox); | |
255 | |
256 gd->hbox = gtk_hbutton_box_new(); | |
257 gtk_button_box_set_layout(GTK_BUTTON_BOX(gd->hbox), GTK_BUTTONBOX_END); | |
258 gtk_box_set_spacing(GTK_BOX(gd->hbox), PREF_PAD_BUTTON_GAP); | |
259 gtk_box_pack_start(GTK_BOX(vbox), gd->hbox, FALSE, FALSE, 0); | |
260 gtk_widget_show(gd->hbox); | |
261 | |
262 if (gd->cancel_cb) | |
263 { | |
264 gd->cancel_button = generic_dialog_add_button(gd, GTK_STOCK_CANCEL, NULL, gd->cancel_cb, TRUE); | |
265 } | |
266 else | |
267 { | |
268 gd->cancel_button = NULL; | |
269 } | |
270 | |
271 if (generic_dialog_get_alternative_button_order(gd->hbox)) | |
272 { | |
273 g_signal_connect(G_OBJECT(gd->dialog), "show", | |
274 G_CALLBACK(generic_dialog_show_cb), gd); | |
275 } | |
276 | |
277 gd->default_cb = NULL; | |
278 } | |
279 | |
280 GenericDialog *generic_dialog_new(const gchar *title, | |
281 const gchar *wmclass, const gchar *wmsubclass, | |
282 GtkWidget *parent, gint auto_close, | |
283 void (*cancel_cb)(GenericDialog *, gpointer), gpointer data) | |
284 { | |
285 GenericDialog *gd; | |
286 | |
287 gd = g_new0(GenericDialog, 1); | |
288 generic_dialog_setup(gd, title, wmclass, wmsubclass, | |
289 parent, auto_close, cancel_cb, data); | |
290 return gd; | |
291 } | |
292 /* | |
293 *----------------------------------------------------------------------------- | |
294 * simple warning dialog | |
295 *----------------------------------------------------------------------------- | |
296 */ | |
297 | |
298 static void warning_dialog_ok_cb(GenericDialog *gd, gpointer data) | |
299 { | |
300 /* no op */ | |
301 } | |
302 | |
303 GenericDialog *warning_dialog(const gchar *heading, const gchar *text, | |
304 const gchar *icon_stock_id, GtkWidget *parent) | |
305 { | |
306 GenericDialog *gd; | |
307 | |
308 gd = generic_dialog_new(heading, PACKAGE, "warning", parent, TRUE, NULL, NULL); | |
309 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, warning_dialog_ok_cb, TRUE); | |
310 | |
311 generic_dialog_add_message(gd, icon_stock_id, heading, text); | |
312 | |
313 gtk_widget_show(gd->dialog); | |
314 | |
315 return gd; | |
316 } | |
317 | |
318 /* | |
319 *----------------------------------------------------------------------------- | |
320 * generic file ops dialog routines | |
321 *----------------------------------------------------------------------------- | |
322 */ | |
323 | |
324 void file_dialog_close(FileDialog *fd) | |
325 { | |
326 g_free(fd->source_path); | |
327 g_free(fd->dest_path); | |
328 if (fd->source_list) path_list_free(fd->source_list); | |
329 | |
330 generic_dialog_close(GENERIC_DIALOG(fd)); | |
331 } | |
332 | |
333 FileDialog *file_dialog_new(const gchar *title, | |
334 const gchar *wmclass, const gchar *wmsubclass, | |
335 GtkWidget *parent, | |
336 void (*cancel_cb)(FileDialog *, gpointer), gpointer data) | |
337 { | |
338 FileDialog *fd = NULL; | |
339 | |
340 fd = g_new0(FileDialog, 1); | |
341 | |
342 generic_dialog_setup(GENERIC_DIALOG(fd), title, | |
343 wmclass, wmsubclass, parent, FALSE, | |
344 (void *)cancel_cb, data); | |
345 | |
346 return fd; | |
347 } | |
348 | |
349 GtkWidget *file_dialog_add_button(FileDialog *fd, const gchar *stock_id, const gchar *text, | |
350 void (*func_cb)(FileDialog *, gpointer), gint is_default) | |
351 { | |
352 return generic_dialog_add_button(GENERIC_DIALOG(fd), stock_id, text, | |
353 (void *)func_cb, is_default); | |
354 } | |
355 | |
356 static void file_dialog_entry_cb(GtkWidget *widget, gpointer data) | |
357 { | |
358 FileDialog *fd = data; | |
359 g_free(fd->dest_path); | |
360 fd->dest_path = remove_trailing_slash(gtk_entry_get_text(GTK_ENTRY(fd->entry))); | |
361 } | |
362 | |
363 static void file_dialog_entry_enter_cb(const gchar *path, gpointer data) | |
364 { | |
365 GenericDialog *gd = data; | |
366 | |
367 file_dialog_entry_cb(NULL, data); | |
368 | |
369 if (gd->default_cb) gd->default_cb(gd, gd->data); | |
370 } | |
371 | |
372 void file_dialog_add_path_widgets(FileDialog *fd, const gchar *default_path, const gchar *path, | |
373 const gchar *history_key, const gchar *filter, const gchar *filter_desc) | |
374 { | |
375 GtkWidget *tabcomp; | |
376 GtkWidget *list; | |
377 | |
378 if (fd->entry) return; | |
379 | |
380 tabcomp = tab_completion_new_with_history(&fd->entry, NULL, | |
381 history_key, -1, file_dialog_entry_enter_cb, fd); | |
382 gtk_box_pack_end(GTK_BOX(GENERIC_DIALOG(fd)->vbox), tabcomp, FALSE, FALSE, 0); | |
383 generic_dialog_attach_default(GENERIC_DIALOG(fd), fd->entry); | |
384 gtk_widget_show(tabcomp); | |
385 | |
386 if (path && path[0] == '/') | |
387 { | |
388 fd->dest_path = g_strdup(path); | |
389 } | |
390 else | |
391 { | |
392 const gchar *base; | |
393 | |
394 base = tab_completion_set_to_last_history(fd->entry); | |
395 | |
396 if (!base) base = default_path; | |
397 if (!base) base = homedir(); | |
398 | |
399 if (path) | |
400 { | |
401 fd->dest_path = concat_dir_and_file(base, path); | |
402 } | |
403 else | |
404 { | |
405 fd->dest_path = g_strdup(base); | |
406 } | |
407 } | |
408 | |
409 list = path_selection_new_with_files(fd->entry, fd->dest_path, filter, filter_desc); | |
410 path_selection_add_select_func(fd->entry, file_dialog_entry_enter_cb, fd); | |
411 gtk_box_pack_end(GTK_BOX(GENERIC_DIALOG(fd)->vbox), list, TRUE, TRUE, 0); | |
412 gtk_widget_show(list); | |
413 | |
414 gtk_widget_grab_focus(fd->entry); | |
415 if (fd->dest_path) | |
416 { | |
417 gtk_entry_set_text(GTK_ENTRY(fd->entry), fd->dest_path); | |
418 gtk_editable_set_position(GTK_EDITABLE(fd->entry), strlen(fd->dest_path)); | |
419 } | |
420 | |
421 g_signal_connect(G_OBJECT(fd->entry), "changed", | |
422 G_CALLBACK(file_dialog_entry_cb), fd); | |
423 } | |
424 | |
425 void file_dialog_add_filter(FileDialog *fd, const gchar *filter, const gchar *filter_desc, gint set) | |
426 { | |
427 if (!fd->entry) return; | |
428 path_selection_add_filter(fd->entry, filter, filter_desc, set); | |
429 } | |
430 | |
431 void file_dialog_clear_filter(FileDialog *fd) | |
432 { | |
433 if (!fd->entry) return; | |
434 path_selection_clear_filter(fd->entry); | |
435 } | |
436 | |
437 void file_dialog_sync_history(FileDialog *fd, gint dir_only) | |
438 { | |
439 if (!fd->dest_path) return; | |
440 | |
441 if (!dir_only || | |
442 (dir_only && isdir(fd->dest_path)) ) | |
443 { | |
444 tab_completion_append_to_history(fd->entry, fd->dest_path); | |
445 } | |
446 else | |
447 { | |
448 gchar *buf = remove_level_from_path(fd->dest_path); | |
449 tab_completion_append_to_history(fd->entry, buf); | |
450 g_free(buf); | |
451 } | |
452 } | |
453 | |
454 |