diff --git a/ChangeLog b/ChangeLog index 95b37d0b83..a4ddcf40ad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,23 @@ 2003-09-15 Matthias Clasen + Smart separators; see + http://mail.gnome.org/archives/gtk-devel-list/2003-September/msg00133.html: + + * gtk/gtkuimanager.c (update_smart_separators): New function which + implements "smart" separators by iterating once over the entries of a + menu, hiding and showing separators as necessary. + (update_node): Mark separators used as fences of placeholders as + hidden. Explicitly added separators are marked as smart. Call + update_smart_separators after updating a menu or toolbar node. + Connect update_smart_separators to "notify::visible" signal on menu + and tool items. + + * tests/merge-[12].ui: Test smart separators. + + Changes to allow setting action state before connecting signal; see + the thread starting at + http://mail.gnome.org/archives/gtk-devel-list/2003-September/msg00140.html: + * gtk/gtkactiongroup.[hc]: (gtk_action_group_add_radio_actions): (gtk_action_group_add_radio_actions_full): Add value parameter to allow setting the currently selected group member before connecting signals. diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 95b37d0b83..a4ddcf40ad 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,5 +1,23 @@ 2003-09-15 Matthias Clasen + Smart separators; see + http://mail.gnome.org/archives/gtk-devel-list/2003-September/msg00133.html: + + * gtk/gtkuimanager.c (update_smart_separators): New function which + implements "smart" separators by iterating once over the entries of a + menu, hiding and showing separators as necessary. + (update_node): Mark separators used as fences of placeholders as + hidden. Explicitly added separators are marked as smart. Call + update_smart_separators after updating a menu or toolbar node. + Connect update_smart_separators to "notify::visible" signal on menu + and tool items. + + * tests/merge-[12].ui: Test smart separators. + + Changes to allow setting action state before connecting signal; see + the thread starting at + http://mail.gnome.org/archives/gtk-devel-list/2003-September/msg00140.html: + * gtk/gtkactiongroup.[hc]: (gtk_action_group_add_radio_actions): (gtk_action_group_add_radio_actions_full): Add value parameter to allow setting the currently selected group member before connecting signals. diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 95b37d0b83..a4ddcf40ad 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,5 +1,23 @@ 2003-09-15 Matthias Clasen + Smart separators; see + http://mail.gnome.org/archives/gtk-devel-list/2003-September/msg00133.html: + + * gtk/gtkuimanager.c (update_smart_separators): New function which + implements "smart" separators by iterating once over the entries of a + menu, hiding and showing separators as necessary. + (update_node): Mark separators used as fences of placeholders as + hidden. Explicitly added separators are marked as smart. Call + update_smart_separators after updating a menu or toolbar node. + Connect update_smart_separators to "notify::visible" signal on menu + and tool items. + + * tests/merge-[12].ui: Test smart separators. + + Changes to allow setting action state before connecting signal; see + the thread starting at + http://mail.gnome.org/archives/gtk-devel-list/2003-September/msg00140.html: + * gtk/gtkactiongroup.[hc]: (gtk_action_group_add_radio_actions): (gtk_action_group_add_radio_actions_full): Add value parameter to allow setting the currently selected group member before connecting signals. diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 95b37d0b83..a4ddcf40ad 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,5 +1,23 @@ 2003-09-15 Matthias Clasen + Smart separators; see + http://mail.gnome.org/archives/gtk-devel-list/2003-September/msg00133.html: + + * gtk/gtkuimanager.c (update_smart_separators): New function which + implements "smart" separators by iterating once over the entries of a + menu, hiding and showing separators as necessary. + (update_node): Mark separators used as fences of placeholders as + hidden. Explicitly added separators are marked as smart. Call + update_smart_separators after updating a menu or toolbar node. + Connect update_smart_separators to "notify::visible" signal on menu + and tool items. + + * tests/merge-[12].ui: Test smart separators. + + Changes to allow setting action state before connecting signal; see + the thread starting at + http://mail.gnome.org/archives/gtk-devel-list/2003-September/msg00140.html: + * gtk/gtkactiongroup.[hc]: (gtk_action_group_add_radio_actions): (gtk_action_group_add_radio_actions_full): Add value parameter to allow setting the currently selected group member before connecting signals. diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 95b37d0b83..a4ddcf40ad 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,5 +1,23 @@ 2003-09-15 Matthias Clasen + Smart separators; see + http://mail.gnome.org/archives/gtk-devel-list/2003-September/msg00133.html: + + * gtk/gtkuimanager.c (update_smart_separators): New function which + implements "smart" separators by iterating once over the entries of a + menu, hiding and showing separators as necessary. + (update_node): Mark separators used as fences of placeholders as + hidden. Explicitly added separators are marked as smart. Call + update_smart_separators after updating a menu or toolbar node. + Connect update_smart_separators to "notify::visible" signal on menu + and tool items. + + * tests/merge-[12].ui: Test smart separators. + + Changes to allow setting action state before connecting signal; see + the thread starting at + http://mail.gnome.org/archives/gtk-devel-list/2003-September/msg00140.html: + * gtk/gtkactiongroup.[hc]: (gtk_action_group_add_radio_actions): (gtk_action_group_add_radio_actions_full): Add value parameter to allow setting the currently selected group member before connecting signals. diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog index bf0bc1a7ed..a810a23007 100644 --- a/docs/reference/ChangeLog +++ b/docs/reference/ChangeLog @@ -1,5 +1,7 @@ 2003-09-15 Matthias Clasen + * gtk/tmpl/gtkuimanager.sgml: Add a paragraph about smart separators. + * gtk/gtk-sections.txt: Add gtk_action_group_add_toggle_actions[_full]. 2003-09-12 Matthias Clasen diff --git a/docs/reference/gtk/tmpl/gtkuimanager.sgml b/docs/reference/gtk/tmpl/gtkuimanager.sgml index 012166f84f..a34872a37e 100644 --- a/docs/reference/gtk/tmpl/gtkuimanager.sgml +++ b/docs/reference/gtk/tmpl/gtkuimanager.sgml @@ -127,6 +127,17 @@ has the path /ui/menubar/JustifyMenu/Left and the toolitem with the same name has path /ui/toolbar1/JustifyToolItems/Left. + +Smart Separators + +The separators created by #GtkUIManager are "smart", i.e. they do not show up in the +UI unless they end up between two visible menu or tool items. Separators which are located +at the very beginning or end of the menu or toolbar containing them, or multiple separators +next to each other, are hidden. This is a useful feature, since the merging of UI elements +from multiple sources can make it hard or impossible to determine in advance whether a +separator will end up in such an unfortunate position. + + @@ -256,6 +267,21 @@ members and should not be accessed directly. @Returns: + + + + + +@GTK_UI_MANAGER_AUTO: +@GTK_UI_MANAGER_MENUBAR: +@GTK_UI_MANAGER_MENU: +@GTK_UI_MANAGER_TOOLBAR: +@GTK_UI_MANAGER_PLACEHOLDER: +@GTK_UI_MANAGER_POPUP: +@GTK_UI_MANAGER_MENUITEM: +@GTK_UI_MANAGER_TOOLITEM: +@GTK_UI_MANAGER_SEPARATOR: + @@ -266,6 +292,8 @@ members and should not be accessed directly. @path: @name: @action: +@type: +@top: diff --git a/gtk/gtkuimanager.c b/gtk/gtkuimanager.c index 03a978dbd9..5a0538e918 100644 --- a/gtk/gtkuimanager.c +++ b/gtk/gtkuimanager.c @@ -102,37 +102,37 @@ struct _NodeUIReference GQuark action_quark; }; -static void gtk_ui_manager_class_init (GtkUIManagerClass *class); -static void gtk_ui_manager_init (GtkUIManager *self); -static void gtk_ui_manager_finalize (GObject *object); -static void gtk_ui_manager_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gtk_ui_manager_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void queue_update (GtkUIManager *self); -static void dirty_all_nodes (GtkUIManager *self); -static GNode *get_child_node (GtkUIManager *self, - GNode *parent, - const gchar *childname, - gint childname_length, - NodeType node_type, - gboolean create, - gboolean top); -static GNode *get_node (GtkUIManager *self, - const gchar *path, - NodeType node_type, - gboolean create); -static gboolean free_node (GNode *node); +static void gtk_ui_manager_class_init (GtkUIManagerClass *class); +static void gtk_ui_manager_init (GtkUIManager *self); +static void gtk_ui_manager_finalize (GObject *object); +static void gtk_ui_manager_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_ui_manager_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void queue_update (GtkUIManager *self); +static void dirty_all_nodes (GtkUIManager *self); +static GNode * get_child_node (GtkUIManager *self, + GNode *parent, + const gchar *childname, + gint childname_length, + NodeType node_type, + gboolean create, + gboolean top); +static GNode * get_node (GtkUIManager *self, + const gchar *path, + NodeType node_type, + gboolean create); +static gboolean free_node (GNode *node); +static void node_prepend_ui_reference (Node *node, + guint merge_id, + GQuark action_quark); +static void node_remove_ui_reference (Node *node, + guint merge_id); -static void node_prepend_ui_reference (Node *node, - guint merge_id, - GQuark action_quark); -static void node_remove_ui_reference (Node *node, - guint merge_id); enum @@ -1569,6 +1569,79 @@ find_toolbar_position (GNode *node, return TRUE; } +enum { + SEPARATOR_MODE_SMART, + SEPARATOR_MODE_VISIBLE, + SEPARATOR_MODE_HIDDEN +}; + +static void +update_smart_separators (GtkWidget *proxy) +{ + GtkWidget *parent = NULL; + + if (GTK_IS_MENU (proxy) || GTK_IS_TOOLBAR (proxy)) + parent = proxy; + else if (GTK_IS_MENU_ITEM (proxy) || GTK_IS_TOOL_ITEM (proxy)) + parent = gtk_widget_get_parent (proxy); + + if (parent) + { + gboolean visible; + GList *children, *cur, *last; + + children = gtk_container_get_children (GTK_CONTAINER (parent)); + + visible = FALSE; + last = NULL; + cur = children; + while (cur) + { + if (GTK_IS_SEPARATOR_MENU_ITEM (cur->data) || + GTK_IS_SEPARATOR_TOOL_ITEM (cur->data)) + { + gint mode = + GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cur->data), + "gtk-separator-mode")); + switch (mode) + { + case SEPARATOR_MODE_VISIBLE: + gtk_widget_show (GTK_WIDGET (cur->data)); + last = NULL; + visible = FALSE; + break; + case SEPARATOR_MODE_HIDDEN: + gtk_widget_hide (GTK_WIDGET (cur->data)); + break; + case SEPARATOR_MODE_SMART: + if (visible) + { + gtk_widget_show (GTK_WIDGET (cur->data)); + last = cur; + visible = FALSE; + } + else + gtk_widget_hide (GTK_WIDGET (cur->data)); + break; + } + } + else if (GTK_WIDGET_VISIBLE (cur->data)) + { + last = NULL; + if (GTK_IS_TEAROFF_MENU_ITEM (cur->data)) + visible = FALSE; + else + visible = TRUE; + } + + cur = cur->next; + } + + if (last) + gtk_widget_hide (GTK_WIDGET (last->data)); + } +} + static void update_node (GtkUIManager *self, GNode *node, @@ -1756,11 +1829,17 @@ update_node (GtkUIManager *self, if (find_menu_position (node, &menushell, &pos)) { - NODE_INFO (node)->proxy = gtk_separator_menu_item_new (); + info->proxy = gtk_separator_menu_item_new (); + g_object_set_data (G_OBJECT (info->proxy), + "gtk-separator-mode", + GINT_TO_POINTER (SEPARATOR_MODE_HIDDEN)); gtk_menu_shell_insert (GTK_MENU_SHELL (menushell), NODE_INFO (node)->proxy, pos); - NODE_INFO (node)->extra = gtk_separator_menu_item_new (); + info->extra = gtk_separator_menu_item_new (); + g_object_set_data (G_OBJECT (info->extra), + "gtk-separator-mode", + GINT_TO_POINTER (SEPARATOR_MODE_HIDDEN)); gtk_menu_shell_insert (GTK_MENU_SHELL (menushell), NODE_INFO (node)->extra, pos+1); } @@ -1795,11 +1874,17 @@ update_node (GtkUIManager *self, item = gtk_separator_tool_item_new (); gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, pos); - NODE_INFO(node)->proxy = GTK_WIDGET (item); + info->proxy = GTK_WIDGET (item); + g_object_set_data (G_OBJECT (info->proxy), + "gtk-separator-mode", + GINT_TO_POINTER (SEPARATOR_MODE_HIDDEN)); item = gtk_separator_tool_item_new (); gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, pos+1); - NODE_INFO (node)->extra = GTK_WIDGET (item); + info->extra = GTK_WIDGET (item); + g_object_set_data (G_OBJECT (info->extra), + "gtk-separator-mode", + GINT_TO_POINTER (SEPARATOR_MODE_HIDDEN)); } } break; @@ -1808,6 +1893,9 @@ update_node (GtkUIManager *self, if (info->proxy && G_OBJECT_TYPE (info->proxy) != GTK_ACTION_GET_CLASS (action)->menu_item_type) { + g_signal_handlers_disconnect_by_func (info->proxy, + G_CALLBACK (update_smart_separators), + 0); gtk_action_disconnect_proxy (info->action, info->proxy); gtk_container_remove (GTK_CONTAINER (info->proxy->parent), info->proxy); @@ -1829,15 +1917,23 @@ update_node (GtkUIManager *self, } else { + g_signal_handlers_disconnect_by_func (info->proxy, + G_CALLBACK (update_smart_separators), + 0); gtk_menu_item_set_submenu (GTK_MENU_ITEM (info->proxy), NULL); gtk_action_connect_proxy (action, info->proxy); } + g_signal_connect (info->proxy, "notify::visible", + G_CALLBACK (update_smart_separators), 0); break; case NODE_TYPE_TOOLITEM: /* remove the proxy if it is of the wrong type ... */ if (info->proxy && G_OBJECT_TYPE (info->proxy) != GTK_ACTION_GET_CLASS (action)->toolbar_item_type) { + g_signal_handlers_disconnect_by_func (info->proxy, + G_CALLBACK (update_smart_separators), + 0); gtk_action_disconnect_proxy (info->action, info->proxy); gtk_container_remove (GTK_CONTAINER (info->proxy->parent), info->proxy); @@ -1859,8 +1955,13 @@ update_node (GtkUIManager *self, } else { + g_signal_handlers_disconnect_by_func (info->proxy, + G_CALLBACK (update_smart_separators), + 0); gtk_action_connect_proxy (action, info->proxy); } + g_signal_connect (info->proxy, "notify::visible", + G_CALLBACK (update_smart_separators), 0); break; case NODE_TYPE_SEPARATOR: if (NODE_INFO (node->parent)->type == NODE_TYPE_TOOLBAR || @@ -1881,6 +1982,9 @@ update_node (GtkUIManager *self, GtkToolItem *item = gtk_separator_tool_item_new (); gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, pos); info->proxy = GTK_WIDGET (item); + g_object_set_data (G_OBJECT (info->proxy), + "gtk-separator-mode", + GINT_TO_POINTER (SEPARATOR_MODE_SMART)); gtk_widget_show (info->proxy); } } @@ -1899,6 +2003,9 @@ update_node (GtkUIManager *self, if (find_menu_position (node, &menushell, &pos)) { info->proxy = gtk_separator_menu_item_new (); + g_object_set_data (G_OBJECT (info->proxy), + "gtk-separator-mode", + GINT_TO_POINTER (SEPARATOR_MODE_SMART)); gtk_menu_shell_insert (GTK_MENU_SHELL (menushell), info->proxy, pos); gtk_widget_show (info->proxy); @@ -1926,6 +2033,12 @@ update_node (GtkUIManager *self, update_node (self, current, add_tearoffs && (info->type != NODE_TYPE_POPUP)); } + if (info->type == NODE_TYPE_MENU) + update_smart_separators (gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy))); + else if (info->type == NODE_TYPE_TOOLBAR) + update_smart_separators (info->proxy); + + /* handle cleanup of dead nodes */ if (node->children == NULL && info->uifiles == NULL) { diff --git a/tests/merge-1.ui b/tests/merge-1.ui index 55b3455592..a7fb9779d4 100644 --- a/tests/merge-1.ui +++ b/tests/merge-1.ui @@ -12,6 +12,7 @@ + diff --git a/tests/merge-2.ui b/tests/merge-2.ui index 18fbc607f6..a073f917dc 100644 --- a/tests/merge-2.ui +++ b/tests/merge-2.ui @@ -3,8 +3,10 @@ - + + + @@ -13,7 +15,7 @@ - +