1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * gdl-dock-paned.h
4 *
5 * This file is part of the GNOME Devtools Libraries.
6 *
7 * Copyright (C) 2002 Gustavo Giráldez <gustavo.giraldez@gmx.net>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
28 #include "gdl-i18n.h"
29 #include <string.h>
30 #include <gtk/gtkhpaned.h>
31 #include <gtk/gtkvpaned.h>
33 #include "gdl-tools.h"
34 #include "gdl-dock-paned.h"
37 /* Private prototypes */
39 static void gdl_dock_paned_class_init (GdlDockPanedClass *klass);
40 static void gdl_dock_paned_instance_init (GdlDockPaned *paned);
41 static GObject *gdl_dock_paned_constructor (GType type,
42 guint n_construct_properties,
43 GObjectConstructParam *construct_param);
44 static void gdl_dock_paned_set_property (GObject *object,
45 guint prop_id,
46 const GValue *value,
47 GParamSpec *pspec);
48 static void gdl_dock_paned_get_property (GObject *object,
49 guint prop_id,
50 GValue *value,
51 GParamSpec *pspec);
53 static void gdl_dock_paned_destroy (GtkObject *object);
55 static void gdl_dock_paned_add (GtkContainer *container,
56 GtkWidget *widget);
57 static void gdl_dock_paned_forall (GtkContainer *container,
58 gboolean include_internals,
59 GtkCallback callback,
60 gpointer callback_data);
61 static GType gdl_dock_paned_child_type (GtkContainer *container);
63 static gboolean gdl_dock_paned_dock_request (GdlDockObject *object,
64 gint x,
65 gint y,
66 GdlDockRequest *request);
67 static void gdl_dock_paned_dock (GdlDockObject *object,
68 GdlDockObject *requestor,
69 GdlDockPlacement position,
70 GValue *other_data);
72 static void gdl_dock_paned_set_orientation (GdlDockItem *item,
73 GtkOrientation orientation);
75 static gboolean gdl_dock_paned_child_placement (GdlDockObject *object,
76 GdlDockObject *child,
77 GdlDockPlacement *placement);
80 /* ----- Class variables and definitions ----- */
82 #define SPLIT_RATIO 0.3
84 enum {
85 PROP_0,
86 PROP_POSITION
87 };
90 /* ----- Private functions ----- */
92 GDL_CLASS_BOILERPLATE (GdlDockPaned, gdl_dock_paned, GdlDockItem, GDL_TYPE_DOCK_ITEM);
94 static void
95 gdl_dock_paned_class_init (GdlDockPanedClass *klass)
96 {
97 GObjectClass *g_object_class;
98 GtkObjectClass *gtk_object_class;
99 GtkWidgetClass *widget_class;
100 GtkContainerClass *container_class;
101 GdlDockObjectClass *object_class;
102 GdlDockItemClass *item_class;
104 g_object_class = G_OBJECT_CLASS (klass);
105 gtk_object_class = GTK_OBJECT_CLASS (klass);
106 widget_class = GTK_WIDGET_CLASS (klass);
107 container_class = GTK_CONTAINER_CLASS (klass);
108 object_class = GDL_DOCK_OBJECT_CLASS (klass);
109 item_class = GDL_DOCK_ITEM_CLASS (klass);
111 g_object_class->set_property = gdl_dock_paned_set_property;
112 g_object_class->get_property = gdl_dock_paned_get_property;
113 g_object_class->constructor = gdl_dock_paned_constructor;
115 gtk_object_class->destroy = gdl_dock_paned_destroy;
117 container_class->add = gdl_dock_paned_add;
118 container_class->forall = gdl_dock_paned_forall;
119 container_class->child_type = gdl_dock_paned_child_type;
121 object_class->is_compound = TRUE;
123 object_class->dock_request = gdl_dock_paned_dock_request;
124 object_class->dock = gdl_dock_paned_dock;
125 object_class->child_placement = gdl_dock_paned_child_placement;
127 item_class->has_grip = FALSE;
128 item_class->set_orientation = gdl_dock_paned_set_orientation;
130 g_object_class_install_property (
131 g_object_class, PROP_POSITION,
132 g_param_spec_uint ("position", _("Position"),
133 _("Position of the divider in pixels"),
134 0, G_MAXINT, 0,
135 G_PARAM_READWRITE |
136 GDL_DOCK_PARAM_EXPORT | GDL_DOCK_PARAM_AFTER));
137 }
139 static void
140 gdl_dock_paned_instance_init (GdlDockPaned *paned)
141 {
142 paned->position_changed = FALSE;
143 paned->in_drag = FALSE;
144 paned->last_drag_position = -1;
145 }
147 static void
148 gdl_dock_paned_resize_paned_ancestors (GdlDockPaned *paned,
149 GdlDockExpansionDirection expansion_direction,
150 gint diff)
151 {
152 GtkWidget *widget, *last_widget;
154 g_return_if_fail (GDL_IS_DOCK_PANED (paned));
156 last_widget = GTK_WIDGET (paned);
158 /* make sure resizing only can be done in the drag direction */
159 if (expansion_direction == GDL_DOCK_EXPANSION_DIRECTION_NONE ||
160 ((expansion_direction == GDL_DOCK_EXPANSION_DIRECTION_DOWN ||
161 expansion_direction == GDL_DOCK_EXPANSION_DIRECTION_UP) &&
162 !GTK_IS_VPANED (GDL_DOCK_ITEM (paned)->child)) ||
163 ((expansion_direction == GDL_DOCK_EXPANSION_DIRECTION_LEFT ||
164 expansion_direction == GDL_DOCK_EXPANSION_DIRECTION_RIGHT) &&
165 !GTK_IS_HPANED (GDL_DOCK_ITEM (paned)->child)))
166 {
167 return;
168 }
170 for (widget = GTK_WIDGET (paned)->parent; widget != NULL;
171 widget = widget->parent) {
173 if (GTK_IS_PANED (widget)) {
175 GtkPaned *paned = GTK_PANED (widget);
177 if (last_widget == paned->child1) {
179 if (!GDL_IS_DOCK_OBJECT(widget->parent)) {
180 GtkRequisition requisition;
181 GtkAllocation allocation = paned->child1->allocation;
183 gtk_widget_size_request (paned->child1, &requisition);
185 gint new_height =
186 (allocation.height > requisition.height && diff > 0 ?
187 allocation.height : requisition.height) + diff;
189 gtk_widget_set_size_request (paned->child1, -1, new_height);
190 }
192 gtk_paned_set_position (paned, gtk_paned_get_position (paned) + diff);
193 }
195 } else if (!GDL_IS_DOCK_OBJECT (widget)) {
196 break;
197 }
199 last_widget = widget;
200 }
201 }
203 static void
204 gdl_dock_paned_notify_cb (GObject *g_object,
205 GParamSpec *pspec,
206 gpointer user_data)
207 {
208 GdlDockPaned *paned;
210 g_return_if_fail (user_data != NULL && GDL_IS_DOCK_PANED (user_data));
212 /* chain the notification to the GdlDockPaned */
213 g_object_notify (G_OBJECT (user_data), pspec->name);
215 paned = GDL_DOCK_PANED (user_data);
217 if (GDL_DOCK_ITEM_USER_ACTION (user_data) && !strcmp (pspec->name, "position")) {
219 GdlDockExpansionDirection expansion_direction;
221 paned->position_changed = TRUE;
223 g_object_get (GDL_DOCK_OBJECT(paned)->master,
224 "expand-direction", &expansion_direction,
225 NULL);
227 switch (expansion_direction) {
228 case GDL_DOCK_EXPANSION_DIRECTION_DOWN:
229 if (paned->in_drag) {
230 gint max_position, position, diff;
231 g_object_get (GDL_DOCK_ITEM (paned)->child,
232 "max-position", &max_position,
233 "position", &position,
234 NULL);
236 diff = position - paned->last_drag_position;
237 paned->last_drag_position = position;
239 if (diff > 0 && position == max_position) {
240 gdl_dock_paned_resize_paned_ancestors (paned, expansion_direction, diff + 1);
241 } else {
242 gdl_dock_paned_resize_paned_ancestors (paned, expansion_direction, diff);
243 }
245 }
246 break;
247 default:
248 ;
249 }
250 }
251 }
253 static gboolean
254 gdl_dock_paned_button_cb (GtkWidget *widget,
255 GdkEventButton *event,
256 gpointer user_data)
257 {
258 GdlDockPaned *paned;
260 g_return_val_if_fail (user_data != NULL && GDL_IS_DOCK_PANED (user_data), FALSE);
262 paned = GDL_DOCK_PANED (user_data);
263 if (event->button == 1) {
264 if (event->type == GDK_BUTTON_PRESS) {
266 GdlDockExpansionDirection expansion_direction;
268 GDL_DOCK_ITEM_SET_FLAGS (user_data, GDL_DOCK_USER_ACTION);
270 paned->in_drag = TRUE;
272 g_object_get (GDL_DOCK_OBJECT (paned)->master,
273 "expand-direction", &expansion_direction,
274 NULL);
276 switch (expansion_direction) {
277 case GDL_DOCK_EXPANSION_DIRECTION_DOWN:
278 {
279 gint max_position, position;
280 g_object_get (GDL_DOCK_ITEM (paned)->child,
281 "max-position", &max_position,
282 "position", &position,
283 NULL);
285 paned->last_drag_position = position;
286 /* expand the paned's ancestors a bit if the separator is in max position
287 * to allow dragging in all directions */
288 if (position == max_position)
289 gdl_dock_paned_resize_paned_ancestors (paned, expansion_direction, 1);
290 break;
291 }
292 default:
293 ;
294 }
295 }
296 else if (event->type == GDK_BUTTON_RELEASE) {
297 paned->last_drag_position = -1;
298 paned->in_drag = FALSE;
299 }
300 else {
301 GDL_DOCK_ITEM_UNSET_FLAGS (user_data, GDL_DOCK_USER_ACTION);
302 if (paned->position_changed) {
303 /* emit pending layout changed signal to track separator position */
304 if (GDL_DOCK_OBJECT (paned)->master)
305 g_signal_emit_by_name (GDL_DOCK_OBJECT (paned)->master, "layout-changed");
306 paned->position_changed = FALSE;
307 }
308 }
309 }
311 return FALSE;
312 }
314 static void
315 gdl_dock_paned_create_child (GdlDockPaned *paned,
316 GtkOrientation orientation)
317 {
318 GdlDockItem *item;
320 item = GDL_DOCK_ITEM (paned);
322 if (item->child)
323 gtk_widget_unparent (GTK_WIDGET (item->child));
325 /* create the container paned */
326 if (orientation == GTK_ORIENTATION_HORIZONTAL)
327 item->child = gtk_hpaned_new ();
328 else
329 item->child = gtk_vpaned_new ();
331 /* get notification for propagation */
332 g_signal_connect (item->child, "notify::position",
333 (GCallback) gdl_dock_paned_notify_cb, (gpointer) item);
334 g_signal_connect (item->child, "button-press-event",
335 (GCallback) gdl_dock_paned_button_cb, (gpointer) item);
336 g_signal_connect (item->child, "button-release-event",
337 (GCallback) gdl_dock_paned_button_cb, (gpointer) item);
339 gtk_widget_set_parent (item->child, GTK_WIDGET (item));
340 gtk_widget_show (item->child);
341 }
343 static GObject *
344 gdl_dock_paned_constructor (GType type,
345 guint n_construct_properties,
346 GObjectConstructParam *construct_param)
347 {
348 GObject *g_object;
350 g_object = GDL_CALL_PARENT_WITH_DEFAULT (G_OBJECT_CLASS,
351 constructor,
352 (type,
353 n_construct_properties,
354 construct_param),
355 NULL);
356 if (g_object) {
357 GdlDockItem *item = GDL_DOCK_ITEM (g_object);
359 if (!item->child)
360 gdl_dock_paned_create_child (GDL_DOCK_PANED (g_object),
361 item->orientation);
362 /* otherwise, the orientation was set as a construction
363 parameter and the child is already created */
364 }
366 return g_object;
367 }
369 static void
370 gdl_dock_paned_set_property (GObject *object,
371 guint prop_id,
372 const GValue *value,
373 GParamSpec *pspec)
374 {
375 GdlDockItem *item = GDL_DOCK_ITEM (object);
377 switch (prop_id) {
378 case PROP_POSITION:
379 if (item->child && GTK_IS_PANED (item->child))
380 gtk_paned_set_position (GTK_PANED (item->child),
381 g_value_get_uint (value));
382 break;
383 default:
384 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
385 break;
386 }
387 }
389 static void
390 gdl_dock_paned_get_property (GObject *object,
391 guint prop_id,
392 GValue *value,
393 GParamSpec *pspec)
394 {
395 GdlDockItem *item = GDL_DOCK_ITEM (object);
397 switch (prop_id) {
398 case PROP_POSITION:
399 if (item->child && GTK_IS_PANED (item->child))
400 g_value_set_uint (value,
401 gtk_paned_get_position (GTK_PANED (item->child)));
402 else
403 g_value_set_uint (value, 0);
404 break;
405 default:
406 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
407 break;
408 }
409 }
411 static void
412 gdl_dock_paned_destroy (GtkObject *object)
413 {
414 GdlDockItem *item = GDL_DOCK_ITEM (object);
416 /* we need to call the virtual first, since in GdlDockDestroy our
417 children dock objects are detached */
418 GDL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
420 /* after that we can remove the GtkNotebook */
421 if (item->child) {
422 gtk_widget_unparent (item->child);
423 item->child = NULL;
424 };
425 }
427 static void
428 gdl_dock_paned_add (GtkContainer *container,
429 GtkWidget *widget)
430 {
431 GdlDockItem *item;
432 GtkPaned *paned;
433 GdlDockPlacement pos = GDL_DOCK_NONE;
435 g_return_if_fail (container != NULL && widget != NULL);
436 g_return_if_fail (GDL_IS_DOCK_PANED (container));
437 g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
439 item = GDL_DOCK_ITEM (container);
440 g_return_if_fail (item->child != NULL);
441 paned = GTK_PANED (item->child);
442 g_return_if_fail (!paned->child1 || !paned->child2);
444 if (!paned->child1)
445 pos = item->orientation == GTK_ORIENTATION_HORIZONTAL ?
446 GDL_DOCK_LEFT : GDL_DOCK_TOP;
447 else if (!paned->child2)
448 pos = item->orientation == GTK_ORIENTATION_HORIZONTAL ?
449 GDL_DOCK_RIGHT : GDL_DOCK_BOTTOM;
451 if (pos != GDL_DOCK_NONE)
452 gdl_dock_object_dock (GDL_DOCK_OBJECT (container),
453 GDL_DOCK_OBJECT (widget),
454 pos, NULL);
455 }
457 static void
458 gdl_dock_paned_forall (GtkContainer *container,
459 gboolean include_internals,
460 GtkCallback callback,
461 gpointer callback_data)
462 {
463 GdlDockItem *item;
465 g_return_if_fail (container != NULL);
466 g_return_if_fail (GDL_IS_DOCK_PANED (container));
467 g_return_if_fail (callback != NULL);
469 if (include_internals) {
470 /* use GdlDockItem's forall */
471 GDL_CALL_PARENT (GTK_CONTAINER_CLASS, forall,
472 (container, include_internals, callback, callback_data));
473 }
474 else {
475 item = GDL_DOCK_ITEM (container);
476 if (item->child)
477 gtk_container_foreach (GTK_CONTAINER (item->child), callback, callback_data);
478 }
479 }
481 static GType
482 gdl_dock_paned_child_type (GtkContainer *container)
483 {
484 GdlDockItem *item = GDL_DOCK_ITEM (container);
486 if (gtk_container_child_type (GTK_CONTAINER (item->child)) == G_TYPE_NONE)
487 return G_TYPE_NONE;
488 else
489 return GDL_TYPE_DOCK_ITEM;
490 }
492 static void
493 gdl_dock_paned_request_foreach (GdlDockObject *object,
494 gpointer user_data)
495 {
496 struct {
497 gint x, y;
498 GdlDockRequest *request;
499 gboolean may_dock;
500 } *data = user_data;
502 GdlDockRequest my_request;
503 gboolean may_dock;
505 my_request = *data->request;
506 may_dock = gdl_dock_object_dock_request (object, data->x, data->y, &my_request);
507 if (may_dock) {
508 data->may_dock = TRUE;
509 *data->request = my_request;
510 }
511 }
513 static gboolean
514 gdl_dock_paned_dock_request (GdlDockObject *object,
515 gint x,
516 gint y,
517 GdlDockRequest *request)
518 {
519 GdlDockItem *item;
520 guint bw;
521 gint rel_x, rel_y;
522 GtkAllocation *alloc;
523 gboolean may_dock = FALSE;
524 GdlDockRequest my_request;
526 g_return_val_if_fail (GDL_IS_DOCK_ITEM (object), FALSE);
528 /* we get (x,y) in our allocation coordinates system */
530 item = GDL_DOCK_ITEM (object);
532 /* Get item's allocation. */
533 alloc = &(GTK_WIDGET (object)->allocation);
534 bw = GTK_CONTAINER (object)->border_width;
536 /* Get coordinates relative to our window. */
537 rel_x = x - alloc->x;
538 rel_y = y - alloc->y;
540 if (request)
541 my_request = *request;
543 /* Check if coordinates are inside the widget. */
544 if (rel_x > 0 && rel_x < alloc->width &&
545 rel_y > 0 && rel_y < alloc->height) {
546 GtkRequisition my, other;
547 gint divider = -1;
549 gdl_dock_item_preferred_size (GDL_DOCK_ITEM (my_request.applicant), &other);
550 gdl_dock_item_preferred_size (GDL_DOCK_ITEM (object), &my);
552 /* It's inside our area. */
553 may_dock = TRUE;
555 /* Set docking indicator rectangle to the widget size. */
556 my_request.rect.x = bw;
557 my_request.rect.y = bw;
558 my_request.rect.width = alloc->width - 2*bw;
559 my_request.rect.height = alloc->height - 2*bw;
561 my_request.target = object;
563 /* See if it's in the border_width band. */
564 if (rel_x < bw) {
565 my_request.position = GDL_DOCK_LEFT;
566 my_request.rect.width *= SPLIT_RATIO;
567 divider = other.width;
568 } else if (rel_x > alloc->width - bw) {
569 my_request.position = GDL_DOCK_RIGHT;
570 my_request.rect.x += my_request.rect.width * (1 - SPLIT_RATIO);
571 my_request.rect.width *= SPLIT_RATIO;
572 divider = MAX (0, my.width - other.width);
573 } else if (rel_y < bw) {
574 my_request.position = GDL_DOCK_TOP;
575 my_request.rect.height *= SPLIT_RATIO;
576 divider = other.height;
577 } else if (rel_y > alloc->height - bw) {
578 my_request.position = GDL_DOCK_BOTTOM;
579 my_request.rect.y += my_request.rect.height * (1 - SPLIT_RATIO);
580 my_request.rect.height *= SPLIT_RATIO;
581 divider = MAX (0, my.height - other.height);
583 } else { /* Otherwise try our children. */
584 struct {
585 gint x, y;
586 GdlDockRequest *request;
587 gboolean may_dock;
588 } data;
590 /* give them coordinates in their allocation system... the
591 GtkPaned has no window, so our children allocation
592 coordinates are our window coordinates */
593 data.x = rel_x;
594 data.y = rel_y;
595 data.request = &my_request;
596 data.may_dock = FALSE;
598 gtk_container_foreach (GTK_CONTAINER (object),
599 (GtkCallback) gdl_dock_paned_request_foreach,
600 &data);
602 may_dock = data.may_dock;
603 if (!may_dock) {
604 /* the pointer is on the handle, so snap to top/bottom
605 or left/right */
606 may_dock = TRUE;
607 if (item->orientation == GTK_ORIENTATION_HORIZONTAL) {
608 if (rel_y < alloc->height / 2) {
609 my_request.position = GDL_DOCK_TOP;
610 my_request.rect.height *= SPLIT_RATIO;
611 divider = other.height;
612 } else {
613 my_request.position = GDL_DOCK_BOTTOM;
614 my_request.rect.y += my_request.rect.height * (1 - SPLIT_RATIO);
615 my_request.rect.height *= SPLIT_RATIO;
616 divider = MAX (0, my.height - other.height);
617 }
618 } else {
619 if (rel_x < alloc->width / 2) {
620 my_request.position = GDL_DOCK_LEFT;
621 my_request.rect.width *= SPLIT_RATIO;
622 divider = other.width;
623 } else {
624 my_request.position = GDL_DOCK_RIGHT;
625 my_request.rect.x += my_request.rect.width * (1 - SPLIT_RATIO);
626 my_request.rect.width *= SPLIT_RATIO;
627 divider = MAX (0, my.width - other.width);
628 }
629 }
630 }
631 }
633 if (divider >= 0 && my_request.position != GDL_DOCK_CENTER) {
634 if (G_IS_VALUE (&my_request.extra))
635 g_value_unset (&my_request.extra);
636 g_value_init (&my_request.extra, G_TYPE_UINT);
637 g_value_set_uint (&my_request.extra, (guint) divider);
638 }
640 if (may_dock) {
641 /* adjust returned coordinates so they are relative to
642 our allocation */
643 my_request.rect.x += alloc->x;
644 my_request.rect.y += alloc->y;
645 }
646 }
648 if (may_dock && request)
649 *request = my_request;
651 return may_dock;
652 }
654 static void
655 gdl_dock_paned_dock (GdlDockObject *object,
656 GdlDockObject *requestor,
657 GdlDockPlacement position,
658 GValue *other_data)
659 {
660 GtkPaned *paned;
661 gboolean done = FALSE;
662 gboolean hresize = FALSE;
663 gboolean wresize = FALSE;
664 gint temp = 0;
666 g_return_if_fail (GDL_IS_DOCK_PANED (object));
667 g_return_if_fail (GDL_DOCK_ITEM (object)->child != NULL);
669 paned = GTK_PANED (GDL_DOCK_ITEM (object)->child);
671 if (GDL_IS_DOCK_ITEM (requestor)) {
672 g_object_get (G_OBJECT (requestor), "preferred_height", &temp, NULL);
673 if (temp == -2)
674 hresize = TRUE;
675 temp = 0;
676 g_object_get (G_OBJECT (requestor), "preferred_width", &temp, NULL);
677 if (temp == -2)
678 wresize = TRUE;
679 }
681 /* see if we can dock the item in our paned */
682 switch (GDL_DOCK_ITEM (object)->orientation) {
683 case GTK_ORIENTATION_HORIZONTAL:
684 if (!paned->child1 && position == GDL_DOCK_LEFT) {
685 gtk_paned_pack1 (paned, GTK_WIDGET (requestor), FALSE, FALSE);
686 done = TRUE;
687 } else if (!paned->child2 && position == GDL_DOCK_RIGHT) {
688 gtk_paned_pack2 (paned, GTK_WIDGET (requestor), TRUE, FALSE);
689 done = TRUE;
690 }
691 break;
692 case GTK_ORIENTATION_VERTICAL:
693 if (!paned->child1 && position == GDL_DOCK_TOP) {
694 gtk_paned_pack1 (paned, GTK_WIDGET (requestor), hresize, FALSE);
695 done = TRUE;
696 } else if (!paned->child2 && position == GDL_DOCK_BOTTOM) {
697 gtk_paned_pack2 (paned, GTK_WIDGET (requestor), TRUE, FALSE);
698 done = TRUE;
699 }
700 break;
701 default:
702 break;
703 }
705 if (!done) {
706 /* this will create another paned and reparent us there */
707 GDL_CALL_PARENT (GDL_DOCK_OBJECT_CLASS, dock, (object, requestor, position,
708 other_data));
709 }
710 else {
711 gdl_dock_item_show_grip (GDL_DOCK_ITEM (requestor));
712 GDL_DOCK_OBJECT_SET_FLAGS (requestor, GDL_DOCK_ATTACHED);
713 }
714 }
716 static void
717 gdl_dock_paned_set_orientation (GdlDockItem *item,
718 GtkOrientation orientation)
719 {
720 GtkPaned *old_paned = NULL, *new_paned;
721 GtkWidget *child1, *child2;
723 g_return_if_fail (GDL_IS_DOCK_PANED (item));
725 if (item->child) {
726 old_paned = GTK_PANED (item->child);
727 g_object_ref (old_paned);
728 gtk_widget_unparent (GTK_WIDGET (old_paned));
729 item->child = NULL;
730 }
732 gdl_dock_paned_create_child (GDL_DOCK_PANED (item), orientation);
734 if (old_paned) {
735 new_paned = GTK_PANED (item->child);
736 child1 = old_paned->child1;
737 child2 = old_paned->child2;
739 if (child1) {
740 g_object_ref (child1);
741 gtk_container_remove (GTK_CONTAINER (old_paned), child1);
742 gtk_paned_pack1 (new_paned, child1, TRUE, FALSE);
743 g_object_unref (child1);
744 }
745 if (child2) {
746 g_object_ref (child2);
747 gtk_container_remove (GTK_CONTAINER (old_paned), child2);
748 gtk_paned_pack1 (new_paned, child2, TRUE, FALSE);
749 g_object_unref (child2);
750 }
751 }
753 GDL_CALL_PARENT (GDL_DOCK_ITEM_CLASS, set_orientation, (item, orientation));
754 }
756 static gboolean
757 gdl_dock_paned_child_placement (GdlDockObject *object,
758 GdlDockObject *child,
759 GdlDockPlacement *placement)
760 {
761 GdlDockItem *item = GDL_DOCK_ITEM (object);
762 GtkPaned *paned;
763 GdlDockPlacement pos = GDL_DOCK_NONE;
765 if (item->child) {
766 paned = GTK_PANED (item->child);
767 if (GTK_WIDGET (child) == paned->child1)
768 pos = item->orientation == GTK_ORIENTATION_HORIZONTAL ?
769 GDL_DOCK_LEFT : GDL_DOCK_TOP;
770 else if (GTK_WIDGET (child) == paned->child2)
771 pos = item->orientation == GTK_ORIENTATION_HORIZONTAL ?
772 GDL_DOCK_RIGHT : GDL_DOCK_BOTTOM;
773 }
775 if (pos != GDL_DOCK_NONE) {
776 if (placement)
777 *placement = pos;
778 return TRUE;
779 }
780 else
781 return FALSE;
782 }
785 /* ----- Public interface ----- */
787 GtkWidget *
788 gdl_dock_paned_new (GtkOrientation orientation)
789 {
790 GdlDockPaned *paned;
792 paned = GDL_DOCK_PANED (g_object_new (GDL_TYPE_DOCK_PANED,
793 "orientation", orientation, NULL));
794 GDL_DOCK_OBJECT_UNSET_FLAGS (paned, GDL_DOCK_AUTOMATIC);
796 return GTK_WIDGET (paned);
797 }