source: trunk/third/eog/collection/eog-item-factory-simple.c @ 19173

Revision 19173, 16.7 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19172, which included commits to RCS files with non-trunk default branches.
Line 
1/* Eye of Gnome - default item factory for icons
2 *
3 * Copyright (C) 2000-2002 The Free Software Foundation
4 *
5 * Author: Federico Mena-Quintero <federico@gnu.org>
6 *         Jens Finke <jens@gnome.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22
23#include <config.h>
24#include <pango/pango-layout.h>
25#include <gtk/gtksignal.h>
26#include <libgnome/gnome-macros.h>
27#include <libgnomecanvas/gnome-canvas-pixbuf.h>
28#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
29#include <libgnomecanvas/gnome-canvas-text.h>
30#include <libgnomevfs/gnome-vfs-types.h>
31#include <libgnomevfs/gnome-vfs-uri.h>
32#include "eog-item-factory-simple.h"
33#include "eog-collection-model.h"
34#include "cimage.h"
35#include <math.h>
36
37
38/* Private part of the EogItemFactorySimple structure */
39struct _EogItemFactorySimplePrivate {
40        /* item metrics */
41        EogSimpleMetrics *metrics;
42
43        /* default pixmap if the image is not loaded so far */
44        GdkPixbuf *dummy;
45
46        GdkPixbuf *shaded_bgr;
47};
48
49
50
51/* Icon item structure */
52typedef struct {
53        /* unique id */
54        guint id;
55
56        /* Base group */
57        GnomeCanvasItem *item;
58
59        /* Icon image and its selection rectangle */
60        GnomeCanvasItem *image;
61
62        /* Caption and its selection and focus rectangles */
63        GnomeCanvasItem *caption;
64
65        /* border */
66        GnomeCanvasItem *border;
67
68        /* image background */
69        GnomeCanvasItem *bgr;
70} IconItem;
71
72
73
74static void eog_item_factory_simple_class_init (EogItemFactorySimpleClass *class);
75static void eog_item_factory_simple_instance_init (EogItemFactorySimple *factory);
76static void eog_item_factory_simple_dispose (GObject *object);
77static void eog_item_factory_simple_finalize (GObject *object);
78static EogItemFactorySimple* eog_item_factory_simple_construct (EogItemFactorySimple *factory);
79
80static GnomeCanvasItem *ii_factory_create_item (EogItemFactory *factory,
81                                                GnomeCanvasGroup *parent, guint id);
82static void ii_factory_update_item (EogItemFactory *factory,
83                                    EogCollectionModel *model,
84                                    GnomeCanvasItem *item,
85                                    EogItemUpdateHint hint);
86static void ii_factory_get_item_size (EogItemFactory *factory,
87                                      gint *width, gint *height);
88
89GNOME_CLASS_BOILERPLATE (EogItemFactorySimple, eog_item_factory_simple,
90                         EogItemFactory, EOG_TYPE_ITEM_FACTORY);
91
92/* Class initialization function for the icon list item factory */
93static void
94eog_item_factory_simple_class_init (EogItemFactorySimpleClass *class)
95{
96        GObjectClass *object_class;
97        EogItemFactoryClass *ei_factory_class;
98
99        object_class = (GObjectClass *) class;
100        ei_factory_class = (EogItemFactoryClass *) class;
101
102        object_class->dispose = eog_item_factory_simple_dispose;
103        object_class->finalize = eog_item_factory_simple_finalize;
104
105        ei_factory_class->create_item = ii_factory_create_item;
106        ei_factory_class->update_item = ii_factory_update_item;
107        ei_factory_class->get_item_size = ii_factory_get_item_size;
108}
109
110/* Object initialization function for the icon list item factory */
111static void
112eog_item_factory_simple_instance_init (EogItemFactorySimple *factory)
113{
114        EogItemFactorySimplePrivate *priv;
115        EogSimpleMetrics *metrics;
116
117        priv = g_new0 (EogItemFactorySimplePrivate, 1);
118
119        metrics = g_new0 (EogSimpleMetrics, 1);
120        metrics->twidth = 92;
121        metrics->theight = 69;
122        metrics->cspace = 10;
123        metrics->border = 5;
124        priv->metrics = metrics;
125
126        factory->priv = priv;
127}
128
129/* Destroy handler for the icon list item factory */
130static void
131eog_item_factory_simple_dispose (GObject *object)
132{
133        EogItemFactorySimple *factory;
134        EogItemFactorySimplePrivate *priv;
135
136        g_return_if_fail (object != NULL);
137        g_return_if_fail (EOG_IS_ITEM_FACTORY_SIMPLE (object));
138
139        factory = EOG_ITEM_FACTORY_SIMPLE (object);
140        priv = factory->priv;
141       
142        if (priv->dummy)
143                g_object_unref (priv->dummy);
144        priv->dummy = NULL;
145       
146        if (priv->metrics)
147                g_free (priv->metrics);
148        priv->metrics = NULL;
149
150        if (priv->shaded_bgr)
151                g_object_unref (priv->shaded_bgr);
152        priv->shaded_bgr = NULL;
153
154        GNOME_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
155}
156
157static void
158eog_item_factory_simple_finalize (GObject *object)
159{
160        EogItemFactorySimple *factory;
161
162        g_return_if_fail (object != NULL);
163        g_return_if_fail (EOG_IS_ITEM_FACTORY_SIMPLE (object));
164
165        factory = EOG_ITEM_FACTORY_SIMPLE (object);
166        g_free (factory->priv);
167
168        GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
169}
170
171
172
173/* Default signal handlers */
174
175/* Called when an icon's main group is destroyed */
176static void
177icon_destroyed (GObject *object, gpointer data)
178{
179        IconItem *icon;
180
181        icon = (IconItem*)data;
182        g_free (icon);
183}
184
185/* Create_item handler for the icon list item factory */
186static GnomeCanvasItem *
187ii_factory_create_item (EogItemFactory *factory,
188                        GnomeCanvasGroup *parent, guint unique_id)
189{
190        IconItem *icon;
191
192        g_return_val_if_fail (factory != NULL, NULL);
193        g_return_val_if_fail (EOG_IS_ITEM_FACTORY_SIMPLE (factory), NULL);
194        g_return_val_if_fail (parent != NULL, NULL);
195        g_return_val_if_fail (GNOME_IS_CANVAS_GROUP (parent), NULL);
196
197        icon = g_new (IconItem, 1);
198
199        icon->id = unique_id;
200        icon->item = gnome_canvas_item_new (parent,
201                                            GNOME_TYPE_CANVAS_GROUP,
202                                            "x", 0.0,
203                                            "y", 0.0,
204                                            NULL);
205        g_object_set_data (G_OBJECT (icon->item), "IconItem", icon);
206        g_signal_connect (G_OBJECT (icon->item), "destroy",
207                          G_CALLBACK (icon_destroyed),
208                          icon);
209
210        /* Border */
211        icon->border = gnome_canvas_item_new (GNOME_CANVAS_GROUP (icon->item),
212                                              GNOME_TYPE_CANVAS_RECT,
213                                              NULL);
214       
215        /* background */
216        icon->bgr = gnome_canvas_item_new (GNOME_CANVAS_GROUP (icon->item),
217                                           GNOME_TYPE_CANVAS_PIXBUF,
218                                           NULL);
219
220        /* Image */
221        icon->image = gnome_canvas_item_new (GNOME_CANVAS_GROUP (icon->item),
222                                             GNOME_TYPE_CANVAS_PIXBUF,
223                                             NULL);
224        /* Caption */
225        icon->caption = gnome_canvas_item_new (GNOME_CANVAS_GROUP (icon->item),
226                                               GNOME_TYPE_CANVAS_TEXT,
227                                               NULL);
228
229        return icon->item;
230}
231
232#if 0
233/* Converts a GdkColor's RGB fields into a packed color integer */
234static guint
235color_to_rgba (GdkColor *color)
236{
237        return (((color->red & 0xff00) << 16)
238                | ((color->green & 0xff00) << 8)
239                | (color->blue & 0xff00)
240                | 0xff);
241}
242#endif
243
244static void
245create_shaded_background (GdkPixbuf *pbf)
246{
247        int width, height;
248        double dl;       
249        double tmp;
250        int x, y;
251        int n_cols;   
252        int cvd = 5;        /* color value decrement */
253        int light = 230;     /* gray value */
254        int dark  = 150;     /* gray value */
255        int ppc;             /* pixels per color */
256        guchar *buf;
257
258        g_return_if_fail (pbf != NULL);
259       
260        width =  gdk_pixbuf_get_width (pbf);
261        height = gdk_pixbuf_get_height (pbf);
262        buf = gdk_pixbuf_get_pixels (pbf);
263
264        tmp = width*width + height*height;
265        dl = sqrt (tmp);
266       
267        n_cols = (light - dark)/cvd;
268        ppc = dl / n_cols;
269
270        for (y = 0; y < height; y++) {
271                gint color;
272                gint ppcy; /* pixels per color yet */
273               
274                color = light - (cvd * (y/ppc));
275                ppcy =  y % ppc;
276 
277                for (x = 0; x < width; x++) {
278                        *buf = color;
279                        *(buf+1) = color;
280                        *(buf+2) = color;
281                        buf += 3;
282                       
283                        ppcy++;
284                        if (ppcy == ppc) {
285                                ppcy = 0;
286                                color = color - cvd;
287                        }
288                }
289        }
290}
291
292/* Shrink the string until its pixel width is <= max_width */
293static char*
294ensure_max_caption_width (gchar *str, PangoLayout *layout,  int max_width)
295{
296        char *result;
297        char *buffer;
298        const char *dots = "...";
299        int dot_width;
300        int len;
301        int str_len;
302        int px_width, px_height;
303
304        pango_layout_set_text (layout, str, -1);
305        pango_layout_get_pixel_size (layout, &px_width, &px_height);
306
307        if (px_width < max_width) return g_strdup (str);
308
309        pango_layout_set_text (layout, dots, -1);
310        pango_layout_get_pixel_size (layout, &dot_width, &px_height);
311
312        buffer =  g_strdup (str);
313        str_len = g_utf8_strlen (str, -1);
314        len = str_len;
315        g_assert (len > 0);
316
317        while (px_width > (max_width - dot_width)) {
318                len--;
319
320                if (len > 0) {
321                        g_free (buffer);
322                        buffer = g_new0 (gchar, str_len);
323                        buffer = g_utf8_strncpy (buffer, str, len);
324                }
325                else {
326                        break;
327                }
328
329                pango_layout_set_text (layout, buffer, -1);
330                pango_layout_get_pixel_size (layout, &px_width, &px_height);
331        }
332
333        result = g_strconcat (buffer, dots, NULL);
334        g_free (buffer);       
335
336        return result;
337}
338
339static void
340update_item_image (EogItemFactorySimple *factory, GnomeCanvasItem *item, CImage *cimage)
341{
342        EogItemFactorySimplePrivate *priv;
343        EogSimpleMetrics *metrics;
344        IconItem *icon;
345        int image_w, image_h;
346        int image_x, image_y;
347        double x1, y1;
348        GdkPixbuf *thumb;
349       
350        metrics = factory->priv->metrics;
351        priv = factory->priv;
352
353        icon = g_object_get_data (G_OBJECT (item), "IconItem");
354        g_assert (icon != NULL);
355
356        /* obtain thumbnail image */
357        if (cimage_has_thumbnail (cimage)) {
358                thumb = cimage_get_thumbnail (cimage);
359                image_w = gdk_pixbuf_get_width (thumb);
360                image_h = gdk_pixbuf_get_height (thumb);
361        }
362        else {
363                thumb = priv->dummy;
364                g_object_ref (thumb);
365                image_w = gdk_pixbuf_get_width (thumb);
366                image_h = gdk_pixbuf_get_height (thumb);
367        }
368        g_assert (thumb != NULL);
369
370        /* Configure image */
371        image_x = metrics->border + (metrics->twidth - image_w) / 2;
372        image_y = metrics->border + (metrics->theight - image_h) / 2;
373
374        gnome_canvas_item_set (icon->image,
375                               "pixbuf", thumb,
376                               "x", (double) image_x,
377                               "y", (double) image_y,
378                               "width_set", FALSE,
379                               "height_set", FALSE,
380                               NULL);
381
382        /* configure background */
383        x1 = metrics->border;
384        y1 = metrics->border;
385#if 0
386        x2 = x1 + metrics->twidth;
387        y2 = y1 + metrics->theight;
388#endif
389
390        gnome_canvas_item_set (icon->bgr,
391                               "pixbuf", priv->shaded_bgr,
392                               "x", (double) x1,
393                               "y", (double) y1,
394                               "width_set", FALSE,
395                               "height_set", FALSE,
396                               NULL);
397
398        g_object_unref (thumb);
399}
400
401static void
402update_item_caption (EogItemFactorySimple *factory, GnomeCanvasItem *item, CImage *cimage)
403{
404        GtkStyle *style;
405        PangoLayout  *layout;
406        IconItem *icon;
407        gchar *caption;
408        gchar *temp;
409        EogSimpleMetrics *metrics;
410        int caption_h;
411        int caption_w;
412        int caption_x;
413        int caption_y;
414
415        icon = g_object_get_data (G_OBJECT (item), "IconItem");
416        g_assert (icon != NULL);
417        metrics = factory->priv->metrics;
418       
419        layout = gtk_widget_create_pango_layout (GTK_WIDGET (icon->caption->canvas), NULL);
420        g_assert (layout != NULL);
421
422        /* obtain caption text */
423        if (cimage_has_caption (cimage)) {
424                caption = cimage_get_caption (cimage);
425        }
426        else {
427                GnomeVFSURI *uri;
428                uri = cimage_get_uri (cimage);
429                caption = g_path_get_basename (gnome_vfs_uri_get_path (uri));
430                gnome_vfs_uri_unref (uri);
431
432                if (!g_utf8_validate (caption, -1, 0)) {
433                        gchar *tmp = g_locale_to_utf8 (caption, -1, 0, 0, 0);
434                        g_free (caption);
435                        caption = tmp;
436                }
437
438                cimage_set_caption (cimage, caption);
439        }
440
441        temp = ensure_max_caption_width (caption, layout, metrics->twidth);
442        g_free (caption);
443        caption = temp;
444       
445        pango_layout_set_text (layout, caption, -1);
446        pango_layout_get_pixel_size (layout, &caption_w, &caption_h);
447
448        caption_x = metrics->border + (metrics->twidth - caption_w) / 2;
449        caption_y = metrics->border + metrics->theight + metrics->cspace;
450
451        style = gtk_widget_get_style (GTK_WIDGET (item->canvas));
452        g_assert (style != NULL);
453
454        gnome_canvas_item_set (icon->caption,
455                               "text", caption,
456                               "font_desc", style->font_desc,
457                               "anchor", GTK_ANCHOR_NW,
458                               "x", (double) caption_x,
459                               "y", (double) caption_y,
460                               "fill_color", "White",
461                               NULL);
462
463        g_object_unref (layout);
464        g_free (caption);
465}       
466
467static void
468update_item_selection (EogItemFactorySimple *factory, GnomeCanvasItem *item, CImage *cimage)
469{
470        IconItem *icon;
471        int item_w, item_h;
472
473        ii_factory_get_item_size (EOG_ITEM_FACTORY (factory), &item_w, &item_h);
474
475        icon = g_object_get_data (G_OBJECT (item), "IconItem");
476        g_assert (icon != NULL);
477
478        if (cimage_is_selected (cimage))
479                gnome_canvas_item_set (icon->border,
480                                       "x1", 0.0,
481                                       "y1", 0.0,
482                                       "x2", (double) item_w,
483                                       "y2", (double) item_h,
484                                       "outline_color", "Red",
485                                       "fill_color",  "Black",
486                                       "width_pixels", 2,
487                                       NULL);
488        else
489                gnome_canvas_item_set (icon->border,
490                                       "x1", 0.0,
491                                       "y1", 0.0,
492                                       "x2", (double) item_w,
493                                       "y2", (double) item_h,
494                                       "outline_color", "DarkBlue",
495                                       "fill_color", "Black",
496                                       "width_pixels", 2,
497                                       NULL);
498
499}
500
501/* Configure_item handler for the icon list item factory */
502static void
503ii_factory_update_item (EogItemFactory *factory,
504                        EogCollectionModel *model,
505                        GnomeCanvasItem *item,
506                        EogItemUpdateHint hint)
507{
508        EogItemFactorySimple *ii_factory;
509        CImage *cimage = NULL;
510        IconItem *icon;
511
512        g_return_if_fail (factory != NULL);
513        g_return_if_fail (EOG_IS_ITEM_FACTORY_SIMPLE (factory));
514        g_return_if_fail (item != NULL);
515        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
516        g_return_if_fail (model != NULL);
517        g_return_if_fail (EOG_IS_COLLECTION_MODEL (model));
518
519        ii_factory = EOG_ITEM_FACTORY_SIMPLE (factory);
520       
521        icon = g_object_get_data (G_OBJECT (item), "IconItem");
522        cimage = eog_collection_model_get_image (model, icon->id);
523        g_return_if_fail (cimage != NULL);
524
525        if ((hint & EOG_ITEM_UPDATE_IMAGE) == EOG_ITEM_UPDATE_IMAGE) {
526                update_item_image (ii_factory, item, cimage);
527        }
528
529        if ((hint & EOG_ITEM_UPDATE_CAPTION) == EOG_ITEM_UPDATE_CAPTION) {
530                update_item_caption (ii_factory, item, cimage);
531        }
532
533        if ((hint & EOG_ITEM_UPDATE_SELECTION_STATE) == EOG_ITEM_UPDATE_SELECTION_STATE) {
534                update_item_selection (ii_factory, item, cimage);
535        }
536}
537
538/* Get_item_size handler for the icon list item factory */
539static void
540ii_factory_get_item_size (EogItemFactory *factory,
541                          gint *width, gint *height)
542{
543        EogItemFactorySimple *ii_factory;
544        EogSimpleMetrics *metrics;
545
546        g_return_if_fail (factory != NULL);
547        g_return_if_fail (EOG_IS_ITEM_FACTORY_SIMPLE (factory));
548
549        ii_factory = EOG_ITEM_FACTORY_SIMPLE (factory);
550        metrics = ii_factory->priv->metrics;
551
552        *width = metrics->twidth + 2*metrics->border;
553        *height = metrics->theight + 2*metrics->border +
554                metrics->cspace + 12 /* font height; FIXME don't hardcode this */;
555}
556
557
558
559static void
560shade_bgr_destroy_notify_cb (guchar *pixels, gpointer data)
561{
562        g_free (pixels);
563}
564
565static EogItemFactorySimple*
566eog_item_factory_simple_construct (EogItemFactorySimple *factory)
567{
568        EogItemFactorySimplePrivate *priv;
569        char *dummy_file;
570        guchar *buffer;
571
572        priv = factory->priv;
573
574        /* load dummy pixmap file */
575        dummy_file = gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_PIXMAP,
576                                                "gnome-eog.png", TRUE, NULL);
577        priv->dummy = gdk_pixbuf_new_from_file (dummy_file, NULL);
578        g_free (dummy_file);
579
580        buffer = g_new0 (guchar, 3*priv->metrics->twidth * priv->metrics->theight);
581        priv->shaded_bgr = gdk_pixbuf_new_from_data (buffer,
582                                                     GDK_COLORSPACE_RGB,
583                                                     FALSE,
584                                                     8,
585                                                     priv->metrics->twidth,
586                                                     priv->metrics->theight,
587                                                     3 * priv->metrics->twidth,
588                                                     (GdkPixbufDestroyNotify) shade_bgr_destroy_notify_cb,
589                                                     NULL);
590        g_object_ref (priv->shaded_bgr);
591        create_shaded_background (priv->shaded_bgr);
592
593        return factory;
594}
595
596
597EogItemFactorySimple *
598eog_item_factory_simple_new (void)
599{
600        EogItemFactorySimple *factory;
601
602        factory = EOG_ITEM_FACTORY_SIMPLE (g_object_new (EOG_TYPE_ITEM_FACTORY_SIMPLE, NULL));
603        return eog_item_factory_simple_construct (factory);
604}
605
606/**
607 * eog_item_factory_simple_set_item_metrics:
608 * @factory: An icon list item factory.
609 * @item_width: Total width of items, in pixels.
610 * @item_height: Total height of items, in pixels.
611 * @image_width: Maximum width of images for icons, in pixels.
612 * @image_height: Maximum height of images for icons, in pixels.
613 *
614 * Sets the metrics of the items that will be created in the future by an icon
615 * list item factory.  This includes the total size of items and the maximum
616 * size of icon images.
617 **/
618void
619eog_item_factory_simple_set_metrics (EogItemFactorySimple *factory,
620                                     EogSimpleMetrics *metrics)
621{
622        EogItemFactorySimplePrivate *priv;
623
624        g_return_if_fail (factory != NULL);
625        g_return_if_fail (EOG_IS_ITEM_FACTORY_SIMPLE (factory));
626        g_return_if_fail (metrics->twidth > 0);
627        g_return_if_fail (metrics->theight > 0);
628        g_return_if_fail (metrics->cspace >= 0);
629        g_return_if_fail (metrics->border >= 0);
630
631        priv = factory->priv;
632
633        if (priv->metrics)
634                g_free (priv->metrics);
635       
636        priv->metrics = metrics;
637
638        eog_item_factory_configuration_changed (EOG_ITEM_FACTORY (factory));
639}
640
641EogSimpleMetrics*
642eog_item_factory_simple_get_metrics (EogItemFactorySimple *factory)
643{
644        g_return_val_if_fail (factory != NULL, NULL);
645        g_return_val_if_fail (EOG_IS_ITEM_FACTORY_SIMPLE (factory), NULL);
646
647        return factory->priv->metrics;
648}
Note: See TracBrowser for help on using the repository browser.