tkCanvLine.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:73k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkCanvLine.c --
  3.  *
  4.  * This file implements line items for canvas widgets.
  5.  *
  6.  * Copyright (c) 1991-1994 The Regents of the University of California.
  7.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  8.  * Copyright (c) 1998-1999 by Scriptics Corporation.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * RCS: @(#) $Id: tkCanvLine.c,v 1.13.2.2 2006/10/16 15:35:50 das Exp $
  14.  */
  15. #include <stdio.h>
  16. #include "tkInt.h"
  17. #include "tkPort.h"
  18. #include "tkCanvas.h"
  19. /*
  20.  * The structure below defines the record for each line item.
  21.  */
  22. typedef enum {
  23.     ARROWS_NONE, ARROWS_FIRST, ARROWS_LAST, ARROWS_BOTH
  24. } Arrows;
  25. typedef struct LineItem  {
  26.     Tk_Item header; /* Generic stuff that's the same for all
  27.  * types.  MUST BE FIRST IN STRUCTURE. */
  28.     Tk_Outline outline; /* Outline structure */
  29.     Tk_Canvas canvas; /* Canvas containing item.  Needed for
  30.  * parsing arrow shapes. */
  31.     int numPoints; /* Number of points in line (always >= 0). */
  32.     double *coordPtr; /* Pointer to malloc-ed array containing
  33.  * x- and y-coords of all points in line.
  34.  * X-coords are even-valued indices, y-coords
  35.  * are corresponding odd-valued indices. If
  36.  * the line has arrowheads then the first
  37.  * and last points have been adjusted to refer
  38.  * to the necks of the arrowheads rather than
  39.  * their tips.  The actual endpoints are
  40.  * stored in the *firstArrowPtr and
  41.  * *lastArrowPtr, if they exist. */
  42.     int capStyle; /* Cap style for line. */
  43.     int joinStyle; /* Join style for line. */
  44.     GC arrowGC; /* Graphics context for drawing arrowheads. */
  45.     Arrows arrow; /* Indicates whether or not to draw arrowheads:
  46.  * "none", "first", "last", or "both". */
  47.     float arrowShapeA; /* Distance from tip of arrowhead to center. */
  48.     float arrowShapeB; /* Distance from tip of arrowhead to trailing
  49.  * point, measured along shaft. */
  50.     float arrowShapeC; /* Distance of trailing points from outside
  51.  * edge of shaft. */
  52.     double *firstArrowPtr; /* Points to array of PTS_IN_ARROW points
  53.  * describing polygon for arrowhead at first
  54.  * point in line.  First point of arrowhead
  55.  * is tip.  Malloc'ed.  NULL means no arrowhead
  56.  * at first point. */
  57.     double *lastArrowPtr; /* Points to polygon for arrowhead at last
  58.  * point in line (PTS_IN_ARROW points, first
  59.  * of which is tip).  Malloc'ed.  NULL means
  60.  * no arrowhead at last point. */
  61.     Tk_SmoothMethod *smooth; /* Non-zero means draw line smoothed (i.e.
  62.  * with Bezier splines). */
  63.     int splineSteps; /* Number of steps in each spline segment. */
  64. } LineItem;
  65. /*
  66.  * Number of points in an arrowHead:
  67.  */
  68. #define PTS_IN_ARROW 6
  69. /*
  70.  * Prototypes for procedures defined in this file:
  71.  */
  72. static int ArrowheadPostscript _ANSI_ARGS_((Tcl_Interp *interp,
  73.     Tk_Canvas canvas, LineItem *linePtr,
  74.     double *arrowPtr));
  75. static void ComputeLineBbox _ANSI_ARGS_((Tk_Canvas canvas,
  76.     LineItem *linePtr));
  77. static int ConfigureLine _ANSI_ARGS_((Tcl_Interp *interp,
  78.     Tk_Canvas canvas, Tk_Item *itemPtr, int objc,
  79.     Tcl_Obj *CONST objv[], int flags));
  80. static int ConfigureArrows _ANSI_ARGS_((Tk_Canvas canvas,
  81.     LineItem *linePtr));
  82. static int CreateLine _ANSI_ARGS_((Tcl_Interp *interp,
  83.     Tk_Canvas canvas, struct Tk_Item *itemPtr,
  84.     int objc, Tcl_Obj *CONST objv[]));
  85. static void DeleteLine _ANSI_ARGS_((Tk_Canvas canvas,
  86.     Tk_Item *itemPtr, Display *display));
  87. static void DisplayLine _ANSI_ARGS_((Tk_Canvas canvas,
  88.     Tk_Item *itemPtr, Display *display, Drawable dst,
  89.     int x, int y, int width, int height));
  90. static int GetLineIndex _ANSI_ARGS_((Tcl_Interp *interp,
  91.     Tk_Canvas canvas, Tk_Item *itemPtr,
  92.     Tcl_Obj *obj, int *indexPtr));
  93. static int LineCoords _ANSI_ARGS_((Tcl_Interp *interp,
  94.     Tk_Canvas canvas, Tk_Item *itemPtr,
  95.     int objc, Tcl_Obj *CONST objv[]));
  96. static void LineDeleteCoords _ANSI_ARGS_((Tk_Canvas canvas,
  97.     Tk_Item *itemPtr, int first, int last));
  98. static void LineInsert _ANSI_ARGS_((Tk_Canvas canvas,
  99.     Tk_Item *itemPtr, int beforeThis, Tcl_Obj *obj));
  100. static int LineToArea _ANSI_ARGS_((Tk_Canvas canvas,
  101.     Tk_Item *itemPtr, double *rectPtr));
  102. static double LineToPoint _ANSI_ARGS_((Tk_Canvas canvas,
  103.     Tk_Item *itemPtr, double *coordPtr));
  104. static int LineToPostscript _ANSI_ARGS_((Tcl_Interp *interp,
  105.     Tk_Canvas canvas, Tk_Item *itemPtr, int prepass));
  106. static int ArrowParseProc _ANSI_ARGS_((ClientData clientData,
  107.     Tcl_Interp *interp, Tk_Window tkwin,
  108.     CONST char *value, char *recordPtr, int offset));
  109. static char * ArrowPrintProc _ANSI_ARGS_((ClientData clientData,
  110.     Tk_Window tkwin, char *recordPtr, int offset,
  111.     Tcl_FreeProc **freeProcPtr));
  112. static int ParseArrowShape _ANSI_ARGS_((ClientData clientData,
  113.     Tcl_Interp *interp, Tk_Window tkwin,
  114.     CONST char *value, char *recordPtr, int offset));
  115. static char * PrintArrowShape _ANSI_ARGS_((ClientData clientData,
  116.     Tk_Window tkwin, char *recordPtr, int offset,
  117.     Tcl_FreeProc **freeProcPtr));
  118. static void ScaleLine _ANSI_ARGS_((Tk_Canvas canvas,
  119.     Tk_Item *itemPtr, double originX, double originY,
  120.     double scaleX, double scaleY));
  121. static void TranslateLine _ANSI_ARGS_((Tk_Canvas canvas,
  122.     Tk_Item *itemPtr, double deltaX, double deltaY));
  123. /*
  124.  * Information used for parsing configuration specs.  If you change any
  125.  * of the default strings, be sure to change the corresponding default
  126.  * values in CreateLine.
  127.  */
  128. static Tk_CustomOption arrowShapeOption = {
  129.     (Tk_OptionParseProc *) ParseArrowShape,
  130.     PrintArrowShape, (ClientData) NULL
  131. };
  132. static Tk_CustomOption arrowOption = {
  133.     (Tk_OptionParseProc *) ArrowParseProc,
  134.     ArrowPrintProc, (ClientData) NULL
  135. };
  136. static Tk_CustomOption smoothOption = {
  137.     (Tk_OptionParseProc *) TkSmoothParseProc,
  138.     TkSmoothPrintProc, (ClientData) NULL
  139. };
  140. static Tk_CustomOption stateOption = {
  141.     (Tk_OptionParseProc *) TkStateParseProc,
  142.     TkStatePrintProc, (ClientData) 2
  143. };
  144. static Tk_CustomOption tagsOption = {
  145.     (Tk_OptionParseProc *) Tk_CanvasTagsParseProc,
  146.     Tk_CanvasTagsPrintProc, (ClientData) NULL
  147. };
  148. static Tk_CustomOption dashOption = {
  149.     (Tk_OptionParseProc *) TkCanvasDashParseProc,
  150.     TkCanvasDashPrintProc, (ClientData) NULL
  151. };
  152. static Tk_CustomOption offsetOption = {
  153.     (Tk_OptionParseProc *) TkOffsetParseProc,
  154.     TkOffsetPrintProc,
  155.     (ClientData) (TK_OFFSET_RELATIVE|TK_OFFSET_INDEX)
  156. };
  157. static Tk_CustomOption pixelOption = {
  158.     (Tk_OptionParseProc *) TkPixelParseProc,
  159.     TkPixelPrintProc, (ClientData) NULL
  160. };
  161. static Tk_ConfigSpec configSpecs[] = {
  162.     {TK_CONFIG_CUSTOM, "-activedash", (char *) NULL, (char *) NULL,
  163. (char *) NULL, Tk_Offset(LineItem, outline.activeDash),
  164. TK_CONFIG_NULL_OK, &dashOption},
  165.     {TK_CONFIG_COLOR, "-activefill", (char *) NULL, (char *) NULL,
  166. (char *) NULL, Tk_Offset(LineItem, outline.activeColor),
  167. TK_CONFIG_NULL_OK},
  168.     {TK_CONFIG_BITMAP, "-activestipple", (char *) NULL, (char *) NULL,
  169. (char *) NULL, Tk_Offset(LineItem, outline.activeStipple),
  170. TK_CONFIG_NULL_OK},
  171.     {TK_CONFIG_CUSTOM, "-activewidth", (char *) NULL, (char *) NULL,
  172. "0.0", Tk_Offset(LineItem, outline.activeWidth),
  173. TK_CONFIG_DONT_SET_DEFAULT, &pixelOption},
  174.     {TK_CONFIG_CUSTOM, "-arrow", (char *) NULL, (char *) NULL,
  175. "none", Tk_Offset(LineItem, arrow), TK_CONFIG_DONT_SET_DEFAULT, &arrowOption},
  176.     {TK_CONFIG_CUSTOM, "-arrowshape", (char *) NULL, (char *) NULL,
  177. "8 10 3", Tk_Offset(LineItem, arrowShapeA),
  178. TK_CONFIG_DONT_SET_DEFAULT, &arrowShapeOption},
  179.     {TK_CONFIG_CAP_STYLE, "-capstyle", (char *) NULL, (char *) NULL,
  180. "butt", Tk_Offset(LineItem, capStyle), TK_CONFIG_DONT_SET_DEFAULT},
  181.     {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,
  182. "black", Tk_Offset(LineItem, outline.color), TK_CONFIG_NULL_OK},
  183.     {TK_CONFIG_CUSTOM, "-dash", (char *) NULL, (char *) NULL,
  184. (char *) NULL, Tk_Offset(LineItem, outline.dash),
  185. TK_CONFIG_NULL_OK, &dashOption},
  186.     {TK_CONFIG_PIXELS, "-dashoffset", (char *) NULL, (char *) NULL,
  187. "0", Tk_Offset(LineItem, outline.offset),
  188. TK_CONFIG_DONT_SET_DEFAULT},
  189.     {TK_CONFIG_CUSTOM, "-disableddash", (char *) NULL, (char *) NULL,
  190. (char *) NULL, Tk_Offset(LineItem, outline.disabledDash),
  191. TK_CONFIG_NULL_OK, &dashOption},
  192.     {TK_CONFIG_COLOR, "-disabledfill", (char *) NULL, (char *) NULL,
  193. (char *) NULL, Tk_Offset(LineItem, outline.disabledColor),
  194. TK_CONFIG_NULL_OK},
  195.     {TK_CONFIG_BITMAP, "-disabledstipple", (char *) NULL, (char *) NULL,
  196. (char *) NULL, Tk_Offset(LineItem, outline.disabledStipple),
  197. TK_CONFIG_NULL_OK},
  198.     {TK_CONFIG_CUSTOM, "-disabledwidth", (char *) NULL, (char *) NULL,
  199. "0.0", Tk_Offset(LineItem, outline.disabledWidth),
  200. TK_CONFIG_DONT_SET_DEFAULT, &pixelOption},
  201.     {TK_CONFIG_JOIN_STYLE, "-joinstyle", (char *) NULL, (char *) NULL,
  202. "round", Tk_Offset(LineItem, joinStyle), TK_CONFIG_DONT_SET_DEFAULT},
  203.     {TK_CONFIG_CUSTOM, "-offset", (char *) NULL, (char *) NULL,
  204. "0,0", Tk_Offset(LineItem, outline.tsoffset),
  205. TK_CONFIG_DONT_SET_DEFAULT, &offsetOption},
  206.     {TK_CONFIG_CUSTOM, "-smooth", (char *) NULL, (char *) NULL,
  207. "0", Tk_Offset(LineItem, smooth),
  208. TK_CONFIG_DONT_SET_DEFAULT, &smoothOption},
  209.     {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL,
  210. "12", Tk_Offset(LineItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT},
  211.     {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL,
  212. (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK,
  213. &stateOption},
  214.     {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,
  215. (char *) NULL, Tk_Offset(LineItem, outline.stipple),
  216. TK_CONFIG_NULL_OK},
  217.     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
  218. (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption},
  219.     {TK_CONFIG_CUSTOM, "-width", (char *) NULL, (char *) NULL,
  220. "1.0", Tk_Offset(LineItem, outline.width),
  221. TK_CONFIG_DONT_SET_DEFAULT, &pixelOption},
  222.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  223. (char *) NULL, 0, 0}
  224. };
  225. /*
  226.  * The structures below defines the line item type by means
  227.  * of procedures that can be invoked by generic item code.
  228.  */
  229. Tk_ItemType tkLineType = {
  230.     "line", /* name */
  231.     sizeof(LineItem), /* itemSize */
  232.     CreateLine, /* createProc */
  233.     configSpecs, /* configSpecs */
  234.     ConfigureLine, /* configureProc */
  235.     LineCoords, /* coordProc */
  236.     DeleteLine, /* deleteProc */
  237.     DisplayLine, /* displayProc */
  238.     TK_CONFIG_OBJS, /* flags */
  239.     LineToPoint, /* pointProc */
  240.     LineToArea, /* areaProc */
  241.     LineToPostscript, /* postscriptProc */
  242.     ScaleLine, /* scaleProc */
  243.     TranslateLine, /* translateProc */
  244.     (Tk_ItemIndexProc *) GetLineIndex, /* indexProc */
  245.     (Tk_ItemCursorProc *) NULL, /* icursorProc */
  246.     (Tk_ItemSelectionProc *) NULL, /* selectionProc */
  247.     (Tk_ItemInsertProc *) LineInsert, /* insertProc */
  248.     LineDeleteCoords, /* dTextProc */
  249.     (Tk_ItemType *) NULL, /* nextPtr */
  250. };
  251. /*
  252.  * The definition below determines how large are static arrays
  253.  * used to hold spline points (splines larger than this have to
  254.  * have their arrays malloc-ed).
  255.  */
  256. #define MAX_STATIC_POINTS 200
  257. /*
  258.  *--------------------------------------------------------------
  259.  *
  260.  * CreateLine --
  261.  *
  262.  * This procedure is invoked to create a new line item in
  263.  * a canvas.
  264.  *
  265.  * Results:
  266.  * A standard Tcl return value.  If an error occurred in
  267.  * creating the item, then an error message is left in
  268.  * the interp's result;  in this case itemPtr is left uninitialized,
  269.  * so it can be safely freed by the caller.
  270.  *
  271.  * Side effects:
  272.  * A new line item is created.
  273.  *
  274.  *--------------------------------------------------------------
  275.  */
  276. static int
  277. CreateLine(interp, canvas, itemPtr, objc, objv)
  278.     Tcl_Interp *interp; /* Interpreter for error reporting. */
  279.     Tk_Canvas canvas; /* Canvas to hold new item. */
  280.     Tk_Item *itemPtr; /* Record to hold new item;  header
  281.  * has been initialized by caller. */
  282.     int objc; /* Number of arguments in objv. */
  283.     Tcl_Obj *CONST objv[]; /* Arguments describing line. */
  284. {
  285.     LineItem *linePtr = (LineItem *) itemPtr;
  286.     int i;
  287.     if (objc == 0) {
  288. panic("canvas did not pass any coordsn");
  289.     }
  290.     /*
  291.      * Carry out initialization that is needed to set defaults and to
  292.      * allow proper cleanup after errors during the the remainder of
  293.      * this procedure.
  294.      */
  295.     Tk_CreateOutline(&(linePtr->outline));
  296.     linePtr->canvas = canvas;
  297.     linePtr->numPoints = 0;
  298.     linePtr->coordPtr = NULL;
  299.     linePtr->capStyle = CapButt;
  300.     linePtr->joinStyle = JoinRound;
  301.     linePtr->arrowGC = None;
  302.     linePtr->arrow = ARROWS_NONE;
  303.     linePtr->arrowShapeA = (float)8.0;
  304.     linePtr->arrowShapeB = (float)10.0;
  305.     linePtr->arrowShapeC = (float)3.0;
  306.     linePtr->firstArrowPtr = NULL;
  307.     linePtr->lastArrowPtr = NULL;
  308.     linePtr->smooth = (Tk_SmoothMethod *) NULL;
  309.     linePtr->splineSteps = 12;
  310.     /*
  311.      * Count the number of points and then parse them into a point
  312.      * array.  Leading arguments are assumed to be points if they
  313.      * start with a digit or a minus sign followed by a digit.
  314.      */
  315.     for (i = 1; i < objc; i++) {
  316. char *arg = Tcl_GetString(objv[i]);
  317. if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) {
  318.     break;
  319. }
  320.     }
  321.     if (LineCoords(interp, canvas, itemPtr, i, objv) != TCL_OK) {
  322. goto error;
  323.     }
  324.     if (ConfigureLine(interp, canvas, itemPtr, objc-i, objv+i, 0) == TCL_OK) {
  325. return TCL_OK;
  326.     }
  327.     error:
  328.     DeleteLine(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));
  329.     return TCL_ERROR;
  330. }
  331. /*
  332.  *--------------------------------------------------------------
  333.  *
  334.  * LineCoords --
  335.  *
  336.  * This procedure is invoked to process the "coords" widget
  337.  * command on lines.  See the user documentation for details
  338.  * on what it does.
  339.  *
  340.  * Results:
  341.  * Returns TCL_OK or TCL_ERROR, and sets the interp's result.
  342.  *
  343.  * Side effects:
  344.  * The coordinates for the given item may be changed.
  345.  *
  346.  *--------------------------------------------------------------
  347.  */
  348. static int
  349. LineCoords(interp, canvas, itemPtr, objc, objv)
  350.     Tcl_Interp *interp; /* Used for error reporting. */
  351.     Tk_Canvas canvas; /* Canvas containing item. */
  352.     Tk_Item *itemPtr; /* Item whose coordinates are to be
  353.  * read or modified. */
  354.     int objc; /* Number of coordinates supplied in
  355.  * objv. */
  356.     Tcl_Obj *CONST objv[]; /* Array of coordinates: x1, y1,
  357.  * x2, y2, ... */
  358. {
  359.     LineItem *linePtr = (LineItem *) itemPtr;
  360.     int i, numPoints;
  361.     double *coordPtr;
  362.     if (objc == 0) {
  363. int numCoords;
  364. Tcl_Obj *subobj, *obj = Tcl_NewObj();
  365. numCoords = 2*linePtr->numPoints;
  366. if (linePtr->firstArrowPtr != NULL) {
  367.     coordPtr = linePtr->firstArrowPtr;
  368. } else {
  369.     coordPtr = linePtr->coordPtr;
  370. }
  371. for (i = 0; i < numCoords; i++, coordPtr++) {
  372.     if (i == 2) {
  373. coordPtr = linePtr->coordPtr+2;
  374.     }
  375.     if ((linePtr->lastArrowPtr != NULL) && (i == (numCoords-2))) {
  376. coordPtr = linePtr->lastArrowPtr;
  377.     }
  378.     subobj = Tcl_NewDoubleObj(*coordPtr);
  379.     Tcl_ListObjAppendElement(interp, obj, subobj);
  380. }
  381. Tcl_SetObjResult(interp, obj);
  382. return TCL_OK;
  383.     }
  384.     if (objc == 1) {
  385. if (Tcl_ListObjGetElements(interp, objv[0], &objc,
  386. (Tcl_Obj ***) &objv) != TCL_OK) {
  387.     return TCL_ERROR;
  388. }
  389.     }
  390.     if (objc & 1) {
  391. char buf[64 + TCL_INTEGER_SPACE];
  392. sprintf(buf, "wrong # coordinates: expected an even number, got %d",
  393. objc);
  394. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  395. return TCL_ERROR;
  396.     } else if (objc < 4) {
  397. char buf[64 + TCL_INTEGER_SPACE];
  398. sprintf(buf, "wrong # coordinates: expected at least 4, got %d", objc);
  399. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  400. return TCL_ERROR;
  401.     } else {
  402. numPoints = objc/2;
  403. if (linePtr->numPoints != numPoints) {
  404.     coordPtr = (double *) ckalloc((unsigned)
  405.     (sizeof(double) * objc));
  406.     if (linePtr->coordPtr != NULL) {
  407. ckfree((char *) linePtr->coordPtr);
  408.     }
  409.     linePtr->coordPtr = coordPtr;
  410.     linePtr->numPoints = numPoints;
  411. }
  412. coordPtr = linePtr->coordPtr;
  413. for (i = 0; i <objc; i++) {
  414.     if (Tk_CanvasGetCoordFromObj(interp, canvas, objv[i],
  415.     coordPtr++) != TCL_OK) {
  416.    return TCL_ERROR;
  417.        }
  418.    }
  419. /*
  420.  * Update arrowheads by throwing away any existing arrow-head
  421.  * information and calling ConfigureArrows to recompute it.
  422.  */
  423. if (linePtr->firstArrowPtr != NULL) {
  424.     ckfree((char *) linePtr->firstArrowPtr);
  425.     linePtr->firstArrowPtr = NULL;
  426. }
  427. if (linePtr->lastArrowPtr != NULL) {
  428.     ckfree((char *) linePtr->lastArrowPtr);
  429.     linePtr->lastArrowPtr = NULL;
  430. }
  431. if (linePtr->arrow != ARROWS_NONE) {
  432.     ConfigureArrows(canvas, linePtr);
  433. }
  434. ComputeLineBbox(canvas, linePtr);
  435.     }
  436.     return TCL_OK;
  437. }
  438. /*
  439.  *--------------------------------------------------------------
  440.  *
  441.  * ConfigureLine --
  442.  *
  443.  * This procedure is invoked to configure various aspects
  444.  * of a line item such as its background color.
  445.  *
  446.  * Results:
  447.  * A standard Tcl result code.  If an error occurs, then
  448.  * an error message is left in the interp's result.
  449.  *
  450.  * Side effects:
  451.  * Configuration information, such as colors and stipple
  452.  * patterns, may be set for itemPtr.
  453.  *
  454.  *--------------------------------------------------------------
  455.  */
  456. static int
  457. ConfigureLine(interp, canvas, itemPtr, objc, objv, flags)
  458.     Tcl_Interp *interp; /* Used for error reporting. */
  459.     Tk_Canvas canvas; /* Canvas containing itemPtr. */
  460.     Tk_Item *itemPtr; /* Line item to reconfigure. */
  461.     int objc; /* Number of elements in objv.  */
  462.     Tcl_Obj *CONST objv[]; /* Arguments describing things to configure. */
  463.     int flags; /* Flags to pass to Tk_ConfigureWidget. */
  464. {
  465.     LineItem *linePtr = (LineItem *) itemPtr;
  466.     XGCValues gcValues;
  467.     GC newGC, arrowGC;
  468.     unsigned long mask;
  469.     Tk_Window tkwin;
  470.     Tk_State state;
  471.     tkwin = Tk_CanvasTkwin(canvas);
  472.     if (TCL_OK != Tk_ConfigureWidget(interp, tkwin, configSpecs, objc,
  473.     (CONST char **) objv, (char *) linePtr, flags|TK_CONFIG_OBJS)) {
  474. return TCL_ERROR;
  475.     }
  476.     /*
  477.      * A few of the options require additional processing, such as
  478.      * graphics contexts.
  479.      */
  480.     state = itemPtr->state;
  481.     if(state == TK_STATE_NULL) {
  482. state = ((TkCanvas *)canvas)->canvas_state;
  483.     }
  484.     if (linePtr->outline.activeWidth > linePtr->outline.width ||
  485.     linePtr->outline.activeDash.number != 0 ||
  486.     linePtr->outline.activeColor != NULL ||
  487.     linePtr->outline.activeStipple != None) {
  488. itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT;
  489.     } else {
  490. itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT;
  491.     }
  492.     mask = Tk_ConfigOutlineGC(&gcValues, canvas, itemPtr,
  493.     &(linePtr->outline));
  494.     if (mask) {
  495. if (linePtr->arrow == ARROWS_NONE) {
  496.     gcValues.cap_style = linePtr->capStyle;
  497.     mask |= GCCapStyle;
  498. }
  499. gcValues.join_style = linePtr->joinStyle;
  500. mask |= GCJoinStyle;
  501. newGC = Tk_GetGC(tkwin, mask, &gcValues);
  502. #ifdef MAC_OSX_TK
  503. /*
  504.  * Mac OS X CG drawing needs access to linewidth even for 
  505.  * arrow fills (as linewidth controls antialiasing).
  506.  */
  507. mask |= GCLineWidth;
  508. #else
  509. gcValues.line_width = 0;
  510. #endif
  511. arrowGC = Tk_GetGC(tkwin, mask, &gcValues);
  512.     } else {
  513. newGC = arrowGC = None;
  514.     }
  515.     if (linePtr->outline.gc != None) {
  516. Tk_FreeGC(Tk_Display(tkwin), linePtr->outline.gc);
  517.     }
  518.     if (linePtr->arrowGC != None) {
  519. Tk_FreeGC(Tk_Display(tkwin), linePtr->arrowGC);
  520.     }
  521.     linePtr->outline.gc = newGC;
  522.     linePtr->arrowGC = arrowGC;
  523.     /*
  524.      * Keep spline parameters within reasonable limits.
  525.      */
  526.     if (linePtr->splineSteps < 1) {
  527. linePtr->splineSteps = 1;
  528.     } else if (linePtr->splineSteps > 100) {
  529. linePtr->splineSteps = 100;
  530.     }
  531.     if ((!linePtr->numPoints) || (state==TK_STATE_HIDDEN)) {
  532. ComputeLineBbox(canvas, linePtr);
  533. return TCL_OK;
  534.     }
  535.     /*
  536.      * Setup arrowheads, if needed.  If arrowheads are turned off,
  537.      * restore the line's endpoints (they were shortened when the
  538.      * arrowheads were added).
  539.      */
  540.     if ((linePtr->firstArrowPtr != NULL) && (linePtr->arrow != ARROWS_FIRST)
  541.     && (linePtr->arrow != ARROWS_BOTH)) {
  542. linePtr->coordPtr[0] = linePtr->firstArrowPtr[0];
  543. linePtr->coordPtr[1] = linePtr->firstArrowPtr[1];
  544. ckfree((char *) linePtr->firstArrowPtr);
  545. linePtr->firstArrowPtr = NULL;
  546.     }
  547.     if ((linePtr->lastArrowPtr != NULL) && (linePtr->arrow != ARROWS_LAST)
  548.     && (linePtr->arrow != ARROWS_BOTH)) {
  549. int i;
  550. i = 2*(linePtr->numPoints-1);
  551. linePtr->coordPtr[i] = linePtr->lastArrowPtr[0];
  552. linePtr->coordPtr[i+1] = linePtr->lastArrowPtr[1];
  553. ckfree((char *) linePtr->lastArrowPtr);
  554. linePtr->lastArrowPtr = NULL;
  555.     }
  556.     if (linePtr->arrow != ARROWS_NONE) {
  557. ConfigureArrows(canvas, linePtr);
  558.     }
  559.     /*
  560.      * Recompute bounding box for line.
  561.      */
  562.     ComputeLineBbox(canvas, linePtr);
  563.     return TCL_OK;
  564. }
  565. /*
  566.  *--------------------------------------------------------------
  567.  *
  568.  * DeleteLine --
  569.  *
  570.  * This procedure is called to clean up the data structure
  571.  * associated with a line item.
  572.  *
  573.  * Results:
  574.  * None.
  575.  *
  576.  * Side effects:
  577.  * Resources associated with itemPtr are released.
  578.  *
  579.  *--------------------------------------------------------------
  580.  */
  581. static void
  582. DeleteLine(canvas, itemPtr, display)
  583.     Tk_Canvas canvas; /* Info about overall canvas widget. */
  584.     Tk_Item *itemPtr; /* Item that is being deleted. */
  585.     Display *display; /* Display containing window for
  586.  * canvas. */
  587. {
  588.     LineItem *linePtr = (LineItem *) itemPtr;
  589.     Tk_DeleteOutline(display, &(linePtr->outline));
  590.     if (linePtr->coordPtr != NULL) {
  591. ckfree((char *) linePtr->coordPtr);
  592.     }
  593.     if (linePtr->arrowGC != None) {
  594. Tk_FreeGC(display, linePtr->arrowGC);
  595.     }
  596.     if (linePtr->firstArrowPtr != NULL) {
  597. ckfree((char *) linePtr->firstArrowPtr);
  598.     }
  599.     if (linePtr->lastArrowPtr != NULL) {
  600. ckfree((char *) linePtr->lastArrowPtr);
  601.     }
  602. }
  603. /*
  604.  *--------------------------------------------------------------
  605.  *
  606.  * ComputeLineBbox --
  607.  *
  608.  * This procedure is invoked to compute the bounding box of
  609.  * all the pixels that may be drawn as part of a line.
  610.  *
  611.  * Results:
  612.  * None.
  613.  *
  614.  * Side effects:
  615.  * The fields x1, y1, x2, and y2 are updated in the header
  616.  * for itemPtr.
  617.  *
  618.  *--------------------------------------------------------------
  619.  */
  620. static void
  621. ComputeLineBbox(canvas, linePtr)
  622.     Tk_Canvas canvas; /* Canvas that contains item. */
  623.     LineItem *linePtr; /* Item whose bbos is to be
  624.  * recomputed. */
  625. {
  626.     double *coordPtr;
  627.     int i, intWidth;
  628.     double width;
  629.     Tk_State state = linePtr->header.state;
  630.     Tk_TSOffset *tsoffset;
  631.     if(state == TK_STATE_NULL) {
  632. state = ((TkCanvas *)canvas)->canvas_state;
  633.     }
  634.     if (!(linePtr->numPoints) || (state==TK_STATE_HIDDEN)) {
  635. linePtr->header.x1 = -1;
  636. linePtr->header.x2 = -1;
  637. linePtr->header.y1 = -1;
  638. linePtr->header.y2 = -1;
  639. return;
  640.     }
  641.     width = linePtr->outline.width;
  642.     if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)linePtr) {
  643. if (linePtr->outline.activeWidth>width) {
  644.     width = linePtr->outline.activeWidth;
  645. }
  646.     } else if (state==TK_STATE_DISABLED) {
  647. if (linePtr->outline.disabledWidth>0) {
  648.     width = linePtr->outline.disabledWidth;
  649. }
  650.     }
  651.     coordPtr = linePtr->coordPtr;
  652.     linePtr->header.x1 = linePtr->header.x2 = (int) *coordPtr;
  653.     linePtr->header.y1 = linePtr->header.y2 = (int) coordPtr[1];
  654.     /*
  655.      * Compute the bounding box of all the points in the line,
  656.      * then expand in all directions by the line's width to take
  657.      * care of butting or rounded corners and projecting or
  658.      * rounded caps.  This expansion is an overestimate (worst-case
  659.      * is square root of two over two) but it's simple.  Don't do
  660.      * anything special for curves.  This causes an additional
  661.      * overestimate in the bounding box, but is faster.
  662.      */
  663.     for (i = 1, coordPtr = linePtr->coordPtr+2; i < linePtr->numPoints;
  664.     i++, coordPtr += 2) {
  665. TkIncludePoint((Tk_Item *) linePtr, coordPtr);
  666.     }
  667.     width = linePtr->outline.width;
  668.     if (width < 1.0) {
  669. width = 1.0;
  670.     }
  671.     if (linePtr->arrow != ARROWS_NONE) {
  672. if (linePtr->arrow != ARROWS_LAST) {
  673.     TkIncludePoint((Tk_Item *) linePtr, linePtr->firstArrowPtr);
  674. }
  675. if (linePtr->arrow != ARROWS_FIRST) {
  676.     TkIncludePoint((Tk_Item *) linePtr, linePtr->lastArrowPtr);
  677. }
  678.     }
  679.     tsoffset = &linePtr->outline.tsoffset;
  680.     if (tsoffset->flags & TK_OFFSET_INDEX) {
  681. double *coordPtr = linePtr->coordPtr + (tsoffset->flags & ~TK_OFFSET_INDEX);
  682. if (tsoffset->flags <= 0) {
  683.     coordPtr = linePtr->coordPtr;
  684.     if ((linePtr->arrow == ARROWS_FIRST) || (linePtr->arrow == ARROWS_BOTH)) {
  685. coordPtr = linePtr->firstArrowPtr;
  686.     }
  687. }
  688. if (tsoffset->flags > (linePtr->numPoints * 2)) {
  689.     coordPtr = linePtr->coordPtr + (linePtr->numPoints * 2);
  690.     if ((linePtr->arrow == ARROWS_LAST) || (linePtr->arrow == ARROWS_BOTH)) {
  691. coordPtr = linePtr->lastArrowPtr;
  692.     }
  693. }
  694. tsoffset->xoffset = (int) (coordPtr[0] + 0.5);
  695. tsoffset->yoffset = (int) (coordPtr[1] + 0.5);
  696.     } else {
  697. if (tsoffset->flags & TK_OFFSET_LEFT) {
  698.     tsoffset->xoffset = linePtr->header.x1;
  699. } else if (tsoffset->flags & TK_OFFSET_CENTER) {
  700.     tsoffset->xoffset = (linePtr->header.x1 + linePtr->header.x2)/2;
  701. } else if (tsoffset->flags & TK_OFFSET_RIGHT) {
  702.     tsoffset->xoffset = linePtr->header.x2;
  703. }
  704. if (tsoffset->flags & TK_OFFSET_TOP) {
  705.     tsoffset->yoffset = linePtr->header.y1;
  706. } else if (tsoffset->flags & TK_OFFSET_MIDDLE) {
  707.     tsoffset->yoffset = (linePtr->header.y1 + linePtr->header.y2)/2;
  708. } else if (tsoffset->flags & TK_OFFSET_BOTTOM) {
  709.     tsoffset->yoffset = linePtr->header.y2;
  710. }
  711.     }
  712.     intWidth = (int) (width + 0.5);
  713.     linePtr->header.x1 -= intWidth;
  714.     linePtr->header.x2 += intWidth;
  715.     linePtr->header.y1 -= intWidth;
  716.     linePtr->header.y2 += intWidth;
  717.     if (linePtr->numPoints==1) {
  718. linePtr->header.x1 -= 1;
  719. linePtr->header.x2 += 1;
  720. linePtr->header.y1 -= 1;
  721. linePtr->header.y2 += 1;
  722. return;
  723.     }
  724.     /*
  725.      * For mitered lines, make a second pass through all the points.
  726.      * Compute the locations of the two miter vertex points and add
  727.      * those into the bounding box.
  728.      */
  729.     if (linePtr->joinStyle == JoinMiter) {
  730. for (i = linePtr->numPoints, coordPtr = linePtr->coordPtr; i >= 3;
  731. i--, coordPtr += 2) {
  732.     double miter[4];
  733.     int j;
  734.     
  735.     if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4,
  736.     width, miter, miter+2)) {
  737. for (j = 0; j < 4; j += 2) {
  738.     TkIncludePoint((Tk_Item *) linePtr, miter+j);
  739. }
  740.     }
  741. }
  742.     }
  743.     /*
  744.      * Add in the sizes of arrowheads, if any.
  745.      */
  746.     if (linePtr->arrow != ARROWS_NONE) {
  747. if (linePtr->arrow != ARROWS_LAST) {
  748.     for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW;
  749.     i++, coordPtr += 2) {
  750. TkIncludePoint((Tk_Item *) linePtr, coordPtr);
  751.     }
  752. }
  753. if (linePtr->arrow != ARROWS_FIRST) {
  754.     for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW;
  755.     i++, coordPtr += 2) {
  756. TkIncludePoint((Tk_Item *) linePtr, coordPtr);
  757.     }
  758. }
  759.     }
  760.     /*
  761.      * Add one more pixel of fudge factor just to be safe (e.g.
  762.      * X may round differently than we do).
  763.      */
  764.     linePtr->header.x1 -= 1;
  765.     linePtr->header.x2 += 1;
  766.     linePtr->header.y1 -= 1;
  767.     linePtr->header.y2 += 1;
  768. }
  769. /*
  770.  *--------------------------------------------------------------
  771.  *
  772.  * DisplayLine --
  773.  *
  774.  * This procedure is invoked to draw a line item in a given
  775.  * drawable.
  776.  *
  777.  * Results:
  778.  * None.
  779.  *
  780.  * Side effects:
  781.  * ItemPtr is drawn in drawable using the transformation
  782.  * information in canvas.
  783.  *
  784.  *--------------------------------------------------------------
  785.  */
  786. static void
  787. DisplayLine(canvas, itemPtr, display, drawable, x, y, width, height)
  788.     Tk_Canvas canvas; /* Canvas that contains item. */
  789.     Tk_Item *itemPtr; /* Item to be displayed. */
  790.     Display *display; /* Display on which to draw item. */
  791.     Drawable drawable; /* Pixmap or window in which to draw
  792.  * item. */
  793.     int x, y, width, height; /* Describes region of canvas that
  794.  * must be redisplayed (not used). */
  795. {
  796.     LineItem *linePtr = (LineItem *) itemPtr;
  797.     XPoint staticPoints[MAX_STATIC_POINTS*3];
  798.     XPoint *pointPtr;
  799.     double linewidth;
  800.     int numPoints;
  801.     Tk_State state = itemPtr->state;
  802.     Pixmap stipple = linePtr->outline.stipple;
  803.     if ((!linePtr->numPoints)||(linePtr->outline.gc==None)) {
  804. return;
  805.     }
  806.     if (state == TK_STATE_NULL) {
  807.     state = ((TkCanvas *)canvas)->canvas_state;
  808.     }
  809.     linewidth = linePtr->outline.width;
  810.     if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
  811. if (linePtr->outline.activeStipple != None) {
  812.     stipple = linePtr->outline.activeStipple;
  813. }
  814. if (linePtr->outline.activeWidth != linewidth) {
  815.     linewidth = linePtr->outline.activeWidth;
  816. }
  817.     } else if (state==TK_STATE_DISABLED) {
  818. if (linePtr->outline.disabledStipple != None) {
  819.     stipple = linePtr->outline.disabledStipple;
  820. }
  821. if (linePtr->outline.disabledWidth != linewidth) {
  822.     linewidth = linePtr->outline.disabledWidth;
  823. }
  824.     }
  825.     /*
  826.      * Build up an array of points in screen coordinates.  Use a
  827.      * static array unless the line has an enormous number of points;
  828.      * in this case, dynamically allocate an array.  For smoothed lines,
  829.      * generate the curve points on each redisplay.
  830.      */
  831.     if ((linePtr->smooth) && (linePtr->numPoints > 2)) {
  832. numPoints = linePtr->smooth->coordProc(canvas, (double *) NULL,
  833. linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL,
  834. (double *) NULL);
  835.     } else {
  836. numPoints = linePtr->numPoints;
  837.     }
  838.     if (numPoints <= MAX_STATIC_POINTS) {
  839. pointPtr = staticPoints;
  840.     } else {
  841. pointPtr = (XPoint *)ckalloc((unsigned)(numPoints * 3*sizeof(XPoint)));
  842.     }
  843.     if ((linePtr->smooth) && (linePtr->numPoints > 2)) {
  844. numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr,
  845. linePtr->numPoints, linePtr->splineSteps, pointPtr,
  846. (double *) NULL);
  847.     } else {
  848. numPoints = TkCanvTranslatePath((TkCanvas*)canvas, numPoints,
  849. linePtr->coordPtr, 0, pointPtr);
  850.     }
  851.     /*
  852.      * Display line, the free up line storage if it was dynamically
  853.      * allocated.  If we're stippling, then modify the stipple offset
  854.      * in the GC.  Be sure to reset the offset when done, since the
  855.      * GC is supposed to be read-only.
  856.      */
  857.     if (Tk_ChangeOutlineGC(canvas, itemPtr, &(linePtr->outline))) {
  858. Tk_CanvasSetOffset(canvas, linePtr->arrowGC, &linePtr->outline.tsoffset);
  859.     }
  860.     if (numPoints>1) {
  861. XDrawLines(display, drawable, linePtr->outline.gc, pointPtr, numPoints,
  862.     CoordModeOrigin);
  863.     } else {
  864. int intwidth = (int) (linewidth + 0.5);
  865.         if (intwidth<1) {
  866.     intwidth=1;
  867. }
  868. XFillArc(display, drawable, linePtr->outline.gc,
  869. pointPtr->x - intwidth/2, pointPtr->y - intwidth/2,
  870. (unsigned int)intwidth+1, (unsigned int)intwidth+1, 0, 64*360);
  871.     }
  872.     if (pointPtr != staticPoints) {
  873. ckfree((char *) pointPtr);
  874.     }
  875.     /*
  876.      * Display arrowheads, if they are wanted.
  877.      */
  878.     if (linePtr->firstArrowPtr != NULL) {
  879. TkFillPolygon(canvas, linePtr->firstArrowPtr, PTS_IN_ARROW,
  880. display, drawable, linePtr->arrowGC, NULL);
  881.     }
  882.     if (linePtr->lastArrowPtr != NULL) {
  883. TkFillPolygon(canvas, linePtr->lastArrowPtr, PTS_IN_ARROW,
  884. display, drawable, linePtr->arrowGC, NULL);
  885.     }
  886.     if (Tk_ResetOutlineGC(canvas, itemPtr, &(linePtr->outline))) {
  887. XSetTSOrigin(display, linePtr->arrowGC, 0, 0);
  888.     }
  889. }
  890. /*
  891.  *--------------------------------------------------------------
  892.  *
  893.  * LineInsert --
  894.  *
  895.  * Insert coords into a line item at a given index.
  896.  *
  897.  * Results:
  898.  * None.
  899.  *
  900.  * Side effects:
  901.  * The coords in the given item is modified.
  902.  *
  903.  *--------------------------------------------------------------
  904.  */
  905. static void
  906. LineInsert(canvas, itemPtr, beforeThis, obj)
  907.     Tk_Canvas canvas; /* Canvas containing text item. */
  908.     Tk_Item *itemPtr; /* Line item to be modified. */
  909.     int beforeThis; /* Index before which new coordinates
  910.  * are to be inserted. */
  911.     Tcl_Obj *obj; /* New coordinates to be inserted. */
  912. {
  913.     LineItem *linePtr = (LineItem *) itemPtr;
  914.     int length, objc, i;
  915.     double *new, *coordPtr;
  916.     Tk_State state = itemPtr->state;
  917.     Tcl_Obj **objv;
  918.     if(state == TK_STATE_NULL) {
  919. state = ((TkCanvas *)canvas)->canvas_state;
  920.     }
  921.     if (!obj || (Tcl_ListObjGetElements((Tcl_Interp *) NULL, obj, &objc, &objv) != TCL_OK)
  922.     || !objc || objc&1) {
  923. return;
  924.     }
  925.     length = 2*linePtr->numPoints;
  926.     if (beforeThis < 0) {
  927. beforeThis = 0;
  928.     }
  929.     if (beforeThis > length) {
  930. beforeThis = length;
  931.     }
  932.     if (linePtr->firstArrowPtr != NULL) {
  933. linePtr->coordPtr[0] = linePtr->firstArrowPtr[0];
  934. linePtr->coordPtr[1] = linePtr->firstArrowPtr[1];
  935.     }
  936.     if (linePtr->lastArrowPtr != NULL) {
  937. linePtr->coordPtr[length-2] = linePtr->lastArrowPtr[0];
  938. linePtr->coordPtr[length-1] = linePtr->lastArrowPtr[1];
  939.     }
  940.     new = (double *) ckalloc((unsigned)(sizeof(double) * (length + objc)));
  941.     for(i=0; i<beforeThis; i++) {
  942. new[i] = linePtr->coordPtr[i];
  943.     }
  944.     for(i=0; i<objc; i++) {
  945. if (Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,objv[i],
  946. new+(i+beforeThis))!=TCL_OK) {
  947.     Tcl_ResetResult(((TkCanvas *)canvas)->interp);
  948.     ckfree((char *) new);
  949.     return;
  950. }
  951.     }
  952.     for(i=beforeThis; i<length; i++) {
  953. new[i+objc] = linePtr->coordPtr[i];
  954.     }
  955.     if(linePtr->coordPtr) ckfree((char *)linePtr->coordPtr);
  956.     linePtr->coordPtr = new;
  957.     linePtr->numPoints = (length + objc)/2;
  958.     if ((length>3) && (state != TK_STATE_HIDDEN)) {
  959. /*
  960.  * This is some optimizing code that will result that only the part
  961.  * of the polygon that changed (and the objects that are overlapping
  962.  * with that part) need to be redrawn. A special flag is set that
  963.  * instructs the general canvas code not to redraw the whole
  964.  * object. If this flag is not set, the canvas will do the redrawing,
  965.  * otherwise I have to do it here.
  966.  */
  967. itemPtr->redraw_flags |= TK_ITEM_DONT_REDRAW;
  968. if (beforeThis>0) {beforeThis -= 2; objc+=2; }
  969. if ((beforeThis+objc)<length) objc+=2;
  970. if (linePtr->smooth) {
  971.     if(beforeThis>0) {
  972. beforeThis-=2; objc+=2;
  973.     }
  974.     if((beforeThis+objc+2)<length) {
  975. objc+=2;
  976.     }
  977. }
  978. itemPtr->x1 = itemPtr->x2 = (int) linePtr->coordPtr[beforeThis];
  979. itemPtr->y1 = itemPtr->y2 = (int) linePtr->coordPtr[beforeThis+1];
  980. if ((linePtr->firstArrowPtr != NULL) && (beforeThis<1)) {
  981.     /* include old first arrow */
  982.     for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW;
  983.     i++, coordPtr += 2) {
  984. TkIncludePoint(itemPtr, coordPtr);
  985.     }
  986. }
  987. if ((linePtr->lastArrowPtr != NULL) && ((beforeThis+objc)>=length)) {
  988. /* include old last arrow */
  989.     for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW;
  990.     i++, coordPtr += 2) {
  991. TkIncludePoint(itemPtr, coordPtr);
  992.     }
  993. }
  994. coordPtr = linePtr->coordPtr+beforeThis+2;
  995. for(i=2; i<objc; i+=2) {
  996.     TkIncludePoint(itemPtr, coordPtr);
  997. coordPtr+=2;
  998. }
  999.     }
  1000.     if (linePtr->firstArrowPtr != NULL) {
  1001. ckfree((char *) linePtr->firstArrowPtr);
  1002. linePtr->firstArrowPtr = NULL;
  1003.     }
  1004.     if (linePtr->lastArrowPtr != NULL) {
  1005. ckfree((char *) linePtr->lastArrowPtr);
  1006. linePtr->lastArrowPtr = NULL;
  1007.     }
  1008.     if (linePtr->arrow != ARROWS_NONE) {
  1009.     ConfigureArrows(canvas, linePtr);
  1010.     }
  1011.     if(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW) {
  1012. double width;
  1013. int intWidth;
  1014. if ((linePtr->firstArrowPtr != NULL) && (beforeThis>2)) {
  1015.     /* include new first arrow */
  1016.     for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW;
  1017.     i++, coordPtr += 2) {
  1018. TkIncludePoint(itemPtr, coordPtr);
  1019.     }
  1020. }
  1021. if ((linePtr->lastArrowPtr != NULL) && ((beforeThis+objc)<(length-2))) {
  1022.     /* include new right arrow */
  1023.     for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW;
  1024.     i++, coordPtr += 2) {
  1025. TkIncludePoint(itemPtr, coordPtr);
  1026.     }
  1027. }
  1028. width = linePtr->outline.width;
  1029. if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
  1030. if (linePtr->outline.activeWidth>width) {
  1031.     width = linePtr->outline.activeWidth;
  1032. }
  1033. } else if (state==TK_STATE_DISABLED) {
  1034. if (linePtr->outline.disabledWidth>0) {
  1035.     width = linePtr->outline.disabledWidth;
  1036. }
  1037. }
  1038. intWidth = (int) (width + 0.5);
  1039. if (intWidth < 1) {
  1040.     intWidth = 1;
  1041. }
  1042. itemPtr->x1 -= intWidth; itemPtr->y1 -= intWidth;
  1043. itemPtr->x2 += intWidth; itemPtr->y2 += intWidth;
  1044. Tk_CanvasEventuallyRedraw(canvas, itemPtr->x1, itemPtr->y1,
  1045. itemPtr->x2, itemPtr->y2);
  1046.     }
  1047.     ComputeLineBbox(canvas, linePtr);
  1048. }
  1049. /*
  1050.  *--------------------------------------------------------------
  1051.  *
  1052.  * LineDeleteCoords --
  1053.  *
  1054.  * Delete one or more coordinates from a line item.
  1055.  *
  1056.  * Results:
  1057.  * None.
  1058.  *
  1059.  * Side effects:
  1060.  * Characters between "first" and "last", inclusive, get
  1061.  * deleted from itemPtr.
  1062.  *
  1063.  *--------------------------------------------------------------
  1064.  */
  1065. static void
  1066. LineDeleteCoords(canvas, itemPtr, first, last)
  1067.     Tk_Canvas canvas; /* Canvas containing itemPtr. */
  1068.     Tk_Item *itemPtr; /* Item in which to delete characters. */
  1069.     int first; /* Index of first character to delete. */
  1070.     int last; /* Index of last character to delete. */
  1071. {
  1072.     LineItem *linePtr = (LineItem *) itemPtr;
  1073.     int count, i, first1, last1;
  1074.     int length = 2*linePtr->numPoints;
  1075.     double *coordPtr;
  1076.     Tk_State state = itemPtr->state;
  1077.     if(state == TK_STATE_NULL) {
  1078. state = ((TkCanvas *)canvas)->canvas_state;
  1079.     }
  1080.     first &= -2;
  1081.     last &= -2;
  1082.     if (first < 0) {
  1083. first = 0;
  1084.     }
  1085.     if (last >= length) {
  1086. last = length-2;
  1087.     }
  1088.     if (first > last) {
  1089. return;
  1090.     }
  1091.     if (linePtr->firstArrowPtr != NULL) {
  1092. linePtr->coordPtr[0] = linePtr->firstArrowPtr[0];
  1093. linePtr->coordPtr[1] = linePtr->firstArrowPtr[1];
  1094.     }
  1095.     if (linePtr->lastArrowPtr != NULL) {
  1096. linePtr->coordPtr[length-2] = linePtr->lastArrowPtr[0];
  1097. linePtr->coordPtr[length-1] = linePtr->lastArrowPtr[1];
  1098.     }
  1099.     first1 = first; last1 = last;
  1100.     if(first1>0) first1 -= 2;
  1101.     if(last1<length-2) last1 += 2;
  1102.     if (linePtr->smooth) {
  1103. if(first1>0) first1 -= 2;
  1104. if(last1<length-2) last1 += 2;
  1105.     }
  1106.     if((first1<2) && (last1 >= length-2)) {
  1107. /*
  1108.  * This is some optimizing code that will result that only the part
  1109.  * of the line that changed (and the objects that are overlapping
  1110.  * with that part) need to be redrawn. A special flag is set that
  1111.  * instructs the general canvas code not to redraw the whole
  1112.  * object. If this flag is set, the redrawing has to be done here,
  1113.  * otherwise the general Canvas code will take care of it.
  1114.  */
  1115. itemPtr->redraw_flags |= TK_ITEM_DONT_REDRAW;
  1116. itemPtr->x1 = itemPtr->x2 = (int) linePtr->coordPtr[first1];
  1117. itemPtr->y1 = itemPtr->y2 = (int) linePtr->coordPtr[first1+1];
  1118. if ((linePtr->firstArrowPtr != NULL) && (first1<2)) {
  1119.     /* include old first arrow */
  1120.     for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW;
  1121.     i++, coordPtr += 2) {
  1122. TkIncludePoint(itemPtr, coordPtr);
  1123.     }
  1124. }
  1125. if ((linePtr->lastArrowPtr != NULL) && (last1>=length-2)) {
  1126. /* include old last arrow */
  1127.     for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW;
  1128.     i++, coordPtr += 2) {
  1129. TkIncludePoint(itemPtr, coordPtr);
  1130.     }
  1131. }
  1132. coordPtr = linePtr->coordPtr+first1+2;
  1133. for (i=first1+2; i<=last1; i+=2) {
  1134.     TkIncludePoint(itemPtr, coordPtr);
  1135.     coordPtr+=2;
  1136. }
  1137.     }
  1138.     count = last + 2 - first;
  1139.     for (i=last+2; i<length; i++) {
  1140. linePtr->coordPtr[i-count] = linePtr->coordPtr[i];
  1141.     }
  1142.     linePtr->numPoints -= count/2;
  1143.     if (linePtr->firstArrowPtr != NULL) {
  1144. ckfree((char *) linePtr->firstArrowPtr);
  1145. linePtr->firstArrowPtr = NULL;
  1146.     }
  1147.     if (linePtr->lastArrowPtr != NULL) {
  1148. ckfree((char *) linePtr->lastArrowPtr);
  1149. linePtr->lastArrowPtr = NULL;
  1150.     }
  1151.     if (linePtr->arrow != ARROWS_NONE) {
  1152.     ConfigureArrows(canvas, linePtr);
  1153.     }
  1154.     if(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW) {
  1155. double width;
  1156. int intWidth;
  1157. if ((linePtr->firstArrowPtr != NULL) && (first1<4)) {
  1158.     /* include new first arrow */
  1159.     for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW;
  1160.     i++, coordPtr += 2) {
  1161. TkIncludePoint(itemPtr, coordPtr);
  1162.     }
  1163. }
  1164. if ((linePtr->lastArrowPtr != NULL) && (last1>(length-4))) {
  1165.     /* include new right arrow */
  1166.     for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW;
  1167.     i++, coordPtr += 2) {
  1168. TkIncludePoint(itemPtr, coordPtr);
  1169.     }
  1170. }
  1171. width = linePtr->outline.width;
  1172. if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
  1173. if (linePtr->outline.activeWidth>width) {
  1174.     width = linePtr->outline.activeWidth;
  1175. }
  1176. } else if (state==TK_STATE_DISABLED) {
  1177. if (linePtr->outline.disabledWidth>0) {
  1178.     width = linePtr->outline.disabledWidth;
  1179. }
  1180. }
  1181. intWidth = (int) (width + 0.5);
  1182. if (intWidth < 1) {
  1183.     intWidth = 1;
  1184. }
  1185. itemPtr->x1 -= intWidth; itemPtr->y1 -= intWidth;
  1186. itemPtr->x2 += intWidth; itemPtr->y2 += intWidth;
  1187. Tk_CanvasEventuallyRedraw(canvas, itemPtr->x1, itemPtr->y1,
  1188. itemPtr->x2, itemPtr->y2);
  1189.     }
  1190.     ComputeLineBbox(canvas, linePtr);
  1191. }
  1192. /*
  1193.  *--------------------------------------------------------------
  1194.  *
  1195.  * LineToPoint --
  1196.  *
  1197.  * Computes the distance from a given point to a given
  1198.  * line, in canvas units.
  1199.  *
  1200.  * Results:
  1201.  * The return value is 0 if the point whose x and y coordinates
  1202.  * are pointPtr[0] and pointPtr[1] is inside the line.  If the
  1203.  * point isn't inside the line then the return value is the
  1204.  * distance from the point to the line.
  1205.  *
  1206.  * Side effects:
  1207.  * None.
  1208.  *
  1209.  *--------------------------------------------------------------
  1210.  */
  1211. /* ARGSUSED */
  1212. static double
  1213. LineToPoint(canvas, itemPtr, pointPtr)
  1214.     Tk_Canvas canvas; /* Canvas containing item. */
  1215.     Tk_Item *itemPtr; /* Item to check against point. */
  1216.     double *pointPtr; /* Pointer to x and y coordinates. */
  1217. {
  1218.     Tk_State state = itemPtr->state;
  1219.     LineItem *linePtr = (LineItem *) itemPtr;
  1220.     double *coordPtr, *linePoints;
  1221.     double staticSpace[2*MAX_STATIC_POINTS];
  1222.     double poly[10];
  1223.     double bestDist, dist, width;
  1224.     int numPoints, count;
  1225.     int changedMiterToBevel; /* Non-zero means that a mitered corner
  1226.  * had to be treated as beveled after all
  1227.  * because the angle was < 11 degrees. */
  1228.     bestDist = 1.0e36;
  1229.     /*
  1230.      * Handle smoothed lines by generating an expanded set of points
  1231.      * against which to do the check.
  1232.      */
  1233.     if(state == TK_STATE_NULL) {
  1234. state = ((TkCanvas *)canvas)->canvas_state;
  1235.     }
  1236.     width = linePtr->outline.width;
  1237.     if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
  1238. if (linePtr->outline.activeWidth>width) {
  1239.     width = linePtr->outline.activeWidth;
  1240. }
  1241.     } else if (state==TK_STATE_DISABLED) {
  1242. if (linePtr->outline.disabledWidth>0) {
  1243.     width = linePtr->outline.disabledWidth;
  1244. }
  1245.     }
  1246.     if ((linePtr->smooth) && (linePtr->numPoints > 2)) {
  1247. numPoints = linePtr->smooth->coordProc(canvas, (double *) NULL,
  1248. linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL,
  1249. (double *) NULL);
  1250. if (numPoints <= MAX_STATIC_POINTS) {
  1251.     linePoints = staticSpace;
  1252. } else {
  1253.     linePoints = (double *) ckalloc((unsigned)
  1254.     (2*numPoints*sizeof(double)));
  1255. }
  1256. numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr,
  1257. linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL,
  1258. linePoints);
  1259.     } else {
  1260. numPoints = linePtr->numPoints;
  1261. linePoints = linePtr->coordPtr;
  1262.     }
  1263.     if (width < 1.0) {
  1264. width = 1.0;
  1265.     }
  1266.     if (!numPoints || itemPtr->state==TK_STATE_HIDDEN) {
  1267. return bestDist;
  1268.     } else if (numPoints == 1) {
  1269. bestDist = hypot(linePoints[0] - pointPtr[0], linePoints[1] - pointPtr[1])
  1270.     - width/2.0;
  1271. if (bestDist < 0) bestDist = 0;
  1272. return bestDist;
  1273.     }
  1274.     /*
  1275.      * The overall idea is to iterate through all of the edges of
  1276.      * the line, computing a polygon for each edge and testing the
  1277.      * point against that polygon.  In addition, there are additional
  1278.      * tests to deal with rounded joints and caps.
  1279.      */
  1280.     changedMiterToBevel = 0;
  1281.     for (count = numPoints, coordPtr = linePoints; count >= 2;
  1282.     count--, coordPtr += 2) {
  1283. /*
  1284.  * If rounding is done around the first point then compute
  1285.  * the distance between the point and the point.
  1286.  */
  1287. if (((linePtr->capStyle == CapRound) && (count == numPoints))
  1288. || ((linePtr->joinStyle == JoinRound)
  1289. && (count != numPoints))) {
  1290.     dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1])
  1291.     - width/2.0;
  1292.     if (dist <= 0.0) {
  1293. bestDist = 0.0;
  1294. goto done;
  1295.     } else if (dist < bestDist) {
  1296. bestDist = dist;
  1297.     }
  1298. }
  1299. /*
  1300.  * Compute the polygonal shape corresponding to this edge,
  1301.  * consisting of two points for the first point of the edge
  1302.  * and two points for the last point of the edge.
  1303.  */
  1304. if (count == numPoints) {
  1305.     TkGetButtPoints(coordPtr+2, coordPtr, width,
  1306.     linePtr->capStyle == CapProjecting, poly, poly+2);
  1307. } else if ((linePtr->joinStyle == JoinMiter) && !changedMiterToBevel) {
  1308.     poly[0] = poly[6];
  1309.     poly[1] = poly[7];
  1310.     poly[2] = poly[4];
  1311.     poly[3] = poly[5];
  1312. } else {
  1313.     TkGetButtPoints(coordPtr+2, coordPtr, width, 0,
  1314.     poly, poly+2);
  1315.     /*
  1316.      * If this line uses beveled joints, then check the distance
  1317.      * to a polygon comprising the last two points of the previous
  1318.      * polygon and the first two from this polygon;  this checks
  1319.      * the wedges that fill the mitered joint.
  1320.      */
  1321.     if ((linePtr->joinStyle == JoinBevel) || changedMiterToBevel) {
  1322. poly[8] = poly[0];
  1323. poly[9] = poly[1];
  1324. dist = TkPolygonToPoint(poly, 5, pointPtr);
  1325. if (dist <= 0.0) {
  1326.     bestDist = 0.0;
  1327.     goto done;
  1328. } else if (dist < bestDist) {
  1329.     bestDist = dist;
  1330. }
  1331. changedMiterToBevel = 0;
  1332.     }
  1333. }
  1334. if (count == 2) {
  1335.     TkGetButtPoints(coordPtr, coordPtr+2, width,
  1336.     linePtr->capStyle == CapProjecting, poly+4, poly+6);
  1337. } else if (linePtr->joinStyle == JoinMiter) {
  1338.     if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4,
  1339.     width, poly+4, poly+6) == 0) {
  1340. changedMiterToBevel = 1;
  1341. TkGetButtPoints(coordPtr, coordPtr+2, width,
  1342. 0, poly+4, poly+6);
  1343.     }
  1344. } else {
  1345.     TkGetButtPoints(coordPtr, coordPtr+2, width, 0,
  1346.     poly+4, poly+6);
  1347. }
  1348. poly[8] = poly[0];
  1349. poly[9] = poly[1];
  1350. dist = TkPolygonToPoint(poly, 5, pointPtr);
  1351. if (dist <= 0.0) {
  1352.     bestDist = 0.0;
  1353.     goto done;
  1354. } else if (dist < bestDist) {
  1355.     bestDist = dist;
  1356. }
  1357.     }
  1358.     /*
  1359.      * If caps are rounded, check the distance to the cap around the
  1360.      * final end point of the line.
  1361.      */
  1362.     if (linePtr->capStyle == CapRound) {
  1363. dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1])
  1364. - width/2.0;
  1365. if (dist <= 0.0) {
  1366.     bestDist = 0.0;
  1367.     goto done;
  1368. } else if (dist < bestDist) {
  1369.     bestDist = dist;
  1370. }
  1371.     }
  1372.     /*
  1373.      * If there are arrowheads, check the distance to the arrowheads.
  1374.      */
  1375.     if (linePtr->arrow != ARROWS_NONE) {
  1376. if (linePtr->arrow != ARROWS_LAST) {
  1377.     dist = TkPolygonToPoint(linePtr->firstArrowPtr, PTS_IN_ARROW,
  1378.     pointPtr);
  1379.     if (dist <= 0.0) {
  1380. bestDist = 0.0;
  1381. goto done;
  1382.     } else if (dist < bestDist) {
  1383. bestDist = dist;
  1384.     }
  1385. }
  1386. if (linePtr->arrow != ARROWS_FIRST) {
  1387.     dist = TkPolygonToPoint(linePtr->lastArrowPtr, PTS_IN_ARROW,
  1388.     pointPtr);
  1389.     if (dist <= 0.0) {
  1390. bestDist = 0.0;
  1391. goto done;
  1392.     } else if (dist < bestDist) {
  1393. bestDist = dist;
  1394.     }
  1395. }
  1396.     }
  1397.     done:
  1398.     if ((linePoints != staticSpace) && (linePoints != linePtr->coordPtr)) {
  1399. ckfree((char *) linePoints);
  1400.     }
  1401.     return bestDist;
  1402. }
  1403. /*
  1404.  *--------------------------------------------------------------
  1405.  *
  1406.  * LineToArea --
  1407.  *
  1408.  * This procedure is called to determine whether an item
  1409.  * lies entirely inside, entirely outside, or overlapping
  1410.  * a given rectangular area.
  1411.  *
  1412.  * Results:
  1413.  * -1 is returned if the item is entirely outside the
  1414.  * area, 0 if it overlaps, and 1 if it is entirely
  1415.  * inside the given area.
  1416.  *
  1417.  * Side effects:
  1418.  * None.
  1419.  *
  1420.  *--------------------------------------------------------------
  1421.  */
  1422. /* ARGSUSED */
  1423. static int
  1424. LineToArea(canvas, itemPtr, rectPtr)
  1425.     Tk_Canvas canvas; /* Canvas containing item. */
  1426.     Tk_Item *itemPtr; /* Item to check against line. */
  1427.     double *rectPtr;
  1428. {
  1429.     LineItem *linePtr = (LineItem *) itemPtr;
  1430.     double staticSpace[2*MAX_STATIC_POINTS];
  1431.     double *linePoints;
  1432.     int numPoints, result;
  1433.     double radius, width;
  1434.     Tk_State state = itemPtr->state;
  1435.     if(state == TK_STATE_NULL) {
  1436. state = ((TkCanvas *)canvas)->canvas_state;
  1437.     }
  1438.     width = linePtr->outline.width;
  1439.     if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
  1440. if (linePtr->outline.activeWidth>width) {
  1441.     width = linePtr->outline.activeWidth;
  1442. }
  1443.     } else if (state==TK_STATE_DISABLED) {
  1444. if (linePtr->outline.disabledWidth>0) {
  1445.     width = linePtr->outline.disabledWidth;
  1446. }
  1447.     }
  1448.     radius = (width+1.0)/2.0;
  1449.     if ((state==TK_STATE_HIDDEN) || !linePtr->numPoints) {
  1450. return -1;
  1451.     } else if (linePtr->numPoints == 1) {
  1452. double oval[4];
  1453. oval[0] = linePtr->coordPtr[0]-radius;
  1454. oval[1] = linePtr->coordPtr[1]-radius;
  1455. oval[2] = linePtr->coordPtr[0]+radius;
  1456. oval[3] = linePtr->coordPtr[1]+radius;
  1457. return TkOvalToArea(oval, rectPtr);
  1458.     }
  1459.     /*
  1460.      * Handle smoothed lines by generating an expanded set of points
  1461.      * against which to do the check.
  1462.      */
  1463.     if ((linePtr->smooth) && (linePtr->numPoints > 2)) {
  1464. numPoints = linePtr->smooth->coordProc(canvas, (double *) NULL,
  1465. linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL,
  1466. (double *) NULL);
  1467. if (numPoints <= MAX_STATIC_POINTS) {
  1468.     linePoints = staticSpace;
  1469. } else {
  1470.     linePoints = (double *) ckalloc((unsigned)
  1471.     (2*numPoints*sizeof(double)));
  1472. }
  1473. numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr,
  1474. linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL,
  1475. linePoints);
  1476.     } else {
  1477. numPoints = linePtr->numPoints;
  1478. linePoints = linePtr->coordPtr;
  1479.     }
  1480.     /*
  1481.      * Check the segments of the line.
  1482.      */
  1483.      if (width < 1.0) {
  1484. width = 1.0;
  1485.     }
  1486.     result = TkThickPolyLineToArea(linePoints, numPoints, 
  1487.     width, linePtr->capStyle, linePtr->joinStyle,
  1488.     rectPtr);
  1489.     if (result == 0) {
  1490. goto done;
  1491.     }
  1492.     /*
  1493.      * Check arrowheads, if any.
  1494.      */
  1495.     if (linePtr->arrow != ARROWS_NONE) {
  1496. if (linePtr->arrow != ARROWS_LAST) {
  1497.     if (TkPolygonToArea(linePtr->firstArrowPtr, PTS_IN_ARROW,
  1498.     rectPtr) != result) {
  1499. result = 0;
  1500. goto done;
  1501.     }
  1502. }
  1503. if (linePtr->arrow != ARROWS_FIRST) {
  1504.     if (TkPolygonToArea(linePtr->lastArrowPtr, PTS_IN_ARROW,
  1505.     rectPtr) != result) {
  1506. result = 0;
  1507. goto done;
  1508.     }
  1509. }
  1510.     }
  1511.     done:
  1512.     if ((linePoints != staticSpace) && (linePoints != linePtr->coordPtr)) {
  1513. ckfree((char *) linePoints);
  1514.     }
  1515.     return result;
  1516. }
  1517. /*
  1518.  *--------------------------------------------------------------
  1519.  *
  1520.  * ScaleLine --
  1521.  *
  1522.  * This procedure is invoked to rescale a line item.
  1523.  *
  1524.  * Results:
  1525.  * None.
  1526.  *
  1527.  * Side effects:
  1528.  * The line referred to by itemPtr is rescaled so that the
  1529.  * following transformation is applied to all point
  1530.  * coordinates:
  1531.  * x' = originX + scaleX*(x-originX)
  1532.  * y' = originY + scaleY*(y-originY)
  1533.  *
  1534.  *--------------------------------------------------------------
  1535.  */
  1536. static void
  1537. ScaleLine(canvas, itemPtr, originX, originY, scaleX, scaleY)
  1538.     Tk_Canvas canvas; /* Canvas containing line. */
  1539.     Tk_Item *itemPtr; /* Line to be scaled. */
  1540.     double originX, originY; /* Origin about which to scale rect. */
  1541.     double scaleX; /* Amount to scale in X direction. */
  1542.     double scaleY; /* Amount to scale in Y direction. */
  1543. {
  1544.     LineItem *linePtr = (LineItem *) itemPtr;
  1545.     double *coordPtr;
  1546.     int i;
  1547.     /*
  1548.      * Delete any arrowheads before scaling all the points (so that
  1549.      * the end-points of the line get restored).
  1550.      */
  1551.     if (linePtr->firstArrowPtr != NULL) {
  1552. linePtr->coordPtr[0] = linePtr->firstArrowPtr[0];
  1553. linePtr->coordPtr[1] = linePtr->firstArrowPtr[1];
  1554. ckfree((char *) linePtr->firstArrowPtr);
  1555. linePtr->firstArrowPtr = NULL;
  1556.     }
  1557.     if (linePtr->lastArrowPtr != NULL) {
  1558. int i;
  1559. i = 2*(linePtr->numPoints-1);
  1560. linePtr->coordPtr[i] = linePtr->lastArrowPtr[0];
  1561. linePtr->coordPtr[i+1] = linePtr->lastArrowPtr[1];
  1562. ckfree((char *) linePtr->lastArrowPtr);
  1563. linePtr->lastArrowPtr = NULL;
  1564.     }
  1565.     for (i = 0, coordPtr = linePtr->coordPtr; i < linePtr->numPoints;
  1566.     i++, coordPtr += 2) {
  1567. coordPtr[0] = originX + scaleX*(*coordPtr - originX);
  1568. coordPtr[1] = originY + scaleY*(coordPtr[1] - originY);
  1569.     }
  1570.     if (linePtr->arrow != ARROWS_NONE) {
  1571. ConfigureArrows(canvas, linePtr);
  1572.     }
  1573.     ComputeLineBbox(canvas, linePtr);
  1574. }
  1575. /*
  1576.  *--------------------------------------------------------------
  1577.  *
  1578.  * GetLineIndex --
  1579.  *
  1580.  * Parse an index into a line item and return either its value
  1581.  * or an error.
  1582.  *
  1583.  * Results:
  1584.  * A standard Tcl result.  If all went well, then *indexPtr is
  1585.  * filled in with the index (into itemPtr) corresponding to
  1586.  * string.  Otherwise an error message is left in
  1587.  * interp->result.
  1588.  *
  1589.  * Side effects:
  1590.  * None.
  1591.  *
  1592.  *--------------------------------------------------------------
  1593.  */
  1594. static int
  1595. GetLineIndex(interp, canvas, itemPtr, obj, indexPtr)
  1596.     Tcl_Interp *interp; /* Used for error reporting. */
  1597.     Tk_Canvas canvas; /* Canvas containing item. */
  1598.     Tk_Item *itemPtr; /* Item for which the index is being
  1599.  * specified. */
  1600.     Tcl_Obj *obj; /* Specification of a particular coord
  1601.  * in itemPtr's line. */
  1602.     int *indexPtr; /* Where to store converted index. */
  1603. {
  1604.     LineItem *linePtr = (LineItem *) itemPtr;
  1605.     int length;
  1606.     char *string = Tcl_GetStringFromObj(obj, &length);
  1607.     if (string[0] == 'e') {
  1608. if (strncmp(string, "end", (unsigned) length) == 0) {
  1609.     *indexPtr = 2*linePtr->numPoints;
  1610. } else {
  1611.     badIndex:
  1612.     /*
  1613.      * Some of the paths here leave messages in interp->result,
  1614.      * so we have to clear it out before storing our own message.
  1615.      */
  1616.     Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
  1617.     Tcl_AppendResult(interp, "bad index "", string, """,
  1618.     (char *) NULL);
  1619.     return TCL_ERROR;
  1620. }
  1621.     } else if (string[0] == '@') {
  1622. int i;
  1623. double x ,y, bestDist, dist, *coordPtr;
  1624. char *end, *p;
  1625. p = string+1;
  1626. x = strtod(p, &end);
  1627. if ((end == p) || (*end != ',')) {
  1628.     goto badIndex;
  1629. }
  1630. p = end+1;
  1631. y = strtod(p, &end);
  1632. if ((end == p) || (*end != 0)) {
  1633.     goto badIndex;
  1634. }
  1635. bestDist = 1.0e36;
  1636. coordPtr = linePtr->coordPtr;
  1637. *indexPtr = 0;
  1638. for(i=0; i<linePtr->numPoints; i++) {
  1639.     dist = hypot(coordPtr[0] - x, coordPtr[1] - y);
  1640.     if (dist<bestDist) {
  1641. bestDist = dist;
  1642. *indexPtr = 2*i;
  1643.     }
  1644.     coordPtr += 2;
  1645. }
  1646.     } else {
  1647. if (Tcl_GetIntFromObj(interp, obj, indexPtr) != TCL_OK) {
  1648.     goto badIndex;
  1649. }
  1650. *indexPtr &= -2; /* if index is odd, make it even */
  1651. if (*indexPtr < 0){
  1652.     *indexPtr = 0;
  1653. } else if (*indexPtr > (2*linePtr->numPoints)) {
  1654.     *indexPtr = (2*linePtr->numPoints);
  1655. }
  1656.     }
  1657.     return TCL_OK;
  1658. }
  1659. /*
  1660.  *--------------------------------------------------------------
  1661.  *
  1662.  * TranslateLine --
  1663.  *
  1664.  * This procedure is called to move a line by a given amount.
  1665.  *
  1666.  * Results:
  1667.  * None.
  1668.  *
  1669.  * Side effects:
  1670.  * The position of the line is offset by (xDelta, yDelta), and
  1671.  * the bounding box is updated in the generic part of the item
  1672.  * structure.
  1673.  *
  1674.  *--------------------------------------------------------------
  1675.  */
  1676. static void
  1677. TranslateLine(canvas, itemPtr, deltaX, deltaY)
  1678.     Tk_Canvas canvas; /* Canvas containing item. */
  1679.     Tk_Item *itemPtr; /* Item that is being moved. */
  1680.     double deltaX, deltaY; /* Amount by which item is to be
  1681.  * moved. */
  1682. {
  1683.     LineItem *linePtr = (LineItem *) itemPtr;
  1684.     double *coordPtr;
  1685.     int i;
  1686.     for (i = 0, coordPtr = linePtr->coordPtr; i < linePtr->numPoints;
  1687.     i++, coordPtr += 2) {
  1688. coordPtr[0] += deltaX;
  1689. coordPtr[1] += deltaY;
  1690.     }
  1691.     if (linePtr->firstArrowPtr != NULL) {
  1692. for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW;
  1693. i++, coordPtr += 2) {
  1694.     coordPtr[0] += deltaX;
  1695.     coordPtr[1] += deltaY;
  1696. }
  1697.     }
  1698.     if (linePtr->lastArrowPtr != NULL) {
  1699. for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW;
  1700. i++, coordPtr += 2) {
  1701.     coordPtr[0] += deltaX;
  1702.     coordPtr[1] += deltaY;
  1703. }
  1704.     }
  1705.     ComputeLineBbox(canvas, linePtr);
  1706. }
  1707. /*
  1708.  *--------------------------------------------------------------
  1709.  *
  1710.  * ParseArrowShape --
  1711.  *
  1712.  * This procedure is called back during option parsing to
  1713.  * parse arrow shape information.
  1714.  *
  1715.  * Results:
  1716.  * The return value is a standard Tcl result:  TCL_OK means
  1717.  * that the arrow shape information was parsed ok, and
  1718.  * TCL_ERROR means it couldn't be parsed.
  1719.  *
  1720.  * Side effects:
  1721.  * Arrow information in recordPtr is updated.
  1722.  *
  1723.  *--------------------------------------------------------------
  1724.  */
  1725. /* ARGSUSED */
  1726. static int
  1727. ParseArrowShape(clientData, interp, tkwin, value, recordPtr, offset)
  1728.     ClientData clientData; /* Not used. */
  1729.     Tcl_Interp *interp; /* Used for error reporting. */
  1730.     Tk_Window tkwin; /* Not used. */
  1731.     CONST char *value; /* Textual specification of arrow shape. */
  1732.     char *recordPtr; /* Pointer to item record in which to
  1733.  * store arrow information. */
  1734.     int offset; /* Offset of shape information in widget
  1735.  * record. */
  1736. {
  1737.     LineItem *linePtr = (LineItem *) recordPtr;
  1738.     double a, b, c;
  1739.     int argc;
  1740.     CONST char **argv = NULL;
  1741.     if (offset != Tk_Offset(LineItem, arrowShapeA)) {
  1742. panic("ParseArrowShape received bogus offset");
  1743.     }
  1744.     if (Tcl_SplitList(interp, (char *) value, &argc, &argv) != TCL_OK) {
  1745. syntaxError:
  1746. Tcl_ResetResult(interp);
  1747. Tcl_AppendResult(interp, "bad arrow shape "", value,
  1748. "": must be list with three numbers", (char *) NULL);
  1749. if (argv != NULL) {
  1750.     ckfree((char *) argv);
  1751. }
  1752. return TCL_ERROR;
  1753.     }
  1754.     if (argc != 3) {
  1755. goto syntaxError;
  1756.     }
  1757.     if ((Tk_CanvasGetCoord(interp, linePtr->canvas, argv[0], &a) != TCL_OK)
  1758.     || (Tk_CanvasGetCoord(interp, linePtr->canvas, argv[1], &b)
  1759. != TCL_OK)
  1760.     || (Tk_CanvasGetCoord(interp, linePtr->canvas, argv[2], &c)
  1761. != TCL_OK)) {
  1762. goto syntaxError;
  1763.     }
  1764.     linePtr->arrowShapeA = (float)a;
  1765.     linePtr->arrowShapeB = (float)b;
  1766.     linePtr->arrowShapeC = (float)c;
  1767.     ckfree((char *) argv);
  1768.     return TCL_OK;
  1769. }
  1770. /*
  1771.  *--------------------------------------------------------------
  1772.  *
  1773.  * PrintArrowShape --
  1774.  *
  1775.  * This procedure is a callback invoked by the configuration
  1776.  * code to return a printable value describing an arrow shape.
  1777.  *
  1778.  * Results:
  1779.  * None.
  1780.  *
  1781.  * Side effects:
  1782.  * None.
  1783.  *
  1784.  *--------------------------------------------------------------
  1785.  */
  1786.     /* ARGSUSED */
  1787. static char *
  1788. PrintArrowShape(clientData, tkwin, recordPtr, offset, freeProcPtr)
  1789.     ClientData clientData; /* Not used. */
  1790.     Tk_Window tkwin; /* Window associated with linePtr's widget. */
  1791.     char *recordPtr; /* Pointer to item record containing current
  1792.  * shape information. */
  1793.     int offset; /* Offset of arrow information in record. */
  1794.     Tcl_FreeProc **freeProcPtr; /* Store address of procedure to call to
  1795.  * free string here. */
  1796. {
  1797.     LineItem *linePtr = (LineItem *) recordPtr;
  1798.     char *buffer;
  1799.     buffer = (char *) ckalloc(120);
  1800.     sprintf(buffer, "%.5g %.5g %.5g", linePtr->arrowShapeA,
  1801.     linePtr->arrowShapeB, linePtr->arrowShapeC);
  1802.     *freeProcPtr = TCL_DYNAMIC;
  1803.     return buffer;
  1804. }
  1805. /*
  1806.  *--------------------------------------------------------------
  1807.  *
  1808.  * ArrowParseProc --
  1809.  *
  1810.  * This procedure is invoked during option processing to handle
  1811.  * the "-arrow" option.
  1812.  *
  1813.  * Results:
  1814.  * A standard Tcl return value.
  1815.  *
  1816.  * Side effects:
  1817.  * The arrow for a given item gets replaced by the arrow
  1818.  * indicated in the value argument.
  1819.  *
  1820.  *--------------------------------------------------------------
  1821.  */
  1822. static int
  1823. ArrowParseProc(clientData, interp, tkwin, value, widgRec, offset)
  1824.     ClientData clientData; /* some flags.*/
  1825.     Tcl_Interp *interp; /* Used for reporting errors. */
  1826.     Tk_Window tkwin; /* Window containing canvas widget. */
  1827.     CONST char *value; /* Value of option. */
  1828.     char *widgRec; /* Pointer to record for item. */
  1829.     int offset; /* Offset into item. */
  1830. {
  1831.     int c;
  1832.     size_t length;
  1833.     register Arrows *arrowPtr = (Arrows *) (widgRec + offset);
  1834.     if(value == NULL || *value == 0) {
  1835. *arrowPtr = ARROWS_NONE;
  1836. return TCL_OK;
  1837.     }
  1838.     c = value[0];
  1839.     length = strlen(value);
  1840.     if ((c == 'n') && (strncmp(value, "none", length) == 0)) {
  1841. *arrowPtr = ARROWS_NONE;
  1842. return TCL_OK;
  1843.     }
  1844.     if ((c == 'f') && (strncmp(value, "first", length) == 0)) {
  1845. *arrowPtr = ARROWS_FIRST;
  1846. return TCL_OK;
  1847.     }
  1848.     if ((c == 'l') && (strncmp(value, "last", length) == 0)) {
  1849. *arrowPtr = ARROWS_LAST;
  1850. return TCL_OK;
  1851.     }
  1852.     if ((c == 'b') && (strncmp(value, "both", length) == 0)) {
  1853. *arrowPtr = ARROWS_BOTH;
  1854. return TCL_OK;
  1855.     }
  1856.     Tcl_AppendResult(interp, "bad arrow spec "", value, 
  1857.     "": must be none, first, last, or both",
  1858.     (char *) NULL);
  1859.     *arrowPtr = ARROWS_NONE;
  1860.     return TCL_ERROR;
  1861. }
  1862. /*
  1863.  *--------------------------------------------------------------
  1864.  *
  1865.  * ArrowPrintProc --
  1866.  *
  1867.  * This procedure is invoked by the Tk configuration code
  1868.  * to produce a printable string for the "-arrow"
  1869.  * configuration option.
  1870.  *
  1871.  * Results:
  1872.  * The return value is a string describing the arrows for
  1873.  * the item referred to by "widgRec".  In addition, *freeProcPtr
  1874.  * is filled in with the address of a procedure to call to free
  1875.  * the result string when it's no longer needed (or NULL to
  1876.  * indicate that the string doesn't need to be freed).
  1877.  *
  1878.  * Side effects:
  1879.  * None.
  1880.  *
  1881.  *--------------------------------------------------------------
  1882.  */
  1883. static char *
  1884. ArrowPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
  1885.     ClientData clientData; /* Ignored. */
  1886.     Tk_Window tkwin; /* Window containing canvas widget. */
  1887.     char *widgRec; /* Pointer to record for item. */
  1888.     int offset; /* Offset into item. */
  1889.     Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with
  1890.  * information about how to reclaim
  1891.  * storage for return string. */
  1892. {
  1893.     register Arrows *arrowPtr = (Arrows *) (widgRec + offset);
  1894.     switch (*arrowPtr) {
  1895.       case ARROWS_FIRST:
  1896. return "first";
  1897.       case ARROWS_LAST:
  1898. return "last";
  1899.       case ARROWS_BOTH:
  1900. return "both";
  1901.       default:
  1902. return "none";
  1903.     }
  1904. }
  1905. /*
  1906.  *--------------------------------------------------------------
  1907.  *
  1908.  * ConfigureArrows --
  1909.  *
  1910.  * If arrowheads have been requested for a line, this
  1911.  * procedure makes arrangements for the arrowheads.
  1912.  *
  1913.  * Results:
  1914.  * Always returns TCL_OK.
  1915.  *
  1916.  * Side effects:
  1917.  * Information in linePtr is set up for one or two arrowheads.
  1918.  * the firstArrowPtr and lastArrowPtr polygons are allocated
  1919.  * and initialized, if need be, and the end points of the line
  1920.  * are adjusted so that a thick line doesn't stick out past
  1921.  * the arrowheads.
  1922.  *
  1923.  *--------------------------------------------------------------
  1924.  */
  1925. /* ARGSUSED */
  1926. static int
  1927. ConfigureArrows(canvas, linePtr)
  1928.     Tk_Canvas canvas; /* Canvas in which arrows will be
  1929.  * displayed (interp and tkwin
  1930.  * fields are needed). */
  1931.     LineItem *linePtr; /* Item to configure for arrows. */
  1932. {
  1933.     double *poly, *coordPtr;
  1934.     double dx, dy, length, sinTheta, cosTheta, temp;
  1935.     double fracHeight; /* Line width as fraction of
  1936.  * arrowhead width. */
  1937.     double backup; /* Distance to backup end points
  1938.  * so the line ends in the middle
  1939.  * of the arrowhead. */
  1940.     double vertX, vertY; /* Position of arrowhead vertex. */
  1941.     double shapeA, shapeB, shapeC; /* Adjusted coordinates (see
  1942.  * explanation below). */
  1943.     double width;
  1944.     Tk_State state = linePtr->header.state;
  1945.     if (linePtr->numPoints <2) {
  1946. return TCL_OK;
  1947.     }
  1948.     if(state == TK_STATE_NULL) {
  1949. state = ((TkCanvas *)canvas)->canvas_state;
  1950.     }
  1951.     width = linePtr->outline.width;
  1952.     if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)linePtr) {
  1953. if (linePtr->outline.activeWidth>width) {
  1954.     width = linePtr->outline.activeWidth;
  1955. }
  1956.     } else if (state==TK_STATE_DISABLED) {
  1957. if (linePtr->outline.disabledWidth>0) {
  1958.     width = linePtr->outline.disabledWidth;
  1959. }
  1960.     }
  1961.     /*
  1962.      * The code below makes a tiny increase in the shape parameters
  1963.      * for the line.  This is a bit of a hack, but it seems to result
  1964.      * in displays that more closely approximate the specified parameters.
  1965.      * Without the adjustment, the arrows come out smaller than expected.
  1966.      */
  1967.     shapeA = linePtr->arrowShapeA + 0.001;
  1968.     shapeB = linePtr->arrowShapeB + 0.001;
  1969.     shapeC = linePtr->arrowShapeC + width/2.0 + 0.001;
  1970.     /*
  1971.      * If there's an arrowhead on the first point of the line, compute
  1972.      * its polygon and adjust the first point of the line so that the
  1973.      * line doesn't stick out past the leading edge of the arrowhead.
  1974.      */
  1975.     fracHeight = (width/2.0)/shapeC;
  1976.     backup = fracHeight*shapeB + shapeA*(1.0 - fracHeight)/2.0;
  1977.     if (linePtr->arrow != ARROWS_LAST) {
  1978. poly = linePtr->firstArrowPtr;
  1979. if (poly == NULL) {
  1980.     poly = (double *) ckalloc((unsigned)
  1981.     (2*PTS_IN_ARROW*sizeof(double)));
  1982.     poly[0] = poly[10] = linePtr->coordPtr[0];
  1983.     poly[1] = poly[11] = linePtr->coordPtr[1];
  1984.     linePtr->firstArrowPtr = poly;
  1985. }
  1986. dx = poly[0] - linePtr->coordPtr[2];
  1987. dy = poly[1] - linePtr->coordPtr[3];
  1988. length = hypot(dx, dy);
  1989. if (length == 0) {
  1990.     sinTheta = cosTheta = 0.0;
  1991. } else {
  1992.     sinTheta = dy/length;
  1993.     cosTheta = dx/length;
  1994. }
  1995. vertX = poly[0] - shapeA*cosTheta;
  1996. vertY = poly[1] - shapeA*sinTheta;
  1997. temp = shapeC*sinTheta;
  1998. poly[2] = poly[0] - shapeB*cosTheta + temp;
  1999. poly[8] = poly[2] - 2*temp;
  2000. temp = shapeC*cosTheta;
  2001. poly[3] = poly[1] - shapeB*sinTheta - temp;
  2002. poly[9] = poly[3] + 2*temp;
  2003. poly[4] = poly[2]*fracHeight + vertX*(1.0-fracHeight);
  2004. poly[5] = poly[3]*fracHeight + vertY*(1.0-fracHeight);
  2005. poly[6] = poly[8]*fracHeight + vertX*(1.0-fracHeight);
  2006. poly[7] = poly[9]*fracHeight + vertY*(1.0-fracHeight);
  2007. /*
  2008.  * Polygon done.  Now move the first point towards the second so
  2009.  * that the corners at the end of the line are inside the
  2010.  * arrowhead.
  2011.  */
  2012. linePtr->coordPtr[0] = poly[0] - backup*cosTheta;
  2013. linePtr->coordPtr[1] = poly[1] - backup*sinTheta;
  2014.     }
  2015.     /*
  2016.      * Similar arrowhead calculation for the last point of the line.
  2017.      */
  2018.     if (linePtr->arrow != ARROWS_FIRST) {
  2019. coordPtr = linePtr->coordPtr + 2*(linePtr->numPoints-2);
  2020. poly = linePtr->lastArrowPtr;
  2021. if (poly == NULL) {
  2022.     poly = (double *) ckalloc((unsigned)
  2023.     (2*PTS_IN_ARROW*sizeof(double)));
  2024.     poly[0] = poly[10] = coordPtr[2];
  2025.     poly[1] = poly[11] = coordPtr[3];
  2026.     linePtr->lastArrowPtr = poly;
  2027. }
  2028. dx = poly[0] - coordPtr[0];
  2029. dy = poly[1] - coordPtr[1];
  2030. length = hypot(dx, dy);
  2031. if (length == 0) {
  2032.     sinTheta = cosTheta = 0.0;
  2033. } else {
  2034.     sinTheta = dy/length;
  2035.     cosTheta = dx/length;
  2036. }
  2037. vertX = poly[0] - shapeA*cosTheta;
  2038. vertY = poly[1] - shapeA*sinTheta;
  2039. temp = shapeC*sinTheta;
  2040. poly[2] = poly[0] - shapeB*cosTheta + temp;
  2041. poly[8] = poly[2] - 2*temp;
  2042. temp = shapeC*cosTheta;
  2043. poly[3] = poly[1] - shapeB*sinTheta - temp;
  2044. poly[9] = poly[3] + 2*temp;
  2045. poly[4] = poly[2]*fracHeight + vertX*(1.0-fracHeight);
  2046. poly[5] = poly[3]*fracHeight + vertY*(1.0-fracHeight);
  2047. poly[6] = poly[8]*fracHeight + vertX*(1.0-fracHeight);
  2048. poly[7] = poly[9]*fracHeight + vertY*(1.0-fracHeight);
  2049. coordPtr[2] = poly[0] - backup*cosTheta;
  2050. coordPtr[3] = poly[1] - backup*sinTheta;
  2051.     }
  2052.     return TCL_OK;
  2053. }
  2054. /*
  2055.  *--------------------------------------------------------------
  2056.  *
  2057.  * LineToPostscript --
  2058.  *
  2059.  * This procedure is called to generate Postscript for
  2060.  * line items.
  2061.  *
  2062.  * Results:
  2063.  * The return value is a standard Tcl result.  If an error
  2064.  * occurs in generating Postscript then an error message is
  2065.  * left in the interp's result, replacing whatever used
  2066.  * to be there.  If no error occurs, then Postscript for the
  2067.  * item is appended to the result.
  2068.  *
  2069.  * Side effects:
  2070.  * None.
  2071.  *
  2072.  *--------------------------------------------------------------
  2073.  */
  2074. static int
  2075. LineToPostscript(interp, canvas, itemPtr, prepass)
  2076.     Tcl_Interp *interp; /* Leave Postscript or error message
  2077.  * here. */
  2078.     Tk_Canvas canvas; /* Information about overall canvas. */
  2079.     Tk_Item *itemPtr; /* Item for which Postscript is
  2080.  * wanted. */
  2081.     int prepass; /* 1 means this is a prepass to
  2082.  * collect font information;  0 means
  2083.  * final Postscript is being created. */
  2084. {
  2085.     LineItem *linePtr = (LineItem *) itemPtr;
  2086.     char buffer[64 + TCL_INTEGER_SPACE];
  2087.     char *style;
  2088.     double width;
  2089.     XColor *color;
  2090.     Pixmap stipple;
  2091.     Tk_State state = itemPtr->state;
  2092.     if(state == TK_STATE_NULL) {
  2093. state = ((TkCanvas *)canvas)->canvas_state;
  2094.     }
  2095.     width = linePtr->outline.width;
  2096.     color = linePtr->outline.color;
  2097.     stipple = linePtr->outline.stipple;
  2098.     if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
  2099. if (linePtr->outline.activeWidth>width) {
  2100.     width = linePtr->outline.activeWidth;
  2101. }
  2102. if (linePtr->outline.activeColor!=NULL) {
  2103.     color = linePtr->outline.activeColor;
  2104. }
  2105. if (linePtr->outline.activeStipple!=None) {
  2106.     stipple = linePtr->outline.activeStipple;
  2107. }
  2108.     } else if (state==TK_STATE_DISABLED) {
  2109. if (linePtr->outline.disabledWidth>0) {
  2110.     width = linePtr->outline.disabledWidth;
  2111. }
  2112. if (linePtr->outline.disabledColor!=NULL) {
  2113.     color = linePtr->outline.disabledColor;
  2114. }
  2115. if (linePtr->outline.disabledStipple!=None) {
  2116.     stipple = linePtr->outline.disabledStipple;
  2117. }
  2118.     }
  2119.     if (color == NULL || linePtr->numPoints<1 || linePtr->coordPtr==NULL) {
  2120. return TCL_OK;
  2121.     }
  2122.     if (linePtr->numPoints==1) {
  2123. sprintf(buffer, "%.15g %.15g translate %.15g %.15g",
  2124. linePtr->coordPtr[0], Tk_CanvasPsY(canvas, linePtr->coordPtr[1]),
  2125. width/2.0, width/2.0);
  2126. Tcl_AppendResult(interp, "matrix currentmatrixn",buffer,
  2127. " scale 1 0 moveto 0 0 1 0 360 arcnsetmatrixn", (char *) NULL);
  2128. if (Tk_CanvasPsColor(interp, canvas, color)
  2129. != TCL_OK) {
  2130.     return TCL_ERROR;
  2131. }
  2132. if (stipple != None) {
  2133.     Tcl_AppendResult(interp, "clip ", (char *) NULL);
  2134.     if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) {
  2135. return TCL_ERROR;
  2136.     }
  2137. } else {
  2138.     Tcl_AppendResult(interp, "filln", (char *) NULL);
  2139. }
  2140. return TCL_OK;
  2141.     }
  2142.     /*
  2143.      * Generate a path for the line's center-line (do this differently
  2144.      * for straight lines and smoothed lines).
  2145.      */
  2146.     if ((!linePtr->smooth) || (linePtr->numPoints < 3)) {
  2147. Tk_CanvasPsPath(interp, canvas, linePtr->coordPtr, linePtr->numPoints);
  2148.     } else {
  2149. if ((stipple == None) && linePtr->smooth->postscriptProc) {
  2150.     linePtr->smooth->postscriptProc(interp, canvas,
  2151.     linePtr->coordPtr, linePtr->numPoints, linePtr->splineSteps);
  2152. } else {
  2153.     /*
  2154.      * Special hack: Postscript printers don't appear to be able
  2155.      * to turn a path drawn with "curveto"s into a clipping path
  2156.      * without exceeding resource limits, so TkMakeBezierPostscript
  2157.      * won't work for stippled curves.  Instead, generate all of
  2158.      * the intermediate points here and output them into the
  2159.      * Postscript file with "lineto"s instead.
  2160.      */
  2161.     double staticPoints[2*MAX_STATIC_POINTS];
  2162.     double *pointPtr;
  2163.     int numPoints;
  2164.     numPoints = linePtr->smooth->coordProc(canvas, (double *) NULL,
  2165.     linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL,
  2166.     (double *) NULL);
  2167.     pointPtr = staticPoints;
  2168.     if (numPoints > MAX_STATIC_POINTS) {
  2169. pointPtr = (double *) ckalloc((unsigned)
  2170. (numPoints * 2 * sizeof(double)));
  2171.     }
  2172.     numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr,
  2173.     linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL,
  2174.     pointPtr);
  2175.     Tk_CanvasPsPath(interp, canvas, pointPtr, numPoints);
  2176.     if (pointPtr != staticPoints) {
  2177. ckfree((char *) pointPtr);
  2178.     }
  2179. }
  2180.     }
  2181.     /*
  2182.      * Set other line-drawing parameters and stroke out the line.
  2183.      */
  2184.     style = "0 setlinecapn";
  2185.     if (linePtr->capStyle == CapRound) {
  2186. style = "1 setlinecapn";
  2187.     } else if (linePtr->capStyle == CapProjecting) {
  2188. style = "2 setlinecapn";
  2189.     }
  2190.     Tcl_AppendResult(interp, style, (char *) NULL);
  2191.     style = "0 setlinejoinn";
  2192.     if (linePtr->joinStyle == JoinRound) {
  2193. style = "1 setlinejoinn";
  2194.     } else if (linePtr->joinStyle == JoinBevel) {
  2195. style = "2 setlinejoinn";
  2196.     }
  2197.     Tcl_AppendResult(interp, style, (char *) NULL);
  2198.     if (Tk_CanvasPsOutline(canvas, itemPtr,
  2199.     &(linePtr->outline)) != TCL_OK) {
  2200. return TCL_ERROR;
  2201.     }
  2202.     /*
  2203.      * Output polygons for the arrowheads, if there are any.
  2204.      */
  2205.     if (linePtr->firstArrowPtr != NULL) {
  2206. if (stipple != None) {
  2207.     Tcl_AppendResult(interp, "grestore gsaven",
  2208.     (char *) NULL);
  2209. }
  2210. if (ArrowheadPostscript(interp, canvas, linePtr,
  2211. linePtr->firstArrowPtr) != TCL_OK) {
  2212.     return TCL_ERROR;
  2213. }
  2214.     }
  2215.     if (linePtr->lastArrowPtr != NULL) {
  2216. if (stipple != None) {
  2217.     Tcl_AppendResult(interp, "grestore gsaven", (char *) NULL);
  2218. }
  2219. if (ArrowheadPostscript(interp, canvas, linePtr,
  2220. linePtr->lastArrowPtr) != TCL_OK) {
  2221.     return TCL_ERROR;
  2222. }
  2223.     }
  2224.     return TCL_OK;
  2225. }
  2226. /*
  2227.  *--------------------------------------------------------------
  2228.  *
  2229.  * ArrowheadPostscript --
  2230.  *
  2231.  * This procedure is called to generate Postscript for
  2232.  * an arrowhead for a line item.
  2233.  *
  2234.  * Results:
  2235.  * The return value is a standard Tcl result.  If an error
  2236.  * occurs in generating Postscript then an error message is
  2237.  * left in the interp's result, replacing whatever used
  2238.  * to be there.  If no error occurs, then Postscript for the
  2239.  * arrowhead is appended to the result.
  2240.  *
  2241.  * Side effects:
  2242.  * None.
  2243.  *
  2244.  *--------------------------------------------------------------
  2245.  */
  2246. static int
  2247. ArrowheadPostscript(interp, canvas, linePtr, arrowPtr)
  2248.     Tcl_Interp *interp; /* Leave Postscript or error message
  2249.  * here. */
  2250.     Tk_Canvas canvas; /* Information about overall canvas. */
  2251.     LineItem *linePtr; /* Line item for which Postscript is
  2252.  * being generated. */
  2253.     double *arrowPtr; /* Pointer to first of five points
  2254.  * describing arrowhead polygon. */
  2255. {
  2256.     Pixmap stipple;
  2257.     Tk_State state = linePtr->header.state;
  2258.     if(state == TK_STATE_NULL) {
  2259. state = ((TkCanvas *)canvas)->canvas_state;
  2260.     }
  2261.     stipple = linePtr->outline.stipple;
  2262.     if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)linePtr) {
  2263. if (linePtr->outline.activeStipple!=None) {
  2264.     stipple = linePtr->outline.activeStipple;
  2265. }
  2266.     } else if (state==TK_STATE_DISABLED) {
  2267. if (linePtr->outline.activeStipple!=None) {
  2268.     stipple = linePtr->outline.disabledStipple;
  2269. }
  2270.     }
  2271.     Tk_CanvasPsPath(interp, canvas, arrowPtr, PTS_IN_ARROW);
  2272.     if (stipple != None) {
  2273. Tcl_AppendResult(interp, "clip ", (char *) NULL);
  2274. if (Tk_CanvasPsStipple(interp, canvas, stipple)
  2275. != TCL_OK) {
  2276.     return TCL_ERROR;
  2277. }
  2278.     } else {
  2279. Tcl_AppendResult(interp, "filln", (char *) NULL);
  2280.     }
  2281.     return TCL_OK;
  2282. }