]> Pileus Git - ~andy/gtk/blob - gtk/gtkradioaction.c
38959da49e13cb1fa14069587ea62b9a3eec6fbc
[~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
39 #define GTK_RADIO_ACTION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_RADIO_ACTION, GtkRadioActionPrivate))
40
41 struct _GtkRadioActionPrivate 
42 {
43   GSList *group;
44   gint    value;
45 };
46
47 enum 
48 {
49   CHANGED,
50   LAST_SIGNAL
51 };
52
53 enum 
54 {
55   PROP_0,
56   PROP_VALUE
57 };
58
59 static void gtk_radio_action_init         (GtkRadioAction *action);
60 static void gtk_radio_action_class_init   (GtkRadioActionClass *class);
61 static void gtk_radio_action_finalize     (GObject *object);
62 static void gtk_radio_action_set_property (GObject         *object,
63                                            guint            prop_id,
64                                            const GValue    *value,
65                                            GParamSpec      *pspec);
66 static void gtk_radio_action_get_property (GObject         *object,
67                                            guint            prop_id,
68                                            GValue          *value,
69                                            GParamSpec      *pspec);
70 static void gtk_radio_action_activate     (GtkAction *action);
71 static GtkWidget *create_menu_item        (GtkAction *action);
72
73
74 GType
75 gtk_radio_action_get_type (void)
76 {
77   static GtkType type = 0;
78
79   if (!type)
80     {
81       static const GTypeInfo type_info =
82       {
83         sizeof (GtkRadioActionClass),
84         (GBaseInitFunc) NULL,
85         (GBaseFinalizeFunc) NULL,
86         (GClassInitFunc) gtk_radio_action_class_init,
87         (GClassFinalizeFunc) NULL,
88         NULL,
89         
90         sizeof (GtkRadioAction),
91         0, /* n_preallocs */
92         (GInstanceInitFunc) gtk_radio_action_init,
93       };
94
95       type = g_type_register_static (GTK_TYPE_TOGGLE_ACTION,
96                                      "GtkRadioAction",
97                                      &type_info, 0);
98     }
99   return type;
100 }
101
102 static GObjectClass *parent_class = NULL;
103 static guint         radio_action_signals[LAST_SIGNAL] = { 0 };
104
105 static void
106 gtk_radio_action_class_init (GtkRadioActionClass *klass)
107 {
108   GObjectClass *gobject_class;
109   GtkActionClass *action_class;
110
111   parent_class = g_type_class_peek_parent (klass);
112   gobject_class = G_OBJECT_CLASS (klass);
113   action_class = GTK_ACTION_CLASS (klass);
114
115   gobject_class->finalize = gtk_radio_action_finalize;
116   gobject_class->set_property = gtk_radio_action_set_property;
117   gobject_class->get_property = gtk_radio_action_get_property;
118
119   action_class->activate = gtk_radio_action_activate;
120
121   action_class->create_menu_item = create_menu_item;
122
123   /**
124    * GtkRadioAction:value:
125    *
126    * The value is an arbitrary integer which can be used as a
127    * convenient way to determine which action in the group is 
128    * currently active in an ::activate or ::changed signal handler.
129    * See gtk_radio_action_get_current_value() and #GtkRadioActionEntry
130    * for convenient ways to get and set this property.
131    *
132    * Since: 2.4
133    */
134   g_object_class_install_property (gobject_class,
135                                    PROP_VALUE,
136                                    g_param_spec_int ("value",
137                                                      _("The value"),
138                                                      _("The value returned by gtk_radio_action_get_current_value() when this action is the current action of its group."),
139                                                      G_MININT,
140                                                      G_MAXINT,
141                                                      0,
142                                                      G_PARAM_READWRITE));
143
144   /**
145    * GtkRadioAction::changed:
146    * @action: the action on which the signal is emitted
147    * @current: the member of @action<!-- -->s group which has just been activated
148    *
149    * The ::changed signal is emitted on every member of a radio group when the
150    * active member is changed. The signal gets emitted after the ::activate signals
151    * for the previous and current active members.
152    *
153    * Since: 2.4
154    */
155   radio_action_signals[CHANGED] =
156     g_signal_new ("changed",
157                   G_OBJECT_CLASS_TYPE (klass),
158                   G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
159                   G_STRUCT_OFFSET (GtkRadioActionClass, changed),  NULL, NULL,
160                   g_cclosure_marshal_VOID__OBJECT,
161                   G_TYPE_NONE, 1, GTK_TYPE_RADIO_ACTION);
162
163   g_type_class_add_private (gobject_class, sizeof (GtkRadioActionPrivate));
164 }
165
166 static void
167 gtk_radio_action_init (GtkRadioAction *action)
168 {
169   action->private_data = GTK_RADIO_ACTION_GET_PRIVATE (action);
170   action->private_data->group = g_slist_prepend (NULL, action);
171   action->private_data->value = 0;
172 }
173
174 static void
175 gtk_radio_action_finalize (GObject *object)
176 {
177   GtkRadioAction *action;
178   GSList *tmp_list;
179
180   action = GTK_RADIO_ACTION (object);
181
182   action->private_data->group = g_slist_remove (action->private_data->group, action);
183
184   tmp_list = action->private_data->group;
185
186   while (tmp_list)
187     {
188       GtkRadioAction *tmp_action = tmp_list->data;
189
190       tmp_list = tmp_list->next;
191       tmp_action->private_data->group = action->private_data->group;
192     }
193
194   if (parent_class->finalize)
195     (* parent_class->finalize) (object);
196 }
197
198 static void
199 gtk_radio_action_set_property (GObject         *object,
200                                guint            prop_id,
201                                const GValue    *value,
202                                GParamSpec      *pspec)
203 {
204   GtkRadioAction *radio_action;
205   
206   radio_action = GTK_RADIO_ACTION (object);
207
208   switch (prop_id)
209     {
210     case PROP_VALUE:
211       radio_action->private_data->value = g_value_get_int (value);
212       break;
213     default:
214       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
215       break;
216     }
217 }
218
219 static void
220 gtk_radio_action_get_property (GObject    *object,
221                                guint       prop_id,
222                                GValue     *value,
223                                GParamSpec *pspec)
224 {
225   GtkRadioAction *radio_action;
226
227   radio_action = GTK_RADIO_ACTION (object);
228
229   switch (prop_id)
230     {
231     case PROP_VALUE:
232       g_value_set_int (value, radio_action->private_data->value);
233       break;
234     default:
235       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
236       break;
237     }
238 }
239
240 static void
241 gtk_radio_action_activate (GtkAction *action)
242 {
243   GtkRadioAction *radio_action;
244   GtkToggleAction *toggle_action;
245   GtkToggleAction *tmp_action;
246   GSList *tmp_list;
247
248   radio_action = GTK_RADIO_ACTION (action);
249   toggle_action = GTK_TOGGLE_ACTION (action);
250
251   if (toggle_action->private_data->active)
252     {
253       tmp_list = radio_action->private_data->group;
254
255       while (tmp_list)
256         {
257           tmp_action = tmp_list->data;
258           tmp_list = tmp_list->next;
259
260           if (tmp_action->private_data->active && (tmp_action != toggle_action)) 
261             {
262               toggle_action->private_data->active = !toggle_action->private_data->active;
263               break;
264             }
265         }
266     }
267   else
268     {
269       toggle_action->private_data->active = !toggle_action->private_data->active;
270
271       tmp_list = radio_action->private_data->group;
272       while (tmp_list)
273         {
274           tmp_action = tmp_list->data;
275           tmp_list = tmp_list->next;
276
277           if (tmp_action->private_data->active && (tmp_action != toggle_action))
278             {
279               gtk_action_activate (GTK_ACTION (tmp_action));
280               break;
281             }
282         }
283
284       tmp_list = radio_action->private_data->group;
285       while (tmp_list)
286         {
287           tmp_action = tmp_list->data;
288           tmp_list = tmp_list->next;
289           
290           g_signal_emit (tmp_action, radio_action_signals[CHANGED], 0, radio_action);
291         }
292     }
293
294   gtk_toggle_action_toggled (toggle_action);
295 }
296
297 static GtkWidget *
298 create_menu_item (GtkAction *action)
299 {
300   return g_object_new (GTK_TYPE_CHECK_MENU_ITEM, 
301                        "draw_as_radio", TRUE,
302                        NULL);
303 }
304
305 /**
306  * gtk_radio_action_get_group:
307  * @action: the action object
308  *
309  * Returns the list representing the radio group for this object
310  *
311  * Returns: the list representing the radio group for this object
312  *
313  * Since: 2.4
314  */
315 GSList *
316 gtk_radio_action_get_group (GtkRadioAction *action)
317 {
318   g_return_val_if_fail (GTK_IS_RADIO_ACTION (action), NULL);
319
320   return action->private_data->group;
321 }
322
323 /**
324  * gtk_radio_action_set_group:
325  * @action: the action object
326  * @group: a list representing a radio group
327  *
328  * Sets the radio group for the radio action object.
329  *
330  * Since: 2.4
331  */
332 void
333 gtk_radio_action_set_group (GtkRadioAction *action, 
334                             GSList         *group)
335 {
336   g_return_if_fail (GTK_IS_RADIO_ACTION (action));
337   g_return_if_fail (!g_slist_find (group, action));
338
339   if (action->private_data->group)
340     {
341       GSList *slist;
342
343       action->private_data->group = g_slist_remove (action->private_data->group, action);
344
345       for (slist = action->private_data->group; slist; slist = slist->next)
346         {
347           GtkRadioAction *tmp_action = slist->data;
348
349           tmp_action->private_data->group = action->private_data->group;
350         }
351     }
352
353   action->private_data->group = g_slist_prepend (group, action);
354
355   if (group)
356     {
357       GSList *slist;
358
359       for (slist = action->private_data->group; slist; slist = slist->next)
360         {
361           GtkRadioAction *tmp_action = slist->data;
362
363           tmp_action->private_data->group = action->private_data->group;
364         }
365     }
366   else
367     {
368       gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
369     }
370 }
371
372 /**
373  * gtk_radio_action_get_current_value:
374  * @action: a #GtkRadioAction
375  * 
376  * Obtains the value property of the the currently active member of 
377  * the group to which @action belongs.
378  * 
379  * Return value: The value of the currently active group member
380  *
381  * Since: 2.4
382  **/
383 gint
384 gtk_radio_action_get_current_value (GtkRadioAction *action)
385 {
386   GSList *slist;
387
388   g_return_val_if_fail (GTK_IS_RADIO_ACTION (action), 0);
389
390   if (action->private_data->group)
391     {
392       for (slist = action->private_data->group; slist; slist = slist->next)
393         {
394           GtkToggleAction *toggle_action = slist->data;
395
396           if (toggle_action->private_data->active)
397             return GTK_RADIO_ACTION (toggle_action)->private_data->value;
398         }
399     }
400
401   return action->private_data->value;
402 }