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, see <http://www.gnu.org/licenses/>.
19 * Mark McLoughlin <mark@skynet.ie>
24 * @Short_description: A container which can hide its child
27 * A #GtkExpander allows the user to hide or show its child by clicking
28 * on an expander triangle similar to the triangles used in a #GtkTreeView.
30 * Normally you use an expander as you would use any other descendant
31 * of #GtkBin; you create the child widget and use gtk_container_add()
32 * to add it to the expander. When the expander is toggled, it will take
33 * care of showing and hiding the child automatically.
35 * <refsect2 id="expander-special-usage">
36 * <title>Special Usage</title>
38 * There are situations in which you may prefer to show and hide the
39 * expanded widget yourself, such as when you want to actually create
40 * the widget at expansion time. In this case, create a #GtkExpander
41 * but do not add a child to it. The expander widget has an
42 * #GtkExpander:expanded property which can be used to monitor
43 * its expansion state. You should watch this property with a signal
44 * connection as follows:
47 * <programlisting id="expander-callback-example">
48 * expander = gtk_expander_new_with_mnemonic ("_More Options");
49 * g_signal_connect (expander, "notify::expanded",
50 * G_CALLBACK (expander_callback), NULL);
55 * expander_callback (GObject *object,
56 * GParamSpec *param_spec,
59 * GtkExpander *expander;
61 * expander = GTK_EXPANDER (object);
63 * if (gtk_expander_get_expanded (expander))
65 * /* Show or create widgets */
69 * /* Hide or destroy widgets */
75 * <refsect2 id="GtkExpander-BUILDER-UI">
76 * <title>GtkExpander as GtkBuildable</title>
78 * The GtkExpander implementation of the GtkBuildable interface
79 * supports placing a child in the label position by specifying
80 * "label" as the "type" attribute of a <child> element.
81 * A normal content child can be specified without specifying
82 * a <child> type attribute.
85 * <title>A UI definition fragment with GtkExpander</title>
86 * <programlisting><![CDATA[
87 * <object class="GtkExpander">
88 * <child type="label">
89 * <object class="GtkLabel" id="expander-label"/>
92 * <object class="GtkEntry" id="expander-content"/>
95 * ]]></programlisting>
105 #include "gtkexpander.h"
107 #include "gtklabel.h"
108 #include "gtkbuildable.h"
109 #include "gtkcontainer.h"
110 #include "gtkmarshalers.h"
113 #include "gtkprivate.h"
115 #include "a11y/gtkexpanderaccessible.h"
118 #define DEFAULT_EXPANDER_SIZE 10
119 #define DEFAULT_EXPANDER_SPACING 2
134 struct _GtkExpanderPrivate
136 GtkWidget *label_widget;
137 GdkWindow *event_window;
143 guint use_underline : 1;
144 guint use_markup : 1;
145 guint button_down : 1;
147 guint label_fill : 1;
148 guint resize_toplevel : 1;
151 static void gtk_expander_set_property (GObject *object,
155 static void gtk_expander_get_property (GObject *object,
160 static void gtk_expander_destroy (GtkWidget *widget);
161 static void gtk_expander_realize (GtkWidget *widget);
162 static void gtk_expander_unrealize (GtkWidget *widget);
163 static void gtk_expander_size_allocate (GtkWidget *widget,
164 GtkAllocation *allocation);
165 static void gtk_expander_map (GtkWidget *widget);
166 static void gtk_expander_unmap (GtkWidget *widget);
167 static gboolean gtk_expander_draw (GtkWidget *widget,
169 static gboolean gtk_expander_button_press (GtkWidget *widget,
170 GdkEventButton *event);
171 static gboolean gtk_expander_button_release (GtkWidget *widget,
172 GdkEventButton *event);
173 static gboolean gtk_expander_enter_notify (GtkWidget *widget,
174 GdkEventCrossing *event);
175 static gboolean gtk_expander_leave_notify (GtkWidget *widget,
176 GdkEventCrossing *event);
177 static gboolean gtk_expander_focus (GtkWidget *widget,
178 GtkDirectionType direction);
179 static void gtk_expander_grab_notify (GtkWidget *widget,
180 gboolean was_grabbed);
181 static void gtk_expander_state_flags_changed (GtkWidget *widget,
182 GtkStateFlags previous_state);
183 static gboolean gtk_expander_drag_motion (GtkWidget *widget,
184 GdkDragContext *context,
188 static void gtk_expander_drag_leave (GtkWidget *widget,
189 GdkDragContext *context,
192 static void gtk_expander_add (GtkContainer *container,
194 static void gtk_expander_remove (GtkContainer *container,
196 static void gtk_expander_forall (GtkContainer *container,
197 gboolean include_internals,
198 GtkCallback callback,
199 gpointer callback_data);
201 static void gtk_expander_activate (GtkExpander *expander);
203 static void get_expander_bounds (GtkExpander *expander,
207 static void gtk_expander_buildable_init (GtkBuildableIface *iface);
208 static void gtk_expander_buildable_add_child (GtkBuildable *buildable,
215 static void gtk_expander_get_preferred_width (GtkWidget *widget,
218 static void gtk_expander_get_preferred_height (GtkWidget *widget,
221 static void gtk_expander_get_preferred_height_for_width (GtkWidget *layout,
223 gint *minimum_height,
224 gint *natural_height);
225 static void gtk_expander_get_preferred_width_for_height (GtkWidget *layout,
227 gint *minimum_height,
228 gint *natural_height);
230 G_DEFINE_TYPE_WITH_CODE (GtkExpander, gtk_expander, GTK_TYPE_BIN,
231 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
232 gtk_expander_buildable_init))
235 gtk_expander_class_init (GtkExpanderClass *klass)
237 GObjectClass *gobject_class;
238 GtkWidgetClass *widget_class;
239 GtkContainerClass *container_class;
241 gobject_class = (GObjectClass *) klass;
242 widget_class = (GtkWidgetClass *) klass;
243 container_class = (GtkContainerClass *) klass;
245 gobject_class->set_property = gtk_expander_set_property;
246 gobject_class->get_property = gtk_expander_get_property;
248 widget_class->destroy = gtk_expander_destroy;
249 widget_class->realize = gtk_expander_realize;
250 widget_class->unrealize = gtk_expander_unrealize;
251 widget_class->size_allocate = gtk_expander_size_allocate;
252 widget_class->map = gtk_expander_map;
253 widget_class->unmap = gtk_expander_unmap;
254 widget_class->draw = gtk_expander_draw;
255 widget_class->button_press_event = gtk_expander_button_press;
256 widget_class->button_release_event = gtk_expander_button_release;
257 widget_class->enter_notify_event = gtk_expander_enter_notify;
258 widget_class->leave_notify_event = gtk_expander_leave_notify;
259 widget_class->focus = gtk_expander_focus;
260 widget_class->grab_notify = gtk_expander_grab_notify;
261 widget_class->state_flags_changed = gtk_expander_state_flags_changed;
262 widget_class->drag_motion = gtk_expander_drag_motion;
263 widget_class->drag_leave = gtk_expander_drag_leave;
264 widget_class->get_preferred_width = gtk_expander_get_preferred_width;
265 widget_class->get_preferred_height = gtk_expander_get_preferred_height;
266 widget_class->get_preferred_height_for_width = gtk_expander_get_preferred_height_for_width;
267 widget_class->get_preferred_width_for_height = gtk_expander_get_preferred_width_for_height;
269 container_class->add = gtk_expander_add;
270 container_class->remove = gtk_expander_remove;
271 container_class->forall = gtk_expander_forall;
273 klass->activate = gtk_expander_activate;
275 g_type_class_add_private (klass, sizeof (GtkExpanderPrivate));
277 g_object_class_install_property (gobject_class,
279 g_param_spec_boolean ("expanded",
281 P_("Whether the expander has been opened to reveal the child widget"),
283 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
285 g_object_class_install_property (gobject_class,
287 g_param_spec_string ("label",
289 P_("Text of the expander's label"),
291 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
293 g_object_class_install_property (gobject_class,
295 g_param_spec_boolean ("use-underline",
297 P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
299 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
301 g_object_class_install_property (gobject_class,
303 g_param_spec_boolean ("use-markup",
305 P_("The text of the label includes XML markup. See pango_parse_markup()"),
307 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
309 g_object_class_install_property (gobject_class,
311 g_param_spec_int ("spacing",
313 P_("Space to put between the label and the child"),
317 GTK_PARAM_READWRITE));
319 g_object_class_install_property (gobject_class,
321 g_param_spec_object ("label-widget",
323 P_("A widget to display in place of the usual expander label"),
325 GTK_PARAM_READWRITE));
327 g_object_class_install_property (gobject_class,
329 g_param_spec_boolean ("label-fill",
331 P_("Whether the label widget should fill all available horizontal space"),
333 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
336 * GtkExpander:resize-toplevel:
338 * When this property is %TRUE, the expander will resize the toplevel
339 * widget containing the expander upon expanding and collapsing.
343 g_object_class_install_property (gobject_class,
344 PROP_RESIZE_TOPLEVEL,
345 g_param_spec_boolean ("resize-toplevel",
346 P_("Resize toplevel"),
347 P_("Whether the expander will resize the toplevel window upon expanding and collapsing"),
349 GTK_PARAM_READWRITE));
351 gtk_widget_class_install_style_property (widget_class,
352 g_param_spec_int ("expander-size",
354 P_("Size of the expander arrow"),
357 DEFAULT_EXPANDER_SIZE,
358 GTK_PARAM_READABLE));
360 gtk_widget_class_install_style_property (widget_class,
361 g_param_spec_int ("expander-spacing",
362 P_("Indicator Spacing"),
363 P_("Spacing around expander arrow"),
366 DEFAULT_EXPANDER_SPACING,
367 GTK_PARAM_READABLE));
369 widget_class->activate_signal =
370 g_signal_new (I_("activate"),
371 G_TYPE_FROM_CLASS (gobject_class),
372 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
373 G_STRUCT_OFFSET (GtkExpanderClass, activate),
375 _gtk_marshal_VOID__VOID,
378 gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_EXPANDER_ACCESSIBLE);
382 gtk_expander_init (GtkExpander *expander)
384 GtkExpanderPrivate *priv;
386 expander->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (expander,
390 gtk_widget_set_can_focus (GTK_WIDGET (expander), TRUE);
391 gtk_widget_set_has_window (GTK_WIDGET (expander), FALSE);
393 priv->label_widget = NULL;
394 priv->event_window = NULL;
397 priv->expanded = FALSE;
398 priv->use_underline = FALSE;
399 priv->use_markup = FALSE;
400 priv->button_down = FALSE;
401 priv->prelight = FALSE;
402 priv->label_fill = FALSE;
403 priv->expand_timer = 0;
404 priv->resize_toplevel = 0;
406 gtk_drag_dest_set (GTK_WIDGET (expander), 0, NULL, 0, 0);
407 gtk_drag_dest_set_track_motion (GTK_WIDGET (expander), TRUE);
411 gtk_expander_buildable_add_child (GtkBuildable *buildable,
417 gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child));
418 else if (strcmp (type, "label") == 0)
419 gtk_expander_set_label_widget (GTK_EXPANDER (buildable), GTK_WIDGET (child));
421 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (GTK_EXPANDER (buildable), type);
425 gtk_expander_buildable_init (GtkBuildableIface *iface)
427 iface->add_child = gtk_expander_buildable_add_child;
431 gtk_expander_set_property (GObject *object,
436 GtkExpander *expander = GTK_EXPANDER (object);
441 gtk_expander_set_expanded (expander, g_value_get_boolean (value));
444 gtk_expander_set_label (expander, g_value_get_string (value));
446 case PROP_USE_UNDERLINE:
447 gtk_expander_set_use_underline (expander, g_value_get_boolean (value));
449 case PROP_USE_MARKUP:
450 gtk_expander_set_use_markup (expander, g_value_get_boolean (value));
453 gtk_expander_set_spacing (expander, g_value_get_int (value));
455 case PROP_LABEL_WIDGET:
456 gtk_expander_set_label_widget (expander, g_value_get_object (value));
458 case PROP_LABEL_FILL:
459 gtk_expander_set_label_fill (expander, g_value_get_boolean (value));
461 case PROP_RESIZE_TOPLEVEL:
462 gtk_expander_set_resize_toplevel (expander, g_value_get_boolean (value));
465 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
471 gtk_expander_get_property (GObject *object,
476 GtkExpander *expander = GTK_EXPANDER (object);
477 GtkExpanderPrivate *priv = expander->priv;
482 g_value_set_boolean (value, priv->expanded);
485 g_value_set_string (value, gtk_expander_get_label (expander));
487 case PROP_USE_UNDERLINE:
488 g_value_set_boolean (value, priv->use_underline);
490 case PROP_USE_MARKUP:
491 g_value_set_boolean (value, priv->use_markup);
494 g_value_set_int (value, priv->spacing);
496 case PROP_LABEL_WIDGET:
497 g_value_set_object (value,
499 G_OBJECT (priv->label_widget) : NULL);
501 case PROP_LABEL_FILL:
502 g_value_set_boolean (value, priv->label_fill);
504 case PROP_RESIZE_TOPLEVEL:
505 g_value_set_boolean (value, gtk_expander_get_resize_toplevel (expander));
508 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
514 gtk_expander_destroy (GtkWidget *widget)
516 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
518 if (priv->expand_timer)
520 g_source_remove (priv->expand_timer);
521 priv->expand_timer = 0;
524 GTK_WIDGET_CLASS (gtk_expander_parent_class)->destroy (widget);
528 gtk_expander_realize (GtkWidget *widget)
530 GtkAllocation allocation;
531 GtkExpanderPrivate *priv;
533 GdkWindowAttr attributes;
534 gint attributes_mask;
536 GdkRectangle expander_rect;
539 priv = GTK_EXPANDER (widget)->priv;
541 gtk_widget_set_realized (widget, TRUE);
543 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
545 get_expander_bounds (GTK_EXPANDER (widget), &expander_rect);
547 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
549 GtkRequisition label_requisition;
551 gtk_widget_get_preferred_size (priv->label_widget,
552 &label_requisition, NULL);
553 label_height = label_requisition.height;
558 gtk_widget_get_allocation (widget, &allocation);
560 attributes.window_type = GDK_WINDOW_CHILD;
561 attributes.x = allocation.x + border_width;
562 attributes.y = allocation.y + border_width;
563 attributes.width = MAX (allocation.width - 2 * border_width, 1);
564 attributes.height = MAX (expander_rect.height, label_height - 2 * border_width);
565 attributes.wclass = GDK_INPUT_ONLY;
566 attributes.event_mask = gtk_widget_get_events (widget)
567 | GDK_BUTTON_PRESS_MASK
568 | GDK_BUTTON_RELEASE_MASK
569 | GDK_ENTER_NOTIFY_MASK
570 | GDK_LEAVE_NOTIFY_MASK;
572 attributes_mask = GDK_WA_X | GDK_WA_Y;
574 window = gtk_widget_get_parent_window (widget);
575 gtk_widget_set_window (widget, window);
576 g_object_ref (window);
578 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
579 &attributes, attributes_mask);
580 gdk_window_set_user_data (priv->event_window, widget);
584 gtk_expander_unrealize (GtkWidget *widget)
586 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
588 if (priv->event_window)
590 gdk_window_set_user_data (priv->event_window, NULL);
591 gdk_window_destroy (priv->event_window);
592 priv->event_window = NULL;
595 GTK_WIDGET_CLASS (gtk_expander_parent_class)->unrealize (widget);
599 get_expander_bounds (GtkExpander *expander,
602 GtkAllocation allocation;
604 GtkExpanderPrivate *priv;
607 gint expander_spacing;
608 gboolean interior_focus;
613 widget = GTK_WIDGET (expander);
614 priv = expander->priv;
616 gtk_widget_get_allocation (widget, &allocation);
618 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
620 gtk_widget_style_get (widget,
621 "interior-focus", &interior_focus,
622 "focus-line-width", &focus_width,
623 "focus-padding", &focus_pad,
624 "expander-size", &expander_size,
625 "expander-spacing", &expander_spacing,
628 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
630 rect->x = allocation.x + border_width;
631 rect->y = allocation.y + border_width;
634 rect->x += expander_spacing;
636 rect->x += allocation.width - 2 * border_width -
637 expander_spacing - expander_size;
639 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
641 GtkAllocation label_allocation;
643 gtk_widget_get_allocation (priv->label_widget, &label_allocation);
645 if (expander_size < label_allocation.height)
646 rect->y += focus_width + focus_pad + (label_allocation.height - expander_size) / 2;
648 rect->y += expander_spacing;
652 rect->y += expander_spacing;
658 rect->x += focus_width + focus_pad;
660 rect->x -= focus_width + focus_pad;
661 rect->y += focus_width + focus_pad;
664 rect->width = rect->height = expander_size;
668 gtk_expander_size_allocate (GtkWidget *widget,
669 GtkAllocation *allocation)
671 GtkExpander *expander;
673 GtkExpanderPrivate *priv;
674 gboolean child_visible = FALSE;
677 gint expander_spacing;
678 gboolean interior_focus;
681 gint label_height, top_min_height;
682 gint label_xpad, label_xoffset;
683 gint child_ypad, child_yoffset;
685 expander = GTK_EXPANDER (widget);
686 child = gtk_bin_get_child (GTK_BIN (widget));
687 priv = expander->priv;
689 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
691 gtk_widget_set_allocation (widget, allocation);
693 gtk_widget_style_get (widget,
694 "interior-focus", &interior_focus,
695 "focus-line-width", &focus_width,
696 "focus-padding", &focus_pad,
697 "expander-size", &expander_size,
698 "expander-spacing", &expander_spacing,
702 /* Calculate some offsets/padding first */
703 label_xoffset = border_width + expander_size + focus_width + 2 * expander_spacing + focus_pad;
704 label_xpad = 2 * border_width + expander_size + 2 * focus_width + 2 * expander_spacing + 2 * focus_pad;
706 child_yoffset = border_width + priv->spacing + (interior_focus ? 0 : 2 * focus_width + 2 * focus_pad);
707 child_ypad = 2 * border_width + priv->spacing + (interior_focus ? 0 : 2 * focus_width + 2 * focus_pad);
708 top_min_height = 2 * expander_spacing + expander_size;
710 child_visible = (child && gtk_widget_get_child_visible (child));
712 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
714 GtkAllocation label_allocation;
715 gint natural_label_width;
718 gtk_widget_get_preferred_width (priv->label_widget, NULL, &natural_label_width);
720 if (priv->label_fill)
721 label_allocation.width = allocation->width - label_xpad;
723 label_allocation.width = MIN (natural_label_width, allocation->width - label_xpad);
724 label_allocation.width = MAX (label_allocation.width, 1);
726 /* We distribute the minimum height to the label widget and prioritize
727 * the child widget giving it the remaining height
729 gtk_widget_get_preferred_height_for_width (priv->label_widget,
730 label_allocation.width, &label_height, NULL);
732 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
734 if (priv->label_fill)
735 label_allocation.x = allocation->x + label_xoffset;
737 label_allocation.x = allocation->x + label_xoffset;
739 label_allocation.x = allocation->x + allocation->width -
740 (label_allocation.width + label_xoffset);
742 label_allocation.y = allocation->y + border_width + focus_width + focus_pad;
743 label_allocation.height = MIN (label_height,
744 allocation->height - 2 * border_width -
745 2 * focus_width - 2 * focus_pad -
746 (child_visible ? priv->spacing : 0));
747 label_allocation.height = MAX (label_allocation.height, 1);
749 gtk_widget_size_allocate (priv->label_widget, &label_allocation);
751 label_height = label_allocation.height;
758 if (gtk_widget_get_realized (widget))
762 get_expander_bounds (expander, &rect);
764 gdk_window_move_resize (priv->event_window,
765 allocation->x + border_width,
766 allocation->y + border_width,
767 MAX (allocation->width - 2 * border_width, 1),
768 MAX (rect.height, label_height - 2 * border_width));
773 GtkAllocation child_allocation;
776 top_height = MAX (top_min_height,
777 label_height + (interior_focus ? 2 * focus_width + 2 * focus_pad : 0));
779 child_allocation.x = allocation->x + border_width;
780 child_allocation.y = allocation->y + top_height + child_yoffset;
782 child_allocation.width = MAX (allocation->width - 2 * border_width, 1);
783 child_allocation.height = allocation->height - top_height - child_ypad;
784 child_allocation.height = MAX (child_allocation.height, 1);
786 gtk_widget_size_allocate (child, &child_allocation);
791 gtk_expander_map (GtkWidget *widget)
793 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
795 if (priv->label_widget)
796 gtk_widget_map (priv->label_widget);
798 GTK_WIDGET_CLASS (gtk_expander_parent_class)->map (widget);
800 if (priv->event_window)
801 gdk_window_show (priv->event_window);
805 gtk_expander_unmap (GtkWidget *widget)
807 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
809 if (priv->event_window)
810 gdk_window_hide (priv->event_window);
812 GTK_WIDGET_CLASS (gtk_expander_parent_class)->unmap (widget);
814 if (priv->label_widget)
815 gtk_widget_unmap (priv->label_widget);
819 gtk_expander_paint_prelight (GtkExpander *expander,
822 GtkAllocation allocation;
824 GtkContainer *container;
825 GtkExpanderPrivate *priv;
827 GtkStyleContext *context;
828 gboolean interior_focus;
832 int expander_spacing;
835 priv = expander->priv;
836 widget = GTK_WIDGET (expander);
837 container = GTK_CONTAINER (expander);
839 gtk_widget_style_get (widget,
840 "interior-focus", &interior_focus,
841 "focus-line-width", &focus_width,
842 "focus-padding", &focus_pad,
843 "expander-size", &expander_size,
844 "expander-spacing", &expander_spacing,
847 gtk_widget_get_allocation (widget, &allocation);
849 border_width = gtk_container_get_border_width (container);
850 area.x = border_width;
851 area.y = border_width;
852 area.width = allocation.width - (2 * border_width);
854 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
856 GtkAllocation label_widget_allocation;
858 gtk_widget_get_allocation (priv->label_widget, &label_widget_allocation);
859 area.height = label_widget_allocation.height;
864 area.height += interior_focus ? (focus_width + focus_pad) * 2 : 0;
865 area.height = MAX (area.height, expander_size + 2 * expander_spacing);
866 area.height += !interior_focus ? (focus_width + focus_pad) * 2 : 0;
868 context = gtk_widget_get_style_context (widget);
869 gtk_render_background (context, cr,
871 area.width, area.height);
875 gtk_expander_paint (GtkExpander *expander,
878 GtkExpanderPrivate *priv = expander->priv;
881 GtkAllocation allocation;
882 GtkStyleContext *context;
883 GtkStateFlags state = 0;
886 widget = GTK_WIDGET (expander);
887 context = gtk_widget_get_style_context (widget);
888 state = gtk_widget_get_state_flags (widget);
890 get_expander_bounds (expander, &clip);
891 gtk_widget_get_allocation (widget, &allocation);
893 gtk_style_context_save (context);
895 state &= ~(GTK_STATE_FLAG_PRELIGHT);
896 if (expander->priv->prelight)
898 state |= GTK_STATE_FLAG_PRELIGHT;
899 gtk_style_context_set_state (context, state);
900 gtk_expander_paint_prelight (expander, cr);
903 gtk_widget_style_get (widget, "expander-size", &size, NULL);
905 /* Set active flag as per the expanded state */
907 state |= GTK_STATE_FLAG_ACTIVE;
909 state &= ~(GTK_STATE_FLAG_ACTIVE);
911 gtk_style_context_set_state (context, state);
912 gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
914 gtk_render_expander (context, cr,
915 clip.x - allocation.x,
916 clip.y - allocation.y,
919 gtk_style_context_restore (context);
923 gtk_expander_paint_focus (GtkExpander *expander,
927 GtkExpanderPrivate *priv;
929 GtkStyleContext *context;
930 gint x, y, width, height;
931 gboolean interior_focus;
936 gint expander_spacing;
938 GtkAllocation allocation;
940 widget = GTK_WIDGET (expander);
941 priv = expander->priv;
943 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
944 gtk_widget_get_allocation (widget, &allocation);
946 gtk_widget_style_get (widget,
947 "interior-focus", &interior_focus,
948 "focus-line-width", &focus_width,
949 "focus-padding", &focus_pad,
950 "expander-size", &expander_size,
951 "expander-spacing", &expander_spacing,
954 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
958 if (priv->label_widget)
960 if (gtk_widget_get_visible (priv->label_widget))
962 GtkAllocation label_allocation;
964 gtk_widget_get_allocation (priv->label_widget, &label_allocation);
965 width = label_allocation.width;
966 height = label_allocation.height;
969 width += 2 * focus_pad + 2 * focus_width;
970 height += 2 * focus_pad + 2 * focus_width;
978 x += expander_spacing * 2 + expander_size;
982 x += allocation.width - 2 * border_width
983 - expander_spacing * 2 - expander_size - width;
988 width += expander_size + 2 * expander_spacing;
989 height = MAX (height, expander_size + 2 * expander_spacing);
994 get_expander_bounds (expander, &rect);
996 x = rect.x - allocation.x - focus_pad;
997 y = rect.y - allocation.y - focus_pad;
998 width = rect.width + 2 * focus_pad;
999 height = rect.height + 2 * focus_pad;
1002 context = gtk_widget_get_style_context (widget);
1003 gtk_render_focus (context, cr,
1004 x, y, width, height);
1008 gtk_expander_draw (GtkWidget *widget,
1011 GtkExpander *expander = GTK_EXPANDER (widget);
1013 gtk_expander_paint (expander, cr);
1015 if (gtk_widget_has_visible_focus (widget))
1016 gtk_expander_paint_focus (expander, cr);
1018 GTK_WIDGET_CLASS (gtk_expander_parent_class)->draw (widget, cr);
1024 gtk_expander_button_press (GtkWidget *widget,
1025 GdkEventButton *event)
1027 GtkExpander *expander = GTK_EXPANDER (widget);
1029 if (event->button == GDK_BUTTON_PRIMARY && event->window == expander->priv->event_window)
1031 expander->priv->button_down = TRUE;
1039 gtk_expander_button_release (GtkWidget *widget,
1040 GdkEventButton *event)
1042 GtkExpander *expander = GTK_EXPANDER (widget);
1044 if (event->button == GDK_BUTTON_PRIMARY && expander->priv->button_down)
1046 gtk_widget_activate (widget);
1047 expander->priv->button_down = FALSE;
1055 gtk_expander_grab_notify (GtkWidget *widget,
1056 gboolean was_grabbed)
1059 GTK_EXPANDER (widget)->priv->button_down = FALSE;
1063 gtk_expander_state_flags_changed (GtkWidget *widget,
1064 GtkStateFlags previous_state)
1066 if (!gtk_widget_is_sensitive (widget))
1067 GTK_EXPANDER (widget)->priv->button_down = FALSE;
1071 gtk_expander_redraw_expander (GtkExpander *expander)
1073 GtkAllocation allocation;
1074 GtkWidget *widget = GTK_WIDGET (expander);
1076 if (gtk_widget_get_realized (widget))
1078 gtk_widget_get_allocation (widget, &allocation);
1079 gdk_window_invalidate_rect (gtk_widget_get_window (widget), &allocation, FALSE);
1084 gtk_expander_enter_notify (GtkWidget *widget,
1085 GdkEventCrossing *event)
1087 GtkExpander *expander = GTK_EXPANDER (widget);
1089 if (event->window == expander->priv->event_window &&
1090 event->detail != GDK_NOTIFY_INFERIOR)
1092 expander->priv->prelight = TRUE;
1094 if (expander->priv->label_widget)
1095 gtk_widget_set_state_flags (expander->priv->label_widget,
1096 GTK_STATE_FLAG_PRELIGHT,
1099 gtk_expander_redraw_expander (expander);
1106 gtk_expander_leave_notify (GtkWidget *widget,
1107 GdkEventCrossing *event)
1109 GtkExpander *expander = GTK_EXPANDER (widget);
1111 if (event->window == expander->priv->event_window &&
1112 event->detail != GDK_NOTIFY_INFERIOR)
1114 expander->priv->prelight = FALSE;
1116 if (expander->priv->label_widget)
1117 gtk_widget_unset_state_flags (expander->priv->label_widget,
1118 GTK_STATE_FLAG_PRELIGHT);
1120 gtk_expander_redraw_expander (expander);
1127 expand_timeout (gpointer data)
1129 GtkExpander *expander = GTK_EXPANDER (data);
1130 GtkExpanderPrivate *priv = expander->priv;
1132 priv->expand_timer = 0;
1133 gtk_expander_set_expanded (expander, TRUE);
1139 gtk_expander_drag_motion (GtkWidget *widget,
1140 GdkDragContext *context,
1145 GtkExpander *expander = GTK_EXPANDER (widget);
1146 GtkExpanderPrivate *priv = expander->priv;
1148 if (!priv->expanded && !priv->expand_timer)
1150 GtkSettings *settings;
1153 settings = gtk_widget_get_settings (widget);
1154 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
1156 priv->expand_timer = gdk_threads_add_timeout (timeout, (GSourceFunc) expand_timeout, expander);
1163 gtk_expander_drag_leave (GtkWidget *widget,
1164 GdkDragContext *context,
1167 GtkExpander *expander = GTK_EXPANDER (widget);
1168 GtkExpanderPrivate *priv = expander->priv;
1170 if (priv->expand_timer)
1172 g_source_remove (priv->expand_timer);
1173 priv->expand_timer = 0;
1186 focus_current_site (GtkExpander *expander,
1187 GtkDirectionType direction)
1189 GtkWidget *current_focus;
1191 current_focus = gtk_container_get_focus_child (GTK_CONTAINER (expander));
1196 return gtk_widget_child_focus (current_focus, direction);
1200 focus_in_site (GtkExpander *expander,
1202 GtkDirectionType direction)
1207 gtk_widget_grab_focus (GTK_WIDGET (expander));
1210 if (expander->priv->label_widget)
1211 return gtk_widget_child_focus (expander->priv->label_widget, direction);
1216 GtkWidget *child = gtk_bin_get_child (GTK_BIN (expander));
1218 if (child && gtk_widget_get_child_visible (child))
1219 return gtk_widget_child_focus (child, direction);
1227 g_assert_not_reached ();
1232 get_next_site (GtkExpander *expander,
1234 GtkDirectionType direction)
1238 ltr = gtk_widget_get_direction (GTK_WIDGET (expander)) != GTK_TEXT_DIR_RTL;
1245 case GTK_DIR_TAB_BACKWARD:
1249 case GTK_DIR_TAB_FORWARD:
1252 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:
1300 g_assert_not_reached ();
1305 gtk_expander_resize_toplevel (GtkExpander *expander)
1307 GtkExpanderPrivate *priv = expander->priv;
1308 GtkWidget *child = gtk_bin_get_child (GTK_BIN (expander));
1310 if (child && priv->resize_toplevel &&
1311 gtk_widget_get_realized (GTK_WIDGET (expander)))
1313 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (expander));
1315 if (toplevel && gtk_widget_get_realized (toplevel))
1317 GtkAllocation toplevel_allocation;
1319 gtk_widget_get_allocation (toplevel, &toplevel_allocation);
1323 GtkRequisition child_requisition;
1325 gtk_widget_get_preferred_size (child, &child_requisition, NULL);
1327 toplevel_allocation.height += child_requisition.height;
1331 GtkAllocation child_allocation;
1333 gtk_widget_get_allocation (child, &child_allocation);
1335 toplevel_allocation.height -= child_allocation.height;
1338 gtk_window_resize (GTK_WINDOW (toplevel),
1339 toplevel_allocation.width,
1340 toplevel_allocation.height);
1346 gtk_expander_focus (GtkWidget *widget,
1347 GtkDirectionType direction)
1349 GtkExpander *expander = GTK_EXPANDER (widget);
1351 if (!focus_current_site (expander, direction))
1353 GtkWidget *old_focus_child;
1354 gboolean widget_is_focus;
1355 FocusSite site = FOCUS_NONE;
1357 widget_is_focus = gtk_widget_is_focus (widget);
1358 old_focus_child = gtk_container_get_focus_child (GTK_CONTAINER (widget));
1360 if (old_focus_child && old_focus_child == expander->priv->label_widget)
1362 else if (old_focus_child)
1364 else if (widget_is_focus)
1365 site = FOCUS_WIDGET;
1367 while ((site = get_next_site (expander, site, direction)) != FOCUS_NONE)
1369 if (focus_in_site (expander, site, direction))
1380 gtk_expander_add (GtkContainer *container,
1383 GTK_CONTAINER_CLASS (gtk_expander_parent_class)->add (container, widget);
1385 gtk_widget_set_child_visible (widget, GTK_EXPANDER (container)->priv->expanded);
1386 gtk_widget_queue_resize (GTK_WIDGET (container));
1390 gtk_expander_remove (GtkContainer *container,
1393 GtkExpander *expander = GTK_EXPANDER (container);
1395 if (GTK_EXPANDER (expander)->priv->label_widget == widget)
1396 gtk_expander_set_label_widget (expander, NULL);
1398 GTK_CONTAINER_CLASS (gtk_expander_parent_class)->remove (container, widget);
1402 gtk_expander_forall (GtkContainer *container,
1403 gboolean include_internals,
1404 GtkCallback callback,
1405 gpointer callback_data)
1407 GtkBin *bin = GTK_BIN (container);
1408 GtkExpanderPrivate *priv = GTK_EXPANDER (container)->priv;
1411 child = gtk_bin_get_child (bin);
1413 (* callback) (child, callback_data);
1415 if (priv->label_widget)
1416 (* callback) (priv->label_widget, callback_data);
1420 gtk_expander_activate (GtkExpander *expander)
1422 gtk_expander_set_expanded (expander, !expander->priv->expanded);
1427 gtk_expander_get_preferred_width (GtkWidget *widget,
1431 GtkExpander *expander;
1433 GtkExpanderPrivate *priv;
1436 gint expander_spacing;
1437 gboolean interior_focus;
1441 child = gtk_bin_get_child (GTK_BIN (widget));
1442 expander = GTK_EXPANDER (widget);
1443 priv = expander->priv;
1445 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1447 gtk_widget_style_get (GTK_WIDGET (widget),
1448 "interior-focus", &interior_focus,
1449 "focus-line-width", &focus_width,
1450 "focus-padding", &focus_pad,
1451 "expander-size", &expander_size,
1452 "expander-spacing", &expander_spacing,
1455 *minimum_size = *natural_size =
1456 expander_size + 2 * expander_spacing +
1457 2 * focus_width + 2 * focus_pad;
1459 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
1461 gint label_min, label_nat;
1463 gtk_widget_get_preferred_width (priv->label_widget,
1464 &label_min, &label_nat);
1466 *minimum_size += label_min;
1467 *natural_size += label_nat;
1470 if (child && gtk_widget_get_child_visible (child))
1472 gint child_min, child_nat;
1474 gtk_widget_get_preferred_width (child,
1475 &child_min, &child_nat);
1477 *minimum_size = MAX (*minimum_size, child_min);
1478 *natural_size = MAX (*natural_size, child_nat);
1482 *minimum_size += 2 * border_width;
1483 *natural_size += 2 * border_width;
1487 gtk_expander_get_preferred_height (GtkWidget *widget,
1491 GtkExpander *expander;
1493 GtkExpanderPrivate *priv;
1496 gint expander_spacing;
1497 gboolean interior_focus;
1501 child = gtk_bin_get_child (GTK_BIN (widget));
1502 expander = GTK_EXPANDER (widget);
1503 priv = expander->priv;
1505 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1507 gtk_widget_style_get (GTK_WIDGET (widget),
1508 "interior-focus", &interior_focus,
1509 "focus-line-width", &focus_width,
1510 "focus-padding", &focus_pad,
1511 "expander-size", &expander_size,
1512 "expander-spacing", &expander_spacing,
1515 *minimum_size = *natural_size =
1516 interior_focus ? (2 * focus_width + 2 * focus_pad) : 0;
1519 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
1521 gint label_min, label_nat;
1523 gtk_widget_get_preferred_height (priv->label_widget,
1524 &label_min, &label_nat);
1526 *minimum_size += label_min;
1527 *natural_size += label_nat;
1530 *minimum_size = MAX (*minimum_size, expander_size + 2 * expander_spacing);
1531 *natural_size = MAX (*natural_size, *minimum_size);
1533 if (!interior_focus)
1535 gint extra = 2 * focus_width + 2 * focus_pad;
1536 *minimum_size += extra;
1537 *natural_size += extra;
1540 if (child && gtk_widget_get_child_visible (child))
1542 gint child_min, child_nat;
1544 gtk_widget_get_preferred_height (child,
1545 &child_min, &child_nat);
1547 *minimum_size += child_min + priv->spacing;
1548 *natural_size += child_nat + priv->spacing;
1552 *minimum_size += 2 * border_width;
1553 *natural_size += 2 * border_width;
1557 gtk_expander_get_preferred_height_for_width (GtkWidget *widget,
1559 gint *minimum_height,
1560 gint *natural_height)
1562 GtkExpander *expander;
1564 GtkExpanderPrivate *priv;
1567 gint expander_spacing;
1568 gboolean interior_focus;
1573 child = gtk_bin_get_child (GTK_BIN (widget));
1574 expander = GTK_EXPANDER (widget);
1575 priv = expander->priv;
1577 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1579 gtk_widget_style_get (GTK_WIDGET (widget),
1580 "interior-focus", &interior_focus,
1581 "focus-line-width", &focus_width,
1582 "focus-padding", &focus_pad,
1583 "expander-size", &expander_size,
1584 "expander-spacing", &expander_spacing,
1587 label_xpad = 2 * border_width + expander_size + 2 * expander_spacing - 2 * focus_width + 2 * focus_pad;
1589 *minimum_height = *natural_height =
1590 interior_focus ? (2 * focus_width + 2 * focus_pad) : 0;
1593 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
1595 gint label_min, label_nat;
1597 gtk_widget_get_preferred_height_for_width (priv->label_widget,
1598 MAX (width - label_xpad, 1),
1599 &label_min, &label_nat);
1601 *minimum_height += label_min;
1602 *natural_height += label_nat;
1605 *minimum_height = MAX (*minimum_height, expander_size + 2 * expander_spacing);
1606 *natural_height = MAX (*natural_height, *minimum_height);
1608 if (!interior_focus)
1610 gint extra = 2 * focus_width + 2 * focus_pad;
1611 *minimum_height += extra;
1612 *natural_height += extra;
1615 if (child && gtk_widget_get_child_visible (child))
1617 gint child_min, child_nat;
1619 gtk_widget_get_preferred_height_for_width (child,
1620 MAX (width - 2 * border_width, 1),
1621 &child_min, &child_nat);
1623 *minimum_height += child_min + priv->spacing;
1624 *natural_height += child_nat + priv->spacing;
1627 *minimum_height += 2 * border_width;
1628 *natural_height += 2 * border_width;
1632 gtk_expander_get_preferred_width_for_height (GtkWidget *widget,
1634 gint *minimum_width,
1635 gint *natural_width)
1637 GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_width, natural_width);
1644 * @label: the text of the label
1646 * Creates a new expander using @label as the text of the label.
1648 * Return value: a new #GtkExpander widget.
1653 gtk_expander_new (const gchar *label)
1655 return g_object_new (GTK_TYPE_EXPANDER, "label", label, NULL);
1659 * gtk_expander_new_with_mnemonic:
1660 * @label: (allow-none): the text of the label with an underscore
1661 * in front of the mnemonic character
1663 * Creates a new expander using @label as the text of the label.
1664 * If characters in @label are preceded by an underscore, they are underlined.
1665 * If you need a literal underscore character in a label, use '__' (two
1666 * underscores). The first underlined character represents a keyboard
1667 * accelerator called a mnemonic.
1668 * Pressing Alt and that key activates the button.
1670 * Return value: a new #GtkExpander widget.
1675 gtk_expander_new_with_mnemonic (const gchar *label)
1677 return g_object_new (GTK_TYPE_EXPANDER,
1679 "use-underline", TRUE,
1684 * gtk_expander_set_expanded:
1685 * @expander: a #GtkExpander
1686 * @expanded: whether the child widget is revealed
1688 * Sets the state of the expander. Set to %TRUE, if you want
1689 * the child widget to be revealed, and %FALSE if you want the
1690 * child widget to be hidden.
1695 gtk_expander_set_expanded (GtkExpander *expander,
1698 GtkExpanderPrivate *priv;
1701 g_return_if_fail (GTK_IS_EXPANDER (expander));
1703 priv = expander->priv;
1705 expanded = expanded != FALSE;
1707 if (priv->expanded != expanded)
1709 GtkWidget *widget = GTK_WIDGET (expander);
1711 priv->expanded = expanded;
1713 child = gtk_bin_get_child (GTK_BIN (expander));
1717 gtk_widget_set_child_visible (child, priv->expanded);
1718 gtk_widget_queue_resize (widget);
1719 gtk_expander_resize_toplevel (expander);
1722 g_object_notify (G_OBJECT (expander), "expanded");
1727 * gtk_expander_get_expanded:
1728 * @expander:a #GtkExpander
1730 * Queries a #GtkExpander and returns its current state. Returns %TRUE
1731 * if the child widget is revealed.
1733 * See gtk_expander_set_expanded().
1735 * Return value: the current state of the expander
1740 gtk_expander_get_expanded (GtkExpander *expander)
1742 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1744 return expander->priv->expanded;
1748 * gtk_expander_set_spacing:
1749 * @expander: a #GtkExpander
1750 * @spacing: distance between the expander and child in pixels
1752 * Sets the spacing field of @expander, which is the number of
1753 * pixels to place between expander and the child.
1758 gtk_expander_set_spacing (GtkExpander *expander,
1761 g_return_if_fail (GTK_IS_EXPANDER (expander));
1762 g_return_if_fail (spacing >= 0);
1764 if (expander->priv->spacing != spacing)
1766 expander->priv->spacing = spacing;
1768 gtk_widget_queue_resize (GTK_WIDGET (expander));
1770 g_object_notify (G_OBJECT (expander), "spacing");
1775 * gtk_expander_get_spacing:
1776 * @expander: a #GtkExpander
1778 * Gets the value set by gtk_expander_set_spacing().
1780 * Return value: spacing between the expander and child
1785 gtk_expander_get_spacing (GtkExpander *expander)
1787 g_return_val_if_fail (GTK_IS_EXPANDER (expander), 0);
1789 return expander->priv->spacing;
1793 * gtk_expander_set_label:
1794 * @expander: a #GtkExpander
1795 * @label: (allow-none): a string
1797 * Sets the text of the label of the expander to @label.
1799 * This will also clear any previously set labels.
1804 gtk_expander_set_label (GtkExpander *expander,
1807 g_return_if_fail (GTK_IS_EXPANDER (expander));
1811 gtk_expander_set_label_widget (expander, NULL);
1817 child = gtk_label_new (label);
1818 gtk_label_set_use_underline (GTK_LABEL (child), expander->priv->use_underline);
1819 gtk_label_set_use_markup (GTK_LABEL (child), expander->priv->use_markup);
1820 gtk_widget_show (child);
1822 gtk_expander_set_label_widget (expander, child);
1825 g_object_notify (G_OBJECT (expander), "label");
1829 * gtk_expander_get_label:
1830 * @expander: a #GtkExpander
1832 * Fetches the text from a label widget including any embedded
1833 * underlines indicating mnemonics and Pango markup, as set by
1834 * gtk_expander_set_label(). If the label text has not been set the
1835 * return value will be %NULL. This will be the case if you create an
1836 * empty button with gtk_button_new() to use as a container.
1838 * Note that this function behaved differently in versions prior to
1839 * 2.14 and used to return the label text stripped of embedded
1840 * underlines indicating mnemonics and Pango markup. This problem can
1841 * be avoided by fetching the label text directly from the label
1844 * Return value: The text of the label widget. This string is owned
1845 * by the widget and must not be modified or freed.
1850 gtk_expander_get_label (GtkExpander *expander)
1852 GtkExpanderPrivate *priv;
1854 g_return_val_if_fail (GTK_IS_EXPANDER (expander), NULL);
1856 priv = expander->priv;
1858 if (GTK_IS_LABEL (priv->label_widget))
1859 return gtk_label_get_label (GTK_LABEL (priv->label_widget));
1865 * gtk_expander_set_use_underline:
1866 * @expander: a #GtkExpander
1867 * @use_underline: %TRUE if underlines in the text indicate mnemonics
1869 * If true, an underline in the text of the expander label indicates
1870 * the next character should be used for the mnemonic accelerator key.
1875 gtk_expander_set_use_underline (GtkExpander *expander,
1876 gboolean use_underline)
1878 GtkExpanderPrivate *priv;
1880 g_return_if_fail (GTK_IS_EXPANDER (expander));
1882 priv = expander->priv;
1884 use_underline = use_underline != FALSE;
1886 if (priv->use_underline != use_underline)
1888 priv->use_underline = use_underline;
1890 if (GTK_IS_LABEL (priv->label_widget))
1891 gtk_label_set_use_underline (GTK_LABEL (priv->label_widget), use_underline);
1893 g_object_notify (G_OBJECT (expander), "use-underline");
1898 * gtk_expander_get_use_underline:
1899 * @expander: a #GtkExpander
1901 * Returns whether an embedded underline in the expander label
1902 * indicates a mnemonic. See gtk_expander_set_use_underline().
1904 * Return value: %TRUE if an embedded underline in the expander
1905 * label indicates the mnemonic accelerator keys
1910 gtk_expander_get_use_underline (GtkExpander *expander)
1912 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1914 return expander->priv->use_underline;
1918 * gtk_expander_set_use_markup:
1919 * @expander: a #GtkExpander
1920 * @use_markup: %TRUE if the label's text should be parsed for markup
1922 * Sets whether the text of the label contains markup in <link
1923 * linkend="PangoMarkupFormat">Pango's text markup
1924 * language</link>. See gtk_label_set_markup().
1929 gtk_expander_set_use_markup (GtkExpander *expander,
1930 gboolean use_markup)
1932 GtkExpanderPrivate *priv;
1934 g_return_if_fail (GTK_IS_EXPANDER (expander));
1936 priv = expander->priv;
1938 use_markup = use_markup != FALSE;
1940 if (priv->use_markup != use_markup)
1942 priv->use_markup = use_markup;
1944 if (GTK_IS_LABEL (priv->label_widget))
1945 gtk_label_set_use_markup (GTK_LABEL (priv->label_widget), use_markup);
1947 g_object_notify (G_OBJECT (expander), "use-markup");
1952 * gtk_expander_get_use_markup:
1953 * @expander: a #GtkExpander
1955 * Returns whether the label's text is interpreted as marked up with
1956 * the <link linkend="PangoMarkupFormat">Pango text markup
1957 * language</link>. See gtk_expander_set_use_markup().
1959 * Return value: %TRUE if the label's text will be parsed for markup
1964 gtk_expander_get_use_markup (GtkExpander *expander)
1966 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1968 return expander->priv->use_markup;
1972 * gtk_expander_set_label_widget:
1973 * @expander: a #GtkExpander
1974 * @label_widget: (allow-none): the new label widget
1976 * Set the label widget for the expander. This is the widget
1977 * that will appear embedded alongside the expander arrow.
1982 gtk_expander_set_label_widget (GtkExpander *expander,
1983 GtkWidget *label_widget)
1985 GtkExpanderPrivate *priv;
1988 g_return_if_fail (GTK_IS_EXPANDER (expander));
1989 g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget));
1990 g_return_if_fail (label_widget == NULL || gtk_widget_get_parent (label_widget) == NULL);
1992 priv = expander->priv;
1994 if (priv->label_widget == label_widget)
1997 if (priv->label_widget)
1999 gtk_widget_set_state_flags (priv->label_widget, 0, TRUE);
2000 gtk_widget_unparent (priv->label_widget);
2003 priv->label_widget = label_widget;
2004 widget = GTK_WIDGET (expander);
2008 priv->label_widget = label_widget;
2010 gtk_widget_set_parent (label_widget, widget);
2013 gtk_widget_set_state_flags (label_widget,
2014 GTK_STATE_FLAG_PRELIGHT,
2018 if (gtk_widget_get_visible (widget))
2019 gtk_widget_queue_resize (widget);
2021 g_object_freeze_notify (G_OBJECT (expander));
2022 g_object_notify (G_OBJECT (expander), "label-widget");
2023 g_object_notify (G_OBJECT (expander), "label");
2024 g_object_thaw_notify (G_OBJECT (expander));
2028 * gtk_expander_get_label_widget:
2029 * @expander: a #GtkExpander
2031 * Retrieves the label widget for the frame. See
2032 * gtk_expander_set_label_widget().
2034 * Return value: (transfer none): the label widget,
2035 * or %NULL if there is none
2040 gtk_expander_get_label_widget (GtkExpander *expander)
2042 g_return_val_if_fail (GTK_IS_EXPANDER (expander), NULL);
2044 return expander->priv->label_widget;
2048 * gtk_expander_set_label_fill:
2049 * @expander: a #GtkExpander
2050 * @label_fill: %TRUE if the label should should fill
2051 * all available horizontal space
2053 * Sets whether the label widget should fill all available
2054 * horizontal space allocated to @expander.
2059 gtk_expander_set_label_fill (GtkExpander *expander,
2060 gboolean label_fill)
2062 GtkExpanderPrivate *priv;
2064 g_return_if_fail (GTK_IS_EXPANDER (expander));
2066 priv = expander->priv;
2068 label_fill = label_fill != FALSE;
2070 if (priv->label_fill != label_fill)
2072 priv->label_fill = label_fill;
2074 if (priv->label_widget != NULL)
2075 gtk_widget_queue_resize (GTK_WIDGET (expander));
2077 g_object_notify (G_OBJECT (expander), "label-fill");
2082 * gtk_expander_get_label_fill:
2083 * @expander: a #GtkExpander
2085 * Returns whether the label widget will fill all available
2086 * horizontal space allocated to @expander.
2088 * Return value: %TRUE if the label widget will fill all
2089 * available horizontal space
2094 gtk_expander_get_label_fill (GtkExpander *expander)
2096 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
2098 return expander->priv->label_fill;
2102 * gtk_expander_set_resize_toplevel:
2103 * @expander: a #GtkExpander
2104 * @resize_toplevel: whether to resize the toplevel
2106 * Sets whether the expander will resize the toplevel widget
2107 * containing the expander upon resizing and collpasing.
2112 gtk_expander_set_resize_toplevel (GtkExpander *expander,
2113 gboolean resize_toplevel)
2115 g_return_if_fail (GTK_IS_EXPANDER (expander));
2117 if (expander->priv->resize_toplevel != resize_toplevel)
2119 expander->priv->resize_toplevel = resize_toplevel ? TRUE : FALSE;
2120 g_object_notify (G_OBJECT (expander), "resize-toplevel");
2125 * gtk_expander_get_resize_toplevel:
2126 * @expander: a #GtkExpander
2128 * Returns whether the expander will resize the toplevel widget
2129 * containing the expander upon resizing and collpasing.
2131 * Return value: the "resize toplevel" setting.
2136 gtk_expander_get_resize_toplevel (GtkExpander *expander)
2138 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
2140 return expander->priv->resize_toplevel;