diff options
author | Benjamin Otte <otte@redhat.com> | 2019-10-22 23:46:34 +0200 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2020-05-30 19:26:46 -0400 |
commit | 0011ce949c3580e02c4b2c3d83584a6c6e82090c (patch) | |
tree | b6719987a5562d02cdad90149fcd03b0985c876a /gtk/gtklistbase.c | |
parent | cc987b31aef665d7c27c81b22872efb3ade754c3 (diff) | |
download | gtk+-0011ce949c3580e02c4b2c3d83584a6c6e82090c.tar.gz |
listbase: Move GtkScrollable implementation
Shared code between GtkGridView and GtkListView.
Diffstat (limited to 'gtk/gtklistbase.c')
-rw-r--r-- | gtk/gtklistbase.c | 281 |
1 files changed, 280 insertions, 1 deletions
diff --git a/gtk/gtklistbase.c b/gtk/gtklistbase.c index ca93a53b3e..cb44ef5913 100644 --- a/gtk/gtklistbase.c +++ b/gtk/gtklistbase.c @@ -21,17 +21,296 @@ #include "gtklistbaseprivate.h" -G_DEFINE_ABSTRACT_TYPE (GtkListBase, gtk_list_base, GTK_TYPE_WIDGET) +#include "gtkadjustment.h" +#include "gtkscrollable.h" + +typedef struct _GtkListBasePrivate GtkListBasePrivate; + +struct _GtkListBasePrivate +{ + GtkAdjustment *adjustment[2]; + GtkScrollablePolicy scroll_policy[2]; +}; + +enum +{ + PROP_0, + PROP_HADJUSTMENT, + PROP_HSCROLL_POLICY, + PROP_VADJUSTMENT, + PROP_VSCROLL_POLICY, + + N_PROPS +}; + +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkListBase, gtk_list_base, GTK_TYPE_WIDGET, + G_ADD_PRIVATE (GtkListBase) + G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL)) + +static GParamSpec *properties[N_PROPS] = { NULL, }; + +static void +gtk_list_base_adjustment_value_changed_cb (GtkAdjustment *adjustment, + GtkListBase *self) +{ + GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self); + GtkOrientation orientation; + + orientation = adjustment == priv->adjustment[GTK_ORIENTATION_HORIZONTAL] + ? GTK_ORIENTATION_HORIZONTAL + : GTK_ORIENTATION_VERTICAL; + + GTK_LIST_BASE_GET_CLASS (self)->adjustment_value_changed (self, orientation); +} + +static void +gtk_list_base_clear_adjustment (GtkListBase *self, + GtkOrientation orientation) +{ + GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self); + + if (priv->adjustment[orientation] == NULL) + return; + + g_signal_handlers_disconnect_by_func (priv->adjustment[orientation], + gtk_list_base_adjustment_value_changed_cb, + self); + g_clear_object (&priv->adjustment[orientation]); +} + +static void +gtk_list_base_dispose (GObject *object) +{ + GtkListBase *self = GTK_LIST_BASE (object); + + gtk_list_base_clear_adjustment (self, GTK_ORIENTATION_HORIZONTAL); + gtk_list_base_clear_adjustment (self, GTK_ORIENTATION_VERTICAL); + + G_OBJECT_CLASS (gtk_list_base_parent_class)->dispose (object); +} + +static void +gtk_list_base_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GtkListBase *self = GTK_LIST_BASE (object); + GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self); + + switch (property_id) + { + case PROP_HADJUSTMENT: + g_value_set_object (value, priv->adjustment[GTK_ORIENTATION_HORIZONTAL]); + break; + + case PROP_HSCROLL_POLICY: + g_value_set_enum (value, priv->scroll_policy[GTK_ORIENTATION_HORIZONTAL]); + break; + + case PROP_VADJUSTMENT: + g_value_set_object (value, priv->adjustment[GTK_ORIENTATION_VERTICAL]); + break; + + case PROP_VSCROLL_POLICY: + g_value_set_enum (value, priv->scroll_policy[GTK_ORIENTATION_VERTICAL]); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gtk_list_base_set_adjustment (GtkListBase *self, + GtkOrientation orientation, + GtkAdjustment *adjustment) +{ + GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self); + + if (priv->adjustment[orientation] == adjustment) + return; + + if (adjustment == NULL) + adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + g_object_ref_sink (adjustment); + + gtk_list_base_clear_adjustment (self, orientation); + + priv->adjustment[orientation] = adjustment; + + g_signal_connect (adjustment, "value-changed", + G_CALLBACK (gtk_list_base_adjustment_value_changed_cb), + self); + + gtk_widget_queue_allocate (GTK_WIDGET (self)); +} + +static void +gtk_list_base_set_scroll_policy (GtkListBase *self, + GtkOrientation orientation, + GtkScrollablePolicy scroll_policy) +{ + GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self); + + if (priv->scroll_policy[orientation] == scroll_policy) + return; + + priv->scroll_policy[orientation] = scroll_policy; + + gtk_widget_queue_resize (GTK_WIDGET (self)); + + g_object_notify_by_pspec (G_OBJECT (self), + orientation == GTK_ORIENTATION_HORIZONTAL + ? properties[PROP_HSCROLL_POLICY] + : properties[PROP_VSCROLL_POLICY]); +} + +static void +gtk_list_base_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkListBase *self = GTK_LIST_BASE (object); + + switch (property_id) + { + case PROP_HADJUSTMENT: + gtk_list_base_set_adjustment (self, GTK_ORIENTATION_HORIZONTAL, g_value_get_object (value)); + break; + + case PROP_HSCROLL_POLICY: + gtk_list_base_set_scroll_policy (self, GTK_ORIENTATION_HORIZONTAL, g_value_get_enum (value)); + break; + + case PROP_VADJUSTMENT: + gtk_list_base_set_adjustment (self, GTK_ORIENTATION_VERTICAL, g_value_get_object (value)); + break; + + case PROP_VSCROLL_POLICY: + gtk_list_base_set_scroll_policy (self, GTK_ORIENTATION_VERTICAL, g_value_get_enum (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} static void gtk_list_base_class_init (GtkListBaseClass *klass) { + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + gpointer iface; + + gobject_class->dispose = gtk_list_base_dispose; + gobject_class->get_property = gtk_list_base_get_property; + gobject_class->set_property = gtk_list_base_set_property; + + /* GtkScrollable implementation */ + iface = g_type_default_interface_peek (GTK_TYPE_SCROLLABLE); + properties[PROP_HADJUSTMENT] = + g_param_spec_override ("hadjustment", + g_object_interface_find_property (iface, "hadjustment")); + properties[PROP_HSCROLL_POLICY] = + g_param_spec_override ("hscroll-policy", + g_object_interface_find_property (iface, "hscroll-policy")); + properties[PROP_VADJUSTMENT] = + g_param_spec_override ("vadjustment", + g_object_interface_find_property (iface, "vadjustment")); + properties[PROP_VSCROLL_POLICY] = + g_param_spec_override ("vscroll-policy", + g_object_interface_find_property (iface, "vscroll-policy")); + + g_object_class_install_properties (gobject_class, N_PROPS, properties); } static void gtk_list_base_init (GtkListBase *self) { + GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self); + + priv->adjustment[GTK_ORIENTATION_HORIZONTAL] = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + priv->adjustment[GTK_ORIENTATION_VERTICAL] = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN); gtk_widget_set_focusable (GTK_WIDGET (self), TRUE); } +static gboolean +gtk_list_base_adjustment_is_flipped (GtkListBase *self, + GtkOrientation orientation) +{ + if (orientation == GTK_ORIENTATION_VERTICAL) + return FALSE; + + return gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL; +} + +void +gtk_list_base_get_adjustment_values (GtkListBase *self, + GtkOrientation orientation, + int *value, + int *size, + int *page_size) +{ + GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self); + int val, upper, ps; + + val = gtk_adjustment_get_value (priv->adjustment[orientation]); + upper = gtk_adjustment_get_upper (priv->adjustment[orientation]); + ps = gtk_adjustment_get_page_size (priv->adjustment[orientation]); + if (gtk_list_base_adjustment_is_flipped (self, orientation)) + val = upper - ps - val; + + if (value) + *value = val; + if (size) + *size = upper; + if (page_size) + *page_size = ps; +} + +int +gtk_list_base_set_adjustment_values (GtkListBase *self, + GtkOrientation orientation, + int value, + int size, + int page_size) +{ + GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self); + + size = MAX (size, page_size); + value = MAX (value, 0); + value = MIN (value, size - page_size); + + g_signal_handlers_block_by_func (priv->adjustment[orientation], + gtk_list_base_adjustment_value_changed_cb, + self); + gtk_adjustment_configure (priv->adjustment[orientation], + gtk_list_base_adjustment_is_flipped (self, orientation) + ? size - page_size - value + : value, + 0, + size, + page_size * 0.1, + page_size * 0.9, + page_size); + g_signal_handlers_unblock_by_func (priv->adjustment[orientation], + gtk_list_base_adjustment_value_changed_cb, + self); + + return value; +} + +GtkScrollablePolicy +gtk_list_base_get_scroll_policy (GtkListBase *self, + GtkOrientation orientation) +{ + GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self); + + return priv->scroll_policy[orientation]; +} + |