[gtk/wip/otte/listview: 90/135] gridview: Add a focus tracker
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/listview: 90/135] gridview: Add a focus tracker
- Date: Sun, 8 Dec 2019 04:17:15 +0000 (UTC)
commit 3767c5df3dea387a979b70423f8d4e3382668f4a
Author: Benjamin Otte <otte redhat com>
Date: Sun Oct 20 20:09:24 2019 +0200
gridview: Add a focus tracker
... and use that to properly update selections when moving around with
the arrow keys.
gtk/gtkgridview.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 96 insertions(+)
---
diff --git a/gtk/gtkgridview.c b/gtk/gtkgridview.c
index 9440f4d1ec..52159753c2 100644
--- a/gtk/gtkgridview.c
+++ b/gtk/gtkgridview.c
@@ -25,6 +25,7 @@
#include "gtkintl.h"
#include "gtklistitemfactory.h"
#include "gtklistitemmanagerprivate.h"
+#include "gtkmain.h"
#include "gtkorientableprivate.h"
#include "gtkprivate.h"
#include "gtkscrollable.h"
@@ -78,6 +79,8 @@ struct _GtkGridView
guint anchor_ystart : 1;
/* the last item that was selected - basically the location to extend selections from */
GtkListItemTracker *selected;
+ /* the item that has input focus */
+ GtkListItemTracker *focus;
};
struct _Cell
@@ -396,6 +399,62 @@ gtk_grid_view_select_item (GtkGridView *self,
}
}
+static gboolean
+gtk_grid_view_focus (GtkWidget *widget,
+ GtkDirectionType direction)
+{
+ GtkGridView *self = GTK_GRID_VIEW (widget);
+ GtkWidget *old_focus_child, *new_focus_child;
+
+ old_focus_child = gtk_widget_get_focus_child (widget);
+
+ if (old_focus_child == NULL &&
+ (direction == GTK_DIR_TAB_FORWARD || direction == GTK_DIR_TAB_BACKWARD))
+ {
+ Cell *cell;
+ 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);
+ cell = gtk_list_item_manager_get_nth (self->item_manager, pos, NULL);
+ if (cell && gtk_widget_grab_focus (cell->parent.widget))
+ goto moved_focus;
+ }
+
+ if (!GTK_WIDGET_CLASS (gtk_grid_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 &&
+ GTK_IS_LIST_ITEM (new_focus_child))
+ {
+ GdkModifierType state;
+ GdkModifierType mask;
+ gboolean extend = FALSE, modify = FALSE;
+
+ if (old_focus_child && gtk_get_current_event_state (&state))
+ {
+ mask = gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_MODIFY_SELECTION);
+ if ((state & mask) == mask)
+ modify = TRUE;
+ mask = gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_EXTEND_SELECTION);
+ if ((state & mask) == mask)
+ extend = TRUE;
+ }
+
+ gtk_grid_view_select_item (self,
+ gtk_list_item_get_position (GTK_LIST_ITEM (new_focus_child)),
+ modify,
+ extend);
+ }
+
+ return TRUE;
+}
+
static gboolean
gtk_grid_view_adjustment_is_flipped (GtkGridView *self,
GtkOrientation orientation)
@@ -1038,6 +1097,11 @@ gtk_grid_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_grid_view_parent_class)->dispose (object);
@@ -1272,6 +1336,27 @@ gtk_grid_view_compute_scroll_align (GtkGridView *self,
}
}
+static void
+gtk_grid_view_update_focus_tracker (GtkGridView *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,
+ self->max_columns,
+ self->max_columns);
+ }
+}
+
static void
gtk_grid_view_scroll_to_item (GtkWidget *widget,
const char *action_name,
@@ -1309,6 +1394,14 @@ gtk_grid_view_scroll_to_item (GtkWidget *widget,
&xalign, &xstart);
gtk_grid_view_set_anchor (self, pos, xalign, xstart, yalign, ystart);
+
+ /* 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_grid_view_update_focus_tracker (self);
}
static void
@@ -1336,6 +1429,7 @@ gtk_grid_view_class_init (GtkGridViewClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gpointer iface;
+ widget_class->focus = gtk_grid_view_focus;
widget_class->measure = gtk_grid_view_measure;
widget_class->size_allocate = gtk_grid_view_size_allocate;
@@ -1538,6 +1632,7 @@ gtk_grid_view_init (GtkGridView *self)
self->anchor_xstart = TRUE;
self->anchor_ystart = TRUE;
self->selected = gtk_list_item_tracker_new (self->item_manager);
+ self->focus = gtk_list_item_tracker_new (self->item_manager);
self->min_columns = 1;
self->max_columns = DEFAULT_MAX_COLUMNS;
@@ -1742,6 +1837,7 @@ gtk_grid_view_set_max_columns (GtkGridView *self,
self->anchor_xstart,
self->anchor_yalign,
self->anchor_ystart);
+ gtk_grid_view_update_focus_tracker (self);
gtk_widget_queue_resize (GTK_WIDGET (self));
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]