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 tolevel"),
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);
891 get_expander_bounds (expander, &clip);
892 gtk_widget_get_allocation (widget, &allocation);
894 gtk_style_context_save (context);
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 state = gtk_style_context_get_state (context);
907 /* Set active flag as per the expanded state */
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 /* The expander is the only animatable region */
915 gtk_style_context_push_animatable_region (context, GUINT_TO_POINTER (1));
917 gtk_render_expander (context, cr,
918 clip.x - allocation.x,
919 clip.y - allocation.y,
922 gtk_style_context_pop_animatable_region (context);
923 gtk_style_context_restore (context);
927 gtk_expander_paint_focus (GtkExpander *expander,
931 GtkExpanderPrivate *priv;
933 GtkStyleContext *context;
934 gint x, y, width, height;
935 gboolean interior_focus;
940 gint expander_spacing;
942 GtkAllocation allocation;
944 widget = GTK_WIDGET (expander);
945 priv = expander->priv;
947 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
948 gtk_widget_get_allocation (widget, &allocation);
950 gtk_widget_style_get (widget,
951 "interior-focus", &interior_focus,
952 "focus-line-width", &focus_width,
953 "focus-padding", &focus_pad,
954 "expander-size", &expander_size,
955 "expander-spacing", &expander_spacing,
958 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
962 if (priv->label_widget)
964 if (gtk_widget_get_visible (priv->label_widget))
966 GtkAllocation label_allocation;
968 gtk_widget_get_allocation (priv->label_widget, &label_allocation);
969 width = label_allocation.width;
970 height = label_allocation.height;
973 width += 2 * focus_pad + 2 * focus_width;
974 height += 2 * focus_pad + 2 * focus_width;
982 x += expander_spacing * 2 + expander_size;
986 x += allocation.width - 2 * border_width
987 - expander_spacing * 2 - expander_size - width;
992 width += expander_size + 2 * expander_spacing;
993 height = MAX (height, expander_size + 2 * expander_spacing);
998 get_expander_bounds (expander, &rect);
1000 x = rect.x - allocation.x - focus_pad;
1001 y = rect.y - allocation.y - focus_pad;
1002 width = rect.width + 2 * focus_pad;
1003 height = rect.height + 2 * focus_pad;
1006 context = gtk_widget_get_style_context (widget);
1007 gtk_render_focus (context, cr,
1008 x, y, width, height);
1012 gtk_expander_draw (GtkWidget *widget,
1015 GtkExpander *expander = GTK_EXPANDER (widget);
1017 gtk_expander_paint (expander, cr);
1019 if (gtk_widget_has_focus (widget))
1020 gtk_expander_paint_focus (expander, cr);
1022 GTK_WIDGET_CLASS (gtk_expander_parent_class)->draw (widget, cr);
1028 gtk_expander_button_press (GtkWidget *widget,
1029 GdkEventButton *event)
1031 GtkExpander *expander = GTK_EXPANDER (widget);
1033 if (event->button == 1 && event->window == expander->priv->event_window)
1035 expander->priv->button_down = TRUE;
1043 gtk_expander_button_release (GtkWidget *widget,
1044 GdkEventButton *event)
1046 GtkExpander *expander = GTK_EXPANDER (widget);
1048 if (event->button == 1 && expander->priv->button_down)
1050 gtk_widget_activate (widget);
1051 expander->priv->button_down = FALSE;
1059 gtk_expander_grab_notify (GtkWidget *widget,
1060 gboolean was_grabbed)
1063 GTK_EXPANDER (widget)->priv->button_down = FALSE;
1067 gtk_expander_state_flags_changed (GtkWidget *widget,
1068 GtkStateFlags previous_state)
1070 if (!gtk_widget_is_sensitive (widget))
1071 GTK_EXPANDER (widget)->priv->button_down = FALSE;
1075 gtk_expander_redraw_expander (GtkExpander *expander)
1077 GtkAllocation allocation;
1078 GtkWidget *widget = GTK_WIDGET (expander);
1080 if (gtk_widget_get_realized (widget))
1082 gtk_widget_get_allocation (widget, &allocation);
1083 gdk_window_invalidate_rect (gtk_widget_get_window (widget), &allocation, FALSE);
1088 gtk_expander_enter_notify (GtkWidget *widget,
1089 GdkEventCrossing *event)
1091 GtkExpander *expander = GTK_EXPANDER (widget);
1093 if (event->window == expander->priv->event_window &&
1094 event->detail != GDK_NOTIFY_INFERIOR)
1096 expander->priv->prelight = TRUE;
1098 if (expander->priv->label_widget)
1099 gtk_widget_set_state_flags (expander->priv->label_widget,
1100 GTK_STATE_FLAG_PRELIGHT,
1103 gtk_expander_redraw_expander (expander);
1110 gtk_expander_leave_notify (GtkWidget *widget,
1111 GdkEventCrossing *event)
1113 GtkExpander *expander = GTK_EXPANDER (widget);
1115 if (event->window == expander->priv->event_window &&
1116 event->detail != GDK_NOTIFY_INFERIOR)
1118 expander->priv->prelight = FALSE;
1120 if (expander->priv->label_widget)
1121 gtk_widget_unset_state_flags (expander->priv->label_widget,
1122 GTK_STATE_FLAG_PRELIGHT);
1124 gtk_expander_redraw_expander (expander);
1131 expand_timeout (gpointer data)
1133 GtkExpander *expander = GTK_EXPANDER (data);
1134 GtkExpanderPrivate *priv = expander->priv;
1136 priv->expand_timer = 0;
1137 gtk_expander_set_expanded (expander, TRUE);
1143 gtk_expander_drag_motion (GtkWidget *widget,
1144 GdkDragContext *context,
1149 GtkExpander *expander = GTK_EXPANDER (widget);
1150 GtkExpanderPrivate *priv = expander->priv;
1152 if (!priv->expanded && !priv->expand_timer)
1154 GtkSettings *settings;
1157 settings = gtk_widget_get_settings (widget);
1158 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
1160 priv->expand_timer = gdk_threads_add_timeout (timeout, (GSourceFunc) expand_timeout, expander);
1167 gtk_expander_drag_leave (GtkWidget *widget,
1168 GdkDragContext *context,
1171 GtkExpander *expander = GTK_EXPANDER (widget);
1172 GtkExpanderPrivate *priv = expander->priv;
1174 if (priv->expand_timer)
1176 g_source_remove (priv->expand_timer);
1177 priv->expand_timer = 0;
1190 focus_current_site (GtkExpander *expander,
1191 GtkDirectionType direction)
1193 GtkWidget *current_focus;
1195 current_focus = gtk_container_get_focus_child (GTK_CONTAINER (expander));
1200 return gtk_widget_child_focus (current_focus, direction);
1204 focus_in_site (GtkExpander *expander,
1206 GtkDirectionType direction)
1211 gtk_widget_grab_focus (GTK_WIDGET (expander));
1214 if (expander->priv->label_widget)
1215 return gtk_widget_child_focus (expander->priv->label_widget, direction);
1220 GtkWidget *child = gtk_bin_get_child (GTK_BIN (expander));
1222 if (child && gtk_widget_get_child_visible (child))
1223 return gtk_widget_child_focus (child, direction);
1231 g_assert_not_reached ();
1236 get_next_site (GtkExpander *expander,
1238 GtkDirectionType direction)
1242 ltr = gtk_widget_get_direction (GTK_WIDGET (expander)) != GTK_TEXT_DIR_RTL;
1249 case GTK_DIR_TAB_BACKWARD:
1253 case GTK_DIR_TAB_FORWARD:
1256 return FOCUS_WIDGET;
1261 case GTK_DIR_TAB_BACKWARD:
1265 return ltr ? FOCUS_NONE : FOCUS_LABEL;
1266 case GTK_DIR_TAB_FORWARD:
1270 return ltr ? FOCUS_LABEL : FOCUS_NONE;
1276 case GTK_DIR_TAB_BACKWARD:
1278 return FOCUS_WIDGET;
1280 return ltr ? FOCUS_WIDGET : FOCUS_CHILD;
1281 case GTK_DIR_TAB_FORWARD:
1285 return ltr ? FOCUS_CHILD : FOCUS_WIDGET;
1291 case GTK_DIR_TAB_BACKWARD:
1295 case GTK_DIR_TAB_FORWARD:
1302 g_assert_not_reached ();
1307 gtk_expander_resize_toplevel (GtkExpander *expander)
1309 GtkExpanderPrivate *priv = expander->priv;
1310 GtkWidget *child = gtk_bin_get_child (GTK_BIN (expander));
1312 if (child && priv->resize_toplevel &&
1313 gtk_widget_get_realized (GTK_WIDGET (expander)))
1315 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (expander));
1317 if (toplevel && gtk_widget_get_realized (toplevel))
1319 GtkAllocation toplevel_allocation;
1321 gtk_widget_get_allocation (toplevel, &toplevel_allocation);
1325 GtkRequisition child_requisition;
1327 gtk_widget_get_preferred_size (child, &child_requisition, NULL);
1329 toplevel_allocation.height += child_requisition.height;
1333 GtkAllocation child_allocation;
1335 gtk_widget_get_allocation (child, &child_allocation);
1337 toplevel_allocation.height -= child_allocation.height;
1340 gtk_window_resize (GTK_WINDOW (toplevel),
1341 toplevel_allocation.width,
1342 toplevel_allocation.height);
1348 gtk_expander_focus (GtkWidget *widget,
1349 GtkDirectionType direction)
1351 GtkExpander *expander = GTK_EXPANDER (widget);
1353 if (!focus_current_site (expander, direction))
1355 GtkWidget *old_focus_child;
1356 gboolean widget_is_focus;
1357 FocusSite site = FOCUS_NONE;
1359 widget_is_focus = gtk_widget_is_focus (widget);
1360 old_focus_child = gtk_container_get_focus_child (GTK_CONTAINER (widget));
1362 if (old_focus_child && old_focus_child == expander->priv->label_widget)
1364 else if (old_focus_child)
1366 else if (widget_is_focus)
1367 site = FOCUS_WIDGET;
1369 while ((site = get_next_site (expander, site, direction)) != FOCUS_NONE)
1371 if (focus_in_site (expander, site, direction))
1382 gtk_expander_add (GtkContainer *container,
1385 GTK_CONTAINER_CLASS (gtk_expander_parent_class)->add (container, widget);
1387 gtk_widget_set_child_visible (widget, GTK_EXPANDER (container)->priv->expanded);
1388 gtk_widget_queue_resize (GTK_WIDGET (container));
1392 gtk_expander_remove (GtkContainer *container,
1395 GtkExpander *expander = GTK_EXPANDER (container);
1397 if (GTK_EXPANDER (expander)->priv->label_widget == widget)
1398 gtk_expander_set_label_widget (expander, NULL);
1400 GTK_CONTAINER_CLASS (gtk_expander_parent_class)->remove (container, widget);
1404 gtk_expander_forall (GtkContainer *container,
1405 gboolean include_internals,
1406 GtkCallback callback,
1407 gpointer callback_data)
1409 GtkBin *bin = GTK_BIN (container);
1410 GtkExpanderPrivate *priv = GTK_EXPANDER (container)->priv;
1413 child = gtk_bin_get_child (bin);
1415 (* callback) (child, callback_data);
1417 if (priv->label_widget)
1418 (* callback) (priv->label_widget, callback_data);
1422 gtk_expander_activate (GtkExpander *expander)
1424 gtk_expander_set_expanded (expander, !expander->priv->expanded);
1429 gtk_expander_get_preferred_width (GtkWidget *widget,
1433 GtkExpander *expander;
1435 GtkExpanderPrivate *priv;
1438 gint expander_spacing;
1439 gboolean interior_focus;
1443 child = gtk_bin_get_child (GTK_BIN (widget));
1444 expander = GTK_EXPANDER (widget);
1445 priv = expander->priv;
1447 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1449 gtk_widget_style_get (GTK_WIDGET (widget),
1450 "interior-focus", &interior_focus,
1451 "focus-line-width", &focus_width,
1452 "focus-padding", &focus_pad,
1453 "expander-size", &expander_size,
1454 "expander-spacing", &expander_spacing,
1457 *minimum_size = *natural_size =
1458 expander_size + 2 * expander_spacing +
1459 2 * focus_width + 2 * focus_pad;
1461 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
1463 gint label_min, label_nat;
1465 gtk_widget_get_preferred_width (priv->label_widget,
1466 &label_min, &label_nat);
1468 *minimum_size += label_min;
1469 *natural_size += label_nat;
1472 if (child && gtk_widget_get_child_visible (child))
1474 gint child_min, child_nat;
1476 gtk_widget_get_preferred_width (child,
1477 &child_min, &child_nat);
1479 *minimum_size = MAX (*minimum_size, child_min);
1480 *natural_size = MAX (*natural_size, child_nat);
1484 *minimum_size += 2 * border_width;
1485 *natural_size += 2 * border_width;
1489 gtk_expander_get_preferred_height (GtkWidget *widget,
1493 GtkExpander *expander;
1495 GtkExpanderPrivate *priv;
1498 gint expander_spacing;
1499 gboolean interior_focus;
1503 child = gtk_bin_get_child (GTK_BIN (widget));
1504 expander = GTK_EXPANDER (widget);
1505 priv = expander->priv;
1507 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1509 gtk_widget_style_get (GTK_WIDGET (widget),
1510 "interior-focus", &interior_focus,
1511 "focus-line-width", &focus_width,
1512 "focus-padding", &focus_pad,
1513 "expander-size", &expander_size,
1514 "expander-spacing", &expander_spacing,
1517 *minimum_size = *natural_size =
1518 interior_focus ? (2 * focus_width + 2 * focus_pad) : 0;
1521 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
1523 gint label_min, label_nat;
1525 gtk_widget_get_preferred_height (priv->label_widget,
1526 &label_min, &label_nat);
1528 *minimum_size += label_min;
1529 *natural_size += label_nat;
1532 *minimum_size = MAX (*minimum_size, expander_size + 2 * expander_spacing);
1533 *natural_size = MAX (*natural_size, *minimum_size);
1535 if (!interior_focus)
1537 gint extra = 2 * focus_width + 2 * focus_pad;
1538 *minimum_size += extra;
1539 *natural_size += extra;
1542 if (child && gtk_widget_get_child_visible (child))
1544 gint child_min, child_nat;
1546 gtk_widget_get_preferred_height (child,
1547 &child_min, &child_nat);
1549 *minimum_size += child_min + priv->spacing;
1550 *natural_size += child_nat + priv->spacing;
1554 *minimum_size += 2 * border_width;
1555 *natural_size += 2 * border_width;
1559 gtk_expander_get_preferred_height_for_width (GtkWidget *widget,
1561 gint *minimum_height,
1562 gint *natural_height)
1564 GtkExpander *expander;
1566 GtkExpanderPrivate *priv;
1569 gint expander_spacing;
1570 gboolean interior_focus;
1575 child = gtk_bin_get_child (GTK_BIN (widget));
1576 expander = GTK_EXPANDER (widget);
1577 priv = expander->priv;
1579 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1581 gtk_widget_style_get (GTK_WIDGET (widget),
1582 "interior-focus", &interior_focus,
1583 "focus-line-width", &focus_width,
1584 "focus-padding", &focus_pad,
1585 "expander-size", &expander_size,
1586 "expander-spacing", &expander_spacing,
1589 label_xpad = 2 * border_width + expander_size + 2 * expander_spacing - 2 * focus_width + 2 * focus_pad;
1591 *minimum_height = *natural_height =
1592 interior_focus ? (2 * focus_width + 2 * focus_pad) : 0;
1595 if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
1597 gint label_min, label_nat;
1599 gtk_widget_get_preferred_height_for_width (priv->label_widget,
1600 MAX (width - label_xpad, 1),
1601 &label_min, &label_nat);
1603 *minimum_height += label_min;
1604 *natural_height += label_nat;
1607 *minimum_height = MAX (*minimum_height, expander_size + 2 * expander_spacing);
1608 *natural_height = MAX (*natural_height, *minimum_height);
1610 if (!interior_focus)
1612 gint extra = 2 * focus_width + 2 * focus_pad;
1613 *minimum_height += extra;
1614 *natural_height += extra;
1617 if (child && gtk_widget_get_child_visible (child))
1619 gint child_min, child_nat;
1621 gtk_widget_get_preferred_height_for_width (child,
1622 MAX (width - 2 * border_width, 1),
1623 &child_min, &child_nat);
1625 *minimum_height += child_min + priv->spacing;
1626 *natural_height += child_nat + priv->spacing;
1629 *minimum_height += 2 * border_width;
1630 *natural_height += 2 * border_width;
1634 gtk_expander_get_preferred_width_for_height (GtkWidget *widget,
1636 gint *minimum_width,
1637 gint *natural_width)
1639 GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_width, natural_width);
1646 * @label: the text of the label
1648 * Creates a new expander using @label as the text of the label.
1650 * Return value: a new #GtkExpander widget.
1655 gtk_expander_new (const gchar *label)
1657 return g_object_new (GTK_TYPE_EXPANDER, "label", label, NULL);
1661 * gtk_expander_new_with_mnemonic:
1662 * @label: (allow-none): the text of the label with an underscore
1663 * in front of the mnemonic character
1665 * Creates a new expander using @label as the text of the label.
1666 * If characters in @label are preceded by an underscore, they are underlined.
1667 * If you need a literal underscore character in a label, use '__' (two
1668 * underscores). The first underlined character represents a keyboard
1669 * accelerator called a mnemonic.
1670 * Pressing Alt and that key activates the button.
1672 * Return value: a new #GtkExpander widget.
1677 gtk_expander_new_with_mnemonic (const gchar *label)
1679 return g_object_new (GTK_TYPE_EXPANDER,
1681 "use-underline", TRUE,
1686 * gtk_expander_set_expanded:
1687 * @expander: a #GtkExpander
1688 * @expanded: whether the child widget is revealed
1690 * Sets the state of the expander. Set to %TRUE, if you want
1691 * the child widget to be revealed, and %FALSE if you want the
1692 * child widget to be hidden.
1697 gtk_expander_set_expanded (GtkExpander *expander,
1700 GtkExpanderPrivate *priv;
1703 g_return_if_fail (GTK_IS_EXPANDER (expander));
1705 priv = expander->priv;
1707 expanded = expanded != FALSE;
1709 if (priv->expanded != expanded)
1711 GtkWidget *widget = GTK_WIDGET (expander);
1712 GtkSettings *settings = gtk_widget_get_settings (widget);
1713 GtkStyleContext *context;
1714 gboolean enable_animations;
1716 context = gtk_widget_get_style_context (widget);
1717 priv->expanded = expanded;
1719 g_object_get (settings, "gtk-enable-animations", &enable_animations, NULL);
1721 if (enable_animations && gtk_widget_get_realized (widget))
1723 gtk_style_context_save (context);
1724 gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
1726 gtk_style_context_notify_state_change (context,
1727 gtk_widget_get_window (widget),
1728 GUINT_TO_POINTER (1),
1731 gtk_style_context_restore (context);
1734 child = gtk_bin_get_child (GTK_BIN (expander));
1738 gtk_widget_set_child_visible (child, priv->expanded);
1739 gtk_widget_queue_resize (widget);
1740 gtk_expander_resize_toplevel (expander);
1743 g_object_notify (G_OBJECT (expander), "expanded");
1748 * gtk_expander_get_expanded:
1749 * @expander:a #GtkExpander
1751 * Queries a #GtkExpander and returns its current state. Returns %TRUE
1752 * if the child widget is revealed.
1754 * See gtk_expander_set_expanded().
1756 * Return value: the current state of the expander
1761 gtk_expander_get_expanded (GtkExpander *expander)
1763 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1765 return expander->priv->expanded;
1769 * gtk_expander_set_spacing:
1770 * @expander: a #GtkExpander
1771 * @spacing: distance between the expander and child in pixels
1773 * Sets the spacing field of @expander, which is the number of
1774 * pixels to place between expander and the child.
1779 gtk_expander_set_spacing (GtkExpander *expander,
1782 g_return_if_fail (GTK_IS_EXPANDER (expander));
1783 g_return_if_fail (spacing >= 0);
1785 if (expander->priv->spacing != spacing)
1787 expander->priv->spacing = spacing;
1789 gtk_widget_queue_resize (GTK_WIDGET (expander));
1791 g_object_notify (G_OBJECT (expander), "spacing");
1796 * gtk_expander_get_spacing:
1797 * @expander: a #GtkExpander
1799 * Gets the value set by gtk_expander_set_spacing().
1801 * Return value: spacing between the expander and child
1806 gtk_expander_get_spacing (GtkExpander *expander)
1808 g_return_val_if_fail (GTK_IS_EXPANDER (expander), 0);
1810 return expander->priv->spacing;
1814 * gtk_expander_set_label:
1815 * @expander: a #GtkExpander
1816 * @label: (allow-none): a string
1818 * Sets the text of the label of the expander to @label.
1820 * This will also clear any previously set labels.
1825 gtk_expander_set_label (GtkExpander *expander,
1828 g_return_if_fail (GTK_IS_EXPANDER (expander));
1832 gtk_expander_set_label_widget (expander, NULL);
1838 child = gtk_label_new (label);
1839 gtk_label_set_use_underline (GTK_LABEL (child), expander->priv->use_underline);
1840 gtk_label_set_use_markup (GTK_LABEL (child), expander->priv->use_markup);
1841 gtk_widget_show (child);
1843 gtk_expander_set_label_widget (expander, child);
1846 g_object_notify (G_OBJECT (expander), "label");
1850 * gtk_expander_get_label:
1851 * @expander: a #GtkExpander
1853 * Fetches the text from a label widget including any embedded
1854 * underlines indicating mnemonics and Pango markup, as set by
1855 * gtk_expander_set_label(). If the label text has not been set the
1856 * return value will be %NULL. This will be the case if you create an
1857 * empty button with gtk_button_new() to use as a container.
1859 * Note that this function behaved differently in versions prior to
1860 * 2.14 and used to return the label text stripped of embedded
1861 * underlines indicating mnemonics and Pango markup. This problem can
1862 * be avoided by fetching the label text directly from the label
1865 * Return value: The text of the label widget. This string is owned
1866 * by the widget and must not be modified or freed.
1871 gtk_expander_get_label (GtkExpander *expander)
1873 GtkExpanderPrivate *priv;
1875 g_return_val_if_fail (GTK_IS_EXPANDER (expander), NULL);
1877 priv = expander->priv;
1879 if (GTK_IS_LABEL (priv->label_widget))
1880 return gtk_label_get_label (GTK_LABEL (priv->label_widget));
1886 * gtk_expander_set_use_underline:
1887 * @expander: a #GtkExpander
1888 * @use_underline: %TRUE if underlines in the text indicate mnemonics
1890 * If true, an underline in the text of the expander label indicates
1891 * the next character should be used for the mnemonic accelerator key.
1896 gtk_expander_set_use_underline (GtkExpander *expander,
1897 gboolean use_underline)
1899 GtkExpanderPrivate *priv;
1901 g_return_if_fail (GTK_IS_EXPANDER (expander));
1903 priv = expander->priv;
1905 use_underline = use_underline != FALSE;
1907 if (priv->use_underline != use_underline)
1909 priv->use_underline = use_underline;
1911 if (GTK_IS_LABEL (priv->label_widget))
1912 gtk_label_set_use_underline (GTK_LABEL (priv->label_widget), use_underline);
1914 g_object_notify (G_OBJECT (expander), "use-underline");
1919 * gtk_expander_get_use_underline:
1920 * @expander: a #GtkExpander
1922 * Returns whether an embedded underline in the expander label
1923 * indicates a mnemonic. See gtk_expander_set_use_underline().
1925 * Return value: %TRUE if an embedded underline in the expander
1926 * label indicates the mnemonic accelerator keys
1931 gtk_expander_get_use_underline (GtkExpander *expander)
1933 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1935 return expander->priv->use_underline;
1939 * gtk_expander_set_use_markup:
1940 * @expander: a #GtkExpander
1941 * @use_markup: %TRUE if the label's text should be parsed for markup
1943 * Sets whether the text of the label contains markup in <link
1944 * linkend="PangoMarkupFormat">Pango's text markup
1945 * language</link>. See gtk_label_set_markup().
1950 gtk_expander_set_use_markup (GtkExpander *expander,
1951 gboolean use_markup)
1953 GtkExpanderPrivate *priv;
1955 g_return_if_fail (GTK_IS_EXPANDER (expander));
1957 priv = expander->priv;
1959 use_markup = use_markup != FALSE;
1961 if (priv->use_markup != use_markup)
1963 priv->use_markup = use_markup;
1965 if (GTK_IS_LABEL (priv->label_widget))
1966 gtk_label_set_use_markup (GTK_LABEL (priv->label_widget), use_markup);
1968 g_object_notify (G_OBJECT (expander), "use-markup");
1973 * gtk_expander_get_use_markup:
1974 * @expander: a #GtkExpander
1976 * Returns whether the label's text is interpreted as marked up with
1977 * the <link linkend="PangoMarkupFormat">Pango text markup
1978 * language</link>. See gtk_expander_set_use_markup().
1980 * Return value: %TRUE if the label's text will be parsed for markup
1985 gtk_expander_get_use_markup (GtkExpander *expander)
1987 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1989 return expander->priv->use_markup;
1993 * gtk_expander_set_label_widget:
1994 * @expander: a #GtkExpander
1995 * @label_widget: (allow-none): the new label widget
1997 * Set the label widget for the expander. This is the widget
1998 * that will appear embedded alongside the expander arrow.
2003 gtk_expander_set_label_widget (GtkExpander *expander,
2004 GtkWidget *label_widget)
2006 GtkExpanderPrivate *priv;
2009 g_return_if_fail (GTK_IS_EXPANDER (expander));
2010 g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget));
2011 g_return_if_fail (label_widget == NULL || gtk_widget_get_parent (label_widget) == NULL);
2013 priv = expander->priv;
2015 if (priv->label_widget == label_widget)
2018 if (priv->label_widget)
2020 gtk_widget_set_state_flags (priv->label_widget, 0, TRUE);
2021 gtk_widget_unparent (priv->label_widget);
2024 priv->label_widget = label_widget;
2025 widget = GTK_WIDGET (expander);
2029 priv->label_widget = label_widget;
2031 gtk_widget_set_parent (label_widget, widget);
2034 gtk_widget_set_state_flags (label_widget,
2035 GTK_STATE_FLAG_PRELIGHT,
2039 if (gtk_widget_get_visible (widget))
2040 gtk_widget_queue_resize (widget);
2042 g_object_freeze_notify (G_OBJECT (expander));
2043 g_object_notify (G_OBJECT (expander), "label-widget");
2044 g_object_notify (G_OBJECT (expander), "label");
2045 g_object_thaw_notify (G_OBJECT (expander));
2049 * gtk_expander_get_label_widget:
2050 * @expander: a #GtkExpander
2052 * Retrieves the label widget for the frame. See
2053 * gtk_expander_set_label_widget().
2055 * Return value: (transfer none): the label widget,
2056 * or %NULL if there is none
2061 gtk_expander_get_label_widget (GtkExpander *expander)
2063 g_return_val_if_fail (GTK_IS_EXPANDER (expander), NULL);
2065 return expander->priv->label_widget;
2069 * gtk_expander_set_label_fill:
2070 * @expander: a #GtkExpander
2071 * @label_fill: %TRUE if the label should should fill
2072 * all available horizontal space
2074 * Sets whether the label widget should fill all available
2075 * horizontal space allocated to @expander.
2080 gtk_expander_set_label_fill (GtkExpander *expander,
2081 gboolean label_fill)
2083 GtkExpanderPrivate *priv;
2085 g_return_if_fail (GTK_IS_EXPANDER (expander));
2087 priv = expander->priv;
2089 label_fill = label_fill != FALSE;
2091 if (priv->label_fill != label_fill)
2093 priv->label_fill = label_fill;
2095 if (priv->label_widget != NULL)
2096 gtk_widget_queue_resize (GTK_WIDGET (expander));
2098 g_object_notify (G_OBJECT (expander), "label-fill");
2103 * gtk_expander_get_label_fill:
2104 * @expander: a #GtkExpander
2106 * Returns whether the label widget will fill all available
2107 * horizontal space allocated to @expander.
2109 * Return value: %TRUE if the label widget will fill all
2110 * available horizontal space
2115 gtk_expander_get_label_fill (GtkExpander *expander)
2117 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
2119 return expander->priv->label_fill;
2123 * gtk_expander_set_resize_toplevel:
2124 * @expander: a #GtkExpander
2125 * @resize_toplevel: whether to resize the toplevel
2127 * Sets whether the expander will resize the toplevel widget
2128 * containing the expander upon resizing and collpasing.
2133 gtk_expander_set_resize_toplevel (GtkExpander *expander,
2134 gboolean resize_toplevel)
2136 g_return_if_fail (GTK_IS_EXPANDER (expander));
2138 if (expander->priv->resize_toplevel != resize_toplevel)
2140 expander->priv->resize_toplevel = resize_toplevel ? TRUE : FALSE;
2141 g_object_notify (G_OBJECT (expander), "resize-toplevel");
2146 * gtk_expander_get_resize_toplevel:
2147 * @expander: a #GtkExpander
2149 * Returns whether the expander will resize the toplevel widget
2150 * containing the expander upon resizing and collpasing.
2152 * Return value: the "resize toplevel" setting.
2157 gtk_expander_get_resize_toplevel (GtkExpander *expander)
2159 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
2161 return expander->priv->resize_toplevel;