]> Pileus Git - ~andy/gtk/blob - gtk/gtkpaned.c
ae4da2a5e9170b95b40ec9f46509bf37bb0ed0d4
[~andy/gtk] / gtk / gtkpaned.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library 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.
8  *
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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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.
18  */
19 #include "gtkpaned.h"
20
21
22 static void gtk_paned_class_init (GtkPanedClass    *klass);
23 static void gtk_paned_init       (GtkPaned         *paned);
24 static void gtk_paned_realize    (GtkWidget *widget);
25 static void gtk_paned_map        (GtkWidget      *widget);
26 static void gtk_paned_unmap      (GtkWidget      *widget);
27 static void gtk_paned_unrealize  (GtkWidget *widget);
28 static gint gtk_paned_expose     (GtkWidget      *widget,
29                                   GdkEventExpose *event);
30 static void gtk_paned_add        (GtkContainer   *container,
31                                   GtkWidget      *widget);
32 static void gtk_paned_remove     (GtkContainer   *container,
33                                   GtkWidget      *widget);
34 static void gtk_paned_forall     (GtkContainer   *container,
35                                   gboolean        include_internals,
36                                   GtkCallback     callback,
37                                   gpointer        callback_data);
38 static GtkType gtk_paned_child_type (GtkContainer *container);
39
40
41 static GtkContainerClass *parent_class = NULL;
42
43
44 GtkType
45 gtk_paned_get_type (void)
46 {
47   static GtkType paned_type = 0;
48   
49   if (!paned_type)
50     {
51       GtkTypeInfo paned_info =
52       {
53         "GtkPaned",
54         sizeof (GtkPaned),
55         sizeof (GtkPanedClass),
56         (GtkClassInitFunc) gtk_paned_class_init,
57         (GtkObjectInitFunc) gtk_paned_init,
58         /* reserved_1 */ NULL,
59         /* reserved_2 */ NULL,
60         (GtkClassInitFunc) NULL,
61       };
62       
63       paned_type = gtk_type_unique (GTK_TYPE_CONTAINER, &paned_info);
64     }
65   
66   return paned_type;
67 }
68
69 static void
70 gtk_paned_class_init (GtkPanedClass *class)
71 {
72   GtkObjectClass *object_class;
73   GtkWidgetClass *widget_class;
74   GtkContainerClass *container_class;
75   
76   object_class = (GtkObjectClass*) class;
77   widget_class = (GtkWidgetClass*) class;
78   container_class = (GtkContainerClass*) class;
79   
80   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
81   
82   widget_class->realize = gtk_paned_realize;
83   widget_class->map = gtk_paned_map;
84   widget_class->unmap = gtk_paned_unmap;
85   widget_class->unrealize = gtk_paned_unrealize;
86   widget_class->expose_event = gtk_paned_expose;
87   
88   container_class->add = gtk_paned_add;
89   container_class->remove = gtk_paned_remove;
90   container_class->forall = gtk_paned_forall;
91   container_class->child_type = gtk_paned_child_type;
92 }
93
94 static GtkType
95 gtk_paned_child_type (GtkContainer *container)
96 {
97   if (!GTK_PANED (container)->child1 || !GTK_PANED (container)->child2)
98     return GTK_TYPE_WIDGET;
99   else
100     return GTK_TYPE_NONE;
101 }
102
103 static void
104 gtk_paned_init (GtkPaned *paned)
105 {
106   GTK_WIDGET_UNSET_FLAGS (paned, GTK_NO_WINDOW);
107   
108   paned->child1 = NULL;
109   paned->child2 = NULL;
110   paned->handle = NULL;
111   paned->xor_gc = NULL;
112   
113   paned->handle_size = 10;
114   paned->gutter_size = 6;
115   paned->position_set = FALSE;
116   paned->in_drag = FALSE;
117   
118   paned->handle_xpos = -1;
119   paned->handle_ypos = -1;
120 }
121
122
123 static void
124 gtk_paned_realize (GtkWidget *widget)
125 {
126   GtkPaned *paned;
127   GdkWindowAttr attributes;
128   gint attributes_mask;
129   
130   g_return_if_fail (widget != NULL);
131   g_return_if_fail (GTK_IS_PANED (widget));
132   
133   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
134   paned = GTK_PANED (widget);
135   
136   attributes.x = widget->allocation.x;
137   attributes.y = widget->allocation.y;
138   attributes.width = widget->allocation.width;
139   attributes.height = widget->allocation.height;
140   attributes.window_type = GDK_WINDOW_CHILD;
141   attributes.wclass = GDK_INPUT_OUTPUT;
142   attributes.visual = gtk_widget_get_visual (widget);
143   attributes.colormap = gtk_widget_get_colormap (widget);
144   attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
145   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
146   
147   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
148                                    &attributes, attributes_mask);
149   gdk_window_set_user_data (widget->window, paned);
150   
151   attributes.x = paned->handle_xpos;
152   attributes.y = paned->handle_ypos;
153   attributes.width = paned->handle_size;
154   attributes.height = paned->handle_size;
155   attributes.cursor = paned->cursor = gdk_cursor_new (GDK_CROSS);
156   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
157                             GDK_BUTTON_RELEASE_MASK |
158                             GDK_POINTER_MOTION_MASK |
159                             GDK_POINTER_MOTION_HINT_MASK);
160   attributes_mask |= GDK_WA_CURSOR;
161   
162   paned->handle = gdk_window_new (widget->window,
163                                   &attributes, attributes_mask);
164   gdk_window_set_user_data (paned->handle, paned);
165   
166   widget->style = gtk_style_attach (widget->style, widget->window);
167   
168   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
169   gtk_style_set_background (widget->style, paned->handle, GTK_STATE_NORMAL);
170
171   gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
172   
173   gdk_window_show (paned->handle);
174 }
175
176 static void
177 gtk_paned_map (GtkWidget *widget)
178 {
179   GtkPaned *paned;
180   
181   g_return_if_fail (widget != NULL);
182   g_return_if_fail (GTK_IS_PANED (widget));
183   
184   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
185   paned = GTK_PANED (widget);
186   
187   gdk_window_show (widget->window);
188   
189   if (paned->child1 &&
190       GTK_WIDGET_VISIBLE (paned->child1) &&
191       !GTK_WIDGET_MAPPED (paned->child1))
192     gtk_widget_map (paned->child1);
193   if (paned->child2 &&
194       GTK_WIDGET_VISIBLE (paned->child2) &&
195       !GTK_WIDGET_MAPPED (paned->child2))
196     gtk_widget_map (paned->child2);
197 }
198
199 static void
200 gtk_paned_unmap (GtkWidget *widget)
201 {
202   g_return_if_fail (widget != NULL);
203   g_return_if_fail (GTK_IS_PANED (widget));
204   
205   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
206   
207   gdk_window_hide (widget->window);
208 }
209
210 static void
211 gtk_paned_unrealize (GtkWidget *widget)
212 {
213   GtkPaned *paned;
214   
215   g_return_if_fail (widget != NULL);
216   g_return_if_fail (GTK_IS_PANED (widget));
217   
218   paned = GTK_PANED (widget);
219   
220   if (paned->xor_gc)
221     {
222       gdk_gc_destroy (paned->xor_gc);
223       paned->xor_gc = NULL;
224     }
225   
226   if (paned->handle)
227     {
228       gdk_window_set_user_data (paned->handle, NULL);
229       gdk_window_destroy (paned->handle);
230       paned->handle = NULL;
231       gdk_cursor_destroy (paned->cursor);
232       paned->cursor = NULL;
233     }
234   
235   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
236     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
237 }
238
239 static gint
240 gtk_paned_expose (GtkWidget      *widget,
241                   GdkEventExpose *event)
242 {
243   GtkPaned *paned;
244   GdkEventExpose child_event;
245   
246   g_return_val_if_fail (widget != NULL, FALSE);
247   g_return_val_if_fail (GTK_IS_PANED (widget), FALSE);
248   g_return_val_if_fail (event != NULL, FALSE);
249   
250   if (GTK_WIDGET_DRAWABLE (widget))
251     {
252       paned = GTK_PANED (widget);
253       
254       /* An expose event for the handle */
255       if (event->window == paned->handle)
256         {
257            gtk_paint_box (widget->style, paned->handle,
258                           GTK_WIDGET_STATE(widget),
259                           GTK_SHADOW_OUT, 
260                           &event->area, widget, "paned",
261                           0, 0,
262                           paned->handle_size, paned->handle_size);
263         }
264       else
265         {
266           child_event = *event;
267           if (paned->child1 &&
268               GTK_WIDGET_NO_WINDOW (paned->child1) &&
269               gtk_widget_intersect (paned->child1, &event->area, &child_event.area))
270             gtk_widget_event (paned->child1, (GdkEvent*) &child_event);
271           
272           if (paned->child2 &&
273               GTK_WIDGET_NO_WINDOW (paned->child2) &&
274               gtk_widget_intersect (paned->child2, &event->area, &child_event.area))
275             gtk_widget_event (paned->child2, (GdkEvent*) &child_event);
276           
277           /* redraw the groove if necessary */
278           if (gdk_rectangle_intersect (&paned->groove_rectangle, 
279                                        &event->area, 
280                                        &child_event.area))
281             gtk_widget_draw (widget, &child_event.area);
282         }
283     }
284   return FALSE;
285 }
286
287 void
288 gtk_paned_add1 (GtkPaned     *paned,
289                 GtkWidget    *widget)
290 {
291   g_return_if_fail (widget != NULL);
292   
293   if (!paned->child1)
294     {
295       gtk_widget_set_parent (widget, GTK_WIDGET (paned));
296       
297       if (GTK_WIDGET_VISIBLE (widget->parent))
298         {
299           if (GTK_WIDGET_REALIZED (widget->parent) &&
300               !GTK_WIDGET_REALIZED (widget))
301             gtk_widget_realize (widget);
302           
303           if (GTK_WIDGET_MAPPED (widget->parent) &&
304               !GTK_WIDGET_MAPPED (widget))
305             gtk_widget_map (widget);
306         }
307       
308       paned->child1 = widget;
309       
310       if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (paned))
311         gtk_widget_queue_resize (widget);
312     }
313 }
314
315 void
316 gtk_paned_add2 (GtkPaned  *paned,
317                 GtkWidget *widget)
318 {
319   g_return_if_fail (widget != NULL);
320   
321   if (!paned->child2)
322     {
323       gtk_widget_set_parent (widget, GTK_WIDGET (paned));
324       
325       if (GTK_WIDGET_VISIBLE (widget->parent))
326         {
327           if (GTK_WIDGET_REALIZED (widget->parent) &&
328               !GTK_WIDGET_REALIZED (widget))
329             gtk_widget_realize (widget);
330           
331           if (GTK_WIDGET_MAPPED (widget->parent) &&
332               !GTK_WIDGET_MAPPED (widget))
333             gtk_widget_map (widget);
334         }
335       
336       paned->child2 = widget;
337       
338       if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (paned))
339         gtk_widget_queue_resize (widget);
340     }
341 }
342
343 static void
344 gtk_paned_add (GtkContainer *container,
345                GtkWidget    *widget)
346 {
347   GtkPaned *paned;
348   
349   g_return_if_fail (container != NULL);
350   g_return_if_fail (GTK_IS_PANED (container));
351   g_return_if_fail (widget != NULL);
352   
353   paned = GTK_PANED (container);
354   
355   if (!paned->child1)
356     gtk_paned_add1 (GTK_PANED (container),widget);
357   else if (!paned->child2)
358     gtk_paned_add2 (GTK_PANED (container),widget);
359 }
360
361 static void
362 gtk_paned_remove (GtkContainer *container,
363                   GtkWidget    *widget)
364 {
365   GtkPaned *paned;
366   gboolean was_visible;
367   
368   g_return_if_fail (container != NULL);
369   g_return_if_fail (GTK_IS_PANED (container));
370   g_return_if_fail (widget != NULL);
371   
372   paned = GTK_PANED (container);
373   was_visible = GTK_WIDGET_VISIBLE (widget);
374   
375   if (paned->child1 == widget)
376     {
377       gtk_widget_unparent (widget);
378       
379       paned->child1 = NULL;
380       
381       if (was_visible && GTK_WIDGET_VISIBLE (container))
382         gtk_widget_queue_resize (GTK_WIDGET (container));
383     }
384   else if (paned->child2 == widget)
385     {
386       gtk_widget_unparent (widget);
387       
388       paned->child2 = NULL;
389       
390       if (was_visible && GTK_WIDGET_VISIBLE (container))
391         gtk_widget_queue_resize (GTK_WIDGET (container));
392     }
393 }
394
395 static void
396 gtk_paned_forall (GtkContainer *container,
397                   gboolean      include_internals,
398                   GtkCallback   callback,
399                   gpointer      callback_data)
400 {
401   GtkPaned *paned;
402   
403   g_return_if_fail (container != NULL);
404   g_return_if_fail (GTK_IS_PANED (container));
405   g_return_if_fail (callback != NULL);
406   
407   paned = GTK_PANED (container);
408   
409   if (paned->child1)
410     (* callback) (paned->child1, callback_data);
411   if (paned->child2)
412     (* callback) (paned->child2, callback_data);
413 }
414
415 void
416 gtk_paned_handle_size (GtkPaned *paned,
417                        guint16   size)
418 {
419   gint x,y;
420   
421   g_return_if_fail (paned != NULL);
422   g_return_if_fail (GTK_IS_PANED (paned));
423
424   if (paned->handle)
425     {
426       gdk_window_get_geometry (paned->handle, &x, &y, NULL, NULL, NULL);
427       gdk_window_move_resize (paned->handle,
428                               x + paned->handle_size / 2 - size / 2,
429                               y + paned->handle_size / 2 - size / 2,
430                               size, size);
431     }
432   paned->handle_size = size;
433 }
434
435 void
436 gtk_paned_gutter_size (GtkPaned *paned,
437                        guint16   size)
438 {
439   g_return_if_fail (paned != NULL);
440   g_return_if_fail (GTK_IS_PANED (paned));
441
442   paned->gutter_size = size;
443   
444   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (paned)))
445     gtk_widget_queue_resize (GTK_WIDGET (paned));
446 }