diff options
author | Taybin Rutkin <taybin@taybin.com> | 2005-09-25 18:42:24 +0000 |
---|---|---|
committer | Taybin Rutkin <taybin@taybin.com> | 2005-09-25 18:42:24 +0000 |
commit | 209d967b1bb80a9735d690d8f4f0455ecb9970ca (patch) | |
tree | 9d76ddcd7c1ac9d91bb2b1a33d31b66ce4ded5de /gtk2_ardour/canvas-imageframe.c | |
parent | e4b9aed743fc765219ac775905a221c017c88fba (diff) |
Initial import of gtk2_ardour.
git-svn-id: svn://localhost/trunk/ardour2@24 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'gtk2_ardour/canvas-imageframe.c')
-rw-r--r-- | gtk2_ardour/canvas-imageframe.c | 586 |
1 files changed, 586 insertions, 0 deletions
diff --git a/gtk2_ardour/canvas-imageframe.c b/gtk2_ardour/canvas-imageframe.c new file mode 100644 index 0000000000..d186e86f50 --- /dev/null +++ b/gtk2_ardour/canvas-imageframe.c @@ -0,0 +1,586 @@ +/* Image item type for GtkCanvas widget + * + * GtkCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is + * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties. + * + * Copyright (C) 1998 The Free Software Foundation + * + * Author: Federico Mena <federico@nuclecu.unam.mx> + */ + + +#include <string.h> /* for memcpy() */ +#include <math.h> +#include <stdio.h> +#include "libart_lgpl/art_misc.h" +#include "libart_lgpl/art_affine.h" +#include "libart_lgpl/art_pixbuf.h" +#include "libart_lgpl/art_rgb_pixbuf_affine.h" +#include "canvas-imageframe.h" +#include <gtk-canvas/gtk-canvas-util.h> +#include <gtk-canvas/gtk-canvastypebuiltins.h> + + +enum { + ARG_0, + ARG_PIXBUF, + ARG_X, + ARG_Y, + ARG_WIDTH, + ARG_HEIGHT, + ARG_DRAWWIDTH, + ARG_ANCHOR +}; + + +static void gtk_canvas_imageframe_class_init(GtkCanvasImageFrameClass* class) ; +static void gtk_canvas_imageframe_init(GtkCanvasImageFrame* image) ; +static void gtk_canvas_imageframe_destroy(GtkObject* object) ; +static void gtk_canvas_imageframe_set_arg(GtkObject* object, GtkArg* arg, guint arg_id) ; +static void gtk_canvas_imageframe_get_arg(GtkObject* object, GtkArg* arg, guint arg_id) ; + +static void gtk_canvas_imageframe_update(GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) ; +static void gtk_canvas_imageframe_realize(GtkCanvasItem *item) ; +static void gtk_canvas_imageframe_unrealize(GtkCanvasItem *item) ; +static void gtk_canvas_imageframe_draw(GtkCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) ; +static double gtk_canvas_imageframe_point(GtkCanvasItem *item, double x, double y, int cx, int cy, GtkCanvasItem **actual_item) ; +static void gtk_canvas_imageframe_translate(GtkCanvasItem *item, double dx, double dy) ; +static void gtk_canvas_imageframe_bounds(GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2) ; +static void gtk_canvas_imageframe_render(GtkCanvasItem *item, GtkCanvasBuf *buf) ; + +static GtkCanvasItemClass *parent_class; + + +GtkType +gtk_canvas_imageframe_get_type (void) +{ + static GtkType imageframe_type = 0; + + if (!imageframe_type) { + GtkTypeInfo imageframe_info = { + "GtkCanvasImageFrame", + sizeof (GtkCanvasImageFrame), + sizeof (GtkCanvasImageFrameClass), + (GtkClassInitFunc) gtk_canvas_imageframe_class_init, + (GtkObjectInitFunc) gtk_canvas_imageframe_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + imageframe_type = gtk_type_unique (gtk_canvas_item_get_type (), &imageframe_info); + } + + return imageframe_type; +} + +static void +gtk_canvas_imageframe_class_init (GtkCanvasImageFrameClass *class) +{ + GtkObjectClass *object_class; + GtkCanvasItemClass *item_class; + + object_class = (GtkObjectClass *) class; + item_class = (GtkCanvasItemClass *) class; + + parent_class = gtk_type_class (gtk_canvas_item_get_type ()); + + gtk_object_add_arg_type ("GtkCanvasImageFrame::pixbuf", GTK_TYPE_BOXED, GTK_ARG_WRITABLE, ARG_PIXBUF); + gtk_object_add_arg_type ("GtkCanvasImageFrame::x", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X); + gtk_object_add_arg_type ("GtkCanvasImageFrame::y", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y); + gtk_object_add_arg_type ("GtkCanvasImageFrame::width", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_WIDTH); + gtk_object_add_arg_type ("GtkCanvasImageFrame::drawwidth", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_DRAWWIDTH); + gtk_object_add_arg_type ("GtkCanvasImageFrame::height", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_HEIGHT); + gtk_object_add_arg_type ("GtkCanvasImageFrame::anchor", GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, ARG_ANCHOR); + + object_class->destroy = gtk_canvas_imageframe_destroy; + object_class->set_arg = gtk_canvas_imageframe_set_arg; + object_class->get_arg = gtk_canvas_imageframe_get_arg; + + item_class->update = gtk_canvas_imageframe_update; + item_class->realize = gtk_canvas_imageframe_realize; + item_class->unrealize = gtk_canvas_imageframe_unrealize; + item_class->draw = gtk_canvas_imageframe_draw; + item_class->point = gtk_canvas_imageframe_point; + item_class->translate = gtk_canvas_imageframe_translate; + item_class->bounds = gtk_canvas_imageframe_bounds; + item_class->render = gtk_canvas_imageframe_render; +} + +static void +gtk_canvas_imageframe_init (GtkCanvasImageFrame *image) +{ + image->x = 0.0; + image->y = 0.0; + image->width = 0.0; + image->height = 0.0; + image->drawwidth = 0.0; + image->anchor = GTK_ANCHOR_CENTER; + GTK_CANVAS_ITEM(image)->object.flags |= GTK_CANVAS_ITEM_NO_AUTO_REDRAW; +} + +static void +gtk_canvas_imageframe_destroy (GtkObject *object) +{ + GtkCanvasImageFrame *image; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_CANVAS_IS_CANVAS_IMAGEFRAME (object)); + + image = GTK_CANVAS_IMAGEFRAME (object); + + image->cwidth = 0; + image->cheight = 0; + + if (image->pixbuf) + { + art_pixbuf_free (image->pixbuf); + image->pixbuf = NULL; + } + + if(GTK_OBJECT_CLASS (parent_class)->destroy) + { + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); + } +} + +/* Get's the image bounds expressed as item-relative coordinates. */ +static void +get_bounds_item_relative (GtkCanvasImageFrame *image, double *px1, double *py1, double *px2, double *py2) +{ + GtkCanvasItem *item; + double x, y; + + item = GTK_CANVAS_ITEM (image); + + /* Get item coordinates */ + + x = image->x; + y = image->y; + + /* Anchor image */ + + switch (image->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + x -= image->width / 2; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + x -= image->width; + break; + } + + switch (image->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + y -= image->height / 2; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + y -= image->height; + break; + } + + /* Bounds */ + + *px1 = x; + *py1 = y; + *px2 = x + image->width; + *py2 = y + image->height; +} + +static void +get_bounds (GtkCanvasImageFrame *image, double *px1, double *py1, double *px2, double *py2) +{ + GtkCanvasItem *item; + double i2c[6]; + ArtDRect i_bbox, c_bbox; + + item = GTK_CANVAS_ITEM (image); + + gtk_canvas_item_i2c_affine (item, i2c); + + get_bounds_item_relative (image, &i_bbox.x0, &i_bbox.y0, &i_bbox.x1, &i_bbox.y1); + art_drect_affine_transform (&c_bbox, &i_bbox, i2c); + + /* add a fudge factor */ + *px1 = c_bbox.x0 - 1; + *py1 = c_bbox.y0 - 1; + *px2 = c_bbox.x1 + 1; + *py2 = c_bbox.y1 + 1; +} + +/* deprecated */ +static void +recalc_bounds (GtkCanvasImageFrame *image) +{ + GtkCanvasItem *item; + + item = GTK_CANVAS_ITEM (image); + + get_bounds (image, &item->x1, &item->y1, &item->x2, &item->y2); + + item->x1 = image->cx; + item->y1 = image->cy; + item->x2 = image->cx + image->cwidth; + item->y2 = image->cy + image->cheight; + + gtk_canvas_group_child_bounds (GTK_CANVAS_GROUP (item->parent), item); +} + +static void +gtk_canvas_imageframe_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + GtkCanvasItem *item; + GtkCanvasImageFrame *image; + int update; + int calc_bounds; + + item = GTK_CANVAS_ITEM (object); + image = GTK_CANVAS_IMAGEFRAME (object); + + update = FALSE; + calc_bounds = FALSE; + + switch (arg_id) { + case ARG_PIXBUF: + if (item->canvas->aa && GTK_VALUE_BOXED (*arg)) { + if (image->pixbuf != NULL) + art_pixbuf_free (image->pixbuf); + image->pixbuf = GTK_VALUE_BOXED (*arg); + } + update = TRUE; + break; + + case ARG_X: + image->x = GTK_VALUE_DOUBLE (*arg); + update = TRUE; + break; + + case ARG_Y: + image->y = GTK_VALUE_DOUBLE (*arg); + update = TRUE; + break; + + case ARG_WIDTH: + image->width = fabs (GTK_VALUE_DOUBLE (*arg)); + update = TRUE; + break; + + case ARG_HEIGHT: + image->height = fabs (GTK_VALUE_DOUBLE (*arg)); + update = TRUE; + break; + + case ARG_DRAWWIDTH: + image->drawwidth = fabs (GTK_VALUE_DOUBLE (*arg)); + update = TRUE; + break; + + case ARG_ANCHOR: + image->anchor = GTK_VALUE_ENUM (*arg); + update = TRUE; + break; + + default: + break; + } + +#ifdef OLD_XFORM + if (update) + (* GTK_CANVAS_ITEM_CLASS (item->object.klass)->update) (item, NULL, NULL, 0); + + if (calc_bounds) + recalc_bounds (image); +#else + if (update) + gtk_canvas_item_request_update (item); +#endif +} + +static void +gtk_canvas_imageframe_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + GtkCanvasImageFrame *image; + + image = GTK_CANVAS_IMAGEFRAME (object); + + switch (arg_id) { + + case ARG_X: + GTK_VALUE_DOUBLE (*arg) = image->x; + break; + + case ARG_Y: + GTK_VALUE_DOUBLE (*arg) = image->y; + break; + + case ARG_WIDTH: + GTK_VALUE_DOUBLE (*arg) = image->width; + break; + + case ARG_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = image->height; + break; + + case ARG_DRAWWIDTH: + GTK_VALUE_DOUBLE (*arg) = image->drawwidth; + break; + + case ARG_ANCHOR: + GTK_VALUE_ENUM (*arg) = image->anchor; + break; + + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static void +gtk_canvas_imageframe_update (GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) +{ + GtkCanvasImageFrame *image; + ArtDRect i_bbox, c_bbox; + int w = 0; + int h = 0; + + image = GTK_CANVAS_IMAGEFRAME (item); + + if (parent_class->update) + (* parent_class->update) (item, affine, clip_path, flags); + + /* only works for non-rotated, non-skewed transforms */ + image->cwidth = (int) (image->width * affine[0] + 0.5); + image->cheight = (int) (image->height * affine[3] + 0.5); + + if (image->pixbuf) { + image->need_recalc = TRUE ; + } + +#ifdef OLD_XFORM + recalc_bounds (image); +#else + get_bounds_item_relative (image, &i_bbox.x0, &i_bbox.y0, &i_bbox.x1, &i_bbox.y1); + art_drect_affine_transform (&c_bbox, &i_bbox, affine); + + /* these values only make sense in the non-rotated, non-skewed case */ + image->cx = c_bbox.x0; + image->cy = c_bbox.y0; + + /* add a fudge factor */ + c_bbox.x0--; + c_bbox.y0--; + c_bbox.x1++; + c_bbox.y1++; + + gtk_canvas_update_bbox (item, c_bbox.x0, c_bbox.y0, c_bbox.x1, c_bbox.y1); + + if (image->pixbuf) { + w = image->pixbuf->width; + h = image->pixbuf->height; + } + + image->affine[0] = (affine[0] * image->width) / w; + image->affine[1] = (affine[1] * image->height) / h; + image->affine[2] = (affine[2] * image->width) / w; + image->affine[3] = (affine[3] * image->height) / h; + image->affine[4] = i_bbox.x0 * affine[0] + i_bbox.y0 * affine[2] + affine[4]; + image->affine[5] = i_bbox.x0 * affine[1] + i_bbox.y0 * affine[3] + affine[5]; + +#endif +} + +static void +gtk_canvas_imageframe_realize (GtkCanvasItem *item) +{ + GtkCanvasImageFrame *image; + + image = GTK_CANVAS_IMAGEFRAME (item); + + if (parent_class->realize) + (* parent_class->realize) (item); + +} + +static void +gtk_canvas_imageframe_unrealize (GtkCanvasItem *item) +{ + GtkCanvasImageFrame *image; + + image = GTK_CANVAS_IMAGEFRAME(item); + + if (parent_class->unrealize) + (* parent_class->unrealize) (item); +} + +static void +recalc_if_needed (GtkCanvasImageFrame *image) +{} + +static void +gtk_canvas_imageframe_draw (GtkCanvasItem *item, GdkDrawable *drawable, + int x, int y, int width, int height) +{ + fprintf(stderr, "please don't use the CanvasImageFrame item in a non-aa Canvas\n") ; + abort() ; +} + +static double +gtk_canvas_imageframe_point (GtkCanvasItem *item, double x, double y, + int cx, int cy, GtkCanvasItem **actual_item) +{ + GtkCanvasImageFrame *image; + int x1, y1, x2, y2; + int dx, dy; + + image = GTK_CANVAS_IMAGEFRAME (item); + + *actual_item = item; + + recalc_if_needed (image); + + x1 = image->cx - item->canvas->close_enough; + y1 = image->cy - item->canvas->close_enough; + x2 = image->cx + image->cwidth - 1 + item->canvas->close_enough; + y2 = image->cy + image->cheight - 1 + item->canvas->close_enough; + + /* Hard case: is point inside image's gravity region? */ + + //if ((cx >= x1) && (cy >= y1) && (cx <= x2) && (cy <= y2)) + //return dist_to_mask (image, cx, cy) / item->canvas->pixels_per_unit; + + /* Point is outside image */ + + x1 += item->canvas->close_enough; + y1 += item->canvas->close_enough; + x2 -= item->canvas->close_enough; + y2 -= item->canvas->close_enough; + + if (cx < x1) + dx = x1 - cx; + else if (cx > x2) + dx = cx - x2; + else + dx = 0; + + if (cy < y1) + dy = y1 - cy; + else if (cy > y2) + dy = cy - y2; + else + dy = 0; + + return sqrt (dx * dx + dy * dy) / item->canvas->pixels_per_unit; +} + +static void +gtk_canvas_imageframe_translate (GtkCanvasItem *item, double dx, double dy) +{ +#ifdef OLD_XFORM + GtkCanvasImageFrame *image; + + image = GTK_CANVAS_IMAGEFRAME (item); + + image->x += dx; + image->y += dy; + + recalc_bounds (image); +#endif +} + +static void +gtk_canvas_imageframe_bounds (GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2) +{ + GtkCanvasImageFrame *image; + + image = GTK_CANVAS_IMAGEFRAME (item); + + *x1 = image->x; + *y1 = image->y; + + switch (image->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + *x1 -= image->width / 2.0; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + *x1 -= image->width; + break; + } + + switch (image->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + *y1 -= image->height / 2.0; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + *y1 -= image->height; + break; + } + + *x2 = *x1 + image->width; + *y2 = *y1 + image->height; +} + +static void +gtk_canvas_imageframe_render (GtkCanvasItem *item, GtkCanvasBuf *buf) +{ + GtkCanvasImageFrame *image; + + image = GTK_CANVAS_IMAGEFRAME (item); + + gtk_canvas_buf_ensure_buf (buf); + +#ifdef VERBOSE + { + char str[128]; + art_affine_to_string (str, image->affine); + g_print ("gtk_canvas_imageframe_render %s\n", str); + } +#endif + + art_rgb_pixbuf_affine (buf->buf, + buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1, + buf->buf_rowstride, + image->pixbuf, + image->affine, + ART_FILTER_NEAREST, NULL); + + buf->is_bg = 0; +} |