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

Revision 15781, 12.6 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15780, which included commits to RCS files with non-trunk default branches.
RevLine 
[14481]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
[15780]133  requisition->width += GTK_CONTAINER (paned)->border_width * 2 + _gtk_paned_get_gutter_size (paned);
[14481]134  requisition->height += GTK_CONTAINER (paned)->border_width * 2;
135}
136
137static void
138gtk_hpaned_size_allocate (GtkWidget     *widget,
139                          GtkAllocation *allocation)
140{
[15780]141  GtkPaned *paned = GTK_PANED (widget);
[14481]142  GtkRequisition child1_requisition;
143  GtkRequisition child2_requisition;
144  GtkAllocation child1_allocation;
145  GtkAllocation child2_allocation;
146
[15780]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);
[14481]150
151  widget->allocation = *allocation;
[15780]152
[14481]153  if (paned->child1)
154    gtk_widget_get_child_requisition (paned->child1, &child1_requisition);
155  else
156    child1_requisition.width = 0;
157
158  if (paned->child2)
159    gtk_widget_get_child_requisition (paned->child2, &child2_requisition);
160  else
161    child2_requisition.width = 0;
162   
163  gtk_paned_compute_position (paned,
164                              MAX (1, (gint) widget->allocation.width
165                                   - gutter_size
166                                   - 2 * border_width),
167                              child1_requisition.width,
168                              child2_requisition.width);
169 
170  child1_allocation.height = child2_allocation.height = MAX (1, (gint) allocation->height - border_width * 2);
171  child1_allocation.width = paned->child1_size;
172  child1_allocation.y = child2_allocation.y = border_width;
173  child1_allocation.x = border_width;
[15780]174     
175  if (GTK_WIDGET_REALIZED (widget))
176    gdk_window_move_resize (widget->window,
177                            allocation->x, allocation->y,
178                            allocation->width, allocation->height);
[14481]179 
[15780]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;
[14481]185
[15780]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;
[14481]198     
[15780]199      paned->handle_ypos = (gint) allocation->height - border_width - 2 * paned->handle_size;
200      paned->handle_xpos = 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.x = (child1_allocation.x +
208                                   child1_allocation.width + gutter_size / 2 - 1);
209      paned->groove_rectangle.y = 0;
210      paned->groove_rectangle.width = 2;
211      paned->groove_rectangle.height = allocation->height;
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 
[14481]231    }
[15780]232     
233  child2_allocation.x = child1_allocation.x + child1_allocation.width + gutter_size;
[14481]234  child2_allocation.width = MAX (1, (gint) allocation->width -
235                                 child2_allocation.x - border_width);
236 
237  /* Now allocate the childen, making sure, when resizing not to
238   * overlap the windows */
239  if (GTK_WIDGET_MAPPED(widget) &&
240      paned->child1 && GTK_WIDGET_VISIBLE (paned->child1) &&
241      paned->child1->allocation.width < child1_allocation.width)
242    {
243      if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
244        gtk_widget_size_allocate (paned->child2, &child2_allocation);
245      gtk_widget_size_allocate (paned->child1, &child1_allocation);     
246    }
247  else
248    {
249      if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1))
250        gtk_widget_size_allocate (paned->child1, &child1_allocation);
251      if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
252        gtk_widget_size_allocate (paned->child2, &child2_allocation);
253    }
254}
255
256static void
257gtk_hpaned_draw (GtkWidget    *widget,
258                GdkRectangle *area)
259{
[15780]260  GtkPaned *paned = GTK_PANED (widget);
[14481]261  GdkRectangle handle_area, child_area;
262  guint16 border_width;
[15780]263  gboolean handle_full_size = _gtk_paned_is_handle_full_size (paned);
[14481]264
265  g_return_if_fail (widget != NULL);
266  g_return_if_fail (GTK_IS_PANED (widget));
267
268  if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
269    {
270      gint width, height;
271     
272      border_width = GTK_CONTAINER (paned)->border_width;
273
274      gdk_window_clear_area (widget->window,
275                             area->x, area->y, area->width, area->height);
276
277      /* Redraw the handle
278       */
279      gdk_window_get_size (paned->handle, &width, &height);
280     
281      handle_area.x = paned->handle_xpos;
282      handle_area.y = paned->handle_ypos;
283      handle_area.width = width;
284      handle_area.height = height;
285
286      if (gdk_rectangle_intersect (&handle_area, area, &child_area))
287        {
288          child_area.x -= handle_area.x;
289          child_area.y -= handle_area.y;
290          gtk_paint_box (widget->style, paned->handle,
291                         GTK_WIDGET_STATE(widget),
292                         GTK_SHADOW_OUT,
[15780]293                         &child_area, widget,
294                         handle_full_size ? "hpaned" : "paned",
[14481]295                         0, 0,
296                         width, height);
297        }
298
299      /* Redraw the groove
300       */
[15780]301      if (!handle_full_size)
302        gtk_paint_vline(widget->style, widget->window, GTK_STATE_NORMAL,
303                        area, widget, "hpaned",
304                        0, widget->allocation.height - 1,
305                        border_width + paned->child1_size + _gtk_paned_get_gutter_size (paned) / 2 - 1);
306     
[14481]307      /* Redraw the children
308       */
309      if (paned->child1 &&
310          gtk_widget_intersect (paned->child1, area, &child_area))
311        gtk_widget_draw (paned->child1, &child_area);
312      if (paned->child2 &&
313          gtk_widget_intersect (paned->child2, area, &child_area))
314        gtk_widget_draw (paned->child2, &child_area);
315
316    }
317}
318
319static void
320gtk_hpaned_xor_line (GtkPaned *paned)
321{
322  GtkWidget *widget;
323  GdkGCValues values;
324  guint16 xpos;
325
326  widget = GTK_WIDGET(paned);
327
328  if (!paned->xor_gc)
329    {
330      values.function = GDK_INVERT;
331      values.subwindow_mode = GDK_INCLUDE_INFERIORS;
332      paned->xor_gc = gdk_gc_new_with_values (widget->window,
333                                              &values,
334                                              GDK_GC_FUNCTION |
335                                              GDK_GC_SUBWINDOW);
336    }
337
338  xpos = paned->child1_size
[15780]339    + GTK_CONTAINER (paned)->border_width + _gtk_paned_get_gutter_size (paned) / 2;
[14481]340
341  gdk_draw_line (widget->window, paned->xor_gc,
342                 xpos,
343                 0,
344                 xpos,
345                 widget->allocation.height - 1);
346}
347
348static gint
349gtk_hpaned_button_press (GtkWidget *widget, GdkEventButton *event)
350{
[15780]351  GtkPaned *paned = GTK_PANED (widget);
352  gint gutter_size = _gtk_paned_get_gutter_size (paned);
[14481]353
354  if (!paned->in_drag &&
355      (event->window == paned->handle) && (event->button == 1))
356    {
357      paned->in_drag = TRUE;
358      /* We need a server grab here, not gtk_grab_add(), since
359       * we don't want to pass events on to the widget's children */
360      gdk_pointer_grab (paned->handle, FALSE,
361                        GDK_POINTER_MOTION_HINT_MASK
362                        | GDK_BUTTON1_MOTION_MASK
363                        | GDK_BUTTON_RELEASE_MASK,
364                        NULL, NULL, event->time);
365      paned->child1_size += event->x - paned->handle_size / 2;
366      paned->child1_size = CLAMP (paned->child1_size, 0,
[15780]367                                  widget->allocation.width - gutter_size
[14481]368                                  - 2 * GTK_CONTAINER (paned)->border_width);
369      gtk_hpaned_xor_line (paned);
370    }
371
372  return TRUE;
373}
374
375static gint
376gtk_hpaned_button_release (GtkWidget *widget, GdkEventButton *event)
377{
378  GtkPaned *paned;
379
380  g_return_val_if_fail (widget != NULL,FALSE);
381  g_return_val_if_fail (GTK_IS_PANED (widget),FALSE);
382
383  paned = GTK_PANED (widget);
384
385  if (paned->in_drag && (event->button == 1))
386    {
387      gtk_hpaned_xor_line (paned);
388      paned->in_drag = FALSE;
389      paned->position_set = TRUE;
390      gdk_pointer_ungrab (event->time);
391      gtk_widget_queue_resize (GTK_WIDGET (paned));
392    }
393
394  return TRUE;
395}
396
397static gint
398gtk_hpaned_motion (GtkWidget *widget, GdkEventMotion *event)
399{
400  GtkPaned *paned;
401  gint x;
402
403  g_return_val_if_fail (widget != NULL, FALSE);
404  g_return_val_if_fail (GTK_IS_PANED (widget), FALSE);
405
406  paned = GTK_PANED (widget);
407
408  if (event->is_hint || event->window != widget->window)
409    gtk_widget_get_pointer(widget, &x, NULL);
410  else
411    x = event->x;
412
413  if (paned->in_drag)
414    {
[15780]415      gint size = x - GTK_CONTAINER (paned)->border_width - _gtk_paned_get_gutter_size (paned) / 2;
[14481]416     
417      gtk_hpaned_xor_line (paned);
418      paned->child1_size = CLAMP (size,
419                                  paned->min_position,
420                                  paned->max_position);
421      gtk_hpaned_xor_line (paned);
422    }
423
424  return TRUE;
425}
Note: See TracBrowser for help on using the repository browser.