source: trunk/third/gtk/gtk/gtkhpaned.c @ 14482

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