[gtk/stack-fixes: 8/9] stack sidebar: Use the selection model
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/stack-fixes: 8/9] stack sidebar: Use the selection model
- Date: Sun, 10 Feb 2019 22:22:08 +0000 (UTC)
commit 339041cb88c6333c3f08dc647bfacf229a79abdf
Author: Matthias Clasen <mclasen redhat com>
Date: Fri Feb 8 18:27:10 2019 -0500
stack sidebar: Use the selection model
Make GtkStackSidebar and GtkStack communicate via
the selection model that GtkStack now exposes.
This is parallel to the GtkStackSwitcher changes
in the previous commit.
gtk/gtkstacksidebar.c | 251 +++++++++++++++++++++-----------------------------
1 file changed, 103 insertions(+), 148 deletions(-)
---
diff --git a/gtk/gtkstacksidebar.c b/gtk/gtkstacksidebar.c
index bf1b13759d..4ac5c7f713 100644
--- a/gtk/gtkstacksidebar.c
+++ b/gtk/gtkstacksidebar.c
@@ -28,6 +28,7 @@
#include "gtkscrolledwindow.h"
#include "gtkseparator.h"
#include "gtkstylecontext.h"
+#include "gtkselectionmodel.h"
#include "gtkprivate.h"
#include "gtkintl.h"
@@ -58,8 +59,8 @@ struct _GtkStackSidebarPrivate
{
GtkListBox *list;
GtkStack *stack;
+ GtkSelectionModel *pages;
GHashTable *rows;
- gboolean in_child_changed;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkStackSidebar, gtk_stack_sidebar, GTK_TYPE_BIN)
@@ -129,30 +130,14 @@ sort_list (GtkListBoxRow *row1,
GtkListBoxRow *row2,
gpointer userdata)
{
- GtkStackSidebar *sidebar = GTK_STACK_SIDEBAR (userdata);
- GtkStackSidebarPrivate *priv = gtk_stack_sidebar_get_instance_private (sidebar);
- GtkWidget *item;
- GtkWidget *widget;
gint left = 0; gint right = 0;
if (row1)
- {
- item = gtk_bin_get_child (GTK_BIN (row1));
- widget = g_object_get_data (G_OBJECT (item), "stack-child");
- g_object_get (gtk_stack_get_page (GTK_STACK (priv->stack), widget),
- "position", &left,
- NULL);
- }
+ left = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (row1), "child-index"));
if (row2)
- {
- item = gtk_bin_get_child (GTK_BIN (row2));
- widget = g_object_get_data (G_OBJECT (item), "stack-child");
- g_object_get (gtk_stack_get_page (GTK_STACK (priv->stack), widget),
- "position", &right,
- NULL);
- }
+ right = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (row2), "child-index"));
if (left < right)
return -1;
@@ -170,18 +155,13 @@ gtk_stack_sidebar_row_selected (GtkListBox *box,
{
GtkStackSidebar *sidebar = GTK_STACK_SIDEBAR (userdata);
GtkStackSidebarPrivate *priv = gtk_stack_sidebar_get_instance_private (sidebar);
- GtkWidget *item;
- GtkWidget *widget;
-
- if (priv->in_child_changed)
- return;
+ guint index;
- if (!row)
+ if (row == NULL)
return;
- item = gtk_bin_get_child (GTK_BIN (row));
- widget = g_object_get_data (G_OBJECT (item), "stack-child");
- gtk_stack_set_visible_child (priv->stack, widget);
+ index = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (row), "child-index"));
+ gtk_selection_model_select_item (priv->pages, index, TRUE);
}
static void
@@ -218,24 +198,25 @@ gtk_stack_sidebar_init (GtkStackSidebar *sidebar)
static void
update_row (GtkStackSidebar *sidebar,
- GtkWidget *widget,
+ GtkStackPage *page,
GtkWidget *row)
{
- GtkStackSidebarPrivate *priv = gtk_stack_sidebar_get_instance_private (sidebar);
GtkWidget *item;
gchar *title;
gboolean needs_attention;
+ gboolean visible;
GtkStyleContext *context;
- g_object_get (gtk_stack_get_page (GTK_STACK (priv->stack), widget),
+ g_object_get (page,
"title", &title,
"needs-attention", &needs_attention,
+ "visible", &visible,
NULL);
item = gtk_bin_get_child (GTK_BIN (row));
gtk_label_set_text (GTK_LABEL (item), title);
- gtk_widget_set_visible (row, gtk_widget_get_visible (widget) && title != NULL);
+ gtk_widget_set_visible (row, visible && title != NULL);
context = gtk_widget_get_style_context (row);
if (needs_attention)
@@ -247,29 +228,19 @@ update_row (GtkStackSidebar *sidebar,
}
static void
-on_position_updated (GtkWidget *widget,
- GParamSpec *pspec,
- GtkStackSidebar *sidebar)
-{
- GtkStackSidebarPrivate *priv = gtk_stack_sidebar_get_instance_private (sidebar);
-
- gtk_list_box_invalidate_sort (priv->list);
-}
-
-static void
-on_child_updated (GtkWidget *widget,
- GParamSpec *pspec,
- GtkStackSidebar *sidebar)
+on_page_updated (GtkStackPage *page,
+ GParamSpec *pspec,
+ GtkStackSidebar *sidebar)
{
GtkStackSidebarPrivate *priv = gtk_stack_sidebar_get_instance_private (sidebar);
GtkWidget *row;
- row = g_hash_table_lookup (priv->rows, widget);
- update_row (sidebar, widget, row);
+ row = g_hash_table_lookup (priv->rows, page);
+ update_row (sidebar, page, row);
}
static void
-add_child (GtkWidget *widget,
+add_child (guint position,
GtkStackSidebar *sidebar)
{
GtkStackSidebarPrivate *priv = gtk_stack_sidebar_get_instance_private (sidebar);
@@ -277,144 +248,139 @@ add_child (GtkWidget *widget,
GtkWidget *row;
GtkStackPage *page;
- /* Check we don't actually already know about this widget */
- if (g_hash_table_lookup (priv->rows, widget))
- return;
-
/* Make a pretty item when we add kids */
item = gtk_label_new ("");
gtk_widget_set_halign (item, GTK_ALIGN_START);
gtk_widget_set_valign (item, GTK_ALIGN_CENTER);
row = gtk_list_box_row_new ();
gtk_container_add (GTK_CONTAINER (row), item);
- gtk_widget_show (item);
-
- update_row (sidebar, widget, row);
-
- /* Hook up for events */
- page = gtk_stack_get_page (GTK_STACK (priv->stack), widget);
- g_signal_connect (widget, "notify::visible",
- G_CALLBACK (on_child_updated), sidebar);
- g_signal_connect (page, "notify::title",
- G_CALLBACK (on_child_updated), sidebar);
- g_signal_connect (page, "notify::needs-attention",
- G_CALLBACK (on_child_updated), sidebar);
- g_signal_connect (page, "notify::position",
- G_CALLBACK (on_position_updated), sidebar);
-
- g_object_set_data (G_OBJECT (item), I_("stack-child"), widget);
- g_hash_table_insert (priv->rows, widget, row);
+
+ page = g_list_model_get_item (G_LIST_MODEL (priv->pages), position);
+ update_row (sidebar, page, row);
+
gtk_container_add (GTK_CONTAINER (priv->list), row);
-}
-static void
-remove_child (GtkWidget *widget,
- GtkStackSidebar *sidebar)
-{
- GtkStackSidebarPrivate *priv = gtk_stack_sidebar_get_instance_private (sidebar);
- GtkWidget *row;
+ g_object_set_data (G_OBJECT (row), "child-index", GUINT_TO_POINTER (position));
+ if (gtk_selection_model_is_selected (priv->pages, position))
+ gtk_list_box_select_row (priv->list, GTK_LIST_BOX_ROW (row));
+ else
+ gtk_list_box_unselect_row (priv->list, GTK_LIST_BOX_ROW (row));
- row = g_hash_table_lookup (priv->rows, widget);
- if (!row)
- return;
+ g_signal_connect (page, "notify", G_CALLBACK (on_page_updated), sidebar);
- if (priv->stack)
- {
- GtkStackPage *page = gtk_stack_get_page (GTK_STACK (priv->stack), widget);
- if (page)
- {
- g_signal_handlers_disconnect_by_func (page, on_child_updated, sidebar);
- g_signal_handlers_disconnect_by_func (page, on_position_updated, sidebar);
- }
- }
+ g_hash_table_insert (priv->rows, page, row);
- gtk_container_remove (GTK_CONTAINER (priv->list), row);
- g_hash_table_remove (priv->rows, widget);
+ g_object_unref (page);
}
static void
populate_sidebar (GtkStackSidebar *sidebar)
{
GtkStackSidebarPrivate *priv = gtk_stack_sidebar_get_instance_private (sidebar);
- GtkWidget *widget, *row;
-
- gtk_container_foreach (GTK_CONTAINER (priv->stack), (GtkCallback)add_child, sidebar);
+ guint i;
- widget = gtk_stack_get_visible_child (priv->stack);
- if (widget)
- {
- row = g_hash_table_lookup (priv->rows, widget);
- gtk_list_box_select_row (priv->list, GTK_LIST_BOX_ROW (row));
- }
+ for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (priv->pages)); i++)
+ add_child (i, sidebar);
}
static void
clear_sidebar (GtkStackSidebar *sidebar)
{
GtkStackSidebarPrivate *priv = gtk_stack_sidebar_get_instance_private (sidebar);
+ GHashTableIter iter;
+ GtkStackPage *page;
+ GtkWidget *row;
- gtk_container_foreach (GTK_CONTAINER (priv->stack), (GtkCallback)remove_child, sidebar);
+ g_hash_table_iter_init (&iter, priv->rows);
+ while (g_hash_table_iter_next (&iter, (gpointer *)&page, (gpointer *)&row))
+ {
+ gtk_container_remove (GTK_CONTAINER (priv->list), row);
+ g_hash_table_iter_remove (&iter);
+ g_signal_handlers_disconnect_by_func (page, on_page_updated, sidebar);
+ }
}
static void
-on_child_changed (GtkWidget *widget,
- GParamSpec *pspec,
- GtkStackSidebar *sidebar)
+items_changed_cb (GListModel *model,
+ guint position,
+ guint removed,
+ guint added,
+ GtkStackSidebar *sidebar)
+{
+ /* FIXME: we can do better */
+ clear_sidebar (sidebar);
+ populate_sidebar (sidebar);
+}
+
+static void
+selection_changed_cb (GtkSelectionModel *model,
+ guint position,
+ guint n_items,
+ GtkStackSidebar *sidebar)
{
GtkStackSidebarPrivate *priv = gtk_stack_sidebar_get_instance_private (sidebar);
- GtkWidget *child;
- GtkWidget *row;
+ guint i;
- child = gtk_stack_get_visible_child (GTK_STACK (widget));
- row = g_hash_table_lookup (priv->rows, child);
- if (row != NULL)
+ for (i = position; i < position + n_items; i++)
{
- priv->in_child_changed = TRUE;
- gtk_list_box_select_row (priv->list, GTK_LIST_BOX_ROW (row));
- priv->in_child_changed = FALSE;
+ GtkStackPage *page;
+ GtkWidget *row;
+
+ page = g_list_model_get_item (G_LIST_MODEL (priv->pages), i);
+ row = g_hash_table_lookup (priv->rows, page);
+ if (gtk_selection_model_is_selected (priv->pages, i))
+ gtk_list_box_select_row (priv->list, GTK_LIST_BOX_ROW (row));
+ else
+ gtk_list_box_unselect_row (priv->list, GTK_LIST_BOX_ROW (row));
+ g_object_unref (page);
}
}
static void
-on_stack_child_added (GtkContainer *container,
- GtkWidget *widget,
- GtkStackSidebar *sidebar)
+disconnect_stack_signals (GtkStackSidebar *sidebar)
{
- add_child (widget, sidebar);
+ GtkStackSidebarPrivate *priv = gtk_stack_sidebar_get_instance_private (sidebar);
+
+ g_signal_handlers_disconnect_by_func (priv->pages, items_changed_cb, sidebar);
+ g_signal_handlers_disconnect_by_func (priv->pages, selection_changed_cb, sidebar);
}
static void
-on_stack_child_removed (GtkContainer *container,
- GtkWidget *widget,
- GtkStackSidebar *sidebar)
+connect_stack_signals (GtkStackSidebar *sidebar)
{
- remove_child (widget, sidebar);
+ GtkStackSidebarPrivate *priv = gtk_stack_sidebar_get_instance_private (sidebar);
+
+ g_signal_connect (priv->pages, "items-changed", G_CALLBACK (items_changed_cb), sidebar);
+ g_signal_connect (priv->pages, "selection-changed", G_CALLBACK (selection_changed_cb), sidebar);
}
static void
-disconnect_stack_signals (GtkStackSidebar *sidebar)
+set_stack (GtkStackSidebar *sidebar,
+ GtkStack *stack)
{
GtkStackSidebarPrivate *priv = gtk_stack_sidebar_get_instance_private (sidebar);
- g_signal_handlers_disconnect_by_func (priv->stack, on_stack_child_added, sidebar);
- g_signal_handlers_disconnect_by_func (priv->stack, on_stack_child_removed, sidebar);
- g_signal_handlers_disconnect_by_func (priv->stack, on_child_changed, sidebar);
- g_signal_handlers_disconnect_by_func (priv->stack, disconnect_stack_signals, sidebar);
+ if (stack)
+ {
+ priv->stack = g_object_ref (stack);
+ priv->pages = gtk_stack_get_pages (stack);
+ populate_sidebar (sidebar);
+ connect_stack_signals (sidebar);
+ }
}
static void
-connect_stack_signals (GtkStackSidebar *sidebar)
+unset_stack (GtkStackSidebar *sidebar)
{
GtkStackSidebarPrivate *priv = gtk_stack_sidebar_get_instance_private (sidebar);
- g_signal_connect_after (priv->stack, "add",
- G_CALLBACK (on_stack_child_added), sidebar);
- g_signal_connect_after (priv->stack, "remove",
- G_CALLBACK (on_stack_child_removed), sidebar);
- g_signal_connect (priv->stack, "notify::visible-child",
- G_CALLBACK (on_child_changed), sidebar);
- g_signal_connect_swapped (priv->stack, "destroy",
- G_CALLBACK (disconnect_stack_signals), sidebar);
+ if (priv->stack)
+ {
+ disconnect_stack_signals (sidebar);
+ clear_sidebar (sidebar);
+ g_clear_object (&priv->stack);
+ g_clear_object (&priv->pages);
+ }
}
static void
@@ -422,7 +388,7 @@ gtk_stack_sidebar_dispose (GObject *object)
{
GtkStackSidebar *sidebar = GTK_STACK_SIDEBAR (object);
- gtk_stack_sidebar_set_stack (sidebar, NULL);
+ unset_stack (sidebar);
G_OBJECT_CLASS (gtk_stack_sidebar_parent_class)->dispose (object);
}
@@ -487,28 +453,17 @@ void
gtk_stack_sidebar_set_stack (GtkStackSidebar *sidebar,
GtkStack *stack)
{
- GtkStackSidebarPrivate *priv;
+ GtkStackSidebarPrivate *priv = gtk_stack_sidebar_get_instance_private (sidebar);
g_return_if_fail (GTK_IS_STACK_SIDEBAR (sidebar));
g_return_if_fail (GTK_IS_STACK (stack) || stack == NULL);
- priv = gtk_stack_sidebar_get_instance_private (sidebar);
if (priv->stack == stack)
return;
- if (priv->stack)
- {
- disconnect_stack_signals (sidebar);
- clear_sidebar (sidebar);
- g_clear_object (&priv->stack);
- }
- if (stack)
- {
- priv->stack = g_object_ref (stack);
- populate_sidebar (sidebar);
- connect_stack_signals (sidebar);
- }
+ unset_stack (sidebar);
+ set_stack (sidebar, stack);
gtk_widget_queue_resize (GTK_WIDGET (sidebar));
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]