togglebutton: Add grouping

This is the replacement for groups of radiobuttons
with draw-indicator = FALSE.
This commit is contained in:
Matthias Clasen 2020-08-30 21:48:00 -04:00
parent b69e8d8e7b
commit 28d7f497ef
3 changed files with 134 additions and 0 deletions

View File

@ -3322,6 +3322,7 @@ gtk_toggle_button_new_with_mnemonic
gtk_toggle_button_toggled
gtk_toggle_button_get_active
gtk_toggle_button_set_active
gtk_toggle_button_set_group
<SUBSECTION Standard>
GTK_TOGGLE_BUTTON

View File

@ -101,6 +101,9 @@
typedef struct _GtkToggleButtonPrivate GtkToggleButtonPrivate;
struct _GtkToggleButtonPrivate
{
GtkToggleButton *group_next;
GtkToggleButton *group_prev;
guint active : 1;
};
@ -112,6 +115,7 @@ enum {
enum {
PROP_0,
PROP_ACTIVE,
PROP_GROUP,
NUM_PROPERTIES
};
@ -134,6 +138,9 @@ gtk_toggle_button_set_property (GObject *object,
case PROP_ACTIVE:
gtk_toggle_button_set_active (tb, g_value_get_boolean (value));
break;
case PROP_GROUP:
gtk_toggle_button_set_group (GTK_TOGGLE_BUTTON (object), g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -187,6 +194,50 @@ gtk_toggle_button_clicked (GtkButton *button)
gtk_toggle_button_set_active (toggle_button, !priv->active);
}
static void
gtk_toggle_button_dispose (GObject *object)
{
GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (object);
gtk_toggle_button_set_group (toggle_button, NULL);
G_OBJECT_CLASS (gtk_toggle_button_parent_class)->dispose (object);
}
static GtkToggleButton *
get_group_next (GtkToggleButton *self)
{
return ((GtkToggleButtonPrivate *)gtk_toggle_button_get_instance_private (self))->group_next;
}
static GtkToggleButton *
get_group_prev (GtkToggleButton *self)
{
return ((GtkToggleButtonPrivate *)gtk_toggle_button_get_instance_private (self))->group_prev;
}
static GtkToggleButton *
get_group_first (GtkToggleButton *self)
{
GtkToggleButton *group_first = NULL;
GtkToggleButton *iter;
/* Find first in group */
iter = self;
while (iter)
{
group_first = iter;
iter = get_group_prev (iter);
if (!iter)
break;
}
g_assert (group_first);
return group_first;
}
static void
gtk_toggle_button_class_init (GtkToggleButtonClass *class)
{
@ -194,6 +245,7 @@ gtk_toggle_button_class_init (GtkToggleButtonClass *class)
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
GtkButtonClass *button_class = GTK_BUTTON_CLASS (class);
gobject_class->dispose = gtk_toggle_button_dispose;
gobject_class->set_property = gtk_toggle_button_set_property;
gobject_class->get_property = gtk_toggle_button_get_property;
@ -210,6 +262,13 @@ gtk_toggle_button_class_init (GtkToggleButtonClass *class)
FALSE,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
toggle_button_props[PROP_GROUP] =
g_param_spec_object ("group",
P_("Group"),
P_("The toggle button whose group this widget belongs to."),
GTK_TYPE_TOGGLE_BUTTON,
GTK_PARAM_WRITABLE);
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, toggle_button_props);
/**
@ -313,6 +372,21 @@ gtk_toggle_button_set_active (GtkToggleButton *toggle_button,
if (priv->active == is_active)
return;
if (is_active && (priv->group_prev || priv->group_next))
{
GtkToggleButton *group_first = NULL;
GtkToggleButton *iter;
group_first = get_group_first (toggle_button);
g_assert (group_first);
/* Set all buttons in group to !active */
for (iter = group_first; iter; iter = get_group_next (iter))
gtk_toggle_button_set_active (iter, FALSE);
/* ... and the next code block will set this one to active */
}
priv->active = is_active;
if (is_active)
@ -363,3 +437,58 @@ gtk_toggle_button_toggled (GtkToggleButton *toggle_button)
g_signal_emit (toggle_button, toggle_button_signals[TOGGLED], 0);
}
/**
* gtk_toggle_button_set_group:
* @self: a #GtkToggleButton
* @group: (nullable) (transfer none): another #GtkToggleButton to
* form a group with
*
* Adds @self to the group of @group. In a group of multiple toggle buttons,
* only one button can be active at a time.
*/
void
gtk_toggle_button_set_group (GtkToggleButton *self,
GtkToggleButton *group)
{
GtkToggleButtonPrivate *priv = gtk_toggle_button_get_instance_private (self);
GtkToggleButtonPrivate *group_priv = gtk_toggle_button_get_instance_private (group);
g_return_if_fail (GTK_IS_TOGGLE_BUTTON (self));
if (!group)
{
if (priv->group_prev)
{
GtkToggleButtonPrivate *p = gtk_toggle_button_get_instance_private (priv->group_prev);
p->group_next = priv->group_next;
}
if (priv->group_next)
{
GtkToggleButtonPrivate *p = gtk_toggle_button_get_instance_private (priv->group_next);
p->group_prev = priv->group_prev;
}
priv->group_next = NULL;
priv->group_prev = NULL;
g_object_notify_by_pspec (G_OBJECT (self), toggle_button_props[PROP_GROUP]);
return;
}
if (priv->group_next == group)
return;
priv->group_prev = NULL;
if (group_priv->group_prev)
{
GtkToggleButtonPrivate *prev = gtk_toggle_button_get_instance_private (group_priv->group_prev);
prev->group_next = self;
priv->group_prev = group_priv->group_prev;
}
group_priv->group_prev = self;
priv->group_next = group;
g_object_notify_by_pspec (G_OBJECT (self), toggle_button_props[PROP_GROUP]);
}

View File

@ -79,6 +79,10 @@ GDK_AVAILABLE_IN_ALL
gboolean gtk_toggle_button_get_active (GtkToggleButton *toggle_button);
GDK_AVAILABLE_IN_ALL
void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
GDK_AVAILABLE_IN_ALL
void gtk_toggle_button_set_group (GtkToggleButton *toggle_button,
GtkToggleButton *group);
G_END_DECLS