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"
117 #include "a11y/gtkexpanderaccessible.h"
120 #define DEFAULT_EXPANDER_SIZE 10
121 #define DEFAULT_EXPANDER_SPACING 2
136 struct _GtkExpanderPrivate
138 GtkWidget *label_widget;
139 GdkWindow *event_window;
145 guint use_underline : 1;
146 guint use_markup : 1;
147 guint button_down : 1;
149 guint label_fill : 1;
150 guint resize_toplevel : 1;
153 static void gtk_expander_set_property (GObject *object,
157 static void gtk_expander_get_property (GObject *object,
162 static void gtk_expander_destroy (GtkWidget *widget);
163 static void gtk_expander_realize (GtkWidget *widget);
164 static void gtk_expander_unrealize (GtkWidget *widget);
165 static void gtk_expander_size_allocate (GtkWidget *widget,
166 GtkAllocation *allocation);
167 static void gtk_expander_map (GtkWidget *widget);
168 static void gtk_expander_unmap (GtkWidget *widget);
169 static gboolean gtk_expander_draw (GtkWidget *widget,
171 static gboolean gtk_expander_button_press (GtkWidget *widget,
172 GdkEventButton *event);
173 static gboolean gtk_expander_button_release (GtkWidget *widget,
174 GdkEventButton *event);
175 static gboolean gtk_expander_enter_notify (GtkWidget *widget,
176 GdkEventCrossing *event);
177 static gboolean gtk_expander_leave_notify (GtkWidget *widget,
178 GdkEventCrossing *event);
179 static gboolean gtk_expander_focus (GtkWidget *widget,
180 GtkDirectionType direction);
181 static void gtk_expander_grab_notify (GtkWidget *widget,
182 gboolean was_grabbed);
183 static void gtk_expander_state_flags_changed (GtkWidget *widget,
184 GtkStateFlags previous_state);
185 static gboolean gtk_expander_drag_motion (GtkWidget *widget,
186 GdkDragContext *context,
190 static void gtk_expander_drag_leave (GtkWidget *widget,
191 GdkDragContext *context,
194 static void gtk_expander_add (GtkContainer *container,
196 static void gtk_expander_remove (GtkContainer *container,
198 static void gtk_expander_forall (GtkContainer *container,
199 gboolean include_internals,
200 GtkCallback callback,
201 gpointer callback_data);
203 static void gtk_expander_activate (GtkExpander *expander);
205 static void get_expander_bounds (GtkExpander *expander,
209 static void gtk_expander_buildable_init (GtkBuildableIface *iface);
210 static void gtk_expander_buildable_add_child (GtkBuildable *buildable,
217 static void gtk_expander_get_preferred_width (GtkWidget *widget,
220 static void gtk_expander_get_preferred_height (GtkWidget *widget,
223 static void gtk_expander_get_preferred_height_for_width (GtkWidget *layout,
225 gint *minimum_height,
226 gint *natural_height);
227 static void gtk_expander_get_preferred_width_for_height (GtkWidget *layout,
229 gint *minimum_height,
230 gint *natural_height);
232 G_DEFINE_TYPE_WITH_CODE (GtkExpander, gtk_expander, GTK_TYPE_BIN,
233 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
234 gtk_expander_buildable_init))
237 gtk_expander_class_init (GtkExpanderClass *klass)
239 GObjectClass *gobject_class;
240 GtkWidgetClass *widget_class;
241 GtkContainerClass *container_class;
243 gobject_class = (GObjectClass *) klass;
244 widget_class = (GtkWidgetClass *) klass;
245 container_class = (GtkContainerClass *) klass;
247 gobject_class->set_property = gtk_expander_set_property;
248 gobject_class->get_property = gtk_expander_get_property;
250 widget_class->destroy = gtk_expander_destroy;
251 widget_class->realize = gtk_expander_realize;
252 widget_class->unrealize = gtk_expander_unrealize;
253 widget_class->size_allocate = gtk_expander_size_allocate;
254 widget_class->map = gtk_expander_map;
255 widget_class->unmap = gtk_expander_unmap;
256 widget_class->draw = gtk_expander_draw;
257 widget_class->button_press_event = gtk_expander_button_press;
258 widget_class->button_release_event = gtk_expander_button_release;
259 widget_class->enter_notify_event = gtk_expander_enter_notify;
260 widget_class->leave_notify_event = gtk_expander_leave_notify;
261 widget_class->focus = gtk_expander_focus;
262 widget_class->grab_notify = gtk_expander_grab_notify;
263 widget_class->state_flags_changed = gtk_expander_state_flags_changed;
264 widget_class->drag_motion = gtk_expander_drag_motion;
265 widget_class->drag_leave = gtk_expander_drag_leave;
266 widget_class->get_preferred_width = gtk_expander_get_preferred_width;
267 widget_class->get_preferred_height = gtk_expander_get_preferred_height;
268 widget_class->get_preferred_height_for_width = gtk_expander_get_preferred_height_for_width;
269 widget_class->get_preferred_width_for_height = gtk_expander_get_preferred_width_for_height;
271 container_class->add = gtk_expander_add;
272 container_class->remove = gtk_expander_remove;
273 container_class->forall = gtk_expander_forall;
275 klass->activate = gtk_expander_activate;
277 g_type_class_add_private (klass, sizeof (GtkExpanderPrivate));
279 g_object_class_install_property (gobject_class,
281 g_param_spec_boolean ("expanded",
283 P_("Whether the expander has been opened to reveal the child widget"),
285 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
287 g_object_class_install_property (gobject_class,
289 g_param_spec_string ("label",
291 P_("Text of the expander's label"),
293 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
295 g_object_class_install_property (gobject_class,
297 g_param_spec_boolean ("use-underline",
299 P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
301 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
303 g_object_class_install_property (gobject_class,
305 g_param_spec_boolean ("use-markup",
307 P_("The text of the label includes XML markup. See pango_parse_markup()"),
309 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
311 g_object_class_install_property (gobject_class,
313 g_param_spec_int ("spacing",
315 P_("Space to put between the label and the child"),
319 GTK_PARAM_READWRITE));
321 g_object_class_install_property (gobject_class,
323 g_param_spec_object ("label-widget",
325 P_("A widget to display in place of the usual expander label"),
327 GTK_PARAM_READWRITE));
329 g_object_class_install_property (gobject_class,
331 g_param_spec_boolean ("label-fill",
333 P_("Whether the label widget should fill all available horizontal space"),
335 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
338 * GtkExpander:resize-toplevel:
340 * When this property is %TRUE, the expander will resize the toplevel
341 * widget containing the expander upon expanding and collapsing.
345 g_object_class_install_property (gobject_class,
346 PROP_RESIZE_TOPLEVEL,
347 g_param_spec_boolean ("resize-toplevel",
348 P_("Resize toplevel"),
349 P_("Whether the expander will resize the toplevel window upon expanding and collapsing"),
351 GTK_PARAM_READWRITE));
353 gtk_widget_class_install_style_property (widget_class,
354 g_param_spec_int ("expander-size",
356 P_("Size of the expander arrow"),
359 DEFAULT_EXPANDER_SIZE,
360 GTK_PARAM_READABLE));
362 gtk_widget_class_install_style_property (widget_class,
363 g_param_spec_int ("expander-spacing",
364 P_("Indicator Spacing"),
365 P_("Spacing around expander arrow"),
368 DEFAULT_EXPANDER_SPACING,
369 GTK_PARAM_READABLE));
371 widget_class->activate_signal =
372 g_signal_new (I_("activate"),
373 G_TYPE_FROM_CLASS (gobject_class),
374 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
375 G_STRUCT_OFFSET (GtkExpanderClass, activate),
377 _gtk_marshal_VOID__VOID,
380 gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_EXPANDER_ACCESSIBLE);
384 gtk_expander_init (GtkExpander *expander)
386 GtkExpanderPrivate *priv;
388 expander->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (expander,
392 gtk_widget_set_can_focus (GTK_WIDGET (expander), TRUE);
393 gtk_widget_set_has_window (GTK_WIDGET (expander), FALSE);
395 priv->label_widget = NULL;
396 priv->event_window = NULL;
399 priv->expanded = FALSE;
400 priv->use_underline = FALSE;
401 priv->use_markup = FALSE;
402 priv->button_down = FALSE;
403 priv->prelight = FALSE;
404 priv->label_fill = FALSE;
405 priv->expand_timer = 0;
406 priv->resize_toplevel = 0;
408 gtk_drag_dest_set (GTK_WIDGET (expander), 0, NULL, 0, 0);
409 gtk_drag_dest_set_track_motion (GTK_WIDGET (expander), TRUE);
413 gtk_expander_buildable_add_child (GtkBuildable *buildable,
419 gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child));
420 else if (strcmp (type, "label") == 0)
421 gtk_expander_set_label_widget (GTK_EXPANDER (buildable), GTK_WIDGET (child));
423 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (GTK_EXPANDER (buildable), type);
427 gtk_expander_buildable_init (GtkBuildableIface *iface)
429 iface->add_child = gtk_expander_buildable_add_child;
433 gtk_expander_set_property (GObject *object,
438 GtkExpander *expander = GTK_EXPANDER (object);
443 gtk_expander_set_expanded (expander, g_value_get_boolean (value));
446 gtk_expander_set_label (expander, g_value_get_string (value));
448 case PROP_USE_UNDERLINE:
449 gtk_expander_set_use_underline (expander, g_value_get_boolean (value));
451 case PROP_USE_MARKUP:
452 gtk_expander_set_use_markup (expander, g_value_get_boolean (value));
455 gtk_expander_set_spacing (expander, g_value_get_int (value));
457 case PROP_LABEL_WIDGET:
458 gtk_expander_set_label_widget (expander, g_value_get_object (value));
460 case PROP_LABEL_FILL:
461 gtk_expander_set_label_fill (expander, g_value_get_boolean (value));
463 case PROP_RESIZE_TOPLEVEL:
464 gtk_expander_set_resize_toplevel (expander, g_value_get_boolean (value));
467 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
473 gtk_expander_get_property (GObject *object,
478 GtkExpander *expander = GTK_EXPANDER (object);
479 GtkExpanderPrivate *priv = expander->priv;
484 g_value_set_boolean (value, priv->expanded);
487 g_value_set_string (value, gtk_expander_get_label (expander));
489 case PROP_USE_UNDERLINE:
490 g_value_set_boolean (value, priv->use_underline);
492 case PROP_USE_MARKUP:
493 g_value_set_boolean (value, priv->use_markup);
496 g_value_set_int (value, priv->spacing);
498 case PROP_LABEL_WIDGET:
499 g_value_set_object (value,
501 G_OBJECT (priv->label_widget) : NULL);
503 case PROP_LABEL_FILL:
504 g_value_set_boolean (value, priv->label_fill);
506 case PROP_RESIZE_TOPLEVEL:
507 g_value_set_boolean (value, gtk_expander_get_resize_toplevel (expander));
510 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
516 gtk_expander_destroy (GtkWidget *widget)
518 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
520 if (priv->expand_timer)
522 g_source_remove (priv->expand_timer);
523 priv->expand_timer = 0;
526 GTK_WIDGET_CLASS (gtk_expander_parent_class)->destroy (widget);
530 gtk_expander_realize (GtkWidget *widget)
532 GtkAllocation allocation;
533 GtkExpanderPrivate *priv;
535 GdkWindowAttr attributes;
536 gint attributes_mask;
538 GdkRectangle expander_rect;
541 priv = GTK_EXPANDER (widget)->priv;
543 gtk_widget_set_realized (widget, TRUE);
545 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
547 get_expander_bounds (GTK_EXPANDER (widget), &expander_rect);
549 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
551 GtkRequisition label_requisition;
553 gtk_widget_get_preferred_size (priv->label_widget,
554 &label_requisition, NULL);
555 label_height = label_requisition.height;
560 gtk_widget_get_allocation (widget, &allocation);
562 attributes.window_type = GDK_WINDOW_CHILD;
563 attributes.x = allocation.x + border_width;
564 attributes.y = allocation.y + border_width;
565 attributes.width = MAX (allocation.width - 2 * border_width, 1);
566 attributes.height = MAX (expander_rect.height, label_height - 2 * border_width);
567 attributes.wclass = GDK_INPUT_ONLY;
568 attributes.event_mask = gtk_widget_get_events (widget)
569 | GDK_BUTTON_PRESS_MASK
570 | GDK_BUTTON_RELEASE_MASK
571 | GDK_ENTER_NOTIFY_MASK
572 | GDK_LEAVE_NOTIFY_MASK;
574 attributes_mask = GDK_WA_X | GDK_WA_Y;
576 window = gtk_widget_get_parent_window (widget);
577 gtk_widget_set_window (widget, window);
578 g_object_ref (window);
580 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
581 &attributes, attributes_mask);
582 gdk_window_set_user_data (priv->event_window, widget);
586 gtk_expander_unrealize (GtkWidget *widget)
588 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
590 if (priv->event_window)
592 gdk_window_set_user_data (priv->event_window, NULL);
593 gdk_window_destroy (priv->event_window);
594 priv->event_window = NULL;
597 GTK_WIDGET_CLASS (gtk_expander_parent_class)->unrealize (widget);
601 get_expander_bounds (GtkExpander *expander,
604 GtkAllocation allocation;
606 GtkExpanderPrivate *priv;
609 gint expander_spacing;
610 gboolean interior_focus;
615 widget = GTK_WIDGET (expander);
616 priv = expander->priv;
618 gtk_widget_get_allocation (widget, &allocation);
620 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
622 gtk_widget_style_get (widget,
623 "interior-focus", &interior_focus,
624 "focus-line-width", &focus_width,
625 "focus-padding", &focus_pad,
626 "expander-size", &expander_size,
627 "expander-spacing", &expander_spacing,
630 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
632 rect->x = allocation.x + border_width;
633 rect->y = allocation.y + border_width;
636 rect->x += expander_spacing;
638 rect->x += allocation.width - 2 * border_width -
639 expander_spacing - expander_size;
641 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
643 GtkAllocation label_allocation;
645 gtk_widget_get_allocation (priv->label_widget, &label_allocation);
647 if (expander_size < label_allocation.height)
648 rect->y += focus_width + focus_pad + (label_allocation.height - expander_size) / 2;
650 rect->y += expander_spacing;
654 rect->y += expander_spacing;
660 rect->x += focus_width + focus_pad;
662 rect->x -= focus_width + focus_pad;
663 rect->y += focus_width + focus_pad;
666 rect->width = rect->height = expander_size;
670 gtk_expander_size_allocate (GtkWidget *widget,
671 GtkAllocation *allocation)
673 GtkExpander *expander;
675 GtkExpanderPrivate *priv;
676 gboolean child_visible = FALSE;
679 gint expander_spacing;
680 gboolean interior_focus;
683 gint label_height, top_min_height;
684 gint label_xpad, label_xoffset;
685 gint child_ypad, child_yoffset;
687 expander = GTK_EXPANDER (widget);
688 child = gtk_bin_get_child (GTK_BIN (widget));
689 priv = expander->priv;
691 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
693 gtk_widget_set_allocation (widget, allocation);
695 gtk_widget_style_get (widget,
696 "interior-focus", &interior_focus,
697 "focus-line-width", &focus_width,
698 "focus-padding", &focus_pad,
699 "expander-size", &expander_size,
700 "expander-spacing", &expander_spacing,
704 /* Calculate some offsets/padding first */
705 label_xoffset = border_width + expander_size + focus_width + 2 * expander_spacing + focus_pad;
706 label_xpad = 2 * border_width + expander_size + 2 * focus_width + 2 * expander_spacing + 2 * focus_pad;
708 child_yoffset = border_width + priv->spacing + (interior_focus ? 0 : 2 * focus_width + 2 * focus_pad);
709 child_ypad = 2 * border_width + priv->spacing + (interior_focus ? 0 : 2 * focus_width + 2 * focus_pad);
710 top_min_height = 2 * expander_spacing + expander_size;
712 child_visible = (child && gtk_widget_get_child_visible (child));
714 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
716 GtkAllocation label_allocation;
717 gint natural_label_width;
720 gtk_widget_get_preferred_width (priv->label_widget, NULL, &natural_label_width);
722 if (priv->label_fill)
723 label_allocation.width = allocation->width - label_xpad;
725 label_allocation.width = MIN (natural_label_width, allocation->width - label_xpad);
726 label_allocation.width = MAX (label_allocation.width, 1);
728 /* We distribute the minimum height to the label widget and prioritize
729 * the child widget giving it the remaining height
731 gtk_widget_get_preferred_height_for_width (priv->label_widget,
732 label_allocation.width, &label_height, NULL);
734 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
736 if (priv->label_fill)
737 label_allocation.x = allocation->x + label_xoffset;
739 label_allocation.x = allocation->x + label_xoffset;
741 label_allocation.x = allocation->x + allocation->width -
742 (label_allocation.width + label_xoffset);
744 label_allocation.y = allocation->y + border_width + focus_width + focus_pad;
745 label_allocation.height = MIN (label_height,
746 allocation->height - 2 * border_width -
747 2 * focus_width - 2 * focus_pad -
748 (child_visible ? priv->spacing : 0));
749 label_allocation.height = MAX (label_allocation.height, 1);
751 gtk_widget_size_allocate (priv->label_widget, &label_allocation);
753 label_height = label_allocation.height;
760 if (gtk_widget_get_realized (widget))
764 get_expander_bounds (expander, &rect);
766 gdk_window_move_resize (priv->event_window,
767 allocation->x + border_width,
768 allocation->y + border_width,
769 MAX (allocation->width - 2 * border_width, 1),
770 MAX (rect.height, label_height - 2 * border_width));
775 GtkAllocation child_allocation;
778 top_height = MAX (top_min_height,
779 label_height + (interior_focus ? 2 * focus_width + 2 * focus_pad : 0));
781 child_allocation.x = allocation->x + border_width;
782 child_allocation.y = allocation->y + top_height + child_yoffset;
784 child_allocation.width = MAX (allocation->width - 2 * border_width, 1);
785 child_allocation.height = allocation->height - top_height - child_ypad;
786 child_allocation.height = MAX (child_allocation.height, 1);
788 gtk_widget_size_allocate (child, &child_allocation);
793 gtk_expander_map (GtkWidget *widget)
795 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
797 if (priv->label_widget)
798 gtk_widget_map (priv->label_widget);
800 GTK_WIDGET_CLASS (gtk_expander_parent_class)->map (widget);
802 if (priv->event_window)
803 gdk_window_show (priv->event_window);
807 gtk_expander_unmap (GtkWidget *widget)
809 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
811 if (priv->event_window)
812 gdk_window_hide (priv->event_window);
814 GTK_WIDGET_CLASS (gtk_expander_parent_class)->unmap (widget);
816 if (priv->label_widget)
817 gtk_widget_unmap (priv->label_widget);
821 gtk_expander_paint_prelight (GtkExpander *expander,
824 GtkAllocation allocation;
826 GtkContainer *container;
827 GtkExpanderPrivate *priv;
829 GtkStyleContext *context;
830 gboolean interior_focus;
834 int expander_spacing;
837 priv = expander->priv;
838 widget = GTK_WIDGET (expander);
839 container = GTK_CONTAINER (expander);
841 gtk_widget_style_get (widget,
842 "interior-focus", &interior_focus,
843 "focus-line-width", &focus_width,
844 "focus-padding", &focus_pad,
845 "expander-size", &expander_size,
846 "expander-spacing", &expander_spacing,
849 gtk_widget_get_allocation (widget, &allocation);
851 border_width = gtk_container_get_border_width (container);
852 area.x = border_width;
853 area.y = border_width;
854 area.width = allocation.width - (2 * border_width);
856 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
858 GtkAllocation label_widget_allocation;
860 gtk_widget_get_allocation (priv->label_widget, &label_widget_allocation);
861 area.height = label_widget_allocation.height;
866 area.height += interior_focus ? (focus_width + focus_pad) * 2 : 0;
867 area.height = MAX (area.height, expander_size + 2 * expander_spacing);
868 area.height += !interior_focus ? (focus_width + focus_pad) * 2 : 0;
870 context = gtk_widget_get_style_context (widget);
871 gtk_render_background (context, cr,
873 area.width, area.height);
877 gtk_expander_paint (GtkExpander *expander,
880 GtkExpanderPrivate *priv = expander->priv;
883 GtkAllocation allocation;
884 GtkStyleContext *context;
885 GtkStateFlags state = 0;
888 widget = GTK_WIDGET (expander);
889 context = gtk_widget_get_style_context (widget);
890 state = gtk_widget_get_state_flags (widget);
892 get_expander_bounds (expander, &clip);
893 gtk_widget_get_allocation (widget, &allocation);
895 gtk_style_context_save (context);
897 state &= ~(GTK_STATE_FLAG_PRELIGHT);
898 if (expander->priv->prelight)
900 state |= GTK_STATE_FLAG_PRELIGHT;
901 gtk_style_context_set_state (context, state);
902 gtk_expander_paint_prelight (expander, cr);
905 gtk_widget_style_get (widget, "expander-size", &size, NULL);
907 /* Set active flag as per the expanded state */
909 state |= GTK_STATE_FLAG_ACTIVE;
911 state &= ~(GTK_STATE_FLAG_ACTIVE);
913 gtk_style_context_set_state (context, state);
914 gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
916 /* The expander is the only animatable region */
917 gtk_style_context_push_animatable_region (context, GUINT_TO_POINTER (1));
919 gtk_render_expander (context, cr,
920 clip.x - allocation.x,
921 clip.y - allocation.y,
924 gtk_style_context_pop_animatable_region (context);
925 gtk_style_context_restore (context);
929 gtk_expander_paint_focus (GtkExpander *expander,
933 GtkExpanderPrivate *priv;
935 GtkStyleContext *context;
936 gint x, y, width, height;
937 gboolean interior_focus;
942 gint expander_spacing;
944 GtkAllocation allocation;
946 widget = GTK_WIDGET (expander);
947 priv = expander->priv;
949 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
950 gtk_widget_get_allocation (widget, &allocation);
952 gtk_widget_style_get (widget,
953 "interior-focus", &interior_focus,
954 "focus-line-width", &focus_width,
955 "focus-padding", &focus_pad,
956 "expander-size", &expander_size,
957 "expander-spacing", &expander_spacing,
960 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
964 if (priv->label_widget)
966 if (gtk_widget_get_visible (priv->label_widget))
968 GtkAllocation label_allocation;
970 gtk_widget_get_allocation (priv->label_widget, &label_allocation);
971 width = label_allocation.width;
972 height = label_allocation.height;
975 width += 2 * focus_pad + 2 * focus_width;
976 height += 2 * focus_pad + 2 * focus_width;
984 x += expander_spacing * 2 + expander_size;
988 x += allocation.width - 2 * border_width
989 - expander_spacing * 2 - expander_size - width;
994 width += expander_size + 2 * expander_spacing;
995 height = MAX (height, expander_size + 2 * expander_spacing);
1000 get_expander_bounds (expander, &rect);
1002 x = rect.x - allocation.x - focus_pad;
1003 y = rect.y - allocation.y - focus_pad;
1004 width = rect.width + 2 * focus_pad;
1005 height = rect.height + 2 * focus_pad;
1008 context = gtk_widget_get_style_context (widget);
1009 gtk_render_focus (context, cr,
1010 x, y, width, height);
1014 gtk_expander_draw (GtkWidget *widget,
1017 GtkExpander *expander = GTK_EXPANDER (widget);
1019 gtk_expander_paint (expander, cr);
1021 if (gtk_widget_has_visible_focus (widget))
1022 gtk_expander_paint_focus (expander, cr);
1024 GTK_WIDGET_CLASS (gtk_expander_parent_class)->draw (widget, cr);
1030 gtk_expander_button_press (GtkWidget *widget,
1031 GdkEventButton *event)
1033 GtkExpander *expander = GTK_EXPANDER (widget);
1035 if (event->button == GDK_BUTTON_PRIMARY && event->window == expander->priv->event_window)
1037 expander->priv->button_down = TRUE;
1045 gtk_expander_button_release (GtkWidget *widget,
1046 GdkEventButton *event)
1048 GtkExpander *expander = GTK_EXPANDER (widget);
1050 if (event->button == GDK_BUTTON_PRIMARY && expander->priv->button_down)
1052 gtk_widget_activate (widget);
1053 expander->priv->button_down = FALSE;
1061 gtk_expander_grab_notify (GtkWidget *widget,
1062 gboolean was_grabbed)
1065 GTK_EXPANDER (widget)->priv->button_down = FALSE;
1069 gtk_expander_state_flags_changed (GtkWidget *widget,
1070 GtkStateFlags previous_state)
1072 if (!gtk_widget_is_sensitive (widget))
1073 GTK_EXPANDER (widget)->priv->button_down = FALSE;
1077 gtk_expander_redraw_expander (GtkExpander *expander)
1079 GtkAllocation allocation;
1080 GtkWidget *widget = GTK_WIDGET (expander);
1082 if (gtk_widget_get_realized (widget))
1084 gtk_widget_get_allocation (widget, &allocation);
1085 gdk_window_invalidate_rect (gtk_widget_get_window (widget), &allocation, FALSE);
1090 gtk_expander_enter_notify (GtkWidget *widget,
1091 GdkEventCrossing *event)
1093 GtkExpander *expander = GTK_EXPANDER (widget);
1095 if (event->window == expander->priv->event_window &&
1096 event->detail != GDK_NOTIFY_INFERIOR)
1098 expander->priv->prelight = TRUE;
1100 if (expander->priv->label_widget)
1101 gtk_widget_set_state_flags (expander->priv->label_widget,
1102 GTK_STATE_FLAG_PRELIGHT,
1105 gtk_expander_redraw_expander (expander);
1112 gtk_expander_leave_notify (GtkWidget *widget,
1113 GdkEventCrossing *event)
1115 GtkExpander *expander = GTK_EXPANDER (widget);
1117 if (event->window == expander->priv->event_window &&
1118 event->detail != GDK_NOTIFY_INFERIOR)
1120 expander->priv->prelight = FALSE;
1122 if (expander->priv->label_widget)
1123 gtk_widget_unset_state_flags (expander->priv->label_widget,
1124 GTK_STATE_FLAG_PRELIGHT);
1126 gtk_expander_redraw_expander (expander);
1133 expand_timeout (gpointer data)
1135 GtkExpander *expander = GTK_EXPANDER (data);
1136 GtkExpanderPrivate *priv = expander->priv;
1138 priv->expand_timer = 0;
1139 gtk_expander_set_expanded (expander, TRUE);
1145 gtk_expander_drag_motion (GtkWidget *widget,
1146 GdkDragContext *context,
1151 GtkExpander *expander = GTK_EXPANDER (widget);
1152 GtkExpanderPrivate *priv = expander->priv;
1154 if (!priv->expanded && !priv->expand_timer)
1156 GtkSettings *settings;
1159 settings = gtk_widget_get_settings (widget);
1160 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
1162 priv->expand_timer = gdk_threads_add_timeout (timeout, (GSourceFunc) expand_timeout, expander);
1169 gtk_expander_drag_leave (GtkWidget *widget,
1170 GdkDragContext *context,
1173 GtkExpander *expander = GTK_EXPANDER (widget);
1174 GtkExpanderPrivate *priv = expander->priv;
1176 if (priv->expand_timer)
1178 g_source_remove (priv->expand_timer);
1179 priv->expand_timer = 0;
1192 focus_current_site (GtkExpander *expander,
1193 GtkDirectionType direction)
1195 GtkWidget *current_focus;
1197 current_focus = gtk_container_get_focus_child (GTK_CONTAINER (expander));
1202 return gtk_widget_child_focus (current_focus, direction);
1206 focus_in_site (GtkExpander *expander,
1208 GtkDirectionType direction)
1213 gtk_widget_grab_focus (GTK_WIDGET (expander));
1216 if (expander->priv->label_widget)
1217 return gtk_widget_child_focus (expander->priv->label_widget, direction);
1222 GtkWidget *child = gtk_bin_get_child (GTK_BIN (expander));
1224 if (child && gtk_widget_get_child_visible (child))
1225 return gtk_widget_child_focus (child, direction);
1233 g_assert_not_reached ();
1238 get_next_site (GtkExpander *expander,
1240 GtkDirectionType direction)
1244 ltr = gtk_widget_get_direction (GTK_WIDGET (expander)) != GTK_TEXT_DIR_RTL;
1251 case GTK_DIR_TAB_BACKWARD:
1255 case GTK_DIR_TAB_FORWARD:
1258 return FOCUS_WIDGET;
1263 case GTK_DIR_TAB_BACKWARD:
1267 return ltr ? FOCUS_NONE : FOCUS_LABEL;
1268 case GTK_DIR_TAB_FORWARD:
1272 return ltr ? FOCUS_LABEL : FOCUS_NONE;
1278 case GTK_DIR_TAB_BACKWARD:
1280 return FOCUS_WIDGET;
1282 return ltr ? FOCUS_WIDGET : FOCUS_CHILD;
1283 case GTK_DIR_TAB_FORWARD:
1287 return ltr ? FOCUS_CHILD : FOCUS_WIDGET;
1293 case GTK_DIR_TAB_BACKWARD:
1297 case GTK_DIR_TAB_FORWARD:
1304 g_assert_not_reached ();
1309 gtk_expander_resize_toplevel (GtkExpander *expander)
1311 GtkExpanderPrivate *priv = expander->priv;
1312 GtkWidget *child = gtk_bin_get_child (GTK_BIN (expander));
1314 if (child && priv->resize_toplevel &&
1315 gtk_widget_get_realized (GTK_WIDGET (expander)))
1317 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (expander));
1319 if (toplevel && gtk_widget_get_realized (toplevel))
1321 GtkAllocation toplevel_allocation;
1323 gtk_widget_get_allocation (toplevel, &toplevel_allocation);
1327 GtkRequisition child_requisition;
1329 gtk_widget_get_preferred_size (child, &child_requisition, NULL);
1331 toplevel_allocation.height += child_requisition.height;
1335 GtkAllocation child_allocation;
1337 gtk_widget_get_allocation (child, &child_allocation);
1339 toplevel_allocation.height -= child_allocation.height;
1342 gtk_window_resize (GTK_WINDOW (toplevel),
1343 toplevel_allocation.width,
1344 toplevel_allocation.height);
1350 gtk_expander_focus (GtkWidget *widget,
1351 GtkDirectionType direction)
1353 GtkExpander *expander = GTK_EXPANDER (widget);
1355 if (!focus_current_site (expander, direction))
1357 GtkWidget *old_focus_child;
1358 gboolean widget_is_focus;
1359 FocusSite site = FOCUS_NONE;
1361 widget_is_focus = gtk_widget_is_focus (widget);
1362 old_focus_child = gtk_container_get_focus_child (GTK_CONTAINER (widget));
1364 if (old_focus_child && old_focus_child == expander->priv->label_widget)
1366 else if (old_focus_child)
1368 else if (widget_is_focus)
1369 site = FOCUS_WIDGET;
1371 while ((site = get_next_site (expander, site, direction)) != FOCUS_NONE)
1373 if (focus_in_site (expander, site, direction))
1384 gtk_expander_add (GtkContainer *container,
1387 GTK_CONTAINER_CLASS (gtk_expander_parent_class)->add (container, widget);
1389 gtk_widget_set_child_visible (widget, GTK_EXPANDER (container)->priv->expanded);
1390 gtk_widget_queue_resize (GTK_WIDGET (container));
1394 gtk_expander_remove (GtkContainer *container,
1397 GtkExpander *expander = GTK_EXPANDER (container);
1399 if (GTK_EXPANDER (expander)->priv->label_widget == widget)
1400 gtk_expander_set_label_widget (expander, NULL);
1402 GTK_CONTAINER_CLASS (gtk_expander_parent_class)->remove (container, widget);
1406 gtk_expander_forall (GtkContainer *container,
1407 gboolean include_internals,
1408 GtkCallback callback,
1409 gpointer callback_data)
1411 GtkBin *bin = GTK_BIN (container);
1412 GtkExpanderPrivate *priv = GTK_EXPANDER (container)->priv;
1415 child = gtk_bin_get_child (bin);
1417 (* callback) (child, callback_data);
1419 if (priv->label_widget)
1420 (* callback) (priv->label_widget, callback_data);
1424 gtk_expander_activate (GtkExpander *expander)
1426 gtk_expander_set_expanded (expander, !expander->priv->expanded);
1431 gtk_expander_get_preferred_width (GtkWidget *widget,
1435 GtkExpander *expander;
1437 GtkExpanderPrivate *priv;
1440 gint expander_spacing;
1441 gboolean interior_focus;
1445 child = gtk_bin_get_child (GTK_BIN (widget));
1446 expander = GTK_EXPANDER (widget);
1447 priv = expander->priv;
1449 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1451 gtk_widget_style_get (GTK_WIDGET (widget),
1452 "interior-focus", &interior_focus,
1453 "focus-line-width", &focus_width,
1454 "focus-padding", &focus_pad,
1455 "expander-size", &expander_size,
1456 "expander-spacing", &expander_spacing,
1459 *minimum_size = *natural_size =
1460 expander_size + 2 * expander_spacing +
1461 2 * focus_width + 2 * focus_pad;
1463 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
1465 gint label_min, label_nat;
1467 gtk_widget_get_preferred_width (priv->label_widget,
1468 &label_min, &label_nat);
1470 *minimum_size += label_min;
1471 *natural_size += label_nat;
1474 if (child && gtk_widget_get_child_visible (child))
1476 gint child_min, child_nat;
1478 gtk_widget_get_preferred_width (child,
1479 &child_min, &child_nat);
1481 *minimum_size = MAX (*minimum_size, child_min);
1482 *natural_size = MAX (*natural_size, child_nat);
1486 *minimum_size += 2 * border_width;
1487 *natural_size += 2 * border_width;
1491 gtk_expander_get_preferred_height (GtkWidget *widget,
1495 GtkExpander *expander;
1497 GtkExpanderPrivate *priv;
1500 gint expander_spacing;
1501 gboolean interior_focus;
1505 child = gtk_bin_get_child (GTK_BIN (widget));
1506 expander = GTK_EXPANDER (widget);
1507 priv = expander->priv;
1509 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1511 gtk_widget_style_get (GTK_WIDGET (widget),
1512 "interior-focus", &interior_focus,
1513 "focus-line-width", &focus_width,
1514 "focus-padding", &focus_pad,
1515 "expander-size", &expander_size,
1516 "expander-spacing", &expander_spacing,
1519 *minimum_size = *natural_size =
1520 interior_focus ? (2 * focus_width + 2 * focus_pad) : 0;
1523 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
1525 gint label_min, label_nat;
1527 gtk_widget_get_preferred_height (priv->label_widget,
1528 &label_min, &label_nat);
1530 *minimum_size += label_min;
1531 *natural_size += label_nat;
1534 *minimum_size = MAX (*minimum_size, expander_size + 2 * expander_spacing);
1535 *natural_size = MAX (*natural_size, *minimum_size);
1537 if (!interior_focus)
1539 gint extra = 2 * focus_width + 2 * focus_pad;
1540 *minimum_size += extra;
1541 *natural_size += extra;
1544 if (child && gtk_widget_get_child_visible (child))
1546 gint child_min, child_nat;
1548 gtk_widget_get_preferred_height (child,
1549 &child_min, &child_nat);
1551 *minimum_size += child_min + priv->spacing;
1552 *natural_size += child_nat + priv->spacing;
1556 *minimum_size += 2 * border_width;
1557 *natural_size += 2 * border_width;
1561 gtk_expander_get_preferred_height_for_width (GtkWidget *widget,
1563 gint *minimum_height,
1564 gint *natural_height)
1566 GtkExpander *expander;
1568 GtkExpanderPrivate *priv;
1571 gint expander_spacing;
1572 gboolean interior_focus;
1577 child = gtk_bin_get_child (GTK_BIN (widget));
1578 expander = GTK_EXPANDER (widget);
1579 priv = expander->priv;
1581 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1583 gtk_widget_style_get (GTK_WIDGET (widget),
1584 "interior-focus", &interior_focus,
1585 "focus-line-width", &focus_width,
1586 "focus-padding", &focus_pad,
1587 "expander-size", &expander_size,
1588 "expander-spacing", &expander_spacing,
1591 label_xpad = 2 * border_width + expander_size + 2 * expander_spacing - 2 * focus_width + 2 * focus_pad;
1593 *minimum_height = *natural_height =
1594 interior_focus ? (2 * focus_width + 2 * focus_pad) : 0;
1597 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
1599 gint label_min, label_nat;
1601 gtk_widget_get_preferred_height_for_width (priv->label_widget,
1602 MAX (width - label_xpad, 1),
1603 &label_min, &label_nat);
1605 *minimum_height += label_min;
1606 *natural_height += label_nat;
1609 *minimum_height = MAX (*minimum_height, expander_size + 2 * expander_spacing);
1610 *natural_height = MAX (*natural_height, *minimum_height);
1612 if (!interior_focus)
1614 gint extra = 2 * focus_width + 2 * focus_pad;
1615 *minimum_height += extra;
1616 *natural_height += extra;
1619 if (child && gtk_widget_get_child_visible (child))
1621 gint child_min, child_nat;
1623 gtk_widget_get_preferred_height_for_width (child,
1624 MAX (width - 2 * border_width, 1),
1625 &child_min, &child_nat);
1627 *minimum_height += child_min + priv->spacing;
1628 *natural_height += child_nat + priv->spacing;
1631 *minimum_height += 2 * border_width;
1632 *natural_height += 2 * border_width;
1636 gtk_expander_get_preferred_width_for_height (GtkWidget *widget,
1638 gint *minimum_width,
1639 gint *natural_width)
1641 GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_width, natural_width);
1648 * @label: the text of the label
1650 * Creates a new expander using @label as the text of the label.
1652 * Return value: a new #GtkExpander widget.
1657 gtk_expander_new (const gchar *label)
1659 return g_object_new (GTK_TYPE_EXPANDER, "label", label, NULL);
1663 * gtk_expander_new_with_mnemonic:
1664 * @label: (allow-none): the text of the label with an underscore
1665 * in front of the mnemonic character
1667 * Creates a new expander using @label as the text of the label.
1668 * If characters in @label are preceded by an underscore, they are underlined.
1669 * If you need a literal underscore character in a label, use '__' (two
1670 * underscores). The first underlined character represents a keyboard
1671 * accelerator called a mnemonic.
1672 * Pressing Alt and that key activates the button.
1674 * Return value: a new #GtkExpander widget.
1679 gtk_expander_new_with_mnemonic (const gchar *label)
1681 return g_object_new (GTK_TYPE_EXPANDER,
1683 "use-underline", TRUE,
1688 * gtk_expander_set_expanded:
1689 * @expander: a #GtkExpander
1690 * @expanded: whether the child widget is revealed
1692 * Sets the state of the expander. Set to %TRUE, if you want
1693 * the child widget to be revealed, and %FALSE if you want the
1694 * child widget to be hidden.
1699 gtk_expander_set_expanded (GtkExpander *expander,
1702 GtkExpanderPrivate *priv;
1705 g_return_if_fail (GTK_IS_EXPANDER (expander));
1707 priv = expander->priv;
1709 expanded = expanded != FALSE;
1711 if (priv->expanded != expanded)
1713 GtkWidget *widget = GTK_WIDGET (expander);
1714 GtkSettings *settings = gtk_widget_get_settings (widget);
1715 GtkStyleContext *context;
1716 gboolean enable_animations;
1718 context = gtk_widget_get_style_context (widget);
1719 priv->expanded = expanded;
1721 g_object_get (settings, "gtk-enable-animations", &enable_animations, NULL);
1723 if (enable_animations && gtk_widget_get_realized (widget))
1725 gtk_style_context_save (context);
1726 gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
1728 gtk_style_context_notify_state_change (context,
1729 gtk_widget_get_window (widget),
1730 GUINT_TO_POINTER (1),
1733 gtk_style_context_restore (context);
1736 child = gtk_bin_get_child (GTK_BIN (expander));
1740 gtk_widget_set_child_visible (child, priv->expanded);
1741 gtk_widget_queue_resize (widget);
1742 gtk_expander_resize_toplevel (expander);
1745 g_object_notify (G_OBJECT (expander), "expanded");
1750 * gtk_expander_get_expanded:
1751 * @expander:a #GtkExpander
1753 * Queries a #GtkExpander and returns its current state. Returns %TRUE
1754 * if the child widget is revealed.
1756 * See gtk_expander_set_expanded().
1758 * Return value: the current state of the expander
1763 gtk_expander_get_expanded (GtkExpander *expander)
1765 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1767 return expander->priv->expanded;
1771 * gtk_expander_set_spacing:
1772 * @expander: a #GtkExpander
1773 * @spacing: distance between the expander and child in pixels
1775 * Sets the spacing field of @expander, which is the number of
1776 * pixels to place between expander and the child.
1781 gtk_expander_set_spacing (GtkExpander *expander,
1784 g_return_if_fail (GTK_IS_EXPANDER (expander));
1785 g_return_if_fail (spacing >= 0);
1787 if (expander->priv->spacing != spacing)
1789 expander->priv->spacing = spacing;
1791 gtk_widget_queue_resize (GTK_WIDGET (expander));
1793 g_object_notify (G_OBJECT (expander), "spacing");
1798 * gtk_expander_get_spacing:
1799 * @expander: a #GtkExpander
1801 * Gets the value set by gtk_expander_set_spacing().
1803 * Return value: spacing between the expander and child
1808 gtk_expander_get_spacing (GtkExpander *expander)
1810 g_return_val_if_fail (GTK_IS_EXPANDER (expander), 0);
1812 return expander->priv->spacing;
1816 * gtk_expander_set_label:
1817 * @expander: a #GtkExpander
1818 * @label: (allow-none): a string
1820 * Sets the text of the label of the expander to @label.
1822 * This will also clear any previously set labels.
1827 gtk_expander_set_label (GtkExpander *expander,
1830 g_return_if_fail (GTK_IS_EXPANDER (expander));
1834 gtk_expander_set_label_widget (expander, NULL);
1840 child = gtk_label_new (label);
1841 gtk_label_set_use_underline (GTK_LABEL (child), expander->priv->use_underline);
1842 gtk_label_set_use_markup (GTK_LABEL (child), expander->priv->use_markup);
1843 gtk_widget_show (child);
1845 gtk_expander_set_label_widget (expander, child);
1848 g_object_notify (G_OBJECT (expander), "label");
1852 * gtk_expander_get_label:
1853 * @expander: a #GtkExpander
1855 * Fetches the text from a label widget including any embedded
1856 * underlines indicating mnemonics and Pango markup, as set by
1857 * gtk_expander_set_label(). If the label text has not been set the
1858 * return value will be %NULL. This will be the case if you create an
1859 * empty button with gtk_button_new() to use as a container.
1861 * Note that this function behaved differently in versions prior to
1862 * 2.14 and used to return the label text stripped of embedded
1863 * underlines indicating mnemonics and Pango markup. This problem can
1864 * be avoided by fetching the label text directly from the label
1867 * Return value: The text of the label widget. This string is owned
1868 * by the widget and must not be modified or freed.
1873 gtk_expander_get_label (GtkExpander *expander)
1875 GtkExpanderPrivate *priv;
1877 g_return_val_if_fail (GTK_IS_EXPANDER (expander), NULL);
1879 priv = expander->priv;
1881 if (GTK_IS_LABEL (priv->label_widget))
1882 return gtk_label_get_label (GTK_LABEL (priv->label_widget));
1888 * gtk_expander_set_use_underline:
1889 * @expander: a #GtkExpander
1890 * @use_underline: %TRUE if underlines in the text indicate mnemonics
1892 * If true, an underline in the text of the expander label indicates
1893 * the next character should be used for the mnemonic accelerator key.
1898 gtk_expander_set_use_underline (GtkExpander *expander,
1899 gboolean use_underline)
1901 GtkExpanderPrivate *priv;
1903 g_return_if_fail (GTK_IS_EXPANDER (expander));
1905 priv = expander->priv;
1907 use_underline = use_underline != FALSE;
1909 if (priv->use_underline != use_underline)
1911 priv->use_underline = use_underline;
1913 if (GTK_IS_LABEL (priv->label_widget))
1914 gtk_label_set_use_underline (GTK_LABEL (priv->label_widget), use_underline);
1916 g_object_notify (G_OBJECT (expander), "use-underline");
1921 * gtk_expander_get_use_underline:
1922 * @expander: a #GtkExpander
1924 * Returns whether an embedded underline in the expander label
1925 * indicates a mnemonic. See gtk_expander_set_use_underline().
1927 * Return value: %TRUE if an embedded underline in the expander
1928 * label indicates the mnemonic accelerator keys
1933 gtk_expander_get_use_underline (GtkExpander *expander)
1935 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1937 return expander->priv->use_underline;
1941 * gtk_expander_set_use_markup:
1942 * @expander: a #GtkExpander
1943 * @use_markup: %TRUE if the label's text should be parsed for markup
1945 * Sets whether the text of the label contains markup in <link
1946 * linkend="PangoMarkupFormat">Pango's text markup
1947 * language</link>. See gtk_label_set_markup().
1952 gtk_expander_set_use_markup (GtkExpander *expander,
1953 gboolean use_markup)
1955 GtkExpanderPrivate *priv;
1957 g_return_if_fail (GTK_IS_EXPANDER (expander));
1959 priv = expander->priv;
1961 use_markup = use_markup != FALSE;
1963 if (priv->use_markup != use_markup)
1965 priv->use_markup = use_markup;
1967 if (GTK_IS_LABEL (priv->label_widget))
1968 gtk_label_set_use_markup (GTK_LABEL (priv->label_widget), use_markup);
1970 g_object_notify (G_OBJECT (expander), "use-markup");
1975 * gtk_expander_get_use_markup:
1976 * @expander: a #GtkExpander
1978 * Returns whether the label's text is interpreted as marked up with
1979 * the <link linkend="PangoMarkupFormat">Pango text markup
1980 * language</link>. See gtk_expander_set_use_markup().
1982 * Return value: %TRUE if the label's text will be parsed for markup
1987 gtk_expander_get_use_markup (GtkExpander *expander)
1989 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1991 return expander->priv->use_markup;
1995 * gtk_expander_set_label_widget:
1996 * @expander: a #GtkExpander
1997 * @label_widget: (allow-none): the new label widget
1999 * Set the label widget for the expander. This is the widget
2000 * that will appear embedded alongside the expander arrow.
2005 gtk_expander_set_label_widget (GtkExpander *expander,
2006 GtkWidget *label_widget)
2008 GtkExpanderPrivate *priv;
2011 g_return_if_fail (GTK_IS_EXPANDER (expander));
2012 g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget));
2013 g_return_if_fail (label_widget == NULL || gtk_widget_get_parent (label_widget) == NULL);
2015 priv = expander->priv;
2017 if (priv->label_widget == label_widget)
2020 if (priv->label_widget)
2022 gtk_widget_set_state_flags (priv->label_widget, 0, TRUE);
2023 gtk_widget_unparent (priv->label_widget);
2026 priv->label_widget = label_widget;
2027 widget = GTK_WIDGET (expander);
2031 priv->label_widget = label_widget;
2033 gtk_widget_set_parent (label_widget, widget);
2036 gtk_widget_set_state_flags (label_widget,
2037 GTK_STATE_FLAG_PRELIGHT,
2041 if (gtk_widget_get_visible (widget))
2042 gtk_widget_queue_resize (widget);
2044 g_object_freeze_notify (G_OBJECT (expander));
2045 g_object_notify (G_OBJECT (expander), "label-widget");
2046 g_object_notify (G_OBJECT (expander), "label");
2047 g_object_thaw_notify (G_OBJECT (expander));
2051 * gtk_expander_get_label_widget:
2052 * @expander: a #GtkExpander
2054 * Retrieves the label widget for the frame. See
2055 * gtk_expander_set_label_widget().
2057 * Return value: (transfer none): the label widget,
2058 * or %NULL if there is none
2063 gtk_expander_get_label_widget (GtkExpander *expander)
2065 g_return_val_if_fail (GTK_IS_EXPANDER (expander), NULL);
2067 return expander->priv->label_widget;
2071 * gtk_expander_set_label_fill:
2072 * @expander: a #GtkExpander
2073 * @label_fill: %TRUE if the label should should fill
2074 * all available horizontal space
2076 * Sets whether the label widget should fill all available
2077 * horizontal space allocated to @expander.
2082 gtk_expander_set_label_fill (GtkExpander *expander,
2083 gboolean label_fill)
2085 GtkExpanderPrivate *priv;
2087 g_return_if_fail (GTK_IS_EXPANDER (expander));
2089 priv = expander->priv;
2091 label_fill = label_fill != FALSE;
2093 if (priv->label_fill != label_fill)
2095 priv->label_fill = label_fill;
2097 if (priv->label_widget != NULL)
2098 gtk_widget_queue_resize (GTK_WIDGET (expander));
2100 g_object_notify (G_OBJECT (expander), "label-fill");
2105 * gtk_expander_get_label_fill:
2106 * @expander: a #GtkExpander
2108 * Returns whether the label widget will fill all available
2109 * horizontal space allocated to @expander.
2111 * Return value: %TRUE if the label widget will fill all
2112 * available horizontal space
2117 gtk_expander_get_label_fill (GtkExpander *expander)
2119 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
2121 return expander->priv->label_fill;
2125 * gtk_expander_set_resize_toplevel:
2126 * @expander: a #GtkExpander
2127 * @resize_toplevel: whether to resize the toplevel
2129 * Sets whether the expander will resize the toplevel widget
2130 * containing the expander upon resizing and collpasing.
2135 gtk_expander_set_resize_toplevel (GtkExpander *expander,
2136 gboolean resize_toplevel)
2138 g_return_if_fail (GTK_IS_EXPANDER (expander));
2140 if (expander->priv->resize_toplevel != resize_toplevel)
2142 expander->priv->resize_toplevel = resize_toplevel ? TRUE : FALSE;
2143 g_object_notify (G_OBJECT (expander), "resize-toplevel");
2148 * gtk_expander_get_resize_toplevel:
2149 * @expander: a #GtkExpander
2151 * Returns whether the expander will resize the toplevel widget
2152 * containing the expander upon resizing and collpasing.
2154 * Return value: the "resize toplevel" setting.
2159 gtk_expander_get_resize_toplevel (GtkExpander *expander)
2161 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
2163 return expander->priv->resize_toplevel;