diff --git a/gtk/gtklistbase.c b/gtk/gtklistbase.c index 7b781bf3b3..81ac56cc6f 100644 --- a/gtk/gtklistbase.c +++ b/gtk/gtklistbase.c @@ -23,6 +23,8 @@ #include "gtkadjustment.h" #include "gtkbitset.h" +#include "gtkcssnodeprivate.h" +#include "gtkcsspositionvalueprivate.h" #include "gtkdragsourceprivate.h" #include "gtkdropcontrollermotion.h" #include "gtkgesturedrag.h" @@ -1995,6 +1997,30 @@ gtk_list_base_get_orientation (GtkListBase *self) return priv->orientation; } +void +gtk_list_base_get_border_spacing (GtkListBase *self, + int *xspacing, + int *yspacing) +{ + GtkCssStyle *style = gtk_css_node_get_style (gtk_widget_get_css_node (GTK_WIDGET (self))); + GtkCssValue *border_spacing = style->size->border_spacing; + + if (gtk_list_base_get_orientation (self) == GTK_ORIENTATION_HORIZONTAL) + { + if (xspacing) + *xspacing = _gtk_css_position_value_get_y (border_spacing, 0); + if (yspacing) + *yspacing = _gtk_css_position_value_get_x (border_spacing, 0); + } + else + { + if (xspacing) + *xspacing = _gtk_css_position_value_get_x (border_spacing, 0); + if (yspacing) + *yspacing = _gtk_css_position_value_get_y (border_spacing, 0); + } +} + GtkListItemManager * gtk_list_base_get_manager (GtkListBase *self) { diff --git a/gtk/gtklistbaseprivate.h b/gtk/gtklistbaseprivate.h index c79bd8b13d..e8ab5b5db7 100644 --- a/gtk/gtklistbaseprivate.h +++ b/gtk/gtklistbaseprivate.h @@ -62,6 +62,9 @@ struct _GtkListBaseClass GtkOrientation gtk_list_base_get_orientation (GtkListBase *self); #define gtk_list_base_get_opposite_orientation(self) OPPOSITE_ORIENTATION(gtk_list_base_get_orientation(self)) guint gtk_list_base_get_focus_position (GtkListBase *self); +void gtk_list_base_get_border_spacing (GtkListBase *self, + int *xspacing, + int *yspacing); GtkListItemManager * gtk_list_base_get_manager (GtkListBase *self); GtkScrollablePolicy gtk_list_base_get_scroll_policy (GtkListBase *self, GtkOrientation orientation); diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c index f210ac26ce..f822c53529 100644 --- a/gtk/gtklistview.c +++ b/gtk/gtklistview.c @@ -193,22 +193,23 @@ gtk_list_view_split (GtkListBase *base, { GtkListView *self = GTK_LIST_VIEW (base); GtkListTile *new_tile; - guint row_height; + int spacing, row_height; - row_height = tile->area.height / tile->n_items; + gtk_list_base_get_border_spacing (GTK_LIST_BASE (self), NULL, &spacing); + row_height = (tile->area.height - (tile->n_items - 1) * spacing) / tile->n_items; new_tile = gtk_list_tile_split (self->item_manager, tile, n_items); gtk_list_tile_set_area_size (self->item_manager, tile, tile->area.width, - row_height * tile->n_items); + row_height * tile->n_items + spacing * (tile->n_items - 1)); gtk_list_tile_set_area (self->item_manager, new_tile, &(GdkRectangle) { tile->area.x, - tile->area.y + tile->area.height, + tile->area.y + tile->area.height + spacing, tile->area.width, - row_height * new_tile->n_items + row_height * new_tile->n_items + spacing * (new_tile->n_items - 1) }); return new_tile; @@ -239,6 +240,9 @@ gtk_list_view_get_allocation (GtkListBase *base, { /* item is not allocated yet */ GtkListTile *other; + int spacing; + + gtk_list_base_get_border_spacing (GTK_LIST_BASE (self), NULL, &spacing); for (other = gtk_rb_tree_node_get_previous (tile); other; @@ -248,7 +252,7 @@ gtk_list_view_get_allocation (GtkListBase *base, { area->x = other->area.x; area->width = other->area.width; - area->y = other->area.y + other->area.height; + area->y = other->area.y + other->area.height + spacing; break; } } @@ -262,7 +266,7 @@ gtk_list_view_get_allocation (GtkListBase *base, { area->x = other->area.x; area->width = other->area.width; - area->y = other->area.y; + area->y = MAX (0, other->area.y - spacing); break; } } @@ -272,36 +276,6 @@ gtk_list_view_get_allocation (GtkListBase *base, return TRUE; } -static GtkBitset * -gtk_list_view_get_items_in_rect (GtkListBase *base, - const cairo_rectangle_int_t *rect) -{ - GtkListView *self = GTK_LIST_VIEW (base); - guint first, last, n_items; - GtkBitset *result; - GtkListTile *tile; - - result = gtk_bitset_new_empty (); - - n_items = gtk_list_base_get_n_items (base); - if (n_items == 0) - return result; - - tile = gtk_list_item_manager_get_tile_at (self->item_manager, 0, rect->y); - if (tile) - first = gtk_list_tile_get_position (self->item_manager, tile); - else - first = rect->y < 0 ? 0 : n_items - 1; - tile = gtk_list_item_manager_get_tile_at (self->item_manager, 0, rect->y + rect->height); - if (tile) - last = gtk_list_tile_get_position (self->item_manager, tile); - else - last = rect->y + rect->height < 0 ? 0 : n_items - 1; - - gtk_bitset_add_range_closed (result, first, last); - return result; -} - static guint gtk_list_view_move_focus_along (GtkListBase *base, guint pos, @@ -326,9 +300,8 @@ gtk_list_view_get_position_from_allocation (GtkListBase *base, { GtkListView *self = GTK_LIST_VIEW (base); GtkListTile *tile; - int row_height, tile_pos; - tile = gtk_list_item_manager_get_tile_at (self->item_manager, x, y); + tile = gtk_list_item_manager_get_nearest_tile (self->item_manager, x, y); if (tile == NULL) return FALSE; @@ -344,22 +317,60 @@ gtk_list_view_get_position_from_allocation (GtkListBase *base, } *pos = gtk_list_tile_get_position (self->item_manager, tile); - row_height = (tile->area.height / tile->n_items); - tile_pos = (y - tile->area.y) / row_height; - - *pos += tile_pos; - if (area) + *area = tile->area; + + if (tile->n_items > 1) { - area->x = tile->area.x; - area->width = tile->area.width; - area->y = tile->area.y + tile_pos * row_height; - area->height = row_height; + int row_height, tile_pos, spacing; + + gtk_list_base_get_border_spacing (GTK_LIST_BASE (self), NULL, &spacing); + row_height = (tile->area.height - (tile->n_items - 1) * spacing) / tile->n_items; + if (y >= tile->area.y + tile->area.height) + tile_pos = tile->n_items - 1; + else + tile_pos = (y - tile->area.y) / (row_height + spacing); + + *pos += tile_pos; + if (area) + { + area->y = tile->area.y + tile_pos * (row_height + spacing); + area->height = row_height; + } } return TRUE; } +static GtkBitset * +gtk_list_view_get_items_in_rect (GtkListBase *base, + const cairo_rectangle_int_t *rect) +{ + guint first, last; + cairo_rectangle_int_t area; + GtkBitset *result; + + result = gtk_bitset_new_empty (); + + if (!gtk_list_view_get_position_from_allocation (base, rect->x, rect->y, &first, &area)) + return result; + if (area.y + area.height < rect->y) + first++; + + if (!gtk_list_view_get_position_from_allocation (base, + rect->x + rect->width - 1, + rect->y + rect->height - 1, + &last, &area)) + return result; + if (area.y >= rect->y + rect->height) + last--; + + if (last >= first) + gtk_bitset_add_range_closed (result, first, last); + + return result; +} + static guint gtk_list_view_move_focus_across (GtkListBase *base, guint pos, @@ -432,9 +443,14 @@ gtk_list_view_measure_list (GtkWidget *widget, { GtkListView *self = GTK_LIST_VIEW (widget); GtkListTile *tile; - int min, nat, child_min, child_nat; + int min, nat, child_min, child_nat, spacing; GArray *min_heights, *nat_heights; - guint n_unknown; + guint n_unknown, n_items; + + n_items = gtk_list_base_get_n_items (GTK_LIST_BASE (self)); + if (n_items == 0) + return; + gtk_list_base_get_border_spacing (GTK_LIST_BASE (self), NULL, &spacing); min_heights = g_array_new (FALSE, FALSE, sizeof (int)); nat_heights = g_array_new (FALSE, FALSE, sizeof (int)); @@ -470,8 +486,8 @@ gtk_list_view_measure_list (GtkWidget *widget, g_array_free (min_heights, TRUE); g_array_free (nat_heights, TRUE); - *minimum = min; - *natural = nat; + *minimum = min + spacing * (n_items - 1); + *natural = nat + spacing * (n_items - 1); } static void @@ -500,7 +516,7 @@ gtk_list_view_size_allocate (GtkWidget *widget, GtkListView *self = GTK_LIST_VIEW (widget); GtkListTile *tile; GArray *heights; - int min, nat, row_height, y, list_width; + int min, nat, row_height, y, list_width, spacing; GtkOrientation orientation, opposite_orientation; GtkScrollablePolicy scroll_policy, opposite_scroll_policy; @@ -508,6 +524,7 @@ gtk_list_view_size_allocate (GtkWidget *widget, opposite_orientation = OPPOSITE_ORIENTATION (orientation); scroll_policy = gtk_list_base_get_scroll_policy (GTK_LIST_BASE (self), orientation); opposite_scroll_policy = gtk_list_base_get_scroll_policy (GTK_LIST_BASE (self), opposite_orientation); + gtk_list_base_get_border_spacing (GTK_LIST_BASE (self), NULL, &spacing); /* step 0: exit early if list is empty */ tile = gtk_list_tile_gc (self->item_manager, gtk_list_item_manager_get_first (self->item_manager)); @@ -559,9 +576,15 @@ gtk_list_view_size_allocate (GtkWidget *widget, { gtk_list_tile_set_area_position (self->item_manager, tile, 0, y); if (tile->widget == NULL) - gtk_list_tile_set_area_size (self->item_manager, tile, list_width, row_height * tile->n_items); + { + gtk_list_tile_set_area_size (self->item_manager, + tile, + list_width, + row_height * tile->n_items + + spacing * (tile->n_items - 1)); + } - y += tile->area.height; + y += tile->area.height + spacing; } /* step 4: allocate the rest */