listview: Implement gtk_list_view_scroll_to()
This adds a flags enum so we can also do select/focus at the same time. It's implemented in GtkListBase, so adding support forgridview should be easy.
This commit is contained in:
committed by
Matthias Clasen
parent
94a27a132a
commit
9d5ee049ef
@@ -295,6 +295,22 @@ typedef enum
|
||||
GTK_LIST_TAB_CELL
|
||||
} GtkListTabBehavior;
|
||||
|
||||
/**
|
||||
* GtkListScrollFlags:
|
||||
* @GTK_LIST_SCROLL_NONE: Don't do anything extra
|
||||
* @GTK_LIST_SCROLL_FOCUS: Focus the target item
|
||||
* @GTK_LIST_SCROLL_SELECT: Select the target item and
|
||||
* unselect all other items.
|
||||
*
|
||||
* List of actions to perform when scrolling to items in
|
||||
* a list widget.
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_LIST_SCROLL_NONE = 0,
|
||||
GTK_LIST_SCROLL_FOCUS = 1 << 0,
|
||||
GTK_LIST_SCROLL_SELECT = 1 << 1
|
||||
} GtkListScrollFlags;
|
||||
|
||||
/**
|
||||
* GtkMessageType:
|
||||
* @GTK_MESSAGE_INFO: Informational message
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "gtkmultiselection.h"
|
||||
#include "gtkorientable.h"
|
||||
#include "gtkscrollable.h"
|
||||
#include "gtkscrollinfo.h"
|
||||
#include "gtksingleselection.h"
|
||||
#include "gtksnapshot.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
@@ -528,7 +529,7 @@ gtk_list_base_get_n_items (GtkListBase *self)
|
||||
return g_list_model_get_n_items (G_LIST_MODEL (priv->model));
|
||||
}
|
||||
|
||||
guint
|
||||
static guint
|
||||
gtk_list_base_get_focus_position (GtkListBase *self)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
@@ -818,23 +819,19 @@ gtk_list_base_set_property (GObject *object,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_compute_scroll_align (GtkListBase *self,
|
||||
GtkOrientation orientation,
|
||||
int cell_start,
|
||||
int cell_end,
|
||||
gtk_list_base_compute_scroll_align (int cell_start,
|
||||
int cell_size,
|
||||
int visible_start,
|
||||
int visible_size,
|
||||
double current_align,
|
||||
GtkPackType current_side,
|
||||
double *new_align,
|
||||
GtkPackType *new_side)
|
||||
{
|
||||
int visible_start, visible_size, visible_end;
|
||||
int cell_size;
|
||||
int cell_end, visible_end;
|
||||
|
||||
gtk_list_base_get_adjustment_values (GTK_LIST_BASE (self),
|
||||
orientation,
|
||||
&visible_start, NULL, &visible_size);
|
||||
visible_end = visible_start + visible_size;
|
||||
cell_size = cell_end - cell_start;
|
||||
cell_end = cell_start + cell_size;
|
||||
|
||||
if (cell_size <= visible_size)
|
||||
{
|
||||
@@ -878,26 +875,38 @@ gtk_list_base_compute_scroll_align (GtkListBase *self,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_scroll_to_item (GtkListBase *self,
|
||||
guint pos)
|
||||
gtk_list_base_scroll_to_item (GtkListBase *self,
|
||||
guint pos,
|
||||
GtkScrollInfo *scroll)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
double align_along, align_across;
|
||||
GtkPackType side_along, side_across;
|
||||
GdkRectangle area;
|
||||
GdkRectangle area, viewport;
|
||||
int x, y;
|
||||
|
||||
if (!gtk_list_base_get_allocation (GTK_LIST_BASE (self), pos, &area))
|
||||
return;
|
||||
{
|
||||
g_clear_pointer (&scroll, gtk_scroll_info_unref);
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_list_base_compute_scroll_align (self,
|
||||
gtk_list_base_get_orientation (GTK_LIST_BASE (self)),
|
||||
area.y, area.y + area.height,
|
||||
gtk_list_base_get_adjustment_values (GTK_LIST_BASE (self),
|
||||
gtk_list_base_get_orientation (GTK_LIST_BASE (self)),
|
||||
&viewport.y, NULL, &viewport.height);
|
||||
gtk_list_base_get_adjustment_values (GTK_LIST_BASE (self),
|
||||
gtk_list_base_get_opposite_orientation (GTK_LIST_BASE (self)),
|
||||
&viewport.x, NULL, &viewport.width);
|
||||
|
||||
gtk_scroll_info_compute_scroll (scroll, &area, &viewport, &x, &y);
|
||||
|
||||
gtk_list_base_compute_scroll_align (area.y, area.height,
|
||||
y, viewport.height,
|
||||
priv->anchor_align_along, priv->anchor_side_along,
|
||||
&align_along, &side_along);
|
||||
|
||||
gtk_list_base_compute_scroll_align (self,
|
||||
gtk_list_base_get_opposite_orientation (GTK_LIST_BASE (self)),
|
||||
area.x, area.x + area.width,
|
||||
gtk_list_base_compute_scroll_align (area.x, area.width,
|
||||
x, viewport.width,
|
||||
priv->anchor_align_across, priv->anchor_side_across,
|
||||
&align_across, &side_across);
|
||||
|
||||
@@ -905,6 +914,8 @@ gtk_list_base_scroll_to_item (GtkListBase *self,
|
||||
pos,
|
||||
align_across, side_across,
|
||||
align_along, side_along);
|
||||
|
||||
g_clear_pointer (&scroll, gtk_scroll_info_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -920,7 +931,7 @@ gtk_list_base_scroll_to_item_action (GtkWidget *widget,
|
||||
|
||||
g_variant_get (parameter, "u", &pos);
|
||||
|
||||
gtk_list_base_scroll_to_item (self, pos);
|
||||
gtk_list_base_scroll_to_item (self, pos, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -940,7 +951,7 @@ gtk_list_base_set_focus_child (GtkWidget *widget,
|
||||
|
||||
if (pos != gtk_list_item_tracker_get_position (priv->item_manager, priv->focus))
|
||||
{
|
||||
gtk_list_base_scroll_to_item (self, pos);
|
||||
gtk_list_base_scroll_to_item (self, pos, NULL);
|
||||
gtk_list_item_tracker_set_position (priv->item_manager,
|
||||
priv->focus,
|
||||
pos,
|
||||
@@ -2320,3 +2331,42 @@ gtk_list_base_get_tab_behavior (GtkListBase *self)
|
||||
return priv->tab_behavior;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_list_base_scroll_to (GtkListBase *self,
|
||||
guint pos,
|
||||
GtkListScrollFlags flags,
|
||||
GtkScrollInfo *scroll)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
|
||||
if (flags & GTK_LIST_SCROLL_FOCUS)
|
||||
{
|
||||
GtkListItemTracker *old_focus;
|
||||
|
||||
/* We need a tracker here to keep the focus widget around,
|
||||
* because we need to update the focus tracker before grabbing
|
||||
* focus, because otherwise gtk_list_base_set_focus_child() will
|
||||
* scroll to the item, and we want to avoid that.
|
||||
*/
|
||||
old_focus = gtk_list_item_tracker_new (priv->item_manager);
|
||||
gtk_list_item_tracker_set_position (priv->item_manager, old_focus, gtk_list_base_get_focus_position (self), 0, 0);
|
||||
|
||||
gtk_list_item_tracker_set_position (priv->item_manager, priv->focus, pos, 0, 0);
|
||||
|
||||
/* XXX: Is this the proper check? */
|
||||
if (gtk_widget_get_state_flags (GTK_WIDGET (self)) & GTK_STATE_FLAG_FOCUS_WITHIN)
|
||||
{
|
||||
GtkListTile *tile = gtk_list_item_manager_get_nth (priv->item_manager, pos, NULL);
|
||||
|
||||
gtk_widget_grab_focus (tile->widget);
|
||||
}
|
||||
|
||||
gtk_list_item_tracker_free (priv->item_manager, old_focus);
|
||||
}
|
||||
|
||||
if (flags & GTK_LIST_SCROLL_SELECT)
|
||||
gtk_list_base_select_item (self, pos, FALSE, FALSE);
|
||||
|
||||
gtk_list_base_scroll_to_item (self, pos, scroll);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,6 @@ 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);
|
||||
@@ -95,3 +94,7 @@ GtkListTabBehavior gtk_list_base_get_tab_behavior (GtkListBase
|
||||
|
||||
void gtk_list_base_allocate (GtkListBase *self);
|
||||
|
||||
void gtk_list_base_scroll_to (GtkListBase *self,
|
||||
guint pos,
|
||||
GtkListScrollFlags flags,
|
||||
GtkScrollInfo *scroll);
|
||||
|
||||
@@ -1349,3 +1349,30 @@ gtk_list_view_get_tab_behavior (GtkListView *self)
|
||||
return gtk_list_base_get_tab_behavior (GTK_LIST_BASE (self));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_list_view_scroll_to:
|
||||
* @self: The listview to scroll in
|
||||
* @pos: position of the item
|
||||
* @flags: actions to perform
|
||||
* @scroll: (nullable) (transfer full): details of how to perform
|
||||
* the scroll operation or %NULL to scroll into view
|
||||
*
|
||||
* Scrolls to the item at the given position and performs the actions
|
||||
* specified in @flags.
|
||||
*
|
||||
* This function works no matter if the listview is shown or focused
|
||||
* or not. If it isn't, then the changes will take effect once that happens.
|
||||
*
|
||||
* Since: 4.12
|
||||
*/
|
||||
void
|
||||
gtk_list_view_scroll_to (GtkListView *self,
|
||||
guint pos,
|
||||
GtkListScrollFlags flags,
|
||||
GtkScrollInfo *scroll)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_LIST_VIEW (self));
|
||||
|
||||
gtk_list_base_scroll_to (GTK_LIST_BASE (self), pos, flags, scroll);
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +89,11 @@ GDK_AVAILABLE_IN_4_12
|
||||
GtkListTabBehavior
|
||||
gtk_list_view_get_tab_behavior (GtkListView *self);
|
||||
|
||||
GDK_AVAILABLE_IN_4_12
|
||||
void gtk_list_view_scroll_to (GtkListView *self,
|
||||
guint pos,
|
||||
GtkListScrollFlags flags,
|
||||
GtkScrollInfo *scroll);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkListView, g_object_unref)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user