slowly fixing up ArdourDialog nonsense
[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_boxed ("pixbuf",
104                                                              _("pixbuf"),
105                                                              _("the pixbuf"),
106                                                              GDK_TYPE_PIXBUF,
107                                                              G_PARAM_WRITABLE)); 
108         g_object_class_install_property (gobject_class,
109                                          PROP_X,
110                                          g_param_spec_double ("x",
111                                                               _("x"),
112                                                               _("x coordinate of upper left corner of rect"),
113                                                               -G_MAXDOUBLE,
114                                                               G_MAXDOUBLE,
115                                                               0.0,
116                                                               G_PARAM_READWRITE));  
117         
118         g_object_class_install_property (gobject_class,
119                                          PROP_Y,
120                                          g_param_spec_double ("y",
121                                                               _("y"),
122                                                               _("y coordinate of upper left corner of rect "),
123                                                               -G_MAXDOUBLE,
124                                                               G_MAXDOUBLE,
125                                                               0.0,
126                                                               G_PARAM_READWRITE));  
127         g_object_class_install_property (gobject_class,
128                                          PROP_WIDTH,
129                                          g_param_spec_double ("width",
130                                                               _("width"),
131                                                               _("the width"),
132                                                               -G_MAXDOUBLE,
133                                                               G_MAXDOUBLE,
134                                                               0.0,
135                                                               G_PARAM_READWRITE));  
136         
137         g_object_class_install_property (gobject_class,
138                                          PROP_DRAWWIDTH,
139                                          g_param_spec_double ("drawwidth",
140                                                               _("drawwidth"),
141                                                               _("drawn width"),
142                                                               -G_MAXDOUBLE,
143                                                               G_MAXDOUBLE,
144                                                               0.0,
145                                                               G_PARAM_READWRITE));  
146         g_object_class_install_property (gobject_class,
147                                          PROP_HEIGHT,
148                                          g_param_spec_double ("height",
149                                                               _("height"),
150                                                               _("the height"),
151                                                               -G_MAXDOUBLE,
152                                                               G_MAXDOUBLE,
153                                                               0.0,
154                                                               G_PARAM_READWRITE));  
155         g_object_class_install_property (gobject_class,
156                                          PROP_ANCHOR,
157                                          g_param_spec_enum ("anchor",
158                                                             _("anchor"),
159                                                             _("the anchor"),
160                                                             GTK_TYPE_ANCHOR_TYPE,
161                                                             GTK_ANCHOR_NW,
162                                                             G_PARAM_READWRITE));  
163
164         object_class->destroy = gnome_canvas_imageframe_destroy;
165
166         item_class->update = gnome_canvas_imageframe_update;
167         item_class->realize = gnome_canvas_imageframe_realize;
168         item_class->unrealize = gnome_canvas_imageframe_unrealize;
169         item_class->draw = gnome_canvas_imageframe_draw;
170         item_class->point = gnome_canvas_imageframe_point;
171         item_class->bounds = gnome_canvas_imageframe_bounds;
172         item_class->render = gnome_canvas_imageframe_render;
173 }
174
175 static void
176 gnome_canvas_imageframe_init (GnomeCanvasImageFrame *image)
177 {
178         image->x = 0.0;
179         image->y = 0.0;
180         image->width = 0.0;
181         image->height = 0.0;
182         image->drawwidth = 0.0;
183         image->anchor = GTK_ANCHOR_CENTER;
184         // GTK2FIX
185         // GNOME_CANVAS_ITEM(image)->object.flags |= GNOME_CANVAS_ITEM_NO_AUTO_REDRAW;
186 }
187
188 static void
189 gnome_canvas_imageframe_destroy (GtkObject *object)
190 {
191         GnomeCanvasImageFrame *image;
192
193         g_return_if_fail (object != NULL);
194         g_return_if_fail (GNOME_CANVAS_IS_CANVAS_IMAGEFRAME (object));
195
196         image = GNOME_CANVAS_IMAGEFRAME (object);
197         
198         image->cwidth = 0;
199         image->cheight = 0;
200
201         if (image->pixbuf)
202         {
203                 art_pixbuf_free (image->pixbuf);
204                 image->pixbuf = NULL;
205         }
206
207         if(GTK_OBJECT_CLASS (parent_class)->destroy)
208         {
209                 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
210         }
211 }
212
213 /* Get's the image bounds expressed as item-relative coordinates. */
214 static void
215 get_bounds_item_relative (GnomeCanvasImageFrame *image, double *px1, double *py1, double *px2, double *py2)
216 {
217         GnomeCanvasItem *item;
218         double x, y;
219
220         item = GNOME_CANVAS_ITEM (image);
221
222         /* Get item coordinates */
223
224         x = image->x;
225         y = image->y;
226
227         /* Anchor image */
228
229         switch (image->anchor) {
230         case GTK_ANCHOR_NW:
231         case GTK_ANCHOR_W:
232         case GTK_ANCHOR_SW:
233                 break;
234
235         case GTK_ANCHOR_N:
236         case GTK_ANCHOR_CENTER:
237         case GTK_ANCHOR_S:
238                 x -= image->width / 2;
239                 break;
240
241         case GTK_ANCHOR_NE:
242         case GTK_ANCHOR_E:
243         case GTK_ANCHOR_SE:
244                 x -= image->width;
245                 break;
246         }
247
248         switch (image->anchor) {
249         case GTK_ANCHOR_NW:
250         case GTK_ANCHOR_N:
251         case GTK_ANCHOR_NE:
252                 break;
253
254         case GTK_ANCHOR_W:
255         case GTK_ANCHOR_CENTER:
256         case GTK_ANCHOR_E:
257                 y -= image->height / 2;
258                 break;
259
260         case GTK_ANCHOR_SW:
261         case GTK_ANCHOR_S:
262         case GTK_ANCHOR_SE:
263                 y -= image->height;
264                 break;
265         }
266
267         /* Bounds */
268
269         *px1 = x;
270         *py1 = y;
271         *px2 = x + image->width;
272         *py2 = y + image->height;
273 }
274
275 static void
276 gnome_canvas_imageframe_set_property (GObject *object,
277                                       guint            prop_id,
278                                       const GValue   *value,
279                                       GParamSpec     *pspec)
280 {
281         GnomeCanvasItem *item;
282         GnomeCanvasImageFrame *image;
283         int update;
284         int calc_bounds;
285
286         item = GNOME_CANVAS_ITEM (object);
287         image = GNOME_CANVAS_IMAGEFRAME (object);
288
289         update = FALSE;
290         calc_bounds = FALSE;
291
292         switch (prop_id) {
293         case PROP_PIXBUF:
294                 if (item->canvas->aa && g_value_get_boxed (value)) {
295                         if (image->pixbuf != NULL)
296                                 art_pixbuf_free (image->pixbuf);
297                         image->pixbuf = g_value_get_boxed (value);
298                 }
299                 update = TRUE;
300                 break;
301
302         case PROP_X:
303                 image->x = g_value_get_double (value);
304                 update = TRUE;
305                 break;
306
307         case PROP_Y:
308                 image->y = g_value_get_double (value);
309                 update = TRUE;
310                 break;
311
312         case PROP_WIDTH:
313                 image->width = fabs (g_value_get_double (value));
314                 update = TRUE;
315                 break;
316
317         case PROP_HEIGHT:
318                 image->height = fabs (g_value_get_double (value));
319                 update = TRUE;
320                 break;
321                 
322         case PROP_DRAWWIDTH:
323                 image->drawwidth = fabs (g_value_get_double (value));
324                 update = TRUE;
325                 break;
326
327         case PROP_ANCHOR:
328                 image->anchor = g_value_get_enum (value);
329                 update = TRUE;
330                 break;
331
332         default:
333                 break;
334         }
335
336         if (update)
337                 gnome_canvas_item_request_update (item);
338 }
339
340 static void
341 gnome_canvas_imageframe_get_property (GObject *object,
342                                       guint            prop_id,
343                                       GValue   *value,
344                                       GParamSpec     *pspec)
345 {
346         GnomeCanvasImageFrame *image;
347
348         image = GNOME_CANVAS_IMAGEFRAME (object);
349
350         switch (prop_id) {
351
352         case PROP_X:
353                 g_value_set_double (value, image->x);
354                 break;
355
356         case PROP_Y:
357                 g_value_set_double (value, image->y);
358                 break;
359
360         case PROP_WIDTH:
361                 g_value_set_double (value, image->width);
362                 break;
363           
364         case PROP_HEIGHT:
365                 g_value_set_double (value, image->height);
366                 break;
367                 
368         case PROP_DRAWWIDTH:
369                 g_value_set_double (value, image->drawwidth);
370                 break;
371
372         case PROP_ANCHOR:
373                 g_value_set_enum (value, image->anchor);
374                 break;
375
376         default:
377                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
378                 break;
379         }
380 }
381
382 static void
383 gnome_canvas_imageframe_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
384 {
385         GnomeCanvasImageFrame *image;
386         ArtDRect i_bbox, c_bbox;
387         int w = 0;
388         int h = 0;
389
390         image = GNOME_CANVAS_IMAGEFRAME (item);
391
392         if (parent_class->update)
393                 (* parent_class->update) (item, affine, clip_path, flags);
394
395         /* only works for non-rotated, non-skewed transforms */
396         image->cwidth = (int) (image->width * affine[0] + 0.5);
397         image->cheight = (int) (image->height * affine[3] + 0.5);
398
399         if (image->pixbuf) {
400                 image->need_recalc = TRUE ;
401         }
402
403         get_bounds_item_relative (image, &i_bbox.x0, &i_bbox.y0, &i_bbox.x1, &i_bbox.y1);
404         art_drect_affine_transform (&c_bbox, &i_bbox, affine);
405
406         /* these values only make sense in the non-rotated, non-skewed case */
407         image->cx = c_bbox.x0;
408         image->cy = c_bbox.y0;
409
410         /* add a fudge factor */
411         c_bbox.x0--;
412         c_bbox.y0--;
413         c_bbox.x1++;
414         c_bbox.y1++;
415
416         gnome_canvas_update_bbox (item, c_bbox.x0, c_bbox.y0, c_bbox.x1, c_bbox.y1);
417
418         if (image->pixbuf) {
419                 w = image->pixbuf->width;
420                 h = image->pixbuf->height;
421         }
422
423         image->affine[0] = (affine[0] * image->width) / w;
424         image->affine[1] = (affine[1] * image->height) / h;
425         image->affine[2] = (affine[2] * image->width) / w;
426         image->affine[3] = (affine[3] * image->height) / h;
427         image->affine[4] = i_bbox.x0 * affine[0] + i_bbox.y0 * affine[2] + affine[4];
428         image->affine[5] = i_bbox.x0 * affine[1] + i_bbox.y0 * affine[3] + affine[5];
429 }
430
431 static void
432 gnome_canvas_imageframe_realize (GnomeCanvasItem *item)
433 {
434         GnomeCanvasImageFrame *image;
435
436         image = GNOME_CANVAS_IMAGEFRAME (item);
437
438         if (parent_class->realize)
439                 (* parent_class->realize) (item);
440
441 }
442
443 static void
444 gnome_canvas_imageframe_unrealize (GnomeCanvasItem *item)
445 {
446         GnomeCanvasImageFrame *image;
447
448         image = GNOME_CANVAS_IMAGEFRAME(item);
449
450         if (parent_class->unrealize)
451                 (* parent_class->unrealize) (item);
452 }
453
454 static void
455 recalc_if_needed (GnomeCanvasImageFrame *image)
456 {}
457
458 static void
459 gnome_canvas_imageframe_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
460                          int x, int y, int width, int height)
461 {
462         fprintf(stderr, "please don't use the CanvasImageFrame item in a non-aa Canvas\n") ;
463         abort() ;
464 }
465
466 static double
467 gnome_canvas_imageframe_point (GnomeCanvasItem *item, double x, double y,
468                           int cx, int cy, GnomeCanvasItem **actual_item)
469 {
470         GnomeCanvasImageFrame *image;
471         int x1, y1, x2, y2;
472         int dx, dy;
473
474         image = GNOME_CANVAS_IMAGEFRAME (item);
475
476         *actual_item = item;
477
478         recalc_if_needed (image);
479
480         x1 = image->cx - item->canvas->close_enough;
481         y1 = image->cy - item->canvas->close_enough;
482         x2 = image->cx + image->cwidth - 1 + item->canvas->close_enough;
483         y2 = image->cy + image->cheight - 1 + item->canvas->close_enough;
484
485         /* Hard case: is point inside image's gravity region? */
486
487         //if ((cx >= x1) && (cy >= y1) && (cx <= x2) && (cy <= y2))
488                 //return dist_to_mask (image, cx, cy) / item->canvas->pixels_per_unit;
489
490         /* Point is outside image */
491
492         x1 += item->canvas->close_enough;
493         y1 += item->canvas->close_enough;
494         x2 -= item->canvas->close_enough;
495         y2 -= item->canvas->close_enough;
496
497         if (cx < x1)
498                 dx = x1 - cx;
499         else if (cx > x2)
500                 dx = cx - x2;
501         else
502                 dx = 0;
503
504         if (cy < y1)
505                 dy = y1 - cy;
506         else if (cy > y2)
507                 dy = cy - y2;
508         else
509                 dy = 0;
510
511         return sqrt (dx * dx + dy * dy) / item->canvas->pixels_per_unit;
512 }
513
514 static void
515 gnome_canvas_imageframe_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
516 {
517         GnomeCanvasImageFrame *image;
518
519         image = GNOME_CANVAS_IMAGEFRAME (item);
520
521         *x1 = image->x;
522         *y1 = image->y;
523
524         switch (image->anchor) {
525         case GTK_ANCHOR_NW:
526         case GTK_ANCHOR_W:
527         case GTK_ANCHOR_SW:
528                 break;
529
530         case GTK_ANCHOR_N:
531         case GTK_ANCHOR_CENTER:
532         case GTK_ANCHOR_S:
533                 *x1 -= image->width / 2.0;
534                 break;
535
536         case GTK_ANCHOR_NE:
537         case GTK_ANCHOR_E:
538         case GTK_ANCHOR_SE:
539                 *x1 -= image->width;
540                 break;
541         }
542
543         switch (image->anchor) {
544         case GTK_ANCHOR_NW:
545         case GTK_ANCHOR_N:
546         case GTK_ANCHOR_NE:
547                 break;
548
549         case GTK_ANCHOR_W:
550         case GTK_ANCHOR_CENTER:
551         case GTK_ANCHOR_E:
552                 *y1 -= image->height / 2.0;
553                 break;
554
555         case GTK_ANCHOR_SW:
556         case GTK_ANCHOR_S:
557         case GTK_ANCHOR_SE:
558                 *y1 -= image->height;
559                 break;
560         }
561
562         *x2 = *x1 + image->width;
563         *y2 = *y1 + image->height;
564 }
565
566 static void
567 gnome_canvas_imageframe_render      (GnomeCanvasItem *item, GnomeCanvasBuf *buf)
568 {
569         GnomeCanvasImageFrame *image;
570
571         image = GNOME_CANVAS_IMAGEFRAME (item);
572
573         gnome_canvas_buf_ensure_buf (buf);
574
575 #ifdef VERBOSE
576         {
577                 char str[128];
578                 art_affine_to_string (str, image->affine);
579                 g_print ("gnome_canvas_imageframe_render %s\n", str);
580         }
581 #endif
582
583         art_rgb_pixbuf_affine (buf->buf,
584                         buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1,
585                         buf->buf_rowstride,
586                         image->pixbuf,
587                         image->affine,
588                         ART_FILTER_NEAREST, NULL);
589
590         buf->is_bg = 0;
591 }