diff --git a/docs/reference/gtk/meson.build b/docs/reference/gtk/meson.build index e002c3feda..797784e81c 100644 --- a/docs/reference/gtk/meson.build +++ b/docs/reference/gtk/meson.build @@ -27,6 +27,7 @@ private_headers = [ 'gtkcolumnlistitemfactoryprivate.h', 'gtkcolumnviewcellprivate.h', 'gtkcolumnviewcolumnprivate.h', + 'gtkcolumnviewlayoutprivate.h', 'gtkcolumnviewprivate.h', 'gtkcomboboxprivate.h', 'gtkconstraintexpressionprivate.h', diff --git a/gtk/gtkcolumnlistitemfactory.c b/gtk/gtkcolumnlistitemfactory.c index ac5c3e1766..0b2151f12f 100644 --- a/gtk/gtkcolumnlistitemfactory.c +++ b/gtk/gtkcolumnlistitemfactory.c @@ -23,6 +23,7 @@ #include "gtkboxlayout.h" #include "gtkcolumnviewcolumnprivate.h" +#include "gtkcolumnviewlayoutprivate.h" #include "gtklistitemfactoryprivate.h" #include "gtklistitemprivate.h" @@ -51,7 +52,7 @@ gtk_column_list_item_factory_setup (GtkListItemFactory *factory, /* FIXME: evil */ gtk_widget_set_layout_manager (GTK_WIDGET (widget), - gtk_box_layout_new (GTK_ORIENTATION_HORIZONTAL)); + gtk_column_view_layout_new (self->view)); GTK_LIST_ITEM_FACTORY_CLASS (gtk_column_list_item_factory_parent_class)->setup (factory, widget, list_item); diff --git a/gtk/gtkcolumnview.c b/gtk/gtkcolumnview.c index 00b5e3a21b..8582e7293d 100644 --- a/gtk/gtkcolumnview.c +++ b/gtk/gtkcolumnview.c @@ -118,6 +118,93 @@ G_DEFINE_TYPE_WITH_CODE (GtkColumnView, gtk_column_view, GTK_TYPE_WIDGET, static GParamSpec *properties[N_PROPS] = { NULL, }; static guint signals[LAST_SIGNAL] = { 0 }; +static void +gtk_column_view_measure (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + GtkColumnView *self = GTK_COLUMN_VIEW (widget); + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + gtk_column_view_measure_across (self, minimum, natural); + } + else + { + gtk_widget_measure (GTK_WIDGET (self->listview), + orientation, for_size, + minimum, natural, + minimum_baseline, natural_baseline); + } +} + +static int +gtk_column_view_allocate_columns (GtkColumnView *self, + int width) +{ + GtkScrollablePolicy scroll_policy; + int col_min, col_nat, widget_min, widget_nat, extra, col_size, x; + guint i; + + gtk_column_view_measure_across (self, &col_min, &col_nat); + gtk_widget_measure (GTK_WIDGET (self->listview), + GTK_ORIENTATION_HORIZONTAL, -1, + &widget_min, &widget_nat, + NULL, NULL); + + scroll_policy = gtk_scrollable_get_hscroll_policy (GTK_SCROLLABLE (self->listview)); + if (scroll_policy == GTK_SCROLL_MINIMUM) + { + extra = widget_min - col_min; + col_size = col_min; + } + else + { + extra = widget_nat - col_nat; + col_size = col_nat; + } + width -= extra; + width = MAX (width, col_size); + + x = 0; + for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->columns)); i++) + { + GtkColumnViewColumn *column; + + column = g_list_model_get_item (G_LIST_MODEL (self->columns), i); + gtk_column_view_column_measure (column, &col_min, &col_nat); + if (scroll_policy == GTK_SCROLL_MINIMUM) + col_size = col_min; + else + col_size = col_nat; + + gtk_column_view_column_allocate (column, x, col_size); + x += col_size; + + g_object_unref (column); + } + + return width + extra; +} + +static void +gtk_column_view_allocate (GtkWidget *widget, + int width, + int height, + int baseline) +{ + GtkColumnView *self = GTK_COLUMN_VIEW (widget); + int full_width; + + full_width = gtk_column_view_allocate_columns (self, width); + + gtk_widget_allocate (GTK_WIDGET (self->listview), full_width, height, baseline, NULL); +} + static void gtk_column_view_activate_cb (GtkListView *listview, guint pos, @@ -261,6 +348,9 @@ gtk_column_view_class_init (GtkColumnViewClass *klass) GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gpointer iface; + widget_class->measure = gtk_column_view_measure; + widget_class->size_allocate = gtk_column_view_allocate; + gobject_class->dispose = gtk_column_view_dispose; gobject_class->finalize = gtk_column_view_finalize; gobject_class->get_property = gtk_column_view_get_property; @@ -362,7 +452,6 @@ gtk_column_view_init (GtkColumnView *self) gtk_css_node_add_class (gtk_widget_get_css_node (GTK_WIDGET (self)), g_quark_from_static_string (I_("view"))); - gtk_widget_set_layout_manager (GTK_WIDGET (self), gtk_box_layout_new (GTK_ORIENTATION_VERTICAL)); gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN); } @@ -531,3 +620,31 @@ gtk_column_view_remove_column (GtkColumnView *self, g_list_store_remove (self->columns, i); } +void +gtk_column_view_measure_across (GtkColumnView *self, + int *minimum, + int *natural) +{ + guint i; + int min, nat; + + min = 0; + nat = 0; + + for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->columns)); i++) + { + GtkColumnViewColumn *column; + int col_min, col_nat; + + column = g_list_model_get_item (G_LIST_MODEL (self->columns), i); + gtk_column_view_column_measure (column, &col_min, &col_nat); + min += col_min; + nat += col_nat; + + g_object_unref (column); + } + + *minimum = min; + *natural = nat; +} + diff --git a/gtk/gtkcolumnviewcell.c b/gtk/gtkcolumnviewcell.c index db3085dbe2..ecaa39dd46 100644 --- a/gtk/gtkcolumnviewcell.c +++ b/gtk/gtkcolumnviewcell.c @@ -44,17 +44,6 @@ struct _GtkColumnViewCellClass G_DEFINE_TYPE (GtkColumnViewCell, gtk_column_view_cell, GTK_TYPE_LIST_ITEM_WIDGET) -void -gtk_column_view_cell_measure_contents (GtkColumnViewCell *self, - int *minimum, - int *natural) -{ - GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self)); - - if (child) - gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, minimum, natural, NULL, NULL); -} - static void gtk_column_view_cell_measure (GtkWidget *widget, GtkOrientation orientation, @@ -64,19 +53,10 @@ gtk_column_view_cell_measure (GtkWidget *widget, int *minimum_baseline, int *natural_baseline) { - GtkColumnViewCell *self = GTK_COLUMN_VIEW_CELL (widget); + GtkWidget *child = gtk_widget_get_first_child (widget); - if (orientation == GTK_ORIENTATION_HORIZONTAL) - { - gtk_column_view_column_measure (self->column, minimum, natural); - } - else - { - GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self)); - - if (child) - gtk_widget_measure (child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline); - } + if (child) + gtk_widget_measure (child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline); } static void @@ -202,3 +182,9 @@ gtk_column_view_cell_get_prev (GtkColumnViewCell *self) { return self->prev_cell; } + +GtkColumnViewColumn * +gtk_column_view_cell_get_column (GtkColumnViewCell *self) +{ + return self->column; +} diff --git a/gtk/gtkcolumnviewcellprivate.h b/gtk/gtkcolumnviewcellprivate.h index 1ebdc710f4..4378d082e7 100644 --- a/gtk/gtkcolumnviewcellprivate.h +++ b/gtk/gtkcolumnviewcellprivate.h @@ -42,10 +42,7 @@ void gtk_column_view_cell_remove (GtkColumnViewCe GtkColumnViewCell * gtk_column_view_cell_get_next (GtkColumnViewCell *self); GtkColumnViewCell * gtk_column_view_cell_get_prev (GtkColumnViewCell *self); - -void gtk_column_view_cell_measure_contents (GtkColumnViewCell *self, - int *minimum, - int *natural); +GtkColumnViewColumn * gtk_column_view_cell_get_column (GtkColumnViewCell *self); G_END_DECLS diff --git a/gtk/gtkcolumnviewcolumn.c b/gtk/gtkcolumnviewcolumn.c index a34e81fa84..aaa8c32fdc 100644 --- a/gtk/gtkcolumnviewcolumn.c +++ b/gtk/gtkcolumnviewcolumn.c @@ -52,6 +52,8 @@ struct _GtkColumnViewColumn int minimum_size_request; int natural_size_request; + int allocation_offset; + int allocation_size; /* This list isn't sorted - this is just caching for performance */ GtkColumnViewCell *first_cell; /* no reference, just caching */ @@ -310,7 +312,11 @@ gtk_column_view_column_measure (GtkColumnViewColumn *self, for (cell = self->first_cell; cell; cell = gtk_column_view_cell_get_next (cell)) { - gtk_column_view_cell_measure_contents (cell, &cell_min, &cell_nat); + gtk_widget_measure (GTK_WIDGET (cell), + GTK_ORIENTATION_HORIZONTAL, + -1, + &cell_min, &cell_nat, + NULL, NULL); min = MAX (min, cell_min); nat = MAX (nat, cell_nat); @@ -324,6 +330,26 @@ gtk_column_view_column_measure (GtkColumnViewColumn *self, *natural = self->natural_size_request; } +void +gtk_column_view_column_allocate (GtkColumnViewColumn *self, + int offset, + int size) +{ + self->allocation_offset = offset; + self->allocation_size = size; +} + +void +gtk_column_view_column_get_allocation (GtkColumnViewColumn *self, + int *offset, + int *size) +{ + if (offset) + *offset = self->allocation_offset; + if (size) + *size = self->allocation_size; +} + static void gtk_column_view_column_create_cells (GtkColumnViewColumn *self) { diff --git a/gtk/gtkcolumnviewcolumnprivate.h b/gtk/gtkcolumnviewcolumnprivate.h index fc0fe07c78..d7e06a5b0f 100644 --- a/gtk/gtkcolumnviewcolumnprivate.h +++ b/gtk/gtkcolumnviewcolumnprivate.h @@ -37,5 +37,11 @@ void gtk_column_view_column_queue_resize (GtkColu void gtk_column_view_column_measure (GtkColumnViewColumn *self, int *minimum, int *natural); +void gtk_column_view_column_allocate (GtkColumnViewColumn *self, + int offset, + int size); +void gtk_column_view_column_get_allocation (GtkColumnViewColumn *self, + int *offset, + int *size); #endif /* __GTK_COLUMN_VIEW_COLUMN_PRIVATE_H__ */ diff --git a/gtk/gtkcolumnviewlayout.c b/gtk/gtkcolumnviewlayout.c new file mode 100644 index 0000000000..3afd6a2af3 --- /dev/null +++ b/gtk/gtkcolumnviewlayout.c @@ -0,0 +1,149 @@ +/* + * Copyright © 2019 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.1 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 . + * + * Authors: Benjamin Otte + */ + +#include "config.h" + +#include "gtkcolumnviewlayoutprivate.h" + +#include "gtkcolumnviewcellprivate.h" +#include "gtkcolumnviewcolumnprivate.h" +#include "gtkcolumnviewprivate.h" +#include "gtkwidgetprivate.h" + +struct _GtkColumnViewLayout +{ + GtkLayoutManager parent_instance; + + GtkColumnView *view; /* no reference */ +}; + +G_DEFINE_TYPE (GtkColumnViewLayout, gtk_column_view_layout, GTK_TYPE_LAYOUT_MANAGER) + +static void +gtk_column_view_layout_measure_along (GtkColumnViewLayout *self, + GtkWidget *widget, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + GtkOrientation orientation = GTK_ORIENTATION_VERTICAL; + GtkWidget *child; + + for (child = _gtk_widget_get_first_child (widget); + child != NULL; + child = _gtk_widget_get_next_sibling (child)) + { + int child_min = 0; + int child_nat = 0; + int child_min_baseline = -1; + int child_nat_baseline = -1; + + gtk_widget_measure (child, orientation, for_size, + &child_min, &child_nat, + &child_min_baseline, &child_nat_baseline); + + *minimum = MAX (*minimum, child_min); + *natural = MAX (*natural, child_nat); + + if (child_min_baseline > -1) + *minimum_baseline = MAX (*minimum_baseline, child_min_baseline); + if (child_nat_baseline > -1) + *natural_baseline = MAX (*natural_baseline, child_nat_baseline); + } +} + +static void +gtk_column_view_layout_measure (GtkLayoutManager *layout, + GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + GtkColumnViewLayout *self = GTK_COLUMN_VIEW_LAYOUT (layout); + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + gtk_column_view_measure_across (GTK_COLUMN_VIEW (self->view), + minimum, + natural); + } + else + { + gtk_column_view_layout_measure_along (self, + widget, + for_size, + minimum, + natural, + minimum_baseline, + natural_baseline); + } +} + +static void +gtk_column_view_layout_allocate (GtkLayoutManager *layout_manager, + GtkWidget *widget, + int width, + int height, + int baseline) +{ + GtkWidget *child; + + for (child = _gtk_widget_get_first_child (widget); + child != NULL; + child = _gtk_widget_get_next_sibling (child)) + { + GtkColumnViewCell *cell = GTK_COLUMN_VIEW_CELL (child); + GtkColumnViewColumn *column = gtk_column_view_cell_get_column (cell); + int col_x, col_width; + + gtk_column_view_column_get_allocation (column, &col_x, &col_width); + gtk_widget_size_allocate (child, &(GtkAllocation) { col_x, 0, col_width, height }, baseline); + } +} + +static void +gtk_column_view_layout_class_init (GtkColumnViewLayoutClass *klass) +{ + GtkLayoutManagerClass *layout_manager_class = GTK_LAYOUT_MANAGER_CLASS (klass); + + layout_manager_class->measure = gtk_column_view_layout_measure; + layout_manager_class->allocate = gtk_column_view_layout_allocate; +} + +static void +gtk_column_view_layout_init (GtkColumnViewLayout *self) +{ +} + +GtkLayoutManager * +gtk_column_view_layout_new (GtkColumnView *view) +{ + GtkColumnViewLayout *result; + + result = g_object_new (GTK_TYPE_COLUMN_VIEW_LAYOUT, NULL); + + result->view = view; + + return GTK_LAYOUT_MANAGER (result); +} diff --git a/gtk/gtkcolumnviewlayoutprivate.h b/gtk/gtkcolumnviewlayoutprivate.h new file mode 100644 index 0000000000..6e786cdbd5 --- /dev/null +++ b/gtk/gtkcolumnviewlayoutprivate.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2019 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.1 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 . + * + * Authors: Benjamin Otte + */ + +#ifndef __GTK_COLUMN_VIEW_LAYOUT_PRIVATE_H__ +#define __GTK_COLUMN_VIEW_LAYOUT_PRIVATE_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_COLUMN_VIEW_LAYOUT (gtk_column_view_layout_get_type ()) + +G_DECLARE_FINAL_TYPE (GtkColumnViewLayout, gtk_column_view_layout, GTK, COLUMN_VIEW_LAYOUT, GtkLayoutManager) + +GtkLayoutManager * gtk_column_view_layout_new (GtkColumnView *view); + + +#endif /* __GTK_COLUMN_VIEW_LAYOUT_PRIVATE_H__ */ diff --git a/gtk/gtkcolumnviewprivate.h b/gtk/gtkcolumnviewprivate.h index 417a942ab4..d95577fe98 100644 --- a/gtk/gtkcolumnviewprivate.h +++ b/gtk/gtkcolumnviewprivate.h @@ -22,5 +22,8 @@ #include "gtk/gtkcolumnview.h" +void gtk_column_view_measure_across (GtkColumnView *self, + int *minimum, + int *natural); #endif /* __GTK_COLUMN_VIEW_PRIVATE_H__ */ diff --git a/gtk/meson.build b/gtk/meson.build index 80fffed33e..565c23ad5b 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -37,6 +37,9 @@ gtk_private_sources = files([ 'gtkcolorpickershell.c', 'gtkcolorscale.c', 'gtkcolorswatch.c', + 'gtkcolumnlistitemfactory.c', + 'gtkcolumnviewcell.c', + 'gtkcolumnviewlayout.c', 'gtkconstraintexpression.c', 'gtkconstraintsolver.c', 'gtkconstraintvflparser.c', @@ -193,9 +196,7 @@ gtk_public_sources = files([ 'gtkcolorchooserdialog.c', 'gtkcolorchooserwidget.c', 'gtkcolorutils.c', - 'gtkcolumnlistitemfactory.c', 'gtkcolumnview.c', - 'gtkcolumnviewcell.c', 'gtkcolumnviewcolumn.c', 'gtkcombobox.c', 'gtkcomboboxtext.c',