Compare commits

...

9 Commits

Author SHA1 Message Date
Matthias Clasen
10c43ba4ae Clean up headers
Move the private scrollinfo api to just the private
header, and include it where needed.
2023-08-04 21:51:35 -04:00
Matthias Clasen
84518ac231 scrollinfo: Add missing annotations 2023-08-04 21:51:35 -04:00
Matthias Clasen
bc550cfa04 Add gtk_column_view_scroll_to
This function takes a column as well, to allow
for horizontal scrolling (not currently implemented).
2023-08-04 21:51:35 -04:00
Matthias Clasen
e8a2617a8a Add gtk_grid_view_scroll_to
This does the same as gtk_list_view_scroll_to, just
for a grid view.
2023-08-04 21:51:35 -04:00
Benjamin Otte
4e05a96361 gtk-demo: Make arrowing in suggestionentry scroll the dropdown 2023-08-04 21:16:12 -04:00
Benjamin Otte
9d5ee049ef 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.
2023-08-04 21:16:12 -04:00
Benjamin Otte
94a27a132a viewport: Use gtk_viewport_scroll_to() for focus scrolling 2023-08-04 21:16:12 -04:00
Benjamin Otte
1d5e5fcede viewport: Add gtk_viewport_scroll_to()
First implementation of GtkScrollInfo
2023-08-04 21:16:12 -04:00
Benjamin Otte
464a4fe4b6 gtk: Add GtkScrollInfo
This struct carries information about scrolling a scrollable, so that
individual scrollables can share this struct for their scrolling APIs.

For now, there's not much information here, we're still trying to cook
up an API that works well.
2023-08-04 21:16:12 -04:00
18 changed files with 617 additions and 53 deletions

View File

@@ -801,7 +801,7 @@ suggestion_entry_key_pressed (GtkEventControllerKey *controller,
selected = matches - 1;
}
gtk_single_selection_set_selected (self->selection, selected);
gtk_list_view_scroll_to (GTK_LIST_VIEW (self->list), selected, GTK_LIST_SCROLL_SELECT, NULL);
return TRUE;
}

View File

@@ -223,6 +223,7 @@
#include <gtk/gtkscalebutton.h>
#include <gtk/gtkscrollable.h>
#include <gtk/gtkscrollbar.h>
#include <gtk/gtkscrollinfo.h>
#include <gtk/gtkscrolledwindow.h>
#include <gtk/gtksearchbar.h>
#include <gtk/gtksearchentry.h>

View File

@@ -2174,3 +2174,37 @@ gtk_column_view_set_header_factory (GtkColumnView *self,
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HEADER_FACTORY]);
}
/**
* gtk_column_view_scroll_to:
* @self: The columnview to scroll in
* @pos: position of the item
* @column: (nullable): the column to scroll into view
* @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 column and performs
* the actions specified in @flags.
*
* This function works no matter if the columnview is shown or focused
* or not. If it isn't, then the changes will take effect once that happens.
*
* Since: 4.12
*/
void
gtk_column_view_scroll_to (GtkColumnView *self,
guint pos,
GtkColumnViewColumn *column,
GtkListScrollFlags flags,
GtkScrollInfo *scroll)
{
g_return_if_fail (GTK_IS_COLUMN_VIEW (self));
g_return_if_fail (column == NULL || GTK_IS_COLUMN_VIEW_COLUMN (column));
g_return_if_fail (column == NULL || gtk_column_view_column_get_column_view (column) == self);
gtk_list_view_scroll_to (self->listview, pos, flags, scroll);
if (column)
g_warning ("column scrolling is not implemented");
}

View File

@@ -130,5 +130,12 @@ GDK_AVAILABLE_IN_4_12
GtkListItemFactory *
gtk_column_view_get_header_factory (GtkColumnView *self);
GDK_AVAILABLE_IN_4_12
void gtk_column_view_scroll_to (GtkColumnView *self,
guint pos,
GtkColumnViewColumn *column,
GtkListScrollFlags flags,
GtkScrollInfo *scroll);
G_END_DECLS

View File

@@ -295,6 +295,24 @@ 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.
*
* Since: 4.12
*/
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

View File

@@ -1564,3 +1564,29 @@ gtk_grid_view_get_tab_behavior (GtkGridView *self)
return gtk_list_base_get_tab_behavior (GTK_LIST_BASE (self));
}
/**
* gtk_grid_view_scroll_to:
* @self: The gridview 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 if the gridview is not shown or not focused,
* the changes will take effect once that happens.
*
* Since: 4.12
*/
void
gtk_grid_view_scroll_to (GtkGridView *self,
guint pos,
GtkListScrollFlags flags,
GtkScrollInfo *scroll)
{
g_return_if_fail (GTK_IS_GRID_VIEW (self));
gtk_list_base_scroll_to (GTK_LIST_BASE (self), pos, flags, scroll);
}

