/* * Rectangle.c -- Implementation of rectangle item. * * Authors : Patrick Lecoanet. * Creation date : Fri Dec 2 14:47:42 1994 * * $Id$ */ /* * Copyright (c) 1993 - 1999 CENA, Patrick Lecoanet -- * * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this code; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include "Item.h" #include "Geo.h" #include "Draw.h" #include "Types.h" #include "Image.h" #include "Color.h" #include "WidgetInfo.h" static const char rcsid[] = "$Id$"; static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; /* * Bit offset of flags. */ #define FILLED_BIT 1 /* If the rectangle is filled with color/pattern */ /* ********************************************************************************** * * Specific Rectangle item record * ********************************************************************************** */ typedef struct _RectangleItemStruct { ItemStruct header; /* Public data */ ZnPoint coords[2]; unsigned char flags; ReliefStyle relief; LineStyle line_style; int line_width; ZnColor line_color; Pixmap fill_pattern; Pixmap line_pattern; ZnColorGradient fill_color; ZnGradientGeom grad_geom; int line_alpha; int fill_alpha; char *tile_name; /* Private data */ ZnPoint dev[4]; ZnImage tile; ZnColorGradient gradient; ArtSVP *outline_svp; ArtSVP *fill_svp; } RectangleItemStruct, *RectangleItem; static ZnAttrConfig rect_attrs[] = { { ZN_CONFIG_BOOL, "-composerotation", NULL, Tk_Offset(RectangleItemStruct, header.flags), COMPOSE_ROTATION_BIT, ZN_COORDS_FLAG, False }, { ZN_CONFIG_BOOL, "-composescale", NULL, Tk_Offset(RectangleItemStruct, header.flags), COMPOSE_SCALE_BIT, ZN_COORDS_FLAG, False }, { ZN_CONFIG_UINT, "-fillalpha", NULL, Tk_Offset(RectangleItemStruct, fill_alpha), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_GRADIENT_COLOR, "-fillcolor", NULL, Tk_Offset(RectangleItemStruct, fill_color), 0, ZN_DRAW_FLAG|ZN_BORDER_FLAG, False }, { ZN_CONFIG_BOOL, "-filled", NULL, Tk_Offset(RectangleItemStruct, flags), FILLED_BIT, ZN_COORDS_FLAG, False }, { ZN_CONFIG_PATTERN, "-fillpattern", NULL, Tk_Offset(RectangleItemStruct, fill_pattern), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_GRADIENT_GEOM, "-gradient", NULL, Tk_Offset(RectangleItemStruct, grad_geom), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_UINT, "-linealpha", NULL, Tk_Offset(RectangleItemStruct, line_alpha), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_COLOR, "-linecolor", NULL, Tk_Offset(RectangleItemStruct, line_color), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_PATTERN, "-linepattern", NULL, Tk_Offset(RectangleItemStruct, line_pattern), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_LINE_STYLE, "-linestyle", NULL, Tk_Offset(RectangleItemStruct, line_style), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_DIM, "-linewidth", NULL, Tk_Offset(RectangleItemStruct, line_width), 0, ZN_COORDS_FLAG, False }, { ZN_CONFIG_PRI, "-priority", NULL, Tk_Offset(RectangleItemStruct, header.priority), 0, ZN_DRAW_FLAG|ZN_REPICK_FLAG, False }, { ZN_CONFIG_RELIEF, "-relief", NULL, Tk_Offset(RectangleItemStruct, relief), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_BOOL, "-sensitive", NULL, Tk_Offset(RectangleItemStruct, header.flags), SENSITIVE_BIT, ZN_REPICK_FLAG, False }, { ZN_CONFIG_TAGS, "-tags", NULL, Tk_Offset(RectangleItemStruct, header.tags), 0, 0, False }, { ZN_CONFIG_IMAGE, "-tile", NULL, Tk_Offset(RectangleItemStruct, tile_name), 0, ZN_DRAW_FLAG|ZN_TILE_FLAG, False }, { ZN_CONFIG_BOOL, "-visible", NULL, Tk_Offset(RectangleItemStruct, header.flags), VISIBLE_BIT, ZN_DRAW_FLAG|ZN_REPICK_FLAG|ZN_VIS_FLAG, False }, { ZN_CONFIG_END, NULL, NULL, 0, 0, 0 } }; /* ********************************************************************************** * * RectTileChange -- * ********************************************************************************** */ static void RectTileChange(ClientData client_data, int x, int y, int width, int height, int image_width, int image_height) { RectangleItem rect = (RectangleItem) client_data; InvalidateImage(rect->tile_name); ITEM.Invalidate((Item) rect, ZN_COORDS_FLAG); } /* ********************************************************************************** * * Init -- * ********************************************************************************** */ static int Init(Item item, int *argc, Tcl_Obj *CONST *args[]) { WidgetInfo *wi = item->wi; RectangleItem rect = (RectangleItem) item; Tcl_Obj **elems; int num_elems; rect->gradient = NULL; /* Init attributes */ SET(item->flags, VISIBLE_BIT); SET(item->flags, SENSITIVE_BIT); SET(item->flags, COMPOSE_ROTATION_BIT); SET(item->flags, COMPOSE_SCALE_BIT); item->priority = DEFAULT_RECTANGLE_PRIORITY; if (*argc < 1) { Tcl_AppendResult(wi->interp, " rectangle coords expected", NULL); return ZN_ERROR; } if ((Tcl_ListObjGetElements(wi->interp, (*args)[0], &num_elems, &elems) == ZN_ERROR) || (num_elems != 4) || (Tcl_GetDoubleFromObj(wi->interp, elems[0], &rect->coords[0].x) == ZN_ERROR) || (Tcl_GetDoubleFromObj(wi->interp, elems[1], &rect->coords[0].y) == ZN_ERROR) || (Tcl_GetDoubleFromObj(wi->interp, elems[2], &rect->coords[1].x) == ZN_ERROR) || (Tcl_GetDoubleFromObj(wi->interp, elems[3], &rect->coords[1].y) == ZN_ERROR)) { Tcl_AppendResult(wi->interp, " malformed rectangle coords", NULL); return ZN_ERROR; }; (*args)++; (*argc)--; CLEAR(rect->flags, FILLED_BIT); rect->relief = RELIEF_FLAT; rect->line_style = LINE_SIMPLE; rect->line_width = 1; rect->line_pattern = ZnUnspecifiedPattern; rect->tile_name = ""; rect->tile = ZnUnspecifiedImage; rect->fill_pattern = ZnUnspecifiedPattern; rect->line_color = ZnGetColorByValue(wi->win, wi->fore_color); rect->line_alpha = 255; rect->fill_color = ZnGetColorGradient(wi->interp, wi->win, ZnNameOfColor(wi->fore_color)); rect->fill_alpha = 255; rect->grad_geom = NULL; rect->outline_svp = rect->fill_svp = NULL; return ZN_OK; } /* ********************************************************************************** * * Clone -- * ********************************************************************************** */ static void Clone(Item item) { RectangleItem rect = (RectangleItem) item; WidgetInfo *wi = item->wi; char *text; if (rect->gradient) { rect->gradient = ZnGetColorGradientByValue(rect->gradient); } if (strlen(rect->tile_name) != 0) { text = ZnMalloc((strlen(rect->tile_name) + 1) * sizeof(char)); strcpy(text, rect->tile_name); rect->tile_name = text; rect->tile = Tk_GetImage(wi->interp, wi->win, rect->tile_name, RectTileChange, (ClientData) rect); } if (rect->line_pattern != ZnUnspecifiedPattern) { rect->line_pattern = Tk_GetBitmap(wi->interp, wi->win, Tk_NameOfBitmap(wi->dpy, rect->line_pattern)); } if (rect->fill_pattern != ZnUnspecifiedPattern) { rect->fill_pattern = Tk_GetBitmap(wi->interp, wi->win, Tk_NameOfBitmap(wi->dpy, rect->fill_pattern)); } rect->line_color = ZnGetColorByValue(wi->win, rect->line_color); rect->fill_color = ZnGetColorGradientByValue(rect->fill_color); if (rect->grad_geom) { rect->grad_geom = GradientGeomDuplicate(rect->grad_geom); } if (rect->outline_svp) { } if (rect->fill_svp) { } } /* ********************************************************************************** * * Destroy -- * ********************************************************************************** */ static void Destroy(Item item) { WidgetInfo *wi = item->wi; RectangleItem rect = (RectangleItem) item; if (rect->tile != ZnUnspecifiedImage) { Tk_FreeImage(rect->tile); rect->tile = ZnUnspecifiedImage; } if (strlen(rect->tile_name) != 0) { ZnFree(rect->tile_name); } if (rect->gradient) { ZnFreeColorGradient(rect->gradient); } if (rect->line_pattern != ZnUnspecifiedPattern) { Tk_FreeBitmap(wi->dpy, rect->line_pattern); } if (rect->fill_pattern != ZnUnspecifiedPattern) { Tk_FreeBitmap(wi->dpy, rect->fill_pattern); } ZnFreeColorGradient(rect->fill_color); ZnFreeColor(rect->line_color); if (rect->grad_geom) { GradientGeomDelete(rect->grad_geom); } if (rect->outline_svp) { art_svp_free(rect->outline_svp); } if (rect->fill_svp) { art_svp_free(rect->fill_svp); } } /* ********************************************************************************** * * Configure -- * ********************************************************************************** */ static int Configure(Item item, int argc, Tcl_Obj *CONST argv[], int *flags) { WidgetInfo *wi = item->wi; RectangleItem rect = (RectangleItem) item; int status = ZN_OK; status = ITEM_P.ConfigureAttributes((char *) item, -1, argc, argv, flags); if (rect->gradient && (ISSET(*flags, ZN_BORDER_FLAG) || (rect->relief == RELIEF_FLAT))) { ZnFreeColorGradient(rect->gradient); rect->gradient = NULL; } if ((rect->relief != RELIEF_FLAT) && !rect->gradient) { rect->gradient = ZnGetReliefGradient(wi->interp, wi->win, ZnNameOfColor(ZnColorGradientMidColor(wi->win, rect->fill_color))); } if (ISSET(*flags, ZN_TILE_FLAG)) { Tk_Image tile; if (strcmp(rect->tile_name, "") != 0) { tile = Tk_GetImage(wi->interp, wi->win, rect->tile_name, RectTileChange, (ClientData) rect); if (tile == NULL) { /* * The name will not be in sync with the image in * this case. */ status = ZN_ERROR; } } else { tile = ZnUnspecifiedImage; } if (rect->tile != ZnUnspecifiedImage) { Tk_FreeImage(rect->tile); } rect->tile = tile; } return status; } /* ********************************************************************************** * * Query -- * ********************************************************************************** */ static int Query(Item item, int argc, Tcl_Obj *CONST argv[]) { if (ITEM_P.QueryAttribute((char *) item, -1, argv[0]) == ZN_ERROR) { return ZN_ERROR; } return ZN_OK; } /* ********************************************************************************** * * ComputeCoordinates -- * ********************************************************************************** */ static void ComputeCoordinates(Item item, ZnBool force) { WidgetInfo *wi = item->wi; RectangleItem rect = (RectangleItem) item; ZnPoint p[4]; int i; ResetBBox(&item->item_bounding_box); if (!rect->line_width && ISCLEAR(rect->flags, FILLED_BIT)) { return; } p[0] = rect->coords[0]; p[2] = rect->coords[1]; p[1].x = p[2].x; p[1].y = p[0].y; p[3].x = p[0].x; p[3].y = p[2].y; ZnTransformPoints(wi->current_transfo, p, rect->dev, 4); for (i = 0; i < 4; i++) { rect->dev[i].x = REAL_TO_INT(rect->dev[i].x); rect->dev[i].y = REAL_TO_INT(rect->dev[i].y); } /* * Add all points to the bounding box. Then expand by the line * width to account for mitered corners. This is an overestimate. */ AddPointsToBBox(&item->item_bounding_box, rect->dev, 4); if (rect->line_width > 0) { item->item_bounding_box.orig.x -= rect->line_width; item->item_bounding_box.orig.y -= rect->line_width; item->item_bounding_box.corner.x += rect->line_width; item->item_bounding_box.corner.y += rect->line_width; } item->item_bounding_box.orig.x -= 1; item->item_bounding_box.orig.y -= 1; item->item_bounding_box.corner.x += 1; item->item_bounding_box.corner.y += 1; if (wi->local_render) { ArtVpath vpath[6]; if (ISSET(rect->flags, FILLED_BIT) || rect->line_width) { vpath[0].code = ART_MOVETO; vpath[0].x = rect->dev[0].x; vpath[0].y = rect->dev[0].y; vpath[1].code = ART_LINETO; vpath[1].x = rect->dev[3].x; vpath[1].y = rect->dev[3].y; vpath[2].code = ART_LINETO; vpath[2].x = rect->dev[2].x; vpath[2].y = rect->dev[2].y; vpath[3].code = ART_LINETO; vpath[3].x = rect->dev[1].x; vpath[3].y = rect->dev[1].y; vpath[4].code = ART_LINETO; vpath[4].x = rect->dev[0].x; vpath[4].y = rect->dev[0].y; vpath[5].code = ART_END; } if (rect->fill_svp) { art_svp_free(rect->fill_svp); rect->fill_svp = NULL; } if (ISSET(rect->flags, FILLED_BIT)) { rect->fill_svp = art_svp_from_vpath(vpath); } if (rect->outline_svp) { art_svp_free(rect->outline_svp); rect->outline_svp = NULL; } if (rect->line_width) { rect->outline_svp = art_svp_vpath_stroke(vpath, ART_PATH_STROKE_JOIN_MITER, ART_PATH_STROKE_CAP_SQUARE, rect->line_width, 2, 1); } } } /* ********************************************************************************** * * ToArea -- * Tell if the object is entirely outside (-1), * entirely inside (1) or in between (0). * ********************************************************************************** */ static int ToArea(Item item, ZnBBox *area, Tk_Uid tag_uid, int enclosed, ZnBool report) { RectangleItem rect = (RectangleItem) item; int result; result = -1; if (ISSET(rect->flags, FILLED_BIT)) { result = PolygonInBBox(rect->dev, 4, area, NULL); } else if (rect->line_width > 0) { int i; ZnPoint pts[5]; for (i = 0; i < 4; i++) { pts[i] = rect->dev[i]; } pts[4] = pts[0]; result = PolylineInBBox(pts, 5, rect->line_width, CapProjecting, JoinMiter, area); } return result; } /* ********************************************************************************** * * Draw -- * ********************************************************************************** */ static void Draw(Item item) { WidgetInfo *wi = item->wi; RectangleItem rect = (RectangleItem) item; XGCValues values; int i, gc_mask; ZnBool aligned; ZnDim delta; XRectangle r; XPoint xp[5]; delta = rect->dev[0].y - rect->dev[1].y; delta = ABS(delta); aligned = delta < X_PRECISION_LIMIT; delta = rect->dev[0].x - rect->dev[1].x; delta = ABS(delta); aligned |= delta < X_PRECISION_LIMIT; if (aligned) { if (rect->dev[0].x < rect->dev[2].x) { r.x = rect->dev[0].x; r.width = rect->dev[2].x - r.x; } else { r.x = rect->dev[2].x; r.width = rect->dev[0].x - r.x; } if (rect->dev[0].y < rect->dev[2].y) { r.y = rect->dev[0].y; r.height = rect->dev[2].y - r.y; } else { r.y = rect->dev[2].y; r.height = rect->dev[0].y - r.y; } } else { for (i = 0; i < 4; i++) { xp[i].x = rect->dev[i].x; xp[i].y = rect->dev[i].y; } xp[i] = xp[0]; } /* * Fill if requested. */ if (ISSET(rect->flags, FILLED_BIT)) { if (rect->grad_geom) { if (aligned) { DrawRectangleGradient(wi, rect->grad_geom, rect->fill_color, &r); } else { ZnPoly poly; POLY_CONTOUR1(&poly, rect->dev, 4); DrawPolygonGradient(wi, rect->grad_geom, rect->fill_color, &poly, &item->item_bounding_box); } } else { values.foreground = ZnPixel(ZnColorGradientMidColor(wi->win, rect->fill_color)); if (rect->tile != ZnUnspecifiedImage) { /* Fill tiled */ Pixmap pmap = GetImagePixmap(wi->win, rect->tile_name, rect->tile, NULL); values.fill_style = FillTiled; values.tile = pmap; values.ts_x_origin = (int) item->item_bounding_box.orig.x; values.ts_y_origin = (int) item->item_bounding_box.orig.y; XChangeGC(wi->dpy, wi->gc, GCTileStipXOrigin|GCTileStipYOrigin|GCFillStyle|GCTile, &values); } else if (rect->fill_pattern != ZnUnspecifiedPattern) { /* Fill stippled */ values.fill_style = FillStippled; values.stipple = rect->fill_pattern; values.ts_x_origin = (int) item->item_bounding_box.orig.x; values.ts_y_origin = (int) item->item_bounding_box.orig.y; XChangeGC(wi->dpy, wi->gc, GCTileStipXOrigin|GCTileStipYOrigin|GCFillStyle|GCStipple|GCForeground, &values); } else { /* Fill solid */ values.fill_style = FillSolid; XChangeGC(wi->dpy, wi->gc, GCForeground | GCFillStyle, &values); } if (aligned) { XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, r.x, r.y, r.width, r.height); } else { XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, xp, 4, Convex, CoordModeOrigin); } } } /* Draw the outline */ if (rect->line_width) { if (rect->relief != RELIEF_FLAT) { if (aligned) { DrawRectangleRelief(wi, rect->relief, rect->gradient, &r, rect->line_width); } else { ZnPoint p[5]; for (i = 0; i < 4; i++) { p[4-i].x = rect->dev[i].x; p[4-i].y = rect->dev[i].y; } p[0] = p[4]; DrawPolygonRelief(wi, rect->relief, rect->gradient, p, 5, rect->line_width); } } else { SetLineStyle(wi->dpy, wi->gc, rect->line_style); gc_mask = GCFillStyle|GCLineWidth|GCForeground|GCJoinStyle; values.foreground = ZnPixel(rect->line_color); values.line_width = (rect->line_width == 1) ? 0 : rect->line_width; values.join_style = JoinMiter; if (!aligned) { gc_mask |= GCCapStyle; values.cap_style = CapProjecting; } if (rect->line_pattern == ZnUnspecifiedPattern) { values.fill_style = FillSolid; XChangeGC(wi->dpy, wi->gc, gc_mask, &values); } else { values.fill_style = FillStippled; values.stipple = rect->line_pattern; gc_mask |= GCStipple; XChangeGC(wi->dpy, wi->gc, gc_mask, &values); } if (aligned) { XDrawRectangle(wi->dpy, wi->draw_buffer, wi->gc, r.x, r.y, r.width, r.height); } else { XDrawLines(wi->dpy, wi->draw_buffer, wi->gc, xp, 5, CoordModeOrigin); } } } } /* ********************************************************************************** * * Render -- * ********************************************************************************** */ static void Render(Item item) { WidgetInfo *wi = item->wi; RectangleItem rect = (RectangleItem) item; XColor *color = ZnColorGradientMidColor(wi->win, rect->fill_color); ArtPixBuf *pixbuf = NULL; if (rect->fill_svp != NULL) { if (strlen(rect->tile_name) != 0) { pixbuf = GetImagePixbuf(wi->win, rect->tile_name, rect->tile); } ITEM_P.RenderSVP(wi, rect->fill_svp, color->red, color->green, color->blue, rect->fill_alpha & 0xff, item->item_bounding_box.orig.x, item->item_bounding_box.orig.y, pixbuf); } if (rect->outline_svp != NULL) { ITEM_P.RenderSVP(wi, rect->outline_svp, rect->line_color->red, rect->line_color->green, rect->line_color->blue, rect->line_alpha & 0xff, 0, 0, NULL); } } /* ********************************************************************************** * * IsSensitive -- * ********************************************************************************** */ static ZnBool IsSensitive(Item item, int item_part) { return (ISSET(item->flags, SENSITIVE_BIT) && item->parent->class->IsSensitive(item->parent, ZN_NO_PART)); } /* ********************************************************************************** * * Pick -- * ********************************************************************************** */ static double Pick(Item item, ZnPoint *p, Item start_item, int aperture, Item *a_item, int *part) { RectangleItem rect = (RectangleItem) item; double best_dist; best_dist = PolygonToPointDist(rect->dev, 4, p); if (ISSET(rect->flags, FILLED_BIT)) { if (best_dist <= 0.0) { return 0.0; } } best_dist = ABS(best_dist); if (rect->line_width > 1) { double dist; int i; ZnPoint pts[5]; for (i = 0; i < 4; i++) { pts[i] = rect->dev[i]; } pts[4] = pts[0]; dist = PolylineToPointDist(pts, 5, rect->line_width, CapProjecting, JoinMiter, p); if (dist <= 0.0) { return 0.0; } best_dist = MIN(dist, best_dist); } return best_dist; } /* ********************************************************************************** * * PostScript -- * ********************************************************************************** */ static void PostScript(Item item, PostScriptInfo ps_info) { } /* ********************************************************************************** * * GetClipVertices -- * Get the clipping shape. * ********************************************************************************** */ static ZnBool GetClipVertices(Item item, ZnPoly *poly) { RectangleItem rect = (RectangleItem) item; double delta; ZnBool aligned; ZnPoint *points; delta = rect->dev[0].y - rect->dev[1].y; delta = ABS(delta); aligned = delta < PRECISION_LIMIT; delta = rect->dev[0].x - rect->dev[1].x; delta = ABS(delta); aligned |= delta < PRECISION_LIMIT; if (aligned) { ZnListAssertSize(item->wi->work_pts, 2); points = (ZnPoint *) ZnListArray(item->wi->work_pts); POLY_CONTOUR1(poly, points, 2); if (rect->dev[0].x < rect->dev[2].x) { points[0].x = rect->dev[0].x; points[1].x = rect->dev[2].x+1.0; } else { points[0].x = rect->dev[2].x; points[1].x = rect->dev[0].x+1.0; } if (rect->dev[0].y < rect->dev[2].y) { points[0].y = rect->dev[0].y; points[1].y = rect->dev[2].y+1.0; } else { points[0].y = rect->dev[2].y; points[1].y = rect->dev[0].y+1.0; } } else { POLY_CONTOUR1(poly, rect->dev, 4); } return aligned; } /* ********************************************************************************** * * Coords -- * Return or edit the item vertices. * ********************************************************************************** */ static int Coords(Item item, int contour, int index, int cmd, ZnPoint **pts, int *num_pts) { RectangleItem rect = (RectangleItem) item; if ((cmd == COORDS_ADD) || (cmd == COORDS_ADD_LAST) || (cmd == COORDS_REMOVE)) { Tcl_AppendResult(item->wi->interp, " rectangles can't add or remove vertices", NULL); return ZN_ERROR; } else if (cmd == COORDS_REPLACE_ALL) { if (*num_pts != 2) { Tcl_AppendResult(item->wi->interp, " coords command need 2 points on rectangles", NULL); return ZN_ERROR; } rect->coords[0] = (*pts)[0]; rect->coords[1] = (*pts)[1]; ITEM.Invalidate(item, ZN_COORDS_FLAG); } else if (cmd == COORDS_REPLACE) { if (*num_pts < 1) { Tcl_AppendResult(item->wi->interp, " coords command need at least 1 point", NULL); return ZN_ERROR; } if (index < 0) { index += 2; } if ((index < 0) || (index > 1)) { range_err: Tcl_AppendResult(item->wi->interp, " incorrect coord index, should be between -2 and 1", NULL); return ZN_ERROR; } rect->coords[index] = (*pts)[0]; ITEM.Invalidate(item, ZN_COORDS_FLAG); } else if (cmd == COORDS_READ_ALL) { *num_pts = 2; *pts = rect->coords; } else if (cmd == COORDS_READ) { if (index < 0) { index += 2; } if ((index < 0) || (index > 1)) { goto range_err; } *num_pts = 1; *pts = &rect->coords[index]; } return ZN_OK; } /* ********************************************************************************** * * Exported functions struct -- * ********************************************************************************** */ static ItemClassStruct RECTANGLE_ITEM_CLASS = { sizeof(RectangleItemStruct), False, /* has_fields */ 0, /* num_parts */ False, /* has_anchors */ "rectangle", rect_attrs, Init, Clone, Destroy, Configure, Query, NULL, /* GetFieldSet */ NULL, /* GetAnchor */ GetClipVertices, 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 ZnRectangle = (ZnItemClassId) &RECTANGLE_ITEM_CLASS;