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