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_zlist.c,v 1.5 2004/09/21 08:44:32 makeinu Exp $
22 */
23
24 /*
25 * These codes are mostly taken from Another X image viewer.
26 *
27 * Another X image viewer Author:
28 * David Ramboz <dramboz@users.sourceforge.net>
29 */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <gdk/gdkkeysyms.h>
38
39 #include "gtk2-compat.h"
40 #include "gimv_zlist.h"
41
42 #define bw(widget) ((gint) GTK_CONTAINER(widget)->border_width)
43
44 #define CELL_COL_FROM_X(list, x) \
45 (GIMV_SCROLLED_VX (list, (x) - (list)->x_pad - bw (list)) / (list)->cell_width)
46 #define CELL_ROW_FROM_Y(list, y) \
47 (GIMV_SCROLLED_VY (list, (y) - (list)->y_pad - bw (list)) / (list)->cell_height)
48
49 #define CELL_X_FROM_COL(list, col) \
50 (GIMV_SCROLLED_X (list, (col) * (list)->cell_width + (list)->x_pad))
51 #define CELL_Y_FROM_ROW(list, row) \
52 (GIMV_SCROLLED_Y (list, (row) * (list)->cell_height + (list)->y_pad))
53
54 #define LIST_WIDTH(list) ((list)->columns * (list)->cell_width /* + (list)->cell_x_pad */)
55 #define LIST_HEIGHT(list) ((list)->rows * (list)->cell_height /* + (list)->cell_y_pad */)
56
57 #define HIGHLIGHT_SIZE 2
58
59 #ifdef USE_GTK2
60 # ifdef GTK_DISABLE_DEPRECATED
61 # include "gimv_marshal.h"
62 # endif
63 # define WIDGET_DRAW(widget) gtk_widget_queue_draw (widget)
64 # define WIDGET_DRAW_AREA(widget, area) \
65 gtk_widget_queue_draw_area (widget, \
66 (area)->x, (area)->y, \
67 (area)->width, (area)->height)
68 #else /* USE_GTK2 */
69 # define WIDGET_DRAW(widget) gtk_widget_draw (widget, NULL)
70 # define WIDGET_DRAW_AREA(widget, area) gtk_widget_draw (widget, area)
71 #endif /* USE_GTK2 */
72
73 static void gimv_zlist_class_init (GimvZListClass *klass);
74 static void gimv_zlist_init (GimvZList *list);
75
76 #ifdef USE_GTK2
77 static void gimv_zlist_finalize (GObject *object);
78 #else
79 static void gimv_zlist_finalize (GtkObject *object);
80 #endif
81 static void gimv_zlist_map (GtkWidget *widget);
82 static void gimv_zlist_unmap (GtkWidget *widget);
83 static void gimv_zlist_realize (GtkWidget *widget);
84 static void gimv_zlist_unrealize (GtkWidget *widget);
85 static void gimv_zlist_size_request (GtkWidget *widget,
86 GtkRequisition *requisition);
87 static void gimv_zlist_size_allocate (GtkWidget *widget,
88 GtkAllocation *allocation);
89 static gint gimv_zlist_expose (GtkWidget *widget,
90 GdkEventExpose *event);
91 static void gimv_zlist_update (GimvZList *list);
92 static void gimv_zlist_draw_horizontal_list (GtkWidget *widget,
93 GdkRectangle *area);
94 static void gimv_zlist_draw_vertical_list (GtkWidget *widget,
95 GdkRectangle *area);
96 static void gimv_zlist_draw_selection_region (GimvZList *list,
97 GdkRectangle *area);
98 static void gimv_zlist_draw (GtkWidget *widget,
99 GdkRectangle *area);
100 static void gimv_zlist_redraw_selection_region (GtkWidget *list,
101 gint prev_x,
102 gint prev_y,
103 gint next_x,
104 gint next_y);
105
106 static gint gimv_zlist_button_press (GtkWidget *widget,
107 GdkEventButton *event);
108 static gint gimv_zlist_button_release (GtkWidget *widget,
109 GdkEventButton *event);
110 static gint gimv_zlist_motion_notify (GtkWidget *widget,
111 GdkEventMotion *event);
112 static gint gimv_zlist_key_press (GtkWidget *widget,
113 GdkEventKey *event);
114 static gint gimv_zlist_focus_in (GtkWidget *widget,
115 GdkEventFocus *event);
116 static gint gimv_zlist_focus_out (GtkWidget *widget,
117 GdkEventFocus *event);
118 static gint gimv_zlist_drag_motion (GtkWidget *widget,
119 GdkDragContext *context,
120 gint x,
121 gint y,
122 guint time);
123 static gint gimv_zlist_drag_drop (GtkWidget *widget,
124 GdkDragContext *context,
125 gint x,
126 gint y,
127 guint time);
128 static void gimv_zlist_drag_leave (GtkWidget *widget,
129 GdkDragContext *context,
130 guint time);
131 static void gimv_zlist_highlight (GtkWidget *widget);
132 static void gimv_zlist_unhighlight (GtkWidget *widget);
133 static gint gimv_zlist_focus (GtkContainer *container,
134 GtkDirectionType dir);
135 static void gimv_zlist_cell_draw_focus (GimvZList *list,
136 gint index);
137 static void gimv_zlist_cell_draw_default (GimvZList *list,
138 gint index);
139
140
141 static void gimv_zlist_forall (GtkContainer *container,
142 gboolean include_internals,
143 GtkCallback callback,
144 gpointer callback_data);
145 static void gimv_zlist_adjust_adjustments (GimvScrolled *scrolled);
146 static void gimv_zlist_cell_pos (GimvZList *list,
147 gint index,
148 gint *row,
149 gint *col);
150 static void gimv_zlist_cell_area (GimvZList *list,
151 gint index,
152 GdkRectangle *cell_area);
153
154 enum {
155 CLEAR,
156 CELL_DRAW,
157 CELL_SIZE_REQUEST,
158 CELL_DRAW_FOCUS,
159 CELL_DRAW_DEFAULT,
160 CELL_SELECT,
161 CELL_UNSELECT,
162 LAST_SIGNAL
163 };
164
165 static GtkWidgetClass *parent_class = NULL;
166
167 static guint gimv_zlist_signals [LAST_SIGNAL] = { 0 };
168
169
170 GtkType
gimv_zlist_get_type(void)171 gimv_zlist_get_type (void)
172 {
173 static GtkType type = 0;
174
175 #ifdef USE_GTK2
176 if (!type) {
177 static const GTypeInfo gimv_zlist_type_info = {
178 sizeof (GimvZListClass),
179 NULL, /* base_init */
180 NULL, /* base_finalize */
181 (GClassInitFunc) gimv_zlist_class_init,
182 NULL, /* class_finalize */
183 NULL, /* class_data */
184 sizeof (GimvZList),
185 0, /* n_preallocs */
186 (GInstanceInitFunc) gimv_zlist_init,
187 };
188
189 type = g_type_register_static (GIMV_TYPE_SCROLLED,
190 "GimvZList",
191 &gimv_zlist_type_info,
192 0);
193 }
194 #else /* USE_GTK2 */
195 if (!type) {
196 static const GtkTypeInfo gimv_zlist_type_info = {
197 "GimvZList",
198 sizeof (GimvZList),
199 sizeof (GimvZListClass),
200 (GtkClassInitFunc) gimv_zlist_class_init,
201 (GtkObjectInitFunc) gimv_zlist_init,
202 /* reserved_1 */ NULL,
203 /* reserved_2 */ NULL,
204 (GtkClassInitFunc) NULL,
205 };
206
207 type = gtk_type_unique (GIMV_TYPE_SCROLLED, &gimv_zlist_type_info);
208 }
209 #endif /* USE_GTK2 */
210
211 return type;
212 }
213
214
215 static void
gimv_zlist_class_init(GimvZListClass * klass)216 gimv_zlist_class_init (GimvZListClass *klass)
217 {
218 GtkObjectClass *object_class;
219 GtkWidgetClass *widget_class;
220 GtkContainerClass *container_class;
221 GimvScrolledClass *scrolled_class;
222
223 parent_class = gtk_type_class (GIMV_TYPE_SCROLLED);
224
225 object_class = (GtkObjectClass*) klass;
226 widget_class = (GtkWidgetClass*) klass;
227 container_class = (GtkContainerClass*) klass;
228 scrolled_class = (GimvScrolledClass*) klass;
229
230 #if (defined USE_GTK2) && (defined GTK_DISABLE_DEPRECATED)
231 gimv_zlist_signals [CLEAR] =
232 g_signal_new ("clear",
233 G_TYPE_FROM_CLASS (object_class),
234 G_SIGNAL_RUN_FIRST,
235 G_STRUCT_OFFSET (GimvZListClass, clear),
236 NULL, NULL,
237 g_cclosure_marshal_VOID__VOID,
238 G_TYPE_NONE, 0);
239
240 gimv_zlist_signals [CELL_DRAW] =
241 g_signal_new ("cell_draw",
242 G_TYPE_FROM_CLASS (object_class),
243 G_SIGNAL_RUN_FIRST,
244 G_STRUCT_OFFSET (GimvZListClass, cell_draw),
245 NULL, NULL,
246 gimv_marshal_VOID__POINTER_POINTER_POINTER,
247 G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER);
248
249 gimv_zlist_signals [CELL_SIZE_REQUEST] =
250 g_signal_new ("cell_size_request",
251 G_TYPE_FROM_CLASS (object_class),
252 G_SIGNAL_RUN_FIRST,
253 G_STRUCT_OFFSET (GimvZListClass, cell_size_request),
254 NULL, NULL,
255 gimv_marshal_VOID__POINTER_POINTER,
256 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
257
258 gimv_zlist_signals [CELL_DRAW_FOCUS] =
259 g_signal_new ("cell_draw_focus",
260 G_TYPE_FROM_CLASS (object_class),
261 G_SIGNAL_RUN_FIRST,
262 G_STRUCT_OFFSET (GimvZListClass, cell_draw_focus),
263 NULL, NULL,
264 gimv_marshal_VOID__POINTER_POINTER,
265 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
266
267 gimv_zlist_signals [CELL_DRAW_DEFAULT] =
268 g_signal_new ("cell_draw_default",
269 G_TYPE_FROM_CLASS (object_class),
270 G_SIGNAL_RUN_FIRST,
271 G_STRUCT_OFFSET (GimvZListClass, cell_draw_default),
272 NULL, NULL,
273 gimv_marshal_VOID__POINTER_POINTER,
274 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
275
276 gimv_zlist_signals [CELL_SELECT] =
277 g_signal_new ("cell_select",
278 G_TYPE_FROM_CLASS (object_class),
279 G_SIGNAL_RUN_FIRST,
280 G_STRUCT_OFFSET (GimvZListClass, cell_select),
281 NULL, NULL,
282 g_cclosure_marshal_VOID__INT,
283 G_TYPE_NONE, 1, G_TYPE_INT);
284
285 gimv_zlist_signals [CELL_UNSELECT] =
286 g_signal_new ("cell_unselect",
287 G_TYPE_FROM_CLASS (object_class),
288 G_SIGNAL_RUN_FIRST,
289 G_STRUCT_OFFSET (GimvZListClass, cell_unselect),
290 NULL, NULL,
291 g_cclosure_marshal_VOID__INT,
292 G_TYPE_NONE, 1, G_TYPE_INT);
293 #else /* (defined USE_GTK2) && (defined GTK_DISABLE_DEPRECATED) */
294 gimv_zlist_signals [CLEAR] =
295 gtk_signal_new ("clear",
296 GTK_RUN_FIRST,
297 GTK_CLASS_TYPE(object_class),
298 GTK_SIGNAL_OFFSET(GimvZListClass, clear),
299 gtk_marshal_NONE__NONE,
300 GTK_TYPE_NONE, 0);
301
302 gimv_zlist_signals [CELL_DRAW] =
303 gtk_signal_new ("cell_draw",
304 GTK_RUN_FIRST,
305 GTK_CLASS_TYPE(object_class),
306 GTK_SIGNAL_OFFSET(GimvZListClass, cell_draw),
307 gtk_marshal_NONE__POINTER_POINTER_POINTER,
308 GTK_TYPE_NONE, 3,
309 GTK_TYPE_POINTER, GTK_TYPE_POINTER, GTK_TYPE_POINTER);
310
311 gimv_zlist_signals [CELL_SIZE_REQUEST] =
312 gtk_signal_new ("cell_size_request",
313 GTK_RUN_FIRST,
314 GTK_CLASS_TYPE(object_class),
315 GTK_SIGNAL_OFFSET(GimvZListClass, cell_size_request),
316 gtk_marshal_NONE__POINTER_POINTER,
317 GTK_TYPE_NONE, 2,
318 GTK_TYPE_POINTER, GTK_TYPE_POINTER);
319
320 gimv_zlist_signals [CELL_DRAW_FOCUS] =
321 gtk_signal_new ("cell_draw_focus",
322 GTK_RUN_FIRST,
323 GTK_CLASS_TYPE(object_class),
324 GTK_SIGNAL_OFFSET(GimvZListClass, cell_draw_focus),
325 gtk_marshal_NONE__POINTER_POINTER,
326 GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_POINTER);
327
328 gimv_zlist_signals [CELL_DRAW_DEFAULT] =
329 gtk_signal_new ("cell_draw_default",
330 GTK_RUN_FIRST,
331 GTK_CLASS_TYPE(object_class),
332 GTK_SIGNAL_OFFSET(GimvZListClass, cell_draw_default),
333 gtk_marshal_NONE__POINTER_POINTER,
334 GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_POINTER);
335
336 gimv_zlist_signals [CELL_SELECT] =
337 gtk_signal_new ("cell_select",
338 GTK_RUN_FIRST,
339 GTK_CLASS_TYPE(object_class),
340 GTK_SIGNAL_OFFSET(GimvZListClass, cell_select),
341 gtk_marshal_NONE__INT,
342 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
343
344 gimv_zlist_signals [CELL_UNSELECT] =
345 gtk_signal_new ("cell_unselect",
346 GTK_RUN_FIRST,
347 GTK_CLASS_TYPE(object_class),
348 GTK_SIGNAL_OFFSET(GimvZListClass, cell_unselect),
349 gtk_marshal_NONE__INT,
350 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
351
352 gtk_object_class_add_signals (object_class, gimv_zlist_signals, LAST_SIGNAL);
353 #endif /* (defined USE_GTK2) && (defined GTK_DISABLE_DEPRECATED) */
354
355 OBJECT_CLASS_SET_FINALIZE_FUNC (klass, gimv_zlist_finalize);
356
357 widget_class->map = gimv_zlist_map;
358 widget_class->unmap = gimv_zlist_unmap;
359 widget_class->realize = gimv_zlist_realize;
360 widget_class->unrealize = gimv_zlist_unrealize;
361 widget_class->size_request = gimv_zlist_size_request;
362 widget_class->size_allocate = gimv_zlist_size_allocate;
363 widget_class->expose_event = gimv_zlist_expose;
364 #ifndef USE_GTK2
365 widget_class->draw = gimv_zlist_draw;
366 #endif
367
368 widget_class->button_press_event = gimv_zlist_button_press;
369 widget_class->button_release_event = gimv_zlist_button_release;
370 widget_class->motion_notify_event = gimv_zlist_motion_notify;
371 widget_class->key_press_event = gimv_zlist_key_press;
372 widget_class->focus_in_event = gimv_zlist_focus_in;
373 widget_class->focus_out_event = gimv_zlist_focus_out;
374 widget_class->drag_motion = gimv_zlist_drag_motion;
375 widget_class->drag_drop = gimv_zlist_drag_drop;
376 widget_class->drag_leave = gimv_zlist_drag_leave;
377
378 container_class->forall = gimv_zlist_forall;
379 /* container_class->focus = gimv_zlist_focus; */
380 scrolled_class->adjust_adjustments = gimv_zlist_adjust_adjustments;
381
382 klass->cell_draw = NULL;
383 klass->cell_size_request = NULL;
384 klass->cell_draw_focus = NULL;
385 klass->cell_draw_default = NULL;
386 klass->cell_select = NULL;
387 klass->cell_unselect = NULL;
388 }
389
390
391 static void
gimv_zlist_init(GimvZList * list)392 gimv_zlist_init (GimvZList *list)
393 {
394 GTK_WIDGET_UNSET_FLAGS (list, GTK_NO_WINDOW);
395 GTK_WIDGET_SET_FLAGS (list, GTK_CAN_FOCUS);
396
397 list->flags = 0;
398 list->cell_width = 1;
399 list->cell_height = 1;
400 list->rows = 1;
401 list->columns = 1;
402 list->cells = NULL;
403 list->cell_count = 0;
404 list->selection_mode = GTK_SELECTION_SINGLE;
405 list->selection = NULL;
406 list->focus = -1;
407 list->anchor = -1;
408 list->cell_x_pad = 4;
409 list->cell_y_pad = 4;
410 list->x_pad = 0;
411 list->y_pad = 0;
412 list->entered_cell = NULL;
413
414 list->region_select = GIMV_ZLIST_REGION_SELECT_OFF;
415 list->region_line_gc = NULL;
416 list->selection_mask = NULL;
417 }
418
419
420 void
gimv_zlist_construct(GimvZList * list,int flags)421 gimv_zlist_construct (GimvZList *list, int flags)
422 {
423 g_return_if_fail (list);
424
425 list->flags = flags;
426 list->cells = g_array_new (0, 0, sizeof (gpointer));
427 }
428
429
430 GtkWidget*
gimv_zlist_new(guint flags)431 gimv_zlist_new (guint flags)
432 {
433 GimvZList *list;
434
435 #ifdef USE_GTK2
436 list = g_object_new (gimv_zlist_get_type (), NULL);
437 #else /* USE_GTK2 */
438 list = (GimvZList*) gtk_type_new (gimv_zlist_get_type());
439 #endif /* USE_GTK2 */
440 g_return_val_if_fail (list, NULL);
441
442 gimv_zlist_construct (list, flags);
443
444 return (GtkWidget*) list;
445 }
446
447
448 void
gimv_zlist_set_to_vertical(GimvZList * zlist)449 gimv_zlist_set_to_vertical (GimvZList *zlist)
450 {
451 g_return_if_fail (GIMV_IS_ZLIST (zlist));
452
453 zlist->flags &= ~GIMV_ZLIST_HORIZONTAL;
454
455 if (GTK_WIDGET_VISIBLE (zlist)) {
456 WIDGET_DRAW (GTK_WIDGET (zlist));
457 }
458 }
459
460
461 void
gimv_zlist_set_to_horizontal(GimvZList * zlist)462 gimv_zlist_set_to_horizontal (GimvZList *zlist)
463 {
464 g_return_if_fail (GIMV_IS_ZLIST (zlist));
465
466 zlist->flags |= GIMV_ZLIST_HORIZONTAL;
467
468 if (GTK_WIDGET_VISIBLE (zlist)) {
469 WIDGET_DRAW (GTK_WIDGET (zlist));
470 }
471 }
472
473
474 static void
475 #ifdef USE_GTK2
gimv_zlist_finalize(GObject * object)476 gimv_zlist_finalize (GObject *object)
477 #else /* USE_GTK2 */
478 gimv_zlist_finalize (GtkObject *object)
479 #endif /* USE_GTK2 */
480 {
481 if (GIMV_ZLIST (object)->region_line_gc)
482 gdk_gc_destroy (GIMV_ZLIST (object)->region_line_gc);
483
484 OBJECT_CLASS_FINALIZE_SUPER (parent_class, object);
485 }
486
487
488 static void
gimv_zlist_map(GtkWidget * widget)489 gimv_zlist_map (GtkWidget *widget)
490 {
491 GTK_WIDGET_SET_FLAGS(widget, GTK_MAPPED);
492 gdk_window_show (widget->window);
493 gimv_zlist_update(GIMV_ZLIST (widget));
494 }
495
496
497 static void
gimv_zlist_unmap(GtkWidget * widget)498 gimv_zlist_unmap (GtkWidget *widget)
499 {
500 GTK_WIDGET_UNSET_FLAGS(widget, GTK_MAPPED);
501 gdk_window_hide (widget->window);
502 }
503
504
505 static void
gimv_zlist_realize(GtkWidget * widget)506 gimv_zlist_realize (GtkWidget *widget)
507 {
508 GdkWindowAttr attributes;
509 gint attributes_mask;
510
511 GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
512
513 attributes.window_type = GDK_WINDOW_CHILD;
514 attributes.x = widget->allocation.x + bw (widget);
515 attributes.y = widget->allocation.y + bw (widget);
516 attributes.width = widget->allocation.width - 2 * bw (widget);
517 attributes.height = widget->allocation.height - 2 * bw (widget);
518 attributes.wclass = GDK_INPUT_OUTPUT;
519 attributes.visual = gtk_widget_get_visual (widget);
520 attributes.colormap = gtk_widget_get_colormap (widget);
521 attributes.event_mask = gtk_widget_get_events (widget);
522 attributes.event_mask |= (GDK_EXPOSURE_MASK |
523 GDK_BUTTON_PRESS_MASK |
524 GDK_BUTTON_RELEASE_MASK |
525 GDK_POINTER_MOTION_MASK |
526 GDK_KEY_PRESS_MASK);
527 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
528
529 widget->window = gdk_window_new (gtk_widget_get_parent_window(widget),
530 &attributes, attributes_mask);
531 gdk_window_set_user_data (widget->window, widget);
532 widget->style = gtk_style_attach (widget->style, widget->window);
533
534 gdk_window_set_background (widget->window,
535 &widget->style->base [GTK_STATE_NORMAL]);
536
537 gimv_scrolled_realize (GIMV_SCROLLED(widget));
538 }
539
540
541 static void
gimv_zlist_unrealize(GtkWidget * widget)542 gimv_zlist_unrealize (GtkWidget *widget)
543 {
544 gimv_scrolled_unrealize (GIMV_SCROLLED(widget));
545
546 if (parent_class->unrealize)
547 (* parent_class->unrealize) (widget);
548 }
549
550
551 static void
gimv_zlist_size_request(GtkWidget * widget,GtkRequisition * requisition)552 gimv_zlist_size_request (GtkWidget *widget, GtkRequisition *requisition)
553 {
554 requisition->width = requisition->height = 50;
555 }
556
557
558 static void
gimv_zlist_size_allocate(GtkWidget * widget,GtkAllocation * allocation)559 gimv_zlist_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
560 {
561 if (allocation->x == widget->allocation.x
562 && allocation->y == widget->allocation.y
563 && allocation->width == widget->allocation.width
564 && allocation->height == widget->allocation.height)
565 {
566 return;
567 }
568
569 widget->allocation = *allocation;
570
571 if (GTK_WIDGET_REALIZED(widget))
572 gdk_window_move_resize (widget->window,
573 allocation->x + bw (widget),
574 allocation->y + bw (widget),
575 allocation->width - 2 * bw (widget),
576 allocation->height - 2 * bw (widget));
577
578 gimv_zlist_update (GIMV_ZLIST(widget));
579 }
580
581
582 static void
gimv_zlist_update(GimvZList * list)583 gimv_zlist_update (GimvZList *list)
584 {
585 GtkWidget *widget;
586 GtkAdjustment *adj;
587
588 widget = GTK_WIDGET(list);
589
590 if (list->flags & GIMV_ZLIST_HORIZONTAL) {
591 if (list->flags & GIMV_ZLIST_1)
592 list->cell_height = widget->allocation.height - 2 * bw (widget);
593
594 list->rows = MAX(1, (widget->allocation.height - 2 * bw (widget)) / list->cell_height);
595 list->columns = list->cell_count % list->rows ?
596 list->cell_count / list->rows + 1 :
597 list->cell_count / list->rows;
598
599 list->y_pad = (widget->allocation.height - LIST_HEIGHT(list) - 2 * bw (widget)) / 2;
600 if (list->y_pad < 0) list->y_pad = 0;
601
602 gimv_zlist_adjust_adjustments (GIMV_SCROLLED(list));
603 adj = GIMV_SCROLLED(widget)->h_adjustment;
604 if (adj && !GIMV_SCROLLED(widget)->freeze_count
605 && adj->value > adj->upper - adj->page_size)
606 {
607 adj->value = adj->upper - adj->page_size;
608 #ifdef USE_GTK2
609 g_signal_emit_by_name (G_OBJECT(adj), "value_changed", NULL);
610 #else /* USE_GTK2 */
611 gtk_signal_emit_by_name (GTK_OBJECT(adj), "value_changed", NULL);
612 #endif /* USE_GTK2 */
613 }
614
615 } else {
616 if (list->flags & GIMV_ZLIST_1)
617 list->cell_width = widget->allocation.width - 2 * bw (widget);
618
619 list->columns = MAX(1, (widget->allocation.width - 2 * bw (widget)) / list->cell_width);
620 list->rows = list->cell_count % list->columns ?
621 list->cell_count / list->columns + 1 :
622 list->cell_count / list->columns;
623
624 list->x_pad = (widget->allocation.width - LIST_WIDTH(list) - 2 * bw (widget)) / 2;
625 if (list->x_pad < 0) list->x_pad = 0;
626
627 gimv_zlist_adjust_adjustments (GIMV_SCROLLED(widget));
628 adj = GIMV_SCROLLED(widget)->v_adjustment;
629 if (adj
630 && !GIMV_SCROLLED(widget)->freeze_count
631 && adj->value > adj->upper - adj->page_size)
632 {
633 adj->value = adj->upper - adj->page_size;
634 #ifdef USE_GTK2
635 g_signal_emit_by_name (G_OBJECT(adj), "value_changed", NULL);
636 #else /* USE_GTK2 */
637 gtk_signal_emit_by_name (GTK_OBJECT(adj), "value_changed", NULL);
638 #endif /* USE_GTK2 */
639 }
640 }
641 }
642
643
644 static gint
gimv_zlist_expose(GtkWidget * widget,GdkEventExpose * event)645 gimv_zlist_expose (GtkWidget *widget, GdkEventExpose *event)
646 {
647 if (GTK_WIDGET_DRAWABLE(widget) && event->window == widget->window)
648 gimv_zlist_draw (widget, &event->area);
649
650 return FALSE; /* xxx */
651 }
652
653
654 gboolean
gimv_zlist_get_cell_area(GimvZList * list,gint index,GdkRectangle * area)655 gimv_zlist_get_cell_area (GimvZList *list, gint index, GdkRectangle *area)
656 {
657 gint col, row;
658
659 g_return_val_if_fail (GIMV_IS_ZLIST (list), FALSE);
660 g_return_val_if_fail (area, FALSE);
661 g_return_val_if_fail (index >= 0 && index < list->cell_count, FALSE);
662
663 if (list->flags & GIMV_ZLIST_HORIZONTAL){
664 col = index / list->rows;
665 row = index % list->rows;
666 } else {
667 col = index % list->columns;
668 row = index / list->columns;
669 }
670
671 area->x = CELL_X_FROM_COL(list, col) + list->cell_x_pad;
672 area->y = CELL_Y_FROM_ROW(list, row) + list->cell_y_pad;
673 area->width = list->cell_width - list->cell_x_pad;
674 area->height = list->cell_height - list->cell_y_pad;
675
676 return TRUE;
677 }
678
679
680 static void
gimv_zlist_draw_horizontal_list(GtkWidget * widget,GdkRectangle * area)681 gimv_zlist_draw_horizontal_list (GtkWidget *widget, GdkRectangle *area)
682 {
683 GimvZList *list;
684 gpointer *cell;
685 GdkRectangle cell_area, intersect_area;
686 gint first_row, last_row;
687 gint first_column, last_column;
688 gint i, j, idx, c;
689
690 list = GIMV_ZLIST (widget);
691
692 first_column = CELL_COL_FROM_X(list, area->x);
693 first_column = CLAMP(first_column, 0, list->columns);
694 last_column = CELL_COL_FROM_X(list, area->x + area->width) + 1;
695 last_column = CLAMP(last_column, 0, list->columns);
696
697 first_row = CELL_ROW_FROM_Y(list, area->y);
698 first_row = CLAMP(first_row, 0, list->rows);
699 last_row = CELL_ROW_FROM_Y(list, area->y + area->height) + 1;
700 last_row = CLAMP(last_row, 0, list->rows);
701
702 /* clear the padding area (bottom & top) */
703 c = list->y_pad - area->y;
704 if (c > 0)
705 gdk_window_clear_area (widget->window,
706 area->x, area->y,
707 area->width, c);
708
709 c = area->y + area->height - (LIST_HEIGHT(list) + list->y_pad);
710 if (c > 0)
711 gdk_window_clear_area (widget->window,
712 area->x, area->y + area->height - c,
713 area->width, c);
714
715
716 for (j = first_column; j < last_column; j++) {
717
718 /* clear the cell vertical padding */
719 if (list->cell_x_pad)
720 gdk_window_clear_area (widget->window,
721 CELL_X_FROM_COL(list, j), area->y,
722 list->cell_x_pad, area->height);
723
724 idx = j * list->rows + first_row;
725 for (i = first_row; i < last_row; i++, idx++) {
726
727 /* clear the cell horizontal padding */
728 if (list->cell_y_pad)
729 gdk_window_clear_area (widget->window,
730 area->x, CELL_Y_FROM_ROW(list, i),
731 area->width, list->cell_y_pad);
732
733 cell_area.x = CELL_X_FROM_COL(list, j) + list->cell_x_pad;
734 cell_area.y = CELL_Y_FROM_ROW(list, i) + list->cell_y_pad;
735 cell_area.width = list->cell_width - list->cell_x_pad;
736 cell_area.height = list->cell_height - list->cell_y_pad;
737
738 if (gdk_rectangle_intersect (area, &cell_area, &intersect_area)) {
739 if (idx < list->cell_count) {
740 cell = GIMV_ZLIST_CELL_FROM_INDEX (list, idx);
741
742 #ifdef USE_GTK2
743 g_signal_emit (G_OBJECT(list), gimv_zlist_signals [CELL_DRAW], 0,
744 cell, &cell_area, &intersect_area);
745 #else /* USE_GTK2 */
746 gtk_signal_emit (GTK_OBJECT(list), gimv_zlist_signals [CELL_DRAW],
747 cell, &cell_area, &intersect_area);
748 #endif /* USE_GTK2 */
749 } else {
750 gdk_window_clear_area (widget->window,
751 intersect_area.x, intersect_area.y,
752 intersect_area.width, intersect_area.height);
753 }
754 }
755 } /* rows loop */
756 } /* columns loop */
757
758 /* clear the right of the list XXX should hasppen */
759 c = area->x + area->width - CELL_X_FROM_COL(list, j);
760 if (c > 0)
761 gdk_window_clear_area (widget->window,
762 CELL_X_FROM_COL(list, j), area->y,
763 c, area->height);
764 /* clear the bottom of the list */
765 c = area->y + area->height - CELL_Y_FROM_ROW(list, last_row);
766 if (c > 0)
767 gdk_window_clear_area (widget->window,
768 area->x, CELL_Y_FROM_ROW(list, last_row),
769 area->width, c);
770 }
771
772
773 static void
gimv_zlist_draw_vertical_list(GtkWidget * widget,GdkRectangle * area)774 gimv_zlist_draw_vertical_list (GtkWidget *widget, GdkRectangle *area)
775 {
776 GimvZList *list;
777 gpointer *cell;
778 GdkRectangle cell_area, intersect_area;
779 gint first_row, last_row;
780 gint first_column, last_column;
781 gint i, j, idx, c;
782
783 list = GIMV_ZLIST (widget);
784
785 first_column = CELL_COL_FROM_X(list, area->x);
786 first_column = CLAMP(first_column, 0, list->columns);
787 last_column = CELL_COL_FROM_X(list, area->x + area->width) + 1;
788 last_column = CLAMP(last_column, 0, list->columns);
789
790 first_row = CELL_ROW_FROM_Y(list, area->y);
791 first_row = CLAMP(first_row, 0, list->rows);
792 last_row = CELL_ROW_FROM_Y(list, area->y + area->height) + 1;
793 last_row = CLAMP(last_row, 0, list->rows);
794
795 /* clear the padding area (right & left) */
796 c = list->x_pad - area->x;
797 if (c > 0)
798 gdk_window_clear_area (widget->window,
799 area->x, area->y,
800 c, area->height);
801
802 c = area->x + area->width - (LIST_WIDTH(list) + list->x_pad);
803 if (c > 0)
804 gdk_window_clear_area (widget->window,
805 area->x + area->width - c, area->y,
806 c, area->height);
807
808 for (i = first_row; i < last_row; i++) {
809
810 /* clear the cell horizontal padding */
811 if (list->cell_y_pad)
812 gdk_window_clear_area (widget->window,
813 area->x, CELL_Y_FROM_ROW(list, i),
814 area->width, list->cell_y_pad);
815
816 idx = i * list->columns + first_column;
817 for (j = first_column; j < last_column; j++, idx++) {
818
819 /* clear the cell vertical padding */
820 if (list->cell_x_pad)
821 gdk_window_clear_area (widget->window,
822 CELL_X_FROM_COL(list, j), area->y,
823 list->cell_x_pad, area->height);
824
825 cell_area.x = CELL_X_FROM_COL(list, j) + list->cell_x_pad;
826 cell_area.y = CELL_Y_FROM_ROW(list, i) + list->cell_y_pad;
827 cell_area.width = list->cell_width - list->cell_x_pad;
828 cell_area.height = list->cell_height - list->cell_y_pad;
829
830 if (gdk_rectangle_intersect (area, &cell_area, &intersect_area)) {
831 if (idx < list->cell_count) {
832 cell = GIMV_ZLIST_CELL_FROM_INDEX (list, idx);
833
834 #ifdef USE_GTK2
835 g_signal_emit (G_OBJECT(list), gimv_zlist_signals [CELL_DRAW], 0,
836 cell, &cell_area, &intersect_area);
837 #else /* USE_GTK2 */
838 gtk_signal_emit (GTK_OBJECT(list), gimv_zlist_signals [CELL_DRAW],
839 cell, &cell_area, &intersect_area);
840 #endif /* USE_GTK2 */
841 } else {
842 gdk_window_clear_area (widget->window,
843 intersect_area.x, intersect_area.y,
844 intersect_area.width, intersect_area.height);
845 }
846 }
847 } /* columns loop */
848 } /* rows loop */
849
850 /* clear the right of the list XXX should hasppen */
851 c = area->x + area->width - CELL_X_FROM_COL(list, last_column);
852 if (c > 0)
853 gdk_window_clear_area (widget->window,
854 CELL_X_FROM_COL(list, last_column), area->y,
855 c, area->height);
856 /* clear the bottom of the list */
857 c = area->y + area->height - CELL_Y_FROM_ROW(list, i);
858 if (c > 0)
859 gdk_window_clear_area (widget->window,
860 area->x, CELL_Y_FROM_ROW(list, i),
861 area->width, c);
862 }
863
864
865 static void
gimv_zlist_draw_selection_region(GimvZList * list,GdkRectangle * area)866 gimv_zlist_draw_selection_region (GimvZList *list, GdkRectangle *area)
867 {
868 GtkWidget *widget;
869 GimvScrolled *scrolled;
870 GtkAdjustment *hadj, *vadj;
871 GdkRectangle widget_area, region_area, draw_area;
872 gint ds_vx, ds_vy, de_vx, de_vy;
873 gchar dash[] = {2, 1};
874
875 widget = GTK_WIDGET (list);
876 scrolled = GIMV_SCROLLED (list);
877
878 hadj = scrolled->h_adjustment;
879 vadj = scrolled->v_adjustment;
880
881 ds_vx = scrolled->drag_start_vx;
882 ds_vy = scrolled->drag_start_vy;
883 de_vx = GIMV_SCROLLED_VX (scrolled, scrolled->drag_motion_x);
884 de_vy = GIMV_SCROLLED_VY (scrolled, scrolled->drag_motion_y);
885
886 region_area.x = GIMV_SCROLLED_X (list, MIN (ds_vx, de_vx));
887 region_area.y = GIMV_SCROLLED_Y (list, MIN (ds_vy, de_vy));
888 region_area.width = abs (de_vx - ds_vx);
889 region_area.height = abs (de_vy - ds_vy);
890
891 widget_area.x = widget_area.y = 0;
892 widget_area.width = widget->allocation.width;
893 widget_area.height = widget->allocation.height;
894
895 if (!gdk_rectangle_intersect (&widget_area, ®ion_area, &draw_area))
896 return;
897
898 if (!list->region_line_gc) {
899 list->region_line_gc = gdk_gc_new (widget->window);
900 gdk_gc_copy (list->region_line_gc, widget->style->black_gc);
901 gdk_gc_set_line_attributes (list->region_line_gc, 1,
902 GDK_LINE_ON_OFF_DASH,
903 GDK_CAP_NOT_LAST,
904 GDK_JOIN_MITER);
905 gdk_gc_set_dashes (list->region_line_gc, 0, dash, 2);
906 }
907
908 gdk_draw_rectangle (widget->window,
909 list->region_line_gc,
910 FALSE,
911 draw_area.x, draw_area.y,
912 draw_area.width, draw_area.height);
913 }
914
915
916 static void
gimv_zlist_draw(GtkWidget * widget,GdkRectangle * area)917 gimv_zlist_draw (GtkWidget *widget, GdkRectangle *area)
918 {
919 GimvZList *list;
920 GimvScrolled *scr;
921 GdkRectangle list_area;
922
923 list = GIMV_ZLIST(widget);
924 scr = GIMV_SCROLLED(widget);
925
926 if (!GTK_WIDGET_DRAWABLE(widget) || scr->freeze_count)
927 return;
928
929 list_area.x = list_area.y = 0;
930 /* xxx */
931 list_area.width = widget->allocation.width;
932 list_area.height = widget->allocation.height;
933
934 if (!area)
935 area = &list_area;
936
937 if (!list->cell_count) {
938 gdk_window_clear_area (widget->window,
939 area->x, area->y,
940 area->width, area->height);
941 return;
942 }
943
944 if (list->flags & GIMV_ZLIST_HORIZONTAL) {
945 gimv_zlist_draw_horizontal_list (widget, area);
946 } else {
947 gimv_zlist_draw_vertical_list (widget, area);
948 }
949
950 if (list->focus > -1)
951 gimv_zlist_cell_draw_focus (list, list->focus);
952
953 if (list->region_select)
954 gimv_zlist_draw_selection_region (list, area);
955
956 if (list->flags & GIMV_ZLIST_HIGHLIGHTED)
957 gimv_zlist_highlight (widget);
958 }
959
960
961 static void
gimv_zlist_redraw_selection_region(GtkWidget * widget,gint prev_x,gint prev_y,gint next_x,gint next_y)962 gimv_zlist_redraw_selection_region (GtkWidget *widget,
963 gint prev_x, gint prev_y,
964 gint next_x, gint next_y)
965 {
966 GimvScrolled *scrolled;
967 GdkRectangle widget_area, area, draw_area;
968 gint start_x, start_y;
969 gint low, high;
970
971 scrolled = GIMV_SCROLLED (widget);
972
973 start_x = GIMV_SCROLLED_X (scrolled, scrolled->drag_start_vx);
974 start_y = GIMV_SCROLLED_Y (scrolled, scrolled->drag_start_vy);
975
976 widget_area.x = widget_area.y = 0;
977 widget_area.width = widget->allocation.width;
978 widget_area.height = widget->allocation.height;
979
980 /* horizontal line */
981 low = MIN (start_x, prev_x);
982 high = MAX (start_x, prev_x);
983 area.x = low - 1;
984 area.y = start_y - 1;
985 area.width = high - area.x + 3;
986 area.height = 3;
987 if (gdk_rectangle_intersect (&widget_area, &area, &draw_area))
988 gimv_zlist_draw (widget, &draw_area);
989
990 area.y = prev_y - 1;
991 if (gdk_rectangle_intersect (&widget_area, &area, &draw_area))
992 gimv_zlist_draw (widget, &draw_area);
993
994 /* vertical line */
995 low = MIN (start_y, prev_y);
996 high = MAX (start_y, prev_y);
997 area.x = start_x - 1;
998 area.y = low - 1;
999 area.width = 3;
1000 area.height = high - area.y + 3;
1001 if (gdk_rectangle_intersect (&widget_area, &area, &draw_area))
1002 gimv_zlist_draw (widget, &draw_area);
1003
1004 area.x = prev_x - 1;
1005 if (gdk_rectangle_intersect (&widget_area, &area, &draw_area))
1006 gimv_zlist_draw (widget, &draw_area);
1007 }
1008
1009
1010 static gint
gimv_zlist_button_press(GtkWidget * widget,GdkEventButton * event)1011 gimv_zlist_button_press (GtkWidget *widget, GdkEventButton *event)
1012 {
1013 GimvZList *list;
1014 gpointer *cell;
1015 gint retval = FALSE, idx;
1016
1017 list = GIMV_ZLIST(widget);
1018
1019 /* grab focus */
1020 if (!GTK_WIDGET_HAS_FOCUS(list))
1021 gtk_widget_grab_focus (widget);
1022
1023 /* call parent method */
1024 if (parent_class->button_press_event)
1025 retval = parent_class->button_press_event (widget, event);
1026
1027 list->region_select = GIMV_ZLIST_REGION_SELECT_OFF;
1028
1029 if (event->type != GDK_BUTTON_PRESS ||
1030 event->button != 1 ||
1031 event->window != widget->window)
1032 {
1033 return retval || FALSE;
1034 }
1035
1036 /* get the selected cell's index */
1037 idx = gimv_zlist_cell_index_from_xy (list, event->x, event->y);
1038
1039 /* set to region select mode */
1040 if (idx < 0) {
1041 if (event->state & GDK_CONTROL_MASK) { /* toggle mode */
1042 list->region_select = GIMV_ZLIST_REGION_SELECT_TOGGLE;
1043 gimv_zlist_set_selection_mask (list, NULL);
1044 } else if (event->state & GDK_SHIFT_MASK) { /* expand mode */
1045 list->region_select = GIMV_ZLIST_REGION_SELECT_EXPAND;
1046 gimv_zlist_set_selection_mask (list, NULL);
1047 } else {
1048 list->region_select = GIMV_ZLIST_REGION_SELECT_NORMAL;
1049 gimv_zlist_unselect_all (list);
1050 }
1051
1052 } else {
1053 /* get the selected cell */
1054 cell = GIMV_ZLIST_CELL_FROM_INDEX (list, idx);
1055
1056 /* set focus */
1057 if (list->focus != idx) {
1058 if (list->focus > -1)
1059 gimv_zlist_cell_draw_default (list, list->focus);
1060 list->focus = idx;
1061 }
1062
1063 /* set to the DnD mode */
1064 if (list->flags & GIMV_ZLIST_USES_DND
1065 && g_list_find (list->selection, GUINT_TO_POINTER(idx)))
1066 {
1067 list->anchor = idx;
1068 gimv_zlist_cell_draw_focus (list, idx);
1069 return retval || FALSE;
1070 }
1071
1072 /* set selection */
1073 switch (list->selection_mode) {
1074 case GTK_SELECTION_SINGLE:
1075 #ifndef USE_GTK2
1076 case GTK_SELECTION_MULTIPLE:
1077 #endif
1078 list->anchor = idx;
1079 gimv_zlist_cell_draw_focus (list, idx);
1080 break;
1081
1082 case GTK_SELECTION_BROWSE:
1083 gimv_zlist_unselect_all (list);
1084 gimv_zlist_cell_select (list, idx);
1085 break;
1086
1087 case GTK_SELECTION_EXTENDED:
1088 if (event->state & GDK_CONTROL_MASK) {
1089 list->anchor = idx;
1090 gimv_zlist_cell_toggle (list, idx);
1091 } else if (event->state & GDK_SHIFT_MASK) {
1092 gimv_zlist_extend_selection (list, idx);
1093 } else {
1094 list->anchor = idx;
1095
1096 if (!g_list_find (list->selection, GUINT_TO_POINTER(idx))) {
1097 gimv_zlist_unselect_all (list);
1098 gimv_zlist_cell_select (list, idx);
1099 }
1100 }
1101 break;
1102
1103 default:
1104 break;
1105 }
1106 }
1107
1108 if (gdk_pointer_grab (widget->window, FALSE,
1109 GDK_POINTER_MOTION_HINT_MASK |
1110 GDK_BUTTON1_MOTION_MASK |
1111 GDK_BUTTON_RELEASE_MASK,
1112 NULL, NULL, event->time))
1113 return retval || FALSE;
1114
1115 gtk_grab_add (widget);
1116
1117 return retval || FALSE;
1118 }
1119
1120
1121 static gint
gimv_zlist_button_release(GtkWidget * widget,GdkEventButton * event)1122 gimv_zlist_button_release (GtkWidget *widget, GdkEventButton *event)
1123 {
1124 GimvZList *list;
1125 gpointer *cell;
1126 gint retval = FALSE, index;
1127
1128 list = GIMV_ZLIST(widget);
1129
1130 /* call parent class callback */
1131 if (parent_class->button_release_event)
1132 retval = parent_class->button_release_event (widget, event);
1133
1134 if (GTK_WIDGET_HAS_GRAB(widget))
1135 gtk_grab_remove (widget);
1136
1137 if (gdk_pointer_is_grabbed ())
1138 gdk_pointer_ungrab (event->time);
1139
1140 index = gimv_zlist_cell_index_from_xy (list, event->x, event->y);
1141 if (index < 0) goto FUNC_END;
1142
1143 cell = GIMV_ZLIST_CELL_FROM_INDEX (list, index);
1144
1145 switch (list->selection_mode) {
1146 case GTK_SELECTION_SINGLE:
1147 if (list->anchor == index) {
1148 list->focus = index;
1149 gimv_zlist_unselect_all (list);
1150 gimv_zlist_cell_toggle (list, index);
1151 }
1152 list->anchor = index;
1153 break;
1154
1155 #ifndef USE_GTK2
1156 case GTK_SELECTION_MULTIPLE:
1157 if (list->anchor == index) {
1158 list->focus = index;
1159 gimv_zlist_cell_toggle (list, index);
1160 }
1161 list->anchor = index;
1162 break;
1163 #endif
1164
1165 case GTK_SELECTION_EXTENDED:
1166 if (event->state & GDK_CONTROL_MASK) {
1167 } else if (event->state & GDK_SHIFT_MASK) {
1168 } else {
1169 if (event->button == 1 && !list->region_select) {
1170 gimv_zlist_unselect_all (list);
1171 gimv_zlist_cell_select (list, index);
1172 }
1173 }
1174
1175 if ((list->flags & GIMV_ZLIST_USES_DND)) {
1176 gint x, y;
1177
1178 /* on a drag-drop event, the event->x & event->y always seem to be 0 */
1179 gdk_window_get_pointer (widget->window, &x, &y, NULL);
1180 index = gimv_zlist_cell_index_from_xy (list, x, y);
1181 if (index < 0) goto FUNC_END;
1182 /*
1183 if (list->anchor == index)
1184 gimv_zlist_extend_selection (list, list->focus);
1185 */
1186 }
1187
1188 list->anchor = list->focus;
1189 break;
1190
1191 default:
1192 break;
1193 }
1194
1195 FUNC_END:
1196
1197 /* unset region select */
1198 if (list->region_select)
1199 gimv_zlist_draw (widget, NULL);
1200 gimv_zlist_unset_selection_mask (list);
1201 list->region_select = GIMV_ZLIST_REGION_SELECT_OFF;
1202
1203 return retval || FALSE;
1204 }
1205
1206
1207 static gint
gimv_zlist_motion_notify(GtkWidget * widget,GdkEventMotion * event)1208 gimv_zlist_motion_notify (GtkWidget *widget, GdkEventMotion *event)
1209 {
1210 GimvScrolled *scrolled;
1211 GimvZList *list;
1212 gpointer *cell;
1213 gint index, x, y, retval = FALSE;
1214
1215 gint start_x, start_y, end_x, end_y, prev_x = 0, prev_y = 0;
1216 gint flags;
1217 gboolean pressed;
1218
1219 list = GIMV_ZLIST(widget);
1220 scrolled = GIMV_SCROLLED (widget);
1221
1222 flags = scrolled->autoscroll_flags;
1223 pressed = scrolled->pressed;
1224
1225 index = gimv_zlist_cell_index_from_xy (list, x, y);
1226
1227 if (list->region_select) {
1228 prev_x = scrolled->drag_motion_x;
1229 prev_y = scrolled->drag_motion_y;
1230 }
1231
1232 /* call parent class callback */
1233 if (parent_class->motion_notify_event)
1234 retval = parent_class->motion_notify_event (widget, event);
1235
1236 if (list->region_select) {
1237 if ((pressed && (flags & GIMV_SCROLLED_AUTO_SCROLL_MOTION))
1238 || (flags & GIMV_SCROLLED_AUTO_SCROLL_MOTION_ALL))
1239 {
1240 start_x = MIN (scrolled->drag_start_vx, GIMV_SCROLLED_VX (scrolled, event->x));
1241 start_y = MIN (scrolled->drag_start_vy, GIMV_SCROLLED_VY (scrolled, event->y));
1242 end_x = MAX (scrolled->drag_start_vx, GIMV_SCROLLED_VX (scrolled, event->x));
1243 end_y = MAX (scrolled->drag_start_vy, GIMV_SCROLLED_VY (scrolled, event->y));
1244
1245 gimv_zlist_cell_select_by_pixel_region (list,
1246 start_x, start_y,
1247 end_x, end_y);
1248
1249 gimv_zlist_redraw_selection_region (widget,
1250 prev_x, prev_y,
1251 event->x, event->y);
1252 }
1253 }
1254
1255 if (list->flags & GIMV_ZLIST_USES_DND) return retval || FALSE;
1256
1257 gdk_window_get_pointer (widget->window, &x, &y, NULL);
1258
1259 index = gimv_zlist_cell_index_from_xy (list, x, y);
1260 if (index < 0) return retval || FALSE;
1261
1262
1263 cell = GIMV_ZLIST_CELL_FROM_INDEX (list, index);
1264
1265 if (gdk_pointer_is_grabbed() && GTK_WIDGET_HAS_GRAB(widget)) {
1266
1267 if (index == list->focus) return retval || FALSE;
1268
1269 gimv_zlist_cell_draw_default (list, list->focus);
1270 list->focus = index;
1271
1272 switch (list->selection_mode) {
1273 case GTK_SELECTION_SINGLE:
1274 #ifndef USE_GTK2
1275 case GTK_SELECTION_MULTIPLE:
1276 #endif
1277 gimv_zlist_cell_draw_focus (list, index);
1278 break;
1279
1280 case GTK_SELECTION_BROWSE:
1281 gimv_zlist_unselect_all (list);
1282 gimv_zlist_cell_select (list, index);
1283 break;
1284
1285 #if 0
1286 case GTK_SELECTION_EXTENDED:
1287 if (event->state & GDK_CONTROL_MASK) {
1288 list->anchor = index;
1289 gimv_zlist_cell_toggle (list, index);
1290 } else {
1291 gimv_zlist_extend_selection (list, index);
1292 }
1293 break;
1294 #endif
1295
1296 default:
1297 break;
1298 }
1299 } else {
1300 }
1301
1302 return retval || FALSE;
1303 }
1304
1305 /*
1306 * GtkContainers doesn't seem to forward the focus movement to
1307 * containers which don't have child widgets
1308 *
1309 */
1310
1311 static gint
gimv_zlist_key_press(GtkWidget * widget,GdkEventKey * event)1312 gimv_zlist_key_press (GtkWidget *widget, GdkEventKey *event)
1313 {
1314 gint direction = -1;
1315
1316 g_return_val_if_fail (widget && event, FALSE);
1317
1318 if (GTK_WIDGET_HAS_FOCUS (widget)) {
1319 switch (event->keyval) {
1320 case GDK_Up:
1321 direction = GTK_DIR_UP;
1322 break;
1323 case GDK_Down:
1324 direction = GTK_DIR_DOWN;
1325 break;
1326 case GDK_Left:
1327 direction = GTK_DIR_LEFT;
1328 break;
1329 case GDK_Right:
1330 direction = GTK_DIR_RIGHT;
1331 break;
1332 /*
1333 case GDK_Tab:
1334 case GDK_ISO_Left_Tab:
1335 if (event->state & GDK_SHIFT_MASK)
1336 direction = GTK_DIR_TAB_BACKWARD;
1337 else
1338 direction = GTK_DIR_TAB_FORWARD;
1339 break;
1340 */
1341 case GDK_Page_Up:
1342 gimv_scrolled_page_up (GIMV_SCROLLED (widget));
1343 break;
1344 case GDK_Page_Down:
1345 gimv_scrolled_page_down (GIMV_SCROLLED (widget));
1346 break;
1347 default:
1348 break;
1349 }
1350 }
1351
1352 if (direction != -1) {
1353 gimv_zlist_focus (GTK_CONTAINER(widget), direction);
1354 return FALSE;
1355 }
1356
1357 if (parent_class->key_press_event &&
1358 (* parent_class->key_press_event) (widget, event))
1359 return TRUE;
1360
1361 return FALSE;
1362 }
1363
1364
1365 static gint
gimv_zlist_focus_in(GtkWidget * widget,GdkEventFocus * event)1366 gimv_zlist_focus_in (GtkWidget *widget, GdkEventFocus *event)
1367 {
1368 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
1369
1370 #ifndef USE_GTK2
1371 gtk_widget_draw_focus (widget);
1372 #endif
1373
1374 return FALSE;
1375 }
1376
1377
1378 static gint
gimv_zlist_focus_out(GtkWidget * widget,GdkEventFocus * event)1379 gimv_zlist_focus_out (GtkWidget *widget, GdkEventFocus *event)
1380 {
1381 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
1382
1383 #ifndef USE_GTK2
1384 gtk_widget_draw_default (widget);
1385 #endif
1386
1387 return FALSE;
1388 }
1389
1390
1391 static gint
gimv_zlist_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time)1392 gimv_zlist_drag_motion (GtkWidget *widget,
1393 GdkDragContext *context,
1394 gint x,
1395 gint y,
1396 guint time)
1397 {
1398 GimvZList *list;
1399 gint index, retval = FALSE;
1400
1401 g_return_val_if_fail (widget, FALSE);
1402
1403 if (parent_class->button_press_event)
1404 retval = parent_class->drag_motion (widget, context, x, y, time);
1405
1406 list = GIMV_ZLIST(widget);
1407
1408 if (!(list->flags & GIMV_ZLIST_USES_DND))
1409 return retval || FALSE;
1410
1411 if (!(list->flags & GIMV_ZLIST_HIGHLIGHTED)) {
1412 list->flags |= GIMV_ZLIST_HIGHLIGHTED;
1413 gimv_zlist_highlight (widget);
1414 }
1415
1416 index = gimv_zlist_cell_index_from_xy (GIMV_ZLIST(widget), x, y);
1417 if (index < 0)
1418 return retval || FALSE;
1419 /*
1420 if (g_list_find (ZLIST(widget)->selection, GUINT_TO_POINTER(index)))
1421 return TRUE;
1422 */
1423 return retval || FALSE;
1424 }
1425
1426
1427 static gint
gimv_zlist_drag_drop(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time)1428 gimv_zlist_drag_drop (GtkWidget *widget,
1429 GdkDragContext *context,
1430 gint x,
1431 gint y,
1432 guint time)
1433 {
1434 GimvZList *list;
1435
1436 list = GIMV_ZLIST(widget);
1437
1438 if (!(list->flags & GIMV_ZLIST_USES_DND))
1439 return FALSE;
1440
1441 return FALSE;
1442 }
1443
1444
1445 static void
gimv_zlist_drag_leave(GtkWidget * widget,GdkDragContext * context,guint time)1446 gimv_zlist_drag_leave (GtkWidget *widget,
1447 GdkDragContext *context,
1448 guint time)
1449 {
1450 GimvZList *list;
1451
1452 if (parent_class->drag_leave)
1453 parent_class->drag_leave (widget, context, time);
1454
1455 list = GIMV_ZLIST(widget);
1456 if (list->flags & GIMV_ZLIST_HIGHLIGHTED) {
1457 list->flags &= ~GIMV_ZLIST_HIGHLIGHTED;
1458 gimv_zlist_unhighlight (widget);
1459 }
1460 }
1461
1462 static void
gimv_zlist_highlight(GtkWidget * widget)1463 gimv_zlist_highlight (GtkWidget *widget)
1464 {
1465 #ifdef USE_GTK2
1466 gtk_paint_shadow (widget->style,
1467 widget->window,
1468 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
1469 NULL, NULL, NULL,
1470 0, 0,
1471 widget->allocation.width - 2 * bw (widget),
1472 widget->allocation.height - 2 * bw (widget));
1473 #else /* USE_GTK2 */
1474 gtk_draw_shadow (widget->style,
1475 widget->window,
1476 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
1477 0, 0,
1478 widget->allocation.width - 2 * bw (widget),
1479 widget->allocation.height - 2 * bw (widget));
1480 #endif /* USE_GTK2 */
1481
1482 gdk_draw_rectangle (widget->window,
1483 widget->style->black_gc,
1484 FALSE,
1485 0, 0,
1486 widget->allocation.width - 2 * bw (widget) - 1,
1487 widget->allocation.height - 2 * bw (widget) - 1);
1488
1489 }
1490
1491
1492 static void
gimv_zlist_unhighlight(GtkWidget * widget)1493 gimv_zlist_unhighlight (GtkWidget *widget)
1494 {
1495 GdkRectangle area;
1496
1497 area.x = 0; area.y = 0;
1498 area.width = HIGHLIGHT_SIZE;
1499 area.height = widget->allocation.height - 2 * bw (widget);
1500 WIDGET_DRAW_AREA (widget, &area);
1501
1502 area.width = widget->allocation.width - 2 * bw (widget);
1503 area.height = HIGHLIGHT_SIZE;
1504 WIDGET_DRAW_AREA (widget, &area);
1505
1506 area.y = widget->allocation.height - 2 * bw (widget) - HIGHLIGHT_SIZE;
1507 WIDGET_DRAW_AREA (widget, &area);
1508
1509 area.x = widget->allocation.width - 2 * bw (widget) - HIGHLIGHT_SIZE;
1510 area.y = 0;
1511 area.width = HIGHLIGHT_SIZE;
1512 area.height = widget->allocation.height - 2 * bw (widget);
1513 WIDGET_DRAW_AREA (widget, &area);
1514 }
1515
1516
1517 static void
gimv_zlist_forall(GtkContainer * container,gboolean include_internals,GtkCallback callback,gpointer callback_data)1518 gimv_zlist_forall (GtkContainer *container,
1519 gboolean include_internals,
1520 GtkCallback callback,
1521 gpointer callback_data)
1522 {
1523 /*
1524 GimvZList *list;
1525 gint i;
1526
1527 list = ZLIST(container);
1528
1529 if (include_internals)
1530 for (i = 0; i < list->cell_count; i++)
1531 (* callback) (GIMV_ZLIST_CELL_FROM_INDEX (list, i), callback_data);
1532 */
1533 }
1534
1535
1536 static gint
gimv_zlist_focus(GtkContainer * container,GtkDirectionType dir)1537 gimv_zlist_focus (GtkContainer *container, GtkDirectionType dir)
1538 {
1539 GimvZList *list;
1540 gint focus;
1541
1542 list = GIMV_ZLIST(container);
1543
1544 if (list->focus < 0)
1545 return FALSE;
1546
1547 focus = list->focus;
1548 switch (dir) {
1549 case GTK_DIR_LEFT:
1550 focus -= list->flags & GIMV_ZLIST_HORIZONTAL ? list->rows : 1;
1551 break;
1552 case GTK_DIR_RIGHT:
1553 focus += list->flags & GIMV_ZLIST_HORIZONTAL ? list->rows : 1;
1554 break;
1555 case GTK_DIR_UP:
1556 case GTK_DIR_TAB_BACKWARD:
1557 focus -= list->flags & GIMV_ZLIST_HORIZONTAL ? 1 : list->columns;
1558 break;
1559 case GTK_DIR_DOWN:
1560 case GTK_DIR_TAB_FORWARD:
1561 focus += list->flags & GIMV_ZLIST_HORIZONTAL ? 1 : list->columns;
1562 break;
1563 default:
1564 return FALSE;
1565 break;
1566 }
1567
1568 if (focus < 0 || focus >= list->cell_count)
1569 return FALSE;
1570
1571 gimv_zlist_cell_draw_default (list, list->focus);
1572 list->focus = focus;
1573 gimv_zlist_cell_draw_focus (list, focus);
1574 gimv_zlist_moveto (list, focus);
1575
1576 return TRUE;
1577 }
1578
1579
1580 guint
gimv_zlist_add(GimvZList * list,gpointer cell)1581 gimv_zlist_add (GimvZList *list, gpointer cell)
1582 {
1583 g_return_val_if_fail (GIMV_IS_ZLIST (list), 0);
1584
1585 return gimv_zlist_insert (list, list->cells->len, cell);
1586 }
1587
1588
1589 guint
gimv_zlist_insert(GimvZList * list,guint pos,gpointer cell)1590 gimv_zlist_insert (GimvZList *list, guint pos, gpointer cell)
1591 {
1592 GtkRequisition requisition = { 0 };
1593 gint adjust = FALSE;
1594
1595 g_return_val_if_fail (GIMV_IS_ZLIST (list), 0);
1596
1597 if (pos > list->cells->len)
1598 pos = list->cells->len;
1599 list->cells = g_array_insert_val (list->cells, pos, cell);
1600
1601 #ifdef USE_GTK2
1602 g_signal_emit (G_OBJECT(list), gimv_zlist_signals [CELL_SIZE_REQUEST], 0,
1603 cell, &requisition);
1604 #else /* USE_GTK2 */
1605 gtk_signal_emit (GTK_OBJECT(list), gimv_zlist_signals [CELL_SIZE_REQUEST],
1606 cell, &requisition);
1607 #endif /* USE_GTK2 */
1608
1609 if (list->flags & GIMV_ZLIST_HORIZONTAL) {
1610 if (list->cell_count && list->cell_count % list->rows == 0) {
1611 list->columns++;
1612 adjust = TRUE;
1613 }
1614 } else {
1615 if (list->cell_count && list->cell_count % list->columns == 0) {
1616 list->rows ++;
1617 adjust = TRUE;
1618 }
1619 }
1620
1621 list->cell_count++;
1622
1623 if (requisition.width + list->cell_x_pad > list->cell_width ||
1624 requisition.height + list->cell_y_pad > list->cell_height)
1625 {
1626 list->cell_width
1627 = MAX(list->cell_width, requisition.width + list->cell_x_pad);
1628 list->cell_height
1629 = MAX(list->cell_height, requisition.height + list->cell_y_pad);
1630
1631 gimv_zlist_update (list);
1632 WIDGET_DRAW (GTK_WIDGET (list));
1633
1634 } else {
1635
1636 if (adjust)
1637 gimv_zlist_adjust_adjustments (GIMV_SCROLLED(list));
1638
1639 gimv_zlist_update (list);
1640 gimv_zlist_draw_cell (list, list->cell_count - 1);
1641 }
1642
1643 return pos;
1644 }
1645
1646
1647 void
gimv_zlist_remove(GimvZList * list,gpointer cell)1648 gimv_zlist_remove (GimvZList *list, gpointer cell)
1649 {
1650 GdkRectangle area;
1651 GList *item;
1652 gint index, *i;
1653
1654 index = gimv_zlist_cell_index (list, cell);
1655 if (index == -1)
1656 return;
1657
1658 list->cells = g_array_remove_index (list->cells, index);
1659 list->cell_count --;
1660
1661 list->selection = g_list_remove (list->selection, GUINT_TO_POINTER(index));
1662 item = list->selection;
1663 while (item) {
1664 i = (guint *) &item->data;
1665 if (*i > index)
1666 *i -= 1;
1667 item = item->next;
1668 }
1669
1670 if (list->focus == index)
1671 list->focus = -1;
1672 else if (list->focus > index)
1673 list->focus --;
1674
1675 if (list->anchor == index)
1676 list->anchor = -1;
1677 else if (list->anchor > index)
1678 list->anchor --;
1679
1680 if ((list->flags & GIMV_ZLIST_HORIZONTAL) && list->cell_count % list->rows == 0) {
1681 list->columns --;
1682 gimv_zlist_adjust_adjustments (GIMV_SCROLLED(list));
1683 } else if (!(list->flags & GIMV_ZLIST_HORIZONTAL) && list->cell_count % list->columns == 0) {
1684 list->rows --;
1685 gimv_zlist_adjust_adjustments (GIMV_SCROLLED(list));
1686 }
1687
1688 gimv_zlist_cell_area (list, index, &area);
1689
1690 /* using gdk_window_copy_area will be faster but harder too */
1691 area.width = GTK_WIDGET(list)->allocation.width - area.x;
1692 area.height = GTK_WIDGET(list)->allocation.height - area.y;
1693
1694 gimv_zlist_update (list);
1695 gimv_zlist_draw (GTK_WIDGET(list), &area);
1696
1697 if (list->flags & GIMV_ZLIST_HORIZONTAL) {
1698 area.width -= list->cell_width;
1699 area.height = area.y;
1700 area.x += list->cell_width;
1701 area.y = 0;
1702 } else {
1703 area.width = area.x;
1704 area.height -= list->cell_height;
1705 area.x = 0;
1706 area.y += list->cell_height;
1707 }
1708
1709 WIDGET_DRAW_AREA (GTK_WIDGET (list), &area);
1710 }
1711
1712
1713 static void
gimv_zlist_adjust_adjustments(GimvScrolled * scrolled)1714 gimv_zlist_adjust_adjustments (GimvScrolled *scrolled)
1715 {
1716 GimvZList *list;
1717 GtkWidget *widget;
1718 GtkAdjustment *adj;
1719
1720 list = GIMV_ZLIST(scrolled);
1721 widget = GTK_WIDGET(scrolled);
1722
1723 if (!GTK_WIDGET_DRAWABLE(widget) || scrolled->freeze_count)
1724 return;
1725
1726 if (scrolled->h_adjustment) {
1727 adj = scrolled->h_adjustment;
1728
1729 adj->page_size = widget->allocation.width - 2 * bw (widget);
1730 adj->page_increment = adj->page_size;
1731 adj->step_increment = list->cell_width;
1732 adj->lower = 0;
1733 adj->upper = LIST_WIDTH(list) + 2 * list->x_pad + list->cell_x_pad;
1734
1735 #ifdef USE_GTK2
1736 g_signal_emit_by_name (G_OBJECT(adj), "changed");
1737 #else /* USE_GTK2 */
1738 gtk_signal_emit_by_name (GTK_OBJECT(adj), "changed");
1739 #endif /* USE_GTK2 */
1740 }
1741
1742 if (scrolled->v_adjustment) {
1743 adj = scrolled->v_adjustment;
1744
1745 adj->page_size = widget->allocation.height - 2 * bw (widget);
1746 adj->page_increment = adj->page_size;
1747 adj->step_increment = list->cell_height;
1748 adj->lower = 0;
1749 adj->upper = LIST_HEIGHT(list) + 2 * list->y_pad + list->cell_y_pad;
1750
1751 #ifdef USE_GTK2
1752 g_signal_emit_by_name (G_OBJECT(adj), "changed");
1753 #else /* USE_GTK2 */
1754 gtk_signal_emit_by_name (GTK_OBJECT(adj), "changed");
1755 #endif /* USE_GTK2 */
1756 }
1757 }
1758
1759
1760 void
gimv_zlist_clear(GimvZList * list)1761 gimv_zlist_clear (GimvZList *list)
1762 {
1763 GimvScrolled *scrolled;
1764
1765 g_return_if_fail (list);
1766
1767 gimv_zlist_unselect_all (list);
1768
1769 #ifdef USE_GTK2
1770 g_signal_emit (G_OBJECT(list), gimv_zlist_signals [CLEAR], 0);
1771 #else /* USE_GTK2 */
1772 gtk_signal_emit (GTK_OBJECT(list), gimv_zlist_signals [CLEAR]);
1773 #endif /* USE_GTK2 */
1774
1775 g_array_set_size (list->cells, 0);
1776 list->cell_count = 0;
1777 list->focus = -1;
1778 list->anchor = -1;
1779 list->entered_cell = NULL;
1780
1781 if (list->flags & GIMV_ZLIST_HORIZONTAL)
1782 list->columns = 1;
1783 else
1784 list->rows = 1;
1785
1786 scrolled = GIMV_SCROLLED(list);
1787 gimv_zlist_adjust_adjustments (GIMV_SCROLLED(list));
1788 scrolled->h_adjustment->value = 0;
1789 scrolled->v_adjustment->value = 0;
1790 #ifdef USE_GTK2
1791 g_signal_emit_by_name (G_OBJECT(scrolled->h_adjustment), "value_changed");
1792 g_signal_emit_by_name (G_OBJECT(scrolled->v_adjustment), "value_changed");
1793 #else /* USE_GTK2 */
1794 gtk_signal_emit_by_name (GTK_OBJECT(scrolled->h_adjustment), "value_changed");
1795 gtk_signal_emit_by_name (GTK_OBJECT(scrolled->v_adjustment), "value_changed");
1796 #endif /* USE_GTK2 */
1797
1798 gimv_zlist_draw (GTK_WIDGET(list), NULL);
1799 }
1800
1801
1802 void
gimv_zlist_set_cell_padding(GimvZList * list,gint x_pad,gint y_pad)1803 gimv_zlist_set_cell_padding (GimvZList *list, gint x_pad, gint y_pad)
1804 {
1805 g_return_if_fail (list);
1806 g_return_if_fail (x_pad >= 0 && y_pad >= 0);
1807
1808 list->cell_width += x_pad - list->cell_x_pad;
1809 list->cell_height += y_pad - list->cell_y_pad;
1810
1811 list->cell_x_pad = x_pad;
1812 list->cell_y_pad = y_pad;
1813
1814 gimv_zlist_update (list);
1815 WIDGET_DRAW (GTK_WIDGET (list));
1816 }
1817
1818
1819 void
gimv_zlist_set_cell_size(GimvZList * list,gint width,gint height)1820 gimv_zlist_set_cell_size (GimvZList *list, gint width, gint height)
1821 {
1822 g_return_if_fail (GIMV_IS_ZLIST (list));
1823
1824 if (width > 0)
1825 list->cell_width = width + list->cell_x_pad;
1826
1827 if (height > 0)
1828 list->cell_height = height + list->cell_y_pad;
1829
1830 gimv_zlist_update (list);
1831 gimv_zlist_draw (GTK_WIDGET(list), NULL);
1832 }
1833
1834
1835 void
gimv_zlist_set_selection_mode(GimvZList * list,GtkSelectionMode mode)1836 gimv_zlist_set_selection_mode (GimvZList *list, GtkSelectionMode mode)
1837 {
1838 g_return_if_fail (GIMV_IS_ZLIST (list));
1839
1840 list->selection_mode = mode;
1841 gimv_zlist_unselect_all (list);
1842 WIDGET_DRAW (GTK_WIDGET (list));
1843 }
1844
1845
1846 gint
gimv_zlist_cell_index_from_xy(GimvZList * list,gint x,gint y)1847 gimv_zlist_cell_index_from_xy (GimvZList *list, gint x, gint y)
1848 {
1849 GimvScrolled *scr;
1850 gint row, column, cell_x, cell_y, index;
1851
1852 scr = GIMV_SCROLLED(list);
1853
1854 if (!list->cell_count || x < list->x_pad || y < list->y_pad)
1855 return -1;
1856
1857 row = CELL_ROW_FROM_Y(list, y);
1858 column = CELL_COL_FROM_X(list, x);
1859
1860 if (row >= list->rows || column >= list->columns)
1861 return -1;
1862
1863 cell_x = CELL_X_FROM_COL(list, column);
1864 if (x < list->cell_x_pad * 2 + cell_x)
1865 return -1;
1866
1867 cell_y = CELL_Y_FROM_ROW(list, row);
1868 if (y < list->cell_y_pad * 2 + cell_y)
1869 return -1;
1870
1871 index = list->flags & GIMV_ZLIST_HORIZONTAL ? column * list->rows + row : row * list->columns + column;
1872
1873 return index < list->cell_count ? index : -1;
1874 }
1875
1876
1877 void
gimv_zlist_set_1(GimvZList * list,gint one)1878 gimv_zlist_set_1 (GimvZList *list, gint one)
1879 {
1880 g_return_if_fail (list);
1881
1882 if (one)
1883 list->flags |= GIMV_ZLIST_1;
1884 else
1885 list->flags &= ~GIMV_ZLIST_1;
1886
1887 gimv_zlist_update (list);
1888 WIDGET_DRAW (GTK_WIDGET (list));
1889 }
1890
1891
1892 gpointer
gimv_zlist_cell_from_xy(GimvZList * list,gint x,gint y)1893 gimv_zlist_cell_from_xy (GimvZList *list, gint x, gint y)
1894 {
1895 gint index;
1896
1897 index = gimv_zlist_cell_index_from_xy (list, x, y);
1898 return index < 0 ? NULL : GIMV_ZLIST_CELL_FROM_INDEX (list, index);
1899 }
1900
1901
1902 static void
gimv_zlist_cell_pos(GimvZList * list,gint index,gint * row,gint * col)1903 gimv_zlist_cell_pos (GimvZList *list, gint index, gint *row, gint *col)
1904 {
1905 g_return_if_fail (list && index != -1 && row && col);
1906
1907 if (list->flags & GIMV_ZLIST_HORIZONTAL) {
1908 *row = index % list->rows;
1909 *col = index / list->rows;
1910 } else {
1911 *row = index / list->columns;
1912 *col = index % list->columns;
1913 }
1914 }
1915
1916
1917 static void
gimv_zlist_cell_area(GimvZList * list,gint index,GdkRectangle * cell_area)1918 gimv_zlist_cell_area (GimvZList *list, gint index, GdkRectangle *cell_area)
1919 {
1920 gint row, col;
1921 g_return_if_fail (list && index != -1 && cell_area);
1922
1923 gimv_zlist_cell_pos (list, index, &row, &col);
1924
1925 cell_area->x = CELL_X_FROM_COL(list, col) + list->cell_x_pad;
1926 cell_area->y = CELL_Y_FROM_ROW(list, row) + list->cell_y_pad;
1927 cell_area->width = list->cell_width - list->cell_x_pad;
1928 cell_area->height = list->cell_height - list->cell_y_pad;
1929
1930 }
1931
1932
1933 void
gimv_zlist_draw_cell(GimvZList * list,gint index)1934 gimv_zlist_draw_cell (GimvZList *list, gint index)
1935 {
1936 GtkWidget *cell;
1937 GdkRectangle cell_area;
1938
1939 g_return_if_fail (list && index != -1);
1940
1941 if (!GTK_WIDGET_DRAWABLE(list))
1942 return;
1943
1944 gimv_zlist_cell_area (list, index, &cell_area);
1945 cell = GIMV_ZLIST_CELL_FROM_INDEX (list, index);
1946
1947 #ifdef USE_GTK2
1948 g_signal_emit (G_OBJECT(list), gimv_zlist_signals [CELL_DRAW], 0,
1949 cell, &cell_area, &cell_area);
1950 #else /* USE_GTK2 */
1951 gtk_signal_emit (GTK_OBJECT(list), gimv_zlist_signals [CELL_DRAW],
1952 cell, &cell_area, &cell_area);
1953 #endif /* USE_GTK2 */
1954
1955 if (index == list->focus)
1956 gimv_zlist_cell_draw_focus (list, index);
1957 }
1958
1959
1960 gint
gimv_zlist_cell_index(GimvZList * list,gpointer cell)1961 gimv_zlist_cell_index (GimvZList *list, gpointer cell)
1962 {
1963 gint i;
1964 g_return_val_if_fail (list && cell, -1);
1965
1966 for (i = 0; i < list->cell_count; i++)
1967 if (GIMV_ZLIST_CELL_FROM_INDEX (list, i) == cell)
1968 return i;
1969
1970 return -1;
1971 }
1972
1973
1974 gint
gimv_zlist_update_cell_size(GimvZList * list,gpointer cell)1975 gimv_zlist_update_cell_size (GimvZList *list, gpointer cell)
1976 {
1977 GtkRequisition requisition;
1978
1979 g_return_val_if_fail (list && cell, FALSE);
1980
1981 if (list->flags & GIMV_ZLIST_1)
1982 return FALSE;
1983
1984 #ifdef USE_GTK2
1985 g_signal_emit (G_OBJECT(list), gimv_zlist_signals [CELL_SIZE_REQUEST], 0,
1986 cell, &requisition);
1987 #else /* USE_GTK2 */
1988 gtk_signal_emit (GTK_OBJECT(list), gimv_zlist_signals [CELL_SIZE_REQUEST],
1989 cell, &requisition);
1990 #endif /* USE_GTK2 */
1991
1992 if (requisition.width + list->cell_x_pad > list->cell_width ||
1993 requisition.height + list->cell_y_pad > list->cell_height) {
1994 list->cell_width = MAX(list->cell_width, requisition.width + list->cell_x_pad);
1995 list->cell_height = MAX(list->cell_height, requisition.height + list->cell_y_pad);
1996
1997 gimv_zlist_update (list);
1998 WIDGET_DRAW (GTK_WIDGET (list));
1999
2000 return TRUE;
2001 }
2002
2003 return FALSE;
2004 }
2005
2006
2007 /*
2008 *
2009 * Focus & Selection handling
2010 *
2011 */
2012
2013 static void
gimv_zlist_cell_draw_focus(GimvZList * list,gint index)2014 gimv_zlist_cell_draw_focus (GimvZList *list, gint index)
2015 {
2016 GdkRectangle cell_area;
2017 g_return_if_fail (list && index != -1);
2018
2019 gimv_zlist_cell_area (list, index, &cell_area);
2020
2021 #ifdef USE_GTK2
2022 g_signal_emit (G_OBJECT(list), gimv_zlist_signals [CELL_DRAW_FOCUS], 0,
2023 GIMV_ZLIST_CELL_FROM_INDEX (list, index), &cell_area);
2024 #else /* USE_GTK2 */
2025 gtk_signal_emit (GTK_OBJECT(list), gimv_zlist_signals [CELL_DRAW_FOCUS],
2026 GIMV_ZLIST_CELL_FROM_INDEX (list, index), &cell_area);
2027 #endif /* USE_GTK2 */
2028 }
2029
2030
2031 static void
gimv_zlist_cell_draw_default(GimvZList * list,gint index)2032 gimv_zlist_cell_draw_default (GimvZList *list, gint index)
2033 {
2034 GdkRectangle cell_area;
2035
2036 g_return_if_fail (list);
2037 if (index < 0) return;
2038 /* g_return_if_fail (index != -1); */
2039
2040 gimv_zlist_cell_area (list, index, &cell_area);
2041
2042 #ifdef USE_GTK2
2043 g_signal_emit (G_OBJECT(list), gimv_zlist_signals [CELL_DRAW_DEFAULT], 0,
2044 GIMV_ZLIST_CELL_FROM_INDEX (list, index), &cell_area);
2045 #else /* USE_GTK2 */
2046 gtk_signal_emit (GTK_OBJECT(list), gimv_zlist_signals [CELL_DRAW_DEFAULT],
2047 GIMV_ZLIST_CELL_FROM_INDEX (list, index), &cell_area);
2048 #endif /* USE_GTK2 */
2049 }
2050
2051
2052 void
gimv_zlist_cell_select(GimvZList * list,gint index)2053 gimv_zlist_cell_select (GimvZList *list, gint index)
2054 {
2055 GList *node;
2056
2057 g_return_if_fail (GIMV_IS_ZLIST (list) && index != -1);
2058
2059 node = g_list_find (list->selection, GUINT_TO_POINTER(index));
2060 if (!node) {
2061 #ifdef USE_GTK2
2062 g_signal_emit (G_OBJECT(list), gimv_zlist_signals [CELL_SELECT], 0, index);
2063 #else /* USE_GTK2 */
2064 gtk_signal_emit (GTK_OBJECT(list), gimv_zlist_signals [CELL_SELECT], index);
2065 #endif /* USE_GTK2 */
2066 list->selection = g_list_prepend (list->selection, GUINT_TO_POINTER(index));
2067 gimv_zlist_draw_cell (list, index);
2068 }
2069 }
2070
2071
2072 void
gimv_zlist_cell_unselect(GimvZList * list,gint index)2073 gimv_zlist_cell_unselect (GimvZList *list, gint index)
2074 {
2075 GList *node;
2076
2077 g_return_if_fail (GIMV_IS_ZLIST (list) && index != -1);
2078
2079 node = g_list_find (list->selection, GUINT_TO_POINTER(index));
2080 if (node) {
2081 #ifdef USE_GTK2
2082 g_signal_emit (G_OBJECT(list), gimv_zlist_signals [CELL_UNSELECT], 0, index);
2083 #else /* USE_GTK2 */
2084 gtk_signal_emit (GTK_OBJECT(list), gimv_zlist_signals [CELL_UNSELECT], index);
2085 #endif /* USE_GTK2 */
2086 list->selection = g_list_remove (list->selection, GUINT_TO_POINTER(index));
2087 gimv_zlist_draw_cell (list, index);
2088 }
2089 }
2090
2091
2092 void
gimv_zlist_cell_toggle(GimvZList * list,gint index)2093 gimv_zlist_cell_toggle (GimvZList *list, gint index)
2094 {
2095 g_return_if_fail (GIMV_IS_ZLIST (list) && index != -1);
2096
2097 if (g_list_find (list->selection, GUINT_TO_POINTER(index)))
2098 gimv_zlist_cell_unselect (list, index);
2099 else
2100 gimv_zlist_cell_select (list, index);
2101 }
2102
2103
2104 void
gimv_zlist_unselect_all(GimvZList * list)2105 gimv_zlist_unselect_all (GimvZList *list)
2106 {
2107 GList *item;
2108
2109 item = list->selection;
2110 while (item) {
2111 #ifdef USE_GTK2
2112 g_signal_emit (G_OBJECT(list), gimv_zlist_signals [CELL_UNSELECT], 0,
2113 GPOINTER_TO_UINT(item->data));
2114 #else /* USE_GTK2 */
2115 gtk_signal_emit (GTK_OBJECT(list), gimv_zlist_signals [CELL_UNSELECT],
2116 GPOINTER_TO_UINT(item->data));
2117 #endif /* USE_GTK2 */
2118 gimv_zlist_draw_cell (list, GPOINTER_TO_UINT(item->data));
2119
2120 item = item->next;
2121 }
2122
2123 g_list_free (list->selection);
2124 list->selection = NULL;
2125 }
2126
2127
2128 void
gimv_zlist_extend_selection(GimvZList * list,gint to)2129 gimv_zlist_extend_selection (GimvZList *list, gint to)
2130 {
2131 GList *item;
2132 gint i, s, e;
2133
2134 g_return_if_fail (list && to != -1);
2135
2136 if (list->anchor < to) {
2137 s = list->anchor;
2138 e = to;
2139 } else {
2140 s = to;
2141 e = list->anchor;
2142 }
2143
2144 for (i = s; i <= e; i++)
2145 /* XXX the state of the cell should be cached in the cells array */
2146 if (!g_list_find (list->selection, GUINT_TO_POINTER(i)))
2147 gimv_zlist_cell_select (list, i);
2148 else if (i == list->focus)
2149 gimv_zlist_cell_draw_focus (list, i);
2150
2151 item = list->selection;
2152 while (item) {
2153 i = GPOINTER_TO_UINT(item->data);
2154 item = item->next;
2155
2156 if (i < s || i > e)
2157 gimv_zlist_cell_unselect (list, i);
2158 }
2159 }
2160
2161
2162 static void
select_each_cell_by_region(GimvZList * list,gint index,gboolean in_region)2163 select_each_cell_by_region (GimvZList *list, gint index, gboolean in_region)
2164 {
2165 gboolean select = FALSE, selected = FALSE;
2166 gboolean is_mask = FALSE;
2167
2168 g_return_if_fail (index < list->cell_count);
2169
2170 if (g_list_find (list->selection, GUINT_TO_POINTER (index)))
2171 selected = TRUE;
2172
2173 if (g_list_find (list->selection_mask, GUINT_TO_POINTER (index)))
2174 is_mask = TRUE;
2175
2176 switch (list->region_select) {
2177 case GIMV_ZLIST_REGION_SELECT_TOGGLE:
2178 if ((in_region && !is_mask) || (!in_region && is_mask))
2179 select = TRUE;
2180 break;
2181
2182 case GIMV_ZLIST_REGION_SELECT_EXPAND:
2183 if (in_region || is_mask)
2184 select = TRUE;
2185 break;
2186
2187 case GIMV_ZLIST_REGION_SELECT_NORMAL:
2188 if (in_region)
2189 select = TRUE;
2190 break;
2191 default:
2192 break;
2193 }
2194
2195 if (select && !selected)
2196 gimv_zlist_cell_select (list, index);
2197 if (!select && selected)
2198 gimv_zlist_cell_unselect (list, index);
2199 }
2200
2201
2202 void
gimv_zlist_cell_select_by_region(GimvZList * list,guint start_col,guint start_row,guint end_col,guint end_row)2203 gimv_zlist_cell_select_by_region (GimvZList *list,
2204 guint start_col, guint start_row,
2205 guint end_col, guint end_row)
2206 {
2207 gint index = 0, i, j, cols, rows;
2208 guint col, row;
2209
2210 g_return_if_fail (list);
2211 g_return_if_fail (GIMV_IS_ZLIST (list));
2212 g_return_if_fail (end_col >= start_col);
2213 g_return_if_fail (end_row >= start_row);
2214
2215 if (list->flags & GIMV_ZLIST_HORIZONTAL) {
2216 cols = list->rows;
2217 rows = list->columns;
2218 } else {
2219 cols = list->columns;
2220 rows = list->rows;
2221 }
2222
2223 for (i = 0; i < rows; i++) {
2224 for (j = 0; j < cols; j++) {
2225 gboolean in_region = FALSE;
2226
2227 if (list->flags & GIMV_ZLIST_HORIZONTAL) {
2228 index = list->rows * i + j;
2229 } else {
2230 index = list->columns * i + j;
2231 }
2232 if (index >= list->cell_count) break;
2233
2234 if (list->flags & GIMV_ZLIST_HORIZONTAL) {
2235 col = i;
2236 row = j;
2237 } else {
2238 col = j;
2239 row = i;
2240 }
2241
2242 if (row >= start_row && row <= end_row && col >= start_col && col <= end_col)
2243 in_region = TRUE;
2244
2245 select_each_cell_by_region (list, index, in_region);
2246 }
2247
2248 if (index >= list->cell_count) break;
2249 }
2250 }
2251
2252
2253 void
gimv_zlist_cell_select_by_pixel_region(GimvZList * list,gint start_x,gint start_y,gint end_x,gint end_y)2254 gimv_zlist_cell_select_by_pixel_region (GimvZList *list,
2255 gint start_x, gint start_y,
2256 gint end_x, gint end_y)
2257 {
2258 gint start_col, start_row, end_col, end_row, cell_x, cell_y;
2259
2260 g_return_if_fail (list);
2261 g_return_if_fail (GIMV_IS_ZLIST (list));
2262 g_return_if_fail (end_x >= start_x);
2263 g_return_if_fail (end_y >= start_y);
2264
2265 start_x = start_x - list->x_pad - bw (list);
2266 if (start_x < 0) start_x = 0;
2267 start_y = start_y - list->y_pad - bw (list);
2268 if (start_y < 0) start_y = 0;
2269
2270 end_x = end_x - list->x_pad - bw (list);
2271 if (end_x < 0) end_x = 0;
2272 end_y = end_y - list->y_pad - bw (list);
2273 if (end_y < 0) end_y = 0;
2274
2275 start_col = start_x / list->cell_width;
2276 start_row = start_y / list->cell_height;
2277 end_col = end_x / list->cell_width;
2278 end_row = end_y / list->cell_height;
2279
2280 /*
2281 cell_x = CELL_X_FROM_COL(list, start_col);
2282 if (start_x < list->cell_x_pad * 2 + cell_x && start_col > 1)
2283 start_col--;
2284 cell_y = CELL_Y_FROM_ROW(list, start_row);
2285 if (start_y < list->cell_y_pad * 2 + cell_y && start_row > 1)
2286 start_row--;
2287 */
2288
2289 cell_x = CELL_X_FROM_COL(list, end_col);
2290
2291 if (GIMV_SCROLLED_X (GIMV_SCROLLED (list), end_x) < list->cell_x_pad * 2 + cell_x
2292 && end_col > 0 && end_col > start_col)
2293 {
2294 end_col--;
2295 }
2296
2297 cell_y = CELL_Y_FROM_ROW(list, end_row);
2298
2299 if (GIMV_SCROLLED_Y (GIMV_SCROLLED (list), end_y) < list->cell_y_pad * 2 + cell_y
2300 && end_row > 0 && end_row > start_row)
2301 {
2302 end_row--;
2303 }
2304
2305 gimv_zlist_cell_select_by_region (list,
2306 start_col, start_row,
2307 end_col, end_row);
2308 }
2309
2310
2311 void
gimv_zlist_set_selection_mask(GimvZList * list,GList * mask_list)2312 gimv_zlist_set_selection_mask (GimvZList *list, GList *mask_list)
2313 {
2314 g_return_if_fail (list);
2315 g_return_if_fail (GIMV_IS_ZLIST (list));
2316
2317 if (mask_list) {
2318 list->selection_mask = mask_list;
2319 } else {
2320 if (list->selection)
2321 list->selection_mask = g_list_copy (list->selection);
2322 else
2323 list->selection_mask = NULL;
2324 }
2325 }
2326
2327
2328 void
gimv_zlist_unset_selection_mask(GimvZList * list)2329 gimv_zlist_unset_selection_mask (GimvZList *list)
2330 {
2331 g_return_if_fail (list);
2332 g_return_if_fail (GIMV_IS_ZLIST (list));
2333
2334 if (list->selection_mask)
2335 g_list_free (list->selection_mask);
2336 list->selection_mask = NULL;
2337 }
2338
2339
2340 void
gimv_zlist_moveto(GimvZList * list,gint index)2341 gimv_zlist_moveto (GimvZList *list, gint index)
2342 {
2343 GdkRectangle cell_area;
2344 GtkAdjustment *adj;
2345
2346 g_return_if_fail (list && index != -1);
2347
2348 if (!GTK_WIDGET_DRAWABLE(list) || GIMV_SCROLLED(list)->freeze_count)
2349 return;
2350
2351 gimv_zlist_cell_area (list, index, &cell_area);
2352
2353 if (list->flags & GIMV_ZLIST_HORIZONTAL) { /* horizontal list */
2354
2355 adj = GIMV_SCROLLED(list)->h_adjustment;
2356
2357 if (cell_area.x < 0) {
2358 adj->value += cell_area.x;
2359 #ifdef USE_GTK2
2360 g_signal_emit_by_name (G_OBJECT(adj), "value_changed");
2361 #else /* USE_GTK2 */
2362 gtk_signal_emit_by_name (GTK_OBJECT(adj), "value_changed");
2363 #endif /* USE_GTK2 */
2364 }
2365
2366 if (cell_area.x + cell_area.width > GTK_WIDGET(list)->allocation.width) {
2367 adj->value += (cell_area.x - adj->page_size) + cell_area.width;
2368 #ifdef USE_GTK2
2369 g_signal_emit_by_name (G_OBJECT(adj), "value_changed");
2370 #else /* USE_GTK2 */
2371 gtk_signal_emit_by_name (GTK_OBJECT(adj), "value_changed");
2372 #endif /* USE_GTK2 */
2373 }
2374
2375 } else { /* vertical list */
2376
2377 adj = GIMV_SCROLLED(list)->v_adjustment;
2378
2379 if (cell_area.y < 0) {
2380 adj->value += cell_area.y;
2381 #ifdef USE_GTK2
2382 g_signal_emit_by_name (G_OBJECT(adj), "value_changed");
2383 #else /* USE_GTK2 */
2384 gtk_signal_emit_by_name (GTK_OBJECT(adj), "value_changed");
2385 #endif /* USE_GTK2 */
2386 }
2387
2388 if (cell_area.y + cell_area.height > GTK_WIDGET(list)->allocation.height) {
2389 adj->value += (cell_area.y - adj->page_size) + cell_area.height;
2390 #ifdef USE_GTK2
2391 g_signal_emit_by_name (G_OBJECT(adj), "value_changed");
2392 #else /* USE_GTK2 */
2393 gtk_signal_emit_by_name (GTK_OBJECT(adj), "value_changed");
2394 #endif /* USE_GTK2 */
2395 }
2396 }
2397 }
2398
2399
2400 void
gimv_zlist_cell_set_focus(GimvZList * list,gint index)2401 gimv_zlist_cell_set_focus (GimvZList *list, gint index)
2402 {
2403 g_return_if_fail (GIMV_IS_ZLIST (list));
2404 g_return_if_fail (index >= 0 && index < list->cell_count);
2405
2406 list->focus = index;
2407 gimv_zlist_cell_draw_focus (list, list->focus);
2408 }
2409
2410
2411 void
gimv_zlist_cell_unset_focus(GimvZList * list)2412 gimv_zlist_cell_unset_focus (GimvZList *list)
2413 {
2414 gint focus;
2415
2416 g_return_if_fail (GIMV_IS_ZLIST (list));
2417
2418 focus = list->focus;
2419 list->focus = -1;
2420
2421 if (focus >= 0 && focus < list->cell_count)
2422 gimv_zlist_cell_draw_default (list, focus);
2423 }
2424