]> Pileus Git - ~andy/gtk/blob - gtk/gtkradiobutton.c
Patch from Matthias Clasen to remove remove all instances of
[~andy/gtk] / gtk / gtkradiobutton.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 "gtklabel.h"
28 #include "gtkradiobutton.h"
29 #include "gtksignal.h"
30
31
32 enum {
33   ARG_0,
34   ARG_GROUP
35 };
36
37
38 static void gtk_radio_button_class_init     (GtkRadioButtonClass  *klass);
39 static void gtk_radio_button_init           (GtkRadioButton       *radio_button);
40 static void gtk_radio_button_destroy        (GtkObject            *object);
41 static void gtk_radio_button_clicked        (GtkButton            *button);
42 static void gtk_radio_button_draw_indicator (GtkCheckButton       *check_button,
43                                              GdkRectangle         *area);
44 static void gtk_radio_button_set_arg        (GtkObject            *object,
45                                              GtkArg               *arg,
46                                              guint                 arg_id);
47 static void gtk_radio_button_get_arg        (GtkObject            *object,
48                                              GtkArg               *arg,
49                                              guint                 arg_id);
50
51
52 static GtkCheckButtonClass *parent_class = NULL;
53
54
55 GtkType
56 gtk_radio_button_get_type (void)
57 {
58   static GtkType radio_button_type = 0;
59
60   if (!radio_button_type)
61     {
62       static const GtkTypeInfo radio_button_info =
63       {
64         "GtkRadioButton",
65         sizeof (GtkRadioButton),
66         sizeof (GtkRadioButtonClass),
67         (GtkClassInitFunc) gtk_radio_button_class_init,
68         (GtkObjectInitFunc) gtk_radio_button_init,
69         /* reserved_1 */ NULL,
70         /* reserved_2 */ NULL,
71         (GtkClassInitFunc) NULL,
72       };
73
74       radio_button_type = gtk_type_unique (gtk_check_button_get_type (), &radio_button_info);
75     }
76
77   return radio_button_type;
78 }
79
80 static void
81 gtk_radio_button_class_init (GtkRadioButtonClass *class)
82 {
83   GtkObjectClass *object_class;
84   GtkButtonClass *button_class;
85   GtkCheckButtonClass *check_button_class;
86
87   object_class = (GtkObjectClass*) class;
88   button_class = (GtkButtonClass*) class;
89   check_button_class = (GtkCheckButtonClass*) class;
90
91   parent_class = gtk_type_class (gtk_check_button_get_type ());
92
93   gtk_object_add_arg_type ("GtkRadioButton::group", GTK_TYPE_RADIO_BUTTON, GTK_ARG_WRITABLE, ARG_GROUP);
94
95   object_class->set_arg = gtk_radio_button_set_arg;
96   object_class->get_arg = gtk_radio_button_get_arg;
97   object_class->destroy = gtk_radio_button_destroy;
98
99   button_class->clicked = gtk_radio_button_clicked;
100
101   check_button_class->draw_indicator = gtk_radio_button_draw_indicator;
102 }
103
104 static void
105 gtk_radio_button_init (GtkRadioButton *radio_button)
106 {
107   GTK_WIDGET_SET_FLAGS (radio_button, GTK_NO_WINDOW);
108   GTK_WIDGET_UNSET_FLAGS (radio_button, GTK_RECEIVES_DEFAULT);
109
110   GTK_TOGGLE_BUTTON (radio_button)->active = TRUE;
111
112   radio_button->group = g_slist_prepend (NULL, radio_button);
113
114   gtk_widget_set_state (GTK_WIDGET (radio_button), GTK_STATE_ACTIVE);
115 }
116
117 static void
118 gtk_radio_button_set_arg (GtkObject      *object,
119                           GtkArg         *arg,
120                           guint           arg_id)
121 {
122   GtkRadioButton *radio_button;
123
124   radio_button = GTK_RADIO_BUTTON (object);
125
126   switch (arg_id)
127     {
128       GSList *slist;
129
130     case ARG_GROUP:
131       if (GTK_VALUE_OBJECT (*arg))
132         slist = gtk_radio_button_get_group ((GtkRadioButton*) GTK_VALUE_OBJECT (*arg));
133       else
134         slist = NULL;
135       gtk_radio_button_set_group (radio_button, slist);
136       break;
137     default:
138       break;
139     }
140 }
141
142 static void
143 gtk_radio_button_get_arg (GtkObject      *object,
144                           GtkArg         *arg,
145                           guint           arg_id)
146 {
147   GtkRadioButton *radio_button;
148
149   radio_button = GTK_RADIO_BUTTON (object);
150
151   switch (arg_id)
152     {
153     default:
154       arg->type = GTK_TYPE_INVALID;
155       break;
156     }
157 }
158
159 void
160 gtk_radio_button_set_group (GtkRadioButton *radio_button,
161                             GSList         *group)
162 {
163   g_return_if_fail (GTK_IS_RADIO_BUTTON (radio_button));
164   g_return_if_fail (!g_slist_find (group, radio_button));
165
166   if (radio_button->group)
167     {
168       GSList *slist;
169       
170       radio_button->group = g_slist_remove (radio_button->group, radio_button);
171       
172       for (slist = radio_button->group; slist; slist = slist->next)
173         {
174           GtkRadioButton *tmp_button;
175           
176           tmp_button = slist->data;
177           
178           tmp_button->group = radio_button->group;
179         }
180     }
181   
182   radio_button->group = g_slist_prepend (group, radio_button);
183   
184   if (group)
185     {
186       GSList *slist;
187       
188       for (slist = group; slist; slist = slist->next)
189         {
190           GtkRadioButton *tmp_button;
191           
192           tmp_button = slist->data;
193           
194           tmp_button->group = radio_button->group;
195         }
196     }
197
198   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), group == NULL);
199 }
200
201 GtkWidget*
202 gtk_radio_button_new (GSList *group)
203 {
204   GtkRadioButton *radio_button;
205
206   radio_button = gtk_type_new (gtk_radio_button_get_type ());
207
208   if (group)
209     gtk_radio_button_set_group (radio_button, group);
210
211   return GTK_WIDGET (radio_button);
212 }
213
214 GtkWidget*
215 gtk_radio_button_new_with_label (GSList      *group,
216                                  const gchar *label)
217 {
218   GtkWidget *radio_button;
219   GtkWidget *label_widget;
220
221   radio_button = gtk_radio_button_new (group);
222   label_widget = gtk_label_new (label);
223   gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
224
225   gtk_container_add (GTK_CONTAINER (radio_button), label_widget);
226   gtk_widget_show (label_widget);
227
228   return radio_button;
229 }
230
231
232 /**
233  * gtk_radio_button_new_with_mnemonic:
234  * @group: the radio button group
235  * @label: the text of the button, with an underscore in front of the
236  *         mnemonic character
237  * @returns: a new #GtkRadioButton
238  *
239  * Creates a new #GtkRadioButton containing a label. The label
240  * will be created using gtk_label_new_with_mnemonic(), so underscores
241  * in @label indicate the mnemonic for the button.
242  **/
243 GtkWidget*
244 gtk_radio_button_new_with_mnemonic (GSList      *group,
245                                     const gchar *label)
246 {
247   GtkWidget *radio_button;
248   GtkWidget *label_widget;
249
250   radio_button = gtk_radio_button_new (group);
251   label_widget = gtk_label_new_with_mnemonic (label);
252   gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
253
254   gtk_container_add (GTK_CONTAINER (radio_button), label_widget);
255   gtk_widget_show (label_widget);
256
257   return radio_button;
258 }
259
260 GtkWidget*
261 gtk_radio_button_new_from_widget (GtkRadioButton *group)
262 {
263   GSList *l = NULL;
264   if (group)
265     l = gtk_radio_button_get_group (group);
266   return gtk_radio_button_new (l);
267 }
268
269
270 GtkWidget*
271 gtk_radio_button_new_with_label_from_widget (GtkRadioButton *group,
272                                              const gchar    *label)
273 {
274   GSList *l = NULL;
275   if (group)
276     l = gtk_radio_button_get_group (group);
277   return gtk_radio_button_new_with_label (l, label);
278 }
279
280 /**
281  * gtk_radio_button_new_with_mnemonic_from_widget:
282  * @group: widget to get radio group from
283  * @label: the text of the button, with an underscore in front of the
284  *         mnemonic character
285  * @returns: a new #GtkRadioButton
286  *
287  * Creates a new #GtkRadioButton containing a label. The label
288  * will be created using gtk_label_new_with_mnemonic(), so underscores
289  * in @label indicate the mnemonic for the button.
290  **/
291 GtkWidget*
292 gtk_radio_button_new_with_mnemonic_from_widget (GtkRadioButton *group,
293                                                 const gchar    *label)
294 {
295   GSList *l = NULL;
296   if (group)
297     l = gtk_radio_button_get_group (group);
298   return gtk_radio_button_new_with_mnemonic (l, label);
299 }
300
301 GSList*
302 gtk_radio_button_get_group (GtkRadioButton *radio_button)
303 {
304   g_return_val_if_fail (GTK_IS_RADIO_BUTTON (radio_button), NULL);
305
306   return radio_button->group;
307 }
308
309
310 static void
311 gtk_radio_button_destroy (GtkObject *object)
312 {
313   GtkRadioButton *radio_button;
314   GtkRadioButton *tmp_button;
315   GSList *tmp_list;
316
317   g_return_if_fail (GTK_IS_RADIO_BUTTON (object));
318
319   radio_button = GTK_RADIO_BUTTON (object);
320
321   radio_button->group = g_slist_remove (radio_button->group, radio_button);
322   tmp_list = radio_button->group;
323
324   while (tmp_list)
325     {
326       tmp_button = tmp_list->data;
327       tmp_list = tmp_list->next;
328
329       tmp_button->group = radio_button->group;
330     }
331
332   if (GTK_OBJECT_CLASS (parent_class)->destroy)
333     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
334 }
335
336 static void
337 gtk_radio_button_clicked (GtkButton *button)
338 {
339   GtkToggleButton *toggle_button;
340   GtkRadioButton *radio_button;
341   GtkToggleButton *tmp_button;
342   GtkStateType new_state;
343   GSList *tmp_list;
344   gint toggled;
345
346   g_return_if_fail (GTK_IS_RADIO_BUTTON (button));
347
348   radio_button = GTK_RADIO_BUTTON (button);
349   toggle_button = GTK_TOGGLE_BUTTON (button);
350   toggled = FALSE;
351
352   gtk_widget_ref (GTK_WIDGET (button));
353
354   if (toggle_button->active)
355     {
356       tmp_button = NULL;
357       tmp_list = radio_button->group;
358
359       while (tmp_list)
360         {
361           tmp_button = tmp_list->data;
362           tmp_list = tmp_list->next;
363
364           if (tmp_button->active && tmp_button != toggle_button)
365             break;
366
367           tmp_button = NULL;
368         }
369
370       if (!tmp_button)
371         {
372           new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
373         }
374       else
375         {
376           toggled = TRUE;
377           toggle_button->active = !toggle_button->active;
378           new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL);
379         }
380     }
381   else
382     {
383       toggled = TRUE;
384       toggle_button->active = !toggle_button->active;
385
386       tmp_list = radio_button->group;
387       while (tmp_list)
388         {
389           tmp_button = tmp_list->data;
390           tmp_list = tmp_list->next;
391
392           if (tmp_button->active && (tmp_button != toggle_button))
393             {
394               gtk_button_clicked (GTK_BUTTON (tmp_button));
395               break;
396             }
397         }
398
399       new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
400     }
401
402   if (GTK_WIDGET_STATE (button) != new_state)
403     gtk_widget_set_state (GTK_WIDGET (button), new_state);
404
405   if (toggled)
406     gtk_toggle_button_toggled (toggle_button);
407
408   gtk_widget_queue_draw (GTK_WIDGET (button));
409
410   gtk_widget_unref (GTK_WIDGET (button));
411 }
412
413 static void
414 gtk_radio_button_draw_indicator (GtkCheckButton *check_button,
415                                  GdkRectangle   *area)
416 {
417   GtkWidget *widget;
418   GtkButton *button;
419   GtkToggleButton *toggle_button;
420   GtkStateType state_type;
421   GtkShadowType shadow_type;
422   GdkRectangle restrict_area;
423   GdkRectangle new_area;
424   gint x, y;
425   gint indicator_size, indicator_spacing;
426
427   g_return_if_fail (GTK_IS_RADIO_BUTTON (check_button));
428
429   if (GTK_WIDGET_VISIBLE (check_button) && GTK_WIDGET_MAPPED (check_button))
430     {
431       widget = GTK_WIDGET (check_button);
432       button = GTK_BUTTON (check_button);
433       toggle_button = GTK_TOGGLE_BUTTON (check_button);
434
435       state_type = GTK_WIDGET_STATE (widget);
436       if ((state_type != GTK_STATE_NORMAL) &&
437           (state_type != GTK_STATE_PRELIGHT))
438         state_type = GTK_STATE_NORMAL;
439
440       _gtk_check_button_get_props (check_button, &indicator_size, &indicator_spacing);
441
442       restrict_area.x = widget->allocation.x + GTK_CONTAINER (widget)->border_width;
443       restrict_area.y = widget->allocation.y + GTK_CONTAINER (widget)->border_width;
444       restrict_area.width = widget->allocation.width - ( 2 * GTK_CONTAINER (widget)->border_width);
445       restrict_area.height = widget->allocation.height - ( 2 * GTK_CONTAINER (widget)->border_width);
446
447       if (gdk_rectangle_intersect (area, &restrict_area, &new_area))
448         {
449            if (state_type != GTK_STATE_NORMAL)
450              gtk_paint_flat_box(widget->style, widget->window, state_type, 
451                                 GTK_SHADOW_ETCHED_OUT,
452                                 area, widget, "radiobutton",
453                                 new_area.x, new_area.y,
454                                 new_area.width, new_area.height);
455         }
456       
457       x = widget->allocation.x + indicator_spacing + GTK_CONTAINER (widget)->border_width;
458       y = widget->allocation.y + (widget->allocation.height - indicator_size) / 2;
459       
460       if (GTK_TOGGLE_BUTTON (widget)->active)
461         shadow_type = GTK_SHADOW_IN;
462       else
463         shadow_type = GTK_SHADOW_OUT;
464
465       if (GTK_TOGGLE_BUTTON (widget)->inconsistent)
466         shadow_type = GTK_SHADOW_ETCHED_IN;
467       
468       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
469         x = widget->allocation.x + widget->allocation.width - (indicator_size + x - widget->allocation.x);
470
471       gtk_paint_option (widget->style, widget->window,
472                         GTK_WIDGET_STATE (widget), shadow_type,
473                         area, widget, "radiobutton",
474                         x, y, indicator_size, indicator_size);
475     }
476 }