]> Pileus Git - ~andy/gtk/blob - gtk/gtktogglebutton.c
don't show event_window (gtk_toggle_button_map) (gtk_toggle_button_unmap):
[~andy/gtk] / gtk / gtktogglebutton.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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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 #include "gtklabel.h"
20 #include "gtkmain.h"
21 #include "gtksignal.h"
22 #include "gtktogglebutton.h"
23
24
25 #define DEFAULT_LEFT_POS  4
26 #define DEFAULT_TOP_POS   4
27 #define DEFAULT_SPACING   7
28
29 enum {
30   TOGGLED,
31   LAST_SIGNAL
32 };
33
34 enum {
35   ARG_0,
36   ARG_ACTIVE,
37   ARG_DRAW_INDICATOR
38 };
39
40
41 static void gtk_toggle_button_class_init (GtkToggleButtonClass *klass);
42 static void gtk_toggle_button_init       (GtkToggleButton      *toggle_button);
43 static void gtk_toggle_button_paint      (GtkWidget            *widget,
44                                           GdkRectangle         *area);
45 static void gtk_toggle_button_draw       (GtkWidget            *widget,
46                                           GdkRectangle         *area);
47 static void gtk_toggle_button_pressed    (GtkButton            *button);
48 static void gtk_toggle_button_released   (GtkButton            *button);
49 static void gtk_toggle_button_clicked    (GtkButton            *button);
50 static void gtk_toggle_button_enter      (GtkButton            *button);
51 static void gtk_toggle_button_leave      (GtkButton            *button);
52 static void gtk_toggle_button_set_arg    (GtkObject            *object,
53                                           GtkArg               *arg,
54                                           guint                 arg_id);
55 static void gtk_toggle_button_get_arg    (GtkObject            *object,
56                                           GtkArg               *arg,
57                                           guint                 arg_id);
58 static void gtk_toggle_button_leave      (GtkButton            *button);
59 static void gtk_toggle_button_realize    (GtkWidget            *widget);
60 static void gtk_toggle_button_unrealize  (GtkWidget            *widget);
61 static void gtk_toggle_button_map        (GtkWidget            *widget);
62 static void gtk_toggle_button_unmap      (GtkWidget            *widget);
63
64 static guint toggle_button_signals[LAST_SIGNAL] = { 0 };
65 static GtkContainerClass *parent_class = NULL;
66
67 GtkType
68 gtk_toggle_button_get_type (void)
69 {
70   static GtkType toggle_button_type = 0;
71
72   if (!toggle_button_type)
73     {
74       GtkTypeInfo toggle_button_info =
75       {
76         "GtkToggleButton",
77         sizeof (GtkToggleButton),
78         sizeof (GtkToggleButtonClass),
79         (GtkClassInitFunc) gtk_toggle_button_class_init,
80         (GtkObjectInitFunc) gtk_toggle_button_init,
81         /* reserved_1 */ NULL,
82         /* reserved_2 */ NULL,
83         (GtkClassInitFunc) NULL,
84       };
85
86       toggle_button_type = gtk_type_unique (gtk_button_get_type (), &toggle_button_info);
87     }
88
89   return toggle_button_type;
90 }
91
92 static void
93 gtk_toggle_button_class_init (GtkToggleButtonClass *class)
94 {
95   GtkObjectClass *object_class;
96   GtkWidgetClass *widget_class;
97   GtkContainerClass *container_class;
98   GtkButtonClass *button_class;
99
100   object_class = (GtkObjectClass*) class;
101   widget_class = (GtkWidgetClass*) class;
102   container_class = (GtkContainerClass*) class;
103   button_class = (GtkButtonClass*) class;
104
105   parent_class = gtk_type_class (GTK_TYPE_BUTTON);
106
107   gtk_object_add_arg_type ("GtkToggleButton::active", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_ACTIVE);
108   gtk_object_add_arg_type ("GtkToggleButton::draw_indicator", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_DRAW_INDICATOR);
109
110   toggle_button_signals[TOGGLED] =
111     gtk_signal_new ("toggled",
112                     GTK_RUN_FIRST,
113                     object_class->type,
114                     GTK_SIGNAL_OFFSET (GtkToggleButtonClass, toggled),
115                     gtk_marshal_NONE__NONE,
116                     GTK_TYPE_NONE, 0);
117
118   gtk_object_class_add_signals (object_class, toggle_button_signals, LAST_SIGNAL);
119
120   object_class->set_arg = gtk_toggle_button_set_arg;
121   object_class->get_arg = gtk_toggle_button_get_arg;
122
123   widget_class->draw = gtk_toggle_button_draw;
124   widget_class->realize = gtk_toggle_button_realize;
125   widget_class->unrealize = gtk_toggle_button_unrealize;
126   widget_class->map = gtk_toggle_button_map;
127   widget_class->unmap = gtk_toggle_button_unmap;
128
129   button_class->pressed = gtk_toggle_button_pressed;
130   button_class->released = gtk_toggle_button_released;
131   button_class->clicked = gtk_toggle_button_clicked;
132   button_class->enter = gtk_toggle_button_enter;
133   button_class->leave = gtk_toggle_button_leave;
134
135   class->toggled = NULL;
136 }
137
138 static void
139 gtk_toggle_button_init (GtkToggleButton *toggle_button)
140 {
141   toggle_button->active = FALSE;
142   toggle_button->draw_indicator = FALSE;
143 }
144
145
146 GtkWidget*
147 gtk_toggle_button_new (void)
148 {
149   return GTK_WIDGET (gtk_type_new (gtk_toggle_button_get_type ()));
150 }
151
152 GtkWidget*
153 gtk_toggle_button_new_with_label (const gchar *label)
154 {
155   GtkWidget *toggle_button;
156   GtkWidget *label_widget;
157
158   toggle_button = gtk_toggle_button_new ();
159   label_widget = gtk_label_new (label);
160   gtk_misc_set_alignment (GTK_MISC (label_widget), 0.5, 0.5);
161
162   gtk_container_add (GTK_CONTAINER (toggle_button), label_widget);
163   gtk_widget_show (label_widget);
164
165   return toggle_button;
166 }
167
168 static void
169 gtk_toggle_button_set_arg (GtkObject *object,
170                            GtkArg    *arg,
171                            guint      arg_id)
172 {
173   GtkToggleButton *tb;
174
175   tb = GTK_TOGGLE_BUTTON (object);
176
177   switch (arg_id)
178     {
179     case ARG_ACTIVE:
180       gtk_toggle_button_set_state (tb, GTK_VALUE_BOOL (*arg));
181       break;
182     case ARG_DRAW_INDICATOR:
183       gtk_toggle_button_set_mode (tb, GTK_VALUE_BOOL (*arg));
184       break;
185     default:
186       break;
187     }
188 }
189
190 static void
191 gtk_toggle_button_get_arg (GtkObject *object,
192                            GtkArg    *arg,
193                            guint      arg_id)
194 {
195   GtkToggleButton *tb;
196
197   tb = GTK_TOGGLE_BUTTON (object);
198
199   switch (arg_id)
200     {
201     case ARG_ACTIVE:
202       GTK_VALUE_BOOL (*arg) = tb->active;
203       break;
204     case ARG_DRAW_INDICATOR:
205       GTK_VALUE_BOOL (*arg) = tb->draw_indicator;
206       break;
207     default:
208       arg->type = GTK_TYPE_INVALID;
209       break;
210     }
211 }
212
213 void
214 gtk_toggle_button_set_mode (GtkToggleButton *toggle_button,
215                             gint             draw_indicator)
216 {
217   g_return_if_fail (toggle_button != NULL);
218   g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));
219
220   draw_indicator = draw_indicator ? TRUE : FALSE;
221
222   if (toggle_button->draw_indicator != draw_indicator)
223     {
224       if (GTK_WIDGET_REALIZED(toggle_button))
225         {
226           gtk_widget_unrealize(GTK_WIDGET(toggle_button));
227           toggle_button->draw_indicator = draw_indicator;
228           gtk_widget_realize(GTK_WIDGET(toggle_button));
229           gtk_widget_show(GTK_WIDGET(toggle_button));
230         }
231       else
232         toggle_button->draw_indicator = draw_indicator;
233
234       if (GTK_WIDGET_VISIBLE (toggle_button))
235         gtk_widget_queue_resize (GTK_WIDGET (toggle_button));
236     }
237 }
238
239 void
240 gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
241                              gint             state)
242 {
243   g_return_if_fail (toggle_button != NULL);
244   g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));
245
246   if (toggle_button->active != (state != FALSE))
247     gtk_button_clicked (GTK_BUTTON (toggle_button));
248 }
249
250 void
251 gtk_toggle_button_toggled (GtkToggleButton *toggle_button)
252 {
253   gtk_signal_emit (GTK_OBJECT (toggle_button), toggle_button_signals[TOGGLED]);
254 }
255
256
257 static void
258 gtk_toggle_button_paint (GtkWidget    *widget,
259                          GdkRectangle *area)
260 {
261   GtkButton *button;
262   GtkToggleButton *toggle_button;
263   GtkShadowType shadow_type;
264   gint width, height;
265   gint x, y;
266
267   if (GTK_WIDGET_DRAWABLE (widget))
268     {
269       button = GTK_BUTTON (widget);
270       toggle_button = GTK_TOGGLE_BUTTON (widget);
271
272       x = 0;
273       y = 0;
274       width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2;
275       height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2;
276
277       gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
278       gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height);
279
280       if (GTK_WIDGET_HAS_DEFAULT (widget) &&
281           GTK_BUTTON (widget)->relief == GTK_RELIEF_NORMAL)
282         {
283           gtk_paint_box (widget->style, widget->window,
284                          GTK_STATE_NORMAL, GTK_SHADOW_IN,
285                          area, widget, "togglebuttondefault",
286                          x, y, width, height);
287         }
288
289       if (GTK_WIDGET_CAN_DEFAULT (widget))
290         {
291           x += widget->style->klass->xthickness;
292           y += widget->style->klass->ythickness;
293           width -= 2 * x + DEFAULT_SPACING;
294           height -= 2 * y + DEFAULT_SPACING;
295           x += DEFAULT_LEFT_POS;
296           y += DEFAULT_TOP_POS;
297         }
298
299       if (GTK_WIDGET_HAS_FOCUS (widget))
300         {
301           x += 1;
302           y += 1;
303           width -= 2;
304           height -= 2;
305         }
306
307       if ((GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) ||
308           toggle_button->active)
309         shadow_type = GTK_SHADOW_IN;
310       else
311         shadow_type = GTK_SHADOW_OUT;
312
313       if ((button->relief != GTK_RELIEF_NONE) ||
314           ((GTK_WIDGET_STATE(widget) != GTK_STATE_NORMAL) &&
315            (GTK_WIDGET_STATE(widget) != GTK_STATE_INSENSITIVE)))
316         gtk_paint_box (widget->style, widget->window,
317                        GTK_WIDGET_STATE (widget),
318                        shadow_type, area, widget, "togglebutton",
319                        x, y, width, height);
320
321       if (GTK_WIDGET_HAS_FOCUS (widget))
322         {
323           x -= 1;
324           y -= 1;
325           width += 2;
326           height += 2;
327
328           gtk_paint_focus (widget->style, widget->window,
329                            area, widget, "togglebutton",
330                            x, y, width - 1, height - 1);
331         }
332     }
333 }
334
335 static void
336 gtk_toggle_button_draw (GtkWidget    *widget,
337                         GdkRectangle *area)
338 {
339   GtkButton *button;
340   GdkRectangle child_area;
341   GdkRectangle tmp_area;
342
343   g_return_if_fail (widget != NULL);
344   g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget));
345   g_return_if_fail (area != NULL);
346
347   if (GTK_WIDGET_DRAWABLE (widget))
348     {
349       button = GTK_BUTTON (widget);
350
351       tmp_area = *area;
352       tmp_area.x -= GTK_CONTAINER (button)->border_width;
353       tmp_area.y -= GTK_CONTAINER (button)->border_width;
354
355       gtk_toggle_button_paint (widget, &tmp_area);
356
357       if (GTK_BIN (button)->child && gtk_widget_intersect (GTK_BIN (button)->child, &tmp_area, &child_area))
358         gtk_widget_draw (GTK_BIN (button)->child, &child_area);
359     }
360 }
361
362 static void
363 gtk_toggle_button_pressed (GtkButton *button)
364 {
365   GtkToggleButton *toggle_button;
366   GtkStateType new_state;
367
368   g_return_if_fail (button != NULL);
369   g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
370
371   toggle_button = GTK_TOGGLE_BUTTON (button);
372
373   button->button_down = TRUE;
374
375   if (toggle_button->active)
376     new_state = (button->in_button ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE);
377   else
378     new_state = (button->in_button ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL);
379
380   if (GTK_WIDGET_STATE (button) != new_state)
381     {
382       gtk_widget_set_state (GTK_WIDGET (button), new_state);
383       gtk_widget_queue_draw (GTK_WIDGET (button));
384     }
385 }
386
387 static void
388 gtk_toggle_button_released (GtkButton *button)
389 {
390   GtkToggleButton *toggle_button;
391   GtkStateType new_state;
392
393   g_return_if_fail (button != NULL);
394   g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
395
396   if (button->button_down)
397     {
398       toggle_button = GTK_TOGGLE_BUTTON (button);
399
400       button->button_down = FALSE;
401
402       if (button->in_button)
403         {
404           gtk_button_clicked (button);
405         }
406       else
407         {
408           if (toggle_button->active)
409             new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
410           else
411             new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL);
412
413           if (GTK_WIDGET_STATE (button) != new_state)
414             {
415               gtk_widget_set_state (GTK_WIDGET (button), new_state);
416               gtk_widget_queue_draw (GTK_WIDGET (button));
417             }
418         }
419     }
420 }
421
422 static void
423 gtk_toggle_button_clicked (GtkButton *button)
424 {
425   GtkToggleButton *toggle_button;
426   GtkStateType new_state;
427
428   g_return_if_fail (button != NULL);
429   g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
430
431   toggle_button = GTK_TOGGLE_BUTTON (button);
432   toggle_button->active = !toggle_button->active;
433
434   gtk_toggle_button_toggled (toggle_button);
435
436   if (toggle_button->active)
437     new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
438   else
439     new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL);
440
441   if (GTK_WIDGET_STATE (button) != new_state)
442     gtk_widget_set_state (GTK_WIDGET (button), new_state);
443   gtk_widget_queue_draw (GTK_WIDGET (button));
444 }
445
446 static void
447 gtk_toggle_button_enter (GtkButton *button)
448 {
449   GtkToggleButton *toggle_button;
450   GtkStateType new_state;
451
452   g_return_if_fail (button != NULL);
453   g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
454
455   toggle_button = GTK_TOGGLE_BUTTON (button);
456
457   if (toggle_button->active)
458     new_state = (button->button_down ? GTK_STATE_NORMAL : GTK_STATE_PRELIGHT);
459   else
460     new_state = (button->button_down ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT);
461
462   if (GTK_WIDGET_STATE (button) != new_state)
463     {
464       gtk_widget_set_state (GTK_WIDGET (button), new_state);
465       gtk_widget_queue_draw (GTK_WIDGET (button));
466     }
467 }
468
469 static void
470 gtk_toggle_button_leave (GtkButton *button)
471 {
472   GtkToggleButton *toggle_button;
473   GtkStateType new_state;
474
475   g_return_if_fail (button != NULL);
476   g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
477
478   toggle_button = GTK_TOGGLE_BUTTON (button);
479
480   new_state = (toggle_button->active ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL);
481
482   if (GTK_WIDGET_STATE (button) != new_state)
483     {
484       gtk_widget_set_state (GTK_WIDGET (button), new_state);
485       gtk_widget_queue_draw (GTK_WIDGET (button));
486     }
487 }
488
489 static void
490 gtk_toggle_button_realize (GtkWidget *widget)
491 {
492   GtkToggleButton *toggle_button;
493   GdkWindowAttr attributes;
494   gint attributes_mask;
495   gint border_width;
496   
497   g_return_if_fail (widget != NULL);
498   g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget));
499   
500   toggle_button = GTK_TOGGLE_BUTTON (widget);
501   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
502   
503   border_width = GTK_CONTAINER (widget)->border_width;
504   
505   attributes.window_type = GDK_WINDOW_CHILD;
506   attributes.x = widget->allocation.x + border_width;
507   attributes.y = widget->allocation.y + border_width;
508   attributes.width = widget->allocation.width - border_width * 2;
509   attributes.height = widget->allocation.height - border_width * 2;
510   attributes.event_mask = gtk_widget_get_events (widget);
511   attributes.event_mask |= (GDK_EXPOSURE_MASK |
512                             GDK_BUTTON_PRESS_MASK |
513                             GDK_BUTTON_RELEASE_MASK |
514                             GDK_ENTER_NOTIFY_MASK |
515                             GDK_LEAVE_NOTIFY_MASK);
516
517   if (toggle_button->draw_indicator)
518     {
519       GTK_WIDGET_SET_FLAGS (toggle_button, GTK_NO_WINDOW);
520       attributes.wclass = GDK_INPUT_ONLY;
521       attributes_mask = GDK_WA_X | GDK_WA_Y;
522
523       widget->window = gtk_widget_get_parent_window(widget);
524       gdk_window_ref(widget->window);
525       
526       toggle_button->event_window = 
527         gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
528       gdk_window_set_user_data (toggle_button->event_window, toggle_button);
529     }
530   else
531     {
532       GTK_WIDGET_UNSET_FLAGS (toggle_button, GTK_NO_WINDOW);
533       attributes.wclass = GDK_INPUT_OUTPUT;
534       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
535       attributes.visual = gtk_widget_get_visual (widget);
536       attributes.colormap = gtk_widget_get_colormap (widget);
537       widget->window = 
538         gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
539       gdk_window_set_user_data (widget->window, toggle_button);
540     }
541   widget->style = gtk_style_attach (widget->style, widget->window);
542 }
543   
544 static void
545 gtk_toggle_button_unrealize (GtkWidget *widget)
546 {
547   GtkToggleButton *toggle_button;
548   
549   g_return_if_fail (widget != NULL);
550   g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget));
551
552   toggle_button = GTK_TOGGLE_BUTTON (widget);
553   
554   if (toggle_button->draw_indicator)
555     {
556       gdk_window_set_user_data (toggle_button->event_window, NULL);
557       gdk_window_destroy (toggle_button->event_window);
558       toggle_button->event_window = NULL;
559     }
560
561   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
562     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
563 }
564
565 static void
566 gtk_toggle_button_map (GtkWidget *widget)
567 {
568   g_return_if_fail (widget != NULL);
569   g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget));
570
571   if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_MAPPED (widget))
572     if (GTK_TOGGLE_BUTTON (widget)->draw_indicator)
573       gdk_window_show (GTK_TOGGLE_BUTTON (widget)->event_window);
574
575   GTK_WIDGET_CLASS (parent_class)->map (widget);
576 }
577
578 static void
579 gtk_toggle_button_unmap (GtkWidget *widget)
580 {
581   g_return_if_fail (widget != NULL);
582   g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget));
583
584   if (GTK_WIDGET_MAPPED (widget))
585     if (GTK_TOGGLE_BUTTON (widget)->draw_indicator)
586       gdk_window_hide (GTK_TOGGLE_BUTTON (widget)->event_window);
587
588   GTK_WIDGET_CLASS (parent_class)->unmap (widget);
589 }