comparison src/gtkexpander.c @ 11735:8d7c99f20e4c

[gaim-migrate @ 14026] Switch from using our old GaimGtkDisclosure widget to using the official GtkExpander widget. It works better and should make us look more uniform with other gtk apps. To maintain compatability with gtk < 2.4, I grabbed the gtkexpander.c and gtkexpander.h files from gtk+ CVS. I haven't tested compiling on a computer with gtk < 2.4 yet, so it's possible we'll need to get more stuff from gtk+ CVS. For future reference, gtkexpander.h was not modified, and gtkexpander.c was only modified to check if version is > 2.4 then do nothing. I also changed the #includes to use <> instead of "" committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Sun, 23 Oct 2005 03:24:53 +0000
parents
children 0b4923aee31d
comparison
equal deleted inserted replaced
11734:2f6b4c544d5b 11735:8d7c99f20e4c
1 /* GTK - The GIMP Toolkit
2 *
3 * Copyright (C) 2003 Sun Microsystems, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Authors:
21 * Mark McLoughlin <mark@skynet.ie>
22 */
23
24 /*
25 #include <config.h>
26 */
27
28 #include <gtk/gtkversion.h>
29 #if !GTK_CHECK_VERSION(2,4,0)
30 #include "gtkexpander.h"
31
32 #include <gtk/gtklabel.h>
33 #include <gtk/gtkcontainer.h>
34 #include <gtk/gtkmarshalers.h>
35 #include <gtk/gtkmain.h>
36 #include <gtk/gtkintl.h>
37 #include <gtk/gtkprivate.h>
38 #include <gdk/gdkkeysyms.h>
39 #include <gtk/gtkalias.h>
40
41 #define GTK_EXPANDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_EXPANDER, GtkExpanderPrivate))
42
43 #define DEFAULT_EXPANDER_SIZE 10
44 #define DEFAULT_EXPANDER_SPACING 2
45
46 enum
47 {
48 PROP_0,
49 PROP_EXPANDED,
50 PROP_LABEL,
51 PROP_USE_UNDERLINE,
52 PROP_USE_MARKUP,
53 PROP_SPACING,
54 PROP_LABEL_WIDGET
55 };
56
57 struct _GtkExpanderPrivate
58 {
59 GtkWidget *label_widget;
60 GdkWindow *event_window;
61 gint spacing;
62
63 GtkExpanderStyle expander_style;
64 guint animation_timeout;
65
66 guint expanded : 1;
67 guint use_underline : 1;
68 guint use_markup : 1;
69 guint button_down : 1;
70 guint prelight : 1;
71 };
72
73 static void gtk_expander_class_init (GtkExpanderClass *klass);
74 static void gtk_expander_init (GtkExpander *expander);
75
76 static void gtk_expander_set_property (GObject *object,
77 guint prop_id,
78 const GValue *value,
79 GParamSpec *pspec);
80 static void gtk_expander_get_property (GObject *object,
81 guint prop_id,
82 GValue *value,
83 GParamSpec *pspec);
84
85 static void gtk_expander_destroy (GtkObject *object);
86
87 static void gtk_expander_realize (GtkWidget *widget);
88 static void gtk_expander_unrealize (GtkWidget *widget);
89 static void gtk_expander_size_request (GtkWidget *widget,
90 GtkRequisition *requisition);
91 static void gtk_expander_size_allocate (GtkWidget *widget,
92 GtkAllocation *allocation);
93 static void gtk_expander_map (GtkWidget *widget);
94 static void gtk_expander_unmap (GtkWidget *widget);
95 static gboolean gtk_expander_expose (GtkWidget *widget,
96 GdkEventExpose *event);
97 static gboolean gtk_expander_button_press (GtkWidget *widget,
98 GdkEventButton *event);
99 static gboolean gtk_expander_button_release (GtkWidget *widget,
100 GdkEventButton *event);
101 static gboolean gtk_expander_enter_notify (GtkWidget *widget,
102 GdkEventCrossing *event);
103 static gboolean gtk_expander_leave_notify (GtkWidget *widget,
104 GdkEventCrossing *event);
105 static gboolean gtk_expander_focus (GtkWidget *widget,
106 GtkDirectionType direction);
107 static void gtk_expander_grab_notify (GtkWidget *widget,
108 gboolean was_grabbed);
109 static void gtk_expander_state_changed (GtkWidget *widget,
110 GtkStateType previous_state);
111
112 static void gtk_expander_add (GtkContainer *container,
113 GtkWidget *widget);
114 static void gtk_expander_remove (GtkContainer *container,
115 GtkWidget *widget);
116 static void gtk_expander_forall (GtkContainer *container,
117 gboolean include_internals,
118 GtkCallback callback,
119 gpointer callback_data);
120
121 static void gtk_expander_activate (GtkExpander *expander);
122
123 static void get_expander_bounds (GtkExpander *expander,
124 GdkRectangle *rect);
125
126 static GtkBinClass *parent_class = NULL;
127
128 GType
129 gtk_expander_get_type (void)
130 {
131 static GType expander_type = 0;
132
133 if (!expander_type)
134 {
135 static const GTypeInfo expander_info =
136 {
137 sizeof (GtkExpanderClass),
138 NULL, /* base_init */
139 NULL, /* base_finalize */
140 (GClassInitFunc) gtk_expander_class_init,
141 NULL, /* class_finalize */
142 NULL, /* class_data */
143 sizeof (GtkExpander),
144 0, /* n_preallocs */
145 (GInstanceInitFunc) gtk_expander_init,
146 };
147
148 expander_type = g_type_register_static (GTK_TYPE_BIN,
149 "GtkExpander",
150 &expander_info, 0);
151 }
152
153 return expander_type;
154 }
155
156 static void
157 gtk_expander_class_init (GtkExpanderClass *klass)
158 {
159 GObjectClass *gobject_class;
160 GtkObjectClass *object_class;
161 GtkWidgetClass *widget_class;
162 GtkContainerClass *container_class;
163
164 parent_class = g_type_class_peek_parent (klass);
165
166 gobject_class = (GObjectClass *) klass;
167 object_class = (GtkObjectClass *) klass;
168 widget_class = (GtkWidgetClass *) klass;
169 container_class = (GtkContainerClass *) klass;
170
171 gobject_class->set_property = gtk_expander_set_property;
172 gobject_class->get_property = gtk_expander_get_property;
173
174 object_class->destroy = gtk_expander_destroy;
175
176 widget_class->realize = gtk_expander_realize;
177 widget_class->unrealize = gtk_expander_unrealize;
178 widget_class->size_request = gtk_expander_size_request;
179 widget_class->size_allocate = gtk_expander_size_allocate;
180 widget_class->map = gtk_expander_map;
181 widget_class->unmap = gtk_expander_unmap;
182 widget_class->expose_event = gtk_expander_expose;
183 widget_class->button_press_event = gtk_expander_button_press;
184 widget_class->button_release_event = gtk_expander_button_release;
185 widget_class->enter_notify_event = gtk_expander_enter_notify;
186 widget_class->leave_notify_event = gtk_expander_leave_notify;
187 widget_class->focus = gtk_expander_focus;
188 widget_class->grab_notify = gtk_expander_grab_notify;
189 widget_class->state_changed = gtk_expander_state_changed;
190
191 container_class->add = gtk_expander_add;
192 container_class->remove = gtk_expander_remove;
193 container_class->forall = gtk_expander_forall;
194
195 klass->activate = gtk_expander_activate;
196
197 g_type_class_add_private (klass, sizeof (GtkExpanderPrivate));
198
199 g_object_class_install_property (gobject_class,
200 PROP_EXPANDED,
201 g_param_spec_boolean ("expanded",
202 P_("Expanded"),
203 P_("Whether the expander has been opened to reveal the child widget"),
204 FALSE,
205 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
206
207 g_object_class_install_property (gobject_class,
208 PROP_LABEL,
209 g_param_spec_string ("label",
210 P_("Label"),
211 P_("Text of the expander's label"),
212 NULL,
213 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
214
215 g_object_class_install_property (gobject_class,
216 PROP_USE_UNDERLINE,
217 g_param_spec_boolean ("use_underline",
218 P_("Use underline"),
219 P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
220 FALSE,
221 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
222
223 g_object_class_install_property (gobject_class,
224 PROP_USE_MARKUP,
225 g_param_spec_boolean ("use_markup",
226 P_("Use markup"),
227 P_("The text of the label includes XML markup. See pango_parse_markup()"),
228 FALSE,
229 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
230
231 g_object_class_install_property (gobject_class,
232 PROP_SPACING,
233 g_param_spec_int ("spacing",
234 P_("Spacing"),
235 P_("Space to put between the label and the child"),
236 0,
237 G_MAXINT,
238 0,
239 G_PARAM_READWRITE));
240
241 g_object_class_install_property (gobject_class,
242 PROP_LABEL_WIDGET,
243 g_param_spec_object ("label_widget",
244 P_("Label widget"),
245 P_("A widget to display in place of the usual expander label"),
246 GTK_TYPE_WIDGET,
247 G_PARAM_READWRITE));
248
249 gtk_widget_class_install_style_property (widget_class,
250 g_param_spec_int ("expander-size",
251 P_("Expander Size"),
252 P_("Size of the expander arrow"),
253 0,
254 G_MAXINT,
255 DEFAULT_EXPANDER_SIZE,
256 G_PARAM_READABLE));
257
258 gtk_widget_class_install_style_property (widget_class,
259 g_param_spec_int ("expander-spacing",
260 P_("Indicator Spacing"),
261 P_("Spacing around expander arrow"),
262 0,
263 G_MAXINT,
264 DEFAULT_EXPANDER_SPACING,
265 G_PARAM_READABLE));
266
267 widget_class->activate_signal =
268 g_signal_new ("activate",
269 G_TYPE_FROM_CLASS (gobject_class),
270 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
271 G_STRUCT_OFFSET (GtkExpanderClass, activate),
272 NULL, NULL,
273 _gtk_marshal_VOID__VOID,
274 G_TYPE_NONE, 0);
275 }
276
277 static void
278 gtk_expander_init (GtkExpander *expander)
279 {
280 GtkExpanderPrivate *priv;
281
282 expander->priv = priv = GTK_EXPANDER_GET_PRIVATE (expander);
283
284 GTK_WIDGET_SET_FLAGS (expander, GTK_CAN_FOCUS);
285 GTK_WIDGET_SET_FLAGS (expander, GTK_NO_WINDOW);
286
287 priv->label_widget = NULL;
288 priv->event_window = NULL;
289 priv->spacing = 0;
290
291 priv->expander_style = GTK_EXPANDER_COLLAPSED;
292 priv->animation_timeout = 0;
293
294 priv->expanded = FALSE;
295 priv->use_underline = FALSE;
296 priv->use_markup = FALSE;
297 priv->button_down = FALSE;
298 priv->prelight = FALSE;
299 }
300
301 static void
302 gtk_expander_set_property (GObject *object,
303 guint prop_id,
304 const GValue *value,
305 GParamSpec *pspec)
306 {
307 GtkExpander *expander = GTK_EXPANDER (object);
308
309 switch (prop_id)
310 {
311 case PROP_EXPANDED:
312 gtk_expander_set_expanded (expander, g_value_get_boolean (value));
313 break;
314 case PROP_LABEL:
315 gtk_expander_set_label (expander, g_value_get_string (value));
316 break;
317 case PROP_USE_UNDERLINE:
318 gtk_expander_set_use_underline (expander, g_value_get_boolean (value));
319 break;
320 case PROP_USE_MARKUP:
321 gtk_expander_set_use_markup (expander, g_value_get_boolean (value));
322 break;
323 case PROP_SPACING:
324 gtk_expander_set_spacing (expander, g_value_get_int (value));
325 break;
326 case PROP_LABEL_WIDGET:
327 gtk_expander_set_label_widget (expander, g_value_get_object (value));
328 break;
329 default:
330 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
331 break;
332 }
333 }
334
335 static void
336 gtk_expander_get_property (GObject *object,
337 guint prop_id,
338 GValue *value,
339 GParamSpec *pspec)
340 {
341 GtkExpander *expander = GTK_EXPANDER (object);
342 GtkExpanderPrivate *priv = expander->priv;
343
344 switch (prop_id)
345 {
346 case PROP_EXPANDED:
347 g_value_set_boolean (value, priv->expanded);
348 break;
349 case PROP_LABEL:
350 g_value_set_string (value, gtk_expander_get_label (expander));
351 break;
352 case PROP_USE_UNDERLINE:
353 g_value_set_boolean (value, priv->use_underline);
354 break;
355 case PROP_USE_MARKUP:
356 g_value_set_boolean (value, priv->use_markup);
357 break;
358 case PROP_SPACING:
359 g_value_set_int (value, priv->spacing);
360 break;
361 case PROP_LABEL_WIDGET:
362 g_value_set_object (value,
363 priv->label_widget ?
364 G_OBJECT (priv->label_widget) : NULL);
365 break;
366 default:
367 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
368 break;
369 }
370 }
371
372 static void
373 gtk_expander_destroy (GtkObject *object)
374 {
375 GtkExpanderPrivate *priv = GTK_EXPANDER (object)->priv;
376
377 if (priv->animation_timeout)
378 {
379 g_source_remove (priv->animation_timeout);
380 priv->animation_timeout = 0;
381 }
382
383 GTK_OBJECT_CLASS (parent_class)->destroy (object);
384 }
385
386 static void
387 gtk_expander_realize (GtkWidget *widget)
388 {
389 GtkExpanderPrivate *priv;
390 GdkWindowAttr attributes;
391 gint attributes_mask;
392 gint border_width;
393 GdkRectangle expander_rect;
394
395 priv = GTK_EXPANDER (widget)->priv;
396 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
397
398 border_width = GTK_CONTAINER (widget)->border_width;
399
400 get_expander_bounds (GTK_EXPANDER (widget), &expander_rect);
401
402 attributes.window_type = GDK_WINDOW_CHILD;
403 attributes.x = widget->allocation.x + border_width;
404 attributes.y = expander_rect.y;
405 attributes.width = MAX (widget->allocation.width - 2 * border_width, 1);
406 attributes.height = expander_rect.width;
407 attributes.wclass = GDK_INPUT_ONLY;
408 attributes.event_mask = gtk_widget_get_events (widget) |
409 GDK_BUTTON_PRESS_MASK |
410 GDK_BUTTON_RELEASE_MASK |
411 GDK_ENTER_NOTIFY_MASK |
412 GDK_LEAVE_NOTIFY_MASK;
413
414 attributes_mask = GDK_WA_X | GDK_WA_Y;
415
416 widget->window = gtk_widget_get_parent_window (widget);
417 g_object_ref (widget->window);
418
419 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
420 &attributes, attributes_mask);
421 gdk_window_set_user_data (priv->event_window, widget);
422
423 widget->style = gtk_style_attach (widget->style, widget->window);
424 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
425 }
426
427 static void
428 gtk_expander_unrealize (GtkWidget *widget)
429 {
430 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
431
432 if (priv->event_window)
433 {
434 gdk_window_set_user_data (priv->event_window, NULL);
435 gdk_window_destroy (priv->event_window);
436 priv->event_window = NULL;
437 }
438
439 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
440 }
441
442 static void
443 gtk_expander_size_request (GtkWidget *widget,
444 GtkRequisition *requisition)
445 {
446 GtkExpander *expander;
447 GtkBin *bin;
448 GtkExpanderPrivate *priv;
449 gint border_width;
450 gint expander_size;
451 gint expander_spacing;
452 gboolean interior_focus;
453 gint focus_width;
454 gint focus_pad;
455
456 bin = GTK_BIN (widget);
457 expander = GTK_EXPANDER (widget);
458 priv = expander->priv;
459
460 border_width = GTK_CONTAINER (widget)->border_width;
461
462 gtk_widget_style_get (widget,
463 "interior-focus", &interior_focus,
464 "focus-line-width", &focus_width,
465 "focus-padding", &focus_pad,
466 "expander-size", &expander_size,
467 "expander-spacing", &expander_spacing,
468 NULL);
469
470 requisition->width = expander_size + 2 * expander_spacing +
471 2 * focus_width + 2 * focus_pad;
472 requisition->height = interior_focus ? (2 * focus_width + 2 * focus_pad) : 0;
473
474 if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
475 {
476 GtkRequisition label_requisition;
477
478 gtk_widget_size_request (priv->label_widget, &label_requisition);
479
480 requisition->width += label_requisition.width;
481 requisition->height += label_requisition.height;
482 }
483
484 requisition->height = MAX (expander_size + 2 * expander_spacing, requisition->height);
485
486 if (!interior_focus)
487 requisition->height += 2 * focus_width + 2 * focus_pad;
488
489 if (bin->child && GTK_WIDGET_CHILD_VISIBLE (bin->child))
490 {
491 GtkRequisition child_requisition;
492
493 gtk_widget_size_request (bin->child, &child_requisition);
494
495 requisition->width = MAX (requisition->width, child_requisition.width);
496 requisition->height += child_requisition.height + priv->spacing;
497 }
498
499 requisition->width += 2 * border_width;
500 requisition->height += 2 * border_width;
501 }
502
503 static void
504 get_expander_bounds (GtkExpander *expander,
505 GdkRectangle *rect)
506 {
507 GtkWidget *widget;
508 GtkBin *bin;
509 GtkExpanderPrivate *priv;
510 gint border_width;
511 gint expander_size;
512 gint expander_spacing;
513 gboolean interior_focus;
514 gint focus_width;
515 gint focus_pad;
516 gboolean ltr;
517
518 widget = GTK_WIDGET (expander);
519 bin = GTK_BIN (expander);
520 priv = expander->priv;
521
522 border_width = GTK_CONTAINER (expander)->border_width;
523
524 gtk_widget_style_get (widget,
525 "interior-focus", &interior_focus,
526 "focus-line-width", &focus_width,
527 "focus-padding", &focus_pad,
528 "expander-size", &expander_size,
529 "expander-spacing", &expander_spacing,
530 NULL);
531
532 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
533
534 rect->x = widget->allocation.x + border_width;
535 rect->y = widget->allocation.y + border_width;
536
537 if (ltr)
538 rect->x += expander_spacing;
539 else
540 rect->x += widget->allocation.width - 2 * border_width -
541 expander_spacing - expander_size;
542
543 if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
544 {
545 GtkAllocation label_allocation;
546
547 label_allocation = priv->label_widget->allocation;
548
549 if (expander_size < label_allocation.height)
550 rect->y += focus_width + focus_pad + (label_allocation.height - expander_size) / 2;
551 else
552 rect->y += expander_spacing;
553 }
554 else
555 {
556 rect->y += expander_spacing;
557 }
558
559 if (!interior_focus)
560 {
561 if (ltr)
562 rect->x += focus_width + focus_pad;
563 else
564 rect->x -= focus_width + focus_pad;
565 rect->y += focus_width + focus_pad;
566 }
567
568 rect->width = rect->height = expander_size;
569 }
570
571 static void
572 gtk_expander_size_allocate (GtkWidget *widget,
573 GtkAllocation *allocation)
574 {
575 GtkExpander *expander;
576 GtkBin *bin;
577 GtkExpanderPrivate *priv;
578 GtkRequisition child_requisition;
579 gboolean child_visible = FALSE;
580 gint border_width;
581 gint expander_size;
582 gint expander_spacing;
583 gboolean interior_focus;
584 gint focus_width;
585 gint focus_pad;
586 gint label_height;
587
588 expander = GTK_EXPANDER (widget);
589 bin = GTK_BIN (widget);
590 priv = expander->priv;
591
592 border_width = GTK_CONTAINER (widget)->border_width;
593
594 gtk_widget_style_get (widget,
595 "interior-focus", &interior_focus,
596 "focus-line-width", &focus_width,
597 "focus-padding", &focus_pad,
598 "expander-size", &expander_size,
599 "expander-spacing", &expander_spacing,
600 NULL);
601
602 child_requisition.width = 0;
603 child_requisition.height = 0;
604 if (bin->child && GTK_WIDGET_CHILD_VISIBLE (bin->child))
605 {
606 child_visible = TRUE;
607 gtk_widget_get_child_requisition (bin->child, &child_requisition);
608 }
609
610 widget->allocation = *allocation;
611
612 if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
613 {
614 GtkAllocation label_allocation;
615 GtkRequisition label_requisition;
616 gboolean ltr;
617
618 gtk_widget_get_child_requisition (priv->label_widget, &label_requisition);
619
620 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
621
622 if (ltr)
623 label_allocation.x = (widget->allocation.x +
624 border_width + focus_width + focus_pad +
625 expander_size + 2 * expander_spacing);
626 else
627 label_allocation.x = (widget->allocation.x + widget->allocation.width -
628 (label_requisition.width +
629 border_width + focus_width + focus_pad +
630 expander_size + 2 * expander_spacing));
631
632 label_allocation.y = widget->allocation.y + border_width + focus_width + focus_pad;
633
634 label_allocation.width = MIN (label_requisition.width,
635 allocation->width - 2 * border_width -
636 expander_size - 2 * expander_spacing -
637 2 * focus_width - 2 * focus_pad);
638 label_allocation.width = MAX (label_allocation.width, 1);
639
640 label_allocation.height = MIN (label_requisition.height,
641 allocation->height - 2 * border_width -
642 2 * focus_width - 2 * focus_pad -
643 (child_visible ? priv->spacing : 0));
644 label_allocation.height = MAX (label_allocation.height, 1);
645
646 gtk_widget_size_allocate (priv->label_widget, &label_allocation);
647
648 label_height = label_allocation.height;
649 }
650 else
651 {
652 label_height = 0;
653 }
654
655 if (GTK_WIDGET_REALIZED (widget))
656 {
657 GdkRectangle rect;
658
659 get_expander_bounds (expander, &rect);
660
661 gdk_window_move_resize (priv->event_window,
662 allocation->x + border_width, rect.y,
663 MAX (allocation->width - 2 * border_width, 1), rect.width);
664 }
665
666 if (child_visible)
667 {
668 GtkAllocation child_allocation;
669 gint top_height;
670
671 top_height = MAX (2 * expander_spacing + expander_size,
672 label_height +
673 (interior_focus ? 2 * focus_width + 2 * focus_pad : 0));
674
675 child_allocation.x = widget->allocation.x + border_width;
676 child_allocation.y = widget->allocation.y + border_width + top_height + priv->spacing;
677
678 if (!interior_focus)
679 child_allocation.y += 2 * focus_width + 2 * focus_pad;
680
681 child_allocation.width = MAX (allocation->width - 2 * border_width, 1);
682
683 child_allocation.height = allocation->height - top_height -
684 2 * border_width - priv->spacing -
685 (!interior_focus ? 2 * focus_width + 2 * focus_pad : 0);
686 child_allocation.height = MAX (child_allocation.height, 1);
687
688 gtk_widget_size_allocate (bin->child, &child_allocation);
689 }
690 }
691
692 static void
693 gtk_expander_map (GtkWidget *widget)
694 {
695 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
696
697 if (priv->label_widget)
698 gtk_widget_map (priv->label_widget);
699
700 GTK_WIDGET_CLASS (parent_class)->map (widget);
701
702 if (priv->event_window)
703 gdk_window_show (priv->event_window);
704 }
705
706 static void
707 gtk_expander_unmap (GtkWidget *widget)
708 {
709 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
710
711 if (priv->event_window)
712 gdk_window_hide (priv->event_window);
713
714 GTK_WIDGET_CLASS (parent_class)->unmap (widget);
715
716 if (priv->label_widget)
717 gtk_widget_unmap (priv->label_widget);
718 }
719
720 static void
721 gtk_expander_paint_prelight (GtkExpander *expander)
722 {
723 GtkWidget *widget;
724 GtkContainer *container;
725 GtkExpanderPrivate *priv;
726 GdkRectangle area;
727 gboolean interior_focus;
728 int focus_width;
729 int focus_pad;
730 int expander_size;
731 int expander_spacing;
732
733 priv = expander->priv;
734 widget = GTK_WIDGET (expander);
735 container = GTK_CONTAINER (expander);
736
737 gtk_widget_style_get (widget,
738 "interior-focus", &interior_focus,
739 "focus-line-width", &focus_width,
740 "focus-padding", &focus_pad,
741 "expander-size", &expander_size,
742 "expander-spacing", &expander_spacing,
743 NULL);
744
745 area.x = widget->allocation.x + container->border_width;
746 area.y = widget->allocation.y + container->border_width;
747 area.width = widget->allocation.width - (2 * container->border_width);
748
749 if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
750 area.height = priv->label_widget->allocation.height;
751 else
752 area.height = 0;
753
754 area.height += interior_focus ? (focus_width + focus_pad) * 2 : 0;
755 area.height = MAX (area.height, expander_size + 2 * expander_spacing);
756 area.height += !interior_focus ? (focus_width + focus_pad) * 2 : 0;
757
758 gtk_paint_flat_box (widget->style, widget->window,
759 GTK_STATE_PRELIGHT,
760 GTK_SHADOW_ETCHED_OUT,
761 &area, widget, "expander",
762 area.x, area.y,
763 area.width, area.height);
764 }
765
766 static void
767 gtk_expander_paint (GtkExpander *expander)
768 {
769 GtkWidget *widget;
770 GdkRectangle clip;
771 GtkStateType state;
772
773 widget = GTK_WIDGET (expander);
774
775 get_expander_bounds (expander, &clip);
776
777 state = widget->state;
778 if (expander->priv->prelight)
779 {
780 state = GTK_STATE_PRELIGHT;
781
782 gtk_expander_paint_prelight (expander);
783 }
784
785 gtk_paint_expander (widget->style,
786 widget->window,
787 state,
788 &clip,
789 widget,
790 "expander",
791 clip.x + clip.width / 2,
792 clip.y + clip.height / 2,
793 expander->priv->expander_style);
794 }
795
796 static void
797 gtk_expander_paint_focus (GtkExpander *expander,
798 GdkRectangle *area)
799 {
800 GtkWidget *widget;
801 GtkExpanderPrivate *priv;
802 gint x, y, width, height;
803 gboolean interior_focus;
804 gint border_width;
805 gint focus_width;
806 gint focus_pad;
807 gint expander_size;
808 gint expander_spacing;
809 gboolean ltr;
810
811 widget = GTK_WIDGET (expander);
812 priv = expander->priv;
813
814 border_width = GTK_CONTAINER (widget)->border_width;
815
816 gtk_widget_style_get (widget,
817 "interior-focus", &interior_focus,
818 "focus-line-width", &focus_width,
819 "focus-padding", &focus_pad,
820 "expander-size", &expander_size,
821 "expander-spacing", &expander_spacing,
822 NULL);
823
824 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
825
826 x = widget->allocation.x + border_width;
827 y = widget->allocation.y + border_width;
828
829 if (ltr && interior_focus)
830 x += expander_spacing * 2 + expander_size;
831
832 width = height = 0;
833
834 if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
835 {
836 GtkAllocation label_allocation = priv->label_widget->allocation;
837
838 width = label_allocation.width;
839 height = label_allocation.height;
840 }
841
842 if (!interior_focus)
843 {
844 width += expander_size + 2 * expander_spacing;
845 height = MAX (height, expander_size + 2 * expander_spacing);
846 }
847
848 width += 2 * focus_pad + 2 * focus_width;
849 height += 2 * focus_pad + 2 * focus_width;
850
851 gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
852 area, widget, "expander",
853 x, y, width, height);
854 }
855
856 static gboolean
857 gtk_expander_expose (GtkWidget *widget,
858 GdkEventExpose *event)
859 {
860 if (GTK_WIDGET_DRAWABLE (widget))
861 {
862 GtkExpander *expander = GTK_EXPANDER (widget);
863
864 gtk_expander_paint (expander);
865
866 if (GTK_WIDGET_HAS_FOCUS (expander))
867 gtk_expander_paint_focus (expander, &event->area);
868
869 GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
870 }
871
872 return FALSE;
873 }
874
875 static gboolean
876 gtk_expander_button_press (GtkWidget *widget,
877 GdkEventButton *event)
878 {
879 GtkExpander *expander = GTK_EXPANDER (widget);
880
881 if (event->button == 1 && event->window == expander->priv->event_window)
882 {
883 expander->priv->button_down = TRUE;
884 return TRUE;
885 }
886
887 return FALSE;
888 }
889
890 static gboolean
891 gtk_expander_button_release (GtkWidget *widget,
892 GdkEventButton *event)
893 {
894 GtkExpander *expander = GTK_EXPANDER (widget);
895
896 if (event->button == 1 && expander->priv->button_down)
897 {
898 gtk_widget_activate (widget);
899 expander->priv->button_down = FALSE;
900 return TRUE;
901 }
902
903 return FALSE;
904 }
905
906 static void
907 gtk_expander_grab_notify (GtkWidget *widget,
908 gboolean was_grabbed)
909 {
910 if (!was_grabbed)
911 GTK_EXPANDER (widget)->priv->button_down = FALSE;
912 }
913
914 static void
915 gtk_expander_state_changed (GtkWidget *widget,
916 GtkStateType previous_state)
917 {
918 if (!GTK_WIDGET_IS_SENSITIVE (widget))
919 GTK_EXPANDER (widget)->priv->button_down = FALSE;
920 }
921
922 static void
923 gtk_expander_redraw_expander (GtkExpander *expander)
924 {
925 GtkWidget *widget;
926
927 widget = GTK_WIDGET (expander);
928
929 if (GTK_WIDGET_REALIZED (widget))
930 gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
931 }
932
933 static gboolean
934 gtk_expander_enter_notify (GtkWidget *widget,
935 GdkEventCrossing *event)
936 {
937 GtkExpander *expander = GTK_EXPANDER (widget);
938 GtkWidget *event_widget;
939
940 event_widget = gtk_get_event_widget ((GdkEvent *) event);
941
942 if (event_widget == widget &&
943 event->detail != GDK_NOTIFY_INFERIOR)
944 {
945 expander->priv->prelight = TRUE;
946
947 if (expander->priv->label_widget)
948 gtk_widget_set_state (expander->priv->label_widget, GTK_STATE_PRELIGHT);
949
950 gtk_expander_redraw_expander (expander);
951 }
952
953 return FALSE;
954 }
955
956 static gboolean
957 gtk_expander_leave_notify (GtkWidget *widget,
958 GdkEventCrossing *event)
959 {
960 GtkExpander *expander = GTK_EXPANDER (widget);
961 GtkWidget *event_widget;
962
963 event_widget = gtk_get_event_widget ((GdkEvent *) event);
964
965 if (event_widget == widget &&
966 event->detail != GDK_NOTIFY_INFERIOR)
967 {
968 expander->priv->prelight = FALSE;
969
970 if (expander->priv->label_widget)
971 gtk_widget_set_state (expander->priv->label_widget, GTK_STATE_NORMAL);
972
973 gtk_expander_redraw_expander (expander);
974 }
975
976 return FALSE;
977 }
978
979 typedef enum
980 {
981 FOCUS_NONE,
982 FOCUS_WIDGET,
983 FOCUS_LABEL,
984 FOCUS_CHILD
985 } FocusSite;
986
987 static gboolean
988 focus_current_site (GtkExpander *expander,
989 GtkDirectionType direction)
990 {
991 GtkWidget *current_focus;
992
993 current_focus = GTK_CONTAINER (expander)->focus_child;
994
995 if (!current_focus)
996 return FALSE;
997
998 return gtk_widget_child_focus (current_focus, direction);
999 }
1000
1001 static gboolean
1002 focus_in_site (GtkExpander *expander,
1003 FocusSite site,
1004 GtkDirectionType direction)
1005 {
1006 switch (site)
1007 {
1008 case FOCUS_WIDGET:
1009 gtk_widget_grab_focus (GTK_WIDGET (expander));
1010 return TRUE;
1011 case FOCUS_LABEL:
1012 if (expander->priv->label_widget)
1013 return gtk_widget_child_focus (expander->priv->label_widget, direction);
1014 else
1015 return FALSE;
1016 case FOCUS_CHILD:
1017 {
1018 GtkWidget *child = gtk_bin_get_child (GTK_BIN (expander));
1019
1020 if (child && GTK_WIDGET_CHILD_VISIBLE (child))
1021 return gtk_widget_child_focus (child, direction);
1022 else
1023 return FALSE;
1024 }
1025 case FOCUS_NONE:
1026 break;
1027 }
1028
1029 g_assert_not_reached ();
1030 return FALSE;
1031 }
1032
1033 static FocusSite
1034 get_next_site (GtkExpander *expander,
1035 FocusSite site,
1036 GtkDirectionType direction)
1037 {
1038 gboolean ltr;
1039
1040 ltr = gtk_widget_get_direction (GTK_WIDGET (expander)) != GTK_TEXT_DIR_RTL;
1041
1042 switch (site)
1043 {
1044 case FOCUS_NONE:
1045 switch (direction)
1046 {
1047 case GTK_DIR_TAB_BACKWARD:
1048 case GTK_DIR_LEFT:
1049 case GTK_DIR_UP:
1050 return FOCUS_CHILD;
1051 case GTK_DIR_TAB_FORWARD:
1052 case GTK_DIR_DOWN:
1053 case GTK_DIR_RIGHT:
1054 return FOCUS_WIDGET;
1055 }
1056 case FOCUS_WIDGET:
1057 switch (direction)
1058 {
1059 case GTK_DIR_TAB_BACKWARD:
1060 case GTK_DIR_UP:
1061 return FOCUS_NONE;
1062 case GTK_DIR_LEFT:
1063 return ltr ? FOCUS_NONE : FOCUS_LABEL;
1064 case GTK_DIR_TAB_FORWARD:
1065 case GTK_DIR_DOWN:
1066 return FOCUS_LABEL;
1067 case GTK_DIR_RIGHT:
1068 return ltr ? FOCUS_LABEL : FOCUS_NONE;
1069 break;
1070 }
1071 case FOCUS_LABEL:
1072 switch (direction)
1073 {
1074 case GTK_DIR_TAB_BACKWARD:
1075 case GTK_DIR_UP:
1076 return FOCUS_WIDGET;
1077 case GTK_DIR_LEFT:
1078 return ltr ? FOCUS_WIDGET : FOCUS_CHILD;
1079 case GTK_DIR_TAB_FORWARD:
1080 case GTK_DIR_DOWN:
1081 return FOCUS_CHILD;
1082 case GTK_DIR_RIGHT:
1083 return ltr ? FOCUS_CHILD : FOCUS_WIDGET;
1084 break;
1085 }
1086 case FOCUS_CHILD:
1087 switch (direction)
1088 {
1089 case GTK_DIR_TAB_BACKWARD:
1090 case GTK_DIR_LEFT:
1091 case GTK_DIR_UP:
1092 return FOCUS_LABEL;
1093 case GTK_DIR_TAB_FORWARD:
1094 case GTK_DIR_DOWN:
1095 case GTK_DIR_RIGHT:
1096 return FOCUS_NONE;
1097 }
1098 }
1099
1100 g_assert_not_reached ();
1101 return FOCUS_NONE;
1102 }
1103
1104 static gboolean
1105 gtk_expander_focus (GtkWidget *widget,
1106 GtkDirectionType direction)
1107 {
1108 GtkExpander *expander = GTK_EXPANDER (widget);
1109
1110 if (!focus_current_site (expander, direction))
1111 {
1112 GtkWidget *old_focus_child;
1113 gboolean widget_is_focus;
1114 FocusSite site = FOCUS_NONE;
1115
1116 widget_is_focus = gtk_widget_is_focus (widget);
1117 old_focus_child = GTK_CONTAINER (widget)->focus_child;
1118
1119 if (old_focus_child && old_focus_child == expander->priv->label_widget)
1120 site = FOCUS_LABEL;
1121 else if (old_focus_child)
1122 site = FOCUS_CHILD;
1123 else if (widget_is_focus)
1124 site = FOCUS_WIDGET;
1125
1126 while ((site = get_next_site (expander, site, direction)) != FOCUS_NONE)
1127 {
1128 if (focus_in_site (expander, site, direction))
1129 return TRUE;
1130 }
1131
1132 return FALSE;
1133 }
1134
1135 return TRUE;
1136 }
1137
1138 static void
1139 gtk_expander_add (GtkContainer *container,
1140 GtkWidget *widget)
1141 {
1142 GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
1143
1144 gtk_widget_set_child_visible (widget, GTK_EXPANDER (container)->priv->expanded);
1145 gtk_widget_queue_resize (GTK_WIDGET (container));
1146 }
1147
1148 static void
1149 gtk_expander_remove (GtkContainer *container,
1150 GtkWidget *widget)
1151 {
1152 GtkExpander *expander = GTK_EXPANDER (container);
1153
1154 if (GTK_EXPANDER (expander)->priv->label_widget == widget)
1155 gtk_expander_set_label_widget (expander, NULL);
1156 else
1157 GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
1158 }
1159
1160 static void
1161 gtk_expander_forall (GtkContainer *container,
1162 gboolean include_internals,
1163 GtkCallback callback,
1164 gpointer callback_data)
1165 {
1166 GtkBin *bin = GTK_BIN (container);
1167 GtkExpanderPrivate *priv = GTK_EXPANDER (container)->priv;
1168
1169 if (bin->child)
1170 (* callback) (bin->child, callback_data);
1171
1172 if (priv->label_widget)
1173 (* callback) (priv->label_widget, callback_data);
1174 }
1175
1176 static void
1177 gtk_expander_activate (GtkExpander *expander)
1178 {
1179 gtk_expander_set_expanded (expander, !expander->priv->expanded);
1180 }
1181
1182
1183 /**
1184 * gtk_expander_new:
1185 * @label: the text of the label
1186 *
1187 * Creates a new expander using @label as the text of the label.
1188 *
1189 * Return value: a new #GtkExpander widget.
1190 *
1191 * Since: 2.4
1192 **/
1193 GtkWidget *
1194 gtk_expander_new (const gchar *label)
1195 {
1196 return g_object_new (GTK_TYPE_EXPANDER, "label", label, NULL);
1197 }
1198
1199 /**
1200 * gtk_expander_new_with_mnemonic:
1201 * @label: the text of the label with an underscore in front of the
1202 * mnemonic character
1203 *
1204 * Creates a new expander using @label as the text of the label.
1205 * If characters in @label are preceded by an underscore, they are underlined.
1206 * If you need a literal underscore character in a label, use '__' (two
1207 * underscores). The first underlined character represents a keyboard
1208 * accelerator called a mnemonic.
1209 * Pressing Alt and that key activates the button.
1210 *
1211 * Return value: a new #GtkExpander widget.
1212 *
1213 * Since: 2.4
1214 **/
1215 GtkWidget *
1216 gtk_expander_new_with_mnemonic (const gchar *label)
1217 {
1218 return g_object_new (GTK_TYPE_EXPANDER,
1219 "label", label,
1220 "use_underline", TRUE,
1221 NULL);
1222 }
1223
1224 static gboolean
1225 gtk_expander_animation_timeout (GtkExpander *expander)
1226 {
1227 GtkExpanderPrivate *priv = expander->priv;
1228 GdkRectangle area;
1229 gboolean finish = FALSE;
1230
1231 GDK_THREADS_ENTER();
1232
1233 if (GTK_WIDGET_REALIZED (expander))
1234 {
1235 get_expander_bounds (expander, &area);
1236 gdk_window_invalidate_rect (GTK_WIDGET (expander)->window, &area, TRUE);
1237 }
1238
1239 if (priv->expanded)
1240 {
1241 if (priv->expander_style == GTK_EXPANDER_COLLAPSED)
1242 {
1243 priv->expander_style = GTK_EXPANDER_SEMI_EXPANDED;
1244 }
1245 else
1246 {
1247 priv->expander_style = GTK_EXPANDER_EXPANDED;
1248 finish = TRUE;
1249 }
1250 }
1251 else
1252 {
1253 if (priv->expander_style == GTK_EXPANDER_EXPANDED)
1254 {
1255 priv->expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
1256 }
1257 else
1258 {
1259 priv->expander_style = GTK_EXPANDER_COLLAPSED;
1260 finish = TRUE;
1261 }
1262 }
1263
1264 if (finish)
1265 {
1266 priv->animation_timeout = 0;
1267 if (GTK_BIN (expander)->child)
1268 gtk_widget_set_child_visible (GTK_BIN (expander)->child, priv->expanded);
1269 gtk_widget_queue_resize (GTK_WIDGET (expander));
1270 }
1271
1272 GDK_THREADS_LEAVE();
1273
1274 return !finish;
1275 }
1276
1277 static void
1278 gtk_expander_start_animation (GtkExpander *expander)
1279 {
1280 GtkExpanderPrivate *priv = expander->priv;
1281
1282 if (priv->animation_timeout)
1283 g_source_remove (priv->animation_timeout);
1284
1285 priv->animation_timeout =
1286 g_timeout_add (50,
1287 (GSourceFunc) gtk_expander_animation_timeout,
1288 expander);
1289 }
1290
1291 /**
1292 * gtk_expander_set_expanded:
1293 * @expander: a #GtkExpander
1294 * @expanded: whether the child widget is revealed
1295 *
1296 * Sets the state of the expander. Set to %TRUE, if you want
1297 * the child widget to be revealed, and %FALSE if you want the
1298 * child widget to be hidden.
1299 *
1300 * Since: 2.4
1301 **/
1302 void
1303 gtk_expander_set_expanded (GtkExpander *expander,
1304 gboolean expanded)
1305 {
1306 GtkExpanderPrivate *priv;
1307
1308 g_return_if_fail (GTK_IS_EXPANDER (expander));
1309
1310 priv = expander->priv;
1311
1312 expanded = expanded != FALSE;
1313
1314 if (priv->expanded != expanded)
1315 {
1316 priv->expanded = expanded;
1317
1318 if (GTK_WIDGET_REALIZED (expander))
1319 {
1320 gtk_expander_start_animation (expander);
1321 }
1322 else
1323 {
1324 priv->expander_style = expanded ? GTK_EXPANDER_EXPANDED :
1325 GTK_EXPANDER_COLLAPSED;
1326
1327 if (GTK_BIN (expander)->child)
1328 {
1329 gtk_widget_set_child_visible (GTK_BIN (expander)->child, priv->expanded);
1330 gtk_widget_queue_resize (GTK_WIDGET (expander));
1331 }
1332 }
1333
1334 g_object_notify (G_OBJECT (expander), "expanded");
1335 }
1336 }
1337
1338 /**
1339 * gtk_expander_get_expanded:
1340 * @expander:a #GtkExpander
1341 *
1342 * Queries a #GtkExpander and returns its current state. Returns %TRUE
1343 * if the child widget is revealed.
1344 *
1345 * See gtk_expander_set_expanded().
1346 *
1347 * Return value: the current state of the expander.
1348 *
1349 * Since: 2.4
1350 **/
1351 gboolean
1352 gtk_expander_get_expanded (GtkExpander *expander)
1353 {
1354 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1355
1356 return expander->priv->expanded;
1357 }
1358
1359 /**
1360 * gtk_expander_set_spacing:
1361 * @expander: a #GtkExpander
1362 * @spacing: distance between the expander and child in pixels.
1363 *
1364 * Sets the spacing field of @expander, which is the number of pixels to
1365 * place between expander and the child.
1366 *
1367 * Since: 2.4
1368 **/
1369 void
1370 gtk_expander_set_spacing (GtkExpander *expander,
1371 gint spacing)
1372 {
1373 g_return_if_fail (GTK_IS_EXPANDER (expander));
1374 g_return_if_fail (spacing >= 0);
1375
1376 if (expander->priv->spacing != spacing)
1377 {
1378 expander->priv->spacing = spacing;
1379
1380 gtk_widget_queue_resize (GTK_WIDGET (expander));
1381
1382 g_object_notify (G_OBJECT (expander), "spacing");
1383 }
1384 }
1385
1386 /**
1387 * gtk_expander_get_spacing:
1388 * @expander: a #GtkExpander
1389 *
1390 * Gets the value set by gtk_expander_set_spacing().
1391 *
1392 * Return value: spacing between the expander and child.
1393 *
1394 * Since: 2.4
1395 **/
1396 gint
1397 gtk_expander_get_spacing (GtkExpander *expander)
1398 {
1399 g_return_val_if_fail (GTK_IS_EXPANDER (expander), 0);
1400
1401 return expander->priv->spacing;
1402 }
1403
1404 /**
1405 * gtk_expander_set_label:
1406 * @expander: a #GtkExpander
1407 * @label: a string
1408 *
1409 * Sets the text of the label of the expander to @label.
1410 *
1411 * This will also clear any previously set labels.
1412 *
1413 * Since: 2.4
1414 **/
1415 void
1416 gtk_expander_set_label (GtkExpander *expander,
1417 const gchar *label)
1418 {
1419 g_return_if_fail (GTK_IS_EXPANDER (expander));
1420
1421 if (!label)
1422 {
1423 gtk_expander_set_label_widget (expander, NULL);
1424 }
1425 else
1426 {
1427 GtkWidget *child;
1428
1429 child = gtk_label_new (label);
1430 gtk_label_set_use_underline (GTK_LABEL (child), expander->priv->use_underline);
1431 gtk_label_set_use_markup (GTK_LABEL (child), expander->priv->use_markup);
1432 gtk_widget_show (child);
1433
1434 gtk_expander_set_label_widget (expander, child);
1435 }
1436
1437 g_object_notify (G_OBJECT (expander), "label");
1438 }
1439
1440 /**
1441 * gtk_expander_get_label:
1442 * @expander: a #GtkExpander
1443 *
1444 * Fetches the text from the label of the expander, as set by
1445 * gtk_expander_set_label(). If the label text has not
1446 * been set the return value will be %NULL. This will be the
1447 * case if you create an empty button with gtk_button_new() to
1448 * use as a container.
1449 *
1450 * Return value: The text of the label widget. This string is owned
1451 * by the widget and must not be modified or freed.
1452 *
1453 * Since: 2.4
1454 **/
1455 G_CONST_RETURN char *
1456 gtk_expander_get_label (GtkExpander *expander)
1457 {
1458 GtkExpanderPrivate *priv;
1459
1460 g_return_val_if_fail (GTK_IS_EXPANDER (expander), NULL);
1461
1462 priv = expander->priv;
1463
1464 if (priv->label_widget && GTK_IS_LABEL (priv->label_widget))
1465 return gtk_label_get_text (GTK_LABEL (priv->label_widget));
1466 else
1467 return NULL;
1468 }
1469
1470 /**
1471 * gtk_expander_set_use_underline:
1472 * @expander: a #GtkExpander
1473 * @use_underline: %TRUE if underlines in the text indicate mnemonics
1474 *
1475 * If true, an underline in the text of the expander label indicates
1476 * the next character should be used for the mnemonic accelerator key.
1477 *
1478 * Since: 2.4
1479 **/
1480 void
1481 gtk_expander_set_use_underline (GtkExpander *expander,
1482 gboolean use_underline)
1483 {
1484 GtkExpanderPrivate *priv;
1485
1486 g_return_if_fail (GTK_IS_EXPANDER (expander));
1487
1488 priv = expander->priv;
1489
1490 use_underline = use_underline != FALSE;
1491
1492 if (priv->use_underline != use_underline)
1493 {
1494 priv->use_underline = use_underline;
1495
1496 if (priv->label_widget && GTK_IS_LABEL (priv->label_widget))
1497 gtk_label_set_use_underline (GTK_LABEL (priv->label_widget), use_underline);
1498
1499 g_object_notify (G_OBJECT (expander), "use-underline");
1500 }
1501 }
1502
1503 /**
1504 * gtk_expander_get_use_underline:
1505 * @expander: a #GtkExpander
1506 *
1507 * Returns whether an embedded underline in the expander label indicates a
1508 * mnemonic. See gtk_expander_set_use_underline().
1509 *
1510 * Return value: %TRUE if an embedded underline in the expander label
1511 * indicates the mnemonic accelerator keys.
1512 *
1513 * Since: 2.4
1514 **/
1515 gboolean
1516 gtk_expander_get_use_underline (GtkExpander *expander)
1517 {
1518 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1519
1520 return expander->priv->use_underline;
1521 }
1522
1523 /**
1524 * gtk_expander_set_use_markup:
1525 * @expander: a #GtkExpander
1526 * @use_markup: %TRUE if the label's text should be parsed for markup
1527 *
1528 * Sets whether the text of the label contains markup in <link
1529 * linkend="PangoMarkupFormat">Pango's text markup
1530 * language</link>. See gtk_label_set_markup().
1531 *
1532 * Since: 2.4
1533 **/
1534 void
1535 gtk_expander_set_use_markup (GtkExpander *expander,
1536 gboolean use_markup)
1537 {
1538 GtkExpanderPrivate *priv;
1539
1540 g_return_if_fail (GTK_IS_EXPANDER (expander));
1541
1542 priv = expander->priv;
1543
1544 use_markup = use_markup != FALSE;
1545
1546 if (priv->use_markup != use_markup)
1547 {
1548 priv->use_markup = use_markup;
1549
1550 if (priv->label_widget && GTK_IS_LABEL (priv->label_widget))
1551 gtk_label_set_use_markup (GTK_LABEL (priv->label_widget), use_markup);
1552
1553 g_object_notify (G_OBJECT (expander), "use-markup");
1554 }
1555 }
1556
1557 /**
1558 * gtk_expander_get_use_markup:
1559 * @expander: a #GtkExpander
1560 *
1561 * Returns whether the label's text is interpreted as marked up with
1562 * the <link linkend="PangoMarkupFormat">Pango text markup
1563 * language</link>. See gtk_expander_set_use_markup ().
1564 *
1565 * Return value: %TRUE if the label's text will be parsed for markup
1566 *
1567 * Since: 2.4
1568 **/
1569 gboolean
1570 gtk_expander_get_use_markup (GtkExpander *expander)
1571 {
1572 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1573
1574 return expander->priv->use_markup;
1575 }
1576
1577 /**
1578 * gtk_expander_set_label_widget:
1579 * @expander: a #GtkExpander
1580 * @label_widget: the new label widget
1581 *
1582 * Set the label widget for the expander. This is the widget
1583 * that will appear embedded alongside the expander arrow.
1584 *
1585 * Since: 2.4
1586 **/
1587 void
1588 gtk_expander_set_label_widget (GtkExpander *expander,
1589 GtkWidget *label_widget)
1590 {
1591 GtkExpanderPrivate *priv;
1592
1593 g_return_if_fail (GTK_IS_EXPANDER (expander));
1594 g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget));
1595 g_return_if_fail (label_widget == NULL || label_widget->parent == NULL);
1596
1597 priv = expander->priv;
1598
1599 if (priv->label_widget == label_widget)
1600 return;
1601
1602 if (priv->label_widget)
1603 {
1604 gtk_widget_set_state (priv->label_widget, GTK_STATE_NORMAL);
1605 gtk_widget_unparent (priv->label_widget);
1606 }
1607
1608 priv->label_widget = label_widget;
1609
1610 if (label_widget)
1611 {
1612 priv->label_widget = label_widget;
1613
1614 gtk_widget_set_parent (label_widget, GTK_WIDGET (expander));
1615
1616 if (priv->prelight)
1617 gtk_widget_set_state (label_widget, GTK_STATE_PRELIGHT);
1618 }
1619
1620 if (GTK_WIDGET_VISIBLE (expander))
1621 gtk_widget_queue_resize (GTK_WIDGET (expander));
1622
1623 g_object_freeze_notify (G_OBJECT (expander));
1624 g_object_notify (G_OBJECT (expander), "label-widget");
1625 g_object_notify (G_OBJECT (expander), "label");
1626 g_object_thaw_notify (G_OBJECT (expander));
1627 }
1628
1629 /**
1630 * gtk_expander_get_label_widget:
1631 * @expander: a #GtkExpander
1632 *
1633 * Retrieves the label widget for the frame. See
1634 * gtk_expander_set_label_widget().
1635 *
1636 * Return value: the label widget, or %NULL if there is none.
1637 *
1638 * Since: 2.4
1639 **/
1640 GtkWidget *
1641 gtk_expander_get_label_widget (GtkExpander *expander)
1642 {
1643 g_return_val_if_fail (GTK_IS_EXPANDER (expander), NULL);
1644
1645 return expander->priv->label_widget;
1646 }
1647
1648 #define __GTK_EXPANDER_C__
1649 #include <gtk/gtkaliasdef.c>
1650
1651 #endif /* Gtk 2.4 */