Gnime::Canvas::Points init fix
[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 //GTK2FIX
22 //#include <libgnomecanvas/gnome-canvastypebuiltins.h>
23
24
25 enum {
26         ARG_0,
27         ARG_PIXBUF,
28         ARG_X,
29         ARG_Y,
30         ARG_WIDTH,
31         ARG_HEIGHT,
32         ARG_DRAWWIDTH,
33         ARG_ANCHOR
34 };
35
36
37 static void gnome_canvas_imageframe_class_init(GnomeCanvasImageFrameClass* class) ;
38 static void gnome_canvas_imageframe_init(GnomeCanvasImageFrame* image) ;
39 static void gnome_canvas_imageframe_destroy(GtkObject* object) ;
40 static void gnome_canvas_imageframe_set_arg(GtkObject* object, GtkArg* arg, guint arg_id) ;
41 static void gnome_canvas_imageframe_get_arg(GtkObject* object, GtkArg* arg, guint arg_id) ;
42
43 static void gnome_canvas_imageframe_update(GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) ;
44 static void gnome_canvas_imageframe_realize(GnomeCanvasItem *item) ;
45 static void gnome_canvas_imageframe_unrealize(GnomeCanvasItem *item) ;
46 static void gnome_canvas_imageframe_draw(GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) ;
47 static double gnome_canvas_imageframe_point(GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item) ;
48 static void gnome_canvas_imageframe_bounds(GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2) ;
49 static void gnome_canvas_imageframe_render(GnomeCanvasItem *item, GnomeCanvasBuf *buf) ;
50
51 static GnomeCanvasItemClass *parent_class;
52
53
54 GtkType
55 gnome_canvas_imageframe_get_type (void)
56 {
57         static GtkType imageframe_type = 0;
58
59         if (!imageframe_type) {
60                 GtkTypeInfo imageframe_info = {
61                         "GnomeCanvasImageFrame",
62                         sizeof (GnomeCanvasImageFrame),
63                         sizeof (GnomeCanvasImageFrameClass),
64                         (GtkClassInitFunc) gnome_canvas_imageframe_class_init,
65                         (GtkObjectInitFunc) gnome_canvas_imageframe_init,
66                         NULL, /* reserved_1 */
67                         NULL, /* reserved_2 */
68                         (GtkClassInitFunc) NULL
69                 };
70
71                 imageframe_type = gtk_type_unique (gnome_canvas_item_get_type (), &imageframe_info);
72         }
73
74         return imageframe_type;
75 }
76
77 static void
78 gnome_canvas_imageframe_class_init (GnomeCanvasImageFrameClass *class)
79 {
80         GtkObjectClass *object_class;
81         GnomeCanvasItemClass *item_class;
82
83         object_class = (GtkObjectClass *) class;
84         item_class = (GnomeCanvasItemClass *) class;
85
86         parent_class = gtk_type_class (gnome_canvas_item_get_type ());
87
88         gtk_object_add_arg_type ("GnomeCanvasImageFrame::pixbuf", GTK_TYPE_BOXED, GTK_ARG_WRITABLE, ARG_PIXBUF);
89         gtk_object_add_arg_type ("GnomeCanvasImageFrame::x", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X);
90         gtk_object_add_arg_type ("GnomeCanvasImageFrame::y", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y);
91         gtk_object_add_arg_type ("GnomeCanvasImageFrame::width", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_WIDTH);
92         gtk_object_add_arg_type ("GnomeCanvasImageFrame::drawwidth", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_DRAWWIDTH);
93         gtk_object_add_arg_type ("GnomeCanvasImageFrame::height", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_HEIGHT);
94         gtk_object_add_arg_type ("GnomeCanvasImageFrame::anchor", GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, ARG_ANCHOR);
95
96         object_class->destroy = gnome_canvas_imageframe_destroy;
97         object_class->set_arg = gnome_canvas_imageframe_set_arg;
98         object_class->get_arg = gnome_canvas_imageframe_get_arg;
99
100         item_class->update = gnome_canvas_imageframe_update;
101         item_class->realize = gnome_canvas_imageframe_realize;
102         item_class->unrealize = gnome_canvas_imageframe_unrealize;
103         item_class->draw = gnome_canvas_imageframe_draw;
104         item_class->point = gnome_canvas_imageframe_point;
105         item_class->bounds = gnome_canvas_imageframe_bounds;
106         item_class->render = gnome_canvas_imageframe_render;
107 }
108
109 static void
110 gnome_canvas_imageframe_init (GnomeCanvasImageFrame *image)
111 {
112         image->x = 0.0;
113         image->y = 0.0;
114         image->width = 0.0;
115         image->height = 0.0;
116         image->drawwidth = 0.0;
117         image->anchor = GTK_ANCHOR_CENTER;
118         // GTK2FIX
119         // GNOME_CANVAS_ITEM(image)->object.flags |= GNOME_CANVAS_ITEM_NO_AUTO_REDRAW;
120 }
121
122 static void
123 gnome_canvas_imageframe_destroy (GtkObject *object)
124 {
125         GnomeCanvasImageFrame *image;
126
127         g_return_if_fail (object != NULL);
128         g_return_if_fail (GNOME_CANVAS_IS_CANVAS_IMAGEFRAME (object));
129
130         image = GNOME_CANVAS_IMAGEFRAME (object);
131         
132         image->cwidth = 0;
133         image->cheight = 0;
134
135         if (image->pixbuf)
136         {
137                 art_pixbuf_free (image->pixbuf);
138                 image->pixbuf = NULL;
139         }
140
141         if(GTK_OBJECT_CLASS (parent_class)->destroy)
142         {
143                 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
144         }
145 }
146
147 /* Get's the image bounds expressed as item-relative coordinates. */
148 static void
149 get_bounds_item_relative (GnomeCanvasImageFrame *image, double *px1, double *py1, double *px2, double *py2)
150 {
151         GnomeCanvasItem *item;
152         double x, y;
153
154         item = GNOME_CANVAS_ITEM (image);
155
156         /* Get item coordinates */
157
158         x = image->x;
159         y = image->y;
160
161         /* Anchor image */
162
163         switch (image->anchor) {
164         case GTK_ANCHOR_NW:
165         case GTK_ANCHOR_W:
166         case GTK_ANCHOR_SW:
167                 break;
168
169         case GTK_ANCHOR_N:
170         case GTK_ANCHOR_CENTER:
171         case GTK_ANCHOR_S:
172                 x -= image->width / 2;
173                 break;
174
175         case GTK_ANCHOR_NE:
176         case GTK_ANCHOR_E:
177         case GTK_ANCHOR_SE:
178                 x -= image->width;
179                 break;
180         }
181
182         switch (image->anchor) {
183         case GTK_ANCHOR_NW:
184         case GTK_ANCHOR_N:
185         case GTK_ANCHOR_NE:
186                 break;
187
188         case GTK_ANCHOR_W:
189         case GTK_ANCHOR_CENTER:
190         case GTK_ANCHOR_E:
191                 y -= image->height / 2;
192                 break;
193
194         case GTK_ANCHOR_SW:
195         case GTK_ANCHOR_S:
196         case GTK_ANCHOR_SE:
197                 y -= image->height;
198                 break;
199         }
200
201         /* Bounds */
202
203         *px1 = x;
204         *py1 = y;
205         *px2 = x + image->width;
206         *py2 = y + image->height;
207 }
208
209 static void
210 gnome_canvas_imageframe_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
211 {
212         GnomeCanvasItem *item;
213         GnomeCanvasImageFrame *image;
214         int update;
215         int calc_bounds;
216
217         item = GNOME_CANVAS_ITEM (object);
218         image = GNOME_CANVAS_IMAGEFRAME (object);
219
220         update = FALSE;
221         calc_bounds = FALSE;
222
223         switch (arg_id) {
224         case ARG_PIXBUF:
225                 if (item->canvas->aa && GTK_VALUE_BOXED (*arg)) {
226                         if (image->pixbuf != NULL)
227                                 art_pixbuf_free (image->pixbuf);
228                         image->pixbuf = GTK_VALUE_BOXED (*arg);
229                 }
230                 update = TRUE;
231                 break;
232
233         case ARG_X:
234                 image->x = GTK_VALUE_DOUBLE (*arg);
235                 update = TRUE;
236                 break;
237
238         case ARG_Y:
239                 image->y = GTK_VALUE_DOUBLE (*arg);
240                 update = TRUE;
241                 break;
242
243         case ARG_WIDTH:
244                 image->width = fabs (GTK_VALUE_DOUBLE (*arg));
245                 update = TRUE;
246                 break;
247
248         case ARG_HEIGHT:
249                 image->height = fabs (GTK_VALUE_DOUBLE (*arg));
250                 update = TRUE;
251                 break;
252                 
253         case ARG_DRAWWIDTH:
254                 image->drawwidth = fabs (GTK_VALUE_DOUBLE (*arg));
255                 update = TRUE;
256                 break;
257
258         case ARG_ANCHOR:
259                 image->anchor = GTK_VALUE_ENUM (*arg);
260                 update = TRUE;
261                 break;
262
263         default:
264                 break;
265         }
266
267         if (update)
268                 gnome_canvas_item_request_update (item);
269 }
270
271 static void
272 gnome_canvas_imageframe_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
273 {
274         GnomeCanvasImageFrame *image;
275
276         image = GNOME_CANVAS_IMAGEFRAME (object);
277
278         switch (arg_id) {
279
280         case ARG_X:
281                 GTK_VALUE_DOUBLE (*arg) = image->x;
282                 break;
283
284         case ARG_Y:
285                 GTK_VALUE_DOUBLE (*arg) = image->y;
286                 break;
287
288         case ARG_WIDTH:
289                 GTK_VALUE_DOUBLE (*arg) = image->width;
290                 break;
291
292         case ARG_HEIGHT:
293                 GTK_VALUE_DOUBLE (*arg) = image->height;
294                 break;
295                 
296         case ARG_DRAWWIDTH:
297                 GTK_VALUE_DOUBLE (*arg) = image->drawwidth;
298                 break;
299
300         case ARG_ANCHOR:
301                 GTK_VALUE_ENUM (*arg) = image->anchor;
302                 break;
303
304         default:
305                 arg->type = GTK_TYPE_INVALID;
306                 break;
307         }
308 }
309
310 static void
311 gnome_canvas_imageframe_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
312 {
313         GnomeCanvasImageFrame *image;
314         ArtDRect i_bbox, c_bbox;
315         int w = 0;
316         int h = 0;
317
318         image = GNOME_CANVAS_IMAGEFRAME (item);
319
320         if (parent_class->update)
321                 (* parent_class->update) (item, affine, clip_path, flags);
322
323         /* only works for non-rotated, non-skewed transforms */
324         image->cwidth = (int) (image->width * affine[0] + 0.5);
325         image->cheight = (int) (image->height * affine[3] + 0.5);
326
327         if (image->pixbuf) {
328                 image->need_recalc = TRUE ;
329         }
330
331         get_bounds_item_relative (image, &i_bbox.x0, &i_bbox.y0, &i_bbox.x1, &i_bbox.y1);
332         art_drect_affine_transform (&c_bbox, &i_bbox, affine);
333
334         /* these values only make sense in the non-rotated, non-skewed case */
335         image->cx = c_bbox.x0;
336         image->cy = c_bbox.y0;
337
338         /* add a fudge factor */
339         c_bbox.x0--;
340         c_bbox.y0--;
341         c_bbox.x1++;
342         c_bbox.y1++;
343
344         gnome_canvas_update_bbox (item, c_bbox.x0, c_bbox.y0, c_bbox.x1, c_bbox.y1);
345
346         if (image->pixbuf) {
347                 w = image->pixbuf->width;
348                 h = image->pixbuf->height;
349         }
350
351         image->affine[0] = (affine[0] * image->width) / w;
352         image->affine[1] = (affine[1] * image->height) / h;
353         image->affine[2] = (affine[2] * image->width) / w;
354         image->affine[3] = (affine[3] * image->height) / h;
355         image->affine[4] = i_bbox.x0 * affine[0] + i_bbox.y0 * affine[2] + affine[4];
356         image->affine[5] = i_bbox.x0 * affine[1] + i_bbox.y0 * affine[3] + affine[5];
357 }
358
359 static void
360 gnome_canvas_imageframe_realize (GnomeCanvasItem *item)
361 {
362         GnomeCanvasImageFrame *image;
363
364         image = GNOME_CANVAS_IMAGEFRAME (item);
365
366         if (parent_class->realize)
367                 (* parent_class->realize) (item);
368
369 }
370
371 static void
372 gnome_canvas_imageframe_unrealize (GnomeCanvasItem *item)
373 {
374         GnomeCanvasImageFrame *image;
375
376         image = GNOME_CANVAS_IMAGEFRAME(item);
377
378         if (parent_class->unrealize)
379                 (* parent_class->unrealize) (item);
380 }
381
382 static void
383 recalc_if_needed (GnomeCanvasImageFrame *image)
384 {}
385
386 static void
387 gnome_canvas_imageframe_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
388                          int x, int y, int width, int height)
389 {
390         fprintf(stderr, "please don't use the CanvasImageFrame item in a non-aa Canvas\n") ;
391         abort() ;
392 }
393
394 static double
395 gnome_canvas_imageframe_point (GnomeCanvasItem *item, double x, double y,
396                           int cx, int cy, GnomeCanvasItem **actual_item)
397 {
398         GnomeCanvasImageFrame *image;
399         int x1, y1, x2, y2;
400         int dx, dy;
401
402         image = GNOME_CANVAS_IMAGEFRAME (item);
403
404         *actual_item = item;
405
406         recalc_if_needed (image);
407
408         x1 = image->cx - item->canvas->close_enough;
409         y1 = image->cy - item->canvas->close_enough;
410         x2 = image->cx + image->cwidth - 1 + item->canvas->close_enough;
411         y2 = image->cy + image->cheight - 1 + item->canvas->close_enough;
412
413         /* Hard case: is point inside image's gravity region? */
414
415         //if ((cx >= x1) && (cy >= y1) && (cx <= x2) && (cy <= y2))
416                 //return dist_to_mask (image, cx, cy) / item->canvas->pixels_per_unit;
417
418         /* Point is outside image */
419
420         x1 += item->canvas->close_enough;
421         y1 += item->canvas->close_enough;
422         x2 -= item->canvas->close_enough;
423         y2 -= item->canvas->close_enough;
424
425         if (cx < x1)
426                 dx = x1 - cx;
427         else if (cx > x2)
428                 dx = cx - x2;
429         else
430                 dx = 0;
431
432         if (cy < y1)
433                 dy = y1 - cy;
434         else if (cy > y2)
435                 dy = cy - y2;
436         else
437                 dy = 0;
438
439         return sqrt (dx * dx + dy * dy) / item->canvas->pixels_per_unit;
440 }
441
442 static void
443 gnome_canvas_imageframe_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
444 {
445         GnomeCanvasImageFrame *image;
446
447         image = GNOME_CANVAS_IMAGEFRAME (item);
448
449         *x1 = image->x;
450         *y1 = image->y;
451
452         switch (image->anchor) {
453         case GTK_ANCHOR_NW:
454         case GTK_ANCHOR_W:
455         case GTK_ANCHOR_SW:
456                 break;
457
458         case GTK_ANCHOR_N:
459         case GTK_ANCHOR_CENTER:
460         case GTK_ANCHOR_S:
461                 *x1 -= image->width / 2.0;
462                 break;
463
464         case GTK_ANCHOR_NE:
465         case GTK_ANCHOR_E:
466         case GTK_ANCHOR_SE:
467                 *x1 -= image->width;
468                 break;
469         }
470
471         switch (image->anchor) {
472         case GTK_ANCHOR_NW:
473         case GTK_ANCHOR_N:
474         case GTK_ANCHOR_NE:
475                 break;
476
477         case GTK_ANCHOR_W:
478         case GTK_ANCHOR_CENTER:
479         case GTK_ANCHOR_E:
480                 *y1 -= image->height / 2.0;
481                 break;
482
483         case GTK_ANCHOR_SW:
484         case GTK_ANCHOR_S:
485         case GTK_ANCHOR_SE:
486                 *y1 -= image->height;
487                 break;
488         }
489
490         *x2 = *x1 + image->width;
491         *y2 = *y1 + image->height;
492 }
493
494 static void
495 gnome_canvas_imageframe_render      (GnomeCanvasItem *item, GnomeCanvasBuf *buf)
496 {
497         GnomeCanvasImageFrame *image;
498
499         image = GNOME_CANVAS_IMAGEFRAME (item);
500
501         gnome_canvas_buf_ensure_buf (buf);
502
503 #ifdef VERBOSE
504         {
505                 char str[128];
506                 art_affine_to_string (str, image->affine);
507                 g_print ("gnome_canvas_imageframe_render %s\n", str);
508         }
509 #endif
510
511         art_rgb_pixbuf_affine (buf->buf,
512                         buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1,
513                         buf->buf_rowstride,
514                         image->pixbuf,
515                         image->affine,
516                         ART_FILTER_NEAREST, NULL);
517
518         buf->is_bg = 0;
519 }