summaryrefslogtreecommitdiff
path: root/src/caja-side-pane.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/caja-side-pane.c')
-rw-r--r--src/caja-side-pane.c675
1 files changed, 675 insertions, 0 deletions
diff --git a/src/caja-side-pane.c b/src/caja-side-pane.c
new file mode 100644
index 00000000..0037a0fb
--- /dev/null
+++ b/src/caja-side-pane.c
@@ -0,0 +1,675 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* caja-side-pane.c
+ *
+ * Copyright (C) 2002 Ximian Inc.
+ *
+ * Caja is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Caja is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Dave Camp <[email protected]>
+ */
+
+#include <config.h>
+#include "caja-side-pane.h"
+
+#include <eel/eel-glib-extensions.h>
+#include <eel/eel-gtk-macros.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+typedef struct
+{
+ char *title;
+ char *tooltip;
+ GtkWidget *widget;
+ GtkWidget *menu_item;
+ GtkWidget *shortcut;
+} SidePanel;
+
+struct _CajaSidePaneDetails
+{
+ GtkWidget *notebook;
+ GtkWidget *menu;
+
+ GtkWidget *title_frame;
+ GtkWidget *title_hbox;
+ GtkWidget *title_label;
+ GtkWidget *shortcut_box;
+ GList *panels;
+};
+
+static void caja_side_pane_class_init (CajaSidePaneClass *klass);
+static void caja_side_pane_init (GObject *object);
+static void caja_side_pane_dispose (GObject *object);
+static void caja_side_pane_finalize (GObject *object);
+
+enum
+{
+ CLOSE_REQUESTED,
+ SWITCH_PAGE,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+EEL_CLASS_BOILERPLATE (CajaSidePane, caja_side_pane, GTK_TYPE_VBOX)
+
+static SidePanel *
+panel_for_widget (CajaSidePane *side_pane, GtkWidget *widget)
+{
+ GList *l;
+ SidePanel *panel;
+
+ for (l = side_pane->details->panels; l != NULL; l = l->next)
+ {
+ panel = l->data;
+ if (panel->widget == widget)
+ {
+ return panel;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+side_panel_free (SidePanel *panel)
+{
+ g_free (panel->title);
+ g_free (panel->tooltip);
+ g_slice_free (SidePanel, panel);
+}
+
+static void
+switch_page_callback (GtkWidget *notebook,
+ GtkWidget *page,
+ guint page_num,
+ gpointer user_data)
+{
+ CajaSidePane *side_pane;
+ SidePanel *panel;
+
+ side_pane = CAJA_SIDE_PANE (user_data);
+
+ panel = panel_for_widget (side_pane,
+ gtk_notebook_get_nth_page (GTK_NOTEBOOK (side_pane->details->notebook),
+ page_num));
+
+ if (panel && side_pane->details->title_label)
+ {
+ gtk_label_set_text (GTK_LABEL (side_pane->details->title_label),
+ panel->title);
+ }
+
+ g_signal_emit (side_pane, signals[SWITCH_PAGE], 0,
+ panel ? panel->widget : NULL);
+}
+
+static void
+select_panel (CajaSidePane *side_pane, SidePanel *panel)
+{
+ int page_num;
+
+ page_num = gtk_notebook_page_num
+ (GTK_NOTEBOOK (side_pane->details->notebook), panel->widget);
+ gtk_notebook_set_current_page
+ (GTK_NOTEBOOK (side_pane->details->notebook), page_num);
+}
+
+static void
+caja_side_pane_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ int width;
+ GtkAllocation child_allocation, frame_allocation;
+ CajaSidePane *pane;
+ GtkWidget *frame;
+ GtkWidget *hbox;
+ GtkRequisition child_requisition;
+
+ GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
+
+ pane = CAJA_SIDE_PANE(widget);
+ frame = pane->details->title_frame;
+ hbox = pane->details->title_hbox;
+
+ gtk_widget_get_child_requisition (hbox, &child_requisition);
+ width = child_requisition.width;
+
+ gtk_widget_get_allocation (frame, &frame_allocation);
+ child_allocation = frame_allocation;
+ child_allocation.width = MAX (width, frame_allocation.width);
+
+ gtk_widget_size_allocate (frame, &child_allocation);
+}
+
+/* initializing the class object by installing the operations we override */
+static void
+caja_side_pane_class_init (CajaSidePaneClass *klass)
+{
+ GObjectClass *gobject_class;
+ GtkWidgetClass *widget_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ widget_class = GTK_WIDGET_CLASS (klass);
+
+ gobject_class->finalize = caja_side_pane_finalize;
+ gobject_class->dispose = caja_side_pane_dispose;
+ widget_class->size_allocate = caja_side_pane_size_allocate;
+
+ signals[CLOSE_REQUESTED] = g_signal_new
+ ("close_requested",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CajaSidePaneClass,
+ close_requested),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals[SWITCH_PAGE] = g_signal_new
+ ("switch_page",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CajaSidePaneClass,
+ switch_page),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
+
+ g_type_class_add_private (gobject_class, sizeof (CajaSidePaneDetails));
+}
+
+static void
+panel_item_activate_callback (GtkMenuItem *item,
+ gpointer user_data)
+{
+ CajaSidePane *side_pane;
+ SidePanel *panel;
+
+ side_pane = CAJA_SIDE_PANE (user_data);
+
+ panel = g_object_get_data (G_OBJECT (item), "panel-item");
+
+ select_panel (side_pane, panel);
+}
+
+
+static void
+menu_position_under (GtkMenu *menu,
+ int *x,
+ int *y,
+ gboolean *push_in,
+ gpointer user_data)
+{
+ GtkWidget *widget;
+ GtkAllocation allocation;
+
+ g_return_if_fail (GTK_IS_BUTTON (user_data));
+ g_return_if_fail (!gtk_widget_get_has_window (GTK_WIDGET (user_data)));
+
+ widget = GTK_WIDGET (user_data);
+
+ gdk_window_get_origin (gtk_widget_get_window (widget), x, y);
+ gtk_widget_get_allocation (widget, &allocation);
+
+ *x += allocation.x;
+ *y += allocation.y + allocation.height;
+
+ *push_in = FALSE;
+}
+
+static gboolean
+select_button_press_callback (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ CajaSidePane *side_pane;
+
+ side_pane = CAJA_SIDE_PANE (user_data);
+
+ if ((event->type == GDK_BUTTON_PRESS) && event->button == 1)
+ {
+ GtkRequisition requisition;
+ GtkAllocation allocation;
+ gint width;
+
+ gtk_widget_get_allocation (widget, &allocation);
+ width = allocation.width;
+ gtk_widget_set_size_request (side_pane->details->menu, -1, -1);
+ gtk_widget_size_request (side_pane->details->menu, &requisition);
+ gtk_widget_set_size_request (side_pane->details->menu,
+ MAX (width, requisition.width), -1);
+
+ gtk_widget_grab_focus (widget);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+ gtk_menu_popup (GTK_MENU (side_pane->details->menu),
+ NULL, NULL, menu_position_under, widget,
+ event->button, event->time);
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+select_button_key_press_callback (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer user_data)
+{
+ CajaSidePane *side_pane;
+
+ side_pane = CAJA_SIDE_PANE (user_data);
+
+ if (event->keyval == GDK_space ||
+ event->keyval == GDK_KP_Space ||
+ event->keyval == GDK_Return ||
+ event->keyval == GDK_KP_Enter)
+ {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+ gtk_menu_popup (GTK_MENU (side_pane->details->menu),
+ NULL, NULL, menu_position_under, widget,
+ 1, event->time);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+close_clicked_callback (GtkWidget *widget,
+ gpointer user_data)
+{
+ CajaSidePane *side_pane;
+
+ side_pane = CAJA_SIDE_PANE (user_data);
+
+ g_signal_emit (side_pane, signals[CLOSE_REQUESTED], 0);
+}
+
+static void
+menu_deactivate_callback (GtkWidget *widget,
+ gpointer user_data)
+{
+ GtkWidget *menu_button;
+
+ menu_button = GTK_WIDGET (user_data);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (menu_button), FALSE);
+}
+
+static void
+menu_detach_callback (GtkWidget *widget,
+ GtkMenu *menu)
+{
+ CajaSidePane *side_pane;
+
+ side_pane = CAJA_SIDE_PANE (widget);
+
+ side_pane->details->menu = NULL;
+}
+
+static void
+caja_side_pane_init (GObject *object)
+{
+ CajaSidePane *side_pane;
+ GtkWidget *frame;
+ GtkWidget *hbox;
+ GtkWidget *close_button;
+ GtkWidget *select_button;
+ GtkWidget *select_hbox;
+ GtkWidget *arrow;
+ GtkWidget *image;
+
+ side_pane = CAJA_SIDE_PANE (object);
+
+ side_pane->details = G_TYPE_INSTANCE_GET_PRIVATE (object, CAJA_TYPE_SIDE_PANE, CajaSidePaneDetails);
+
+ /* The frame (really a vbox) has the border */
+ frame = gtk_vbox_new (FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (frame), 4);
+ side_pane->details->title_frame = frame;
+ gtk_widget_show (frame);
+ gtk_box_pack_start (GTK_BOX (side_pane), frame, FALSE, FALSE, 0);
+
+ /* And the title_hbox is what gets the same size as the other
+ headers */
+ hbox = gtk_hbox_new (FALSE, 0);
+ side_pane->details->title_hbox = hbox;
+ gtk_widget_show (hbox);
+ gtk_container_add (GTK_CONTAINER (frame), hbox);
+
+ select_button = gtk_toggle_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (select_button), GTK_RELIEF_NONE);
+ gtk_widget_show (select_button);
+
+ g_signal_connect (select_button,
+ "button_press_event",
+ G_CALLBACK (select_button_press_callback),
+ side_pane);
+ g_signal_connect (select_button,
+ "key_press_event",
+ G_CALLBACK (select_button_key_press_callback),
+ side_pane);
+
+ select_hbox = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (select_hbox);
+
+ side_pane->details->title_label = gtk_label_new ("");
+ eel_add_weak_pointer (&side_pane->details->title_label);
+
+ gtk_widget_show (side_pane->details->title_label);
+ gtk_box_pack_start (GTK_BOX (select_hbox),
+ side_pane->details->title_label,
+ FALSE, FALSE, 0);
+
+ arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
+ gtk_widget_show (arrow);
+ gtk_box_pack_end (GTK_BOX (select_hbox), arrow, FALSE, FALSE, 0);
+
+ gtk_container_add (GTK_CONTAINER (select_button), select_hbox);
+ gtk_box_pack_start (GTK_BOX (hbox), select_button, TRUE, TRUE, 0);
+
+ close_button = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
+ g_signal_connect (close_button,
+ "clicked",
+ G_CALLBACK (close_clicked_callback),
+ side_pane);
+
+ gtk_widget_show (close_button);
+
+ image = gtk_image_new_from_stock (GTK_STOCK_CLOSE,
+ GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image);
+
+ gtk_container_add (GTK_CONTAINER (close_button), image);
+
+ gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
+
+ side_pane->details->shortcut_box = gtk_hbox_new (TRUE, 0);
+ gtk_widget_show (side_pane->details->shortcut_box);
+ gtk_box_pack_end (GTK_BOX (hbox),
+ side_pane->details->shortcut_box,
+ FALSE, FALSE, 0);
+
+ side_pane->details->notebook = gtk_notebook_new ();
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (side_pane->details->notebook),
+ FALSE);
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (side_pane->details->notebook),
+ FALSE);
+ g_signal_connect_object (side_pane->details->notebook,
+ "switch_page",
+ G_CALLBACK (switch_page_callback),
+ side_pane,
+ 0);
+
+ gtk_widget_show (side_pane->details->notebook);
+
+ gtk_box_pack_start (GTK_BOX (side_pane), side_pane->details->notebook,
+ TRUE, TRUE, 0);
+
+ side_pane->details->menu = gtk_menu_new ();
+ g_signal_connect (side_pane->details->menu,
+ "deactivate",
+ G_CALLBACK (menu_deactivate_callback),
+ select_button);
+ gtk_menu_attach_to_widget (GTK_MENU (side_pane->details->menu),
+ GTK_WIDGET (side_pane),
+ menu_detach_callback);
+
+ gtk_widget_show (side_pane->details->menu);
+
+ gtk_widget_set_tooltip_text (close_button,
+ _("Close the side pane"));
+}
+
+static void
+caja_side_pane_dispose (GObject *object)
+{
+ CajaSidePane *side_pane;
+
+ side_pane = CAJA_SIDE_PANE (object);
+
+ if (side_pane->details->menu)
+ {
+ gtk_menu_detach (GTK_MENU (side_pane->details->menu));
+ side_pane->details->menu = NULL;
+ }
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
+}
+
+static void
+caja_side_pane_finalize (GObject *object)
+{
+ CajaSidePane *side_pane;
+ GList *l;
+
+ side_pane = CAJA_SIDE_PANE (object);
+
+ for (l = side_pane->details->panels; l != NULL; l = l->next)
+ {
+ side_panel_free (l->data);
+ }
+
+ g_list_free (side_pane->details->panels);
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+CajaSidePane *
+caja_side_pane_new (void)
+{
+ return CAJA_SIDE_PANE (gtk_widget_new (caja_side_pane_get_type (), NULL));
+}
+
+void
+caja_side_pane_add_panel (CajaSidePane *side_pane,
+ GtkWidget *widget,
+ const char *title,
+ const char *tooltip)
+{
+ SidePanel *panel;
+
+ g_return_if_fail (side_pane != NULL);
+ g_return_if_fail (CAJA_IS_SIDE_PANE (side_pane));
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (title != NULL);
+ g_return_if_fail (tooltip != NULL);
+
+ panel = g_slice_new0 (SidePanel);
+ panel->title = g_strdup (title);
+ panel->tooltip = g_strdup (tooltip);
+ panel->widget = widget;
+
+ gtk_widget_show (widget);
+
+ panel->menu_item = gtk_image_menu_item_new_with_label (title);
+ gtk_widget_show (panel->menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (side_pane->details->menu),
+ panel->menu_item);
+ g_object_set_data (G_OBJECT (panel->menu_item), "panel-item", panel);
+
+ g_signal_connect (panel->menu_item,
+ "activate",
+ G_CALLBACK (panel_item_activate_callback),
+ side_pane);
+
+ side_pane->details->panels = g_list_append (side_pane->details->panels,
+ panel);
+
+ gtk_notebook_append_page (GTK_NOTEBOOK (side_pane->details->notebook),
+ widget,
+ NULL);
+}
+
+void
+caja_side_pane_remove_panel (CajaSidePane *side_pane,
+ GtkWidget *widget)
+{
+ SidePanel *panel;
+ int page_num;
+
+ g_return_if_fail (side_pane != NULL);
+ g_return_if_fail (CAJA_IS_SIDE_PANE (side_pane));
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ panel = panel_for_widget (side_pane, widget);
+
+ g_return_if_fail (panel != NULL);
+
+ if (panel)
+ {
+ page_num = gtk_notebook_page_num (GTK_NOTEBOOK (side_pane->details->notebook),
+ widget);
+ gtk_notebook_remove_page (GTK_NOTEBOOK (side_pane->details->notebook),
+ page_num);
+ gtk_container_remove (GTK_CONTAINER (side_pane->details->menu),
+ panel->menu_item);
+
+ side_pane->details->panels =
+ g_list_remove (side_pane->details->panels,
+ panel);
+
+ side_panel_free (panel);
+ }
+}
+
+void
+caja_side_pane_show_panel (CajaSidePane *side_pane,
+ GtkWidget *widget)
+{
+ SidePanel *panel;
+ int page_num;
+
+ g_return_if_fail (side_pane != NULL);
+ g_return_if_fail (CAJA_IS_SIDE_PANE (side_pane));
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ panel = panel_for_widget (side_pane, widget);
+
+ g_return_if_fail (panel != NULL);
+
+ page_num = gtk_notebook_page_num (GTK_NOTEBOOK (side_pane->details->notebook),
+ widget);
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (side_pane->details->notebook),
+ page_num);
+}
+
+
+static void
+shortcut_clicked_callback (GtkWidget *button,
+ gpointer user_data)
+{
+ CajaSidePane *side_pane;
+ GtkWidget *page;
+
+ side_pane = CAJA_SIDE_PANE (user_data);
+
+ page = GTK_WIDGET (g_object_get_data (G_OBJECT (button), "side-page"));
+
+ caja_side_pane_show_panel (side_pane, page);
+}
+
+static GtkWidget *
+create_shortcut (CajaSidePane *side_pane,
+ SidePanel *panel,
+ GdkPixbuf *pixbuf)
+{
+ GtkWidget *button;
+ GtkWidget *image;
+
+ button = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+
+ g_object_set_data (G_OBJECT (button), "side-page", panel->widget);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (shortcut_clicked_callback), side_pane);
+
+ gtk_widget_set_tooltip_text (button, panel->tooltip);
+
+ image = gtk_image_new_from_pixbuf (pixbuf);
+ gtk_widget_show (image);
+ gtk_container_add (GTK_CONTAINER (button), image);
+
+ return button;
+}
+
+void
+caja_side_pane_set_panel_image (CajaSidePane *side_pane,
+ GtkWidget *widget,
+ GdkPixbuf *pixbuf)
+{
+ SidePanel *panel;
+ GtkWidget *image;
+
+ g_return_if_fail (side_pane != NULL);
+ g_return_if_fail (CAJA_IS_SIDE_PANE (side_pane));
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
+
+ panel = panel_for_widget (side_pane, widget);
+
+ g_return_if_fail (panel != NULL);
+
+ if (pixbuf)
+ {
+ image = gtk_image_new_from_pixbuf (pixbuf);
+ gtk_widget_show (image);
+ }
+ else
+ {
+ image = NULL;
+ }
+
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (panel->menu_item),
+ image);
+
+ if (panel->shortcut)
+ {
+ gtk_widget_destroy (panel->shortcut);
+ panel->shortcut = NULL;
+ }
+
+ if (pixbuf)
+ {
+ panel->shortcut = create_shortcut (side_pane, panel, pixbuf);
+ gtk_widget_show (panel->shortcut);
+ gtk_box_pack_start (GTK_BOX (side_pane->details->shortcut_box),
+ panel->shortcut,
+ FALSE, FALSE, 0);
+ }
+}
+
+GtkWidget *
+caja_side_pane_get_current_panel (CajaSidePane *side_pane)
+{
+ int index;
+
+ index = gtk_notebook_get_current_page (GTK_NOTEBOOK (side_pane->details->notebook));
+ return gtk_notebook_get_nth_page (GTK_NOTEBOOK (side_pane->details->notebook), index);
+}
+
+GtkWidget *
+caja_side_pane_get_title (CajaSidePane *side_pane)
+{
+ return side_pane->details->title_hbox;
+}