View File

@@ -85,6 +85,13 @@ void gtk_grid_view_set_single_click_activate (GtkGridView
GDK_AVAILABLE_IN_ALL
gboolean gtk_grid_view_get_single_click_activate (GtkGridView *self);
GDK_AVAILABLE_IN_4_12
void gtk_grid_view_scroll_to (GtkGridView *self,
guint pos,
GtkListScrollFlags flags,
GtkScrollInfo *scroll);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkGridView, g_object_unref)
G_END_DECLS

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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)

249
gtk/gtkscrollinfo.c Normal file
View File

@@ -0,0 +1,249 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2023 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* GtkScrollInfo:
*
* The `GtkScrollInfo` can be used to provide more accurate data on how a scroll
* operation should be performed.
*
* Scrolling functions usually allow passing a %NULL scroll info which will cause
* the default values to be used and just scroll the element into view.
*
* Since: 4.12
*/
#include "config.h"
#include "gtkscrollinfoprivate.h"
#include <math.h>
struct _GtkScrollInfo
{
guint ref_count;
gboolean enabled[2]; /* directions */
};
static GtkScrollInfo default_scroll_info = {
1,
{ TRUE, TRUE }
};
G_DEFINE_BOXED_TYPE (GtkScrollInfo, gtk_scroll_info,
gtk_scroll_info_ref,
gtk_scroll_info_unref)
/**
* gtk_scroll_info_new:
*
* Creates a new scroll info for scrolling an element into view.
*
* Returns: A new scroll info
*
* Since: 4.12
**/
GtkScrollInfo *
gtk_scroll_info_new (void)
{
GtkScrollInfo *self;
self = g_new0 (GtkScrollInfo, 1);
self->ref_count = 1;
self->enabled[GTK_ORIENTATION_HORIZONTAL] = TRUE;
self->enabled[GTK_ORIENTATION_VERTICAL] = TRUE;
return self;
}
/**
* gtk_scroll_info_ref:
* @self: a `GtkScrollInfo`
*
* Increases the reference count of a `GtkScrollInfo` by one.
*
* Returns: the passed in `GtkScrollInfo`.
*
* Since: 4.12
*/
GtkScrollInfo *
gtk_scroll_info_ref (GtkScrollInfo *self)
{
g_return_val_if_fail (self != NULL, NULL);
self->ref_count++;
return self;
}
/**
* gtk_scroll_info_unref:
* @self: a `GtkScrollInfo`
*
* Decreases the reference count of a `GtkScrollInfo` by one.
*
* If the resulting reference count is zero, frees the self.
*
* Since: 4.12
*/
void
gtk_scroll_info_unref (GtkScrollInfo *self)
{
g_return_if_fail (self != NULL);
g_return_if_fail (self->ref_count > 0);
self->ref_count--;
if (self->ref_count > 0)
return;
g_free (self);
}
/**
* gtk_scroll_info_set_enable_horizontal:
* @self: a `GtkScrollInfo`
* @horizontal: if scrolling in the horizontal direction
* should happen
*
* Turns horizontal scrolling on or off.
*
* Since: 4.12
*/
void
gtk_scroll_info_set_enable_horizontal (GtkScrollInfo *self,
gboolean horizontal)
{
g_return_if_fail (self != NULL);
self->enabled[GTK_ORIENTATION_HORIZONTAL] = horizontal;
}
/**
* gtk_scroll_info_get_enable_horizontal:
* @self: a `GtkScrollInfo`
*
* Checks if horizontal scrolling is enabled.
*
* Returns: %TRUE if horizontal scrolling is enabled.
*
* Since: 4.12
*/
gboolean
gtk_scroll_info_get_enable_horizontal (GtkScrollInfo *self)
{
g_return_val_if_fail (self != NULL, FALSE);
return self->enabled[GTK_ORIENTATION_HORIZONTAL];
}
/**
* gtk_scroll_info_set_enable_vertical:
* @self: a `GtkScrollInfo`
* @vertical: if scrolling in the vertical direction
* should happen
*
* Turns vertical scrolling on or off.
*
* Since: 4.12
*/
void
gtk_scroll_info_set_enable_vertical (GtkScrollInfo *self,
gboolean vertical)
{
g_return_if_fail (self != NULL);
self->enabled[GTK_ORIENTATION_VERTICAL] = vertical;
}
/**
* gtk_scroll_info_get_enable_vertical:
* @self: a `GtkScrollInfo`
*
* Checks if vertical scrolling is enabled.
*
* Returns: %TRUE if vertical scrolling is enabled.
*
* Since: 4.12
*/
gboolean
gtk_scroll_info_get_enable_vertical (GtkScrollInfo *self)
{
g_return_val_if_fail (self != NULL, FALSE);
return self->enabled[GTK_ORIENTATION_VERTICAL];
}
int
gtk_scroll_info_compute_for_orientation (GtkScrollInfo *self,
GtkOrientation orientation,
int area_origin,
int area_size,
int viewport_origin,
int viewport_size)
{
float origin, size;
int delta;
if (self == NULL)
self = &default_scroll_info;
if (!self->enabled[orientation])
return viewport_origin;
origin = viewport_origin;
size = viewport_size;
if (area_origin <= origin)
delta = area_origin - ceil (origin);
else if (area_origin + area_size > origin + size)
delta = area_origin + area_size - floor (origin + size);
else
delta = 0;
return viewport_origin + delta;
}
/*<private>
* gtk_scroll_info_compute_scroll:
* @self: a `GtkScrollInfo`
* @area: area to scroll
* @viewport: viewport area to scroll into
* @out_x: (out): x coordinate to scroll viewport to
* @out_y: (out): y coordinate to scroll viewport to
*
* Computes The new x/y coordinate to move the viewport to
* according to this scroll info.
*/
void
gtk_scroll_info_compute_scroll (GtkScrollInfo *self,
const cairo_rectangle_int_t *area,
const cairo_rectangle_int_t *viewport,
int *out_x,
int *out_y)
{
*out_x = gtk_scroll_info_compute_for_orientation (self,
GTK_ORIENTATION_HORIZONTAL,
area->x, area->width,
viewport->x, viewport->width);
*out_y = gtk_scroll_info_compute_for_orientation (self,
GTK_ORIENTATION_VERTICAL,
area->y, area->height,
viewport->y, viewport->height);
}

