X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkradioaction.c;h=4a5aaa786f1e27d340bd2fa8485529cc56a78bf3;hb=45ad8a06ad511ad95a74172172b9fe459bc666ad;hp=e0ea5f1f9bd7c4f1f84cedba7cea38886363acff;hpb=e7e395652cfac4aa5385aa91fd6079fae13dd129;p=~andy%2Fgtk diff --git a/gtk/gtkradioaction.c b/gtk/gtkradioaction.c index e0ea5f1f9..4a5aaa786 100644 --- a/gtk/gtkradioaction.c +++ b/gtk/gtkradioaction.c @@ -14,9 +14,7 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with the Gnome Library; see the file COPYING.LIB. 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 . */ /* @@ -28,53 +26,61 @@ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ -#include +#include "config.h" #include "gtkradioaction.h" -#include "gtktoggleactionprivate.h" +#include "gtkradiomenuitem.h" +#include "gtktoggletoolbutton.h" +#include "gtkintl.h" +#include "gtkprivate.h" + +/** + * SECTION:gtkradioaction + * @Short_description: An action of which only one in a group can be active + * @Title: GtkRadioAction + * + * A #GtkRadioAction is similar to #GtkRadioMenuItem. A number of radio + * actions can be linked together so that only one may be active at any + * one time. + */ -#define GTK_RADIO_ACTION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_RADIO_ACTION, GtkRadioActionPrivate)) struct _GtkRadioActionPrivate { GSList *group; + gint value; }; -static void gtk_radio_action_init (GtkRadioAction *action); -static void gtk_radio_action_class_init (GtkRadioActionClass *class); +enum +{ + CHANGED, + LAST_SIGNAL +}; -GType -gtk_radio_action_get_type (void) +enum { - static GtkType type = 0; + PROP_0, + PROP_VALUE, + PROP_GROUP, + PROP_CURRENT_VALUE +}; - if (!type) - { - static const GTypeInfo type_info = - { - sizeof (GtkRadioActionClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) gtk_radio_action_class_init, - (GClassFinalizeFunc) NULL, - NULL, - - sizeof (GtkRadioAction), - 0, /* n_preallocs */ - (GInstanceInitFunc) gtk_radio_action_init, - }; - - type = g_type_register_static (GTK_TYPE_TOGGLE_ACTION, - "GtkRadioAction", - &type_info, 0); - } - return type; -} +static void gtk_radio_action_finalize (GObject *object); +static void gtk_radio_action_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_radio_action_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void gtk_radio_action_activate (GtkAction *action); +static GtkWidget *create_menu_item (GtkAction *action); -static void gtk_radio_action_finalize (GObject *object); -static void gtk_radio_action_activate (GtkAction *action); -static GObjectClass *parent_class = NULL; +G_DEFINE_TYPE (GtkRadioAction, gtk_radio_action, GTK_TYPE_TOGGLE_ACTION) + +static guint radio_action_signals[LAST_SIGNAL] = { 0 }; static void gtk_radio_action_class_init (GtkRadioActionClass *klass) @@ -82,22 +88,141 @@ gtk_radio_action_class_init (GtkRadioActionClass *klass) GObjectClass *gobject_class; GtkActionClass *action_class; - parent_class = g_type_class_peek_parent (klass); gobject_class = G_OBJECT_CLASS (klass); action_class = GTK_ACTION_CLASS (klass); gobject_class->finalize = gtk_radio_action_finalize; + gobject_class->set_property = gtk_radio_action_set_property; + gobject_class->get_property = gtk_radio_action_get_property; action_class->activate = gtk_radio_action_activate; + action_class->create_menu_item = create_menu_item; + + /** + * GtkRadioAction:value: + * + * The value is an arbitrary integer which can be used as a + * convenient way to determine which action in the group is + * currently active in an ::activate or ::changed signal handler. + * See gtk_radio_action_get_current_value() and #GtkRadioActionEntry + * for convenient ways to get and set this property. + * + * Since: 2.4 + */ + g_object_class_install_property (gobject_class, + PROP_VALUE, + g_param_spec_int ("value", + P_("The value"), + P_("The value returned by gtk_radio_action_get_current_value() when this action is the current action of its group."), + G_MININT, + G_MAXINT, + 0, + GTK_PARAM_READWRITE)); + + /** + * GtkRadioAction:group: + * + * Sets a new group for a radio action. + * + * Since: 2.4 + */ + g_object_class_install_property (gobject_class, + PROP_GROUP, + g_param_spec_object ("group", + P_("Group"), + P_("The radio action whose group this action belongs to."), + GTK_TYPE_RADIO_ACTION, + GTK_PARAM_WRITABLE)); + + /** + * GtkRadioAction:current-value: + * + * The value property of the currently active member of the group to which + * this action belongs. + * + * Since: 2.10 + */ + g_object_class_install_property (gobject_class, + PROP_CURRENT_VALUE, + g_param_spec_int ("current-value", + P_("The current value"), + P_("The value property of the currently active member of the group to which this action belongs."), + G_MININT, + G_MAXINT, + 0, + GTK_PARAM_READWRITE)); + + /** + * GtkRadioAction::changed: + * @action: the action on which the signal is emitted + * @current: the member of @actions group which has just been activated + * + * The ::changed signal is emitted on every member of a radio group when the + * active member is changed. The signal gets emitted after the ::activate signals + * for the previous and current active members. + * + * Since: 2.4 + */ + radio_action_signals[CHANGED] = + g_signal_new (I_("changed"), + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, + G_STRUCT_OFFSET (GtkRadioActionClass, changed), NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GTK_TYPE_RADIO_ACTION); + g_type_class_add_private (gobject_class, sizeof (GtkRadioActionPrivate)); } static void gtk_radio_action_init (GtkRadioAction *action) { - action->private_data = GTK_RADIO_ACTION_GET_PRIVATE (action); + action->private_data = G_TYPE_INSTANCE_GET_PRIVATE (action, + GTK_TYPE_RADIO_ACTION, + GtkRadioActionPrivate); + action->private_data->group = g_slist_prepend (NULL, action); + action->private_data->value = 0; + + gtk_toggle_action_set_draw_as_radio (GTK_TOGGLE_ACTION (action), TRUE); +} + +/** + * gtk_radio_action_new: + * @name: A unique name for the action + * @label: (allow-none): The label displayed in menu items and on buttons, + * or %NULL + * @tooltip: (allow-none): A tooltip for this action, or %NULL + * @stock_id: (allow-none): The stock icon to display in widgets representing + * this action, or %NULL + * @value: The value which gtk_radio_action_get_current_value() should + * return if this action is selected. + * + * Creates a new #GtkRadioAction object. To add the action to + * a #GtkActionGroup and set the accelerator for the action, + * call gtk_action_group_add_action_with_accel(). + * + * Return value: a new #GtkRadioAction + * + * Since: 2.4 + */ +GtkRadioAction * +gtk_radio_action_new (const gchar *name, + const gchar *label, + const gchar *tooltip, + const gchar *stock_id, + gint value) +{ + g_return_val_if_fail (name != NULL, NULL); + + return g_object_new (GTK_TYPE_RADIO_ACTION, + "name", name, + "label", label, + "tooltip", tooltip, + "stock-id", stock_id, + "value", value, + NULL); } static void @@ -120,8 +245,71 @@ gtk_radio_action_finalize (GObject *object) tmp_action->private_data->group = action->private_data->group; } - if (parent_class->finalize) - (* parent_class->finalize) (object); + G_OBJECT_CLASS (gtk_radio_action_parent_class)->finalize (object); +} + +static void +gtk_radio_action_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkRadioAction *radio_action; + + radio_action = GTK_RADIO_ACTION (object); + + switch (prop_id) + { + case PROP_VALUE: + radio_action->private_data->value = g_value_get_int (value); + break; + case PROP_GROUP: + { + GtkRadioAction *arg; + GSList *slist = NULL; + + if (G_VALUE_HOLDS_OBJECT (value)) + { + arg = GTK_RADIO_ACTION (g_value_get_object (value)); + if (arg) + slist = gtk_radio_action_get_group (arg); + gtk_radio_action_set_group (radio_action, slist); + } + } + break; + case PROP_CURRENT_VALUE: + gtk_radio_action_set_current_value (radio_action, + g_value_get_int (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_radio_action_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkRadioAction *radio_action; + + radio_action = GTK_RADIO_ACTION (object); + + switch (prop_id) + { + case PROP_VALUE: + g_value_set_int (value, radio_action->private_data->value); + break; + case PROP_CURRENT_VALUE: + g_value_set_int (value, + gtk_radio_action_get_current_value (radio_action)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } static void @@ -131,11 +319,13 @@ gtk_radio_action_activate (GtkAction *action) GtkToggleAction *toggle_action; GtkToggleAction *tmp_action; GSList *tmp_list; + gboolean active; radio_action = GTK_RADIO_ACTION (action); toggle_action = GTK_TOGGLE_ACTION (action); - if (toggle_action->private_data->active) + active = gtk_toggle_action_get_active (toggle_action); + if (active) { tmp_list = radio_action->private_data->group; @@ -144,16 +334,20 @@ gtk_radio_action_activate (GtkAction *action) tmp_action = tmp_list->data; tmp_list = tmp_list->next; - if (tmp_action->private_data->active && (tmp_action != toggle_action)) + if (gtk_toggle_action_get_active (tmp_action) && + (tmp_action != toggle_action)) { - toggle_action->private_data->active = !toggle_action->private_data->active; + _gtk_toggle_action_set_active (toggle_action, !active); + break; } } + g_object_notify (G_OBJECT (action), "active"); } else { - toggle_action->private_data->active = !toggle_action->private_data->active; + _gtk_toggle_action_set_active (toggle_action, !active); + g_object_notify (G_OBJECT (action), "active"); tmp_list = radio_action->private_data->group; while (tmp_list) @@ -161,24 +355,60 @@ gtk_radio_action_activate (GtkAction *action) tmp_action = tmp_list->data; tmp_list = tmp_list->next; - if (tmp_action->private_data->active && (tmp_action != toggle_action)) + if (gtk_toggle_action_get_active (tmp_action) && + (tmp_action != toggle_action)) { - gtk_action_activate (GTK_ACTION (tmp_action)); + _gtk_action_emit_activate (GTK_ACTION (tmp_action)); break; } } + + tmp_list = radio_action->private_data->group; + while (tmp_list) + { + tmp_action = tmp_list->data; + tmp_list = tmp_list->next; + + g_object_notify (G_OBJECT (tmp_action), "current-value"); + + g_signal_emit (tmp_action, radio_action_signals[CHANGED], 0, radio_action); + } } gtk_toggle_action_toggled (toggle_action); } +static GtkWidget * +create_menu_item (GtkAction *action) +{ + return g_object_new (GTK_TYPE_CHECK_MENU_ITEM, + "draw-as-radio", TRUE, + NULL); +} + /** * gtk_radio_action_get_group: * @action: the action object * - * Returns the list representing the radio group for this object + * Returns the list representing the radio group for this object. + * Note that the returned list is only valid until the next change + * to the group. + * + * A common way to set up a group of radio group is the following: + * |[ + * GSList *group = NULL; + * GtkRadioAction *action; + * + * while (/* more actions to add */) + * { + * action = gtk_radio_action_new (...); + * + * gtk_radio_action_set_group (action, group); + * group = gtk_radio_action_get_group (action); + * } + * ]| * - * Returns: the list representing the radio group for this object + * Returns: (element-type GtkRadioAction) (transfer none): the list representing the radio group for this object * * Since: 2.4 */ @@ -193,7 +423,7 @@ gtk_radio_action_get_group (GtkRadioAction *action) /** * gtk_radio_action_set_group: * @action: the action object - * @group: a list representing a radio group + * @group: (element-type GtkRadioAction): a list representing a radio group * * Sets the radio group for the radio action object. * @@ -238,3 +468,130 @@ gtk_radio_action_set_group (GtkRadioAction *action, gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); } } + +/** + * gtk_radio_action_join_group: + * @action: the action object + * @group_source: (allow-none): a radio action object whos group we are + * joining, or %NULL to remove the radio action from its group + * + * Joins a radio action object to the group of another radio action object. + * + * Use this in language bindings instead of the gtk_radio_action_get_group() + * and gtk_radio_action_set_group() methods + * + * A common way to set up a group of radio actions is the following: + * |[ + * GtkRadioAction *action; + * GtkRadioAction *last_action; + * + * while (/* more actions to add */) + * { + * action = gtk_radio_action_new (...); + * + * gtk_radio_action_join_group (action, last_action); + * last_action = action; + * } + * ]| + * + * Since: 3.0 + */ +void +gtk_radio_action_join_group (GtkRadioAction *action, + GtkRadioAction *group_source) +{ + g_return_if_fail (GTK_IS_RADIO_ACTION (action)); + g_return_if_fail (group_source == NULL || GTK_IS_RADIO_ACTION (group_source)); + + if (group_source) + { + GSList *group; + group = gtk_radio_action_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_action_set_group (group_source, NULL); + group = gtk_radio_action_get_group (group_source); + } + + gtk_radio_action_set_group (action, group); + } + else + { + gtk_radio_action_set_group (action, NULL); + } +} + +/** + * gtk_radio_action_get_current_value: + * @action: a #GtkRadioAction + * + * Obtains the value property of the currently active member of + * the group to which @action belongs. + * + * Return value: The value of the currently active group member + * + * Since: 2.4 + **/ +gint +gtk_radio_action_get_current_value (GtkRadioAction *action) +{ + GSList *slist; + + g_return_val_if_fail (GTK_IS_RADIO_ACTION (action), 0); + + if (action->private_data->group) + { + for (slist = action->private_data->group; slist; slist = slist->next) + { + GtkToggleAction *toggle_action = slist->data; + + if (gtk_toggle_action_get_active (toggle_action)) + return GTK_RADIO_ACTION (toggle_action)->private_data->value; + } + } + + return action->private_data->value; +} + +/** + * gtk_radio_action_set_current_value: + * @action: a #GtkRadioAction + * @current_value: the new value + * + * Sets the currently active group member to the member with value + * property @current_value. + * + * Since: 2.10 + **/ +void +gtk_radio_action_set_current_value (GtkRadioAction *action, + gint current_value) +{ + GSList *slist; + + g_return_if_fail (GTK_IS_RADIO_ACTION (action)); + + if (action->private_data->group) + { + for (slist = action->private_data->group; slist; slist = slist->next) + { + GtkRadioAction *radio_action = slist->data; + + if (radio_action->private_data->value == current_value) + { + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (radio_action), + TRUE); + return; + } + } + } + + if (action->private_data->value == current_value) + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); + else + g_warning ("Radio group does not contain an action with value '%d'", + current_value); +}