Compare commits
9 Commits
wip/matthi
...
matthiasc/
Author | SHA1 | Date | |
---|---|---|---|
|
10c43ba4ae | ||
|
84518ac231 | ||
|
bc550cfa04 | ||
|
e8a2617a8a | ||
|
4e05a96361 | ||
|
9d5ee049ef | ||
|
94a27a132a | ||
|
1d5e5fcede | ||
|
464a4fe4b6 |
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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>
|
||||
|
@@ -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");
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
||||
|
249
gtk/gtkscrollinfo.c
Normal file
249
gtk/gtkscrollinfo.c
Normal 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
61
gtk/gtkscrollinfo.h
Normal 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
|
||||
|
42
gtk/gtkscrollinfoprivate.h
Normal file
42
gtk/gtkscrollinfoprivate.h
Normal 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
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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',
|
||||
|
Reference in New Issue
Block a user