61
gtk/gtkscrollinfo.h Normal file
View File

@@ -0,0 +1,61 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2023 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gdk/gdk.h>
#include <gtk/gtkenums.h>
#include <gtk/gtktypes.h>
#include <graphene.h>
G_BEGIN_DECLS
#define GTK_TYPE_SCROLL_INFO (gtk_scroll_info_get_type ())
GDK_AVAILABLE_IN_4_12
GType gtk_scroll_info_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_12
GtkScrollInfo * gtk_scroll_info_new (void);
GDK_AVAILABLE_IN_4_12
GtkScrollInfo * gtk_scroll_info_ref (GtkScrollInfo *self);
GDK_AVAILABLE_IN_4_12
void gtk_scroll_info_unref (GtkScrollInfo *self);
GDK_AVAILABLE_IN_4_12
void gtk_scroll_info_set_enable_horizontal (GtkScrollInfo *self,
gboolean horizontal);
GDK_AVAILABLE_IN_4_12
gboolean gtk_scroll_info_get_enable_horizontal (GtkScrollInfo *self);
GDK_AVAILABLE_IN_4_12
void gtk_scroll_info_set_enable_vertical (GtkScrollInfo *self,
gboolean vertical);
GDK_AVAILABLE_IN_4_12
gboolean gtk_scroll_info_get_enable_vertical (GtkScrollInfo *self);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkScrollInfo, gtk_scroll_info_unref)
G_END_DECLS

View File

@@ -0,0 +1,42 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2023 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkscrollinfo.h>
G_BEGIN_DECLS
void gtk_scroll_info_compute_scroll (GtkScrollInfo *self,
const cairo_rectangle_int_t *area,
const cairo_rectangle_int_t *viewport,
int *out_x,
int *out_y);
int gtk_scroll_info_compute_for_orientation (GtkScrollInfo *self,
GtkOrientation orientation,
int area_origin,
int area_size,
int viewport_origin,
int viewport_size);
G_END_DECLS

View File

@@ -46,6 +46,7 @@ typedef struct _GtkListItemFactory GtkListItemFactory;
typedef struct _GtkNative GtkNative;
typedef struct _GtkRequisition GtkRequisition;
typedef struct _GtkRoot GtkRoot;
typedef struct _GtkScrollInfo GtkScrollInfo;
typedef struct _GtkSettings GtkSettings;
typedef struct _GtkShortcut GtkShortcut;
typedef struct _GtkShortcutAction GtkShortcutAction;

View File

