]> Pileus Git - ~andy/gtk/blob - gtk/gtkpaned.c
Fixed up some warnings.
[~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       static const 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->last_allocation = -1;
117   paned->in_drag = FALSE;
118   
119   paned->handle_xpos = -1;
120   paned->handle_ypos = -1;
121 }
122
123
124 static void
125 gtk_paned_realize (GtkWidget *widget)
126 {
127   GtkPaned *paned;
128   GdkWindowAttr attributes;
129   gint attributes_mask;
130   
131   g_return_if_fail (widget != NULL);
132   g_return_if_fail (GTK_IS_PANED (widget));
133   
134   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
135   paned = GTK_PANED (widget);
136   
137   attributes.x = widget->allocation.x;
138   attributes.y = widget->allocation.y;
139   attributes.width = widget->allocation.width;
140   attributes.height = widget->allocation.height;
141   attributes.window_type = GDK_WINDOW_CHILD;
142   attributes.wclass = GDK_INPUT_OUTPUT;
143   attributes.visual = gtk_widget_get_visual (widget);
144   attributes.colormap = gtk_widget_get_colormap (widget);
145   attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
146   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
147   
148   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
149                                    &attributes, attributes_mask);
150   gdk_window_set_user_data (widget->window, paned);
151   
152   attributes.x = paned->handle_xpos;
153   attributes.y = paned->handle_ypos;
154   attributes.width = paned->handle_size;
155   attributes.height = paned->handle_size;
156   attributes.cursor = gdk_cursor_new (GDK_CROSS);
157   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
158                             GDK_BUTTON_RELEASE_MASK |
159                             GDK_POINTER_MOTION_MASK |
160                             GDK_POINTER_MOTION_HINT_MASK);
161   attributes_mask |= GDK_WA_CURSOR;
162   
163   paned->handle = gdk_window_new (widget->window,
164                                   &attributes, attributes_mask);
165   gdk_window_set_user_data (paned->handle, paned);
166   gdk_cursor_destroy (attributes.cursor);
167   
168   widget->style = gtk_style_attach (widget->style, widget->window);
169   
170   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
171   gtk_style_set_background (widget->style, paned->handle, GTK_STATE_NORMAL);
172
173   gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
174   
175   gdk_window_show (paned->handle);
176 }
177
178 static void
179 gtk_paned_map (GtkWidget *widget)
180 {
181   GtkPaned *paned;
182   
183   g_return_if_fail (widget != NULL);
184   g_return_if_fail (GTK_IS_PANED (widget));
185   
186   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
187   paned = GTK_PANED (widget);
188   
189   gdk_window_show (widget->window);
190   
191   if (paned->child1 &&
192       GTK_WIDGET_VISIBLE (paned->child1) &&
193       !GTK_WIDGET_MAPPED (paned->child1))
194     gtk_widget_map (paned->child1);
195   if (paned->child2 &&
196       GTK_WIDGET_VISIBLE (paned->child2) &&
197       !GTK_WIDGET_MAPPED (paned->child2))
198     gtk_widget_map (paned->child2);
199 }
200
201 static void
202 gtk_paned_unmap (GtkWidget *widget)
203 {
204   g_return_if_fail (widget != NULL);
205   g_return_if_fail (GTK_IS_PANED (widget));
206   
207   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
208   
209   gdk_window_hide (widget->window);
210 }
211
212 static void
213 gtk_paned_unrealize (GtkWidget *widget)
214 {
215   GtkPaned *paned;
216   
217   g_return_if_fail (widget != NULL);
218   g_return_if_fail (GTK_IS_PANED (widget));
219   
220   paned = GTK_PANED (widget);
221   
222   if (paned->xor_gc)
223     {
224       gdk_gc_destroy (paned->xor_gc);
225       paned->xor_gc = NULL;
226     }
227   
228   if (paned->handle)
229     {
230       gdk_window_set_user_data (paned->handle, NULL);
231       gdk_window_destroy (paned->handle);
232       paned->handle = 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   gtk_paned_pack1 (paned, widget, FALSE, TRUE);
292 }
293
294 void
295 gtk_paned_add2 (GtkPaned  *paned,
296                 GtkWidget *widget)
297 {
298   gtk_paned_pack2 (paned, widget, TRUE, TRUE);
299 }
300
301 void
302 gtk_paned_pack1 (GtkPaned     *paned,
303                  GtkWidget    *widget,
304                  gboolean      resize,
305                  gboolean      shrink)
306 {
307   g_return_if_fail (paned != NULL);
308   g_return_if_fail (GTK_IS_PANED (paned));
309   g_return_if_fail (widget != NULL);
310   
311   if (!paned->child1)
312     {
313       gtk_widget_set_parent (widget, GTK_WIDGET (paned));
314       
315       if (GTK_WIDGET_VISIBLE (widget->parent))
316         {
317           if (GTK_WIDGET_REALIZED (widget->parent) &&
318               !GTK_WIDGET_REALIZED (widget))
319             gtk_widget_realize (widget);
320           
321           if (GTK_WIDGET_MAPPED (widget->parent) &&
322               !GTK_WIDGET_MAPPED (widget))
323             gtk_widget_map (widget);
324         }
325       
326       paned->child1 = widget;
327       paned->child1_resize = resize;
328       paned->child1_shrink = shrink;
329       
330       if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (paned))
331         gtk_widget_queue_resize (widget);
332     }
333 }
334
335 void
336 gtk_paned_pack2 (GtkPaned  *paned,
337                  GtkWidget *widget,
338                  gboolean   resize,
339                  gboolean   shrink)
340 {
341   g_return_if_fail (paned != NULL);
342   g_return_if_fail (GTK_IS_PANED (paned));
343   g_return_if_fail (widget != NULL);
344   
345   if (!paned->child2)
346     {
347       gtk_widget_set_parent (widget, GTK_WIDGET (paned));
348       
349       if (GTK_WIDGET_VISIBLE (widget->parent))
350         {
351           if (GTK_WIDGET_REALIZED (widget->parent) &&
352               !GTK_WIDGET_REALIZED (widget))
353             gtk_widget_realize (widget);
354           
355           if (GTK_WIDGET_MAPPED (widget->parent) &&
356               !GTK_WIDGET_MAPPED (widget))
357             gtk_widget_map (widget);
358         }
359       
360       paned->child2 = widget;
361       paned->child2_resize = resize;
362       paned->child2_shrink = shrink;
363       
364       if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (paned))
365         gtk_widget_queue_resize (widget);
366     }
367 }
368
369 static void
370 gtk_paned_add (GtkContainer *container,
371                GtkWidget    *widget)
372 {
373   GtkPaned *paned;
374   
375   g_return_if_fail (container != NULL);
376   g_return_if_fail (GTK_IS_PANED (container));
377   g_return_if_fail (widget != NULL);
378   
379   paned = GTK_PANED (container);
380   
381   if (!paned->child1)
382     gtk_paned_add1 (GTK_PANED (container),widget);
383   else if (!paned->child2)
384     gtk_paned_add2 (GTK_PANED (container),widget);
385 }
386
387 static void
388 gtk_paned_remove (GtkContainer *container,
389                   GtkWidget    *widget)
390 {
391   GtkPaned *paned;
392   gboolean was_visible;
393   
394   g_return_if_fail (container != NULL);
395   g_return_if_fail (GTK_IS_PANED (container));
396   g_return_if_fail (widget != NULL);
397   
398   paned = GTK_PANED (container);
399   was_visible = GTK_WIDGET_VISIBLE (widget);
400   
401   if (paned->child1 == widget)
402     {
403       gtk_widget_unparent (widget);
404       
405       paned->child1 = NULL;
406       
407       if (was_visible && GTK_WIDGET_VISIBLE (container))
408         gtk_widget_queue_resize (GTK_WIDGET (container));
409     }
410   else if (paned->child2 == widget)
411     {
412       gtk_widget_unparent (widget);
413       
414       paned->child2 = NULL;
415       
416       if (was_visible && GTK_WIDGET_VISIBLE (container))
417         gtk_widget_queue_resize (GTK_WIDGET (container));
418     }
419 }
420
421 static void
422 gtk_paned_forall (GtkContainer *container,
423                   gboolean      include_internals,
424                   GtkCallback   callback,
425                   gpointer      callback_data)
426 {
427   GtkPaned *paned;
428   
429   g_return_if_fail (container != NULL);
430   g_return_if_fail (GTK_IS_PANED (container));
431   g_return_if_fail (callback != NULL);
432   
433   paned = GTK_PANED (container);
434   
435   if (paned->child1)
436     (* callback) (paned->child1, callback_data);
437   if (paned->child2)
438     (* callback) (paned->child2, callback_data);
439 }
440
441 void
442 gtk_paned_set_position    (GtkPaned  *paned,
443                            gint       position)
444 {
445   g_return_if_fail (paned != NULL);
446   g_return_if_fail (GTK_IS_PANED (paned));
447
448   if (position >= 0)
449     {
450       paned->child1_size = CLAMP (position,
451                                   paned->min_position,
452                                   paned->max_position);
453       paned->position_set = TRUE;
454     }
455   else
456     paned->position_set = FALSE;
457
458   gtk_widget_queue_resize (GTK_WIDGET (paned));
459 }
460
461 void
462 gtk_paned_set_handle_size (GtkPaned *paned,
463                            guint16   size)
464 {
465   gint x,y;
466   
467   g_return_if_fail (paned != NULL);
468   g_return_if_fail (GTK_IS_PANED (paned));
469
470   if (paned->handle)
471     {
472       gdk_window_get_geometry (paned->handle, &x, &y, NULL, NULL, NULL);
473       gdk_window_move_resize (paned->handle,
474                               x + paned->handle_size / 2 - size / 2,
475                               y + paned->handle_size / 2 - size / 2,
476                               size, size);
477     }
478   paned->handle_size = size;
479 }
480
481 void
482 gtk_paned_set_gutter_size (GtkPaned *paned,
483                            guint16   size)
484 {
485   g_return_if_fail (paned != NULL);
486   g_return_if_fail (GTK_IS_PANED (paned));
487
488   paned->gutter_size = size;
489   
490   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (paned)))
491     gtk_widget_queue_resize (GTK_WIDGET (paned));
492 }
493
494 void
495 gtk_paned_compute_position (GtkPaned *paned,
496                             gint      allocation,
497                             gint      child1_req,
498                             gint      child2_req)
499 {
500   g_return_if_fail (paned != NULL);
501   g_return_if_fail (GTK_IS_PANED (paned));
502
503   paned->min_position = paned->child1_shrink ? 0 : child1_req;
504
505   paned->max_position = allocation;
506   if (!paned->child2_shrink)
507     paned->max_position -= child2_req;
508
509   if (!paned->position_set)
510     {
511       if (paned->child1_resize && !paned->child2_resize)
512         paned->child1_size = allocation - child2_req;
513       else if (!paned->child1_resize && paned->child2_resize)
514         paned->child1_size = child1_req;
515       else
516         paned->child1_size = allocation * ((gdouble)child1_req / (child1_req + child2_req));
517     }
518   else
519     {
520       if (paned->last_allocation < 0)
521         paned->last_allocation = allocation;
522       
523       if (paned->child1_resize && !paned->child2_resize)
524         paned->child1_size += (allocation - paned->last_allocation);
525       else if (!(!paned->child1_resize && paned->child2_resize))
526         paned->child1_size = allocation * ((gdouble)paned->child1_size / (paned->last_allocation));
527     }
528
529   paned->child1_size = CLAMP (paned->child1_size,
530                               paned->min_position,
531                               paned->max_position);
532
533   paned->last_allocation = allocation;
534   
535 }