From 4a5be7c74e1df189d7f91c479a0da050d8272306 Mon Sep 17 00:00:00 2001 From: Tristan Van Berkom Date: Wed, 24 Nov 2010 20:00:10 +0900 Subject: [PATCH] Getting closer to updating the treemenu view properly from the model signals --- gtk/gtktreemenu.c | 199 ++++++++++++++++++++++++++++++++++------------ tests/testcombo.c | 6 +- 2 files changed, 152 insertions(+), 53 deletions(-) diff --git a/gtk/gtktreemenu.c b/gtk/gtktreemenu.c index db970c99ff..e9d63514e8 100644 --- a/gtk/gtktreemenu.c +++ b/gtk/gtktreemenu.c @@ -78,6 +78,9 @@ static void gtk_tree_menu_populate (GtkTreeMenu static GtkWidget *gtk_tree_menu_create_item (GtkTreeMenu *menu, GtkTreeIter *iter, gboolean header_item); +static void gtk_tree_menu_create_submenu (GtkTreeMenu *menu, + GtkWidget *item, + GtkTreePath *path); static void gtk_tree_menu_set_area (GtkTreeMenu *menu, GtkCellArea *area); static GtkWidget *gtk_tree_menu_get_path_item (GtkTreeMenu *menu, @@ -618,8 +621,17 @@ gtk_tree_menu_get_path_item (GtkTreeMenu *menu, GtkTreeRowReference *row = g_object_get_qdata (G_OBJECT (child), tree_menu_path_quark); - if (row && gtk_tree_row_reference_valid (row)) - path = gtk_tree_row_reference_get_path (row); + if (row) + { + path = gtk_tree_row_reference_get_path (row); + + if (!path) + /* Return any first child where it's row-reference became invalid, + * this is because row-references get null paths before we recieve + * the "row-deleted" signal. + */ + item = child; + } } else { @@ -628,6 +640,13 @@ gtk_tree_menu_get_path_item (GtkTreeMenu *menu, /* It's always a cellview */ if (GTK_IS_CELL_VIEW (view)) path = gtk_cell_view_get_displayed_row (GTK_CELL_VIEW (view)); + + if (!path) + /* Return any first child where it's row-reference became invalid, + * this is because row-references get null paths before we recieve + * the "row-deleted" signal. + */ + item = child; } if (path) @@ -650,43 +669,97 @@ gtk_tree_menu_path_in_menu (GtkTreeMenu *menu, gboolean *header_item) { GtkTreeMenuPrivate *priv = menu->priv; - GtkTreePath *parent_path = gtk_tree_path_copy (path); gboolean in_menu = FALSE; gboolean is_header = FALSE; /* Check if the is in root of the model */ - if (gtk_tree_path_get_depth (parent_path) == 1) + if (gtk_tree_path_get_depth (path) == 1) { if (!priv->root) - in_menu = TRUE; + { + g_print ("gtk_tree_menu_path_in_menu: Found in root menu !\n"); + in_menu = TRUE; + } } /* If we are a submenu, compare the parent path */ - else if (priv->root && gtk_tree_path_up (parent_path)) + else if (priv->root && gtk_tree_path_get_depth (path) > 1) { - GtkTreePath *root_path = - gtk_tree_row_reference_get_path (priv->root); + GtkTreePath *root_path = gtk_tree_row_reference_get_path (priv->root); + GtkTreePath *parent_path = gtk_tree_path_copy (path); + + gtk_tree_path_up (parent_path); if (gtk_tree_path_compare (root_path, parent_path) == 0) - in_menu = TRUE; + { + in_menu = TRUE; + g_print ("gtk_tree_menu_path_in_menu: Found in this menu !\n"); + } if (!in_menu && priv->menu_with_header && gtk_tree_path_compare (root_path, path) == 0) { + g_print ("gtk_tree_menu_path_in_menu: Found as menu header !\n"); in_menu = TRUE; is_header = TRUE; } - gtk_tree_path_free (root_path); + gtk_tree_path_free (parent_path); } - gtk_tree_path_free (parent_path); - if (header_item) *header_item = is_header; return in_menu; } +static GtkWidget * +gtk_tree_menu_path_needs_submenu (GtkTreeMenu *menu, + GtkTreePath *search) +{ + GtkWidget *item = NULL; + GList *children, *l; + GtkTreePath *parent_path; + + if (gtk_tree_path_get_depth (search) <= 1) + return NULL; + + parent_path = gtk_tree_path_copy (search); + gtk_tree_path_up (parent_path); + + children = gtk_container_get_children (GTK_CONTAINER (menu)); + + for (l = children; item == NULL && l != NULL; l = l->next) + { + GtkWidget *child = l->data; + GtkTreePath *path = NULL; + + /* Separators dont get submenus, if it already has a submenu then let + * the submenu handle inserted rows */ + if (!GTK_IS_SEPARATOR_MENU_ITEM (child) && + !gtk_menu_item_get_submenu (GTK_MENU_ITEM (child))) + { + GtkWidget *view = gtk_bin_get_child (GTK_BIN (child)); + + /* It's always a cellview */ + if (GTK_IS_CELL_VIEW (view)) + path = gtk_cell_view_get_displayed_row (GTK_CELL_VIEW (view)); + } + + if (path) + { + if (gtk_tree_path_compare (parent_path, path) == 0) + item = child; + + gtk_tree_path_free (path); + } + } + + g_list_free (children); + gtk_tree_path_free (parent_path); + + return item; +} + static void row_inserted_cb (GtkTreeModel *model, GtkTreePath *path, @@ -695,11 +768,11 @@ row_inserted_cb (GtkTreeModel *model, { GtkTreeMenuPrivate *priv = menu->priv; gint *indices, index, depth; + GtkWidget *item; /* If the iter should be in this menu then go ahead and insert it */ if (gtk_tree_menu_path_in_menu (menu, path, NULL)) { - GtkWidget *item; if (priv->wrap_width > 0) rebuild_menu (menu); @@ -728,6 +801,19 @@ row_inserted_cb (GtkTreeModel *model, gtk_cell_area_context_flush (menu->priv->context); } } + else + { + /* Create submenus for iters if we need to */ + item = gtk_tree_menu_path_needs_submenu (menu, path); + if (item) + { + GtkTreePath *item_path = gtk_tree_path_copy (path); + + gtk_tree_path_up (item_path); + gtk_tree_menu_create_submenu (menu, item, item_path); + gtk_tree_path_free (item_path); + } + } } static void @@ -737,29 +823,25 @@ row_deleted_cb (GtkTreeModel *model, { GtkTreeMenuPrivate *priv = menu->priv; GtkWidget *item; - gboolean header_item; - gboolean in_menu; - - in_menu = gtk_tree_menu_path_in_menu (menu, path, &header_item); /* If it's the header item we leave it to the parent menu * to remove us from its menu */ - if (!header_item && in_menu) + item = gtk_tree_menu_get_path_item (menu, path); + + g_print ("Deleting item %p\n", item); + + if (item) { - item = gtk_tree_menu_get_path_item (menu, path); - if (item) + if (priv->wrap_width > 0) + rebuild_menu (menu); + else { - if (priv->wrap_width > 0) - rebuild_menu (menu); - else - { - /* Get rid of the deleted item */ - gtk_widget_destroy (item); - - /* Resize everything */ - gtk_cell_area_context_flush (menu->priv->context); - } + /* Get rid of the deleted item */ + gtk_widget_destroy (item); + + /* Resize everything */ + gtk_cell_area_context_flush (menu->priv->context); } } } @@ -1082,6 +1164,41 @@ relayout_item (GtkTreeMenu *menu, current_row, current_row + rows); } +static void +gtk_tree_menu_create_submenu (GtkTreeMenu *menu, + GtkWidget *item, + GtkTreePath *path) +{ + GtkTreeMenuPrivate *priv = menu->priv; + GtkWidget *view; + GtkWidget *submenu; + + view = gtk_bin_get_child (GTK_BIN (item)); + gtk_cell_view_set_draw_sensitive (GTK_CELL_VIEW (view), TRUE); + + submenu = gtk_tree_menu_new_with_area (priv->area); + + gtk_tree_menu_set_row_separator_func (GTK_TREE_MENU (submenu), + priv->row_separator_func, + priv->row_separator_data, + priv->row_separator_destroy); + gtk_tree_menu_set_header_func (GTK_TREE_MENU (submenu), + priv->header_func, + priv->header_data, + priv->header_destroy); + + gtk_tree_menu_set_wrap_width (GTK_TREE_MENU (submenu), priv->wrap_width); + gtk_tree_menu_set_row_span_column (GTK_TREE_MENU (submenu), priv->row_span_col); + gtk_tree_menu_set_column_span_column (GTK_TREE_MENU (submenu), priv->col_span_col); + + gtk_tree_menu_set_model_internal (GTK_TREE_MENU (submenu), priv->model); + gtk_tree_menu_set_root (GTK_TREE_MENU (submenu), path); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu); + + g_signal_connect (submenu, "menu-activate", + G_CALLBACK (submenu_activated_cb), menu); +} + static GtkWidget * gtk_tree_menu_create_item (GtkTreeMenu *menu, GtkTreeIter *iter, @@ -1127,27 +1244,7 @@ gtk_tree_menu_create_item (GtkTreeMenu *menu, /* Add a GtkTreeMenu submenu to render the children of this row */ if (header_item == FALSE && gtk_tree_model_iter_has_child (priv->model, iter)) - { - GtkWidget *submenu; - - submenu = gtk_tree_menu_new_with_area (priv->area); - - gtk_tree_menu_set_row_separator_func (GTK_TREE_MENU (submenu), - priv->row_separator_func, - priv->row_separator_data, - priv->row_separator_destroy); - gtk_tree_menu_set_header_func (GTK_TREE_MENU (submenu), - priv->header_func, - priv->header_data, - priv->header_destroy); - - gtk_tree_menu_set_model_internal (GTK_TREE_MENU (submenu), priv->model); - gtk_tree_menu_set_root (GTK_TREE_MENU (submenu), path); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu); - - g_signal_connect (submenu, "menu-activate", - G_CALLBACK (submenu_activated_cb), menu); - } + gtk_tree_menu_create_submenu (menu, item, path); } gtk_tree_path_free (path); diff --git a/tests/testcombo.c b/tests/testcombo.c index f321fb0a55..1de03fc79d 100644 --- a/tests/testcombo.c +++ b/tests/testcombo.c @@ -1092,6 +1092,7 @@ main (int argc, char **argv) g_object_set (renderer, "text", "la la la", NULL); gtk_container_add (GTK_CONTAINER (boom), cellview); +#if 0 /* GtkComboBox list */ tmp = gtk_frame_new ("GtkComboBox (list)"); gtk_box_pack_start (GTK_BOX (mainbox), tmp, FALSE, FALSE, 0); @@ -1333,7 +1334,7 @@ main (int argc, char **argv) NULL); gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 0); - +#endif /* Capitals */ tmp = gtk_frame_new ("Where are you ?"); @@ -1368,6 +1369,7 @@ main (int argc, char **argv) gdk_threads_add_timeout (1000, (GSourceFunc) capital_animation, model); #endif +#if 0 /* Ellipsizing growing combos */ tmp = gtk_frame_new ("Unconstrained Menu"); gtk_box_pack_start (GTK_BOX (mainbox), tmp, FALSE, FALSE, 0); @@ -1388,7 +1390,7 @@ main (int argc, char **argv) "text", 0, NULL); gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 0); gtk_combo_box_set_popup_fixed_width (GTK_COMBO_BOX (combobox), FALSE); - +#endif gtk_widget_show_all (window); gtk_main ();