From bea7d5d318697f9bf8f7c4828f8905df89b6265a Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Mon, 13 Mar 2023 05:04:29 +0100 Subject: [PATCH] columnview: Add GtkColumnViewRowWidget This is a copy/paste of GtkListItemWidget for now. Modifications will happen in future commits. --- gtk/gtkcolumnlistitemfactory.c | 10 +- gtk/gtkcolumnlistitemfactoryprivate.h | 6 +- gtk/gtkcolumnview.c | 10 +- gtk/gtkcolumnviewcolumn.c | 20 +-- gtk/gtkcolumnviewprivate.h | 10 +- gtk/gtkcolumnviewrowwidget.c | 167 ++++++++++++++++++++++++++ gtk/gtkcolumnviewrowwidgetprivate.h | 63 ++++++++++ gtk/meson.build | 1 + 8 files changed, 259 insertions(+), 28 deletions(-) create mode 100644 gtk/gtkcolumnviewrowwidget.c create mode 100644 gtk/gtkcolumnviewrowwidgetprivate.h diff --git a/gtk/gtkcolumnlistitemfactory.c b/gtk/gtkcolumnlistitemfactory.c index d36d911f14..cbf80b34be 100644 --- a/gtk/gtkcolumnlistitemfactory.c +++ b/gtk/gtkcolumnlistitemfactory.c @@ -49,7 +49,7 @@ gtk_column_list_item_factory_setup (GtkListItemFactory *factory, gpointer data) { GtkColumnListItemFactory *self = GTK_COLUMN_LIST_ITEM_FACTORY (factory); - GtkListItemWidget *widget = data; + GtkColumnViewRowWidget *widget = data; GListModel *columns; guint i; @@ -82,14 +82,14 @@ gtk_column_list_item_factory_teardown (GtkListItemFactory *factory, GFunc func, gpointer data) { - GtkListItemWidget *widget = data; + GtkColumnViewRowWidget *widget = data; GtkWidget *child; GTK_LIST_ITEM_FACTORY_CLASS (gtk_column_list_item_factory_parent_class)->teardown (factory, item, unbind, func, data); while ((child = gtk_widget_get_first_child (GTK_WIDGET (widget)))) { - gtk_list_item_widget_remove_child (GTK_LIST_ITEM_WIDGET (widget), child); + gtk_column_view_row_widget_remove_child (GTK_COLUMN_VIEW_ROW_WIDGET (widget), child); } } @@ -165,7 +165,7 @@ gtk_column_list_item_factory_new (GtkColumnView *view) void gtk_column_list_item_factory_add_column (GtkColumnListItemFactory *factory, - GtkListItemWidget *list_item, + GtkColumnViewRowWidget *list_item, GtkColumnViewColumn *column, gboolean check_bind) { @@ -173,7 +173,7 @@ gtk_column_list_item_factory_add_column (GtkColumnListItemFactory *factory, GtkWidget *cell; cell = gtk_column_view_cell_new (column); - gtk_list_item_widget_add_child (GTK_LIST_ITEM_WIDGET (list_item), GTK_WIDGET (cell)); + gtk_column_view_row_widget_add_child (GTK_COLUMN_VIEW_ROW_WIDGET (list_item), GTK_WIDGET (cell)); gtk_list_item_base_update (GTK_LIST_ITEM_BASE (cell), gtk_list_item_base_get_position (base), gtk_list_item_base_get_item (base), diff --git a/gtk/gtkcolumnlistitemfactoryprivate.h b/gtk/gtkcolumnlistitemfactoryprivate.h index acddf2f56e..320502b4e5 100644 --- a/gtk/gtkcolumnlistitemfactoryprivate.h +++ b/gtk/gtkcolumnlistitemfactoryprivate.h @@ -20,8 +20,8 @@ #ifndef __GTK_COLUMN_LIST_ITEM_FACTORY_H__ #define __GTK_COLUMN_LIST_ITEM_FACTORY_H__ -#include #include +#include G_BEGIN_DECLS @@ -47,12 +47,12 @@ GtkColumnListItemFactory * gtk_column_list_item_factory_new (GtkColumnView *view); void gtk_column_list_item_factory_add_column (GtkColumnListItemFactory *factory, - GtkListItemWidget *list_item, + GtkColumnViewRowWidget *list_item, GtkColumnViewColumn *column, gboolean check_bind); void gtk_column_list_item_factory_remove_column (GtkColumnListItemFactory *factory, - GtkListItemWidget *list_item, + GtkColumnViewRowWidget *list_item, guint col_pos, GtkColumnViewColumn *column); diff --git a/gtk/gtkcolumnview.c b/gtk/gtkcolumnview.c index ba1be8f42e..46878f5bbe 100644 --- a/gtk/gtkcolumnview.c +++ b/gtk/gtkcolumnview.c @@ -142,7 +142,7 @@ gtk_column_list_view_create_list_widget (GtkListBase *base) GtkListView *self = GTK_LIST_VIEW (base); GtkWidget *result; - result = gtk_list_item_widget_new (self->factory, + result = gtk_column_view_row_widget_new (self->factory, "row", GTK_ACCESSIBLE_ROLE_ROW); @@ -924,7 +924,7 @@ gtk_column_view_in_header (GtkColumnView *self, GtkWidget *header; graphene_rect_t rect; -header = gtk_column_view_column_get_header (column); + header = gtk_column_view_column_get_header (column); if (!gtk_widget_compute_bounds (header, self->header, &rect)) return FALSE; @@ -1288,7 +1288,7 @@ 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_ACCESSIBLE_ROLE_ROW); + self->header = gtk_column_view_row_widget_new (NULL, "header", GTK_ACCESSIBLE_ROLE_ROW); 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)); @@ -1640,10 +1640,10 @@ gtk_column_view_measure_across (GtkColumnView *self, *natural = nat; } -GtkListItemWidget * +GtkColumnViewRowWidget * gtk_column_view_get_header_widget (GtkColumnView *self) { - return GTK_LIST_ITEM_WIDGET (self->header); + return GTK_COLUMN_VIEW_ROW_WIDGET (self->header); } GtkListView * diff --git a/gtk/gtkcolumnviewcolumn.c b/gtk/gtkcolumnviewcolumn.c index 58432d7a33..beb88fd95c 100644 --- a/gtk/gtkcolumnviewcolumn.c +++ b/gtk/gtkcolumnviewcolumn.c @@ -23,9 +23,9 @@ #include "gtkcolumnviewsorterprivate.h" #include "gtkcolumnviewprivate.h" +#include "gtkcolumnviewrowwidgetprivate.h" #include "gtkcolumnviewtitleprivate.h" #include "gtklistbaseprivate.h" -#include "gtklistitemwidgetprivate.h" #include "gtkmain.h" #include "gtkprivate.h" #include "gtkrbtreeprivate.h" @@ -528,17 +528,17 @@ gtk_column_view_column_create_cells (GtkColumnViewColumn *self) row != NULL; row = gtk_widget_get_next_sibling (row)) { - GtkListItemWidget *list_item; + GtkColumnViewRowWidget *list_item; GtkListItemBase *base; GtkWidget *cell; if (!gtk_widget_get_root (row)) continue; - list_item = GTK_LIST_ITEM_WIDGET (row); + list_item = GTK_COLUMN_VIEW_ROW_WIDGET (row); base = GTK_LIST_ITEM_BASE (row); cell = gtk_column_view_cell_new (self); - gtk_list_item_widget_add_child (list_item, cell); + gtk_column_view_row_widget_add_child (list_item, cell); gtk_list_item_base_update (GTK_LIST_ITEM_BASE (cell), gtk_list_item_base_get_position (base), gtk_list_item_base_get_item (base), @@ -561,7 +561,7 @@ gtk_column_view_column_create_header (GtkColumnViewColumn *self) self->header = gtk_column_view_title_new (self); gtk_widget_set_visible (self->header, self->visible); - gtk_list_item_widget_add_child (gtk_column_view_get_header_widget (self->view), + gtk_column_view_row_widget_add_child (gtk_column_view_get_header_widget (self->view), self->header); gtk_column_view_column_queue_resize (self); } @@ -572,7 +572,7 @@ 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), + gtk_column_view_row_widget_remove_child (gtk_column_view_get_header_widget (self->view), self->header); self->header = NULL; gtk_column_view_column_queue_resize (self); @@ -634,16 +634,16 @@ gtk_column_view_column_set_position (GtkColumnViewColumn *self, { GtkColumnViewCell *cell; - gtk_list_item_widget_reorder_child (gtk_column_view_get_header_widget (self->view), + gtk_column_view_row_widget_reorder_child (gtk_column_view_get_header_widget (self->view), self->header, position); for (cell = self->first_cell; cell; cell = gtk_column_view_cell_get_next (cell)) { - GtkListItemWidget *list_item; + GtkColumnViewRowWidget *list_item; - list_item = GTK_LIST_ITEM_WIDGET (gtk_widget_get_parent (GTK_WIDGET (cell))); - gtk_list_item_widget_reorder_child (list_item, GTK_WIDGET (cell), position); + list_item = GTK_COLUMN_VIEW_ROW_WIDGET (gtk_widget_get_parent (GTK_WIDGET (cell))); + gtk_column_view_row_widget_reorder_child (list_item, GTK_WIDGET (cell), position); } } diff --git a/gtk/gtkcolumnviewprivate.h b/gtk/gtkcolumnviewprivate.h index 2d080b9aa5..a1433a8dbb 100644 --- a/gtk/gtkcolumnviewprivate.h +++ b/gtk/gtkcolumnviewprivate.h @@ -25,17 +25,17 @@ #include "gtk/gtksizerequest.h" #include "gtk/gtkcolumnviewsorterprivate.h" -#include "gtk/gtklistitemwidgetprivate.h" +#include "gtk/gtkcolumnviewrowwidgetprivate.h" -GtkListItemWidget * gtk_column_view_get_header_widget (GtkColumnView *self); +GtkColumnViewRowWidget *gtk_column_view_get_header_widget (GtkColumnView *self); GtkListView * gtk_column_view_get_list_view (GtkColumnView *self); void gtk_column_view_measure_across (GtkColumnView *self, int *minimum, int *natural); -void gtk_column_view_distribute_width (GtkColumnView *self, - int width, - GtkRequestedSize *sizes); +void gtk_column_view_distribute_width (GtkColumnView *self, + int width, + GtkRequestedSize *sizes); #endif /* __GTK_COLUMN_VIEW_PRIVATE_H__ */ diff --git a/gtk/gtkcolumnviewrowwidget.c b/gtk/gtkcolumnviewrowwidget.c new file mode 100644 index 0000000000..06a57b9d11 --- /dev/null +++ b/gtk/gtkcolumnviewrowwidget.c @@ -0,0 +1,167 @@ +/* + * Copyright © 2018 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 "gtkcolumnviewrowwidgetprivate.h" + +#include "gtkbinlayout.h" +#include "gtklistitemfactoryprivate.h" +#include "gtklistbaseprivate.h" +#include "gtkwidget.h" +#include "gtkwidgetprivate.h" + +G_DEFINE_TYPE (GtkColumnViewRowWidget, gtk_column_view_row_widget, GTK_TYPE_LIST_FACTORY_WIDGET) + +static gboolean +gtk_column_view_row_widget_focus (GtkWidget *widget, + GtkDirectionType direction) +{ + GtkWidget *child, *focus_child; + + /* The idea of this function is the following: + * 1. If any child can take focus, do not ever attempt + * to take focus. + * 2. Otherwise, if this item is selectable or activatable, + * allow focusing this widget. + * + * This makes sure every item in a list is focusable for + * activation and selection handling, but no useless widgets + * get focused and moving focus is as fast as possible. + */ + + focus_child = gtk_widget_get_focus_child (widget); + if (focus_child && gtk_widget_child_focus (focus_child, direction)) + return TRUE; + + for (child = focus_child ? gtk_widget_get_next_sibling (focus_child) + : gtk_widget_get_first_child (widget); + child; + child = gtk_widget_get_next_sibling (child)) + { + if (gtk_widget_child_focus (child, direction)) + return TRUE; + } + + if (focus_child) + return FALSE; + + if (gtk_widget_is_focus (widget)) + return FALSE; + + return gtk_widget_grab_focus (widget); +} + +static gboolean +gtk_column_view_row_widget_grab_focus (GtkWidget *widget) +{ + GtkWidget *child; + + for (child = gtk_widget_get_first_child (widget); + child; + child = gtk_widget_get_next_sibling (child)) + { + if (gtk_widget_grab_focus (child)) + return TRUE; + } + + if (!gtk_list_factory_widget_get_selectable (GTK_LIST_FACTORY_WIDGET (widget))) + return FALSE; + + return GTK_WIDGET_CLASS (gtk_column_view_row_widget_parent_class)->grab_focus (widget); +} + +static void +gtk_column_view_row_widget_class_init (GtkColumnViewRowWidgetClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + widget_class->focus = gtk_column_view_row_widget_focus; + widget_class->grab_focus = gtk_column_view_row_widget_grab_focus; + + /* This gets overwritten by gtk_column_view_row_widget_new() but better safe than sorry */ + gtk_widget_class_set_css_name (widget_class, I_("row")); + gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT); +} + +static void +gtk_column_view_row_widget_init (GtkColumnViewRowWidget *self) +{ + gtk_widget_set_focusable (GTK_WIDGET (self), TRUE); +} + +GtkWidget * +gtk_column_view_row_widget_new (GtkListItemFactory *factory, + const char *css_name, + GtkAccessibleRole role) +{ + g_return_val_if_fail (css_name != NULL, NULL); + + return g_object_new (GTK_TYPE_COLUMN_VIEW_ROW_WIDGET, + "css-name", css_name, + "accessible-role", role, + "factory", factory, + "selectable", TRUE, + "activatable", TRUE, + NULL); +} + +void +gtk_column_view_row_widget_add_child (GtkColumnViewRowWidget *self, + GtkWidget *child) +{ + gtk_widget_set_parent (child, GTK_WIDGET (self)); +} + +void +gtk_column_view_row_widget_reorder_child (GtkColumnViewRowWidget *self, + GtkWidget *child, + guint position) +{ + GtkWidget *widget = GTK_WIDGET (self); + GtkWidget *sibling = NULL; + + if (position > 0) + { + GtkWidget *c; + guint i; + + for (c = gtk_widget_get_first_child (widget), i = 0; + c; + c = gtk_widget_get_next_sibling (c), i++) + { + if (i + 1 == position) + { + sibling = c; + break; + } + } + } + + if (child != sibling) + gtk_widget_insert_after (child, widget, sibling); +} + +void +gtk_column_view_row_widget_remove_child (GtkColumnViewRowWidget *self, + GtkWidget *child) +{ + gtk_widget_unparent (child); +} + diff --git a/gtk/gtkcolumnviewrowwidgetprivate.h b/gtk/gtkcolumnviewrowwidgetprivate.h new file mode 100644 index 0000000000..b4ea9b2413 --- /dev/null +++ b/gtk/gtkcolumnviewrowwidgetprivate.h @@ -0,0 +1,63 @@ +/* + * Copyright © 2018 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_ROW_WIDGET_PRIVATE_H__ +#define __GTK_COLUMN_VIEW_ROW_WIDGET_PRIVATE_H__ + +#include "gtklistfactorywidgetprivate.h" + +G_BEGIN_DECLS + +#define GTK_TYPE_COLUMN_VIEW_ROW_WIDGET (gtk_column_view_row_widget_get_type ()) +#define GTK_COLUMN_VIEW_ROW_WIDGET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_COLUMN_VIEW_ROW_WIDGET, GtkColumnViewRowWidget)) +#define GTK_COLUMN_VIEW_ROW_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_COLUMN_VIEW_ROW_WIDGET, GtkColumnViewRowWidgetClass)) +#define GTK_IS_COLUMN_VIEW_ROW_WIDGET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_COLUMN_VIEW_ROW_WIDGET)) +#define GTK_IS_COLUMN_VIEW_ROW_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_COLUMN_VIEW_ROW_WIDGET)) +#define GTK_COLUMN_VIEW_ROW_WIDGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_COLUMN_VIEW_ROW_WIDGET, GtkColumnViewRowWidgetClass)) + +typedef struct _GtkColumnViewRowWidget GtkColumnViewRowWidget; +typedef struct _GtkColumnViewRowWidgetClass GtkColumnViewRowWidgetClass; + +struct _GtkColumnViewRowWidget +{ + GtkListFactoryWidget parent_instance; +}; + +struct _GtkColumnViewRowWidgetClass +{ + GtkListFactoryWidgetClass parent_class; +}; + +GType gtk_column_view_row_widget_get_type (void) G_GNUC_CONST; + +GtkWidget * gtk_column_view_row_widget_new (GtkListItemFactory *factory, + const char *css_name, + GtkAccessibleRole role); + +void gtk_column_view_row_widget_add_child (GtkColumnViewRowWidget *self, + GtkWidget *child); +void gtk_column_view_row_widget_reorder_child (GtkColumnViewRowWidget *self, + GtkWidget *child, + guint position); +void gtk_column_view_row_widget_remove_child (GtkColumnViewRowWidget *self, + GtkWidget *child); + +G_END_DECLS + +#endif /* __GTK_COLUMN_VIEW_ROW_WIDGET_PRIVATE_H__ */ diff --git a/gtk/meson.build b/gtk/meson.build index c22900ff60..c43a916847 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -40,6 +40,7 @@ gtk_private_sources = files([ 'gtkcolorswatch.c', 'gtkcolumnlistitemfactory.c', 'gtkcolumnviewcell.c', + 'gtkcolumnviewrowwidget.c', 'gtkcolumnviewlayout.c', 'gtkcolumnviewtitle.c', 'gtkconstraintexpression.c',