/* * Copyright (C) 2003 Marco Pesenti Gritti * * This program 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, or (at your option) * any later version. * * This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "egg-editable-toolbar.h" #include "egg-toolbars-model.h" #include "eggtoolbar.h" #include "eggtoolitem.h" #include "eggseparatortoolitem.h" #include "eggintl.h" #include static void egg_editable_toolbar_class_init (EggEditableToolbarClass *klass); static void egg_editable_toolbar_init (EggEditableToolbar *t); static void egg_editable_toolbar_finalize (GObject *object); #define MIN_TOOLBAR_HEIGHT 20 static GtkTargetEntry source_drag_types[] = { {EGG_TOOLBAR_ITEM_TYPE, 0, 0}, }; static int n_source_drag_types = G_N_ELEMENTS (source_drag_types); static GtkTargetEntry dest_drag_types[] = { {EGG_TOOLBAR_ITEM_TYPE, 0, 0}, }; static int n_dest_drag_types = G_N_ELEMENTS (dest_drag_types); enum { PROP_0, PROP_TOOLBARS_MODEL, PROP_MENU_MERGE }; enum { ACTION_REQUEST, LAST_SIGNAL }; static guint egg_editable_toolbar_signals[LAST_SIGNAL] = { 0 }; static GObjectClass *parent_class = NULL; struct EggEditableToolbarPrivate { EggMenuMerge *merge; EggToolbarsModel *model; gboolean edit_mode; GtkWidget *selected_toolbar; }; GType egg_editable_toolbar_get_type (void) { static GType egg_editable_toolbar_type = 0; if (egg_editable_toolbar_type == 0) { static const GTypeInfo our_info = { sizeof (EggEditableToolbarClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) egg_editable_toolbar_class_init, NULL, NULL, /* class_data */ sizeof (EggEditableToolbar), 0, /* n_preallocs */ (GInstanceInitFunc) egg_editable_toolbar_init }; egg_editable_toolbar_type = g_type_register_static (GTK_TYPE_VBOX, "EggEditableToolbar", &our_info, 0); } return egg_editable_toolbar_type; } static int get_toolbar_position (EggEditableToolbar *etoolbar, GtkWidget *toolbar) { GList *l; int result; l = gtk_container_get_children (GTK_CONTAINER (etoolbar)); result = g_list_index (l, toolbar); g_list_free (l); return result; } static int get_n_toolbars (EggEditableToolbar *etoolbar) { GList *l; int result; l = gtk_container_get_children (GTK_CONTAINER (etoolbar)); result = g_list_length (l); g_list_free (l); return result; } static GtkWidget * get_toolbar_nth (EggEditableToolbar *etoolbar, int position) { GList *l; GtkWidget *result; l = gtk_container_get_children (GTK_CONTAINER (etoolbar)); result = g_list_nth_data (l, position); g_list_free (l); return result; } static EggAction * find_action (EggEditableToolbar *t, const char *name) { GList *l = t->priv->merge->action_groups; EggAction *action = NULL; g_return_val_if_fail (IS_EGG_EDITABLE_TOOLBAR (t), NULL); g_return_val_if_fail (name != NULL, NULL); for (; l != NULL; l = l->next) { EggAction *tmp; tmp = egg_action_group_get_action (EGG_ACTION_GROUP (l->data), name); if (tmp) action = tmp; } return action; } static void drag_data_received_cb (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time_, EggEditableToolbar *etoolbar) { int pos, toolbar_pos; g_return_if_fail (IS_EGG_EDITABLE_TOOLBAR (etoolbar)); pos = egg_toolbar_get_drop_index (EGG_TOOLBAR (widget), x, y); toolbar_pos = get_toolbar_position (etoolbar, widget); if (strcmp (selection_data->data, "separator") == 0) { egg_toolbars_model_add_separator (etoolbar->priv->model, toolbar_pos, pos); } else { GdkAtom target; target = gtk_drag_dest_find_target (widget, context, NULL); egg_toolbars_model_add_item (etoolbar->priv->model, toolbar_pos, pos, target, selection_data->data); } } static void drag_data_delete_cb (GtkWidget *widget, GdkDragContext *context, EggEditableToolbar *etoolbar) { int pos, toolbar_pos; g_return_if_fail (IS_EGG_EDITABLE_TOOLBAR (etoolbar)); pos = egg_toolbar_get_item_index (EGG_TOOLBAR (widget->parent), EGG_TOOL_ITEM (widget)); toolbar_pos = get_toolbar_position (etoolbar, widget->parent); egg_toolbars_model_remove_item (etoolbar->priv->model, toolbar_pos, pos); } static void drag_data_get_cb (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint32 time, EggEditableToolbar *etoolbar) { EggAction *action; const char *target; g_return_if_fail (IS_EGG_EDITABLE_TOOLBAR (etoolbar)); action = EGG_ACTION (g_object_get_data (G_OBJECT (widget), "egg-action")); if (action) { target = action->name; } else { target = "separator"; } gtk_selection_data_set (selection_data, selection_data->target, 8, target, strlen (target)); } static void remove_toolbar_cb (GtkWidget *menuitem, EggEditableToolbar *etoolbar) { int pos; pos = get_toolbar_position (etoolbar, etoolbar->priv->selected_toolbar); egg_toolbars_model_remove_toolbar (etoolbar->priv->model, pos); } static void popup_toolbar_context_menu_cb (GtkWidget *toolbar, EggEditableToolbar *t) { GtkWidget *menu; GtkWidget *item; GtkWidget *image; if (t->priv->edit_mode) { EggTbModelFlags flags; int position; t->priv->selected_toolbar = toolbar; menu = gtk_menu_new (); item = gtk_image_menu_item_new_with_mnemonic (_("_Remove Toolbar")); gtk_widget_show (item); image = gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU); gtk_widget_show (image); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (item, "activate", G_CALLBACK (remove_toolbar_cb), t); position = get_toolbar_position (t, toolbar); flags = egg_toolbars_model_get_flags (t->priv->model, position); if (flags && EGG_TB_MODEL_NOT_REMOVABLE) { gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE); } gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 2, gtk_get_current_event_time ()); t->priv->selected_toolbar = NULL; } } static GtkWidget * create_toolbar (EggEditableToolbar *t) { GtkWidget *toolbar; toolbar = egg_toolbar_new (); egg_toolbar_set_show_arrow (EGG_TOOLBAR (toolbar), TRUE); gtk_widget_show (toolbar); gtk_drag_dest_set (toolbar, GTK_DEST_DEFAULT_DROP, dest_drag_types, n_dest_drag_types, GDK_ACTION_MOVE | GDK_ACTION_COPY); g_signal_connect (toolbar, "drag_data_received", G_CALLBACK (drag_data_received_cb), t); g_signal_connect (toolbar, "popup_context_menu", G_CALLBACK (popup_toolbar_context_menu_cb), t); return toolbar; } static GtkWidget * create_item (EggEditableToolbar *t, EggToolbarsModel *model, int toolbar_position, int position) { GtkWidget *item; EggAction *action; const char *action_name; gboolean is_separator; action_name = egg_toolbars_model_item_nth (model, toolbar_position, position, &is_separator); if (is_separator) { item = GTK_WIDGET (egg_separator_tool_item_new ()); } else { g_signal_emit (G_OBJECT (t), egg_editable_toolbar_signals[ACTION_REQUEST], 0, action_name); action = find_action (t, action_name); item = egg_action_create_tool_item (action); } gtk_widget_show (item); gtk_drag_source_set (item, GDK_BUTTON1_MASK, source_drag_types, n_source_drag_types, GDK_ACTION_MOVE); g_signal_connect (item, "drag_data_get", G_CALLBACK (drag_data_get_cb), t); g_signal_connect (item, "drag_data_delete", G_CALLBACK (drag_data_delete_cb), t); if (t->priv->edit_mode) { egg_tool_item_set_use_drag_window (EGG_TOOL_ITEM (item), TRUE); } return item; } static void toolbar_added_cb (EggToolbarsModel *model, int position, EggEditableToolbar *t) { GtkWidget *toolbar; toolbar = create_toolbar (t); gtk_widget_set_size_request (toolbar, -1, MIN_TOOLBAR_HEIGHT); gtk_box_pack_start (GTK_BOX (t), toolbar, FALSE, FALSE, 0); /* FIXME reorder to match position */ } static void toolbar_removed_cb (EggToolbarsModel *model, int position, EggEditableToolbar *t) { GtkWidget *toolbar; toolbar = get_toolbar_nth (t, position); gtk_widget_destroy (toolbar); } static void item_added_cb (EggToolbarsModel *model, int toolbar_position, int position, EggEditableToolbar *t) { GtkWidget *toolbar; GtkWidget *item; toolbar = get_toolbar_nth (t, toolbar_position); gtk_widget_set_size_request (toolbar, -1, -1); item = create_item (t, model, toolbar_position, position); egg_toolbar_insert (EGG_TOOLBAR (toolbar), EGG_TOOL_ITEM (item), position); } static void item_removed_cb (EggToolbarsModel *model, int toolbar_position, int position, EggEditableToolbar *t) { GtkWidget *toolbar; GtkWidget *item; toolbar = get_toolbar_nth (t, toolbar_position); item = GTK_WIDGET (egg_toolbar_get_nth_item (EGG_TOOLBAR (toolbar), position)); gtk_container_remove (GTK_CONTAINER (toolbar), item); if (egg_toolbars_model_n_items (model, toolbar_position) == 0) { gtk_widget_set_size_request (toolbar, -1, MIN_TOOLBAR_HEIGHT); egg_toolbars_model_remove_toolbar (model, toolbar_position); } } static void egg_editable_toolbar_set_model (EggEditableToolbar *t, EggToolbarsModel *model) { g_return_if_fail (IS_EGG_TOOLBARS_MODEL (model)); g_return_if_fail (IS_EGG_EDITABLE_TOOLBAR (t)); t->priv->model = model; g_signal_connect_object (model, "item_added", G_CALLBACK (item_added_cb), t, 0); g_signal_connect_object (model, "item_removed", G_CALLBACK (item_removed_cb), t, 0); g_signal_connect_object (model, "toolbar_added", G_CALLBACK (toolbar_added_cb), t, 0); g_signal_connect_object (model, "toolbar_removed", G_CALLBACK (toolbar_removed_cb), t, 0); } static void egg_editable_toolbar_construct (EggEditableToolbar *t) { int i, l, n_items, n_toolbars; EggToolbarsModel *model = t->priv->model; g_return_if_fail (model != NULL); n_toolbars = egg_toolbars_model_n_toolbars (model); for (i = 0; i < n_toolbars; i++) { GtkWidget *toolbar; toolbar = create_toolbar (t); gtk_box_pack_start (GTK_BOX (t), toolbar, FALSE, FALSE, 0); n_items = egg_toolbars_model_n_items (model, i); for (l = 0; l < n_items; l++) { GtkWidget *item; item = create_item (t, model, i, l); egg_toolbar_insert (EGG_TOOLBAR (toolbar), EGG_TOOL_ITEM (item), l); } if (n_items == 0) { gtk_widget_set_size_request (toolbar, -1, MIN_TOOLBAR_HEIGHT); } } } static void egg_editable_toolbar_set_merge (EggEditableToolbar *t, EggMenuMerge *merge) { g_return_if_fail (EGG_IS_MENU_MERGE (merge)); g_return_if_fail (IS_EGG_EDITABLE_TOOLBAR (t)); t->priv->merge = merge; egg_editable_toolbar_construct (t); } static void egg_editable_toolbar_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { EggEditableToolbar *t = EGG_EDITABLE_TOOLBAR (object); switch (prop_id) { case PROP_MENU_MERGE: egg_editable_toolbar_set_merge (t, g_value_get_object (value)); break; case PROP_TOOLBARS_MODEL: egg_editable_toolbar_set_model (t, g_value_get_object (value)); break; } } static void egg_editable_toolbar_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { EggEditableToolbar *t = EGG_EDITABLE_TOOLBAR (object); switch (prop_id) { case PROP_MENU_MERGE: g_value_set_object (value, t->priv->merge); break; case PROP_TOOLBARS_MODEL: g_value_set_object (value, t->priv->model); break; } } static void egg_editable_toolbar_class_init (EggEditableToolbarClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); object_class->finalize = egg_editable_toolbar_finalize; object_class->set_property = egg_editable_toolbar_set_property; object_class->get_property = egg_editable_toolbar_get_property; egg_editable_toolbar_signals[ACTION_REQUEST] = g_signal_new ("action_request", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggEditableToolbarClass, action_request), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); g_object_class_install_property (object_class, PROP_MENU_MERGE, g_param_spec_object ("MenuMerge", "MenuMerge", "Menu merge", EGG_TYPE_MENU_MERGE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_TOOLBARS_MODEL, g_param_spec_object ("ToolbarsModel", "ToolbarsModel", "Toolbars Model", EGG_TOOLBARS_MODEL_TYPE, G_PARAM_READWRITE)); } static void egg_editable_toolbar_init (EggEditableToolbar *t) { t->priv = g_new0 (EggEditableToolbarPrivate, 1); t->priv->merge = NULL; t->priv->edit_mode = FALSE; } static void egg_editable_toolbar_finalize (GObject *object) { EggEditableToolbar *t = EGG_EDITABLE_TOOLBAR (object); g_return_if_fail (object != NULL); g_return_if_fail (IS_EGG_EDITABLE_TOOLBAR (object)); g_free (t->priv); G_OBJECT_CLASS (parent_class)->finalize (object); } GtkWidget * egg_editable_toolbar_new (EggMenuMerge *merge, EggToolbarsModel *model) { EggEditableToolbar *t; t = EGG_EDITABLE_TOOLBAR (g_object_new (EGG_EDITABLE_TOOLBAR_TYPE, "ToolbarsModel", model, "MenuMerge", merge, NULL)); g_return_val_if_fail (t->priv != NULL, NULL); return GTK_WIDGET (t); } void egg_editable_toolbar_set_edit_mode (EggEditableToolbar *etoolbar, gboolean mode) { int i, l, n_toolbars, n_items; etoolbar->priv->edit_mode = mode; n_toolbars = get_n_toolbars (etoolbar); for (i = 0; i < n_toolbars; i++) { GtkWidget *toolbar; toolbar = get_toolbar_nth (etoolbar, i); n_items = egg_toolbar_get_n_items (EGG_TOOLBAR (toolbar)); for (l = 0; l < n_items; l++) { EggToolItem *item; item = egg_toolbar_get_nth_item (EGG_TOOLBAR (toolbar), l); egg_tool_item_set_use_drag_window (item, mode); } } } void egg_editable_toolbar_show (EggEditableToolbar *etoolbar, const char *name) { int i, n_toolbars; EggToolbarsModel *model = etoolbar->priv->model; g_return_if_fail (model != NULL); n_toolbars = egg_toolbars_model_n_toolbars (model); for (i = 0; i < n_toolbars; i++) { const char *toolbar_name; toolbar_name = egg_toolbars_model_toolbar_nth (model, i); if (strcmp (toolbar_name, name) == 0) { gtk_widget_show (get_toolbar_nth (etoolbar, i)); } } } void egg_editable_toolbar_hide (EggEditableToolbar *etoolbar, const char *name) { int i, n_toolbars; EggToolbarsModel *model = etoolbar->priv->model; g_return_if_fail (model != NULL); n_toolbars = egg_toolbars_model_n_toolbars (model); for (i = 0; i < n_toolbars; i++) { const char *toolbar_name; toolbar_name = egg_toolbars_model_toolbar_nth (model, i); if (strcmp (toolbar_name, name) == 0) { gtk_widget_hide (get_toolbar_nth (etoolbar, i)); } } } void egg_editable_toolbar_set_drag_dest (EggEditableToolbar *etoolbar, const GtkTargetEntry *targets, gint n_targets, const char *toolbar_name) { int i, n_toolbars; EggToolbarsModel *model = etoolbar->priv->model; g_return_if_fail (model != NULL); n_toolbars = egg_toolbars_model_n_toolbars (model); for (i = 0; i < n_toolbars; i++) { const char *name; name = egg_toolbars_model_toolbar_nth (model, i); if (strcmp (toolbar_name, name) == 0) { GtkWidget *widget = get_toolbar_nth (etoolbar, i); gtk_drag_dest_unset (widget); gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_DROP, targets, n_targets, GDK_ACTION_MOVE | GDK_ACTION_COPY); } } }