diff options
-rw-r--r-- | gtk/gtkscrolledwindow.c | 59 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/testscrolledge.c | 129 |
3 files changed, 187 insertions, 3 deletions
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c index dd2b928a2d..bf813e0218 100644 --- a/gtk/gtkscrolledwindow.c +++ b/gtk/gtkscrolledwindow.c @@ -208,6 +208,7 @@ enum { SCROLL_CHILD, MOVE_FOCUS_OUT, + EDGE_OVERSHOT, LAST_SIGNAL }; @@ -545,7 +546,33 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class) _gtk_marshal_VOID__ENUM, G_TYPE_NONE, 1, GTK_TYPE_DIRECTION_TYPE); - + + /** + * GtkScrolledWindow::edge-overshot: + * @scrolled_window: a #GtkScrolledWindow + * @pos: edge side that was hit + * + * The ::edge-overshot signal is emitted whenever user initiated scrolling + * makes the scrolledwindow firmly surpass (ie. with some edge resistance) + * the lower or upper limits defined by the adjustment in that orientation. + * + * If a similar behavior without edge resistance is desired, one alternative + * may be to check on #GtkAdjustment::value-changed that the value equals + * either #GtkAdjustment:lower or #GtkAdjustment:upper - #GtkAdjustment:page-size. + * + * Note: The @pos argument is LTR/RTL aware, so callers should be aware too + * if intending to provide behavior on horizontal edges. + * + * Since: 3.16 + */ + signals[EDGE_OVERSHOT] = + g_signal_new (I_("edge-overshot"), + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, 0, + NULL, NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, 1, GTK_TYPE_POSITION_TYPE); + binding_set = gtk_binding_set_by_class (class); add_scroll_binding (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK, GTK_SCROLL_STEP_BACKWARD, TRUE); @@ -2525,20 +2552,46 @@ _gtk_scrolled_window_set_adjustment_value (GtkScrolledWindow *scrolled_window, { GtkScrolledWindowPrivate *priv = scrolled_window->priv; gdouble lower, upper, *prev_value; + GtkPositionType edge_pos; + gboolean vertical; lower = gtk_adjustment_get_lower (adjustment) - MAX_OVERSHOOT_DISTANCE; upper = gtk_adjustment_get_upper (adjustment) - gtk_adjustment_get_page_size (adjustment) + MAX_OVERSHOOT_DISTANCE; if (adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar))) - prev_value = &priv->unclamped_hadj_value; + vertical = FALSE; else if (adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar))) + vertical = TRUE; + else + return; + + if (vertical) prev_value = &priv->unclamped_vadj_value; else + prev_value = &priv->unclamped_hadj_value; + + value = CLAMP (value, lower, upper); + + if (*prev_value == value) return; - *prev_value = CLAMP (value, lower, upper); + *prev_value = value; gtk_adjustment_set_value (adjustment, value); + + if (value == lower) + edge_pos = vertical ? GTK_POS_TOP : GTK_POS_LEFT; + else if (value == upper) + edge_pos = vertical ? GTK_POS_BOTTOM : GTK_POS_RIGHT; + else + return; + + /* Invert horizontal edge position on RTL */ + if (!vertical && + gtk_widget_get_direction (GTK_WIDGET (scrolled_window)) == GTK_TEXT_DIR_RTL) + edge_pos = (edge_pos == GTK_POS_LEFT) ? GTK_POS_RIGHT : GTK_POS_LEFT; + + g_signal_emit (scrolled_window, signals[EDGE_OVERSHOT], 0, edge_pos); } static gboolean diff --git a/tests/Makefile.am b/tests/Makefile.am index d0eabaec91..779a611225 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -133,6 +133,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \ testexpander \ testvolumebutton \ testscrolledwindow \ + testscrolledge \ testswitch \ testcellarea \ testswitch \ @@ -270,6 +271,7 @@ testgrouping_DEPENDENCIES = $(TEST_DEPS) testtooltips_DEPENDENCIES = $(TEST_DEPS) testvolumebutton_DEPENDENCIES = $(TEST_DEPS) testscrolledwindow_DEPENDENCIES = $(TEST_DEPS) +testscrolledge_DEPENDENCIES = $(TEST_DEPS) testcellarea_DEPENDENCIES = $(TEST_DEPS) testtreemenu_DEPENDENCIES = $(TEST_DEPS) testwindows_DEPENDENCIES = $(TEST_DEPS) diff --git a/tests/testscrolledge.c b/tests/testscrolledge.c new file mode 100644 index 0000000000..c92402df58 --- /dev/null +++ b/tests/testscrolledge.c @@ -0,0 +1,129 @@ +/* testscrolledge.c + * + * Copyright (C) 2014 Matthias Clasen <mclasen@redhat.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <gtk/gtk.h> + +static guint add_rows_id = 0; + +static void +populate_list (GtkListBox *list) +{ + gint i; + gchar *text; + GtkWidget *row, *label; + gint n; + GList *l; + + l = gtk_container_get_children (GTK_CONTAINER (list)); + n = g_list_length (l); + g_list_free (l); + + for (i = 1; i <= 50; i++) + { + row = gtk_list_box_row_new (); + text = g_strdup_printf ("List row %d", i + n); + label = gtk_label_new (text); + g_free (text); + + g_object_set (label, "margin", 10, NULL); + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_container_add (GTK_CONTAINER (row), label); + gtk_widget_show_all (row); + gtk_container_add (GTK_CONTAINER (list), row); + } +} + +static GtkWidget *popup; +static GtkWidget *spinner; + +static gboolean +add_rows (gpointer data) +{ + GtkListBox *list = data; + + gtk_widget_hide (popup); + gtk_spinner_stop (GTK_SPINNER (spinner)); + + populate_list (list); + add_rows_id = 0; + + return G_SOURCE_REMOVE; +} + +static void +edge_overshot (GtkScrolledWindow *sw, + GtkPositionType pos, + GtkListBox *list) +{ + if (pos == GTK_POS_BOTTOM) + { + gtk_spinner_start (GTK_SPINNER (spinner)); + gtk_widget_show (popup); + + if (add_rows_id == 0) + add_rows_id = g_timeout_add (2000, add_rows, list); + } +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *win; + GtkWidget *sw; + GtkWidget *list; + GtkWidget *overlay; + GtkWidget *label; + + gtk_init (NULL, NULL); + + win = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (win), 600, 400); + + overlay = gtk_overlay_new (); + popup = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); + gtk_widget_set_halign (popup, GTK_ALIGN_CENTER); + gtk_widget_set_valign (popup, GTK_ALIGN_END); + g_object_set (popup, "margin", 40, NULL); + label = gtk_label_new ("Getting more rows..."); + spinner = gtk_spinner_new (); + gtk_widget_show (spinner); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (popup), label); + gtk_container_add (GTK_CONTAINER (popup), spinner); + + gtk_overlay_add_overlay (GTK_OVERLAY (overlay), popup); + gtk_widget_set_no_show_all (popup, TRUE); + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + list = gtk_list_box_new (); + gtk_list_box_set_selection_mode (GTK_LIST_BOX (list), GTK_SELECTION_NONE); + + gtk_container_add (GTK_CONTAINER (win), overlay); + gtk_container_add (GTK_CONTAINER (overlay), sw); + gtk_container_add (GTK_CONTAINER (sw), list); + populate_list (GTK_LIST_BOX (list)); + + g_signal_connect (sw, "edge-overshot", G_CALLBACK (edge_overshot), list); + + gtk_widget_show_all (win); + + gtk_main (); + + return 0; +} |