diff options
author | Benjamin Otte <otte@redhat.com> | 2019-10-22 23:46:34 +0200 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2019-10-28 10:49:01 +0100 |
commit | 010808794ffe3420bd9bd9ad02c7f96db23188ff (patch) | |
tree | d943f44b49ccd2d0018cef705d93ef2f2081e381 | |
parent | 6ad943c4009d9f67944947c993cf623c484ce195 (diff) | |
download | gtk+-010808794ffe3420bd9bd9ad02c7f96db23188ff.tar.gz |
listbase: Move GtkScrollable implementation
Shared code between GtkGridView and GtkListView.
-rw-r--r-- | gtk/gtkgridview.c | 233 | ||||
-rw-r--r-- | gtk/gtklistbase.c | 281 | ||||
-rw-r--r-- | gtk/gtklistbaseprivate.h | 15 | ||||
-rw-r--r-- | gtk/gtklistview.c | 189 |
4 files changed, 357 insertions, 361 deletions
diff --git a/gtk/gtkgridview.c b/gtk/gtkgridview.c index 008434cf29..c0515f641c 100644 --- a/gtk/gtkgridview.c +++ b/gtk/gtkgridview.c @@ -21,7 +21,6 @@ #include "gtkgridview.h" -#include "gtkadjustment.h" #include "gtkbindings.h" #include "gtkintl.h" #include "gtklistbaseprivate.h" @@ -30,7 +29,6 @@ #include "gtkmain.h" #include "gtkorientableprivate.h" #include "gtkprivate.h" -#include "gtkscrollable.h" #include "gtksingleselection.h" #include "gtktypebuiltins.h" #include "gtkwidgetprivate.h" @@ -64,8 +62,6 @@ struct _GtkGridView GListModel *model; GtkListItemManager *item_manager; - GtkAdjustment *adjustment[2]; - GtkScrollablePolicy scroll_policy[2]; GtkOrientation orientation; guint min_columns; guint max_columns; @@ -106,14 +102,10 @@ enum { PROP_0, PROP_FACTORY, - PROP_HADJUSTMENT, - PROP_HSCROLL_POLICY, PROP_MAX_COLUMNS, PROP_MIN_COLUMNS, PROP_MODEL, PROP_ORIENTATION, - PROP_VADJUSTMENT, - PROP_VSCROLL_POLICY, N_PROPS }; @@ -124,8 +116,7 @@ enum { }; G_DEFINE_TYPE_WITH_CODE (GtkGridView, gtk_grid_view, GTK_TYPE_LIST_BASE, - G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL) - G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL)) + G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL)) static GParamSpec *properties[N_PROPS] = { NULL, }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -462,35 +453,22 @@ moved_focus: return TRUE; } -static gboolean -gtk_grid_view_adjustment_is_flipped (GtkGridView *self, - GtkOrientation orientation) -{ - if (orientation == GTK_ORIENTATION_VERTICAL) - return FALSE; - - return gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL; -} - static void -gtk_grid_view_adjustment_value_changed_cb (GtkAdjustment *adjustment, - GtkGridView *self) +gtk_grid_view_adjustment_value_changed (GtkListBase *base, + GtkOrientation orientation) { + GtkGridView *self = GTK_GRID_VIEW (base); int page_size, total_size, value, from_start; guint pos, anchor_pos, n_items; int offset, height, top, bottom; double xalign, yalign; gboolean xstart, ystart; - page_size = gtk_adjustment_get_page_size (adjustment); - value = gtk_adjustment_get_value (adjustment); - total_size = gtk_adjustment_get_upper (adjustment); + gtk_list_base_get_adjustment_values (base, orientation, &value, &total_size, &page_size); anchor_pos = gtk_list_item_tracker_get_position (self->item_manager, self->anchor); n_items = g_list_model_get_n_items (self->model); - if (gtk_grid_view_adjustment_is_flipped (self, self->orientation)) - value = total_size - page_size - value; - if (adjustment == self->adjustment[self->orientation]) + if (orientation == self->orientation) { /* Compute how far down we've scrolled. That's the height * we want to align to. */ @@ -587,13 +565,13 @@ gtk_grid_view_adjustment_value_changed_cb (GtkAdjustment *adjustment, /* Ugh, we're in the last row and don't have enough items * to fill the row. * Do it the hard way then... */ - adjustment = self->adjustment[OPPOSITE_ORIENTATION (self->orientation)]; + gtk_list_base_get_adjustment_values (base, + OPPOSITE_ORIENTATION (self->orientation), + &value, &total_size, &page_size); pos = n_items - 1; xstart = FALSE; - xalign = (ceil (self->column_width * (pos % self->n_columns + 1)) - - gtk_adjustment_get_value (adjustment)) - / gtk_adjustment_get_page_size (adjustment); + xalign = (ceil (self->column_width * (pos % self->n_columns + 1)) - value) / page_size; } gtk_grid_view_set_anchor (self, pos, xalign, xstart, yalign, ystart); @@ -602,36 +580,6 @@ gtk_grid_view_adjustment_value_changed_cb (GtkAdjustment *adjustment, } static int -gtk_grid_view_update_adjustment_with_values (GtkGridView *self, - GtkOrientation orientation, - int value, - int upper, - int page_size) -{ - upper = MAX (upper, page_size); - value = MAX (0, value); - value = MIN (value, upper - page_size); - - g_signal_handlers_block_by_func (self->adjustment[orientation], - gtk_grid_view_adjustment_value_changed_cb, - self); - gtk_adjustment_configure (self->adjustment[orientation], - gtk_grid_view_adjustment_is_flipped (self, orientation) - ? value = upper - page_size - value - : value, - 0, - upper, - page_size * 0.1, - page_size * 0.9, - page_size); - g_signal_handlers_unblock_by_func (self->adjustment[orientation], - gtk_grid_view_adjustment_value_changed_cb, - self); - - return value; -} - -static int gtk_grid_view_update_adjustment (GtkGridView *self, GtkOrientation orientation) { @@ -640,10 +588,7 @@ gtk_grid_view_update_adjustment (GtkGridView *self, anchor_pos = gtk_list_item_tracker_get_position (self->item_manager, self->anchor); if (anchor_pos == GTK_INVALID_LIST_POSITION) - { - gtk_grid_view_update_adjustment_with_values (self, orientation, 0, 0, 0); - return 0; - } + return gtk_list_base_set_adjustment_values (GTK_LIST_BASE (self), orientation, 0, 0, 0); page_size = gtk_widget_get_size (GTK_WIDGET (self), orientation); @@ -665,11 +610,11 @@ gtk_grid_view_update_adjustment (GtkGridView *self, if (!self->anchor_ystart) value += cell_size; - value = gtk_grid_view_update_adjustment_with_values (self, - self->orientation, - value - self->anchor_yalign * page_size, - aug->size, - page_size); + value = gtk_list_base_set_adjustment_values (GTK_LIST_BASE (self), + self->orientation, + value - self->anchor_yalign * page_size, + aug->size, + page_size); } else { @@ -681,11 +626,11 @@ gtk_grid_view_update_adjustment (GtkGridView *self, value = ceil (self->column_width * (i + 1)); total_size = round (self->n_columns * self->column_width); - value = gtk_grid_view_update_adjustment_with_values (self, - OPPOSITE_ORIENTATION (self->orientation), - value - self->anchor_xalign * page_size, - total_size, - page_size); + value = gtk_list_base_set_adjustment_values (GTK_LIST_BASE (self), + OPPOSITE_ORIENTATION (self->orientation), + value - self->anchor_xalign * page_size, + total_size, + page_size); } return value; @@ -765,7 +710,7 @@ gtk_grid_view_compute_n_columns (GtkGridView *self, guint n_columns; /* rounding down is exactly what we want here, so int division works */ - if (self->scroll_policy[OPPOSITE_ORIENTATION (self->orientation)] == GTK_SCROLL_MINIMUM) + if (gtk_list_base_get_scroll_policy (GTK_LIST_BASE (self), OPPOSITE_ORIENTATION (self->orientation)) == GTK_SCROLL_MINIMUM) n_columns = for_size / MAX (1, min); else n_columns = for_size / MAX (1, nat); @@ -782,6 +727,7 @@ gtk_grid_view_measure_list (GtkWidget *widget, int *natural) { GtkGridView *self = GTK_GRID_VIEW (widget); + GtkScrollablePolicy scroll_policy; Cell *cell; int height, row_height, child_min, child_nat, column_size, col_min, col_nat; gboolean measured; @@ -789,6 +735,7 @@ gtk_grid_view_measure_list (GtkWidget *widget, guint n_unknown, n_columns; guint i; + scroll_policy = gtk_list_base_get_scroll_policy (GTK_LIST_BASE (self), self->orientation); heights = g_array_new (FALSE, FALSE, sizeof (int)); n_unknown = 0; height = 0; @@ -810,7 +757,7 @@ gtk_grid_view_measure_list (GtkWidget *widget, gtk_widget_measure (cell->parent.widget, self->orientation, column_size, &child_min, &child_nat, NULL, NULL); - if (self->scroll_policy[self->orientation] == GTK_SCROLL_MINIMUM) + if (scroll_policy == GTK_SCROLL_MINIMUM) row_height = MAX (row_height, child_min); else row_height = MAX (row_height, child_nat); @@ -930,10 +877,12 @@ gtk_grid_view_size_allocate (GtkWidget *widget, GArray *heights; int min_row_height, row_height, col_min, col_nat; GtkOrientation opposite_orientation; + GtkScrollablePolicy scroll_policy; gboolean known; int x, y; guint i; + scroll_policy = gtk_list_base_get_scroll_policy (GTK_LIST_BASE (self), self->orientation); opposite_orientation = OPPOSITE_ORIENTATION (self->orientation); min_row_height = ceil ((double) height / GTK_GRID_VIEW_MAX_VISIBLE_ROWS); @@ -968,7 +917,7 @@ gtk_grid_view_size_allocate (GtkWidget *widget, gtk_widget_measure (cell->parent.widget, self->orientation, self->column_width, &min, &nat, NULL, NULL); - if (self->scroll_policy[self->orientation] == GTK_SCROLL_MINIMUM) + if (scroll_policy == GTK_SCROLL_MINIMUM) size = min; else size = nat; @@ -1066,28 +1015,12 @@ gtk_grid_view_size_allocate (GtkWidget *widget, } static void -gtk_grid_view_clear_adjustment (GtkGridView *self, - GtkOrientation orientation) -{ - if (self->adjustment[orientation] == NULL) - return; - - g_signal_handlers_disconnect_by_func (self->adjustment[orientation], - gtk_grid_view_adjustment_value_changed_cb, - self); - g_clear_object (&self->adjustment[orientation]); -} - -static void gtk_grid_view_dispose (GObject *object) { GtkGridView *self = GTK_GRID_VIEW (object); g_clear_object (&self->model); - gtk_grid_view_clear_adjustment (self, GTK_ORIENTATION_HORIZONTAL); - gtk_grid_view_clear_adjustment (self, GTK_ORIENTATION_VERTICAL); - if (self->anchor) { gtk_list_item_tracker_free (self->item_manager, self->anchor); @@ -1122,14 +1055,6 @@ gtk_grid_view_get_property (GObject *object, g_value_set_object (value, gtk_list_item_manager_get_factory (self->item_manager)); break; - case PROP_HADJUSTMENT: - g_value_set_object (value, self->adjustment[GTK_ORIENTATION_HORIZONTAL]); - break; - - case PROP_HSCROLL_POLICY: - g_value_set_enum (value, self->scroll_policy[GTK_ORIENTATION_HORIZONTAL]); - break; - case PROP_MAX_COLUMNS: g_value_set_uint (value, self->max_columns); break; @@ -1146,14 +1071,6 @@ gtk_grid_view_get_property (GObject *object, g_value_set_enum (value, self->orientation); break; - case PROP_VADJUSTMENT: - g_value_set_object (value, self->adjustment[GTK_ORIENTATION_VERTICAL]); - break; - - case PROP_VSCROLL_POLICY: - g_value_set_enum (value, self->scroll_policy[GTK_ORIENTATION_VERTICAL]); - break; - default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -1161,47 +1078,6 @@ gtk_grid_view_get_property (GObject *object, } static void -gtk_grid_view_set_adjustment (GtkGridView *self, - GtkOrientation orientation, - GtkAdjustment *adjustment) -{ - if (self->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_grid_view_clear_adjustment (self, orientation); - - self->adjustment[orientation] = adjustment; - - g_signal_connect (adjustment, "value-changed", - G_CALLBACK (gtk_grid_view_adjustment_value_changed_cb), - self); - - gtk_widget_queue_allocate (GTK_WIDGET (self)); -} - -static void -gtk_grid_view_set_scroll_policy (GtkGridView *self, - GtkOrientation orientation, - GtkScrollablePolicy scroll_policy) -{ - if (self->scroll_policy[orientation] == scroll_policy) - return; - - self->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_grid_view_set_property (GObject *object, guint property_id, const GValue *value, @@ -1215,14 +1091,6 @@ gtk_grid_view_set_property (GObject *object, gtk_grid_view_set_factory (self, g_value_get_object (value)); break; - case PROP_HADJUSTMENT: - gtk_grid_view_set_adjustment (self, GTK_ORIENTATION_HORIZONTAL, g_value_get_object (value)); - break; - - case PROP_HSCROLL_POLICY: - gtk_grid_view_set_scroll_policy (self, GTK_ORIENTATION_HORIZONTAL, g_value_get_enum (value)); - break; - case PROP_MAX_COLUMNS: gtk_grid_view_set_max_columns (self, g_value_get_uint (value)); break; @@ -1248,14 +1116,6 @@ gtk_grid_view_set_property (GObject *object, gtk_grid_view_set_model (self, g_value_get_object (value)); break; - case PROP_VADJUSTMENT: - gtk_grid_view_set_adjustment (self, GTK_ORIENTATION_VERTICAL, g_value_get_object (value)); - break; - - case PROP_VSCROLL_POLICY: - gtk_grid_view_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; @@ -1315,10 +1175,9 @@ gtk_grid_view_compute_scroll_align (GtkGridView *self, int visible_start, visible_size, visible_end; int cell_size; - visible_start = gtk_adjustment_get_value (self->adjustment[orientation]); - visible_size = gtk_adjustment_get_page_size (self->adjustment[orientation]); - if (gtk_grid_view_adjustment_is_flipped (self, orientation)) - visible_start = gtk_adjustment_get_upper (self->adjustment[orientation]) - visible_size - visible_start; + 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; @@ -1580,7 +1439,9 @@ gtk_grid_view_move_cursor_page_up (GtkWidget *widget, return; if (!gtk_grid_view_get_size_at_position (self, pos, &start, &size)) return; - page_size = gtk_adjustment_get_page_size(self->adjustment[self->orientation]); + gtk_list_base_get_adjustment_values (GTK_LIST_BASE (self), + self->orientation, + NULL, NULL, &page_size); if (!gtk_grid_view_get_cell_at_y (self, MAX (0, start + size - page_size), &new_pos, @@ -1615,7 +1476,9 @@ gtk_grid_view_move_cursor_page_down (GtkWidget *widget, return; if (!gtk_grid_view_get_size_at_position (self, pos, &start, NULL)) return; - page_size = gtk_adjustment_get_page_size(self->adjustment[self->orientation]); + gtk_list_base_get_adjustment_values (GTK_LIST_BASE (self), + self->orientation, + NULL, NULL, &page_size); if (gtk_grid_view_get_cell_at_y (self, start + page_size, &new_pos, @@ -1708,10 +1571,12 @@ gtk_grid_view_add_move_binding (GtkBindingSet *binding_set, static void gtk_grid_view_class_init (GtkGridViewClass *klass) { + GtkListBaseClass *list_base_class = GTK_LIST_BASE_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkBindingSet *binding_set; - gpointer iface; + + list_base_class->adjustment_value_changed = gtk_grid_view_adjustment_value_changed; widget_class->focus = gtk_grid_view_focus; widget_class->measure = gtk_grid_view_measure; @@ -1721,21 +1586,6 @@ gtk_grid_view_class_init (GtkGridViewClass *klass) gobject_class->get_property = gtk_grid_view_get_property; gobject_class->set_property = gtk_grid_view_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")); - /** * GtkGridView:factory: * @@ -1969,9 +1819,6 @@ gtk_grid_view_init (GtkGridView *self) self->min_columns = 1; self->max_columns = DEFAULT_MAX_COLUMNS; self->orientation = GTK_ORIENTATION_VERTICAL; - - self->adjustment[GTK_ORIENTATION_HORIZONTAL] = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); - self->adjustment[GTK_ORIENTATION_VERTICAL] = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); } /** diff --git a/gtk/gtklistbase.c b/gtk/gtklistbase.c index e46b4f29d0..880b259d93 100644 --- a/gtk/gtklistbase.c +++ b/gtk/gtklistbase.c @@ -21,16 +21,295 @@ #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); } +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]; +} + diff --git a/gtk/gtklistbaseprivate.h b/gtk/gtklistbaseprivate.h index cfd704f611..39acd980e4 100644 --- a/gtk/gtklistbaseprivate.h +++ b/gtk/gtklistbaseprivate.h @@ -30,7 +30,22 @@ struct _GtkListBase struct _GtkListBaseClass { GtkWidgetClass parent_class; + + void (* adjustment_value_changed) (GtkListBase *self, + GtkOrientation orientation); }; +GtkScrollablePolicy gtk_list_base_get_scroll_policy (GtkListBase *self, + GtkOrientation orientation); +void gtk_list_base_get_adjustment_values (GtkListBase *self, + GtkOrientation orientation, + int *value, + int *size, + int *page_size); +int gtk_list_base_set_adjustment_values (GtkListBase *self, + GtkOrientation orientation, + int value, + int size, + int page_size); #endif /* __GTK_LIST_BASE_PRIVATE_H__ */ diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c index a5623d1ae2..3affde8d10 100644 --- a/gtk/gtklistview.c +++ b/gtk/gtklistview.c @@ -21,7 +21,6 @@ #include "gtklistview.h" -#include "gtkadjustment.h" #include "gtkbindings.h" #include "gtkintl.h" #include "gtklistbaseprivate.h" @@ -30,7 +29,6 @@ #include "gtkorientableprivate.h" #include "gtkprivate.h" #include "gtkrbtreeprivate.h" -#include "gtkscrollable.h" #include "gtkselectionmodel.h" #include "gtksingleselection.h" #include "gtkstylecontext.h" @@ -64,8 +62,6 @@ struct _GtkListView GListModel *model; GtkListItemManager *item_manager; - GtkAdjustment *adjustment[2]; - GtkScrollablePolicy scroll_policy[2]; gboolean show_separators; GtkOrientation orientation; @@ -101,13 +97,9 @@ enum { PROP_0, PROP_FACTORY, - PROP_HADJUSTMENT, - PROP_HSCROLL_POLICY, PROP_MODEL, PROP_ORIENTATION, PROP_SHOW_SEPARATORS, - PROP_VADJUSTMENT, - PROP_VSCROLL_POLICY, N_PROPS }; @@ -118,8 +110,7 @@ enum { }; G_DEFINE_TYPE_WITH_CODE (GtkListView, gtk_list_view, GTK_TYPE_LIST_BASE, - G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL) - G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL)) + G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL)) static GParamSpec *properties[N_PROPS] = { NULL, }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -344,21 +335,13 @@ gtk_list_view_set_anchor (GtkListView *self, } } -static gboolean -gtk_list_view_adjustment_is_flipped (GtkListView *self, - GtkOrientation orientation) -{ - if (orientation == GTK_ORIENTATION_VERTICAL) - return FALSE; - - return gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL; -} - static void -gtk_list_view_adjustment_value_changed_cb (GtkAdjustment *adjustment, - GtkListView *self) +gtk_list_view_adjustment_value_changed (GtkListBase *base, + GtkOrientation orientation) { - if (adjustment == self->adjustment[self->orientation]) + GtkListView *self = GTK_LIST_VIEW (base); + + if (orientation == self->orientation) { int page_size, total_size, value, from_start; int row_start, row_end; @@ -366,12 +349,7 @@ gtk_list_view_adjustment_value_changed_cb (GtkAdjustment *adjustment, gboolean top; guint pos; - page_size = gtk_adjustment_get_page_size (adjustment); - value = gtk_adjustment_get_value (adjustment); - total_size = gtk_adjustment_get_upper (adjustment); - - if (gtk_list_view_adjustment_is_flipped (self, self->orientation)) - value = total_size - page_size - value; + gtk_list_base_get_adjustment_values (base, orientation, &value, &total_size, &page_size); /* Compute how far down we've scrolled. That's the height * we want to align to. */ @@ -453,31 +431,10 @@ gtk_list_view_update_adjustments (GtkListView *self, else { upper = self->list_width; - value = gtk_adjustment_get_value (self->adjustment[orientation]); - if (gtk_list_view_adjustment_is_flipped (self, orientation)) - value = upper - value - page_size; + gtk_list_base_get_adjustment_values (GTK_LIST_BASE (self), orientation, &value, NULL, NULL); } - upper = MAX (upper, page_size); - value = MAX (value, 0); - value = MIN (value, upper - page_size); - - g_signal_handlers_block_by_func (self->adjustment[orientation], - gtk_list_view_adjustment_value_changed_cb, - self); - gtk_adjustment_configure (self->adjustment[orientation], - gtk_list_view_adjustment_is_flipped (self, orientation) - ? upper - page_size - value - : value, - 0, - upper, - page_size * 0.1, - page_size * 0.9, - page_size); - g_signal_handlers_unblock_by_func (self->adjustment[orientation], - gtk_list_view_adjustment_value_changed_cb, - self); - - return value; + + return gtk_list_base_set_adjustment_values (GTK_LIST_BASE (self), orientation, value, upper, page_size); } static int @@ -652,8 +609,10 @@ gtk_list_view_size_allocate (GtkWidget *widget, int min, nat, row_height; int x, y; GtkOrientation opposite_orientation; + GtkScrollablePolicy scroll_policy; opposite_orientation = OPPOSITE_ORIENTATION (self->orientation); + scroll_policy = gtk_list_base_get_scroll_policy (GTK_LIST_BASE (self), self->orientation); /* step 0: exit early if list is empty */ if (gtk_list_item_manager_get_root (self->item_manager) == NULL) @@ -664,7 +623,7 @@ gtk_list_view_size_allocate (GtkWidget *widget, -1, &min, &nat, NULL, NULL); self->list_width = self->orientation == GTK_ORIENTATION_VERTICAL ? width : height; - if (self->scroll_policy[opposite_orientation] == GTK_SCROLL_MINIMUM) + if (scroll_policy == GTK_SCROLL_MINIMUM) self->list_width = MAX (min, self->list_width); else self->list_width = MAX (nat, self->list_width); @@ -682,7 +641,7 @@ gtk_list_view_size_allocate (GtkWidget *widget, gtk_widget_measure (row->parent.widget, self->orientation, self->list_width, &min, &nat, NULL, NULL); - if (self->scroll_policy[self->orientation] == GTK_SCROLL_MINIMUM) + if (scroll_policy == GTK_SCROLL_MINIMUM) row_height = min; else row_height = nat; @@ -812,28 +771,12 @@ moved_focus: } static void -gtk_list_view_clear_adjustment (GtkListView *self, - GtkOrientation orientation) -{ - if (self->adjustment[orientation] == NULL) - return; - - g_signal_handlers_disconnect_by_func (self->adjustment[orientation], - gtk_list_view_adjustment_value_changed_cb, - self); - g_clear_object (&self->adjustment[orientation]); -} - -static void gtk_list_view_dispose (GObject *object) { GtkListView *self = GTK_LIST_VIEW (object); g_clear_object (&self->model); - gtk_list_view_clear_adjustment (self, GTK_ORIENTATION_HORIZONTAL); - gtk_list_view_clear_adjustment (self, GTK_ORIENTATION_VERTICAL); - if (self->anchor) { gtk_list_item_tracker_free (self->item_manager, self->anchor); @@ -878,14 +821,6 @@ gtk_list_view_get_property (GObject *object, g_value_set_object (value, gtk_list_item_manager_get_factory (self->item_manager)); break; - case PROP_HADJUSTMENT: - g_value_set_object (value, self->adjustment[GTK_ORIENTATION_HORIZONTAL]); - break; - - case PROP_HSCROLL_POLICY: - g_value_set_enum (value, self->scroll_policy[GTK_ORIENTATION_HORIZONTAL]); - break; - case PROP_MODEL: g_value_set_object (value, self->model); break; @@ -898,14 +833,6 @@ gtk_list_view_get_property (GObject *object, g_value_set_boolean (value, self->show_separators); break; - case PROP_VADJUSTMENT: - g_value_set_object (value, self->adjustment[GTK_ORIENTATION_VERTICAL]); - break; - - case PROP_VSCROLL_POLICY: - g_value_set_enum (value, self->scroll_policy[GTK_ORIENTATION_VERTICAL]); - break; - default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -913,47 +840,6 @@ gtk_list_view_get_property (GObject *object, } static void -gtk_list_view_set_adjustment (GtkListView *self, - GtkOrientation orientation, - GtkAdjustment *adjustment) -{ - if (self->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_view_clear_adjustment (self, orientation); - - self->adjustment[orientation] = adjustment; - - g_signal_connect (adjustment, "value-changed", - G_CALLBACK (gtk_list_view_adjustment_value_changed_cb), - self); - - gtk_widget_queue_allocate (GTK_WIDGET (self)); -} - -static void -gtk_list_view_set_scroll_policy (GtkListView *self, - GtkOrientation orientation, - GtkScrollablePolicy scroll_policy) -{ - if (self->scroll_policy[orientation] == scroll_policy) - return; - - self->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_view_set_property (GObject *object, guint property_id, const GValue *value, @@ -967,14 +853,6 @@ gtk_list_view_set_property (GObject *object, gtk_list_view_set_factory (self, g_value_get_object (value)); break; - case PROP_HADJUSTMENT: - gtk_list_view_set_adjustment (self, GTK_ORIENTATION_HORIZONTAL, g_value_get_object (value)); - break; - - case PROP_HSCROLL_POLICY: - gtk_list_view_set_scroll_policy (self, GTK_ORIENTATION_HORIZONTAL, g_value_get_enum (value)); - break; - case PROP_MODEL: gtk_list_view_set_model (self, g_value_get_object (value)); break; @@ -996,14 +874,6 @@ gtk_list_view_set_property (GObject *object, gtk_list_view_set_show_separators (self, g_value_get_boolean (value)); break; - case PROP_VADJUSTMENT: - gtk_list_view_set_adjustment (self, GTK_ORIENTATION_VERTICAL, g_value_get_object (value)); - break; - - case PROP_VSCROLL_POLICY: - gtk_list_view_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; @@ -1084,10 +954,11 @@ gtk_list_view_compute_scroll_align (GtkListView *self, int visible_start, visible_size, visible_end; int cell_size; - visible_start = gtk_adjustment_get_value (self->adjustment[orientation]); - visible_size = gtk_adjustment_get_page_size (self->adjustment[orientation]); - if (gtk_list_view_adjustment_is_flipped (self, orientation)) - visible_start = gtk_adjustment_get_upper (self->adjustment[orientation]) - visible_size - visible_start; + 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; @@ -1446,10 +1317,12 @@ gtk_list_view_add_move_binding (GtkBindingSet *binding_set, static void gtk_list_view_class_init (GtkListViewClass *klass) { + GtkListBaseClass *list_base_class = GTK_LIST_BASE_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkBindingSet *binding_set; - gpointer iface; + + list_base_class->adjustment_value_changed = gtk_list_view_adjustment_value_changed; widget_class->measure = gtk_list_view_measure; widget_class->size_allocate = gtk_list_view_size_allocate; @@ -1460,21 +1333,6 @@ gtk_list_view_class_init (GtkListViewClass *klass) gobject_class->get_property = gtk_list_view_get_property; gobject_class->set_property = gtk_list_view_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")); - /** * GtkListView:factory: * @@ -1657,9 +1515,6 @@ gtk_list_view_init (GtkListView *self) self->anchor = gtk_list_item_tracker_new (self->item_manager); self->selected = gtk_list_item_tracker_new (self->item_manager); self->orientation = GTK_ORIENTATION_VERTICAL; - - self->adjustment[GTK_ORIENTATION_HORIZONTAL] = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); - self->adjustment[GTK_ORIENTATION_VERTICAL] = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); } /** |