listview: cull listitems that are out of view

Use set_child_visible(FALSE) on those widgets and don't allocate them.

This should usually be the majority of items, so it's quite a worthwhile
addition.

Idea by Ivan Molodetskikh.

Related: #3334
This commit is contained in:
Benjamin Otte
2022-06-01 04:29:15 +02:00
parent 526b62e0be
commit 39645d3258

View File

@@ -37,6 +37,13 @@
#include "gtktypebuiltins.h"
#include "gtkwidgetprivate.h"
/* Allow shadows to overdraw without immediately culling the widget at the viewport
* boundary.
* Choose this so that roughly 1 extra widget gets drawn on each side of the viewport,
* but not more. Icons are 16px, text height is somewhere there, too.
*/
#define GTK_LIST_BASE_CHILD_MAX_OVERDRAW 10
typedef struct _RubberbandData RubberbandData;
struct _RubberbandData
@@ -1351,6 +1358,22 @@ gtk_list_base_size_allocate_child (GtkListBase *self,
int height)
{
GtkAllocation child_allocation;
int self_width, self_height;
self_width = gtk_widget_get_width (GTK_WIDGET (self));
self_height = gtk_widget_get_height (GTK_WIDGET (self));
if (y + height + GTK_LIST_BASE_CHILD_MAX_OVERDRAW <= 0 ||
y - GTK_LIST_BASE_CHILD_MAX_OVERDRAW >= self_height ||
x + width + GTK_LIST_BASE_CHILD_MAX_OVERDRAW <= 0 ||
x - GTK_LIST_BASE_CHILD_MAX_OVERDRAW >= self_width)
{
/* child is fully outside the viewport, hide it and don't allocate it */
gtk_widget_set_child_visible (child, FALSE);
return;
}
gtk_widget_set_child_visible (child, TRUE);
if (gtk_list_base_get_orientation (GTK_LIST_BASE (self)) == GTK_ORIENTATION_VERTICAL)
{
@@ -1363,9 +1386,7 @@ gtk_list_base_size_allocate_child (GtkListBase *self,
}
else
{
int mirror_point = gtk_widget_get_width (GTK_WIDGET (self));
child_allocation.x = mirror_point - x - width;
child_allocation.x = self_width - x - width;
child_allocation.y = y;
child_allocation.width = width;
child_allocation.height = height;
@@ -1382,9 +1403,7 @@ gtk_list_base_size_allocate_child (GtkListBase *self,
}
else
{
int mirror_point = gtk_widget_get_width (GTK_WIDGET (self));
child_allocation.x = mirror_point - y - height;
child_allocation.x = self_width - y - height;
child_allocation.y = x;
child_allocation.width = height;
child_allocation.height = width;