1 /* Image item type for GtkCanvas widget
3 * GtkCanvas 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>
12 #include <string.h> /* for memcpy() */
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 <gtk-canvas/gtk-canvas-util.h>
21 #include <gtk-canvas/gtk-canvastypebuiltins.h>
36 static void gtk_canvas_imageframe_class_init(GtkCanvasImageFrameClass* class) ;
37 static void gtk_canvas_imageframe_init(GtkCanvasImageFrame* image) ;
38 static void gtk_canvas_imageframe_destroy(GtkObject* object) ;
39 static void gtk_canvas_imageframe_set_arg(GtkObject* object, GtkArg* arg, guint arg_id) ;
40 static void gtk_canvas_imageframe_get_arg(GtkObject* object, GtkArg* arg, guint arg_id) ;
42 static void gtk_canvas_imageframe_update(GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) ;
43 static void gtk_canvas_imageframe_realize(GtkCanvasItem *item) ;
44 static void gtk_canvas_imageframe_unrealize(GtkCanvasItem *item) ;
45 static void gtk_canvas_imageframe_draw(GtkCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) ;
46 static double gtk_canvas_imageframe_point(GtkCanvasItem *item, double x, double y, int cx, int cy, GtkCanvasItem **actual_item) ;
47 static void gtk_canvas_imageframe_translate(GtkCanvasItem *item, double dx, double dy) ;
48 static void gtk_canvas_imageframe_bounds(GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2) ;
49 static void gtk_canvas_imageframe_render(GtkCanvasItem *item, GtkCanvasBuf *buf) ;
51 static GtkCanvasItemClass *parent_class;
55 gtk_canvas_imageframe_get_type (void)
57 static GtkType imageframe_type = 0;
59 if (!imageframe_type) {
60 GtkTypeInfo imageframe_info = {
61 "GtkCanvasImageFrame",
62 sizeof (GtkCanvasImageFrame),
63 sizeof (GtkCanvasImageFrameClass),
64 (GtkClassInitFunc) gtk_canvas_imageframe_class_init,
65 (GtkObjectInitFunc) gtk_canvas_imageframe_init,
66 NULL, /* reserved_1 */
67 NULL, /* reserved_2 */
68 (GtkClassInitFunc) NULL
71 imageframe_type = gtk_type_unique (gtk_canvas_item_get_type (), &imageframe_info);
74 return imageframe_type;
78 gtk_canvas_imageframe_class_init (GtkCanvasImageFrameClass *class)
80 GtkObjectClass *object_class;
81 GtkCanvasItemClass *item_class;
83 object_class = (GtkObjectClass *) class;
84 item_class = (GtkCanvasItemClass *) class;
86 parent_class = gtk_type_class (gtk_canvas_item_get_type ());
88 gtk_object_add_arg_type ("GtkCanvasImageFrame::pixbuf", GTK_TYPE_BOXED, GTK_ARG_WRITABLE, ARG_PIXBUF);
89 gtk_object_add_arg_type ("GtkCanvasImageFrame::x", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X);
90 gtk_object_add_arg_type ("GtkCanvasImageFrame::y", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y);
91 gtk_object_add_arg_type ("GtkCanvasImageFrame::width", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_WIDTH);
92 gtk_object_add_arg_type ("GtkCanvasImageFrame::drawwidth", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_DRAWWIDTH);
93 gtk_object_add_arg_type ("GtkCanvasImageFrame::height", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_HEIGHT);
94 gtk_object_add_arg_type ("GtkCanvasImageFrame::anchor", GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, ARG_ANCHOR);
96 object_class->destroy = gtk_canvas_imageframe_destroy;
97 object_class->set_arg = gtk_canvas_imageframe_set_arg;
98 object_class->get_arg = gtk_canvas_imageframe_get_arg;
100 item_class->update = gtk_canvas_imageframe_update;
101 item_class->realize = gtk_canvas_imageframe_realize;
102 item_class->unrealize = gtk_canvas_imageframe_unrealize;
103 item_class->draw = gtk_canvas_imageframe_draw;
104 item_class->point = gtk_canvas_imageframe_point;
105 item_class->translate = gtk_canvas_imageframe_translate;
106 item_class->bounds = gtk_canvas_imageframe_bounds;
107 item_class->render = gtk_canvas_imageframe_render;
111 gtk_canvas_imageframe_init (GtkCanvasImageFrame *image)
117 image->drawwidth = 0.0;
118 image->anchor = GTK_ANCHOR_CENTER;
119 GTK_CANVAS_ITEM(image)->object.flags |= GTK_CANVAS_ITEM_NO_AUTO_REDRAW;
123 gtk_canvas_imageframe_destroy (GtkObject *object)
125 GtkCanvasImageFrame *image;
127 g_return_if_fail (object != NULL);
128 g_return_if_fail (GTK_CANVAS_IS_CANVAS_IMAGEFRAME (object));
130 image = GTK_CANVAS_IMAGEFRAME (object);
137 art_pixbuf_free (image->pixbuf);
138 image->pixbuf = NULL;
141 if(GTK_OBJECT_CLASS (parent_class)->destroy)
143 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
147 /* Get's the image bounds expressed as item-relative coordinates. */
149 get_bounds_item_relative (GtkCanvasImageFrame *image, double *px1, double *py1, double *px2, double *py2)
154 item = GTK_CANVAS_ITEM (image);
156 /* Get item coordinates */
163 switch (image->anchor) {
170 case GTK_ANCHOR_CENTER:
172 x -= image->width / 2;
182 switch (image->anchor) {
189 case GTK_ANCHOR_CENTER:
191 y -= image->height / 2;
205 *px2 = x + image->width;
206 *py2 = y + image->height;
210 get_bounds (GtkCanvasImageFrame *image, double *px1, double *py1, double *px2, double *py2)
214 ArtDRect i_bbox, c_bbox;
216 item = GTK_CANVAS_ITEM (image);
218 gtk_canvas_item_i2c_affine (item, i2c);
220 get_bounds_item_relative (image, &i_bbox.x0, &i_bbox.y0, &i_bbox.x1, &i_bbox.y1);
221 art_drect_affine_transform (&c_bbox, &i_bbox, i2c);
223 /* add a fudge factor */
224 *px1 = c_bbox.x0 - 1;
225 *py1 = c_bbox.y0 - 1;
226 *px2 = c_bbox.x1 + 1;
227 *py2 = c_bbox.y1 + 1;
232 recalc_bounds (GtkCanvasImageFrame *image)
236 item = GTK_CANVAS_ITEM (image);
238 get_bounds (image, &item->x1, &item->y1, &item->x2, &item->y2);
240 item->x1 = image->cx;
241 item->y1 = image->cy;
242 item->x2 = image->cx + image->cwidth;
243 item->y2 = image->cy + image->cheight;
245 gtk_canvas_group_child_bounds (GTK_CANVAS_GROUP (item->parent), item);
249 gtk_canvas_imageframe_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
252 GtkCanvasImageFrame *image;
256 item = GTK_CANVAS_ITEM (object);
257 image = GTK_CANVAS_IMAGEFRAME (object);
264 if (item->canvas->aa && GTK_VALUE_BOXED (*arg)) {
265 if (image->pixbuf != NULL)
266 art_pixbuf_free (image->pixbuf);
267 image->pixbuf = GTK_VALUE_BOXED (*arg);
273 image->x = GTK_VALUE_DOUBLE (*arg);
278 image->y = GTK_VALUE_DOUBLE (*arg);
283 image->width = fabs (GTK_VALUE_DOUBLE (*arg));
288 image->height = fabs (GTK_VALUE_DOUBLE (*arg));
293 image->drawwidth = fabs (GTK_VALUE_DOUBLE (*arg));
298 image->anchor = GTK_VALUE_ENUM (*arg);
308 (* GTK_CANVAS_ITEM_CLASS (item->object.klass)->update) (item, NULL, NULL, 0);
311 recalc_bounds (image);
314 gtk_canvas_item_request_update (item);
319 gtk_canvas_imageframe_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
321 GtkCanvasImageFrame *image;
323 image = GTK_CANVAS_IMAGEFRAME (object);
328 GTK_VALUE_DOUBLE (*arg) = image->x;
332 GTK_VALUE_DOUBLE (*arg) = image->y;
336 GTK_VALUE_DOUBLE (*arg) = image->width;
340 GTK_VALUE_DOUBLE (*arg) = image->height;
344 GTK_VALUE_DOUBLE (*arg) = image->drawwidth;
348 GTK_VALUE_ENUM (*arg) = image->anchor;
352 arg->type = GTK_TYPE_INVALID;
358 gtk_canvas_imageframe_update (GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
360 GtkCanvasImageFrame *image;
361 ArtDRect i_bbox, c_bbox;
365 image = GTK_CANVAS_IMAGEFRAME (item);
367 if (parent_class->update)
368 (* parent_class->update) (item, affine, clip_path, flags);
370 /* only works for non-rotated, non-skewed transforms */
371 image->cwidth = (int) (image->width * affine[0] + 0.5);
372 image->cheight = (int) (image->height * affine[3] + 0.5);
375 image->need_recalc = TRUE ;
379 recalc_bounds (image);
381 get_bounds_item_relative (image, &i_bbox.x0, &i_bbox.y0, &i_bbox.x1, &i_bbox.y1);
382 art_drect_affine_transform (&c_bbox, &i_bbox, affine);
384 /* these values only make sense in the non-rotated, non-skewed case */
385 image->cx = c_bbox.x0;
386 image->cy = c_bbox.y0;
388 /* add a fudge factor */
394 gtk_canvas_update_bbox (item, c_bbox.x0, c_bbox.y0, c_bbox.x1, c_bbox.y1);
397 w = image->pixbuf->width;
398 h = image->pixbuf->height;
401 image->affine[0] = (affine[0] * image->width) / w;
402 image->affine[1] = (affine[1] * image->height) / h;
403 image->affine[2] = (affine[2] * image->width) / w;
404 image->affine[3] = (affine[3] * image->height) / h;
405 image->affine[4] = i_bbox.x0 * affine[0] + i_bbox.y0 * affine[2] + affine[4];
406 image->affine[5] = i_bbox.x0 * affine[1] + i_bbox.y0 * affine[3] + affine[5];
412 gtk_canvas_imageframe_realize (GtkCanvasItem *item)
414 GtkCanvasImageFrame *image;
416 image = GTK_CANVAS_IMAGEFRAME (item);
418 if (parent_class->realize)
419 (* parent_class->realize) (item);
424 gtk_canvas_imageframe_unrealize (GtkCanvasItem *item)
426 GtkCanvasImageFrame *image;
428 image = GTK_CANVAS_IMAGEFRAME(item);
430 if (parent_class->unrealize)
431 (* parent_class->unrealize) (item);
435 recalc_if_needed (GtkCanvasImageFrame *image)
439 gtk_canvas_imageframe_draw (GtkCanvasItem *item, GdkDrawable *drawable,
440 int x, int y, int width, int height)
442 fprintf(stderr, "please don't use the CanvasImageFrame item in a non-aa Canvas\n") ;
447 gtk_canvas_imageframe_point (GtkCanvasItem *item, double x, double y,
448 int cx, int cy, GtkCanvasItem **actual_item)
450 GtkCanvasImageFrame *image;
454 image = GTK_CANVAS_IMAGEFRAME (item);
458 recalc_if_needed (image);
460 x1 = image->cx - item->canvas->close_enough;
461 y1 = image->cy - item->canvas->close_enough;
462 x2 = image->cx + image->cwidth - 1 + item->canvas->close_enough;
463 y2 = image->cy + image->cheight - 1 + item->canvas->close_enough;
465 /* Hard case: is point inside image's gravity region? */
467 //if ((cx >= x1) && (cy >= y1) && (cx <= x2) && (cy <= y2))
468 //return dist_to_mask (image, cx, cy) / item->canvas->pixels_per_unit;
470 /* Point is outside image */
472 x1 += item->canvas->close_enough;
473 y1 += item->canvas->close_enough;
474 x2 -= item->canvas->close_enough;
475 y2 -= item->canvas->close_enough;
491 return sqrt (dx * dx + dy * dy) / item->canvas->pixels_per_unit;
495 gtk_canvas_imageframe_translate (GtkCanvasItem *item, double dx, double dy)
498 GtkCanvasImageFrame *image;
500 image = GTK_CANVAS_IMAGEFRAME (item);
505 recalc_bounds (image);
510 gtk_canvas_imageframe_bounds (GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
512 GtkCanvasImageFrame *image;
514 image = GTK_CANVAS_IMAGEFRAME (item);
519 switch (image->anchor) {
526 case GTK_ANCHOR_CENTER:
528 *x1 -= image->width / 2.0;
538 switch (image->anchor) {
545 case GTK_ANCHOR_CENTER:
547 *y1 -= image->height / 2.0;
553 *y1 -= image->height;
557 *x2 = *x1 + image->width;
558 *y2 = *y1 + image->height;
562 gtk_canvas_imageframe_render (GtkCanvasItem *item, GtkCanvasBuf *buf)
564 GtkCanvasImageFrame *image;
566 image = GTK_CANVAS_IMAGEFRAME (item);
568 gtk_canvas_buf_ensure_buf (buf);
573 art_affine_to_string (str, image->affine);
574 g_print ("gtk_canvas_imageframe_render %s\n", str);
578 art_rgb_pixbuf_affine (buf->buf,
579 buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1,
583 ART_FILTER_NEAREST, NULL);