1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
34 static void gtk_paned_class_init (GtkPanedClass *klass);
35 static void gtk_paned_init (GtkPaned *paned);
36 static void gtk_paned_set_arg (GtkObject *object,
39 static void gtk_paned_get_arg (GtkObject *object,
42 static void gtk_paned_realize (GtkWidget *widget);
43 static void gtk_paned_map (GtkWidget *widget);
44 static void gtk_paned_unmap (GtkWidget *widget);
45 static void gtk_paned_unrealize (GtkWidget *widget);
46 static gint gtk_paned_expose (GtkWidget *widget,
47 GdkEventExpose *event);
48 static void gtk_paned_add (GtkContainer *container,
50 static void gtk_paned_remove (GtkContainer *container,
52 static void gtk_paned_forall (GtkContainer *container,
53 gboolean include_internals,
55 gpointer callback_data);
56 static GtkType gtk_paned_child_type (GtkContainer *container);
58 static GtkContainerClass *parent_class = NULL;
62 gtk_paned_get_type (void)
64 static GtkType paned_type = 0;
68 static const GtkTypeInfo paned_info =
72 sizeof (GtkPanedClass),
73 (GtkClassInitFunc) gtk_paned_class_init,
74 (GtkObjectInitFunc) gtk_paned_init,
75 /* reserved_1 */ NULL,
76 /* reserved_2 */ NULL,
77 (GtkClassInitFunc) NULL,
80 paned_type = gtk_type_unique (GTK_TYPE_CONTAINER, &paned_info);
87 gtk_paned_class_init (GtkPanedClass *class)
89 GtkObjectClass *object_class;
90 GtkWidgetClass *widget_class;
91 GtkContainerClass *container_class;
93 object_class = (GtkObjectClass *) class;
94 widget_class = (GtkWidgetClass *) class;
95 container_class = (GtkContainerClass *) class;
97 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
99 object_class->set_arg = gtk_paned_set_arg;
100 object_class->get_arg = gtk_paned_get_arg;
102 widget_class->realize = gtk_paned_realize;
103 widget_class->map = gtk_paned_map;
104 widget_class->unmap = gtk_paned_unmap;
105 widget_class->unrealize = gtk_paned_unrealize;
106 widget_class->expose_event = gtk_paned_expose;
108 container_class->add = gtk_paned_add;
109 container_class->remove = gtk_paned_remove;
110 container_class->forall = gtk_paned_forall;
111 container_class->child_type = gtk_paned_child_type;
113 gtk_object_add_arg_type("GtkPaned::handle_size", GTK_TYPE_UINT,
114 GTK_ARG_READWRITE, ARG_HANDLE_SIZE);
118 gtk_paned_child_type (GtkContainer *container)
120 if (!GTK_PANED (container)->child1 || !GTK_PANED (container)->child2)
121 return GTK_TYPE_WIDGET;
123 return GTK_TYPE_NONE;
127 gtk_paned_init (GtkPaned *paned)
129 GTK_WIDGET_UNSET_FLAGS (paned, GTK_NO_WINDOW);
131 paned->child1 = NULL;
132 paned->child2 = NULL;
133 paned->handle = NULL;
134 paned->xor_gc = NULL;
135 paned->cursor_type = GDK_CROSS;
137 paned->handle_width = 5;
138 paned->handle_height = 5;
139 paned->handle_size = 5;
140 paned->position_set = FALSE;
141 paned->last_allocation = -1;
142 paned->in_drag = FALSE;
144 paned->handle_xpos = -1;
145 paned->handle_ypos = -1;
149 gtk_paned_set_arg (GtkObject *object,
153 GtkPaned *paned = GTK_PANED (object);
157 case ARG_HANDLE_SIZE:
158 gtk_paned_set_handle_size (paned, GTK_VALUE_UINT (*arg));
166 gtk_paned_get_arg (GtkObject *object,
170 GtkPaned *paned = GTK_PANED (object);
174 case ARG_HANDLE_SIZE:
175 GTK_VALUE_UINT (*arg) = paned->handle_size;
178 arg->type = GTK_TYPE_INVALID;
184 gtk_paned_realize (GtkWidget *widget)
187 GdkWindowAttr attributes;
188 gint attributes_mask;
190 g_return_if_fail (widget != NULL);
191 g_return_if_fail (GTK_IS_PANED (widget));
193 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
194 paned = GTK_PANED (widget);
196 attributes.x = widget->allocation.x;
197 attributes.y = widget->allocation.y;
198 attributes.width = widget->allocation.width;
199 attributes.height = widget->allocation.height;
200 attributes.window_type = GDK_WINDOW_CHILD;
201 attributes.wclass = GDK_INPUT_OUTPUT;
202 attributes.visual = gtk_widget_get_visual (widget);
203 attributes.colormap = gtk_widget_get_colormap (widget);
204 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
205 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
207 widget->window = gdk_window_new (gtk_widget_get_parent_window(widget),
208 &attributes, attributes_mask);
209 gdk_window_set_user_data (widget->window, paned);
211 attributes.x = paned->handle_xpos;
212 attributes.y = paned->handle_ypos;
213 attributes.width = paned->handle_width;
214 attributes.height = paned->handle_height;
215 attributes.cursor = gdk_cursor_new (paned->cursor_type);
216 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
217 GDK_BUTTON_RELEASE_MASK |
218 GDK_POINTER_MOTION_MASK |
219 GDK_POINTER_MOTION_HINT_MASK);
220 attributes_mask |= GDK_WA_CURSOR;
222 paned->handle = gdk_window_new (widget->window,
223 &attributes, attributes_mask);
224 gdk_window_set_user_data (paned->handle, paned);
225 gdk_cursor_destroy (attributes.cursor);
227 widget->style = gtk_style_attach (widget->style, widget->window);
229 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
230 gtk_style_set_background (widget->style, paned->handle, GTK_STATE_NORMAL);
232 gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
234 gdk_window_show (paned->handle);
238 gtk_paned_map (GtkWidget *widget)
242 g_return_if_fail (widget != NULL);
243 g_return_if_fail (GTK_IS_PANED (widget));
245 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
246 paned = GTK_PANED (widget);
249 GTK_WIDGET_VISIBLE (paned->child1) &&
250 !GTK_WIDGET_MAPPED (paned->child1))
251 gtk_widget_map (paned->child1);
253 GTK_WIDGET_VISIBLE (paned->child2) &&
254 !GTK_WIDGET_MAPPED (paned->child2))
255 gtk_widget_map (paned->child2);
257 gdk_window_show (widget->window);
261 gtk_paned_unmap (GtkWidget *widget)
263 g_return_if_fail (widget != NULL);
264 g_return_if_fail (GTK_IS_PANED (widget));
266 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
268 gdk_window_hide (widget->window);
272 gtk_paned_unrealize (GtkWidget *widget)
276 g_return_if_fail (widget != NULL);
277 g_return_if_fail (GTK_IS_PANED (widget));
279 paned = GTK_PANED (widget);
283 gdk_gc_destroy (paned->xor_gc);
284 paned->xor_gc = NULL;
289 gdk_window_set_user_data (paned->handle, NULL);
290 gdk_window_destroy (paned->handle);
291 paned->handle = NULL;
294 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
295 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
301 gtk_paned_expose (GtkWidget *widget,
302 GdkEventExpose *event)
305 GdkEventExpose child_event;
307 g_return_val_if_fail (widget != NULL, FALSE);
308 g_return_val_if_fail (GTK_IS_PANED (widget), FALSE);
309 g_return_val_if_fail (event != NULL, FALSE);
311 if (GTK_WIDGET_DRAWABLE (widget))
313 paned = GTK_PANED (widget);
315 if (event->window != paned->handle)
317 child_event = *event;
320 GTK_WIDGET_NO_WINDOW (paned->child1) &&
321 gtk_widget_intersect (paned->child1, &event->area, &child_event.area))
322 gtk_widget_event (paned->child1, (GdkEvent *) &child_event);
325 GTK_WIDGET_NO_WINDOW (paned->child2) &&
326 gtk_widget_intersect (paned->child2, &event->area, &child_event.area))
327 gtk_widget_event (paned->child2, (GdkEvent *) &child_event);
335 gtk_paned_add1 (GtkPaned *paned,
338 gtk_paned_pack1 (paned, widget, FALSE, TRUE);
342 gtk_paned_add2 (GtkPaned *paned,
345 gtk_paned_pack2 (paned, widget, TRUE, TRUE);
349 gtk_paned_pack1 (GtkPaned *paned,
354 g_return_if_fail (paned != NULL);
355 g_return_if_fail (GTK_IS_PANED (paned));
356 g_return_if_fail (GTK_IS_WIDGET (child));
360 paned->child1 = child;
361 paned->child1_resize = resize;
362 paned->child1_shrink = shrink;
364 gtk_widget_set_parent (child, GTK_WIDGET (paned));
366 if (GTK_WIDGET_REALIZED (child->parent))
367 gtk_widget_realize (child);
369 if (GTK_WIDGET_VISIBLE (child->parent) && GTK_WIDGET_VISIBLE (child))
371 if (GTK_WIDGET_MAPPED (child->parent))
372 gtk_widget_map (child);
374 gtk_widget_queue_resize (child);
380 gtk_paned_pack2 (GtkPaned *paned,
385 g_return_if_fail (paned != NULL);
386 g_return_if_fail (GTK_IS_PANED (paned));
387 g_return_if_fail (GTK_IS_WIDGET (child));
391 paned->child2 = child;
392 paned->child2_resize = resize;
393 paned->child2_shrink = shrink;
395 gtk_widget_set_parent (child, GTK_WIDGET (paned));
397 if (GTK_WIDGET_REALIZED (child->parent))
398 gtk_widget_realize (child);
400 if (GTK_WIDGET_VISIBLE (child->parent) && GTK_WIDGET_VISIBLE (child))
402 if (GTK_WIDGET_MAPPED (child->parent))
403 gtk_widget_map (child);
405 gtk_widget_queue_resize (child);
412 gtk_paned_add (GtkContainer *container,
417 g_return_if_fail (container != NULL);
418 g_return_if_fail (GTK_IS_PANED (container));
419 g_return_if_fail (widget != NULL);
421 paned = GTK_PANED (container);
424 gtk_paned_add1 (GTK_PANED (container), widget);
425 else if (!paned->child2)
426 gtk_paned_add2 (GTK_PANED (container), widget);
430 gtk_paned_remove (GtkContainer *container,
434 gboolean was_visible;
436 g_return_if_fail (container != NULL);
437 g_return_if_fail (GTK_IS_PANED (container));
438 g_return_if_fail (widget != NULL);
440 paned = GTK_PANED (container);
441 was_visible = GTK_WIDGET_VISIBLE (widget);
443 if (paned->child1 == widget)
445 gtk_widget_unparent (widget);
447 paned->child1 = NULL;
449 if (was_visible && GTK_WIDGET_VISIBLE (container))
450 gtk_widget_queue_resize (GTK_WIDGET (container));
452 else if (paned->child2 == widget)
454 gtk_widget_unparent (widget);
456 paned->child2 = NULL;
458 if (was_visible && GTK_WIDGET_VISIBLE (container))
459 gtk_widget_queue_resize (GTK_WIDGET (container));
464 gtk_paned_forall (GtkContainer *container,
465 gboolean include_internals,
466 GtkCallback callback,
467 gpointer callback_data)
471 g_return_if_fail (container != NULL);
472 g_return_if_fail (GTK_IS_PANED (container));
473 g_return_if_fail (callback != NULL);
475 paned = GTK_PANED (container);
478 (*callback) (paned->child1, callback_data);
480 (*callback) (paned->child2, callback_data);
484 * gtk_paned_get_position:
485 * @paned: a #GtkPaned widget
487 * Obtains the position of the divider between the two panes.
489 * Return value: position of the divider
492 gtk_paned_get_position (GtkPaned *paned)
494 g_return_val_if_fail (paned != NULL, 0);
495 g_return_val_if_fail (GTK_IS_PANED (paned), 0);
497 return paned->child1_size;
501 * gtk_paned_set_position:
502 * @paned: a #GtkPaned widget
503 * @position: pixel position of divider
505 * Sets the position of the divider between the two panes.
508 gtk_paned_set_position (GtkPaned *paned,
511 g_return_if_fail (paned != NULL);
512 g_return_if_fail (GTK_IS_PANED (paned));
516 /* We don't clamp here - the assumption is that
517 * if the total allocation changes at the same time
518 * as the position, the position set is with reference
519 * to the new total size. If only the position changes,
520 * then clamping will occur in gtk_paned_compute_position()
522 paned->child1_size = position;
523 paned->position_set = TRUE;
527 paned->position_set = FALSE;
530 gtk_widget_queue_resize (GTK_WIDGET (paned));
534 gtk_paned_set_handle_size (GtkPaned *paned,
537 g_return_if_fail (paned != NULL);
538 g_return_if_fail (GTK_IS_PANED (paned));
540 gtk_widget_queue_resize (GTK_WIDGET (paned));
542 paned->handle_size = size;
546 gtk_paned_compute_position(GtkPaned *paned,
551 g_return_if_fail (paned != NULL);
552 g_return_if_fail (GTK_IS_PANED (paned));
554 paned->min_position = paned->child1_shrink ? 0 : child1_req;
556 paned->max_position = allocation;
557 if (!paned->child2_shrink)
558 paned->max_position = MAX (1, paned->max_position - child2_req);
560 if (!paned->position_set)
562 if (paned->child1_resize && !paned->child2_resize)
563 paned->child1_size = MAX (1, allocation - child2_req);
564 else if (!paned->child1_resize && paned->child2_resize)
565 paned->child1_size = child1_req;
566 else if (child1_req + child2_req != 0)
567 paned->child1_size = allocation * ((gdouble)child1_req / (child1_req + child2_req));
569 paned->child1_size = allocation * 0.5;
573 /* If the position was set before the initial allocation.
574 * (paned->last_allocation <= 0) just clamp it and leave it.
576 if (paned->last_allocation > 0)
578 if (paned->child1_resize && !paned->child2_resize)
579 paned->child1_size += allocation - paned->last_allocation;
580 else if (!(!paned->child1_resize && paned->child2_resize))
581 paned->child1_size = allocation * ((gdouble) paned->child1_size / (paned->last_allocation));
585 paned->child1_size = CLAMP (paned->child1_size,
587 paned->max_position);
589 paned->last_allocation = allocation;