@@ -30,11 +30,13 @@
#include "gtkmarshalers.h"
#include "gtkprivate.h"
#include "gtkscrollable.h"
#include "gtkscrollinfoprivate.h"
#include "gtktypebuiltins.h"
#include "gtkwidgetprivate.h"
#include "gtkbuildable.h"
#include "gtktext.h"
#include <math.h>
/**
* GtkViewport:
@@ -602,30 +604,12 @@ gtk_viewport_set_scroll_to_focus (GtkViewport *viewport,
g_object_notify (G_OBJECT (viewport), "scroll-to-focus");
}
static void
scroll_to_view (GtkAdjustment *adj,
double pos,
double size)
{
double value, page_size;
value = gtk_adjustment_get_value (adj);
page_size = gtk_adjustment_get_page_size (adj);
if (pos < 0)
gtk_adjustment_animate_to_value (adj, value + pos);
else if (pos + size >= page_size)
gtk_adjustment_animate_to_value (adj, value + pos + size - page_size);
}
static void
focus_change_handler (GtkWidget *widget)
{
GtkViewport *viewport = GTK_VIEWPORT (widget);
GtkRoot *root;
GtkWidget *focus_widget;
graphene_rect_t rect;
graphene_point_t p;
if ((gtk_widget_get_state_flags (widget) & GTK_STATE_FLAG_FOCUS_WITHIN) == 0)
return;
@@ -639,16 +623,7 @@ focus_change_handler (GtkWidget *widget)
if (GTK_IS_TEXT (focus_widget))
focus_widget = gtk_widget_get_parent (focus_widget);
if (!gtk_widget_compute_bounds (focus_widget, viewport->child, &rect))
return;
if (!gtk_widget_compute_point (viewport->child, widget,
&GRAPHENE_POINT_INIT (rect.origin.x, rect.origin.y),
&p))
return;
scroll_to_view (viewport->adjustment[GTK_ORIENTATION_HORIZONTAL], p.x, rect.size.width);
scroll_to_view (viewport->adjustment[GTK_ORIENTATION_VERTICAL], p.y, rect.size.height);
gtk_viewport_scroll_to (viewport, focus_widget, NULL);
}
static void
@@ -720,3 +695,54 @@ gtk_viewport_get_child (GtkViewport *viewport)
return viewport->child;
}
/**
* gtk_viewport_scroll_to:
* @viewport: a `GtkViewport`
* @descendant: a descendant widget of the viewport
* @scroll: (nullable) (transfer full): details of how to perform
* the scroll operation or NULL to scroll into view
*
* Scrolls a descendant of the viewport into view.
*
* The viewport and the descendant must be visible and mapped for
* this function to work, otherwise no scrolling will be performed.
*
* Since: 4.12
**/
void
gtk_viewport_scroll_to (GtkViewport *viewport,
GtkWidget *descendant,
GtkScrollInfo *scroll)
{
graphene_rect_t bounds;
int x, y;
double adj_x, adj_y;
g_return_if_fail (GTK_IS_VIEWPORT (viewport));
g_return_if_fail (GTK_IS_WIDGET (descendant));
if (!gtk_widget_compute_bounds (descendant, GTK_WIDGET (viewport), &bounds))
return;
adj_x = gtk_adjustment_get_value (viewport->adjustment[GTK_ORIENTATION_HORIZONTAL]);
adj_y = gtk_adjustment_get_value (viewport->adjustment[GTK_ORIENTATION_VERTICAL]);
gtk_scroll_info_compute_scroll (scroll,
&(GdkRectangle) {
floor (bounds.origin.x + adj_x),
floor (bounds.origin.y + adj_y),
ceil (bounds.origin.x + bounds.size.width) - floor (bounds.origin.x),
ceil (bounds.origin.y + bounds.size.height) - floor (bounds.origin.y)
},
&(GdkRectangle) {
adj_x,
adj_y,
gtk_widget_get_width (GTK_WIDGET (viewport)),
gtk_widget_get_height (GTK_WIDGET (viewport))
},
&x, &y);
gtk_adjustment_animate_to_value (viewport->adjustment[GTK_ORIENTATION_HORIZONTAL], x);
gtk_adjustment_animate_to_value (viewport->adjustment[GTK_ORIENTATION_VERTICAL], y);
}

View File

@@ -61,6 +61,11 @@ void gtk_viewport_set_child (GtkViewport *viewport,
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_viewport_get_child (GtkViewport *viewport);
GDK_AVAILABLE_IN_4_12
void gtk_viewport_scroll_to (GtkViewport *viewport,
GtkWidget *descendant,
GtkScrollInfo *scroll);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkViewport, g_object_unref)
G_END_DECLS

View File

@@ -327,6 +327,7 @@ gtk_public_sources = files([
'gtkscalebutton.c',
'gtkscrollable.c',
'gtkscrollbar.c',
'gtkscrollinfo.c',
'gtkscrolledwindow.c',
'gtksearchbar.c',
'gtksearchentry.c',
@@ -557,6 +558,7 @@ gtk_public_headers = files([
'gtkscalebutton.h',
'gtkscrollable.h',
'gtkscrollbar.h',
'gtkscrollinfo.h',
'gtkscrolledwindow.h',
'gtksearchbar.h',
'gtksearchentry.h',