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_hpaned.c,v 1.3 2004/03/07 11:53:30 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_hpaned.h"
37 #include <gtk/gtkmain.h>
38 #include <gtk/gtksignal.h>
39
40 static void gimv_hpaned_class_init (GimvHPanedClass *klass);
41 static void gimv_hpaned_init (GimvHPaned *hpaned);
42 static void gimv_hpaned_size_request (GtkWidget *widget,
43 GtkRequisition *requisition);
44 static void gimv_hpaned_size_allocate (GtkWidget *widget,
45 GtkAllocation *allocation);
46 static void gimv_hpaned_draw (GtkWidget *widget,
47 GdkRectangle *area);
48 static void gimv_hpaned_xor_line (GimvPaned *paned);
49 static gint gimv_hpaned_button_press (GtkWidget *widget,
50 GdkEventButton *event);
51 static gint gimv_hpaned_button_release (GtkWidget *widget,
52 GdkEventButton *event);
53
54
55 GtkType
gimv_hpaned_get_type(void)56 gimv_hpaned_get_type (void)
57 {
58 static GtkType hpaned_type = 0;
59
60 if (!hpaned_type) {
61 static const GtkTypeInfo hpaned_info = {
62 "GimvHPaned",
63 sizeof (GimvHPaned),
64 sizeof (GimvHPanedClass),
65 (GtkClassInitFunc) gimv_hpaned_class_init,
66 (GtkObjectInitFunc) gimv_hpaned_init,
67 /* reserved_1 */ NULL,
68 /* reserved_2 */ NULL,
69 (GtkClassInitFunc) NULL,
70 };
71 hpaned_type = gtk_type_unique (gimv_paned_get_type (),
72 &hpaned_info);
73 }
74 return hpaned_type;
75 }
76
77
78 static void
gimv_hpaned_class_init(GimvHPanedClass * class)79 gimv_hpaned_class_init (GimvHPanedClass *class)
80 {
81 GtkWidgetClass *widget_class;
82 GimvPanedClass *paned_class;
83
84 widget_class = (GtkWidgetClass*) class;
85 paned_class = (GimvPanedClass*) class;
86
87 widget_class->size_request = gimv_hpaned_size_request;
88 widget_class->size_allocate = gimv_hpaned_size_allocate;
89 #ifndef USE_GTK2
90 widget_class->draw = gimv_hpaned_draw;
91 #endif
92 widget_class->button_press_event = gimv_hpaned_button_press;
93 widget_class->button_release_event = gimv_hpaned_button_release;
94
95 paned_class->xor_line = gimv_hpaned_xor_line;
96 }
97
98
99 static void
gimv_hpaned_init(GimvHPaned * hpaned)100 gimv_hpaned_init (GimvHPaned *hpaned)
101 {
102 GIMV_PANED (hpaned)->horizontal = TRUE;
103 }
104
105
106 GtkWidget*
gimv_hpaned_new(void)107 gimv_hpaned_new (void)
108 {
109 GimvHPaned *hpaned;
110
111 hpaned = gtk_type_new (gimv_hpaned_get_type ());
112
113 return GTK_WIDGET (hpaned);
114 }
115
116
117 static void
gimv_hpaned_size_request(GtkWidget * widget,GtkRequisition * requisition)118 gimv_hpaned_size_request (GtkWidget *widget,
119 GtkRequisition *requisition)
120 {
121 GimvPaned *paned;
122 GtkRequisition child_requisition;
123
124 g_return_if_fail (widget != NULL);
125 g_return_if_fail (GIMV_IS_HPANED (widget));
126 g_return_if_fail (requisition != NULL);
127
128 paned = GIMV_PANED (widget);
129 requisition->width = 0;
130 requisition->height = 0;
131
132 if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1)) {
133 gtk_widget_size_request (paned->child1, &child_requisition);
134
135 requisition->height = child_requisition.height;
136 requisition->width = child_requisition.width;
137 }
138
139 if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2)) {
140 gtk_widget_size_request (paned->child2, &child_requisition);
141
142 requisition->height = MAX (requisition->height,
143 child_requisition.height);
144 requisition->width += child_requisition.width;
145 }
146
147 requisition->width += (GTK_CONTAINER (paned)->border_width * 2
148 + paned->gutter_size);
149 requisition->height += GTK_CONTAINER (paned)->border_width * 2;
150 }
151
152
153 static void
gimv_hpaned_size_allocate(GtkWidget * widget,GtkAllocation * allocation)154 gimv_hpaned_size_allocate (GtkWidget *widget,
155 GtkAllocation *allocation)
156 {
157 GimvPaned *paned;
158 GtkRequisition child1_requisition;
159 GtkRequisition child2_requisition;
160 GtkAllocation child1_allocation;
161 GtkAllocation child2_allocation;
162 gint border_width, gutter_size;
163
164 g_return_if_fail (widget != NULL);
165 g_return_if_fail (GIMV_IS_HPANED (widget));
166 g_return_if_fail (allocation != NULL);
167
168 widget->allocation = *allocation;
169 paned = GIMV_PANED (widget);
170 border_width = GTK_CONTAINER (paned)->border_width;
171 gutter_size = paned->gutter_size;
172
173 if (paned->child1)
174 gtk_widget_get_child_requisition (paned->child1,
175 &child1_requisition);
176 else
177 child1_requisition.width = 0;
178
179 if (paned->child2)
180 gtk_widget_get_child_requisition (paned->child2,
181 &child2_requisition);
182 else
183 child2_requisition.width = 0;
184
185 gimv_paned_compute_position (paned,
186 MAX (1, (gint) widget->allocation.width
187 - gutter_size
188 - 2 * border_width),
189 child1_requisition.width,
190 child2_requisition.width);
191
192 if (paned->child_hidden != 0) {
193 gutter_size = 0;
194 if ((paned->child_hidden == 1) && paned->child1) {
195 /* hide child1 and show child2 if it exists. */
196 gtk_widget_hide (paned->child1);
197 if (paned->child2 && !GTK_WIDGET_VISIBLE (paned->child2))
198 gtk_widget_show (paned->child2);
199 }
200 if ((paned->child_hidden == 2) && paned->child2) {
201 /* hide child2 and show child1 if it exists. */
202 gtk_widget_hide (paned->child2);
203 if (paned->child1 && !GTK_WIDGET_VISIBLE (paned->child1))
204 gtk_widget_show (paned->child1);
205 }
206 } else {
207 /* Show both children. */
208 if (paned->child1 && !GTK_WIDGET_VISIBLE (paned->child1))
209 gtk_widget_show (paned->child1);
210 if (paned->child2 && !GTK_WIDGET_VISIBLE (paned->child2))
211 gtk_widget_show (paned->child2);
212 }
213
214 /* Move the handle before the children so we don't get extra expose
215 * events */
216
217 paned->handle_ypos = border_width;
218 paned->handle_xpos = paned->child1_size + border_width;
219
220 if (GTK_WIDGET_REALIZED (widget)) {
221 gdk_window_move_resize (widget->window,
222 allocation->x, allocation->y,
223 allocation->width, allocation->height);
224
225 if (paned->child_hidden == 0) {
226 gdk_window_move_resize (paned->handle,
227 paned->handle_xpos,
228 paned->handle_ypos,
229 paned->gutter_size,
230 allocation->height);
231 gdk_window_show (paned->handle);
232 } else
233 gdk_window_hide (paned->handle);
234 }
235
236 child1_allocation.height = child2_allocation.height
237 = MAX (1, (gint) allocation->height - border_width * 2);
238 child1_allocation.width = paned->child1_size;
239 child1_allocation.y = child2_allocation.y = border_width;
240 child1_allocation.x = border_width;
241
242 child2_allocation.x
243 = child1_allocation.x + child1_allocation.width + gutter_size;
244 child2_allocation.width
245 = MAX (1, (gint) allocation->width - child2_allocation.x - border_width);
246
247 /* Now allocate the childen, making sure, when resizing not to
248 * overlap the windows */
249 if (GTK_WIDGET_MAPPED(widget) &&
250 paned->child1 && GTK_WIDGET_VISIBLE (paned->child1) &&
251 paned->child1->allocation.width < child1_allocation.width)
252 {
253 if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
254 gtk_widget_size_allocate (paned->child2, &child2_allocation);
255 gtk_widget_size_allocate (paned->child1, &child1_allocation);
256 } else {
257 if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1))
258 gtk_widget_size_allocate (paned->child1, &child1_allocation);
259 if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
260 gtk_widget_size_allocate (paned->child2, &child2_allocation);
261 }
262 }
263
264
265 static void
gimv_hpaned_draw(GtkWidget * widget,GdkRectangle * area)266 gimv_hpaned_draw (GtkWidget *widget,
267 GdkRectangle *area)
268 {
269 GimvPaned *paned;
270 GdkRectangle handle_area, child_area;
271 guint16 border_width;
272
273 g_return_if_fail (widget != NULL);
274 g_return_if_fail (GIMV_IS_PANED (widget));
275
276 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) {
277 gint width, height;
278
279 paned = GIMV_PANED (widget);
280 border_width = GTK_CONTAINER (paned)->border_width;
281
282 gdk_window_clear_area (widget->window,
283 area->x, area->y,
284 area->width, area->height);
285
286 gdk_window_get_size (paned->handle, &width, &height);
287
288 handle_area.x = paned->handle_xpos;
289 handle_area.y = paned->handle_ypos;
290 handle_area.width = width;
291 handle_area.height = height;
292
293 if (gdk_rectangle_intersect (&handle_area, area, &child_area)){
294 child_area.x -= handle_area.x;
295 child_area.y -= handle_area.y;
296
297 gtk_paint_flat_box (widget->style, paned->handle,
298 GTK_WIDGET_STATE (widget),
299 GTK_SHADOW_NONE,
300 &child_area, widget, "paned",
301 0, 0,
302 width, height);
303 }
304
305 /* Redraw the children
306 */
307 if (paned->child1 &&
308 gtk_widget_intersect (paned->child1, area, &child_area))
309 gtk_widget_draw (paned->child1, &child_area);
310 if (paned->child2 &&
311 gtk_widget_intersect (paned->child2, area, &child_area))
312 gtk_widget_draw (paned->child2, &child_area);
313
314 }
315 }
316
317
318 static void
gimv_hpaned_xor_line(GimvPaned * paned)319 gimv_hpaned_xor_line (GimvPaned *paned)
320 {
321 GtkWidget *widget;
322 GdkGCValues values;
323 guint16 xpos;
324
325 widget = GTK_WIDGET(paned);
326
327 if (!paned->xor_gc) {
328 GdkBitmap *stipple;
329
330 stipple = gdk_bitmap_create_from_data (NULL, gray50_bits,
331 gray50_width,
332 gray50_height);
333
334 values.function = GDK_INVERT;
335 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
336 values.fill = GDK_STIPPLED;
337 values.stipple = stipple;
338 paned->xor_gc = gdk_gc_new_with_values (widget->window,
339 &values,
340 GDK_GC_FUNCTION |
341 GDK_GC_SUBWINDOW |
342 GDK_GC_FILL |
343 GDK_GC_STIPPLE);
344 gdk_bitmap_unref (stipple);
345 }
346
347 xpos = paned->child1_size + GTK_CONTAINER (paned)->border_width;
348
349 gdk_draw_rectangle (widget->window, paned->xor_gc,
350 TRUE,
351 xpos,
352 0,
353 paned->gutter_size,
354 widget->allocation.height - 1);
355 }
356
357
358 static gint
gimv_hpaned_button_press(GtkWidget * widget,GdkEventButton * event)359 gimv_hpaned_button_press (GtkWidget *widget, GdkEventButton *event)
360 {
361 GimvPaned *paned;
362
363 g_return_val_if_fail (widget != NULL,FALSE);
364 g_return_val_if_fail (GIMV_IS_PANED (widget),FALSE);
365
366 paned = GIMV_PANED (widget);
367
368 if (!paned->in_drag &&
369 (event->window == paned->handle) && (event->button == 1))
370 {
371 paned->in_drag = TRUE;
372 /* We need a server grab here, not gtk_grab_add(), since
373 * we don't want to pass events on to the widget's children */
374 gdk_pointer_grab (paned->handle, FALSE,
375 GDK_POINTER_MOTION_HINT_MASK
376 | GDK_BUTTON1_MOTION_MASK
377 | GDK_BUTTON_RELEASE_MASK,
378 NULL, NULL, event->time);
379 paned->child1_size += event->x - paned->gutter_size / 2;
380 paned->child1_size = CLAMP (paned->child1_size, 0,
381 widget->allocation.width
382 - paned->gutter_size
383 - 2 * GTK_CONTAINER (paned)->border_width);
384 gimv_hpaned_xor_line (paned);
385 }
386
387 return TRUE;
388 }
389
390
391 static gint
gimv_hpaned_button_release(GtkWidget * widget,GdkEventButton * event)392 gimv_hpaned_button_release (GtkWidget *widget, GdkEventButton *event)
393 {
394 GimvPaned *paned;
395
396 g_return_val_if_fail (widget != NULL,FALSE);
397 g_return_val_if_fail (GIMV_IS_PANED (widget),FALSE);
398
399 paned = GIMV_PANED (widget);
400
401 if (paned->in_drag && (event->button == 1)) {
402 gimv_hpaned_xor_line (paned);
403 paned->in_drag = FALSE;
404 paned->position_set = TRUE;
405 gdk_pointer_ungrab (event->time);
406 gtk_widget_queue_resize (GTK_WIDGET (paned));
407 }
408
409 return TRUE;
410 }
411
412 #endif /* USE_NORMAL_PANED */
413