[gtk/wip/otte/listview: 3/9] listview: Add a focus tracker
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/listview: 3/9] listview: Add a focus tracker
- Date: Fri, 18 Oct 2019 02:10:07 +0000 (UTC)
commit ec866664608112f3f676452312b5f65db6b1b2e9
Author: Benjamin Otte <otte redhat com>
Date: Wed Oct 16 14:57:39 2019 +0200
listview: Add a focus tracker
This ensures that the row with the input focus always stays available,
even when scrolled out of view.
gtk/gtklistview.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
---
diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c
index 1f199d40dd..56ce86797d 100644
--- a/gtk/gtklistview.c
+++ b/gtk/gtklistview.c
@@ -74,6 +74,8 @@ struct _GtkListView
double anchor_align;
/* the last item that was selected - basically the location to extend selections from */
GtkListItemTracker *selected;
+ /* the item that has input focus */
+ GtkListItemTracker *focus;
};
struct _ListRow
@@ -663,9 +665,25 @@ gtk_list_view_focus (GtkWidget *widget,
old_focus_child = gtk_widget_get_focus_child (widget);
+ if (old_focus_child == NULL &&
+ (direction == GTK_DIR_TAB_FORWARD || direction == GTK_DIR_TAB_BACKWARD))
+ {
+ ListRow *row;
+ guint pos;
+
+ /* When tabbing into the listview, don't focus the first/last item,
+ * but keep the previously focused item
+ */
+ pos = gtk_list_item_tracker_get_position (self->item_manager, self->focus);
+ row = gtk_list_item_manager_get_nth (self->item_manager, pos, NULL);
+ if (row && gtk_widget_grab_focus (row->parent.widget))
+ goto moved_focus;
+ }
+
if (!GTK_WIDGET_CLASS (gtk_list_view_parent_class)->focus (widget, direction))
return FALSE;
+moved_focus:
new_focus_child = gtk_widget_get_focus_child (widget);
if (old_focus_child != new_focus_child &&
@@ -727,6 +745,11 @@ gtk_list_view_dispose (GObject *object)
gtk_list_item_tracker_free (self->item_manager, self->selected);
self->selected = NULL;
}
+ if (self->focus)
+ {
+ gtk_list_item_tracker_free (self->item_manager, self->focus);
+ self->focus = NULL;
+ }
g_clear_object (&self->item_manager);
G_OBJECT_CLASS (gtk_list_view_parent_class)->dispose (object);
@@ -927,6 +950,27 @@ gtk_list_view_unselect_all (GtkWidget *widget,
gtk_selection_model_unselect_all (selection_model);
}
+static void
+gtk_list_view_update_focus_tracker (GtkListView *self)
+{
+ GtkWidget *focus_child;
+ guint pos;
+
+ focus_child = gtk_widget_get_focus_child (GTK_WIDGET (self));
+ if (!GTK_IS_LIST_ITEM (focus_child))
+ return;
+
+ pos = gtk_list_item_get_position (GTK_LIST_ITEM (focus_child));
+ if (pos != gtk_list_item_tracker_get_position (self->item_manager, self->focus))
+ {
+ gtk_list_item_tracker_set_position (self->item_manager,
+ self->focus,
+ pos,
+ GTK_LIST_VIEW_EXTRA_ITEMS,
+ GTK_LIST_VIEW_EXTRA_ITEMS);
+ }
+}
+
static void
gtk_list_view_scroll_to_item (GtkWidget *widget,
const char *action_name,
@@ -971,6 +1015,14 @@ gtk_list_view_scroll_to_item (GtkWidget *widget,
else
gtk_list_view_set_anchor (self, pos, 1.0);
}
+
+ /* HACK HACK HACK
+ *
+ * GTK has no way to track the focused child. But we now that when a listitem
+ * gets focus, it calls this action. So we update our focus tracker from here
+ * because it's the closest we can get to accurate tracking.
+ */
+ gtk_list_view_update_focus_tracker (self);
}
static void
@@ -1183,6 +1235,7 @@ static void
gtk_list_view_init (GtkListView *self)
{
self->item_manager = gtk_list_item_manager_new (GTK_WIDGET (self), "row", ListRow, ListRowAugment,
list_row_augment);
+ self->focus = gtk_list_item_tracker_new (self->item_manager);
self->anchor = gtk_list_item_tracker_new (self->item_manager);
self->selected = gtk_list_item_tracker_new (self->item_manager);
self->orientation = GTK_ORIENTATION_VERTICAL;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]