From 2b578a24e4338fd7c96b6a45879be14feb945158 Mon Sep 17 00:00:00 2001 From: Corey Berla Date: Sat, 26 Nov 2022 21:02:14 -0800 Subject: [PATCH 1/3] treeexpander: Add hide-expander property When set to TRUE hide-expander hides the expander icon in a GtkTreeListRow. Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/4969 --- gtk/gtktreeexpander.c | 79 ++++++++++++++++++++++++++++++++++++++++++- gtk/gtktreeexpander.h | 5 +++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/gtk/gtktreeexpander.c b/gtk/gtktreeexpander.c index ef40403938..eb0a78f950 100644 --- a/gtk/gtktreeexpander.c +++ b/gtk/gtktreeexpander.c @@ -52,6 +52,13 @@ * [method@Gtk.TreeExpander.set_child] sets the widget that displays * the actual row contents. * + * `GtkTreeExpander` can be modified with properties such as [property@Gtk.indent-for-icon], + * [property@Gtk.indent-for-depth], and [property@Gtk.hide-expander] to achieve a + * different appearance. This can even be done to influence individual rows, for example + * by binding the [property@Gtk.hide-expander] property to the treelistrow's model's + * item count to hide the expander for rows without children, even if the row is + * expandable. + * * # CSS nodes * * ``` @@ -85,6 +92,7 @@ struct _GtkTreeExpander GtkWidget *expander_icon; guint notify_handler; + gboolean hide_expander; gboolean indent_for_icon; guint expand_timer; @@ -94,6 +102,7 @@ enum { PROP_0, PROP_CHILD, + PROP_HIDE_EXPANDER, PROP_ITEM, PROP_LIST_ROW, PROP_INDENT_FOR_ICON, @@ -170,7 +179,7 @@ gtk_tree_expander_update_for_list_row (GtkTreeExpander *self) guint i, depth; depth = gtk_tree_list_row_get_depth (self->list_row); - if (gtk_tree_list_row_is_expandable (self->list_row)) + if (gtk_tree_list_row_is_expandable (self->list_row) && !self->hide_expander) { if (self->expander_icon == NULL) { @@ -394,6 +403,10 @@ gtk_tree_expander_get_property (GObject *object, g_value_set_object (value, self->child); break; + case PROP_HIDE_EXPANDER: + g_value_set_boolean (value, gtk_tree_expander_get_hide_expander (self)); + break; + case PROP_ITEM: g_value_take_object (value, gtk_tree_expander_get_item (self)); break; @@ -426,6 +439,10 @@ gtk_tree_expander_set_property (GObject *object, gtk_tree_expander_set_child (self, g_value_get_object (value)); break; + case PROP_HIDE_EXPANDER: + gtk_tree_expander_set_hide_expander (self, g_value_get_boolean (value)); + break; + case PROP_LIST_ROW: gtk_tree_expander_set_list_row (self, g_value_get_object (value)); break; @@ -532,6 +549,23 @@ gtk_tree_expander_class_init (GtkTreeExpanderClass *klass) GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + /** + * GtkTreeExpander:hide-expander: (attributes org.gtk.Property.get=gtk_tree_expander_get_hide_expander org.gtk.Property.set=gtk_tree_expander_set_hide_expander) + * + * Whether the expander icon should be hidden in a GtkTreeListRow. + * Note that this property simply hides the icon. The actions and keybinding + * (i.e. collapse and expand) are not affected by this property. + * + * A common use for this property would be to bind to the number of children in a + * GtkTreeListRow's model in order to hide the expander when a row has no children. + * + * Since: 4.10 + */ + properties[PROP_HIDE_EXPANDER] = + g_param_spec_boolean ("hide-expander", NULL, NULL, + FALSE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + /** * GtkTreeExpander:item: (attributes org.gtk.Property.get=gtk_tree_expander_get_item) * @@ -891,3 +925,46 @@ gtk_tree_expander_set_indent_for_icon (GtkTreeExpander *self, g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INDENT_FOR_ICON]); } + +/** + * gtk_tree_expander_get_hide_expander: (attributes org.gtk.Method.get_property=hide-expander) + * @self: a `GtkTreeExpander` + * + * Gets whether the TreeExpander should be hidden in a GtkTreeListRow. + * + * Returns: TRUE if the expander icon should be hidden. Otherwise FALSE. + * + * Since: 4.10 + */ +gboolean +gtk_tree_expander_get_hide_expander (GtkTreeExpander *self) +{ + g_return_val_if_fail (GTK_IS_TREE_EXPANDER (self), FALSE); + + return self->hide_expander; +} + +/** + * gtk_tree_expander_set_hide_expander: (attributes org.gtk.Method.set_property=hide-expander) + * @self: a `GtkTreeExpander` widget + * @hide_expander: TRUE if the expander should be hidden. Otherwise FALSE. + * + * Sets whether the expander icon should be visible in a GtkTreeListRow. + * + * Since: 4.10 + */ +void +gtk_tree_expander_set_hide_expander (GtkTreeExpander *self, + gboolean hide_expander) +{ + g_return_if_fail (GTK_IS_TREE_EXPANDER (self)); + + if (hide_expander == self->hide_expander) + return; + + self->hide_expander = hide_expander; + + gtk_tree_expander_update_for_list_row (self); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HIDE_EXPANDER]); +} diff --git a/gtk/gtktreeexpander.h b/gtk/gtktreeexpander.h index eec33f091f..676185b176 100644 --- a/gtk/gtktreeexpander.h +++ b/gtk/gtktreeexpander.h @@ -55,6 +55,11 @@ gboolean gtk_tree_expander_get_indent_for_icon (GtkTreeExpander GDK_AVAILABLE_IN_4_6 void gtk_tree_expander_set_indent_for_icon (GtkTreeExpander *self, gboolean indent_for_icon); +GDK_AVAILABLE_IN_4_10 +gboolean gtk_tree_expander_get_hide_expander (GtkTreeExpander *self); +GDK_AVAILABLE_IN_4_10 +void gtk_tree_expander_set_hide_expander (GtkTreeExpander *self, + gboolean hide_expander); G_END_DECLS From 648b38761c11af8f9b70ac02140425c988091984 Mon Sep 17 00:00:00 2001 From: Corey Berla Date: Sat, 26 Nov 2022 21:28:22 -0800 Subject: [PATCH 2/3] treeexpander: Add indent-for-depth property When set to TRUE, indent-for-depth indents each level of depth with an additional indent --- gtk/gtktreeexpander.c | 68 ++++++++++++++++++++++++++++++++++++++++++- gtk/gtktreeexpander.h | 5 ++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/gtk/gtktreeexpander.c b/gtk/gtktreeexpander.c index eb0a78f950..23b3e04e23 100644 --- a/gtk/gtktreeexpander.c +++ b/gtk/gtktreeexpander.c @@ -93,6 +93,7 @@ struct _GtkTreeExpander guint notify_handler; gboolean hide_expander; + gboolean indent_for_depth; gboolean indent_for_icon; guint expand_timer; @@ -103,6 +104,7 @@ enum PROP_0, PROP_CHILD, PROP_HIDE_EXPANDER, + PROP_INDENT_FOR_DEPTH, PROP_ITEM, PROP_LIST_ROW, PROP_INDENT_FOR_ICON, @@ -178,7 +180,7 @@ gtk_tree_expander_update_for_list_row (GtkTreeExpander *self) GtkWidget *child; guint i, depth; - depth = gtk_tree_list_row_get_depth (self->list_row); + depth = self->indent_for_depth ? gtk_tree_list_row_get_depth (self->list_row) : 0; if (gtk_tree_list_row_is_expandable (self->list_row) && !self->hide_expander) { if (self->expander_icon == NULL) @@ -407,6 +409,10 @@ gtk_tree_expander_get_property (GObject *object, g_value_set_boolean (value, gtk_tree_expander_get_hide_expander (self)); break; + case PROP_INDENT_FOR_DEPTH: + g_value_set_boolean (value, gtk_tree_expander_get_indent_for_depth (self)); + break; + case PROP_ITEM: g_value_take_object (value, gtk_tree_expander_get_item (self)); break; @@ -443,6 +449,10 @@ gtk_tree_expander_set_property (GObject *object, gtk_tree_expander_set_hide_expander (self, g_value_get_boolean (value)); break; + case PROP_INDENT_FOR_DEPTH: + gtk_tree_expander_set_indent_for_depth (self, g_value_get_boolean (value)); + break; + case PROP_LIST_ROW: gtk_tree_expander_set_list_row (self, g_value_get_object (value)); break; @@ -566,6 +576,18 @@ gtk_tree_expander_class_init (GtkTreeExpanderClass *klass) FALSE, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + /** + * GtkTreeExpander:indent-for-depth: (attributes org.gtk.Property.get=gtk_tree_expander_get_indent_for_depth org.gtk.Property.set=gtk_tree_expander_set_indent_for_depth) + * + * TreeExpander indents the child according to its depth. + * + * Since: 4.10 + */ + properties[PROP_INDENT_FOR_DEPTH] = + g_param_spec_boolean ("indent-for-depth", NULL, NULL, + TRUE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + /** * GtkTreeExpander:item: (attributes org.gtk.Property.get=gtk_tree_expander_get_item) * @@ -731,6 +753,7 @@ gtk_tree_expander_init (GtkTreeExpander *self) gtk_widget_set_focusable (GTK_WIDGET (self), TRUE); self->indent_for_icon = TRUE; + self->indent_for_depth = TRUE; controller = gtk_drop_controller_motion_new (); g_signal_connect (controller, "enter", G_CALLBACK (gtk_tree_expander_drag_enter), self); @@ -883,6 +906,49 @@ gtk_tree_expander_set_list_row (GtkTreeExpander *self, g_object_thaw_notify (G_OBJECT (self)); } +/** + * gtk_tree_expander_get_indent_for_depth: (attributes org.gtk.Method.get_property=indent-for-depth) + * @self: a `GtkTreeExpander` + * + * TreeExpander indents each level of depth with an additional indent. + * + * Returns: TRUE if the child should be indented . Otherwise FALSE. + * + * Since: 4.10 + */ +gboolean +gtk_tree_expander_get_indent_for_depth (GtkTreeExpander *self) +{ + g_return_val_if_fail (GTK_IS_TREE_EXPANDER (self), FALSE); + + return self->indent_for_depth; +} + +/** + * gtk_tree_expander_set_indent_for_depth: (attributes org.gtk.Method.set_property=indent-for-depth) + * @self: a `GtkTreeExpander` widget + * @indent_for_depth: TRUE if the child should be indented. Otherwise FALSE. + * + * Sets if the TreeExpander should indent the child according to its depth. + * + * Since: 4.10 + */ +void +gtk_tree_expander_set_indent_for_depth (GtkTreeExpander *self, + gboolean indent_for_depth) +{ + g_return_if_fail (GTK_IS_TREE_EXPANDER (self)); + + if (indent_for_depth == self->indent_for_depth) + return; + + self->indent_for_depth = indent_for_depth; + + gtk_tree_expander_update_for_list_row (self); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INDENT_FOR_DEPTH]); +} + /** * gtk_tree_expander_get_indent_for_icon: (attributes org.gtk.Method.get_property=indent-for-icon) * @self: a `GtkTreeExpander` diff --git a/gtk/gtktreeexpander.h b/gtk/gtktreeexpander.h index 676185b176..f2d9e6e5d4 100644 --- a/gtk/gtktreeexpander.h +++ b/gtk/gtktreeexpander.h @@ -50,6 +50,11 @@ GtkTreeListRow * gtk_tree_expander_get_list_row (GtkTreeExpander GDK_AVAILABLE_IN_ALL void gtk_tree_expander_set_list_row (GtkTreeExpander *self, GtkTreeListRow *list_row); +GDK_AVAILABLE_IN_4_10 +gboolean gtk_tree_expander_get_indent_for_depth (GtkTreeExpander *self); +GDK_AVAILABLE_IN_4_10 +void gtk_tree_expander_set_indent_for_depth (GtkTreeExpander *self, + gboolean indent_for_depth); GDK_AVAILABLE_IN_4_6 gboolean gtk_tree_expander_get_indent_for_icon (GtkTreeExpander *self); GDK_AVAILABLE_IN_4_6 From 72bc97fff551a4d1170cd7336ab85a40d9714ae3 Mon Sep 17 00:00:00 2001 From: Corey Berla Date: Sun, 27 Nov 2022 12:22:30 -0800 Subject: [PATCH 3/3] treeexpander: Minor formatting changes --- gtk/gtktreeexpander.c | 44 +++++++++++++++++++++---------------------- gtk/gtktreeexpander.h | 28 +++++++++++++-------------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/gtk/gtktreeexpander.c b/gtk/gtktreeexpander.c index 23b3e04e23..cad8c8d8d0 100644 --- a/gtk/gtktreeexpander.c +++ b/gtk/gtktreeexpander.c @@ -105,9 +105,9 @@ enum PROP_CHILD, PROP_HIDE_EXPANDER, PROP_INDENT_FOR_DEPTH, + PROP_INDENT_FOR_ICON, PROP_ITEM, PROP_LIST_ROW, - PROP_INDENT_FOR_ICON, N_PROPS }; @@ -413,6 +413,10 @@ gtk_tree_expander_get_property (GObject *object, g_value_set_boolean (value, gtk_tree_expander_get_indent_for_depth (self)); break; + case PROP_INDENT_FOR_ICON: + g_value_set_boolean (value, gtk_tree_expander_get_indent_for_icon (self)); + break; + case PROP_ITEM: g_value_take_object (value, gtk_tree_expander_get_item (self)); break; @@ -421,10 +425,6 @@ gtk_tree_expander_get_property (GObject *object, g_value_set_object (value, self->list_row); break; - case PROP_INDENT_FOR_ICON: - g_value_set_boolean (value, gtk_tree_expander_get_indent_for_icon (self)); - break; - default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -453,14 +453,14 @@ gtk_tree_expander_set_property (GObject *object, gtk_tree_expander_set_indent_for_depth (self, g_value_get_boolean (value)); break; - case PROP_LIST_ROW: - gtk_tree_expander_set_list_row (self, g_value_get_object (value)); - break; - case PROP_INDENT_FOR_ICON: gtk_tree_expander_set_indent_for_icon (self, g_value_get_boolean (value)); break; + case PROP_LIST_ROW: + gtk_tree_expander_set_list_row (self, g_value_get_object (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -588,6 +588,18 @@ gtk_tree_expander_class_init (GtkTreeExpanderClass *klass) TRUE, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + /** + * GtkTreeExpander:indent-for-icon: (attributes org.gtk.Property.get=gtk_tree_expander_get_indent_for_icon org.gtk.Property.set=gtk_tree_expander_set_indent_for_icon) + * + * TreeExpander indents the child by the width of an expander-icon if it is not expandable. + * + * Since: 4.6 + */ + properties[PROP_INDENT_FOR_ICON] = + g_param_spec_boolean ("indent-for-icon", NULL, NULL, + TRUE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + /** * GtkTreeExpander:item: (attributes org.gtk.Property.get=gtk_tree_expander_get_item) * @@ -608,18 +620,6 @@ gtk_tree_expander_class_init (GtkTreeExpanderClass *klass) GTK_TYPE_TREE_LIST_ROW, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); - /** - * GtkTreeExpander:indent-for-icon: (attributes org.gtk.Property.get=gtk_tree_expander_get_indent_for_icon org.gtk.Property.set=gtk_tree_expander_set_indent_for_icon) - * - * TreeExpander indents the child by the width of an expander-icon if it is not expandable. - * - * Since: 4.6 - */ - properties[PROP_INDENT_FOR_ICON] = - g_param_spec_boolean ("indent-for-icon", NULL, NULL, - TRUE, - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - g_object_class_install_properties (gobject_class, N_PROPS, properties); /** @@ -978,7 +978,7 @@ gtk_tree_expander_get_indent_for_icon (GtkTreeExpander *self) */ void gtk_tree_expander_set_indent_for_icon (GtkTreeExpander *self, - gboolean indent_for_icon) + gboolean indent_for_icon) { g_return_if_fail (GTK_IS_TREE_EXPANDER (self)); diff --git a/gtk/gtktreeexpander.h b/gtk/gtktreeexpander.h index f2d9e6e5d4..bb4db67a4a 100644 --- a/gtk/gtktreeexpander.h +++ b/gtk/gtktreeexpander.h @@ -35,36 +35,36 @@ GDK_AVAILABLE_IN_ALL G_DECLARE_FINAL_TYPE (GtkTreeExpander, gtk_tree_expander, GTK, TREE_EXPANDER, GtkWidget) GDK_AVAILABLE_IN_ALL -GtkWidget * gtk_tree_expander_new (void); +GtkWidget * gtk_tree_expander_new (void); GDK_AVAILABLE_IN_ALL -GtkWidget * gtk_tree_expander_get_child (GtkTreeExpander *self); +GtkWidget * gtk_tree_expander_get_child (GtkTreeExpander *self); GDK_AVAILABLE_IN_ALL -void gtk_tree_expander_set_child (GtkTreeExpander *self, - GtkWidget *child); +void gtk_tree_expander_set_child (GtkTreeExpander *self, + GtkWidget *child); GDK_AVAILABLE_IN_ALL -gpointer gtk_tree_expander_get_item (GtkTreeExpander *self); +gpointer gtk_tree_expander_get_item (GtkTreeExpander *self); GDK_AVAILABLE_IN_ALL -GtkTreeListRow * gtk_tree_expander_get_list_row (GtkTreeExpander *self); +GtkTreeListRow * gtk_tree_expander_get_list_row (GtkTreeExpander *self); GDK_AVAILABLE_IN_ALL -void gtk_tree_expander_set_list_row (GtkTreeExpander *self, - GtkTreeListRow *list_row); +void gtk_tree_expander_set_list_row (GtkTreeExpander *self, + GtkTreeListRow *list_row); GDK_AVAILABLE_IN_4_10 gboolean gtk_tree_expander_get_indent_for_depth (GtkTreeExpander *self); GDK_AVAILABLE_IN_4_10 void gtk_tree_expander_set_indent_for_depth (GtkTreeExpander *self, gboolean indent_for_depth); GDK_AVAILABLE_IN_4_6 -gboolean gtk_tree_expander_get_indent_for_icon (GtkTreeExpander *self); +gboolean gtk_tree_expander_get_indent_for_icon (GtkTreeExpander *self); GDK_AVAILABLE_IN_4_6 -void gtk_tree_expander_set_indent_for_icon (GtkTreeExpander *self, - gboolean indent_for_icon); +void gtk_tree_expander_set_indent_for_icon (GtkTreeExpander *self, + gboolean indent_for_icon); GDK_AVAILABLE_IN_4_10 -gboolean gtk_tree_expander_get_hide_expander (GtkTreeExpander *self); +gboolean gtk_tree_expander_get_hide_expander (GtkTreeExpander *self); GDK_AVAILABLE_IN_4_10 -void gtk_tree_expander_set_hide_expander (GtkTreeExpander *self, - gboolean hide_expander); +void gtk_tree_expander_set_hide_expander (GtkTreeExpander *self, + gboolean hide_expander); G_END_DECLS