1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * This file is part of the GNOME Devtools Libraries.
4 *
5 * Copyright (C) 2003 Jeroen Zwartepoorte <jeroen@xs4all.nl>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include "gdl-i18n.h"
27 #include <stdlib.h>
28 #include <string.h>
30 #include "gdl-tools.h"
31 #include "gdl-dock.h"
32 #include "gdl-dock-master.h"
33 #include "gdl-dock-bar.h"
34 #include "libgdltypebuiltins.h"
36 enum {
37 PROP_0,
38 PROP_MASTER,
39 PROP_DOCKBAR_STYLE
40 };
42 /* ----- Private prototypes ----- */
44 static void gdl_dock_bar_class_init (GdlDockBarClass *klass);
45 static void gdl_dock_bar_instance_init (GdlDockBar *dockbar);
47 static void gdl_dock_bar_get_property (GObject *object,
48 guint prop_id,
49 GValue *value,
50 GParamSpec *pspec);
51 static void gdl_dock_bar_set_property (GObject *object,
52 guint prop_id,
53 const GValue *value,
54 GParamSpec *pspec);
56 static void gdl_dock_bar_destroy (GtkObject *object);
58 static void gdl_dock_bar_attach (GdlDockBar *dockbar,
59 GdlDockMaster *master);
60 static void gdl_dock_bar_remove_item (GdlDockBar *dockbar,
61 GdlDockItem *item);
63 /* ----- Class variables and definitions ----- */
65 struct _GdlDockBarPrivate {
66 GdlDockMaster *master;
67 GSList *items;
68 GtkTooltips *tooltips;
69 GtkOrientation orientation;
70 GdlDockBarStyle dockbar_style;
71 };
73 /* ----- Private functions ----- */
75 GDL_CLASS_BOILERPLATE (GdlDockBar, gdl_dock_bar, GtkBox, GTK_TYPE_BOX)
77 static void gdl_dock_bar_size_request (GtkWidget *widget,
78 GtkRequisition *requisition );
79 static void gdl_dock_bar_size_allocate (GtkWidget *widget,
80 GtkAllocation *allocation );
81 static void gdl_dock_bar_size_vrequest (GtkWidget *widget,
82 GtkRequisition *requisition );
83 static void gdl_dock_bar_size_vallocate (GtkWidget *widget,
84 GtkAllocation *allocation );
85 static void gdl_dock_bar_size_hrequest (GtkWidget *widget,
86 GtkRequisition *requisition );
87 static void gdl_dock_bar_size_hallocate (GtkWidget *widget,
88 GtkAllocation *allocation );
89 static void update_dock_items (GdlDockBar *dockbar, gboolean full_update);
91 void
92 gdl_dock_bar_class_init (GdlDockBarClass *klass)
93 {
94 GObjectClass *g_object_class;
95 GtkObjectClass *gtk_object_class;
96 GtkWidgetClass *widget_class;
98 g_object_class = G_OBJECT_CLASS (klass);
99 gtk_object_class = GTK_OBJECT_CLASS (klass);
101 g_object_class->get_property = gdl_dock_bar_get_property;
102 g_object_class->set_property = gdl_dock_bar_set_property;
104 gtk_object_class->destroy = gdl_dock_bar_destroy;
106 g_object_class_install_property (
107 g_object_class, PROP_MASTER,
108 g_param_spec_object ("master", _("Master"),
109 _("GdlDockMaster object which the dockbar widget "
110 "is attached to"),
111 GDL_TYPE_DOCK_MASTER,
112 G_PARAM_READWRITE));
114 g_object_class_install_property (
115 g_object_class, PROP_DOCKBAR_STYLE,
116 g_param_spec_enum ("dockbar-style", _("Dockbar style"),
117 _("Dockbar style to show items on it"),
118 GDL_TYPE_DOCK_BAR_STYLE,
119 GDL_DOCK_BAR_BOTH,
120 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
122 widget_class = GTK_WIDGET_CLASS (klass);
123 widget_class->size_request = gdl_dock_bar_size_request;
124 widget_class->size_allocate = gdl_dock_bar_size_allocate;
125 }
127 static void
128 gdl_dock_bar_instance_init (GdlDockBar *dockbar)
129 {
130 dockbar->_priv = g_new0 (GdlDockBarPrivate, 1);
131 dockbar->_priv->master = NULL;
132 dockbar->_priv->items = NULL;
133 dockbar->_priv->tooltips = gtk_tooltips_new ();
134 dockbar->_priv->orientation = GTK_ORIENTATION_VERTICAL;
135 dockbar->_priv->dockbar_style = GDL_DOCK_BAR_BOTH;
136 g_object_ref (dockbar->_priv->tooltips);
137 gtk_object_sink (GTK_OBJECT (dockbar->_priv->tooltips));
138 }
140 static void
141 gdl_dock_bar_get_property (GObject *object,
142 guint prop_id,
143 GValue *value,
144 GParamSpec *pspec)
145 {
146 GdlDockBar *dockbar = GDL_DOCK_BAR (object);
148 switch (prop_id) {
149 case PROP_MASTER:
150 g_value_set_object (value, dockbar->_priv->master);
151 break;
152 case PROP_DOCKBAR_STYLE:
153 g_value_set_enum (value, dockbar->_priv->dockbar_style);
154 break;
155 default:
156 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
157 };
158 }
160 static void
161 gdl_dock_bar_set_property (GObject *object,
162 guint prop_id,
163 const GValue *value,
164 GParamSpec *pspec)
165 {
166 GdlDockBar *dockbar = GDL_DOCK_BAR (object);
168 switch (prop_id) {
169 case PROP_MASTER:
170 gdl_dock_bar_attach (dockbar, g_value_get_object (value));
171 break;
172 case PROP_DOCKBAR_STYLE:
173 dockbar->_priv->dockbar_style = g_value_get_enum (value);
174 update_dock_items (dockbar, TRUE);
175 break;
176 default:
177 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
178 };
179 }
181 static void
182 on_dock_item_foreach_disconnect (GdlDockItem *item, GdlDockBar *dock_bar)
183 {
184 g_signal_handlers_disconnect_by_func (item, gdl_dock_bar_remove_item,
185 dock_bar);
186 }
188 static void
189 gdl_dock_bar_destroy (GtkObject *object)
190 {
191 GdlDockBar *dockbar = GDL_DOCK_BAR (object);
193 if (dockbar->_priv) {
194 GdlDockBarPrivate *priv = dockbar->_priv;
196 if (priv->items) {
197 g_slist_foreach (priv->items,
198 (GFunc) on_dock_item_foreach_disconnect,
199 object);
200 g_slist_free (priv->items);
201 }
203 if (priv->master) {
204 g_signal_handlers_disconnect_matched (priv->master,
205 G_SIGNAL_MATCH_DATA,
206 0, 0, NULL, NULL, dockbar);
207 g_object_unref (priv->master);
208 priv->master = NULL;
209 }
211 if (priv->tooltips) {
212 g_object_unref (priv->tooltips);
213 priv->tooltips = NULL;
214 }
216 dockbar->_priv = NULL;
218 g_free (priv);
219 }
221 GDL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
222 }
224 static void
225 gdl_dock_bar_remove_item (GdlDockBar *dockbar,
226 GdlDockItem *item)
227 {
228 GdlDockBarPrivate *priv;
229 GtkWidget *button;
231 g_return_if_fail (GDL_IS_DOCK_BAR (dockbar));
232 g_return_if_fail (GDL_IS_DOCK_ITEM (item));
234 priv = dockbar->_priv;
236 if (g_slist_index (priv->items, item) == -1) {
237 g_warning ("Item has not been added to the dockbar");
238 return;
239 }
241 priv->items = g_slist_remove (priv->items, item);
243 button = g_object_get_data (G_OBJECT (item), "GdlDockBarButton");
244 g_assert (button != NULL);
245 gtk_container_remove (GTK_CONTAINER (dockbar), button);
246 g_object_set_data (G_OBJECT (item), "GdlDockBarButton", NULL);
247 g_signal_handlers_disconnect_by_func (item,
248 G_CALLBACK (gdl_dock_bar_remove_item),
249 dockbar);
250 }
252 static void
253 gdl_dock_bar_item_clicked (GtkWidget *button,
254 GdlDockItem *item)
255 {
256 GdlDockBar *dockbar;
257 GdlDockObject *controller;
259 g_return_if_fail (item != NULL);
261 dockbar = g_object_get_data (G_OBJECT (item), "GdlDockBar");
262 g_assert (dockbar != NULL);
263 g_object_set_data (G_OBJECT (item), "GdlDockBar", NULL);
265 controller = gdl_dock_master_get_controller (GDL_DOCK_OBJECT_GET_MASTER (item));
267 GDL_DOCK_OBJECT_UNSET_FLAGS (item, GDL_DOCK_ICONIFIED);
268 gdl_dock_item_show_item (item);
269 gdl_dock_bar_remove_item (dockbar, item);
270 gtk_widget_queue_resize (GTK_WIDGET (controller));
271 }
273 static void
274 gdl_dock_bar_add_item (GdlDockBar *dockbar,
275 GdlDockItem *item)
276 {
277 GdlDockBarPrivate *priv;
278 GtkWidget *button;
279 gchar *stock_id;
280 gchar *name;
281 GdkPixbuf *pixbuf_icon;
282 GtkWidget *image, *box, *label;
284 g_return_if_fail (GDL_IS_DOCK_BAR (dockbar));
285 g_return_if_fail (GDL_IS_DOCK_ITEM (item));
287 priv = dockbar->_priv;
289 if (g_slist_index (priv->items, item) != -1) {
290 g_warning ("Item has already been added to the dockbar");
291 return;
292 }
294 priv->items = g_slist_append (priv->items, item);
296 /* Create a button for the item. */
297 button = gtk_button_new ();
298 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
300 if (dockbar->_priv->orientation == GTK_ORIENTATION_HORIZONTAL)
301 box = gtk_hbox_new (FALSE, 0);
302 else
303 box = gtk_vbox_new (FALSE, 0);
305 g_object_get (item, "stock-id", &stock_id, "pixbuf-icon", &pixbuf_icon,
306 "long-name", &name, NULL);
308 if (dockbar->_priv->dockbar_style == GDL_DOCK_BAR_TEXT ||
309 dockbar->_priv->dockbar_style == GDL_DOCK_BAR_BOTH) {
310 label = gtk_label_new (name);
311 if (dockbar->_priv->orientation == GTK_ORIENTATION_VERTICAL)
312 gtk_label_set_angle (GTK_LABEL (label), 90);
313 gtk_box_pack_start_defaults (GTK_BOX (box), label);
314 }
316 /* FIXME: For now AUTO behaves same as BOTH */
318 if (dockbar->_priv->dockbar_style == GDL_DOCK_BAR_ICONS ||
319 dockbar->_priv->dockbar_style == GDL_DOCK_BAR_BOTH ||
320 dockbar->_priv->dockbar_style == GDL_DOCK_BAR_AUTO) {
321 if (stock_id) {
322 image = gtk_image_new_from_stock (stock_id,
323 GTK_ICON_SIZE_SMALL_TOOLBAR);
324 g_free (stock_id);
325 } else if (pixbuf_icon) {
326 image = gtk_image_new_from_pixbuf (pixbuf_icon);
327 } else {
328 image = gtk_image_new_from_stock (GTK_STOCK_NEW,
329 GTK_ICON_SIZE_SMALL_TOOLBAR);
330 }
331 gtk_box_pack_start_defaults (GTK_BOX (box), image);
332 }
334 gtk_container_add (GTK_CONTAINER (button), box);
335 gtk_box_pack_start (GTK_BOX (dockbar), button, FALSE, FALSE, 0);
337 gtk_tooltips_set_tip (priv->tooltips, button, name, name);
338 g_free (name);
340 g_object_set_data (G_OBJECT (item), "GdlDockBar", dockbar);
341 g_object_set_data (G_OBJECT (item), "GdlDockBarButton", button);
342 g_signal_connect (G_OBJECT (button), "clicked",
343 G_CALLBACK (gdl_dock_bar_item_clicked), item);
345 gtk_widget_show_all (button);
347 /* Set up destroy notify */
348 g_signal_connect_swapped (item, "destroy",
349 G_CALLBACK (gdl_dock_bar_remove_item),
350 dockbar);
351 }
353 static void
354 build_list (GdlDockObject *object, GList **list)
355 {
356 /* add only items, not toplevels */
357 if (GDL_IS_DOCK_ITEM (object))
358 *list = g_list_prepend (*list, object);
359 }
361 static void
362 update_dock_items (GdlDockBar *dockbar, gboolean full_update)
363 {
364 GdlDockMaster *master;
365 GList *items, *l;
367 g_return_if_fail (dockbar != NULL);
369 if (!dockbar->_priv->master)
370 return;
372 master = dockbar->_priv->master;
374 /* build items list */
375 items = NULL;
376 gdl_dock_master_foreach (master, (GFunc) build_list, &items);
378 if (!full_update) {
379 for (l = items; l != NULL; l = l->next) {
380 GdlDockItem *item = GDL_DOCK_ITEM (l->data);
382 if (g_slist_index (dockbar->_priv->items, item) != -1 &&
383 !GDL_DOCK_ITEM_ICONIFIED (item))
384 gdl_dock_bar_remove_item (dockbar, item);
385 else if (g_slist_index (dockbar->_priv->items, item) == -1 &&
386 GDL_DOCK_ITEM_ICONIFIED (item))
387 gdl_dock_bar_add_item (dockbar, item);
388 }
389 } else {
390 for (l = items; l != NULL; l = l->next) {
391 GdlDockItem *item = GDL_DOCK_ITEM (l->data);
393 if (g_slist_index (dockbar->_priv->items, item) != -1)
394 gdl_dock_bar_remove_item (dockbar, item);
395 if (GDL_DOCK_ITEM_ICONIFIED (item))
396 gdl_dock_bar_add_item (dockbar, item);
397 }
398 }
399 g_list_free (items);
400 }
402 static void
403 gdl_dock_bar_layout_changed_cb (GdlDockMaster *master,
404 GdlDockBar *dockbar)
405 {
406 update_dock_items (dockbar, FALSE);
407 }
409 static void
410 gdl_dock_bar_attach (GdlDockBar *dockbar,
411 GdlDockMaster *master)
412 {
413 g_return_if_fail (dockbar != NULL);
414 g_return_if_fail (master == NULL || GDL_IS_DOCK_MASTER (master));
416 if (dockbar->_priv->master) {
417 g_signal_handlers_disconnect_matched (dockbar->_priv->master,
418 G_SIGNAL_MATCH_DATA,
419 0, 0, NULL, NULL, dockbar);
420 g_object_unref (dockbar->_priv->master);
421 }
423 dockbar->_priv->master = master;
424 if (dockbar->_priv->master) {
425 g_object_ref (dockbar->_priv->master);
426 g_signal_connect (dockbar->_priv->master, "layout-changed",
427 G_CALLBACK (gdl_dock_bar_layout_changed_cb),
428 dockbar);
429 }
431 update_dock_items (dockbar, FALSE);
432 }
434 static void gdl_dock_bar_size_request (GtkWidget *widget,
435 GtkRequisition *requisition )
436 {
437 GdlDockBar *dockbar;
439 dockbar = GDL_DOCK_BAR (widget);
441 /* default to vertical for unknown values */
442 switch (dockbar->_priv->orientation) {
443 case GTK_ORIENTATION_HORIZONTAL:
444 gdl_dock_bar_size_hrequest (widget, requisition);
445 break;
446 case GTK_ORIENTATION_VERTICAL:
447 default:
448 gdl_dock_bar_size_vrequest (widget, requisition);
449 break;
450 }
451 }
453 static void gdl_dock_bar_size_allocate (GtkWidget *widget,
454 GtkAllocation *allocation )
455 {
456 GdlDockBar *dockbar;
458 dockbar = GDL_DOCK_BAR (widget);
460 /* default to vertical for unknown values */
461 switch (dockbar->_priv->orientation) {
462 case GTK_ORIENTATION_HORIZONTAL:
463 gdl_dock_bar_size_hallocate (widget, allocation);
464 break;
465 case GTK_ORIENTATION_VERTICAL:
466 default:
467 gdl_dock_bar_size_vallocate (widget, allocation);
468 break;
469 }
470 }
472 static void gdl_dock_bar_size_vrequest (GtkWidget *widget,
473 GtkRequisition *requisition )
474 {
475 GtkBox *box;
476 GtkBoxChild *child;
477 GtkRequisition child_requisition;
478 GList *children;
479 gint nvis_children;
480 gint height;
482 box = GTK_BOX (widget);
483 requisition->width = 0;
484 requisition->height = 0;
485 nvis_children = 0;
487 children = box->children;
488 while (children)
489 {
490 child = children->data;
491 children = children->next;
493 if (GTK_WIDGET_VISIBLE (child->widget))
494 {
495 gtk_widget_size_request (child->widget, &child_requisition);
497 if (box->homogeneous)
498 {
499 height = child_requisition.height + child->padding * 2;
500 requisition->height = MAX (requisition->height, height);
501 }
502 else
503 {
504 requisition->height += child_requisition.height + child->padding * 2;
505 }
507 requisition->width = MAX (requisition->width, child_requisition.width);
509 nvis_children += 1;
510 }
511 }
513 if (nvis_children > 0)
514 {
515 if (box->homogeneous)
516 requisition->height *= nvis_children;
517 requisition->height += (nvis_children - 1) * box->spacing;
518 }
520 requisition->width += GTK_CONTAINER (box)->border_width * 2;
521 requisition->height += GTK_CONTAINER (box)->border_width * 2;
523 }
525 static void gdl_dock_bar_size_vallocate (GtkWidget *widget,
526 GtkAllocation *allocation)
527 {
528 GtkBox *box;
529 GtkBoxChild *child;
530 GList *children;
531 GtkAllocation child_allocation;
532 gint nvis_children;
533 gint nexpand_children;
534 gint child_height;
535 gint height;
536 gint extra;
537 gint y;
539 box = GTK_BOX (widget);
540 widget->allocation = *allocation;
542 nvis_children = 0;
543 nexpand_children = 0;
544 children = box->children;
546 while (children)
547 {
548 child = children->data;
549 children = children->next;
551 if (GTK_WIDGET_VISIBLE (child->widget))
552 {
553 nvis_children += 1;
554 if (child->expand)
555 nexpand_children += 1;
556 }
557 }
559 if (nvis_children > 0)
560 {
561 if (box->homogeneous)
562 {
563 height = (allocation->height -
564 GTK_CONTAINER (box)->border_width * 2 -
565 (nvis_children - 1) * box->spacing);
566 extra = height / nvis_children;
567 }
568 else if (nexpand_children > 0)
569 {
570 height = (gint) allocation->height - (gint) widget->requisition.height;
571 extra = height / nexpand_children;
572 }
573 else
574 {
575 height = 0;
576 extra = 0;
577 }
579 y = allocation->y + GTK_CONTAINER (box)->border_width;
580 child_allocation.x = allocation->x + GTK_CONTAINER (box)->border_width;
581 child_allocation.width = MAX (1, (gint) allocation->width - (gint) GTK_CONTAINER (box)->border_width * 2);
583 children = box->children;
584 while (children)
585 {
586 child = children->data;
587 children = children->next;
589 if ((child->pack == GTK_PACK_START) && GTK_WIDGET_VISIBLE (child->widget))
590 {
591 if (box->homogeneous)
592 {
593 if (nvis_children == 1)
594 child_height = height;
595 else
596 child_height = extra;
598 nvis_children -= 1;
599 height -= extra;
600 }
601 else
602 {
603 GtkRequisition child_requisition;
605 gtk_widget_get_child_requisition (child->widget, &child_requisition);
606 child_height = child_requisition.height + child->padding * 2;
608 if (child->expand)
609 {
610 if (nexpand_children == 1)
611 child_height += height;
612 else
613 child_height += extra;
615 nexpand_children -= 1;
616 height -= extra;
617 }
618 }
620 if (child->fill)
621 {
622 child_allocation.height = MAX (1, child_height - (gint)child->padding * 2);
623 child_allocation.y = y + child->padding;
624 }
625 else
626 {
627 GtkRequisition child_requisition;
629 gtk_widget_get_child_requisition (child->widget, &child_requisition);
630 child_allocation.height = child_requisition.height;
631 child_allocation.y = y + (child_height - child_allocation.height) / 2;
632 }
634 gtk_widget_size_allocate (child->widget, &child_allocation);
636 y += child_height + box->spacing;
637 }
638 }
640 y = allocation->y + allocation->height - GTK_CONTAINER (box)->border_width;
642 children = box->children;
643 while (children)
644 {
645 child = children->data;
646 children = children->next;
648 if ((child->pack == GTK_PACK_END) && GTK_WIDGET_VISIBLE (child->widget))
649 {
650 GtkRequisition child_requisition;
651 gtk_widget_get_child_requisition (child->widget, &child_requisition);
653 if (box->homogeneous)
654 {
655 if (nvis_children == 1)
656 child_height = height;
657 else
658 child_height = extra;
660 nvis_children -= 1;
661 height -= extra;
662 }
663 else
664 {
665 child_height = child_requisition.height + child->padding * 2;
667 if (child->expand)
668 {
669 if (nexpand_children == 1)
670 child_height += height;
671 else
672 child_height += extra;
674 nexpand_children -= 1;
675 height -= extra;
676 }
677 }
679 if (child->fill)
680 {
681 child_allocation.height = MAX (1, child_height - (gint)child->padding * 2);
682 child_allocation.y = y + child->padding - child_height;
683 }
684 else
685 {
686 child_allocation.height = child_requisition.height;
687 child_allocation.y = y + (child_height - child_allocation.height) / 2 - child_height;
688 }
690 gtk_widget_size_allocate (child->widget, &child_allocation);
692 y -= (child_height + box->spacing);
693 }
694 }
695 }
696 }
698 static void gdl_dock_bar_size_hrequest (GtkWidget *widget,
699 GtkRequisition *requisition )
700 {
701 GtkBox *box;
702 GtkBoxChild *child;
703 GList *children;
704 gint nvis_children;
705 gint width;
707 box = GTK_BOX (widget);
708 requisition->width = 0;
709 requisition->height = 0;
710 nvis_children = 0;
712 children = box->children;
713 while (children)
714 {
715 child = children->data;
716 children = children->next;
718 if (GTK_WIDGET_VISIBLE (child->widget))
719 {
720 GtkRequisition child_requisition;
722 gtk_widget_size_request (child->widget, &child_requisition);
724 if (box->homogeneous)
725 {
726 width = child_requisition.width + child->padding * 2;
727 requisition->width = MAX (requisition->width, width);
728 }
729 else
730 {
731 requisition->width += child_requisition.width + child->padding * 2;
732 }
734 requisition->height = MAX (requisition->height, child_requisition.height);
736 nvis_children += 1;
737 }
738 }
740 if (nvis_children > 0)
741 {
742 if (box->homogeneous)
743 requisition->width *= nvis_children;
744 requisition->width += (nvis_children - 1) * box->spacing;
745 }
747 requisition->width += GTK_CONTAINER (box)->border_width * 2;
748 requisition->height += GTK_CONTAINER (box)->border_width * 2;
749 }
751 static void gdl_dock_bar_size_hallocate (GtkWidget *widget,
752 GtkAllocation *allocation)
753 {
754 GtkBox *box;
755 GtkBoxChild *child;
756 GList *children;
757 GtkAllocation child_allocation;
758 gint nvis_children;
759 gint nexpand_children;
760 gint child_width;
761 gint width;
762 gint extra;
763 gint x;
764 GtkTextDirection direction;
766 box = GTK_BOX (widget);
767 widget->allocation = *allocation;
769 direction = gtk_widget_get_direction (widget);
771 nvis_children = 0;
772 nexpand_children = 0;
773 children = box->children;
775 while (children)
776 {
777 child = children->data;
778 children = children->next;
780 if (GTK_WIDGET_VISIBLE (child->widget))
781 {
782 nvis_children += 1;
783 if (child->expand)
784 nexpand_children += 1;
785 }
786 }
788 if (nvis_children > 0)
789 {
790 if (box->homogeneous)
791 {
792 width = (allocation->width -
793 GTK_CONTAINER (box)->border_width * 2 -
794 (nvis_children - 1) * box->spacing);
795 extra = width / nvis_children;
796 }
797 else if (nexpand_children > 0)
798 {
799 width = (gint) allocation->width - (gint) widget->requisition.width;
800 extra = width / nexpand_children;
801 }
802 else
803 {
804 width = 0;
805 extra = 0;
806 }
808 x = allocation->x + GTK_CONTAINER (box)->border_width;
809 child_allocation.y = allocation->y + GTK_CONTAINER (box)->border_width;
810 child_allocation.height = MAX (1, (gint) allocation->height - (gint) GTK_CONTAINER (box)->border_width * 2);
812 children = box->children;
813 while (children)
814 {
815 child = children->data;
816 children = children->next;
818 if ((child->pack == GTK_PACK_START) && GTK_WIDGET_VISIBLE (child->widget))
819 {
820 if (box->homogeneous)
821 {
822 if (nvis_children == 1)
823 child_width = width;
824 else
825 child_width = extra;
827 nvis_children -= 1;
828 width -= extra;
829 }
830 else
831 {
832 GtkRequisition child_requisition;
834 gtk_widget_get_child_requisition (child->widget, &child_requisition);
836 child_width = child_requisition.width + child->padding * 2;
838 if (child->expand)
839 {
840 if (nexpand_children == 1)
841 child_width += width;
842 else
843 child_width += extra;
845 nexpand_children -= 1;
846 width -= extra;
847 }
848 }
850 if (child->fill)
851 {
852 child_allocation.width = MAX (1, (gint) child_width - (gint) child->padding * 2);
853 child_allocation.x = x + child->padding;
854 }
855 else
856 {
857 GtkRequisition child_requisition;
859 gtk_widget_get_child_requisition (child->widget, &child_requisition);
860 child_allocation.width = child_requisition.width;
861 child_allocation.x = x + (child_width - child_allocation.width) / 2;
862 }
864 if (direction == GTK_TEXT_DIR_RTL)
865 child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
867 gtk_widget_size_allocate (child->widget, &child_allocation);
869 x += child_width + box->spacing;
870 }
871 }
873 x = allocation->x + allocation->width - GTK_CONTAINER (box)->border_width;
875 children = box->children;
876 while (children)
877 {
878 child = children->data;
879 children = children->next;
881 if ((child->pack == GTK_PACK_END) && GTK_WIDGET_VISIBLE (child->widget))
882 {
883 GtkRequisition child_requisition;
884 gtk_widget_get_child_requisition (child->widget, &child_requisition);
886 if (box->homogeneous)
887 {
888 if (nvis_children == 1)
889 child_width = width;
890 else
891 child_width = extra;
893 nvis_children -= 1;
894 width -= extra;
895 }
896 else
897 {
898 child_width = child_requisition.width + child->padding * 2;
900 if (child->expand)
901 {
902 if (nexpand_children == 1)
903 child_width += width;
904 else
905 child_width += extra;
907 nexpand_children -= 1;
908 width -= extra;
909 }
910 }
912 if (child->fill)
913 {
914 child_allocation.width = MAX (1, (gint)child_width - (gint)child->padding * 2);
915 child_allocation.x = x + child->padding - child_width;
916 }
917 else
918 {
919 child_allocation.width = child_requisition.width;
920 child_allocation.x = x + (child_width - child_allocation.width) / 2 - child_width;
921 }
923 if (direction == GTK_TEXT_DIR_RTL)
924 child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
926 gtk_widget_size_allocate (child->widget, &child_allocation);
928 x -= (child_width + box->spacing);
929 }
930 }
931 }
932 }
934 GtkWidget *
935 gdl_dock_bar_new (GdlDock *dock)
936 {
937 GdlDockMaster *master = NULL;
939 /* get the master of the given dock */
940 if (dock)
941 master = GDL_DOCK_OBJECT_GET_MASTER (dock);
943 return g_object_new (GDL_TYPE_DOCK_BAR,
944 "master", master, NULL);
945 }
947 GtkOrientation gdl_dock_bar_get_orientation (GdlDockBar *dockbar)
948 {
949 g_return_val_if_fail (GDL_IS_DOCK_BAR (dockbar),
950 GTK_ORIENTATION_VERTICAL);
952 return dockbar->_priv->orientation;
953 }
955 void gdl_dock_bar_set_orientation (GdlDockBar *dockbar,
956 GtkOrientation orientation)
957 {
958 g_return_if_fail (GDL_IS_DOCK_BAR (dockbar));
960 dockbar->_priv->orientation = orientation;
962 gtk_widget_queue_resize (GTK_WIDGET (dockbar));
963 }
965 void gdl_dock_bar_set_style(GdlDockBar* dockbar,
966 GdlDockBarStyle style)
967 {
968 g_object_set(G_OBJECT(dockbar), "dockbar-style", style, NULL);
969 }
971 GdlDockBarStyle gdl_dock_bar_get_style(GdlDockBar* dockbar)
972 {
973 GdlDockBarStyle style;
974 g_object_get(G_OBJECT(dockbar), "dockbar-style", &style, NULL);
975 return style;
976 }