source: trunk/third/gtk/gtk/gtkcheckbutton.c @ 15781

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