[gtk/wip/otte/listview: 51/155] listitemmanager: Move list of listitems here
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/listview: 51/155] listitemmanager: Move list of listitems here
- Date: Tue, 4 Feb 2020 19:39:26 +0000 (UTC)
commit aa9538a3036e0bfc6481d679754a8204305983af
Author: Benjamin Otte <otte redhat com>
Date: Wed Feb 6 20:48:08 2019 +0100
listitemmanager: Move list of listitems here
All the listview infrastructure moved with it, so the next step is
moving that back...
gtk/gtklistitemmanager.c | 676 ++++++++++++++++++++++++++++++++++++++--
gtk/gtklistitemmanagerprivate.h | 45 ++-
gtk/gtklistview.c | 658 +++-----------------------------------
3 files changed, 748 insertions(+), 631 deletions(-)
---
diff --git a/gtk/gtklistitemmanager.c b/gtk/gtklistitemmanager.c
index 00bce1a10be..6cadec777be 100644
--- a/gtk/gtklistitemmanager.c
+++ b/gtk/gtklistitemmanager.c
@@ -24,6 +24,8 @@
#include "gtklistitemprivate.h"
#include "gtkwidgetprivate.h"
+#define GTK_LIST_VIEW_MAX_LIST_ITEMS 200
+
struct _GtkListItemManager
{
GObject parent_instance;
@@ -31,6 +33,14 @@ struct _GtkListItemManager
GtkWidget *widget;
GtkSelectionModel *model;
GtkListItemFactory *factory;
+
+ GtkRbTree *items;
+
+ /* managing the visible region */
+ GtkWidget *anchor; /* may be NULL if list is empty */
+ int anchor_align; /* what to align the anchor to */
+ guint anchor_start; /* start of region we allocate row widgets for */
+ guint anchor_end; /* end of same region - first position to not have a widget */
};
struct _GtkListItemManagerClass
@@ -45,57 +55,669 @@ struct _GtkListItemManagerChange
G_DEFINE_TYPE (GtkListItemManager, gtk_list_item_manager, G_TYPE_OBJECT)
-static void
-gtk_list_item_manager_dispose (GObject *object)
+void
+gtk_list_item_manager_augment_node (GtkRbTree *tree,
+ gpointer node_augment,
+ gpointer node,
+ gpointer left,
+ gpointer right)
{
- GtkListItemManager *self = GTK_LIST_ITEM_MANAGER (object);
+ GtkListItemManagerItem *item = node;
+ GtkListItemManagerItemAugment *aug = node_augment;
- g_clear_object (&self->model);
- g_clear_object (&self->factory);
+ aug->n_items = item->n_items;
- G_OBJECT_CLASS (gtk_list_item_manager_parent_class)->dispose (object);
-}
+ if (left)
+ {
+ GtkListItemManagerItemAugment *left_aug = gtk_rb_tree_get_augment (tree, left);
-static void
-gtk_list_item_manager_class_init (GtkListItemManagerClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ aug->n_items += left_aug->n_items;
+ }
- object_class->dispose = gtk_list_item_manager_dispose;
+ if (right)
+ {
+ GtkListItemManagerItemAugment *right_aug = gtk_rb_tree_get_augment (tree, right);
+
+ aug->n_items += right_aug->n_items;
+ }
}
static void
-gtk_list_item_manager_init (GtkListItemManager *self)
+gtk_list_item_manager_clear_node (gpointer _item)
{
+ GtkListItemManagerItem *item = _item;
+
+ g_assert (item->widget == NULL);
}
GtkListItemManager *
-gtk_list_item_manager_new (GtkWidget *widget)
+gtk_list_item_manager_new_for_size (GtkWidget *widget,
+ gsize element_size,
+ gsize augment_size,
+ GtkRbTreeAugmentFunc augment_func)
{
GtkListItemManager *self;
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+ g_return_val_if_fail (element_size >= sizeof (GtkListItemManagerItem), NULL);
+ g_return_val_if_fail (augment_size >= sizeof (GtkListItemManagerItemAugment), NULL);
self = g_object_new (GTK_TYPE_LIST_ITEM_MANAGER, NULL);
+ /* not taking a ref because the widget refs us */
self->widget = widget;
+ self->items = gtk_rb_tree_new_for_size (element_size,
+ augment_size,
+ augment_func,
+ gtk_list_item_manager_clear_node,
+ NULL);
+
return self;
}
+gpointer
+gtk_list_item_manager_get_first (GtkListItemManager *self)
+{
+ return gtk_rb_tree_get_first (self->items);
+}
+
+gpointer
+gtk_list_item_manager_get_root (GtkListItemManager *self)
+{
+ return gtk_rb_tree_get_root (self->items);
+}
+
+/*
+ * gtk_list_item_manager_get_nth:
+ * @self: a #GtkListItemManager
+ * @position: position of the item
+ * @offset: (out): offset into the returned item
+ *
+ * Looks up the GtkListItemManagerItem that represents @position.
+ *
+ * If a the returned item represents multiple rows, the @offset into
+ * the returned item for @position will be set. If the returned item
+ * represents a row with an existing widget, @offset will always be 0.
+ *
+ * Returns: (type GtkListItemManagerItem): the item for @position or
+ * %NULL if position is out of range
+ **/
+gpointer
+gtk_list_item_manager_get_nth (GtkListItemManager *self,
+ guint position,
+ guint *offset)
+{
+ GtkListItemManagerItem *item, *tmp;
+
+ item = gtk_rb_tree_get_root (self->items);
+
+ while (item)
+ {
+ tmp = gtk_rb_tree_node_get_left (item);
+ if (tmp)
+ {
+ GtkListItemManagerItemAugment *aug = gtk_rb_tree_get_augment (self->items, tmp);
+ if (position < aug->n_items)
+ {
+ item = tmp;
+ continue;
+ }
+ position -= aug->n_items;
+ }
+
+ if (position < item->n_items)
+ break;
+ position -= item->n_items;
+
+ item = gtk_rb_tree_node_get_right (item);
+ }
+
+ if (offset)
+ *offset = item ? position : 0;
+
+ return item;
+}
+
+guint
+gtk_list_item_manager_get_item_position (GtkListItemManager *self,
+ gpointer item)
+{
+ GtkListItemManagerItem *parent, *left;
+ int pos;
+
+ left = gtk_rb_tree_node_get_left (item);
+ if (left)
+ {
+ GtkListItemManagerItemAugment *aug = gtk_rb_tree_get_augment (self->items, left);
+ pos = aug->n_items;
+ }
+ else
+ {
+ pos = 0;
+ }
+
+ for (parent = gtk_rb_tree_node_get_parent (item);
+ parent != NULL;
+ parent = gtk_rb_tree_node_get_parent (item))
+ {
+ left = gtk_rb_tree_node_get_left (parent);
+
+ if (left != item)
+ {
+ if (left)
+ {
+ GtkListItemManagerItemAugment *aug = gtk_rb_tree_get_augment (self->items, left);
+ pos += aug->n_items;
+ }
+ pos += parent->n_items;
+ }
+
+ item = parent;
+ }
+
+ return pos;
+}
+
+gpointer
+gtk_list_item_manager_get_item_augment (GtkListItemManager *self,
+ gpointer item)
+{
+ return gtk_rb_tree_get_augment (self->items, item);
+}
+
+static void
+gtk_list_item_manager_remove_items (GtkListItemManager *self,
+ GtkListItemManagerChange *change,
+ guint position,
+ guint n_items)
+{
+ GtkListItemManagerItem *item;
+
+ if (n_items == 0)
+ return;
+
+ item = gtk_list_item_manager_get_nth (self, position, NULL);
+
+ while (n_items > 0)
+ {
+ if (item->n_items > n_items)
+ {
+ item->n_items -= n_items;
+ gtk_rb_tree_node_mark_dirty (item);
+ n_items = 0;
+ }
+ else
+ {
+ GtkListItemManagerItem *next = gtk_rb_tree_node_get_next (item);
+ if (item->widget)
+ gtk_list_item_manager_release_list_item (self, change, item->widget);
+ item->widget = NULL;
+ n_items -= item->n_items;
+ gtk_rb_tree_remove (self->items, item);
+ item = next;
+ }
+ }
+
+ gtk_widget_queue_resize (GTK_WIDGET (self->widget));
+}
+
+static void
+gtk_list_item_manager_add_items (GtkListItemManager *self,
+ guint position,
+ guint n_items)
+{
+ GtkListItemManagerItem *item;
+ guint offset;
+
+ if (n_items == 0)
+ return;
+
+ item = gtk_list_item_manager_get_nth (self, position, &offset);
+
+ if (item == NULL || item->widget)
+ item = gtk_rb_tree_insert_before (self->items, item);
+ item->n_items += n_items;
+ gtk_rb_tree_node_mark_dirty (item);
+
+ gtk_widget_queue_resize (GTK_WIDGET (self->widget));
+}
+
+static void
+gtk_list_item_manager_unset_anchor (GtkListItemManager *self)
+{
+ self->anchor = NULL;
+ self->anchor_align = 0;
+ self->anchor_start = 0;
+ self->anchor_end = 0;
+}
+
+static gboolean
+gtk_list_item_manager_merge_list_items (GtkListItemManager *self,
+ GtkListItemManagerItem *first,
+ GtkListItemManagerItem *second)
+{
+ if (first->widget || second->widget)
+ return FALSE;
+
+ first->n_items += second->n_items;
+ gtk_rb_tree_node_mark_dirty (first);
+ gtk_rb_tree_remove (self->items, second);
+
+ return TRUE;
+}
+
+static void
+gtk_list_item_manager_release_items (GtkListItemManager *self,
+ GQueue *released)
+{
+ GtkListItemManagerItem *item, *prev, *next;
+ guint i;
+
+ item = gtk_rb_tree_get_first (self->items);
+ i = 0;
+ while (i < self->anchor_start)
+ {
+ if (item->widget)
+ {
+ g_queue_push_tail (released, item->widget);
+ item->widget = NULL;
+ i++;
+ prev = gtk_rb_tree_node_get_previous (item);
+ if (prev && gtk_list_item_manager_merge_list_items (self, prev, item))
+ item = prev;
+ next = gtk_rb_tree_node_get_next (item);
+ if (next && next->widget == NULL)
+ {
+ i += next->n_items;
+ if (!gtk_list_item_manager_merge_list_items (self, next, item))
+ g_assert_not_reached ();
+ item = gtk_rb_tree_node_get_next (next);
+ }
+ else
+ {
+ item = next;
+ }
+ }
+ else
+ {
+ i += item->n_items;
+ item = gtk_rb_tree_node_get_next (item);
+ }
+ }
+
+ item = gtk_list_item_manager_get_nth (self, self->anchor_end, NULL);
+ if (item == NULL)
+ return;
+
+ if (item->widget)
+ {
+ g_queue_push_tail (released, item->widget);
+ item->widget = NULL;
+ prev = gtk_rb_tree_node_get_previous (item);
+ if (prev && gtk_list_item_manager_merge_list_items (self, prev, item))
+ item = prev;
+ }
+
+ while ((next = gtk_rb_tree_node_get_next (item)))
+ {
+ if (next->widget)
+ {
+ g_queue_push_tail (released, next->widget);
+ next->widget = NULL;
+ }
+ gtk_list_item_manager_merge_list_items (self, item, next);
+ }
+}
+
+static void
+gtk_list_item_manager_ensure_items (GtkListItemManager *self,
+ GtkListItemManagerChange *change,
+ guint update_start)
+{
+ GtkListItemManagerItem *item, *new_item;
+ guint i, offset;
+ GtkWidget *widget, *insert_after;
+ GQueue released = G_QUEUE_INIT;
+
+ gtk_list_item_manager_release_items (self, &released);
+
+ item = gtk_list_item_manager_get_nth (self, self->anchor_start, &offset);
+ if (offset > 0)
+ {
+ new_item = gtk_rb_tree_insert_before (self->items, item);
+ new_item->n_items = offset;
+ item->n_items -= offset;
+ gtk_rb_tree_node_mark_dirty (item);
+ }
+
+ insert_after = NULL;
+
+ for (i = self->anchor_start; i < self->anchor_end; i++)
+ {
+ if (item->n_items > 1)
+ {
+ new_item = gtk_rb_tree_insert_before (self->items, item);
+ new_item->n_items = 1;
+ item->n_items--;
+ gtk_rb_tree_node_mark_dirty (item);
+ }
+ else
+ {
+ new_item = item;
+ item = gtk_rb_tree_node_get_next (item);
+ }
+ if (new_item->widget == NULL)
+ {
+ if (change)
+ {
+ new_item->widget = gtk_list_item_manager_try_reacquire_list_item (self,
+ change,
+ i,
+ insert_after);
+ }
+ if (new_item->widget == NULL)
+ {
+ new_item->widget = g_queue_pop_head (&released);
+ if (new_item->widget)
+ {
+ gtk_list_item_manager_move_list_item (self,
+ new_item->widget,
+ i,
+ insert_after);
+ }
+ else
+ {
+ new_item->widget = gtk_list_item_manager_acquire_list_item (self,
+ i,
+ insert_after);
+ }
+ }
+ }
+ else
+ {
+ if (update_start <= i)
+ gtk_list_item_manager_update_list_item (self, new_item->widget, i);
+ }
+ insert_after = new_item->widget;
+ }
+
+ while ((widget = g_queue_pop_head (&released)))
+ gtk_list_item_manager_release_list_item (self, NULL, widget);
+}
+
+void
+gtk_list_item_manager_set_anchor (GtkListItemManager *self,
+ guint position,
+ double align,
+ GtkListItemManagerChange *change,
+ guint update_start)
+{
+ GtkListItemManagerItem *item;
+ guint items_before, items_after, total_items, n_items;
+
+ g_assert (align >= 0.0 && align <= 1.0);
+
+ if (self->model)
+ n_items = g_list_model_get_n_items (G_LIST_MODEL (self->model));
+ else
+ n_items = 0;
+ if (n_items == 0)
+ {
+ gtk_list_item_manager_unset_anchor (self);
+ return;
+ }
+ total_items = MIN (GTK_LIST_VIEW_MAX_LIST_ITEMS, n_items);
+ if (align < 0.5)
+ items_before = ceil (total_items * align);
+ else
+ items_before = floor (total_items * align);
+ items_after = total_items - items_before;
+ self->anchor_start = CLAMP (position, items_before, n_items - items_after) - items_before;
+ self->anchor_end = self->anchor_start + total_items;
+ g_assert (self->anchor_end <= n_items);
+
+ gtk_list_item_manager_ensure_items (self, change, update_start);
+
+ item = gtk_list_item_manager_get_nth (self, position, NULL);
+ self->anchor = item->widget;
+ g_assert (self->anchor);
+ self->anchor_align = align;
+
+ gtk_widget_queue_allocate (GTK_WIDGET (self->widget));
+}
+
+static void
+gtk_list_item_manager_model_items_changed_cb (GListModel *model,
+ guint position,
+ guint removed,
+ guint added,
+ GtkListItemManager *self)
+{
+ GtkListItemManagerChange *change;
+
+ change = gtk_list_item_manager_begin_change (self);
+
+ gtk_list_item_manager_remove_items (self, change, position, removed);
+ gtk_list_item_manager_add_items (self, position, added);
+
+ /* The anchor was removed, but it may just have moved to a different position */
+ if (self->anchor && gtk_list_item_manager_change_contains (change, self->anchor))
+ {
+ /* The anchor was removed, do a more expensive rebuild trying to find if
+ * the anchor maybe got readded somewhere else */
+ GtkListItemManagerItem *item, *new_item;
+ GtkWidget *insert_after;
+ guint i, offset, anchor_pos;
+
+ item = gtk_list_item_manager_get_nth (self, position, &offset);
+ for (new_item = item ? gtk_rb_tree_node_get_previous (item) : gtk_rb_tree_get_last (self->items);
+ new_item && new_item->widget == NULL;
+ new_item = gtk_rb_tree_node_get_previous (new_item))
+ { }
+ if (new_item)
+ insert_after = new_item->widget;
+ else
+ insert_after = NULL; /* we're at the start */
+
+ for (i = 0; i < added; i++)
+ {
+ GtkWidget *widget;
+
+ widget = gtk_list_item_manager_try_reacquire_list_item (self,
+ change,
+ position + i,
+ insert_after);
+ if (widget == NULL)
+ {
+ offset++;
+ continue;
+ }
+
+ if (offset > 0)
+ {
+ new_item = gtk_rb_tree_insert_before (self->items, item);
+ new_item->n_items = offset;
+ item->n_items -= offset;
+ offset = 0;
+ gtk_rb_tree_node_mark_dirty (item);
+ }
+
+ if (item->n_items == 1)
+ {
+ new_item = item;
+ item = gtk_rb_tree_node_get_next (item);
+ }
+ else
+ {
+ new_item = gtk_rb_tree_insert_before (self->items, item);
+ new_item->n_items = 1;
+ item->n_items--;
+ gtk_rb_tree_node_mark_dirty (item);
+ }
+
+ new_item->widget = widget;
+ insert_after = widget;
+
+ if (widget == self->anchor)
+ {
+ anchor_pos = position + i;
+ break;
+ }
+ }
+
+ if (i == added)
+ {
+ /* The anchor wasn't readded. Guess a good anchor position */
+ anchor_pos = gtk_list_item_get_position (GTK_LIST_ITEM (self->anchor));
+
+ anchor_pos = position + (anchor_pos - position) * added / removed;
+ if (anchor_pos >= g_list_model_get_n_items (G_LIST_MODEL (self->model)) &&
+ anchor_pos > 0)
+ anchor_pos--;
+ }
+ gtk_list_item_manager_set_anchor (self, anchor_pos, self->anchor_align, change, position);
+ }
+ else
+ {
+ /* The anchor is still where it was.
+ * We just may need to update its position and check that its surrounding widgets
+ * exist (they might be new ones). */
+ guint anchor_pos;
+
+ if (self->anchor)
+ {
+ anchor_pos = gtk_list_item_get_position (GTK_LIST_ITEM (self->anchor));
+
+ if (anchor_pos >= position)
+ anchor_pos += added - removed;
+ }
+ else
+ {
+ anchor_pos = 0;
+ }
+
+ gtk_list_item_manager_set_anchor (self, anchor_pos, self->anchor_align, change, position);
+ }
+
+ gtk_list_item_manager_end_change (self, change);
+}
+
+static void
+gtk_list_item_manager_model_selection_changed_cb (GListModel *model,
+ guint position,
+ guint n_items,
+ GtkListItemManager *self)
+{
+ GtkListItemManagerItem *item;
+ guint offset;
+
+ item = gtk_list_item_manager_get_nth (self, position, &offset);
+
+ if (offset)
+ {
+ position += item->n_items - offset;
+ if (item->n_items - offset > n_items)
+ n_items = 0;
+ else
+ n_items -= item->n_items - offset;
+ item = gtk_rb_tree_node_get_next (item);
+ }
+
+ while (n_items > 0)
+ {
+ if (item->widget)
+ gtk_list_item_manager_update_list_item (self, item->widget, position);
+ position += item->n_items;
+ n_items -= MIN (n_items, item->n_items);
+ item = gtk_rb_tree_node_get_next (item);
+ }
+}
+
+guint
+gtk_list_item_manager_get_anchor (GtkListItemManager *self,
+ double *align)
+{
+ guint anchor_pos;
+
+ if (self->anchor)
+ anchor_pos = gtk_list_item_get_position (GTK_LIST_ITEM (self->anchor));
+ else
+ anchor_pos = 0;
+
+ if (align)
+ *align = self->anchor_align;
+
+ return anchor_pos;
+}
+
+static void
+gtk_list_item_manager_clear_model (GtkListItemManager *self)
+{
+ if (self->model == NULL)
+ return;
+
+ gtk_list_item_manager_remove_items (self, NULL, 0, g_list_model_get_n_items (G_LIST_MODEL (self->model)));
+
+ g_signal_handlers_disconnect_by_func (self->model,
+ gtk_list_item_manager_model_selection_changed_cb,
+ self);
+ g_signal_handlers_disconnect_by_func (self->model,
+ gtk_list_item_manager_model_items_changed_cb,
+ self);
+ g_clear_object (&self->model);
+
+ gtk_list_item_manager_unset_anchor (self);
+}
+
+static void
+gtk_list_item_manager_dispose (GObject *object)
+{
+ GtkListItemManager *self = GTK_LIST_ITEM_MANAGER (object);
+
+ gtk_list_item_manager_clear_model (self);
+
+ g_clear_object (&self->factory);
+
+ g_clear_pointer (&self->items, gtk_rb_tree_unref);
+
+ G_OBJECT_CLASS (gtk_list_item_manager_parent_class)->dispose (object);
+}
+
+static void
+gtk_list_item_manager_class_init (GtkListItemManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gtk_list_item_manager_dispose;
+}
+
+static void
+gtk_list_item_manager_init (GtkListItemManager *self)
+{
+}
+
void
gtk_list_item_manager_set_factory (GtkListItemManager *self,
GtkListItemFactory *factory)
{
+ guint n_items, anchor;
+ double anchor_align;
+
g_return_if_fail (GTK_IS_LIST_ITEM_MANAGER (self));
g_return_if_fail (GTK_IS_LIST_ITEM_FACTORY (factory));
if (self->factory == factory)
return;
- g_clear_object (&self->factory);
+ n_items = self->model ? g_list_model_get_n_items (G_LIST_MODEL (self->model)) : 0;
+ anchor = gtk_list_item_manager_get_anchor (self, &anchor_align);
+ gtk_list_item_manager_remove_items (self, NULL, 0, n_items);
+
+ g_set_object (&self->factory, factory);
- self->factory = g_object_ref (factory);
+ gtk_list_item_manager_add_items (self, 0, n_items);
+ gtk_list_item_manager_set_anchor (self, anchor, anchor_align, NULL, (guint) -1);
}
GtkListItemFactory *
@@ -111,15 +733,30 @@ gtk_list_item_manager_set_model (GtkListItemManager *self,
GtkSelectionModel *model)
{
g_return_if_fail (GTK_IS_LIST_ITEM_MANAGER (self));
- g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
+ g_return_if_fail (model == NULL || GTK_IS_SELECTION_MODEL (model));
if (self->model == model)
return;
- g_clear_object (&self->model);
+ gtk_list_item_manager_clear_model (self);
if (model)
- self->model = g_object_ref (model);
+ {
+ self->model = g_object_ref (model);
+
+ g_signal_connect (model,
+ "items-changed",
+ G_CALLBACK (gtk_list_item_manager_model_items_changed_cb),
+ self);
+ g_signal_connect (model,
+ "selection-changed",
+ G_CALLBACK (gtk_list_item_manager_model_selection_changed_cb),
+ self);
+
+ gtk_list_item_manager_add_items (self, 0, g_list_model_get_n_items (G_LIST_MODEL (model)));
+
+ gtk_list_item_manager_set_anchor (self, 0, 0, NULL, (guint) -1);
+ }
}
GtkSelectionModel *
@@ -400,3 +1037,4 @@ gtk_list_item_manager_release_list_item (GtkListItemManager *self,
gtk_list_item_factory_unbind (self->factory, GTK_LIST_ITEM (item));
gtk_widget_unparent (item);
}
+
diff --git a/gtk/gtklistitemmanagerprivate.h b/gtk/gtklistitemmanagerprivate.h
index 47a4434d7df..9e1ebab073b 100644
--- a/gtk/gtklistitemmanagerprivate.h
+++ b/gtk/gtklistitemmanagerprivate.h
@@ -24,6 +24,7 @@
#include "gtk/gtktypes.h"
#include "gtk/gtklistitemfactoryprivate.h"
+#include "gtk/gtkrbtreeprivate.h"
#include "gtk/gtkselectionmodel.h"
G_BEGIN_DECLS
@@ -38,10 +39,44 @@ G_BEGIN_DECLS
typedef struct _GtkListItemManager GtkListItemManager;
typedef struct _GtkListItemManagerClass GtkListItemManagerClass;
typedef struct _GtkListItemManagerChange GtkListItemManagerChange;
+typedef struct _GtkListItemManagerItem GtkListItemManagerItem; /* sorry */
+typedef struct _GtkListItemManagerItemAugment GtkListItemManagerItemAugment;
+
+struct _GtkListItemManagerItem
+{
+ GtkWidget *widget;
+ guint n_items;
+};
+
+struct _GtkListItemManagerItemAugment
+{
+ guint n_items;
+};
+
GType gtk_list_item_manager_get_type (void) G_GNUC_CONST;
-GtkListItemManager * gtk_list_item_manager_new (GtkWidget *widget);
+GtkListItemManager * gtk_list_item_manager_new_for_size (GtkWidget *widget,
+ gsize element_size,
+ gsize augment_size,
+ GtkRbTreeAugmentFunc augment_func);
+#define gtk_list_item_manager_new(widget, type, augment_type, augment_func) \
+ gtk_list_item_manager_new_for_size (widget, sizeof (type), sizeof (augment_type), (augment_func))
+
+void gtk_list_item_manager_augment_node (GtkRbTree *tree,
+ gpointer node_augment,
+ gpointer node,
+ gpointer left,
+ gpointer right);
+gpointer gtk_list_item_manager_get_root (GtkListItemManager *self);
+gpointer gtk_list_item_manager_get_first (GtkListItemManager *self);
+gpointer gtk_list_item_manager_get_nth (GtkListItemManager *self,
+ guint position,
+ guint *offset);
+guint gtk_list_item_manager_get_item_position (GtkListItemManager *self,
+ gpointer item);
+gpointer gtk_list_item_manager_get_item_augment (GtkListItemManager *self,
+ gpointer item);
void gtk_list_item_manager_set_factory (GtkListItemManager *self,
GtkListItemFactory *factory);
@@ -52,6 +87,14 @@ GtkSelectionModel * gtk_list_item_manager_get_model (GtkListItemMana
guint gtk_list_item_manager_get_size (GtkListItemManager *self);
+void gtk_list_item_manager_set_anchor (GtkListItemManager *self,
+ guint position,
+ double align,
+ GtkListItemManagerChange *change,
+ guint update_start);
+guint gtk_list_item_manager_get_anchor (GtkListItemManager *self,
+ double *align);
+
GtkListItemManagerChange *
gtk_list_item_manager_begin_change (GtkListItemManager *self);
void gtk_list_item_manager_end_change (GtkListItemManager *self,
diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c
index 36c18d698b5..e91b1b7b62c 100644
--- a/gtk/gtklistview.c
+++ b/gtk/gtklistview.c
@@ -58,26 +58,18 @@ struct _GtkListView
GtkAdjustment *adjustment[2];
GtkScrollablePolicy scroll_policy[2];
- GtkRbTree *rows;
int list_width;
-
- /* managing the visible region */
- GtkWidget *anchor; /* may be NULL if list is empty */
- int anchor_align; /* what to align the anchor to */
- guint anchor_start; /* start of region we allocate row widgets for */
- guint anchor_end; /* end of same region - first position to not have a widget */
};
struct _ListRow
{
- guint n_rows;
+ GtkListItemManagerItem parent;
guint height; /* per row */
- GtkWidget *widget;
};
struct _ListRowAugment
{
- guint n_rows;
+ GtkListItemManagerItemAugment parent;
guint height; /* total */
};
@@ -106,15 +98,15 @@ dump (GtkListView *self)
n_widgets = 0;
n_list_rows = 0;
- g_print ("ANCHOR: %u - %u\n", self->anchor_start, self->anchor_end);
- for (row = gtk_rb_tree_get_first (self->rows);
+ //g_print ("ANCHOR: %u - %u\n", self->anchor_start, self->anchor_end);
+ for (row = gtk_list_item_manager_get_first (self->item_manager);
row;
row = gtk_rb_tree_node_get_next (row))
{
- if (row->widget)
+ if (row->parent.widget)
n_widgets++;
n_list_rows++;
- g_print (" %4u%s (%upx)\n", row->n_rows, row->widget ? " (widget)" : "", row->height);
+ g_print (" %4u%s (%upx)\n", row->parent.n_items, row->parent.widget ? " (widget)" : "", row->height);
}
g_print (" => %u widgets in %u list rows\n", n_widgets, n_list_rows);
@@ -130,15 +122,15 @@ list_row_augment (GtkRbTree *tree,
ListRow *row = node;
ListRowAugment *aug = node_augment;
- aug->height = row->height * row->n_rows;
- aug->n_rows = row->n_rows;
+ gtk_list_item_manager_augment_node (tree, node_augment, node, left, right);
+
+ aug->height = row->height * row->parent.n_items;
if (left)
{
ListRowAugment *left_aug = gtk_rb_tree_get_augment (tree, left);
aug->height += left_aug->height;
- aug->n_rows += left_aug->n_rows;
}
if (right)
@@ -146,94 +138,9 @@ list_row_augment (GtkRbTree *tree,
ListRowAugment *right_aug = gtk_rb_tree_get_augment (tree, right);
aug->height += right_aug->height;
- aug->n_rows += right_aug->n_rows;
}
}
-static void
-list_row_clear (gpointer _row)
-{
- ListRow *row = _row;
-
- g_assert (row->widget == NULL);
-}
-
-static ListRow *
-gtk_list_view_get_row (GtkListView *self,
- guint position,
- guint *offset)
-{
- ListRow *row, *tmp;
-
- row = gtk_rb_tree_get_root (self->rows);
-
- while (row)
- {
- tmp = gtk_rb_tree_node_get_left (row);
- if (tmp)
- {
- ListRowAugment *aug = gtk_rb_tree_get_augment (self->rows, tmp);
- if (position < aug->n_rows)
- {
- row = tmp;
- continue;
- }
- position -= aug->n_rows;
- }
-
- if (position < row->n_rows)
- break;
- position -= row->n_rows;
-
- row = gtk_rb_tree_node_get_right (row);
- }
-
- if (offset)
- *offset = row ? position : 0;
-
- return row;
-}
-
-static guint
-list_row_get_position (GtkListView *self,
- ListRow *row)
-{
- ListRow *parent, *left;
- int pos;
-
- left = gtk_rb_tree_node_get_left (row);
- if (left)
- {
- ListRowAugment *aug = gtk_rb_tree_get_augment (self->rows, left);
- pos = aug->n_rows;
- }
- else
- {
- pos = 0;
- }
-
- for (parent = gtk_rb_tree_node_get_parent (row);
- parent != NULL;
- parent = gtk_rb_tree_node_get_parent (row))
- {
- left = gtk_rb_tree_node_get_left (parent);
-
- if (left != row)
- {
- if (left)
- {
- ListRowAugment *aug = gtk_rb_tree_get_augment (self->rows, left);
- pos += aug->n_rows;
- }
- pos += parent->n_rows;
- }
-
- row = parent;
- }
-
- return pos;
-}
-
static ListRow *
gtk_list_view_get_row_at_y (GtkListView *self,
int y,
@@ -241,14 +148,14 @@ gtk_list_view_get_row_at_y (GtkListView *self,
{
ListRow *row, *tmp;
- row = gtk_rb_tree_get_root (self->rows);
+ row = gtk_list_item_manager_get_root (self->item_manager);
while (row)
{
tmp = gtk_rb_tree_node_get_left (row);
if (tmp)
{
- ListRowAugment *aug = gtk_rb_tree_get_augment (self->rows, tmp);
+ ListRowAugment *aug = gtk_list_item_manager_get_item_augment (self->item_manager, tmp);
if (y < aug->height)
{
row = tmp;
@@ -257,9 +164,9 @@ gtk_list_view_get_row_at_y (GtkListView *self,
y -= aug->height;
}
- if (y < row->height * row->n_rows)
+ if (y < row->height * row->parent.n_items)
break;
- y -= row->height * row->n_rows;
+ y -= row->height * row->parent.n_items;
row = gtk_rb_tree_node_get_right (row);
}
@@ -280,7 +187,7 @@ list_row_get_y (GtkListView *self,
left = gtk_rb_tree_node_get_left (row);
if (left)
{
- ListRowAugment *aug = gtk_rb_tree_get_augment (self->rows, left);
+ ListRowAugment *aug = gtk_list_item_manager_get_item_augment (self->item_manager, left);
y = aug->height;
}
else
@@ -296,10 +203,10 @@ list_row_get_y (GtkListView *self,
{
if (left)
{
- ListRowAugment *aug = gtk_rb_tree_get_augment (self->rows, left);
+ ListRowAugment *aug = gtk_list_item_manager_get_item_augment (self->item_manager, left);
y += aug->height;
}
- y += parent->height * parent->n_rows;
+ y += parent->height * parent->parent.n_items;
}
row = parent;
@@ -314,218 +221,14 @@ gtk_list_view_get_list_height (GtkListView *self)
ListRow *row;
ListRowAugment *aug;
- row = gtk_rb_tree_get_root (self->rows);
+ row = gtk_list_item_manager_get_root (self->item_manager);
if (row == NULL)
return 0;
- aug = gtk_rb_tree_get_augment (self->rows, row);
+ aug = gtk_list_item_manager_get_item_augment (self->item_manager, row);
return aug->height;
}
-static gboolean
-gtk_list_view_merge_list_rows (GtkListView *self,
- ListRow *first,
- ListRow *second)
-{
- if (first->widget || second->widget)
- return FALSE;
-
- first->n_rows += second->n_rows;
- gtk_rb_tree_node_mark_dirty (first);
- gtk_rb_tree_remove (self->rows, second);
-
- return TRUE;
-}
-
-static void
-gtk_list_view_release_rows (GtkListView *self,
- GQueue *released)
-{
- ListRow *row, *prev, *next;
- guint i;
-
- row = gtk_rb_tree_get_first (self->rows);
- i = 0;
- while (i < self->anchor_start)
- {
- if (row->widget)
- {
- g_queue_push_tail (released, row->widget);
- row->widget = NULL;
- i++;
- prev = gtk_rb_tree_node_get_previous (row);
- if (prev && gtk_list_view_merge_list_rows (self, prev, row))
- row = prev;
- next = gtk_rb_tree_node_get_next (row);
- if (next && next->widget == NULL)
- {
- i += next->n_rows;
- if (!gtk_list_view_merge_list_rows (self, next, row))
- g_assert_not_reached ();
- row = gtk_rb_tree_node_get_next (next);
- }
- else
- {
- row = next;
- }
- }
- else
- {
- i += row->n_rows;
- row = gtk_rb_tree_node_get_next (row);
- }
- }
-
- row = gtk_list_view_get_row (self, self->anchor_end, NULL);
- if (row == NULL)
- return;
-
- if (row->widget)
- {
- g_queue_push_tail (released, row->widget);
- row->widget = NULL;
- prev = gtk_rb_tree_node_get_previous (row);
- if (prev && gtk_list_view_merge_list_rows (self, prev, row))
- row = prev;
- }
-
- while ((next = gtk_rb_tree_node_get_next (row)))
- {
- if (next->widget)
- {
- g_queue_push_tail (released, next->widget);
- next->widget = NULL;
- }
- gtk_list_view_merge_list_rows (self, row, next);
- }
-}
-
-static void
-gtk_list_view_ensure_rows (GtkListView *self,
- GtkListItemManagerChange *change,
- guint update_start)
-{
- ListRow *row, *new_row;
- guint i, offset;
- GtkWidget *widget, *insert_after;
- GQueue released = G_QUEUE_INIT;
-
- gtk_list_view_release_rows (self, &released);
-
- row = gtk_list_view_get_row (self, self->anchor_start, &offset);
- if (offset > 0)
- {
- new_row = gtk_rb_tree_insert_before (self->rows, row);
- new_row->n_rows = offset;
- row->n_rows -= offset;
- gtk_rb_tree_node_mark_dirty (row);
- }
-
- insert_after = NULL;
-
- for (i = self->anchor_start; i < self->anchor_end; i++)
- {
- if (row->n_rows > 1)
- {
- new_row = gtk_rb_tree_insert_before (self->rows, row);
- new_row->n_rows = 1;
- row->n_rows--;
- gtk_rb_tree_node_mark_dirty (row);
- }
- else
- {
- new_row = row;
- row = gtk_rb_tree_node_get_next (row);
- }
- if (new_row->widget == NULL)
- {
- if (change)
- {
- new_row->widget = gtk_list_item_manager_try_reacquire_list_item (self->item_manager,
- change,
- i,
- insert_after);
- }
- if (new_row->widget == NULL)
- {
- new_row->widget = g_queue_pop_head (&released);
- if (new_row->widget)
- {
- gtk_list_item_manager_move_list_item (self->item_manager,
- new_row->widget,
- i,
- insert_after);
- }
- else
- {
- new_row->widget = gtk_list_item_manager_acquire_list_item (self->item_manager,
- i,
- insert_after);
- }
- }
- }
- else
- {
- if (update_start <= i)
- gtk_list_item_manager_update_list_item (self->item_manager, new_row->widget, i);
- }
- insert_after = new_row->widget;
- }
-
- while ((widget = g_queue_pop_head (&released)))
- gtk_list_item_manager_release_list_item (self->item_manager, NULL, widget);
-}
-
-static void
-gtk_list_view_unset_anchor (GtkListView *self)
-{
- self->anchor = NULL;
- self->anchor_align = 0;
- self->anchor_start = 0;
- self->anchor_end = 0;
-}
-
-static void
-gtk_list_view_set_anchor (GtkListView *self,
- guint position,
- double align,
- GtkListItemManagerChange *change,
- guint update_start)
-{
- ListRow *row;
- guint items_before, items_after, total_items, n_rows;
-
- g_assert (align >= 0.0 && align <= 1.0);
-
- if (self->model)
- n_rows = g_list_model_get_n_items (self->model);
- else
- n_rows = 0;
- if (n_rows == 0)
- {
- gtk_list_view_unset_anchor (self);
- return;
- }
- total_items = MIN (GTK_LIST_VIEW_MAX_LIST_ITEMS, n_rows);
- if (align < 0.5)
- items_before = ceil (total_items * align);
- else
- items_before = floor (total_items * align);
- items_after = total_items - items_before;
- self->anchor_start = CLAMP (position, items_before, n_rows - items_after) - items_before;
- self->anchor_end = self->anchor_start + total_items;
- g_assert (self->anchor_end <= n_rows);
-
- gtk_list_view_ensure_rows (self, change, update_start);
-
- row = gtk_list_view_get_row (self, position, NULL);
- self->anchor = row->widget;
- g_assert (self->anchor);
- self->anchor_align = align;
-
- gtk_widget_queue_allocate (GTK_WIDGET (self));
-}
-
static void
gtk_list_view_adjustment_value_changed_cb (GtkAdjustment *adjustment,
GtkListView *self)
@@ -539,17 +242,15 @@ gtk_list_view_adjustment_value_changed_cb (GtkAdjustment *adjustment,
row = gtk_list_view_get_row_at_y (self, gtk_adjustment_get_value (adjustment), &dy);
if (row)
{
- pos = list_row_get_position (self, row) + dy / row->height;
+ pos = gtk_list_item_manager_get_item_position (self->item_manager, row) + dy / row->height;
}
else
pos = 0;
- gtk_list_view_set_anchor (self, pos, 0, NULL, (guint) -1);
- }
- else
- {
- gtk_widget_queue_allocate (GTK_WIDGET (self));
+ gtk_list_item_manager_set_anchor (self->item_manager, pos, 0, NULL, (guint) -1);
}
+
+ gtk_widget_queue_allocate (GTK_WIDGET (self));
}
static void
@@ -570,19 +271,19 @@ gtk_list_view_update_adjustments (GtkListView *self,
else
{
ListRow *row;
+ guint anchor;
+ double anchor_align;
page_size = gtk_widget_get_height (GTK_WIDGET (self));
upper = gtk_list_view_get_list_height (self);
- if (self->anchor)
- row = gtk_list_view_get_row (self, gtk_list_item_get_position (GTK_LIST_ITEM (self->anchor)), NULL);
- else
- row = NULL;
+ anchor = gtk_list_item_manager_get_anchor (self->item_manager, &anchor_align);
+ row = gtk_list_item_manager_get_nth (self->item_manager, anchor, NULL);
if (row)
value = list_row_get_y (self, row);
else
value = 0;
- value -= self->anchor_align * (page_size - (row ? row->height : 0));
+ value -= anchor_align * (page_size - (row ? row->height : 0));
}
upper = MAX (upper, page_size);
@@ -637,15 +338,15 @@ gtk_list_view_measure_across (GtkWidget *widget,
min = 0;
nat = 0;
- for (row = gtk_rb_tree_get_first (self->rows);
+ for (row = gtk_list_item_manager_get_first (self->item_manager);
row != NULL;
row = gtk_rb_tree_node_get_next (row))
{
/* ignore unavailable rows */
- if (row->widget == NULL)
+ if (row->parent.widget == NULL)
continue;
- gtk_widget_measure (row->widget,
+ gtk_widget_measure (row->parent.widget,
orientation, for_size,
&child_min, &child_nat, NULL, NULL);
min = MAX (min, child_min);
@@ -675,13 +376,13 @@ gtk_list_view_measure_list (GtkWidget *widget,
min = 0;
nat = 0;
- for (row = gtk_rb_tree_get_first (self->rows);
+ for (row = gtk_list_item_manager_get_first (self->item_manager);
row != NULL;
row = gtk_rb_tree_node_get_next (row))
{
- if (row->widget)
+ if (row->parent.widget)
{
- gtk_widget_measure (row->widget,
+ gtk_widget_measure (row->parent.widget,
orientation, for_size,
&child_min, &child_nat, NULL, NULL);
g_array_append_val (min_heights, child_min);
@@ -691,7 +392,7 @@ gtk_list_view_measure_list (GtkWidget *widget,
}
else
{
- n_unknown += row->n_rows;
+ n_unknown += row->parent.n_items;
}
}
@@ -735,7 +436,7 @@ gtk_list_view_size_allocate (GtkWidget *widget,
int min, nat, row_height;
/* step 0: exit early if list is empty */
- if (gtk_rb_tree_get_root (self->rows) == NULL)
+ if (gtk_list_item_manager_get_root (self->item_manager) == NULL)
return;
/* step 1: determine width of the list */
@@ -750,14 +451,14 @@ gtk_list_view_size_allocate (GtkWidget *widget,
/* step 2: determine height of known list items */
heights = g_array_new (FALSE, FALSE, sizeof (int));
- for (row = gtk_rb_tree_get_first (self->rows);
+ for (row = gtk_list_item_manager_get_first (self->item_manager);
row != NULL;
row = gtk_rb_tree_node_get_next (row))
{
- if (row->widget == NULL)
+ if (row->parent.widget == NULL)
continue;
- gtk_widget_measure (row->widget, GTK_ORIENTATION_VERTICAL,
+ gtk_widget_measure (row->parent.widget, GTK_ORIENTATION_VERTICAL,
self->list_width,
&min, &nat, NULL, NULL);
if (self->scroll_policy[GTK_ORIENTATION_VERTICAL] == GTK_SCROLL_MINIMUM)
@@ -776,11 +477,11 @@ gtk_list_view_size_allocate (GtkWidget *widget,
row_height = gtk_list_view_get_unknown_row_height (self, heights);
g_array_free (heights, TRUE);
- for (row = gtk_rb_tree_get_first (self->rows);
+ for (row = gtk_list_item_manager_get_first (self->item_manager);
row != NULL;
row = gtk_rb_tree_node_get_next (row))
{
- if (row->widget)
+ if (row->parent.widget)
continue;
if (row->height != row_height)
@@ -798,257 +499,20 @@ gtk_list_view_size_allocate (GtkWidget *widget,
child_allocation.x = - gtk_adjustment_get_value (self->adjustment[GTK_ORIENTATION_HORIZONTAL]);
child_allocation.y = - round (gtk_adjustment_get_value (self->adjustment[GTK_ORIENTATION_VERTICAL]));
child_allocation.width = self->list_width;
- for (row = gtk_rb_tree_get_first (self->rows);
+ for (row = gtk_list_item_manager_get_first (self->item_manager);
row != NULL;
row = gtk_rb_tree_node_get_next (row))
{
- if (row->widget)
+ if (row->parent.widget)
{
child_allocation.height = row->height;
- gtk_widget_size_allocate (row->widget, &child_allocation, -1);
+ gtk_widget_size_allocate (row->parent.widget, &child_allocation, -1);
}
- child_allocation.y += row->height * row->n_rows;
+ child_allocation.y += row->height * row->parent.n_items;
}
}
-static guint
-gtk_list_view_get_anchor (GtkListView *self,
- double *align)
-{
- guint anchor_pos;
-
- if (self->anchor)
- anchor_pos = gtk_list_item_get_position (GTK_LIST_ITEM (self->anchor));
- else
- anchor_pos = 0;
-
- if (align)
- *align = self->anchor_align;
-
- return anchor_pos;
-}
-
-static void
-gtk_list_view_remove_rows (GtkListView *self,
- GtkListItemManagerChange *change,
- guint position,
- guint n_rows)
-{
- ListRow *row;
-
- if (n_rows == 0)
- return;
-
- row = gtk_list_view_get_row (self, position, NULL);
-
- while (n_rows > 0)
- {
- if (row->n_rows > n_rows)
- {
- row->n_rows -= n_rows;
- gtk_rb_tree_node_mark_dirty (row);
- n_rows = 0;
- }
- else
- {
- ListRow *next = gtk_rb_tree_node_get_next (row);
- if (row->widget)
- gtk_list_item_manager_release_list_item (self->item_manager, change, row->widget);
- row->widget = NULL;
- n_rows -= row->n_rows;
- gtk_rb_tree_remove (self->rows, row);
- row = next;
- }
- }
-
- gtk_widget_queue_resize (GTK_WIDGET (self));
-}
-
-static void
-gtk_list_view_add_rows (GtkListView *self,
- guint position,
- guint n_rows)
-{
- ListRow *row;
- guint offset;
-
- if (n_rows == 0)
- return;
-
- row = gtk_list_view_get_row (self, position, &offset);
-
- if (row == NULL || row->widget)
- row = gtk_rb_tree_insert_before (self->rows, row);
- row->n_rows += n_rows;
- gtk_rb_tree_node_mark_dirty (row);
-
- gtk_widget_queue_resize (GTK_WIDGET (self));
-}
-
-static void
-gtk_list_view_model_items_changed_cb (GListModel *model,
- guint position,
- guint removed,
- guint added,
- GtkListView *self)
-{
- GtkListItemManagerChange *change;
-
- change = gtk_list_item_manager_begin_change (self->item_manager);
-
- gtk_list_view_remove_rows (self, change, position, removed);
- gtk_list_view_add_rows (self, position, added);
-
- /* The anchor was removed, but it may just have moved to a different position */
- if (self->anchor && gtk_list_item_manager_change_contains (change, self->anchor))
- {
- /* The anchor was removed, do a more expensive rebuild trying to find if
- * the anchor maybe got readded somewhere else */
- ListRow *row, *new_row;
- GtkWidget *insert_after;
- guint i, offset, anchor_pos;
-
- row = gtk_list_view_get_row (self, position, &offset);
- for (new_row = row ? gtk_rb_tree_node_get_previous (row) : gtk_rb_tree_get_last (self->rows);
- new_row && new_row->widget == NULL;
- new_row = gtk_rb_tree_node_get_previous (new_row))
- { }
- if (new_row)
- insert_after = new_row->widget;
- else
- insert_after = NULL; /* we're at the start */
-
- for (i = 0; i < added; i++)
- {
- GtkWidget *widget;
-
- widget = gtk_list_item_manager_try_reacquire_list_item (self->item_manager,
- change,
- position + i,
- insert_after);
- if (widget == NULL)
- {
- offset++;
- continue;
- }
-
- if (offset > 0)
- {
- new_row = gtk_rb_tree_insert_before (self->rows, row);
- new_row->n_rows = offset;
- row->n_rows -= offset;
- offset = 0;
- gtk_rb_tree_node_mark_dirty (row);
- }
-
- if (row->n_rows == 1)
- {
- new_row = row;
- row = gtk_rb_tree_node_get_next (row);
- }
- else
- {
- new_row = gtk_rb_tree_insert_before (self->rows, row);
- new_row->n_rows = 1;
- row->n_rows--;
- gtk_rb_tree_node_mark_dirty (row);
- }
-
- new_row->widget = widget;
- insert_after = widget;
-
- if (widget == self->anchor)
- {
- anchor_pos = position + i;
- break;
- }
- }
-
- if (i == added)
- {
- /* The anchor wasn't readded. Guess a good anchor position */
- anchor_pos = gtk_list_item_get_position (GTK_LIST_ITEM (self->anchor));
-
- anchor_pos = position + (anchor_pos - position) * added / removed;
- if (anchor_pos >= g_list_model_get_n_items (self->model) &&
- anchor_pos > 0)
- anchor_pos--;
- }
- gtk_list_view_set_anchor (self, anchor_pos, self->anchor_align, change, position);
- }
- else
- {
- /* The anchor is still where it was.
- * We just may need to update its position and check that its surrounding widgets
- * exist (they might be new ones). */
- guint anchor_pos;
-
- if (self->anchor)
- {
- anchor_pos = gtk_list_item_get_position (GTK_LIST_ITEM (self->anchor));
-
- if (anchor_pos >= position)
- anchor_pos += added - removed;
- }
- else
- {
- anchor_pos = 0;
- }
-
- gtk_list_view_set_anchor (self, anchor_pos, self->anchor_align, change, position);
- }
-
- gtk_list_item_manager_end_change (self->item_manager, change);
-}
-
-static void
-gtk_list_view_model_selection_changed_cb (GListModel *model,
- guint position,
- guint n_items,
- GtkListView *self)
-{
- ListRow *row;
- guint offset;
-
- row = gtk_list_view_get_row (self, position, &offset);
-
- if (offset)
- {
- position += row->n_rows - offset;
- n_items -= row->n_rows - offset;
- row = gtk_rb_tree_node_get_next (row);
- }
-
- while (n_items > 0)
- {
- if (row->widget)
- gtk_list_item_manager_update_list_item (self->item_manager, row->widget, position);
- position += row->n_rows;
- n_items -= MIN (n_items, row->n_rows);
- row = gtk_rb_tree_node_get_next (row);
- }
-}
-
-static void
-gtk_list_view_clear_model (GtkListView *self)
-{
- if (self->model == NULL)
- return;
-
- gtk_list_view_remove_rows (self, NULL, 0, g_list_model_get_n_items (self->model));
-
- g_signal_handlers_disconnect_by_func (self->model,
- gtk_list_view_model_selection_changed_cb,
- self);
- g_signal_handlers_disconnect_by_func (self->model,
- gtk_list_view_model_items_changed_cb,
- self);
- g_clear_object (&self->model);
-
- gtk_list_view_unset_anchor (self);
-}
-
static void
gtk_list_view_clear_adjustment (GtkListView *self,
GtkOrientation orientation)
@@ -1067,7 +531,7 @@ gtk_list_view_dispose (GObject *object)
{
GtkListView *self = GTK_LIST_VIEW (object);
- gtk_list_view_clear_model (self);
+ g_clear_object (&self->model);
gtk_list_view_clear_adjustment (self, GTK_ORIENTATION_HORIZONTAL);
gtk_list_view_clear_adjustment (self, GTK_ORIENTATION_VERTICAL);
@@ -1082,7 +546,6 @@ gtk_list_view_finalize (GObject *object)
{
GtkListView *self = GTK_LIST_VIEW (object);
- gtk_rb_tree_unref (self->rows);
g_clear_object (&self->item_manager);
G_OBJECT_CLASS (gtk_list_view_parent_class)->finalize (object);
@@ -1302,13 +765,7 @@ gtk_list_view_class_init (GtkListViewClass *klass)
static void
gtk_list_view_init (GtkListView *self)
{
- self->item_manager = gtk_list_item_manager_new (GTK_WIDGET (self));
-
- self->rows = gtk_rb_tree_new (ListRow,
- ListRowAugment,
- list_row_augment,
- list_row_clear,
- NULL);
+ self->item_manager = gtk_list_item_manager_new (GTK_WIDGET (self), ListRow, ListRowAugment,
list_row_augment);
self->adjustment[GTK_ORIENTATION_HORIZONTAL] = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
self->adjustment[GTK_ORIENTATION_VERTICAL] = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
@@ -1368,7 +825,7 @@ gtk_list_view_set_model (GtkListView *self,
if (self->model == model)
return;
- gtk_list_view_clear_model (self);
+ g_clear_object (&self->model);
if (model)
{
@@ -1383,19 +840,7 @@ gtk_list_view_set_model (GtkListView *self,
gtk_list_item_manager_set_model (self->item_manager, selection_model);
- g_signal_connect (model,
- "items-changed",
- G_CALLBACK (gtk_list_view_model_items_changed_cb),
- self);
- g_signal_connect (selection_model,
- "selection-changed",
- G_CALLBACK (gtk_list_view_model_selection_changed_cb),
- self);
-
g_object_unref (selection_model);
-
- gtk_list_view_add_rows (self, 0, g_list_model_get_n_items (model));
- gtk_list_view_set_anchor (self, 0, 0, NULL, (guint) -1);
}
else
{
@@ -1414,22 +859,13 @@ gtk_list_view_set_functions (GtkListView *self,
GDestroyNotify user_destroy)
{
GtkListItemFactory *factory;
- guint n_items, anchor;
- double anchor_align;
g_return_if_fail (GTK_IS_LIST_VIEW (self));
g_return_if_fail (setup_func || bind_func);
g_return_if_fail (user_data != NULL || user_destroy == NULL);
- n_items = self->model ? g_list_model_get_n_items (self->model) : 0;
- anchor = gtk_list_view_get_anchor (self, &anchor_align);
- gtk_list_view_remove_rows (self, NULL, 0, n_items);
-
factory = gtk_list_item_factory_new (setup_func, bind_func, user_data, user_destroy);
gtk_list_item_manager_set_factory (self->item_manager, factory);
g_object_unref (factory);
-
- gtk_list_view_add_rows (self, 0, n_items);
- gtk_list_view_set_anchor (self, anchor, anchor_align, NULL, (guint) -1);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]