listitemmanager: Listen to sections-changed
authorMatthias Clasen <mclasen@redhat.com>
Tue, 23 May 2023 17:49:04 +0000 (13:49 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Sat, 27 May 2023 10:33:50 +0000 (06:33 -0400)
And recreate header and footer tiles as needed.

This commit was tested using a sortlistmodel, changing
the section sorter from sorting only by first char
to sorting by the first two chars, which changes
the number of sections, but leaves the alphabetic
order of items unchanged.

gtk/gtklistitemmanager.c

index aa5c9b1bf86d7bb7f8502935f3354b1022cddc04..3c63c70ac3b4a2800d5eec626784d0556c0613e0 100644 (file)
@@ -1565,6 +1565,67 @@ gtk_list_item_manager_model_items_changed_cb (GListModel         *model,
   gtk_widget_queue_resize (self->widget);
 }
 
+static void
+gtk_list_item_manager_model_sections_changed_cb (GListModel         *model,
+                                                 guint               position,
+                                                 guint               n_items,
+                                                 GtkListItemManager *self)
+{
+  GtkListItemChange change;
+  GtkListTile *tile, *header;
+  guint offset;
+
+  if (!gtk_list_item_manager_has_sections (self))
+    return;
+
+  gtk_list_item_change_init (&change);
+
+  tile = gtk_list_item_manager_get_nth (self, position, &offset);
+  header = gtk_list_tile_get_header (self, tile);
+  gtk_list_item_change_clear_header (&change, &header->widget);
+  gtk_list_tile_set_type (header, GTK_LIST_TILE_UNMATCHED_HEADER);
+
+  n_items -= MIN (n_items, position - offset);
+  while (n_items > 0)
+    {
+      switch (tile->type)
+        {
+        case GTK_LIST_TILE_HEADER:
+        case GTK_LIST_TILE_UNMATCHED_HEADER:
+          gtk_list_item_change_clear_header (&change, &tile->widget);
+          gtk_list_tile_set_type (tile, GTK_LIST_TILE_REMOVED);
+          break;
+
+        case GTK_LIST_TILE_FOOTER:
+        case GTK_LIST_TILE_UNMATCHED_FOOTER:
+          gtk_list_tile_set_type (tile, GTK_LIST_TILE_REMOVED);
+          break;
+
+        case GTK_LIST_TILE_ITEM:
+          n_items -= MIN (n_items, tile->n_items);
+          break;
+
+        case GTK_LIST_TILE_REMOVED:
+        default:
+          g_assert_not_reached ();
+          break;
+        }
+
+      tile = gtk_list_tile_get_next_skip (tile);
+    }
+
+  if (!gtk_list_tile_is_footer (tile))
+    tile = gtk_list_tile_get_footer (self, tile);
+
+  gtk_list_tile_set_type (tile, GTK_LIST_TILE_UNMATCHED_FOOTER);
+
+  gtk_list_item_manager_ensure_items (self, &change, G_MAXUINT, 0);
+
+  gtk_list_item_change_finish (&change);
+
+  gtk_widget_queue_resize (GTK_WIDGET (self->widget));
+}
+
 static void
 gtk_list_item_manager_model_selection_changed_cb (GListModel         *model,
                                                   guint               position,
@@ -1624,6 +1685,9 @@ gtk_list_item_manager_clear_model (GtkListItemManager *self)
   g_signal_handlers_disconnect_by_func (self->model,
                                         gtk_list_item_manager_model_items_changed_cb,
                                         self);
+  g_signal_handlers_disconnect_by_func (self->model,
+                                        gtk_list_item_manager_model_sections_changed_cb,
+                                        self);
   g_clear_object (&self->model);
 
   gtk_list_item_manager_gc_tiles (self);
@@ -1682,6 +1746,11 @@ gtk_list_item_manager_set_model (GtkListItemManager *self,
                         "selection-changed",
                         G_CALLBACK (gtk_list_item_manager_model_selection_changed_cb),
                         self);
+      if (GTK_IS_SECTION_MODEL (model))
+        g_signal_connect (model,
+                          "sections-changed",
+                          G_CALLBACK (gtk_list_item_manager_model_sections_changed_cb),
+                          self);
 
       gtk_list_item_change_init (&change);
       gtk_list_item_manager_add_items (self, &change, 0, g_list_model_get_n_items (G_LIST_MODEL (model)));