1 /* GTK - The GIMP Toolkit
3 * Copyright (C) 2003 Sun Microsystems, Inc.
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.
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.
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.
21 * Mark McLoughlin <mark@skynet.ie>
26 * @Short_description: A container which can hide its child
29 * A #GtkExpander allows the user to hide or show its child by clicking
30 * on an expander triangle similar to the triangles used in a #GtkTreeView.
32 * Normally you use an expander as you would use any other descendant
33 * of #GtkBin; you create the child widget and use gtk_container_add()
34 * to add it to the expander. When the expander is toggled, it will take
35 * care of showing and hiding the child automatically.
37 * <refsect2 id="expander-special-usage">
38 * <title>Special Usage</title>
40 * There are situations in which you may prefer to show and hide the
41 * expanded widget yourself, such as when you want to actually create
42 * the widget at expansion time. In this case, create a #GtkExpander
43 * but do not add a child to it. The expander widget has an
44 * #GtkExpander:expanded property which can be used to monitor
45 * its expansion state. You should watch this property with a signal
46 * connection as follows:
49 * <programlisting id="expander-callback-example">
50 * expander = gtk_expander_new_with_mnemonic ("_More Options");
51 * g_signal_connect (expander, "notify::expanded",
52 * G_CALLBACK (expander_callback), NULL);
57 * expander_callback (GObject *object,
58 * GParamSpec *param_spec,
61 * GtkExpander *expander;
63 * expander = GTK_EXPANDER (object);
65 * if (gtk_expander_get_expanded (expander))
67 * /* Show or create widgets */
71 * /* Hide or destroy widgets */
77 * <refsect2 id="GtkExpander-BUILDER-UI">
78 * <title>GtkExpander as GtkBuildable</title>
80 * The GtkExpander implementation of the GtkBuildable interface
81 * supports placing a child in the label position by specifying
82 * "label" as the "type" attribute of a <child> element.
83 * A normal content child can be specified without specifying
84 * a <child> type attribute.
87 * <title>A UI definition fragment with GtkExpander</title>
88 * <programlisting><![CDATA[
89 * <object class="GtkExpander">
90 * <child type="label">
91 * <object class="GtkLabel" id="expander-label"/>
94 * <object class="GtkEntry" id="expander-content"/>
97 * ]]></programlisting>
107 #include "gtkexpander.h"
109 #include "gtklabel.h"
110 #include "gtkbuildable.h"
111 #include "gtkcontainer.h"
112 #include "gtkmarshalers.h"
115 #include "gtkprivate.h"
119 #define DEFAULT_EXPANDER_SIZE 10
120 #define DEFAULT_EXPANDER_SPACING 2
135 struct _GtkExpanderPrivate
137 GtkWidget *label_widget;
138 GdkWindow *event_window;
144 guint use_underline : 1;
145 guint use_markup : 1;
146 guint button_down : 1;
148 guint label_fill : 1;
149 guint resize_toplevel : 1;
152 static void gtk_expander_set_property (GObject *object,
156 static void gtk_expander_get_property (GObject *object,
161 static void gtk_expander_destroy (GtkWidget *widget);
162 static void gtk_expander_realize (GtkWidget *widget);
163 static void gtk_expander_unrealize (GtkWidget *widget);
164 static void gtk_expander_size_allocate (GtkWidget *widget,
165 GtkAllocation *allocation);
166 static void gtk_expander_map (GtkWidget *widget);
167 static void gtk_expander_unmap (GtkWidget *widget);
168 static gboolean gtk_expander_draw (GtkWidget *widget,
170 static gboolean gtk_expander_button_press (GtkWidget *widget,
171 GdkEventButton *event);
172 static gboolean gtk_expander_button_release (GtkWidget *widget,
173 GdkEventButton *event);
174 static gboolean gtk_expander_enter_notify (GtkWidget *widget,
175 GdkEventCrossing *event);
176 static gboolean gtk_expander_leave_notify (GtkWidget *widget,
177 GdkEventCrossing *event);
178 static gboolean gtk_expander_focus (GtkWidget *widget,
179 GtkDirectionType direction);
180 static void gtk_expander_grab_notify (GtkWidget *widget,
181 gboolean was_grabbed);
182 static void gtk_expander_state_flags_changed (GtkWidget *widget,
183 GtkStateFlags previous_state);
184 static gboolean gtk_expander_drag_motion (GtkWidget *widget,
185 GdkDragContext *context,
189 static void gtk_expander_drag_leave (GtkWidget *widget,
190 GdkDragContext *context,
193 static void gtk_expander_add (GtkContainer *container,
195 static void gtk_expander_remove (GtkContainer *container,
197 static void gtk_expander_forall (GtkContainer *container,
198 gboolean include_internals,
199 GtkCallback callback,
200 gpointer callback_data);
202 static void gtk_expander_activate (GtkExpander *expander);
204 static void get_expander_bounds (GtkExpander *expander,
208 static void gtk_expander_buildable_init (GtkBuildableIface *iface);
209 static void gtk_expander_buildable_add_child (GtkBuildable *buildable,
216 static void gtk_expander_get_preferred_width (GtkWidget *widget,
219 static void gtk_expander_get_preferred_height (GtkWidget *widget,
222 static void gtk_expander_get_preferred_height_for_width (GtkWidget *layout,
224 gint *minimum_height,
225 gint *natural_height);
226 static void gtk_expander_get_preferred_width_for_height (GtkWidget *layout,
228 gint *minimum_height,
229 gint *natural_height);
231 G_DEFINE_TYPE_WITH_CODE (GtkExpander, gtk_expander, GTK_TYPE_BIN,
232 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
233 gtk_expander_buildable_init))
236 gtk_expander_class_init (GtkExpanderClass *klass)
238 GObjectClass *gobject_class;
239 GtkWidgetClass *widget_class;
240 GtkContainerClass *container_class;
242 gobject_class = (GObjectClass *) klass;
243 widget_class = (GtkWidgetClass *) klass;
244 container_class = (GtkContainerClass *) klass;
246 gobject_class->set_property = gtk_expander_set_property;
247 gobject_class->get_property = gtk_expander_get_property;
249 widget_class->destroy = gtk_expander_destroy;
250 widget_class->realize = gtk_expander_realize;
251 widget_class->unrealize = gtk_expander_unrealize;
252 widget_class->size_allocate = gtk_expander_size_allocate;
253 widget_class->map = gtk_expander_map;
254 widget_class->unmap = gtk_expander_unmap;
255 widget_class->draw = gtk_expander_draw;
256 widget_class->button_press_event = gtk_expander_button_press;
257 widget_class->button_release_event = gtk_expander_button_release;
258 widget_class->enter_notify_event = gtk_expander_enter_notify;
259 widget_class->leave_notify_event = gtk_expander_leave_notify;
260 widget_class->focus = gtk_expander_focus;
261 widget_class->grab_notify = gtk_expander_grab_notify;
262 widget_class->state_flags_changed = gtk_expander_state_flags_changed;
263 widget_class->drag_motion = gtk_expander_drag_motion;
264 widget_class->drag_leave = gtk_expander_drag_leave;
265 widget_class->get_preferred_width = gtk_expander_get_preferred_width;
266 widget_class->get_preferred_height = gtk_expander_get_preferred_height;
267 widget_class->get_preferred_height_for_width = gtk_expander_get_preferred_height_for_width;
268 widget_class->get_preferred_width_for_height = gtk_expander_get_preferred_width_for_height;
270 container_class->add = gtk_expander_add;
271 container_class->remove = gtk_expander_remove;
272 container_class->forall = gtk_expander_forall;
274 klass->activate = gtk_expander_activate;
276 g_type_class_add_private (klass, sizeof (GtkExpanderPrivate));
278 g_object_class_install_property (gobject_class,
280 g_param_spec_boolean ("expanded",
282 P_("Whether the expander has been opened to reveal the child widget"),
284 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
286 g_object_class_install_property (gobject_class,
288 g_param_spec_string ("label",
290 P_("Text of the expander's label"),
292 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
294 g_object_class_install_property (gobject_class,
296 g_param_spec_boolean ("use-underline",
298 P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
300 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
302 g_object_class_install_property (gobject_class,
304 g_param_spec_boolean ("use-markup",
306 P_("The text of the label includes XML markup. See pango_parse_markup()"),
308 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
310 g_object_class_install_property (gobject_class,
312 g_param_spec_int ("spacing",
314 P_("Space to put between the label and the child"),
318 GTK_PARAM_READWRITE));
320 g_object_class_install_property (gobject_class,
322 g_param_spec_object ("label-widget",
324 P_("A widget to display in place of the usual expander label"),
326 GTK_PARAM_READWRITE));
328 g_object_class_install_property (gobject_class,
330 g_param_spec_boolean ("label-fill",
332 P_("Whether the label widget should fill all available horizontal space"),
334 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
337 * GtkExpander:resize-toplevel:
339 * When this property is %TRUE, the expander will resize the toplevel
340 * widget containing the expander upon expanding and collapsing.
344 g_object_class_install_property (gobject_class,
345 PROP_RESIZE_TOPLEVEL,
346 g_param_spec_boolean ("resize-toplevel",
347 P_("Resize tolevel"),
348 P_("Whether the expander will resize the toplevel window upon expanding and collapsing"),
350 GTK_PARAM_READWRITE));
352 gtk_widget_class_install_style_property (widget_class,
353 g_param_spec_int ("expander-size",
355 P_("Size of the expander arrow"),
358 DEFAULT_EXPANDER_SIZE,
359 GTK_PARAM_READABLE));
361 gtk_widget_class_install_style_property (widget_class,
362 g_param_spec_int ("expander-spacing",
363 P_("Indicator Spacing"),
364 P_("Spacing around expander arrow"),
367 DEFAULT_EXPANDER_SPACING,
368 GTK_PARAM_READABLE));
370 widget_class->activate_signal =
371 g_signal_new (I_("activate"),
372 G_TYPE_FROM_CLASS (gobject_class),
373 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
374 G_STRUCT_OFFSET (GtkExpanderClass, activate),
376 _gtk_marshal_VOID__VOID,
381 gtk_expander_init (GtkExpander *expander)
383 GtkExpanderPrivate *priv;
385 expander->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (expander,
389 gtk_widget_set_can_focus (GTK_WIDGET (expander), TRUE);
390 gtk_widget_set_has_window (GTK_WIDGET (expander), FALSE);
392 priv->label_widget = NULL;
393 priv->event_window = NULL;
396 priv->expanded = FALSE;
397 priv->use_underline = FALSE;
398 priv->use_markup = FALSE;
399 priv->button_down = FALSE;
400 priv->prelight = FALSE;
401 priv->label_fill = FALSE;
402 priv->expand_timer = 0;
403 priv->resize_toplevel = 0;
405 gtk_drag_dest_set (GTK_WIDGET (expander), 0, NULL, 0, 0);
406 gtk_drag_dest_set_track_motion (GTK_WIDGET (expander), TRUE);
410 gtk_expander_buildable_add_child (GtkBuildable *buildable,
416 gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child));
417 else if (strcmp (type, "label") == 0)
418 gtk_expander_set_label_widget (GTK_EXPANDER (buildable), GTK_WIDGET (child));
420 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (GTK_EXPANDER (buildable), type);
424 gtk_expander_buildable_init (GtkBuildableIface *iface)
426 iface->add_child = gtk_expander_buildable_add_child;
430 gtk_expander_set_property (GObject *object,
435 GtkExpander *expander = GTK_EXPANDER (object);
440 gtk_expander_set_expanded (expander, g_value_get_boolean (value));
443 gtk_expander_set_label (expander, g_value_get_string (value));
445 case PROP_USE_UNDERLINE:
446 gtk_expander_set_use_underline (expander, g_value_get_boolean (value));
448 case PROP_USE_MARKUP:
449 gtk_expander_set_use_markup (expander, g_value_get_boolean (value));
452 gtk_expander_set_spacing (expander, g_value_get_int (value));
454 case PROP_LABEL_WIDGET:
455 gtk_expander_set_label_widget (expander, g_value_get_object (value));
457 case PROP_LABEL_FILL:
458 gtk_expander_set_label_fill (expander, g_value_get_boolean (value));
460 case PROP_RESIZE_TOPLEVEL:
461 gtk_expander_set_resize_toplevel (expander, g_value_get_boolean (value));
464 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
470 gtk_expander_get_property (GObject *object,
475 GtkExpander *expander = GTK_EXPANDER (object);
476 GtkExpanderPrivate *priv = expander->priv;
481 g_value_set_boolean (value, priv->expanded);
484 g_value_set_string (value, gtk_expander_get_label (expander));
486 case PROP_USE_UNDERLINE:
487 g_value_set_boolean (value, priv->use_underline);
489 case PROP_USE_MARKUP:
490 g_value_set_boolean (value, priv->use_markup);
493 g_value_set_int (value, priv->spacing);
495 case PROP_LABEL_WIDGET:
496 g_value_set_object (value,
498 G_OBJECT (priv->label_widget) : NULL);
500 case PROP_LABEL_FILL:
501 g_value_set_boolean (value, priv->label_fill);
503 case PROP_RESIZE_TOPLEVEL:
504 g_value_set_boolean (value, gtk_expander_get_resize_toplevel (expander));
507 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
513 gtk_expander_destroy (GtkWidget *widget)
515 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
517 if (priv->expand_timer)
519 g_source_remove (priv->expand_timer);
520 priv->expand_timer = 0;
523 GTK_WIDGET_CLASS (gtk_expander_parent_class)->destroy (widget);
527 gtk_expander_realize (GtkWidget *widget)
529 GtkAllocation allocation;
530 GtkExpanderPrivate *priv;
532 GdkWindowAttr attributes;
533 gint attributes_mask;
535 GdkRectangle expander_rect;
538 priv = GTK_EXPANDER (widget)->priv;
540 gtk_widget_set_realized (widget, TRUE);
542 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
544 get_expander_bounds (GTK_EXPANDER (widget), &expander_rect);
546 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
548 GtkRequisition label_requisition;
550 gtk_widget_get_preferred_size (priv->label_widget,
551 &label_requisition, NULL);
552 label_height = label_requisition.height;
557 gtk_widget_get_allocation (widget, &allocation);
559 attributes.window_type = GDK_WINDOW_CHILD;
560 attributes.x = allocation.x + border_width;
561 attributes.y = allocation.y + border_width;
562 attributes.width = MAX (allocation.width - 2 * border_width, 1);
563 attributes.height = MAX (expander_rect.height, label_height - 2 * border_width);
564 attributes.wclass = GDK_INPUT_ONLY;
565 attributes.event_mask = gtk_widget_get_events (widget)
566 | GDK_BUTTON_PRESS_MASK
567 | GDK_BUTTON_RELEASE_MASK
568 | GDK_ENTER_NOTIFY_MASK
569 | GDK_LEAVE_NOTIFY_MASK;
571 attributes_mask = GDK_WA_X | GDK_WA_Y;
573 window = gtk_widget_get_parent_window (widget);
574 gtk_widget_set_window (widget, window);
575 g_object_ref (window);
577 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
578 &attributes, attributes_mask);
579 gdk_window_set_user_data (priv->event_window, widget);
583 gtk_expander_unrealize (GtkWidget *widget)
585 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
587 if (priv->event_window)
589 gdk_window_set_user_data (priv->event_window, NULL);
590 gdk_window_destroy (priv->event_window);
591 priv->event_window = NULL;
594 GTK_WIDGET_CLASS (gtk_expander_parent_class)->unrealize (widget);
598 get_expander_bounds (GtkExpander *expander,
601 GtkAllocation allocation;
603 GtkExpanderPrivate *priv;
606 gint expander_spacing;
607 gboolean interior_focus;
612 widget = GTK_WIDGET (expander);
613 priv = expander->priv;
615 gtk_widget_get_allocation (widget, &allocation);
617 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
619 gtk_widget_style_get (widget,
620 "interior-focus", &interior_focus,
621 "focus-line-width", &focus_width,
622 "focus-padding", &focus_pad,
623 "expander-size", &expander_size,
624 "expander-spacing", &expander_spacing,
627 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
629 rect->x = allocation.x + border_width;
630 rect->y = allocation.y + border_width;
633 rect->x += expander_spacing;
635 rect->x += allocation.width - 2 * border_width -
636 expander_spacing - expander_size;
638 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
640 GtkAllocation label_allocation;
642 gtk_widget_get_allocation (priv->label_widget, &label_allocation);
644 if (expander_size < label_allocation.height)
645 rect->y += focus_width + focus_pad + (label_allocation.height - expander_size) / 2;
647 rect->y += expander_spacing;
651 rect->y += expander_spacing;
657 rect->x += focus_width + focus_pad;
659 rect->x -= focus_width + focus_pad;
660 rect->y += focus_width + focus_pad;
663 rect->width = rect->height = expander_size;
667 gtk_expander_size_allocate (GtkWidget *widget,
668 GtkAllocation *allocation)
670 GtkExpander *expander;
672 GtkExpanderPrivate *priv;
673 gboolean child_visible = FALSE;
676 gint expander_spacing;
677 gboolean interior_focus;
680 gint label_height, top_min_height;
681 gint label_xpad, label_xoffset;
682 gint child_ypad, child_yoffset;
684 expander = GTK_EXPANDER (widget);
685 child = gtk_bin_get_child (GTK_BIN (widget));
686 priv = expander->priv;
688 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
690 gtk_widget_set_allocation (widget, allocation);
692 gtk_widget_style_get (widget,
693 "interior-focus", &interior_focus,
694 "focus-line-width", &focus_width,
695 "focus-padding", &focus_pad,
696 "expander-size", &expander_size,
697 "expander-spacing", &expander_spacing,
701 /* Calculate some offsets/padding first */
702 label_xoffset = border_width + expander_size + focus_width + 2 * expander_spacing + focus_pad;
703 label_xpad = 2 * border_width + expander_size + 2 * focus_width + 2 * expander_spacing + 2 * focus_pad;
705 child_yoffset = border_width + priv->spacing + (interior_focus ? 0 : 2 * focus_width + 2 * focus_pad);
706 child_ypad = 2 * border_width + priv->spacing + (interior_focus ? 0 : 2 * focus_width + 2 * focus_pad);
707 top_min_height = 2 * expander_spacing + expander_size;
709 child_visible = (child && gtk_widget_get_child_visible (child));
711 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
713 GtkAllocation label_allocation;
714 gint natural_label_width;
717 gtk_widget_get_preferred_width (priv->label_widget, NULL, &natural_label_width);
719 if (priv->label_fill)
720 label_allocation.width = allocation->width - label_xpad;
722 label_allocation.width = MIN (natural_label_width, allocation->width - label_xpad);
723 label_allocation.width = MAX (label_allocation.width, 1);
725 /* We distribute the minimum height to the label widget and prioritize
726 * the child widget giving it the remaining height
728 gtk_widget_get_preferred_height_for_width (priv->label_widget,
729 label_allocation.width, &label_height, NULL);
731 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
733 if (priv->label_fill)
734 label_allocation.x = allocation->x + label_xoffset;
736 label_allocation.x = allocation->x + label_xoffset;
738 label_allocation.x = allocation->x + allocation->width -
739 (label_allocation.width + label_xoffset);
741 label_allocation.y = allocation->y + border_width + focus_width + focus_pad;
742 label_allocation.height = MIN (label_height,
743 allocation->height - 2 * border_width -
744 2 * focus_width - 2 * focus_pad -
745 (child_visible ? priv->spacing : 0));
746 label_allocation.height = MAX (label_allocation.height, 1);
748 gtk_widget_size_allocate (priv->label_widget, &label_allocation);
750 label_height = label_allocation.height;
757 if (gtk_widget_get_realized (widget))
761 get_expander_bounds (expander, &rect);
763 gdk_window_move_resize (priv->event_window,
764 allocation->x + border_width,
765 allocation->y + border_width,
766 MAX (allocation->width - 2 * border_width, 1),
767 MAX (rect.height, label_height - 2 * border_width));
772 GtkAllocation child_allocation;
775 top_height = MAX (top_min_height,
776 label_height + (interior_focus ? 2 * focus_width + 2 * focus_pad : 0));
778 child_allocation.x = allocation->x + border_width;
779 child_allocation.y = allocation->y + top_height + child_yoffset;
781 child_allocation.width = MAX (allocation->width - 2 * border_width, 1);
782 child_allocation.height = allocation->height - top_height - child_ypad;
783 child_allocation.height = MAX (child_allocation.height, 1);
785 gtk_widget_size_allocate (child, &child_allocation);
790 gtk_expander_map (GtkWidget *widget)
792 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
794 if (priv->label_widget)
795 gtk_widget_map (priv->label_widget);
797 GTK_WIDGET_CLASS (gtk_expander_parent_class)->map (widget);
799 if (priv->event_window)
800 gdk_window_show (priv->event_window);
804 gtk_expander_unmap (GtkWidget *widget)
806 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
808 if (priv->event_window)
809 gdk_window_hide (priv->event_window);
811 GTK_WIDGET_CLASS (gtk_expander_parent_class)->unmap (widget);
813 if (priv->label_widget)
814 gtk_widget_unmap (priv->label_widget);
818 gtk_expander_paint_prelight (GtkExpander *expander,
821 GtkAllocation allocation;
823 GtkContainer *container;
824 GtkExpanderPrivate *priv;
826 GtkStyleContext *context;
827 gboolean interior_focus;
831 int expander_spacing;
834 priv = expander->priv;
835 widget = GTK_WIDGET (expander);
836 container = GTK_CONTAINER (expander);
838 gtk_widget_style_get (widget,
839 "interior-focus", &interior_focus,
840 "focus-line-width", &focus_width,
841 "focus-padding", &focus_pad,
842 "expander-size", &expander_size,
843 "expander-spacing", &expander_spacing,
846 gtk_widget_get_allocation (widget, &allocation);
848 border_width = gtk_container_get_border_width (container);
849 area.x = border_width;
850 area.y = border_width;
851 area.width = allocation.width - (2 * border_width);
853 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
855 GtkAllocation label_widget_allocation;
857 gtk_widget_get_allocation (priv->label_widget, &label_widget_allocation);
858 area.height = label_widget_allocation.height;
863 area.height += interior_focus ? (focus_width + focus_pad) * 2 : 0;
864 area.height = MAX (area.height, expander_size + 2 * expander_spacing);
865 area.height += !interior_focus ? (focus_width + focus_pad) * 2 : 0;
867 context = gtk_widget_get_style_context (widget);
868 gtk_render_background (context, cr,
870 area.width, area.height);
874 gtk_expander_paint (GtkExpander *expander,
877 GtkExpanderPrivate *priv = expander->priv;
880 GtkAllocation allocation;
881 GtkStyleContext *context;
882 GtkStateFlags state = 0;
885 widget = GTK_WIDGET (expander);
886 context = gtk_widget_get_style_context (widget);
888 get_expander_bounds (expander, &clip);
889 gtk_widget_get_allocation (widget, &allocation);
891 gtk_style_context_save (context);
893 if (expander->priv->prelight)
895 state = GTK_STATE_FLAG_PRELIGHT;
896 gtk_style_context_set_state (context, state);
897 gtk_expander_paint_prelight (expander, cr);
900 gtk_widget_style_get (widget, "expander-size", &size, NULL);
902 state = gtk_style_context_get_state (context);
904 /* Set active flag as per the expanded state */
906 state |= GTK_STATE_FLAG_ACTIVE;
908 gtk_style_context_set_state (context, state);
909 gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
911 /* The expander is the only animatable region */
912 gtk_style_context_push_animatable_region (context, GUINT_TO_POINTER (1));
914 gtk_render_expander (context, cr,
915 clip.x - allocation.x,
916 clip.y - allocation.y,
919 gtk_style_context_pop_animatable_region (context);
920 gtk_style_context_restore (context);
924 gtk_expander_paint_focus (GtkExpander *expander,
928 GtkExpanderPrivate *priv;
930 GtkStyleContext *context;
931 gint x, y, width, height;
932 gboolean interior_focus;
937 gint expander_spacing;
939 GtkAllocation allocation;
941 widget = GTK_WIDGET (expander);
942 priv = expander->priv;
944 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
945 gtk_widget_get_allocation (widget, &allocation);
947 gtk_widget_style_get (widget,
948 "interior-focus", &interior_focus,
949 "focus-line-width", &focus_width,
950 "focus-padding", &focus_pad,
951 "expander-size", &expander_size,
952 "expander-spacing", &expander_spacing,
955 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
959 if (priv->label_widget)
961 if (gtk_widget_get_visible (priv->label_widget))
963 GtkAllocation label_allocation;
965 gtk_widget_get_allocation (priv->label_widget, &label_allocation);
966 width = label_allocation.width;
967 height = label_allocation.height;
970 width += 2 * focus_pad + 2 * focus_width;
971 height += 2 * focus_pad + 2 * focus_width;
979 x += expander_spacing * 2 + expander_size;
983 x += allocation.width - 2 * border_width
984 - expander_spacing * 2 - expander_size - width;
989 width += expander_size + 2 * expander_spacing;
990 height = MAX (height, expander_size + 2 * expander_spacing);
995 get_expander_bounds (expander, &rect);
997 x = rect.x - allocation.x - focus_pad;
998 y = rect.y - allocation.y - focus_pad;
999 width = rect.width + 2 * focus_pad;
1000 height = rect.height + 2 * focus_pad;
1003 context = gtk_widget_get_style_context (widget);
1004 gtk_render_focus (context, cr,
1005 x, y, width, height);
1009 gtk_expander_draw (GtkWidget *widget,
1012 GtkExpander *expander = GTK_EXPANDER (widget);
1014 gtk_expander_paint (expander, cr);
1016 if (gtk_widget_has_focus (widget))
1017 gtk_expander_paint_focus (expander, cr);
1019 GTK_WIDGET_CLASS (gtk_expander_parent_class)->draw (widget, cr);
1025 gtk_expander_button_press (GtkWidget *widget,
1026 GdkEventButton *event)
1028 GtkExpander *expander = GTK_EXPANDER (widget);
1030 if (event->button == 1 && event->window == expander->priv->event_window)
1032 expander->priv->button_down = TRUE;
1040 gtk_expander_button_release (GtkWidget *widget,
1041 GdkEventButton *event)
1043 GtkExpander *expander = GTK_EXPANDER (widget);
1045 if (event->button == 1 && expander->priv->button_down)
1047 gtk_widget_activate (widget);
1048 expander->priv->button_down = FALSE;
1056 gtk_expander_grab_notify (GtkWidget *widget,
1057 gboolean was_grabbed)
1060 GTK_EXPANDER (widget)->priv->button_down = FALSE;
1064 gtk_expander_state_flags_changed (GtkWidget *widget,
1065 GtkStateFlags previous_state)
1067 if (!gtk_widget_is_sensitive (widget))
1068 GTK_EXPANDER (widget)->priv->button_down = FALSE;
1072 gtk_expander_redraw_expander (GtkExpander *expander)
1074 GtkAllocation allocation;
1075 GtkWidget *widget = GTK_WIDGET (expander);
1077 if (gtk_widget_get_realized (widget))
1079 gtk_widget_get_allocation (widget, &allocation);
1080 gdk_window_invalidate_rect (gtk_widget_get_window (widget), &allocation, FALSE);
1085 gtk_expander_enter_notify (GtkWidget *widget,
1086 GdkEventCrossing *event)
1088 GtkExpander *expander = GTK_EXPANDER (widget);
1090 if (event->window == expander->priv->event_window &&
1091 event->detail != GDK_NOTIFY_INFERIOR)
1093 expander->priv->prelight = TRUE;
1095 if (expander->priv->label_widget)
1096 gtk_widget_set_state_flags (expander->priv->label_widget,
1097 GTK_STATE_FLAG_PRELIGHT,
1100 gtk_expander_redraw_expander (expander);
1107 gtk_expander_leave_notify (GtkWidget *widget,
1108 GdkEventCrossing *event)
1110 GtkExpander *expander = GTK_EXPANDER (widget);
1112 if (event->window == expander->priv->event_window &&
1113 event->detail != GDK_NOTIFY_INFERIOR)
1115 expander->priv->prelight = FALSE;
1117 if (expander->priv->label_widget)
1118 gtk_widget_unset_state_flags (expander->priv->label_widget,
1119 GTK_STATE_FLAG_PRELIGHT);
1121 gtk_expander_redraw_expander (expander);
1128 expand_timeout (gpointer data)
1130 GtkExpander *expander = GTK_EXPANDER (data);
1131 GtkExpanderPrivate *priv = expander->priv;
1133 priv->expand_timer = 0;
1134 gtk_expander_set_expanded (expander, TRUE);
1140 gtk_expander_drag_motion (GtkWidget *widget,
1141 GdkDragContext *context,
1146 GtkExpander *expander = GTK_EXPANDER (widget);
1147 GtkExpanderPrivate *priv = expander->priv;
1149 if (!priv->expanded && !priv->expand_timer)
1151 GtkSettings *settings;
1154 settings = gtk_widget_get_settings (widget);
1155 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
1157 priv->expand_timer = gdk_threads_add_timeout (timeout, (GSourceFunc) expand_timeout, expander);
1164 gtk_expander_drag_leave (GtkWidget *widget,
1165 GdkDragContext *context,
1168 GtkExpander *expander = GTK_EXPANDER (widget);
1169 GtkExpanderPrivate *priv = expander->priv;
1171 if (priv->expand_timer)
1173 g_source_remove (priv->expand_timer);
1174 priv->expand_timer = 0;
1187 focus_current_site (GtkExpander *expander,
1188 GtkDirectionType direction)
1190 GtkWidget *current_focus;
1192 current_focus = gtk_container_get_focus_child (GTK_CONTAINER (expander));
1197 return gtk_widget_child_focus (current_focus, direction);
1201 focus_in_site (GtkExpander *expander,
1203 GtkDirectionType direction)
1208 gtk_widget_grab_focus (GTK_WIDGET (expander));
1211 if (expander->priv->label_widget)
1212 return gtk_widget_child_focus (expander->priv->label_widget, direction);
1217 GtkWidget *child = gtk_bin_get_child (GTK_BIN (expander));
1219 if (child && gtk_widget_get_child_visible (child))
1220 return gtk_widget_child_focus (child, direction);
1228 g_assert_not_reached ();
1233 get_next_site (GtkExpander *expander,
1235 GtkDirectionType direction)
1239 ltr = gtk_widget_get_direction (GTK_WIDGET (expander)) != GTK_TEXT_DIR_RTL;
1246 case GTK_DIR_TAB_BACKWARD:
1250 case GTK_DIR_TAB_FORWARD:
1253 return FOCUS_WIDGET;
1258 case GTK_DIR_TAB_BACKWARD:
1262 return ltr ? FOCUS_NONE : FOCUS_LABEL;
1263 case GTK_DIR_TAB_FORWARD:
1267 return ltr ? FOCUS_LABEL : FOCUS_NONE;
1273 case GTK_DIR_TAB_BACKWARD:
1275 return FOCUS_WIDGET;
1277 return ltr ? FOCUS_WIDGET : FOCUS_CHILD;
1278 case GTK_DIR_TAB_FORWARD:
1282 return ltr ? FOCUS_CHILD : FOCUS_WIDGET;
1288 case GTK_DIR_TAB_BACKWARD:
1292 case GTK_DIR_TAB_FORWARD:
1299 g_assert_not_reached ();
1304 gtk_expander_resize_toplevel (GtkExpander *expander)
1306 GtkExpanderPrivate *priv = expander->priv;
1307 GtkWidget *child = gtk_bin_get_child (GTK_BIN (expander));
1309 if (child && priv->resize_toplevel &&
1310 gtk_widget_get_realized (GTK_WIDGET (expander)))
1312 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (expander));
1314 if (toplevel && gtk_widget_get_realized (toplevel))
1316 GtkAllocation toplevel_allocation;
1318 gtk_widget_get_allocation (toplevel, &toplevel_allocation);
1322 GtkRequisition child_requisition;
1324 gtk_widget_get_preferred_size (child, &child_requisition, NULL);
1326 toplevel_allocation.height += child_requisition.height;
1330 GtkAllocation child_allocation;
1332 gtk_widget_get_allocation (child, &child_allocation);
1334 toplevel_allocation.height -= child_allocation.height;
1337 gtk_window_resize (GTK_WINDOW (toplevel),
1338 toplevel_allocation.width,
1339 toplevel_allocation.height);
1345 gtk_expander_focus (GtkWidget *widget,
1346 GtkDirectionType direction)
1348 GtkExpander *expander = GTK_EXPANDER (widget);
1350 if (!focus_current_site (expander, direction))
1352 GtkWidget *old_focus_child;
1353 gboolean widget_is_focus;
1354 FocusSite site = FOCUS_NONE;
1356 widget_is_focus = gtk_widget_is_focus (widget);
1357 old_focus_child = gtk_container_get_focus_child (GTK_CONTAINER (widget));
1359 if (old_focus_child && old_focus_child == expander->priv->label_widget)
1361 else if (old_focus_child)
1363 else if (widget_is_focus)
1364 site = FOCUS_WIDGET;
1366 while ((site = get_next_site (expander, site, direction)) != FOCUS_NONE)
1368 if (focus_in_site (expander, site, direction))
1379 gtk_expander_add (GtkContainer *container,
1382 GTK_CONTAINER_CLASS (gtk_expander_parent_class)->add (container, widget);
1384 gtk_widget_set_child_visible (widget, GTK_EXPANDER (container)->priv->expanded);
1385 gtk_widget_queue_resize (GTK_WIDGET (container));
1389 gtk_expander_remove (GtkContainer *container,
1392 GtkExpander *expander = GTK_EXPANDER (container);
1394 if (GTK_EXPANDER (expander)->priv->label_widget == widget)
1395 gtk_expander_set_label_widget (expander, NULL);
1397 GTK_CONTAINER_CLASS (gtk_expander_parent_class)->remove (container, widget);
1401 gtk_expander_forall (GtkContainer *container,
1402 gboolean include_internals,
1403 GtkCallback callback,
1404 gpointer callback_data)
1406 GtkBin *bin = GTK_BIN (container);
1407 GtkExpanderPrivate *priv = GTK_EXPANDER (container)->priv;
1410 child = gtk_bin_get_child (bin);
1412 (* callback) (child, callback_data);
1414 if (priv->label_widget)
1415 (* callback) (priv->label_widget, callback_data);
1419 gtk_expander_activate (GtkExpander *expander)
1421 gtk_expander_set_expanded (expander, !expander->priv->expanded);
1426 gtk_expander_get_preferred_width (GtkWidget *widget,
1430 GtkExpander *expander;
1432 GtkExpanderPrivate *priv;
1435 gint expander_spacing;
1436 gboolean interior_focus;
1440 child = gtk_bin_get_child (GTK_BIN (widget));
1441 expander = GTK_EXPANDER (widget);
1442 priv = expander->priv;
1444 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1446 gtk_widget_style_get (GTK_WIDGET (widget),
1447 "interior-focus", &interior_focus,
1448 "focus-line-width", &focus_width,
1449 "focus-padding", &focus_pad,
1450 "expander-size", &expander_size,
1451 "expander-spacing", &expander_spacing,
1454 *minimum_size = *natural_size =
1455 expander_size + 2 * expander_spacing +
1456 2 * focus_width + 2 * focus_pad;
1458 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
1460 gint label_min, label_nat;
1462 gtk_widget_get_preferred_width (priv->label_widget,
1463 &label_min, &label_nat);
1465 *minimum_size += label_min;
1466 *natural_size += label_nat;
1469 if (child && gtk_widget_get_child_visible (child))
1471 gint child_min, child_nat;
1473 gtk_widget_get_preferred_width (child,
1474 &child_min, &child_nat);
1476 *minimum_size = MAX (*minimum_size, child_min);
1477 *natural_size = MAX (*natural_size, child_nat);
1481 *minimum_size += 2 * border_width;
1482 *natural_size += 2 * border_width;
1486 gtk_expander_get_preferred_height (GtkWidget *widget,
1490 GtkExpander *expander;
1492 GtkExpanderPrivate *priv;
1495 gint expander_spacing;
1496 gboolean interior_focus;
1500 child = gtk_bin_get_child (GTK_BIN (widget));
1501 expander = GTK_EXPANDER (widget);
1502 priv = expander->priv;
1504 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1506 gtk_widget_style_get (GTK_WIDGET (widget),
1507 "interior-focus", &interior_focus,
1508 "focus-line-width", &focus_width,
1509 "focus-padding", &focus_pad,
1510 "expander-size", &expander_size,
1511 "expander-spacing", &expander_spacing,
1514 *minimum_size = *natural_size =
1515 interior_focus ? (2 * focus_width + 2 * focus_pad) : 0;
1518 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
1520 gint label_min, label_nat;
1522 gtk_widget_get_preferred_height (priv->label_widget,
1523 &label_min, &label_nat);
1525 *minimum_size += label_min;
1526 *natural_size += label_nat;
1529 *minimum_size = MAX (*minimum_size, expander_size + 2 * expander_spacing);
1530 *natural_size = MAX (*natural_size, *minimum_size);
1532 if (!interior_focus)
1534 gint extra = 2 * focus_width + 2 * focus_pad;
1535 *minimum_size += extra;
1536 *natural_size += extra;
1539 if (child && gtk_widget_get_child_visible (child))
1541 gint child_min, child_nat;
1543 gtk_widget_get_preferred_height (child,
1544 &child_min, &child_nat);
1546 *minimum_size += child_min + priv->spacing;
1547 *natural_size += child_nat + priv->spacing;
1551 *minimum_size += 2 * border_width;
1552 *natural_size += 2 * border_width;
1556 gtk_expander_get_preferred_height_for_width (GtkWidget *widget,
1558 gint *minimum_height,
1559 gint *natural_height)
1561 GtkExpander *expander;
1563 GtkExpanderPrivate *priv;
1566 gint expander_spacing;
1567 gboolean interior_focus;
1572 child = gtk_bin_get_child (GTK_BIN (widget));
1573 expander = GTK_EXPANDER (widget);
1574 priv = expander->priv;
1576 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1578 gtk_widget_style_get (GTK_WIDGET (widget),
1579 "interior-focus", &interior_focus,
1580 "focus-line-width", &focus_width,
1581 "focus-padding", &focus_pad,
1582 "expander-size", &expander_size,
1583 "expander-spacing", &expander_spacing,
1586 label_xpad = 2 * border_width + expander_size + 2 * expander_spacing - 2 * focus_width + 2 * focus_pad;
1588 *minimum_height = *natural_height =
1589 interior_focus ? (2 * focus_width + 2 * focus_pad) : 0;
1592 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
1594 gint label_min, label_nat;
1596 gtk_widget_get_preferred_height_for_width (priv->label_widget,
1597 MAX (width - label_xpad, 1),
1598 &label_min, &label_nat);
1600 *minimum_height += label_min;
1601 *natural_height += label_nat;
1604 *minimum_height = MAX (*minimum_height, expander_size + 2 * expander_spacing);
1605 *natural_height = MAX (*natural_height, *minimum_height);
1607 if (!interior_focus)
1609 gint extra = 2 * focus_width + 2 * focus_pad;
1610 *minimum_height += extra;
1611 *natural_height += extra;
1614 if (child && gtk_widget_get_child_visible (child))
1616 gint child_min, child_nat;
1618 gtk_widget_get_preferred_height_for_width (child,
1619 MAX (width - 2 * border_width, 1),
1620 &child_min, &child_nat);
1622 *minimum_height += child_min + priv->spacing;
1623 *natural_height += child_nat + priv->spacing;
1626 *minimum_height += 2 * border_width;
1627 *natural_height += 2 * border_width;
1631 gtk_expander_get_preferred_width_for_height (GtkWidget *widget,
1633 gint *minimum_width,
1634 gint *natural_width)
1636 GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_width, natural_width);
1643 * @label: the text of the label
1645 * Creates a new expander using @label as the text of the label.
1647 * Return value: a new #GtkExpander widget.
1652 gtk_expander_new (const gchar *label)
1654 return g_object_new (GTK_TYPE_EXPANDER, "label", label, NULL);
1658 * gtk_expander_new_with_mnemonic:
1659 * @label: (allow-none): the text of the label with an underscore
1660 * in front of the mnemonic character
1662 * Creates a new expander using @label as the text of the label.
1663 * If characters in @label are preceded by an underscore, they are underlined.
1664 * If you need a literal underscore character in a label, use '__' (two
1665 * underscores). The first underlined character represents a keyboard
1666 * accelerator called a mnemonic.
1667 * Pressing Alt and that key activates the button.
1669 * Return value: a new #GtkExpander widget.
1674 gtk_expander_new_with_mnemonic (const gchar *label)
1676 return g_object_new (GTK_TYPE_EXPANDER,
1678 "use-underline", TRUE,
1683 * gtk_expander_set_expanded:
1684 * @expander: a #GtkExpander
1685 * @expanded: whether the child widget is revealed
1687 * Sets the state of the expander. Set to %TRUE, if you want
1688 * the child widget to be revealed, and %FALSE if you want the
1689 * child widget to be hidden.
1694 gtk_expander_set_expanded (GtkExpander *expander,
1697 GtkExpanderPrivate *priv;
1700 g_return_if_fail (GTK_IS_EXPANDER (expander));
1702 priv = expander->priv;
1704 expanded = expanded != FALSE;
1706 if (priv->expanded != expanded)
1708 GtkWidget *widget = GTK_WIDGET (expander);
1709 GtkSettings *settings = gtk_widget_get_settings (widget);
1710 GtkStyleContext *context;
1711 gboolean enable_animations;
1713 context = gtk_widget_get_style_context (widget);
1714 priv->expanded = expanded;
1716 g_object_get (settings, "gtk-enable-animations", &enable_animations, NULL);
1718 if (enable_animations && gtk_widget_get_realized (widget))
1720 gtk_style_context_save (context);
1721 gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
1723 gtk_style_context_notify_state_change (context,
1724 gtk_widget_get_window (widget),
1725 GUINT_TO_POINTER (1),
1728 gtk_style_context_restore (context);
1731 child = gtk_bin_get_child (GTK_BIN (expander));
1735 gtk_widget_set_child_visible (child, priv->expanded);
1736 gtk_widget_queue_resize (widget);
1737 gtk_expander_resize_toplevel (expander);
1740 g_object_notify (G_OBJECT (expander), "expanded");
1745 * gtk_expander_get_expanded:
1746 * @expander:a #GtkExpander
1748 * Queries a #GtkExpander and returns its current state. Returns %TRUE
1749 * if the child widget is revealed.
1751 * See gtk_expander_set_expanded().
1753 * Return value: the current state of the expander
1758 gtk_expander_get_expanded (GtkExpander *expander)
1760 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1762 return expander->priv->expanded;
1766 * gtk_expander_set_spacing:
1767 * @expander: a #GtkExpander
1768 * @spacing: distance between the expander and child in pixels
1770 * Sets the spacing field of @expander, which is the number of
1771 * pixels to place between expander and the child.
1776 gtk_expander_set_spacing (GtkExpander *expander,
1779 g_return_if_fail (GTK_IS_EXPANDER (expander));
1780 g_return_if_fail (spacing >= 0);
1782 if (expander->priv->spacing != spacing)
1784 expander->priv->spacing = spacing;
1786 gtk_widget_queue_resize (GTK_WIDGET (expander));
1788 g_object_notify (G_OBJECT (expander), "spacing");
1793 * gtk_expander_get_spacing:
1794 * @expander: a #GtkExpander
1796 * Gets the value set by gtk_expander_set_spacing().
1798 * Return value: spacing between the expander and child
1803 gtk_expander_get_spacing (GtkExpander *expander)
1805 g_return_val_if_fail (GTK_IS_EXPANDER (expander), 0);
1807 return expander->priv->spacing;
1811 * gtk_expander_set_label:
1812 * @expander: a #GtkExpander
1813 * @label: (allow-none): a string
1815 * Sets the text of the label of the expander to @label.
1817 * This will also clear any previously set labels.
1822 gtk_expander_set_label (GtkExpander *expander,
1825 g_return_if_fail (GTK_IS_EXPANDER (expander));
1829 gtk_expander_set_label_widget (expander, NULL);
1835 child = gtk_label_new (label);
1836 gtk_label_set_use_underline (GTK_LABEL (child), expander->priv->use_underline);
1837 gtk_label_set_use_markup (GTK_LABEL (child), expander->priv->use_markup);
1838 gtk_widget_show (child);
1840 gtk_expander_set_label_widget (expander, child);
1843 g_object_notify (G_OBJECT (expander), "label");
1847 * gtk_expander_get_label:
1848 * @expander: a #GtkExpander
1850 * Fetches the text from a label widget including any embedded
1851 * underlines indicating mnemonics and Pango markup, as set by
1852 * gtk_expander_set_label(). If the label text has not been set the
1853 * return value will be %NULL. This will be the case if you create an
1854 * empty button with gtk_button_new() to use as a container.
1856 * Note that this function behaved differently in versions prior to
1857 * 2.14 and used to return the label text stripped of embedded
1858 * underlines indicating mnemonics and Pango markup. This problem can
1859 * be avoided by fetching the label text directly from the label
1862 * Return value: The text of the label widget. This string is owned
1863 * by the widget and must not be modified or freed.
1867 G_CONST_RETURN char *
1868 gtk_expander_get_label (GtkExpander *expander)
1870 GtkExpanderPrivate *priv;
1872 g_return_val_if_fail (GTK_IS_EXPANDER (expander), NULL);
1874 priv = expander->priv;
1876 if (GTK_IS_LABEL (priv->label_widget))
1877 return gtk_label_get_label (GTK_LABEL (priv->label_widget));
1883 * gtk_expander_set_use_underline:
1884 * @expander: a #GtkExpander
1885 * @use_underline: %TRUE if underlines in the text indicate mnemonics
1887 * If true, an underline in the text of the expander label indicates
1888 * the next character should be used for the mnemonic accelerator key.
1893 gtk_expander_set_use_underline (GtkExpander *expander,
1894 gboolean use_underline)
1896 GtkExpanderPrivate *priv;
1898 g_return_if_fail (GTK_IS_EXPANDER (expander));
1900 priv = expander->priv;
1902 use_underline = use_underline != FALSE;
1904 if (priv->use_underline != use_underline)
1906 priv->use_underline = use_underline;
1908 if (GTK_IS_LABEL (priv->label_widget))
1909 gtk_label_set_use_underline (GTK_LABEL (priv->label_widget), use_underline);
1911 g_object_notify (G_OBJECT (expander), "use-underline");
1916 * gtk_expander_get_use_underline:
1917 * @expander: a #GtkExpander
1919 * Returns whether an embedded underline in the expander label
1920 * indicates a mnemonic. See gtk_expander_set_use_underline().
1922 * Return value: %TRUE if an embedded underline in the expander
1923 * label indicates the mnemonic accelerator keys
1928 gtk_expander_get_use_underline (GtkExpander *expander)
1930 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1932 return expander->priv->use_underline;
1936 * gtk_expander_set_use_markup:
1937 * @expander: a #GtkExpander
1938 * @use_markup: %TRUE if the label's text should be parsed for markup
1940 * Sets whether the text of the label contains markup in <link
1941 * linkend="PangoMarkupFormat">Pango's text markup
1942 * language</link>. See gtk_label_set_markup().
1947 gtk_expander_set_use_markup (GtkExpander *expander,
1948 gboolean use_markup)
1950 GtkExpanderPrivate *priv;
1952 g_return_if_fail (GTK_IS_EXPANDER (expander));
1954 priv = expander->priv;
1956 use_markup = use_markup != FALSE;
1958 if (priv->use_markup != use_markup)
1960 priv->use_markup = use_markup;
1962 if (GTK_IS_LABEL (priv->label_widget))
1963 gtk_label_set_use_markup (GTK_LABEL (priv->label_widget), use_markup);
1965 g_object_notify (G_OBJECT (expander), "use-markup");
1970 * gtk_expander_get_use_markup:
1971 * @expander: a #GtkExpander
1973 * Returns whether the label's text is interpreted as marked up with
1974 * the <link linkend="PangoMarkupFormat">Pango text markup
1975 * language</link>. See gtk_expander_set_use_markup().
1977 * Return value: %TRUE if the label's text will be parsed for markup
1982 gtk_expander_get_use_markup (GtkExpander *expander)
1984 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1986 return expander->priv->use_markup;
1990 * gtk_expander_set_label_widget:
1991 * @expander: a #GtkExpander
1992 * @label_widget: (allow-none): the new label widget
1994 * Set the label widget for the expander. This is the widget
1995 * that will appear embedded alongside the expander arrow.
2000 gtk_expander_set_label_widget (GtkExpander *expander,
2001 GtkWidget *label_widget)
2003 GtkExpanderPrivate *priv;
2006 g_return_if_fail (GTK_IS_EXPANDER (expander));
2007 g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget));
2008 g_return_if_fail (label_widget == NULL || gtk_widget_get_parent (label_widget) == NULL);
2010 priv = expander->priv;
2012 if (priv->label_widget == label_widget)
2015 if (priv->label_widget)
2017 gtk_widget_set_state_flags (priv->label_widget, 0, TRUE);
2018 gtk_widget_unparent (priv->label_widget);
2021 priv->label_widget = label_widget;
2022 widget = GTK_WIDGET (expander);
2026 priv->label_widget = label_widget;
2028 gtk_widget_set_parent (label_widget, widget);
2031 gtk_widget_set_state_flags (label_widget,
2032 GTK_STATE_FLAG_PRELIGHT,
2036 if (gtk_widget_get_visible (widget))
2037 gtk_widget_queue_resize (widget);
2039 g_object_freeze_notify (G_OBJECT (expander));
2040 g_object_notify (G_OBJECT (expander), "label-widget");
2041 g_object_notify (G_OBJECT (expander), "label");
2042 g_object_thaw_notify (G_OBJECT (expander));
2046 * gtk_expander_get_label_widget:
2047 * @expander: a #GtkExpander
2049 * Retrieves the label widget for the frame. See
2050 * gtk_expander_set_label_widget().
2052 * Return value: (transfer none): the label widget,
2053 * or %NULL if there is none
2058 gtk_expander_get_label_widget (GtkExpander *expander)
2060 g_return_val_if_fail (GTK_IS_EXPANDER (expander), NULL);
2062 return expander->priv->label_widget;
2066 * gtk_expander_set_label_fill:
2067 * @expander: a #GtkExpander
2068 * @label_fill: %TRUE if the label should should fill
2069 * all available horizontal space
2071 * Sets whether the label widget should fill all available
2072 * horizontal space allocated to @expander.
2077 gtk_expander_set_label_fill (GtkExpander *expander,
2078 gboolean label_fill)
2080 GtkExpanderPrivate *priv;
2082 g_return_if_fail (GTK_IS_EXPANDER (expander));
2084 priv = expander->priv;
2086 label_fill = label_fill != FALSE;
2088 if (priv->label_fill != label_fill)
2090 priv->label_fill = label_fill;
2092 if (priv->label_widget != NULL)
2093 gtk_widget_queue_resize (GTK_WIDGET (expander));
2095 g_object_notify (G_OBJECT (expander), "label-fill");
2100 * gtk_expander_get_label_fill:
2101 * @expander: a #GtkExpander
2103 * Returns whether the label widget will fill all available
2104 * horizontal space allocated to @expander.
2106 * Return value: %TRUE if the label widget will fill all
2107 * available horizontal space
2112 gtk_expander_get_label_fill (GtkExpander *expander)
2114 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
2116 return expander->priv->label_fill;
2120 * gtk_expander_set_resize_toplevel:
2121 * @expander: a #GtkExpander
2122 * @resize_toplevel: whether to resize the toplevel
2124 * Sets whether the expander will resize the toplevel widget
2125 * containing the expander upon resizing and collpasing.
2130 gtk_expander_set_resize_toplevel (GtkExpander *expander,
2131 gboolean resize_toplevel)
2133 g_return_if_fail (GTK_IS_EXPANDER (expander));
2135 if (expander->priv->resize_toplevel != resize_toplevel)
2137 expander->priv->resize_toplevel = resize_toplevel ? TRUE : FALSE;
2138 g_object_notify (G_OBJECT (expander), "resize-toplevel");
2143 * gtk_expander_get_resize_toplevel:
2144 * @expander: a #GtkExpander
2146 * Returns whether the expander will resize the toplevel widget
2147 * containing the expander upon resizing and collpasing.
2149 * Return value: the "resize toplevel" setting.
2154 gtk_expander_get_resize_toplevel (GtkExpander *expander)
2156 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
2158 return expander->priv->resize_toplevel;