r339: The menu key bindings are now only saved if they actually changed.
[rox-filer.git] / ROX-Filer / src / toolbar.c
blob62bc8d37433c3669c218c7a2852735886949fe50
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 "dnd.h"
35 #include "filer.h"
36 #include "pixmaps.h"
38 extern int collection_menu_button;
40 /* Options bits */
41 static GtkWidget *create_options();
42 static void update_options();
43 static void set_options();
44 static void save_options();
45 static char *toolbar_type(char *data);
47 static OptionsSection options =
49 N_("Toolbar options"),
50 create_options,
51 update_options,
52 set_options,
53 save_options
56 ToolbarType o_toolbar = TOOLBAR_NORMAL;
58 static GtkWidget *menu_toolbar;
59 static GtkTooltips *tooltips = NULL;
61 /* TRUE if the button presses (or released) should open a new window,
62 * rather than reusing the existing one.
64 #define NEW_WIN_BUTTON(button_event) \
65 (o_new_window_on_1 ? ((GdkEventButton *) button_event)->button == 1 \
66 : ((GdkEventButton *) button_event)->button != 1)
68 typedef enum {DROP_TO_PARENT, DROP_TO_HOME} DropDest;
70 /* Static prototypes */
71 static void toolbar_up_clicked(GtkWidget *widget, FilerWindow *filer_window);
72 static void toolbar_home_clicked(GtkWidget *widget, FilerWindow *filer_window);
73 static GtkWidget *add_button(GtkWidget *box, MaskedPixmap *icon,
74 GtkSignalFunc cb, FilerWindow *filer_window,
75 char *label, char *tip);
76 static GtkWidget *create_toolbar(FilerWindow *filer_window);
77 static gboolean drag_motion(GtkWidget *widget,
78 GdkDragContext *context,
79 gint x,
80 gint y,
81 guint time,
82 FilerWindow *filer_window);
83 static void drag_leave(GtkWidget *widget,
84 GdkDragContext *context,
85 guint32 time,
86 FilerWindow *filer_window);
87 static void handle_drops(FilerWindow *filer_window,
88 GtkWidget *button,
89 DropDest dest);
92 /****************************************************************
93 * EXTERNAL INTERFACE *
94 ****************************************************************/
96 void toolbar_init(void)
98 options_sections = g_slist_prepend(options_sections, &options);
99 option_register("toolbar_type", toolbar_type);
101 tooltips = gtk_tooltips_new();
104 /* Create a new toolbar widget, suitable for adding to a filer window,
105 * and return it.
107 GtkWidget *toolbar_new(FilerWindow *filer_window)
109 g_return_val_if_fail(filer_window != NULL, NULL);
110 g_return_val_if_fail(o_toolbar != TOOLBAR_NONE, NULL);
112 return create_toolbar(filer_window);
117 /****************************************************************
118 * INTERNAL FUNCTIONS *
119 ****************************************************************/
121 static void toolbar_help_clicked(GtkWidget *widget, FilerWindow *filer_window)
123 filer_opendir(make_path(app_dir, "Help")->str);
126 static void toolbar_refresh_clicked(GtkWidget *widget,
127 FilerWindow *filer_window)
129 GdkEvent *event;
131 event = gtk_get_current_event();
132 if (event->type == GDK_BUTTON_RELEASE &&
133 ((GdkEventButton *) event)->button != 1)
135 filer_opendir(filer_window->path);
137 else
139 full_refresh();
140 filer_update_dir(filer_window, TRUE);
144 static void toolbar_home_clicked(GtkWidget *widget, FilerWindow *filer_window)
146 GdkEvent *event;
148 event = gtk_get_current_event();
149 if (event->type == GDK_BUTTON_RELEASE && NEW_WIN_BUTTON(event))
151 filer_opendir(home_dir);
153 else
154 filer_change_to(filer_window, home_dir, NULL);
157 static void toolbar_up_clicked(GtkWidget *widget, FilerWindow *filer_window)
159 GdkEvent *event;
161 event = gtk_get_current_event();
162 if (event->type == GDK_BUTTON_RELEASE && NEW_WIN_BUTTON(event))
164 filer_open_parent(filer_window);
166 else
167 change_to_parent(filer_window);
170 static GtkWidget *create_toolbar(FilerWindow *filer_window)
172 GtkWidget *frame, *box;
173 GtkWidget *b;
175 frame = gtk_frame_new(NULL);
176 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
178 box = gtk_hbutton_box_new();
179 gtk_button_box_set_child_size_default(16, 16);
180 gtk_hbutton_box_set_spacing_default(0);
181 gtk_button_box_set_layout(GTK_BUTTON_BOX(box), GTK_BUTTONBOX_START);
183 gtk_container_add(GTK_CONTAINER(frame), box);
185 b = add_button(box, im_up_icon,
186 GTK_SIGNAL_FUNC(toolbar_up_clicked),
187 filer_window,
188 _("Up"), _("Change to parent directory"));
189 handle_drops(filer_window, b, DROP_TO_PARENT);
191 b = add_button(box, im_home_icon,
192 GTK_SIGNAL_FUNC(toolbar_home_clicked),
193 filer_window,
194 _("Home"), _("Change to home directory"));
195 handle_drops(filer_window, b, DROP_TO_HOME);
197 add_button(box, im_refresh_icon,
198 GTK_SIGNAL_FUNC(toolbar_refresh_clicked),
199 filer_window,
200 _("Scan"), _("Rescan directory contents"));
201 add_button(box, im_help,
202 GTK_SIGNAL_FUNC(toolbar_help_clicked),
203 filer_window,
204 _("Help"), _("Show ROX-Filer help"));
206 return frame;
209 /* This is used to simulate a click when button 3 is used (GtkButton
210 * normally ignores this). Currently, this button does not pop in -
211 * this may be fixed in future versions of GTK+.
213 static gint toolbar_other_button = 0;
214 static gint toolbar_adjust_pressed(GtkButton *button,
215 GdkEventButton *event,
216 FilerWindow *filer_window)
218 gint b = event->button;
220 if ((b == 2 || b == 3) && toolbar_other_button == 0)
222 toolbar_other_button = event->button;
223 gtk_grab_add(GTK_WIDGET(button));
224 gtk_button_pressed(button);
227 return TRUE;
230 static gint toolbar_adjust_released(GtkButton *button,
231 GdkEventButton *event,
232 FilerWindow *filer_window)
234 if (event->button == toolbar_other_button)
236 toolbar_other_button = 0;
237 gtk_grab_remove(GTK_WIDGET(button));
238 gtk_button_released(button);
241 return TRUE;
244 static GtkWidget *add_button(GtkWidget *box, MaskedPixmap *icon,
245 GtkSignalFunc cb, FilerWindow *filer_window,
246 char *label, char *tip)
248 GtkWidget *button, *icon_widget;
250 button = gtk_button_new();
251 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
252 GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS);
254 gtk_signal_connect(GTK_OBJECT(button), "button_press_event",
255 GTK_SIGNAL_FUNC(toolbar_adjust_pressed), filer_window);
256 gtk_signal_connect(GTK_OBJECT(button), "button_release_event",
257 GTK_SIGNAL_FUNC(toolbar_adjust_released), filer_window);
258 gtk_signal_connect(GTK_OBJECT(button), "clicked",
259 cb, filer_window);
261 gtk_tooltips_set_tip(tooltips, button, tip, NULL);
263 icon_widget = gtk_pixmap_new(icon->pixmap, icon->mask);
265 if (o_toolbar == TOOLBAR_LARGE)
267 GtkWidget *vbox, *text;
269 vbox = gtk_vbox_new(FALSE, 0);
270 gtk_box_pack_start(GTK_BOX(vbox), icon_widget, TRUE, TRUE, 0);
272 text = gtk_label_new(label);
273 gtk_box_pack_start(GTK_BOX(vbox), text, FALSE, TRUE, 0);
275 gtk_container_add(GTK_CONTAINER(button), vbox);
277 else
278 gtk_container_add(GTK_CONTAINER(button), icon_widget);
280 gtk_container_add(GTK_CONTAINER(box), button);
282 return button;
285 /* Build up some option widgets to go in the options dialog, but don't
286 * fill them in yet.
288 static GtkWidget *create_options(void)
290 GtkWidget *vbox, *menu, *hbox;
292 vbox = gtk_vbox_new(FALSE, 0);
293 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
295 hbox = gtk_hbox_new(FALSE, 4);
296 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
298 gtk_box_pack_start(GTK_BOX(hbox),
299 gtk_label_new(_("Toolbar type for new windows")),
300 FALSE, TRUE, 0);
301 menu_toolbar = gtk_option_menu_new();
302 menu = gtk_menu_new();
303 gtk_menu_append(GTK_MENU(menu),
304 gtk_menu_item_new_with_label(_("None")));
305 gtk_menu_append(GTK_MENU(menu),
306 gtk_menu_item_new_with_label(_("Normal")));
307 gtk_menu_append(GTK_MENU(menu),
308 gtk_menu_item_new_with_label(_("Large")));
309 gtk_option_menu_set_menu(GTK_OPTION_MENU(menu_toolbar), menu);
310 gtk_box_pack_start(GTK_BOX(hbox), menu_toolbar, TRUE, TRUE, 0);
312 return vbox;
315 /* Reflect current state by changing the widgets in the options box */
316 static void update_options()
318 gtk_option_menu_set_history(GTK_OPTION_MENU(menu_toolbar), o_toolbar);
321 /* Set current values by reading the states of the widgets in the options box */
322 static void set_options()
324 GtkWidget *item, *menu;
325 GList *list;
327 menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(menu_toolbar));
328 item = gtk_menu_get_active(GTK_MENU(menu));
329 list = gtk_container_children(GTK_CONTAINER(menu));
330 o_toolbar = (ToolbarType) g_list_index(list, item);
331 g_list_free(list);
334 static void save_options()
336 option_write("toolbar_type", o_toolbar == TOOLBAR_NONE ? "None" :
337 o_toolbar == TOOLBAR_NORMAL ? "Normal" :
338 o_toolbar == TOOLBAR_LARGE ? "Large" :
339 "Unknown");
342 static char *toolbar_type(char *data)
344 if (g_strcasecmp(data, "None") == 0)
345 o_toolbar = TOOLBAR_NONE;
346 else if (g_strcasecmp(data, "Normal") == 0)
347 o_toolbar = TOOLBAR_NORMAL;
348 else if (g_strcasecmp(data, "Large") == 0)
349 o_toolbar = TOOLBAR_LARGE;
350 else
351 return _("Unknown toolbar type");
353 return NULL;
356 /* Called during the drag when the mouse is in a widget registered
357 * as a drop target. Returns TRUE if we can accept the drop.
359 static gboolean drag_motion(GtkWidget *widget,
360 GdkDragContext *context,
361 gint x,
362 gint y,
363 guint time,
364 FilerWindow *filer_window)
366 GdkDragAction action = context->suggested_action;
367 DropDest dest;
369 dest = (DropDest) gtk_object_get_data(GTK_OBJECT(widget),
370 "toolbar_dest");
372 if (dest == DROP_TO_HOME)
373 g_dataset_set_data(context, "drop_dest_path", home_dir);
374 else
376 guchar *slash, *path;
378 slash = strrchr(filer_window->path, '/');
379 if (slash == NULL || slash == filer_window->path)
380 path = g_strdup("/");
381 else
382 path = g_strndup(filer_window->path,
383 slash - filer_window->path);
384 g_dataset_set_data_full(context, "drop_dest_path",
385 path, g_free);
388 g_dataset_set_data(context, "drop_dest_type", drop_dest_dir);
389 gdk_drag_status(context, action, time);
391 dnd_spring_load(context);
392 gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NORMAL);
394 return TRUE;
397 static void drag_leave(GtkWidget *widget,
398 GdkDragContext *context,
399 guint32 time,
400 FilerWindow *filer_window)
402 gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NONE);
403 dnd_spring_abort();
406 static void handle_drops(FilerWindow *filer_window,
407 GtkWidget *button,
408 DropDest dest)
410 make_drop_target(button);
411 gtk_signal_connect(GTK_OBJECT(button), "drag_motion",
412 GTK_SIGNAL_FUNC(drag_motion), filer_window);
413 gtk_signal_connect(GTK_OBJECT(button), "drag_leave",
414 GTK_SIGNAL_FUNC(drag_leave), filer_window);
415 gtk_object_set_data(GTK_OBJECT(button), "toolbar_dest",
416 (gpointer) dest);