X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkradiobutton.c;h=82ab28cb9da467ae73eac8844675c8daffc136ce;hb=bda5987335b8c7828ebf1d289a91accfe2e74dbe;hp=91bedc3f8178bad9b40bd208d2d67412af60ea7e;hpb=7f374a74bae63c9c1011c2a5a9c99de4012e7c61;p=~andy%2Fgtk diff --git a/gtk/gtkradiobutton.c b/gtk/gtkradiobutton.c index 91bedc3f8..82ab28cb9 100644 --- a/gtk/gtkradiobutton.c +++ b/gtk/gtkradiobutton.c @@ -12,9 +12,7 @@ * 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, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /* @@ -24,14 +22,94 @@ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ -#include +#include "config.h" + +#include "gtkradiobutton.h" + +#include "gtkbuttonprivate.h" #include "gtklabel.h" #include "gtkmarshalers.h" -#include "gtkradiobutton.h" #include "gtkprivate.h" #include "gtkintl.h" -#include "gtkalias.h" +#include "a11y/gtkradiobuttonaccessible.h" + +/** + * SECTION:gtkradiobutton + * @Short_description: A choice from multiple check buttons + * @Title: GtkRadioButton + * @See_also: #GtkComboBox + * + * A single radio button performs the same basic function as a #GtkCheckButton, + * as its position in the object hierarchy reflects. It is only when multiple + * radio buttons are grouped together that they become a different user + * interface component in their own right. + * + * Every radio button is a member of some group of radio buttons. When one is + * selected, all other radio buttons in the same group are deselected. A + * #GtkRadioButton is one way of giving the user a choice from many options. + * + * Radio button widgets are created with gtk_radio_button_new(), passing %NULL + * as the argument if this is the first radio button in a group. In subsequent + * calls, the group you wish to add this button to should be passed as an + * argument. Optionally, gtk_radio_button_new_with_label() can be used if you + * want a text label on the radio button. + * + * Alternatively, when adding widgets to an existing group of radio buttons, + * use gtk_radio_button_new_from_widget() with a #GtkRadioButton that already + * has a group assigned to it. The convenience function + * gtk_radio_button_new_with_label_from_widget() is also provided. + * + * To retrieve the group a #GtkRadioButton is assigned to, use + * gtk_radio_button_get_group(). + * + * To remove a #GtkRadioButton from one group and make it part of a new one, + * use gtk_radio_button_set_group(). + * + * The group list does not need to be freed, as each #GtkRadioButton will remove + * itself and its list item when it is destroyed. + * + * + * How to create a group of two radio buttons. + * + * void create_radio_buttons (void) { + * + * GtkWidget *window, *radio1, *radio2, *box, *entry; + * window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + * box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); + * gtk_box_set_homogeneous (GTK_BOX (box), TRUE); + * + * /* Create a radio button with a GtkEntry widget */ + * radio1 = gtk_radio_button_new (NULL); + * entry = gtk_entry_new (); + * gtk_container_add (GTK_CONTAINER (radio1), entry); + * + * + * /* Create a radio button with a label */ + * radio2 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (radio1), + * "I'm the second radio button."); + * + * /* Pack them into a box, then show all the widgets */ + * gtk_box_pack_start (GTK_BOX (box), radio1, TRUE, TRUE, 2); + * gtk_box_pack_start (GTK_BOX (box), radio2, TRUE, TRUE, 2); + * gtk_container_add (GTK_CONTAINER (window), box); + * gtk_widget_show_all (window); + * return; + * } + * + * + * + * When an unselected button in the group is clicked the clicked button + * receives the #GtkToggleButton::toggled signal, as does the previously + * selected button. + * Inside the #GtkToggleButton::toggled handler, gtk_toggle_button_get_active() + * can be used to determine if the button has been selected or deselected. + */ + +struct _GtkRadioButtonPrivate +{ + GSList *group; +}; enum { PROP_0, @@ -39,12 +117,12 @@ enum { }; -static void gtk_radio_button_destroy (GtkObject *object); +static void gtk_radio_button_destroy (GtkWidget *widget); static gboolean gtk_radio_button_focus (GtkWidget *widget, GtkDirectionType direction); static void gtk_radio_button_clicked (GtkButton *button); static void gtk_radio_button_draw_indicator (GtkCheckButton *check_button, - GdkRectangle *area); + cairo_t *cr); static void gtk_radio_button_set_property (GObject *object, guint prop_id, const GValue *value, @@ -62,13 +140,11 @@ static void gtk_radio_button_class_init (GtkRadioButtonClass *class) { GObjectClass *gobject_class; - GtkObjectClass *object_class; GtkButtonClass *button_class; GtkCheckButtonClass *check_button_class; GtkWidgetClass *widget_class; gobject_class = G_OBJECT_CLASS (class); - object_class = (GtkObjectClass*) class; widget_class = (GtkWidgetClass*) class; button_class = (GtkButtonClass*) class; check_button_class = (GtkCheckButtonClass*) class; @@ -76,6 +152,11 @@ gtk_radio_button_class_init (GtkRadioButtonClass *class) gobject_class->set_property = gtk_radio_button_set_property; gobject_class->get_property = gtk_radio_button_get_property; + /** + * GtkRadioButton:group: + * + * Sets a new group for a radio button. + */ g_object_class_install_property (gobject_class, PROP_GROUP, g_param_spec_object ("group", @@ -83,8 +164,7 @@ gtk_radio_button_class_init (GtkRadioButtonClass *class) P_("The radio button whose group this widget belongs to."), GTK_TYPE_RADIO_BUTTON, GTK_PARAM_WRITABLE)); - object_class->destroy = gtk_radio_button_destroy; - + widget_class->destroy = gtk_radio_button_destroy; widget_class->focus = gtk_radio_button_focus; button_class->clicked = gtk_radio_button_clicked; @@ -95,40 +175,50 @@ gtk_radio_button_class_init (GtkRadioButtonClass *class) /** * GtkRadioButton::group-changed: - * @style: the object which received the signal + * @button: the object which received the signal * * Emitted when the group of radio buttons that a radio button belongs * to changes. This is emitted when a radio button switches from * being alone to being part of a group of 2 or more buttons, or - * vice-versa, and when a buttton is moved from one group of 2 or + * vice-versa, and when a button is moved from one group of 2 or * more buttons to a different one, but not when the composition * of the group that a button belongs to changes. * * Since: 2.4 */ group_changed_signal = g_signal_new (I_("group-changed"), - G_OBJECT_CLASS_TYPE (object_class), + G_OBJECT_CLASS_TYPE (gobject_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GtkRadioButtonClass, group_changed), NULL, NULL, _gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + g_type_class_add_private (class, sizeof (GtkRadioButtonPrivate)); + + gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_RADIO_BUTTON_ACCESSIBLE); } static void gtk_radio_button_init (GtkRadioButton *radio_button) { - GTK_WIDGET_SET_FLAGS (radio_button, GTK_NO_WINDOW); - GTK_WIDGET_UNSET_FLAGS (radio_button, GTK_RECEIVES_DEFAULT); + GtkRadioButtonPrivate *priv; + + radio_button->priv = G_TYPE_INSTANCE_GET_PRIVATE (radio_button, + GTK_TYPE_RADIO_BUTTON, + GtkRadioButtonPrivate); + priv = radio_button->priv; + + gtk_widget_set_receives_default (GTK_WIDGET (radio_button), FALSE); - GTK_TOGGLE_BUTTON (radio_button)->active = TRUE; + _gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), TRUE); - GTK_BUTTON (radio_button)->depress_on_activate = FALSE; + GTK_BUTTON (radio_button)->priv->depress_on_activate = FALSE; - radio_button->group = g_slist_prepend (NULL, radio_button); + priv->group = g_slist_prepend (NULL, radio_button); _gtk_button_set_depressed (GTK_BUTTON (radio_button), TRUE); - gtk_widget_set_state (GTK_WIDGET (radio_button), GTK_STATE_ACTIVE); + gtk_widget_set_state_flags (GTK_WIDGET (radio_button), GTK_STATE_FLAG_ACTIVE, TRUE); } static void @@ -144,10 +234,13 @@ gtk_radio_button_set_property (GObject *object, switch (prop_id) { GSList *slist; + GtkRadioButton *button; case PROP_GROUP: - if (G_VALUE_HOLDS_OBJECT (value)) - slist = gtk_radio_button_get_group ((GtkRadioButton*) g_value_get_object (value)); + button = g_value_get_object (value); + + if (button) + slist = gtk_radio_button_get_group (button); else slist = NULL; gtk_radio_button_set_group (radio_button, slist); @@ -172,40 +265,54 @@ gtk_radio_button_get_property (GObject *object, } } +/** + * gtk_radio_button_set_group: + * @radio_button: a #GtkRadioButton. + * @group: (transfer none) (element-type GtkRadioButton): an existing radio + * button group, such as one returned from gtk_radio_button_get_group(). + * + * Sets a #GtkRadioButton's group. It should be noted that this does not change + * the layout of your interface in any way, so if you are changing the group, + * it is likely you will need to re-arrange the user interface to reflect these + * changes. + */ void gtk_radio_button_set_group (GtkRadioButton *radio_button, GSList *group) { + GtkRadioButtonPrivate *priv; GtkWidget *old_group_singleton = NULL; GtkWidget *new_group_singleton = NULL; - + g_return_if_fail (GTK_IS_RADIO_BUTTON (radio_button)); g_return_if_fail (!g_slist_find (group, radio_button)); - if (radio_button->group) + priv = radio_button->priv; + + if (priv->group) { GSList *slist; - radio_button->group = g_slist_remove (radio_button->group, radio_button); - - if (radio_button->group && !radio_button->group->next) - old_group_singleton = g_object_ref (radio_button->group->data); - - for (slist = radio_button->group; slist; slist = slist->next) + priv->group = g_slist_remove (priv->group, radio_button); + + if (priv->group && !priv->group->next) + old_group_singleton = g_object_ref (priv->group->data); + + for (slist = priv->group; slist; slist = slist->next) { GtkRadioButton *tmp_button; tmp_button = slist->data; - - tmp_button->group = radio_button->group; + + tmp_button->priv->group = priv->group; } } if (group && !group->next) new_group_singleton = g_object_ref (group->data); - - radio_button->group = g_slist_prepend (group, radio_button); - + + priv->group = g_slist_prepend (group, radio_button); + if (group) { GSList *slist; @@ -215,8 +322,8 @@ gtk_radio_button_set_group (GtkRadioButton *radio_button, GtkRadioButton *tmp_button; tmp_button = slist->data; - - tmp_button->group = radio_button->group; + + tmp_button->priv->group = priv->group; } } @@ -240,6 +347,71 @@ gtk_radio_button_set_group (GtkRadioButton *radio_button, g_object_unref (radio_button); } +/** + * gtk_radio_button_join_group: + * @radio_button: the #GtkRadioButton object + * @group_source: (allow-none): a radio button object whos group we are + * joining, or %NULL to remove the radio button from its group + * + * Joins a #GtkRadioButton object to the group of another #GtkRadioButton object + * + * Use this in language bindings instead of the gtk_radio_button_get_group() + * and gtk_radio_button_set_group() methods + * + * A common way to set up a group of radio buttons is the following: + * |[ + * GtkRadioButton *radio_button; + * GtkRadioButton *last_button; + * + * while (/* more buttons to add */) + * { + * radio_button = gtk_radio_button_new (...); + * + * gtk_radio_button_join_group (radio_button, last_button); + * last_button = radio_button; + * } + * ]| + * + * Since: 3.0 + */ +void +gtk_radio_button_join_group (GtkRadioButton *radio_button, + GtkRadioButton *group_source) +{ + g_return_if_fail (GTK_IS_RADIO_BUTTON (radio_button)); + g_return_if_fail (group_source == NULL || GTK_IS_RADIO_BUTTON (group_source)); + + if (group_source) + { + GSList *group; + group = gtk_radio_button_get_group (group_source); + + if (!group) + { + /* if we are not already part of a group we need to set up a new one + and then get the newly created group */ + gtk_radio_button_set_group (group_source, NULL); + group = gtk_radio_button_get_group (group_source); + } + + gtk_radio_button_set_group (radio_button, group); + } + else + { + gtk_radio_button_set_group (radio_button, NULL); + } +} + +/** + * gtk_radio_button_new: + * @group: (element-type GtkRadioButton) (allow-none): an existing + * radio button group, or %NULL if you are creating a new group. + * + * Creates a new #GtkRadioButton. To be of any practical value, a widget should + * then be packed into the radio button. + * + * Returns: a new radio button + */ GtkWidget* gtk_radio_button_new (GSList *group) { @@ -253,6 +425,16 @@ gtk_radio_button_new (GSList *group) return GTK_WIDGET (radio_button); } +/** + * gtk_radio_button_new_with_label: + * @group: (element-type GtkRadioButton) (allow-none): an existing + * radio button group, or %NULL if you are creating a new group. + * @label: the text label to display next to the radio button. + * + * Creates a new #GtkRadioButton with a text label. + * + * Returns: a new radio button. + */ GtkWidget* gtk_radio_button_new_with_label (GSList *group, const gchar *label) @@ -270,16 +452,18 @@ gtk_radio_button_new_with_label (GSList *group, /** * gtk_radio_button_new_with_mnemonic: - * @group: the radio button group + * @group: (element-type GtkRadioButton) (allow-none): the radio button + * group * @label: the text of the button, with an underscore in front of the * mnemonic character - * @returns: a new #GtkRadioButton * - * Creates a new #GtkRadioButton containing a label, adding it to the same - * group as @group. The label will be created using - * gtk_label_new_with_mnemonic(), so underscores in @label indicate the + * Creates a new #GtkRadioButton containing a label, adding it to the same + * group as @group. The label will be created using + * gtk_label_new_with_mnemonic(), so underscores in @label indicate the * mnemonic for the button. - **/ + * + * Returns: a new #GtkRadioButton + */ GtkWidget* gtk_radio_button_new_with_mnemonic (GSList *group, const gchar *label) @@ -297,93 +481,123 @@ gtk_radio_button_new_with_mnemonic (GSList *group, return radio_button; } +/** + * gtk_radio_button_new_from_widget: (constructor) + * @radio_group_member: (allow-none): an existing #GtkRadioButton. + * + * Creates a new #GtkRadioButton, adding it to the same group as + * @radio_group_member. As with gtk_radio_button_new(), a widget + * should be packed into the radio button. + * + * Returns: (transfer none): a new radio button. + */ GtkWidget* -gtk_radio_button_new_from_widget (GtkRadioButton *group) +gtk_radio_button_new_from_widget (GtkRadioButton *radio_group_member) { GSList *l = NULL; - if (group) - l = gtk_radio_button_get_group (group); + if (radio_group_member) + l = gtk_radio_button_get_group (radio_group_member); return gtk_radio_button_new (l); } - +/** + * gtk_radio_button_new_with_label_from_widget: (constructor) + * @radio_group_member: (allow-none): widget to get radio group from or %NULL + * @label: a text string to display next to the radio button. + * + * Creates a new #GtkRadioButton with a text label, adding it to + * the same group as @radio_group_member. + * + * Returns: (transfer none): a new radio button. + */ GtkWidget* -gtk_radio_button_new_with_label_from_widget (GtkRadioButton *group, +gtk_radio_button_new_with_label_from_widget (GtkRadioButton *radio_group_member, const gchar *label) { GSList *l = NULL; - if (group) - l = gtk_radio_button_get_group (group); + if (radio_group_member) + l = gtk_radio_button_get_group (radio_group_member); return gtk_radio_button_new_with_label (l, label); } /** - * gtk_radio_button_new_with_mnemonic_from_widget: - * @group: widget to get radio group from + * gtk_radio_button_new_with_mnemonic_from_widget: (constructor) + * @radio_group_member: (allow-none): widget to get radio group from or %NULL * @label: the text of the button, with an underscore in front of the * mnemonic character - * @returns: a new #GtkRadioButton * * Creates a new #GtkRadioButton containing a label. The label * will be created using gtk_label_new_with_mnemonic(), so underscores * in @label indicate the mnemonic for the button. + * + * Returns: (transfer none): a new #GtkRadioButton **/ GtkWidget* -gtk_radio_button_new_with_mnemonic_from_widget (GtkRadioButton *group, +gtk_radio_button_new_with_mnemonic_from_widget (GtkRadioButton *radio_group_member, const gchar *label) { GSList *l = NULL; - if (group) - l = gtk_radio_button_get_group (group); + if (radio_group_member) + l = gtk_radio_button_get_group (radio_group_member); return gtk_radio_button_new_with_mnemonic (l, label); } + +/** + * gtk_radio_button_get_group: + * @radio_button: a #GtkRadioButton. + * + * Retrieves the group assigned to a radio button. + * + * Return value: (element-type GtkRadioButton) (transfer none): a linked list + * containing all the radio buttons in the same group + * as @radio_button. The returned list is owned by the radio button + * and must not be modified or freed. + */ GSList* gtk_radio_button_get_group (GtkRadioButton *radio_button) { g_return_val_if_fail (GTK_IS_RADIO_BUTTON (radio_button), NULL); - return radio_button->group; + return radio_button->priv->group; } static void -gtk_radio_button_destroy (GtkObject *object) +gtk_radio_button_destroy (GtkWidget *widget) { GtkWidget *old_group_singleton = NULL; - GtkRadioButton *radio_button; + GtkRadioButton *radio_button = GTK_RADIO_BUTTON (widget); + GtkRadioButtonPrivate *priv = radio_button->priv; GtkRadioButton *tmp_button; GSList *tmp_list; gboolean was_in_group; - - radio_button = GTK_RADIO_BUTTON (object); - was_in_group = radio_button->group && radio_button->group->next; - - radio_button->group = g_slist_remove (radio_button->group, radio_button); - if (radio_button->group && !radio_button->group->next) - old_group_singleton = radio_button->group->data; + was_in_group = priv->group && priv->group->next; + + priv->group = g_slist_remove (priv->group, radio_button); + if (priv->group && !priv->group->next) + old_group_singleton = priv->group->data; - tmp_list = radio_button->group; + tmp_list = priv->group; while (tmp_list) { tmp_button = tmp_list->data; tmp_list = tmp_list->next; - tmp_button->group = radio_button->group; + tmp_button->priv->group = priv->group; } /* this button is no longer in the group */ - radio_button->group = NULL; + priv->group = NULL; if (old_group_singleton) g_signal_emit (old_group_singleton, group_changed_signal, 0); if (was_in_group) g_signal_emit (radio_button, group_changed_signal, 0); - - if (GTK_OBJECT_CLASS (gtk_radio_button_parent_class)->destroy) - (* GTK_OBJECT_CLASS (gtk_radio_button_parent_class)->destroy) (object); + + GTK_WIDGET_CLASS (gtk_radio_button_parent_class)->destroy (widget); } static void @@ -392,9 +606,12 @@ get_coordinates (GtkWidget *widget, gint *x, gint *y) { - *x = widget->allocation.x + widget->allocation.width / 2; - *y = widget->allocation.y + widget->allocation.height / 2; - + GtkAllocation allocation; + + gtk_widget_get_allocation (widget, &allocation); + *x = allocation.x + allocation.width / 2; + *y = allocation.y + allocation.height / 2; + gtk_widget_translate_coordinates (widget, reference, *x, *y, x, y); } @@ -435,35 +652,41 @@ gtk_radio_button_focus (GtkWidget *widget, GtkDirectionType direction) { GtkRadioButton *radio_button = GTK_RADIO_BUTTON (widget); + GtkRadioButtonPrivate *priv = radio_button->priv; GSList *tmp_slist; /* Radio buttons with draw_indicator unset focus "normally", since * they look like buttons to the user. */ - if (!GTK_TOGGLE_BUTTON (widget)->draw_indicator) + if (!gtk_toggle_button_get_mode (GTK_TOGGLE_BUTTON (widget))) return GTK_WIDGET_CLASS (gtk_radio_button_parent_class)->focus (widget, direction); if (gtk_widget_is_focus (widget)) { + GtkSettings *settings = gtk_widget_get_settings (widget); GSList *focus_list, *tmp_list; GtkWidget *toplevel = gtk_widget_get_toplevel (widget); GtkWidget *new_focus = NULL; + gboolean cursor_only; + gboolean wrap_around; switch (direction) { - case GTK_DIR_TAB_FORWARD: - case GTK_DIR_TAB_BACKWARD: - return FALSE; case GTK_DIR_LEFT: case GTK_DIR_RIGHT: - focus_list = g_slist_copy (radio_button->group); + focus_list = g_slist_copy (priv->group); focus_list = g_slist_sort_with_data (focus_list, left_right_compare, toplevel); break; case GTK_DIR_UP: case GTK_DIR_DOWN: - focus_list = g_slist_copy (radio_button->group); + focus_list = g_slist_copy (priv->group); focus_list = g_slist_sort_with_data (focus_list, up_down_compare, toplevel); break; + case GTK_DIR_TAB_FORWARD: + case GTK_DIR_TAB_BACKWARD: + /* fall through */ + default: + return FALSE; } if (direction == GTK_DIR_LEFT || direction == GTK_DIR_UP) @@ -479,7 +702,7 @@ gtk_radio_button_focus (GtkWidget *widget, { GtkWidget *child = tmp_list->data; - if (GTK_WIDGET_REALIZED (child) && GTK_WIDGET_IS_SENSITIVE (child)) + if (gtk_widget_get_mapped (child) && gtk_widget_is_sensitive (child)) { new_focus = child; break; @@ -489,21 +712,33 @@ gtk_radio_button_focus (GtkWidget *widget, } } + g_object_get (settings, + "gtk-keynav-cursor-only", &cursor_only, + "gtk-keynav-wrap-around", &wrap_around, + NULL); + if (!new_focus) { - if (!gtk_widget_keynav_failed (widget, direction)) + if (cursor_only) { g_slist_free (focus_list); return FALSE; } + if (!wrap_around) + { + g_slist_free (focus_list); + gtk_widget_error_bell (widget); + return TRUE; + } + tmp_list = focus_list; while (tmp_list) { GtkWidget *child = tmp_list->data; - if (GTK_WIDGET_REALIZED (child) && GTK_WIDGET_IS_SENSITIVE (child)) + if (gtk_widget_get_mapped (child) && gtk_widget_is_sensitive (child)) { new_focus = child; break; @@ -517,13 +752,6 @@ gtk_radio_button_focus (GtkWidget *widget, if (new_focus) { - GtkSettings *settings = gtk_widget_get_settings (widget); - gboolean cursor_only; - - g_object_get (settings, - "gtk-keynav-cursor-only", &cursor_only, - NULL); - gtk_widget_grab_focus (new_focus); if (!cursor_only) @@ -541,10 +769,10 @@ gtk_radio_button_focus (GtkWidget *widget, * - there is no currently active radio button. */ - tmp_slist = radio_button->group; + tmp_slist = priv->group; while (tmp_slist) { - if (GTK_TOGGLE_BUTTON (tmp_slist->data)->active) + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (tmp_slist->data))) selected_button = tmp_slist->data; tmp_slist = tmp_slist->next; } @@ -560,31 +788,35 @@ gtk_radio_button_focus (GtkWidget *widget, static void gtk_radio_button_clicked (GtkButton *button) { - GtkToggleButton *toggle_button; - GtkRadioButton *radio_button; + GtkRadioButton *radio_button = GTK_RADIO_BUTTON (button); + GtkRadioButtonPrivate *priv = radio_button->priv; + GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button); GtkToggleButton *tmp_button; - GtkStateType new_state; + GtkStateFlags new_state = 0; GSList *tmp_list; gint toggled; gboolean depressed; - radio_button = GTK_RADIO_BUTTON (button); - toggle_button = GTK_TOGGLE_BUTTON (button); toggled = FALSE; g_object_ref (GTK_WIDGET (button)); - if (toggle_button->active) + new_state = gtk_widget_get_state_flags (GTK_WIDGET (button)) & + ~(GTK_STATE_FLAG_PRELIGHT | + GTK_STATE_FLAG_ACTIVE); + + if (gtk_toggle_button_get_active (toggle_button)) { tmp_button = NULL; - tmp_list = radio_button->group; + tmp_list = priv->group; while (tmp_list) { tmp_button = tmp_list->data; tmp_list = tmp_list->next; - if (tmp_button->active && tmp_button != toggle_button) + if (tmp_button != toggle_button && + gtk_toggle_button_get_active (tmp_button)) break; tmp_button = NULL; @@ -592,45 +824,55 @@ gtk_radio_button_clicked (GtkButton *button) if (!tmp_button) { - new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE); + if (button->priv->in_button) + new_state |= GTK_STATE_FLAG_PRELIGHT; + + new_state |= GTK_STATE_FLAG_ACTIVE; } else { toggled = TRUE; - toggle_button->active = !toggle_button->active; - new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL); + _gtk_toggle_button_set_active (toggle_button, + !gtk_toggle_button_get_active (toggle_button)); + + if (button->priv->in_button) + new_state |= GTK_STATE_FLAG_PRELIGHT; } } else { toggled = TRUE; - toggle_button->active = !toggle_button->active; - - tmp_list = radio_button->group; + _gtk_toggle_button_set_active (toggle_button, + !gtk_toggle_button_get_active (toggle_button)); + + tmp_list = priv->group; while (tmp_list) { tmp_button = tmp_list->data; tmp_list = tmp_list->next; - if (tmp_button->active && (tmp_button != toggle_button)) + if (gtk_toggle_button_get_active (tmp_button) && (tmp_button != toggle_button)) { gtk_button_clicked (GTK_BUTTON (tmp_button)); break; } } - new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE); + if (button->priv->in_button) + new_state |= GTK_STATE_FLAG_PRELIGHT; + + new_state |= GTK_STATE_FLAG_ACTIVE; } - if (toggle_button->inconsistent) + if (gtk_toggle_button_get_inconsistent (toggle_button)) depressed = FALSE; - else if (button->in_button && button->button_down) - depressed = !toggle_button->active; + else if (button->priv->in_button && button->priv->button_down) + depressed = !gtk_toggle_button_get_active (toggle_button); else - depressed = toggle_button->active; + depressed = gtk_toggle_button_get_active (toggle_button); - if (GTK_WIDGET_STATE (button) != new_state) - gtk_widget_set_state (GTK_WIDGET (button), new_state); + if (gtk_widget_get_state_flags (GTK_WIDGET (button)) != new_state) + gtk_widget_set_state_flags (GTK_WIDGET (button), new_state, TRUE); if (toggled) { @@ -648,86 +890,80 @@ gtk_radio_button_clicked (GtkButton *button) static void gtk_radio_button_draw_indicator (GtkCheckButton *check_button, - GdkRectangle *area) + cairo_t *cr) { + GtkAllocation allocation; GtkWidget *widget; GtkWidget *child; GtkButton *button; GtkToggleButton *toggle_button; - GtkStateType state_type; - GtkShadowType shadow_type; + GtkStyleContext *context; + GtkStateFlags state = 0; gint x, y; gint indicator_size, indicator_spacing; gint focus_width; gint focus_pad; + guint border_width; gboolean interior_focus; - if (GTK_WIDGET_DRAWABLE (check_button)) - { - widget = GTK_WIDGET (check_button); - button = GTK_BUTTON (check_button); - toggle_button = GTK_TOGGLE_BUTTON (check_button); + widget = GTK_WIDGET (check_button); + button = GTK_BUTTON (check_button); + toggle_button = GTK_TOGGLE_BUTTON (check_button); + context = gtk_widget_get_style_context (widget); + state = gtk_widget_get_state_flags (widget); - gtk_widget_style_get (widget, - "interior-focus", &interior_focus, - "focus-line-width", &focus_width, - "focus-padding", &focus_pad, - NULL); + border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - _gtk_check_button_get_props (check_button, &indicator_size, &indicator_spacing); + gtk_widget_style_get (widget, + "interior-focus", &interior_focus, + "focus-line-width", &focus_width, + "focus-padding", &focus_pad, + NULL); - x = widget->allocation.x + indicator_spacing + GTK_CONTAINER (widget)->border_width; - y = widget->allocation.y + (widget->allocation.height - indicator_size) / 2; + _gtk_check_button_get_props (check_button, &indicator_size, &indicator_spacing); - child = GTK_BIN (check_button)->child; - if (!interior_focus || !(child && GTK_WIDGET_VISIBLE (child))) - x += focus_width + focus_pad; + gtk_widget_get_allocation (widget, &allocation); - if (toggle_button->inconsistent) - shadow_type = GTK_SHADOW_ETCHED_IN; - else if (toggle_button->active) - shadow_type = GTK_SHADOW_IN; - else - shadow_type = GTK_SHADOW_OUT; - - if (button->activate_timeout || (button->button_down && button->in_button)) - state_type = GTK_STATE_ACTIVE; - else if (button->in_button) - state_type = GTK_STATE_PRELIGHT; - else if (!GTK_WIDGET_IS_SENSITIVE (widget)) - state_type = GTK_STATE_INSENSITIVE; - else - state_type = GTK_STATE_NORMAL; + x = indicator_spacing + border_width; + y = (allocation.height - indicator_size) / 2; - if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) - x = widget->allocation.x + widget->allocation.width - (indicator_size + x - widget->allocation.x); + child = gtk_bin_get_child (GTK_BIN (check_button)); + if (!interior_focus || !(child && gtk_widget_get_visible (child))) + x += focus_width + focus_pad; - if (GTK_WIDGET_STATE (toggle_button) == GTK_STATE_PRELIGHT) - { - GdkRectangle restrict_area; - GdkRectangle new_area; - - restrict_area.x = widget->allocation.x + GTK_CONTAINER (widget)->border_width; - restrict_area.y = widget->allocation.y + GTK_CONTAINER (widget)->border_width; - restrict_area.width = widget->allocation.width - (2 * GTK_CONTAINER (widget)->border_width); - restrict_area.height = widget->allocation.height - (2 * GTK_CONTAINER (widget)->border_width); - - if (gdk_rectangle_intersect (area, &restrict_area, &new_area)) - { - gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_PRELIGHT, - GTK_SHADOW_ETCHED_OUT, - area, widget, "checkbutton", - new_area.x, new_area.y, - new_area.width, new_area.height); - } - } + state &= ~(GTK_STATE_FLAG_INCONSISTENT | + GTK_STATE_FLAG_ACTIVE | + GTK_STATE_FLAG_SELECTED | + GTK_STATE_FLAG_PRELIGHT); - gtk_paint_option (widget->style, widget->window, - state_type, shadow_type, - area, widget, "radiobutton", - x, y, indicator_size, indicator_size); - } -} + if (gtk_toggle_button_get_inconsistent (toggle_button)) + state |= GTK_STATE_FLAG_INCONSISTENT; + else if (gtk_toggle_button_get_active (toggle_button)) + state |= GTK_STATE_FLAG_ACTIVE; + + if (button->priv->activate_timeout || + (button->priv->button_down && button->priv->in_button)) + state |= GTK_STATE_FLAG_SELECTED; + + if (button->priv->in_button && !(state & GTK_STATE_FLAG_INSENSITIVE)) + state |= GTK_STATE_FLAG_PRELIGHT; + + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) + x = allocation.width - (indicator_size + x); + + gtk_style_context_save (context); + gtk_style_context_set_state (context, state); -#define __GTK_RADIO_BUTTON_C__ -#include "gtkaliasdef.c" + if (state & GTK_STATE_FLAG_PRELIGHT) + gtk_render_background (context, cr, + border_width, border_width, + allocation.width - (2 * border_width), + allocation.height - (2 * border_width)); + + gtk_style_context_add_class (context, GTK_STYLE_CLASS_RADIO); + + gtk_render_option (context, cr, + x, y, indicator_size, indicator_size); + + gtk_style_context_restore (context); +}