1/* 2 * tkCanvPoly.c -- 3 * 4 * This file implements polygon items for canvas widgets. 5 * 6 * Copyright (c) 1991-1994 The Regents of the University of California. 7 * Copyright (c) 1994-1997 Sun Microsystems, Inc. 8 * Copyright (c) 1998-2000 Ajuba Solutions. 9 * 10 * See the file "license.terms" for information on usage and redistribution 11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 12 * 13 * RCS: @(#) $Id: tkCanvPoly.c,v 1.10.2.3 2006/10/16 15:35:50 das Exp $ 14 */ 15 16#include <stdio.h> 17#include "tkInt.h" 18#include "tkPort.h" 19#include "tkCanvas.h" 20 21/* 22 * The structure below defines the record for each polygon item. 23 */ 24 25typedef struct PolygonItem { 26 Tk_Item header; /* Generic stuff that's the same for all 27 * types. MUST BE FIRST IN STRUCTURE. */ 28 Tk_Outline outline; /* Outline structure */ 29 int numPoints; /* Number of points in polygon. 30 * Polygon is always closed. */ 31 int pointsAllocated; /* Number of points for which space is 32 * allocated at *coordPtr. */ 33 double *coordPtr; /* Pointer to malloc-ed array containing 34 * x- and y-coords of all points in polygon. 35 * X-coords are even-valued indices, y-coords 36 * are corresponding odd-valued indices. */ 37 int joinStyle; /* Join style for outline */ 38 Tk_TSOffset tsoffset; 39 XColor *fillColor; /* Foreground color for polygon. */ 40 XColor *activeFillColor; /* Foreground color for polygon if state is active. */ 41 XColor *disabledFillColor; /* Foreground color for polygon if state is disabled. */ 42 Pixmap fillStipple; /* Stipple bitmap for filling polygon. */ 43 Pixmap activeFillStipple; /* Stipple bitmap for filling polygon if state is active. */ 44 Pixmap disabledFillStipple; /* Stipple bitmap for filling polygon if state is disabled. */ 45 GC fillGC; /* Graphics context for filling polygon. */ 46 Tk_SmoothMethod *smooth; /* Non-zero means draw shape smoothed (i.e. 47 * with Bezier splines). */ 48 int splineSteps; /* Number of steps in each spline segment. */ 49 int autoClosed; /* Zero means the given polygon was closed, 50 one means that we auto closed it. */ 51} PolygonItem; 52 53/* 54 * Information used for parsing configuration specs: 55 */ 56 57static Tk_CustomOption smoothOption = { 58 (Tk_OptionParseProc *) TkSmoothParseProc, 59 TkSmoothPrintProc, (ClientData) NULL 60}; 61static Tk_CustomOption stateOption = { 62 (Tk_OptionParseProc *) TkStateParseProc, 63 TkStatePrintProc, (ClientData) 2 64}; 65static Tk_CustomOption tagsOption = { 66 (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, 67 Tk_CanvasTagsPrintProc, (ClientData) NULL 68}; 69static Tk_CustomOption dashOption = { 70 (Tk_OptionParseProc *) TkCanvasDashParseProc, 71 TkCanvasDashPrintProc, (ClientData) NULL 72}; 73static Tk_CustomOption offsetOption = { 74 (Tk_OptionParseProc *) TkOffsetParseProc, 75 TkOffsetPrintProc, 76 (ClientData) (TK_OFFSET_RELATIVE|TK_OFFSET_INDEX) 77}; 78static Tk_CustomOption pixelOption = { 79 (Tk_OptionParseProc *) TkPixelParseProc, 80 TkPixelPrintProc, (ClientData) NULL 81}; 82 83static Tk_ConfigSpec configSpecs[] = { 84 {TK_CONFIG_CUSTOM, "-activedash", (char *) NULL, (char *) NULL, 85 (char *) NULL, Tk_Offset(PolygonItem, outline.activeDash), 86 TK_CONFIG_NULL_OK, &dashOption}, 87 {TK_CONFIG_COLOR, "-activefill", (char *) NULL, (char *) NULL, 88 (char *) NULL, Tk_Offset(PolygonItem, activeFillColor), 89 TK_CONFIG_NULL_OK}, 90 {TK_CONFIG_COLOR, "-activeoutline", (char *) NULL, (char *) NULL, 91 (char *) NULL, Tk_Offset(PolygonItem, outline.activeColor), 92 TK_CONFIG_NULL_OK}, 93 {TK_CONFIG_BITMAP, "-activeoutlinestipple", (char *) NULL, (char *) NULL, 94 (char *) NULL, Tk_Offset(PolygonItem, outline.activeStipple), 95 TK_CONFIG_NULL_OK}, 96 {TK_CONFIG_BITMAP, "-activestipple", (char *) NULL, (char *) NULL, 97 (char *) NULL, Tk_Offset(PolygonItem, activeFillStipple), 98 TK_CONFIG_NULL_OK}, 99 {TK_CONFIG_CUSTOM, "-activewidth", (char *) NULL, (char *) NULL, 100 "0.0", Tk_Offset(PolygonItem, outline.activeWidth), 101 TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, 102 {TK_CONFIG_CUSTOM, "-dash", (char *) NULL, (char *) NULL, 103 (char *) NULL, Tk_Offset(PolygonItem, outline.dash), 104 TK_CONFIG_NULL_OK, &dashOption}, 105 {TK_CONFIG_PIXELS, "-dashoffset", (char *) NULL, (char *) NULL, 106 "0", Tk_Offset(PolygonItem, outline.offset), 107 TK_CONFIG_DONT_SET_DEFAULT}, 108 {TK_CONFIG_CUSTOM, "-disableddash", (char *) NULL, (char *) NULL, 109 (char *) NULL, Tk_Offset(PolygonItem, outline.disabledDash), 110 TK_CONFIG_NULL_OK, &dashOption}, 111 {TK_CONFIG_COLOR, "-disabledfill", (char *) NULL, (char *) NULL, 112 (char *) NULL, Tk_Offset(PolygonItem, disabledFillColor), 113 TK_CONFIG_NULL_OK}, 114 {TK_CONFIG_COLOR, "-disabledoutline", (char *) NULL, (char *) NULL, 115 (char *) NULL, Tk_Offset(PolygonItem, outline.disabledColor), 116 TK_CONFIG_NULL_OK}, 117 {TK_CONFIG_BITMAP, "-disabledoutlinestipple", (char *) NULL, (char *) NULL, 118 (char *) NULL, Tk_Offset(PolygonItem, outline.disabledStipple), 119 TK_CONFIG_NULL_OK}, 120 {TK_CONFIG_BITMAP, "-disabledstipple", (char *) NULL, (char *) NULL, 121 (char *) NULL, Tk_Offset(PolygonItem, disabledFillStipple), 122 TK_CONFIG_NULL_OK}, 123 {TK_CONFIG_CUSTOM, "-disabledwidth", (char *) NULL, (char *) NULL, 124 "0.0", Tk_Offset(PolygonItem, outline.disabledWidth), 125 TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, 126 {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, 127 "black", Tk_Offset(PolygonItem, fillColor), TK_CONFIG_NULL_OK}, 128 {TK_CONFIG_JOIN_STYLE, "-joinstyle", (char *) NULL, (char *) NULL, 129 "round", Tk_Offset(PolygonItem, joinStyle), TK_CONFIG_DONT_SET_DEFAULT}, 130 {TK_CONFIG_CUSTOM, "-offset", (char *) NULL, (char *) NULL, 131 "0,0", Tk_Offset(PolygonItem, tsoffset), 132 TK_CONFIG_NULL_OK, &offsetOption}, 133 {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL, 134 (char *) NULL, Tk_Offset(PolygonItem, outline.color), 135 TK_CONFIG_NULL_OK}, 136 {TK_CONFIG_CUSTOM, "-outlineoffset", (char *) NULL, (char *) NULL, 137 "0,0", Tk_Offset(PolygonItem, outline.tsoffset), 138 TK_CONFIG_NULL_OK, &offsetOption}, 139 {TK_CONFIG_BITMAP, "-outlinestipple", (char *) NULL, (char *) NULL, 140 (char *) NULL, Tk_Offset(PolygonItem, outline.stipple), 141 TK_CONFIG_NULL_OK}, 142 {TK_CONFIG_CUSTOM, "-smooth", (char *) NULL, (char *) NULL, 143 "0", Tk_Offset(PolygonItem, smooth), 144 TK_CONFIG_DONT_SET_DEFAULT, &smoothOption}, 145 {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL, 146 "12", Tk_Offset(PolygonItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT}, 147 {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, 148 (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, 149 &stateOption}, 150 {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, 151 (char *) NULL, Tk_Offset(PolygonItem, fillStipple), TK_CONFIG_NULL_OK}, 152 {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, 153 (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, 154 {TK_CONFIG_CUSTOM, "-width", (char *) NULL, (char *) NULL, 155 "1.0", Tk_Offset(PolygonItem, outline.width), 156 TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, 157 {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, 158 (char *) NULL, 0, 0} 159}; 160 161/* 162 * Prototypes for procedures defined in this file: 163 */ 164 165static void ComputePolygonBbox _ANSI_ARGS_((Tk_Canvas canvas, 166 PolygonItem *polyPtr)); 167static int ConfigurePolygon _ANSI_ARGS_((Tcl_Interp *interp, 168 Tk_Canvas canvas, Tk_Item *itemPtr, int objc, 169 Tcl_Obj *CONST objv[], int flags)); 170static int CreatePolygon _ANSI_ARGS_((Tcl_Interp *interp, 171 Tk_Canvas canvas, struct Tk_Item *itemPtr, 172 int objc, Tcl_Obj *CONST objv[])); 173static void DeletePolygon _ANSI_ARGS_((Tk_Canvas canvas, 174 Tk_Item *itemPtr, Display *display)); 175static void DisplayPolygon _ANSI_ARGS_((Tk_Canvas canvas, 176 Tk_Item *itemPtr, Display *display, Drawable dst, 177 int x, int y, int width, int height)); 178static int GetPolygonIndex _ANSI_ARGS_((Tcl_Interp *interp, 179 Tk_Canvas canvas, Tk_Item *itemPtr, 180 Tcl_Obj *obj, int *indexPtr)); 181static int PolygonCoords _ANSI_ARGS_((Tcl_Interp *interp, 182 Tk_Canvas canvas, Tk_Item *itemPtr, 183 int objc, Tcl_Obj *CONST objv[])); 184static void PolygonDeleteCoords _ANSI_ARGS_((Tk_Canvas canvas, 185 Tk_Item *itemPtr, int first, int last)); 186static void PolygonInsert _ANSI_ARGS_((Tk_Canvas canvas, 187 Tk_Item *itemPtr, int beforeThis, Tcl_Obj *obj)); 188static int PolygonToArea _ANSI_ARGS_((Tk_Canvas canvas, 189 Tk_Item *itemPtr, double *rectPtr)); 190static double PolygonToPoint _ANSI_ARGS_((Tk_Canvas canvas, 191 Tk_Item *itemPtr, double *pointPtr)); 192static int PolygonToPostscript _ANSI_ARGS_((Tcl_Interp *interp, 193 Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); 194static void ScalePolygon _ANSI_ARGS_((Tk_Canvas canvas, 195 Tk_Item *itemPtr, double originX, double originY, 196 double scaleX, double scaleY)); 197static void TranslatePolygon _ANSI_ARGS_((Tk_Canvas canvas, 198 Tk_Item *itemPtr, double deltaX, double deltaY)); 199 200/* 201 * The structures below defines the polygon item type by means 202 * of procedures that can be invoked by generic item code. 203 */ 204 205Tk_ItemType tkPolygonType = { 206 "polygon", /* name */ 207 sizeof(PolygonItem), /* itemSize */ 208 CreatePolygon, /* createProc */ 209 configSpecs, /* configSpecs */ 210 ConfigurePolygon, /* configureProc */ 211 PolygonCoords, /* coordProc */ 212 DeletePolygon, /* deleteProc */ 213 DisplayPolygon, /* displayProc */ 214 TK_CONFIG_OBJS, /* flags */ 215 PolygonToPoint, /* pointProc */ 216 PolygonToArea, /* areaProc */ 217 PolygonToPostscript, /* postscriptProc */ 218 ScalePolygon, /* scaleProc */ 219 TranslatePolygon, /* translateProc */ 220 (Tk_ItemIndexProc *) GetPolygonIndex,/* indexProc */ 221 (Tk_ItemCursorProc *) NULL, /* icursorProc */ 222 (Tk_ItemSelectionProc *) NULL, /* selectionProc */ 223 (Tk_ItemInsertProc *) PolygonInsert,/* insertProc */ 224 PolygonDeleteCoords, /* dTextProc */ 225 (Tk_ItemType *) NULL, /* nextPtr */ 226}; 227 228/* 229 * The definition below determines how large are static arrays 230 * used to hold spline points (splines larger than this have to 231 * have their arrays malloc-ed). 232 */ 233 234#define MAX_STATIC_POINTS 200 235 236/* 237 *-------------------------------------------------------------- 238 * 239 * CreatePolygon -- 240 * 241 * This procedure is invoked to create a new polygon item in 242 * a canvas. 243 * 244 * Results: 245 * A standard Tcl return value. If an error occurred in 246 * creating the item, then an error message is left in 247 * the interp's result; in this case itemPtr is 248 * left uninitialized, so it can be safely freed by the 249 * caller. 250 * 251 * Side effects: 252 * A new polygon item is created. 253 * 254 *-------------------------------------------------------------- 255 */ 256 257static int 258CreatePolygon(interp, canvas, itemPtr, objc, objv) 259 Tcl_Interp *interp; /* Interpreter for error reporting. */ 260 Tk_Canvas canvas; /* Canvas to hold new item. */ 261 Tk_Item *itemPtr; /* Record to hold new item; header 262 * has been initialized by caller. */ 263 int objc; /* Number of arguments in objv. */ 264 Tcl_Obj *CONST objv[]; /* Arguments describing polygon. */ 265{ 266 PolygonItem *polyPtr = (PolygonItem *) itemPtr; 267 int i; 268 269 if (objc == 0) { 270 panic("canvas did not pass any coords\n"); 271 } 272 273 /* 274 * Carry out initialization that is needed in order to clean 275 * up after errors during the the remainder of this procedure. 276 */ 277 278 Tk_CreateOutline(&(polyPtr->outline)); 279 polyPtr->numPoints = 0; 280 polyPtr->pointsAllocated = 0; 281 polyPtr->coordPtr = NULL; 282 polyPtr->joinStyle = JoinRound; 283 polyPtr->tsoffset.flags = 0; 284 polyPtr->tsoffset.xoffset = 0; 285 polyPtr->tsoffset.yoffset = 0; 286 polyPtr->fillColor = NULL; 287 polyPtr->activeFillColor = NULL; 288 polyPtr->disabledFillColor = NULL; 289 polyPtr->fillStipple = None; 290 polyPtr->activeFillStipple = None; 291 polyPtr->disabledFillStipple = None; 292 polyPtr->fillGC = None; 293 polyPtr->smooth = (Tk_SmoothMethod *) NULL; 294 polyPtr->splineSteps = 12; 295 polyPtr->autoClosed = 0; 296 297 /* 298 * Count the number of points and then parse them into a point 299 * array. Leading arguments are assumed to be points if they 300 * start with a digit or a minus sign followed by a digit. 301 */ 302 303 for (i = 0; i < objc; i++) { 304 char *arg = Tcl_GetString(objv[i]); 305 if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { 306 break; 307 } 308 } 309 if (i && PolygonCoords(interp, canvas, itemPtr, i, objv) != TCL_OK) { 310 goto error; 311 } 312 313 if (ConfigurePolygon(interp, canvas, itemPtr, objc-i, objv+i, 0) 314 == TCL_OK) { 315 return TCL_OK; 316 } 317 318 error: 319 DeletePolygon(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); 320 return TCL_ERROR; 321} 322 323/* 324 *-------------------------------------------------------------- 325 * 326 * PolygonCoords -- 327 * 328 * This procedure is invoked to process the "coords" widget 329 * command on polygons. See the user documentation for details 330 * on what it does. 331 * 332 * Results: 333 * Returns TCL_OK or TCL_ERROR, and sets the interp's result. 334 * 335 * Side effects: 336 * The coordinates for the given item may be changed. 337 * 338 *-------------------------------------------------------------- 339 */ 340 341static int 342PolygonCoords(interp, canvas, itemPtr, objc, objv) 343 Tcl_Interp *interp; /* Used for error reporting. */ 344 Tk_Canvas canvas; /* Canvas containing item. */ 345 Tk_Item *itemPtr; /* Item whose coordinates are to be 346 * read or modified. */ 347 int objc; /* Number of coordinates supplied in 348 * objv. */ 349 Tcl_Obj *CONST objv[]; /* Array of coordinates: x1, y1, 350 * x2, y2, ... */ 351{ 352 PolygonItem *polyPtr = (PolygonItem *) itemPtr; 353 int i, numPoints; 354 355 if (objc == 0) { 356 /* 357 * Print the coords used to create the polygon. If we auto 358 * closed the polygon then we don't report the last point. 359 */ 360 Tcl_Obj *subobj, *obj = Tcl_NewObj(); 361 for (i = 0; i < 2*(polyPtr->numPoints - polyPtr->autoClosed); i++) { 362 subobj = Tcl_NewDoubleObj(polyPtr->coordPtr[i]); 363 Tcl_ListObjAppendElement(interp, obj, subobj); 364 } 365 Tcl_SetObjResult(interp, obj); 366 return TCL_OK; 367 } 368 if (objc == 1) { 369 if (Tcl_ListObjGetElements(interp, objv[0], &objc, 370 (Tcl_Obj ***) &objv) != TCL_OK) { 371 return TCL_ERROR; 372 } 373 } 374 if (objc & 1) { 375 char buf[64 + TCL_INTEGER_SPACE]; 376 sprintf(buf, "wrong # coordinates: expected an even number, got %d", 377 objc); 378 Tcl_SetResult(interp, buf, TCL_VOLATILE); 379 return TCL_ERROR; 380 } else { 381 numPoints = objc/2; 382 if (polyPtr->pointsAllocated <= numPoints) { 383 if (polyPtr->coordPtr != NULL) { 384 ckfree((char *) polyPtr->coordPtr); 385 } 386 387 /* 388 * One extra point gets allocated here, because we always 389 * add another point to close the polygon. 390 */ 391 392 polyPtr->coordPtr = (double *) ckalloc((unsigned) 393 (sizeof(double) * (objc+2))); 394 polyPtr->pointsAllocated = numPoints+1; 395 } 396 for (i = objc-1; i >= 0; i--) { 397 if (Tk_CanvasGetCoordFromObj(interp, canvas, objv[i], 398 &polyPtr->coordPtr[i]) != TCL_OK) { 399 return TCL_ERROR; 400 } 401 } 402 polyPtr->numPoints = numPoints; 403 polyPtr->autoClosed = 0; 404 405 /* 406 * Close the polygon if it isn't already closed. 407 */ 408 409 if (objc>2 && ((polyPtr->coordPtr[objc-2] != polyPtr->coordPtr[0]) 410 || (polyPtr->coordPtr[objc-1] != polyPtr->coordPtr[1]))) { 411 polyPtr->autoClosed = 1; 412 polyPtr->numPoints++; 413 polyPtr->coordPtr[objc] = polyPtr->coordPtr[0]; 414 polyPtr->coordPtr[objc+1] = polyPtr->coordPtr[1]; 415 } 416 ComputePolygonBbox(canvas, polyPtr); 417 } 418 return TCL_OK; 419} 420 421/* 422 *-------------------------------------------------------------- 423 * 424 * ConfigurePolygon -- 425 * 426 * This procedure is invoked to configure various aspects 427 * of a polygon item such as its background color. 428 * 429 * Results: 430 * A standard Tcl result code. If an error occurs, then 431 * an error message is left in the interp's result. 432 * 433 * Side effects: 434 * Configuration information, such as colors and stipple 435 * patterns, may be set for itemPtr. 436 * 437 *-------------------------------------------------------------- 438 */ 439 440static int 441ConfigurePolygon(interp, canvas, itemPtr, objc, objv, flags) 442 Tcl_Interp *interp; /* Interpreter for error reporting. */ 443 Tk_Canvas canvas; /* Canvas containing itemPtr. */ 444 Tk_Item *itemPtr; /* Polygon item to reconfigure. */ 445 int objc; /* Number of elements in objv. */ 446 Tcl_Obj *CONST objv[]; /* Arguments describing things to configure. */ 447 int flags; /* Flags to pass to Tk_ConfigureWidget. */ 448{ 449 PolygonItem *polyPtr = (PolygonItem *) itemPtr; 450 XGCValues gcValues; 451 GC newGC; 452 unsigned long mask; 453 Tk_Window tkwin; 454 XColor *color; 455 Pixmap stipple; 456 Tk_State state; 457 458 tkwin = Tk_CanvasTkwin(canvas); 459 if (TCL_OK != Tk_ConfigureWidget(interp, tkwin, configSpecs, objc, 460 (CONST char **) objv, (char *) polyPtr, flags|TK_CONFIG_OBJS)) { 461 return TCL_ERROR; 462 } 463 464 /* 465 * A few of the options require additional processing, such as 466 * graphics contexts. 467 */ 468 469 state = itemPtr->state; 470 471 if (polyPtr->outline.activeWidth > polyPtr->outline.width || 472 polyPtr->outline.activeDash.number != 0 || 473 polyPtr->outline.activeColor != NULL || 474 polyPtr->outline.activeStipple != None || 475 polyPtr->activeFillColor != NULL || 476 polyPtr->activeFillStipple != None) { 477 itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; 478 } else { 479 itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; 480 } 481 482 if(state == TK_STATE_NULL) { 483 state = ((TkCanvas *)canvas)->canvas_state; 484 } 485 if (state==TK_STATE_HIDDEN) { 486 ComputePolygonBbox(canvas, polyPtr); 487 return TCL_OK; 488 } 489 490 mask = Tk_ConfigOutlineGC(&gcValues, canvas, itemPtr, &(polyPtr->outline)); 491 if (mask) { 492 gcValues.cap_style = CapRound; 493 gcValues.join_style = polyPtr->joinStyle; 494 mask |= GCCapStyle|GCJoinStyle; 495 newGC = Tk_GetGC(tkwin, mask, &gcValues); 496 } else { 497 newGC = None; 498 } 499 if (polyPtr->outline.gc != None) { 500 Tk_FreeGC(Tk_Display(tkwin), polyPtr->outline.gc); 501 } 502 polyPtr->outline.gc = newGC; 503 504 color = polyPtr->fillColor; 505 stipple = polyPtr->fillStipple; 506 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 507 if (polyPtr->activeFillColor!=NULL) { 508 color = polyPtr->activeFillColor; 509 } 510 if (polyPtr->activeFillStipple!=None) { 511 stipple = polyPtr->activeFillStipple; 512 } 513 } else if (state==TK_STATE_DISABLED) { 514 if (polyPtr->disabledFillColor!=NULL) { 515 color = polyPtr->disabledFillColor; 516 } 517 if (polyPtr->disabledFillStipple!=None) { 518 stipple = polyPtr->disabledFillStipple; 519 } 520 } 521 522 if (color == NULL) { 523 newGC = None; 524 } else { 525 gcValues.foreground = color->pixel; 526 mask = GCForeground; 527 if (stipple != None) { 528 gcValues.stipple = stipple; 529 gcValues.fill_style = FillStippled; 530 mask |= GCStipple|GCFillStyle; 531 } 532#ifdef MAC_OSX_TK 533 /* 534 * Mac OS X CG drawing needs access to the outline linewidth 535 * even for fills (as linewidth controls antialiasing). 536 */ 537 gcValues.line_width = polyPtr->outline.gc != None ? 538 polyPtr->outline.gc->line_width : 0; 539 mask |= GCLineWidth; 540#endif 541 newGC = Tk_GetGC(tkwin, mask, &gcValues); 542 } 543 if (polyPtr->fillGC != None) { 544 Tk_FreeGC(Tk_Display(tkwin), polyPtr->fillGC); 545 } 546 polyPtr->fillGC = newGC; 547 548 /* 549 * Keep spline parameters within reasonable limits. 550 */ 551 552 if (polyPtr->splineSteps < 1) { 553 polyPtr->splineSteps = 1; 554 } else if (polyPtr->splineSteps > 100) { 555 polyPtr->splineSteps = 100; 556 } 557 558 ComputePolygonBbox(canvas, polyPtr); 559 return TCL_OK; 560} 561 562/* 563 *-------------------------------------------------------------- 564 * 565 * DeletePolygon -- 566 * 567 * This procedure is called to clean up the data structure 568 * associated with a polygon item. 569 * 570 * Results: 571 * None. 572 * 573 * Side effects: 574 * Resources associated with itemPtr are released. 575 * 576 *-------------------------------------------------------------- 577 */ 578 579static void 580DeletePolygon(canvas, itemPtr, display) 581 Tk_Canvas canvas; /* Info about overall canvas widget. */ 582 Tk_Item *itemPtr; /* Item that is being deleted. */ 583 Display *display; /* Display containing window for 584 * canvas. */ 585{ 586 PolygonItem *polyPtr = (PolygonItem *) itemPtr; 587 588 Tk_DeleteOutline(display,&(polyPtr->outline)); 589 if (polyPtr->coordPtr != NULL) { 590 ckfree((char *) polyPtr->coordPtr); 591 } 592 if (polyPtr->fillColor != NULL) { 593 Tk_FreeColor(polyPtr->fillColor); 594 } 595 if (polyPtr->activeFillColor != NULL) { 596 Tk_FreeColor(polyPtr->activeFillColor); 597 } 598 if (polyPtr->disabledFillColor != NULL) { 599 Tk_FreeColor(polyPtr->disabledFillColor); 600 } 601 if (polyPtr->fillStipple != None) { 602 Tk_FreeBitmap(display, polyPtr->fillStipple); 603 } 604 if (polyPtr->activeFillStipple != None) { 605 Tk_FreeBitmap(display, polyPtr->activeFillStipple); 606 } 607 if (polyPtr->disabledFillStipple != None) { 608 Tk_FreeBitmap(display, polyPtr->disabledFillStipple); 609 } 610 if (polyPtr->fillGC != None) { 611 Tk_FreeGC(display, polyPtr->fillGC); 612 } 613} 614 615/* 616 *-------------------------------------------------------------- 617 * 618 * ComputePolygonBbox -- 619 * 620 * This procedure is invoked to compute the bounding box of 621 * all the pixels that may be drawn as part of a polygon. 622 * 623 * Results: 624 * None. 625 * 626 * Side effects: 627 * The fields x1, y1, x2, and y2 are updated in the header 628 * for itemPtr. 629 * 630 *-------------------------------------------------------------- 631 */ 632 633static void 634ComputePolygonBbox(canvas, polyPtr) 635 Tk_Canvas canvas; /* Canvas that contains item. */ 636 PolygonItem *polyPtr; /* Item whose bbox is to be 637 * recomputed. */ 638{ 639 double *coordPtr; 640 int i; 641 double width; 642 Tk_State state = polyPtr->header.state; 643 Tk_TSOffset *tsoffset; 644 645 if(state == TK_STATE_NULL) { 646 state = ((TkCanvas *)canvas)->canvas_state; 647 } 648 width = polyPtr->outline.width; 649 if (polyPtr->coordPtr == NULL || (polyPtr->numPoints < 1) || (state==TK_STATE_HIDDEN)) { 650 polyPtr->header.x1 = polyPtr->header.x2 = 651 polyPtr->header.y1 = polyPtr->header.y2 = -1; 652 return; 653 } 654 if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)polyPtr) { 655 if (polyPtr->outline.activeWidth>width) { 656 width = polyPtr->outline.activeWidth; 657 } 658 } else if (state==TK_STATE_DISABLED) { 659 if (polyPtr->outline.disabledWidth>0.0) { 660 width = polyPtr->outline.disabledWidth; 661 } 662 } 663 664 coordPtr = polyPtr->coordPtr; 665 polyPtr->header.x1 = polyPtr->header.x2 = (int) *coordPtr; 666 polyPtr->header.y1 = polyPtr->header.y2 = (int) coordPtr[1]; 667 668 /* 669 * Compute the bounding box of all the points in the polygon, 670 * then expand in all directions by the outline's width to take 671 * care of butting or rounded corners and projecting or 672 * rounded caps. This expansion is an overestimate (worst-case 673 * is square root of two over two) but it's simple. Don't do 674 * anything special for curves. This causes an additional 675 * overestimate in the bounding box, but is faster. 676 */ 677 678 for (i = 1, coordPtr = polyPtr->coordPtr+2; i < polyPtr->numPoints-1; 679 i++, coordPtr += 2) { 680 TkIncludePoint((Tk_Item *) polyPtr, coordPtr); 681 } 682 683 tsoffset = &polyPtr->tsoffset; 684 if (tsoffset->flags & TK_OFFSET_INDEX) { 685 int index = tsoffset->flags & ~TK_OFFSET_INDEX; 686 if (tsoffset->flags == INT_MAX) { 687 index = (polyPtr->numPoints - polyPtr->autoClosed) * 2; 688 if (index < 0) { 689 index = 0; 690 } 691 } 692 index %= (polyPtr->numPoints - polyPtr->autoClosed) * 2; 693 if (index <0) { 694 index += (polyPtr->numPoints - polyPtr->autoClosed) * 2; 695 } 696 tsoffset->xoffset = (int) (polyPtr->coordPtr[index] + 0.5); 697 tsoffset->yoffset = (int) (polyPtr->coordPtr[index+1] + 0.5); 698 } else { 699 if (tsoffset->flags & TK_OFFSET_LEFT) { 700 tsoffset->xoffset = polyPtr->header.x1; 701 } else if (tsoffset->flags & TK_OFFSET_CENTER) { 702 tsoffset->xoffset = (polyPtr->header.x1 + polyPtr->header.x2)/2; 703 } else if (tsoffset->flags & TK_OFFSET_RIGHT) { 704 tsoffset->xoffset = polyPtr->header.x2; 705 } 706 if (tsoffset->flags & TK_OFFSET_TOP) { 707 tsoffset->yoffset = polyPtr->header.y1; 708 } else if (tsoffset->flags & TK_OFFSET_MIDDLE) { 709 tsoffset->yoffset = (polyPtr->header.y1 + polyPtr->header.y2)/2; 710 } else if (tsoffset->flags & TK_OFFSET_BOTTOM) { 711 tsoffset->yoffset = polyPtr->header.y2; 712 } 713 } 714 715 if (polyPtr->outline.gc != None) { 716 tsoffset = &polyPtr->outline.tsoffset; 717 if (tsoffset) { 718 if (tsoffset->flags & TK_OFFSET_INDEX) { 719 int index = tsoffset->flags & ~TK_OFFSET_INDEX; 720 if (tsoffset->flags == INT_MAX) { 721 index = (polyPtr->numPoints - 1) * 2; 722 } 723 index %= (polyPtr->numPoints - 1) * 2; 724 if (index <0) { 725 index += (polyPtr->numPoints - 1) * 2; 726 } 727 tsoffset->xoffset = (int) (polyPtr->coordPtr[index] + 0.5); 728 tsoffset->yoffset = (int) (polyPtr->coordPtr[index+1] + 0.5); 729 } else { 730 if (tsoffset->flags & TK_OFFSET_LEFT) { 731 tsoffset->xoffset = polyPtr->header.x1; 732 } else if (tsoffset->flags & TK_OFFSET_CENTER) { 733 tsoffset->xoffset = (polyPtr->header.x1 + polyPtr->header.x2)/2; 734 } else if (tsoffset->flags & TK_OFFSET_RIGHT) { 735 tsoffset->xoffset = polyPtr->header.x2; 736 } 737 if (tsoffset->flags & TK_OFFSET_TOP) { 738 tsoffset->yoffset = polyPtr->header.y1; 739 } else if (tsoffset->flags & TK_OFFSET_MIDDLE) { 740 tsoffset->yoffset = (polyPtr->header.y1 + polyPtr->header.y2)/2; 741 } else if (tsoffset->flags & TK_OFFSET_BOTTOM) { 742 tsoffset->yoffset = polyPtr->header.y2; 743 } 744 } 745 } 746 747 i = (int) ((width+1.5)/2.0); 748 polyPtr->header.x1 -= i; 749 polyPtr->header.x2 += i; 750 polyPtr->header.y1 -= i; 751 polyPtr->header.y2 += i; 752 753 /* 754 * For mitered lines, make a second pass through all the points. 755 * Compute the locations of the two miter vertex points and add 756 * those into the bounding box. 757 */ 758 759 if (polyPtr->joinStyle == JoinMiter) { 760 double miter[4]; 761 int j; 762 coordPtr = polyPtr->coordPtr; 763 if (polyPtr->numPoints>3) { 764 if (TkGetMiterPoints(coordPtr+2*(polyPtr->numPoints-2), 765 coordPtr, coordPtr+2, width, 766 miter, miter+2)) { 767 for (j = 0; j < 4; j += 2) { 768 TkIncludePoint((Tk_Item *) polyPtr, miter+j); 769 } 770 } 771 } 772 for (i = polyPtr->numPoints ; i >= 3; 773 i--, coordPtr += 2) { 774 775 if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, 776 width, miter, miter+2)) { 777 for (j = 0; j < 4; j += 2) { 778 TkIncludePoint((Tk_Item *) polyPtr, miter+j); 779 } 780 } 781 } 782 } 783 } 784 785 /* 786 * Add one more pixel of fudge factor just to be safe (e.g. 787 * X may round differently than we do). 788 */ 789 790 polyPtr->header.x1 -= 1; 791 polyPtr->header.x2 += 1; 792 polyPtr->header.y1 -= 1; 793 polyPtr->header.y2 += 1; 794} 795 796/* 797 *-------------------------------------------------------------- 798 * 799 * TkFillPolygon -- 800 * 801 * This procedure is invoked to convert a polygon to screen 802 * coordinates and display it using a particular GC. 803 * 804 * Results: 805 * None. 806 * 807 * Side effects: 808 * ItemPtr is drawn in drawable using the transformation 809 * information in canvas. 810 * 811 *-------------------------------------------------------------- 812 */ 813 814void 815TkFillPolygon(canvas, coordPtr, numPoints, display, drawable, gc, outlineGC) 816 Tk_Canvas canvas; /* Canvas whose coordinate system 817 * is to be used for drawing. */ 818 double *coordPtr; /* Array of coordinates for polygon: 819 * x1, y1, x2, y2, .... */ 820 int numPoints; /* Twice this many coordinates are 821 * present at *coordPtr. */ 822 Display *display; /* Display on which to draw polygon. */ 823 Drawable drawable; /* Pixmap or window in which to draw 824 * polygon. */ 825 GC gc; /* Graphics context for drawing. */ 826 GC outlineGC; /* If not None, use this to draw an 827 * outline around the polygon after 828 * filling it. */ 829{ 830 XPoint staticPoints[MAX_STATIC_POINTS]; 831 XPoint *pointPtr; 832 XPoint *pPtr; 833 int i; 834 835 /* 836 * Build up an array of points in screen coordinates. Use a 837 * static array unless the polygon has an enormous number of points; 838 * in this case, dynamically allocate an array. 839 */ 840 841 if (numPoints <= MAX_STATIC_POINTS) { 842 pointPtr = staticPoints; 843 } else { 844 pointPtr = (XPoint *) ckalloc((unsigned) (numPoints * sizeof(XPoint))); 845 } 846 847 for (i = 0, pPtr = pointPtr; i < numPoints; i += 1, coordPtr += 2, pPtr++) { 848 Tk_CanvasDrawableCoords(canvas, coordPtr[0], coordPtr[1], &pPtr->x, 849 &pPtr->y); 850 } 851 852 /* 853 * Display polygon, then free up polygon storage if it was dynamically 854 * allocated. 855 */ 856 857 if (gc != None && numPoints>3) { 858 XFillPolygon(display, drawable, gc, pointPtr, numPoints, Complex, 859 CoordModeOrigin); 860 } 861 if (outlineGC != None) { 862 XDrawLines(display, drawable, outlineGC, pointPtr, 863 numPoints, CoordModeOrigin); 864 } 865 if (pointPtr != staticPoints) { 866 ckfree((char *) pointPtr); 867 } 868} 869 870/* 871 *-------------------------------------------------------------- 872 * 873 * DisplayPolygon -- 874 * 875 * This procedure is invoked to draw a polygon item in a given 876 * drawable. 877 * 878 * Results: 879 * None. 880 * 881 * Side effects: 882 * ItemPtr is drawn in drawable using the transformation 883 * information in canvas. 884 * 885 *-------------------------------------------------------------- 886 */ 887 888static void 889DisplayPolygon(canvas, itemPtr, display, drawable, x, y, width, height) 890 Tk_Canvas canvas; /* Canvas that contains item. */ 891 Tk_Item *itemPtr; /* Item to be displayed. */ 892 Display *display; /* Display on which to draw item. */ 893 Drawable drawable; /* Pixmap or window in which to draw 894 * item. */ 895 int x, y, width, height; /* Describes region of canvas that 896 * must be redisplayed (not used). */ 897{ 898 PolygonItem *polyPtr = (PolygonItem *) itemPtr; 899 Tk_State state = itemPtr->state; 900 Pixmap stipple = polyPtr->fillStipple; 901 double linewidth = polyPtr->outline.width; 902 903 if (((polyPtr->fillGC == None) && (polyPtr->outline.gc == None)) || 904 (polyPtr->numPoints < 1) || 905 (polyPtr->numPoints < 3 && polyPtr->outline.gc == None)) { 906 return; 907 } 908 909 if(state == TK_STATE_NULL) { 910 state = ((TkCanvas *)canvas)->canvas_state; 911 } 912 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 913 if (polyPtr->outline.activeWidth>linewidth) { 914 linewidth = polyPtr->outline.activeWidth; 915 } 916 if (polyPtr->activeFillStipple != None) { 917 stipple = polyPtr->activeFillStipple; 918 } 919 } else if (state==TK_STATE_DISABLED) { 920 if (polyPtr->outline.disabledWidth>0.0) { 921 linewidth = polyPtr->outline.disabledWidth; 922 } 923 if (polyPtr->disabledFillStipple != None) { 924 stipple = polyPtr->disabledFillStipple; 925 } 926 } 927 /* 928 * If we're stippling then modify the stipple offset in the GC. Be 929 * sure to reset the offset when done, since the GC is supposed to be 930 * read-only. 931 */ 932 933 if ((stipple != None) && (polyPtr->fillGC != None)) { 934 Tk_TSOffset *tsoffset = &polyPtr->tsoffset; 935 int w=0; int h=0; 936 int flags = tsoffset->flags; 937 if (!(flags & TK_OFFSET_INDEX) && (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE))) { 938 Tk_SizeOfBitmap(display, stipple, &w, &h); 939 if (flags & TK_OFFSET_CENTER) { 940 w /= 2; 941 } else { 942 w = 0; 943 } 944 if (flags & TK_OFFSET_MIDDLE) { 945 h /= 2; 946 } else { 947 h = 0; 948 } 949 } 950 tsoffset->xoffset -= w; 951 tsoffset->yoffset -= h; 952 Tk_CanvasSetOffset(canvas, polyPtr->fillGC, tsoffset); 953 tsoffset->xoffset += w; 954 tsoffset->yoffset += h; 955 } 956 Tk_ChangeOutlineGC(canvas, itemPtr, &(polyPtr->outline)); 957 958 if(polyPtr->numPoints < 3) { 959 short x,y; 960 int intLineWidth = (int) (linewidth + 0.5); 961 if (intLineWidth < 1) { 962 intLineWidth = 1; 963 } 964 Tk_CanvasDrawableCoords(canvas, polyPtr->coordPtr[0], 965 polyPtr->coordPtr[1], &x,&y); 966 XFillArc(display, drawable, polyPtr->outline.gc, 967 x - intLineWidth/2, y - intLineWidth/2, 968 (unsigned int)intLineWidth+1, (unsigned int)intLineWidth+1, 969 0, 64*360); 970 } else if (!polyPtr->smooth || polyPtr->numPoints < 4) { 971 TkFillPolygon(canvas, polyPtr->coordPtr, polyPtr->numPoints, 972 display, drawable, polyPtr->fillGC, polyPtr->outline.gc); 973 } else { 974 int numPoints; 975 XPoint staticPoints[MAX_STATIC_POINTS]; 976 XPoint *pointPtr; 977 978 /* 979 * This is a smoothed polygon. Display using a set of generated 980 * spline points rather than the original points. 981 */ 982 983 numPoints = polyPtr->smooth->coordProc(canvas, (double *) NULL, 984 polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, 985 (double *) NULL); 986 if (numPoints <= MAX_STATIC_POINTS) { 987 pointPtr = staticPoints; 988 } else { 989 pointPtr = (XPoint *) ckalloc((unsigned) 990 (numPoints * sizeof(XPoint))); 991 } 992 numPoints = polyPtr->smooth->coordProc(canvas, polyPtr->coordPtr, 993 polyPtr->numPoints, polyPtr->splineSteps, pointPtr, 994 (double *) NULL); 995 if (polyPtr->fillGC != None) { 996 XFillPolygon(display, drawable, polyPtr->fillGC, pointPtr, 997 numPoints, Complex, CoordModeOrigin); 998 } 999 if (polyPtr->outline.gc != None) { 1000 XDrawLines(display, drawable, polyPtr->outline.gc, pointPtr, 1001 numPoints, CoordModeOrigin); 1002 } 1003 if (pointPtr != staticPoints) { 1004 ckfree((char *) pointPtr); 1005 } 1006 } 1007 Tk_ResetOutlineGC(canvas, itemPtr, &(polyPtr->outline)); 1008 if ((stipple != None) && (polyPtr->fillGC != None)) { 1009 XSetTSOrigin(display, polyPtr->fillGC, 0, 0); 1010 } 1011} 1012 1013/* 1014 *-------------------------------------------------------------- 1015 * 1016 * PolygonInsert -- 1017 * 1018 * Insert coords into a polugon item at a given index. 1019 * 1020 * Results: 1021 * None. 1022 * 1023 * Side effects: 1024 * The coords in the given item is modified. 1025 * 1026 *-------------------------------------------------------------- 1027 */ 1028 1029static void 1030PolygonInsert(canvas, itemPtr, beforeThis, obj) 1031 Tk_Canvas canvas; /* Canvas containing text item. */ 1032 Tk_Item *itemPtr; /* Line item to be modified. */ 1033 int beforeThis; /* Index before which new coordinates 1034 * are to be inserted. */ 1035 Tcl_Obj *obj; /* New coordinates to be inserted. */ 1036{ 1037 PolygonItem *polyPtr = (PolygonItem *) itemPtr; 1038 int length, objc, i; 1039 Tcl_Obj **objv; 1040 double *new; 1041 Tk_State state = itemPtr->state; 1042 1043 if (state == TK_STATE_NULL) { 1044 state = ((TkCanvas *)canvas)->canvas_state; 1045 } 1046 1047 if (!obj || (Tcl_ListObjGetElements((Tcl_Interp *) NULL, obj, &objc, &objv) != TCL_OK) 1048 || !objc || objc&1) { 1049 return; 1050 } 1051 length = 2*(polyPtr->numPoints - polyPtr->autoClosed); 1052 while(beforeThis>length) beforeThis-=length; 1053 while(beforeThis<0) beforeThis+=length; 1054 new = (double *) ckalloc((unsigned)(sizeof(double) * (length + 2 + objc))); 1055 for (i=0; i<beforeThis; i++) { 1056 new[i] = polyPtr->coordPtr[i]; 1057 } 1058 for (i=0; i<objc; i++) { 1059 if (Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,objv[i], 1060 new+(i+beforeThis))!=TCL_OK) { 1061 ckfree((char *) new); 1062 return; 1063 } 1064 } 1065 1066 for(i=beforeThis; i<length; i++) { 1067 new[i+objc] = polyPtr->coordPtr[i]; 1068 } 1069 if(polyPtr->coordPtr) ckfree((char *) polyPtr->coordPtr); 1070 length+=objc; 1071 polyPtr->coordPtr = new; 1072 polyPtr->numPoints = (length/2) + polyPtr->autoClosed; 1073 1074 /* 1075 * Close the polygon if it isn't already closed, or remove autoclosing 1076 * if the user's coordinates are now closed. 1077 */ 1078 1079 if (polyPtr->autoClosed) { 1080 if ((new[length-2] == new[0]) && (new[length-1] == new[1])) { 1081 polyPtr->autoClosed = 0; 1082 polyPtr->numPoints--; 1083 } 1084 } 1085 else { 1086 if ((new[length-2] != new[0]) || (new[length-1] != new[1])) { 1087 polyPtr->autoClosed = 1; 1088 polyPtr->numPoints++; 1089 } 1090 } 1091 1092 new[length] = new[0]; 1093 new[length+1] = new[1]; 1094 if (((length-objc)>3) && (state != TK_STATE_HIDDEN)) { 1095 /* 1096 * This is some optimizing code that will result that only the part 1097 * of the polygon that changed (and the objects that are overlapping 1098 * with that part) need to be redrawn. A special flag is set that 1099 * instructs the general canvas code not to redraw the whole 1100 * object. If this flag is not set, the canvas will do the redrawing, 1101 * otherwise I have to do it here. 1102 */ 1103 double width; 1104 int j; 1105 itemPtr->redraw_flags |= TK_ITEM_DONT_REDRAW; 1106 1107 /* 1108 * The header elements that normally are used for the 1109 * bounding box, are now used to calculate the bounding 1110 * box for only the part that has to be redrawn. That 1111 * doesn't matter, because afterwards the bounding 1112 * box has to be re-calculated anyway. 1113 */ 1114 1115 itemPtr->x1 = itemPtr->x2 = (int) polyPtr->coordPtr[beforeThis]; 1116 itemPtr->y1 = itemPtr->y2 = (int) polyPtr->coordPtr[beforeThis+1]; 1117 beforeThis-=2; objc+=4; 1118 if(polyPtr->smooth) { 1119 beforeThis-=2; objc+=4; 1120 } /* be carefull; beforeThis could now be negative */ 1121 for(i=beforeThis; i<beforeThis+objc; i+=2) { 1122 j=i; 1123 if(j<0) j+=length; 1124 if(j>=length) j-=length; 1125 TkIncludePoint(itemPtr, polyPtr->coordPtr+j); 1126 } 1127 width = polyPtr->outline.width; 1128 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 1129 if (polyPtr->outline.activeWidth>width) { 1130 width = polyPtr->outline.activeWidth; 1131 } 1132 } else if (state==TK_STATE_DISABLED) { 1133 if (polyPtr->outline.disabledWidth>0.0) { 1134 width = polyPtr->outline.disabledWidth; 1135 } 1136 } 1137 itemPtr->x1 -= (int) width; itemPtr->y1 -= (int) width; 1138 itemPtr->x2 += (int) width; itemPtr->y2 += (int) width; 1139 Tk_CanvasEventuallyRedraw(canvas, 1140 itemPtr->x1, itemPtr->y1, 1141 itemPtr->x2, itemPtr->y2); 1142 } 1143 1144 ComputePolygonBbox(canvas, polyPtr); 1145} 1146 1147/* 1148 *-------------------------------------------------------------- 1149 * 1150 * PolygonDeleteCoords -- 1151 * 1152 * Delete one or more coordinates from a polygon item. 1153 * 1154 * Results: 1155 * None. 1156 * 1157 * Side effects: 1158 * Characters between "first" and "last", inclusive, get 1159 * deleted from itemPtr. 1160 * 1161 *-------------------------------------------------------------- 1162 */ 1163 1164static void 1165PolygonDeleteCoords(canvas, itemPtr, first, last) 1166 Tk_Canvas canvas; /* Canvas containing itemPtr. */ 1167 Tk_Item *itemPtr; /* Item in which to delete characters. */ 1168 int first; /* Index of first character to delete. */ 1169 int last; /* Index of last character to delete. */ 1170{ 1171 PolygonItem *polyPtr = (PolygonItem *) itemPtr; 1172 int count, i; 1173 int length = 2*(polyPtr->numPoints - polyPtr->autoClosed); 1174 1175 while(first>=length) first-=length; 1176 while(first<0) first+=length; 1177 while(last>=length) last-=length; 1178 while(last<0) last+=length; 1179 1180 first &= -2; 1181 last &= -2; 1182 1183 count = last + 2 - first; 1184 if(count<=0) count +=length; 1185 1186 if(count >= length) { 1187 polyPtr->numPoints = 0; 1188 if(polyPtr->coordPtr != NULL) { 1189 ckfree((char *) polyPtr->coordPtr); 1190 } 1191 ComputePolygonBbox(canvas, polyPtr); 1192 return; 1193 } 1194 1195 if(last>=first) { 1196 for(i=last+2; i<length; i++) { 1197 polyPtr->coordPtr[i-count] = polyPtr->coordPtr[i]; 1198 } 1199 } else { 1200 for(i=last; i<=first; i++) { 1201 polyPtr->coordPtr[i-last] = polyPtr->coordPtr[i]; 1202 } 1203 } 1204 polyPtr->coordPtr[length-count] = polyPtr->coordPtr[0]; 1205 polyPtr->coordPtr[length-count+1] = polyPtr->coordPtr[1]; 1206 polyPtr->numPoints -= count/2; 1207 ComputePolygonBbox(canvas, polyPtr); 1208} 1209 1210/* 1211 *-------------------------------------------------------------- 1212 * 1213 * PolygonToPoint -- 1214 * 1215 * Computes the distance from a given point to a given 1216 * polygon, in canvas units. 1217 * 1218 * Results: 1219 * The return value is 0 if the point whose x and y coordinates 1220 * are pointPtr[0] and pointPtr[1] is inside the polygon. If the 1221 * point isn't inside the polygon then the return value is the 1222 * distance from the point to the polygon. 1223 * 1224 * Side effects: 1225 * None. 1226 * 1227 *-------------------------------------------------------------- 1228 */ 1229 1230 /* ARGSUSED */ 1231static double 1232PolygonToPoint(canvas, itemPtr, pointPtr) 1233 Tk_Canvas canvas; /* Canvas containing item. */ 1234 Tk_Item *itemPtr; /* Item to check against point. */ 1235 double *pointPtr; /* Pointer to x and y coordinates. */ 1236{ 1237 PolygonItem *polyPtr = (PolygonItem *) itemPtr; 1238 double *coordPtr, *polyPoints; 1239 double staticSpace[2*MAX_STATIC_POINTS]; 1240 double poly[10]; 1241 double radius; 1242 double bestDist, dist; 1243 int numPoints, count; 1244 int changedMiterToBevel; /* Non-zero means that a mitered corner 1245 * had to be treated as beveled after all 1246 * because the angle was < 11 degrees. */ 1247 double width; 1248 Tk_State state = itemPtr->state; 1249 1250 bestDist = 1.0e36; 1251 1252 if(state == TK_STATE_NULL) { 1253 state = ((TkCanvas *)canvas)->canvas_state; 1254 } 1255 width = polyPtr->outline.width; 1256 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 1257 if (polyPtr->outline.activeWidth>width) { 1258 width = polyPtr->outline.activeWidth; 1259 } 1260 } else if (state==TK_STATE_DISABLED) { 1261 if (polyPtr->outline.disabledWidth>0.0) { 1262 width = polyPtr->outline.disabledWidth; 1263 } 1264 } 1265 radius = width/2.0; 1266 1267 /* 1268 * Handle smoothed polygons by generating an expanded set of points 1269 * against which to do the check. 1270 */ 1271 1272 if ((polyPtr->smooth) && (polyPtr->numPoints>2)) { 1273 numPoints = polyPtr->smooth->coordProc(canvas, (double *) NULL, 1274 polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, 1275 (double *) NULL); 1276 if (numPoints <= MAX_STATIC_POINTS) { 1277 polyPoints = staticSpace; 1278 } else { 1279 polyPoints = (double *) ckalloc((unsigned) 1280 (2*numPoints*sizeof(double))); 1281 } 1282 numPoints = polyPtr->smooth->coordProc(canvas, polyPtr->coordPtr, 1283 polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, 1284 polyPoints); 1285 } else { 1286 numPoints = polyPtr->numPoints; 1287 polyPoints = polyPtr->coordPtr; 1288 } 1289 1290 bestDist = TkPolygonToPoint(polyPoints, numPoints, pointPtr); 1291 if (bestDist<=0.0) { 1292 goto donepoint; 1293 } 1294 if ((polyPtr->outline.gc != None) && (polyPtr->joinStyle == JoinRound)) { 1295 dist = bestDist - radius; 1296 if (dist <= 0.0) { 1297 bestDist = 0.0; 1298 goto donepoint; 1299 } else { 1300 bestDist = dist; 1301 } 1302 } 1303 1304 if ((polyPtr->outline.gc == None) || (width <= 1)) goto donepoint; 1305 1306 /* 1307 * The overall idea is to iterate through all of the edges of 1308 * the line, computing a polygon for each edge and testing the 1309 * point against that polygon. In addition, there are additional 1310 * tests to deal with rounded joints and caps. 1311 */ 1312 1313 changedMiterToBevel = 0; 1314 for (count = numPoints, coordPtr = polyPoints; count >= 2; 1315 count--, coordPtr += 2) { 1316 1317 /* 1318 * If rounding is done around the first point then compute 1319 * the distance between the point and the point. 1320 */ 1321 1322 if (polyPtr->joinStyle == JoinRound) { 1323 dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) 1324 - radius; 1325 if (dist <= 0.0) { 1326 bestDist = 0.0; 1327 goto donepoint; 1328 } else if (dist < bestDist) { 1329 bestDist = dist; 1330 } 1331 } 1332 1333 /* 1334 * Compute the polygonal shape corresponding to this edge, 1335 * consisting of two points for the first point of the edge 1336 * and two points for the last point of the edge. 1337 */ 1338 1339 if (count == numPoints) { 1340 TkGetButtPoints(coordPtr+2, coordPtr, (double) width, 1341 0, poly, poly+2); 1342 } else if ((polyPtr->joinStyle == JoinMiter) && !changedMiterToBevel) { 1343 poly[0] = poly[6]; 1344 poly[1] = poly[7]; 1345 poly[2] = poly[4]; 1346 poly[3] = poly[5]; 1347 } else { 1348 TkGetButtPoints(coordPtr+2, coordPtr, (double) width, 0, 1349 poly, poly+2); 1350 1351 /* 1352 * If this line uses beveled joints, then check the distance 1353 * to a polygon comprising the last two points of the previous 1354 * polygon and the first two from this polygon; this checks 1355 * the wedges that fill the mitered joint. 1356 */ 1357 1358 if ((polyPtr->joinStyle == JoinBevel) || changedMiterToBevel) { 1359 poly[8] = poly[0]; 1360 poly[9] = poly[1]; 1361 dist = TkPolygonToPoint(poly, 5, pointPtr); 1362 if (dist <= 0.0) { 1363 bestDist = 0.0; 1364 goto donepoint; 1365 } else if (dist < bestDist) { 1366 bestDist = dist; 1367 } 1368 changedMiterToBevel = 0; 1369 } 1370 } 1371 if (count == 2) { 1372 TkGetButtPoints(coordPtr, coordPtr+2, (double) width, 1373 0, poly+4, poly+6); 1374 } else if (polyPtr->joinStyle == JoinMiter) { 1375 if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, 1376 (double) width, poly+4, poly+6) == 0) { 1377 changedMiterToBevel = 1; 1378 TkGetButtPoints(coordPtr, coordPtr+2, (double) width, 1379 0, poly+4, poly+6); 1380 } 1381 } else { 1382 TkGetButtPoints(coordPtr, coordPtr+2, (double) width, 0, 1383 poly+4, poly+6); 1384 } 1385 poly[8] = poly[0]; 1386 poly[9] = poly[1]; 1387 dist = TkPolygonToPoint(poly, 5, pointPtr); 1388 if (dist <= 0.0) { 1389 bestDist = 0.0; 1390 goto donepoint; 1391 } else if (dist < bestDist) { 1392 bestDist = dist; 1393 } 1394 } 1395 1396 donepoint: 1397 if ((polyPoints != staticSpace) && polyPoints != polyPtr->coordPtr) { 1398 ckfree((char *) polyPoints); 1399 } 1400 return bestDist; 1401} 1402 1403/* 1404 *-------------------------------------------------------------- 1405 * 1406 * PolygonToArea -- 1407 * 1408 * This procedure is called to determine whether an item 1409 * lies entirely inside, entirely outside, or overlapping 1410 * a given rectangular area. 1411 * 1412 * Results: 1413 * -1 is returned if the item is entirely outside the area 1414 * given by rectPtr, 0 if it overlaps, and 1 if it is entirely 1415 * inside the given area. 1416 * 1417 * Side effects: 1418 * None. 1419 * 1420 *-------------------------------------------------------------- 1421 */ 1422 1423 /* ARGSUSED */ 1424static int 1425PolygonToArea(canvas, itemPtr, rectPtr) 1426 Tk_Canvas canvas; /* Canvas containing item. */ 1427 Tk_Item *itemPtr; /* Item to check against polygon. */ 1428 double *rectPtr; /* Pointer to array of four coordinates 1429 * (x1, y1, x2, y2) describing rectangular 1430 * area. */ 1431{ 1432 PolygonItem *polyPtr = (PolygonItem *) itemPtr; 1433 double *coordPtr; 1434 double staticSpace[2*MAX_STATIC_POINTS]; 1435 double *polyPoints, poly[10]; 1436 double radius; 1437 int numPoints, count; 1438 int changedMiterToBevel; /* Non-zero means that a mitered corner 1439 * had to be treated as beveled after all 1440 * because the angle was < 11 degrees. */ 1441 int inside; /* Tentative guess about what to return, 1442 * based on all points seen so far: one 1443 * means everything seen so far was 1444 * inside the area; -1 means everything 1445 * was outside the area. 0 means overlap 1446 * has been found. */ 1447 double width; 1448 Tk_State state = itemPtr->state; 1449 1450 if(state == TK_STATE_NULL) { 1451 state = ((TkCanvas *)canvas)->canvas_state; 1452 } 1453 1454 width = polyPtr->outline.width; 1455 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 1456 if (polyPtr->outline.activeWidth>width) { 1457 width = polyPtr->outline.activeWidth; 1458 } 1459 } else if (state==TK_STATE_DISABLED) { 1460 if (polyPtr->outline.disabledWidth>0.0) { 1461 width = polyPtr->outline.disabledWidth; 1462 } 1463 } 1464 1465 radius = width/2.0; 1466 inside = -1; 1467 1468 if ((state==TK_STATE_HIDDEN) || polyPtr->numPoints<2) { 1469 return -1; 1470 } else if (polyPtr->numPoints <3) { 1471 double oval[4]; 1472 oval[0] = polyPtr->coordPtr[0]-radius; 1473 oval[1] = polyPtr->coordPtr[1]-radius; 1474 oval[2] = polyPtr->coordPtr[0]+radius; 1475 oval[3] = polyPtr->coordPtr[1]+radius; 1476 return TkOvalToArea(oval, rectPtr); 1477 } 1478 /* 1479 * Handle smoothed polygons by generating an expanded set of points 1480 * against which to do the check. 1481 */ 1482 1483 if (polyPtr->smooth) { 1484 numPoints = polyPtr->smooth->coordProc(canvas, (double *) NULL, 1485 polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, 1486 (double *) NULL); 1487 if (numPoints <= MAX_STATIC_POINTS) { 1488 polyPoints = staticSpace; 1489 } else { 1490 polyPoints = (double *) ckalloc((unsigned) 1491 (2*numPoints*sizeof(double))); 1492 } 1493 numPoints = polyPtr->smooth->coordProc(canvas, polyPtr->coordPtr, 1494 polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, 1495 polyPoints); 1496 } else { 1497 numPoints = polyPtr->numPoints; 1498 polyPoints = polyPtr->coordPtr; 1499 } 1500 1501 /* 1502 * Simple test to see if we are in the polygon. Polygons are 1503 * different from othe canvas items in that they register points 1504 * being inside even if it isn't filled. 1505 */ 1506 inside = TkPolygonToArea(polyPoints, numPoints, rectPtr); 1507 if (inside==0) goto donearea; 1508 1509 if (polyPtr->outline.gc == None) goto donearea ; 1510 1511 /* 1512 * Iterate through all of the edges of the line, computing a polygon 1513 * for each edge and testing the area against that polygon. In 1514 * addition, there are additional tests to deal with rounded joints 1515 * and caps. 1516 */ 1517 1518 changedMiterToBevel = 0; 1519 for (count = numPoints, coordPtr = polyPoints; count >= 2; 1520 count--, coordPtr += 2) { 1521 1522 /* 1523 * If rounding is done around the first point of the edge 1524 * then test a circular region around the point with the 1525 * area. 1526 */ 1527 1528 if (polyPtr->joinStyle == JoinRound) { 1529 poly[0] = coordPtr[0] - radius; 1530 poly[1] = coordPtr[1] - radius; 1531 poly[2] = coordPtr[0] + radius; 1532 poly[3] = coordPtr[1] + radius; 1533 if (TkOvalToArea(poly, rectPtr) != inside) { 1534 inside = 0; 1535 goto donearea; 1536 } 1537 } 1538 1539 /* 1540 * Compute the polygonal shape corresponding to this edge, 1541 * consisting of two points for the first point of the edge 1542 * and two points for the last point of the edge. 1543 */ 1544 1545 if (count == numPoints) { 1546 TkGetButtPoints(coordPtr+2, coordPtr, width, 1547 0, poly, poly+2); 1548 } else if ((polyPtr->joinStyle == JoinMiter) && !changedMiterToBevel) { 1549 poly[0] = poly[6]; 1550 poly[1] = poly[7]; 1551 poly[2] = poly[4]; 1552 poly[3] = poly[5]; 1553 } else { 1554 TkGetButtPoints(coordPtr+2, coordPtr, width, 0, 1555 poly, poly+2); 1556 1557 /* 1558 * If the last joint was beveled, then also check a 1559 * polygon comprising the last two points of the previous 1560 * polygon and the first two from this polygon; this checks 1561 * the wedges that fill the beveled joint. 1562 */ 1563 1564 if ((polyPtr->joinStyle == JoinBevel) || changedMiterToBevel) { 1565 poly[8] = poly[0]; 1566 poly[9] = poly[1]; 1567 if (TkPolygonToArea(poly, 5, rectPtr) != inside) { 1568 inside = 0; 1569 goto donearea; 1570 } 1571 changedMiterToBevel = 0; 1572 } 1573 } 1574 if (count == 2) { 1575 TkGetButtPoints(coordPtr, coordPtr+2, width, 1576 0, poly+4, poly+6); 1577 } else if (polyPtr->joinStyle == JoinMiter) { 1578 if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, 1579 width, poly+4, poly+6) == 0) { 1580 changedMiterToBevel = 1; 1581 TkGetButtPoints(coordPtr, coordPtr+2, width, 1582 0, poly+4, poly+6); 1583 } 1584 } else { 1585 TkGetButtPoints(coordPtr, coordPtr+2, width, 0, 1586 poly+4, poly+6); 1587 } 1588 poly[8] = poly[0]; 1589 poly[9] = poly[1]; 1590 if (TkPolygonToArea(poly, 5, rectPtr) != inside) { 1591 inside = 0; 1592 goto donearea; 1593 } 1594 } 1595 1596 donearea: 1597 if ((polyPoints != staticSpace) && (polyPoints != polyPtr->coordPtr)) { 1598 ckfree((char *) polyPoints); 1599 } 1600 return inside; 1601} 1602 1603/* 1604 *-------------------------------------------------------------- 1605 * 1606 * ScalePolygon -- 1607 * 1608 * This procedure is invoked to rescale a polygon item. 1609 * 1610 * Results: 1611 * None. 1612 * 1613 * Side effects: 1614 * The polygon referred to by itemPtr is rescaled so that the 1615 * following transformation is applied to all point 1616 * coordinates: 1617 * x' = originX + scaleX*(x-originX) 1618 * y' = originY + scaleY*(y-originY) 1619 * 1620 *-------------------------------------------------------------- 1621 */ 1622 1623static void 1624ScalePolygon(canvas, itemPtr, originX, originY, scaleX, scaleY) 1625 Tk_Canvas canvas; /* Canvas containing polygon. */ 1626 Tk_Item *itemPtr; /* Polygon to be scaled. */ 1627 double originX, originY; /* Origin about which to scale rect. */ 1628 double scaleX; /* Amount to scale in X direction. */ 1629 double scaleY; /* Amount to scale in Y direction. */ 1630{ 1631 PolygonItem *polyPtr = (PolygonItem *) itemPtr; 1632 double *coordPtr; 1633 int i; 1634 1635 for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints; 1636 i++, coordPtr += 2) { 1637 *coordPtr = originX + scaleX*(*coordPtr - originX); 1638 coordPtr[1] = originY + scaleY*(coordPtr[1] - originY); 1639 } 1640 ComputePolygonBbox(canvas, polyPtr); 1641} 1642 1643/* 1644 *-------------------------------------------------------------- 1645 * 1646 * GetPolygonIndex -- 1647 * 1648 * Parse an index into a polygon item and return either its value 1649 * or an error. 1650 * 1651 * Results: 1652 * A standard Tcl result. If all went well, then *indexPtr is 1653 * filled in with the index (into itemPtr) corresponding to 1654 * string. Otherwise an error message is left in 1655 * interp->result. 1656 * 1657 * Side effects: 1658 * None. 1659 * 1660 *-------------------------------------------------------------- 1661 */ 1662 1663static int 1664GetPolygonIndex(interp, canvas, itemPtr, obj, indexPtr) 1665 Tcl_Interp *interp; /* Used for error reporting. */ 1666 Tk_Canvas canvas; /* Canvas containing item. */ 1667 Tk_Item *itemPtr; /* Item for which the index is being 1668 * specified. */ 1669 Tcl_Obj *obj; /* Specification of a particular coord 1670 * in itemPtr's line. */ 1671 int *indexPtr; /* Where to store converted index. */ 1672{ 1673 PolygonItem *polyPtr = (PolygonItem *) itemPtr; 1674 int length; 1675 char *string = Tcl_GetStringFromObj(obj, &length); 1676 1677 if (string[0] == 'e') { 1678 if (strncmp(string, "end", (unsigned) length) == 0) { 1679 *indexPtr = 2*(polyPtr->numPoints - polyPtr->autoClosed); 1680 } else { 1681 badIndex: 1682 1683 /* 1684 * Some of the paths here leave messages in interp->result, 1685 * so we have to clear it out before storing our own message. 1686 */ 1687 1688 Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); 1689 Tcl_AppendResult(interp, "bad index \"", string, "\"", 1690 (char *) NULL); 1691 return TCL_ERROR; 1692 } 1693 } else if (string[0] == '@') { 1694 int i; 1695 double x ,y, bestDist, dist, *coordPtr; 1696 char *end, *p; 1697 1698 p = string+1; 1699 x = strtod(p, &end); 1700 if ((end == p) || (*end != ',')) { 1701 goto badIndex; 1702 } 1703 p = end+1; 1704 y = strtod(p, &end); 1705 if ((end == p) || (*end != 0)) { 1706 goto badIndex; 1707 } 1708 bestDist = 1.0e36; 1709 coordPtr = polyPtr->coordPtr; 1710 *indexPtr = 0; 1711 for(i=0; i<(polyPtr->numPoints-1); i++) { 1712 dist = hypot(coordPtr[0] - x, coordPtr[1] - y); 1713 if (dist<bestDist) { 1714 bestDist = dist; 1715 *indexPtr = 2*i; 1716 } 1717 coordPtr += 2; 1718 } 1719 } else { 1720 int count = 2*(polyPtr->numPoints - polyPtr->autoClosed); 1721 if (Tcl_GetIntFromObj(interp, obj, indexPtr) != TCL_OK) { 1722 goto badIndex; 1723 } 1724 *indexPtr &= -2; /* if odd, make it even */ 1725 if (count) { 1726 if (*indexPtr > 0) { 1727 *indexPtr = ((*indexPtr - 2) % count) + 2; 1728 } else { 1729 *indexPtr = -((-(*indexPtr)) % count); 1730 } 1731 } else { 1732 *indexPtr = 0; 1733 } 1734 } 1735 return TCL_OK; 1736} 1737 1738/* 1739 *-------------------------------------------------------------- 1740 * 1741 * TranslatePolygon -- 1742 * 1743 * This procedure is called to move a polygon by a given 1744 * amount. 1745 * 1746 * Results: 1747 * None. 1748 * 1749 * Side effects: 1750 * The position of the polygon is offset by (xDelta, yDelta), 1751 * and the bounding box is updated in the generic part of the 1752 * item structure. 1753 * 1754 *-------------------------------------------------------------- 1755 */ 1756 1757static void 1758TranslatePolygon(canvas, itemPtr, deltaX, deltaY) 1759 Tk_Canvas canvas; /* Canvas containing item. */ 1760 Tk_Item *itemPtr; /* Item that is being moved. */ 1761 double deltaX, deltaY; /* Amount by which item is to be 1762 * moved. */ 1763{ 1764 PolygonItem *polyPtr = (PolygonItem *) itemPtr; 1765 double *coordPtr; 1766 int i; 1767 1768 for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints; 1769 i++, coordPtr += 2) { 1770 *coordPtr += deltaX; 1771 coordPtr[1] += deltaY; 1772 } 1773 ComputePolygonBbox(canvas, polyPtr); 1774} 1775 1776/* 1777 *-------------------------------------------------------------- 1778 * 1779 * PolygonToPostscript -- 1780 * 1781 * This procedure is called to generate Postscript for 1782 * polygon items. 1783 * 1784 * Results: 1785 * The return value is a standard Tcl result. If an error 1786 * occurs in generating Postscript then an error message is 1787 * left in the interp's result, replacing whatever used 1788 * to be there. If no error occurs, then Postscript for the 1789 * item is appended to the result. 1790 * 1791 * Side effects: 1792 * None. 1793 * 1794 *-------------------------------------------------------------- 1795 */ 1796 1797static int 1798PolygonToPostscript(interp, canvas, itemPtr, prepass) 1799 Tcl_Interp *interp; /* Leave Postscript or error message 1800 * here. */ 1801 Tk_Canvas canvas; /* Information about overall canvas. */ 1802 Tk_Item *itemPtr; /* Item for which Postscript is 1803 * wanted. */ 1804 int prepass; /* 1 means this is a prepass to 1805 * collect font information; 0 means 1806 * final Postscript is being created. */ 1807{ 1808 PolygonItem *polyPtr = (PolygonItem *) itemPtr; 1809 char *style; 1810 XColor *color; 1811 XColor *fillColor; 1812 Pixmap stipple; 1813 Pixmap fillStipple; 1814 Tk_State state = itemPtr->state; 1815 double width; 1816 1817 if (polyPtr->numPoints<2 || polyPtr->coordPtr==NULL) { 1818 return TCL_OK; 1819 } 1820 1821 if(state == TK_STATE_NULL) { 1822 state = ((TkCanvas *)canvas)->canvas_state; 1823 } 1824 width = polyPtr->outline.width; 1825 color = polyPtr->outline.color; 1826 stipple = polyPtr->fillStipple; 1827 fillColor = polyPtr->fillColor; 1828 fillStipple = polyPtr->fillStipple; 1829 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 1830 if (polyPtr->outline.activeWidth>width) { 1831 width = polyPtr->outline.activeWidth; 1832 } 1833 if (polyPtr->outline.activeColor!=NULL) { 1834 color = polyPtr->outline.activeColor; 1835 } 1836 if (polyPtr->outline.activeStipple!=None) { 1837 stipple = polyPtr->outline.activeStipple; 1838 } 1839 if (polyPtr->activeFillColor!=NULL) { 1840 fillColor = polyPtr->activeFillColor; 1841 } 1842 if (polyPtr->activeFillStipple!=None) { 1843 fillStipple = polyPtr->activeFillStipple; 1844 } 1845 } else if (state==TK_STATE_DISABLED) { 1846 if (polyPtr->outline.disabledWidth>0.0) { 1847 width = polyPtr->outline.disabledWidth; 1848 } 1849 if (polyPtr->outline.disabledColor!=NULL) { 1850 color = polyPtr->outline.disabledColor; 1851 } 1852 if (polyPtr->outline.disabledStipple!=None) { 1853 stipple = polyPtr->outline.disabledStipple; 1854 } 1855 if (polyPtr->disabledFillColor!=NULL) { 1856 fillColor = polyPtr->disabledFillColor; 1857 } 1858 if (polyPtr->disabledFillStipple!=None) { 1859 fillStipple = polyPtr->disabledFillStipple; 1860 } 1861 } 1862 if (polyPtr->numPoints==2) { 1863 char string[128]; 1864 if (color == NULL) { 1865 return TCL_OK; 1866 } 1867 1868 sprintf(string, "%.15g %.15g translate %.15g %.15g", 1869 polyPtr->coordPtr[0], Tk_CanvasPsY(canvas, polyPtr->coordPtr[1]), 1870 width/2.0, width/2.0); 1871 Tcl_AppendResult(interp, "matrix currentmatrix\n",string, 1872 " scale 1 0 moveto 0 0 1 0 360 arc\nsetmatrix\n", (char *) NULL); 1873 if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) { 1874 return TCL_ERROR; 1875 } 1876 if (stipple != None) { 1877 Tcl_AppendResult(interp, "clip ", (char *) NULL); 1878 if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) { 1879 return TCL_ERROR; 1880 } 1881 } else { 1882 Tcl_AppendResult(interp, "fill\n", (char *) NULL); 1883 } 1884 return TCL_OK; 1885 } 1886 1887 /* 1888 * Fill the area of the polygon. 1889 */ 1890 1891 if (fillColor != NULL && polyPtr->numPoints>3) { 1892 if (!polyPtr->smooth || !polyPtr->smooth->postscriptProc) { 1893 Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr, 1894 polyPtr->numPoints); 1895 } else { 1896 polyPtr->smooth->postscriptProc(interp, canvas, polyPtr->coordPtr, 1897 polyPtr->numPoints, polyPtr->splineSteps); 1898 } 1899 if (Tk_CanvasPsColor(interp, canvas, fillColor) != TCL_OK) { 1900 return TCL_ERROR; 1901 } 1902 if (fillStipple != None) { 1903 Tcl_AppendResult(interp, "eoclip ", (char *) NULL); 1904 if (Tk_CanvasPsStipple(interp, canvas, fillStipple) 1905 != TCL_OK) { 1906 return TCL_ERROR; 1907 } 1908 if (color != NULL) { 1909 Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); 1910 } 1911 } else { 1912 Tcl_AppendResult(interp, "eofill\n", (char *) NULL); 1913 } 1914 } 1915 1916 /* 1917 * Now draw the outline, if there is one. 1918 */ 1919 1920 if (color != NULL) { 1921 1922 if (!polyPtr->smooth || !polyPtr->smooth->postscriptProc) { 1923 Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr, 1924 polyPtr->numPoints); 1925 } else { 1926 polyPtr->smooth->postscriptProc(interp, canvas, polyPtr->coordPtr, 1927 polyPtr->numPoints, polyPtr->splineSteps); 1928 } 1929 1930 if (polyPtr->joinStyle == JoinRound) { 1931 style = "1"; 1932 } else if (polyPtr->joinStyle == JoinBevel) { 1933 style = "2"; 1934 } else { 1935 style = "0"; 1936 } 1937 Tcl_AppendResult(interp, style," setlinejoin 1 setlinecap\n", 1938 (char *) NULL); 1939 if (Tk_CanvasPsOutline(canvas, itemPtr, 1940 &(polyPtr->outline)) != TCL_OK) { 1941 return TCL_ERROR; 1942 } 1943 } 1944 return TCL_OK; 1945} 1946