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/.
27 #include "gtkhpaned.h"
29 static void gtk_hpaned_class_init (GtkHPanedClass *klass);
30 static void gtk_hpaned_init (GtkHPaned *hpaned);
31 static void gtk_hpaned_size_request (GtkWidget *widget,
32 GtkRequisition *requisition);
33 static void gtk_hpaned_size_allocate (GtkWidget *widget,
34 GtkAllocation *allocation);
35 static gint gtk_hpaned_expose (GtkWidget *widget,
36 GdkEventExpose *event);
37 static void gtk_hpaned_xor_line (GtkPaned *paned);
38 static gboolean gtk_hpaned_button_press (GtkWidget *widget,
39 GdkEventButton *event);
40 static gboolean gtk_hpaned_button_release (GtkWidget *widget,
41 GdkEventButton *event);
42 static gboolean gtk_hpaned_motion (GtkWidget *widget,
43 GdkEventMotion *event);
45 static gpointer parent_class;
48 gtk_hpaned_get_type (void)
50 static GtkType hpaned_type = 0;
54 static const GtkTypeInfo hpaned_info =
58 sizeof (GtkHPanedClass),
59 (GtkClassInitFunc) gtk_hpaned_class_init,
60 (GtkObjectInitFunc) gtk_hpaned_init,
61 /* reserved_1 */ NULL,
62 /* reserved_2 */ NULL,
63 (GtkClassInitFunc) NULL,
66 hpaned_type = gtk_type_unique (GTK_TYPE_PANED, &hpaned_info);
73 gtk_hpaned_class_init (GtkHPanedClass *class)
75 GtkWidgetClass *widget_class;
77 parent_class = gtk_type_class (GTK_TYPE_PANED);
79 widget_class = (GtkWidgetClass *) class;
81 widget_class->size_request = gtk_hpaned_size_request;
82 widget_class->size_allocate = gtk_hpaned_size_allocate;
83 widget_class->expose_event = gtk_hpaned_expose;
84 widget_class->button_press_event = gtk_hpaned_button_press;
85 widget_class->button_release_event = gtk_hpaned_button_release;
86 widget_class->motion_notify_event = gtk_hpaned_motion;
90 gtk_hpaned_init (GtkHPaned *hpaned)
94 g_return_if_fail (hpaned != NULL);
95 g_return_if_fail (GTK_IS_PANED (hpaned));
97 paned = GTK_PANED (hpaned);
99 paned->cursor_type = GDK_SB_H_DOUBLE_ARROW;
103 gtk_hpaned_new (void)
107 hpaned = gtk_type_new (GTK_TYPE_HPANED);
109 return GTK_WIDGET (hpaned);
113 gtk_hpaned_size_request (GtkWidget *widget,
114 GtkRequisition *requisition)
116 GtkPaned *paned = GTK_PANED (widget);
117 GtkRequisition child_requisition;
119 requisition->width = 0;
120 requisition->height = 0;
122 if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1))
124 gtk_widget_size_request (paned->child1, &child_requisition);
126 requisition->height = child_requisition.height;
127 requisition->width = child_requisition.width;
130 if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
132 gtk_widget_size_request (paned->child2, &child_requisition);
134 requisition->height = MAX(requisition->height, child_requisition.height);
135 requisition->width += child_requisition.width;
138 requisition->width += GTK_CONTAINER (paned)->border_width * 2;
139 requisition->height += GTK_CONTAINER (paned)->border_width * 2;
141 if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1) &&
142 paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
146 gtk_widget_style_get (widget, "handle_size", &handle_size, NULL);
147 requisition->width += handle_size;
152 gtk_hpaned_size_allocate (GtkWidget *widget,
153 GtkAllocation *allocation)
155 GtkPaned *paned = GTK_PANED (widget);
156 gint border_width = GTK_CONTAINER (paned)->border_width;
158 widget->allocation = *allocation;
159 if (GTK_WIDGET_REALIZED (widget))
160 gdk_window_move_resize (widget->window,
161 allocation->x, allocation->y,
165 if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1) &&
166 paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
168 GtkAllocation child1_allocation;
169 GtkAllocation child2_allocation;
170 GtkRequisition child1_requisition;
171 GtkRequisition child2_requisition;
174 gtk_widget_style_get (widget, "handle_size", &handle_size, NULL);
176 gtk_widget_get_child_requisition (paned->child1, &child1_requisition);
177 gtk_widget_get_child_requisition (paned->child2, &child2_requisition);
179 gtk_paned_compute_position (paned,
180 MAX (1, widget->allocation.width
183 child1_requisition.width,
184 child2_requisition.width);
186 /* Move the handle before the children so we don't get extra expose events */
188 paned->handle_xpos = paned->child1_size + border_width;
189 paned->handle_ypos = border_width;
190 paned->handle_width = handle_size;
191 paned->handle_height = MAX (1, widget->allocation.height - 2 * border_width);
193 if (GTK_WIDGET_REALIZED (widget))
195 gdk_window_show (paned->handle);
196 gdk_window_move_resize (paned->handle,
200 paned->handle_height);
203 child1_allocation.height = child2_allocation.height = MAX (1, (gint) allocation->height - border_width * 2);
204 child1_allocation.width = paned->child1_size;
205 child1_allocation.x = border_width;
206 child1_allocation.y = child2_allocation.y = border_width;
208 child2_allocation.x = child1_allocation.x + child1_allocation.width + paned->handle_width;
209 child2_allocation.width = MAX (1, (gint) allocation->width - child2_allocation.x - border_width);
211 /* Now allocate the childen, making sure, when resizing not to
212 * overlap the windows */
213 if (GTK_WIDGET_MAPPED (widget) &&
214 paned->child1->allocation.width < child1_allocation.width)
216 gtk_widget_size_allocate (paned->child2, &child2_allocation);
217 gtk_widget_size_allocate (paned->child1, &child1_allocation);
221 gtk_widget_size_allocate (paned->child1, &child1_allocation);
222 gtk_widget_size_allocate (paned->child2, &child2_allocation);
227 GtkAllocation child_allocation;
229 if (GTK_WIDGET_REALIZED (widget))
230 gdk_window_hide (paned->handle);
232 child_allocation.x = border_width;
233 child_allocation.y = border_width;
234 child_allocation.width = MAX (1, allocation->width - 2 * border_width);
235 child_allocation.height = MAX (1, allocation->height - 2 * border_width);
237 if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1))
238 gtk_widget_size_allocate (paned->child1, &child_allocation);
239 else if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
240 gtk_widget_size_allocate (paned->child2, &child_allocation);
245 gtk_hpaned_expose (GtkWidget *widget,
246 GdkEventExpose *event)
249 guint16 border_width;
251 g_return_val_if_fail (widget != NULL, FALSE);
252 g_return_val_if_fail (GTK_IS_PANED (widget), FALSE);
254 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
256 paned = GTK_PANED (widget);
257 border_width = GTK_CONTAINER (paned)->border_width;
259 if (event->window == widget->window)
261 gdk_window_clear_area (widget->window,
262 event->area.x, event->area.y,
266 /* Chain up to draw children */
267 GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
269 else if (event->window == paned->handle)
271 gtk_paint_handle (widget->style,
279 GTK_ORIENTATION_VERTICAL);
287 gtk_hpaned_xor_line (GtkPaned *paned)
294 widget = GTK_WIDGET (paned);
296 gtk_widget_style_get (widget, "handle_size", &handle_size, NULL);
300 values.function = GDK_INVERT;
301 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
302 paned->xor_gc = gdk_gc_new_with_values (widget->window,
304 GDK_GC_FUNCTION | GDK_GC_SUBWINDOW);
307 gdk_gc_set_line_attributes (paned->xor_gc, 2, GDK_LINE_SOLID,
308 GDK_CAP_NOT_LAST, GDK_JOIN_BEVEL);
310 xpos = paned->child1_size
311 + GTK_CONTAINER (paned)->border_width + handle_size / 2;
313 gdk_draw_line (widget->window, paned->xor_gc,
317 widget->allocation.height - 1);
321 gtk_hpaned_button_press (GtkWidget *widget,
322 GdkEventButton *event)
324 GtkPaned *paned = GTK_PANED (widget);
327 gtk_widget_style_get (widget, "handle_size", &handle_size, NULL);
329 if (!paned->in_drag &&
330 event->window == paned->handle && event->button == 1)
332 paned->in_drag = TRUE;
333 /* We need a server grab here, not gtk_grab_add(), since
334 * we don't want to pass events on to the widget's children */
335 gdk_pointer_grab(paned->handle, FALSE,
336 GDK_POINTER_MOTION_HINT_MASK
337 | GDK_BUTTON1_MOTION_MASK
338 | GDK_BUTTON_RELEASE_MASK,
339 NULL, NULL, event->time);
340 paned->child1_size += event->x - handle_size / 2;
341 paned->child1_size = CLAMP (paned->child1_size, 0,
342 widget->allocation.width
344 - 2 * GTK_CONTAINER (paned)->border_width);
345 gtk_hpaned_xor_line (paned);
354 gtk_hpaned_button_release (GtkWidget *widget,
355 GdkEventButton *event)
357 GtkPaned *paned = GTK_PANED (widget);
358 GObject *object = G_OBJECT (widget);
360 if (paned->in_drag && (event->button == 1))
362 gtk_hpaned_xor_line (paned);
363 paned->in_drag = FALSE;
364 paned->position_set = TRUE;
365 gdk_pointer_ungrab (event->time);
366 gtk_widget_queue_resize (GTK_WIDGET (paned));
367 g_object_freeze_notify (object);
368 g_object_notify (object, "position");
369 g_object_notify (object, "position_set");
370 g_object_thaw_notify (object);
379 gtk_hpaned_motion (GtkWidget *widget,
380 GdkEventMotion *event)
382 GtkPaned *paned = GTK_PANED (widget);
386 gtk_widget_style_get (widget, "handle_size", &handle_size, NULL);
388 if (event->is_hint || event->window != widget->window)
389 gtk_widget_get_pointer(widget, &x, NULL);
395 gint size = x - GTK_CONTAINER (paned)->border_width - handle_size / 2;
397 gtk_hpaned_xor_line (paned);
398 paned->child1_size = CLAMP (size, paned->min_position, paned->max_position);
399 gtk_hpaned_xor_line (paned);