]> Pileus Git - ~andy/gtk/blob - gtk/gtkradiomenuitem.c
set radio_menu_item->group to NULL after removing it from the list, as it
[~andy/gtk] / gtk / gtkradiomenuitem.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "gtkaccellabel.h"
28 #include "gtkradiomenuitem.h"
29
30
31 static void gtk_radio_menu_item_class_init     (GtkRadioMenuItemClass *klass);
32 static void gtk_radio_menu_item_init           (GtkRadioMenuItem      *radio_menu_item);
33 static void gtk_radio_menu_item_destroy        (GtkObject             *object);
34 static void gtk_radio_menu_item_activate       (GtkMenuItem           *menu_item);
35 static void gtk_radio_menu_item_draw_indicator (GtkCheckMenuItem      *check_menu_item,
36                                                 GdkRectangle          *area);
37
38 static GtkCheckMenuItemClass *parent_class = NULL;
39
40 GtkType
41 gtk_radio_menu_item_get_type (void)
42 {
43   static GtkType radio_menu_item_type = 0;
44
45   if (!radio_menu_item_type)
46     {
47       static const GtkTypeInfo radio_menu_item_info =
48       {
49         "GtkRadioMenuItem",
50         sizeof (GtkRadioMenuItem),
51         sizeof (GtkRadioMenuItemClass),
52         (GtkClassInitFunc) gtk_radio_menu_item_class_init,
53         (GtkObjectInitFunc) gtk_radio_menu_item_init,
54         /* reserved_1 */ NULL,
55         /* reserved_2 */ NULL,
56         (GtkClassInitFunc) NULL,
57       };
58
59       radio_menu_item_type = gtk_type_unique (gtk_check_menu_item_get_type (), &radio_menu_item_info);
60     }
61
62   return radio_menu_item_type;
63 }
64
65 GtkWidget*
66 gtk_radio_menu_item_new (GSList *group)
67 {
68   GtkRadioMenuItem *radio_menu_item;
69
70   radio_menu_item = gtk_type_new (gtk_radio_menu_item_get_type ());
71
72   gtk_radio_menu_item_set_group (radio_menu_item, group);
73
74   return GTK_WIDGET (radio_menu_item);
75 }
76
77 void
78 gtk_radio_menu_item_set_group (GtkRadioMenuItem *radio_menu_item,
79                                GSList           *group)
80 {
81   g_return_if_fail (GTK_IS_RADIO_MENU_ITEM (radio_menu_item));
82   g_return_if_fail (!g_slist_find (group, radio_menu_item));
83   
84   if (radio_menu_item->group)
85     {
86       GSList *slist;
87       
88       radio_menu_item->group = g_slist_remove (radio_menu_item->group, radio_menu_item);
89       
90       for (slist = radio_menu_item->group; slist; slist = slist->next)
91         {
92           GtkRadioMenuItem *tmp_item;
93           
94           tmp_item = slist->data;
95           
96           tmp_item->group = radio_menu_item->group;
97         }
98     }
99   
100   radio_menu_item->group = g_slist_prepend (group, radio_menu_item);
101   
102   if (group)
103     {
104       GSList *slist;
105       
106       for (slist = group; slist; slist = slist->next)
107         {
108           GtkRadioMenuItem *tmp_item;
109           
110           tmp_item = slist->data;
111           
112           tmp_item->group = radio_menu_item->group;
113         }
114     }
115   else
116     {
117       GTK_CHECK_MENU_ITEM (radio_menu_item)->active = TRUE;
118       /* gtk_widget_set_state (GTK_WIDGET (radio_menu_item), GTK_STATE_ACTIVE);
119        */
120     }
121 }
122
123 GtkWidget*
124 gtk_radio_menu_item_new_with_label (GSList *group,
125                                     const gchar *label)
126 {
127   GtkWidget *radio_menu_item;
128   GtkWidget *accel_label;
129
130   radio_menu_item = gtk_radio_menu_item_new (group);
131   accel_label = gtk_accel_label_new (label);
132   gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
133   gtk_container_add (GTK_CONTAINER (radio_menu_item), accel_label);
134   gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), radio_menu_item);
135   gtk_widget_show (accel_label);
136
137   return radio_menu_item;
138 }
139
140
141 /**
142  * gtk_radio_menu_item_new_with_mnemonic:
143  * @group: group the radio menu item is inside
144  * @label: the text of the button, with an underscore in front of the
145  *         mnemonic character
146  * @returns: a new #GtkRadioMenuItem
147  *
148  * Creates a new #GtkRadioMenuItem containing a label. The label
149  * will be created using gtk_label_new_with_mnemonic(), so underscores
150  * in @label indicate the mnemonic for the menu item.
151  **/
152 GtkWidget*
153 gtk_radio_menu_item_new_with_mnemonic (GSList *group,
154                                        const gchar *label)
155 {
156   GtkWidget *radio_menu_item;
157   GtkWidget *accel_label;
158
159   radio_menu_item = gtk_radio_menu_item_new (group);
160   accel_label = gtk_type_new (GTK_TYPE_ACCEL_LABEL);
161   gtk_label_set_text_with_mnemonic (GTK_LABEL (accel_label), label);
162   gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
163
164   gtk_container_add (GTK_CONTAINER (radio_menu_item), accel_label);
165   gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), radio_menu_item);
166   gtk_widget_show (accel_label);
167
168   return radio_menu_item;
169 }
170
171 GSList*
172 gtk_radio_menu_item_get_group (GtkRadioMenuItem *radio_menu_item)
173 {
174   g_return_val_if_fail (GTK_IS_RADIO_MENU_ITEM (radio_menu_item), NULL);
175
176   return radio_menu_item->group;
177 }
178
179
180 static void
181 gtk_radio_menu_item_class_init (GtkRadioMenuItemClass *klass)
182 {
183   GtkObjectClass *object_class;
184   GtkMenuItemClass *menu_item_class;
185   GtkCheckMenuItemClass *check_menu_item_class;
186
187   object_class = (GtkObjectClass*) klass;
188   menu_item_class = (GtkMenuItemClass*) klass;
189   check_menu_item_class = (GtkCheckMenuItemClass*) klass;
190
191   parent_class = gtk_type_class (gtk_check_menu_item_get_type ());
192
193   object_class->destroy = gtk_radio_menu_item_destroy;
194
195   menu_item_class->activate = gtk_radio_menu_item_activate;
196
197   check_menu_item_class->draw_indicator = gtk_radio_menu_item_draw_indicator;
198 }
199
200 static void
201 gtk_radio_menu_item_init (GtkRadioMenuItem *radio_menu_item)
202 {
203   radio_menu_item->group = g_slist_prepend (NULL, radio_menu_item);
204 }
205
206 static void
207 gtk_radio_menu_item_destroy (GtkObject *object)
208 {
209   GtkRadioMenuItem *radio_menu_item;
210   GtkRadioMenuItem *tmp_menu_item;
211   GSList *tmp_list;
212
213   g_return_if_fail (GTK_IS_RADIO_MENU_ITEM (object));
214
215   radio_menu_item = GTK_RADIO_MENU_ITEM (object);
216
217   radio_menu_item->group = g_slist_remove (radio_menu_item->group,
218                                            radio_menu_item);
219   tmp_list = radio_menu_item->group;
220
221   while (tmp_list)
222     {
223       tmp_menu_item = tmp_list->data;
224       tmp_list = tmp_list->next;
225
226       tmp_menu_item->group = radio_menu_item->group;
227     }
228
229   /* this radio menu item is no longer in the group */
230   radio_menu_item->group = NULL;
231   
232   if (GTK_OBJECT_CLASS (parent_class)->destroy)
233     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
234 }
235
236 static void
237 gtk_radio_menu_item_activate (GtkMenuItem *menu_item)
238 {
239   GtkRadioMenuItem *radio_menu_item;
240   GtkCheckMenuItem *check_menu_item;
241   GtkCheckMenuItem *tmp_menu_item;
242   GSList *tmp_list;
243   gint toggled;
244
245   g_return_if_fail (GTK_IS_RADIO_MENU_ITEM (menu_item));
246
247   radio_menu_item = GTK_RADIO_MENU_ITEM (menu_item);
248   check_menu_item = GTK_CHECK_MENU_ITEM (menu_item);
249   toggled = FALSE;
250
251   if (check_menu_item->active)
252     {
253       tmp_menu_item = NULL;
254       tmp_list = radio_menu_item->group;
255
256       while (tmp_list)
257         {
258           tmp_menu_item = tmp_list->data;
259           tmp_list = tmp_list->next;
260
261           if (tmp_menu_item->active && (tmp_menu_item != check_menu_item))
262             break;
263
264           tmp_menu_item = NULL;
265         }
266
267       if (tmp_menu_item)
268         {
269           toggled = TRUE;
270           check_menu_item->active = !check_menu_item->active;
271         }
272     }
273   else
274     {
275       toggled = TRUE;
276       check_menu_item->active = !check_menu_item->active;
277
278       tmp_list = radio_menu_item->group;
279       while (tmp_list)
280         {
281           tmp_menu_item = tmp_list->data;
282           tmp_list = tmp_list->next;
283
284           if (tmp_menu_item->active && (tmp_menu_item != check_menu_item))
285             {
286               gtk_menu_item_activate (GTK_MENU_ITEM (tmp_menu_item));
287               break;
288             }
289         }
290     }
291
292   if (toggled)
293     gtk_check_menu_item_toggled (check_menu_item);
294   gtk_widget_queue_draw (GTK_WIDGET (radio_menu_item));
295 }
296
297 static void
298 gtk_radio_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item,
299                                     GdkRectangle     *area)
300 {
301   GtkWidget *widget;
302   GtkStateType state_type;
303   GtkShadowType shadow_type;
304   gint width, height;
305   gint x, y;
306
307   g_return_if_fail (GTK_IS_RADIO_MENU_ITEM (check_menu_item));
308
309   if (GTK_WIDGET_DRAWABLE (check_menu_item))
310     {
311       widget = GTK_WIDGET (check_menu_item);
312
313       width = 8;
314       height = 8;
315       x = (GTK_CONTAINER (check_menu_item)->border_width +
316            widget->style->xthickness + 2);
317       y = (widget->allocation.height - height) / 2;
318
319       if (check_menu_item->active ||
320           check_menu_item->always_show_toggle ||
321           (GTK_WIDGET_STATE (check_menu_item) == GTK_STATE_PRELIGHT))
322         {
323           state_type = GTK_WIDGET_STATE (widget);
324           if (check_menu_item->active ||
325               !check_menu_item->always_show_toggle)
326             shadow_type = GTK_SHADOW_IN;
327           else
328             shadow_type = GTK_SHADOW_OUT;
329
330           if (check_menu_item->inconsistent)
331             shadow_type = GTK_SHADOW_ETCHED_IN;
332           
333           gtk_paint_option (widget->style, widget->window,
334                             state_type, shadow_type,
335                             area, widget, "option",
336                             x, y, width, height);
337         }
338     }
339 }
340