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