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