diff options
author | Benjamin Otte <otte.benjamin@googlemail.com> | 2022-05-03 22:05:47 +0000 |
---|---|---|
committer | Benjamin Otte <otte.benjamin@googlemail.com> | 2022-05-03 22:05:47 +0000 |
commit | 23fc3d9ecd7e350e8b1a226ed0f1a54c2b42a549 (patch) | |
tree | bac8e471a738749dcf3c72b73929625b6ccb33fc | |
parent | c645da00dc1b29a1d974f36cced0ed79831c55a8 (diff) | |
parent | 07299dd9c79ca171f2c8fa3ca60300b821b2c8a3 (diff) | |
download | gtk+-23fc3d9ecd7e350e8b1a226ed0f1a54c2b42a549.tar.gz |
Merge branch 'checkbutton-label' into 'main'
Expose GtkCheckButton label child for manipulation
Closes #4698
See merge request GNOME/gtk!4489
-rw-r--r-- | gtk/gtkcheckbutton.c | 162 | ||||
-rw-r--r-- | gtk/gtkcheckbutton.h | 5 |
2 files changed, 147 insertions, 20 deletions
diff --git a/gtk/gtkcheckbutton.c b/gtk/gtkcheckbutton.c index 4357a10010..d304fae93c 100644 --- a/gtk/gtkcheckbutton.c +++ b/gtk/gtkcheckbutton.c @@ -86,9 +86,10 @@ * ``` * * A `GtkCheckButton` has a main node with name checkbutton. If the - * [property@Gtk.CheckButton:label] property is set, it contains a label - * child. The indicator node is named check when no group is set, and - * radio if the checkbutton is grouped together with other checkbuttons. + * [property@Gtk.CheckButton:label] or [property@Gtk.CheckButton:child] + * properties are set, it contains a child widget. The indicator node + * is named check when no group is set, and radio if the checkbutton + * is grouped together with other checkbuttons. * * # Accessibility * @@ -97,11 +98,12 @@ typedef struct { GtkWidget *indicator_widget; - GtkWidget *label_widget; + GtkWidget *child; - guint inconsistent: 1; - guint active: 1; + guint inconsistent: 1; + guint active: 1; guint use_underline: 1; + guint child_type: 1; GtkCheckButton *group_next; GtkCheckButton *group_prev; @@ -116,6 +118,7 @@ enum { PROP_LABEL, PROP_INCONSISTENT, PROP_USE_UNDERLINE, + PROP_CHILD, /* actionable properties */ PROP_ACTION_NAME, @@ -129,6 +132,11 @@ enum { LAST_SIGNAL }; +enum { + LABEL_CHILD, + WIDGET_CHILD +}; + static void gtk_check_button_actionable_iface_init (GtkActionableInterface *iface); static guint signals[LAST_SIGNAL] = { 0 }; @@ -146,7 +154,7 @@ gtk_check_button_dispose (GObject *object) g_clear_object (&priv->action_helper); g_clear_pointer (&priv->indicator_widget, gtk_widget_unparent); - g_clear_pointer (&priv->label_widget, gtk_widget_unparent); + g_clear_pointer (&priv->child, gtk_widget_unparent); gtk_check_button_set_group (GTK_CHECK_BUTTON (object), NULL); @@ -226,6 +234,9 @@ gtk_check_button_set_property (GObject *object, case PROP_USE_UNDERLINE: gtk_check_button_set_use_underline (GTK_CHECK_BUTTON (object), g_value_get_boolean (value)); break; + case PROP_CHILD: + gtk_check_button_set_child (GTK_CHECK_BUTTON (object), g_value_get_object (value)); + break; case PROP_ACTION_NAME: gtk_check_button_set_action_name (GTK_ACTIONABLE (object), g_value_get_string (value)); break; @@ -260,6 +271,9 @@ gtk_check_button_get_property (GObject *object, case PROP_USE_UNDERLINE: g_value_set_boolean (value, gtk_check_button_get_use_underline (GTK_CHECK_BUTTON (object))); break; + case PROP_CHILD: + g_value_set_object (value, gtk_check_button_get_child (GTK_CHECK_BUTTON (object))); + break; case PROP_ACTION_NAME: g_value_set_string (value, gtk_action_helper_get_action_name (priv->action_helper)); break; @@ -489,6 +503,36 @@ gtk_check_button_focus (GtkWidget *widget, } static void +gtk_check_button_real_set_child (GtkCheckButton *self, + GtkWidget *child, + guint child_type) +{ + GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self); + + g_return_if_fail (GTK_IS_CHECK_BUTTON (self)); + + g_clear_pointer (&priv->child, gtk_widget_unparent); + + priv->child = child; + + if (priv->child) + { + gtk_widget_set_parent (priv->child, GTK_WIDGET (self)); + gtk_widget_insert_after (priv->child, GTK_WIDGET (self), priv->indicator_widget); + } + + if (child_type == priv->child_type) + return; + + priv->child_type = child_type; + if (child_type != LABEL_CHILD) + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LABEL]); + else + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CHILD]); + +} + +static void gtk_check_button_real_activate (GtkCheckButton *self) { GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self); @@ -592,6 +636,20 @@ gtk_check_button_class_init (GtkCheckButtonClass *class) FALSE, GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); + /** + * GtkCheckButton:child: (attributes org.gtk.Property.get=gtk_check_button_get_child org.gtk.Property.set=gtk_check_button_set_child) + * + * The child widget. + * + * Since: 4.8 + */ + props[PROP_CHILD] = + g_param_spec_object ("child", + P_("Child"), + P_("The child widget"), + GTK_TYPE_WIDGET, + GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); + g_object_class_install_properties (object_class, LAST_PROP, props); g_object_class_override_property (object_class, PROP_ACTION_NAME, "action-name"); @@ -856,7 +914,7 @@ gtk_check_button_set_active (GtkCheckButton *self, * gtk_check_button_get_label: (attributes org.gtk.Method.get_property=label) * @self: a `GtkCheckButton` * - * Returns the label of the check button. + * Returns the label of the check button or `NULL` if [property@CheckButton:child] is set. * * Returns: (nullable) (transfer none): The label @self shows next * to the indicator. If no label is shown, %NULL will be returned. @@ -868,8 +926,8 @@ gtk_check_button_get_label (GtkCheckButton *self) g_return_val_if_fail (GTK_IS_CHECK_BUTTON (self), ""); - if (priv->label_widget) - return gtk_label_get_label (GTK_LABEL (priv->label_widget)); + if (priv->child_type == LABEL_CHILD && priv->child != NULL) + return gtk_label_get_label (GTK_LABEL (priv->child)); return NULL; } @@ -891,33 +949,41 @@ gtk_check_button_set_label (GtkCheckButton *self, const char *label) { GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self); + GtkWidget *child; g_return_if_fail (GTK_IS_CHECK_BUTTON (self)); + g_object_freeze_notify (G_OBJECT (self)); + if (label == NULL || label[0] == '\0') { - g_clear_pointer (&priv->label_widget, gtk_widget_unparent); + gtk_check_button_real_set_child (self, NULL, LABEL_CHILD); gtk_widget_remove_css_class (GTK_WIDGET (self), "text-button"); } else { - if (!priv->label_widget) + if (priv->child_type != LABEL_CHILD || priv->child == NULL) { - priv->label_widget = gtk_label_new (NULL); - gtk_widget_set_hexpand (priv->label_widget, TRUE); - gtk_label_set_xalign (GTK_LABEL (priv->label_widget), 0.0f); - gtk_label_set_use_underline (GTK_LABEL (priv->label_widget), priv->use_underline); - gtk_widget_insert_after (priv->label_widget, GTK_WIDGET (self), priv->indicator_widget); + child = gtk_label_new (NULL); + gtk_widget_set_hexpand (child, TRUE); + gtk_label_set_xalign (GTK_LABEL (child), 0.0f); + if (priv->use_underline) + gtk_label_set_use_underline (GTK_LABEL (child), priv->use_underline); + gtk_check_button_real_set_child (self, GTK_WIDGET (child), LABEL_CHILD); } + gtk_widget_add_css_class (GTK_WIDGET (self), "text-button"); - gtk_label_set_label (GTK_LABEL (priv->label_widget), label); + gtk_label_set_label (GTK_LABEL (priv->child), label); } + gtk_accessible_update_property (GTK_ACCESSIBLE (self), GTK_ACCESSIBLE_PROPERTY_LABEL, label, -1); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LABEL]); + + g_object_thaw_notify (G_OBJECT (self)); } /** @@ -1045,8 +1111,64 @@ gtk_check_button_set_use_underline (GtkCheckButton *self, return; priv->use_underline = setting; - if (priv->label_widget) - gtk_label_set_use_underline (GTK_LABEL (priv->label_widget), priv->use_underline); + if (priv->child_type == LABEL_CHILD) + gtk_label_set_use_underline (GTK_LABEL (priv->child), priv->use_underline); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_USE_UNDERLINE]); } + +/** + * gtk_check_button_set_child: (attributes org.gtk.Method.set_property=child) + * @button: a `GtkCheckButton` + * @child: (nullable): the child widget + * + * Sets the child widget of @button. + * + * Note that by using this API, you take full responsibility for setting + * up the proper accessibility label and description information for @button. + * Most likely, you'll either set the accessibility label or description + * for @button explicitly, or you'll set a labelled-by or described-by + * relations from @child to @button. + * + * Since: 4.8 + */ +void +gtk_check_button_set_child (GtkCheckButton *button, + GtkWidget *child) +{ + g_return_if_fail (GTK_IS_CHECK_BUTTON (button)); + g_return_if_fail (child == NULL || GTK_IS_WIDGET (child)); + + g_object_freeze_notify (G_OBJECT (button)); + + gtk_widget_remove_css_class (GTK_WIDGET (button), "text-button"); + + gtk_check_button_real_set_child (button, child, WIDGET_CHILD); + + g_object_notify_by_pspec (G_OBJECT (button), props[PROP_CHILD]); + + g_object_thaw_notify (G_OBJECT (button)); +} + +/** + * gtk_check_button_get_child: (attributes org.gtk.Method.get_property=child) + * @button: a `GtkCheckButton` + * + * Gets the child widget of @button or `NULL` if [property@CheckButton:label] is set. + * + * Returns: (nullable) (transfer none): the child widget of @button + * + * Since: 4.8 + */ +GtkWidget * +gtk_check_button_get_child (GtkCheckButton *button) +{ + GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (button); + + g_return_val_if_fail (GTK_IS_CHECK_BUTTON (button), NULL); + + if (priv->child_type == WIDGET_CHILD) + return priv->child; + + return NULL; +} diff --git a/gtk/gtkcheckbutton.h b/gtk/gtkcheckbutton.h index b4d2c63459..91c8b8e998 100644 --- a/gtk/gtkcheckbutton.h +++ b/gtk/gtkcheckbutton.h @@ -95,6 +95,11 @@ gboolean gtk_check_button_get_use_underline (GtkCheckButton *self); GDK_AVAILABLE_IN_ALL void gtk_check_button_set_use_underline (GtkCheckButton *self, gboolean setting); +GDK_AVAILABLE_IN_4_8 +GtkWidget * gtk_check_button_get_child (GtkCheckButton *button); +GDK_AVAILABLE_IN_4_8 +void gtk_check_button_set_child (GtkCheckButton *button, + GtkWidget *child); G_END_DECLS |