r496: Many internal changes to the Options system.
[rox-filer.git] / ROX-Filer / src / toolbar.c
blobfa4a3d1b33613c30c5d2e9bf3d62e3a3e5649462
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@users.sourceforge.net>.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* toolbar.c - for the button bars that go along the tops of windows */
24 #include "config.h"
26 #include <string.h>
28 #include "global.h"
30 #include "toolbar.h"
31 #include "options.h"
32 #include "support.h"
33 #include "main.h"
34 #include "menu.h"
35 #include "dnd.h"
36 #include "filer.h"
37 #include "pixmaps.h"
38 #include "bind.h"
40 typedef struct _Tool Tool;
42 typedef enum {DROP_NONE, DROP_TO_PARENT, DROP_TO_HOME} DropDest;
44 struct _Tool {
45 guchar *label;
46 guchar *name;
47 guchar *tip; /* Tooltip */
48 void (*clicked)(GtkWidget *w, FilerWindow *filer_window);
49 DropDest drop_action;
50 gboolean enabled;
51 MaskedPixmap *icon;
52 GtkWidget **menu; /* Right-click menu widget addr */
55 ToolbarType o_toolbar = TOOLBAR_NORMAL;
57 static GtkTooltips *tooltips = NULL;
59 /* TRUE if the button presses (or released) should open a new window,
60 * rather than reusing the existing one.
62 #define NEW_WIN_BUTTON(button_event) \
63 (o_new_window_on_1 ? ((GdkEventButton *) button_event)->button == 1 \
64 : ((GdkEventButton *) button_event)->button != 1)
66 /* Static prototypes */
67 static void toolbar_close_clicked(GtkWidget *widget, FilerWindow *filer_window);
68 static void toolbar_up_clicked(GtkWidget *widget, FilerWindow *filer_window);
69 static void toolbar_home_clicked(GtkWidget *widget, FilerWindow *filer_window);
70 static void toolbar_help_clicked(GtkWidget *widget, FilerWindow *filer_window);
71 static void toolbar_refresh_clicked(GtkWidget *widget,
72 FilerWindow *filer_window);
73 static void toolbar_large_clicked(GtkWidget *widget, FilerWindow *filer_window);
74 static void toolbar_small_clicked(GtkWidget *widget, FilerWindow *filer_window);
75 static GtkWidget *add_button(GtkWidget *box, Tool *tool,
76 FilerWindow *filer_window);
77 static GtkWidget *create_toolbar(FilerWindow *filer_window);
78 static gboolean drag_motion(GtkWidget *widget,
79 GdkDragContext *context,
80 gint x,
81 gint y,
82 guint time,
83 FilerWindow *filer_window);
84 static void drag_leave(GtkWidget *widget,
85 GdkDragContext *context,
86 guint32 time,
87 FilerWindow *filer_window);
88 static void handle_drops(FilerWindow *filer_window,
89 GtkWidget *button,
90 DropDest dest);
91 static void recreate_toolbar(FilerWindow *filer_window);
92 static void toggle_shaded(GtkWidget *widget);
93 static void option_notify(void);
95 static Tool all_tools[] = {
96 {N_("Close"), "close", N_("Close filer window"),
97 toolbar_close_clicked, DROP_NONE, FALSE,
98 NULL, NULL},
100 {N_("Up"), "up", N_("Change to parent directory"),
101 toolbar_up_clicked, DROP_TO_PARENT, TRUE,
102 NULL, NULL},
104 {N_("Home"), "home", N_("Change to home directory"),
105 toolbar_home_clicked, DROP_TO_HOME, TRUE,
106 NULL, NULL},
108 {N_("Scan"), "refresh", N_("Rescan directory contents"),
109 toolbar_refresh_clicked, DROP_NONE, TRUE,
110 NULL, NULL},
112 {N_("Large"), "large", N_("Display using large icons"),
113 toolbar_large_clicked, DROP_NONE, TRUE,
114 NULL, &display_large_menu},
116 {N_("Small"), "small", N_("Display using small icons"),
117 toolbar_small_clicked, DROP_NONE, TRUE,
118 NULL, &display_small_menu},
120 {N_("Help"), "help", N_("Show ROX-Filer help"),
121 toolbar_help_clicked, DROP_NONE, TRUE,
122 NULL, NULL},
126 /****************************************************************
127 * EXTERNAL INTERFACE *
128 ****************************************************************/
130 void toolbar_init(void)
132 int i;
134 option_add_int("toolbar_type", o_toolbar, NULL);
135 option_add_string("toolbar_disable", "close", NULL);
136 option_add_notify(option_notify);
138 tooltips = gtk_tooltips_new();
140 for (i = 0; i < sizeof(all_tools) / sizeof(*all_tools); i++)
142 Tool *tool = &all_tools[i];
144 if (!tool->icon)
146 guchar *path;
148 path = g_strconcat("pixmaps/",
149 tool->name, ".xpm", NULL);
150 tool->icon = load_pixmap(path);
151 g_free(path);
156 /* Returns a button which can be used to turn a tool on and off.
157 * Button has 'tool_name' set to the tool's name.
158 * NULL if tool number i is too big.
160 GtkWidget *toolbar_tool_option(int i)
162 Tool *tool = &all_tools[i];
163 GtkWidget *button;
164 GtkWidget *icon_widget, *vbox, *text;
166 g_return_val_if_fail(i >= 0, NULL);
168 if (i >= sizeof(all_tools) / sizeof(*all_tools))
169 return NULL;
171 button = gtk_button_new();
172 GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS);
173 gtk_tooltips_set_tip(tooltips, button, _(tool->tip), NULL);
175 icon_widget = gtk_pixmap_new(tool->icon->pixmap,
176 tool->icon->mask);
178 vbox = gtk_vbox_new(FALSE, 0);
179 gtk_box_pack_start(GTK_BOX(vbox), icon_widget, TRUE, TRUE, 0);
181 text = gtk_label_new(_(tool->label));
182 gtk_box_pack_start(GTK_BOX(vbox), text, FALSE, TRUE, 0);
184 gtk_container_add(GTK_CONTAINER(button), vbox);
186 gtk_container_set_border_width(GTK_CONTAINER(button), 1);
187 gtk_misc_set_padding(GTK_MISC(icon_widget), 16, 1);
189 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
190 GTK_SIGNAL_FUNC(toggle_shaded), GTK_OBJECT(vbox));
192 gtk_object_set_data(GTK_OBJECT(button), "tool_name", tool->name);
194 return button;
197 /* Create a new toolbar widget, suitable for adding to a filer window,
198 * and return it.
200 GtkWidget *toolbar_new(FilerWindow *filer_window)
202 g_return_val_if_fail(filer_window != NULL, NULL);
203 g_return_val_if_fail(o_toolbar != TOOLBAR_NONE, NULL);
205 return create_toolbar(filer_window);
209 /****************************************************************
210 * INTERNAL FUNCTIONS *
211 ****************************************************************/
213 static void toolbar_help_clicked(GtkWidget *widget, FilerWindow *filer_window)
215 filer_opendir(make_path(app_dir, "Help")->str);
218 static void toolbar_refresh_clicked(GtkWidget *widget,
219 FilerWindow *filer_window)
221 GdkEvent *event;
223 event = gtk_get_current_event();
224 if (event->type == GDK_BUTTON_RELEASE &&
225 ((GdkEventButton *) event)->button != 1)
227 filer_opendir(filer_window->path);
229 else
231 full_refresh();
232 filer_update_dir(filer_window, TRUE);
236 static void toolbar_home_clicked(GtkWidget *widget, FilerWindow *filer_window)
238 GdkEvent *event;
240 event = gtk_get_current_event();
241 if (event->type == GDK_BUTTON_RELEASE && NEW_WIN_BUTTON(event))
243 filer_opendir(home_dir);
245 else
246 filer_change_to(filer_window, home_dir, NULL);
249 static void toolbar_close_clicked(GtkWidget *widget, FilerWindow *filer_window)
251 GdkEvent *event;
253 g_return_if_fail(filer_window != NULL);
255 event = gtk_get_current_event();
256 if (event->type == GDK_BUTTON_RELEASE &&
257 ((GdkEventButton *) event)->button != 1)
259 filer_opendir(filer_window->path);
261 else
262 gtk_widget_destroy(filer_window->window);
265 static void toolbar_up_clicked(GtkWidget *widget, FilerWindow *filer_window)
267 GdkEvent *event;
269 event = gtk_get_current_event();
270 if (event->type == GDK_BUTTON_RELEASE && NEW_WIN_BUTTON(event))
272 filer_open_parent(filer_window);
274 else
275 change_to_parent(filer_window);
278 static void toolbar_large_clicked(GtkWidget *widget, FilerWindow *filer_window)
280 display_set_layout(filer_window, LARGE_ICONS, DETAILS_NONE);
283 static void toolbar_small_clicked(GtkWidget *widget, FilerWindow *filer_window)
285 display_set_layout(filer_window, SMALL_ICONS, DETAILS_NONE);
288 static GtkWidget *create_toolbar(FilerWindow *filer_window)
290 GtkWidget *box;
291 GtkWidget *b;
292 int i;
294 box = gtk_hbox_new(FALSE, 0);
296 for (i = 0; i < sizeof(all_tools) / sizeof(*all_tools); i++)
298 Tool *tool = &all_tools[i];
300 if (!tool->enabled)
301 continue;
303 b = add_button(box, tool, filer_window);
304 if (tool->drop_action != DROP_NONE)
305 handle_drops(filer_window, b, tool->drop_action);
308 filer_window->toolbar_text = gtk_label_new("");
309 gtk_box_pack_start(GTK_BOX(box), filer_window->toolbar_text,
310 TRUE, TRUE, 4);
312 return box;
315 /* This is used to simulate a click when button 3 is used (GtkButton
316 * normally ignores this).
318 static gint toolbar_other_button = 0;
319 static gint toolbar_adjust_pressed(GtkButton *button,
320 GdkEventButton *event,
321 FilerWindow *filer_window)
323 gint b = event->button;
325 if ((b == 2 || b == 3) && toolbar_other_button == 0)
327 toolbar_other_button = event->button;
328 gtk_grab_add(GTK_WIDGET(button));
329 gtk_button_pressed(button);
332 return TRUE;
335 static gint toolbar_adjust_released(GtkButton *button,
336 GdkEventButton *event,
337 FilerWindow *filer_window)
339 if (event->button == toolbar_other_button)
341 toolbar_other_button = 0;
342 gtk_grab_remove(GTK_WIDGET(button));
343 gtk_button_released(button);
346 return TRUE;
349 static gint menu_pressed(GtkWidget *button,
350 GdkEventButton *event,
351 FilerWindow *filer_window)
353 GtkWidget *menu;
355 if (event->button != 3 && event->button != 2)
356 return FALSE;
358 menu = gtk_object_get_data(GTK_OBJECT(button), "popup_menu");
359 g_return_val_if_fail(menu != NULL, TRUE);
361 show_style_menu(filer_window, event, menu);
363 return TRUE;
366 static GtkWidget *add_button(GtkWidget *box, Tool *tool,
367 FilerWindow *filer_window)
369 GtkWidget *button, *icon_widget;
370 GtkSignalFunc cb = GTK_SIGNAL_FUNC(tool->clicked);
372 button = gtk_button_new();
373 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
374 GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS);
376 if (tool->menu)
378 gtk_object_set_data(GTK_OBJECT(button), "popup_menu",
379 *tool->menu);
380 gtk_signal_connect(GTK_OBJECT(button), "button_press_event",
381 GTK_SIGNAL_FUNC(menu_pressed), filer_window);
383 else
385 gtk_signal_connect(GTK_OBJECT(button), "button_press_event",
386 GTK_SIGNAL_FUNC(toolbar_adjust_pressed), filer_window);
387 gtk_signal_connect(GTK_OBJECT(button), "button_release_event",
388 GTK_SIGNAL_FUNC(toolbar_adjust_released), filer_window);
391 gtk_signal_connect(GTK_OBJECT(button), "clicked",
392 cb, filer_window);
394 gtk_tooltips_set_tip(tooltips, button, _(tool->tip), NULL);
396 icon_widget = gtk_pixmap_new(tool->icon->pixmap, tool->icon->mask);
398 if (o_toolbar == TOOLBAR_LARGE)
400 GtkWidget *vbox, *text;
402 vbox = gtk_vbox_new(FALSE, 0);
403 gtk_box_pack_start(GTK_BOX(vbox), icon_widget, TRUE, TRUE, 0);
405 text = gtk_label_new(_(tool->label));
406 gtk_box_pack_start(GTK_BOX(vbox), text, FALSE, TRUE, 0);
408 gtk_container_add(GTK_CONTAINER(button), vbox);
410 else
411 gtk_container_add(GTK_CONTAINER(button), icon_widget);
413 gtk_container_set_border_width(GTK_CONTAINER(button), 1);
414 gtk_misc_set_padding(GTK_MISC(icon_widget),
415 o_toolbar == TOOLBAR_LARGE ? 16 : 8, 1);
416 gtk_box_pack_start(GTK_BOX(box), button, FALSE, TRUE, 0);
418 return button;
421 static void toggle_shaded(GtkWidget *widget)
423 gtk_widget_set_sensitive(widget, !GTK_WIDGET_SENSITIVE(widget));
426 /* Called during the drag when the mouse is in a widget registered
427 * as a drop target. Returns TRUE if we can accept the drop.
429 static gboolean drag_motion(GtkWidget *widget,
430 GdkDragContext *context,
431 gint x,
432 gint y,
433 guint time,
434 FilerWindow *filer_window)
436 GdkDragAction action = context->suggested_action;
437 DropDest dest;
439 dest = (DropDest) gtk_object_get_data(GTK_OBJECT(widget),
440 "toolbar_dest");
442 if (dest == DROP_TO_HOME)
443 g_dataset_set_data(context, "drop_dest_path", home_dir);
444 else
446 guchar *slash, *path;
448 slash = strrchr(filer_window->path, '/');
449 if (slash == NULL || slash == filer_window->path)
450 path = g_strdup("/");
451 else
452 path = g_strndup(filer_window->path,
453 slash - filer_window->path);
454 g_dataset_set_data_full(context, "drop_dest_path",
455 path, g_free);
458 g_dataset_set_data(context, "drop_dest_type", drop_dest_dir);
459 gdk_drag_status(context, action, time);
461 dnd_spring_load(context);
462 gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NORMAL);
464 return TRUE;
467 static void drag_leave(GtkWidget *widget,
468 GdkDragContext *context,
469 guint32 time,
470 FilerWindow *filer_window)
472 gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NONE);
473 dnd_spring_abort();
476 static void handle_drops(FilerWindow *filer_window,
477 GtkWidget *button,
478 DropDest dest)
480 make_drop_target(button, 0);
481 gtk_signal_connect(GTK_OBJECT(button), "drag_motion",
482 GTK_SIGNAL_FUNC(drag_motion), filer_window);
483 gtk_signal_connect(GTK_OBJECT(button), "drag_leave",
484 GTK_SIGNAL_FUNC(drag_leave), filer_window);
485 gtk_object_set_data(GTK_OBJECT(button), "toolbar_dest",
486 (gpointer) dest);
489 static void recreate_toolbar(FilerWindow *filer_window)
491 GtkWidget *frame = filer_window->toolbar_frame;
493 if (GTK_BIN(frame)->child)
495 filer_window->toolbar_text = NULL;
496 gtk_widget_destroy(((GtkBin *) frame)->child);
499 if (o_toolbar == TOOLBAR_NONE)
500 gtk_widget_hide(frame);
501 else
503 GtkWidget *toolbar;
505 toolbar = toolbar_new(filer_window);
506 gtk_container_add(GTK_CONTAINER(filer_window->toolbar_frame),
507 toolbar);
508 gtk_widget_show_all(frame);
511 filer_target_mode(filer_window, NULL, NULL, NULL);
514 static void option_notify(void)
516 ToolbarType old_type = o_toolbar;
517 guchar *list;
518 int i;
519 gboolean changed = FALSE;
521 list = option_get_static_string("toolbar_disable");
523 for (i = 0; i < sizeof(all_tools) / sizeof(*all_tools); i++)
525 Tool *tool = &all_tools[i];
526 gboolean old = tool->enabled;
528 tool->enabled = !in_list(tool->name, list);
530 if (old != tool->enabled)
531 changed = TRUE;
534 o_toolbar = option_get_int("toolbar_type");
536 if (changed || old_type != o_toolbar)
538 GList *next;
540 for (next = all_filer_windows; next; next = next->next)
542 FilerWindow *filer_window = (FilerWindow *) next->data;
544 recreate_toolbar(filer_window);