13
0
livetrax/gtk2_ardour/canvas-imageframe.c
Paul Davis 2d32c7da36 more work on actions and general compilability
git-svn-id: svn://localhost/trunk/ardour2@56 d708f5d6-7413-0410-9779-e7cbd77b26cf
2005-10-10 20:38:53 +00:00

520 lines
12 KiB
C

/* Image item type for GnomeCanvas widget
*
* GnomeCanvas 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 <libgnomecanvas/gnome-canvas-util.h>
//GTK2FIX
//#include <libgnomecanvas/gnome-canvastypebuiltins.h>
enum {
ARG_0,
ARG_PIXBUF,
ARG_X,
ARG_Y,
ARG_WIDTH,
ARG_HEIGHT,
ARG_DRAWWIDTH,
ARG_ANCHOR
};
static void gnome_canvas_imageframe_class_init(GnomeCanvasImageFrameClass* class) ;
static void gnome_canvas_imageframe_init(GnomeCanvasImageFrame* image) ;
static void gnome_canvas_imageframe_destroy(GtkObject* object) ;
static void gnome_canvas_imageframe_set_arg(GtkObject* object, GtkArg* arg, guint arg_id) ;
static void gnome_canvas_imageframe_get_arg(GtkObject* object, GtkArg* arg, guint arg_id) ;
static void gnome_canvas_imageframe_update(GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) ;
static void gnome_canvas_imageframe_realize(GnomeCanvasItem *item) ;
static void gnome_canvas_imageframe_unrealize(GnomeCanvasItem *item) ;
static void gnome_canvas_imageframe_draw(GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) ;
static double gnome_canvas_imageframe_point(GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item) ;
static void gnome_canvas_imageframe_bounds(GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2) ;
static void gnome_canvas_imageframe_render(GnomeCanvasItem *item, GnomeCanvasBuf *buf) ;
static GnomeCanvasItemClass *parent_class;
GtkType
gnome_canvas_imageframe_get_type (void)
{
static GtkType imageframe_type = 0;
if (!imageframe_type) {
GtkTypeInfo imageframe_info = {
"GnomeCanvasImageFrame",
sizeof (GnomeCanvasImageFrame),
sizeof (GnomeCanvasImageFrameClass),
(GtkClassInitFunc) gnome_canvas_imageframe_class_init,
(GtkObjectInitFunc) gnome_canvas_imageframe_init,
NULL, /* reserved_1 */
NULL, /* reserved_2 */
(GtkClassInitFunc) NULL
};
imageframe_type = gtk_type_unique (gnome_canvas_item_get_type (), &imageframe_info);
}
return imageframe_type;
}
static void
gnome_canvas_imageframe_class_init (GnomeCanvasImageFrameClass *class)
{
GtkObjectClass *object_class;
GnomeCanvasItemClass *item_class;
object_class = (GtkObjectClass *) class;
item_class = (GnomeCanvasItemClass *) class;
parent_class = gtk_type_class (gnome_canvas_item_get_type ());
gtk_object_add_arg_type ("GnomeCanvasImageFrame::pixbuf", GTK_TYPE_BOXED, GTK_ARG_WRITABLE, ARG_PIXBUF);
gtk_object_add_arg_type ("GnomeCanvasImageFrame::x", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X);
gtk_object_add_arg_type ("GnomeCanvasImageFrame::y", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y);
gtk_object_add_arg_type ("GnomeCanvasImageFrame::width", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_WIDTH);
gtk_object_add_arg_type ("GnomeCanvasImageFrame::drawwidth", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_DRAWWIDTH);
gtk_object_add_arg_type ("GnomeCanvasImageFrame::height", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_HEIGHT);
gtk_object_add_arg_type ("GnomeCanvasImageFrame::anchor", GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, ARG_ANCHOR);
object_class->destroy = gnome_canvas_imageframe_destroy;
object_class->set_arg = gnome_canvas_imageframe_set_arg;
object_class->get_arg = gnome_canvas_imageframe_get_arg;
item_class->update = gnome_canvas_imageframe_update;
item_class->realize = gnome_canvas_imageframe_realize;
item_class->unrealize = gnome_canvas_imageframe_unrealize;
item_class->draw = gnome_canvas_imageframe_draw;
item_class->point = gnome_canvas_imageframe_point;
item_class->bounds = gnome_canvas_imageframe_bounds;
item_class->render = gnome_canvas_imageframe_render;
}
static void
gnome_canvas_imageframe_init (GnomeCanvasImageFrame *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;
// GTK2FIX
// GNOME_CANVAS_ITEM(image)->object.flags |= GNOME_CANVAS_ITEM_NO_AUTO_REDRAW;
}
static void
gnome_canvas_imageframe_destroy (GtkObject *object)
{
GnomeCanvasImageFrame *image;
g_return_if_fail (object != NULL);
g_return_if_fail (GNOME_CANVAS_IS_CANVAS_IMAGEFRAME (object));
image = GNOME_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 (GnomeCanvasImageFrame *image, double *px1, double *py1, double *px2, double *py2)
{
GnomeCanvasItem *item;
double x, y;
item = GNOME_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
gnome_canvas_imageframe_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
GnomeCanvasItem *item;
GnomeCanvasImageFrame *image;
int update;
int calc_bounds;
item = GNOME_CANVAS_ITEM (object);
image = GNOME_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;
}
if (update)
gnome_canvas_item_request_update (item);
}
static void
gnome_canvas_imageframe_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
GnomeCanvasImageFrame *image;
image = GNOME_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
gnome_canvas_imageframe_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
{
GnomeCanvasImageFrame *image;
ArtDRect i_bbox, c_bbox;
int w = 0;
int h = 0;
image = GNOME_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 ;
}
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++;
gnome_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];
}
static void
gnome_canvas_imageframe_realize (GnomeCanvasItem *item)
{
GnomeCanvasImageFrame *image;
image = GNOME_CANVAS_IMAGEFRAME (item);
if (parent_class->realize)
(* parent_class->realize) (item);
}
static void
gnome_canvas_imageframe_unrealize (GnomeCanvasItem *item)
{
GnomeCanvasImageFrame *image;
image = GNOME_CANVAS_IMAGEFRAME(item);
if (parent_class->unrealize)
(* parent_class->unrealize) (item);
}
static void
recalc_if_needed (GnomeCanvasImageFrame *image)
{}
static void
gnome_canvas_imageframe_draw (GnomeCanvasItem *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
gnome_canvas_imageframe_point (GnomeCanvasItem *item, double x, double y,
int cx, int cy, GnomeCanvasItem **actual_item)
{
GnomeCanvasImageFrame *image;
int x1, y1, x2, y2;
int dx, dy;
image = GNOME_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
gnome_canvas_imageframe_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
{
GnomeCanvasImageFrame *image;
image = GNOME_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
gnome_canvas_imageframe_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf)
{
GnomeCanvasImageFrame *image;
image = GNOME_CANVAS_IMAGEFRAME (item);
gnome_canvas_buf_ensure_buf (buf);
#ifdef VERBOSE
{
char str[128];
art_affine_to_string (str, image->affine);
g_print ("gnome_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;
}