summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2019-11-07 23:40:47 +0100
committerBenjamin Otte <otte@redhat.com>2019-12-12 07:47:44 +0100
commitda06abeca124d0d302722c5fc02101e50de53531 (patch)
treee45c26c5ec7209ef7678fa65f7ba115ca3bca918
parentf59f1f6af2e3b8cda52d24a6eb7c0071dd972747 (diff)
downloadgtk+-da06abeca124d0d302722c5fc02101e50de53531.tar.gz
columnview: Add a custom LayoutManager
The ColumnView now allocates column widths first and then the individual rows use the new layout manager which looks at the column allocations to allocate their children.
-rw-r--r--gtk/gtkcolumnlistitemfactory.c3
-rw-r--r--gtk/gtkcolumnview.c119
-rw-r--r--gtk/gtkcolumnviewcell.c32
-rw-r--r--gtk/gtkcolumnviewcellprivate.h5
-rw-r--r--gtk/gtkcolumnviewcolumn.c28
-rw-r--r--gtk/gtkcolumnviewcolumnprivate.h6
-rw-r--r--gtk/gtkcolumnviewlayout.c149
-rw-r--r--gtk/gtkcolumnviewlayoutprivate.h35
-rw-r--r--gtk/gtkcolumnviewprivate.h3
-rw-r--r--gtk/meson.build5
10 files changed, 353 insertions, 32 deletions
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
@@ -119,6 +119,93 @@ 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,
GtkColumnView *self)
@@ -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 03f8d52fa5..c18cf7716e 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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+#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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+#ifndef __GTK_COLUMN_VIEW_LAYOUT_PRIVATE_H__
+#define __GTK_COLUMN_VIEW_LAYOUT_PRIVATE_H__
+
+#include <gtk/gtkcolumnview.h>
+#include <gtk/gtklayoutmanager.h>
+
+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 8c2877b913..105a81146b 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',
@@ -206,9 +209,7 @@ gtk_public_sources = files([
'gtkcolorchooserdialog.c',
'gtkcolorchooserwidget.c',
'gtkcolorutils.c',
- 'gtkcolumnlistitemfactory.c',
'gtkcolumnview.c',
- 'gtkcolumnviewcell.c',
'gtkcolumnviewcolumn.c',
'gtkcombobox.c',
'gtkcomboboxtext.c',