]> Pileus Git - ~andy/gtk/blob - gtk/gtkradioaction.c
[GtkRadioAction] Annotate _set_group
[~andy/gtk] / gtk / gtkradioaction.c
1 /*
2  * GTK - The GIMP Toolkit
3  * Copyright (C) 1998, 1999 Red Hat, Inc.
4  * All rights reserved.
5  *
6  * This Library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This Library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with the Gnome Library; see the file COPYING.LIB.  If not,
18  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /*
23  * Author: James Henstridge <james@daa.com.au>
24  *
25  * Modified by the GTK+ Team and others 2003.  See the AUTHORS
26  * file for a list of people on the GTK+ Team.  See the ChangeLog
27  * files for a list of changes.  These files are distributed with
28  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
29  */
30
31 #include "config.h"
32
33 #include "gtkradioaction.h"
34 #include "gtkradiomenuitem.h"
35 #include "gtktoggleactionprivate.h"
36 #include "gtktoggletoolbutton.h"
37 #include "gtkintl.h"
38 #include "gtkprivate.h"
39 #include "gtkalias.h"
40
41 #define GTK_RADIO_ACTION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_RADIO_ACTION, GtkRadioActionPrivate))
42
43 struct _GtkRadioActionPrivate 
44 {
45   GSList *group;
46   gint    value;
47 };
48
49 enum 
50 {
51   CHANGED,
52   LAST_SIGNAL
53 };
54
55 enum 
56 {
57   PROP_0,
58   PROP_VALUE,
59   PROP_GROUP,
60   PROP_CURRENT_VALUE
61 };
62
63 static void gtk_radio_action_finalize     (GObject *object);
64 static void gtk_radio_action_set_property (GObject         *object,
65                                            guint            prop_id,
66                                            const GValue    *value,
67                                            GParamSpec      *pspec);
68 static void gtk_radio_action_get_property (GObject         *object,
69                                            guint            prop_id,
70                                            GValue          *value,
71                                            GParamSpec      *pspec);
72 static void gtk_radio_action_activate     (GtkAction *action);
73 static GtkWidget *create_menu_item        (GtkAction *action);
74
75
76 G_DEFINE_TYPE (GtkRadioAction, gtk_radio_action, GTK_TYPE_TOGGLE_ACTION)
77
78 static guint         radio_action_signals[LAST_SIGNAL] = { 0 };
79
80 static void
81 gtk_radio_action_class_init (GtkRadioActionClass *klass)
82 {
83   GObjectClass *gobject_class;
84   GtkActionClass *action_class;
85
86   gobject_class = G_OBJECT_CLASS (klass);
87   action_class = GTK_ACTION_CLASS (klass);
88
89   gobject_class->finalize = gtk_radio_action_finalize;
90   gobject_class->set_property = gtk_radio_action_set_property;
91   gobject_class->get_property = gtk_radio_action_get_property;
92
93   action_class->activate = gtk_radio_action_activate;
94
95   action_class->create_menu_item = create_menu_item;
96
97   /**
98    * GtkRadioAction:value:
99    *
100    * The value is an arbitrary integer which can be used as a
101    * convenient way to determine which action in the group is 
102    * currently active in an ::activate or ::changed signal handler.
103    * See gtk_radio_action_get_current_value() and #GtkRadioActionEntry
104    * for convenient ways to get and set this property.
105    *
106    * Since: 2.4
107    */
108   g_object_class_install_property (gobject_class,
109                                    PROP_VALUE,
110                                    g_param_spec_int ("value",
111                                                      P_("The value"),
112                                                      P_("The value returned by gtk_radio_action_get_current_value() when this action is the current action of its group."),
113                                                      G_MININT,
114                                                      G_MAXINT,
115                                                      0,
116                                                      GTK_PARAM_READWRITE));
117
118   /**
119    * GtkRadioAction:group:
120    *
121    * Sets a new group for a radio action.
122    *
123    * Since: 2.4
124    */
125   g_object_class_install_property (gobject_class,
126                                    PROP_GROUP,
127                                    g_param_spec_object ("group",
128                                                         P_("Group"),
129                                                         P_("The radio action whose group this action belongs to."),
130                                                         GTK_TYPE_RADIO_ACTION,
131                                                         GTK_PARAM_WRITABLE));
132
133   /**
134    * GtkRadioAction:current-value:
135    *
136    * The value property of the currently active member of the group to which
137    * this action belongs. 
138    *
139    * Since: 2.10
140    */
141   g_object_class_install_property (gobject_class,
142                                    PROP_CURRENT_VALUE,
143                                    g_param_spec_int ("current-value",
144                                                      P_("The current value"),
145                                                      P_("The value property of the currently active member of the group to which this action belongs."),
146                                                      G_MININT,
147                                                      G_MAXINT,
148                                                      0,
149                                                      GTK_PARAM_READWRITE));
150
151   /**
152    * GtkRadioAction::changed:
153    * @action: the action on which the signal is emitted
154    * @current: the member of @action<!-- -->s group which has just been activated
155    *
156    * The ::changed signal is emitted on every member of a radio group when the
157    * active member is changed. The signal gets emitted after the ::activate signals
158    * for the previous and current active members.
159    *
160    * Since: 2.4
161    */
162   radio_action_signals[CHANGED] =
163     g_signal_new (I_("changed"),
164                   G_OBJECT_CLASS_TYPE (klass),
165                   G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
166                   G_STRUCT_OFFSET (GtkRadioActionClass, changed),  NULL, NULL,
167                   g_cclosure_marshal_VOID__OBJECT,
168                   G_TYPE_NONE, 1, GTK_TYPE_RADIO_ACTION);
169
170   g_type_class_add_private (gobject_class, sizeof (GtkRadioActionPrivate));
171 }
172
173 static void
174 gtk_radio_action_init (GtkRadioAction *action)
175 {
176   action->private_data = GTK_RADIO_ACTION_GET_PRIVATE (action);
177   action->private_data->group = g_slist_prepend (NULL, action);
178   action->private_data->value = 0;
179
180   gtk_toggle_action_set_draw_as_radio (GTK_TOGGLE_ACTION (action), TRUE);
181 }
182
183 /**
184  * gtk_radio_action_new:
185  * @name: A unique name for the action
186  * @label: (allow-none): The label displayed in menu items and on buttons, or %NULL
187  * @tooltip: (allow-none): A tooltip for this action, or %NULL
188  * @stock_id: The stock icon to display in widgets representing this
189  *   action, or %NULL
190  * @value: The value which gtk_radio_action_get_current_value() should
191  *   return if this action is selected.
192  *
193  * Creates a new #GtkRadioAction object. To add the action to
194  * a #GtkActionGroup and set the accelerator for the action,
195  * call gtk_action_group_add_action_with_accel().
196  *
197  * Return value: a new #GtkRadioAction
198  *
199  * Since: 2.4
200  */
201 GtkRadioAction *
202 gtk_radio_action_new (const gchar *name,
203                       const gchar *label,
204                       const gchar *tooltip,
205                       const gchar *stock_id,
206                       gint value)
207 {
208   g_return_val_if_fail (name != NULL, NULL);
209
210   return g_object_new (GTK_TYPE_RADIO_ACTION,
211                        "name", name,
212                        "label", label,
213                        "tooltip", tooltip,
214                        "stock-id", stock_id,
215                        "value", value,
216                        NULL);
217 }
218
219 static void
220 gtk_radio_action_finalize (GObject *object)
221 {
222   GtkRadioAction *action;
223   GSList *tmp_list;
224
225   action = GTK_RADIO_ACTION (object);
226
227   action->private_data->group = g_slist_remove (action->private_data->group, action);
228
229   tmp_list = action->private_data->group;
230
231   while (tmp_list)
232     {
233       GtkRadioAction *tmp_action = tmp_list->data;
234
235       tmp_list = tmp_list->next;
236       tmp_action->private_data->group = action->private_data->group;
237     }
238
239   G_OBJECT_CLASS (gtk_radio_action_parent_class)->finalize (object);
240 }
241
242 static void
243 gtk_radio_action_set_property (GObject         *object,
244                                guint            prop_id,
245                                const GValue    *value,
246                                GParamSpec      *pspec)
247 {
248   GtkRadioAction *radio_action;
249   
250   radio_action = GTK_RADIO_ACTION (object);
251
252   switch (prop_id)
253     {
254     case PROP_VALUE:
255       radio_action->private_data->value = g_value_get_int (value);
256       break;
257     case PROP_GROUP: 
258       {
259         GtkRadioAction *arg;
260         GSList *slist = NULL;
261         
262         if (G_VALUE_HOLDS_OBJECT (value)) 
263           {
264             arg = GTK_RADIO_ACTION (g_value_get_object (value));
265             if (arg)
266               slist = gtk_radio_action_get_group (arg);
267             gtk_radio_action_set_group (radio_action, slist);
268           }
269       }
270       break;
271     case PROP_CURRENT_VALUE:
272       gtk_radio_action_set_current_value (radio_action,
273                                           g_value_get_int (value));
274       break;
275     default:
276       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
277       break;
278     }
279 }
280
281 static void
282 gtk_radio_action_get_property (GObject    *object,
283                                guint       prop_id,
284                                GValue     *value,
285                                GParamSpec *pspec)
286 {
287   GtkRadioAction *radio_action;
288
289   radio_action = GTK_RADIO_ACTION (object);
290
291   switch (prop_id)
292     {
293     case PROP_VALUE:
294       g_value_set_int (value, radio_action->private_data->value);
295       break;
296     case PROP_CURRENT_VALUE:
297       g_value_set_int (value,
298                        gtk_radio_action_get_current_value (radio_action));
299       break;
300     default:
301       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
302       break;
303     }
304 }
305
306 static void
307 gtk_radio_action_activate (GtkAction *action)
308 {
309   GtkRadioAction *radio_action;
310   GtkToggleAction *toggle_action;
311   GtkToggleAction *tmp_action;
312   GSList *tmp_list;
313
314   radio_action = GTK_RADIO_ACTION (action);
315   toggle_action = GTK_TOGGLE_ACTION (action);
316
317   if (toggle_action->private_data->active)
318     {
319       tmp_list = radio_action->private_data->group;
320
321       while (tmp_list)
322         {
323           tmp_action = tmp_list->data;
324           tmp_list = tmp_list->next;
325
326           if (tmp_action->private_data->active && (tmp_action != toggle_action)) 
327             {
328               toggle_action->private_data->active = !toggle_action->private_data->active;
329
330               break;
331             }
332         }
333       g_object_notify (G_OBJECT (action), "active");
334     }
335   else
336     {
337       toggle_action->private_data->active = !toggle_action->private_data->active;
338       g_object_notify (G_OBJECT (action), "active");
339
340       tmp_list = radio_action->private_data->group;
341       while (tmp_list)
342         {
343           tmp_action = tmp_list->data;
344           tmp_list = tmp_list->next;
345
346           if (tmp_action->private_data->active && (tmp_action != toggle_action))
347             {
348               _gtk_action_emit_activate (GTK_ACTION (tmp_action));
349               break;
350             }
351         }
352
353       tmp_list = radio_action->private_data->group;
354       while (tmp_list)
355         {
356           tmp_action = tmp_list->data;
357           tmp_list = tmp_list->next;
358           
359           g_object_notify (G_OBJECT (tmp_action), "current-value");
360
361           g_signal_emit (tmp_action, radio_action_signals[CHANGED], 0, radio_action);
362         }
363     }
364
365   gtk_toggle_action_toggled (toggle_action);
366 }
367
368 static GtkWidget *
369 create_menu_item (GtkAction *action)
370 {
371   return g_object_new (GTK_TYPE_CHECK_MENU_ITEM, 
372                        "draw-as-radio", TRUE,
373                        NULL);
374 }
375
376 /**
377  * gtk_radio_action_get_group:
378  * @action: the action object
379  *
380  * Returns the list representing the radio group for this object.
381  * Note that the returned list is only valid until the next change
382  * to the group. 
383  *
384  * A common way to set up a group of radio group is the following:
385  * |[
386  *   GSList *group = NULL;
387  *   GtkRadioAction *action;
388  *  
389  *   while (/&ast; more actions to add &ast;/)
390  *     {
391  *        action = gtk_radio_action_new (...);
392  *        
393  *        gtk_radio_action_set_group (action, group);
394  *        group = gtk_radio_action_get_group (action);
395  *     }
396  * ]|
397  *
398  * Returns:  (element-type GtkAction) (transfer none): the list representing the radio group for this object
399  *
400  * Since: 2.4
401  */
402 GSList *
403 gtk_radio_action_get_group (GtkRadioAction *action)
404 {
405   g_return_val_if_fail (GTK_IS_RADIO_ACTION (action), NULL);
406
407   return action->private_data->group;
408 }
409
410 /**
411  * gtk_radio_action_set_group:
412  * @action: the action object
413  * @group: (element-type GtkAction): a list representing a radio group
414  *
415  * Sets the radio group for the radio action object.
416  *
417  * Since: 2.4
418  */
419 void
420 gtk_radio_action_set_group (GtkRadioAction *action, 
421                             GSList         *group)
422 {
423   g_return_if_fail (GTK_IS_RADIO_ACTION (action));
424   g_return_if_fail (!g_slist_find (group, action));
425
426   if (action->private_data->group)
427     {
428       GSList *slist;
429
430       action->private_data->group = g_slist_remove (action->private_data->group, action);
431
432       for (slist = action->private_data->group; slist; slist = slist->next)
433         {
434           GtkRadioAction *tmp_action = slist->data;
435
436           tmp_action->private_data->group = action->private_data->group;
437         }
438     }
439
440   action->private_data->group = g_slist_prepend (group, action);
441
442   if (group)
443     {
444       GSList *slist;
445
446       for (slist = action->private_data->group; slist; slist = slist->next)
447         {
448           GtkRadioAction *tmp_action = slist->data;
449
450           tmp_action->private_data->group = action->private_data->group;
451         }
452     }
453   else
454     {
455       gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
456     }
457 }
458
459 /**
460  * gtk_radio_action_get_current_value:
461  * @action: a #GtkRadioAction
462  * 
463  * Obtains the value property of the currently active member of 
464  * the group to which @action belongs.
465  * 
466  * Return value: The value of the currently active group member
467  *
468  * Since: 2.4
469  **/
470 gint
471 gtk_radio_action_get_current_value (GtkRadioAction *action)
472 {
473   GSList *slist;
474
475   g_return_val_if_fail (GTK_IS_RADIO_ACTION (action), 0);
476
477   if (action->private_data->group)
478     {
479       for (slist = action->private_data->group; slist; slist = slist->next)
480         {
481           GtkToggleAction *toggle_action = slist->data;
482
483           if (toggle_action->private_data->active)
484             return GTK_RADIO_ACTION (toggle_action)->private_data->value;
485         }
486     }
487
488   return action->private_data->value;
489 }
490
491 /**
492  * gtk_radio_action_set_current_value:
493  * @action: a #GtkRadioAction
494  * @current_value: the new value
495  * 
496  * Sets the currently active group member to the member with value
497  * property @current_value.
498  *
499  * Since: 2.10
500  **/
501 void
502 gtk_radio_action_set_current_value (GtkRadioAction *action,
503                                     gint            current_value)
504 {
505   GSList *slist;
506
507   g_return_if_fail (GTK_IS_RADIO_ACTION (action));
508
509   if (action->private_data->group)
510     {
511       for (slist = action->private_data->group; slist; slist = slist->next)
512         {
513           GtkRadioAction *radio_action = slist->data;
514
515           if (radio_action->private_data->value == current_value)
516             {
517               gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (radio_action),
518                                             TRUE);
519               return;
520             }
521         }
522     }
523
524   if (action->private_data->value == current_value)
525     gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
526   else
527     g_warning ("Radio group does not contain an action with value '%d'",
528                current_value);
529 }
530
531 #define __GTK_RADIO_ACTION_C__
532 #include "gtkaliasdef.c"