a boatload of minor and middle-sized changes to try to speed up undo. imperfect,...
[ardour.git] / gtk2_ardour / canvas-imageframe.c
1 /* Image item type for GnomeCanvas widget
2  *
3  * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget.  Tk is
4  * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
5  *
6  * Copyright (C) 1998 The Free Software Foundation
7  *
8  * Author: Federico Mena <federico@nuclecu.unam.mx>
9  */
10
11
12 #include <string.h> /* for memcpy() */
13 #include <math.h>
14 #include <stdio.h>
15 #include "libart_lgpl/art_misc.h"
16 #include "libart_lgpl/art_affine.h"
17 #include "libart_lgpl/art_pixbuf.h"
18 #include "libart_lgpl/art_rgb_pixbuf_affine.h"
19 #include "canvas-imageframe.h"
20 #include <libgnomecanvas/gnome-canvas-util.h>
21 #include "gettext.h"
22 #define _(Text)  dgettext (PACKAGE,Text)
23
24 //GTK2FIX
25 //#include <libgnomecanvas/gnome-canvastypebuiltins.h>
26
27
28 enum {
29         PROP_0,
30         PROP_PIXBUF,
31         PROP_X,
32         PROP_Y,
33         PROP_WIDTH,
34         PROP_HEIGHT,
35         PROP_DRAWWIDTH,
36         PROP_ANCHOR
37 };
38
39
40 static void gnome_canvas_imageframe_class_init(GnomeCanvasImageFrameClass* class) ;
41 static void gnome_canvas_imageframe_init(GnomeCanvasImageFrame* image) ;
42 static void gnome_canvas_imageframe_destroy(GtkObject* object) ;
43 static void gnome_canvas_imageframe_set_property(GObject* object,
44                                                  guint            prop_id,
45                                                  const GValue   *value,
46                                                  GParamSpec     *pspec);
47 static void gnome_canvas_imageframe_get_property(GObject* object,
48                                                  guint           prop_id,
49                                                  GValue         *value,
50                                                  GParamSpec     *pspec);
51 static void gnome_canvas_imageframe_update(GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) ;
52 static void gnome_canvas_imageframe_realize(GnomeCanvasItem *item) ;
53 static void gnome_canvas_imageframe_unrealize(GnomeCanvasItem *item) ;
54 static void gnome_canvas_imageframe_draw(GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) ;
55 static double gnome_canvas_imageframe_point(GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item) ;
56 static void gnome_canvas_imageframe_bounds(GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2) ;
57 static void gnome_canvas_imageframe_render(GnomeCanvasItem *item, GnomeCanvasBuf *buf) ;
58
59 static GnomeCanvasItemClass *parent_class;
60
61
62 GType
63 gnome_canvas_imageframe_get_type (void)
64 {
65         static GType imageframe_type = 0;
66
67         if (!imageframe_type) {
68                 GtkTypeInfo imageframe_info = {
69                         "GnomeCanvasImageFrame",
70                         sizeof (GnomeCanvasImageFrame),
71                         sizeof (GnomeCanvasImageFrameClass),
72                         (GtkClassInitFunc) gnome_canvas_imageframe_class_init,
73                         (GtkObjectInitFunc) gnome_canvas_imageframe_init,
74                         NULL, /* reserved_1 */
75                         NULL, /* reserved_2 */
76                         (GtkClassInitFunc) NULL
77                 };
78
79                 imageframe_type = gtk_type_unique (gnome_canvas_item_get_type (), &imageframe_info);
80         }
81
82         return imageframe_type;
83 }
84
85 static void
86 gnome_canvas_imageframe_class_init (GnomeCanvasImageFrameClass *class)
87 {
88         GObjectClass *gobject_class;
89         GtkObjectClass *object_class;
90         GnomeCanvasItemClass *item_class;
91
92         gobject_class = (GObjectClass *) class;
93         object_class = (GtkObjectClass *) class;
94         item_class = (GnomeCanvasItemClass *) class;
95
96         parent_class = gtk_type_class (gnome_canvas_item_get_type ());
97
98         gobject_class->set_property = gnome_canvas_imageframe_set_property;
99         gobject_class->get_property = gnome_canvas_imageframe_get_property;
100
101         g_object_class_install_property (gobject_class,
102                                          PROP_PIXBUF,
103                                          g_param_spec_pointer ("pixbuf",
104                                                              _("pixbuf"),
105                                                              _("the pixbuf"),
106                                                              G_PARAM_WRITABLE));
107         g_object_class_install_property (gobject_class,
108                                          PROP_X,
109                                          g_param_spec_double ("x",
110                                                               _("x"),
111                                                               _("x coordinate of upper left corner of rect"),
112                                                               -G_MAXDOUBLE,
113                                                               G_MAXDOUBLE,
114                                                               0.0,
115                                                               G_PARAM_READWRITE));
116
117         g_object_class_install_property (gobject_class,
118                                          PROP_Y,
119                                          g_param_spec_double ("y",
120                                                               _("y"),
121                                                               _("y coordinate of upper left corner of rect "),
122                                                               -G_MAXDOUBLE,
123                                                               G_MAXDOUBLE,
124                                                               0.0,
125                                                               G_PARAM_READWRITE));
126         g_object_class_install_property (gobject_class,
127                                          PROP_WIDTH,
128                                          g_param_spec_double ("width",
129                                                               _("width"),
130                                                               _("the width"),
131                                                               -G_MAXDOUBLE,
132                                                               G_MAXDOUBLE,
133                                                               0.0,
134                                                               G_PARAM_READWRITE));
135
136         g_object_class_install_property (gobject_class,
137                                          PROP_DRAWWIDTH,
138                                          g_param_spec_double ("drawwidth",
139                                                               _("drawwidth"),
140                                                               _("drawn width"),
141                                                               -G_MAXDOUBLE,
142                                                               G_MAXDOUBLE,
143                                                               0.0,
144                                                               G_PARAM_READWRITE));
145         g_object_class_install_property (gobject_class,
146                                          PROP_HEIGHT,
147                                          g_param_spec_double ("height",
148                                                               _("height"),
149                                                               _("the height"),
150                                                               -G_MAXDOUBLE,
151                                                               G_MAXDOUBLE,
152                                                               0.0,
153                                                               G_PARAM_READWRITE));
154         g_object_class_install_property (gobject_class,
155                                          PROP_ANCHOR,
156                                          g_param_spec_enum ("anchor",
157                                                             _("anchor"),
158                                                             _("the anchor"),
159                                                             GTK_TYPE_ANCHOR_TYPE,
160                                                             GTK_ANCHOR_NW,
161                                                             G_PARAM_READWRITE));
162
163         object_class->destroy = gnome_canvas_imageframe_destroy;
164
165         item_class->update = gnome_canvas_imageframe_update;
166         item_class->realize = gnome_canvas_imageframe_realize;
167         item_class->unrealize = gnome_canvas_imageframe_unrealize;
168         item_class->draw = gnome_canvas_imageframe_draw;
169         item_class->point = gnome_canvas_imageframe_point;
170         item_class->bounds = gnome_canvas_imageframe_bounds;
171         item_class->render = gnome_canvas_imageframe_render;
172 }
173
174 static void
175 gnome_canvas_imageframe_init (GnomeCanvasImageFrame *image)
176 {
177         image->x = 0.0;
178         image->y = 0.0;
179         image->width = 0.0;
180         image->height = 0.0;
181         image->drawwidth = 0.0;
182         image->anchor = GTK_ANCHOR_CENTER;
183 }
184
185 static void
186 gnome_canvas_imageframe_destroy (GtkObject *object)
187 {
188         GnomeCanvasImageFrame *image;
189
190         g_return_if_fail (object != NULL);
191         g_return_if_fail (GNOME_CANVAS_IS_CANVAS_IMAGEFRAME (object));
192
193         image = GNOME_CANVAS_IMAGEFRAME (object);
194
195         image->cwidth = 0;
196         image->cheight = 0;
197
198         if (image->pixbuf)
199         {
200                 art_pixbuf_free (image->pixbuf);
201                 image->pixbuf = NULL;
202         }
203
204         if(GTK_OBJECT_CLASS (parent_class)->destroy)
205         {
206                 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
207         }
208 }
209
210 /* Get's the image bounds expressed as item-relative coordinates. */
211 static void
212 get_bounds_item_relative (GnomeCanvasImageFrame *image, double *px1, double *py1, double *px2, double *py2)
213 {
214         GnomeCanvasItem *item;
215         double x, y;
216
217         item = GNOME_CANVAS_ITEM (image);
218
219         /* Get item coordinates */
220
221         x = image->x;
222         y = image->y;
223
224         /* Anchor image */
225
226         switch (image->anchor) {
227         case GTK_ANCHOR_NW:
228         case GTK_ANCHOR_W:
229         case GTK_ANCHOR_SW:
230                 break;
231
232         case GTK_ANCHOR_N:
233         case GTK_ANCHOR_CENTER:
234         case GTK_ANCHOR_S:
235                 x -= image->width / 2;
236                 break;
237
238         case GTK_ANCHOR_NE:
239         case GTK_ANCHOR_E:
240         case GTK_ANCHOR_SE:
241                 x -= image->width;
242                 break;
243         }
244
245         switch (image->anchor) {
246         case GTK_ANCHOR_NW:
247         case GTK_ANCHOR_N:
248         case GTK_ANCHOR_NE:
249                 break;
250
251         case GTK_ANCHOR_W:
252         case GTK_ANCHOR_CENTER:
253         case GTK_ANCHOR_E:
254                 y -= image->height / 2;
255                 break;
256
257         case GTK_ANCHOR_SW:
258         case GTK_ANCHOR_S:
259         case GTK_ANCHOR_SE:
260                 y -= image->height;
261                 break;
262         }
263
264         /* Bounds */
265
266         *px1 = x;
267         *py1 = y;
268         *px2 = x + image->width;
269         *py2 = y + image->height;
270 }
271
272 static void
273 gnome_canvas_imageframe_set_property (GObject *object,
274                                       guint            prop_id,
275                                       const GValue   *value,
276                                       GParamSpec     *pspec)
277 {
278         GnomeCanvasItem *item;
279         GnomeCanvasImageFrame *image;
280         int update;
281         int calc_bounds;
282
283         item = GNOME_CANVAS_ITEM (object);
284         image = GNOME_CANVAS_IMAGEFRAME (object);
285
286         update = FALSE;
287         calc_bounds = FALSE;
288
289         switch (prop_id) {
290         case PROP_PIXBUF:
291                 if (item->canvas->aa && g_value_get_pointer (value)) {
292                         if (image->pixbuf != NULL)
293                                 art_pixbuf_free (image->pixbuf);
294                         image->pixbuf = g_value_get_pointer (value);
295                 }
296                 update = TRUE;
297                 break;
298
299         case PROP_X:
300                 image->x = g_value_get_double (value);
301                 update = TRUE;
302                 break;
303
304         case PROP_Y:
305                 image->y = g_value_get_double (value);
306                 update = TRUE;
307                 break;
308
309         case PROP_WIDTH:
310                 image->width = fabs (g_value_get_double (value));
311                 update = TRUE;
312                 break;
313
314         case PROP_HEIGHT:
315                 image->height = fabs (g_value_get_double (value));
316                 update = TRUE;
317                 break;
318
319         case PROP_DRAWWIDTH:
320                 image->drawwidth = fabs (g_value_get_double (value));
321                 update = TRUE;
322                 break;
323
324         case PROP_ANCHOR:
325                 image->anchor = g_value_get_enum (value);
326                 update = TRUE;
327                 break;
328
329         default:
330                 break;
331         }
332
333         if (update)
334                 gnome_canvas_item_request_update (item);
335 }
336
337 static void
338 gnome_canvas_imageframe_get_property (GObject *object,
339                                       guint            prop_id,
340                                       GValue   *value,
341                                       GParamSpec     *pspec)
342 {
343         GnomeCanvasImageFrame *image;
344
345         image = GNOME_CANVAS_IMAGEFRAME (object);
346
347         switch (prop_id) {
348
349         case PROP_X:
350                 g_value_set_double (value, image->x);
351                 break;
352
353         case PROP_Y:
354                 g_value_set_double (value, image->y);
355                 break;
356
357         case PROP_WIDTH:
358                 g_value_set_double (value, image->width);
359                 break;
360
361         case PROP_HEIGHT:
362                 g_value_set_double (value, image->height);
363                 break;
364
365         case PROP_DRAWWIDTH:
366                 g_value_set_double (value, image->drawwidth);
367                 break;
368
369         case PROP_ANCHOR:
370                 g_value_set_enum (value, image->anchor);
371                 break;
372
373         default:
374                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
375                 break;
376         }
377 }
378
379 static void
380 gnome_canvas_imageframe_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
381 {
382         GnomeCanvasImageFrame *image;
383         ArtDRect i_bbox, c_bbox;
384         int w = 0;
385         int h = 0;
386
387         image = GNOME_CANVAS_IMAGEFRAME (item);
388
389         if (parent_class->update)
390                 (* parent_class->update) (item, affine, clip_path, flags);
391
392         /* only works for non-rotated, non-skewed transforms */
393         image->cwidth = (int) (image->width * affine[0] + 0.5);
394         image->cheight = (int) (image->height * affine[3] + 0.5);
395
396         if (image->pixbuf) {
397                 image->need_recalc = TRUE ;
398         }
399
400         get_bounds_item_relative (image, &i_bbox.x0, &i_bbox.y0, &i_bbox.x1, &i_bbox.y1);
401         art_drect_affine_transform (&c_bbox, &i_bbox, affine);
402
403         /* these values only make sense in the non-rotated, non-skewed case */
404         image->cx = c_bbox.x0;
405         image->cy = c_bbox.y0;
406
407         /* add a fudge factor */
408         c_bbox.x0--;
409         c_bbox.y0--;
410         c_bbox.x1++;
411         c_bbox.y1++;
412
413         gnome_canvas_update_bbox (item, c_bbox.x0, c_bbox.y0, c_bbox.x1, c_bbox.y1);
414
415         if (image->pixbuf) {
416                 w = image->pixbuf->width;
417                 h = image->pixbuf->height;
418         }
419
420         image->affine[0] = (affine[0] * image->width) / w;
421         image->affine[1] = (affine[1] * image->height) / h;
422         image->affine[2] = (affine[2] * image->width) / w;
423         image->affine[3] = (affine[3] * image->height) / h;
424         image->affine[4] = i_bbox.x0 * affine[0] + i_bbox.y0 * affine[2] + affine[4];
425         image->affine[5] = i_bbox.x0 * affine[1] + i_bbox.y0 * affine[3] + affine[5];
426 }
427
428 static void
429 gnome_canvas_imageframe_realize (GnomeCanvasItem *item)
430 {
431         GnomeCanvasImageFrame *image;
432
433         image = GNOME_CANVAS_IMAGEFRAME (item);
434
435         if (parent_class->realize)
436                 (* parent_class->realize) (item);
437
438 }
439
440 static void
441 gnome_canvas_imageframe_unrealize (GnomeCanvasItem *item)
442 {
443         GnomeCanvasImageFrame *image;
444
445         image = GNOME_CANVAS_IMAGEFRAME(item);
446
447         if (parent_class->unrealize)
448                 (* parent_class->unrealize) (item);
449 }
450
451 static void
452 recalc_if_needed (GnomeCanvasImageFrame *image)
453 {}
454
455 static void
456 gnome_canvas_imageframe_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
457                          int x, int y, int width, int height)
458 {
459 }
460
461 static double
462 gnome_canvas_imageframe_point (GnomeCanvasItem *item, double x, double y,
463                           int cx, int cy, GnomeCanvasItem **actual_item)
464 {
465         GnomeCanvasImageFrame *image;
466         int x1, y1, x2, y2;
467         int dx, dy;
468
469         image = GNOME_CANVAS_IMAGEFRAME (item);
470
471         *actual_item = item;
472
473         recalc_if_needed (image);
474
475         x1 = image->cx - item->canvas->close_enough;
476         y1 = image->cy - item->canvas->close_enough;
477         x2 = image->cx + image->cwidth - 1 + item->canvas->close_enough;
478         y2 = image->cy + image->cheight - 1 + item->canvas->close_enough;
479
480         /* Hard case: is point inside image's gravity region? */
481
482         //if ((cx >= x1) && (cy >= y1) && (cx <= x2) && (cy <= y2))
483                 //return dist_to_mask (image, cx, cy) / item->canvas->pixels_per_unit;
484
485         /* Point is outside image */
486
487         x1 += item->canvas->close_enough;
488         y1 += item->canvas->close_enough;
489         x2 -= item->canvas->close_enough;
490         y2 -= item->canvas->close_enough;
491
492         if (cx < x1)
493                 dx = x1 - cx;
494         else if (cx > x2)
495                 dx = cx - x2;
496         else
497                 dx = 0;
498
499         if (cy < y1)
500                 dy = y1 - cy;
501         else if (cy > y2)
502                 dy = cy - y2;
503         else
504                 dy = 0;
505
506         return sqrt (dx * dx + dy * dy) / item->canvas->pixels_per_unit;
507 }
508
509 static void
510 gnome_canvas_imageframe_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
511 {
512         GnomeCanvasImageFrame *image;
513
514         image = GNOME_CANVAS_IMAGEFRAME (item);
515
516         *x1 = image->x;
517         *y1 = image->y;
518
519         switch (image->anchor) {
520         case GTK_ANCHOR_NW:
521         case GTK_ANCHOR_W:
522         case GTK_ANCHOR_SW:
523                 break;
524
525         case GTK_ANCHOR_N:
526         case GTK_ANCHOR_CENTER:
527         case GTK_ANCHOR_S:
528                 *x1 -= image->width / 2.0;
529                 break;
530
531         case GTK_ANCHOR_NE:
532         case GTK_ANCHOR_E:
533         case GTK_ANCHOR_SE:
534                 *x1 -= image->width;
535                 break;
536         }
537
538         switch (image->anchor) {
539         case GTK_ANCHOR_NW:
540         case GTK_ANCHOR_N:
541         case GTK_ANCHOR_NE:
542                 break;
543
544         case GTK_ANCHOR_W:
545         case GTK_ANCHOR_CENTER:
546         case GTK_ANCHOR_E:
547                 *y1 -= image->height / 2.0;
548                 break;
549
550         case GTK_ANCHOR_SW:
551         case GTK_ANCHOR_S:
552         case GTK_ANCHOR_SE:
553                 *y1 -= image->height;
554                 break;
555         }
556
557         *x2 = *x1 + image->width;
558         *y2 = *y1 + image->height;
559 }
560
561 static void
562 gnome_canvas_imageframe_render      (GnomeCanvasItem *item, GnomeCanvasBuf *buf)
563 {
564         GnomeCanvasImageFrame *image;
565
566         image = GNOME_CANVAS_IMAGEFRAME (item);
567
568         gnome_canvas_buf_ensure_buf (buf);
569
570 #ifdef VERBOSE
571         {
572                 char str[128];
573                 art_affine_to_string (str, image->affine);
574                 g_print ("gnome_canvas_imageframe_render %s\n", str);
575         }
576 #endif
577
578         art_rgb_pixbuf_affine (buf->buf,
579                         buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1,
580                         buf->buf_rowstride,
581                         image->pixbuf,
582                         image->affine,
583                         ART_FILTER_NEAREST, NULL);
584
585         buf->is_bg = 0;
586 }