📄 tkcanvline.c
字号:
/* * tkCanvLine.c -- * * This file implements line items for canvas widgets. * * Copyright (c) 1991-1993 The Regents of the University of California. * All rights reserved. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the * above copyright notice and the following two paragraphs appear in * all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */#include <stdio.h>#include "tkInt.h"#include "tkCanvas.h"#include "tkConfig.h"/* * The structure below defines the record for each line item. */typedef struct LineItem { Tk_Item header; /* Generic stuff that's the same for all * types. MUST BE FIRST IN STRUCTURE. */ Tk_Canvas *canvasPtr; /* Canvas containing item. Needed for * parsing arrow shapes. */ int numPoints; /* Number of points in line (always >= 2). */ double *coordPtr; /* Pointer to malloc-ed array containing * x- and y-coords of all points in line. * X-coords are even-valued indices, y-coords * are corresponding odd-valued indices. If * the line has arrowheads then the first * and last points have been adjusted to refer * to the necks of the arrowheads rather than * their tips. The actual endpoints are * stored in the *firstArrowPtr and * *lastArrowPtr, if they exist. */ int width; /* Width of line. */ XColor *fg; /* Foreground color for line. */ Pixmap fillStipple; /* Stipple bitmap for filling line. */ int capStyle; /* Cap style for line. */ int joinStyle; /* Join style for line. */ GC gc; /* Graphics context for filling line. */ Tk_Uid arrow; /* Indicates whether or not to draw arrowheads: * "none", "first", "last", or "both". */ float arrowShapeA; /* Distance from tip of arrowhead to center. */ float arrowShapeB; /* Distance from tip of arrowhead to trailing * point, measured along shaft. */ float arrowShapeC; /* Distance of trailing points from outside * edge of shaft. */ double *firstArrowPtr; /* Points to array of PTS_IN_ARROW points * describing polygon for arrowhead at first * point in line. First point of arrowhead * is tip. Malloc'ed. NULL means no arrowhead * at first point. */ double *lastArrowPtr; /* Points to polygon for arrowhead at last * point in line (PTS_IN_ARROW points, first * of which is tip). Malloc'ed. NULL means * no arrowhead at last point. */ int smooth; /* Non-zero means draw line smoothed (i.e. * with Bezier splines). */ int splineSteps; /* Number of steps in each spline segment. */} LineItem;/* * Number of points in an arrowHead: */#define PTS_IN_ARROW 6/* * Prototypes for procedures defined in this file: */static int ArrowheadPostscript _ANSI_ARGS_((Tk_Canvas *canvasPtr, LineItem *linePtr, double *arrowPtr, Tk_PostscriptInfo *psInfoPtr));static void ComputeLineBbox _ANSI_ARGS_((Tk_Canvas *canvasPtr, LineItem *linePtr));static int ConfigureLine _ANSI_ARGS_(( Tk_Canvas *canvasPtr, Tk_Item *itemPtr, int argc, char **argv, int flags));static int ConfigureArrows _ANSI_ARGS_((Tk_Canvas *canvasPtr, LineItem *linePtr));static int CreateLine _ANSI_ARGS_((Tk_Canvas *canvasPtr, struct Tk_Item *itemPtr, int argc, char **argv));static void DeleteLine _ANSI_ARGS_((Tk_Canvas *canvasPtr, Tk_Item *itemPtr));static void DisplayLine _ANSI_ARGS_((Tk_Canvas *canvasPtr, Tk_Item *itemPtr, Drawable dst));static int LineCoords _ANSI_ARGS_((Tk_Canvas *canvasPtr, Tk_Item *itemPtr, int argc, char **argv));static int LineToArea _ANSI_ARGS_((Tk_Canvas *canvasPtr, Tk_Item *itemPtr, double *rectPtr));static double LineToPoint _ANSI_ARGS_((Tk_Canvas *canvasPtr, Tk_Item *itemPtr, double *coordPtr));static int LineToPostscript _ANSI_ARGS_((Tk_Canvas *canvasPtr, Tk_Item *itemPtr, Tk_PostscriptInfo *psInfoPtr));static int ParseArrowShape _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *value, char *recordPtr, int offset));static char * PrintArrowShape _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *recordPtr, int offset, Tcl_FreeProc **freeProcPtr));static void ScaleLine _ANSI_ARGS_((Tk_Canvas *canvasPtr, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY));static void TranslateLine _ANSI_ARGS_((Tk_Canvas *canvasPtr, Tk_Item *itemPtr, double deltaX, double deltaY));/* * Information used for parsing configuration specs. If you change any * of the default strings, be sure to change the corresponding default * values in CreateLine. */static Tk_CustomOption arrowShapeOption = {ParseArrowShape, PrintArrowShape, (ClientData) NULL};static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_UID, "-arrow", (char *) NULL, (char *) NULL, "none", Tk_Offset(LineItem, arrow), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-arrowshape", (char *) NULL, (char *) NULL, "8 10 3", Tk_Offset(LineItem, arrowShapeA), TK_CONFIG_DONT_SET_DEFAULT, &arrowShapeOption}, {TK_CONFIG_CAP_STYLE, "-capstyle", (char *) NULL, (char *) NULL, "butt", Tk_Offset(LineItem, capStyle), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, "black", Tk_Offset(LineItem, fg), TK_CONFIG_NULL_OK}, {TK_CONFIG_JOIN_STYLE, "-joinstyle", (char *) NULL, (char *) NULL, "round", Tk_Offset(LineItem, joinStyle), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BOOLEAN, "-smooth", (char *) NULL, (char *) NULL, "0", Tk_Offset(LineItem, smooth), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL, "12", Tk_Offset(LineItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(LineItem, fillStipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tkCanvasTagsOption}, {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, "1", Tk_Offset(LineItem, width), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0}};/* * The structures below defines the line item type by means * of procedures that can be invoked by generic item code. */Tk_ItemType TkLineType = { "line", /* name */ sizeof(LineItem), /* itemSize */ CreateLine, /* createProc */ configSpecs, /* configSpecs */ ConfigureLine, /* configureProc */ LineCoords, /* coordProc */ DeleteLine, /* deleteProc */ DisplayLine, /* displayProc */ 0, /* alwaysRedraw */ LineToPoint, /* pointProc */ LineToArea, /* areaProc */ LineToPostscript, /* postscriptProc */ ScaleLine, /* scaleProc */ TranslateLine, /* translateProc */ (Tk_ItemIndexProc *) NULL, /* indexProc */ (Tk_ItemCursorProc *) NULL, /* icursorProc */ (Tk_ItemSelectionProc *) NULL, /* selectionProc */ (Tk_ItemInsertProc *) NULL, /* insertProc */ (Tk_ItemDCharsProc *) NULL, /* dTextProc */ (Tk_ItemType *) NULL /* nextPtr */};/* * The Tk_Uid's below refer to uids for the various arrow types: */static Tk_Uid noneUid = NULL;static Tk_Uid firstUid = NULL;static Tk_Uid lastUid = NULL;static Tk_Uid bothUid = NULL;/* * The definition below determines how large are static arrays * used to hold spline points (splines larger than this have to * have their arrays malloc-ed). */#define MAX_STATIC_POINTS 200/* *-------------------------------------------------------------- * * CreateLine -- * * This procedure is invoked to create a new line item in * a canvas. * * Results: * A standard Tcl return value. If an error occurred in * creating the item, then an error message is left in * canvasPtr->interp->result; in this case itemPtr is * left uninitialized, so it can be safely freed by the * caller. * * Side effects: * A new line item is created. * *-------------------------------------------------------------- */static intCreateLine(canvasPtr, itemPtr, argc, argv) register Tk_Canvas *canvasPtr; /* Canvas to hold new item. */ Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ char **argv; /* Arguments describing line. */{ register LineItem *linePtr = (LineItem *) itemPtr; int i; if (argc < 4) { Tcl_AppendResult(canvasPtr->interp, "wrong # args: should be \"", Tk_PathName(canvasPtr->tkwin), "\" create ", itemPtr->typePtr->name, " x1 y1 x2 y2 ?x3 y3 ...? ?options?", (char *) NULL); return TCL_ERROR; } /* * Carry out initialization that is needed to set defaults and to * allow proper cleanup after errors during the the remainder of * this procedure. */ linePtr->canvasPtr = canvasPtr; linePtr->numPoints = 0; linePtr->coordPtr = NULL; linePtr->width = 1; linePtr->fg = None; linePtr->fillStipple = None; linePtr->capStyle = CapButt; linePtr->joinStyle = JoinRound; linePtr->gc = None; if (noneUid == NULL) { noneUid = Tk_GetUid("none"); firstUid = Tk_GetUid("first"); lastUid = Tk_GetUid("last"); bothUid = Tk_GetUid("both"); } linePtr->arrow = noneUid; linePtr->arrowShapeA = 8.0; linePtr->arrowShapeB = 10.0; linePtr->arrowShapeC = 3.0; linePtr->firstArrowPtr = NULL; linePtr->lastArrowPtr = NULL; linePtr->smooth = 0; linePtr->splineSteps = 12; /* * Count the number of points and then parse them into a point * array. Leading arguments are assumed to be points if they * start with a digit or a minus sign followed by a digit. */ for (i = 4; i < (argc-1); i+=2) { if ((!isdigit(UCHAR(argv[i][0]))) && ((argv[i][0] != '-') || (!isdigit(UCHAR(argv[i][1]))))) { break; } } if (LineCoords(canvasPtr, itemPtr, i, argv) != TCL_OK) { goto error; } if (ConfigureLine(canvasPtr, itemPtr, argc-i, argv+i, 0) == TCL_OK) { return TCL_OK; } error: DeleteLine(canvasPtr, itemPtr); return TCL_ERROR;}/* *-------------------------------------------------------------- * * LineCoords -- * * This procedure is invoked to process the "coords" widget * command on lines. See the user documentation for details * on what it does. * * Results: * Returns TCL_OK or TCL_ERROR, and sets canvasPtr->interp->result. * * Side effects: * The coordinates for the given item may be changed. * *-------------------------------------------------------------- */static intLineCoords(canvasPtr, itemPtr, argc, argv) register Tk_Canvas *canvasPtr; /* Canvas containing item. */ Tk_Item *itemPtr; /* Item whose coordinates are to be * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ char **argv; /* Array of coordinates: x1, y1, * x2, y2, ... */{ register LineItem *linePtr = (LineItem *) itemPtr; char buffer[TCL_DOUBLE_SPACE]; int i, numPoints; if (argc == 0) { double *coordPtr; int numCoords; numCoords = 2*linePtr->numPoints; if (linePtr->firstArrowPtr != NULL) { coordPtr = linePtr->firstArrowPtr; } else { coordPtr = linePtr->coordPtr; } for (i = 0; i < numCoords; i++, coordPtr++) { if (i == 2) { coordPtr = linePtr->coordPtr+2; } if ((linePtr->lastArrowPtr != NULL) && (i == (numCoords-2))) { coordPtr = linePtr->lastArrowPtr; } Tcl_PrintDouble(canvasPtr->interp, *coordPtr, buffer); Tcl_AppendElement(canvasPtr->interp, buffer); } } else if (argc < 4) { Tcl_AppendResult(canvasPtr->interp, "too few coordinates for line: must have at least 4", (char *) NULL); return TCL_ERROR; } else if (argc & 1) { Tcl_AppendResult(canvasPtr->interp, "odd number of coordinates specified for line", (char *) NULL); return TCL_ERROR; } else { numPoints = argc/2; if (linePtr->numPoints != numPoints) { if (linePtr->coordPtr != NULL) { ckfree((char *) linePtr->coordPtr); } linePtr->coordPtr = (double *) ckalloc((unsigned) (sizeof(double) * argc)); linePtr->numPoints = numPoints; } for (i = argc-1; i >= 0; i--) { if (TkGetCanvasCoord(canvasPtr, argv[i], &linePtr->coordPtr[i]) != TCL_OK) { return TCL_ERROR; } } /* * Update arrowheads by throwing away any existing arrow-head * information and calling ConfigureArrows to recompute it. */ if (linePtr->firstArrowPtr != NULL) { ckfree((char *) linePtr->firstArrowPtr); linePtr->firstArrowPtr = NULL; } if (linePtr->lastArrowPtr != NULL) { ckfree((char *) linePtr->lastArrowPtr); linePtr->lastArrowPtr = NULL; } if (linePtr->arrow != noneUid) { ConfigureArrows(canvasPtr, linePtr); } ComputeLineBbox(canvasPtr, linePtr); } return TCL_OK;}/* *-------------------------------------------------------------- * * ConfigureLine -- * * This procedure is invoked to configure various aspects * of a line item such as its background color. * * Results: * A standard Tcl result code. If an error occurs, then * an error message is left in canvasPtr->interp->result. * * Side effects: * Configuration information, such as colors and stipple * patterns, may be set for itemPtr. * *-------------------------------------------------------------- */static intConfigureLine(canvasPtr, itemPtr, argc, argv, flags) Tk_Canvas *canvasPtr; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Line item to reconfigure. */ int argc; /* Number of elements in argv. */ char **argv; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */{ register LineItem *linePtr = (LineItem *) itemPtr; XGCValues gcValues; GC newGC; unsigned long mask; if (Tk_ConfigureWidget(canvasPtr->interp, canvasPtr->tkwin, configSpecs, argc, argv, (char *) linePtr, flags) != TCL_OK) { return TCL_ERROR; } /* * A few of the options require additional processing, such as * graphics contexts. */ if (linePtr->fg == NULL) { newGC = None; } else { gcValues.foreground = linePtr->fg->pixel; gcValues.join_style = linePtr->joinStyle; if (linePtr->width < 0) { linePtr->width = 1; } gcValues.line_width = linePtr->width; mask = GCForeground|GCJoinStyle|GCLineWidth; if (linePtr->fillStipple != None) { gcValues.stipple = linePtr->fillStipple; gcValues.fill_style = FillStippled; mask |= GCStipple|GCFillStyle; } if (linePtr->arrow == noneUid) { gcValues.cap_style = linePtr->capStyle; mask |= GCCapStyle; } newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues); } if (linePtr->gc != None) { Tk_FreeGC(canvasPtr->display, linePtr->gc); } linePtr->gc = newGC; /* * Keep spline parameters within reasonable limits. */ if (linePtr->splineSteps < 1) { linePtr->splineSteps = 1; } else if (linePtr->splineSteps > 100) { linePtr->splineSteps = 100; } /* * Setup arrowheads, if needed. If arrowheads are turned off, * restore the line's endpoints (they were shortened when the * arrowheads were added). */ if ((linePtr->firstArrowPtr != NULL) && (linePtr->arrow != firstUid) && (linePtr->arrow != bothUid)) { linePtr->coordPtr[0] = linePtr->firstArrowPtr[0];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -