]> Pileus Git - ~andy/gtk/blob - gtk/gtkcheckmenuitem.c
Use canonical names for g_object_notify() as well.
[~andy/gtk] / gtk / gtkcheckmenuitem.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-2001.  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 <config.h>
28 #include "gtkcheckmenuitem.h"
29 #include "gtkaccellabel.h"
30 #include "gtkmarshalers.h"
31 #include "gtkprivate.h"
32 #include "gtkintl.h"
33 #include "gtkalias.h"
34
35 enum {
36   TOGGLED,
37   LAST_SIGNAL
38 };
39
40 enum {
41   PROP_0,
42   PROP_ACTIVE,
43   PROP_INCONSISTENT,
44   PROP_DRAW_AS_RADIO
45 };
46
47 static void gtk_check_menu_item_class_init           (GtkCheckMenuItemClass *klass);
48 static void gtk_check_menu_item_init                 (GtkCheckMenuItem      *check_menu_item);
49 static gint gtk_check_menu_item_expose               (GtkWidget             *widget,
50                                                       GdkEventExpose        *event);
51 static void gtk_check_menu_item_activate             (GtkMenuItem           *menu_item);
52 static void gtk_check_menu_item_toggle_size_request  (GtkMenuItem           *menu_item,
53                                                       gint                  *requisition);
54 static void gtk_check_menu_item_draw_indicator       (GtkCheckMenuItem      *check_menu_item,
55                                                       GdkRectangle          *area);
56 static void gtk_real_check_menu_item_draw_indicator  (GtkCheckMenuItem      *check_menu_item,
57                                                       GdkRectangle          *area);
58 static void gtk_check_menu_item_set_property (GObject         *object,
59                                               guint            prop_id,
60                                               const GValue    *value,
61                                               GParamSpec      *pspec);
62 static void gtk_check_menu_item_get_property (GObject         *object,
63                                               guint            prop_id,
64                                               GValue          *value,
65                                               GParamSpec      *pspec);
66
67
68 static GtkMenuItemClass *parent_class = NULL;
69 static guint check_menu_item_signals[LAST_SIGNAL] = { 0 };
70
71
72 GType
73 gtk_check_menu_item_get_type (void)
74 {
75   static GType check_menu_item_type = 0;
76
77   if (!check_menu_item_type)
78     {
79       static const GTypeInfo check_menu_item_info =
80       {
81         sizeof (GtkCheckMenuItemClass),
82         NULL,           /* base_init */
83         NULL,           /* base_finalize */
84         (GClassInitFunc) gtk_check_menu_item_class_init,
85         NULL,           /* class_finalize */
86         NULL,           /* class_data */
87         sizeof (GtkCheckMenuItem),
88         0,              /* n_preallocs */
89         (GInstanceInitFunc) gtk_check_menu_item_init,
90       };
91
92       check_menu_item_type =
93         g_type_register_static (GTK_TYPE_MENU_ITEM, "GtkCheckMenuItem",
94                                 &check_menu_item_info, 0);
95     }
96
97   return check_menu_item_type;
98 }
99
100 static void
101 gtk_check_menu_item_class_init (GtkCheckMenuItemClass *klass)
102 {
103   GObjectClass *gobject_class;
104   GtkWidgetClass *widget_class;
105   GtkMenuItemClass *menu_item_class;
106   
107   gobject_class = G_OBJECT_CLASS (klass);
108   widget_class = (GtkWidgetClass*) klass;
109   menu_item_class = (GtkMenuItemClass*) klass;
110   
111   parent_class = g_type_class_peek_parent (klass);
112
113   gobject_class->set_property = gtk_check_menu_item_set_property;
114   gobject_class->get_property = gtk_check_menu_item_get_property;
115
116   g_object_class_install_property (gobject_class,
117                                    PROP_ACTIVE,
118                                    g_param_spec_boolean ("active",
119                                                          P_("Active"),
120                                                          P_("Whether the menu item is checked"),
121                                                          FALSE,
122                                                          GTK_PARAM_READWRITE));
123   
124   g_object_class_install_property (gobject_class,
125                                    PROP_INCONSISTENT,
126                                    g_param_spec_boolean ("inconsistent",
127                                                          P_("Inconsistent"),
128                                                          P_("Whether to display an \"inconsistent\" state"),
129                                                          FALSE,
130                                                          GTK_PARAM_READWRITE));
131   
132   g_object_class_install_property (gobject_class,
133                                    PROP_DRAW_AS_RADIO,
134                                    g_param_spec_boolean ("draw-as-radio",
135                                                          P_("Draw as radio menu item"),
136                                                          P_("Whether the menu item looks like a radio menu item"),
137                                                          FALSE,
138                                                          GTK_PARAM_READWRITE));
139   
140   gtk_widget_class_install_style_property (widget_class,
141                                            g_param_spec_int ("indicator-size",
142                                                              P_("Indicator Size")
143 ,
144                                                              P_("Size of check or radio indicator"),
145                                                              0,
146                                                              G_MAXINT,
147                                                              12,
148                                                              GTK_PARAM_READABLE));
149
150   widget_class->expose_event = gtk_check_menu_item_expose;
151   
152   menu_item_class->activate = gtk_check_menu_item_activate;
153   menu_item_class->hide_on_activate = FALSE;
154   menu_item_class->toggle_size_request = gtk_check_menu_item_toggle_size_request;
155   
156   klass->toggled = NULL;
157   klass->draw_indicator = gtk_real_check_menu_item_draw_indicator;
158
159   check_menu_item_signals[TOGGLED] =
160     g_signal_new ("toggled",
161                   G_OBJECT_CLASS_TYPE (gobject_class),
162                   G_SIGNAL_RUN_FIRST,
163                   G_STRUCT_OFFSET (GtkCheckMenuItemClass, toggled),
164                   NULL, NULL,
165                   _gtk_marshal_VOID__VOID,
166                   G_TYPE_NONE, 0);
167 }
168
169 GtkWidget*
170 gtk_check_menu_item_new (void)
171 {
172   return g_object_new (GTK_TYPE_CHECK_MENU_ITEM, NULL);
173 }
174
175 GtkWidget*
176 gtk_check_menu_item_new_with_label (const gchar *label)
177 {
178   GtkWidget *check_menu_item;
179   GtkWidget *accel_label;
180
181   check_menu_item = gtk_check_menu_item_new ();
182   accel_label = gtk_accel_label_new (label);
183   gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
184
185   gtk_container_add (GTK_CONTAINER (check_menu_item), accel_label);
186   gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), check_menu_item);
187   gtk_widget_show (accel_label);
188
189   return check_menu_item;
190 }
191
192
193 /**
194  * gtk_check_menu_item_new_with_mnemonic:
195  * @label: The text of the button, with an underscore in front of the
196  *         mnemonic character
197  * @returns: a new #GtkCheckMenuItem
198  *
199  * Creates a new #GtkCheckMenuItem containing a label. The label
200  * will be created using gtk_label_new_with_mnemonic(), so underscores
201  * in @label indicate the mnemonic for the menu item.
202  **/
203 GtkWidget*
204 gtk_check_menu_item_new_with_mnemonic (const gchar *label)
205 {
206   GtkWidget *check_menu_item;
207   GtkWidget *accel_label;
208
209   check_menu_item = gtk_check_menu_item_new ();
210   accel_label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL);
211   gtk_label_set_text_with_mnemonic (GTK_LABEL (accel_label), label);
212   gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
213
214   gtk_container_add (GTK_CONTAINER (check_menu_item), accel_label);
215   gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), check_menu_item);
216   gtk_widget_show (accel_label);
217
218   return check_menu_item;
219 }
220
221 void
222 gtk_check_menu_item_set_active (GtkCheckMenuItem *check_menu_item,
223                                 gboolean          is_active)
224 {
225   g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (check_menu_item));
226
227   is_active = is_active != 0;
228
229   if (check_menu_item->active != is_active)
230     gtk_menu_item_activate (GTK_MENU_ITEM (check_menu_item));
231 }
232
233 /**
234  * gtk_check_menu_item_get_active:
235  * @check_menu_item: a #GtkCheckMenuItem
236  * 
237  * Returns whether the check menu item is active. See
238  * gtk_check_menu_item_set_active ().
239  * 
240  * Return value: %TRUE if the menu item is checked.
241  */
242 gboolean
243 gtk_check_menu_item_get_active (GtkCheckMenuItem *check_menu_item)
244 {
245   g_return_val_if_fail (GTK_IS_CHECK_MENU_ITEM (check_menu_item), FALSE);
246
247   return check_menu_item->active;
248 }
249
250 static void
251 gtk_check_menu_item_toggle_size_request (GtkMenuItem *menu_item,
252                                          gint        *requisition)
253 {
254   guint toggle_spacing;
255   guint indicator_size;
256   
257   g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (menu_item));
258   
259   gtk_widget_style_get (GTK_WIDGET (menu_item),
260                         "toggle-spacing", &toggle_spacing,
261                         "indicator-size", &indicator_size,
262                         NULL);
263
264   *requisition = indicator_size + toggle_spacing;
265 }
266
267 void
268 gtk_check_menu_item_set_show_toggle (GtkCheckMenuItem *menu_item,
269                                      gboolean          always)
270 {
271   g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (menu_item));
272
273 #if 0
274   menu_item->always_show_toggle = always != FALSE;
275 #endif  
276 }
277
278 void
279 gtk_check_menu_item_toggled (GtkCheckMenuItem *check_menu_item)
280 {
281   g_signal_emit (check_menu_item, check_menu_item_signals[TOGGLED], 0);
282 }
283
284 /**
285  * gtk_check_menu_item_set_inconsistent:
286  * @check_menu_item: a #GtkCheckMenuItem
287  * @setting: %TRUE to display an "inconsistent" third state check
288  *
289  * If the user has selected a range of elements (such as some text or
290  * spreadsheet cells) that are affected by a boolean setting, and the
291  * current values in that range are inconsistent, you may want to
292  * display the check in an "in between" state. This function turns on
293  * "in between" display.  Normally you would turn off the inconsistent
294  * state again if the user explicitly selects a setting. This has to be
295  * done manually, gtk_check_menu_item_set_inconsistent() only affects
296  * visual appearance, it doesn't affect the semantics of the widget.
297  * 
298  **/
299 void
300 gtk_check_menu_item_set_inconsistent (GtkCheckMenuItem *check_menu_item,
301                                       gboolean          setting)
302 {
303   g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (check_menu_item));
304   
305   setting = setting != FALSE;
306
307   if (setting != check_menu_item->inconsistent)
308     {
309       check_menu_item->inconsistent = setting;
310       gtk_widget_queue_draw (GTK_WIDGET (check_menu_item));
311       g_object_notify (G_OBJECT (check_menu_item), "inconsistent");
312     }
313 }
314
315 /**
316  * gtk_check_menu_item_get_inconsistent:
317  * @check_menu_item: a #GtkCheckMenuItem
318  * 
319  * Retrieves the value set by gtk_check_menu_item_set_inconsistent().
320  * 
321  * Return value: %TRUE if inconsistent
322  **/
323 gboolean
324 gtk_check_menu_item_get_inconsistent (GtkCheckMenuItem *check_menu_item)
325 {
326   g_return_val_if_fail (GTK_IS_CHECK_MENU_ITEM (check_menu_item), FALSE);
327
328   return check_menu_item->inconsistent;
329 }
330
331 /**
332  * gtk_check_menu_item_set_draw_as_radio:
333  * @check_menu_item: a #GtkCheckMenuItem
334  * @draw_as_radio: whether @check_menu_item is drawn like a #GtkRadioMenuItem
335  *
336  * Sets whether @check_menu_item is drawn like a #GtkRadioMenuItem
337  *
338  * Since: 2.4
339  **/
340 void
341 gtk_check_menu_item_set_draw_as_radio (GtkCheckMenuItem *check_menu_item,
342                                        gboolean          draw_as_radio)
343 {
344   g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (check_menu_item));
345   
346   draw_as_radio = draw_as_radio != FALSE;
347
348   if (draw_as_radio != check_menu_item->draw_as_radio)
349     {
350       check_menu_item->draw_as_radio = draw_as_radio;
351
352       gtk_widget_queue_draw (GTK_WIDGET (check_menu_item));
353
354       g_object_notify (G_OBJECT (check_menu_item), "draw-as-radio");
355     }
356 }
357
358 /**
359  * gtk_check_menu_item_get_draw_as_radio:
360  * @check_menu_item: a #GtkCheckMenuItem
361  * 
362  * Returns whether @check_menu_item looks like a #GtkRadioMenuItem
363  * 
364  * Return value: Whether @check_menu_item looks like a #GtkRadioMenuItem
365  * 
366  * Since: 2.4
367  **/
368 gboolean
369 gtk_check_menu_item_get_draw_as_radio (GtkCheckMenuItem *check_menu_item)
370 {
371   g_return_val_if_fail (GTK_IS_CHECK_MENU_ITEM (check_menu_item), FALSE);
372   
373   return check_menu_item->draw_as_radio;
374 }
375
376 static void
377 gtk_check_menu_item_init (GtkCheckMenuItem *check_menu_item)
378 {
379   check_menu_item->active = FALSE;
380   check_menu_item->always_show_toggle = TRUE;
381 }
382
383 static gint
384 gtk_check_menu_item_expose (GtkWidget      *widget,
385                             GdkEventExpose *event)
386 {
387   if (GTK_WIDGET_CLASS (parent_class)->expose_event)
388     (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
389
390   gtk_check_menu_item_draw_indicator (GTK_CHECK_MENU_ITEM (widget), &event->area);
391
392   return FALSE;
393 }
394
395 static void
396 gtk_check_menu_item_activate (GtkMenuItem *menu_item)
397 {
398   GtkCheckMenuItem *check_menu_item = GTK_CHECK_MENU_ITEM (menu_item);
399   check_menu_item->active = !check_menu_item->active;
400
401   gtk_check_menu_item_toggled (check_menu_item);
402   gtk_widget_queue_draw (GTK_WIDGET (check_menu_item));
403
404   g_object_notify (G_OBJECT (check_menu_item), "active");
405 }
406
407 static void
408 gtk_check_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item,
409                                     GdkRectangle     *area)
410 {
411   if (GTK_CHECK_MENU_ITEM_GET_CLASS (check_menu_item)->draw_indicator)
412     (* GTK_CHECK_MENU_ITEM_GET_CLASS (check_menu_item)->draw_indicator) (check_menu_item, area);
413 }
414
415 static void
416 gtk_real_check_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item,
417                                          GdkRectangle     *area)
418 {
419   GtkWidget *widget;
420   GtkStateType state_type;
421   GtkShadowType shadow_type;
422   gint x, y;
423
424   if (GTK_WIDGET_DRAWABLE (check_menu_item))
425     {
426       guint offset;
427       guint toggle_size;
428       guint toggle_spacing;
429       guint horizontal_padding;
430       guint indicator_size;
431       
432       widget = GTK_WIDGET (check_menu_item);
433
434       gtk_widget_style_get (GTK_WIDGET (check_menu_item),
435                             "toggle-spacing", &toggle_spacing,
436                             "horizontal-padding", &horizontal_padding,
437                             "indicator-size", &indicator_size,
438                             NULL);
439
440       toggle_size = GTK_MENU_ITEM (check_menu_item)->toggle_size;
441       offset = GTK_CONTAINER (check_menu_item)->border_width + widget->style->xthickness;
442       
443       offset = GTK_CONTAINER (check_menu_item)->border_width +
444         widget->style->xthickness + 2; 
445
446       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
447         {
448           x = widget->allocation.x + offset + horizontal_padding +
449             (toggle_size - toggle_spacing - indicator_size) / 2;
450         }
451       else 
452         {
453           x = widget->allocation.x + widget->allocation.width -
454             offset - horizontal_padding - toggle_size + toggle_spacing +
455             (toggle_size - toggle_spacing - indicator_size) / 2;
456         }
457       
458       y = widget->allocation.y + (widget->allocation.height - indicator_size) / 2;
459
460       if (check_menu_item->active ||
461           check_menu_item->always_show_toggle ||
462           (GTK_WIDGET_STATE (check_menu_item) == GTK_STATE_PRELIGHT))
463         {
464           state_type = GTK_WIDGET_STATE (widget);
465           
466           if (check_menu_item->inconsistent)
467             shadow_type = GTK_SHADOW_ETCHED_IN;
468           else if (check_menu_item->active)
469             shadow_type = GTK_SHADOW_IN;
470           else 
471             shadow_type = GTK_SHADOW_OUT;
472           
473           if (!GTK_WIDGET_IS_SENSITIVE (widget))
474             state_type = GTK_STATE_INSENSITIVE;
475
476           if (check_menu_item->draw_as_radio)
477             {
478               gtk_paint_option (widget->style, widget->window,
479                                 state_type, shadow_type,
480                                 area, widget, "option",
481                                 x, y, indicator_size, indicator_size);
482             }
483           else
484             {
485               gtk_paint_check (widget->style, widget->window,
486                                state_type, shadow_type,
487                                area, widget, "check",
488                                x, y, indicator_size, indicator_size);
489             }
490         }
491     }
492 }
493
494
495 static void
496 gtk_check_menu_item_get_property (GObject     *object,
497                                   guint        prop_id,
498                                   GValue      *value,
499                                   GParamSpec  *pspec)
500 {
501   GtkCheckMenuItem *checkitem = GTK_CHECK_MENU_ITEM (object);
502   
503   switch (prop_id)
504     {
505     case PROP_ACTIVE:
506       g_value_set_boolean (value, checkitem->active);
507       break;
508     case PROP_INCONSISTENT:
509       g_value_set_boolean (value, checkitem->inconsistent);
510       break;
511     case PROP_DRAW_AS_RADIO:
512       g_value_set_boolean (value, checkitem->draw_as_radio);
513       break;
514     default:
515       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
516       break;
517     }
518 }
519
520
521 static void
522 gtk_check_menu_item_set_property (GObject      *object,
523                                   guint         prop_id,
524                                   const GValue *value,
525                                   GParamSpec   *pspec)
526 {
527   GtkCheckMenuItem *checkitem = GTK_CHECK_MENU_ITEM (object);
528   
529   switch (prop_id)
530     {
531     case PROP_ACTIVE:
532       gtk_check_menu_item_set_active (checkitem, g_value_get_boolean (value));
533       break;
534     case PROP_INCONSISTENT:
535       gtk_check_menu_item_set_inconsistent (checkitem, g_value_get_boolean (value));
536       break;
537     case PROP_DRAW_AS_RADIO:
538       gtk_check_menu_item_set_draw_as_radio (checkitem, g_value_get_boolean (value));
539       break;
540     default:
541       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
542       break;
543     }
544 }
545
546 #define __GTK_CHECK_MENU_ITEM_C__
547 #include "gtkaliasdef.c"