/* * Icon.c -- Implementation of Icon item. * * Authors : Patrick LECOANET * Creation date : Sat Mar 25 13:53:39 1995 */ /* * Copyright (c) 1993 - 2005 CENA, Patrick Lecoanet -- * * See the file "Copyright" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * */ #include "Item.h" #include "Geo.h" #include "Draw.h" #include "Types.h" #include "Image.h" #include "WidgetInfo.h" #include "tkZinc.h" static const char rcsid[] = "$Id$"; static const char compile_id[] = "$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; /* ********************************************************************************** * * Specific Icon item record * ********************************************************************************** */ typedef struct _IconItemStruct { ZnItemStruct header; /* Public data */ ZnPoint pos; ZnImage image; Tk_Anchor anchor; Tk_Anchor connection_anchor; ZnGradient *color; /* Used only if the image is a bitmap (in GL alpha part * is always meaningful). */ /* Private data */ ZnPoint dev[4]; } IconItemStruct, *IconItem; static ZnAttrConfig icon_attrs[] = { { ZN_CONFIG_ANCHOR, "-anchor", NULL, Tk_Offset(IconItemStruct, anchor), 0, ZN_COORDS_FLAG, False }, { ZN_CONFIG_GRADIENT, "-color", NULL, Tk_Offset(IconItemStruct, color), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_BOOL, "-composealpha", NULL, Tk_Offset(IconItemStruct, header.flags), ZN_COMPOSE_ALPHA_BIT, ZN_DRAW_FLAG, False }, { ZN_CONFIG_BOOL, "-composerotation", NULL, Tk_Offset(IconItemStruct, header.flags), ZN_COMPOSE_ROTATION_BIT, ZN_COORDS_FLAG, False }, { ZN_CONFIG_BOOL, "-composescale", NULL, Tk_Offset(IconItemStruct, header.flags), ZN_COMPOSE_SCALE_BIT, ZN_COORDS_FLAG, False }, { ZN_CONFIG_ITEM, "-connecteditem", NULL, Tk_Offset(IconItemStruct, header.connected_item), 0, ZN_COORDS_FLAG|ZN_ITEM_FLAG, False }, { ZN_CONFIG_ANCHOR, "-connectionanchor", NULL, Tk_Offset(IconItemStruct, connection_anchor), 0, ZN_COORDS_FLAG, False }, { ZN_CONFIG_IMAGE, "-image", NULL, Tk_Offset(IconItemStruct, image), 0, ZN_COORDS_FLAG, False }, { ZN_CONFIG_BITMAP, "-mask", NULL, Tk_Offset(IconItemStruct, image), 0, ZN_COORDS_FLAG, False }, { ZN_CONFIG_POINT, "-position", NULL, Tk_Offset(IconItemStruct, pos), 0, ZN_COORDS_FLAG, False}, { ZN_CONFIG_PRI, "-priority", NULL, Tk_Offset(IconItemStruct, header.priority), 0, ZN_DRAW_FLAG|ZN_REPICK_FLAG, False }, { ZN_CONFIG_BOOL, "-sensitive", NULL, Tk_Offset(IconItemStruct, header.flags), ZN_SENSITIVE_BIT, ZN_REPICK_FLAG, False }, { ZN_CONFIG_TAG_LIST, "-tags", NULL, Tk_Offset(IconItemStruct, header.tags), 0, 0, False }, { ZN_CONFIG_BOOL, "-visible", NULL, Tk_Offset(IconItemStruct, header.flags), ZN_VISIBLE_BIT, ZN_DRAW_FLAG|ZN_REPICK_FLAG|ZN_VIS_FLAG, False }, { ZN_CONFIG_END, NULL, NULL, 0, 0, 0, False } }; /* ********************************************************************************** * * Init -- * ********************************************************************************** */ static int Init(ZnItem item, int *argc, Tcl_Obj *CONST *args[]) { ZnWInfo *wi = item->wi; IconItem icon = (IconItem) item; /*printf("size of an icon(header) = %d(%d)\n", sizeof(IconItemStruct), sizeof(ZnItemStruct));*/ /* Init attributes */ SET(item->flags, ZN_VISIBLE_BIT); SET(item->flags, ZN_SENSITIVE_BIT); SET(item->flags, ZN_COMPOSE_ALPHA_BIT); SET(item->flags, ZN_COMPOSE_ROTATION_BIT); SET(item->flags, ZN_COMPOSE_SCALE_BIT); item->priority = 1; icon->pos.x = icon->pos.y = 0.0; icon->image = ZnUnspecifiedImage; icon->anchor = TK_ANCHOR_NW; icon->connection_anchor = TK_ANCHOR_SW; icon->color = ZnGetGradientByValue(wi->fore_color); return TCL_OK; } /* ********************************************************************************** * * Clone -- * ********************************************************************************** */ static void Clone(ZnItem item) { IconItem icon = (IconItem) item; if (icon->image != ZnUnspecifiedImage) { icon->image = ZnGetImageByValue(icon->image, ZnUpdateItemImage, item); } icon->color = ZnGetGradientByValue(icon->color); } /* ********************************************************************************** * * Destroy -- * ********************************************************************************** */ static void Destroy(ZnItem item) { IconItem icon = (IconItem) item; if (icon->image != ZnUnspecifiedImage) { ZnFreeImage(icon->image, ZnUpdateItemImage, item); icon->image = ZnUnspecifiedImage; } ZnFreeGradient(icon->color); } /* ********************************************************************************** * * Configure -- * ********************************************************************************** */ static int Configure(ZnItem item, int argc, Tcl_Obj *CONST argv[], int *flags) { ZnItem old_connected; old_connected = item->connected_item; if (ZnConfigureAttributes(item->wi, item, item, icon_attrs, argc, argv, flags) == TCL_ERROR) { return TCL_ERROR; } if (ISSET(*flags, ZN_ITEM_FLAG)) { /* * If the new connected item is not appropriate back up * to the old one. */ if ((item->connected_item == ZN_NO_ITEM) || (ISSET(item->connected_item->class->flags, ZN_CLASS_HAS_ANCHORS) && (item->parent == item->connected_item->parent))) { ZnITEM.UpdateItemDependency(item, old_connected); } else { item->connected_item = old_connected; } } return TCL_OK; } /* ********************************************************************************** * * Query -- * ********************************************************************************** */ static int Query(ZnItem item, int argc, Tcl_Obj *CONST argv[]) { if (ZnQueryAttribute(item->wi->interp, item, icon_attrs, argv[0]) == TCL_ERROR) { return TCL_ERROR; } return TCL_OK; } /* * Compute the transformation to be used and the origin * of the icon (upper left point in item coordinates). */ static ZnTransfo * ComputeTransfoAndOrigin(ZnItem item, ZnPoint *origin) { IconItem icon = (IconItem) item; int w, h; ZnTransfo *t; ZnSizeOfImage(icon->image, &w, &h); /* * The connected item support anchors, this is checked by configure. */ if (item->connected_item != ZN_NO_ITEM) { ZnTransfo inv; item->connected_item->class->GetAnchor(item->connected_item, icon->connection_anchor, origin); /* GetAnchor return a position in device coordinates not in * the item coordinate space. To compute the icon origin * (upper left corner), we must apply the inverse transform * to the ref point before calling anchor2origin. */ ZnTransfoInvert(item->transfo, &inv); ZnTransformPoint(&inv, origin, origin); /* * The relevant transform in case of an attachment is the item * transform alone. This is case of local coordinate space where * only the translation is a function of the whole transform * stack, scale and rotation are reset. */ t = item->transfo; } else { origin->x = origin->y = 0; t = item->wi->current_transfo; } ZnAnchor2Origin(origin, (ZnReal) w, (ZnReal) h, icon->anchor, origin); //origin->x = ZnNearestInt(origin->x); //origin->y = ZnNearestInt(origin->y); return t; } /* ********************************************************************************** * * ComputeCoordinates -- * ********************************************************************************** */ static void ComputeCoordinates(ZnItem item, ZnBool force) { //ZnWInfo *wi = item->wi; IconItem icon = (IconItem) item; int width, height, i; ZnPoint quad[4]; ZnTransfo *t; ZnResetBBox(&item->item_bounding_box); /* * If there is no image then nothing to show. */ if (icon->image == ZnUnspecifiedImage) { return; } ZnSizeOfImage(icon->image, &width, &height); t = ComputeTransfoAndOrigin(item, quad); quad[1].x = quad[0].x; quad[1].y = quad[0].y + height; quad[2].x = quad[0].x + width; quad[2].y = quad[1].y; quad[3].x = quad[2].x; quad[3].y = quad[0].y; ZnTransformPoints(t, quad, icon->dev, 4); for (i = 0; i < 4; i++) { icon->dev[i].x = ZnNearestInt(icon->dev[i].x); icon->dev[i].y = ZnNearestInt(icon->dev[i].y); } /* * Compute the bounding box. */ ZnAddPointsToBBox(&item->item_bounding_box, icon->dev, 4); /* * Update connected items. */ SET(item->flags, ZN_UPDATE_DEPENDENT_BIT); } /* ********************************************************************************** * * ToArea -- * Tell if the object is entirely outside (-1), * entirely inside (1) or in between (0). * ********************************************************************************** */ static int ToArea(ZnItem item, ZnToArea ta) { IconItem icon = (IconItem) item; if (icon->image == ZnUnspecifiedImage) { return -1; } return ZnPolygonInBBox(icon->dev, 4, ta->area, NULL); } /* ********************************************************************************** * * Draw -- * ********************************************************************************** */ static void Draw(ZnItem item) { ZnWInfo *wi = item->wi; IconItem icon = (IconItem) item; XGCValues values; unsigned int gc_mask = 0; int w, h; ZnBBox box, inter, *clip_box; TkRegion clip_region, photo_region, clip; ZnBool simple; Pixmap pixmap; if (icon->image == ZnUnspecifiedImage) { return; } ZnSizeOfImage(icon->image, &w, &h); box.orig = *icon->dev; box.corner.x = icon->dev->x + w; box.corner.y = icon->dev->y + h; if (!ZnImageIsBitmap(icon->image)) { if (ZnTransfoIsTranslation(item->wi->current_transfo)) { /* * The code below does not use of Tk_RedrawImage to be * able to clip with the current clip region. */ ZnIntersectBBox(&box, &wi->damaged_area, &inter); box = inter; ZnCurrentClip(wi, &clip_region, NULL, NULL); pixmap = ZnImagePixmap(icon->image, wi->win); photo_region = ZnImageRegion(icon->image); clip = TkCreateRegion(); /* * ZnImageRegion may fail: perl/Tk 800.24 doesn't support * some internal TkPhoto functions. * This is a workaround using a rectangular region based * on the image size. */ if (photo_region == NULL) { XRectangle rect; rect.x = rect.y = 0; rect.width = w; rect.height = h; TkUnionRectWithRegion(&rect, clip, clip); } else { ZnUnionRegion(clip, photo_region, clip); } ZnOffsetRegion(clip, (int) icon->dev->x, (int) icon->dev->y); TkIntersectRegion(clip_region, clip, clip); TkSetRegion(wi->dpy, wi->gc, clip); XCopyArea(wi->dpy, pixmap, wi->draw_buffer, wi->gc, (int) (box.orig.x-icon->dev->x), (int) (box.orig.y-icon->dev->y), (unsigned int) (box.corner.x-box.orig.x), (unsigned int) (box.corner.y-box.orig.y), (int) box.orig.x, (int) box.orig.y); values.clip_x_origin = values.clip_y_origin = 0; XChangeGC(wi->dpy, wi->gc, GCClipXOrigin|GCClipYOrigin, &values); TkSetRegion(wi->dpy, wi->gc, clip_region); TkDestroyRegion(clip); } else { ZnPoint box[4]; int i; XImage *dest_im, *src_im; XImage *dest_mask, *src_mask; Pixmap drw, mask; unsigned int dest_im_width, dest_im_height; unsigned int max_width, max_height; GC gc, mask_gc; TkRegion current_clip; ZnBBox *current_clip_box; dest_im_width = (unsigned int) (item->item_bounding_box.corner.x - item->item_bounding_box.orig.x); max_width = MAX(dest_im_width, (unsigned int) w); dest_im_height = (unsigned int) (item->item_bounding_box.corner.y - item->item_bounding_box.orig.y); max_height = MAX(dest_im_height, (unsigned int) h); mask = Tk_GetPixmap(wi->dpy, wi->draw_buffer, max_width, max_height, 1); drw = Tk_GetPixmap(wi->dpy, wi->draw_buffer, max_width, max_height, Tk_Depth(wi->win)); mask_gc = XCreateGC(wi->dpy, mask, 0, NULL); gc = XCreateGC(wi->dpy, drw, 0, NULL); dest_mask = XCreateImage(wi->dpy, Tk_Visual(wi->win), 1, XYPixmap, 0, NULL, dest_im_width, dest_im_height, 8, 0); dest_mask->data = ZnMalloc(dest_mask->bytes_per_line * dest_mask->height); memset(dest_mask->data, 0, dest_mask->bytes_per_line * dest_mask->height); XSetForeground(wi->dpy, mask_gc, 0); XFillRectangle(wi->dpy, mask, mask_gc, 0, 0, max_width, max_height); dest_im = XCreateImage(wi->dpy, Tk_Visual(wi->win), Tk_Depth(wi->win), ZPixmap, 0, NULL, dest_im_width, dest_im_height, 32, 0); dest_im->data = ZnMalloc(dest_im->bytes_per_line * dest_im->height); memset(dest_im->data, 0, dest_im->bytes_per_line * dest_im->height); pixmap = ZnImagePixmap(icon->image, wi->win); photo_region = ZnImageRegion(icon->image); clip = TkCreateRegion(); /* * ZnImageRegion may fail: perl/Tk 800.24 doesn't support * some internal TkPhoto functions. * This is a workaround using a rectangular region based * on the image size. */ if (photo_region == NULL) { XRectangle rect; rect.x = rect.y = 0; rect.width = w; rect.height = h; TkUnionRectWithRegion(&rect, clip, clip); } else { ZnUnionRegion(clip, photo_region, clip); } XSetForeground(wi->dpy, mask_gc, 1); TkSetRegion(wi->dpy, mask_gc, clip); XFillRectangle(wi->dpy, mask, mask_gc, 0, 0, w, h); src_mask = XGetImage(wi->dpy, mask, 0, 0, w, h, 1, XYPixmap); src_im = XGetImage(wi->dpy, pixmap, 0, 0, w, h, ~0L, ZPixmap); box[0] = icon->dev[0]; box[1] = icon->dev[1]; box[2] = icon->dev[3]; box[3] = icon->dev[2]; for (i = 0; i < 4; i++) { box[i].x -= item->item_bounding_box.orig.x; box[i].y -= item->item_bounding_box.orig.y; box[i].x = ZnNearestInt(box[i].x); box[i].y = ZnNearestInt(box[i].y); } ZnMapImage(src_mask, dest_mask, box); ZnMapImage(src_im, dest_im, box); ZnCurrentClip(wi, ¤t_clip, ¤t_clip_box, NULL); TkSetRegion(wi->dpy, mask_gc, current_clip); XSetClipOrigin(wi->dpy, mask_gc, (int) -item->item_bounding_box.orig.x, (int) -item->item_bounding_box.orig.y); TkPutImage(NULL, 0,wi->dpy, mask, mask_gc, dest_mask, 0, 0, 0, 0, dest_im_width, dest_im_height); TkPutImage(NULL, 0, wi->dpy, drw, gc, dest_im, 0, 0, 0, 0, dest_im_width, dest_im_height); XSetClipMask(wi->dpy, gc, mask); XSetClipOrigin(wi->dpy, gc, (int) item->item_bounding_box.orig.x, (int) item->item_bounding_box.orig.y); XCopyArea(wi->dpy, drw, wi->draw_buffer, gc, 0, 0, dest_im_width, dest_im_height, (int) item->item_bounding_box.orig.x, (int) item->item_bounding_box.orig.y); XFreeGC(wi->dpy, gc); XFreeGC(wi->dpy, mask_gc); Tk_FreePixmap(wi->dpy, drw); Tk_FreePixmap(wi->dpy, mask); XDestroyImage(src_mask); XDestroyImage(dest_mask); XDestroyImage(src_im); XDestroyImage(dest_im); } } else { /* * If the current transform is a pure translation, it is * possible to optimize by directly drawing to the X back * buffer. Else, we draw in a temporary buffer, get * its content as an image, transform the image into another * one and use this last image as a mask to draw in the X * back buffer. */ pixmap = ZnImagePixmap(icon->image, wi->win); if (ZnTransfoIsTranslation(item->wi->current_transfo)) { ZnCurrentClip(wi, NULL, &clip_box, &simple); if (simple) { ZnIntersectBBox(&box, clip_box, &inter); box = inter; } values.fill_style = FillStippled; values.stipple = pixmap; values.ts_x_origin = (int) icon->dev->x; values.ts_y_origin = (int) icon->dev->y; values.foreground = ZnGetGradientPixel(icon->color, 0.0); gc_mask |= GCFillStyle|GCStipple|GCTileStipXOrigin|GCTileStipYOrigin|GCForeground; XChangeGC(wi->dpy, wi->gc, gc_mask, &values); XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, (int) box.orig.x, (int) box.orig.y, (unsigned int) (box.corner.x-box.orig.x), (unsigned int) (box.corner.y-box.orig.y)); } else { ZnPoint box[4]; int i; XImage *dest_im, *src_im; Pixmap drw; unsigned int dest_im_width, dest_im_height; unsigned int max_width, max_height; GC gc; dest_im_width = (unsigned int) (item->item_bounding_box.corner.x - item->item_bounding_box.orig.x); max_width = MAX(dest_im_width, (unsigned int) w); dest_im_height = (unsigned int) (item->item_bounding_box.corner.y - item->item_bounding_box.orig.y); max_height = MAX(dest_im_height, (unsigned int) h); drw = Tk_GetPixmap(wi->dpy, wi->draw_buffer, max_width, max_height, 1); gc = XCreateGC(wi->dpy, drw, 0, NULL); XSetForeground(wi->dpy, gc, 0); XFillRectangle(wi->dpy, drw, gc, 0, 0, max_width, max_height); dest_im = XCreateImage(wi->dpy, Tk_Visual(wi->win), 1, XYPixmap, 0, NULL, dest_im_width, dest_im_height, 8, 0); dest_im->data = ZnMalloc(dest_im->bytes_per_line * dest_im->height); memset(dest_im->data, 0, dest_im->bytes_per_line * dest_im->height); values.fill_style = FillStippled; values.stipple = pixmap; values.ts_x_origin = 0; values.ts_y_origin = 0; values.foreground = 1; gc_mask |= GCFillStyle|GCStipple|GCTileStipXOrigin|GCTileStipYOrigin|GCForeground; XChangeGC(wi->dpy, gc, gc_mask, &values); XFillRectangle(wi->dpy, drw, gc, 0, 0, w, h); src_im = XGetImage(wi->dpy, drw, 0, 0, w, h, 1, XYPixmap); box[0] = icon->dev[0]; box[1] = icon->dev[1]; box[2] = icon->dev[3]; box[3] = icon->dev[2]; for (i = 0; i < 4; i++) { box[i].x -= item->item_bounding_box.orig.x; box[i].y -= item->item_bounding_box.orig.y; box[i].x = ZnNearestInt(box[i].x); box[i].y = ZnNearestInt(box[i].y); } ZnMapImage(src_im, dest_im, box); TkPutImage(NULL, 0,wi->dpy, drw, gc, dest_im, 0, 0, 0, 0, dest_im_width, dest_im_height); values.foreground = ZnGetGradientPixel(icon->color, 0.0); values.stipple = drw; values.ts_x_origin = (int) item->item_bounding_box.orig.x; values.ts_y_origin = (int) item->item_bounding_box.orig.y; values.fill_style = FillStippled; XChangeGC(wi->dpy, wi->gc, GCFillStyle|GCStipple|GCTileStipXOrigin|GCTileStipYOrigin|GCForeground, &values); XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, (int) item->item_bounding_box.orig.x, (int) item->item_bounding_box.orig.y, (int) dest_im_width, (int) dest_im_height); XFreeGC(wi->dpy, gc); Tk_FreePixmap(wi->dpy, drw); XDestroyImage(src_im); XDestroyImage(dest_im); } } } /* ********************************************************************************** * * Render -- * ********************************************************************************** */ #ifdef GL static void Render(ZnItem item) { ZnWInfo *wi = item->wi; IconItem icon = (IconItem) item; if (icon->image != ZnUnspecifiedImage) { ZnRenderImage(wi, icon->image, icon->color, icon->dev, ZnImageIsBitmap(icon->image)); } } #else static void Render(ZnItem item) { } #endif /* ********************************************************************************** * * IsSensitive -- * ********************************************************************************** */ static ZnBool IsSensitive(ZnItem item, int item_part) { return (ISSET(item->flags, ZN_SENSITIVE_BIT) && item->parent->class->IsSensitive(item->parent, ZN_NO_PART)); } /* ********************************************************************************** * * Pick -- * ********************************************************************************** */ static double Pick(ZnItem item, ZnPick ps) { IconItem icon = (IconItem) item; ZnWInfo *wi = item->wi; double dist; double off_dist = MAX(1, wi->pick_aperture+1); int x, y, width, height; ZnPoint p; ZnBBox bbox; ZnTransfo t; if (icon->image == ZnUnspecifiedImage) { return 1.0e40; } ZnTransfoInvert(wi->current_transfo, &t); ZnTransformPoint(&t, ps->point, &p); ZnTransformPoint(&t, &icon->dev[0], &bbox.orig); ZnSizeOfImage(icon->image, &width, &height); bbox.corner.x = bbox.orig.x + width; bbox.corner.y = bbox.orig.y + height; dist = ZnRectangleToPointDist(&bbox, &p); x = (int) (p.x - bbox.orig.x); y = (int) (p.y - bbox.orig.y); /*printf("dist: %g\n", dist);*/ /* * If inside the icon rectangle, try to see if the point * is actually on the image or not. If it lies in an * area that is between pick_aperture+1 around the external * rectangle and the actual shape, the distance will be reported * as pick_aperture+1. Inside the actual shape it will be * reported as 0. This is a kludge, there is currently * no means to compute the real distance in the icon's * vicinity. */ if (dist <= 0) { dist = 0.0; if (icon->image != ZnUnspecifiedImage) { if (ZnPointInImage(icon->image, x, y)) { /* * The point is actually on the image shape. */ return dist; } else { /* * The point is not on the shape but still * inside the image's bounding box. */ return off_dist; } } else { return dist; } } else if (dist < off_dist) { dist = off_dist; } return dist; } /* ********************************************************************************** * * PostScript -- * ********************************************************************************** */ static int PostScript(ZnItem item, ZnBool prepass, ZnBBox *area) { ZnWInfo *wi = item->wi; IconItem icon = (IconItem) item; int w, h, result; ZnPoint origin; char path[500]; if (prepass || (icon->image == ZnUnspecifiedImage)) { return TCL_OK; } ZnSizeOfImage(icon->image, &w, &h); ComputeTransfoAndOrigin(item, &origin); sprintf(path, "/InitialTransform load setmatrix\n" "[%.15g %.15g %.15g %.15g %.15g %.15g] concat\n" "1 -1 scale\n" "%.15g %.15g translate\n", wi->current_transfo->_[0][0], wi->current_transfo->_[0][1], wi->current_transfo->_[1][0], wi->current_transfo->_[1][1], wi->current_transfo->_[2][0], wi->current_transfo->_[2][1], origin.x, origin.y - h); Tcl_AppendResult(wi->interp, path, NULL); if (ZnImageIsBitmap(icon->image)) { if (Tk_PostscriptColor(wi->interp, wi->ps_info, ZnGetGradientColor(icon->color, 0.0, NULL)) != TCL_OK) { return TCL_ERROR; } result = ZnPostscriptBitmap(wi->interp, wi->win, wi->ps_info, icon->image, 0, 0, w, h); } else { result = Tk_PostscriptImage(ZnImageTkImage(icon->image), wi->interp, wi->win, wi->ps_info, 0, 0, w, h, prepass); } return result; } /* ********************************************************************************** * * GetAnchor -- * ********************************************************************************** */ static void GetAnchor(ZnItem item, Tk_Anchor anchor, ZnPoint *p) { IconItem icon = (IconItem) item; if (icon->image == ZnUnspecifiedImage) { *p = *icon->dev; } else { ZnPoint q[4]; q[0] = icon->dev[0]; q[1] = icon->dev[1]; q[2] = icon->dev[3]; q[3] = icon->dev[2]; ZnRectOrigin2Anchor(q, anchor, p); } } /* ********************************************************************************** * * GetClipVertices -- * Get the clipping shape. * Never ever call ZnTriFree on the tristrip returned by GetClipVertices. * ********************************************************************************** */ static ZnBool GetClipVertices(ZnItem item, ZnTriStrip *tristrip) { IconItem icon = (IconItem) item; ZnPoint *points; ZnListAssertSize(ZnWorkPoints, 4); points = ZnListArray(ZnWorkPoints); points[0] = icon->dev[0]; points[1] = icon->dev[1]; points[2] = icon->dev[3]; points[3] = icon->dev[2]; ZnTriStrip1(tristrip, points, 4, False); return False; } /* ********************************************************************************** * * Coords -- * Return or edit the item origin. This doesn't take care of * the possible attachment. The change will be effective at the * end of the attachment. * ********************************************************************************** */ static int Coords(ZnItem item, int contour, int index, int cmd, ZnPoint **pts, char **controls, unsigned int *num_pts) { IconItem icon = (IconItem) item; if ((cmd == ZN_COORDS_ADD) || (cmd == ZN_COORDS_ADD_LAST) || (cmd == ZN_COORDS_REMOVE)) { Tcl_AppendResult(item->wi->interp, " icons can't add or remove vertices", NULL); return TCL_ERROR; } else if ((cmd == ZN_COORDS_REPLACE) || (cmd == ZN_COORDS_REPLACE_ALL)) { if (*num_pts == 0) { Tcl_AppendResult(item->wi->interp, " coords command need 1 point on icons", NULL); return TCL_ERROR; } icon->pos = (*pts)[0]; ZnITEM.Invalidate(item, ZN_COORDS_FLAG); } else if ((cmd == ZN_COORDS_READ) || (cmd == ZN_COORDS_READ_ALL)) { *num_pts = 1; *pts = &icon->pos; } return TCL_OK; } /* ********************************************************************************** * * Exported functions struct -- * ********************************************************************************** */ static ZnItemClassStruct ICON_ITEM_CLASS = { "icon", sizeof(IconItemStruct), icon_attrs, 0, /* num_parts */ ZN_CLASS_HAS_ANCHORS|ZN_CLASS_ONE_COORD, /* flags */ Tk_Offset(IconItemStruct, pos), Init, Clone, Destroy, Configure, Query, NULL, /* GetFieldSet */ GetAnchor, GetClipVertices, NULL, /* GetContours */ Coords, NULL, /* InsertChars */ NULL, /* DeleteChars */ NULL, /* Cursor */ NULL, /* Index */ NULL, /* Part */ NULL, /* Selection */ NULL, /* Contour */ ComputeCoordinates, ToArea, Draw, Render, IsSensitive, Pick, NULL, /* PickVertex */ PostScript }; ZnItemClassId ZnIcon = (ZnItemClassId) &ICON_ITEM_CLASS;