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

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkcanvline.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 71 - (show annotations) (download)
Sat Nov 5 11:07:06 2016 UTC (8 years, 1 month ago) by dashley
File MIME type: text/plain
File size: 74552 byte(s)
Set EOL properties appropriately to facilitate simultaneous Linux and Windows development.
1 /* $Header$ */
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 /* End of tkcanvline.c */

Properties

Name Value
svn:eol-style native
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25