/* * Copyright (C) 2000 Marco Pesenti Gritti * (C) 2001, 2002 Jorn Baayen * * 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 "ephy-editable-toolbar.h" #include "ephy-toolbars-group.h" #include "ephy-debug.h" #include "ephy-dnd.h" #include "eggtoolitem.h" #include "eggtoolbar.h" #include #include /* This is copied from gtkscrollbarwindow.c */ #define DEFAULT_SCROLLBAR_SPACING 3 #define SCROLLBAR_SPACING(w) \ (GTK_SCROLLED_WINDOW_GET_CLASS (w)->scrollbar_spacing >= 0 ? \ GTK_SCROLLED_WINDOW_GET_CLASS (w)->scrollbar_spacing : DEFAULT_SCROLLBAR_SPACING) static GtkTargetEntry dest_drag_types [] = { { "EPHY_TOOLBAR_BUTTON", 0, 0 }, /* FIXME generic way to add types */ { EPHY_DND_URL_TYPE, 0, EPHY_DND_URL } }; static GtkTargetEntry source_drag_types [] = { { "EPHY_TOOLBAR_BUTTON", 0, 0 } }; static void ephy_editable_toolbar_class_init (EphyEditableToolbarClass *klass); static void ephy_editable_toolbar_init (EphyEditableToolbar *t); static void ephy_editable_toolbar_finalize (GObject *object); static void do_merge (EphyEditableToolbar *t); static void setup_editor (EphyEditableToolbar *etoolbar); static void update_editor_sheet (EphyEditableToolbar *etoolbar); static gboolean update_editor_position (EphyEditableToolbar *etoolbar); enum { PROP_0, PROP_TOOLBARS_GROUP, PROP_MENU_MERGE }; static GObjectClass *parent_class = NULL; struct EphyEditableToolbarPrivate { EggMenuMerge *merge; GtkWidget *editor; GtkWidget *main_box; GtkWidget *table; GtkWidget *label_zone; GtkWidget *action_zone; GtkWidget *scrolled_window; GtkWidget *last_toolbar; guint ui_id; gboolean toolbars_dirty; gboolean editor_pos_dirty; gboolean editor_sheet_dirty; gboolean edit_mode; EphyToolbarsGroup *group; GList *actions_list; }; GType ephy_editable_toolbar_get_type (void) { static GType ephy_editable_toolbar_type = 0; if (ephy_editable_toolbar_type == 0) { static const GTypeInfo our_info = { sizeof (EphyEditableToolbarClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) ephy_editable_toolbar_class_init, NULL, NULL, /* class_data */ sizeof (EphyEditableToolbar), 0, /* n_preallocs */ (GInstanceInitFunc) ephy_editable_toolbar_init }; ephy_editable_toolbar_type = g_type_register_static (G_TYPE_OBJECT, "EphyEditableToolbar", &our_info, 0); } return ephy_editable_toolbar_type; } static EggAction * find_action (EphyEditableToolbar *t, const char *name) { GList *l = t->priv->merge->action_groups; EggAction *action = NULL; g_return_val_if_fail (IS_EPHY_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 EggAction * impl_get_action (EphyEditableToolbar *etoolbar, const char *type, const char *name) { EggAction *action; g_return_val_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar), NULL); if (type == NULL) { action = find_action (etoolbar, name); } else { action = NULL; } return action; } static gboolean ui_update (gpointer data) { EphyEditableToolbar *etoolbar = EPHY_EDITABLE_TOOLBAR (data); g_return_val_if_fail (etoolbar != NULL, FALSE); if (etoolbar->priv->toolbars_dirty) { LOG ("Update ui: toolbars") do_merge (etoolbar); etoolbar->priv->toolbars_dirty = FALSE; } if (etoolbar->priv->editor_sheet_dirty) { LOG ("Update ui: editor sheet") update_editor_sheet (etoolbar); etoolbar->priv->editor_sheet_dirty = FALSE; } if (etoolbar->priv->editor_pos_dirty) { LOG ("Update ui: editor position (in idle)") g_idle_add ((GSourceFunc)update_editor_position, etoolbar); etoolbar->priv->editor_pos_dirty = FALSE; } return FALSE; } static void queue_ui_update (EphyEditableToolbar *etoolbar) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_idle_add (ui_update, etoolbar); } static void drag_data_received_cb (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time_, EphyEditableToolbar *etoolbar) { EphyToolbarsToolbar *toolbar; EphyToolbarsToolbar *parent; EphyToolbarsItem *sibling; const char *type = NULL; GdkAtom target; EggAction *action; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); toolbar = (EphyToolbarsToolbar *)g_object_get_data (G_OBJECT (widget), "toolbar_data"); if (!toolbar) { sibling = (EphyToolbarsItem *)g_object_get_data (G_OBJECT (widget), "item_data"); g_return_if_fail (sibling != NULL); parent = sibling->parent; } else { sibling = NULL; parent = toolbar; } g_return_if_fail (parent != NULL); target = gtk_drag_dest_find_target (widget, context, NULL); if (target == gdk_atom_intern (EPHY_DND_URL_TYPE, FALSE)) { type = EPHY_DND_URL_TYPE; } action = ephy_editable_toolbar_get_action (etoolbar, type, selection_data->data); if (action) { ephy_toolbars_group_add_item (etoolbar->priv->group, parent, sibling, action->name); etoolbar->priv->toolbars_dirty = TRUE; queue_ui_update (etoolbar); } } static void drag_data_delete_cb (GtkWidget *widget, GdkDragContext *context, EphyEditableToolbar *etoolbar) { EphyToolbarsItem *node; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); node = (EphyToolbarsItem *)g_object_get_data (G_OBJECT (widget), "item_data"); g_return_if_fail (node != NULL); ephy_toolbars_group_remove_item (etoolbar->priv->group, node); etoolbar->priv->toolbars_dirty = TRUE; queue_ui_update (etoolbar); } static void drag_data_get_cb (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint32 time, EphyEditableToolbar *etoolbar) { EggAction *action; const char *target; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); action = EGG_ACTION (g_object_get_data (G_OBJECT (widget), "egg-action")); target = action->name; LOG ("Drag data get %s", action->name); gtk_selection_data_set (selection_data, selection_data->target, 8, target, strlen (target)); } static GtkWidget * get_item_widget (EphyEditableToolbar *t, gpointer data) { GtkWidget *widget; char *path; path = ephy_toolbars_group_get_path (t->priv->group, data); g_return_val_if_fail (path != NULL, NULL); widget = egg_menu_merge_get_widget (t->priv->merge, path); g_free (path); return widget; } static void connect_item_drag_source (EphyToolbarsItem *item, EphyEditableToolbar *etoolbar) { GtkWidget *toolitem; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_return_if_fail (item != NULL); toolitem = get_item_widget (etoolbar, item); if (!g_object_get_data (G_OBJECT (toolitem), "drag_source_set")) { g_object_set_data (G_OBJECT (toolitem), "drag_source_set", GINT_TO_POINTER (TRUE)); g_signal_connect (toolitem, "drag_data_get", G_CALLBACK (drag_data_get_cb), etoolbar); g_signal_connect (toolitem, "drag_data_delete", G_CALLBACK (drag_data_delete_cb), etoolbar); } } static void disconnect_item_drag_source (EphyToolbarsItem *item, EphyEditableToolbar *etoolbar) { GtkWidget *toolitem; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_return_if_fail (item != NULL); toolitem = get_item_widget (etoolbar, item); if (g_object_get_data (G_OBJECT (toolitem), "drag_source_set")) { g_object_set_data (G_OBJECT (toolitem), "drag_source_set", GINT_TO_POINTER (FALSE)); g_signal_handlers_disconnect_by_func (toolitem, G_CALLBACK (drag_data_get_cb), etoolbar); g_signal_handlers_disconnect_by_func (toolitem, G_CALLBACK (drag_data_delete_cb), etoolbar); } } static void setup_toolbar (EphyToolbarsToolbar *toolbar, EphyEditableToolbar *etoolbar) { GtkWidget *widget; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_return_if_fail (toolbar != NULL); widget = get_item_widget (etoolbar, toolbar); g_object_set_data (G_OBJECT (widget), "toolbar_data", toolbar); if (!g_object_get_data (G_OBJECT (widget), "drag_dest_set")) { LOG ("Setup drag dest for toolbar %s", toolbar->id) g_object_set_data (G_OBJECT (widget), "drag_dest_set", GINT_TO_POINTER (TRUE)); gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_ALL, dest_drag_types, 2, GDK_ACTION_MOVE | GDK_ACTION_COPY); g_signal_connect (widget, "drag_data_received", G_CALLBACK (drag_data_received_cb), etoolbar); } etoolbar->priv->last_toolbar = widget; } static void setup_item (EphyToolbarsItem *item, EphyEditableToolbar *etoolbar) { GtkWidget *toolitem; char *path; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_return_if_fail (item != NULL); path = ephy_toolbars_group_get_path (etoolbar->priv->group, item); g_return_if_fail (path != NULL); toolitem = get_item_widget (etoolbar, item); g_object_set_data (G_OBJECT (toolitem), "item_data", item); LOG ("Setup drag dest for toolbar item %s %p", path, toolitem); if (!g_object_get_data (G_OBJECT (toolitem), "drag_dest_set")) { g_object_set_data (G_OBJECT (toolitem), "drag_dest_set", GINT_TO_POINTER (TRUE)); gtk_drag_dest_set (toolitem, GTK_DEST_DEFAULT_ALL, dest_drag_types, 2, GDK_ACTION_COPY | GDK_ACTION_MOVE); g_signal_connect (toolitem, "drag_data_received", G_CALLBACK (drag_data_received_cb), etoolbar); } g_free (path); } static void ensure_toolbar_min_size (EphyToolbarsToolbar *toolbar, EphyEditableToolbar *t) { GtkWidget *widget; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (t)); g_return_if_fail (toolbar != NULL); widget = get_item_widget (t, toolbar); if (EGG_TOOLBAR (widget)->num_children == 0) { gtk_widget_set_size_request (widget, -1, 20); } else { gtk_widget_set_size_request (widget, -1, -1); } } static void do_merge (EphyEditableToolbar *t) { char *str; guint ui_id; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (t)); str = ephy_toolbars_group_to_string (t->priv->group); g_return_if_fail (str != NULL); LOG ("Merge UI\n%s", str) ui_id = egg_menu_merge_add_ui_from_string (t->priv->merge, str, -1, NULL); if (t->priv->ui_id != 0) { LOG ("Remove old toolbar") egg_menu_merge_remove_ui (t->priv->merge, t->priv->ui_id); } t->priv->ui_id = ui_id; egg_menu_merge_ensure_update (t->priv->merge); ephy_toolbars_group_foreach_toolbar (t->priv->group, (EphyToolbarsGroupForeachToolbarFunc) setup_toolbar, t); ephy_toolbars_group_foreach_item (t->priv->group, (EphyToolbarsGroupForeachItemFunc) setup_item, t); if (t->priv->edit_mode) { ephy_toolbars_group_foreach_item (t->priv->group, (EphyToolbarsGroupForeachItemFunc) connect_item_drag_source, t); } ephy_toolbars_group_foreach_toolbar (t->priv->group, (EphyToolbarsGroupForeachToolbarFunc) ensure_toolbar_min_size, t); g_free (str); } static void ensure_action (EphyToolbarsItem *item, EphyEditableToolbar *t) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (t)); g_return_if_fail (item != NULL); ephy_editable_toolbar_get_action (t, NULL, item->action); } static void group_changed_cb (EphyToolbarsGroup *group, EphyEditableToolbar *t) { g_return_if_fail (IS_EPHY_TOOLBARS_GROUP (group)); g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (t)); t->priv->toolbars_dirty = TRUE; ephy_toolbars_group_foreach_item (t->priv->group, (EphyToolbarsGroupForeachItemFunc) ensure_action, t); queue_ui_update (t); } static void ephy_editable_toolbar_set_group (EphyEditableToolbar *t, EphyToolbarsGroup *group) { g_return_if_fail (IS_EPHY_TOOLBARS_GROUP (group)); g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (t)); t->priv->group = group; g_signal_connect_object (group, "changed", G_CALLBACK (group_changed_cb), t, 0); } static void ephy_editable_toolbar_set_merge (EphyEditableToolbar *t, EggMenuMerge *merge) { g_return_if_fail (EGG_IS_MENU_MERGE (merge)); g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (t)); t->priv->merge = merge; LOG ("Got MenuMerge") ephy_toolbars_group_foreach_item (t->priv->group, (EphyToolbarsGroupForeachItemFunc) ensure_action, t); do_merge (t); } static void ephy_editable_toolbar_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { EphyEditableToolbar *t = EPHY_EDITABLE_TOOLBAR (object); switch (prop_id) { case PROP_MENU_MERGE: ephy_editable_toolbar_set_merge (t, g_value_get_object (value)); break; case PROP_TOOLBARS_GROUP: ephy_editable_toolbar_set_group (t, g_value_get_object (value)); break; } } static void ephy_editable_toolbar_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { EphyEditableToolbar *t = EPHY_EDITABLE_TOOLBAR (object); switch (prop_id) { case PROP_MENU_MERGE: g_value_set_object (value, t->priv->merge); break; case PROP_TOOLBARS_GROUP: g_value_set_object (value, t->priv->group); break; } } static void ephy_editable_toolbar_class_init (EphyEditableToolbarClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); object_class->finalize = ephy_editable_toolbar_finalize; object_class->set_property = ephy_editable_toolbar_set_property; object_class->get_property = ephy_editable_toolbar_get_property; klass->get_action = impl_get_action; 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_GROUP, g_param_spec_object ("ToolbarsGroup", "ToolbarsGroup", "Toolbars Group", EPHY_TOOLBARS_GROUP_TYPE, G_PARAM_READWRITE)); } static void ephy_editable_toolbar_init (EphyEditableToolbar *t) { t->priv = g_new0 (EphyEditableToolbarPrivate, 1); t->priv->merge = NULL; t->priv->editor = NULL; t->priv->ui_id = 0; t->priv->toolbars_dirty = FALSE; t->priv->editor_pos_dirty = FALSE; t->priv->editor_sheet_dirty = FALSE; t->priv->edit_mode = FALSE; t->priv->actions_list = NULL; } static void ephy_editable_toolbar_finalize (GObject *object) { EphyEditableToolbar *t = EPHY_EDITABLE_TOOLBAR (object); g_return_if_fail (object != NULL); g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (object)); if (t->priv->editor) { gtk_widget_destroy (t->priv->editor); } g_free (t->priv); LOG ("EphyEditableToolbar finalized") G_OBJECT_CLASS (parent_class)->finalize (object); } EphyEditableToolbar * ephy_editable_toolbar_new (EggMenuMerge *merge) { EphyEditableToolbar *t; t = EPHY_EDITABLE_TOOLBAR (g_object_new (EPHY_EDITABLE_TOOLBAR_TYPE, "MenuMerge", merge, NULL)); g_return_val_if_fail (t->priv != NULL, NULL); return t; } static void editor_get_dimensions (EphyEditableToolbar *etoolbar, GtkWidget *toolbar, int *x, int *y, int *width, int *height) { GtkWidget *vbox; GtkBin *popwin; GtkWidget *widget; GtkWidget *table; GtkWidget *label_zone; GtkWidget *action_zone; GtkWidget *popup; GtkRequisition requisition; int avail_height; int avail_width; int work_height; int work_width; widget = toolbar; popup = etoolbar->priv->scrolled_window; popwin = GTK_BIN (etoolbar->priv->editor); vbox = etoolbar->priv->main_box; table = etoolbar->priv->table; action_zone = etoolbar->priv->action_zone; label_zone = etoolbar->priv->label_zone; gdk_window_get_origin (toolbar->window, x, y); *y += toolbar->allocation.y + toolbar->allocation.height; avail_height = gdk_screen_height () - *y; avail_width = gdk_screen_width () - *x; gtk_widget_size_request (table, &requisition); *width = MIN (avail_width, requisition.width); *height = MIN (avail_height, requisition.height); work_width = (2 * GTK_BIN (popwin)->child->style->xthickness + 2 * GTK_CONTAINER (popwin)->border_width + 2 * GTK_CONTAINER (popwin->child)->border_width + 2 * GTK_CONTAINER (vbox)->border_width + 2 * GTK_CONTAINER (popup)->border_width + 2 * GTK_CONTAINER (GTK_BIN (popup)->child)->border_width + 2 * GTK_BIN (popup)->child->style->xthickness); *width += work_width; work_height = (2 * GTK_BIN (popwin)->child->style->ythickness + 2 * GTK_CONTAINER (popwin)->border_width + 2 * GTK_CONTAINER (popwin->child)->border_width + 2 * GTK_CONTAINER (vbox)->border_width + 2 * GTK_CONTAINER (popup)->border_width + 2 * GTK_CONTAINER (GTK_BIN (popup)->child)->border_width + 2 * GTK_BIN (popup)->child->style->ythickness); *height += work_height; gtk_widget_size_request (label_zone, &requisition); *height += requisition.height; gtk_widget_size_request (action_zone, &requisition); *height += requisition.height; /* Vbox spacing */ *height += 2 * 12; *x += (toolbar->allocation.x + toolbar->allocation.width)/2 - (*width / 2); } static void hide_editor (EphyEditableToolbar *etoolbar) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); gtk_grab_remove (GTK_WIDGET (etoolbar->priv->editor)); gtk_widget_hide (GTK_WIDGET (etoolbar->priv->editor)); } static void editor_close_cb (GtkWidget *button, EphyEditableToolbar *etoolbar) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); etoolbar->priv->edit_mode = FALSE; ephy_toolbars_group_foreach_item (etoolbar->priv->group, (EphyToolbarsGroupForeachItemFunc) disconnect_item_drag_source, etoolbar); hide_editor (etoolbar); } static void editor_add_toolbar_cb (GtkWidget *button, EphyEditableToolbar *etoolbar) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); ephy_toolbars_group_add_toolbar (etoolbar->priv->group); etoolbar->priv->toolbars_dirty = TRUE; etoolbar->priv->editor_pos_dirty = TRUE; queue_ui_update (etoolbar); } static void editor_drag_data_received_cb (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time_, EphyEditableToolbar *etoolbar) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); etoolbar->priv->editor_sheet_dirty = TRUE; etoolbar->priv->editor_pos_dirty = TRUE; queue_ui_update (etoolbar); } static void editor_drag_data_delete_cb (GtkWidget *widget, GdkDragContext *context, EphyEditableToolbar *etoolbar) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); etoolbar->priv->editor_sheet_dirty = TRUE; etoolbar->priv->editor_pos_dirty = TRUE; queue_ui_update (etoolbar); } static void setup_editor (EphyEditableToolbar *etoolbar) { GtkWidget *editor; GtkWidget *scrolled_window; GtkWidget *vbox; GtkWidget *label_hbox; GtkWidget *image; GtkWidget *label; GtkWidget *bbox; GtkWidget *button; GtkWidget *frame; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); editor = gtk_window_new (GTK_WINDOW_POPUP); etoolbar->priv->editor = editor; frame = gtk_frame_new (NULL); gtk_widget_show (frame); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); gtk_container_add (GTK_CONTAINER (editor), frame); vbox = gtk_vbox_new (FALSE, 12); etoolbar->priv->main_box = vbox; gtk_container_set_border_width (GTK_CONTAINER (vbox), 12); gtk_widget_show (vbox); gtk_container_add (GTK_CONTAINER (frame), vbox); scrolled_window = gtk_scrolled_window_new (NULL, NULL); etoolbar->priv->scrolled_window = scrolled_window; gtk_widget_show (scrolled_window); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0); label_hbox = gtk_hbox_new (FALSE, 6); etoolbar->priv->label_zone = label_hbox; gtk_widget_show (label_hbox); gtk_box_pack_start (GTK_BOX (vbox), label_hbox, FALSE, FALSE, 0); image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG); gtk_widget_show (image); gtk_box_pack_start (GTK_BOX (label_hbox), image, FALSE, FALSE, 0); label = gtk_label_new (_("Drag an item onto the toolbars above to add it, " "from the toolbars in the items table to remove it.")); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (label_hbox), label, FALSE, TRUE, 0); bbox = gtk_hbutton_box_new (); gtk_box_set_spacing (GTK_BOX (bbox), 10); etoolbar->priv->action_zone = bbox; gtk_widget_show (bbox); gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END); gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0); button = gtk_button_new_from_stock (GTK_STOCK_ADD); gtk_widget_show (button); gtk_button_set_label (GTK_BUTTON (button), _("Add Toolbar")); g_signal_connect (button, "clicked", G_CALLBACK (editor_add_toolbar_cb), etoolbar); gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0); button = gtk_button_new_from_stock (GTK_STOCK_CLOSE); gtk_widget_show (button); g_signal_connect (button, "clicked", G_CALLBACK (editor_close_cb), etoolbar); gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0); update_editor_sheet (etoolbar); update_editor_position (etoolbar); } static void add_to_list (EphyToolbarsItem *item, GList **l) { g_return_if_fail (item != NULL); *l = g_list_append (*l, item); } static void update_editor_sheet (EphyEditableToolbar *etoolbar) { GList *l; GList *to_drag = NULL; int x, y, height, width; GtkWidget *table; GtkWidget *viewport; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); viewport = GTK_BIN (etoolbar->priv->scrolled_window)->child; if (viewport) { table = GTK_BIN (viewport)->child; gtk_container_remove (GTK_CONTAINER (viewport), table); } table = gtk_table_new (0, 0, TRUE); etoolbar->priv->table = table; gtk_container_set_border_width (GTK_CONTAINER (table), 12); gtk_table_set_col_spacings (GTK_TABLE (table), 12); gtk_table_set_row_spacings (GTK_TABLE (table), 12); gtk_widget_show (table); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (etoolbar->priv->scrolled_window), table); gtk_drag_dest_set (table, GTK_DEST_DEFAULT_ALL, dest_drag_types, 2, GDK_ACTION_MOVE); g_signal_connect (table, "drag_data_received", G_CALLBACK (editor_drag_data_received_cb), etoolbar); ephy_toolbars_group_foreach_available (etoolbar->priv->group, (EphyToolbarsGroupForeachItemFunc) add_to_list, &to_drag); x = y = 0; width = 4; height = (g_list_length (to_drag) - 1) / width + 1; gtk_table_resize (GTK_TABLE (etoolbar->priv->table), height, width); for (l = to_drag; l != NULL; l = l->next) { GtkWidget *event_box; GtkWidget *vbox; GtkWidget *icon; GtkWidget *label; EphyToolbarsItem *node = (EphyToolbarsItem *) (l->data); EggAction *action; action = ephy_editable_toolbar_get_action (etoolbar, NULL, node->action); g_return_if_fail (action != NULL); event_box = gtk_event_box_new (); gtk_widget_show (event_box); gtk_drag_source_set (event_box, GDK_BUTTON1_MASK, source_drag_types, 1, GDK_ACTION_MOVE); g_signal_connect (event_box, "drag_data_get", G_CALLBACK (drag_data_get_cb), etoolbar); g_signal_connect (event_box, "drag_data_delete", G_CALLBACK (editor_drag_data_delete_cb), etoolbar); g_object_set_data (G_OBJECT (event_box), "egg-action", action); vbox = gtk_vbox_new (0, FALSE); gtk_widget_show (vbox); gtk_container_add (GTK_CONTAINER (event_box), vbox); icon = gtk_image_new_from_stock (action->stock_id ? action->stock_id : GTK_STOCK_DND, GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_widget_show (icon); gtk_box_pack_start (GTK_BOX (vbox), icon, FALSE, TRUE, 0); label = gtk_label_new_with_mnemonic (action->label); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); gtk_table_attach_defaults (GTK_TABLE (etoolbar->priv->table), event_box, x, x + 1, y, y + 1); x ++; if (x >= width) { x = 0; y++; } } g_list_free (to_drag); } static gboolean update_editor_position (EphyEditableToolbar *etoolbar) { GtkWidget *editor; int x, y, height, width; g_return_val_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar), FALSE); editor_get_dimensions (etoolbar, etoolbar->priv->last_toolbar, &x, &y, &width, &height); editor = etoolbar->priv->editor; gtk_widget_set_size_request (GTK_WIDGET (editor), width, height); gtk_window_move (GTK_WINDOW (editor), x, y); LOG ("Editor moved to %d %d %d %d", x, y, width, height) return FALSE; } static gboolean button_press_cb (GtkWidget *w, GdkEvent *event, EphyEditableToolbar *etoolbar) { GtkWidget *widget; GtkWidget *toolitem; g_return_val_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar), FALSE); widget = gtk_get_event_widget (event); toolitem = gtk_widget_get_ancestor (widget, EGG_TYPE_TOOL_ITEM); if (toolitem == NULL) return FALSE; switch (event->type) { case GDK_BUTTON_PRESS: gtk_drag_begin (toolitem, gtk_target_list_new (source_drag_types, 1), GDK_ACTION_MOVE, 1, event); return TRUE; default: break; } return FALSE; } static void show_editor (EphyEditableToolbar *etoolbar) { GtkWidget *editor = etoolbar->priv->editor; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_return_if_fail (editor != NULL); gtk_widget_show (GTK_WIDGET (editor)); gtk_grab_add (editor); g_signal_connect (editor, "button_press_event", G_CALLBACK (button_press_cb), etoolbar); } static void set_action_sensitive (EphyToolbarsItem *item, EphyEditableToolbar *etoolbar) { EggAction *action; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_return_if_fail (item != NULL); if (!item->separator) { action = find_action (etoolbar, item->action); g_object_set (action, "sensitive", TRUE, NULL); } } void ephy_editable_toolbar_edit (EphyEditableToolbar *etoolbar) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); etoolbar->priv->edit_mode = TRUE; ephy_toolbars_group_foreach_item (etoolbar->priv->group, (EphyToolbarsGroupForeachItemFunc) connect_item_drag_source, etoolbar); ephy_toolbars_group_foreach_item (etoolbar->priv->group, (EphyToolbarsGroupForeachItemFunc) set_action_sensitive, etoolbar); setup_editor (etoolbar); show_editor (etoolbar); } EggAction * ephy_editable_toolbar_get_action (EphyEditableToolbar *etoolbar, const char *type, const char *name) { EphyEditableToolbarClass *klass = EPHY_EDITABLE_TOOLBAR_GET_CLASS (etoolbar); return klass->get_action (etoolbar, type, name); }