diff --git a/gtk/gtkcolumnview.c b/gtk/gtkcolumnview.c index 8582e7293d..d6170dfc46 100644 --- a/gtk/gtkcolumnview.c +++ b/gtk/gtkcolumnview.c @@ -25,6 +25,7 @@ #include "gtkbuildable.h" #include "gtkcolumnlistitemfactoryprivate.h" #include "gtkcolumnviewcolumnprivate.h" +#include "gtkcolumnviewlayoutprivate.h" #include "gtkcssnodeprivate.h" #include "gtkintl.h" #include "gtklistview.h" @@ -49,6 +50,8 @@ struct _GtkColumnView GListStore *columns; + GtkWidget *header; + GtkListView *listview; GtkColumnListItemFactory *factory; }; @@ -135,10 +138,18 @@ gtk_column_view_measure (GtkWidget *widget, } else { + int header_min, header_nat, list_min, list_nat; + gtk_widget_measure (GTK_WIDGET (self->listview), orientation, for_size, - minimum, natural, - minimum_baseline, natural_baseline); + &header_min, &header_nat, + NULL, NULL); + gtk_widget_measure (GTK_WIDGET (self->listview), + orientation, for_size, + &list_min, &list_nat, + NULL, NULL); + *minimum = header_min + list_min; + *natural = header_nat + list_nat; } } @@ -151,7 +162,7 @@ gtk_column_view_allocate_columns (GtkColumnView *self, guint i; gtk_column_view_measure_across (self, &col_min, &col_nat); - gtk_widget_measure (GTK_WIDGET (self->listview), + gtk_widget_measure (GTK_WIDGET (self), GTK_ORIENTATION_HORIZONTAL, -1, &widget_min, &widget_nat, NULL, NULL); @@ -198,11 +209,20 @@ gtk_column_view_allocate (GtkWidget *widget, int baseline) { GtkColumnView *self = GTK_COLUMN_VIEW (widget); - int full_width; + int full_width, header_height, min, nat; full_width = gtk_column_view_allocate_columns (self, width); - gtk_widget_allocate (GTK_WIDGET (self->listview), full_width, height, baseline, NULL); + gtk_widget_measure (self->header, GTK_ORIENTATION_VERTICAL, full_width, &min, &nat, NULL, NULL); + if (gtk_scrollable_get_vscroll_policy (GTK_SCROLLABLE (self->listview)) == GTK_SCROLL_MINIMUM) + header_height = min; + else + header_height = nat; + gtk_widget_allocate (self->header, full_width, header_height, -1, NULL); + + gtk_widget_allocate (GTK_WIDGET (self->listview), + full_width, height - header_height, -1, + gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (0, header_height))); } static void @@ -225,6 +245,8 @@ gtk_column_view_dispose (GObject *object) g_object_unref (column); } + g_clear_pointer (&self->header, gtk_widget_unparent); + g_clear_pointer ((GtkWidget **) &self->listview, gtk_widget_unparent); g_clear_object (&self->factory); @@ -441,6 +463,11 @@ gtk_column_view_init (GtkColumnView *self) { self->columns = g_list_store_new (GTK_TYPE_COLUMN_VIEW_COLUMN); + self->header = gtk_list_item_widget_new (NULL, "header"); + gtk_widget_set_can_focus (self->header, FALSE); + gtk_widget_set_layout_manager (self->header, gtk_column_view_layout_new (self)); + gtk_widget_set_parent (self->header, GTK_WIDGET (self)); + self->factory = gtk_column_list_item_factory_new (self); self->listview = GTK_LIST_VIEW (gtk_list_view_new_with_factory ( GTK_LIST_ITEM_FACTORY (g_object_ref (self->factory)))); @@ -648,3 +675,9 @@ gtk_column_view_measure_across (GtkColumnView *self, *natural = nat; } +GtkListItemWidget * +gtk_column_view_get_header_widget (GtkColumnView *self) +{ + return GTK_LIST_ITEM_WIDGET (self->header); +} + diff --git a/gtk/gtkcolumnviewcolumn.c b/gtk/gtkcolumnviewcolumn.c index c18cf7716e..0898c54548 100644 --- a/gtk/gtkcolumnviewcolumn.c +++ b/gtk/gtkcolumnviewcolumn.c @@ -21,6 +21,8 @@ #include "gtkcolumnviewcolumnprivate.h" +#include "gtkcolumnviewprivate.h" +#include "gtkcolumnviewtitleprivate.h" #include "gtkintl.h" #include "gtklistbaseprivate.h" #include "gtklistitemwidgetprivate.h" @@ -49,6 +51,7 @@ struct _GtkColumnViewColumn /* data for the view */ GtkColumnView *view; + GtkWidget *header; int minimum_size_request; int natural_size_request; @@ -291,6 +294,9 @@ gtk_column_view_column_queue_resize (GtkColumnViewColumn *self) self->minimum_size_request = -1; self->natural_size_request = -1; + if (self->header) + gtk_widget_queue_resize (self->header); + for (cell = self->first_cell; cell; cell = gtk_column_view_cell_get_next (cell)) { gtk_widget_queue_resize (GTK_WIDGET (cell)); @@ -307,8 +313,15 @@ gtk_column_view_column_measure (GtkColumnViewColumn *self, GtkColumnViewCell *cell; int min, nat, cell_min, cell_nat; - min = 0; - nat = 0; + if (self->header) + { + gtk_widget_measure (self->header, GTK_ORIENTATION_HORIZONTAL, -1, &min, &nat, NULL, NULL); + } + else + { + min = 0; + nat = 0; + } for (cell = self->first_cell; cell; cell = gtk_column_view_cell_get_next (cell)) { @@ -385,6 +398,30 @@ gtk_column_view_column_remove_cells (GtkColumnViewColumn *self) gtk_column_view_cell_remove (self->first_cell); } +static void +gtk_column_view_column_create_header (GtkColumnViewColumn *self) +{ + if (self->header != NULL) + return; + + self->header = gtk_column_view_title_new (self); + gtk_list_item_widget_add_child (gtk_column_view_get_header_widget (self->view), + self->header); + gtk_column_view_column_queue_resize (self); +} + +static void +gtk_column_view_column_remove_header (GtkColumnViewColumn *self) +{ + if (self->header == NULL) + return; + + gtk_list_item_widget_remove_child (gtk_column_view_get_header_widget (self->view), + self->header); + self->header = NULL; + gtk_column_view_column_queue_resize (self); +} + static void gtk_column_view_column_ensure_cells (GtkColumnViewColumn *self) { @@ -392,6 +429,11 @@ gtk_column_view_column_ensure_cells (GtkColumnViewColumn *self) gtk_column_view_column_create_cells (self); else gtk_column_view_column_remove_cells (self); + + if (self->view) + gtk_column_view_column_create_header (self); + else + gtk_column_view_column_remove_header (self); } /** @@ -419,10 +461,12 @@ gtk_column_view_column_set_column_view (GtkColumnViewColumn *self, if (self->view == view) return; + gtk_column_view_column_remove_cells (self); + gtk_column_view_column_remove_header (self); + self->view = view; - if (view) - gtk_column_view_column_ensure_cells (self); + gtk_column_view_column_ensure_cells (self); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLUMN_VIEW]); } @@ -486,6 +530,9 @@ gtk_column_view_column_set_title (GtkColumnViewColumn *self, g_free (self->title); self->title = g_strdup (title); + if (self->header) + gtk_column_view_title_update (GTK_COLUMN_VIEW_TITLE (self->header)); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TITLE]); } diff --git a/gtk/gtkcolumnviewlayout.c b/gtk/gtkcolumnviewlayout.c index 3afd6a2af3..c4ba28a112 100644 --- a/gtk/gtkcolumnviewlayout.c +++ b/gtk/gtkcolumnviewlayout.c @@ -24,6 +24,7 @@ #include "gtkcolumnviewcellprivate.h" #include "gtkcolumnviewcolumnprivate.h" #include "gtkcolumnviewprivate.h" +#include "gtkcolumnviewtitleprivate.h" #include "gtkwidgetprivate.h" struct _GtkColumnViewLayout @@ -113,10 +114,14 @@ gtk_column_view_layout_allocate (GtkLayoutManager *layout_manager, 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); + GtkColumnViewColumn *column; int col_x, col_width; + if (GTK_IS_COLUMN_VIEW_CELL (child)) + column = gtk_column_view_cell_get_column (GTK_COLUMN_VIEW_CELL (child)); + else + column = gtk_column_view_title_get_column (GTK_COLUMN_VIEW_TITLE (child)); + gtk_column_view_column_get_allocation (column, &col_x, &col_width); gtk_widget_size_allocate (child, &(GtkAllocation) { col_x, 0, col_width, height }, baseline); } diff --git a/gtk/gtkcolumnviewprivate.h b/gtk/gtkcolumnviewprivate.h index d95577fe98..c356fae508 100644 --- a/gtk/gtkcolumnviewprivate.h +++ b/gtk/gtkcolumnviewprivate.h @@ -22,6 +22,10 @@ #include "gtk/gtkcolumnview.h" +#include "gtk/gtklistitemwidgetprivate.h" + +GtkListItemWidget * gtk_column_view_get_header_widget (GtkColumnView *self); + void gtk_column_view_measure_across (GtkColumnView *self, int *minimum, int *natural); diff --git a/gtk/gtkcolumnviewtitle.c b/gtk/gtkcolumnviewtitle.c new file mode 100644 index 0000000000..7170018eb4 --- /dev/null +++ b/gtk/gtkcolumnviewtitle.c @@ -0,0 +1,142 @@ +/* + * 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 "gtkcolumnviewtitleprivate.h" + +#include "gtkcolumnviewcolumnprivate.h" +#include "gtkintl.h" +#include "gtklabel.h" +#include "gtkwidgetprivate.h" + +struct _GtkColumnViewTitle +{ + GtkWidget parent_instance; + + GtkColumnViewColumn *column; + + GtkWidget *title; +}; + +struct _GtkColumnViewTitleClass +{ + GtkWidgetClass parent_class; +}; + +G_DEFINE_TYPE (GtkColumnViewTitle, gtk_column_view_title, GTK_TYPE_WIDGET) + +static void +gtk_column_view_title_measure (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + GtkWidget *child = gtk_widget_get_first_child (widget); + + if (child) + gtk_widget_measure (child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline); +} + +static void +gtk_column_view_title_size_allocate (GtkWidget *widget, + int width, + int height, + int baseline) +{ + GtkWidget *child = gtk_widget_get_first_child (widget); + + if (child) + gtk_widget_allocate (child, width, height, baseline, NULL); +} + +static void +gtk_column_view_title_dispose (GObject *object) +{ + GtkColumnViewTitle *self = GTK_COLUMN_VIEW_TITLE (object); + + g_clear_pointer(&self->title, gtk_widget_unparent); + + g_clear_object (&self->column); + + G_OBJECT_CLASS (gtk_column_view_title_parent_class)->dispose (object); +} + +static void +gtk_column_view_title_class_init (GtkColumnViewTitleClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + widget_class->measure = gtk_column_view_title_measure; + widget_class->size_allocate = gtk_column_view_title_size_allocate; + + gobject_class->dispose = gtk_column_view_title_dispose; + + gtk_widget_class_set_css_name (widget_class, I_("button")); +} + +static void +gtk_column_view_title_resize_func (GtkWidget *widget) +{ + GtkColumnViewTitle *self = GTK_COLUMN_VIEW_TITLE (widget); + + if (self->column) + gtk_column_view_column_queue_resize (self->column); +} + +static void +gtk_column_view_title_init (GtkColumnViewTitle *self) +{ + GtkWidget *widget = GTK_WIDGET (self); + + widget->priv->resize_func = gtk_column_view_title_resize_func; + + self->title = gtk_label_new (NULL); + gtk_widget_set_parent (self->title, widget); +} + +GtkWidget * +gtk_column_view_title_new (GtkColumnViewColumn *column) +{ + GtkColumnViewTitle *title; + + title = g_object_new (GTK_TYPE_COLUMN_VIEW_TITLE, + NULL); + + title->column = g_object_ref (column); + gtk_column_view_title_update (title); + + return GTK_WIDGET (title); +} + +void +gtk_column_view_title_update (GtkColumnViewTitle *self) +{ + gtk_label_set_label (GTK_LABEL (self->title), gtk_column_view_column_get_title (self->column)); +} + +GtkColumnViewColumn * +gtk_column_view_title_get_column (GtkColumnViewTitle *self) +{ + return self->column; +} diff --git a/gtk/gtkcolumnviewtitleprivate.h b/gtk/gtkcolumnviewtitleprivate.h new file mode 100644 index 0000000000..84bc6a4050 --- /dev/null +++ b/gtk/gtkcolumnviewtitleprivate.h @@ -0,0 +1,47 @@ +/* + * 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_TITLE_PRIVATE_H__ +#define __GTK_COLUMN_VIEW_TITLE_PRIVATE_H__ + +#include "gtkcolumnviewcolumn.h" + +G_BEGIN_DECLS + +#define GTK_TYPE_COLUMN_VIEW_TITLE (gtk_column_view_title_get_type ()) +#define GTK_COLUMN_VIEW_TITLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_COLUMN_VIEW_TITLE, GtkColumnViewTitle)) +#define GTK_COLUMN_VIEW_TITLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_COLUMN_VIEW_TITLE, GtkColumnViewTitleClass)) +#define GTK_IS_COLUMN_VIEW_TITLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_COLUMN_VIEW_TITLE)) +#define GTK_IS_COLUMN_VIEW_TITLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_COLUMN_VIEW_TITLE)) +#define GTK_COLUMN_VIEW_TITLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_COLUMN_VIEW_TITLE, GtkColumnViewTitleClass)) + +typedef struct _GtkColumnViewTitle GtkColumnViewTitle; +typedef struct _GtkColumnViewTitleClass GtkColumnViewTitleClass; + +GType gtk_column_view_title_get_type (void) G_GNUC_CONST; + +GtkWidget * gtk_column_view_title_new (GtkColumnViewColumn *column); + +void gtk_column_view_title_update (GtkColumnViewTitle *self); + +GtkColumnViewColumn * gtk_column_view_title_get_column (GtkColumnViewTitle *self); + +G_END_DECLS + +#endif /* __GTK_COLUMN_VIEW_TITLE_PRIVATE_H__ */ diff --git a/gtk/meson.build b/gtk/meson.build index 105a81146b..ee4af20bf3 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -40,6 +40,7 @@ gtk_private_sources = files([ 'gtkcolumnlistitemfactory.c', 'gtkcolumnviewcell.c', 'gtkcolumnviewlayout.c', + 'gtkcolumnviewtitle.c', 'gtkconstraintexpression.c', 'gtkconstraintsolver.c', 'gtkconstraintvflparser.c',