/[dtapublic]/projs/trunk/shared_source/tk_base/tkcanvline.c
ViewVC logotype

Annotation of /projs/trunk/shared_source/tk_base/tkcanvline.c

Parent Directory Parent Directory | Revision Log Revision Log


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

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25