mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-27 14:10:30 +00:00
listitemmanager: Properly handle sections during add/remove
We don't insert sections ourselves yet, but we handle the existing one when items get added or removed.
This commit is contained in:
parent
8bf6498265
commit
8e69c5c89c
@ -23,6 +23,7 @@
|
||||
|
||||
#include "gtklistitembaseprivate.h"
|
||||
#include "gtklistitemwidgetprivate.h"
|
||||
#include "gtksectionmodel.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
|
||||
struct _GtkListItemManager
|
||||
@ -159,7 +160,6 @@ gtk_list_item_manager_new (GtkWidget *widget,
|
||||
GtkListItemBase * (* create_widget) (GtkWidget *))
|
||||
{
|
||||
GtkListItemManager *self;
|
||||
GtkListTile *header, *footer;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
|
||||
|
||||
@ -176,15 +176,18 @@ gtk_list_item_manager_new (GtkWidget *widget,
|
||||
gtk_list_item_manager_clear_node,
|
||||
NULL);
|
||||
|
||||
header = gtk_rb_tree_insert_after (self->items, NULL);
|
||||
header->type = GTK_LIST_TILE_HEADER;
|
||||
|
||||
footer = gtk_rb_tree_insert_before (self->items, NULL);
|
||||
footer->type = GTK_LIST_TILE_FOOTER;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_list_item_manager_has_sections (GtkListItemManager *self)
|
||||
{
|
||||
if (self->model == NULL)
|
||||
return FALSE;
|
||||
|
||||
return GTK_IS_SECTION_MODEL (self->model);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_list_item_manager_get_tile_bounds (GtkListItemManager *self,
|
||||
GdkRectangle *out_bounds)
|
||||
@ -272,6 +275,110 @@ gtk_list_item_manager_get_nth (GtkListItemManager *self,
|
||||
return tile;
|
||||
}
|
||||
|
||||
static GtkListTile *
|
||||
gtk_list_tile_get_header (GtkListItemManager *self,
|
||||
GtkListTile *tile)
|
||||
{
|
||||
GtkListTileAugment *aug;
|
||||
GtkListTile *other;
|
||||
gboolean check_right = FALSE;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
if (check_right)
|
||||
{
|
||||
other = gtk_rb_tree_node_get_right (tile);
|
||||
if (other)
|
||||
{
|
||||
aug = gtk_rb_tree_get_augment (self->items, other);
|
||||
if (aug->has_header)
|
||||
{
|
||||
check_right = TRUE;
|
||||
tile = other;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tile->type == GTK_LIST_TILE_HEADER ||
|
||||
tile->type == GTK_LIST_TILE_UNMATCHED_HEADER)
|
||||
return tile;
|
||||
|
||||
other = gtk_rb_tree_node_get_left (tile);
|
||||
if (other)
|
||||
{
|
||||
aug = gtk_rb_tree_get_augment (self->items, other);
|
||||
if (aug->has_header)
|
||||
{
|
||||
check_right = TRUE;
|
||||
tile = other;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
while ((other = gtk_rb_tree_node_get_parent (tile)))
|
||||
{
|
||||
if (gtk_rb_tree_node_get_right (other) == tile)
|
||||
break;
|
||||
tile = other;
|
||||
}
|
||||
tile = other;
|
||||
check_right = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static GtkListTile *
|
||||
gtk_list_tile_get_footer (GtkListItemManager *self,
|
||||
GtkListTile *tile)
|
||||
{
|
||||
GtkListTileAugment *aug;
|
||||
GtkListTile *other;
|
||||
gboolean check_left = FALSE;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
if (check_left)
|
||||
{
|
||||
other = gtk_rb_tree_node_get_left (tile);
|
||||
if (other)
|
||||
{
|
||||
aug = gtk_rb_tree_get_augment (self->items, other);
|
||||
if (aug->has_footer)
|
||||
{
|
||||
check_left = TRUE;
|
||||
tile = other;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tile->type == GTK_LIST_TILE_FOOTER ||
|
||||
tile->type == GTK_LIST_TILE_UNMATCHED_FOOTER)
|
||||
return tile;
|
||||
|
||||
other = gtk_rb_tree_node_get_right (tile);
|
||||
if (other)
|
||||
{
|
||||
aug = gtk_rb_tree_get_augment (self->items, other);
|
||||
if (aug->has_footer)
|
||||
{
|
||||
check_left = TRUE;
|
||||
tile = other;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
while ((other = gtk_rb_tree_node_get_parent (tile)))
|
||||
{
|
||||
if (gtk_rb_tree_node_get_left (other) == tile)
|
||||
break;
|
||||
tile = other;
|
||||
}
|
||||
tile = other;
|
||||
check_left = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* This computes Manhattan distance */
|
||||
static int
|
||||
rectangle_distance (const cairo_rectangle_int_t *rect,
|
||||
@ -607,7 +714,7 @@ gtk_list_item_manager_remove_items (GtkListItemManager *self,
|
||||
guint position,
|
||||
guint n_items)
|
||||
{
|
||||
GtkListTile *tile, *next;
|
||||
GtkListTile *tile, *header;
|
||||
guint offset;
|
||||
|
||||
if (n_items == 0)
|
||||
@ -616,25 +723,81 @@ gtk_list_item_manager_remove_items (GtkListItemManager *self,
|
||||
tile = gtk_list_item_manager_get_nth (self, position, &offset);
|
||||
if (offset)
|
||||
tile = gtk_list_item_manager_ensure_split (self, tile, offset);
|
||||
for (header = gtk_rb_tree_node_get_previous (tile);
|
||||
header->type != GTK_LIST_TILE_HEADER && header->type != GTK_LIST_TILE_UNMATCHED_HEADER;
|
||||
header = gtk_rb_tree_node_get_previous (header))
|
||||
{
|
||||
if (header->type == GTK_LIST_TILE_ITEM)
|
||||
{
|
||||
header = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (n_items > 0)
|
||||
{
|
||||
if (tile->n_items > n_items)
|
||||
switch (tile->type)
|
||||
{
|
||||
gtk_list_item_manager_ensure_split (self, tile, n_items);
|
||||
g_assert (tile->n_items <= n_items);
|
||||
case GTK_LIST_TILE_HEADER:
|
||||
case GTK_LIST_TILE_UNMATCHED_HEADER:
|
||||
g_assert (header == NULL);
|
||||
header = tile;
|
||||
break;
|
||||
|
||||
case GTK_LIST_TILE_FOOTER:
|
||||
case GTK_LIST_TILE_UNMATCHED_FOOTER:
|
||||
if (header)
|
||||
{
|
||||
header->type = GTK_LIST_TILE_REMOVED;
|
||||
gtk_rb_tree_node_mark_dirty (header);
|
||||
tile->type = GTK_LIST_TILE_REMOVED;
|
||||
gtk_rb_tree_node_mark_dirty (tile);
|
||||
header = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case GTK_LIST_TILE_FILLER:
|
||||
case GTK_LIST_TILE_REMOVED:
|
||||
break;
|
||||
|
||||
case GTK_LIST_TILE_ITEM:
|
||||
if (tile->n_items > n_items)
|
||||
{
|
||||
gtk_list_item_manager_ensure_split (self, tile, n_items);
|
||||
g_assert (tile->n_items <= n_items);
|
||||
}
|
||||
if (tile->widget)
|
||||
gtk_list_item_manager_release_list_item (self, change, tile->widget);
|
||||
tile->widget = NULL;
|
||||
n_items -= tile->n_items;
|
||||
tile->n_items = 0;
|
||||
tile->type = GTK_LIST_TILE_REMOVED;
|
||||
gtk_rb_tree_node_mark_dirty (tile);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
next = gtk_rb_tree_node_get_next (tile);
|
||||
if (tile->widget)
|
||||
gtk_list_item_manager_release_list_item (self, change, tile->widget);
|
||||
tile->widget = NULL;
|
||||
n_items -= tile->n_items;
|
||||
tile->n_items = 0;
|
||||
tile->type = GTK_LIST_TILE_REMOVED;
|
||||
gtk_rb_tree_node_mark_dirty (tile);
|
||||
tile = gtk_rb_tree_node_get_next (tile);
|
||||
}
|
||||
|
||||
tile = next;
|
||||
if (header)
|
||||
{
|
||||
for (;
|
||||
tile->type != GTK_LIST_TILE_ITEM;
|
||||
tile = gtk_rb_tree_node_get_next (tile))
|
||||
{
|
||||
if (tile->type == GTK_LIST_TILE_FOOTER || tile->type == GTK_LIST_TILE_UNMATCHED_FOOTER)
|
||||
{
|
||||
header->type = GTK_LIST_TILE_REMOVED;
|
||||
gtk_rb_tree_node_mark_dirty (header);
|
||||
tile->type = GTK_LIST_TILE_REMOVED;
|
||||
gtk_rb_tree_node_mark_dirty (tile);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self->widget));
|
||||
@ -647,21 +810,60 @@ gtk_list_item_manager_add_items (GtkListItemManager *self,
|
||||
{
|
||||
GtkListTile *tile;
|
||||
guint offset;
|
||||
gboolean has_sections;
|
||||
|
||||
if (n_items == 0)
|
||||
return;
|
||||
|
||||
has_sections = gtk_list_item_manager_has_sections (self);
|
||||
|
||||
tile = gtk_list_item_manager_get_nth (self, position, &offset);
|
||||
if (tile == NULL)
|
||||
tile = gtk_rb_tree_get_last (self->items);
|
||||
{
|
||||
/* at end of list, pick the footer */
|
||||
for (tile = gtk_rb_tree_get_last (self->items);
|
||||
tile && (tile->type == GTK_LIST_TILE_REMOVED || tile->type == GTK_LIST_TILE_FILLER);
|
||||
tile = gtk_rb_tree_node_get_previous (tile))
|
||||
{ }
|
||||
|
||||
if (tile == NULL)
|
||||
{
|
||||
/* empty list, there isn't even a footer yet */
|
||||
tile = gtk_rb_tree_insert_after (self->items, NULL);
|
||||
tile->type = has_sections ? GTK_LIST_TILE_UNMATCHED_HEADER : GTK_LIST_TILE_HEADER;
|
||||
|
||||
tile = gtk_rb_tree_insert_after (self->items, tile);
|
||||
tile->type = has_sections ? GTK_LIST_TILE_UNMATCHED_FOOTER : GTK_LIST_TILE_FOOTER;
|
||||
}
|
||||
else if (has_sections && tile->type == GTK_LIST_TILE_FOOTER)
|
||||
{
|
||||
gtk_list_tile_set_type (tile,
|
||||
GTK_LIST_TILE_UNMATCHED_FOOTER);
|
||||
gtk_list_tile_set_type (gtk_list_tile_get_header (self, tile),
|
||||
GTK_LIST_TILE_UNMATCHED_HEADER);
|
||||
}
|
||||
}
|
||||
if (offset)
|
||||
tile = gtk_list_item_manager_ensure_split (self, tile, offset);
|
||||
|
||||
|
||||
tile = gtk_rb_tree_insert_before (self->items, tile);
|
||||
tile->type = GTK_LIST_TILE_ITEM;
|
||||
tile->n_items = n_items;
|
||||
gtk_rb_tree_node_mark_dirty (tile);
|
||||
|
||||
if (has_sections)
|
||||
{
|
||||
GtkListTile *section = gtk_rb_tree_node_get_previous (tile);
|
||||
|
||||
if (section->type == GTK_LIST_TILE_HEADER)
|
||||
{
|
||||
gtk_list_tile_set_type (section,
|
||||
GTK_LIST_TILE_UNMATCHED_HEADER);
|
||||
gtk_list_tile_set_type (gtk_list_tile_get_footer (self, section),
|
||||
GTK_LIST_TILE_UNMATCHED_FOOTER);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self->widget));
|
||||
}
|
||||
|
||||
@ -1138,6 +1340,7 @@ gtk_list_item_manager_model_selection_changed_cb (GListModel *model,
|
||||
static void
|
||||
gtk_list_item_manager_clear_model (GtkListItemManager *self)
|
||||
{
|
||||
GtkListTile *tile;
|
||||
GSList *l;
|
||||
|
||||
if (self->model == NULL)
|
||||
@ -1156,6 +1359,15 @@ gtk_list_item_manager_clear_model (GtkListItemManager *self)
|
||||
gtk_list_item_manager_model_items_changed_cb,
|
||||
self);
|
||||
g_clear_object (&self->model);
|
||||
|
||||
/* really empty the tiles */
|
||||
for (tile = gtk_list_tile_gc (self, gtk_list_item_manager_get_first (self));
|
||||
tile;
|
||||
tile = gtk_list_tile_gc (self, tile))
|
||||
{
|
||||
g_assert (tile->type == GTK_LIST_TILE_FILLER);
|
||||
}
|
||||
g_assert (gtk_rb_tree_get_root (self->items) == NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user