]> Pileus Git - ~andy/gtk/blob - gtk/gtkhpaned.c
Remove "draw" virtual method and signal
[~andy/gtk] / gtk / gtkhpaned.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 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.
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  * Lesser General Public License for more details.
13  *
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.
18  */
19
20 /*
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/. 
25  */
26
27 #include "gtkhpaned.h"
28
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 void     gtk_hpaned_xor_line       (GtkPaned       *paned);
36 static gboolean gtk_hpaned_button_press   (GtkWidget      *widget,
37                                            GdkEventButton *event);
38 static gboolean gtk_hpaned_button_release (GtkWidget      *widget,
39                                            GdkEventButton *event);
40 static gboolean gtk_hpaned_motion         (GtkWidget      *widget,
41                                            GdkEventMotion *event);
42
43 GtkType
44 gtk_hpaned_get_type (void)
45 {
46   static GtkType hpaned_type = 0;
47
48   if (!hpaned_type)
49     {
50       static const GtkTypeInfo hpaned_info =
51       {
52         "GtkHPaned",
53         sizeof (GtkHPaned),
54         sizeof (GtkHPanedClass),
55         (GtkClassInitFunc) gtk_hpaned_class_init,
56         (GtkObjectInitFunc) gtk_hpaned_init,
57         /* reserved_1 */ NULL,
58         /* reserved_2 */ NULL,
59         (GtkClassInitFunc) NULL,
60       };
61
62       hpaned_type = gtk_type_unique (GTK_TYPE_PANED, &hpaned_info);
63     }
64
65   return hpaned_type;
66 }
67
68 static void
69 gtk_hpaned_class_init (GtkHPanedClass *class)
70 {
71   GtkWidgetClass *widget_class;
72
73   widget_class = (GtkWidgetClass *) class;
74
75   widget_class->size_request = gtk_hpaned_size_request;
76   widget_class->size_allocate = gtk_hpaned_size_allocate;
77   widget_class->button_press_event = gtk_hpaned_button_press;
78   widget_class->button_release_event = gtk_hpaned_button_release;
79   widget_class->motion_notify_event = gtk_hpaned_motion;
80 }
81
82 static void
83 gtk_hpaned_init (GtkHPaned *hpaned)
84 {
85   GtkPaned *paned;
86
87   g_return_if_fail (hpaned != NULL);
88   g_return_if_fail (GTK_IS_PANED (hpaned));
89
90   paned = GTK_PANED (hpaned);
91   
92   paned->cursor_type = GDK_SB_H_DOUBLE_ARROW;
93 }
94
95 GtkWidget *
96 gtk_hpaned_new (void)
97 {
98   GtkHPaned *hpaned;
99
100   hpaned = gtk_type_new (GTK_TYPE_HPANED);
101
102   return GTK_WIDGET (hpaned);
103 }
104
105 static void
106 gtk_hpaned_size_request (GtkWidget      *widget,
107                          GtkRequisition *requisition)
108 {
109   GtkPaned *paned;
110   GtkRequisition child_requisition;
111
112   g_return_if_fail (widget != NULL);
113   g_return_if_fail (GTK_IS_HPANED (widget));
114   g_return_if_fail (requisition != NULL);
115
116   paned = GTK_PANED (widget);
117   requisition->width = 0;
118   requisition->height = 0;
119
120   if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1))
121     {
122       gtk_widget_size_request (paned->child1, &child_requisition);
123
124       requisition->height = child_requisition.height;
125       requisition->width = child_requisition.width;
126     }
127
128   if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
129     {
130       gtk_widget_size_request (paned->child2, &child_requisition);
131
132       requisition->height = MAX(requisition->height, child_requisition.height);
133       requisition->width += child_requisition.width;
134     }
135
136   requisition->width += GTK_CONTAINER (paned)->border_width * 2 + paned->handle_size;
137   requisition->height += GTK_CONTAINER (paned)->border_width * 2;
138 }
139
140 static void
141 gtk_hpaned_size_allocate (GtkWidget     *widget,
142                           GtkAllocation *allocation)
143 {
144   GtkPaned *paned;
145   GtkRequisition child1_requisition;
146   GtkRequisition child2_requisition;
147   GtkAllocation child1_allocation;
148   GtkAllocation child2_allocation;
149   gint border_width;
150
151   g_return_if_fail (widget != NULL);
152   g_return_if_fail (GTK_IS_HPANED (widget));
153   g_return_if_fail (allocation != NULL);
154
155   widget->allocation = *allocation;
156   paned = GTK_PANED (widget);
157   border_width = GTK_CONTAINER (paned)->border_width;
158   
159   if (paned->child1)
160     gtk_widget_get_child_requisition (paned->child1, &child1_requisition);
161   else
162     child1_requisition.width = 0;
163
164   if (paned->child2)
165     gtk_widget_get_child_requisition (paned->child2, &child2_requisition);
166   else
167     child2_requisition.width = 0;
168
169   gtk_paned_compute_position (paned,
170                               MAX (1, (gint) widget->allocation.width
171                                       - (gint) paned->handle_size
172                                    - 2 * border_width),
173                               child1_requisition.width,
174                               child2_requisition.width);
175
176   /* Move the handle before the children so we don't get extra expose events */
177
178   paned->handle_xpos = paned->child1_size + border_width;
179   paned->handle_ypos = border_width;
180   paned->handle_width = paned->handle_size;
181   paned->handle_height = MAX (1, (gint) widget->allocation.height - 2 * border_width);
182
183   if (GTK_WIDGET_REALIZED (widget))
184     {
185       gdk_window_move_resize (widget->window,
186                               allocation->x, allocation->y,
187                               allocation->width,
188                               allocation->height);
189
190       gdk_window_move_resize (paned->handle,
191                               paned->handle_xpos,
192                               paned->handle_ypos,
193                               paned->handle_size,
194                               paned->handle_height);
195     }
196
197   child1_allocation.height = child2_allocation.height = MAX (1, (gint) allocation->height - border_width * 2);
198   child1_allocation.width = paned->child1_size;
199   child1_allocation.x = border_width;
200   child1_allocation.y = child2_allocation.y = border_width;
201   
202   child2_allocation.x = child1_allocation.x + child1_allocation.width +  paned->handle_width;
203   child2_allocation.width = MAX (1, (gint) allocation->width - child2_allocation.x - border_width);
204
205   /* Now allocate the childen, making sure, when resizing not to
206    * overlap the windows */
207   if (GTK_WIDGET_MAPPED (widget) &&
208       paned->child1 && GTK_WIDGET_VISIBLE (paned->child1) &&
209       paned->child1->allocation.width < child1_allocation.width)
210     {
211       if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
212         gtk_widget_size_allocate (paned->child2, &child2_allocation);
213       gtk_widget_size_allocate (paned->child1, &child1_allocation);
214     }
215   else
216     {
217       if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1))
218         gtk_widget_size_allocate (paned->child1, &child1_allocation);
219       if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
220         gtk_widget_size_allocate (paned->child2, &child2_allocation);
221     }
222 }
223
224 static void
225 gtk_hpaned_xor_line (GtkPaned *paned)
226 {
227   GtkWidget *widget;
228   GdkGCValues values;
229   guint16 xpos;
230
231   widget = GTK_WIDGET(paned);
232
233   if (!paned->xor_gc)
234     {
235       values.function = GDK_INVERT;
236       values.subwindow_mode = GDK_INCLUDE_INFERIORS;
237       paned->xor_gc = gdk_gc_new_with_values (widget->window,
238                                               &values,
239                                               GDK_GC_FUNCTION | GDK_GC_SUBWINDOW);
240     }
241
242   gdk_gc_set_line_attributes (paned->xor_gc, 2, GDK_LINE_SOLID,
243                               GDK_CAP_NOT_LAST, GDK_JOIN_BEVEL);
244
245   xpos = paned->child1_size
246     + GTK_CONTAINER (paned)->border_width + paned->handle_size / 2;
247
248   gdk_draw_line (widget->window, paned->xor_gc,
249                  xpos,
250                  0,
251                  xpos,
252                  widget->allocation.height - 1);
253 }
254
255 static gboolean
256 gtk_hpaned_button_press (GtkWidget      *widget,
257                          GdkEventButton *event)
258 {
259   GtkPaned *paned;
260
261   g_return_val_if_fail (widget != NULL, FALSE);
262   g_return_val_if_fail (GTK_IS_PANED (widget), FALSE);
263
264   paned = GTK_PANED (widget);
265
266   if (!paned->in_drag &&
267       event->window == paned->handle && event->button == 1)
268     {
269       paned->in_drag = TRUE;
270       /* We need a server grab here, not gtk_grab_add(), since
271        * we don't want to pass events on to the widget's children */
272       gdk_pointer_grab(paned->handle, FALSE,
273                        GDK_POINTER_MOTION_HINT_MASK
274                        | GDK_BUTTON1_MOTION_MASK
275                        | GDK_BUTTON_RELEASE_MASK,
276                        NULL, NULL, event->time);
277       paned->child1_size += event->x - paned->handle_size / 2;
278       paned->child1_size = CLAMP (paned->child1_size, 0,
279                                   widget->allocation.width
280                                   - paned->handle_size
281                                   - 2 * GTK_CONTAINER (paned)->border_width);
282       gtk_hpaned_xor_line (paned);
283
284       return TRUE;
285     }
286
287   return FALSE;
288 }
289
290 static gboolean
291 gtk_hpaned_button_release (GtkWidget      *widget,
292                            GdkEventButton *event)
293 {
294   GtkPaned *paned;
295
296   g_return_val_if_fail (widget != NULL, FALSE);
297   g_return_val_if_fail (GTK_IS_PANED (widget), FALSE);
298
299   paned = GTK_PANED (widget);
300
301   if (paned->in_drag && (event->button == 1))
302     {
303       gtk_hpaned_xor_line (paned);
304       paned->in_drag = FALSE;
305       paned->position_set = TRUE;
306       gdk_pointer_ungrab (event->time);
307       gtk_widget_queue_resize (GTK_WIDGET (paned));
308
309       return TRUE;
310     }
311
312   return FALSE;
313 }
314
315 static gboolean
316 gtk_hpaned_motion (GtkWidget      *widget,
317                    GdkEventMotion *event)
318 {
319   GtkPaned *paned;
320   gint x;
321
322   g_return_val_if_fail (widget != NULL, FALSE);
323   g_return_val_if_fail (GTK_IS_PANED (widget), FALSE);
324
325   paned = GTK_PANED (widget);
326
327   if (event->is_hint || event->window != widget->window)
328     gtk_widget_get_pointer(widget, &x, NULL);
329   else
330     x = event->x;
331
332   if (paned->in_drag)
333     {
334       gint size = x - GTK_CONTAINER (paned)->border_width - paned->handle_size / 2;
335
336       gtk_hpaned_xor_line (paned);
337       paned->child1_size = CLAMP (size, paned->min_position, paned->max_position);
338       gtk_hpaned_xor_line (paned);
339     }
340
341   return TRUE;
342 }