summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte.benjamin@googlemail.com>2023-04-01 19:33:00 +0000
committerBenjamin Otte <otte.benjamin@googlemail.com>2023-04-01 19:33:00 +0000
commit378df6556b36a9f74ac3095e0445a0c726cd3e0a (patch)
treeae8205922f97e1400edc946ba70f11b0cd8c04b0
parent60921db76f05177a8d3795314bd50a3fc2248c77 (diff)
parent40869137959e7058bb86302a0931f28db4f7df12 (diff)
downloadgtk+-378df6556b36a9f74ac3095e0445a0c726cd3e0a.tar.gz
Merge branch 'wip/otte/listitem-focus' into 'main'
GtkColumnView factories and focus rework See merge request GNOME/gtk!5728
-rw-r--r--demos/gtk-demo/listview_settings.c9
-rw-r--r--demos/gtk-demo/listview_settings.ui24
-rw-r--r--demos/gtk-demo/main-listitem.ui1
-rw-r--r--gtk/gtk.h2
-rw-r--r--gtk/gtkbuilder.c27
-rw-r--r--gtk/gtkbuilderlistitemfactory.c1
-rw-r--r--gtk/gtkbuilderparser.c14
-rw-r--r--gtk/gtkbuilderprivate.h5
-rw-r--r--gtk/gtkcolumnview.c278
-rw-r--r--gtk/gtkcolumnview.h7
-rw-r--r--gtk/gtkcolumnviewcell.c495
-rw-r--r--gtk/gtkcolumnviewcell.h54
-rw-r--r--gtk/gtkcolumnviewcellprivate.h34
-rw-r--r--gtk/gtkcolumnviewcellwidget.c411
-rw-r--r--gtk/gtkcolumnviewcellwidgetprivate.h50
-rw-r--r--gtk/gtkcolumnviewcolumn.c61
-rw-r--r--gtk/gtkcolumnviewcolumnprivate.h10
-rw-r--r--gtk/gtkcolumnviewprivate.h2
-rw-r--r--gtk/gtkcolumnviewrow.c477
-rw-r--r--gtk/gtkcolumnviewrow.h57
-rw-r--r--gtk/gtkcolumnviewrowprivate.h48
-rw-r--r--gtk/gtkcolumnviewrowwidget.c273
-rw-r--r--gtk/gtkcolumnviewrowwidgetprivate.h3
-rw-r--r--gtk/gtkcolumnviewtitle.c48
-rw-r--r--gtk/gtkfilechooserwidget.c18
-rw-r--r--gtk/gtklistitem.c122
-rw-r--r--gtk/gtklistitem.h20
-rw-r--r--gtk/gtklistitemprivate.h11
-rw-r--r--gtk/gtklistitemwidget.c91
-rw-r--r--gtk/gtktreeexpander.c5
-rw-r--r--gtk/meson.build6
-rw-r--r--gtk/ui/gtkfilechooserwidget.ui49
-rw-r--r--po/POTFILES.in2
-rw-r--r--tests/testcolumnview.c16
-rw-r--r--tests/testdatatable.c34
35 files changed, 2221 insertions, 544 deletions
diff --git a/demos/gtk-demo/listview_settings.c b/demos/gtk-demo/listview_settings.c
index fc484f3f45..4e8e69bfbf 100644
--- a/demos/gtk-demo/listview_settings.c
+++ b/demos/gtk-demo/listview_settings.c
@@ -148,9 +148,9 @@ settings_key_new (GSettings *settings,
}
static void
-item_value_changed (GtkEditableLabel *label,
- GParamSpec *pspec,
- GtkListItem *item)
+item_value_changed (GtkEditableLabel *label,
+ GParamSpec *pspec,
+ GtkColumnViewCell *cell)
{
SettingsKey *self;
const char *text;
@@ -162,8 +162,7 @@ item_value_changed (GtkEditableLabel *label,
text = gtk_editable_get_text (GTK_EDITABLE (label));
- g_object_get (item, "item", &self, NULL);
- g_object_unref (self);
+ self = gtk_column_view_cell_get_item (cell);
type = g_settings_schema_key_get_value_type (self->key);
name = g_settings_schema_key_get_name (self->key);
diff --git a/demos/gtk-demo/listview_settings.ui b/demos/gtk-demo/listview_settings.ui
index 15cbb67d9e..49080e5df2 100644
--- a/demos/gtk-demo/listview_settings.ui
+++ b/demos/gtk-demo/listview_settings.ui
@@ -90,13 +90,13 @@
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <template class="GtkListItem">
+ <template class="GtkColumnViewCell">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="name" type="SettingsKey">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</lookup>
</binding>
</object>
@@ -118,12 +118,12 @@
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <template class="GtkListItem">
+ <template class="GtkColumnViewCell">
<property name="child">
<object class="GtkEditableLabel">
<binding name="text">
<lookup name="value" type="SettingsKey">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</lookup>
</binding>
<signal name="notify::label" handler="item_value_changed"/>
@@ -146,13 +146,13 @@
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <template class="GtkListItem">
+ <template class="GtkColumnViewCell">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="type" type="SettingsKey">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</lookup>
</binding>
</object>
@@ -175,13 +175,13 @@
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <template class="GtkListItem">
+ <template class="GtkColumnViewCell">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="default-value" type="SettingsKey">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</lookup>
</binding>
</object>
@@ -205,14 +205,14 @@
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <template class="GtkListItem">
+ <template class="GtkColumnViewCell">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<property name="wrap">1</property>
<binding name="label">
<lookup name="summary" type="SettingsKey">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</lookup>
</binding>
</object>
@@ -236,14 +236,14 @@
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <template class="GtkListItem">
+ <template class="GtkColumnViewCell">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<property name="wrap">1</property>
<binding name="label">
<lookup name="description" type="SettingsKey">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</lookup>
</binding>
</object>
diff --git a/demos/gtk-demo/main-listitem.ui b/demos/gtk-demo/main-listitem.ui
index aab22e3e20..b3427611ed 100644
--- a/demos/gtk-demo/main-listitem.ui
+++ b/demos/gtk-demo/main-listitem.ui
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
+ <property name="focusable">0</property>
<property name="child">
<object class="GtkTreeExpander" id="expander">
<binding name="list-row">
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 14550f65f9..a3973437f3 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -86,7 +86,9 @@
#include <gtk/gtkcolordialogbutton.h>
#include <gtk/gtkcolorutils.h>
#include <gtk/gtkcolumnview.h>
+#include <gtk/gtkcolumnviewcell.h>
#include <gtk/gtkcolumnviewcolumn.h>
+#include <gtk/gtkcolumnviewrow.h>
#include <gtk/gtkcolumnviewsorter.h>
#include <gtk/deprecated/gtkcombobox.h>
#include <gtk/deprecated/gtkcomboboxtext.h>
diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c
index fd221f79c8..8171cb8bf9 100644
--- a/gtk/gtkbuilder.c
+++ b/gtk/gtkbuilder.c
@@ -264,6 +264,7 @@ typedef struct
char *filename;
char *resource_prefix;
GType template_type;
+ gboolean allow_template_parents;
GObject *current_object;
GtkBuilderScope *scope;
} GtkBuilderPrivate;
@@ -1334,6 +1335,15 @@ gtk_builder_add_objects_from_file (GtkBuilder *builder,
return TRUE;
}
+void
+gtk_builder_set_allow_template_parents (GtkBuilder *builder,
+ gboolean allow_parents)
+{
+ GtkBuilderPrivate *priv = gtk_builder_get_instance_private (builder);
+
+ priv->allow_template_parents = allow_parents;
+}
+
/**
* gtk_builder_extend_with_template:
* @builder: a `GtkBuilder`
@@ -1385,6 +1395,18 @@ gtk_builder_extend_with_template (GtkBuilder *builder,
name = g_type_name (template_type);
if (gtk_builder_get_object (builder, name) != object)
gtk_builder_expose_object (builder, name, object);
+ if (priv->allow_template_parents)
+ {
+ GType subtype;
+ for (subtype = g_type_parent (template_type);
+ subtype != G_TYPE_OBJECT;
+ subtype = g_type_parent (subtype))
+ {
+ name = g_type_name (subtype);
+ if (gtk_builder_get_object (builder, name) != object)
+ gtk_builder_expose_object (builder, name, object);
+ }
+ }
filename = g_strconcat ("<", name, " template>", NULL);
_gtk_builder_parser_parse_buffer (builder, filename,
@@ -2815,10 +2837,13 @@ _gtk_builder_get_absolute_filename (GtkBuilder *builder,
}
GType
-_gtk_builder_get_template_type (GtkBuilder *builder)
+gtk_builder_get_template_type (GtkBuilder *builder,
+ gboolean *out_allow_parents)
{
GtkBuilderPrivate *priv = gtk_builder_get_instance_private (builder);
+ *out_allow_parents = priv->allow_template_parents;
+
return priv->template_type;
}
diff --git a/gtk/gtkbuilderlistitemfactory.c b/gtk/gtkbuilderlistitemfactory.c
index cf3f59abaf..de4cf42172 100644
--- a/gtk/gtkbuilderlistitemfactory.c
+++ b/gtk/gtkbuilderlistitemfactory.c
@@ -101,6 +101,7 @@ gtk_builder_list_item_factory_setup (GtkListItemFactory *factory,
if (self->scope)
gtk_builder_set_scope (builder, self->scope);
+ gtk_builder_set_allow_template_parents (builder, TRUE);
if (!gtk_builder_extend_with_template (builder, G_OBJECT (item), G_OBJECT_TYPE (item),
(const char *)g_bytes_get_data (self->data, NULL),
g_bytes_get_size (self->data),
diff --git a/gtk/gtkbuilderparser.c b/gtk/gtkbuilderparser.c
index a1a7bd68c0..d4f1f66f5e 100644
--- a/gtk/gtkbuilderparser.c
+++ b/gtk/gtkbuilderparser.c
@@ -697,11 +697,11 @@ parse_template (GtkBuildableParseContext *context,
const char *parent_class = NULL;
int line;
gpointer line_ptr;
- gboolean has_duplicate;
+ gboolean has_duplicate, allow_parents;
GType template_type;
GType parsed_type;
- template_type = _gtk_builder_get_template_type (data->builder);
+ template_type = gtk_builder_get_template_type (data->builder, &allow_parents);
if (!g_markup_collect_attributes (element_name, names, values, error,
G_MARKUP_COLLECT_STRING, "class", &object_class,
@@ -729,7 +729,8 @@ parse_template (GtkBuildableParseContext *context,
}
parsed_type = g_type_from_name (object_class);
- if (template_type != parsed_type)
+ if (template_type != parsed_type &&
+ (!allow_parents || !g_type_is_a (template_type, parsed_type)))
{
g_set_error (error,
GTK_BUILDER_ERROR,
@@ -768,10 +769,11 @@ parse_template (GtkBuildableParseContext *context,
object_info = g_new0 (ObjectInfo, 1);
object_info->tag_type = TAG_TEMPLATE;
- object_info->type = parsed_type;
- object_info->oclass = g_type_class_ref (parsed_type);
- object_info->id = g_strdup (object_class);
object_info->object = gtk_builder_get_object (data->builder, object_class);
+ object_info->type = template_type;
+ object_info->oclass = g_type_class_ref (template_type);
+ object_info->id = g_strdup (object_class);
+ g_assert (object_info->object);
state_push (data, object_info);
has_duplicate = g_hash_table_lookup_extended (data->object_ids, object_class, NULL, &line_ptr);
diff --git a/gtk/gtkbuilderprivate.h b/gtk/gtkbuilderprivate.h
index 7e717eaf2a..218e33628a 100644
--- a/gtk/gtkbuilderprivate.h
+++ b/gtk/gtkbuilderprivate.h
@@ -264,7 +264,10 @@ void _gtk_builder_menu_start (ParserData *parser_data,
GError **error);
void _gtk_builder_menu_end (ParserData *parser_data);
-GType _gtk_builder_get_template_type (GtkBuilder *builder);
+GType gtk_builder_get_template_type (GtkBuilder *builder,
+ gboolean *out_allow_parents);
+void gtk_builder_set_allow_template_parents (GtkBuilder *builder,
+ gboolean allow_parents);
void _gtk_builder_prefix_error (GtkBuilder *builder,
GtkBuildableParseContext *context,
diff --git a/gtk/gtkcolumnview.c b/gtk/gtkcolumnview.c
index b79ae627e9..5437d684c4 100644
--- a/gtk/gtkcolumnview.c
+++ b/gtk/gtkcolumnview.c
@@ -113,6 +113,45 @@
* some parameters for item creation.
*/
+struct _GtkColumnView
+{
+ GtkWidget parent_instance;
+
+ GListStore *columns;
+
+ GtkColumnViewColumn *focus_column;
+
+ GtkWidget *header;
+
+ GtkListView *listview;
+
+ GtkSorter *sorter;
+
+ GtkAdjustment *hadjustment;
+
+ guint reorderable : 1;
+ guint show_column_separators : 1;
+ guint in_column_resize : 1;
+ guint in_column_reorder : 1;
+
+ int drag_pos;
+ int drag_x;
+ int drag_offset;
+ int drag_column_x;
+
+ guint autoscroll_id;
+ double autoscroll_x;
+ double autoscroll_delta;
+
+ GtkGesture *drag_gesture;
+};
+
+struct _GtkColumnViewClass
+{
+ GtkWidgetClass parent_class;
+};
+
+
#define GTK_TYPE_COLUMN_LIST_VIEW (gtk_column_list_view_get_type ())
G_DECLARE_FINAL_TYPE (GtkColumnListView, gtk_column_list_view, GTK, COLUMN_LIST_VIEW, GtkListView)
@@ -136,12 +175,28 @@ gtk_column_list_view_init (GtkColumnListView *view)
static GtkListItemBase *
gtk_column_list_view_create_list_widget (GtkListBase *base)
{
- GtkListView *self = GTK_LIST_VIEW (base);
+ GtkColumnView *self = GTK_COLUMN_VIEW (gtk_widget_get_parent (GTK_WIDGET (base)));
GtkWidget *result;
+ guint i;
- result = gtk_column_view_row_widget_new (FALSE);
+ result = gtk_column_view_row_widget_new (gtk_list_view_get_factory (self->listview), FALSE);
- gtk_list_factory_widget_set_single_click_activate (GTK_LIST_FACTORY_WIDGET (result), self->single_click_activate);
+ gtk_list_factory_widget_set_single_click_activate (GTK_LIST_FACTORY_WIDGET (result), GTK_LIST_VIEW (base)->single_click_activate);
+
+ for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->columns)); i++)
+ {
+ GtkColumnViewColumn *column = g_list_model_get_item (G_LIST_MODEL (self->columns), i);
+
+ if (gtk_column_view_column_get_visible (column))
+ {
+ GtkWidget *cell;
+
+ cell = gtk_column_view_cell_widget_new (column, gtk_column_view_is_inert (self));
+ gtk_column_view_row_widget_add_child (GTK_COLUMN_VIEW_ROW_WIDGET (result), cell);
+ }
+
+ g_object_unref (column);
+ }
return GTK_LIST_ITEM_BASE (result);
}
@@ -159,44 +214,6 @@ gtk_column_list_view_class_init (GtkColumnListViewClass *klass)
}
-struct _GtkColumnView
-{
- GtkWidget parent_instance;
-
- GListStore *columns;
-
- GtkColumnViewColumn *focus_column;
-
- GtkWidget *header;
-
- GtkListView *listview;
-
- GtkSorter *sorter;
-
- GtkAdjustment *hadjustment;
-
- guint reorderable : 1;
- guint show_column_separators : 1;
- guint in_column_resize : 1;
- guint in_column_reorder : 1;
-
- int drag_pos;
- int drag_x;
- int drag_offset;
- int drag_column_x;
-
- guint autoscroll_id;
- double autoscroll_x;
- double autoscroll_delta;
-
- GtkGesture *drag_gesture;
-};
-
-struct _GtkColumnViewClass
-{
- GtkWidgetClass parent_class;
-};
-
enum
{
PROP_0,
@@ -206,6 +223,7 @@ enum
PROP_HSCROLL_POLICY,
PROP_MODEL,
PROP_REORDERABLE,
+ PROP_ROW_FACTORY,
PROP_SHOW_ROW_SEPARATORS,
PROP_SHOW_COLUMN_SEPARATORS,
PROP_SINGLE_CLICK_ACTIVATE,
@@ -280,6 +298,31 @@ G_DEFINE_TYPE_WITH_CODE (GtkColumnView, gtk_column_view, GTK_TYPE_WIDGET,
static GParamSpec *properties[N_PROPS] = { NULL, };
static guint signals[LAST_SIGNAL] = { 0 };
+gboolean
+gtk_column_view_is_inert (GtkColumnView *self)
+{
+ GtkWidget *widget = GTK_WIDGET (self);
+
+ return !gtk_widget_get_visible (widget) ||
+ gtk_widget_get_root (widget) == NULL;
+}
+
+static void
+gtk_column_view_update_cell_factories (GtkColumnView *self,
+ gboolean inert)
+{
+ guint i, n;
+
+ n = g_list_model_get_n_items (G_LIST_MODEL (self->columns));
+
+ for (i = 0; i < n; i++)
+ {
+ GtkColumnViewColumn *column = g_list_model_get_item (G_LIST_MODEL (self->columns), i);
+
+ gtk_column_view_column_update_factory (column, inert);
+ }
+}
+
static void
gtk_column_view_measure (GtkWidget *widget,
GtkOrientation orientation,
@@ -459,6 +502,50 @@ gtk_column_view_allocate (GtkWidget *widget,
}
static void
+gtk_column_view_root (GtkWidget *widget)
+{
+ GtkColumnView *self = GTK_COLUMN_VIEW (widget);
+
+ GTK_WIDGET_CLASS (gtk_column_view_parent_class)->root (widget);
+
+ if (!gtk_column_view_is_inert (self))
+ gtk_column_view_update_cell_factories (self, FALSE);
+}
+
+static void
+gtk_column_view_unroot (GtkWidget *widget)
+{
+ GtkColumnView *self = GTK_COLUMN_VIEW (widget);
+
+ if (!gtk_column_view_is_inert (self))
+ gtk_column_view_update_cell_factories (self, TRUE);
+
+ GTK_WIDGET_CLASS (gtk_column_view_parent_class)->unroot (widget);
+}
+
+static void
+gtk_column_view_show (GtkWidget *widget)
+{
+ GtkColumnView *self = GTK_COLUMN_VIEW (widget);
+
+ GTK_WIDGET_CLASS (gtk_column_view_parent_class)->show (widget);
+
+ if (!gtk_column_view_is_inert (self))
+ gtk_column_view_update_cell_factories (self, FALSE);
+}
+
+static void
+gtk_column_view_hide (GtkWidget *widget)
+{
+ GtkColumnView *self = GTK_COLUMN_VIEW (widget);
+
+ if (!gtk_column_view_is_inert (self))
+ gtk_column_view_update_cell_factories (self, TRUE);
+
+ GTK_WIDGET_CLASS (gtk_column_view_parent_class)->hide (widget);
+}
+
+static void
gtk_column_view_activate_cb (GtkListView *listview,
guint pos,
GtkColumnView *self)
@@ -549,6 +636,14 @@ gtk_column_view_get_property (GObject *object,
g_value_set_object (value, gtk_list_view_get_model (self->listview));
break;
+ case PROP_REORDERABLE:
+ g_value_set_boolean (value, gtk_column_view_get_reorderable (self));
+ break;
+
+ case PROP_ROW_FACTORY:
+ g_value_set_object (value, gtk_column_view_get_row_factory (self));
+ break;
+
case PROP_SHOW_ROW_SEPARATORS:
g_value_set_boolean (value, gtk_list_view_get_show_separators (self->listview));
break;
@@ -573,10 +668,6 @@ gtk_column_view_get_property (GObject *object,
g_value_set_boolean (value, gtk_column_view_get_single_click_activate (self));
break;
- case PROP_REORDERABLE:
- g_value_set_boolean (value, gtk_column_view_get_reorderable (self));
- break;
-
case PROP_TAB_BEHAVIOR:
g_value_set_enum (value, gtk_list_view_get_tab_behavior (self->listview));
break;
@@ -632,6 +723,14 @@ gtk_column_view_set_property (GObject *object,
gtk_column_view_set_model (self, g_value_get_object (value));
break;
+ case PROP_REORDERABLE:
+ gtk_column_view_set_reorderable (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_ROW_FACTORY:
+ gtk_column_view_set_row_factory (self, g_value_get_object (value));
+ break;
+
case PROP_SHOW_ROW_SEPARATORS:
gtk_column_view_set_show_row_separators (self, g_value_get_boolean (value));
break;
@@ -660,10 +759,6 @@ gtk_column_view_set_property (GObject *object,
gtk_column_view_set_single_click_activate (self, g_value_get_boolean (value));
break;
- case PROP_REORDERABLE:
- gtk_column_view_set_reorderable (self, g_value_get_boolean (value));
- break;
-
case PROP_TAB_BEHAVIOR:
gtk_column_view_set_tab_behavior (self, g_value_get_enum (value));
break;
@@ -685,6 +780,10 @@ gtk_column_view_class_init (GtkColumnViewClass *klass)
widget_class->grab_focus = gtk_widget_grab_focus_child;
widget_class->measure = gtk_column_view_measure;
widget_class->size_allocate = gtk_column_view_allocate;
+ widget_class->root = gtk_column_view_root;
+ widget_class->unroot = gtk_column_view_unroot;
+ widget_class->show = gtk_column_view_show;
+ widget_class->hide = gtk_column_view_hide;
gobject_class->dispose = gtk_column_view_dispose;
gobject_class->finalize = gtk_column_view_finalize;
@@ -737,6 +836,28 @@ gtk_column_view_class_init (GtkColumnViewClass *klass)
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
+ * GtkColumnView:reorderable: (attributes org.gtk.Property.get=gtk_column_view_get_reorderable org.gtk.Property.set=gtk_column_view_set_reorderable)
+ *
+ * Whether columns are reorderable.
+ */
+ properties[PROP_REORDERABLE] =
+ g_param_spec_boolean ("reorderable", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkColumnView:row-factory: (attributes org.gtk.Property.get=gtk_column_view_get_row_factory org.gtk.Property.set=gtk_column_view_set_row_factory)
+ *
+ * The factory used for configuring rows.
+ *
+ * Since: 4.12
+ */
+ properties[PROP_ROW_FACTORY] =
+ g_param_spec_object ("row-factory", NULL, NULL,
+ GTK_TYPE_LIST_ITEM_FACTORY,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
* GtkColumnView:show-row-separators: (attributes org.gtk.Property.get=gtk_column_view_get_show_row_separators org.gtk.Property.set=gtk_column_view_set_show_row_separators)
*
* Show separators between rows.
@@ -777,16 +898,6 @@ gtk_column_view_class_init (GtkColumnViewClass *klass)
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
/**
- * GtkColumnView:reorderable: (attributes org.gtk.Property.get=gtk_column_view_get_reorderable org.gtk.Property.set=gtk_column_view_set_reorderable)
- *
- * Whether columns are reorderable.
- */
- properties[PROP_REORDERABLE] =
- g_param_spec_boolean ("reorderable", NULL, NULL,
- TRUE,
- G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
-
- /**
* GtkColumnView:tab-behavior: (attributes org.gtk.Property.get=gtk_column_view_get_tab_behavior org.gtk.Property.set=gtk_column_view_set_tab_behavior)
*
* Behavior of the <kbd>Tab</kbd> key
@@ -1312,7 +1423,7 @@ gtk_column_view_init (GtkColumnView *self)
self->columns = g_list_store_new (GTK_TYPE_COLUMN_VIEW_COLUMN);
- self->header = gtk_column_view_row_widget_new (TRUE);
+ self->header = gtk_column_view_row_widget_new (NULL, TRUE);
gtk_widget_set_can_focus (self->header, FALSE);
gtk_widget_set_parent (self->header, GTK_WIDGET (self));
@@ -1908,6 +2019,53 @@ gtk_column_view_get_enable_rubberband (GtkColumnView *self)
}
/**
+ * gtk_column_view_set_row_factory: (attributes org.gtk.Method.set_property=row-factory)
+ * @self: a `GtkColumnView`
+ * @factory: (nullable): The row factory
+ *
+ * Sets the factory used for configuring rows. The factory must be for configuring
+ * [class@Gtk.ColumnViewRow] objects.
+ *
+ * If this factory is not set - which is the default - then the defaults will be used.
+ *
+ * This factory is not used to set the widgets displayed in the individual cells. For
+ * that see [method@GtkColumnViewColumn.set_factory] and [class@GtkColumnViewCell].
+ *
+ * Since: 4.12
+ */
+void
+gtk_column_view_set_row_factory (GtkColumnView *self,
+ GtkListItemFactory *factory)
+{
+ g_return_if_fail (GTK_IS_COLUMN_VIEW (self));
+
+ if (factory == gtk_list_view_get_factory (self->listview))
+ return;
+
+ gtk_list_view_set_factory (self->listview, factory);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ROW_FACTORY]);
+}
+
+/**
+ * gtk_column_view_get_row_factory: (attributes org.gtk.Method.get_property=row-factory)
+ * @self: a `GtkColumnView`
+ *
+ * Gets the factory set via [method@Gtk.ColumnView.set_row_factory].
+ *
+ * Returns: (nullable) (transfer none): The factory
+ *
+ * Since: 4.12
+ */
+GtkListItemFactory *
+gtk_column_view_get_row_factory (GtkColumnView *self)
+{
+ g_return_val_if_fail (GTK_IS_COLUMN_VIEW (self), FALSE);
+
+ return gtk_list_view_get_factory (self->listview);
+}
+
+/**
* gtk_column_view_set_tab_behavior: (attributes org.gtk.Method.set_property=tab-behavior)
* @self: a `GtkColumnView`
* @tab_behavior: The desired tab behavior
diff --git a/gtk/gtkcolumnview.h b/gtk/gtkcolumnview.h
index aa04cd9363..afccfcfd9d 100644
--- a/gtk/gtkcolumnview.h
+++ b/gtk/gtkcolumnview.h
@@ -114,5 +114,12 @@ void gtk_column_view_set_tab_behavior (GtkColumnView
GDK_AVAILABLE_IN_4_12
gboolean gtk_column_view_get_tab_behavior (GtkColumnView *self);
+GDK_AVAILABLE_IN_4_12
+void gtk_column_view_set_row_factory (GtkColumnView *self,
+ GtkListItemFactory *factory);
+GDK_AVAILABLE_IN_4_12
+GtkListItemFactory *
+ gtk_column_view_get_row_factory (GtkColumnView *self);
+
G_END_DECLS
diff --git a/gtk/gtkcolumnviewcell.c b/gtk/gtkcolumnviewcell.c
index 97f153a09b..c32bc0fd09 100644
--- a/gtk/gtkcolumnviewcell.c
+++ b/gtk/gtkcolumnviewcell.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2019 Benjamin Otte
+ * Copyright © 2023 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,235 +21,404 @@
#include "gtkcolumnviewcellprivate.h"
-#include "gtkcolumnviewcolumnprivate.h"
-#include "gtkcolumnviewrowwidgetprivate.h"
-#include "gtkcssnodeprivate.h"
-#include "gtkcssnumbervalueprivate.h"
-#include "gtklistitemwidgetprivate.h"
-#include "gtkprivate.h"
-#include "gtkwidgetprivate.h"
+#include "gtklistitembaseprivate.h"
-
-struct _GtkColumnViewCell
-{
- GtkListItemWidget parent_instance;
-
- GtkColumnViewColumn *column;
-
- /* This list isn't sorted - next/prev refer to list elements, not rows in the list */
- GtkColumnViewCell *next_cell;
- GtkColumnViewCell *prev_cell;
-};
+/**
+ * GtkColumnViewCell:
+ *
+ * `GtkColumnViewCell` is used by [class@Gtk.ColumnViewColumn] to represent items
+ * in a cell in [class@Gtk.ColumnView].
+ *
+ * The `GtkColumnViewCell`s are managed by the columnview widget (with its factory)
+ * and cannot be created by applications, but they need to be populated
+ * by application code. This is done by calling [method@Gtk.ColumnViewCell.set_child].
+ *
+ * `GtkColumnViewCell`s exist in 2 stages:
+ *
+ * 1. The unbound stage where the listitem is not currently connected to
+ * an item in the list. In that case, the [property@Gtk.ColumnViewCell:item]
+ * property is set to %NULL.
+ *
+ * 2. The bound stage where the listitem references an item from the list.
+ * The [property@Gtk.ColumnViewCell:item] property is not %NULL.
+ *
+ * Since: 4.12
+ */
struct _GtkColumnViewCellClass
{
- GtkListItemWidgetClass parent_class;
+ GtkListItemClass parent_class;
};
-G_DEFINE_TYPE (GtkColumnViewCell, gtk_column_view_cell, GTK_TYPE_LIST_ITEM_WIDGET)
-
-static int
-get_number (GtkCssValue *value)
+enum
{
- double d = _gtk_css_number_value_get (value, 100);
-
- if (d < 1)
- return ceil (d);
- else
- return floor (d);
-}
+ PROP_0,
+ PROP_CHILD,
+ PROP_FOCUSABLE,
+ PROP_ITEM,
+ PROP_POSITION,
+ PROP_SELECTED,
+
+ N_PROPS
+};
-static int
-unadjust_width (GtkWidget *widget,
- int width)
-{
- GtkCssStyle *style;
- int widget_margins;
- int css_extra;
+G_DEFINE_TYPE (GtkColumnViewCell, gtk_column_view_cell, GTK_TYPE_LIST_ITEM)
- style = gtk_css_node_get_style (gtk_widget_get_css_node (widget));
- css_extra = get_number (style->size->margin_left) +
- get_number (style->size->margin_right) +
- get_number (style->border->border_left_width) +
- get_number (style->border->border_right_width) +
- get_number (style->size->padding_left) +
- get_number (style->size->padding_right);
- widget_margins = widget->priv->margin.left + widget->priv->margin.right;
-
- return MAX (0, width - widget_margins - css_extra);
-}
+static GParamSpec *properties[N_PROPS] = { NULL, };
static void
-gtk_column_view_cell_measure (GtkWidget *widget,
- GtkOrientation orientation,
- int for_size,
- int *minimum,
- int *natural,
- int *minimum_baseline,
- int *natural_baseline)
-{
- GtkColumnViewCell *cell = GTK_COLUMN_VIEW_CELL (widget);
- GtkWidget *child = gtk_widget_get_first_child (widget);
- int fixed_width = gtk_column_view_column_get_fixed_width (cell->column);
- int unadj_width;
-
- unadj_width = unadjust_width (widget, fixed_width);
-
- if (orientation == GTK_ORIENTATION_VERTICAL)
- {
- if (fixed_width > -1)
- {
- if (for_size == -1)
- for_size = unadj_width;
- else
- for_size = MIN (for_size, unadj_width);
- }
- }
+gtk_column_view_cell_dispose (GObject *object)
+{
+ GtkColumnViewCell *self = GTK_COLUMN_VIEW_CELL (object);
- if (child)
- gtk_widget_measure (child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline);
+ g_assert (self->cell == NULL); /* would hold a reference */
+ g_clear_object (&self->child);
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- if (fixed_width > -1)
- {
- *minimum = 0;
- *natural = unadj_width;
- }
- }
+ G_OBJECT_CLASS (gtk_column_view_cell_parent_class)->dispose (object);
}
static void
-gtk_column_view_cell_size_allocate (GtkWidget *widget,
- int width,
- int height,
- int baseline)
+gtk_column_view_cell_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- GtkWidget *child = gtk_widget_get_first_child (widget);
+ GtkColumnViewCell *self = GTK_COLUMN_VIEW_CELL (object);
- if (child)
+ switch (property_id)
{
- int min;
-
- gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, height, &min, NULL, NULL, NULL);
-
- gtk_widget_allocate (child, MAX (min, width), height, baseline, NULL);
+ case PROP_CHILD:
+ g_value_set_object (value, self->child);
+ break;
+
+ case PROP_FOCUSABLE:
+ g_value_set_boolean (value, self->focusable);
+ break;
+
+ case PROP_ITEM:
+ if (self->cell)
+ g_value_set_object (value, gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self->cell)));
+ break;
+
+ case PROP_POSITION:
+ if (self->cell)
+ g_value_set_uint (value, gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self->cell)));
+ else
+ g_value_set_uint (value, GTK_INVALID_LIST_POSITION);
+ break;
+
+ case PROP_SELECTED:
+ if (self->cell)
+ g_value_set_boolean (value, gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self->cell)));
+ else
+ g_value_set_boolean (value, FALSE);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
}
}
static void
-gtk_column_view_cell_dispose (GObject *object)
+gtk_column_view_cell_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
GtkColumnViewCell *self = GTK_COLUMN_VIEW_CELL (object);
- if (self->column)
+ switch (property_id)
{
- gtk_column_view_column_remove_cell (self->column, self);
-
- if (self->prev_cell)
- self->prev_cell->next_cell = self->next_cell;
- if (self->next_cell)
- self->next_cell->prev_cell = self->prev_cell;
+ case PROP_CHILD:
+ gtk_column_view_cell_set_child (self, g_value_get_object (value));
+ break;
- self->prev_cell = NULL;
- self->next_cell = NULL;
+ case PROP_FOCUSABLE:
+ gtk_column_view_cell_set_focusable (self, g_value_get_boolean (value));
+ break;
- g_clear_object (&self->column);
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
}
-
- G_OBJECT_CLASS (gtk_column_view_cell_parent_class)->dispose (object);
-}
-
-static GtkSizeRequestMode
-gtk_column_view_cell_get_request_mode (GtkWidget *widget)
-{
- GtkWidget *child = gtk_widget_get_first_child (widget);
-
- if (child)
- return gtk_widget_get_request_mode (child);
- else
- return GTK_SIZE_REQUEST_CONSTANT_SIZE;
}
static void
gtk_column_view_cell_class_init (GtkColumnViewCellClass *klass)
{
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- widget_class->measure = gtk_column_view_cell_measure;
- widget_class->size_allocate = gtk_column_view_cell_size_allocate;
- widget_class->get_request_mode = gtk_column_view_cell_get_request_mode;
-
gobject_class->dispose = gtk_column_view_cell_dispose;
-
- gtk_widget_class_set_css_name (widget_class, I_("cell"));
- gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GRID_CELL);
+ gobject_class->get_property = gtk_column_view_cell_get_property;
+ gobject_class->set_property = gtk_column_view_cell_set_property;
+
+ /**
+ * GtkColumnViewCell:child: (attributes org.gtk.Property.get=gtk_column_view_cell_get_child org.gtk.Property.set=gtk_column_view_cell_set_child)
+ *
+ * Widget used for display.
+ *
+ * Since: 4.12
+ */
+ properties[PROP_CHILD] =
+ g_param_spec_object ("child", NULL, NULL,
+ GTK_TYPE_WIDGET,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkColumnViewCell:focusable: (attributes org.gtk.Property.get=gtk_column_view_cell_get_focusable org.gtk.Property.set=gtk_column_view_cell_set_focusable)
+ *
+ * If the item can be focused with the keyboard.
+ *
+ * Since: 4.12
+ */
+ properties[PROP_FOCUSABLE] =
+ g_param_spec_boolean ("focusable", NULL, NULL,
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkColumnViewCell:item: (attributes org.gtk.Property.get=gtk_column_view_cell_get_item)
+ *
+ * Displayed item.
+ *
+ * Since: 4.12
+ */
+ properties[PROP_ITEM] =
+ g_param_spec_object ("item", NULL, NULL,
+ G_TYPE_OBJECT,
+ G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkColumnViewCell:position: (attributes org.gtk.Property.get=gtk_column_view_cell_get_position)
+ *
+ * Position of the item.
+ *
+ * Since: 4.12
+ */
+ properties[PROP_POSITION] =
+ g_param_spec_uint ("position", NULL, NULL,
+ 0, G_MAXUINT, GTK_INVALID_LIST_POSITION,
+ G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkColumnViewCell:selected: (attributes org.gtk.Property.get=gtk_column_view_cell_get_selected)
+ *
+ * If the item is currently selected.
+ *
+ * Since: 4.12
+ */
+ properties[PROP_SELECTED] =
+ g_param_spec_boolean ("selected", NULL, NULL,
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
-gtk_column_view_cell_resize_func (GtkWidget *widget)
+gtk_column_view_cell_init (GtkColumnViewCell *self)
{
- GtkColumnViewCell *self = GTK_COLUMN_VIEW_CELL (widget);
+ self->focusable = FALSE;
+}
- if (self->column)
- gtk_column_view_column_queue_resize (self->column);
+GtkColumnViewCell *
+gtk_column_view_cell_new (void)
+{
+ return g_object_new (GTK_TYPE_COLUMN_VIEW_CELL, NULL);
}
-static void
-gtk_column_view_cell_init (GtkColumnViewCell *self)
+void
+gtk_column_view_cell_do_notify (GtkColumnViewCell *column_view_cell,
+ gboolean notify_item,
+ gboolean notify_position,
+ gboolean notify_selected)
+{
+ GObject *object = G_OBJECT (column_view_cell);
+
+ if (notify_item)
+ g_object_notify_by_pspec (object, properties[PROP_ITEM]);
+ if (notify_position)
+ g_object_notify_by_pspec (object, properties[PROP_POSITION]);
+ if (notify_selected)
+ g_object_notify_by_pspec (object, properties[PROP_SELECTED]);
+}
+
+/**
+ * gtk_column_view_cell_get_item: (attributes org.gtk.Method.get_property=item)
+ * @self: a `GtkColumnViewCell`
+ *
+ * Gets the model item that associated with @self.
+ *
+ * If @self is unbound, this function returns %NULL.
+ *
+ * Returns: (nullable) (transfer none) (type GObject): The item displayed
+ *
+ * Since: 4.12
+ **/
+gpointer
+gtk_column_view_cell_get_item (GtkColumnViewCell *self)
{
- GtkWidget *widget = GTK_WIDGET (self);
+ g_return_val_if_fail (GTK_IS_COLUMN_VIEW_CELL (self), NULL);
- gtk_widget_set_focusable (widget, FALSE);
- gtk_widget_set_overflow (widget, GTK_OVERFLOW_HIDDEN);
- /* FIXME: Figure out if setting the manager class to INVALID should work */
- gtk_widget_set_layout_manager (widget, NULL);
- widget->priv->resize_func = gtk_column_view_cell_resize_func;
+ if (self->cell == NULL)
+ return NULL;
+
+ return gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self->cell));
}
+/**
+ * gtk_column_view_cell_get_child: (attributes org.gtk.Method.get_property=child)
+ * @self: a `GtkColumnViewCell`
+ *
+ * Gets the child previously set via gtk_column_view_cell_set_child() or
+ * %NULL if none was set.
+ *
+ * Returns: (transfer none) (nullable): The child
+ *
+ * Since: 4.12
+ */
GtkWidget *
-gtk_column_view_cell_new (GtkColumnViewColumn *column)
+gtk_column_view_cell_get_child (GtkColumnViewCell *self)
{
- GtkColumnViewCell *self;
+ g_return_val_if_fail (GTK_IS_COLUMN_VIEW_CELL (self), NULL);
- self = g_object_new (GTK_TYPE_COLUMN_VIEW_CELL,
- "factory", gtk_column_view_column_get_factory (column),
- NULL);
+ return self->child;
+}
- self->column = g_object_ref (column);
+/**
+ * gtk_column_view_cell_set_child: (attributes org.gtk.Method.set_property=child)
+ * @self: a `GtkColumnViewCell`
+ * @child: (nullable): The list item's child or %NULL to unset
+ *
+ * Sets the child to be used for this listitem.
+ *
+ * This function is typically called by applications when
+ * setting up a listitem so that the widget can be reused when
+ * binding it multiple times.
+ *
+ * Since: 4.12
+ */
+void
+gtk_column_view_cell_set_child (GtkColumnViewCell *self,
+ GtkWidget *child)
+{
+ g_return_if_fail (GTK_IS_COLUMN_VIEW_CELL (self));
+ g_return_if_fail (child == NULL || GTK_IS_WIDGET (child));
+
+ if (self->child == child)
+ return;
+
+ g_clear_object (&self->child);
- self->next_cell = gtk_column_view_column_get_first_cell (self->column);
- if (self->next_cell)
- self->next_cell->prev_cell = self;
+ if (child)
+ {
+ g_object_ref_sink (child);
+ self->child = child;
+ }
- gtk_column_view_column_add_cell (self->column, self);
+ if (self->cell)
+ gtk_column_view_cell_widget_set_child (self->cell, child);
- return GTK_WIDGET (self);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CHILD]);
}
-void
-gtk_column_view_cell_remove (GtkColumnViewCell *self)
+/**
+ * gtk_column_view_cell_get_position: (attributes org.gtk.Method.get_property=position)
+ * @self: a `GtkColumnViewCell`
+ *
+ * Gets the position in the model that @self currently displays.
+ *
+ * If @self is unbound, %GTK_INVALID_LIST_POSITION is returned.
+ *
+ * Returns: The position of this item
+ *
+ * Since: 4.12
+ */
+guint
+gtk_column_view_cell_get_position (GtkColumnViewCell *self)
{
- GtkWidget *widget = GTK_WIDGET (self);
+ g_return_val_if_fail (GTK_IS_COLUMN_VIEW_CELL (self), GTK_INVALID_LIST_POSITION);
- gtk_column_view_row_widget_remove_child (GTK_COLUMN_VIEW_ROW_WIDGET (gtk_widget_get_parent (widget)), widget);
+ if (self->cell == NULL)
+ return GTK_INVALID_LIST_POSITION;
+
+ return gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self->cell));
}
-GtkColumnViewCell *
-gtk_column_view_cell_get_next (GtkColumnViewCell *self)
+/**
+ * gtk_column_view_cell_get_selected: (attributes org.gtk.Method.get_property=selected)
+ * @self: a `GtkColumnViewCell`
+ *
+ * Checks if the item is displayed as selected.
+ *
+ * The selected state is maintained by the liste widget and its model
+ * and cannot be set otherwise.
+ *
+ * Returns: %TRUE if the item is selected.
+ *
+ * Since: 4.12
+ */
+gboolean
+gtk_column_view_cell_get_selected (GtkColumnViewCell *self)
{
- return self->next_cell;
+ g_return_val_if_fail (GTK_IS_COLUMN_VIEW_CELL (self), FALSE);
+
+ if (self->cell == NULL)
+ return FALSE;
+
+ return gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self->cell));
}
-GtkColumnViewCell *
-gtk_column_view_cell_get_prev (GtkColumnViewCell *self)
+/**
+ * gtk_column_view_cell_get_focusable: (attributes org.gtk.Method.get_property=focusable)
+ * @self: a `GtkColumnViewCell`
+ *
+ * Checks if a list item has been set to be focusable via
+ * gtk_column_view_cell_set_focusable().
+ *
+ * Returns: %TRUE if the item is focusable
+ *
+ * Since: 4.12
+ */
+gboolean
+gtk_column_view_cell_get_focusable (GtkColumnViewCell *self)
{
- return self->prev_cell;
+ g_return_val_if_fail (GTK_IS_COLUMN_VIEW_CELL (self), FALSE);
+
+ return self->focusable;
}
-GtkColumnViewColumn *
-gtk_column_view_cell_get_column (GtkColumnViewCell *self)
+/**
+ * gtk_column_view_cell_set_focusable: (attributes org.gtk.Method.set_property=focusable)
+ * @self: a `GtkColumnViewCell`
+ * @focusable: if the item should be focusable
+ *
+ * Sets @self to be focusable.
+ *
+ * If an item is focusable, it can be focused using the keyboard.
+ * This works similar to [method@Gtk.Widget.set_focusable].
+ *
+ * Note that if items are not focusable, the keyboard cannot be used to activate
+ * them and selecting only works if one of the listitem's children is focusable.
+ *
+ * By default, list items are focusable.
+ *
+ * Since: 4.12
+ */
+void
+gtk_column_view_cell_set_focusable (GtkColumnViewCell *self,
+ gboolean focusable)
{
- return self->column;
+ g_return_if_fail (GTK_IS_COLUMN_VIEW_CELL (self));
+
+ if (self->focusable == focusable)
+ return;
+
+ self->focusable = focusable;
+
+ if (self->cell)
+ gtk_widget_set_focusable (GTK_WIDGET (self->cell), focusable);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FOCUSABLE]);
}
diff --git a/gtk/gtkcolumnviewcell.h b/gtk/gtkcolumnviewcell.h
new file mode 100644
index 0000000000..f1490ea80d
--- /dev/null
+++ b/gtk/gtkcolumnviewcell.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2023 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>
+ */
+
+#pragma once
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtktypes.h>
+#include <gtk/gtklistitem.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COLUMN_VIEW_CELL (gtk_column_view_cell_get_type ())
+GDK_AVAILABLE_IN_4_12
+GDK_DECLARE_INTERNAL_TYPE(GtkColumnViewCell, gtk_column_view_cell, GTK, COLUMN_VIEW_CELL, GtkListItem);
+
+GDK_AVAILABLE_IN_4_12
+gpointer gtk_column_view_cell_get_item (GtkColumnViewCell *self);
+GDK_AVAILABLE_IN_4_12
+guint gtk_column_view_cell_get_position (GtkColumnViewCell *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_12
+gboolean gtk_column_view_cell_get_selected (GtkColumnViewCell *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_12
+gboolean gtk_column_view_cell_get_focusable (GtkColumnViewCell *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_12
+void gtk_column_view_cell_set_focusable (GtkColumnViewCell *self,
+ gboolean focusable);
+
+GDK_AVAILABLE_IN_4_12
+void gtk_column_view_cell_set_child (GtkColumnViewCell *self,
+ GtkWidget *child);
+GDK_AVAILABLE_IN_4_12
+GtkWidget * gtk_column_view_cell_get_child (GtkColumnViewCell *self);
+
+G_END_DECLS
+
diff --git a/gtk/gtkcolumnviewcellprivate.h b/gtk/gtkcolumnviewcellprivate.h
index 5e78ea4901..40964d25d4 100644
--- a/gtk/gtkcolumnviewcellprivate.h
+++ b/gtk/gtkcolumnviewcellprivate.h
@@ -1,5 +1,5 @@
/*
- * Copyright © 2019 Benjamin Otte
+ * Copyright © 2023 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,29 +19,31 @@
#pragma once
-#include "gtkcolumnviewcolumn.h"
+#include "gtkcolumnviewcell.h"
+
+#include "gtkcolumnviewcellwidgetprivate.h"
+#include "gtklistitemprivate.h"
G_BEGIN_DECLS
-#define GTK_TYPE_COLUMN_VIEW_CELL (gtk_column_view_cell_get_type ())
-#define GTK_COLUMN_VIEW_CELL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_COLUMN_VIEW_CELL, GtkColumnViewCell))
-#define GTK_COLUMN_VIEW_CELL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_COLUMN_VIEW_CELL, GtkColumnViewCellClass))
-#define GTK_IS_COLUMN_VIEW_CELL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_COLUMN_VIEW_CELL))
-#define GTK_IS_COLUMN_VIEW_CELL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_COLUMN_VIEW_CELL))
-#define GTK_COLUMN_VIEW_CELL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_COLUMN_VIEW_CELL, GtkColumnViewCellClass))
+struct _GtkColumnViewCell
+{
+ GtkListItem parent_instance;
+
+ GtkColumnViewCellWidget *cell; /* has a reference */
-typedef struct _GtkColumnViewCell GtkColumnViewCell;
-typedef struct _GtkColumnViewCellClass GtkColumnViewCellClass;
+ GtkWidget *child;
-GType gtk_column_view_cell_get_type (void) G_GNUC_CONST;
+ guint focusable : 1;
+};
-GtkWidget * gtk_column_view_cell_new (GtkColumnViewColumn *column);
+GtkColumnViewCell * gtk_column_view_cell_new (void);
-void gtk_column_view_cell_remove (GtkColumnViewCell *self);
+void gtk_column_view_cell_do_notify (GtkColumnViewCell *column_view_cell,
+ gboolean notify_item,
+ gboolean notify_position,
+ gboolean notify_selected);
-GtkColumnViewCell * gtk_column_view_cell_get_next (GtkColumnViewCell *self);
-GtkColumnViewCell * gtk_column_view_cell_get_prev (GtkColumnViewCell *self);
-GtkColumnViewColumn * gtk_column_view_cell_get_column (GtkColumnViewCell *self);
G_END_DECLS
diff --git a/gtk/gtkcolumnviewcellwidget.c b/gtk/gtkcolumnviewcellwidget.c
new file mode 100644
index 0000000000..eb3ab7835e
--- /dev/null
+++ b/gtk/gtkcolumnviewcellwidget.c
@@ -0,0 +1,411 @@
+/*
+ * 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 "gtkcolumnviewcellwidgetprivate.h"
+
+#include "gtkcolumnviewcellprivate.h"
+#include "gtkcolumnviewcolumnprivate.h"
+#include "gtkcolumnviewrowwidgetprivate.h"
+#include "gtkcssboxesprivate.h"
+#include "gtkcssnodeprivate.h"
+#include "gtklistfactorywidgetprivate.h"
+#include "gtkprivate.h"
+#include "gtkwidgetprivate.h"
+
+
+struct _GtkColumnViewCellWidget
+{
+ GtkListItemWidget parent_instance;
+
+ GtkColumnViewColumn *column;
+
+ /* This list isn't sorted - next/prev refer to list elements, not rows in the list */
+ GtkColumnViewCellWidget *next_cell;
+ GtkColumnViewCellWidget *prev_cell;
+};
+
+struct _GtkColumnViewCellWidgetClass
+{
+ GtkListItemWidgetClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkColumnViewCellWidget, gtk_column_view_cell_widget, GTK_TYPE_LIST_FACTORY_WIDGET)
+
+static gboolean
+gtk_column_view_cell_widget_focus (GtkWidget *widget,
+ GtkDirectionType direction)
+{
+ GtkWidget *child = gtk_widget_get_first_child (widget);
+
+ if (gtk_widget_get_focus_child (widget))
+ {
+ /* focus is in the child */
+ if (direction == GTK_DIR_TAB_BACKWARD)
+ return gtk_widget_grab_focus_self (widget);
+ else
+ return FALSE;
+ }
+ else if (gtk_widget_is_focus (widget))
+ {
+ /* The widget has focus */
+ if (direction == GTK_DIR_TAB_FORWARD)
+ {
+ if (child)
+ return gtk_widget_child_focus (child, direction);
+ }
+
+ return FALSE;
+ }
+ else
+ {
+ /* focus coming in from the outside */
+ if (direction == GTK_DIR_TAB_BACKWARD)
+ {
+ if (child &&
+ gtk_widget_child_focus (child, direction))
+ return TRUE;
+
+ return gtk_widget_grab_focus_self (widget);
+ }
+ else
+ {
+ if (gtk_widget_grab_focus_self (widget))
+ return TRUE;
+
+ if (child &&
+ gtk_widget_child_focus (child, direction))
+ return TRUE;
+
+ return FALSE;
+ }
+ }
+}
+
+static gboolean
+gtk_column_view_cell_widget_grab_focus (GtkWidget *widget)
+{
+ GtkWidget *child;
+
+ if (GTK_WIDGET_CLASS (gtk_column_view_cell_widget_parent_class)->grab_focus (widget))
+ return TRUE;
+
+ child = gtk_widget_get_first_child (widget);
+ if (child && gtk_widget_grab_focus (child))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gpointer
+gtk_column_view_cell_widget_create_object (GtkListFactoryWidget *fw)
+{
+ return gtk_column_view_cell_new ();
+}
+
+static void
+gtk_column_view_cell_widget_setup_object (GtkListFactoryWidget *fw,
+ gpointer object)
+{
+ GtkColumnViewCellWidget *self = GTK_COLUMN_VIEW_CELL_WIDGET (fw);
+ GtkColumnViewCell *cell = object;
+
+ GTK_LIST_FACTORY_WIDGET_CLASS (gtk_column_view_cell_widget_parent_class)->setup_object (fw, object);
+
+ cell->cell = self;
+
+ gtk_column_view_cell_widget_set_child (GTK_COLUMN_VIEW_CELL_WIDGET (self), cell->child);
+
+ gtk_widget_set_focusable (GTK_WIDGET (self), cell->focusable);
+
+ gtk_column_view_cell_do_notify (cell,
+ gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
+ gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)) != GTK_INVALID_LIST_POSITION,
+ gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self)));
+}
+
+static void
+gtk_column_view_cell_widget_teardown_object (GtkListFactoryWidget *fw,
+ gpointer object)
+{
+ GtkColumnViewCellWidget *self = GTK_COLUMN_VIEW_CELL_WIDGET (fw);
+ GtkColumnViewCell *cell = object;
+
+ GTK_LIST_FACTORY_WIDGET_CLASS (gtk_column_view_cell_widget_parent_class)->teardown_object (fw, object);
+
+ cell->cell = NULL;
+
+ gtk_column_view_cell_widget_set_child (GTK_COLUMN_VIEW_CELL_WIDGET (self), NULL);
+
+ gtk_widget_set_focusable (GTK_WIDGET (self), FALSE);
+
+ gtk_column_view_cell_do_notify (cell,
+ gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
+ gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)) != GTK_INVALID_LIST_POSITION,
+ gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self)));
+}
+
+static void
+gtk_column_view_cell_widget_update_object (GtkListFactoryWidget *fw,
+ gpointer object,
+ guint position,
+ gpointer item,
+ gboolean selected)
+{
+ GtkColumnViewCellWidget *self = GTK_COLUMN_VIEW_CELL_WIDGET (fw);
+ GtkListItemBase *base = GTK_LIST_ITEM_BASE (self);
+ GtkColumnViewCell *cell = object;
+ /* Track notify manually instead of freeze/thaw_notify for performance reasons. */
+ gboolean notify_item = FALSE, notify_position = FALSE, notify_selected = FALSE;
+
+ /* FIXME: It's kinda evil to notify external objects from here... */
+ notify_item = gtk_list_item_base_get_item (base) != item;
+ notify_position = gtk_list_item_base_get_position (base) != position;
+ notify_selected = gtk_list_item_base_get_selected (base) != selected;
+
+ GTK_LIST_FACTORY_WIDGET_CLASS (gtk_column_view_cell_widget_parent_class)->update_object (fw,
+ object,
+ position,
+ item,
+ selected);
+
+ if (cell)
+ gtk_column_view_cell_do_notify (cell, notify_item, notify_position, notify_selected);
+}
+
+static int
+unadjust_width (GtkWidget *widget,
+ int width)
+{
+ GtkCssBoxes boxes;
+
+ if (width <= -1)
+ return -1;
+
+ gtk_css_boxes_init_border_box (&boxes,
+ gtk_css_node_get_style (gtk_widget_get_css_node (widget)),
+ 0, 0,
+ width, 100000);
+ return MAX (0, floor (gtk_css_boxes_get_content_rect (&boxes)->size.width));
+}
+
+static void
+gtk_column_view_cell_widget_measure (GtkWidget *widget,
+ GtkOrientation orientation,
+ int for_size,
+ int *minimum,
+ int *natural,
+ int *minimum_baseline,
+ int *natural_baseline)
+{
+ GtkColumnViewCellWidget *cell = GTK_COLUMN_VIEW_CELL_WIDGET (widget);
+ GtkWidget *child = gtk_widget_get_first_child (widget);
+ int fixed_width, unadj_width;
+
+ fixed_width = gtk_column_view_column_get_fixed_width (cell->column);
+ unadj_width = unadjust_width (widget, fixed_width);
+
+ if (orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ if (fixed_width > -1)
+ {
+ int min;
+
+ if (for_size == -1)
+ for_size = unadj_width;
+ else
+ for_size = MIN (for_size, unadj_width);
+
+ gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, &min, NULL, NULL, NULL);
+ for_size = MAX (for_size, min);
+ }
+ }
+
+ if (child)
+ gtk_widget_measure (child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ if (fixed_width > -1)
+ {
+ *minimum = 0;
+ *natural = unadj_width;
+ }
+ }
+}
+
+static void
+gtk_column_view_cell_widget_size_allocate (GtkWidget *widget,
+ int width,
+ int height,
+ int baseline)
+{
+ GtkWidget *child = gtk_widget_get_first_child (widget);
+
+ if (child)
+ {
+ int min;
+
+ gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, height, &min, NULL, NULL, NULL);
+
+ gtk_widget_allocate (child, MAX (min, width), height, baseline, NULL);
+ }
+}
+
+static void
+gtk_column_view_cell_widget_dispose (GObject *object)
+{
+ GtkColumnViewCellWidget *self = GTK_COLUMN_VIEW_CELL_WIDGET (object);
+
+ if (self->column)
+ {
+ gtk_column_view_column_remove_cell (self->column, self);
+
+ if (self->prev_cell)
+ self->prev_cell->next_cell = self->next_cell;
+ if (self->next_cell)
+ self->next_cell->prev_cell = self->prev_cell;
+
+ self->prev_cell = NULL;
+ self->next_cell = NULL;
+
+ g_clear_object (&self->column);
+ }
+
+ G_OBJECT_CLASS (gtk_column_view_cell_widget_parent_class)->dispose (object);
+}
+
+static GtkSizeRequestMode
+gtk_column_view_cell_widget_get_request_mode (GtkWidget *widget)
+{
+ GtkWidget *child = gtk_widget_get_first_child (widget);
+
+ if (child)
+ return gtk_widget_get_request_mode (child);
+ else
+ return GTK_SIZE_REQUEST_CONSTANT_SIZE;
+}
+
+static void
+gtk_column_view_cell_widget_class_init (GtkColumnViewCellWidgetClass *klass)
+{
+ GtkListFactoryWidgetClass *factory_class = GTK_LIST_FACTORY_WIDGET_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ factory_class->create_object = gtk_column_view_cell_widget_create_object;
+ factory_class->setup_object = gtk_column_view_cell_widget_setup_object;
+ factory_class->update_object = gtk_column_view_cell_widget_update_object;
+ factory_class->teardown_object = gtk_column_view_cell_widget_teardown_object;
+
+ widget_class->focus = gtk_column_view_cell_widget_focus;
+ widget_class->grab_focus = gtk_column_view_cell_widget_grab_focus;
+ widget_class->measure = gtk_column_view_cell_widget_measure;
+ widget_class->size_allocate = gtk_column_view_cell_widget_size_allocate;
+ widget_class->get_request_mode = gtk_column_view_cell_widget_get_request_mode;
+
+ gobject_class->dispose = gtk_column_view_cell_widget_dispose;
+
+ gtk_widget_class_set_css_name (widget_class, I_("cell"));
+ gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GRID_CELL);
+}
+
+static void
+gtk_column_view_cell_widget_resize_func (GtkWidget *widget)
+{
+ GtkColumnViewCellWidget *self = GTK_COLUMN_VIEW_CELL_WIDGET (widget);
+
+ if (self->column)
+ gtk_column_view_column_queue_resize (self->column);
+}
+
+static void
+gtk_column_view_cell_widget_init (GtkColumnViewCellWidget *self)
+{
+ GtkWidget *widget = GTK_WIDGET (self);
+
+ gtk_widget_set_focusable (widget, FALSE);
+ gtk_widget_set_overflow (widget, GTK_OVERFLOW_HIDDEN);
+ /* FIXME: Figure out if setting the manager class to INVALID should work */
+ gtk_widget_set_layout_manager (widget, NULL);
+ widget->priv->resize_func = gtk_column_view_cell_widget_resize_func;
+}
+
+GtkWidget *
+gtk_column_view_cell_widget_new (GtkColumnViewColumn *column,
+ gboolean inert)
+{
+ GtkColumnViewCellWidget *self;
+
+ self = g_object_new (GTK_TYPE_COLUMN_VIEW_CELL_WIDGET,
+ "factory", inert ? NULL : gtk_column_view_column_get_factory (column),
+ NULL);
+
+ self->column = g_object_ref (column);
+
+ self->next_cell = gtk_column_view_column_get_first_cell (self->column);
+ if (self->next_cell)
+ self->next_cell->prev_cell = self;
+
+ gtk_column_view_column_add_cell (self->column, self);
+
+ return GTK_WIDGET (self);
+}
+
+void
+gtk_column_view_cell_widget_remove (GtkColumnViewCellWidget *self)
+{
+ GtkWidget *widget = GTK_WIDGET (self);
+
+ gtk_column_view_row_widget_remove_child (GTK_COLUMN_VIEW_ROW_WIDGET (gtk_widget_get_parent (widget)), widget);
+}
+
+GtkColumnViewCellWidget *
+gtk_column_view_cell_widget_get_next (GtkColumnViewCellWidget *self)
+{
+ return self->next_cell;
+}
+
+GtkColumnViewCellWidget *
+gtk_column_view_cell_widget_get_prev (GtkColumnViewCellWidget *self)
+{
+ return self->prev_cell;
+}
+
+GtkColumnViewColumn *
+gtk_column_view_cell_widget_get_column (GtkColumnViewCellWidget *self)
+{
+ return self->column;
+}
+
+void
+gtk_column_view_cell_widget_set_child (GtkColumnViewCellWidget *self,
+ GtkWidget *child)
+{
+ GtkWidget *cur_child = gtk_widget_get_first_child (GTK_WIDGET (self));
+
+ if (cur_child == child)
+ return;
+
+ g_clear_pointer (&cur_child, gtk_widget_unparent);
+
+ if (child)
+ gtk_widget_set_parent (child, GTK_WIDGET (self));
+}
diff --git a/gtk/gtkcolumnviewcellwidgetprivate.h b/gtk/gtkcolumnviewcellwidgetprivate.h
new file mode 100644
index 0000000000..57632adf9b
--- /dev/null
+++ b/gtk/gtkcolumnviewcellwidgetprivate.h
@@ -0,0 +1,50 @@
+/*
+ * 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>
+ */
+
+#pragma once
+
+#include "gtkcolumnviewcolumn.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COLUMN_VIEW_CELL_WIDGET (gtk_column_view_cell_widget_get_type ())
+#define GTK_COLUMN_VIEW_CELL_WIDGET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_COLUMN_VIEW_CELL_WIDGET, GtkColumnViewCellWidget))
+#define GTK_COLUMN_VIEW_CELL_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_COLUMN_VIEW_CELL_WIDGET, GtkColumnViewCellWidgetClass))
+#define GTK_IS_COLUMN_VIEW_CELL_WIDGET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_COLUMN_VIEW_CELL_WIDGET))
+#define GTK_IS_COLUMN_VIEW_CELL_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_COLUMN_VIEW_CELL_WIDGET))
+#define GTK_COLUMN_VIEW_CELL_WIDGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_COLUMN_VIEW_CELL_WIDGET, GtkColumnViewCellWidgetClass))
+
+typedef struct _GtkColumnViewCellWidget GtkColumnViewCellWidget;
+typedef struct _GtkColumnViewCellWidgetClass GtkColumnViewCellWidgetClass;
+
+GType gtk_column_view_cell_widget_get_type (void) G_GNUC_CONST;
+
+GtkWidget * gtk_column_view_cell_widget_new (GtkColumnViewColumn *column,
+ gboolean inert);
+
+void gtk_column_view_cell_widget_set_child (GtkColumnViewCellWidget *self,
+ GtkWidget *child);
+
+void gtk_column_view_cell_widget_remove (GtkColumnViewCellWidget *self);
+
+GtkColumnViewCellWidget * gtk_column_view_cell_widget_get_next (GtkColumnViewCellWidget *self);
+GtkColumnViewCellWidget * gtk_column_view_cell_widget_get_prev (GtkColumnViewCellWidget *self);
+GtkColumnViewColumn * gtk_column_view_cell_widget_get_column (GtkColumnViewCellWidget *self);
+
+G_END_DECLS
diff --git a/gtk/gtkcolumnviewcolumn.c b/gtk/gtkcolumnviewcolumn.c
index beb88fd95c..32d8e1d562 100644
--- a/gtk/gtkcolumnviewcolumn.c
+++ b/gtk/gtkcolumnviewcolumn.c
@@ -78,7 +78,7 @@ struct _GtkColumnViewColumn
GMenuModel *menu;
/* This list isn't sorted - this is just caching for performance */
- GtkColumnViewCell *first_cell; /* no reference, just caching */
+ GtkColumnViewCellWidget *first_cell; /* no reference, just caching */
};
struct _GtkColumnViewColumnClass
@@ -400,7 +400,7 @@ gtk_column_view_column_new (const char *title,
return result;
}
-GtkColumnViewCell *
+GtkColumnViewCellWidget *
gtk_column_view_column_get_first_cell (GtkColumnViewColumn *self)
{
return self->first_cell;
@@ -408,7 +408,7 @@ gtk_column_view_column_get_first_cell (GtkColumnViewColumn *self)
void
gtk_column_view_column_add_cell (GtkColumnViewColumn *self,
- GtkColumnViewCell *cell)
+ GtkColumnViewCellWidget *cell)
{
self->first_cell = cell;
@@ -418,10 +418,10 @@ gtk_column_view_column_add_cell (GtkColumnViewColumn *self,
void
gtk_column_view_column_remove_cell (GtkColumnViewColumn *self,
- GtkColumnViewCell *cell)
+ GtkColumnViewCellWidget *cell)
{
if (cell == self->first_cell)
- self->first_cell = gtk_column_view_cell_get_next (cell);
+ self->first_cell = gtk_column_view_cell_widget_get_next (cell);
gtk_column_view_column_queue_resize (self);
gtk_widget_queue_resize (GTK_WIDGET (cell));
@@ -430,7 +430,7 @@ gtk_column_view_column_remove_cell (GtkColumnViewColumn *self,
void
gtk_column_view_column_queue_resize (GtkColumnViewColumn *self)
{
- GtkColumnViewCell *cell;
+ GtkColumnViewCellWidget *cell;
if (self->minimum_size_request < 0)
return;
@@ -441,7 +441,7 @@ gtk_column_view_column_queue_resize (GtkColumnViewColumn *self)
if (self->header)
gtk_widget_queue_resize (self->header);
- for (cell = self->first_cell; cell; cell = gtk_column_view_cell_get_next (cell))
+ for (cell = self->first_cell; cell; cell = gtk_column_view_cell_widget_get_next (cell))
{
gtk_widget_queue_resize (GTK_WIDGET (cell));
}
@@ -460,7 +460,7 @@ gtk_column_view_column_measure (GtkColumnViewColumn *self,
if (self->minimum_size_request < 0)
{
- GtkColumnViewCell *cell;
+ GtkColumnViewCellWidget *cell;
int min, nat, cell_min, cell_nat;
if (self->header)
@@ -473,7 +473,7 @@ gtk_column_view_column_measure (GtkColumnViewColumn *self,
nat = 0;
}
- for (cell = self->first_cell; cell; cell = gtk_column_view_cell_get_next (cell))
+ for (cell = self->first_cell; cell; cell = gtk_column_view_cell_widget_get_next (cell))
{
gtk_widget_measure (GTK_WIDGET (cell),
GTK_ORIENTATION_HORIZONTAL,
@@ -532,12 +532,9 @@ gtk_column_view_column_create_cells (GtkColumnViewColumn *self)
GtkListItemBase *base;
GtkWidget *cell;
- if (!gtk_widget_get_root (row))
- continue;
-
list_item = GTK_COLUMN_VIEW_ROW_WIDGET (row);
base = GTK_LIST_ITEM_BASE (row);
- cell = gtk_column_view_cell_new (self);
+ cell = gtk_column_view_cell_widget_new (self, gtk_column_view_is_inert (self->view));
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),
@@ -550,7 +547,7 @@ static void
gtk_column_view_column_remove_cells (GtkColumnViewColumn *self)
{
while (self->first_cell)
- gtk_column_view_cell_remove (self->first_cell);
+ gtk_column_view_cell_widget_remove (self->first_cell);
}
static void
@@ -581,8 +578,7 @@ gtk_column_view_column_remove_header (GtkColumnViewColumn *self)
static void
gtk_column_view_column_ensure_cells (GtkColumnViewColumn *self)
{
- if (self->view && gtk_widget_get_root (GTK_WIDGET (self->view)) &&
- gtk_column_view_column_get_visible (self))
+ if (self->view && gtk_column_view_column_get_visible (self))
gtk_column_view_column_create_cells (self);
else
gtk_column_view_column_remove_cells (self);
@@ -632,13 +628,13 @@ void
gtk_column_view_column_set_position (GtkColumnViewColumn *self,
guint position)
{
- GtkColumnViewCell *cell;
+ GtkColumnViewCellWidget *cell;
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))
+ for (cell = self->first_cell; cell; cell = gtk_column_view_cell_widget_get_next (cell))
{
GtkColumnViewRowWidget *list_item;
@@ -664,6 +660,29 @@ gtk_column_view_column_get_factory (GtkColumnViewColumn *self)
return self->factory;
}
+void
+gtk_column_view_column_update_factory (GtkColumnViewColumn *self,
+ gboolean inert)
+{
+ GtkListItemFactory *factory;
+ GtkColumnViewCellWidget *cell;
+
+ if (self->factory == NULL)
+ return;
+
+ if (inert)
+ factory = NULL;
+ else
+ factory = self->factory;
+
+ for (cell = self->first_cell;
+ cell;
+ cell = gtk_column_view_cell_widget_get_next (cell))
+ {
+ gtk_list_factory_widget_set_factory (GTK_LIST_FACTORY_WIDGET (cell), factory);
+ }
+}
+
/**
* gtk_column_view_column_set_factory: (attributes org.gtk.Method.set_property=factory)
* @self: a `GtkColumnViewColumn`
@@ -679,9 +698,15 @@ gtk_column_view_column_set_factory (GtkColumnViewColumn *self,
g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
g_return_if_fail (factory == NULL || GTK_LIST_ITEM_FACTORY (factory));
+ if (self->factory && !factory)
+ gtk_column_view_column_update_factory (self, TRUE);
+
if (!g_set_object (&self->factory, factory))
return;
+ if (self->view && !gtk_column_view_is_inert (self->view))
+ gtk_column_view_column_update_factory (self, FALSE);
+
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FACTORY]);
}
diff --git a/gtk/gtkcolumnviewcolumnprivate.h b/gtk/gtkcolumnviewcolumnprivate.h
index aa7f1c73fd..fa0c66b2b5 100644
--- a/gtk/gtkcolumnviewcolumnprivate.h
+++ b/gtk/gtkcolumnviewcolumnprivate.h
@@ -21,7 +21,7 @@
#include "gtk/gtkcolumnviewcolumn.h"
-#include "gtk/gtkcolumnviewcellprivate.h"
+#include "gtk/gtkcolumnviewcellwidgetprivate.h"
void gtk_column_view_column_set_column_view (GtkColumnViewColumn *self,
@@ -31,12 +31,14 @@ void gtk_column_view_column_set_position (GtkColu
guint position);
void gtk_column_view_column_add_cell (GtkColumnViewColumn *self,
- GtkColumnViewCell *cell);
+ GtkColumnViewCellWidget *cell);
void gtk_column_view_column_remove_cell (GtkColumnViewColumn *self,
- GtkColumnViewCell *cell);
-GtkColumnViewCell * gtk_column_view_column_get_first_cell (GtkColumnViewColumn *self);
+ GtkColumnViewCellWidget *cell);
+GtkColumnViewCellWidget * gtk_column_view_column_get_first_cell (GtkColumnViewColumn *self);
GtkWidget * gtk_column_view_column_get_header (GtkColumnViewColumn *self);
+void gtk_column_view_column_update_factory (GtkColumnViewColumn *self,
+ gboolean inert);
void gtk_column_view_column_queue_resize (GtkColumnViewColumn *self);
void gtk_column_view_column_measure (GtkColumnViewColumn *self,
int *minimum,
diff --git a/gtk/gtkcolumnviewprivate.h b/gtk/gtkcolumnviewprivate.h
index 679b582aed..1a3061e332 100644
--- a/gtk/gtkcolumnviewprivate.h
+++ b/gtk/gtkcolumnviewprivate.h
@@ -26,6 +26,8 @@
#include "gtk/gtkcolumnviewsorterprivate.h"
#include "gtk/gtkcolumnviewrowwidgetprivate.h"
+gboolean gtk_column_view_is_inert (GtkColumnView *self);
+
GtkColumnViewRowWidget *gtk_column_view_get_header_widget (GtkColumnView *self);
GtkListView * gtk_column_view_get_list_view (GtkColumnView *self);
diff --git a/gtk/gtkcolumnviewrow.c b/gtk/gtkcolumnviewrow.c
new file mode 100644
index 0000000000..1570d626a0
--- /dev/null
+++ b/gtk/gtkcolumnviewrow.c
@@ -0,0 +1,477 @@
+/*
+ * Copyright © 2023 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 "gtkcolumnviewrowprivate.h"
+
+
+/**
+ * GtkColumnViewRow:
+ *
+ * `GtkColumnViewRow` is used by [class@Gtk.ColumnView] to allow configuring
+ * how rows are displayed.
+ *
+ * It is not used to set the widgets displayed in the individual cells. For that
+ * see [method@GtkColumnViewColumn.set_factory] and [class@GtkColumnViewCell].
+ *
+ * Since: 4.12
+ */
+
+struct _GtkColumnViewRowClass
+{
+ GObjectClass parent_class;
+};
+
+enum
+{
+ PROP_0,
+ PROP_ACTIVATABLE,
+ PROP_FOCUSABLE,
+ PROP_ITEM,
+ PROP_POSITION,
+ PROP_SELECTABLE,
+ PROP_SELECTED,
+
+ N_PROPS
+};
+
+G_DEFINE_TYPE (GtkColumnViewRow, gtk_column_view_row, G_TYPE_OBJECT)
+
+static GParamSpec *properties[N_PROPS] = { NULL, };
+
+static void
+gtk_column_view_row_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkColumnViewRow *self = GTK_COLUMN_VIEW_ROW (object);
+
+ switch (property_id)
+ {
+ case PROP_ACTIVATABLE:
+ g_value_set_boolean (value, self->activatable);
+ break;
+
+ case PROP_FOCUSABLE:
+ g_value_set_boolean (value, self->focusable);
+ break;
+
+ case PROP_ITEM:
+ if (self->owner)
+ g_value_set_object (value, gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self->owner)));
+ break;
+
+ case PROP_POSITION:
+ if (self->owner)
+ g_value_set_uint (value, gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self->owner)));
+ else
+ g_value_set_uint (value, GTK_INVALID_LIST_POSITION);
+ break;
+
+ case PROP_SELECTABLE:
+ g_value_set_boolean (value, self->selectable);
+ break;
+
+ case PROP_SELECTED:
+ if (self->owner)
+ g_value_set_boolean (value, gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self->owner)));
+ else
+ g_value_set_boolean (value, FALSE);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_column_view_row_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkColumnViewRow *self = GTK_COLUMN_VIEW_ROW (object);
+
+ switch (property_id)
+ {
+ case PROP_ACTIVATABLE:
+ gtk_column_view_row_set_activatable (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_FOCUSABLE:
+ gtk_column_view_row_set_focusable (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_SELECTABLE:
+ gtk_column_view_row_set_selectable (self, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_column_view_row_class_init (GtkColumnViewRowClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->get_property = gtk_column_view_row_get_property;
+ gobject_class->set_property = gtk_column_view_row_set_property;
+
+ /**
+ * GtkColumnViewRow:activatable: (attributes org.gtk.Property.get=gtk_column_view_row_get_activatable org.gtk.Property.set=gtk_column_view_row_set_activatable)
+ *
+ * If the row can be activated by the user.
+ *
+ * Since: 4.12
+ */
+ properties[PROP_ACTIVATABLE] =
+ g_param_spec_boolean ("activatable", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkColumnViewRow:focusable: (attributes org.gtk.Property.get=gtk_column_view_row_get_focusable org.gtk.Property.set=gtk_column_view_row_set_focusable)
+ *
+ * If the row can be focused with the keyboard.
+ *
+ * Since: 4.12
+ */
+ properties[PROP_FOCUSABLE] =
+ g_param_spec_boolean ("focusable", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkColumnViewRow:item: (attributes org.gtk.Property.get=gtk_column_view_row_get_item)
+ *
+ * The item for this row.
+ *
+ * Since: 4.12
+ */
+ properties[PROP_ITEM] =
+ g_param_spec_object ("item", NULL, NULL,
+ G_TYPE_OBJECT,
+ G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkColumnViewRow:position: (attributes org.gtk.Property.get=gtk_column_view_row_get_position)
+ *
+ * Position of the row.
+ *
+ * Since: 4.12
+ */
+ properties[PROP_POSITION] =
+ g_param_spec_uint ("position", NULL, NULL,
+ 0, G_MAXUINT, GTK_INVALID_LIST_POSITION,
+ G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkColumnViewRow:selectable: (attributes org.gtk.Property.get=gtk_column_view_row_get_selectable org.gtk.Property.set=gtk_column_view_row_set_selectable)
+ *
+ * If the row can be selected by the user.
+ *
+ * Since: 4.12
+ */
+ properties[PROP_SELECTABLE] =
+ g_param_spec_boolean ("selectable", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkColumnViewRow:selected: (attributes org.gtk.Property.get=gtk_column_view_row_get_selected)
+ *
+ * If the item in the row is currently selected.
+ *
+ * Since: 4.12
+ */
+ properties[PROP_SELECTED] =
+ g_param_spec_boolean ("selected", NULL, NULL,
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (gobject_class, N_PROPS, properties);
+}
+
+static void
+gtk_column_view_row_init (GtkColumnViewRow *self)
+{
+ self->selectable = TRUE;
+ self->activatable = TRUE;
+ self->focusable = TRUE;
+}
+
+GtkColumnViewRow *
+gtk_column_view_row_new (void)
+{
+ return g_object_new (GTK_TYPE_COLUMN_VIEW_ROW, NULL);
+}
+
+void
+gtk_column_view_row_do_notify (GtkColumnViewRow *column_view_row,
+ gboolean notify_item,
+ gboolean notify_position,
+ gboolean notify_selected)
+{
+ GObject *object = G_OBJECT (column_view_row);
+
+ if (notify_item)
+ g_object_notify_by_pspec (object, properties[PROP_ITEM]);
+ if (notify_position)
+ g_object_notify_by_pspec (object, properties[PROP_POSITION]);
+ if (notify_selected)
+ g_object_notify_by_pspec (object, properties[PROP_SELECTED]);
+}
+
+/**
+ * gtk_column_view_row_get_item: (attributes org.gtk.Method.get_property=item)
+ * @self: a `GtkColumnViewRow`
+ *
+ * Gets the model item that associated with @self.
+ *
+ * If @self is unbound, this function returns %NULL.
+ *
+ * Returns: (nullable) (transfer none) (type GObject): The item displayed
+ *
+ * Since: 4.12
+ **/
+gpointer
+gtk_column_view_row_get_item (GtkColumnViewRow *self)
+{
+ g_return_val_if_fail (GTK_IS_COLUMN_VIEW_ROW (self), NULL);
+
+ if (self->owner == NULL)
+ return NULL;
+
+ return gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self->owner));
+}
+
+/**
+ * gtk_column_view_row_get_position: (attributes org.gtk.Method.get_property=position)
+ * @self: a `GtkColumnViewRow`
+ *
+ * Gets the position in the model that @self currently displays.
+ *
+ * If @self is unbound, %GTK_INVALID_LIST_POSITION is returned.
+ *
+ * Returns: The position of this row
+ *
+ * Since: 4.12
+ */
+guint
+gtk_column_view_row_get_position (GtkColumnViewRow *self)
+{
+ g_return_val_if_fail (GTK_IS_COLUMN_VIEW_ROW (self), GTK_INVALID_LIST_POSITION);
+
+ if (self->owner == NULL)
+ return GTK_INVALID_LIST_POSITION;
+
+ return gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self->owner));
+}
+
+/**
+ * gtk_column_view_row_get_selected: (attributes org.gtk.Method.get_property=selected)
+ * @self: a `GtkColumnViewRow`
+ *
+ * Checks if the item is selected that this row corresponds to.
+ *
+ * The selected state is maintained by the list widget and its model
+ * and cannot be set otherwise.
+ *
+ * Returns: %TRUE if the item is selected.
+ *
+ * Since: 4.12
+ */
+gboolean
+gtk_column_view_row_get_selected (GtkColumnViewRow *self)
+{
+ g_return_val_if_fail (GTK_IS_COLUMN_VIEW_ROW (self), FALSE);
+
+ if (self->owner == NULL)
+ return FALSE;
+
+ return gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self->owner));
+}
+
+/**
+ * gtk_column_view_row_get_selectable: (attributes org.gtk.Method.get_property=selectable)
+ * @self: a `GtkColumnViewRow`
+ *
+ * Checks if the row has been set to be selectable via
+ * gtk_column_view_row_set_selectable().
+ *
+ * Do not confuse this function with [method@Gtk.ColumnViewRow.get_selected].
+ *
+ * Returns: %TRUE if the row is selectable
+ *
+ * Since: 4.12
+ */
+gboolean
+gtk_column_view_row_get_selectable (GtkColumnViewRow *self)
+{
+ g_return_val_if_fail (GTK_IS_COLUMN_VIEW_ROW (self), FALSE);
+
+ return self->selectable;
+}
+
+/**
+ * gtk_column_view_row_set_selectable: (attributes org.gtk.Method.set_property=selectable)
+ * @self: a `GtkColumnViewRow`
+ * @selectable: if the row should be selectable
+ *
+ * Sets @self to be selectable.
+ *
+ * If a row is selectable, clicking on the row or using the keyboard
+ * will try to select or unselect the row. Whether this succeeds is up to
+ * the model to determine, as it is managing the selected state.
+ *
+ * Note that this means that making a row non-selectable has no
+ * influence on the selected state at all. A non-selectable row
+ * may still be selected.
+ *
+ * By default, rows are selectable.
+ *
+ * Since: 4.12
+ */
+void
+gtk_column_view_row_set_selectable (GtkColumnViewRow *self,
+ gboolean selectable)
+{
+ g_return_if_fail (GTK_IS_COLUMN_VIEW_ROW (self));
+
+ if (self->selectable == selectable)
+ return;
+
+ self->selectable = selectable;
+
+ if (self->owner)
+ gtk_list_factory_widget_set_selectable (GTK_LIST_FACTORY_WIDGET (self->owner), selectable);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTABLE]);
+}
+
+/**
+ * gtk_column_view_row_get_activatable: (attributes org.gtk.Method.get_property=activatable)
+ * @self: a `GtkColumnViewRow`
+ *
+ * Checks if the row has been set to be activatable via
+ * gtk_column_view_row_set_activatable().
+ *
+ * Returns: %TRUE if the row is activatable
+ *
+ * Since: 4.12
+ */
+gboolean
+gtk_column_view_row_get_activatable (GtkColumnViewRow *self)
+{
+ g_return_val_if_fail (GTK_IS_COLUMN_VIEW_ROW (self), FALSE);
+
+ return self->activatable;
+}
+
+/**
+ * gtk_column_view_row_set_activatable: (attributes org.gtk.Method.set_property=activatable)
+ * @self: a `GtkColumnViewRow`
+ * @activatable: if the row should be activatable
+ *
+ * Sets @self to be activatable.
+ *
+ * If a row is activatable, double-clicking on the row, using
+ * the Return key or calling gtk_widget_activate() will activate
+ * the row. Activating instructs the containing columnview to
+ * emit the [signal@Gtk.ColumnView::activate] signal.
+ *
+ * By default, row are activatable.
+ *
+ * Since: 4.12
+ */
+void
+gtk_column_view_row_set_activatable (GtkColumnViewRow *self,
+ gboolean activatable)
+{
+ g_return_if_fail (GTK_IS_COLUMN_VIEW_ROW (self));
+
+ if (self->activatable == activatable)
+ return;
+
+ self->activatable = activatable;
+
+ if (self->owner)
+ gtk_list_factory_widget_set_activatable (GTK_LIST_FACTORY_WIDGET (self->owner), activatable);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIVATABLE]);
+}
+
+/**
+ * gtk_column_view_row_get_focusable: (attributes org.gtk.Method.get_property=focusable)
+ * @self: a `GtkColumnViewRow`
+ *
+ * Checks if a row item has been set to be focusable via
+ * gtk_column_view_row_set_focusable().
+ *
+ * Returns: %TRUE if the row is focusable
+ *
+ * Since: 4.12
+ */
+gboolean
+gtk_column_view_row_get_focusable (GtkColumnViewRow *self)
+{
+ g_return_val_if_fail (GTK_IS_COLUMN_VIEW_ROW (self), FALSE);
+
+ return self->focusable;
+}
+
+/**
+ * gtk_column_view_row_set_focusable: (attributes org.gtk.Method.set_property=focusable)
+ * @self: a `GtkColumnViewRow`
+ * @focusable: if the row should be focusable
+ *
+ * Sets @self to be focusable.
+ *
+ * If a row is focusable, it can be focused using the keyboard.
+ * This works similar to [method@Gtk.Widget.set_focusable].
+ *
+ * Note that if row are not focusable, the contents of cells can still be focused if
+ * they are focusable.
+ *
+ * By default, rows are focusable.
+ *
+ * Since: 4.12
+ */
+void
+gtk_column_view_row_set_focusable (GtkColumnViewRow *self,
+ gboolean focusable)
+{
+ g_return_if_fail (GTK_IS_COLUMN_VIEW_ROW (self));
+
+ if (self->focusable == focusable)
+ return;
+
+ self->focusable = focusable;
+
+ if (self->owner)
+ gtk_widget_set_focusable (GTK_WIDGET (self->owner), focusable);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FOCUSABLE]);
+}
diff --git a/gtk/gtkcolumnviewrow.h b/gtk/gtkcolumnviewrow.h
new file mode 100644
index 0000000000..99fb7c9a7b
--- /dev/null
+++ b/gtk/gtkcolumnviewrow.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2023 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>
+ */
+
+#pragma once
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtktypes.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COLUMN_VIEW_ROW (gtk_column_view_row_get_type ())
+GDK_AVAILABLE_IN_4_12
+GDK_DECLARE_INTERNAL_TYPE(GtkColumnViewRow, gtk_column_view_row, GTK, COLUMN_VIEW_ROW, GObject);
+
+GDK_AVAILABLE_IN_4_12
+gpointer gtk_column_view_row_get_item (GtkColumnViewRow *self);
+GDK_AVAILABLE_IN_4_12
+guint gtk_column_view_row_get_position (GtkColumnViewRow *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_12
+gboolean gtk_column_view_row_get_selected (GtkColumnViewRow *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_12
+gboolean gtk_column_view_row_get_selectable (GtkColumnViewRow *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_12
+void gtk_column_view_row_set_selectable (GtkColumnViewRow *self,
+ gboolean selectable);
+GDK_AVAILABLE_IN_4_12
+gboolean gtk_column_view_row_get_activatable (GtkColumnViewRow *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_12
+void gtk_column_view_row_set_activatable (GtkColumnViewRow *self,
+ gboolean activatable);
+GDK_AVAILABLE_IN_4_12
+gboolean gtk_column_view_row_get_focusable (GtkColumnViewRow *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_12
+void gtk_column_view_row_set_focusable (GtkColumnViewRow *self,
+ gboolean focusable);
+
+G_END_DECLS
+
diff --git a/gtk/gtkcolumnviewrowprivate.h b/gtk/gtkcolumnviewrowprivate.h
new file mode 100644
index 0000000000..4370231884
--- /dev/null
+++ b/gtk/gtkcolumnviewrowprivate.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright © 2023 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>
+ */
+
+#pragma once
+
+#include "gtkcolumnviewrow.h"
+
+#include "gtkcolumnviewrowwidgetprivate.h"
+
+G_BEGIN_DECLS
+
+struct _GtkColumnViewRow
+{
+ GObject parent_instance;
+
+ GtkColumnViewRowWidget *owner; /* has a reference */
+
+ guint activatable : 1;
+ guint selectable : 1;
+ guint focusable : 1;
+};
+
+GtkColumnViewRow * gtk_column_view_row_new (void);
+
+void gtk_column_view_row_do_notify (GtkColumnViewRow *self,
+ gboolean notify_item,
+ gboolean notify_position,
+ gboolean notify_selected);
+
+
+G_END_DECLS
+
diff --git a/gtk/gtkcolumnviewrowwidget.c b/gtk/gtkcolumnviewrowwidget.c
index 234759f036..62cec81b0e 100644
--- a/gtk/gtkcolumnviewrowwidget.c
+++ b/gtk/gtkcolumnviewrowwidget.c
@@ -23,8 +23,9 @@
#include "gtkbinlayout.h"
#include "gtkcolumnviewprivate.h"
-#include "gtkcolumnviewcellprivate.h"
+#include "gtkcolumnviewcellwidgetprivate.h"
#include "gtkcolumnviewcolumnprivate.h"
+#include "gtkcolumnviewrowprivate.h"
#include "gtkcolumnviewtitleprivate.h"
#include "gtklistitemfactoryprivate.h"
#include "gtklistbaseprivate.h"
@@ -56,8 +57,8 @@ gtk_column_view_row_widget_is_header (GtkColumnViewRowWidget *self)
static GtkColumnViewColumn *
gtk_column_view_row_child_get_column (GtkWidget *child)
{
- if (GTK_IS_COLUMN_VIEW_CELL (child))
- return gtk_column_view_cell_get_column (GTK_COLUMN_VIEW_CELL (child));
+ if (GTK_IS_COLUMN_VIEW_CELL_WIDGET (child))
+ return gtk_column_view_cell_widget_get_column (GTK_COLUMN_VIEW_CELL_WIDGET (child));
else
return gtk_column_view_title_get_column (GTK_COLUMN_VIEW_TITLE (child));
@@ -88,8 +89,6 @@ gtk_column_view_row_widget_update (GtkListItemBase *base,
gboolean selected)
{
GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (base);
- GtkListFactoryWidget *fw = GTK_LIST_FACTORY_WIDGET (base);
- gboolean selectable, activatable;
GtkWidget *child;
if (gtk_column_view_row_widget_is_header (self))
@@ -97,31 +96,99 @@ gtk_column_view_row_widget_update (GtkListItemBase *base,
GTK_LIST_ITEM_BASE_CLASS (gtk_column_view_row_widget_parent_class)->update (base, position, item, selected);
- /* This really does not belong here, but doing better
- * requires considerable plumbing that we don't have now,
- * and something like this is needed to fix the filechooser
- * in select_folder mode.
- */
- selectable = TRUE;
- activatable = TRUE;
-
for (child = gtk_widget_get_first_child (GTK_WIDGET (self));
child;
child = gtk_widget_get_next_sibling (child))
{
gtk_list_item_base_update (GTK_LIST_ITEM_BASE (child), position, item, selected);
-
- selectable &= gtk_list_factory_widget_get_selectable (GTK_LIST_FACTORY_WIDGET (child));
- activatable &= gtk_list_factory_widget_get_activatable (GTK_LIST_FACTORY_WIDGET (child));
}
+}
+
+static gpointer
+gtk_column_view_row_widget_create_object (GtkListFactoryWidget *fw)
+{
+ return gtk_column_view_row_new ();
+}
+
+static void
+gtk_column_view_row_widget_setup_object (GtkListFactoryWidget *fw,
+ gpointer object)
+{
+ GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (fw);
+ GtkColumnViewRow *row = object;
+
+ g_assert (!gtk_column_view_row_widget_is_header (self));
+
+ GTK_LIST_FACTORY_WIDGET_CLASS (gtk_column_view_row_widget_parent_class)->setup_object (fw, object);
+
+ row->owner = self;
+
+ gtk_list_factory_widget_set_activatable (fw, row->activatable);
+ gtk_list_factory_widget_set_selectable (fw, row->selectable);
+ gtk_widget_set_focusable (GTK_WIDGET (self), row->focusable);
+
+ gtk_column_view_row_do_notify (row,
+ gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
+ gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)) != GTK_INVALID_LIST_POSITION,
+ gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self)));
+}
+
+static void
+gtk_column_view_row_widget_teardown_object (GtkListFactoryWidget *fw,
+ gpointer object)
+{
+ GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (fw);
+ GtkColumnViewRow *row = object;
+
+ g_assert (!gtk_column_view_row_widget_is_header (self));
+
+ GTK_LIST_FACTORY_WIDGET_CLASS (gtk_column_view_row_widget_parent_class)->teardown_object (fw, object);
+
+ row->owner = NULL;
+
+ gtk_list_factory_widget_set_activatable (fw, FALSE);
+ gtk_list_factory_widget_set_selectable (fw, FALSE);
+ gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
- gtk_list_factory_widget_set_selectable (fw, selectable);
- gtk_list_factory_widget_set_activatable (fw, activatable);
+ gtk_column_view_row_do_notify (row,
+ gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
+ gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)) != GTK_INVALID_LIST_POSITION,
+ gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self)));
+}
+
+static void
+gtk_column_view_row_widget_update_object (GtkListFactoryWidget *fw,
+ gpointer object,
+ guint position,
+ gpointer item,
+ gboolean selected)
+{
+ GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (fw);
+ GtkListItemBase *base = GTK_LIST_ITEM_BASE (self);
+ GtkColumnViewRow *row = object;
+ /* Track notify manually instead of freeze/thaw_notify for performance reasons. */
+ gboolean notify_item = FALSE, notify_position = FALSE, notify_selected = FALSE;
+
+ g_assert (!gtk_column_view_row_widget_is_header (self));
+
+ /* FIXME: It's kinda evil to notify external objects from here... */
+ notify_item = gtk_list_item_base_get_item (base) != item;
+ notify_position = gtk_list_item_base_get_position (base) != position;
+ notify_selected = gtk_list_item_base_get_selected (base) != selected;
+
+ GTK_LIST_FACTORY_WIDGET_CLASS (gtk_column_view_row_widget_parent_class)->update_object (fw,
+ object,
+ position,
+ item,
+ selected);
+
+ if (row)
+ gtk_column_view_row_do_notify (row, notify_item, notify_position, notify_selected);
}
static GtkWidget *
gtk_column_view_next_focus_widget (GtkWidget *widget,
- GtkWidget *child,
+ GtkWidget *current,
GtkDirectionType direction)
{
gboolean forward;
@@ -149,17 +216,27 @@ gtk_column_view_next_focus_widget (GtkWidget *widget,
if (forward)
{
- if (child)
- return gtk_widget_get_next_sibling (child);
- else
+ if (current == NULL)
+ return widget;
+ else if (current == widget)
return gtk_widget_get_first_child (widget);
+ else
+ return gtk_widget_get_next_sibling (current);
}
else
{
- if (child)
- return gtk_widget_get_prev_sibling (child);
- else
+ if (current == NULL)
return gtk_widget_get_last_child (widget);
+ else if (current == widget)
+ return NULL;
+ else
+ {
+ current = gtk_widget_get_prev_sibling (current);
+ if (current)
+ return current;
+ else
+ return widget;
+ }
}
}
@@ -168,76 +245,53 @@ gtk_column_view_row_widget_focus (GtkWidget *widget,
GtkDirectionType direction)
{
GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (widget);
- GtkWidget *child, *focus_child;
+ GtkWidget *child, *current;
GtkColumnView *view;
- /* 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;
+ current = gtk_widget_get_focus_child (widget);
view = gtk_column_view_row_widget_get_column_view (self);
if (gtk_column_view_get_tab_behavior (view) == GTK_LIST_TAB_CELL &&
(direction == GTK_DIR_TAB_FORWARD || direction == GTK_DIR_TAB_BACKWARD))
{
- if (focus_child || gtk_widget_is_focus (widget))
+ if (current || gtk_widget_is_focus (widget))
return FALSE;
}
- if (focus_child == NULL)
+ if (current == NULL)
{
GtkColumnViewColumn *focus_column = gtk_column_view_get_focus_column (view);
if (focus_column)
{
- focus_child = gtk_column_view_row_widget_find_child (self, focus_column);
- if (focus_child && gtk_widget_child_focus (focus_child, direction))
+ current = gtk_column_view_row_widget_find_child (self, focus_column);
+ if (current && gtk_widget_child_focus (current, direction))
return TRUE;
}
}
- for (child = gtk_column_view_next_focus_widget (widget, focus_child, direction);
+ if (gtk_widget_is_focus (widget))
+ current = widget;
+
+ for (child = gtk_column_view_next_focus_widget (widget, current, direction);
child;
child = gtk_column_view_next_focus_widget (widget, child, direction))
{
- if (gtk_widget_child_focus (child, direction))
- return TRUE;
- }
-
- switch (direction)
- {
- case GTK_DIR_TAB_FORWARD:
- case GTK_DIR_TAB_BACKWARD:
- gtk_column_view_set_focus_column (view, NULL);
- break;
-
- case GTK_DIR_LEFT:
- case GTK_DIR_RIGHT:
- return TRUE;
-
- default:
- g_assert_not_reached ();
- case GTK_DIR_UP:
- case GTK_DIR_DOWN:
- break;
+ if (child == widget)
+ {
+ if (gtk_widget_grab_focus_self (widget))
+ {
+ gtk_column_view_set_focus_column (view, NULL);
+ return TRUE;
+ }
+ }
+ else if (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);
+ return FALSE;
}
static gboolean
@@ -259,6 +313,12 @@ gtk_column_view_row_widget_grab_focus (GtkWidget *widget)
else
focus_child = NULL;
+ if (gtk_widget_grab_focus_self (widget))
+ {
+ gtk_column_view_set_focus_column (view, NULL);
+ return TRUE;
+ }
+
for (child = focus_child ? gtk_widget_get_next_sibling (focus_child) : gtk_widget_get_first_child (widget);
child != focus_child;
child = child ? gtk_widget_get_next_sibling (child) : gtk_widget_get_first_child (widget))
@@ -272,10 +332,7 @@ gtk_column_view_row_widget_grab_focus (GtkWidget *widget)
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);
+ return FALSE;
}
static void
@@ -294,56 +351,17 @@ gtk_column_view_row_widget_set_focus_child (GtkWidget *widget,
}
static void
-gtk_column_view_row_widget_root (GtkWidget *widget)
+gtk_column_view_row_widget_dispose (GObject *object)
{
- GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (widget);
-
- GTK_WIDGET_CLASS (gtk_column_view_row_widget_parent_class)->root (widget);
-
- if (!gtk_column_view_row_widget_is_header (self))
- {
- GtkListItemBase *base = GTK_LIST_ITEM_BASE (self);
- GListModel *columns;
- guint i;
-
- columns = gtk_column_view_get_columns (gtk_column_view_row_widget_get_column_view (self));
-
- for (i = 0; i < g_list_model_get_n_items (columns); i++)
- {
- GtkColumnViewColumn *column = g_list_model_get_item (columns, i);
-
- if (gtk_column_view_column_get_visible (column))
- {
- GtkWidget *cell;
-
- cell = gtk_column_view_cell_new (column);
- gtk_column_view_row_widget_add_child (self, 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),
- gtk_list_item_base_get_selected (base));
- }
-
- g_object_unref (column);
- }
- }
-}
-
-static void
-gtk_column_view_row_widget_unroot (GtkWidget *widget)
-{
- GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (widget);
+ GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (object);
GtkWidget *child;
- if (!gtk_column_view_row_widget_is_header (self))
+ while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))))
{
- while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))))
- {
- gtk_column_view_row_widget_remove_child (self, child);
- }
+ gtk_column_view_row_widget_remove_child (self, child);
}
- GTK_WIDGET_CLASS (gtk_column_view_row_widget_parent_class)->unroot (widget);
+ G_OBJECT_CLASS (gtk_column_view_row_widget_parent_class)->dispose (object);
}
static void
@@ -479,8 +497,15 @@ add_arrow_bindings (GtkWidgetClass *widget_class,
static void
gtk_column_view_row_widget_class_init (GtkColumnViewRowWidgetClass *klass)
{
+ GtkListFactoryWidgetClass *factory_class = GTK_LIST_FACTORY_WIDGET_CLASS (klass);
GtkListItemBaseClass *base_class = GTK_LIST_ITEM_BASE_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ factory_class->create_object = gtk_column_view_row_widget_create_object;
+ factory_class->setup_object = gtk_column_view_row_widget_setup_object;
+ factory_class->update_object = gtk_column_view_row_widget_update_object;
+ factory_class->teardown_object = gtk_column_view_row_widget_teardown_object;
base_class->update = gtk_column_view_row_widget_update;
@@ -489,8 +514,8 @@ gtk_column_view_row_widget_class_init (GtkColumnViewRowWidgetClass *klass)
widget_class->set_focus_child = gtk_column_view_row_widget_set_focus_child;
widget_class->measure = gtk_column_view_row_widget_measure;
widget_class->size_allocate = gtk_column_view_row_widget_allocate;
- widget_class->root = gtk_column_view_row_widget_root;
- widget_class->unroot = gtk_column_view_row_widget_unroot;
+
+ object_class->dispose = gtk_column_view_row_widget_dispose;
add_arrow_bindings (widget_class, GDK_KEY_Left, GTK_DIR_LEFT);
add_arrow_bindings (widget_class, GDK_KEY_Right, GTK_DIR_RIGHT);
@@ -507,9 +532,11 @@ gtk_column_view_row_widget_init (GtkColumnViewRowWidget *self)
}
GtkWidget *
-gtk_column_view_row_widget_new (gboolean is_header)
+gtk_column_view_row_widget_new (GtkListItemFactory *factory,
+ gboolean is_header)
{
return g_object_new (GTK_TYPE_COLUMN_VIEW_ROW_WIDGET,
+ "factory", factory,
"css-name", is_header ? "header" : "row",
"selectable", TRUE,
"activatable", TRUE,
diff --git a/gtk/gtkcolumnviewrowwidgetprivate.h b/gtk/gtkcolumnviewrowwidgetprivate.h
index 5cc4aa1dad..4174fb8601 100644
--- a/gtk/gtkcolumnviewrowwidgetprivate.h
+++ b/gtk/gtkcolumnviewrowwidgetprivate.h
@@ -45,7 +45,8 @@ struct _GtkColumnViewRowWidgetClass
GType gtk_column_view_row_widget_get_type (void) G_GNUC_CONST;
-GtkWidget * gtk_column_view_row_widget_new (gboolean is_header);
+GtkWidget * gtk_column_view_row_widget_new (GtkListItemFactory *factory,
+ gboolean is_header);
void gtk_column_view_row_widget_add_child (GtkColumnViewRowWidget *self,
GtkWidget *child);
diff --git a/gtk/gtkcolumnviewtitle.c b/gtk/gtkcolumnviewtitle.c
index 6c7f729f95..43ae56224f 100644
--- a/gtk/gtkcolumnviewtitle.c
+++ b/gtk/gtkcolumnviewtitle.c
@@ -24,6 +24,8 @@
#include "gtkcolumnviewprivate.h"
#include "gtkcolumnviewcolumnprivate.h"
#include "gtkcolumnviewsorterprivate.h"
+#include "gtkcssboxesprivate.h"
+#include "gtkcssnodeprivate.h"
#include "gtkprivate.h"
#include "gtklabel.h"
#include "gtkwidgetprivate.h"
@@ -32,8 +34,6 @@
#include "gtkgestureclick.h"
#include "gtkpopovermenu.h"
#include "gtknative.h"
-#include "gtkcssnodeprivate.h"
-#include "gtkcssnumbervalueprivate.h"
struct _GtkColumnViewTitle
{
@@ -55,34 +55,19 @@ struct _GtkColumnViewTitleClass
G_DEFINE_TYPE (GtkColumnViewTitle, gtk_column_view_title, GTK_TYPE_WIDGET)
static int
-get_number (GtkCssValue *value)
-{
- double d = _gtk_css_number_value_get (value, 100);
-
- if (d < 1)
- return ceil (d);
- else
- return floor (d);
-}
-
-static int
unadjust_width (GtkWidget *widget,
int width)
{
- GtkCssStyle *style;
- int widget_margins;
- int css_extra;
-
- style = gtk_css_node_get_style (gtk_widget_get_css_node (widget));
- css_extra = get_number (style->size->margin_left) +
- get_number (style->size->margin_right) +
- get_number (style->border->border_left_width) +
- get_number (style->border->border_right_width) +
- get_number (style->size->padding_left) +
- get_number (style->size->padding_right);
- widget_margins = widget->priv->margin.left + widget->priv->margin.right;
-
- return MAX (0, width - widget_margins - css_extra);
+ GtkCssBoxes boxes;
+
+ if (width <= -1)
+ return -1;
+
+ gtk_css_boxes_init_border_box (&boxes,
+ gtk_css_node_get_style (gtk_widget_get_css_node (widget)),
+ 0, 0,
+ width, 100000);
+ return MAX (0, floor (gtk_css_boxes_get_content_rect (&boxes)->size.width));
}
static void
@@ -96,19 +81,24 @@ gtk_column_view_title_measure (GtkWidget *widget,
{
GtkColumnViewTitle *self = GTK_COLUMN_VIEW_TITLE (widget);
GtkWidget *child = gtk_widget_get_first_child (widget);
- int fixed_width = gtk_column_view_column_get_fixed_width (self->column);
- int unadj_width;
+ int fixed_width, unadj_width;
+ fixed_width = gtk_column_view_column_get_fixed_width (self->column);
unadj_width = unadjust_width (widget, fixed_width);
if (orientation == GTK_ORIENTATION_VERTICAL)
{
if (fixed_width > -1)
{
+ int min;
+
if (for_size == -1)
for_size = unadj_width;
else
for_size = MIN (for_size, unadj_width);
+
+ gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, &min, NULL, NULL, NULL);
+ for_size = MAX (for_size, min);
}
}
diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c
index ace31f4bd8..cc7136f156 100644
--- a/gtk/gtkfilechooserwidget.c
+++ b/gtk/gtkfilechooserwidget.c
@@ -28,6 +28,7 @@
#include "gtkdropdown.h"
#include "gtkcolumnview.h"
#include "gtkcolumnviewcolumn.h"
+#include "gtkcolumnviewrow.h"
#include "gtkcssnumbervalueprivate.h"
#include "gtkdroptarget.h"
#include "gtkentry.h"
@@ -2023,6 +2024,20 @@ column_view_get_file_type (GtkListItem *item,
return get_type_information (impl, info);
}
+static void
+column_view_row_bind (GtkListItemFactory *factory,
+ GtkColumnViewRow *row,
+ gpointer unused)
+{
+ GFileInfo *info;
+ gboolean selectable;
+
+ info = gtk_column_view_row_get_item (row);
+ selectable = g_file_info_get_attribute_boolean (info, "filechooser::selectable");
+
+ gtk_column_view_row_set_selectable (row, selectable);
+}
+
static char *
file_chooser_get_location (GtkFileChooserWidget *impl,
GFileInfo *info)
@@ -6798,8 +6813,8 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, column_view_location_column);
gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, column_view_size_column);
gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, column_view_time_column);
- gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, column_view_type_column);
gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, filter_combo_hbox);
+ gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, column_view_type_column);
gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, filter_combo);
gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, extra_align);
gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, extra_and_filters);
@@ -6840,6 +6855,7 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
gtk_widget_class_bind_template_callback (widget_class, column_view_get_location);
gtk_widget_class_bind_template_callback (widget_class, column_view_get_size);
gtk_widget_class_bind_template_callback (widget_class, column_view_get_tooltip_text);
+ gtk_widget_class_bind_template_callback (widget_class, column_view_row_bind);
gtk_widget_class_set_css_name (widget_class, I_("filechooser"));
diff --git a/gtk/gtklistitem.c b/gtk/gtklistitem.c
index a44752a4da..267b9ea6c5 100644
--- a/gtk/gtklistitem.c
+++ b/gtk/gtklistitem.c
@@ -21,6 +21,7 @@
#include "gtklistitemprivate.h"
+#include "gtkcolumnviewcell.h"
/**
* GtkListItem:
@@ -41,16 +42,12 @@
* The [property@Gtk.ListItem:item] property is not %NULL.
*/
-struct _GtkListItemClass
-{
- GObjectClass parent_class;
-};
-
enum
{
PROP_0,
PROP_ACTIVATABLE,
PROP_CHILD,
+ PROP_FOCUSABLE,
PROP_ITEM,
PROP_POSITION,
PROP_SELECTABLE,
@@ -92,6 +89,10 @@ gtk_list_item_get_property (GObject *object,
g_value_set_object (value, self->child);
break;
+ case PROP_FOCUSABLE:
+ g_value_set_boolean (value, self->focusable);
+ break;
+
case PROP_ITEM:
if (self->owner)
g_value_set_object (value, gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self->owner)));
@@ -139,6 +140,10 @@ gtk_list_item_set_property (GObject *object,
gtk_list_item_set_child (self, g_value_get_object (value));
break;
+ case PROP_FOCUSABLE:
+ gtk_list_item_set_focusable (self, g_value_get_boolean (value));
+ break;
+
case PROP_SELECTABLE:
gtk_list_item_set_selectable (self, g_value_get_boolean (value));
break;
@@ -179,6 +184,18 @@ gtk_list_item_class_init (GtkListItemClass *klass)
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
+ * GtkListItem:focusable: (attributes org.gtk.Property.get=gtk_list_item_get_focusable org.gtk.Property.set=gtk_list_item_set_focusable)
+ *
+ * If the item can be focused with the keyboard.
+ *
+ * Since: 4.12
+ */
+ properties[PROP_FOCUSABLE] =
+ g_param_spec_boolean ("focusable", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
* GtkListItem:item: (attributes org.gtk.Property.get=gtk_list_item_get_item)
*
* Displayed item.
@@ -226,6 +243,7 @@ gtk_list_item_init (GtkListItem *self)
{
self->selectable = TRUE;
self->activatable = TRUE;
+ self->focusable = TRUE;
}
GtkListItem *
@@ -265,10 +283,12 @@ gtk_list_item_get_item (GtkListItem *self)
{
g_return_val_if_fail (GTK_IS_LIST_ITEM (self), NULL);
- if (self->owner == NULL)
+ if (self->owner)
+ return gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self->owner));
+ else if (GTK_IS_COLUMN_VIEW_CELL (self))
+ return gtk_column_view_cell_get_item (GTK_COLUMN_VIEW_CELL (self));
+ else
return NULL;
-
- return gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self->owner));
}
/**
@@ -285,6 +305,9 @@ gtk_list_item_get_child (GtkListItem *self)
{
g_return_val_if_fail (GTK_IS_LIST_ITEM (self), NULL);
+ if (GTK_IS_COLUMN_VIEW_CELL (self))
+ return gtk_column_view_cell_get_child (GTK_COLUMN_VIEW_CELL (self));
+
return self->child;
}
@@ -306,6 +329,12 @@ gtk_list_item_set_child (GtkListItem *self,
g_return_if_fail (GTK_IS_LIST_ITEM (self));
g_return_if_fail (child == NULL || gtk_widget_get_parent (child) == NULL);
+ if (GTK_IS_COLUMN_VIEW_CELL (self))
+ {
+ gtk_column_view_cell_set_child (GTK_COLUMN_VIEW_CELL (self), child);
+ return;
+ }
+
if (self->child == child)
return;
@@ -315,6 +344,12 @@ gtk_list_item_set_child (GtkListItem *self,
{
g_object_ref_sink (child);
self->child = child;
+
+ /* Workaround that hopefully achieves good enough backwards
+ * compatibility with people using expanders.
+ */
+ if (!self->focusable_set)
+ gtk_list_item_set_focusable (self, !gtk_widget_get_focusable (child));
}
if (self->owner)
@@ -338,10 +373,12 @@ gtk_list_item_get_position (GtkListItem *self)
{
g_return_val_if_fail (GTK_IS_LIST_ITEM (self), GTK_INVALID_LIST_POSITION);
- if (self->owner == NULL)
+ if (self->owner)
+ return gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self->owner));
+ else if (GTK_IS_COLUMN_VIEW_CELL (self))
+ return gtk_column_view_cell_get_position (GTK_COLUMN_VIEW_CELL (self));
+ else
return GTK_INVALID_LIST_POSITION;
-
- return gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self->owner));
}
/**
@@ -360,10 +397,12 @@ gtk_list_item_get_selected (GtkListItem *self)
{
g_return_val_if_fail (GTK_IS_LIST_ITEM (self), FALSE);
- if (self->owner == NULL)
+ if (self->owner)
+ return gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self->owner));
+ else if (GTK_IS_COLUMN_VIEW_CELL (self))
+ return gtk_column_view_cell_get_selected (GTK_COLUMN_VIEW_CELL (self));
+ else
return FALSE;
-
- return gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self->owner));
}
/**
@@ -468,3 +507,58 @@ gtk_list_item_set_activatable (GtkListItem *self,
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIVATABLE]);
}
+
+/**
+ * gtk_list_item_get_focusable: (attributes org.gtk.Method.get_property=focusable)
+ * @self: a `GtkListItem`
+ *
+ * Checks if a list item has been set to be focusable via
+ * gtk_list_item_set_focusable().
+ *
+ * Returns: %TRUE if the item is focusable
+ *
+ * Since: 4.12
+ */
+gboolean
+gtk_list_item_get_focusable (GtkListItem *self)
+{
+ g_return_val_if_fail (GTK_IS_LIST_ITEM (self), FALSE);
+
+ return self->focusable;
+}
+
+/**
+ * gtk_list_item_set_focusable: (attributes org.gtk.Method.set_property=focusable)
+ * @self: a `GtkListItem`
+ * @focusable: if the item should be focusable
+ *
+ * Sets @self to be focusable.
+ *
+ * If an item is focusable, it can be focused using the keyboard.
+ * This works similar to [method@Gtk.Widget.set_focusable].
+ *
+ * Note that if items are not focusable, the keyboard cannot be used to activate
+ * them and selecting only works if one of the listitem's children is focusable.
+ *
+ * By default, list items are focusable.
+ *
+ * Since: 4.12
+ */
+void
+gtk_list_item_set_focusable (GtkListItem *self,
+ gboolean focusable)
+{
+ g_return_if_fail (GTK_IS_LIST_ITEM (self));
+
+ self->focusable_set = TRUE;
+
+ if (self->focusable == focusable)
+ return;
+
+ self->focusable = focusable;
+
+ if (self->owner)
+ gtk_widget_set_focusable (GTK_WIDGET (self->owner), focusable);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FOCUSABLE]);
+}
diff --git a/gtk/gtklistitem.h b/gtk/gtklistitem.h
index f66da44d19..9c5fb844e1 100644
--- a/gtk/gtklistitem.h
+++ b/gtk/gtklistitem.h
@@ -27,18 +27,9 @@
G_BEGIN_DECLS
-#define GTK_TYPE_LIST_ITEM (gtk_list_item_get_type ())
-#define GTK_LIST_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_LIST_ITEM, GtkListItem))
-#define GTK_LIST_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_LIST_ITEM, GtkListItemClass))
-#define GTK_IS_LIST_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_LIST_ITEM))
-#define GTK_IS_LIST_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_LIST_ITEM))
-#define GTK_LIST_ITEM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_LIST_ITEM, GtkListItemClass))
-
-typedef struct _GtkListItem GtkListItem;
-typedef struct _GtkListItemClass GtkListItemClass;
-
+#define GTK_TYPE_LIST_ITEM (gtk_list_item_get_type ())
GDK_AVAILABLE_IN_ALL
-GType gtk_list_item_get_type (void) G_GNUC_CONST;
+GDK_DECLARE_INTERNAL_TYPE (GtkListItem, gtk_list_item, GTK, LIST_ITEM, GObject)
GDK_AVAILABLE_IN_ALL
gpointer gtk_list_item_get_item (GtkListItem *self);
@@ -56,6 +47,11 @@ gboolean gtk_list_item_get_activatable (GtkListItem
GDK_AVAILABLE_IN_ALL
void gtk_list_item_set_activatable (GtkListItem *self,
gboolean activatable);
+GDK_AVAILABLE_IN_4_12
+gboolean gtk_list_item_get_focusable (GtkListItem *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_12
+void gtk_list_item_set_focusable (GtkListItem *self,
+ gboolean focusable);
GDK_AVAILABLE_IN_ALL
void gtk_list_item_set_child (GtkListItem *self,
@@ -63,7 +59,5 @@ void gtk_list_item_set_child (GtkListItem
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_list_item_get_child (GtkListItem *self);
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkListItem, g_object_unref)
-
G_END_DECLS
diff --git a/gtk/gtklistitemprivate.h b/gtk/gtklistitemprivate.h
index af56b37a37..60e122bc10 100644
--- a/gtk/gtklistitemprivate.h
+++ b/gtk/gtklistitemprivate.h
@@ -22,6 +22,8 @@
#include "gtklistitem.h"
#include "gtklistitemwidgetprivate.h"
+#include "gtkcolumnviewcellwidgetprivate.h"
+#include "gtkversion.h"
G_BEGIN_DECLS
@@ -35,6 +37,15 @@ struct _GtkListItem
guint activatable : 1;
guint selectable : 1;
+ guint focusable : 1;
+#if !GTK_CHECK_VERSION (5, 0, 0)
+ guint focusable_set : 1;
+#endif
+};
+
+struct _GtkListItemClass
+{
+ GObjectClass parent_class;
};
GtkListItem * gtk_list_item_new (void);
diff --git a/gtk/gtklistitemwidget.c b/gtk/gtklistitemwidget.c
index ccd56c1b3a..b5fac6f7b8 100644
--- a/gtk/gtklistitemwidget.c
+++ b/gtk/gtklistitemwidget.c
@@ -28,6 +28,7 @@
#include "gtklistitemprivate.h"
#include "gtklistbaseprivate.h"
#include "gtkwidget.h"
+#include "gtkwidgetprivate.h"
G_DEFINE_TYPE (GtkListItemWidget, gtk_list_item_widget, GTK_TYPE_LIST_FACTORY_WIDGET)
@@ -35,59 +36,65 @@ static gboolean
gtk_list_item_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;
+ GtkWidget *child = gtk_widget_get_first_child (widget);
- 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_get_focus_child (widget))
{
- if (gtk_widget_child_focus (child, direction))
- return TRUE;
+ /* focus is in the child */
+ if (direction == GTK_DIR_TAB_BACKWARD)
+ return gtk_widget_grab_focus_self (widget);
+ else
+ return FALSE;
+ }
+ else if (gtk_widget_is_focus (widget))
+ {
+ /* The widget has focus */
+ if (direction == GTK_DIR_TAB_FORWARD)
+ {
+ if (child)
+ return gtk_widget_child_focus (child, direction);
+ }
+
+ return FALSE;
+ }
+ else
+ {
+ /* focus coming in from the outside */
+ if (direction == GTK_DIR_TAB_BACKWARD)
+ {
+ if (child &&
+ gtk_widget_child_focus (child, direction))
+ return TRUE;
+
+ return gtk_widget_grab_focus_self (widget);
+ }
+ else
+ {
+ if (gtk_widget_grab_focus_self (widget))
+ return TRUE;
+
+ if (child &&
+ gtk_widget_child_focus (child, direction))
+ return TRUE;
+
+ return FALSE;
+ }
}
-
- if (focus_child)
- return FALSE;
-
- if (gtk_widget_is_focus (widget))
- return FALSE;
-
- return gtk_widget_grab_focus (widget);
}
static gboolean
gtk_list_item_widget_grab_focus (GtkWidget *widget)
{
- GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (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_WIDGET_CLASS (gtk_list_item_widget_parent_class)->grab_focus (widget))
+ return TRUE;
- if (!gtk_list_factory_widget_get_selectable (GTK_LIST_FACTORY_WIDGET (self)))
- return FALSE;
+ child = gtk_widget_get_first_child (widget);
+ if (child && gtk_widget_grab_focus (child))
+ return TRUE;
- return GTK_WIDGET_CLASS (gtk_list_item_widget_parent_class)->grab_focus (widget);
+ return FALSE;
}
static gpointer
@@ -111,6 +118,7 @@ gtk_list_item_widget_setup_object (GtkListFactoryWidget *fw,
gtk_list_factory_widget_set_activatable (fw, list_item->activatable);
gtk_list_factory_widget_set_selectable (fw, list_item->selectable);
+ gtk_widget_set_focusable (GTK_WIDGET (self), list_item->focusable);
gtk_list_item_do_notify (list_item,
gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
@@ -133,6 +141,7 @@ gtk_list_item_widget_teardown_object (GtkListFactoryWidget *fw,
gtk_list_factory_widget_set_activatable (fw, FALSE);
gtk_list_factory_widget_set_selectable (fw, FALSE);
+ gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
gtk_list_item_do_notify (list_item,
gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
diff --git a/gtk/gtktreeexpander.c b/gtk/gtktreeexpander.c
index 86230e4028..66a520b95c 100644
--- a/gtk/gtktreeexpander.c
+++ b/gtk/gtktreeexpander.c
@@ -45,6 +45,11 @@
* "listitem.toggle-expand" actions are provided to allow adding custom
* UI for managing expanded state.
*
+ * It is important to mention that you want to set the
+ * [property@Gtk.ListItem:focusable] property to FALSE when using this
+ * widget, as you want the keyboard focus to be in the treexpander, and not
+ * inside the list to make use of the keybindings.
+ *
* The `GtkTreeListModel` must be set to not be passthrough. Then it
* will provide [class@Gtk.TreeListRow] items which can be set via
* [method@Gtk.TreeExpander.set_list_row] on the expander.
diff --git a/gtk/meson.build b/gtk/meson.build
index bfe69528a3..b3975fb3fc 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -38,7 +38,7 @@ gtk_private_sources = files([
'gtkcolorpickershell.c',
'gtkcolorscale.c',
'gtkcolorswatch.c',
- 'gtkcolumnviewcell.c',
+ 'gtkcolumnviewcellwidget.c',
'gtkcolumnviewrowwidget.c',
'gtkcolumnviewtitle.c',
'gtkconstraintexpression.c',
@@ -187,7 +187,9 @@ gtk_public_sources = files([
'gtkcolordialogbutton.c',
'gtkcolorutils.c',
'gtkcolumnview.c',
+ 'gtkcolumnviewcell.c',
'gtkcolumnviewcolumn.c',
+ 'gtkcolumnviewrow.c',
'gtkcolumnviewsorter.c',
'gtkcomposetable.c',
'gtkconstraintguide.c',
@@ -440,7 +442,9 @@ gtk_public_headers = files([
'gtkcolordialogbutton.h',
'gtkcolorutils.h',
'gtkcolumnview.h',
+ 'gtkcolumnviewcell.h',
'gtkcolumnviewcolumn.h',
+ 'gtkcolumnviewrow.h',
'gtkcolumnviewsorter.h',
'gtkconstraintguide.h',
'gtkconstraintlayout.h',
diff --git a/gtk/ui/gtkfilechooserwidget.ui b/gtk/ui/gtkfilechooserwidget.ui
index 41f03a6def..71a0d1d258 100644
--- a/gtk/ui/gtkfilechooserwidget.ui
+++ b/gtk/ui/gtkfilechooserwidget.ui
@@ -169,6 +169,11 @@
<style>
<class name="complex"/>
</style>
+ <property name="row-factory">
+ <object class="GtkSignalListItemFactory">
+ <signal name="bind" handler="column_view_row_bind" swapped="no"/>
+ </object>
+ </property>
<signal name="activate" handler="browse_files_view_row_activated_cb" swapped="no"/>
<signal name="keynav-failed" handler="browse_files_view_keynav_failed_cb"/>
<child>
@@ -181,18 +186,18 @@
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <template class="GtkListItem">
+ <template class="GtkColumnViewCell">
<property name="child">
<object class="GtkFileChooserCell">
<binding name="item">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</binding>
- <property name="list-item">GtkListItem</property>
+ <property name="list-item">GtkColumnViewCell</property>
<child>
<object class="GtkBox">
<binding name="tooltip-text">
<closure type="gchararray" function="column_view_get_tooltip_text">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</closure>
</binding>
<child>
@@ -200,7 +205,7 @@
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<binding name="file-info">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</binding>
</object>
</child>
@@ -211,7 +216,7 @@
<property name="min-chars">10</property>
<binding name="text">
<closure type="gchararray" function="column_view_get_file_display_name">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</closure>
</binding>
</object>
@@ -239,13 +244,13 @@
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <template class="GtkListItem">
+ <template class="GtkColumnViewCell">
<property name="child">
<object class="GtkFileChooserCell">
<binding name="item">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</binding>
- <property name="list-item">GtkListItem</property>
+ <property name="list-item">GtkColumnViewCell</property>
<child>
<object class="GtkInscription">
<property name="hexpand">1</property>
@@ -255,12 +260,12 @@
<property name="margin-end">6</property>
<binding name="text">
<closure type="gchararray" function="column_view_get_location">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</closure>
</binding>
<binding name="tooltip-text">
<closure type="gchararray" function="column_view_get_tooltip_text">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</closure>
</binding>
</object>
@@ -283,25 +288,25 @@
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <template class="GtkListItem">
+ <template class="GtkColumnViewCell">
<property name="child">
<object class="GtkFileChooserCell">
<binding name="item">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</binding>
- <property name="list-item">GtkListItem</property>
+ <property name="list-item">GtkColumnViewCell</property>
<child>
<object class="GtkLabel">
<property name="hexpand">1</property>
<property name="xalign">0</property>
<binding name="label">
<closure type="gchararray" function="column_view_get_size">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</closure>
</binding>
<binding name="tooltip-text">
<closure type="gchararray" function="column_view_get_tooltip_text">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</closure>
</binding>
</object>
@@ -366,26 +371,26 @@
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <template class="GtkListItem">
+ <template class="GtkColumnViewCell">
<property name="child">
<object class="GtkFileChooserCell" id="file_chooser_cell">
<binding name="item">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</binding>
- <property name="list-item">GtkListItem</property>
+ <property name="list-item">GtkColumnViewCell</property>
<child>
<object class="GtkBox">
<property name="spacing">6</property>
<binding name="tooltip-text">
<closure type="gchararray" function="column_view_get_tooltip_text">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</closure>
</binding>
<child>
<object class="GtkLabel">
<binding name="label">
<closure type="gchararray" function="column_view_get_file_date">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</closure>
</binding>
</object>
@@ -395,7 +400,7 @@
<property name="visible" bind-source="file_chooser_cell" bind-property="show-time" bind-flags="sync-create"/>
<binding name="label">
<closure type="gchararray" function="column_view_get_file_time">
- <lookup name="item">GtkListItem</lookup>
+ <lookup name="item">GtkColumnViewCell</lookup>
</closure>
</binding>
</object>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1d87546711..2fe8f10bf5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -142,7 +142,7 @@ gtk/gtkcolorplane.c
gtk/gtkcolorscale.c
gtk/gtkcolorswatch.c
gtk/gtkcolumnview.c
-gtk/gtkcolumnviewcell.c
+gtk/gtkcolumnviewcellwidget.c
gtk/gtkcolumnviewcolumn.c
gtk/gtkcolumnviewtitle.c
gtk/gtkconstraint.c
diff --git a/tests/testcolumnview.c b/tests/testcolumnview.c
index b09888de8e..932de560aa 100644
--- a/tests/testcolumnview.c
+++ b/tests/testcolumnview.c
@@ -423,11 +423,11 @@ const char *ui_file =
" <property name='bytes'><![CDATA[\n"
"<?xml version='1.0' encoding='UTF-8'?>\n"
"<interface>\n"
-" <template class='GtkListItem'>\n"
+" <template class='GtkColumnViewCell'>\n"
" <property name='child'>\n"
" <object class='GtkTreeExpander' id='expander'>\n"
" <binding name='list-row'>\n"
-" <lookup name='item'>GtkListItem</lookup>\n"
+" <lookup name='item'>GtkColumnViewCell</lookup>\n"
" </binding>\n"
" <property name='child'>\n"
" <object class='GtkBox'>\n"
@@ -477,12 +477,12 @@ const char *ui_file =
#define SIMPLE_STRING_FACTORY(attr, type) \
"<?xml version='1.0' encoding='UTF-8'?>\n" \
"<interface>\n" \
-" <template class='GtkListItem'>\n" \
+" <template class='GtkColumnViewCell'>\n" \
" <property name='child'>\n" \
" <object class='GtkInscription'>\n" \
" <binding name='text'>\n" \
" <closure type='gchararray' function='get_string'>\n" \
-" <lookup name='item' type='GtkTreeListRow'><lookup name='item'>GtkListItem</lookup></lookup>\n" \
+" <lookup name='item' type='GtkTreeListRow'><lookup name='item'>GtkColumnViewCell</lookup></lookup>\n" \
" <constant type='gchararray'>" attr "</constant>" \
" </closure>\n" \
" </binding>\n" \
@@ -494,12 +494,12 @@ const char *ui_file =
#define BOOLEAN_FACTORY(attr) \
"<?xml version='1.0' encoding='UTF-8'?>\n" \
"<interface>\n" \
-" <template class='GtkListItem'>\n" \
+" <template class='GtkColumnViewCell'>\n" \
" <property name='child'>\n" \
" <object class='GtkCheckButton'>\n" \
" <binding name='active'>\n" \
" <closure type='gboolean' function='get_boolean'>\n" \
-" <lookup name='item' type='GtkTreeListRow'><lookup name='item'>GtkListItem</lookup></lookup>\n" \
+" <lookup name='item' type='GtkTreeListRow'><lookup name='item'>GtkColumnViewCell</lookup></lookup>\n" \
" <constant type='gchararray'>" attr "</constant>" \
" </closure>\n" \
" </binding>\n" \
@@ -511,12 +511,12 @@ const char *ui_file =
#define ICON_FACTORY(attr) \
"<?xml version='1.0' encoding='UTF-8'?>\n" \
"<interface>\n" \
-" <template class='GtkListItem'>\n" \
+" <template class='GtkColumnViewCell'>\n" \
" <property name='child'>\n" \
" <object class='GtkImage'>\n" \
" <binding name='gicon'>\n" \
" <closure type='GIcon' function='get_object'>\n" \
-" <lookup name='item' type='GtkTreeListRow'><lookup name='item'>GtkListItem</lookup></lookup>\n" \
+" <lookup name='item' type='GtkTreeListRow'><lookup name='item'>GtkColumnViewCell</lookup></lookup>\n" \
" <constant type='gchararray'>" attr "</constant>" \
" </closure>\n" \
" </binding>\n" \
diff --git a/tests/testdatatable.c b/tests/testdatatable.c
index 72de5829e4..6e3ca992d2 100644
--- a/tests/testdatatable.c
+++ b/tests/testdatatable.c
@@ -5,6 +5,11 @@
#include "frame-stats.h"
+static gboolean no_auto_scroll = FALSE;
+static gint n_columns = 20;
+static double scroll_pages = 0;
+
+
/* This is our dummy item for the model. */
#define DATA_TABLE_TYPE_ITEM (data_table_item_get_type ())
G_DECLARE_FINAL_TYPE (DataTableItem, data_table_item, DATA_TABLE, ITEM, GObject)
@@ -48,6 +53,18 @@ set_adjustment_to_fraction (GtkAdjustment *adjustment,
fraction * (upper - page_size));
}
+static void
+move_adjustment_by_pages (GtkAdjustment *adjustment,
+ double n_pages)
+{
+ double page_size = gtk_adjustment_get_page_size (adjustment);
+ double value = gtk_adjustment_get_value (adjustment);
+
+ value += page_size * n_pages;
+ /* the adjustment will clamp properly */
+ gtk_adjustment_set_value (adjustment, value);
+}
+
static gboolean
scroll_column_view (GtkWidget *column_view,
GdkFrameClock *frame_clock,
@@ -57,7 +74,10 @@ scroll_column_view (GtkWidget *column_view,
vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (column_view));
- set_adjustment_to_fraction (vadjustment, g_random_double ());
+ if (scroll_pages == 0.0)
+ set_adjustment_to_fraction (vadjustment, g_random_double ());
+ else
+ move_adjustment_by_pages (vadjustment, (g_random_double () * 2 - 1) * scroll_pages);
return TRUE;
}
@@ -172,9 +192,6 @@ parse_widget_arg (const gchar* option_name,
}
}
-static gboolean no_auto_scroll = FALSE;
-static gint n_columns = 20;
-
static GOptionEntry options[] = {
{
"widget",
@@ -203,6 +220,15 @@ static GOptionEntry options[] = {
"Column count",
"COUNT"
},
+ {
+ "pages",
+ 'p',
+ G_OPTION_FLAG_NONE,
+ G_OPTION_ARG_DOUBLE,
+ &scroll_pages,
+ "Maximum number of pages to scroll (or 0 for random)",
+ "COUNT"
+ },
{ NULL }
};