1 /* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */
2
3 /*
4 * GImageView
5 * Copyright (C) 2001 Takuro Ashie
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * $Id: gimv_vpaned.c,v 1.3 2004/03/07 11:53:31 makeinu Exp $
22 */
23
24 /*
25 * These codes are taken from gThumb.
26 * gThumb code Copyright (C) 2001 The Free Software Foundation, Inc.
27 * gThumb author: Paolo Bacchilega
28 */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #ifndef USE_NORMAL_PANED
35
36 #include "gimv_vpaned.h"
37 #include <gtk/gtkmain.h>
38 #include <gtk/gtksignal.h>
39
40 static void gimv_vpaned_class_init (GimvVPanedClass *klass);
41 static void gimv_vpaned_init (GimvVPaned *vpaned);
42 static void gimv_vpaned_size_request (GtkWidget *widget,
43 GtkRequisition *requisition);
44 static void gimv_vpaned_size_allocate (GtkWidget *widget,
45 GtkAllocation *allocation);
46 static void gimv_vpaned_draw (GtkWidget *widget,
47 GdkRectangle *area);
48 static void gimv_vpaned_xor_line (GimvPaned *paned);
49 static gint gimv_vpaned_button_press (GtkWidget *widget,
50 GdkEventButton *event);
51 static gint gimv_vpaned_button_release (GtkWidget *widget,
52 GdkEventButton *event);
53
54 GtkType
gimv_vpaned_get_type(void)55 gimv_vpaned_get_type (void)
56 {
57 static GtkType vpaned_type = 0;
58
59 if (!vpaned_type) {
60 static const GtkTypeInfo vpaned_info = {
61 "GimvVPaned",
62 sizeof (GimvVPaned),
63 sizeof (GimvVPanedClass),
64 (GtkClassInitFunc) gimv_vpaned_class_init,
65 (GtkObjectInitFunc) gimv_vpaned_init,
66 /* reserved_1 */ NULL,
67 /* reserved_2 */ NULL,
68 (GtkClassInitFunc) NULL,
69 };
70 vpaned_type = gtk_type_unique (gimv_paned_get_type (),
71 &vpaned_info);
72 }
73 return vpaned_type;
74 }
75
76
77 static void
gimv_vpaned_class_init(GimvVPanedClass * class)78 gimv_vpaned_class_init (GimvVPanedClass *class)
79 {
80 GtkWidgetClass *widget_class;
81 GimvPanedClass *paned_class;
82
83 widget_class = (GtkWidgetClass*) class;
84 paned_class = (GimvPanedClass*) class;
85
86 widget_class->size_request = gimv_vpaned_size_request;
87 widget_class->size_allocate = gimv_vpaned_size_allocate;
88 #ifndef USE_GTK2
89 widget_class->draw = gimv_vpaned_draw;
90 #endif
91 widget_class->button_press_event = gimv_vpaned_button_press;
92 widget_class->button_release_event = gimv_vpaned_button_release;
93
94 paned_class->xor_line = gimv_vpaned_xor_line;
95 }
96
97
98 static void
gimv_vpaned_init(GimvVPaned * vpaned)99 gimv_vpaned_init (GimvVPaned *vpaned)
100 {
101 GIMV_PANED (vpaned)->horizontal = FALSE;
102 }
103
104
105 GtkWidget*
gimv_vpaned_new(void)106 gimv_vpaned_new (void)
107 {
108 GimvVPaned *vpaned;
109
110 vpaned = gtk_type_new (gimv_vpaned_get_type ());
111
112 return GTK_WIDGET (vpaned);
113 }
114
115
116 static void
gimv_vpaned_size_request(GtkWidget * widget,GtkRequisition * requisition)117 gimv_vpaned_size_request (GtkWidget *widget,
118 GtkRequisition *requisition)
119 {
120 GimvPaned *paned;
121 GtkRequisition child_requisition;
122
123 g_return_if_fail (widget != NULL);
124 g_return_if_fail (GIMV_IS_VPANED (widget));
125 g_return_if_fail (requisition != NULL);
126
127 paned = GIMV_PANED (widget);
128 requisition->width = 0;
129 requisition->height = 0;
130
131 if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1)) {
132 gtk_widget_size_request (paned->child1, &child_requisition);
133
134 requisition->height = child_requisition.height;
135 requisition->width = child_requisition.width;
136 }
137
138 if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2)) {
139 gtk_widget_size_request (paned->child2, &child_requisition);
140
141 requisition->width = MAX (requisition->width,
142 child_requisition.width);
143 requisition->height += child_requisition.height;
144 }
145
146 requisition->height += (GTK_CONTAINER (paned)->border_width * 2
147 + paned->gutter_size);
148 requisition->width += GTK_CONTAINER (paned)->border_width * 2;
149 }
150
151
152 static void
gimv_vpaned_size_allocate(GtkWidget * widget,GtkAllocation * allocation)153 gimv_vpaned_size_allocate (GtkWidget *widget,
154 GtkAllocation *allocation)
155 {
156 GimvPaned *paned;
157 GtkRequisition child1_requisition;
158 GtkRequisition child2_requisition;
159 GtkAllocation child1_allocation;
160 GtkAllocation child2_allocation;
161 gint border_width, gutter_size;
162
163 g_return_if_fail (widget != NULL);
164 g_return_if_fail (GIMV_IS_VPANED (widget));
165 g_return_if_fail (allocation != NULL);
166
167 widget->allocation = *allocation;
168 paned = GIMV_PANED (widget);
169 border_width = GTK_CONTAINER (widget)->border_width;
170 gutter_size = paned->gutter_size;
171
172 if (paned->child1)
173 gtk_widget_get_child_requisition (paned->child1,
174 &child1_requisition);
175 else
176 child1_requisition.height = 0;
177
178 if (paned->child2)
179 gtk_widget_get_child_requisition (paned->child2,
180 &child2_requisition);
181 else
182 child2_requisition.height = 0;
183
184 gimv_paned_compute_position (paned,
185 MAX (1, (gint) widget->allocation.height
186 - gutter_size
187 - 2 * border_width),
188 child1_requisition.height,
189 child2_requisition.height);
190
191 if (paned->child_hidden != 0) {
192 gutter_size = 0;
193 if ((paned->child_hidden == 1) && paned->child1) {
194 /* hide child1 and show child2 if it exists. */
195 gtk_widget_hide (paned->child1);
196 if (paned->child2 && !GTK_WIDGET_VISIBLE (paned->child2))
197 gtk_widget_show (paned->child2);
198 }
199 if ((paned->child_hidden == 2) && paned->child2) {
200 /* hide child2 and show child1 if it exists. */
201 gtk_widget_hide (paned->child2);
202 if (paned->child1 && !GTK_WIDGET_VISIBLE (paned->child1))
203 gtk_widget_show (paned->child1);
204 }
205 } else {
206 /* Show both children. */
207 if (paned->child1 && !GTK_WIDGET_VISIBLE (paned->child1))
208 gtk_widget_show (paned->child1);
209 if (paned->child2 && !GTK_WIDGET_VISIBLE (paned->child2))
210 gtk_widget_show (paned->child2);
211 }
212
213 /* Move the handle before the children so we don't get extra expose
214 * events */
215
216 paned->handle_xpos = border_width;
217 paned->handle_ypos = paned->child1_size + border_width;
218
219 if (GTK_WIDGET_REALIZED (widget)) {
220 gdk_window_move_resize (widget->window,
221 allocation->x, allocation->y,
222 allocation->width, allocation->height);
223
224 if (paned->child_hidden == 0) {
225 gdk_window_move_resize (paned->handle,
226 paned->handle_xpos,
227 paned->handle_ypos,
228 allocation->width,
229 paned->gutter_size);
230 gdk_window_show (paned->handle);
231 } else
232 gdk_window_hide (paned->handle);
233 }
234
235 child1_allocation.width = child2_allocation.width = MAX (1, (gint) allocation->width - border_width * 2);
236 child1_allocation.height = paned->child1_size;
237 child1_allocation.x = child2_allocation.x = border_width;
238 child1_allocation.y = border_width;
239
240 child2_allocation.y = (child1_allocation.y + child1_allocation.height + gutter_size);
241 child2_allocation.height = MAX (1, (gint) allocation->height -
242 child2_allocation.y - border_width);
243
244 /* Now allocate the childen, making sure, when resizing not to
245 * overlap the windows */
246 if (GTK_WIDGET_MAPPED (widget) &&
247 paned->child1 && GTK_WIDGET_VISIBLE (paned->child1) &&
248 paned->child1->allocation.height < child1_allocation.height)
249 {
250 if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
251 gtk_widget_size_allocate (paned->child2,
252 &child2_allocation);
253 gtk_widget_size_allocate (paned->child1, &child1_allocation);
254
255 } else {
256 if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1))
257 gtk_widget_size_allocate (paned->child1,
258 &child1_allocation);
259 if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
260 gtk_widget_size_allocate (paned->child2,
261 &child2_allocation);
262 }
263 }
264
265
266 static void
gimv_vpaned_draw(GtkWidget * widget,GdkRectangle * area)267 gimv_vpaned_draw (GtkWidget *widget,
268 GdkRectangle *area)
269 {
270 GimvPaned *paned;
271 GdkRectangle handle_area, child_area;
272 guint16 border_width;
273
274 g_return_if_fail (widget != NULL);
275 g_return_if_fail (GIMV_IS_PANED (widget));
276
277 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) {
278 gint width, height;
279
280 paned = GIMV_PANED (widget);
281 border_width = GTK_CONTAINER (paned)->border_width;
282
283 gdk_window_clear_area (widget->window,
284 area->x, area->y,
285 area->width, area->height);
286
287 gdk_window_get_size (paned->handle, &width, &height);
288
289 handle_area.x = paned->handle_xpos;
290 handle_area.y = paned->handle_ypos;
291 handle_area.width = width;
292 handle_area.height = height;
293
294 if (gdk_rectangle_intersect (&handle_area, area, &child_area)){
295 child_area.x -= handle_area.x;
296 child_area.y -= handle_area.y;
297
298 gtk_paint_flat_box (widget->style, paned->handle,
299 GTK_WIDGET_STATE (widget),
300 GTK_SHADOW_NONE,
301 &child_area, widget, "paned",
302 0, 0,
303 width, height);
304 }
305
306 /* Redraw the children
307 */
308 if (paned->child1 &&
309 gtk_widget_intersect (paned->child1, area, &child_area))
310 gtk_widget_draw (paned->child1, &child_area);
311 if (paned->child2 &&
312 gtk_widget_intersect (paned->child2, area, &child_area))
313 gtk_widget_draw (paned->child2, &child_area);
314
315 }
316 }
317
318
319 static void
gimv_vpaned_xor_line(GimvPaned * paned)320 gimv_vpaned_xor_line (GimvPaned *paned)
321 {
322 GtkWidget *widget;
323 GdkGCValues values;
324 guint16 ypos;
325
326 widget = GTK_WIDGET(paned);
327
328 if (!paned->xor_gc) {
329 GdkBitmap *stipple;
330
331 stipple = gdk_bitmap_create_from_data (NULL, gray50_bits,
332 gray50_width,
333 gray50_height);
334
335 values.function = GDK_INVERT;
336 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
337 values.fill = GDK_STIPPLED;
338 values.stipple = stipple;
339
340 paned->xor_gc = gdk_gc_new_with_values (widget->window,
341 &values,
342 GDK_GC_FUNCTION |
343 GDK_GC_SUBWINDOW |
344 GDK_GC_FILL |
345 GDK_GC_STIPPLE);
346 gdk_bitmap_unref (stipple);
347 }
348
349 ypos = paned->child1_size + GTK_CONTAINER (paned)->border_width;
350
351 gdk_draw_rectangle (widget->window, paned->xor_gc,
352 TRUE,
353 0,
354 ypos,
355 widget->allocation.width - 1,
356 paned->gutter_size);
357 }
358
359
360 static gint
gimv_vpaned_button_press(GtkWidget * widget,GdkEventButton * event)361 gimv_vpaned_button_press (GtkWidget *widget, GdkEventButton *event)
362 {
363 GimvPaned *paned;
364
365 g_return_val_if_fail (widget != NULL,FALSE);
366 g_return_val_if_fail (GIMV_IS_PANED (widget),FALSE);
367
368 paned = GIMV_PANED (widget);
369
370 if (!paned->in_drag &&
371 (event->window == paned->handle) && (event->button == 1))
372 {
373 paned->in_drag = TRUE;
374 /* We need a server grab here, not gtk_grab_add(), since
375 * we don't want to pass events on to the widget's children */
376 gdk_pointer_grab (paned->handle, FALSE,
377 GDK_POINTER_MOTION_HINT_MASK
378 | GDK_BUTTON1_MOTION_MASK
379 | GDK_BUTTON_RELEASE_MASK,
380 NULL, NULL, event->time);
381 paned->child1_size += event->y - paned->gutter_size / 2;
382 paned->child1_size = CLAMP (paned->child1_size,
383 0,
384 widget->allocation.height
385 - paned->gutter_size
386 - 2 * GTK_CONTAINER (paned)->border_width);
387 gimv_vpaned_xor_line (paned);
388 }
389
390 return TRUE;
391 }
392
393
394 static gint
gimv_vpaned_button_release(GtkWidget * widget,GdkEventButton * event)395 gimv_vpaned_button_release (GtkWidget *widget, GdkEventButton *event)
396 {
397 GimvPaned *paned;
398
399 g_return_val_if_fail (widget != NULL, FALSE);
400 g_return_val_if_fail (GIMV_IS_PANED (widget), FALSE);
401
402 paned = GIMV_PANED (widget);
403
404 if (paned->in_drag && (event->button == 1)) {
405 gimv_vpaned_xor_line (paned);
406 paned->in_drag = FALSE;
407 paned->position_set = TRUE;
408 gdk_pointer_ungrab (event->time);
409 gtk_widget_queue_resize (GTK_WIDGET (paned));
410 }
411
412 return TRUE;
413 }
414
415 #else
416 #endif /* USE_NORMAL_PANED */
417