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,
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;
GtkRbTree *items;
GSList *trackers;
+
+ GtkListTile * (* split_func) (gpointer, GtkListTile *, guint);
+ gpointer user_data;
};
struct _GtkListItemManagerClass
GtkListItemManager *
gtk_list_item_manager_new (GtkWidget *widget,
const char *item_css_name,
- GtkAccessibleRole item_role)
+ GtkAccessibleRole item_role,
+ GtkListTile * (* split_func) (gpointer, GtkListTile *, guint),
+ gpointer user_data)
{
GtkListItemManager *self;
self->widget = widget;
self->item_css_name = g_intern_string (item_css_name);
self->item_role = item_role;
+ self->split_func = split_func;
+ self->user_data = user_data;
self->items = gtk_rb_tree_new_for_size (sizeof (GtkListTile),
sizeof (GtkListTileAugment),
}
}
+static GtkListTile *
+gtk_list_item_manager_ensure_split (GtkListItemManager *self,
+ GtkListTile *tile,
+ guint n_items)
+{
+ return self->split_func (self->user_data, tile, n_items);
+}
+
static void
gtk_list_item_manager_remove_items (GtkListItemManager *self,
GHashTable *change,
guint position,
guint n_items)
{
- GtkListTile *tile;
+ GtkListTile *tile, *next;
+ guint offset;
if (n_items == 0)
return;
- tile = gtk_list_item_manager_get_nth (self, position, NULL);
+ tile = gtk_list_item_manager_get_nth (self, position, &offset);
+ if (offset)
+ tile = gtk_list_item_manager_ensure_split (self, tile, offset);
while (n_items > 0)
{
if (tile->n_items > n_items)
{
- tile->n_items -= n_items;
- gtk_rb_tree_node_mark_dirty (tile);
- n_items = 0;
- }
- else
- {
- GtkListTile *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;
- gtk_rb_tree_remove (self->items, tile);
- tile = next;
+ gtk_list_item_manager_ensure_split (self, tile, n_items);
+ g_assert (tile->n_items <= n_items);
}
+
+ 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;
+ gtk_rb_tree_node_mark_dirty (tile);
+
+ tile = next;
}
gtk_widget_queue_resize (GTK_WIDGET (self->widget));
return;
tile = gtk_list_item_manager_get_nth (self, position, &offset);
+ if (offset)
+ tile = gtk_list_item_manager_ensure_split (self, tile, offset);
- if (tile == NULL || tile->widget)
- tile = gtk_rb_tree_insert_before (self->items, tile);
- tile->n_items += n_items;
+ tile = gtk_rb_tree_insert_before (self->items, tile);
+ tile->n_items = n_items;
gtk_rb_tree_node_mark_dirty (tile);
gtk_widget_queue_resize (GTK_WIDGET (self->widget));
gtk_list_item_manager_release_items (GtkListItemManager *self,
GQueue *released)
{
- GtkListTile *tile, *prev, *next;
+ GtkListTile *tile;
guint position, i, n_items, query_n_items;
gboolean tracked;
{
g_queue_push_tail (released, tile->widget);
tile->widget = NULL;
- i++;
- prev = gtk_rb_tree_node_get_previous (tile);
- if (prev && gtk_list_item_manager_merge_list_items (self, prev, tile))
- tile = prev;
- next = gtk_rb_tree_node_get_next (tile);
- if (next && next->widget == NULL)
- {
- i += next->n_items;
- if (!gtk_list_item_manager_merge_list_items (self, next, tile))
- g_assert_not_reached ();
- tile = gtk_rb_tree_node_get_next (next);
- }
- else
- {
- tile = next;
- }
- }
- else
- {
- i += tile->n_items;
- tile = gtk_rb_tree_node_get_next (tile);
}
+ i += tile->n_items;
+ tile = gtk_rb_tree_node_get_next (tile);
}
position += query_n_items;
}
GHashTable *change,
guint update_start)
{
- GtkListTile *tile, *new_tile;
+ GtkListTile *tile, *other_tile;
GtkWidget *widget, *insert_after;
guint position, i, n_items, query_n_items, offset;
GQueue released = G_QUEUE_INIT;
}
tile = gtk_list_item_manager_get_nth (self, position, &offset);
- for (new_tile = tile;
- new_tile && new_tile->widget == NULL;
- new_tile = gtk_rb_tree_node_get_previous (new_tile))
+ for (other_tile = tile;
+ other_tile && other_tile->widget == NULL;
+ other_tile = gtk_rb_tree_node_get_previous (other_tile))
{ /* do nothing */ }
- insert_after = new_tile ? new_tile->widget : NULL;
+ insert_after = other_tile ? other_tile->widget : NULL;
if (offset > 0)
- {
- g_assert (tile != NULL);
- new_tile = gtk_rb_tree_insert_before (self->items, tile);
- new_tile->n_items = offset;
- tile->n_items -= offset;
- gtk_rb_tree_node_mark_dirty (tile);
- }
+ tile = gtk_list_item_manager_ensure_split (self, tile, offset);
for (i = 0; i < query_n_items; i++)
{
g_assert (tile != NULL);
+
+ while (tile->n_items == 0)
+ tile = gtk_rb_tree_node_get_next (tile);
+
if (tile->n_items > 1)
- {
- new_tile = gtk_rb_tree_insert_before (self->items, tile);
- new_tile->n_items = 1;
- tile->n_items--;
- gtk_rb_tree_node_mark_dirty (tile);
- }
- else
- {
- new_tile = tile;
- tile = gtk_rb_tree_node_get_next (tile);
- }
- if (new_tile->widget == NULL)
+ gtk_list_item_manager_ensure_split (self, tile, 1);
+
+ if (tile->widget == NULL)
{
if (change)
{
- new_tile->widget = gtk_list_item_manager_try_reacquire_list_item (self,
- change,
- position + i,
- insert_after);
+ tile->widget = gtk_list_item_manager_try_reacquire_list_item (self,
+ change,
+ position + i,
+ insert_after);
}
- if (new_tile->widget == NULL)
+ if (tile->widget == NULL)
{
- new_tile->widget = g_queue_pop_head (&released);
- if (new_tile->widget)
+ tile->widget = g_queue_pop_head (&released);
+ if (tile->widget)
{
gtk_list_item_manager_move_list_item (self,
- new_tile->widget,
+ tile->widget,
position + i,
insert_after);
}
else
{
- new_tile->widget = gtk_list_item_manager_acquire_list_item (self,
- position + i,
- insert_after);
+ 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, new_tile->widget, position + i);
+ gtk_list_item_manager_update_list_item (self, tile->widget, position + i);
}
- insert_after = new_tile->widget;
+ insert_after = tile->widget;
+
+ tile = gtk_rb_tree_node_get_next (tile);
}
position += query_n_items;
}
continue;
}
+ while (offset >= tile->n_items)
+ {
+ offset -= tile->n_items;
+ tile = gtk_rb_tree_node_get_next (tile);
+ }
if (offset > 0)
{
- new_tile = gtk_rb_tree_insert_before (self->items, tile);
- new_tile->n_items = offset;
- tile->n_items -= offset;
+ tile = gtk_list_item_manager_ensure_split (self, tile, offset);
offset = 0;
- gtk_rb_tree_node_mark_dirty (tile);
}
+ new_tile = tile;
if (tile->n_items == 1)
- {
- new_tile = tile;
- tile = gtk_rb_tree_node_get_next (tile);
- }
+ tile = gtk_rb_tree_node_get_next (tile);
else
- {
- new_tile = gtk_rb_tree_insert_before (self->items, tile);
- new_tile->n_items = 1;
- tile->n_items--;
- gtk_rb_tree_node_mark_dirty (tile);
- }
+ tile = gtk_list_item_manager_ensure_split (self, tile, 1);
new_tile->widget = widget;
insert_after = widget;