1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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/.
29 #include "gtksignal.h"
30 #include "gtktogglebutton.h"
33 #define DEFAULT_LEFT_POS 4
34 #define DEFAULT_TOP_POS 4
35 #define DEFAULT_SPACING 7
49 static void gtk_toggle_button_class_init (GtkToggleButtonClass *klass);
50 static void gtk_toggle_button_init (GtkToggleButton *toggle_button);
51 static void gtk_toggle_button_paint (GtkWidget *widget,
53 static void gtk_toggle_button_size_allocate (GtkWidget *widget,
54 GtkAllocation *allocation);
55 static void gtk_toggle_button_draw (GtkWidget *widget,
57 static gint gtk_toggle_button_expose (GtkWidget *widget,
58 GdkEventExpose *event);
59 static void gtk_toggle_button_pressed (GtkButton *button);
60 static void gtk_toggle_button_released (GtkButton *button);
61 static void gtk_toggle_button_clicked (GtkButton *button);
62 static void gtk_toggle_button_enter (GtkButton *button);
63 static void gtk_toggle_button_leave (GtkButton *button);
64 static void gtk_toggle_button_set_arg (GtkObject *object,
67 static void gtk_toggle_button_get_arg (GtkObject *object,
70 static void gtk_toggle_button_leave (GtkButton *button);
71 static void gtk_toggle_button_realize (GtkWidget *widget);
72 static void gtk_toggle_button_unrealize (GtkWidget *widget);
73 static void gtk_toggle_button_map (GtkWidget *widget);
74 static void gtk_toggle_button_unmap (GtkWidget *widget);
76 static guint toggle_button_signals[LAST_SIGNAL] = { 0 };
77 static GtkContainerClass *parent_class = NULL;
80 gtk_toggle_button_get_type (void)
82 static GtkType toggle_button_type = 0;
84 if (!toggle_button_type)
86 static const GtkTypeInfo toggle_button_info =
89 sizeof (GtkToggleButton),
90 sizeof (GtkToggleButtonClass),
91 (GtkClassInitFunc) gtk_toggle_button_class_init,
92 (GtkObjectInitFunc) gtk_toggle_button_init,
93 /* reserved_1 */ NULL,
94 /* reserved_2 */ NULL,
95 (GtkClassInitFunc) NULL,
98 toggle_button_type = gtk_type_unique (GTK_TYPE_BUTTON, &toggle_button_info);
101 return toggle_button_type;
105 gtk_toggle_button_class_init (GtkToggleButtonClass *class)
107 GtkObjectClass *object_class;
108 GtkWidgetClass *widget_class;
109 GtkContainerClass *container_class;
110 GtkButtonClass *button_class;
112 object_class = (GtkObjectClass*) class;
113 widget_class = (GtkWidgetClass*) class;
114 container_class = (GtkContainerClass*) class;
115 button_class = (GtkButtonClass*) class;
117 parent_class = gtk_type_class (GTK_TYPE_BUTTON);
119 gtk_object_add_arg_type ("GtkToggleButton::active", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_ACTIVE);
120 gtk_object_add_arg_type ("GtkToggleButton::draw_indicator", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_DRAW_INDICATOR);
122 toggle_button_signals[TOGGLED] =
123 gtk_signal_new ("toggled",
125 GTK_CLASS_TYPE (object_class),
126 GTK_SIGNAL_OFFSET (GtkToggleButtonClass, toggled),
127 gtk_marshal_NONE__NONE,
130 gtk_object_class_add_signals (object_class, toggle_button_signals, LAST_SIGNAL);
132 object_class->set_arg = gtk_toggle_button_set_arg;
133 object_class->get_arg = gtk_toggle_button_get_arg;
135 widget_class->size_allocate = gtk_toggle_button_size_allocate;
136 widget_class->draw = gtk_toggle_button_draw;
137 widget_class->expose_event = gtk_toggle_button_expose;
138 widget_class->realize = gtk_toggle_button_realize;
139 widget_class->unrealize = gtk_toggle_button_unrealize;
140 widget_class->map = gtk_toggle_button_map;
141 widget_class->unmap = gtk_toggle_button_unmap;
143 button_class->pressed = gtk_toggle_button_pressed;
144 button_class->released = gtk_toggle_button_released;
145 button_class->clicked = gtk_toggle_button_clicked;
146 button_class->enter = gtk_toggle_button_enter;
147 button_class->leave = gtk_toggle_button_leave;
149 class->toggled = NULL;
153 gtk_toggle_button_init (GtkToggleButton *toggle_button)
155 toggle_button->active = FALSE;
156 toggle_button->draw_indicator = FALSE;
157 GTK_WIDGET_UNSET_FLAGS (toggle_button, GTK_NO_WINDOW);
162 gtk_toggle_button_new (void)
164 return GTK_WIDGET (gtk_type_new (gtk_toggle_button_get_type ()));
168 gtk_toggle_button_new_with_label (const gchar *label)
170 GtkWidget *toggle_button;
171 GtkWidget *label_widget;
173 toggle_button = gtk_toggle_button_new ();
174 label_widget = gtk_label_new (label);
175 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.5, 0.5);
177 gtk_container_add (GTK_CONTAINER (toggle_button), label_widget);
178 gtk_widget_show (label_widget);
180 return toggle_button;
184 gtk_toggle_button_set_arg (GtkObject *object,
190 tb = GTK_TOGGLE_BUTTON (object);
195 gtk_toggle_button_set_active (tb, GTK_VALUE_BOOL (*arg));
197 case ARG_DRAW_INDICATOR:
198 gtk_toggle_button_set_mode (tb, GTK_VALUE_BOOL (*arg));
206 gtk_toggle_button_get_arg (GtkObject *object,
212 tb = GTK_TOGGLE_BUTTON (object);
217 GTK_VALUE_BOOL (*arg) = tb->active;
219 case ARG_DRAW_INDICATOR:
220 GTK_VALUE_BOOL (*arg) = tb->draw_indicator;
223 arg->type = GTK_TYPE_INVALID;
229 gtk_toggle_button_set_mode (GtkToggleButton *toggle_button,
230 gboolean draw_indicator)
234 g_return_if_fail (toggle_button != NULL);
235 g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));
237 widget = GTK_WIDGET (toggle_button);
239 draw_indicator = draw_indicator ? TRUE : FALSE;
241 if (toggle_button->draw_indicator != draw_indicator)
243 if (GTK_WIDGET_REALIZED (toggle_button))
245 gboolean visible = GTK_WIDGET_VISIBLE (toggle_button);
248 gtk_widget_hide (widget);
250 gtk_widget_unrealize (widget);
251 toggle_button->draw_indicator = draw_indicator;
253 if (toggle_button->draw_indicator)
254 GTK_WIDGET_SET_FLAGS (toggle_button, GTK_NO_WINDOW);
256 GTK_WIDGET_UNSET_FLAGS (toggle_button, GTK_NO_WINDOW);
258 gtk_widget_realize (widget);
261 gtk_widget_show (widget);
265 toggle_button->draw_indicator = draw_indicator;
267 if (toggle_button->draw_indicator)
268 GTK_WIDGET_SET_FLAGS (toggle_button, GTK_NO_WINDOW);
270 GTK_WIDGET_UNSET_FLAGS (toggle_button, GTK_NO_WINDOW);
273 if (GTK_WIDGET_VISIBLE (toggle_button))
274 gtk_widget_queue_resize (GTK_WIDGET (toggle_button));
280 gtk_toggle_button_set_active (GtkToggleButton *toggle_button,
283 g_return_if_fail (toggle_button != NULL);
284 g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));
286 is_active = is_active != 0;
288 if (toggle_button->active != is_active)
289 gtk_button_clicked (GTK_BUTTON (toggle_button));
294 gtk_toggle_button_get_active (GtkToggleButton *toggle_button)
296 g_return_val_if_fail (toggle_button != NULL, FALSE);
297 g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button), FALSE);
299 return (toggle_button->active) ? TRUE : FALSE;
304 gtk_toggle_button_toggled (GtkToggleButton *toggle_button)
306 g_return_if_fail (toggle_button != NULL);
307 g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));
309 gtk_signal_emit (GTK_OBJECT (toggle_button), toggle_button_signals[TOGGLED]);
314 gtk_toggle_button_paint (GtkWidget *widget,
318 GtkToggleButton *toggle_button;
319 GtkShadowType shadow_type;
323 button = GTK_BUTTON (widget);
324 toggle_button = GTK_TOGGLE_BUTTON (widget);
326 if (GTK_WIDGET_DRAWABLE (widget))
330 width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2;
331 height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2;
333 gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
334 gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height);
336 if (GTK_WIDGET_HAS_DEFAULT (widget) &&
337 GTK_BUTTON (widget)->relief == GTK_RELIEF_NORMAL)
339 gtk_paint_box (widget->style, widget->window,
340 GTK_STATE_NORMAL, GTK_SHADOW_IN,
341 area, widget, "togglebuttondefault",
342 x, y, width, height);
345 if (GTK_WIDGET_CAN_DEFAULT (widget))
347 x += widget->style->klass->xthickness;
348 y += widget->style->klass->ythickness;
349 width -= 2 * x + DEFAULT_SPACING;
350 height -= 2 * y + DEFAULT_SPACING;
351 x += DEFAULT_LEFT_POS;
352 y += DEFAULT_TOP_POS;
355 if (GTK_WIDGET_HAS_FOCUS (widget))
363 if ((GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) ||
364 toggle_button->active)
365 shadow_type = GTK_SHADOW_IN;
367 shadow_type = GTK_SHADOW_OUT;
369 if (button->relief != GTK_RELIEF_NONE ||
370 (GTK_WIDGET_STATE(widget) != GTK_STATE_NORMAL &&
371 GTK_WIDGET_STATE(widget) != GTK_STATE_INSENSITIVE))
372 gtk_paint_box (widget->style, widget->window,
373 GTK_WIDGET_STATE (widget),
374 shadow_type, area, widget, "togglebutton",
375 x, y, width, height);
377 if (GTK_WIDGET_HAS_FOCUS (widget))
384 gtk_paint_focus (widget->style, widget->window,
385 area, widget, "togglebutton",
386 x, y, width - 1, height - 1);
392 gtk_toggle_button_size_allocate (GtkWidget *widget,
393 GtkAllocation *allocation)
395 if (!GTK_WIDGET_NO_WINDOW (widget) &&
396 GTK_WIDGET_CLASS (parent_class)->size_allocate)
397 GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
401 gtk_toggle_button_expose (GtkWidget *widget,
402 GdkEventExpose *event)
404 if (!GTK_WIDGET_NO_WINDOW (widget) &&
405 GTK_WIDGET_CLASS (parent_class)->expose_event)
406 return GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
412 gtk_toggle_button_draw (GtkWidget *widget,
415 GdkRectangle child_area;
416 GdkRectangle tmp_area;
419 g_return_if_fail (widget != NULL);
420 g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget));
421 g_return_if_fail (area != NULL);
423 bin = GTK_BIN (widget);
425 if (GTK_WIDGET_DRAWABLE (widget) && !GTK_WIDGET_NO_WINDOW (widget))
428 tmp_area.x -= GTK_CONTAINER (widget)->border_width;
429 tmp_area.y -= GTK_CONTAINER (widget)->border_width;
431 gtk_toggle_button_paint (widget, &tmp_area);
433 if (bin->child && gtk_widget_intersect (bin->child, &tmp_area, &child_area))
434 gtk_widget_draw (bin->child, &child_area);
439 gtk_toggle_button_pressed (GtkButton *button)
441 GtkToggleButton *toggle_button;
442 GtkStateType new_state;
444 g_return_if_fail (button != NULL);
445 g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
447 toggle_button = GTK_TOGGLE_BUTTON (button);
449 button->button_down = TRUE;
451 if (toggle_button->active)
452 new_state = (button->in_button ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE);
454 new_state = (button->in_button ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL);
456 if (GTK_WIDGET_STATE (button) != new_state)
457 gtk_widget_set_state (GTK_WIDGET (button), new_state);
461 gtk_toggle_button_released (GtkButton *button)
463 GtkToggleButton *toggle_button;
464 GtkStateType new_state;
466 g_return_if_fail (button != NULL);
467 g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
469 if (button->button_down)
471 toggle_button = GTK_TOGGLE_BUTTON (button);
473 button->button_down = FALSE;
475 if (button->in_button)
477 gtk_button_clicked (button);
481 if (toggle_button->active)
482 new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
484 new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL);
486 if (GTK_WIDGET_STATE (button) != new_state)
487 gtk_widget_set_state (GTK_WIDGET (button), new_state);
493 gtk_toggle_button_clicked (GtkButton *button)
495 GtkToggleButton *toggle_button;
496 GtkStateType new_state;
498 g_return_if_fail (button != NULL);
499 g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
501 toggle_button = GTK_TOGGLE_BUTTON (button);
502 toggle_button->active = !toggle_button->active;
504 gtk_toggle_button_toggled (toggle_button);
506 if (toggle_button->active)
507 new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
509 new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL);
511 if (GTK_WIDGET_STATE (button) != new_state)
512 gtk_widget_set_state (GTK_WIDGET (button), new_state);
514 gtk_widget_queue_draw (GTK_WIDGET (button));
518 gtk_toggle_button_enter (GtkButton *button)
520 GtkToggleButton *toggle_button;
521 GtkStateType new_state;
523 g_return_if_fail (button != NULL);
524 g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
526 toggle_button = GTK_TOGGLE_BUTTON (button);
528 if (toggle_button->active)
529 new_state = (button->button_down ? GTK_STATE_NORMAL : GTK_STATE_PRELIGHT);
531 new_state = (button->button_down ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT);
533 if (GTK_WIDGET_STATE (button) != new_state)
534 gtk_widget_set_state (GTK_WIDGET (button), new_state);
538 gtk_toggle_button_leave (GtkButton *button)
540 GtkToggleButton *toggle_button;
541 GtkStateType new_state;
543 g_return_if_fail (button != NULL);
544 g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
546 toggle_button = GTK_TOGGLE_BUTTON (button);
548 new_state = (toggle_button->active ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL);
550 if (GTK_WIDGET_STATE (button) != new_state)
551 gtk_widget_set_state (GTK_WIDGET (button), new_state);
555 gtk_toggle_button_realize (GtkWidget *widget)
557 GtkToggleButton *toggle_button;
558 GdkWindowAttr attributes;
559 gint attributes_mask;
562 g_return_if_fail (widget != NULL);
563 g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget));
565 toggle_button = GTK_TOGGLE_BUTTON (widget);
566 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
568 border_width = GTK_CONTAINER (widget)->border_width;
570 attributes.window_type = GDK_WINDOW_CHILD;
571 attributes.x = widget->allocation.x + border_width;
572 attributes.y = widget->allocation.y + border_width;
573 attributes.width = widget->allocation.width - border_width * 2;
574 attributes.height = widget->allocation.height - border_width * 2;
575 attributes.event_mask = gtk_widget_get_events (widget);
576 attributes.event_mask |= (GDK_EXPOSURE_MASK |
577 GDK_BUTTON_PRESS_MASK |
578 GDK_BUTTON_RELEASE_MASK |
579 GDK_ENTER_NOTIFY_MASK |
580 GDK_LEAVE_NOTIFY_MASK);
582 if (GTK_WIDGET_NO_WINDOW (widget))
584 attributes.wclass = GDK_INPUT_ONLY;
585 attributes_mask = GDK_WA_X | GDK_WA_Y;
587 widget->window = gtk_widget_get_parent_window (widget);
588 gdk_window_ref (widget->window);
590 toggle_button->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
591 &attributes, attributes_mask);
592 gdk_window_set_user_data (toggle_button->event_window, toggle_button);
596 attributes.wclass = GDK_INPUT_OUTPUT;
597 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
598 attributes.visual = gtk_widget_get_visual (widget);
599 attributes.colormap = gtk_widget_get_colormap (widget);
600 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
601 &attributes, attributes_mask);
602 gdk_window_set_user_data (widget->window, toggle_button);
605 widget->style = gtk_style_attach (widget->style, widget->window);
607 if (!GTK_WIDGET_NO_WINDOW (widget))
608 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
612 gtk_toggle_button_unrealize (GtkWidget *widget)
614 GtkToggleButton *toggle_button;
616 g_return_if_fail (widget != NULL);
617 g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget));
619 toggle_button = GTK_TOGGLE_BUTTON (widget);
621 if (GTK_WIDGET_NO_WINDOW (widget))
623 gdk_window_set_user_data (toggle_button->event_window, NULL);
624 gdk_window_destroy (toggle_button->event_window);
625 toggle_button->event_window = NULL;
628 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
629 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
633 gtk_toggle_button_map (GtkWidget *widget)
635 g_return_if_fail (widget != NULL);
636 g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget));
638 if (GTK_WIDGET_NO_WINDOW (widget))
639 gdk_window_show (GTK_TOGGLE_BUTTON (widget)->event_window);
641 GTK_WIDGET_CLASS (parent_class)->map (widget);
645 gtk_toggle_button_unmap (GtkWidget *widget)
647 g_return_if_fail (widget != NULL);
648 g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget));
650 if (GTK_WIDGET_NO_WINDOW (widget))
651 gdk_window_hide (GTK_TOGGLE_BUTTON (widget)->event_window);
653 GTK_WIDGET_CLASS (parent_class)->unmap (widget);