From: Benjamin Otte Date: Sun, 9 Apr 2023 02:26:51 +0000 (+0200) Subject: listitemmanager: Add/remove sections as needed X-Git-Tag: archive/raspbian/4.12.3+ds-1+rpi1~1^2^2^2~22^2~1^2~287^2~10 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=a73256e5c96986a4b61d0bd1a46a05fa1ac5ee2a;p=gtk4.git listitemmanager: Add/remove sections as needed When ensuring widgets, ensure that their section is known. This will be relevant when we use section widgets. Also ensure that sections that don't cover any widget get destroyed. --- diff --git a/gtk/gtklistitemmanager.c b/gtk/gtklistitemmanager.c index 430a278a86..4bd66bc79c 100644 --- a/gtk/gtklistitemmanager.c +++ b/gtk/gtklistitemmanager.c @@ -1041,10 +1041,11 @@ gtk_list_item_manager_release_items (GtkListItemManager *self, { GtkListTile *tile; guint position, i, n_items, query_n_items; - gboolean tracked; + gboolean tracked, deleted_section; n_items = g_list_model_get_n_items (G_LIST_MODEL (self->model)); position = 0; + deleted_section = FALSE; while (position < n_items) { @@ -1060,34 +1061,109 @@ gtk_list_item_manager_release_items (GtkListItemManager *self, while (i < position + query_n_items) { g_assert (tile != NULL); - if (tile->widget) + switch (tile->type) { - g_queue_push_tail (released, tile->widget); - tile->widget = NULL; + case GTK_LIST_TILE_ITEM: + if (tile->widget) + { + g_queue_push_tail (released, tile->widget); + tile->widget = NULL; + } + i += tile->n_items; + break; + + case GTK_LIST_TILE_HEADER: + case GTK_LIST_TILE_UNMATCHED_HEADER: + g_assert (deleted_section); + G_GNUC_FALLTHROUGH; + case GTK_LIST_TILE_FOOTER: + case GTK_LIST_TILE_UNMATCHED_FOOTER: + gtk_list_tile_set_type (tile, GTK_LIST_TILE_REMOVED); + deleted_section = TRUE; + break; + + case GTK_LIST_TILE_FILLER: + case GTK_LIST_TILE_REMOVED: + default: + g_assert_not_reached (); + break; } - i += tile->n_items; - tile = gtk_rb_tree_node_get_next (tile); + tile = gtk_list_tile_get_next_skip (tile); + } + if (deleted_section) + { + gtk_list_tile_set_type (gtk_list_tile_get_header (self, tile), + GTK_LIST_TILE_UNMATCHED_HEADER); + gtk_list_tile_set_type (gtk_list_tile_get_footer (self, tile), + GTK_LIST_TILE_UNMATCHED_FOOTER); } position += query_n_items; } } +static void +gtk_list_item_manager_insert_section (GtkListItemManager *self, + guint pos, + GtkListTileType footer_type, + GtkListTileType header_type) +{ + GtkListTile *tile, *other; + guint offset; + + tile = gtk_list_item_manager_get_nth (self, pos, &offset); + if (tile == NULL) + { + if (footer_type == GTK_LIST_TILE_FOOTER) + { + other = gtk_rb_tree_get_last (self->items); + if (other->type != GTK_LIST_TILE_FOOTER && other->type != GTK_LIST_TILE_UNMATCHED_FOOTER) + other = gtk_list_tile_get_previous_skip (other); + gtk_list_tile_set_type (other, footer_type); + } + return; + } + + if (offset) + tile = gtk_list_item_manager_ensure_split (self, tile, offset); + + other = gtk_list_tile_get_previous_skip (tile); + if (other->type == GTK_LIST_TILE_HEADER || other->type == GTK_LIST_TILE_UNMATCHED_HEADER) + { + if (header_type == GTK_LIST_TILE_HEADER) + gtk_list_tile_set_type (other, header_type); + if (footer_type == GTK_LIST_TILE_FOOTER) + { + other = gtk_list_tile_get_previous_skip (other); + if (other) + gtk_list_tile_set_type (other, footer_type); + } + } + else + { + other = gtk_rb_tree_insert_before (self->items, tile); + gtk_list_tile_set_type (other, header_type); + other = gtk_rb_tree_insert_before (self->items, other); + gtk_list_tile_set_type (other, footer_type); + } +} + static void gtk_list_item_manager_ensure_items (GtkListItemManager *self, GHashTable *change, guint update_start) { - GtkListTile *tile, *other_tile; + GtkListTile *tile, *other_tile, *header; GtkWidget *widget, *insert_after; guint position, i, n_items, query_n_items, offset; GQueue released = G_QUEUE_INIT; - gboolean tracked; + gboolean tracked, has_sections; if (self->model == NULL) return; n_items = g_list_model_get_n_items (G_LIST_MODEL (self->model)); position = 0; + has_sections = gtk_list_item_manager_has_sections (self); gtk_list_item_manager_release_items (self, &released); @@ -1101,61 +1177,106 @@ gtk_list_item_manager_ensure_items (GtkListItemManager *self, } tile = gtk_list_item_manager_get_nth (self, position, &offset); + if (offset > 0) + tile = gtk_list_item_manager_ensure_split (self, tile, offset); + + if (has_sections) + { + header = gtk_list_tile_get_header (self, tile); + if (header->type == GTK_LIST_TILE_UNMATCHED_HEADER) + { + guint start, end; + gtk_section_model_get_section (GTK_SECTION_MODEL (self->model), position, &start, &end); + gtk_list_item_manager_insert_section (self, + start, + GTK_LIST_TILE_UNMATCHED_FOOTER, + GTK_LIST_TILE_HEADER); + gtk_list_item_manager_insert_section (self, + end, + GTK_LIST_TILE_FOOTER, + GTK_LIST_TILE_UNMATCHED_HEADER); + } + } + for (other_tile = tile; other_tile && other_tile->widget == NULL; other_tile = gtk_rb_tree_node_get_previous (other_tile)) { /* do nothing */ } insert_after = other_tile ? other_tile->widget : NULL; - if (offset > 0) - tile = gtk_list_item_manager_ensure_split (self, tile, offset); - - for (i = 0; i < query_n_items; i++) + for (i = 0; i < query_n_items;) { g_assert (tile != NULL); - while (tile->n_items == 0) - tile = gtk_rb_tree_node_get_next (tile); - - if (tile->n_items > 1) - gtk_list_item_manager_ensure_split (self, tile, 1); + switch (tile->type) + { + case GTK_LIST_TILE_ITEM: + if (tile->n_items > 1) + gtk_list_item_manager_ensure_split (self, tile, 1); - if (tile->widget == NULL) - { - if (change) - { - tile->widget = gtk_list_item_manager_try_reacquire_list_item (self, - change, - position + i, - insert_after); - } if (tile->widget == NULL) { - tile->widget = g_queue_pop_head (&released); - if (tile->widget) + if (change) { - gtk_list_item_manager_move_list_item (self, - tile->widget, - position + i, - insert_after); + tile->widget = gtk_list_item_manager_try_reacquire_list_item (self, + change, + position + i, + insert_after); } - else + if (tile->widget == NULL) { - tile->widget = gtk_list_item_manager_acquire_list_item (self, - position + i, - insert_after); + tile->widget = g_queue_pop_head (&released); + if (tile->widget) + { + gtk_list_item_manager_move_list_item (self, + tile->widget, + position + i, + insert_after); + } + else + { + tile->widget = gtk_list_item_manager_acquire_list_item (self, + position + i, + insert_after); + } } } - } - else - { - if (update_start <= position + i) - gtk_list_item_manager_update_list_item (self, tile->widget, position + i); - } - insert_after = tile->widget; + else + { + if (update_start <= position + i) + gtk_list_item_manager_update_list_item (self, tile->widget, position + i); + } + insert_after = tile->widget; + i++; + break; - tile = gtk_rb_tree_node_get_next (tile); + case GTK_LIST_TILE_UNMATCHED_HEADER: + if (has_sections) + { + guint start, end; + gtk_section_model_get_section (GTK_SECTION_MODEL (self->model), position + i, &start, &end); + gtk_list_tile_set_type (tile, GTK_LIST_TILE_HEADER); + gtk_list_item_manager_insert_section (self, + end, + GTK_LIST_TILE_FOOTER, + GTK_LIST_TILE_UNMATCHED_HEADER); + } + break; + + case GTK_LIST_TILE_HEADER: + case GTK_LIST_TILE_FOOTER: + break; + + case GTK_LIST_TILE_UNMATCHED_FOOTER: + case GTK_LIST_TILE_FILLER: + case GTK_LIST_TILE_REMOVED: + default: + g_assert_not_reached (); + break; + } + tile = gtk_list_tile_get_next_skip (tile); } + position += query_n_items; }