summaryrefslogtreecommitdiff
path: root/gtk/gtklistbase.c
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2019-10-22 23:46:34 +0200
committerMatthias Clasen <mclasen@redhat.com>2020-05-30 19:26:46 -0400
commit0011ce949c3580e02c4b2c3d83584a6c6e82090c (patch)
treeb6719987a5562d02cdad90149fcd03b0985c876a /gtk/gtklistbase.c
parentcc987b31aef665d7c27c81b22872efb3ade754c3 (diff)
downloadgtk+-0011ce949c3580e02c4b2c3d83584a6c6e82090c.tar.gz
listbase: Move GtkScrollable implementation
Shared code between GtkGridView and GtkListView.
Diffstat (limited to 'gtk/gtklistbase.c')
-rw-r--r--gtk/gtklistbase.c281
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];
+}
+