diff options
author | Benjamin Otte <otte@redhat.com> | 2023-03-02 03:53:56 +0100 |
---|---|---|
committer | Benjamin Otte <otte.benjamin@googlemail.com> | 2023-03-05 15:23:20 +0000 |
commit | d949afb80e3e80dfb798d49d7927df14f87258de (patch) | |
tree | 7fe92fb2fc59a575fa60a6d879260538448c1894 /gtk/gtkgridview.c | |
parent | 08c583b1b331bd0263c5f9360ce3848aa56f54c5 (diff) | |
download | gtk+-d949afb80e3e80dfb798d49d7927df14f87258de.tar.gz |
listitemmanager: Add a split vfunc and use it
Instead of randomly changing tiles, the listitemmanager gains a split
vfunc that listview and gridview implement so they can keep their tile
areas intact. The listitemmanager will now conform to these rules:
1. Never delete a tile.
This ensures that all areas stay intact.
2. Never change the n_items of a tile other than setting them to 0.
This causes "empty" areas to appear, but listview/gridview can
easily check for them by checking for tile->n_items == 0.
gtk_list_tile_gc() will get rid of them.
3. Adding items always creates new tiles that are added with empty area.
That way they don't interrupt any existing machinery until the next
allocation.
4. Adding/removing widgets has no effect on areas
This is useful in particular when scrolling where new widgets are
moving between tiles. When the manager moves the widgets, it may
split some areas, but will not remove any existing tiles, so the
whole area stays intact and the list can deal with further scroll
events before an allocation.
This improve the situation for #3334
Diffstat (limited to 'gtk/gtkgridview.c')
-rw-r--r-- | gtk/gtkgridview.c | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/gtk/gtkgridview.c b/gtk/gtkgridview.c index e5a440f74a..d067b8046a 100644 --- a/gtk/gtkgridview.c +++ b/gtk/gtkgridview.c @@ -152,6 +152,82 @@ dump (GtkGridView *self) g_print (" => %u widgets in %u list rows\n", n_widgets, n_list_rows); } +static GtkListTile * +gtk_grid_view_split (GtkListBase *base, + GtkListTile *tile, + guint n_items) +{ + GtkGridView *self = GTK_GRID_VIEW (base); + GtkListTile *split; + guint col, row_height; + + row_height = tile->area.height / MAX (tile->n_items / self->n_columns, 1); + + /* split off the multirow at the top */ + if (n_items >= self->n_columns) + { + guint top_rows = n_items / self->n_columns; + guint top_items = top_rows * self->n_columns; + + split = tile; + tile = gtk_list_tile_split (self->item_manager, tile, top_items); + gtk_list_tile_set_area (self->item_manager, + tile, + &(GdkRectangle) { + split->area.x, + split->area.y + row_height * top_rows, + split->area.width, + split->area.height - row_height * top_rows, + }); + gtk_list_tile_set_area_size (self->item_manager, + split, + split->area.width, + row_height * top_rows); + n_items -= top_items; + if (n_items == 0) + return tile; + } + + /* split off the multirow at the bottom */ + if (tile->n_items > self->n_columns) + { + split = gtk_list_tile_split (self->item_manager, tile, self->n_columns); + gtk_list_tile_set_area (self->item_manager, + split, + &(GdkRectangle) { + tile->area.x, + tile->area.y + row_height, + tile->area.width, + tile->area.height - row_height, + }); + gtk_list_tile_set_area_size (self->item_manager, + tile, + tile->area.width, + row_height); + } + + g_assert (n_items < tile->n_items); + g_assert (tile->n_items <= self->n_columns); + + /* now it's a single row, do a split at the column boundary */ + col = tile->area.x / self->column_width; + split = gtk_list_tile_split (self->item_manager, tile, n_items); + gtk_list_tile_set_area (self->item_manager, + split, + &(GdkRectangle) { + ceil ((col + n_items) * self->column_width), + tile->area.y, + ceil ((col + n_items + split->n_items) * self->column_width), + tile->area.height, + }); + gtk_list_tile_set_area_size (self->item_manager, + tile, + ceil ((col + n_items) * self->column_width) - tile->area.x, + tile->area.height); + + return split; +} + static gboolean gtk_grid_view_get_allocation_along (GtkListBase *base, guint pos, @@ -813,6 +889,7 @@ gtk_grid_view_class_init (GtkGridViewClass *klass) list_base_class->list_item_name = "child"; list_base_class->list_item_role = GTK_ACCESSIBLE_ROLE_GRID_CELL; + list_base_class->split = gtk_grid_view_split; list_base_class->get_allocation_along = gtk_grid_view_get_allocation_along; list_base_class->get_allocation_across = gtk_grid_view_get_allocation_across; list_base_class->get_items_in_rect = gtk_grid_view_get_items_in_rect; |