listitemmanager: Add section tiles
authorBenjamin Otte <otte@redhat.com>
Fri, 7 Apr 2023 02:00:00 +0000 (04:00 +0200)
committerBenjamin Otte <otte@redhat.com>
Tue, 9 May 2023 15:00:39 +0000 (17:00 +0200)
For now, we just have a HEADER at the start and a FOOTER at the end.
That's hard enough to get right.

gtk/gtklistitemmanager.c
gtk/gtklistitemmanagerprivate.h
testsuite/gtk/listitemmanager.c

index f976b0063e0506beaef97e69c4a5602c5f59636f..10ca102e27a8430266e6915d691ef97d9096fc9e 100644 (file)
@@ -132,6 +132,7 @@ 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);
 
@@ -148,6 +149,12 @@ 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;
 }
 
@@ -618,6 +625,8 @@ gtk_list_item_manager_add_items (GtkListItemManager *self,
     return;
 
   tile = gtk_list_item_manager_get_nth (self, position, &offset);
+  if (tile == NULL)
+    tile = gtk_rb_tree_get_last (self->items);
   if (offset)
     tile = gtk_list_item_manager_ensure_split (self, tile, offset);
 
@@ -761,6 +770,10 @@ gtk_list_tile_gc (GtkListItemManager *self,
             continue;
           break;
 
+        case GTK_LIST_TILE_HEADER:
+        case GTK_LIST_TILE_FOOTER:
+        case GTK_LIST_TILE_UNMATCHED_HEADER:
+        case GTK_LIST_TILE_UNMATCHED_FOOTER:
         case GTK_LIST_TILE_FILLER:
           break;
 
index df6e0d1211eaa11e56cf89c3649160ce5b789673..9efaf0461bfd40a85578c40c2cb7fc3cf186f7b7 100644 (file)
@@ -46,6 +46,10 @@ typedef struct _GtkListItemTracker GtkListItemTracker;
 typedef enum
 {
   GTK_LIST_TILE_ITEM,
+  GTK_LIST_TILE_HEADER,
+  GTK_LIST_TILE_FOOTER,
+  GTK_LIST_TILE_UNMATCHED_HEADER,
+  GTK_LIST_TILE_UNMATCHED_FOOTER,
   GTK_LIST_TILE_FILLER,
   GTK_LIST_TILE_REMOVED,
 } GtkListTileType;
index a8d3096239cbeec60239e620f81bd7bf3fd71ed3..38dcf8238a4cff21e616cb61c845e722dfdcdb1e 100644 (file)
@@ -45,6 +45,11 @@ check_list_item_manager (GtkListItemManager  *items,
   GtkListTile *tile;
   guint n_items = 0;
   guint i;
+  enum {
+    NO_SECTION,
+    MATCHED_SECTION,
+    UNMATCHED_SECTION
+  } section_state = NO_SECTION;
 
   for (tile = gtk_list_item_manager_get_first (items);
        tile != NULL;
@@ -52,7 +57,36 @@ check_list_item_manager (GtkListItemManager  *items,
     {
       switch (tile->type)
         {
+          case GTK_LIST_TILE_HEADER:
+            g_assert_cmpint (section_state, ==, NO_SECTION);
+            g_assert_cmpint (tile->n_items, ==, 0);
+            g_assert_false (tile->widget);
+            section_state = MATCHED_SECTION;
+            break;
+
+          case GTK_LIST_TILE_UNMATCHED_HEADER:
+            g_assert_cmpint (section_state, ==, NO_SECTION);
+            g_assert_cmpint (tile->n_items, ==, 0);
+            g_assert_false (tile->widget);
+            section_state = UNMATCHED_SECTION;
+            break;
+
+          case GTK_LIST_TILE_FOOTER:
+            g_assert_cmpint (section_state, ==, MATCHED_SECTION);
+            g_assert_cmpint (tile->n_items, ==, 0);
+            g_assert_false (tile->widget);
+            section_state = NO_SECTION;
+            break;
+
+          case GTK_LIST_TILE_UNMATCHED_FOOTER:
+            g_assert_cmpint (section_state, ==, UNMATCHED_SECTION);
+            g_assert_cmpint (tile->n_items, ==, 0);
+            g_assert_false (tile->widget);
+            section_state = NO_SECTION;
+            break;
+
           case GTK_LIST_TILE_ITEM:
+            g_assert_cmpint (section_state, !=, NO_SECTION);
             if (tile->widget)
               {
                 GObject *item = g_list_model_get_item (model, n_items);
@@ -81,6 +115,7 @@ check_list_item_manager (GtkListItemManager  *items,
         }
     }
 
+  g_assert_cmpint (section_state, ==, NO_SECTION);
   g_assert_cmpint (n_items, ==, g_list_model_get_n_items (model));
 
   for (i = 0; i < n_trackers; i++)
@@ -109,7 +144,36 @@ check_list_item_manager (GtkListItemManager  *items,
     {
       switch (tile->type)
         {
+          case GTK_LIST_TILE_HEADER:
+            g_assert_cmpint (section_state, ==, NO_SECTION);
+            g_assert_cmpint (tile->n_items, ==, 0);
+            g_assert_false (tile->widget);
+            section_state = MATCHED_SECTION;
+            break;
+
+          case GTK_LIST_TILE_UNMATCHED_HEADER:
+            g_assert_cmpint (section_state, ==, NO_SECTION);
+            g_assert_cmpint (tile->n_items, ==, 0);
+            g_assert_false (tile->widget);
+            section_state = UNMATCHED_SECTION;
+            break;
+
+          case GTK_LIST_TILE_FOOTER:
+            g_assert_cmpint (section_state, ==, MATCHED_SECTION);
+            g_assert_cmpint (tile->n_items, ==, 0);
+            g_assert_false (tile->widget);
+            section_state = NO_SECTION;
+            break;
+
+          case GTK_LIST_TILE_UNMATCHED_FOOTER:
+            g_assert_cmpint (section_state, ==, UNMATCHED_SECTION);
+            g_assert_cmpint (tile->n_items, ==, 0);
+            g_assert_false (tile->widget);
+            section_state = NO_SECTION;
+            break;
+
           case GTK_LIST_TILE_ITEM:
+            g_assert_cmpint (section_state, !=, NO_SECTION);
             if (tile->widget)
               {
                 g_assert_cmpint (tile->n_items, ==, 1);
@@ -126,6 +190,7 @@ check_list_item_manager (GtkListItemManager  *items,
         }
     }
 
+  g_assert_cmpint (section_state, ==, NO_SECTION);
   g_assert_cmpint (n_items, ==, g_list_model_get_n_items (model));
 
   for (i = 0; i < n_trackers; i++)