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