2008-05-05 Paolo Borelli <pborelli@katamail.com>
[nautilus.git] / src / nautilus-side-pane.c
blobd3e6f93e934920c34cbacf3af1c29aea7fdf0732
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 /* nautilus-side-pane.c
4 *
5 * Copyright (C) 2002 Ximian Inc.
6 *
7 * Nautilus is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * Nautilus is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Author: Dave Camp <dave@ximian.com>
24 #include <config.h>
25 #include "nautilus-side-pane.h"
27 #include <eel/eel-glib-extensions.h>
28 #include <eel/eel-gtk-macros.h>
29 #include <gdk/gdkkeysyms.h>
30 #include <gtk/gtkarrow.h>
31 #include <gtk/gtkbutton.h>
32 #include <gtk/gtkframe.h>
33 #include <gtk/gtkhbox.h>
34 #include <gtk/gtkimage.h>
35 #include <gtk/gtklabel.h>
36 #include <gtk/gtkimagemenuitem.h>
37 #include <gtk/gtknotebook.h>
38 #include <gtk/gtkstock.h>
39 #include <gtk/gtktogglebutton.h>
40 #include <glib/gi18n.h>
42 typedef struct {
43 char *title;
44 char *tooltip;
45 GtkWidget *widget;
46 GtkWidget *menu_item;
47 GtkWidget *shortcut;
48 } SidePanel;
50 struct _NautilusSidePaneDetails {
51 GtkWidget *notebook;
52 GtkWidget *menu;
54 GtkWidget *title_frame;
55 GtkWidget *title_hbox;
56 GtkWidget *title_label;
57 GtkWidget *shortcut_box;
58 GList *panels;
61 static void nautilus_side_pane_class_init (NautilusSidePaneClass *klass);
62 static void nautilus_side_pane_init (GObject *object);
63 static void nautilus_side_pane_dispose (GObject *object);
64 static void nautilus_side_pane_finalize (GObject *object);
66 enum {
67 CLOSE_REQUESTED,
68 SWITCH_PAGE,
69 LAST_SIGNAL
72 static guint signals[LAST_SIGNAL];
74 EEL_CLASS_BOILERPLATE (NautilusSidePane, nautilus_side_pane, GTK_TYPE_VBOX)
76 static SidePanel *
77 panel_for_widget (NautilusSidePane *side_pane, GtkWidget *widget)
79 GList *l;
80 SidePanel *panel;
82 for (l = side_pane->details->panels; l != NULL; l = l->next) {
83 panel = l->data;
84 if (panel->widget == widget) {
85 return panel;
89 return NULL;
92 static void
93 side_panel_free (SidePanel *panel)
95 g_free (panel->title);
96 g_free (panel->tooltip);
97 g_slice_free (SidePanel, panel);
100 static void
101 switch_page_callback (GtkWidget *notebook,
102 GtkNotebookPage *page,
103 guint page_num,
104 gpointer user_data)
106 NautilusSidePane *side_pane;
107 SidePanel *panel;
109 side_pane = NAUTILUS_SIDE_PANE (user_data);
111 panel = panel_for_widget (side_pane,
112 gtk_notebook_get_nth_page (GTK_NOTEBOOK (side_pane->details->notebook),
113 page_num));
115 if (panel && side_pane->details->title_label) {
116 gtk_label_set_text (GTK_LABEL (side_pane->details->title_label),
117 panel->title);
120 g_signal_emit (side_pane, signals[SWITCH_PAGE], 0,
121 panel ? panel->widget : NULL);
124 static void
125 select_panel (NautilusSidePane *side_pane, SidePanel *panel)
127 int page_num;
129 page_num = gtk_notebook_page_num
130 (GTK_NOTEBOOK (side_pane->details->notebook), panel->widget);
131 gtk_notebook_set_current_page
132 (GTK_NOTEBOOK (side_pane->details->notebook), page_num);
135 static void
136 nautilus_side_pane_size_allocate (GtkWidget *widget,
137 GtkAllocation *allocation)
139 int width;
140 GtkAllocation child_allocation;
141 NautilusSidePane *pane;
142 GtkWidget *frame;
143 GtkWidget *hbox;
144 GtkRequisition child_requisition;
146 GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
148 pane = NAUTILUS_SIDE_PANE(widget);
149 frame = pane->details->title_frame;
150 hbox = pane->details->title_hbox;
152 gtk_widget_get_child_requisition (hbox, &child_requisition);
153 width = child_requisition.width;
155 child_allocation = frame->allocation;
156 child_allocation.width = MAX (width, frame->allocation.width);
158 gtk_widget_size_allocate (frame, &child_allocation);
161 /* initializing the class object by installing the operations we override */
162 static void
163 nautilus_side_pane_class_init (NautilusSidePaneClass *klass)
165 GObjectClass *gobject_class;
166 GtkWidgetClass *widget_class;
168 gobject_class = G_OBJECT_CLASS (klass);
169 widget_class = GTK_WIDGET_CLASS (klass);
171 gobject_class->finalize = nautilus_side_pane_finalize;
172 gobject_class->dispose = nautilus_side_pane_dispose;
173 widget_class->size_allocate = nautilus_side_pane_size_allocate;
175 signals[CLOSE_REQUESTED] = g_signal_new
176 ("close_requested",
177 G_TYPE_FROM_CLASS (klass),
178 G_SIGNAL_RUN_LAST,
179 G_STRUCT_OFFSET (NautilusSidePaneClass,
180 close_requested),
181 NULL, NULL,
182 g_cclosure_marshal_VOID__VOID,
183 G_TYPE_NONE, 0);
184 signals[SWITCH_PAGE] = g_signal_new
185 ("switch_page",
186 G_TYPE_FROM_CLASS (klass),
187 G_SIGNAL_RUN_LAST,
188 G_STRUCT_OFFSET (NautilusSidePaneClass,
189 switch_page),
190 NULL, NULL,
191 g_cclosure_marshal_VOID__OBJECT,
192 G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
194 g_type_class_add_private (gobject_class, sizeof (NautilusSidePaneDetails));
197 static void
198 panel_item_activate_callback (GtkMenuItem *item,
199 gpointer user_data)
201 NautilusSidePane *side_pane;
202 SidePanel *panel;
204 side_pane = NAUTILUS_SIDE_PANE (user_data);
206 panel = g_object_get_data (G_OBJECT (item), "panel-item");
208 select_panel (side_pane, panel);
212 static void
213 menu_position_under (GtkMenu *menu,
214 int *x,
215 int *y,
216 gboolean *push_in,
217 gpointer user_data)
219 GtkWidget *widget;
221 g_return_if_fail (GTK_IS_BUTTON (user_data));
222 g_return_if_fail (GTK_WIDGET_NO_WINDOW (user_data));
224 widget = GTK_WIDGET (user_data);
226 gdk_window_get_origin (widget->window, x, y);
228 *x += widget->allocation.x;
229 *y += widget->allocation.y + widget->allocation.height;
231 *push_in = FALSE;
234 static gboolean
235 select_button_press_callback (GtkWidget *widget,
236 GdkEventButton *event,
237 gpointer user_data)
239 NautilusSidePane *side_pane;
241 side_pane = NAUTILUS_SIDE_PANE (user_data);
243 if ((event->type == GDK_BUTTON_PRESS) && event->button == 1) {
244 gtk_widget_grab_focus (widget);
246 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
247 gtk_menu_popup (GTK_MENU (side_pane->details->menu),
248 NULL, NULL, menu_position_under, widget,
249 event->button, event->time);
251 return TRUE;
253 return FALSE;
256 static gboolean
257 select_button_key_press_callback (GtkWidget *widget,
258 GdkEventKey *event,
259 gpointer user_data)
261 NautilusSidePane *side_pane;
263 side_pane = NAUTILUS_SIDE_PANE (user_data);
265 if (event->keyval == GDK_space ||
266 event->keyval == GDK_KP_Space ||
267 event->keyval == GDK_Return ||
268 event->keyval == GDK_KP_Enter) {
269 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
270 gtk_menu_popup (GTK_MENU (side_pane->details->menu),
271 NULL, NULL, menu_position_under, widget,
272 1, event->time);
273 return TRUE;
276 return FALSE;
279 static void
280 close_clicked_callback (GtkWidget *widget,
281 gpointer user_data)
283 NautilusSidePane *side_pane;
285 side_pane = NAUTILUS_SIDE_PANE (user_data);
287 g_signal_emit (side_pane, signals[CLOSE_REQUESTED], 0);
290 static void
291 menu_deactivate_callback (GtkWidget *widget,
292 gpointer user_data)
294 GtkWidget *menu_button;
296 menu_button = GTK_WIDGET (user_data);
298 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (menu_button), FALSE);
301 static void
302 menu_detach_callback (GtkWidget *widget,
303 GtkMenu *menu)
305 NautilusSidePane *side_pane;
307 side_pane = NAUTILUS_SIDE_PANE (widget);
309 side_pane->details->menu = NULL;
312 static void
313 nautilus_side_pane_init (GObject *object)
315 NautilusSidePane *side_pane;
316 GtkWidget *frame;
317 GtkWidget *hbox;
318 GtkWidget *close_button;
319 GtkWidget *select_button;
320 GtkWidget *select_hbox;
321 GtkWidget *arrow;
322 GtkWidget *image;
324 side_pane = NAUTILUS_SIDE_PANE (object);
326 side_pane->details = G_TYPE_INSTANCE_GET_PRIVATE (object, NAUTILUS_TYPE_SIDE_PANE, NautilusSidePaneDetails);
328 frame = gtk_frame_new (NULL);
329 side_pane->details->title_frame = frame;
330 gtk_widget_show (frame);
331 gtk_box_pack_start (GTK_BOX (side_pane), frame, FALSE, FALSE, 0);
333 hbox = gtk_hbox_new (FALSE, 0);
334 side_pane->details->title_hbox = hbox;
335 gtk_widget_show (hbox);
336 gtk_container_add (GTK_CONTAINER (frame), hbox);
338 select_button = gtk_toggle_button_new ();
339 gtk_button_set_relief (GTK_BUTTON (select_button), GTK_RELIEF_NONE);
340 gtk_widget_show (select_button);
342 g_signal_connect (select_button,
343 "button_press_event",
344 G_CALLBACK (select_button_press_callback),
345 side_pane);
346 g_signal_connect (select_button,
347 "key_press_event",
348 G_CALLBACK (select_button_key_press_callback),
349 side_pane);
351 select_hbox = gtk_hbox_new (FALSE, 0);
352 gtk_widget_show (select_hbox);
354 side_pane->details->title_label = gtk_label_new ("");
355 eel_add_weak_pointer (&side_pane->details->title_label);
357 gtk_widget_show (side_pane->details->title_label);
358 gtk_box_pack_start (GTK_BOX (select_hbox),
359 side_pane->details->title_label,
360 FALSE, FALSE, 0);
362 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
363 gtk_widget_show (arrow);
364 gtk_box_pack_end (GTK_BOX (select_hbox), arrow, FALSE, FALSE, 0);
366 gtk_container_add (GTK_CONTAINER (select_button), select_hbox);
367 gtk_box_pack_start (GTK_BOX (hbox), select_button, FALSE, FALSE, 0);
369 close_button = gtk_button_new ();
370 gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
371 g_signal_connect (close_button,
372 "clicked",
373 G_CALLBACK (close_clicked_callback),
374 side_pane);
376 gtk_widget_show (close_button);
378 image = gtk_image_new_from_stock (GTK_STOCK_CLOSE,
379 GTK_ICON_SIZE_MENU);
380 gtk_widget_show (image);
382 gtk_container_add (GTK_CONTAINER (close_button), image);
384 gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
386 side_pane->details->shortcut_box = gtk_hbox_new (TRUE, 0);
387 gtk_widget_show (side_pane->details->shortcut_box);
388 gtk_box_pack_end (GTK_BOX (hbox),
389 side_pane->details->shortcut_box,
390 FALSE, FALSE, 0);
392 side_pane->details->notebook = gtk_notebook_new ();
393 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (side_pane->details->notebook),
394 FALSE);
395 gtk_notebook_set_show_border (GTK_NOTEBOOK (side_pane->details->notebook),
396 FALSE);
397 g_signal_connect_object (side_pane->details->notebook,
398 "switch_page",
399 G_CALLBACK (switch_page_callback),
400 side_pane,
403 gtk_widget_show (side_pane->details->notebook);
405 gtk_box_pack_start (GTK_BOX (side_pane), side_pane->details->notebook,
406 TRUE, TRUE, 0);
408 side_pane->details->menu = gtk_menu_new ();
409 g_signal_connect (side_pane->details->menu,
410 "deactivate",
411 G_CALLBACK (menu_deactivate_callback),
412 select_button);
413 gtk_menu_attach_to_widget (GTK_MENU (side_pane->details->menu),
414 GTK_WIDGET (side_pane),
415 menu_detach_callback);
417 gtk_widget_show (side_pane->details->menu);
419 gtk_widget_set_tooltip_text (close_button,
420 _("Close the side pane"));
423 static void
424 nautilus_side_pane_dispose (GObject *object)
426 NautilusSidePane *side_pane;
428 side_pane = NAUTILUS_SIDE_PANE (object);
430 if (side_pane->details->menu) {
431 gtk_menu_detach (GTK_MENU (side_pane->details->menu));
432 side_pane->details->menu = NULL;
435 EEL_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
438 static void
439 nautilus_side_pane_finalize (GObject *object)
441 NautilusSidePane *side_pane;
442 GList *l;
444 side_pane = NAUTILUS_SIDE_PANE (object);
446 for (l = side_pane->details->panels; l != NULL; l = l->next) {
447 side_panel_free (l->data);
450 g_list_free (side_pane->details->panels);
452 EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
455 NautilusSidePane *
456 nautilus_side_pane_new (void)
458 return NAUTILUS_SIDE_PANE (gtk_widget_new (nautilus_side_pane_get_type (), NULL));
461 void
462 nautilus_side_pane_add_panel (NautilusSidePane *side_pane,
463 GtkWidget *widget,
464 const char *title,
465 const char *tooltip)
467 SidePanel *panel;
469 g_return_if_fail (side_pane != NULL);
470 g_return_if_fail (NAUTILUS_IS_SIDE_PANE (side_pane));
471 g_return_if_fail (widget != NULL);
472 g_return_if_fail (GTK_IS_WIDGET (widget));
473 g_return_if_fail (title != NULL);
474 g_return_if_fail (tooltip != NULL);
476 panel = g_slice_new0 (SidePanel);
477 panel->title = g_strdup (title);
478 panel->tooltip = g_strdup (tooltip);
479 panel->widget = widget;
481 gtk_widget_show (widget);
483 panel->menu_item = gtk_image_menu_item_new_with_label (title);
484 gtk_widget_show (panel->menu_item);
485 gtk_menu_shell_append (GTK_MENU_SHELL (side_pane->details->menu),
486 panel->menu_item);
487 g_object_set_data (G_OBJECT (panel->menu_item), "panel-item", panel);
489 g_signal_connect (panel->menu_item,
490 "activate",
491 G_CALLBACK (panel_item_activate_callback),
492 side_pane);
494 side_pane->details->panels = g_list_append (side_pane->details->panels,
495 panel);
497 gtk_notebook_append_page (GTK_NOTEBOOK (side_pane->details->notebook),
498 widget,
499 NULL);
502 void
503 nautilus_side_pane_remove_panel (NautilusSidePane *side_pane,
504 GtkWidget *widget)
506 SidePanel *panel;
507 int page_num;
509 g_return_if_fail (side_pane != NULL);
510 g_return_if_fail (NAUTILUS_IS_SIDE_PANE (side_pane));
511 g_return_if_fail (widget != NULL);
512 g_return_if_fail (GTK_IS_WIDGET (widget));
514 panel = panel_for_widget (side_pane, widget);
516 g_return_if_fail (panel != NULL);
518 if (panel) {
519 page_num = gtk_notebook_page_num (GTK_NOTEBOOK (side_pane->details->notebook),
520 widget);
521 gtk_notebook_remove_page (GTK_NOTEBOOK (side_pane->details->notebook),
522 page_num);
523 gtk_container_remove (GTK_CONTAINER (side_pane->details->menu),
524 panel->menu_item);
526 side_pane->details->panels =
527 g_list_remove (side_pane->details->panels,
528 panel);
530 side_panel_free (panel);
534 void
535 nautilus_side_pane_show_panel (NautilusSidePane *side_pane,
536 GtkWidget *widget)
538 SidePanel *panel;
539 int page_num;
541 g_return_if_fail (side_pane != NULL);
542 g_return_if_fail (NAUTILUS_IS_SIDE_PANE (side_pane));
543 g_return_if_fail (widget != NULL);
544 g_return_if_fail (GTK_IS_WIDGET (widget));
546 panel = panel_for_widget (side_pane, widget);
548 g_return_if_fail (panel != NULL);
550 page_num = gtk_notebook_page_num (GTK_NOTEBOOK (side_pane->details->notebook),
551 widget);
552 gtk_notebook_set_current_page (GTK_NOTEBOOK (side_pane->details->notebook),
553 page_num);
557 static void
558 shortcut_clicked_callback (GtkWidget *button,
559 gpointer user_data)
561 NautilusSidePane *side_pane;
562 GtkWidget *page;
564 side_pane = NAUTILUS_SIDE_PANE (user_data);
566 page = GTK_WIDGET (g_object_get_data (G_OBJECT (button), "side-page"));
568 nautilus_side_pane_show_panel (side_pane, page);
571 static GtkWidget *
572 create_shortcut (NautilusSidePane *side_pane,
573 SidePanel *panel,
574 GdkPixbuf *pixbuf)
576 GtkWidget *button;
577 GtkWidget *image;
579 button = gtk_button_new ();
580 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
582 g_object_set_data (G_OBJECT (button), "side-page", panel->widget);
583 g_signal_connect (button, "clicked",
584 G_CALLBACK (shortcut_clicked_callback), side_pane);
586 gtk_widget_set_tooltip_text (button, panel->tooltip);
588 image = gtk_image_new_from_pixbuf (pixbuf);
589 gtk_widget_show (image);
590 gtk_container_add (GTK_CONTAINER (button), image);
592 return button;
595 void
596 nautilus_side_pane_set_panel_image (NautilusSidePane *side_pane,
597 GtkWidget *widget,
598 GdkPixbuf *pixbuf)
600 SidePanel *panel;
601 GtkWidget *image;
603 g_return_if_fail (side_pane != NULL);
604 g_return_if_fail (NAUTILUS_IS_SIDE_PANE (side_pane));
605 g_return_if_fail (widget != NULL);
606 g_return_if_fail (GTK_IS_WIDGET (widget));
607 g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
609 panel = panel_for_widget (side_pane, widget);
611 g_return_if_fail (panel != NULL);
613 if (pixbuf) {
614 image = gtk_image_new_from_pixbuf (pixbuf);
615 gtk_widget_show (image);
616 } else {
617 image = NULL;
620 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (panel->menu_item),
621 image);
623 if (panel->shortcut) {
624 gtk_widget_destroy (panel->shortcut);
625 panel->shortcut = NULL;
628 if (pixbuf) {
629 panel->shortcut = create_shortcut (side_pane, panel, pixbuf);
630 gtk_widget_show (panel->shortcut);
631 gtk_box_pack_start (GTK_BOX (side_pane->details->shortcut_box),
632 panel->shortcut,
633 FALSE, FALSE, 0);
637 GtkWidget *
638 nautilus_side_pane_get_current_panel (NautilusSidePane *side_pane)
640 int index;
642 index = gtk_notebook_get_current_page (GTK_NOTEBOOK (side_pane->details->notebook));
643 return gtk_notebook_get_nth_page (GTK_NOTEBOOK (side_pane->details->notebook), index);