Paul Davis
2d32c7da36
git-svn-id: svn://localhost/trunk/ardour2@56 d708f5d6-7413-0410-9779-e7cbd77b26cf
520 lines
12 KiB
C
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;
|
|
}
|