Zoom session when the mouse pointer is moved up and down during a playhead drag.
[ardour2.git] / gtk2_ardour / canvas-imageframe.c
blob3654836c792d2e489dc0ef4bc243025c01e0208d
1 /* Image item type for GnomeCanvas widget
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.
6 * Copyright (C) 1998 The Free Software Foundation
8 * Author: Federico Mena <federico@nuclecu.unam.mx>
9 */
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)
24 //GTK2FIX
25 //#include <libgnomecanvas/gnome-canvastypebuiltins.h>
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
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) ;
59 static GnomeCanvasItemClass *parent_class;
62 GType
63 gnome_canvas_imageframe_get_type (void)
65 static GType imageframe_type = 0;
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
79 imageframe_type = gtk_type_unique (gnome_canvas_item_get_type (), &imageframe_info);
82 return imageframe_type;
85 static void
86 gnome_canvas_imageframe_class_init (GnomeCanvasImageFrameClass *class)
88 GObjectClass *gobject_class;
89 GtkObjectClass *object_class;
90 GnomeCanvasItemClass *item_class;
92 gobject_class = (GObjectClass *) class;
93 object_class = (GtkObjectClass *) class;
94 item_class = (GnomeCanvasItemClass *) class;
96 parent_class = gtk_type_class (gnome_canvas_item_get_type ());
98 gobject_class->set_property = gnome_canvas_imageframe_set_property;
99 gobject_class->get_property = gnome_canvas_imageframe_get_property;
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));
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));
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));
163 object_class->destroy = gnome_canvas_imageframe_destroy;
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;
174 static void
175 gnome_canvas_imageframe_init (GnomeCanvasImageFrame *image)
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;
185 static void
186 gnome_canvas_imageframe_destroy (GtkObject *object)
188 GnomeCanvasImageFrame *image;
190 g_return_if_fail (object != NULL);
191 g_return_if_fail (GNOME_CANVAS_IS_CANVAS_IMAGEFRAME (object));
193 image = GNOME_CANVAS_IMAGEFRAME (object);
195 image->cwidth = 0;
196 image->cheight = 0;
198 if (image->pixbuf)
200 art_pixbuf_free (image->pixbuf);
201 image->pixbuf = NULL;
204 if(GTK_OBJECT_CLASS (parent_class)->destroy)
206 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
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)
214 GnomeCanvasItem *item;
215 double x, y;
217 item = GNOME_CANVAS_ITEM (image);
219 /* Get item coordinates */
221 x = image->x;
222 y = image->y;
224 /* Anchor image */
226 switch (image->anchor) {
227 case GTK_ANCHOR_NW:
228 case GTK_ANCHOR_W:
229 case GTK_ANCHOR_SW:
230 break;
232 case GTK_ANCHOR_N:
233 case GTK_ANCHOR_CENTER:
234 case GTK_ANCHOR_S:
235 x -= image->width / 2;
236 break;
238 case GTK_ANCHOR_NE:
239 case GTK_ANCHOR_E:
240 case GTK_ANCHOR_SE:
241 x -= image->width;
242 break;
245 switch (image->anchor) {
246 case GTK_ANCHOR_NW:
247 case GTK_ANCHOR_N:
248 case GTK_ANCHOR_NE:
249 break;
251 case GTK_ANCHOR_W:
252 case GTK_ANCHOR_CENTER:
253 case GTK_ANCHOR_E:
254 y -= image->height / 2;
255 break;
257 case GTK_ANCHOR_SW:
258 case GTK_ANCHOR_S:
259 case GTK_ANCHOR_SE:
260 y -= image->height;
261 break;
264 /* Bounds */
266 *px1 = x;
267 *py1 = y;
268 *px2 = x + image->width;
269 *py2 = y + image->height;
272 static void
273 gnome_canvas_imageframe_set_property (GObject *object,
274 guint prop_id,
275 const GValue *value,
276 GParamSpec *pspec)
278 GnomeCanvasItem *item;
279 GnomeCanvasImageFrame *image;
280 int update;
281 int calc_bounds;
283 item = GNOME_CANVAS_ITEM (object);
284 image = GNOME_CANVAS_IMAGEFRAME (object);
286 update = FALSE;
287 calc_bounds = FALSE;
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);
296 update = TRUE;
297 break;
299 case PROP_X:
300 image->x = g_value_get_double (value);
301 update = TRUE;
302 break;
304 case PROP_Y:
305 image->y = g_value_get_double (value);
306 update = TRUE;
307 break;
309 case PROP_WIDTH:
310 image->width = fabs (g_value_get_double (value));
311 update = TRUE;
312 break;
314 case PROP_HEIGHT:
315 image->height = fabs (g_value_get_double (value));
316 update = TRUE;
317 break;
319 case PROP_DRAWWIDTH:
320 image->drawwidth = fabs (g_value_get_double (value));
321 update = TRUE;
322 break;
324 case PROP_ANCHOR:
325 image->anchor = g_value_get_enum (value);
326 update = TRUE;
327 break;
329 default:
330 break;
333 if (update)
334 gnome_canvas_item_request_update (item);
337 static void
338 gnome_canvas_imageframe_get_property (GObject *object,
339 guint prop_id,
340 GValue *value,
341 GParamSpec *pspec)
343 GnomeCanvasImageFrame *image;
345 image = GNOME_CANVAS_IMAGEFRAME (object);
347 switch (prop_id) {
349 case PROP_X:
350 g_value_set_double (value, image->x);
351 break;
353 case PROP_Y:
354 g_value_set_double (value, image->y);
355 break;
357 case PROP_WIDTH:
358 g_value_set_double (value, image->width);
359 break;
361 case PROP_HEIGHT:
362 g_value_set_double (value, image->height);
363 break;
365 case PROP_DRAWWIDTH:
366 g_value_set_double (value, image->drawwidth);
367 break;
369 case PROP_ANCHOR:
370 g_value_set_enum (value, image->anchor);
371 break;
373 default:
374 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
375 break;
379 static void
380 gnome_canvas_imageframe_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
382 GnomeCanvasImageFrame *image;
383 ArtDRect i_bbox, c_bbox;
384 int w = 0;
385 int h = 0;
387 image = GNOME_CANVAS_IMAGEFRAME (item);
389 if (parent_class->update)
390 (* parent_class->update) (item, affine, clip_path, flags);
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);
396 if (image->pixbuf) {
397 image->need_recalc = TRUE ;
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);
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;
407 /* add a fudge factor */
408 c_bbox.x0--;
409 c_bbox.y0--;
410 c_bbox.x1++;
411 c_bbox.y1++;
413 gnome_canvas_update_bbox (item, c_bbox.x0, c_bbox.y0, c_bbox.x1, c_bbox.y1);
415 if (image->pixbuf) {
416 w = image->pixbuf->width;
417 h = image->pixbuf->height;
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];
428 static void
429 gnome_canvas_imageframe_realize (GnomeCanvasItem *item)
431 GnomeCanvasImageFrame *image;
433 image = GNOME_CANVAS_IMAGEFRAME (item);
435 if (parent_class->realize)
436 (* parent_class->realize) (item);
440 static void
441 gnome_canvas_imageframe_unrealize (GnomeCanvasItem *item)
443 GnomeCanvasImageFrame *image;
445 image = GNOME_CANVAS_IMAGEFRAME(item);
447 if (parent_class->unrealize)
448 (* parent_class->unrealize) (item);
451 static void
452 recalc_if_needed (GnomeCanvasImageFrame *image)
455 static void
456 gnome_canvas_imageframe_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
457 int x, int y, int width, int height)
461 static double
462 gnome_canvas_imageframe_point (GnomeCanvasItem *item, double x, double y,
463 int cx, int cy, GnomeCanvasItem **actual_item)
465 GnomeCanvasImageFrame *image;
466 int x1, y1, x2, y2;
467 int dx, dy;
469 image = GNOME_CANVAS_IMAGEFRAME (item);
471 *actual_item = item;
473 recalc_if_needed (image);
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;
480 /* Hard case: is point inside image's gravity region? */
482 //if ((cx >= x1) && (cy >= y1) && (cx <= x2) && (cy <= y2))
483 //return dist_to_mask (image, cx, cy) / item->canvas->pixels_per_unit;
485 /* Point is outside image */
487 x1 += item->canvas->close_enough;
488 y1 += item->canvas->close_enough;
489 x2 -= item->canvas->close_enough;
490 y2 -= item->canvas->close_enough;
492 if (cx < x1)
493 dx = x1 - cx;
494 else if (cx > x2)
495 dx = cx - x2;
496 else
497 dx = 0;
499 if (cy < y1)
500 dy = y1 - cy;
501 else if (cy > y2)
502 dy = cy - y2;
503 else
504 dy = 0;
506 return sqrt (dx * dx + dy * dy) / item->canvas->pixels_per_unit;
509 static void
510 gnome_canvas_imageframe_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
512 GnomeCanvasImageFrame *image;
514 image = GNOME_CANVAS_IMAGEFRAME (item);
516 *x1 = image->x;
517 *y1 = image->y;
519 switch (image->anchor) {
520 case GTK_ANCHOR_NW:
521 case GTK_ANCHOR_W:
522 case GTK_ANCHOR_SW:
523 break;
525 case GTK_ANCHOR_N:
526 case GTK_ANCHOR_CENTER:
527 case GTK_ANCHOR_S:
528 *x1 -= image->width / 2.0;
529 break;
531 case GTK_ANCHOR_NE:
532 case GTK_ANCHOR_E:
533 case GTK_ANCHOR_SE:
534 *x1 -= image->width;
535 break;
538 switch (image->anchor) {
539 case GTK_ANCHOR_NW:
540 case GTK_ANCHOR_N:
541 case GTK_ANCHOR_NE:
542 break;
544 case GTK_ANCHOR_W:
545 case GTK_ANCHOR_CENTER:
546 case GTK_ANCHOR_E:
547 *y1 -= image->height / 2.0;
548 break;
550 case GTK_ANCHOR_SW:
551 case GTK_ANCHOR_S:
552 case GTK_ANCHOR_SE:
553 *y1 -= image->height;
554 break;
557 *x2 = *x1 + image->width;
558 *y2 = *y1 + image->height;
561 static void
562 gnome_canvas_imageframe_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf)
564 GnomeCanvasImageFrame *image;
566 image = GNOME_CANVAS_IMAGEFRAME (item);
568 gnome_canvas_buf_ensure_buf (buf);
570 #ifdef VERBOSE
572 char str[128];
573 art_affine_to_string (str, image->affine);
574 g_print ("gnome_canvas_imageframe_render %s\n", str);
576 #endif
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);
585 buf->is_bg = 0;