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_zalbum.c,v 1.5 2004/09/21 08:44:32 makeinu Exp $
22 */
23
24 /*
25 * These codes are mostly taken from ProView image viewer.
26 *
27 * ProView image viewer Author:
28 * promax <promax@users.sourceforge.net>
29 */
30
31 /*
32 * modification file from Another X image viewer
33 * David Ramboz <dramboz@users.sourceforge.net>
34 */
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <string.h>
41 #include "gtk2-compat.h"
42 #include "gimv_zalbum.h"
43
44 #define GIMV_ZALBUM_CELL(ptr) ((GimvZAlbumCell *) (ptr))
45 #define bw(widget) GTK_CONTAINER(widget)->border_width
46
47 #define CELL_PADDING 4
48 #define LABEL_HPADDING 8
49 #define LABEL_VPADDING 4
50 #define LINE_HEIGHT(font) ((font)->ascent + (font)->descent + LABEL_VPADDING)
51 #define STRING_BUFFER_SIZE 1024
52 #define CELL_STATE(cell) (GIMV_ZALBUM_CELL (cell)->flags & GIMV_ZALBUM_CELL_SELECTED ? GTK_STATE_SELECTED : GTK_STATE_NORMAL)
53
54 static void gimv_zalbum_class_init (GimvZAlbumClass *klass);
55 static void gimv_zalbum_init (GimvZAlbum *album);
56 #ifdef USE_GTK2
57 static void gimv_zalbum_finalize (GObject *object);
58 #else
59 static void gimv_zalbum_finalize (GtkObject *object);
60 #endif
61 static void gimv_zalbum_clear (GimvZList *list);
62 static void gimv_zalbum_cell_size_request (GimvZList *list,
63 gpointer cell,
64 GtkRequisition *requisition);
65 static void gimv_zalbum_draw_cell (GimvZList *list,
66 gpointer cell,
67 GdkRectangle *cell_area,
68 GdkRectangle *area);
69 static gint draw_cell_pixmap (GdkWindow *window,
70 GdkRectangle *clip_rectangle,
71 GdkGC *fg_gc,
72 GdkPixmap *pixmap,
73 GdkBitmap *mask,
74 gint x,
75 gint y,
76 gint width,
77 gint height);
78 static void gimv_zalbum_draw (GimvZAlbum *album,
79 GimvZAlbumCell *cell,
80 GdkRectangle *cell_area,
81 GdkRectangle *area);
82 #ifdef USE_GTK2
83 static gint make_string (PangoLayout *layout,
84 gint max_width,
85 gchar *buffer,
86 gint buffer_size);
87 #else
88 static gint make_string (GdkFont *font,
89 gint max_width,
90 GdkWChar *buffer,
91 gint src_len,
92 gint buffer_size);
93 #endif
94 static void gimv_zalbum_draw_string (GtkWidget *widget,
95 GimvZAlbumCell *cell,
96 const gchar *string,
97 gint x,
98 gint y,
99 gint max_width,
100 gint max_heihgt,
101 gint center);
102 static void gimv_zalbum_prepare_cell (GimvZAlbum *album,
103 GimvZAlbumCell *cell,
104 GdkRectangle *cell_area,
105 GdkRectangle *area);
106 static void gimv_zalbum_update_max_cell_size(GimvZAlbum *album,
107 GimvZAlbumCell *cell);
108 static void gimv_zalbum_cell_draw_focus (GimvZList *list,
109 gpointer cell,
110 GdkRectangle *cell_area);
111 static void gimv_zalbum_cell_draw_default (GimvZList *list,
112 gpointer cell,
113 GdkRectangle *cell_area);
114 static void gimv_zalbum_cell_select (GimvZList *list,
115 int index);
116 static void gimv_zalbum_cell_unselect (GimvZList *list,
117 int index);
118
119
120 static GtkWidgetClass *parent_class = NULL;
121
122 /* static GdkFont *album_font = NULL; */
123
124
125 GtkType
gimv_zalbum_get_type(void)126 gimv_zalbum_get_type (void) {
127 static GtkType type = 0;
128
129 #ifdef USE_GTK2
130 if (!type) {
131 static const GTypeInfo info = {
132 sizeof (GimvZAlbumClass),
133 NULL, /* base_init */
134 NULL, /* base_finalize */
135 (GClassInitFunc) gimv_zalbum_class_init,
136 NULL, /* class_finalize */
137 NULL, /* class_data */
138 sizeof (GimvZAlbum),
139 0, /* n_preallocs */
140 (GInstanceInitFunc) gimv_zalbum_init,
141 };
142
143 type = g_type_register_static (GIMV_TYPE_ZLIST,
144 "GimvZAlbum",
145 &info,
146 0);
147 }
148 #else /* USE_GTK2 */
149 if (!type) {
150 static GtkTypeInfo info = {
151 "GimvZAlbum",
152 sizeof(GimvZAlbum),
153 sizeof(GimvZAlbumClass),
154 (GtkClassInitFunc)gimv_zalbum_class_init,
155 (GtkObjectInitFunc)gimv_zalbum_init,
156 NULL,
157 NULL,
158 (GtkClassInitFunc)NULL
159 };
160
161 type = gtk_type_unique(gimv_zlist_get_type(), &info);
162 }
163 #endif /* USE_GTK2 */
164
165 return type;
166 }
167
168
169 static void
gimv_zalbum_class_init(GimvZAlbumClass * klass)170 gimv_zalbum_class_init (GimvZAlbumClass *klass) {
171 GtkObjectClass *object_class;
172 GtkWidgetClass *widget_class;
173 GimvZListClass *zlist_class;
174
175 parent_class = gtk_type_class (gimv_zlist_get_type());
176
177 object_class = (GtkObjectClass *) klass;
178 widget_class = (GtkWidgetClass *) klass;
179 zlist_class = (GimvZListClass *) klass;
180
181 OBJECT_CLASS_SET_FINALIZE_FUNC (klass, gimv_zalbum_finalize);
182
183 zlist_class->clear = gimv_zalbum_clear;
184 zlist_class->cell_draw = gimv_zalbum_draw_cell;
185 zlist_class->cell_size_request = gimv_zalbum_cell_size_request;
186 zlist_class->cell_draw_focus = gimv_zalbum_cell_draw_focus;
187 zlist_class->cell_draw_default = gimv_zalbum_cell_draw_default;
188 zlist_class->cell_select = gimv_zalbum_cell_select;
189 zlist_class->cell_unselect = gimv_zalbum_cell_unselect;
190 }
191
192
193 static void
gimv_zalbum_init(GimvZAlbum * zalbum)194 gimv_zalbum_init(GimvZAlbum *zalbum) {
195 zalbum->label_pos = GIMV_ZALBUM_CELL_LABEL_BOTTOM;
196 zalbum->max_pix_width = 0;
197 zalbum->max_pix_height = 0;
198 zalbum->max_cell_width = 0;
199 zalbum->max_cell_height = 0;
200 }
201
202
203 GtkWidget *
gimv_zalbum_new(void)204 gimv_zalbum_new (void) {
205 GimvZAlbum *album;
206 GtkRequisition requisition;
207 gint flags = 0;
208
209 #ifdef USE_GTK2
210 album = g_object_new (gimv_zalbum_get_type (), NULL);
211 #else /* USE_GTK2 */
212 album = gtk_type_new (gimv_zalbum_get_type());
213 #endif /* USE_GTK2 */
214 g_return_val_if_fail (album != NULL, NULL);
215
216 /* flags |= GIMV_ZLIST_HORIZONTAL; */
217
218 gimv_zlist_construct (GIMV_ZLIST(album), flags);
219 gimv_zlist_set_selection_mode (GIMV_ZLIST (album), GTK_SELECTION_EXTENDED);
220
221 gimv_zalbum_cell_size_request (GIMV_ZLIST (album), NULL, &requisition);
222 gimv_zlist_set_cell_padding (GIMV_ZLIST (album), 4, 4);
223 gimv_zlist_set_1 (GIMV_ZLIST (album), 0);
224 gimv_zlist_set_cell_size (GIMV_ZLIST (album), requisition.width, requisition.height);
225
226 album->len = 0;
227
228 return (GtkWidget *) album;
229 }
230
231
232 static void
233 #ifdef USE_GTK2
gimv_zalbum_finalize(GObject * object)234 gimv_zalbum_finalize (GObject *object)
235 #else /* USE_GTK2 */
236 gimv_zalbum_finalize (GtkObject *object)
237 #endif /* USE_GTK2 */
238 {
239 gimv_zalbum_clear (GIMV_ZLIST (object));
240
241 OBJECT_CLASS_FINALIZE_SUPER (parent_class, object);
242 }
243
244
245 guint
gimv_zalbum_add(GimvZAlbum * album,const gchar * name)246 gimv_zalbum_add (GimvZAlbum *album, const gchar *name)
247 {
248 g_return_val_if_fail (GIMV_IS_ZALBUM (album), 0);
249
250 return gimv_zalbum_insert (album, GIMV_ZLIST(album)->cells->len, name);
251 }
252
253
254 guint
gimv_zalbum_insert(GimvZAlbum * album,guint pos,const gchar * name)255 gimv_zalbum_insert (GimvZAlbum *album, guint pos, const gchar *name)
256 {
257 GimvZAlbumCell *cell;
258
259 g_return_val_if_fail (GIMV_IS_ZALBUM (album), 0);
260
261 cell = g_new(GimvZAlbumCell, 1);
262
263 if (name)
264 cell->name = g_strdup (name);
265 else
266 cell->name = NULL;
267
268 cell->ipix = NULL;
269 cell->flags = 0;
270 cell->user_data = NULL;
271
272 album->len++;
273
274 return gimv_zlist_insert (GIMV_ZLIST (album), pos, cell);
275 }
276
277
278 void
gimv_zalbum_remove(GimvZAlbum * album,guint pos)279 gimv_zalbum_remove (GimvZAlbum *album, guint pos)
280 {
281 GimvZAlbumCell *cell;
282
283 g_return_if_fail (GIMV_IS_ZALBUM (album));
284
285 cell = GIMV_ZLIST_CELL_FROM_INDEX (GIMV_ZLIST (album), pos);
286 g_return_if_fail (cell);
287
288 gimv_zlist_remove(GIMV_ZLIST(album), cell);
289
290 g_free ((gpointer) cell->name);
291 if (cell->ipix)
292 gdk_pixmap_unref (cell->ipix);
293 cell->ipix = NULL;
294
295 if (cell->user_data && cell->destroy)
296 cell->destroy (cell->user_data);
297 cell->destroy = NULL;
298 cell->user_data = NULL;
299
300 g_free (cell);
301 }
302
303
304 static void
gimv_zalbum_clear(GimvZList * list)305 gimv_zalbum_clear (GimvZList *list)
306 {
307 GimvZAlbumCell *cell;
308 gint i;
309
310 g_return_if_fail (list);
311
312 for (i = 0; i < list->cell_count; i++) {
313 cell = GIMV_ZLIST_CELL_FROM_INDEX (list, i);
314 g_free ((gpointer) cell->name);
315 if (cell->ipix)
316 gdk_pixmap_unref (cell->ipix);
317 cell->ipix = NULL;
318
319 if (cell->user_data && cell->destroy)
320 cell->destroy (cell->user_data);
321 cell->destroy = NULL;
322 cell->user_data = NULL;
323
324 g_free (cell);
325 }
326
327 GIMV_ZALBUM (list)->len = 0;
328 }
329
330
331 static void
gimv_zalbum_cell_size_request(GimvZList * list,gpointer cell,GtkRequisition * requisition)332 gimv_zalbum_cell_size_request (GimvZList *list, gpointer cell, GtkRequisition *requisition)
333 {
334 GimvZAlbum *album;
335 gint text_height = 0;
336
337 g_return_if_fail (list && requisition);
338
339 album = GIMV_ZALBUM (list);
340
341 switch (album->label_pos) {
342 case GIMV_ZALBUM_CELL_LABEL_LEFT:
343 case GIMV_ZALBUM_CELL_LABEL_RIGHT:
344 text_height = 0;
345 break;
346 case GIMV_ZALBUM_CELL_LABEL_BOTTOM:
347 case GIMV_ZALBUM_CELL_LABEL_TOP:
348 default:
349 text_height = LINE_HEIGHT (gtk_style_get_font (GTK_WIDGET (list)->style));
350 break;
351 }
352
353 requisition->width
354 = MAX (album->max_cell_width, album->max_pix_width)
355 + 2 * CELL_PADDING;
356 requisition->height
357 = MAX (album->max_cell_height, album->max_pix_height)
358 + 2 * CELL_PADDING + text_height;
359 }
360
361
362 static void
gimv_zalbum_draw_cell(GimvZList * list,gpointer cell,GdkRectangle * cell_area,GdkRectangle * area)363 gimv_zalbum_draw_cell (GimvZList *list,
364 gpointer cell,
365 GdkRectangle *cell_area,
366 GdkRectangle *area)
367 {
368 g_return_if_fail (list && cell);
369
370 gimv_zalbum_draw ((GimvZAlbum *) list, (GimvZAlbumCell *) cell, cell_area, area);
371 }
372
373
374 static gint
draw_cell_pixmap(GdkWindow * window,GdkRectangle * clip_rectangle,GdkGC * fg_gc,GdkPixmap * pixmap,GdkBitmap * mask,gint x,gint y,gint width,gint height)375 draw_cell_pixmap (GdkWindow *window,
376 GdkRectangle *clip_rectangle,
377 GdkGC *fg_gc,
378 GdkPixmap *pixmap,
379 GdkBitmap *mask,
380 gint x,
381 gint y,
382 gint width,
383 gint height)
384 {
385 gint xsrc = 0, ysrc = 0;
386
387 if (mask) {
388 gdk_gc_set_clip_mask (fg_gc, mask);
389 gdk_gc_set_clip_origin (fg_gc, x, y);
390 }
391
392 if (x < clip_rectangle->x) {
393 xsrc = clip_rectangle->x - x;
394 width -= xsrc;
395 x = clip_rectangle->x;
396 }
397 if (x + width > clip_rectangle->x + clip_rectangle->width)
398 width = clip_rectangle->x + clip_rectangle->width - x;
399
400 if (y < clip_rectangle->y) {
401 ysrc = clip_rectangle->y - y;
402 height -= ysrc;
403 y = clip_rectangle->y;
404 }
405 if (y + height > clip_rectangle->y + clip_rectangle->height)
406 height = clip_rectangle->y + clip_rectangle->height - y;
407
408 gdk_draw_pixmap (window, fg_gc, pixmap, xsrc, ysrc, x, y, width, height);
409
410 if (mask) {
411 gdk_gc_set_clip_origin (fg_gc, 0, 0);
412 gdk_gc_set_clip_mask (fg_gc, NULL);
413 }
414
415 return x + MAX (width, 0);
416 }
417
418
419 static void
gimv_zalbum_draw(GimvZAlbum * album,GimvZAlbumCell * cell,GdkRectangle * cell_area,GdkRectangle * area)420 gimv_zalbum_draw (GimvZAlbum *album, GimvZAlbumCell *cell,
421 GdkRectangle *cell_area,
422 GdkRectangle *area)
423 {
424 GtkWidget *widget;
425 gint text_area_height, v_text_area_height, xdest, ydest;
426 gint xpad, ypad;
427 gboolean center = TRUE;
428 GdkRectangle widget_area, draw_area;
429
430 g_return_if_fail (album && cell && cell_area);
431
432 widget = GTK_WIDGET (album);
433
434 if (!GTK_WIDGET_DRAWABLE (widget))
435 return;
436
437 widget_area.x = widget_area.y = 0;
438 widget_area.width = widget->allocation.width;
439 widget_area.height = widget->allocation.height;
440 if (!area) {
441 draw_area = widget_area;
442 } else {
443 if (!gdk_rectangle_intersect (area, &widget_area, &draw_area))
444 return;
445 }
446
447 gimv_zalbum_prepare_cell (album, cell, cell_area, &draw_area);
448
449 switch (album->label_pos) {
450 case GIMV_ZALBUM_CELL_LABEL_RIGHT:
451 case GIMV_ZALBUM_CELL_LABEL_LEFT:
452 text_area_height = cell_area->height;
453 v_text_area_height = 0;
454 break;
455 case GIMV_ZALBUM_CELL_LABEL_BOTTOM:
456 case GIMV_ZALBUM_CELL_LABEL_TOP:
457 default:
458 text_area_height = LINE_HEIGHT (gtk_style_get_font (GTK_WIDGET (album)->style));
459 v_text_area_height = text_area_height;
460 break;
461 }
462
463 if (cell->ipix) {
464 GdkRectangle pixmap_area, intersect_area;
465 gboolean need_draw;
466 gint w, h;
467 gint iwidth = 0, iheight = 0;
468
469 gdk_window_get_size (cell->ipix, &iwidth, &iheight);
470
471 w = iwidth;
472 h = iheight;
473
474 switch (album->label_pos) {
475 case GIMV_ZALBUM_CELL_LABEL_RIGHT:
476 xpad = 0;
477 break;
478 case GIMV_ZALBUM_CELL_LABEL_LEFT:
479 /* not implemented yet */
480 /* break; */
481 case GIMV_ZALBUM_CELL_LABEL_BOTTOM:
482 case GIMV_ZALBUM_CELL_LABEL_TOP:
483 default:
484 xpad = (cell_area->width - w) / 2;
485 break;
486 }
487 ypad = (cell_area->height - v_text_area_height - h) / 2;
488
489 if (xpad < 0) {
490 w += xpad;
491 xpad = 0;
492 }
493
494 if (ypad < 0) {
495 h += ypad;
496 ypad = 0;
497 }
498
499 pixmap_area.x = cell_area->x + xpad;
500 pixmap_area.y = cell_area->y + ypad;
501 pixmap_area.width = iwidth;
502 pixmap_area.height = iheight;
503
504 need_draw = gdk_rectangle_intersect (&draw_area, &pixmap_area, &intersect_area);
505
506 if (cell->ipix && need_draw) {
507 draw_cell_pixmap (widget->window,
508 &intersect_area,
509 widget->style->fg_gc[GTK_STATE_NORMAL],
510 cell->ipix, cell->imask,
511 pixmap_area.x, pixmap_area.y,
512 iwidth, iheight);
513 }
514 }
515
516 switch (album->label_pos) {
517 case GIMV_ZALBUM_CELL_LABEL_RIGHT:
518 xdest = cell_area->x + album->max_pix_width + LABEL_HPADDING;
519 ydest = cell_area->y
520 + gtk_style_get_font (GTK_WIDGET (album)->style)->ascent;
521 center = FALSE;
522 break;
523
524 case GIMV_ZALBUM_CELL_LABEL_LEFT:
525 /* not implemented yet */
526 /* break; */
527
528 case GIMV_ZALBUM_CELL_LABEL_TOP:
529 /* not implemented yet */
530 /* break; */
531
532 case GIMV_ZALBUM_CELL_LABEL_BOTTOM:
533 default:
534 xdest = cell_area->x;
535 ydest = (cell_area->y + cell_area->height - v_text_area_height)
536 + gtk_style_get_font (GTK_WIDGET (album)->style)->ascent
537 + LABEL_VPADDING;
538 center = TRUE;
539 break;
540 }
541
542 gimv_zalbum_draw_string (widget, cell, cell->name,
543 xdest, ydest,
544 cell_area->width, text_area_height,
545 center);
546
547 }
548
549
550 /* FIXME */
551 #if USE_GTK2
552 static void
get_string_area_size(GimvZAlbum * album,const gchar * str,gint * width_ret,gint * height_ret,gint * lines_ret)553 get_string_area_size (GimvZAlbum *album, const gchar *str,
554 gint *width_ret, gint *height_ret, gint *lines_ret)
555 {
556 PangoLayout *layout;
557 gint i, width, height, lines = 1;
558
559 for (i = 0; str && str[i]; i++)
560 if (str[i] == '\n') lines++;
561
562 layout = gtk_widget_create_pango_layout (GTK_WIDGET (album), "(NULL)");
563 pango_layout_set_text (layout, str, -1);
564 pango_layout_get_pixel_size (layout, &width, &height);
565
566 if (width_ret)
567 *width_ret = width;
568 if (height_ret)
569 *height_ret = height;
570
571 if (lines_ret) {
572 *lines_ret = lines;
573 }
574
575 g_object_unref (layout);
576 }
577
578
579 static gint
make_string(PangoLayout * layout,gint max_width,gchar * buffer,gint buffer_size)580 make_string (PangoLayout *layout, gint max_width,
581 gchar *buffer, gint buffer_size)
582 {
583 gint utf8len, len, src_len, dots_width, width, height;
584
585 pango_layout_set_text (layout, "...", -1);
586 pango_layout_get_pixel_size (layout, &dots_width, &height);
587
588 utf8len = g_utf8_strlen (buffer, -1);
589 len = src_len = strlen (buffer);
590
591 while (utf8len > 0 && len > 0) {
592 len = g_utf8_offset_to_pointer(buffer, utf8len) - buffer;
593
594 pango_layout_set_text (layout, buffer, len);
595 pango_layout_get_pixel_size (layout, &width, &height);
596 if (width + dots_width > max_width) {
597 utf8len--;
598 } else {
599 break;
600 }
601 }
602
603 if (len < src_len && len < buffer_size - 4) {
604 gchar *str = g_utf8_offset_to_pointer (buffer, utf8len);
605 str[0] = '.';
606 str[1] = '.';
607 str[2] = '.';
608 str[3] = '\0';
609 return len + 3;
610 } else {
611 buffer[buffer_size - 1] = '\0';
612 return buffer_size;
613 }
614 }
615 #else
616 static void
get_string_area_size(GimvZAlbum * album,const gchar * str,gint * width_ret,gint * height_ret,gint * lines_ret)617 get_string_area_size (GimvZAlbum *album, const gchar *str,
618 gint *width_ret, gint *height_ret, gint *lines_ret)
619 {
620 gint i, strwidth = 0, maxwidth = 0, lines;
621 gchar **strs;
622 GdkFont *font = gtk_style_get_font (GTK_WIDGET (album)->style);
623
624 g_return_if_fail (str);
625 g_return_if_fail (font);
626
627 strs = g_strsplit (str, "\n", -1);
628 if (!strs) {
629 *lines_ret = 1;
630 return;
631 }
632
633 for (i = 0; strs[i]; i++) {
634 strwidth = gdk_string_width (font, strs[i]);
635 maxwidth = MAX (maxwidth, strwidth);
636 }
637
638 lines = i++;
639
640 if (lines_ret)
641 *lines_ret = lines;
642
643 g_strfreev (strs);
644
645 if (width_ret)
646 *width_ret = maxwidth;
647 if (height_ret)
648 *height_ret = gdk_string_height (font, str) + LABEL_VPADDING * lines;
649 }
650
651
652 static gint
make_string(GdkFont * font,gint max_width,GdkWChar buffer[],gint src_len,gint buffer_size)653 make_string (GdkFont *font, gint max_width,
654 GdkWChar buffer[], gint src_len, gint buffer_size)
655 {
656 gint dots_width;
657 gint len = src_len;
658
659 dots_width = gdk_text_width (font, "...", 3);
660
661 while (len > 0) {
662 if (gdk_text_width_wc (font, buffer, len) + dots_width > max_width) {
663 len--;
664 } else {
665 break;
666 }
667 }
668
669 if (len < src_len && len < buffer_size - 4) {
670 buffer[len] = '.';
671 buffer[len + 1] = '.';
672 buffer[len + 2] = '.';
673 buffer[len + 3] = '\0';
674 return len + 3;
675 } else {
676 buffer[buffer_size - 1] = '\0';
677 return buffer_size;
678 }
679 }
680 #endif
681
682
683 static void
gimv_zalbum_draw_string(GtkWidget * widget,GimvZAlbumCell * cell,const gchar * string,gint x,gint y,gint max_width,gint max_height,gint center)684 gimv_zalbum_draw_string (GtkWidget *widget, GimvZAlbumCell *cell,
685 const gchar *string,
686 gint x, gint y,
687 gint max_width, gint max_height,
688 gint center)
689 {
690 #ifdef USE_GTK2
691 gchar buffer[STRING_BUFFER_SIZE];
692 gint x_pad, y_pad;
693 gint width = 0, height = 0, str_height, len;
694 PangoLayout *layout;
695 gint vpad = LABEL_VPADDING;
696
697 if (!string || !*string) return;
698
699 layout = gtk_widget_create_pango_layout (widget, "(NULL)");
700 pango_layout_get_pixel_size (layout, &width, &height);
701 str_height = height;
702 pango_layout_set_text (layout, string, -1);
703 pango_layout_get_pixel_size (layout, &width, &height);
704
705 len = strlen(string);
706 strncpy (buffer, string, MIN (len, STRING_BUFFER_SIZE));
707 buffer[MIN (len, STRING_BUFFER_SIZE - 1)] = '\0';
708
709 x_pad = (max_width - width) / 2;
710
711 if (x_pad < 0) {
712 make_string (layout, max_width,
713 buffer, STRING_BUFFER_SIZE);
714 } else {
715 gint len = MIN (strlen (string), STRING_BUFFER_SIZE - 1);
716 strncpy (buffer, string, len);
717 buffer[len] = '\0';
718 }
719
720 pango_layout_set_text (layout, buffer, -1);
721 pango_layout_get_pixel_size (layout, &width, &height);
722 x_pad = (max_width - width) / 2;
723
724 if (!center)
725 x_pad = 0;
726
727 if (GIMV_ZALBUM (widget)->label_pos == GIMV_ZALBUM_CELL_LABEL_TOP
728 || GIMV_ZALBUM (widget)->label_pos == GIMV_ZALBUM_CELL_LABEL_BOTTOM)
729 {
730 vpad /= 2;
731 }
732
733 if (height < max_height) {
734 y_pad = (max_height - height) / 2 + vpad;
735 } else {
736 y_pad = vpad;
737 }
738
739 gdk_draw_layout (widget->window,
740 widget->style->fg_gc[CELL_STATE(cell)],
741 x + x_pad,
742 y + y_pad - str_height,
743 layout);
744
745 g_object_unref (layout);
746 #else
747 GdkFont *font = gtk_style_get_font (widget->style);
748 gchar *str, **strs;
749 gint buffer[STRING_BUFFER_SIZE], lines;
750 gint x_pad, y_pad, len, str_height, i, width, height;
751
752 get_string_area_size (GIMV_ZALBUM (widget), string, &width, &height, &lines);
753 x_pad = (max_width - width) / 2;
754
755 if (x_pad < 0) {
756 len = gdk_mbstowcs (buffer, string, STRING_BUFFER_SIZE);
757 x_pad = (max_width - gdk_text_width_wc (font, buffer, len)) / 2;
758 len = make_string (gtk_style_get_font (widget->style), max_width,
759 buffer, len, STRING_BUFFER_SIZE);
760 str = gdk_wcstombs (buffer);
761 get_string_area_size (GIMV_ZALBUM (widget), string, &width, &height, &lines);
762 x_pad = (max_width - width) / 2;
763 } else {
764 str = g_strdup (string);
765 get_string_area_size (GIMV_ZALBUM (widget), string, &width, &height, &lines);
766 x_pad = (max_width - width) / 2;
767 }
768
769 if (x_pad < 0 || !center)
770 x_pad = 0;
771
772 strs = g_strsplit (str, "\n", -1);
773
774 str_height = gdk_string_height (font, string);
775 if (str_height * lines < max_height)
776 y_pad = (max_height - str_height * lines) / 2;
777 else
778 y_pad = 0;
779
780 for (i = 0; strs && strs[i]; i++) {
781 gdk_draw_string (widget->window,
782 font,
783 widget->style->fg_gc[CELL_STATE(widget)],
784 x + x_pad,
785 y + y_pad + (str_height + LABEL_VPADDING) * i,
786 strs[i]);
787 }
788
789 g_strfreev (strs);
790 g_free (str);
791 #endif
792 }
793 /* END FIXME!! */
794
795
796 static void
gimv_zalbum_prepare_cell(GimvZAlbum * album,GimvZAlbumCell * cell,GdkRectangle * cell_area,GdkRectangle * area)797 gimv_zalbum_prepare_cell (GimvZAlbum *album,
798 GimvZAlbumCell *cell,
799 GdkRectangle *cell_area,
800 GdkRectangle *area)
801 {
802 GtkWidget *widget;
803 GdkRectangle intersect_area;
804
805 widget = GTK_WIDGET(album);
806
807 if (gdk_rectangle_intersect (area, cell_area, &intersect_area))
808 gdk_draw_rectangle (widget->window,
809 widget->style->bg_gc[CELL_STATE(cell)], TRUE,
810 intersect_area.x, intersect_area.y,
811 intersect_area.width, intersect_area.height);
812
813 #ifdef USE_GTK2
814 gtk_paint_shadow (widget->style, widget->window,
815 CELL_STATE(cell), GTK_SHADOW_OUT,
816 NULL, NULL, NULL,
817 cell_area->x, cell_area->y,
818 cell_area->width, cell_area->height);
819 #else /* USE_GTK2 */
820 gtk_draw_shadow (widget->style, widget->window,
821 CELL_STATE(cell), GTK_SHADOW_OUT,
822 cell_area->x, cell_area->y,
823 cell_area->width, cell_area->height);
824 #endif /* USE_GTK2 */
825
826 cell_area->x += CELL_PADDING;
827 cell_area->y += CELL_PADDING;
828 cell_area->width -= CELL_PADDING * 2;
829 cell_area->height -= CELL_PADDING * 2;
830 }
831
832
833 void
gimv_zalbum_set_label_position(GimvZAlbum * album,GimvZAlbumLabelPosition pos)834 gimv_zalbum_set_label_position (GimvZAlbum *album, GimvZAlbumLabelPosition pos)
835 {
836 g_return_if_fail (GIMV_IS_ZALBUM (album));
837
838 album->label_pos = pos;
839
840 if (GTK_WIDGET_VISIBLE (album)) {
841 #ifdef USE_GTK2
842 gtk_widget_queue_draw (GTK_WIDGET (album));
843 #else /* USE_GTK2 */
844 gtk_widget_draw (GTK_WIDGET (album), NULL);
845 #endif /* USE_GTK2 */
846 }
847 }
848
849
850 void
gimv_zalbum_set_min_pixmap_size(GimvZAlbum * album,guint width,guint height)851 gimv_zalbum_set_min_pixmap_size (GimvZAlbum *album,
852 guint width, guint height)
853 {
854 g_return_if_fail (GIMV_IS_ZALBUM (album));
855
856 album->max_pix_width = width;
857 album->max_pix_height = height;
858 }
859
860
861 void
gimv_zalbum_set_min_cell_size(GimvZAlbum * album,guint width,guint height)862 gimv_zalbum_set_min_cell_size (GimvZAlbum *album,
863 guint width, guint height)
864 {
865 g_return_if_fail (GIMV_IS_ZALBUM (album));
866
867 album->max_cell_width = width;
868 album->max_cell_height = height;
869 }
870
871
872 static void
gimv_zalbum_update_max_cell_size(GimvZAlbum * album,GimvZAlbumCell * cell)873 gimv_zalbum_update_max_cell_size (GimvZAlbum *album, GimvZAlbumCell *cell)
874 {
875 gint pix_width, pix_height, iwidth, iheight, cell_width, cell_height;
876 gint string_area_width, str_width, str_height;
877
878 g_return_if_fail (album);
879 g_return_if_fail (cell);
880
881 if (cell->ipix) {
882 gdk_window_get_size (cell->ipix, &iwidth, &iheight);
883 } else {
884 iwidth = album->max_pix_width;
885 iheight = album->max_pix_height;
886 }
887
888 album->max_pix_width = MAX(album->max_pix_width, iwidth);
889 album->max_pix_height = MAX(album->max_pix_height, iheight);
890
891 if (cell->name) {
892 get_string_area_size (album, cell->name,
893 &str_width, &str_height, NULL);
894 /*
895 str_width = gdk_string_width (font, cell->name);
896 str_height = gdk_string_height (font, cell->name);
897 */
898 } else {
899 str_width = 0;
900 str_height = 0;
901 }
902
903 switch (album->label_pos) {
904 case GIMV_ZALBUM_CELL_LABEL_LEFT:
905 case GIMV_ZALBUM_CELL_LABEL_RIGHT:
906 {
907 pix_width = album->max_pix_width;
908 pix_height = album->max_pix_height;
909 string_area_width = str_width + LABEL_HPADDING;
910
911 break;
912 }
913 case GIMV_ZALBUM_CELL_LABEL_BOTTOM:
914 case GIMV_ZALBUM_CELL_LABEL_TOP:
915 default:
916 pix_width = iwidth;
917 pix_height = iheight;
918 string_area_width = 0;
919
920 break;
921 }
922
923 cell_width = pix_width + string_area_width;
924 cell_height = MAX (pix_height, str_height);
925
926 album->max_cell_width
927 = MAX (MAX(album->max_cell_width, cell_width), album->max_pix_width);
928 album->max_cell_height
929 = MAX (MAX(album->max_cell_height, cell_height), album->max_pix_height);
930 }
931
932
933 void
gimv_zalbum_set_pixmap(GimvZAlbum * album,guint idx,GdkPixmap * pixmap,GdkBitmap * mask)934 gimv_zalbum_set_pixmap (GimvZAlbum *album, guint idx,
935 GdkPixmap *pixmap, GdkBitmap *mask)
936 {
937 GimvZAlbumCell *cell;
938
939 g_return_if_fail (GIMV_IS_ZALBUM (album));
940
941 cell = GIMV_ZLIST_CELL_FROM_INDEX(album, idx);
942
943 g_return_if_fail (cell);
944
945 if (cell->ipix)
946 gdk_pixmap_unref (cell->ipix);
947 cell->ipix = NULL;
948 cell->imask = NULL;
949
950 if (!pixmap) return;
951
952 cell->ipix = gdk_pixmap_ref (pixmap);
953 if (mask) cell->imask = gdk_bitmap_ref (mask);
954
955 if (cell->ipix) {
956 gimv_zalbum_update_max_cell_size (album, cell);
957
958 if (!gimv_zlist_update_cell_size(GIMV_ZLIST(album), (gpointer) cell))
959 gimv_zlist_draw_cell (GIMV_ZLIST(album), idx);
960 }
961 }
962
963
964 void
gimv_zalbum_set_cell_data(GimvZAlbum * album,guint idx,gpointer user_data)965 gimv_zalbum_set_cell_data (GimvZAlbum *album, guint idx, gpointer user_data)
966 {
967 gimv_zalbum_set_cell_data_full (album, idx, user_data, NULL);
968 }
969
970
971 void
gimv_zalbum_set_cell_data_full(GimvZAlbum * album,guint idx,gpointer user_data,GtkDestroyNotify destroy)972 gimv_zalbum_set_cell_data_full (GimvZAlbum *album,
973 guint idx,
974 gpointer user_data,
975 GtkDestroyNotify destroy)
976 {
977 GimvZAlbumCell *cell;
978
979 g_return_if_fail (GIMV_IS_ZALBUM (album));
980
981 if (idx < 0 || idx >= album->len) return;
982
983 cell = GIMV_ZLIST_CELL_FROM_INDEX (GIMV_ZLIST (album), idx);
984 g_return_if_fail (cell);
985
986 cell->user_data = user_data;
987 cell->destroy = destroy;
988 }
989
990
991 gpointer
gimv_zalbum_get_cell_data(GimvZAlbum * album,guint idx)992 gimv_zalbum_get_cell_data (GimvZAlbum *album, guint idx)
993 {
994 GimvZAlbumCell *cell;
995
996 g_return_val_if_fail (GIMV_IS_ZALBUM (album), NULL);
997
998 if (idx < 0 || idx >= album->len) return NULL;
999
1000 cell = GIMV_ZLIST_CELL_FROM_INDEX (GIMV_ZLIST (album), idx);
1001 g_return_val_if_fail (cell, NULL);
1002
1003 return cell->user_data;
1004 }
1005
1006
1007 static void
gimv_zalbum_cell_draw_focus(GimvZList * list,gpointer cell,GdkRectangle * cell_area)1008 gimv_zalbum_cell_draw_focus (GimvZList *list, gpointer cell, GdkRectangle *cell_area)
1009 {
1010 g_return_if_fail (GIMV_IS_ZALBUM (list));
1011
1012 if (!GTK_WIDGET_MAPPED (list)) return;
1013
1014 #ifdef USE_GTK2
1015 gtk_paint_shadow(GTK_WIDGET(list)->style, GTK_WIDGET(list)->window,
1016 CELL_STATE(cell), GTK_SHADOW_IN,
1017 NULL, NULL, NULL,
1018 cell_area->x, cell_area->y,
1019 cell_area->width, cell_area->height);
1020 #else /* USE_GTK2 */
1021 gtk_draw_shadow(GTK_WIDGET(list)->style, GTK_WIDGET(list)->window,
1022 CELL_STATE(cell), GTK_SHADOW_IN,
1023 cell_area->x, cell_area->y,
1024 cell_area->width, cell_area->height);
1025 #endif /* USE_GTK2 */
1026 }
1027
1028
1029 static void
gimv_zalbum_cell_draw_default(GimvZList * list,gpointer cell,GdkRectangle * cell_area)1030 gimv_zalbum_cell_draw_default (GimvZList *list, gpointer cell, GdkRectangle *cell_area)
1031 {
1032 g_return_if_fail (GIMV_IS_ZALBUM (list));
1033
1034 if (!GTK_WIDGET_MAPPED (list)) return;
1035
1036 #ifdef USE_GTK2
1037 gtk_paint_shadow(GTK_WIDGET(list)->style, GTK_WIDGET(list)->window,
1038 CELL_STATE(cell), GTK_SHADOW_OUT,
1039 NULL, NULL, NULL,
1040 cell_area->x, cell_area->y,
1041 cell_area->width, cell_area->height);
1042 #else /* USE_GTK2 */
1043 gtk_draw_shadow(GTK_WIDGET(list)->style, GTK_WIDGET (list)->window,
1044 CELL_STATE(cell), GTK_SHADOW_OUT,
1045 cell_area->x, cell_area->y,
1046 cell_area->width, cell_area->height);
1047 #endif /* USE_GTK2 */
1048 }
1049
1050
1051 static void
gimv_zalbum_cell_select(GimvZList * list,int index)1052 gimv_zalbum_cell_select (GimvZList *list, int index)
1053 {
1054 GimvZAlbumCell *cell;
1055
1056 cell = GIMV_ZLIST_CELL_FROM_INDEX (list, index);
1057 g_return_if_fail (cell);
1058
1059 GIMV_ZALBUM_CELL (cell)->flags |= GIMV_ZALBUM_CELL_SELECTED;
1060 }
1061
1062
1063 static void
gimv_zalbum_cell_unselect(GimvZList * list,int index)1064 gimv_zalbum_cell_unselect (GimvZList *list, int index)
1065 {
1066 GimvZAlbumCell *cell;
1067
1068 cell = GIMV_ZLIST_CELL_FROM_INDEX (list, index);
1069 g_return_if_fail (cell);
1070
1071 GIMV_ZALBUM_CELL (cell)->flags &= ~GIMV_ZALBUM_CELL_SELECTED;
1072 }
1073