source: trunk/third/gtk/gtk/gtkvpaned.c @ 17071

Revision 17071, 12.5 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17070, which included commits to RCS files with non-trunk default branches.
Line 
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
20/*
21 * Modified by the GTK+ Team and others 1997-1999.  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 "gtkvpaned.h"
28#include "gtkmain.h"
29#include "gtksignal.h"
30
31static void gtk_vpaned_class_init       (GtkVPanedClass *klass);
32static void gtk_vpaned_init             (GtkVPaned      *vpaned);
33static void gtk_vpaned_size_request     (GtkWidget      *widget,
34                                         GtkRequisition *requisition);
35static void gtk_vpaned_size_allocate    (GtkWidget          *widget,
36                                         GtkAllocation      *allocation);
37static void gtk_vpaned_draw             (GtkWidget    *widget,
38                                         GdkRectangle *area);
39static void gtk_vpaned_xor_line         (GtkPaned *paned);
40static gint gtk_vpaned_button_press     (GtkWidget *widget,
41                                         GdkEventButton *event);
42static gint gtk_vpaned_button_release   (GtkWidget *widget,
43                                         GdkEventButton *event);
44static gint gtk_vpaned_motion           (GtkWidget *widget,
45                                         GdkEventMotion *event);
46
47guint
48gtk_vpaned_get_type (void)
49{
50  static guint vpaned_type = 0;
51
52  if (!vpaned_type)
53    {
54      static const GtkTypeInfo vpaned_info =
55      {
56        "GtkVPaned",
57        sizeof (GtkVPaned),
58        sizeof (GtkVPanedClass),
59        (GtkClassInitFunc) gtk_vpaned_class_init,
60        (GtkObjectInitFunc) gtk_vpaned_init,
61        /* reserved_1 */ NULL,
62        /* reserved_2 */ NULL,
63        (GtkClassInitFunc) NULL,
64      };
65
66      vpaned_type = gtk_type_unique (gtk_paned_get_type (), &vpaned_info);
67    }
68
69  return vpaned_type;
70}
71
72static void
73gtk_vpaned_class_init (GtkVPanedClass *class)
74{
75  GtkWidgetClass *widget_class;
76
77  widget_class = (GtkWidgetClass*) class;
78
79  widget_class->size_request = gtk_vpaned_size_request;
80  widget_class->size_allocate = gtk_vpaned_size_allocate;
81  widget_class->draw = gtk_vpaned_draw;
82  widget_class->button_press_event = gtk_vpaned_button_press;
83  widget_class->button_release_event = gtk_vpaned_button_release;
84  widget_class->motion_notify_event = gtk_vpaned_motion;
85}
86
87static void
88gtk_vpaned_init (GtkVPaned *vpaned)
89{
90}
91
92GtkWidget*
93gtk_vpaned_new (void)
94{
95  GtkVPaned *vpaned;
96
97  vpaned = gtk_type_new (gtk_vpaned_get_type ());
98
99  return GTK_WIDGET (vpaned);
100}
101
102static void
103gtk_vpaned_size_request (GtkWidget      *widget,
104                         GtkRequisition *requisition)
105{
106  GtkPaned *paned;
107  GtkRequisition child_requisition;
108
109  g_return_if_fail (widget != NULL);
110  g_return_if_fail (GTK_IS_VPANED (widget));
111  g_return_if_fail (requisition != NULL);
112
113  paned = GTK_PANED (widget);
114  requisition->width = 0;
115  requisition->height = 0;
116
117  if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1))
118    {
119      gtk_widget_size_request (paned->child1, &child_requisition);
120
121      requisition->height = child_requisition.height;
122      requisition->width = child_requisition.width;
123    }
124
125  if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
126    {
127      gtk_widget_size_request (paned->child2, &child_requisition);
128
129      requisition->width = MAX (requisition->width, child_requisition.width);
130      requisition->height += child_requisition.height;
131    }
132
133  requisition->height += GTK_CONTAINER (paned)->border_width * 2 + _gtk_paned_get_gutter_size (paned);
134  requisition->width += GTK_CONTAINER (paned)->border_width * 2;
135}
136
137static void
138gtk_vpaned_size_allocate (GtkWidget     *widget,
139                          GtkAllocation *allocation)
140{
141  GtkPaned *paned = GTK_PANED (widget);
142  GtkRequisition child1_requisition;
143  GtkRequisition child2_requisition;
144  GtkAllocation child1_allocation;
145  GtkAllocation child2_allocation;
146
147  gint border_width = GTK_CONTAINER (widget)->border_width;
148  gint gutter_size = _gtk_paned_get_gutter_size (paned);
149  gboolean handle_full_size = _gtk_paned_is_handle_full_size (paned);
150
151  widget->allocation = *allocation;
152
153  if (paned->child1)
154    gtk_widget_get_child_requisition (paned->child1, &child1_requisition);
155  else
156    child1_requisition.height = 0;
157
158  if (paned->child2)
159    gtk_widget_get_child_requisition (paned->child2, &child2_requisition);
160  else
161    child2_requisition.height = 0;
162   
163  gtk_paned_compute_position (paned,
164                              MAX (1, (gint) widget->allocation.height
165                                   - gutter_size
166                                   - 2 * border_width),
167                              child1_requisition.height,
168                              child2_requisition.height);
169
170  child1_allocation.width = child2_allocation.width = MAX (1, (gint) allocation->width - border_width * 2);
171  child1_allocation.height = paned->child1_size;
172  child1_allocation.x = child2_allocation.x = border_width;
173  child1_allocation.y = border_width;
174     
175  if (GTK_WIDGET_REALIZED (widget))
176    gdk_window_move_resize (widget->window,
177                            allocation->x, allocation->y,
178                            allocation->width, allocation->height);
179 
180  /* Move the handle before the children so we don't get extra expose events
181   */
182  if (handle_full_size)
183    {
184      GdkRectangle rect;
185
186      _gtk_paned_get_handle_rect (paned, &rect);
187
188      paned->handle_xpos = rect.x;
189      paned->handle_ypos = rect.y;
190
191      if (GTK_WIDGET_REALIZED (widget))
192        gdk_window_move_resize (paned->handle,
193                                rect.x, rect.y, rect.width, rect.height);
194    }
195  else
196    {
197      GdkRectangle old_groove_rectangle;
198     
199      paned->handle_xpos = (gint) allocation->width - border_width - 2 * paned->handle_size;
200      paned->handle_ypos = paned->child1_size + border_width + gutter_size / 2 - paned->handle_size / 2;
201     
202      if (GTK_WIDGET_REALIZED (widget))
203        gdk_window_move (paned->handle, paned->handle_xpos, paned->handle_ypos);
204     
205      old_groove_rectangle = paned->groove_rectangle;
206     
207      paned->groove_rectangle.y = (child1_allocation.y +
208                                   child1_allocation.height + gutter_size / 2 - 1);
209      paned->groove_rectangle.x = 0;
210      paned->groove_rectangle.height = 2;
211      paned->groove_rectangle.width = allocation->width;
212     
213      if (GTK_WIDGET_DRAWABLE (widget) &&
214          ((paned->groove_rectangle.x != old_groove_rectangle.x) ||
215           (paned->groove_rectangle.y != old_groove_rectangle.y) ||
216           (paned->groove_rectangle.width != old_groove_rectangle.width) ||
217           (paned->groove_rectangle.height != old_groove_rectangle.height)))
218        {
219          gtk_widget_queue_clear_area (widget,
220                                       old_groove_rectangle.x,
221                                       old_groove_rectangle.y,
222                                       old_groove_rectangle.width,
223                                       old_groove_rectangle.height);
224          gtk_widget_queue_draw_area (widget,
225                                      paned->groove_rectangle.x,
226                                      paned->groove_rectangle.y,
227                                      paned->groove_rectangle.width,
228                                      paned->groove_rectangle.height);
229        }
230    }
231 
232  child2_allocation.y = child1_allocation.y + child1_allocation.height + gutter_size;
233  child2_allocation.height = MAX (1, (gint) allocation->height -
234                                  child2_allocation.y - border_width);
235 
236  /* Now allocate the childen, making sure, when resizing not to
237   * overlap the windows */
238  if (GTK_WIDGET_MAPPED(widget) &&
239      paned->child1 && GTK_WIDGET_VISIBLE (paned->child1) &&
240      paned->child1->allocation.height < child1_allocation.height)
241    {
242      if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
243        gtk_widget_size_allocate (paned->child2, &child2_allocation);
244      gtk_widget_size_allocate (paned->child1, &child1_allocation);     
245    }
246  else
247    {
248      if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1))
249        gtk_widget_size_allocate (paned->child1, &child1_allocation);
250      if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
251        gtk_widget_size_allocate (paned->child2, &child2_allocation);
252    }
253}
254
255static void
256gtk_vpaned_draw (GtkWidget    *widget,
257                 GdkRectangle *area)
258{
259  GtkPaned *paned = GTK_PANED (widget);
260  GdkRectangle handle_area, child_area;
261  guint16 border_width;
262  gboolean handle_full_size = _gtk_paned_is_handle_full_size (paned);
263
264  if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
265    {
266      gint width, height;
267     
268      border_width = GTK_CONTAINER (paned)->border_width;
269
270      gdk_window_clear_area (widget->window,
271                             area->x, area->y, area->width, area->height);
272
273      /* Redraw the handle
274       */
275      gdk_window_get_size (paned->handle, &width, &height);
276     
277      handle_area.x = paned->handle_xpos;
278      handle_area.y = paned->handle_ypos;
279      handle_area.width = width;
280      handle_area.height = height;
281
282      if (gdk_rectangle_intersect (&handle_area, area, &child_area))
283        {
284          child_area.x -= handle_area.x;
285          child_area.y -= handle_area.y;
286          gtk_paint_box (widget->style, paned->handle,
287                         GTK_WIDGET_STATE(widget),
288                         GTK_SHADOW_OUT,
289                         &child_area, widget,
290                         handle_full_size ? "vpaned" : "paned",
291                         0, 0,
292                         width, height);
293        }
294
295      /* Redraw the groove
296       */
297      if (!handle_full_size)
298        gtk_paint_hline(widget->style, widget->window, GTK_STATE_NORMAL,
299                        area, widget, "vpaned",
300                        0, widget->allocation.width - 1,
301                        border_width + paned->child1_size + _gtk_paned_get_gutter_size (paned) / 2 - 1);
302
303      /* Redraw the children
304       */
305      if (paned->child1 &&
306          gtk_widget_intersect (paned->child1, area, &child_area))
307        gtk_widget_draw (paned->child1, &child_area);
308      if (paned->child2 &&
309          gtk_widget_intersect (paned->child2, area, &child_area))
310        gtk_widget_draw (paned->child2, &child_area);
311
312    }
313}
314
315static void
316gtk_vpaned_xor_line (GtkPaned *paned)
317{
318  GtkWidget *widget;
319  GdkGCValues values;
320  guint16 ypos;
321
322  widget = GTK_WIDGET(paned);
323
324  if (!paned->xor_gc)
325    {
326      values.function = GDK_INVERT;
327      values.subwindow_mode = GDK_INCLUDE_INFERIORS;
328      paned->xor_gc = gdk_gc_new_with_values (widget->window,
329                                              &values,
330                                              GDK_GC_FUNCTION |
331                                              GDK_GC_SUBWINDOW);
332    }
333
334  ypos = paned->child1_size
335    + GTK_CONTAINER (paned)->border_width + _gtk_paned_get_gutter_size (paned) / 2;
336
337  gdk_draw_line (widget->window, paned->xor_gc,
338                 0,
339                 ypos,
340                 widget->allocation.width - 1,
341                 ypos);
342}
343
344static gint
345gtk_vpaned_button_press (GtkWidget *widget, GdkEventButton *event)
346{
347  GtkPaned *paned = GTK_PANED (widget);
348  gint gutter_size = _gtk_paned_get_gutter_size (paned);
349
350  if (!paned->in_drag &&
351      (event->window == paned->handle) && (event->button == 1))
352    {
353      paned->in_drag = TRUE;
354      /* We need a server grab here, not gtk_grab_add(), since
355       * we don't want to pass events on to the widget's children */
356      gdk_pointer_grab (paned->handle, FALSE,
357                        GDK_POINTER_MOTION_HINT_MASK
358                        | GDK_BUTTON1_MOTION_MASK
359                        | GDK_BUTTON_RELEASE_MASK,
360                        NULL, NULL, event->time);
361      paned->child1_size += event->y - paned->handle_size / 2;
362      paned->child1_size = CLAMP (paned->child1_size, 0,
363                                  widget->allocation.height - gutter_size
364                                  - 2 * GTK_CONTAINER (paned)->border_width);
365      gtk_vpaned_xor_line (paned);
366    }
367
368  return TRUE;
369}
370
371static gint
372gtk_vpaned_button_release (GtkWidget *widget, GdkEventButton *event)
373{
374  GtkPaned *paned;
375
376  g_return_val_if_fail (widget != NULL, FALSE);
377  g_return_val_if_fail (GTK_IS_PANED (widget), FALSE);
378
379  paned = GTK_PANED (widget);
380
381  if (paned->in_drag && (event->button == 1))
382    {
383      gtk_vpaned_xor_line (paned);
384      paned->in_drag = FALSE;
385      paned->position_set = TRUE;
386      gdk_pointer_ungrab (event->time);
387      gtk_widget_queue_resize (GTK_WIDGET (paned));
388    }
389
390  return TRUE;
391}
392
393static gint
394gtk_vpaned_motion (GtkWidget *widget, GdkEventMotion *event)
395{
396  GtkPaned *paned;
397  gint y;
398
399  g_return_val_if_fail (widget != NULL, FALSE);
400  g_return_val_if_fail (GTK_IS_PANED (widget), FALSE);
401
402  if (event->is_hint || event->window != widget->window)
403      gtk_widget_get_pointer(widget, NULL, &y);
404  else
405      y = event->y;
406
407  paned = GTK_PANED (widget);
408
409  if (paned->in_drag)
410    {
411      gint size = y - GTK_CONTAINER (paned)->border_width - _gtk_paned_get_gutter_size (paned)/2;
412     
413      gtk_vpaned_xor_line (paned);
414      paned->child1_size = CLAMP (size,
415                                  paned->min_position,
416                                  paned->max_position);
417      gtk_vpaned_xor_line (paned);
418    }
419
420  return TRUE;
421}
Note: See TracBrowser for help on using the repository browser.