]> Pileus Git - ~andy/gtk/blob - gtk/gtkcheckbutton.c
Remove all references to offscreen flag which was no longer used.
[~andy/gtk] / gtk / gtkcheckbutton.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
20 /*
21  * Modified by the GTK+ Team and others 1997-1999.  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 "gtkcheckbutton.h"
28 #include "gtklabel.h"
29
30
31 #define INDICATOR_SIZE     10
32 #define INDICATOR_SPACING  2
33
34
35 static void gtk_check_button_class_init          (GtkCheckButtonClass *klass);
36 static void gtk_check_button_init                (GtkCheckButton      *check_button);
37 static void gtk_check_button_draw                (GtkWidget           *widget,
38                                                   GdkRectangle        *area);
39 static void gtk_check_button_draw_focus          (GtkWidget           *widget);
40 static void gtk_check_button_size_request        (GtkWidget           *widget,
41                                                   GtkRequisition      *requisition);
42 static void gtk_check_button_size_allocate       (GtkWidget           *widget,
43                                                   GtkAllocation       *allocation);
44 static gint gtk_check_button_expose              (GtkWidget           *widget,
45                                                   GdkEventExpose      *event);
46 static void gtk_check_button_paint               (GtkWidget           *widget,
47                                                   GdkRectangle        *area);
48 static void gtk_check_button_draw_indicator      (GtkCheckButton      *check_button,
49                                                   GdkRectangle        *area);
50 static void gtk_real_check_button_draw_indicator (GtkCheckButton      *check_button,
51                                                   GdkRectangle        *area);
52
53 static GtkToggleButtonClass *parent_class = NULL;
54
55
56 GtkType
57 gtk_check_button_get_type (void)
58 {
59   static GtkType check_button_type = 0;
60   
61   if (!check_button_type)
62     {
63       static const GtkTypeInfo check_button_info =
64       {
65         "GtkCheckButton",
66         sizeof (GtkCheckButton),
67         sizeof (GtkCheckButtonClass),
68         (GtkClassInitFunc) gtk_check_button_class_init,
69         (GtkObjectInitFunc) gtk_check_button_init,
70         /* reserved_1 */ NULL,
71         /* reserved_2 */ NULL,
72         (GtkClassInitFunc) NULL,
73       };
74       
75       check_button_type = gtk_type_unique (GTK_TYPE_TOGGLE_BUTTON, &check_button_info);
76     }
77   
78   return check_button_type;
79 }
80
81 static void
82 gtk_check_button_class_init (GtkCheckButtonClass *class)
83 {
84   GtkWidgetClass *widget_class;
85   
86   widget_class = (GtkWidgetClass*) class;
87   parent_class = gtk_type_class (gtk_toggle_button_get_type ());
88   
89   widget_class->draw = gtk_check_button_draw;
90   widget_class->draw_focus = gtk_check_button_draw_focus;
91   widget_class->size_request = gtk_check_button_size_request;
92   widget_class->size_allocate = gtk_check_button_size_allocate;
93   widget_class->expose_event = gtk_check_button_expose;
94   
95   class->indicator_size = INDICATOR_SIZE;
96   class->indicator_spacing = INDICATOR_SPACING;
97   class->draw_indicator = gtk_real_check_button_draw_indicator;
98 }
99
100 static void
101 gtk_check_button_init (GtkCheckButton *check_button)
102 {
103   GTK_WIDGET_SET_FLAGS (check_button, GTK_NO_WINDOW);
104   GTK_WIDGET_UNSET_FLAGS (check_button, GTK_RECEIVES_DEFAULT);
105   GTK_TOGGLE_BUTTON (check_button)->draw_indicator = TRUE;
106 }
107
108 GtkWidget*
109 gtk_check_button_new (void)
110 {
111   return gtk_widget_new (GTK_TYPE_CHECK_BUTTON, NULL);
112 }
113
114
115 GtkWidget*
116 gtk_check_button_new_with_label (const gchar *label)
117 {
118   GtkWidget *check_button;
119   GtkWidget *label_widget;
120   
121   check_button = gtk_check_button_new ();
122   label_widget = gtk_label_new (label);
123   gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
124   
125   gtk_container_add (GTK_CONTAINER (check_button), label_widget);
126   gtk_widget_show (label_widget);
127   
128   return check_button;
129 }
130
131 /* This should only be called when toggle_button->draw_indicator
132  * is true.
133  */
134 static void
135 gtk_check_button_paint (GtkWidget    *widget,
136                         GdkRectangle *area)
137 {
138   GtkCheckButton *check_button;
139   
140   g_return_if_fail (widget != NULL);
141   g_return_if_fail (GTK_IS_CHECK_BUTTON (widget));
142   
143   check_button = GTK_CHECK_BUTTON (widget);
144   
145   if (GTK_WIDGET_DRAWABLE (widget))
146     {
147       gint border_width;
148           
149       gtk_check_button_draw_indicator (check_button, area);
150       
151       border_width = GTK_CONTAINER (widget)->border_width;
152       if (GTK_WIDGET_HAS_FOCUS (widget))
153         gtk_paint_focus (widget->style, widget->window,
154                          NULL, widget, "checkbutton",
155                          border_width + widget->allocation.x,
156                          border_width + widget->allocation.y,
157                          widget->allocation.width - 2 * border_width - 1,
158                          widget->allocation.height - 2 * border_width - 1);
159     }
160 }
161
162 static void
163 gtk_check_button_draw (GtkWidget    *widget,
164                        GdkRectangle *area)
165 {
166   GtkCheckButton *check_button;
167   GtkToggleButton *toggle_button;
168   GtkBin *bin;
169   GdkRectangle child_area;
170   
171   g_return_if_fail (widget != NULL);
172   g_return_if_fail (GTK_IS_CHECK_BUTTON (widget));
173   g_return_if_fail (area != NULL);
174   
175   check_button = GTK_CHECK_BUTTON (widget);
176   toggle_button = GTK_TOGGLE_BUTTON (widget);
177   bin = GTK_BIN (widget);
178   
179   if (GTK_WIDGET_DRAWABLE (widget))
180     {
181       if (toggle_button->draw_indicator)
182         {
183           gtk_check_button_paint (widget, area);
184
185           if (bin->child && gtk_widget_intersect (bin->child, area, &child_area))
186             gtk_widget_draw (bin->child, &child_area);
187         }
188       else
189         {
190           if (GTK_WIDGET_CLASS (parent_class)->draw)
191             (* GTK_WIDGET_CLASS (parent_class)->draw) (widget, area);
192         }
193     }
194 }
195
196 static void
197 gtk_check_button_draw_focus (GtkWidget *widget)
198 {
199   gint border_width;
200   
201   g_return_if_fail (widget != NULL);
202   g_return_if_fail (GTK_IS_CHECK_BUTTON (widget));
203   
204   border_width = GTK_CONTAINER (widget)->border_width;
205   gtk_widget_queue_clear_area (widget->parent, 
206                                border_width + widget->allocation.x,
207                                border_width + widget->allocation.y,
208                                widget->allocation.width - 2 * border_width,
209                                widget->allocation.height - 2 * border_width);
210 }
211
212 static void
213 gtk_check_button_size_request (GtkWidget      *widget,
214                                GtkRequisition *requisition)
215 {
216   GtkToggleButton *toggle_button;
217   gint temp;
218   
219   g_return_if_fail (widget != NULL);
220   g_return_if_fail (GTK_IS_CHECK_BUTTON (widget));
221   g_return_if_fail (requisition != NULL);
222   
223   toggle_button = GTK_TOGGLE_BUTTON (widget);
224   
225   if (GTK_WIDGET_CLASS (parent_class)->size_request)
226     (* GTK_WIDGET_CLASS (parent_class)->size_request) (widget, requisition);
227   
228   if (toggle_button->draw_indicator)
229     {
230       requisition->width += (GTK_CHECK_BUTTON_GET_CLASS (widget)->indicator_size +
231                              GTK_CHECK_BUTTON_GET_CLASS (widget)->indicator_spacing * 3 + 2);
232       
233       temp = (GTK_CHECK_BUTTON_GET_CLASS (widget)->indicator_size +
234               GTK_CHECK_BUTTON_GET_CLASS (widget)->indicator_spacing * 2);
235       requisition->height = MAX (requisition->height, temp) + 2;
236     }
237 }
238
239 static void
240 gtk_check_button_size_allocate (GtkWidget     *widget,
241                                 GtkAllocation *allocation)
242 {
243   GtkCheckButton *check_button;
244   GtkToggleButton *toggle_button;
245   GtkButton *button;
246   GtkAllocation child_allocation;
247   
248   g_return_if_fail (widget != NULL);
249   g_return_if_fail (GTK_IS_CHECK_BUTTON (widget));
250   g_return_if_fail (allocation != NULL);
251   
252   check_button = GTK_CHECK_BUTTON (widget);
253   toggle_button = GTK_TOGGLE_BUTTON (widget);
254
255   if (toggle_button->draw_indicator)
256     {
257       widget->allocation = *allocation;
258       if (GTK_WIDGET_REALIZED (widget))
259         gdk_window_move_resize (toggle_button->event_window,
260                                 allocation->x, allocation->y,
261                                 allocation->width, allocation->height);
262       
263       button = GTK_BUTTON (widget);
264       
265       if (GTK_BIN (button)->child && GTK_WIDGET_VISIBLE (GTK_BIN (button)->child))
266         {
267           child_allocation.x = (GTK_CONTAINER (widget)->border_width +
268                                 GTK_CHECK_BUTTON_GET_CLASS (widget)->indicator_size +
269                                 GTK_CHECK_BUTTON_GET_CLASS (widget)->indicator_spacing * 3 + 1 +
270                                 widget->allocation.x);
271           child_allocation.y = GTK_CONTAINER (widget)->border_width + 1 +
272             widget->allocation.y;
273           child_allocation.width = MAX (1, allocation->width - 
274                                         (GTK_CONTAINER (widget)->border_width +
275                                          GTK_CHECK_BUTTON_GET_CLASS (widget)->indicator_size +
276                                          GTK_CHECK_BUTTON_GET_CLASS (widget)->indicator_spacing * 3 + 1)  -
277                                         GTK_CONTAINER (widget)->border_width - 1);
278           child_allocation.height = MAX (1, allocation->height - (GTK_CONTAINER (widget)->border_width + 1) * 2);
279           
280           if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
281             child_allocation.x = allocation->x + allocation->width
282               - (child_allocation.x - allocation->x + child_allocation.width);
283           
284           gtk_widget_size_allocate (GTK_BIN (button)->child, &child_allocation);
285         }
286     }
287   else
288     {
289       if (GTK_WIDGET_CLASS (parent_class)->size_allocate)
290         (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
291     }
292 }
293
294 static gint
295 gtk_check_button_expose (GtkWidget      *widget,
296                          GdkEventExpose *event)
297 {
298   GtkCheckButton *check_button;
299   GtkToggleButton *toggle_button;
300   GtkBin *bin;
301   GdkEventExpose child_event;
302   
303   g_return_val_if_fail (widget != NULL, FALSE);
304   g_return_val_if_fail (GTK_IS_CHECK_BUTTON (widget), FALSE);
305   g_return_val_if_fail (event != NULL, FALSE);
306   
307   check_button = GTK_CHECK_BUTTON (widget);
308   toggle_button = GTK_TOGGLE_BUTTON (widget);
309   bin = GTK_BIN (widget);
310   
311   if (GTK_WIDGET_DRAWABLE (widget))
312     {
313       if (toggle_button->draw_indicator)
314         {
315           gtk_check_button_paint (widget, &event->area);
316           
317           child_event = *event;
318           if (bin->child && GTK_WIDGET_NO_WINDOW (bin->child) &&
319               gtk_widget_intersect (bin->child, &event->area, &child_event.area))
320             gtk_widget_event (bin->child, (GdkEvent*) &child_event);
321         }
322       else
323         {
324           if (GTK_WIDGET_CLASS (parent_class)->expose_event)
325             (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
326         }
327     }
328   
329   return FALSE;
330 }
331
332
333 static void
334 gtk_check_button_draw_indicator (GtkCheckButton *check_button,
335                                  GdkRectangle   *area)
336 {
337   GtkCheckButtonClass *class;
338   
339   g_return_if_fail (check_button != NULL);
340   g_return_if_fail (GTK_IS_CHECK_BUTTON (check_button));
341   
342   class = GTK_CHECK_BUTTON_GET_CLASS (check_button);
343   
344   if (class->draw_indicator)
345     (* class->draw_indicator) (check_button, area);
346 }
347
348 static void
349 gtk_real_check_button_draw_indicator (GtkCheckButton *check_button,
350                                       GdkRectangle   *area)
351 {
352   GtkWidget *widget;
353   GtkToggleButton *toggle_button;
354   GtkStateType state_type;
355   GtkShadowType shadow_type;
356   GdkRectangle restrict_area;
357   GdkRectangle new_area;
358   gint width, height;
359   gint x, y;
360   GdkWindow *window;
361   
362   g_return_if_fail (check_button != NULL);
363   g_return_if_fail (GTK_IS_CHECK_BUTTON (check_button));
364   
365   widget = GTK_WIDGET (check_button);
366   toggle_button = GTK_TOGGLE_BUTTON (check_button);
367   
368   if (GTK_WIDGET_DRAWABLE (check_button))
369     {
370       window = widget->window;
371       
372       state_type = GTK_WIDGET_STATE (widget);
373       if (state_type != GTK_STATE_NORMAL &&
374           state_type != GTK_STATE_PRELIGHT)
375         state_type = GTK_STATE_NORMAL;
376       
377       restrict_area.x = widget->allocation.x + GTK_CONTAINER (widget)->border_width;
378       restrict_area.y = widget->allocation.y + GTK_CONTAINER (widget)->border_width;
379       restrict_area.width = widget->allocation.width - ( 2 * GTK_CONTAINER (widget)->border_width);
380       restrict_area.height = widget->allocation.height - ( 2 * GTK_CONTAINER (widget)->border_width);
381       
382       if (gdk_rectangle_intersect (area, &restrict_area, &new_area))
383         {
384           if (state_type != GTK_STATE_NORMAL)
385             gtk_paint_flat_box (widget->style, window, state_type, 
386                                 GTK_SHADOW_ETCHED_OUT, 
387                                 area, widget, "checkbutton",
388                                 new_area.x, new_area.y,
389                                 new_area.width, new_area.height);
390         }
391       
392       x = widget->allocation.x + GTK_CHECK_BUTTON_GET_CLASS (widget)->indicator_spacing + GTK_CONTAINER (widget)->border_width;
393       y = widget->allocation.y + (widget->allocation.height - GTK_CHECK_BUTTON_GET_CLASS (widget)->indicator_size) / 2;
394       width = GTK_CHECK_BUTTON_GET_CLASS (widget)->indicator_size;
395       height = GTK_CHECK_BUTTON_GET_CLASS (widget)->indicator_size;
396       
397       if (GTK_TOGGLE_BUTTON (widget)->active)
398         {
399           state_type = GTK_STATE_ACTIVE;
400           shadow_type = GTK_SHADOW_IN;
401         }
402       else
403         {
404           shadow_type = GTK_SHADOW_OUT;
405           state_type = GTK_WIDGET_STATE (widget);
406         }
407
408       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
409         x = widget->allocation.x + widget->allocation.width - (width + x - widget->allocation.x);
410
411       gtk_paint_check (widget->style, window,
412                        state_type, shadow_type,
413                        area, widget, "checkbutton",
414                        x, y, width, height);
415     }
416 }