/* * Rectangle.c -- Implementation of rectangle item. * * Authors : Patrick Lecoanet. * Creation date : Fri Dec 2 14:47:42 1994 * * $Id$ */ /* * Copyright (c) 1994 - 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 "Color.h" #include "WidgetInfo.h" #include "tkZinc.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 */ #define ALIGNED_BIT 2 /* ********************************************************************************** * * Specific Rectangle item record * ********************************************************************************** */ typedef struct _RectangleItemStruct { ZnItemStruct header; /* Public data */ ZnPoint coords[2]; unsigned short flags; ZnReliefStyle relief; ZnLineStyle line_style; ZnDim line_width; ZnGradient *line_color; ZnImage line_pattern; ZnGradient *fill_color; ZnImage tile; /* Private data */ ZnPoint dev[4]; ZnGradient *gradient; ZnPoint *grad_geo; } RectangleItemStruct, *RectangleItem; static ZnAttrConfig rect_attrs[] = { { ZN_CONFIG_BOOL, "-composealpha", NULL, Tk_Offset(RectangleItemStruct, header.flags), ZN_COMPOSE_ALPHA_BIT, ZN_DRAW_FLAG, False }, { ZN_CONFIG_BOOL, "-composerotation", NULL, Tk_Offset(RectangleItemStruct, header.flags), ZN_COMPOSE_ROTATION_BIT, ZN_COORDS_FLAG, False }, { ZN_CONFIG_BOOL, "-composescale", NULL, Tk_Offset(RectangleItemStruct, header.flags), ZN_COMPOSE_SCALE_BIT, ZN_COORDS_FLAG, False }, { ZN_CONFIG_GRADIENT, "-fillcolor", NULL, Tk_Offset(RectangleItemStruct, fill_color), 0, ZN_COORDS_FLAG|ZN_BORDER_FLAG, False }, { ZN_CONFIG_BOOL, "-filled", NULL, Tk_Offset(RectangleItemStruct, flags), FILLED_BIT, ZN_COORDS_FLAG, False }, { ZN_CONFIG_BITMAP, "-fillpattern", NULL, Tk_Offset(RectangleItemStruct, tile), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_GRADIENT, "-linecolor", NULL, Tk_Offset(RectangleItemStruct, line_color), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_BITMAP, "-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), ZN_SENSITIVE_BIT, ZN_REPICK_FLAG, False }, { ZN_CONFIG_TAG_LIST, "-tags", NULL, Tk_Offset(RectangleItemStruct, header.tags), 0, 0, False }, { ZN_CONFIG_IMAGE, "-tile", NULL, Tk_Offset(RectangleItemStruct, tile), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_BOOL, "-visible", NULL, Tk_Offset(RectangleItemStruct, 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; RectangleItem rect = (RectangleItem) item; unsigned int num_points; ZnPoint *points; rect->gradient = NULL; rect->grad_geo = NULL; /* 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; if (*argc < 1) { Tcl_AppendResult(wi->interp, " rectangle coords expected", NULL); return TCL_ERROR; } if (ZnParseCoordList(wi, (*args)[0], &points, NULL, &num_points, NULL) == TCL_ERROR) { return TCL_ERROR; } if (num_points != 2) { Tcl_AppendResult(wi->interp, " malformed rectangle coords", NULL); return TCL_ERROR; }; rect->coords[0] = points[0]; rect->coords[1] = points[1]; (*args)++; (*argc)--; CLEAR(rect->flags, FILLED_BIT); rect->relief = ZN_RELIEF_FLAT; rect->line_style = ZN_LINE_SIMPLE; rect->line_width = 1; rect->line_pattern = ZnUnspecifiedImage; rect->tile = ZnUnspecifiedImage; rect->line_color = ZnGetGradientByValue(wi->fore_color); rect->fill_color = ZnGetGradientByValue(wi->fore_color); return TCL_OK; } /* ********************************************************************************** * * Clone -- * ********************************************************************************** */ static void Clone(ZnItem item) { RectangleItem rect = (RectangleItem) item; if (rect->gradient) { rect->gradient = ZnGetGradientByValue(rect->gradient); } if (rect->tile != ZnUnspecifiedImage) { rect->tile = ZnGetImageByValue(rect->tile, ZnUpdateItemImage, item); } if (rect->line_pattern != ZnUnspecifiedImage) { rect->line_pattern = ZnGetImageByValue(rect->line_pattern, NULL, NULL); } rect->line_color = ZnGetGradientByValue(rect->line_color); rect->fill_color = ZnGetGradientByValue(rect->fill_color); rect->grad_geo = NULL; } /* ********************************************************************************** * * Destroy -- * ********************************************************************************** */ static void Destroy(ZnItem item) { RectangleItem rect = (RectangleItem) item; if (rect->tile != ZnUnspecifiedImage) { ZnFreeImage(rect->tile, ZnUpdateItemImage, item); rect->tile = ZnUnspecifiedImage; } if (rect->gradient) { ZnFreeGradient(rect->gradient); } if (rect->line_pattern != ZnUnspecifiedImage) { ZnFreeImage(rect->line_pattern, NULL, NULL); rect->line_pattern = ZnUnspecifiedImage; } if (rect->grad_geo) { ZnFree(rect->grad_geo); } ZnFreeGradient(rect->fill_color); ZnFreeGradient(rect->line_color); } /* ********************************************************************************** * * Configure -- * ********************************************************************************** */ static int Configure(ZnItem item, int argc, Tcl_Obj *CONST argv[], int *flags) { ZnWInfo *wi = item->wi; RectangleItem rect = (RectangleItem) item; int status = TCL_OK; XColor *color; unsigned short alpha; status = ZnConfigureAttributes(wi, item, item, rect_attrs, argc, argv, flags); if (rect->gradient && (ISSET(*flags, ZN_BORDER_FLAG) || (rect->relief == ZN_RELIEF_FLAT))) { ZnFreeGradient(rect->gradient); rect->gradient = NULL; } if ((rect->relief != ZN_RELIEF_FLAT) && !rect->gradient) { color = ZnGetGradientColor(rect->line_color, 51.0, &alpha); rect->gradient = ZnGetReliefGradient(wi->interp, wi->win, Tk_NameOfColor(color), alpha); if (rect->gradient == NULL) { status = TCL_ERROR; } } return status; } /* ********************************************************************************** * * Query -- * ********************************************************************************** */ static int Query(ZnItem item, int argc, Tcl_Obj *CONST argv[]) { if (ZnQueryAttribute(item->wi->interp, item, rect_attrs, argv[0]) == TCL_ERROR) { return TCL_ERROR; } return TCL_OK; } /* ********************************************************************************** * * ComputeCoordinates -- * ********************************************************************************** */ static void ComputeCoordinates(ZnItem item, ZnBool force) { ZnWInfo *wi = item->wi; RectangleItem rect = (RectangleItem) item; ZnPoint p[4]; int i; ZnBool aligned; ZnDim delta, lw2; ZnResetBBox(&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 = ZnNearestInt(rect->dev[i].x); rect->dev[i].y = ZnNearestInt(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. */ ZnAddPointsToBBox(&item->item_bounding_box, rect->dev, 4); if (rect->line_width > 0) { lw2 = rect->line_width/2.0; item->item_bounding_box.orig.x -= lw2; item->item_bounding_box.orig.y -= lw2; item->item_bounding_box.corner.x += lw2; item->item_bounding_box.corner.y += lw2; } item->item_bounding_box.orig.x -= 0.5; item->item_bounding_box.orig.y -= 0.5; item->item_bounding_box.corner.x += 0.5; item->item_bounding_box.corner.y += 0.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[3].x; delta = ABS(delta); aligned &= delta < X_PRECISION_LIMIT; ASSIGN(rect->flags, ALIGNED_BIT, aligned); #ifdef GL /* * Compute the gradient geometry */ if (!ZnGradientFlat(rect->fill_color)) { ZnPoly shape; if (rect->fill_color->type == ZN_AXIAL_GRADIENT) { int angle = rect->fill_color->angle; if ((angle != 0) && (angle != 90) && (angle != 180) && (angle != 270)) { if (!rect->grad_geo) { rect->grad_geo = ZnMalloc(6*sizeof(ZnPoint)); } ZnPolyContour1(&shape, p, 4, False); ZnComputeGradient(rect->fill_color, wi, &shape, rect->grad_geo); } else { goto free_ggeo; } } else { if (!rect->grad_geo) { rect->grad_geo = ZnMalloc(6*sizeof(ZnPoint)); } if (rect->fill_color->type == ZN_PATH_GRADIENT) { ZnPolyContour1(&shape, rect->coords, 2, False); } else { ZnPolyContour1(&shape, p, 4, False); } ZnComputeGradient(rect->fill_color, wi, &shape, rect->grad_geo); } } else { free_ggeo: if (rect->grad_geo) { ZnFree(rect->grad_geo); rect->grad_geo = NULL; } } #endif } /* ********************************************************************************** * * ToArea -- * Tell if the object is entirely outside (-1), * entirely inside (1) or in between (0). * ********************************************************************************** */ static int ToArea(ZnItem item, ZnToArea ta) { RectangleItem rect = (RectangleItem) item; int result, result2; ZnBBox *area = ta->area; result = -1; if (ISSET(rect->flags, FILLED_BIT)) { result = ZnPolygonInBBox(rect->dev, 4, area, NULL); if (result == 0) { return 0; } } 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]; result2 = ZnPolylineInBBox(pts, 5, rect->line_width, CapProjecting, JoinMiter, area); if (ISCLEAR(rect->flags, FILLED_BIT)) { if (result2 == 0) { return 0; } result = result2; } else if (result2 != result) { return 0; } } return result; } /* ********************************************************************************** * * Draw -- * ********************************************************************************** */ static void Draw(ZnItem item) { ZnWInfo *wi = item->wi; RectangleItem rect = (RectangleItem) item; XGCValues values; unsigned int i, gc_mask; XRectangle r; XPoint xp[5]; if (ISSET(rect->flags, ALIGNED_BIT)) { if (rect->dev[0].x < rect->dev[2].x) { r.x = (int) rect->dev[0].x; r.width = ((int) rect->dev[2].x) - r.x; } else { r.x = (int) rect->dev[2].x; r.width = ((int) rect->dev[0].x) - r.x; } if (rect->dev[0].y < rect->dev[2].y) { r.y = (int) rect->dev[0].y; r.height = ((int) rect->dev[2].y) - r.y; } else { r.y = (int) rect->dev[2].y; r.height = ((int) rect->dev[0].y) - r.y; } } else { for (i = 0; i < 4; i++) { xp[i].x = (int) rect->dev[i].x; xp[i].y = (int) rect->dev[i].y; } xp[i] = xp[0]; } /* * Fill if requested. */ if (ISSET(rect->flags, FILLED_BIT)) { values.foreground = ZnGetGradientPixel(rect->fill_color, 0.0); if (rect->tile != ZnUnspecifiedImage) { if (!ZnImageIsBitmap(rect->tile)) { /* Fill tiled */ values.fill_style = FillTiled; values.tile = ZnImagePixmap(rect->tile, wi->win); if (ISSET(rect->flags, ALIGNED_BIT)) { values.ts_x_origin = (int) r.x; values.ts_y_origin = (int) r.y; } else { 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 { values.fill_style = FillStippled; values.stipple = ZnImagePixmap(rect->tile, wi->win); if (ISSET(rect->flags, ALIGNED_BIT)) { values.ts_x_origin = (int) r.x; values.ts_y_origin = (int) r.y; } else { 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 (ISSET(rect->flags, ALIGNED_BIT)) { 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 != ZN_RELIEF_FLAT) { if (ISSET(rect->flags, ALIGNED_BIT)) { ZnDrawRectangleRelief(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]; ZnDrawPolygonRelief(wi, rect->relief, rect->gradient, p, 5, rect->line_width); } } else { ZnSetLineStyle(wi, rect->line_style); gc_mask = GCFillStyle|GCLineWidth|GCForeground|GCJoinStyle; values.foreground = ZnGetGradientPixel(rect->line_color, 0.0); values.line_width = (rect->line_width == 1) ? 0 : (int) rect->line_width; values.join_style = JoinMiter; if (ISCLEAR(rect->flags, ALIGNED_BIT)) { gc_mask |= GCCapStyle; values.cap_style = CapProjecting; } if (rect->line_pattern == ZnUnspecifiedImage) { values.fill_style = FillSolid; XChangeGC(wi->dpy, wi->gc, gc_mask, &values); } else { values.fill_style = FillStippled; values.stipple = ZnImagePixmap(rect->line_pattern, wi->win); gc_mask |= GCStipple; XChangeGC(wi->dpy, wi->gc, gc_mask, &values); } if (ISSET(rect->flags, ALIGNED_BIT)) { 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 -- * ********************************************************************************** */ #ifdef GL static void RectRenderCB(void *closure) { RectangleItem rect = (RectangleItem) closure; glBegin(GL_TRIANGLE_STRIP); glVertex2d(rect->dev[0].x, rect->dev[0].y); glVertex2d(rect->dev[3].x, rect->dev[3].y); glVertex2d(rect->dev[1].x, rect->dev[1].y); glVertex2d(rect->dev[2].x, rect->dev[2].y); glEnd(); } #endif #ifdef GL static void Render(ZnItem item) { ZnWInfo *wi = item->wi; RectangleItem rect = (RectangleItem) item; int i; #ifdef GL_LIST if (!item->gl_list) { item->gl_list = glGenLists(1); glNewList(item->gl_list, GL_COMPILE); #endif if (ISSET(rect->flags, FILLED_BIT)) { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); if (!ZnGradientFlat(rect->fill_color)) { ZnBool fast = (rect->fill_color->type == ZN_AXIAL_GRADIENT) && !rect->grad_geo; ZnPoly poly; ZnPolyContour1(&poly, rect->dev, 4, False); ZnRenderGradient(wi, rect->fill_color, fast ? NULL: RectRenderCB, rect, fast ? rect->dev : rect->grad_geo, &poly); } else if (rect->tile != ZnUnspecifiedImage) { /* Fill tiled/patterned */ if (ISSET(rect->flags, ALIGNED_BIT)) { ZnBBox bbox; bbox.orig = rect->dev[0]; bbox.corner = rect->dev[2]; ZnRenderTile(wi, rect->tile, rect->fill_color, NULL, NULL, (ZnPoint *) &bbox); } else { ZnRenderTile(wi, rect->tile, rect->fill_color, RectRenderCB, rect, (ZnPoint *) &item->item_bounding_box); } } else { unsigned short alpha; XColor *color = ZnGetGradientColor(rect->fill_color, 0.0, &alpha); alpha = ZnComposeAlpha(alpha, wi->alpha); glColor4us(color->red, color->green, color->blue, alpha); RectRenderCB(rect); } } if (rect->line_width) { 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]; if (rect->relief != ZN_RELIEF_FLAT) { ZnRenderPolygonRelief(wi, rect->relief, rect->gradient, False, p, 5, rect->line_width); } else { ZnRenderPolyline(wi, p, 5, rect->line_width, rect->line_style, CapRound, JoinMiter, NULL, NULL, rect->line_color); } } #ifdef GL_LIST glEndList(); } glCallList(item->gl_list); #endif } #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) { RectangleItem rect = (RectangleItem) item; double best_dist; ZnPoint *p = ps->point; best_dist = ZnPolygonToPointDist(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 = ZnPolylineToPointDist(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 int PostScript(ZnItem item, ZnBool prepass, ZnBBox *area) { ZnWInfo *wi = item->wi; RectangleItem rect = (RectangleItem) item; char path[500]; if (ISCLEAR(rect->flags, FILLED_BIT) && (rect->line_width == 0)) { return TCL_OK; } /* * Create the rectangle path. */ sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto %.15g %.15g lineto %.15g %.15g lineto closepath\n", rect->dev[0].x, rect->dev[0].y, rect->dev[1].x, rect->dev[1].y, rect->dev[2].x, rect->dev[2].y, rect->dev[3].x, rect->dev[3].y); Tcl_AppendResult(wi->interp, path, NULL); /* * Emit code to draw the filled area. */ if (ISSET(rect->flags, FILLED_BIT)) { if (rect->line_width) { Tcl_AppendResult(wi->interp, "gsave\n", NULL); } if (!ZnGradientFlat(rect->fill_color)) { if (ZnPostscriptGradient(wi->interp, wi->ps_info, rect->fill_color, rect->grad_geo ? rect->grad_geo : rect->dev, NULL) != TCL_OK) { return TCL_ERROR; } } else if (rect->tile != ZnUnspecifiedImage) { if (!ZnImageIsBitmap(rect->tile)) { /* Fill tiled */ if (ZnPostscriptTile(wi->interp, wi->win, wi->ps_info, rect->tile) != TCL_OK) { return TCL_ERROR; } } else { /* Fill stippled */ if (Tk_PostscriptColor(wi->interp, wi->ps_info, ZnGetGradientColor(rect->fill_color, 0.0, NULL)) != TCL_OK) { return TCL_ERROR; } Tcl_AppendResult(wi->interp, "clip ", NULL); if (ZnPostscriptStipple(wi->interp, wi->win, wi->ps_info, rect->tile) != TCL_OK) { return TCL_ERROR; } } } else { /* Fill solid */ if (Tk_PostscriptColor(wi->interp, wi->ps_info, ZnGetGradientColor(rect->fill_color, 0.0, NULL)) != TCL_OK) { return TCL_ERROR; } Tcl_AppendResult(wi->interp, "fill\n", NULL); } if (rect->line_width) { Tcl_AppendResult(wi->interp, "grestore\n", NULL); } } /* * Then emit code code to stroke the outline. */ if (rect->line_width) { if (rect->relief != ZN_RELIEF_FLAT) { /* TODO No support yet */ } else { Tcl_AppendResult(wi->interp, "0 setlinejoin 2 setlinecap\n", NULL); if (ZnPostscriptOutline(wi->interp, wi->ps_info, wi->win, rect->line_width, rect->line_style, rect->line_color, rect->line_pattern) != TCL_OK) { return TCL_ERROR; } } } return TCL_OK; } /* ********************************************************************************** * * GetClipVertices -- * Get the clipping shape. * Never ever call ZnTriFree on the tristrip returned by GetClipVertices. * ********************************************************************************** */ static ZnBool GetClipVertices(ZnItem item, ZnTriStrip *tristrip) { RectangleItem rect = (RectangleItem) item; ZnPoint *points; if (ISSET(rect->flags, ALIGNED_BIT)) { ZnListAssertSize(ZnWorkPoints, 2); points = ZnListArray(ZnWorkPoints); ZnTriStrip1(tristrip, points, 2, False); tristrip->strips[0].fan = False; 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 { ZnListAssertSize(ZnWorkPoints, 4); points = ZnListArray(ZnWorkPoints); points[0] = rect->dev[1]; points[1] = rect->dev[2]; points[2] = rect->dev[0]; points[3] = rect->dev[3]; ZnTriStrip1(tristrip, points, 4, False); } return ISSET(rect->flags, ALIGNED_BIT); } /* ********************************************************************************** * * Coords -- * Return or edit the item vertices. * ********************************************************************************** */ static int Coords(ZnItem item, int contour, int index, int cmd, ZnPoint **pts, char **controls, unsigned int *num_pts) { RectangleItem rect = (RectangleItem) item; if ((cmd == ZN_COORDS_ADD) || (cmd == ZN_COORDS_ADD_LAST) || (cmd == ZN_COORDS_REMOVE)) { Tcl_AppendResult(item->wi->interp, " rectangles can't add or remove vertices", NULL); return TCL_ERROR; } else if (cmd == ZN_COORDS_REPLACE_ALL) { if (*num_pts != 2) { Tcl_AppendResult(item->wi->interp, " coords command need 2 points on rectangles", NULL); return TCL_ERROR; } rect->coords[0] = (*pts)[0]; rect->coords[1] = (*pts)[1]; ZnITEM.Invalidate(item, ZN_COORDS_FLAG); } else if (cmd == ZN_COORDS_REPLACE) { if (*num_pts < 1) { Tcl_AppendResult(item->wi->interp, " coords command need at least 1 point", NULL); return TCL_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 TCL_ERROR; } rect->coords[index] = (*pts)[0]; ZnITEM.Invalidate(item, ZN_COORDS_FLAG); } else if (cmd == ZN_COORDS_READ_ALL) { *num_pts = 2; *pts = rect->coords; } else if (cmd == ZN_COORDS_READ) { if (index < 0) { index += 2; } if ((index < 0) || (index > 1)) { goto range_err; } *num_pts = 1; *pts = &rect->coords[index]; } return TCL_OK; } /* ********************************************************************************** * * GetAnchor -- * ********************************************************************************** */ static void GetAnchor(ZnItem item, Tk_Anchor anchor, ZnPoint *p) { ZnBBox *bbox = &item->item_bounding_box; ZnOrigin2Anchor(&bbox->orig, bbox->corner.x - bbox->orig.x, bbox->corner.y - bbox->orig.y, anchor, p); } /* ********************************************************************************** * * Exported functions struct -- * ********************************************************************************** */ static ZnItemClassStruct RECTANGLE_ITEM_CLASS = { "rectangle", sizeof(RectangleItemStruct), rect_attrs, 0, /* num_parts */ 0, /* flags */ -1, 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 ZnRectangle = (ZnItemClassId) &RECTANGLE_ITEM_CLASS;