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