[gtk/wip/otte/listview: 31/101] listview: Implement an anchor
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/listview: 31/101] listview: Implement an anchor
- Date: Sat, 19 Oct 2019 19:48:01 +0000 (UTC)
commit b4581b662f963f2b91be8687de489ea1df70cebc
Author: Benjamin Otte <otte redhat com>
Date: Wed Sep 19 07:08:30 2018 +0200
listview: Implement an anchor
The anchor selection is very basic: just anchor the top row.
That's vastly better than any other widget already though.
gtk/gtklistview.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 167 insertions(+), 5 deletions(-)
---
diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c
index aa83bed361..903907f2df 100644
--- a/gtk/gtklistview.c
+++ b/gtk/gtklistview.c
@@ -51,6 +51,12 @@ struct _GtkListView
GtkRbTree *rows;
int list_width;
+
+ /* managing the visible region */
+ guint anchor_pos;
+ int anchor_dy;
+ guint first_visible_pos;
+ guint lasst_visible_pos;
};
struct _ListRow
@@ -157,6 +163,112 @@ gtk_list_view_get_row (GtkListView *self,
return row;
}
+static guint
+list_row_get_position (GtkListView *self,
+ ListRow *row)
+{
+ ListRow *parent, *left;
+ int pos;
+
+ left = gtk_rb_tree_node_get_left (row);
+ if (left)
+ {
+ ListRowAugment *aug = gtk_rb_tree_get_augment (self->rows, left);
+ pos = aug->n_rows;
+ }
+ else
+ {
+ pos = 0;
+ }
+
+ for (parent = gtk_rb_tree_node_get_parent (row);
+ parent != NULL;
+ parent = gtk_rb_tree_node_get_parent (row))
+ {
+ left = gtk_rb_tree_node_get_left (parent);
+
+ if (left != row)
+ {
+ if (left)
+ {
+ ListRowAugment *aug = gtk_rb_tree_get_augment (self->rows, left);
+ pos += aug->n_rows;
+ }
+ pos += parent->n_rows;
+ }
+
+ row = parent;
+ }
+
+ return pos;
+}
+
+static ListRow *
+gtk_list_view_get_row_at_y (GtkListView *self,
+ int y,
+ int *offset)
+{
+ ListRow *row, *tmp;
+
+ row = gtk_rb_tree_get_root (self->rows);
+
+ while (row)
+ {
+ tmp = gtk_rb_tree_node_get_left (row);
+ if (tmp)
+ {
+ ListRowAugment *aug = gtk_rb_tree_get_augment (self->rows, tmp);
+ if (y < aug->height)
+ {
+ row = tmp;
+ continue;
+ }
+ y -= aug->height;
+ }
+
+ if (y < row->height)
+ break;
+ y -= row->height;
+
+ row = gtk_rb_tree_node_get_right (row);
+ }
+
+ if (offset)
+ *offset = row ? y : 0;
+
+ return row;
+}
+
+static int
+list_row_get_y (GtkListView *self,
+ ListRow *row)
+{
+ ListRow *parent;
+ int y = 0;
+
+ y = 0;
+ for (parent = gtk_rb_tree_node_get_parent (row);
+ parent != NULL;
+ parent = gtk_rb_tree_node_get_parent (row))
+ {
+ ListRow *left = gtk_rb_tree_node_get_left (parent);
+
+ if (left != row)
+ {
+ if (left)
+ {
+ ListRowAugment *aug = gtk_rb_tree_get_augment (self->rows, left);
+ y += aug->height;
+ }
+ y += parent->height;
+ }
+
+ row = parent;
+ }
+
+ return y ;
+}
+
static int
gtk_list_view_get_list_height (GtkListView *self)
{
@@ -184,15 +296,23 @@ gtk_list_view_update_adjustments (GtkListView *self,
value = 0;
if (_gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL)
value = upper - page_size - value;
+ value = gtk_adjustment_get_value (self->adjustment[orientation]);
}
else
{
+ ListRow *row;
+
page_size = gtk_widget_get_height (GTK_WIDGET (self));
upper = gtk_list_view_get_list_height (self);
- value = 0;
+
+ row = gtk_list_view_get_row (self, self->anchor_pos, NULL);
+ if (row)
+ value = list_row_get_y (self, row);
+ else
+ value = 0;
+ value += self->anchor_dy;
}
upper = MAX (upper, page_size);
- value = gtk_adjustment_get_value (self->adjustment[orientation]);
gtk_adjustment_configure (self->adjustment[orientation],
value,
@@ -310,11 +430,24 @@ gtk_list_view_remove_rows (GtkListView *self,
guint n_rows)
{
ListRow *row;
- guint i;
+ guint i, n_remaining;
if (n_rows == 0)
return;
+ n_remaining = self->model ? g_list_model_get_n_items (self->model) : 0;
+ if (self->anchor_pos >= position + n_rows)
+ {
+ self->anchor_pos -= n_rows;
+ }
+ else if (self->anchor_pos >= position)
+ {
+ self->anchor_pos = position;
+ if (self->anchor_pos > 0 && self->anchor_pos >= n_remaining)
+ self->anchor_pos = n_remaining - 1;
+ self->anchor_dy = 0;
+ }
+
row = gtk_list_view_get_row (self, position, NULL);
for (i = 0; i < n_rows; i++)
@@ -333,11 +466,18 @@ gtk_list_view_add_rows (GtkListView *self,
guint n_rows)
{
ListRow *row;
- guint i;
+ guint i, n_total;
if (n_rows == 0)
return;
+ n_total = self->model ? g_list_model_get_n_items (self->model) : 0;
+ if (self->anchor_pos >= position)
+ {
+ if (n_total != n_rows) /* the model was not empty before */
+ self->anchor_pos += n_rows;
+ }
+
row = gtk_list_view_get_row (self, position, NULL);
for (i = 0; i < n_rows; i++)
@@ -385,7 +525,29 @@ static void
gtk_list_view_adjustment_value_changed_cb (GtkAdjustment *adjustment,
GtkListView *self)
{
- gtk_widget_queue_allocate (GTK_WIDGET (self));
+ if (adjustment == self->adjustment[GTK_ORIENTATION_VERTICAL])
+ {
+ ListRow *row;
+ guint pos;
+ int dy;
+
+ row = gtk_list_view_get_row_at_y (self, gtk_adjustment_get_value (adjustment), &dy);
+ if (row)
+ pos = list_row_get_position (self, row);
+ else
+ pos = 0;
+
+ if (pos != self->anchor_pos || dy != self->anchor_dy)
+ {
+ self->anchor_pos = pos;
+ self->anchor_dy = dy;
+ gtk_widget_queue_allocate (GTK_WIDGET (self));
+ }
+ }
+ else
+ {
+ gtk_widget_queue_allocate (GTK_WIDGET (self));
+ }
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]