1/* 2 * tkRectOval.c -- 3 * 4 * This file implements rectangle and oval 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 * 9 * See the file "license.terms" for information on usage and redistribution of 10 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 11 * 12 * RCS: @(#) $Id$ 13 */ 14 15#include <stdio.h> 16#include "tkInt.h" 17#include "tkCanvas.h" 18 19/* 20 * The structure below defines the record for each rectangle/oval item. 21 */ 22 23typedef struct RectOvalItem { 24 Tk_Item header; /* Generic stuff that's the same for all 25 * types. MUST BE FIRST IN STRUCTURE. */ 26 Tk_Outline outline; /* Outline structure */ 27 double bbox[4]; /* Coordinates of bounding box for rectangle 28 * or oval (x1, y1, x2, y2). Item includes x1 29 * and x2 but not y1 and y2. */ 30 Tk_TSOffset tsoffset; 31 XColor *fillColor; /* Color for filling rectangle/oval. */ 32 XColor *activeFillColor; /* Color for filling rectangle/oval if state 33 * is active. */ 34 XColor *disabledFillColor; /* Color for filling rectangle/oval if state 35 * is disabled. */ 36 Pixmap fillStipple; /* Stipple bitmap for filling item. */ 37 Pixmap activeFillStipple; /* Stipple bitmap for filling item if state is 38 * active. */ 39 Pixmap disabledFillStipple; /* Stipple bitmap for filling item if state is 40 * disabled. */ 41 GC fillGC; /* Graphics context for filling item. */ 42} RectOvalItem; 43 44/* 45 * Information used for parsing configuration specs: 46 */ 47 48static Tk_CustomOption stateOption = { 49 (Tk_OptionParseProc *) TkStateParseProc, 50 TkStatePrintProc, (ClientData) 2 51}; 52static Tk_CustomOption tagsOption = { 53 (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, 54 Tk_CanvasTagsPrintProc, (ClientData) NULL 55}; 56static Tk_CustomOption dashOption = { 57 (Tk_OptionParseProc *) TkCanvasDashParseProc, 58 TkCanvasDashPrintProc, (ClientData) NULL 59}; 60static Tk_CustomOption offsetOption = { 61 (Tk_OptionParseProc *) TkOffsetParseProc, 62 TkOffsetPrintProc, (ClientData) TK_OFFSET_RELATIVE 63}; 64static Tk_CustomOption pixelOption = { 65 (Tk_OptionParseProc *) TkPixelParseProc, 66 TkPixelPrintProc, (ClientData) NULL 67}; 68 69static Tk_ConfigSpec configSpecs[] = { 70 {TK_CONFIG_CUSTOM, "-activedash", NULL, NULL, 71 NULL, Tk_Offset(RectOvalItem, outline.activeDash), 72 TK_CONFIG_NULL_OK, &dashOption}, 73 {TK_CONFIG_COLOR, "-activefill", NULL, NULL, 74 NULL, Tk_Offset(RectOvalItem, activeFillColor), TK_CONFIG_NULL_OK}, 75 {TK_CONFIG_COLOR, "-activeoutline", NULL, NULL, 76 NULL, Tk_Offset(RectOvalItem, outline.activeColor), TK_CONFIG_NULL_OK}, 77 {TK_CONFIG_BITMAP, "-activeoutlinestipple", NULL, NULL, 78 NULL, Tk_Offset(RectOvalItem, outline.activeStipple), 79 TK_CONFIG_NULL_OK}, 80 {TK_CONFIG_BITMAP, "-activestipple", NULL, NULL, 81 NULL, Tk_Offset(RectOvalItem, activeFillStipple), TK_CONFIG_NULL_OK}, 82 {TK_CONFIG_CUSTOM, "-activewidth", NULL, NULL, 83 "0.0", Tk_Offset(RectOvalItem, outline.activeWidth), 84 TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, 85 {TK_CONFIG_CUSTOM, "-dash", NULL, NULL, 86 NULL, Tk_Offset(RectOvalItem, outline.dash), 87 TK_CONFIG_NULL_OK, &dashOption}, 88 {TK_CONFIG_PIXELS, "-dashoffset", NULL, NULL, 89 "0", Tk_Offset(RectOvalItem, outline.offset), 90 TK_CONFIG_DONT_SET_DEFAULT}, 91 {TK_CONFIG_CUSTOM, "-disableddash", NULL, NULL, 92 NULL, Tk_Offset(RectOvalItem, outline.disabledDash), 93 TK_CONFIG_NULL_OK, &dashOption}, 94 {TK_CONFIG_COLOR, "-disabledfill", NULL, NULL, 95 NULL, Tk_Offset(RectOvalItem, disabledFillColor), TK_CONFIG_NULL_OK}, 96 {TK_CONFIG_COLOR, "-disabledoutline", NULL, NULL, 97 NULL, Tk_Offset(RectOvalItem, outline.disabledColor), 98 TK_CONFIG_NULL_OK}, 99 {TK_CONFIG_BITMAP, "-disabledoutlinestipple", NULL, NULL, 100 NULL, Tk_Offset(RectOvalItem, outline.disabledStipple), 101 TK_CONFIG_NULL_OK}, 102 {TK_CONFIG_BITMAP, "-disabledstipple", NULL, NULL, 103 NULL, Tk_Offset(RectOvalItem, disabledFillStipple), TK_CONFIG_NULL_OK}, 104 {TK_CONFIG_PIXELS, "-disabledwidth", NULL, NULL, 105 "0.0", Tk_Offset(RectOvalItem, outline.disabledWidth), 106 TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, 107 {TK_CONFIG_COLOR, "-fill", NULL, NULL, 108 NULL, Tk_Offset(RectOvalItem, fillColor), TK_CONFIG_NULL_OK}, 109 {TK_CONFIG_CUSTOM, "-offset", NULL, NULL, 110 "0,0", Tk_Offset(RectOvalItem, tsoffset), 111 TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, 112 {TK_CONFIG_COLOR, "-outline", NULL, NULL, 113 "black", Tk_Offset(RectOvalItem, outline.color), TK_CONFIG_NULL_OK}, 114 {TK_CONFIG_CUSTOM, "-outlineoffset", NULL, NULL, 115 "0,0", Tk_Offset(RectOvalItem, outline.tsoffset), 116 TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, 117 {TK_CONFIG_BITMAP, "-outlinestipple", NULL, NULL, 118 NULL, Tk_Offset(RectOvalItem, outline.stipple), TK_CONFIG_NULL_OK}, 119 {TK_CONFIG_CUSTOM, "-state", NULL, NULL, 120 NULL, Tk_Offset(Tk_Item, state),TK_CONFIG_NULL_OK, &stateOption}, 121 {TK_CONFIG_BITMAP, "-stipple", NULL, NULL, 122 NULL, Tk_Offset(RectOvalItem, fillStipple),TK_CONFIG_NULL_OK}, 123 {TK_CONFIG_CUSTOM, "-tags", NULL, NULL, 124 NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, 125 {TK_CONFIG_CUSTOM, "-width", NULL, NULL, 126 "1.0", Tk_Offset(RectOvalItem, outline.width), 127 TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, 128 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} 129}; 130 131/* 132 * Prototypes for functions defined in this file: 133 */ 134 135static void ComputeRectOvalBbox(Tk_Canvas canvas, 136 RectOvalItem *rectOvalPtr); 137static int ConfigureRectOval(Tcl_Interp *interp, Tk_Canvas canvas, 138 Tk_Item *itemPtr, int objc, Tcl_Obj *CONST objv[], 139 int flags); 140static int CreateRectOval(Tcl_Interp *interp, Tk_Canvas canvas, 141 Tk_Item *itemPtr, int objc, Tcl_Obj *CONST objv[]); 142static void DeleteRectOval(Tk_Canvas canvas, Tk_Item *itemPtr, 143 Display *display); 144static void DisplayRectOval(Tk_Canvas canvas, Tk_Item *itemPtr, 145 Display *display, Drawable dst, int x, int y, 146 int width, int height); 147static int OvalToArea(Tk_Canvas canvas, Tk_Item *itemPtr, 148 double *areaPtr); 149static double OvalToPoint(Tk_Canvas canvas, Tk_Item *itemPtr, 150 double *pointPtr); 151static int RectOvalCoords(Tcl_Interp *interp, Tk_Canvas canvas, 152 Tk_Item *itemPtr, int objc, Tcl_Obj *CONST objv[]); 153static int RectOvalToPostscript(Tcl_Interp *interp, 154 Tk_Canvas canvas, Tk_Item *itemPtr, int prepass); 155static int RectToArea(Tk_Canvas canvas, Tk_Item *itemPtr, 156 double *areaPtr); 157static double RectToPoint(Tk_Canvas canvas, Tk_Item *itemPtr, 158 double *pointPtr); 159static void ScaleRectOval(Tk_Canvas canvas, Tk_Item *itemPtr, 160 double originX, double originY, 161 double scaleX, double scaleY); 162static void TranslateRectOval(Tk_Canvas canvas, Tk_Item *itemPtr, 163 double deltaX, double deltaY); 164 165/* 166 * The structures below defines the rectangle and oval item types by means of 167 * functions that can be invoked by generic item code. 168 */ 169 170Tk_ItemType tkRectangleType = { 171 "rectangle", /* name */ 172 sizeof(RectOvalItem), /* itemSize */ 173 CreateRectOval, /* createProc */ 174 configSpecs, /* configSpecs */ 175 ConfigureRectOval, /* configureProc */ 176 RectOvalCoords, /* coordProc */ 177 DeleteRectOval, /* deleteProc */ 178 DisplayRectOval, /* displayProc */ 179 TK_CONFIG_OBJS, /* flags */ 180 RectToPoint, /* pointProc */ 181 RectToArea, /* areaProc */ 182 RectOvalToPostscript, /* postscriptProc */ 183 ScaleRectOval, /* scaleProc */ 184 TranslateRectOval, /* translateProc */ 185 NULL, /* indexProc */ 186 NULL, /* icursorProc */ 187 NULL, /* selectionProc */ 188 NULL, /* insertProc */ 189 NULL, /* dTextProc */ 190 NULL, /* nextPtr */ 191}; 192 193Tk_ItemType tkOvalType = { 194 "oval", /* name */ 195 sizeof(RectOvalItem), /* itemSize */ 196 CreateRectOval, /* createProc */ 197 configSpecs, /* configSpecs */ 198 ConfigureRectOval, /* configureProc */ 199 RectOvalCoords, /* coordProc */ 200 DeleteRectOval, /* deleteProc */ 201 DisplayRectOval, /* displayProc */ 202 TK_CONFIG_OBJS, /* flags */ 203 OvalToPoint, /* pointProc */ 204 OvalToArea, /* areaProc */ 205 RectOvalToPostscript, /* postscriptProc */ 206 ScaleRectOval, /* scaleProc */ 207 TranslateRectOval, /* translateProc */ 208 NULL, /* indexProc */ 209 NULL, /* cursorProc */ 210 NULL, /* selectionProc */ 211 NULL, /* insertProc */ 212 NULL, /* dTextProc */ 213 NULL, /* nextPtr */ 214}; 215 216/* 217 *-------------------------------------------------------------- 218 * 219 * CreateRectOval -- 220 * 221 * This function is invoked to create a new rectangle or oval item in a 222 * canvas. 223 * 224 * Results: 225 * A standard Tcl return value. If an error occurred in creating the 226 * item, then an error message is left in the interp's result; in this 227 * case itemPtr is left uninitialized, so it can be safely freed by the 228 * caller. 229 * 230 * Side effects: 231 * A new rectangle or oval item is created. 232 * 233 *-------------------------------------------------------------- 234 */ 235 236static int 237CreateRectOval( 238 Tcl_Interp *interp, /* For error reporting. */ 239 Tk_Canvas canvas, /* Canvas to hold new item. */ 240 Tk_Item *itemPtr, /* Record to hold new item; header has been 241 * initialized by caller. */ 242 int objc, /* Number of arguments in objv. */ 243 Tcl_Obj *CONST objv[]) /* Arguments describing rectangle. */ 244{ 245 RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; 246 int i; 247 248 if (objc == 0) { 249 Tcl_Panic("canvas did not pass any coords\n"); 250 } 251 252 /* 253 * Carry out initialization that is needed in order to clean up after 254 * errors during the the remainder of this function. 255 */ 256 257 Tk_CreateOutline(&(rectOvalPtr->outline)); 258 rectOvalPtr->tsoffset.flags = 0; 259 rectOvalPtr->tsoffset.xoffset = 0; 260 rectOvalPtr->tsoffset.yoffset = 0; 261 rectOvalPtr->fillColor = NULL; 262 rectOvalPtr->activeFillColor = NULL; 263 rectOvalPtr->disabledFillColor = NULL; 264 rectOvalPtr->fillStipple = None; 265 rectOvalPtr->activeFillStipple = None; 266 rectOvalPtr->disabledFillStipple = None; 267 rectOvalPtr->fillGC = None; 268 269 /* 270 * Process the arguments to fill in the item record. 271 */ 272 273 for (i = 1; i < objc; i++) { 274 char *arg = Tcl_GetString(objv[i]); 275 276 if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { 277 break; 278 } 279 } 280 if ((RectOvalCoords(interp, canvas, itemPtr, i, objv) != TCL_OK)) { 281 goto error; 282 } 283 if (ConfigureRectOval(interp, canvas, itemPtr, objc-i, objv+i, 0) 284 == TCL_OK) { 285 return TCL_OK; 286 } 287 288 error: 289 DeleteRectOval(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); 290 return TCL_ERROR; 291} 292 293/* 294 *-------------------------------------------------------------- 295 * 296 * RectOvalCoords -- 297 * 298 * This function is invoked to process the "coords" widget command on 299 * rectangles and ovals. See the user documentation for details on what 300 * it does. 301 * 302 * Results: 303 * Returns TCL_OK or TCL_ERROR, and sets the interp's result. 304 * 305 * Side effects: 306 * The coordinates for the given item may be changed. 307 * 308 *-------------------------------------------------------------- 309 */ 310 311static int 312RectOvalCoords( 313 Tcl_Interp *interp, /* Used for error reporting. */ 314 Tk_Canvas canvas, /* Canvas containing item. */ 315 Tk_Item *itemPtr, /* Item whose coordinates are to be read or 316 * modified. */ 317 int objc, /* Number of coordinates supplied in objv. */ 318 Tcl_Obj *CONST objv[]) /* Array of coordinates: x1,y1,x2,y2,... */ 319{ 320 RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; 321 322 /* 323 * If no coordinates, return the current coordinates (i.e. bounding box). 324 */ 325 326 if (objc == 0) { 327 Tcl_Obj *obj = Tcl_NewObj(); 328 329 Tcl_ListObjAppendElement(NULL, obj, 330 Tcl_NewDoubleObj(rectOvalPtr->bbox[0])); 331 Tcl_ListObjAppendElement(NULL, obj, 332 Tcl_NewDoubleObj(rectOvalPtr->bbox[1])); 333 Tcl_ListObjAppendElement(NULL, obj, 334 Tcl_NewDoubleObj(rectOvalPtr->bbox[2])); 335 Tcl_ListObjAppendElement(NULL, obj, 336 Tcl_NewDoubleObj(rectOvalPtr->bbox[3])); 337 Tcl_SetObjResult(interp, obj); 338 return TCL_OK; 339 } 340 341 /* 342 * If one "coordinate", treat as list of coordinates. 343 */ 344 345 if (objc == 1) { 346 if (Tcl_ListObjGetElements(interp, objv[0], &objc, 347 (Tcl_Obj ***) &objv) != TCL_OK) { 348 return TCL_ERROR; 349 } 350 } 351 352 /* 353 * Better have four coordinates now. Spit out an error message otherwise. 354 */ 355 356 if (objc != 4) { 357 char buf[64 + TCL_INTEGER_SPACE]; 358 359 sprintf(buf, "wrong # coordinates: expected 0 or 4, got %d", objc); 360 Tcl_SetResult(interp, buf, TCL_VOLATILE); 361 return TCL_ERROR; 362 } 363 364 /* 365 * Parse the coordinates and update our bounding box. 366 */ 367 368 if ((Tk_CanvasGetCoordFromObj(interp, canvas, objv[0], 369 &rectOvalPtr->bbox[0]) != TCL_OK) 370 || (Tk_CanvasGetCoordFromObj(interp, canvas, objv[1], 371 &rectOvalPtr->bbox[1]) != TCL_OK) 372 || (Tk_CanvasGetCoordFromObj(interp, canvas, objv[2], 373 &rectOvalPtr->bbox[2]) != TCL_OK) 374 || (Tk_CanvasGetCoordFromObj(interp, canvas, objv[3], 375 &rectOvalPtr->bbox[3]) != TCL_OK)) { 376 return TCL_ERROR; 377 } 378 ComputeRectOvalBbox(canvas, rectOvalPtr); 379 return TCL_OK; 380} 381 382/* 383 *-------------------------------------------------------------- 384 * 385 * ConfigureRectOval -- 386 * 387 * This function is invoked to configure various aspects of a rectangle 388 * or oval item, such as its border and background colors. 389 * 390 * Results: 391 * A standard Tcl result code. If an error occurs, then an error message 392 * is left in the interp's result. 393 * 394 * Side effects: 395 * Configuration information, such as colors and stipple patterns, may be 396 * set for itemPtr. 397 * 398 *-------------------------------------------------------------- 399 */ 400 401static int 402ConfigureRectOval( 403 Tcl_Interp *interp, /* Used for error reporting. */ 404 Tk_Canvas canvas, /* Canvas containing itemPtr. */ 405 Tk_Item *itemPtr, /* Rectangle item to reconfigure. */ 406 int objc, /* Number of elements in objv. */ 407 Tcl_Obj *CONST objv[], /* Arguments describing things to configure. */ 408 int flags) /* Flags to pass to Tk_ConfigureWidget. */ 409{ 410 RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; 411 XGCValues gcValues; 412 GC newGC; 413 unsigned long mask; 414 Tk_Window tkwin; 415 Tk_TSOffset *tsoffset; 416 XColor *color; 417 Pixmap stipple; 418 Tk_State state; 419 420 tkwin = Tk_CanvasTkwin(canvas); 421 422 if (TCL_OK != Tk_ConfigureWidget(interp, tkwin, configSpecs, objc, 423 (CONST char **)objv, (char *) rectOvalPtr, flags|TK_CONFIG_OBJS)) { 424 return TCL_ERROR; 425 } 426 state = itemPtr->state; 427 428 /* 429 * A few of the options require additional processing, such as graphics 430 * contexts. 431 */ 432 433 if (rectOvalPtr->outline.activeWidth > rectOvalPtr->outline.width || 434 rectOvalPtr->outline.activeDash.number != 0 || 435 rectOvalPtr->outline.activeColor != NULL || 436 rectOvalPtr->outline.activeStipple != None || 437 rectOvalPtr->activeFillColor != NULL || 438 rectOvalPtr->activeFillStipple != None) { 439 itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; 440 } else { 441 itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; 442 } 443 444 tsoffset = &rectOvalPtr->outline.tsoffset; 445 flags = tsoffset->flags; 446 if (flags & TK_OFFSET_LEFT) { 447 tsoffset->xoffset = (int) (rectOvalPtr->bbox[0] + 0.5); 448 } else if (flags & TK_OFFSET_CENTER) { 449 tsoffset->xoffset = (int) 450 ((rectOvalPtr->bbox[0]+rectOvalPtr->bbox[2]+1)/2); 451 } else if (flags & TK_OFFSET_RIGHT) { 452 tsoffset->xoffset = (int) (rectOvalPtr->bbox[2] + 0.5); 453 } 454 if (flags & TK_OFFSET_TOP) { 455 tsoffset->yoffset = (int) (rectOvalPtr->bbox[1] + 0.5); 456 } else if (flags & TK_OFFSET_MIDDLE) { 457 tsoffset->yoffset = (int) 458 ((rectOvalPtr->bbox[1]+rectOvalPtr->bbox[3]+1)/2); 459 } else if (flags & TK_OFFSET_BOTTOM) { 460 tsoffset->yoffset = (int) (rectOvalPtr->bbox[2] + 0.5); 461 } 462 463 /* 464 * Configure the outline graphics context. If mask is non-zero, the gc has 465 * changed and must be reallocated, provided that the new settings specify 466 * a valid outline (non-zero width and non-NULL color) 467 */ 468 469 mask = Tk_ConfigOutlineGC(&gcValues, canvas, itemPtr, 470 &(rectOvalPtr->outline)); 471 if (mask && \ 472 rectOvalPtr->outline.width != 0 && \ 473 rectOvalPtr->outline.color != NULL) { 474 gcValues.cap_style = CapProjecting; 475 mask |= GCCapStyle; 476 newGC = Tk_GetGC(tkwin, mask, &gcValues); 477 } else { 478 newGC = None; 479 } 480 if (rectOvalPtr->outline.gc != None) { 481 Tk_FreeGC(Tk_Display(tkwin), rectOvalPtr->outline.gc); 482 } 483 rectOvalPtr->outline.gc = newGC; 484 485 if (state == TK_STATE_NULL) { 486 state = ((TkCanvas *)canvas)->canvas_state; 487 } 488 if (state == TK_STATE_HIDDEN) { 489 ComputeRectOvalBbox(canvas, rectOvalPtr); 490 return TCL_OK; 491 } 492 493 color = rectOvalPtr->fillColor; 494 stipple = rectOvalPtr->fillStipple; 495 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 496 if (rectOvalPtr->activeFillColor!=NULL) { 497 color = rectOvalPtr->activeFillColor; 498 } 499 if (rectOvalPtr->activeFillStipple!=None) { 500 stipple = rectOvalPtr->activeFillStipple; 501 } 502 } else if (state == TK_STATE_DISABLED) { 503 if (rectOvalPtr->disabledFillColor!=NULL) { 504 color = rectOvalPtr->disabledFillColor; 505 } 506 if (rectOvalPtr->disabledFillStipple!=None) { 507 stipple = rectOvalPtr->disabledFillStipple; 508 } 509 } 510 511 if (color == NULL) { 512 newGC = None; 513 } else { 514 gcValues.foreground = color->pixel; 515 if (stipple != None) { 516 gcValues.stipple = stipple; 517 gcValues.fill_style = FillStippled; 518 mask = GCForeground|GCStipple|GCFillStyle; 519 } else { 520 mask = GCForeground; 521 } 522#ifdef MAC_OSX_TK 523 /* 524 * Mac OS X CG drawing needs access to the outline linewidth 525 * even for fills (as linewidth controls antialiasing). 526 */ 527 gcValues.line_width = rectOvalPtr->outline.gc != None ? 528 rectOvalPtr->outline.gc->line_width : 0; 529 mask |= GCLineWidth; 530#endif 531 newGC = Tk_GetGC(tkwin, mask, &gcValues); 532 } 533 if (rectOvalPtr->fillGC != None) { 534 Tk_FreeGC(Tk_Display(tkwin), rectOvalPtr->fillGC); 535 } 536 rectOvalPtr->fillGC = newGC; 537 538 tsoffset = &rectOvalPtr->tsoffset; 539 flags = tsoffset->flags; 540 if (flags & TK_OFFSET_LEFT) { 541 tsoffset->xoffset = (int) (rectOvalPtr->bbox[0] + 0.5); 542 } else if (flags & TK_OFFSET_CENTER) { 543 tsoffset->xoffset = (int) 544 ((rectOvalPtr->bbox[0]+rectOvalPtr->bbox[2]+1)/2); 545 } else if (flags & TK_OFFSET_RIGHT) { 546 tsoffset->xoffset = (int) (rectOvalPtr->bbox[2] + 0.5); 547 } 548 if (flags & TK_OFFSET_TOP) { 549 tsoffset->yoffset = (int) (rectOvalPtr->bbox[1] + 0.5); 550 } else if (flags & TK_OFFSET_MIDDLE) { 551 tsoffset->yoffset = (int) 552 ((rectOvalPtr->bbox[1]+rectOvalPtr->bbox[3]+1)/2); 553 } else if (flags & TK_OFFSET_BOTTOM) { 554 tsoffset->yoffset = (int) (rectOvalPtr->bbox[3] + 0.5); 555 } 556 557 ComputeRectOvalBbox(canvas, rectOvalPtr); 558 559 return TCL_OK; 560} 561 562/* 563 *-------------------------------------------------------------- 564 * 565 * DeleteRectOval -- 566 * 567 * This function is called to clean up the data structure associated with 568 * a rectangle or oval item. 569 * 570 * Results: 571 * None. 572 * 573 * Side effects: 574 * Resources associated with itemPtr are released. 575 * 576 *-------------------------------------------------------------- 577 */ 578 579static void 580DeleteRectOval( 581 Tk_Canvas canvas, /* Info about overall widget. */ 582 Tk_Item *itemPtr, /* Item that is being deleted. */ 583 Display *display) /* Display containing window for canvas. */ 584{ 585 RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; 586 587 Tk_DeleteOutline(display, &(rectOvalPtr->outline)); 588 if (rectOvalPtr->fillColor != NULL) { 589 Tk_FreeColor(rectOvalPtr->fillColor); 590 } 591 if (rectOvalPtr->activeFillColor != NULL) { 592 Tk_FreeColor(rectOvalPtr->activeFillColor); 593 } 594 if (rectOvalPtr->disabledFillColor != NULL) { 595 Tk_FreeColor(rectOvalPtr->disabledFillColor); 596 } 597 if (rectOvalPtr->fillStipple != None) { 598 Tk_FreeBitmap(display, rectOvalPtr->fillStipple); 599 } 600 if (rectOvalPtr->activeFillStipple != None) { 601 Tk_FreeBitmap(display, rectOvalPtr->activeFillStipple); 602 } 603 if (rectOvalPtr->disabledFillStipple != None) { 604 Tk_FreeBitmap(display, rectOvalPtr->disabledFillStipple); 605 } 606 if (rectOvalPtr->fillGC != None) { 607 Tk_FreeGC(display, rectOvalPtr->fillGC); 608 } 609} 610 611/* 612 *-------------------------------------------------------------- 613 * 614 * ComputeRectOvalBbox -- 615 * 616 * This function is invoked to compute the bounding box of all the pixels 617 * that may be drawn as part of a rectangle or oval. 618 * 619 * Results: 620 * None. 621 * 622 * Side effects: 623 * The fields x1, y1, x2, and y2 are updated in the header for itemPtr. 624 * 625 *-------------------------------------------------------------- 626 */ 627 628 /* ARGSUSED */ 629static void 630ComputeRectOvalBbox( 631 Tk_Canvas canvas, /* Canvas that contains item. */ 632 RectOvalItem *rectOvalPtr) /* Item whose bbox is to be recomputed. */ 633{ 634 int bloat, tmp; 635 double dtmp, width; 636 Tk_State state = rectOvalPtr->header.state; 637 638 if (state == TK_STATE_NULL) { 639 state = ((TkCanvas *)canvas)->canvas_state; 640 } 641 642 width = rectOvalPtr->outline.width; 643 if (state == TK_STATE_HIDDEN) { 644 rectOvalPtr->header.x1 = rectOvalPtr->header.y1 = 645 rectOvalPtr->header.x2 = rectOvalPtr->header.y2 = -1; 646 return; 647 } 648 if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)rectOvalPtr) { 649 if (rectOvalPtr->outline.activeWidth>width) { 650 width = rectOvalPtr->outline.activeWidth; 651 } 652 } else if (state == TK_STATE_DISABLED) { 653 if (rectOvalPtr->outline.disabledWidth>0) { 654 width = rectOvalPtr->outline.disabledWidth; 655 } 656 } 657 658 /* 659 * Make sure that the first coordinates are the lowest ones. 660 */ 661 662 if (rectOvalPtr->bbox[1] > rectOvalPtr->bbox[3]) { 663 double tmpY = rectOvalPtr->bbox[3]; 664 665 rectOvalPtr->bbox[3] = rectOvalPtr->bbox[1]; 666 rectOvalPtr->bbox[1] = tmpY; 667 } 668 if (rectOvalPtr->bbox[0] > rectOvalPtr->bbox[2]) { 669 double tmpX = rectOvalPtr->bbox[2]; 670 671 rectOvalPtr->bbox[2] = rectOvalPtr->bbox[0]; 672 rectOvalPtr->bbox[0] = tmpX; 673 } 674 675 if (rectOvalPtr->outline.gc == None) { 676 /* 677 * The Win32 switch was added for 8.3 to solve a problem with ovals 678 * leaving traces on bottom and right of 1 pixel. This may not be the 679 * correct place to solve it, but it works. 680 */ 681 682#ifdef __WIN32__ 683 bloat = 1; 684#else 685 bloat = 0; 686#endif 687 } else { 688#ifdef MAC_OSX_TK 689 /* 690 * Mac OS X CoreGraphics needs correct rounding here otherwise it will 691 * draw outside the bounding box. Probably correct on other platforms 692 * as well? 693 */ 694 695 bloat = (int) (width+1.5)/2; 696#else 697 bloat = (int) (width+1)/2; 698#endif 699 } 700 701 /* 702 * Special note: the rectangle is always drawn at least 1x1 in size, so 703 * round up the upper coordinates to be at least 1 unit greater than the 704 * lower ones. 705 */ 706 707 tmp = (int) ((rectOvalPtr->bbox[0] >= 0) ? rectOvalPtr->bbox[0] + .5 708 : rectOvalPtr->bbox[0] - .5); 709 rectOvalPtr->header.x1 = tmp - bloat; 710 tmp = (int) ((rectOvalPtr->bbox[1] >= 0) ? rectOvalPtr->bbox[1] + .5 711 : rectOvalPtr->bbox[1] - .5); 712 rectOvalPtr->header.y1 = tmp - bloat; 713 dtmp = rectOvalPtr->bbox[2]; 714 if (dtmp < (rectOvalPtr->bbox[0] + 1)) { 715 dtmp = rectOvalPtr->bbox[0] + 1; 716 } 717 tmp = (int) ((dtmp >= 0) ? dtmp + .5 : dtmp - .5); 718 rectOvalPtr->header.x2 = tmp + bloat; 719 dtmp = rectOvalPtr->bbox[3]; 720 if (dtmp < (rectOvalPtr->bbox[1] + 1)) { 721 dtmp = rectOvalPtr->bbox[1] + 1; 722 } 723 tmp = (int) ((dtmp >= 0) ? dtmp + .5 : dtmp - .5); 724 rectOvalPtr->header.y2 = tmp + bloat; 725} 726 727/* 728 *-------------------------------------------------------------- 729 * 730 * DisplayRectOval -- 731 * 732 * This function is invoked to draw a rectangle or oval item in a given 733 * drawable. 734 * 735 * Results: 736 * None. 737 * 738 * Side effects: 739 * ItemPtr is drawn in drawable using the transformation information in 740 * canvas. 741 * 742 *-------------------------------------------------------------- 743 */ 744 745static void 746DisplayRectOval( 747 Tk_Canvas canvas, /* Canvas that contains item. */ 748 Tk_Item *itemPtr, /* Item to be displayed. */ 749 Display *display, /* Display on which to draw item. */ 750 Drawable drawable, /* Pixmap or window in which to draw item. */ 751 int x, int y, int width, int height) 752 /* Describes region of canvas that must be 753 * redisplayed (not used). */ 754{ 755 RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; 756 short x1, y1, x2, y2; 757 Pixmap fillStipple; 758 Tk_State state = itemPtr->state; 759 760 /* 761 * Compute the screen coordinates of the bounding box for the item. Make 762 * sure that the bbox is at least one pixel large, since some X servers 763 * will die if it isn't. 764 */ 765 766 Tk_CanvasDrawableCoords(canvas, rectOvalPtr->bbox[0], rectOvalPtr->bbox[1], 767 &x1, &y1); 768 Tk_CanvasDrawableCoords(canvas, rectOvalPtr->bbox[2], rectOvalPtr->bbox[3], 769 &x2, &y2); 770 if (x2 <= x1) { 771 x2 = x1+1; 772 } 773 if (y2 <= y1) { 774 y2 = y1+1; 775 } 776 777 /* 778 * Display filled part first (if wanted), then outline. If we're 779 * stippling, then modify the stipple offset in the GC. Be sure to reset 780 * the offset when done, since the GC is supposed to be read-only. 781 */ 782 783 if (state == TK_STATE_NULL) { 784 state = ((TkCanvas *)canvas)->canvas_state; 785 } 786 fillStipple = rectOvalPtr->fillStipple; 787 if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)rectOvalPtr) { 788 if (rectOvalPtr->activeFillStipple != None) { 789 fillStipple = rectOvalPtr->activeFillStipple; 790 } 791 } else if (state == TK_STATE_DISABLED) { 792 if (rectOvalPtr->disabledFillStipple != None) { 793 fillStipple = rectOvalPtr->disabledFillStipple; 794 } 795 } 796 797 if (rectOvalPtr->fillGC != None) { 798 if (fillStipple != None) { 799 Tk_TSOffset *tsoffset; 800 int w = 0, h = 0; 801 802 tsoffset = &rectOvalPtr->tsoffset; 803 if (tsoffset) { 804 int flags = tsoffset->flags; 805 806 if (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE)) { 807 Tk_SizeOfBitmap(display, fillStipple, &w, &h); 808 if (flags & TK_OFFSET_CENTER) { 809 w /= 2; 810 } else { 811 w = 0; 812 } 813 if (flags & TK_OFFSET_MIDDLE) { 814 h /= 2; 815 } else { 816 h = 0; 817 } 818 } 819 tsoffset->xoffset -= w; 820 tsoffset->yoffset -= h; 821 } 822 Tk_CanvasSetOffset(canvas, rectOvalPtr->fillGC, tsoffset); 823 if (tsoffset) { 824 tsoffset->xoffset += w; 825 tsoffset->yoffset += h; 826 } 827 } 828 if (rectOvalPtr->header.typePtr == &tkRectangleType) { 829 XFillRectangle(display, drawable, rectOvalPtr->fillGC, 830 x1, y1, (unsigned int) (x2-x1), (unsigned int) (y2-y1)); 831 } else { 832 XFillArc(display, drawable, rectOvalPtr->fillGC, 833 x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1), 834 0, 360*64); 835 } 836 if (fillStipple != None) { 837 XSetTSOrigin(display, rectOvalPtr->fillGC, 0, 0); 838 } 839 } 840 841 if (rectOvalPtr->outline.gc != None) { 842 Tk_ChangeOutlineGC(canvas, itemPtr, &(rectOvalPtr->outline)); 843 if (rectOvalPtr->header.typePtr == &tkRectangleType) { 844 XDrawRectangle(display, drawable, rectOvalPtr->outline.gc, 845 x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1)); 846 } else { 847 XDrawArc(display, drawable, rectOvalPtr->outline.gc, 848 x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1), 0, 360*64); 849 } 850 Tk_ResetOutlineGC(canvas, itemPtr, &(rectOvalPtr->outline)); 851 } 852} 853 854/* 855 *-------------------------------------------------------------- 856 * 857 * RectToPoint -- 858 * 859 * Computes the distance from a given point to a given rectangle, in 860 * canvas units. 861 * 862 * Results: 863 * The return value is 0 if the point whose x and y coordinates are 864 * coordPtr[0] and coordPtr[1] is inside the rectangle. If the point 865 * isn't inside the rectangle then the return value is the distance from 866 * the point to the rectangle. If itemPtr is filled, then anywhere in the 867 * interior is considered "inside"; if itemPtr isn't filled, then 868 * "inside" means only the area occupied by the outline. 869 * 870 * Side effects: 871 * None. 872 * 873 *-------------------------------------------------------------- 874 */ 875 876 /* ARGSUSED */ 877static double 878RectToPoint( 879 Tk_Canvas canvas, /* Canvas containing item. */ 880 Tk_Item *itemPtr, /* Item to check against point. */ 881 double *pointPtr) /* Pointer to x and y coordinates. */ 882{ 883 RectOvalItem *rectPtr = (RectOvalItem *) itemPtr; 884 double xDiff, yDiff, x1, y1, x2, y2, inc, tmp; 885 double width; 886 Tk_State state = itemPtr->state; 887 888 if (state == TK_STATE_NULL) { 889 state = ((TkCanvas *)canvas)->canvas_state; 890 } 891 892 width = rectPtr->outline.width; 893 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 894 if (rectPtr->outline.activeWidth>width) { 895 width = rectPtr->outline.activeWidth; 896 } 897 } else if (state == TK_STATE_DISABLED) { 898 if (rectPtr->outline.disabledWidth>0) { 899 width = rectPtr->outline.disabledWidth; 900 } 901 } 902 903 /* 904 * Generate a new larger rectangle that includes the border width, if 905 * there is one. 906 */ 907 908 x1 = rectPtr->bbox[0]; 909 y1 = rectPtr->bbox[1]; 910 x2 = rectPtr->bbox[2]; 911 y2 = rectPtr->bbox[3]; 912 if (rectPtr->outline.gc != None) { 913 inc = width/2.0; 914 x1 -= inc; 915 y1 -= inc; 916 x2 += inc; 917 y2 += inc; 918 } 919 920 /* 921 * If the point is inside the rectangle, handle specially: distance is 0 922 * if rectangle is filled, otherwise compute distance to nearest edge of 923 * rectangle and subtract width of edge. 924 */ 925 926 if ((pointPtr[0] >= x1) && (pointPtr[0] < x2) 927 && (pointPtr[1] >= y1) && (pointPtr[1] < y2)) { 928 if ((rectPtr->fillGC != None) || (rectPtr->outline.gc == None)) { 929 return 0.0; 930 } 931 xDiff = pointPtr[0] - x1; 932 tmp = x2 - pointPtr[0]; 933 if (tmp < xDiff) { 934 xDiff = tmp; 935 } 936 yDiff = pointPtr[1] - y1; 937 tmp = y2 - pointPtr[1]; 938 if (tmp < yDiff) { 939 yDiff = tmp; 940 } 941 if (yDiff < xDiff) { 942 xDiff = yDiff; 943 } 944 xDiff -= width; 945 if (xDiff < 0.0) { 946 return 0.0; 947 } 948 return xDiff; 949 } 950 951 /* 952 * Point is outside rectangle. 953 */ 954 955 if (pointPtr[0] < x1) { 956 xDiff = x1 - pointPtr[0]; 957 } else if (pointPtr[0] > x2) { 958 xDiff = pointPtr[0] - x2; 959 } else { 960 xDiff = 0; 961 } 962 963 if (pointPtr[1] < y1) { 964 yDiff = y1 - pointPtr[1]; 965 } else if (pointPtr[1] > y2) { 966 yDiff = pointPtr[1] - y2; 967 } else { 968 yDiff = 0; 969 } 970 971 return hypot(xDiff, yDiff); 972} 973 974/* 975 *-------------------------------------------------------------- 976 * 977 * OvalToPoint -- 978 * 979 * Computes the distance from a given point to a given oval, in canvas 980 * units. 981 * 982 * Results: 983 * The return value is 0 if the point whose x and y coordinates are 984 * coordPtr[0] and coordPtr[1] is inside the oval. If the point isn't 985 * inside the oval then the return value is the distance from the point 986 * to the oval. If itemPtr is filled, then anywhere in the interior is 987 * considered "inside"; if itemPtr isn't filled, then "inside" means only 988 * the area occupied by the outline. 989 * 990 * Side effects: 991 * None. 992 * 993 *-------------------------------------------------------------- 994 */ 995 996 /* ARGSUSED */ 997static double 998OvalToPoint( 999 Tk_Canvas canvas, /* Canvas containing item. */ 1000 Tk_Item *itemPtr, /* Item to check against point. */ 1001 double *pointPtr) /* Pointer to x and y coordinates. */ 1002{ 1003 RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr; 1004 double width; 1005 int filled; 1006 Tk_State state = itemPtr->state; 1007 1008 if (state == TK_STATE_NULL) { 1009 state = ((TkCanvas *)canvas)->canvas_state; 1010 } 1011 1012 width = (double) ovalPtr->outline.width; 1013 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 1014 if (ovalPtr->outline.activeWidth>width) { 1015 width = (double) ovalPtr->outline.activeWidth; 1016 } 1017 } else if (state == TK_STATE_DISABLED) { 1018 if (ovalPtr->outline.disabledWidth>0) { 1019 width = (double) ovalPtr->outline.disabledWidth; 1020 } 1021 } 1022 1023 1024 filled = ovalPtr->fillGC != None; 1025 if (ovalPtr->outline.gc == None) { 1026 width = 0.0; 1027 filled = 1; 1028 } 1029 return TkOvalToPoint(ovalPtr->bbox, width, filled, pointPtr); 1030} 1031 1032/* 1033 *-------------------------------------------------------------- 1034 * 1035 * RectToArea -- 1036 * 1037 * This function is called to determine whether an item lies entirely 1038 * inside, entirely outside, or overlapping a given rectangle. 1039 * 1040 * Results: 1041 * -1 is returned if the item is entirely outside the area given by 1042 * rectPtr, 0 if it overlaps, and 1 if it is entirely inside the given 1043 * area. 1044 * 1045 * Side effects: 1046 * None. 1047 * 1048 *-------------------------------------------------------------- 1049 */ 1050 1051 /* ARGSUSED */ 1052static int 1053RectToArea( 1054 Tk_Canvas canvas, /* Canvas containing item. */ 1055 Tk_Item *itemPtr, /* Item to check against rectangle. */ 1056 double *areaPtr) /* Pointer to array of four coordinates (x1, 1057 * y1, x2, y2) describing rectangular area. */ 1058{ 1059 RectOvalItem *rectPtr = (RectOvalItem *) itemPtr; 1060 double halfWidth; 1061 double width; 1062 Tk_State state = itemPtr->state; 1063 1064 if (state == TK_STATE_NULL) { 1065 state = ((TkCanvas *)canvas)->canvas_state; 1066 } 1067 1068 width = rectPtr->outline.width; 1069 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 1070 if (rectPtr->outline.activeWidth>width) { 1071 width = rectPtr->outline.activeWidth; 1072 } 1073 } else if (state == TK_STATE_DISABLED) { 1074 if (rectPtr->outline.disabledWidth>0) { 1075 width = rectPtr->outline.disabledWidth; 1076 } 1077 } 1078 1079 halfWidth = width/2.0; 1080 if (rectPtr->outline.gc == None) { 1081 halfWidth = 0.0; 1082 } 1083 1084 if ((areaPtr[2] <= (rectPtr->bbox[0] - halfWidth)) 1085 || (areaPtr[0] >= (rectPtr->bbox[2] + halfWidth)) 1086 || (areaPtr[3] <= (rectPtr->bbox[1] - halfWidth)) 1087 || (areaPtr[1] >= (rectPtr->bbox[3] + halfWidth))) { 1088 return -1; 1089 } 1090 if ((rectPtr->fillGC == None) && (rectPtr->outline.gc != None) 1091 && (areaPtr[0] >= (rectPtr->bbox[0] + halfWidth)) 1092 && (areaPtr[1] >= (rectPtr->bbox[1] + halfWidth)) 1093 && (areaPtr[2] <= (rectPtr->bbox[2] - halfWidth)) 1094 && (areaPtr[3] <= (rectPtr->bbox[3] - halfWidth))) { 1095 return -1; 1096 } 1097 if ((areaPtr[0] <= (rectPtr->bbox[0] - halfWidth)) 1098 && (areaPtr[1] <= (rectPtr->bbox[1] - halfWidth)) 1099 && (areaPtr[2] >= (rectPtr->bbox[2] + halfWidth)) 1100 && (areaPtr[3] >= (rectPtr->bbox[3] + halfWidth))) { 1101 return 1; 1102 } 1103 return 0; 1104} 1105 1106/* 1107 *-------------------------------------------------------------- 1108 * 1109 * OvalToArea -- 1110 * 1111 * This function is called to determine whether an item lies entirely 1112 * inside, entirely outside, or overlapping a given rectangular area. 1113 * 1114 * Results: 1115 * -1 is returned if the item is entirely outside the area given by 1116 * rectPtr, 0 if it overlaps, and 1 if it is entirely inside the given 1117 * area. 1118 * 1119 * Side effects: 1120 * None. 1121 * 1122 *-------------------------------------------------------------- 1123 */ 1124 1125 /* ARGSUSED */ 1126static int 1127OvalToArea( 1128 Tk_Canvas canvas, /* Canvas containing item. */ 1129 Tk_Item *itemPtr, /* Item to check against oval. */ 1130 double *areaPtr) /* Pointer to array of four coordinates (x1, 1131 * y1, x2, y2) describing rectangular area. */ 1132{ 1133 RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr; 1134 double oval[4], halfWidth; 1135 int result; 1136 double width; 1137 Tk_State state = itemPtr->state; 1138 1139 if (state == TK_STATE_NULL) { 1140 state = ((TkCanvas *)canvas)->canvas_state; 1141 } 1142 1143 width = ovalPtr->outline.width; 1144 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 1145 if (ovalPtr->outline.activeWidth>width) { 1146 width = ovalPtr->outline.activeWidth; 1147 } 1148 } else if (state == TK_STATE_DISABLED) { 1149 if (ovalPtr->outline.disabledWidth>0) { 1150 width = ovalPtr->outline.disabledWidth; 1151 } 1152 } 1153 1154 /* 1155 * Expand the oval to include the width of the outline, if any. 1156 */ 1157 1158 halfWidth = width/2.0; 1159 if (ovalPtr->outline.gc == None) { 1160 halfWidth = 0.0; 1161 } 1162 oval[0] = ovalPtr->bbox[0] - halfWidth; 1163 oval[1] = ovalPtr->bbox[1] - halfWidth; 1164 oval[2] = ovalPtr->bbox[2] + halfWidth; 1165 oval[3] = ovalPtr->bbox[3] + halfWidth; 1166 1167 result = TkOvalToArea(oval, areaPtr); 1168 1169 /* 1170 * If the rectangle appears to overlap the oval and the oval isn't filled, 1171 * do one more check to see if perhaps all four of the rectangle's corners 1172 * are totally inside the oval's unfilled center, in which case we should 1173 * return "outside". 1174 */ 1175 1176 if ((result == 0) && (ovalPtr->outline.gc != None) 1177 && (ovalPtr->fillGC == None)) { 1178 double centerX, centerY, height; 1179 double xDelta1, yDelta1, xDelta2, yDelta2; 1180 1181 centerX = (ovalPtr->bbox[0] + ovalPtr->bbox[2])/2.0; 1182 centerY = (ovalPtr->bbox[1] + ovalPtr->bbox[3])/2.0; 1183 width = (ovalPtr->bbox[2] - ovalPtr->bbox[0])/2.0 - halfWidth; 1184 height = (ovalPtr->bbox[3] - ovalPtr->bbox[1])/2.0 - halfWidth; 1185 xDelta1 = (areaPtr[0] - centerX)/width; 1186 xDelta1 *= xDelta1; 1187 yDelta1 = (areaPtr[1] - centerY)/height; 1188 yDelta1 *= yDelta1; 1189 xDelta2 = (areaPtr[2] - centerX)/width; 1190 xDelta2 *= xDelta2; 1191 yDelta2 = (areaPtr[3] - centerY)/height; 1192 yDelta2 *= yDelta2; 1193 if (((xDelta1 + yDelta1) < 1.0) 1194 && ((xDelta1 + yDelta2) < 1.0) 1195 && ((xDelta2 + yDelta1) < 1.0) 1196 && ((xDelta2 + yDelta2) < 1.0)) { 1197 return -1; 1198 } 1199 } 1200 return result; 1201} 1202 1203/* 1204 *-------------------------------------------------------------- 1205 * 1206 * ScaleRectOval -- 1207 * 1208 * This function is invoked to rescale a rectangle or oval item. 1209 * 1210 * Results: 1211 * None. 1212 * 1213 * Side effects: 1214 * The rectangle or oval referred to by itemPtr is rescaled so that the 1215 * following transformation is applied to all point coordinates: 1216 * x' = originX + scaleX*(x-originX) 1217 * y' = originY + scaleY*(y-originY) 1218 * 1219 *-------------------------------------------------------------- 1220 */ 1221 1222static void 1223ScaleRectOval( 1224 Tk_Canvas canvas, /* Canvas containing rectangle. */ 1225 Tk_Item *itemPtr, /* Rectangle to be scaled. */ 1226 double originX, double originY, 1227 /* Origin about which to scale rect. */ 1228 double scaleX, /* Amount to scale in X direction. */ 1229 double scaleY) /* Amount to scale in Y direction. */ 1230{ 1231 RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; 1232 1233 rectOvalPtr->bbox[0] = originX + scaleX*(rectOvalPtr->bbox[0] - originX); 1234 rectOvalPtr->bbox[1] = originY + scaleY*(rectOvalPtr->bbox[1] - originY); 1235 rectOvalPtr->bbox[2] = originX + scaleX*(rectOvalPtr->bbox[2] - originX); 1236 rectOvalPtr->bbox[3] = originY + scaleY*(rectOvalPtr->bbox[3] - originY); 1237 ComputeRectOvalBbox(canvas, rectOvalPtr); 1238} 1239 1240/* 1241 *-------------------------------------------------------------- 1242 * 1243 * TranslateRectOval -- 1244 * 1245 * This function is called to move a rectangle or oval by a given amount. 1246 * 1247 * Results: 1248 * None. 1249 * 1250 * Side effects: 1251 * The position of the rectangle or oval is offset by (xDelta, yDelta), 1252 * and the bounding box is updated in the generic part of the item 1253 * structure. 1254 * 1255 *-------------------------------------------------------------- 1256 */ 1257 1258static void 1259TranslateRectOval( 1260 Tk_Canvas canvas, /* Canvas containing item. */ 1261 Tk_Item *itemPtr, /* Item that is being moved. */ 1262 double deltaX, double deltaY) 1263 /* Amount by which item is to be moved. */ 1264{ 1265 RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; 1266 1267 rectOvalPtr->bbox[0] += deltaX; 1268 rectOvalPtr->bbox[1] += deltaY; 1269 rectOvalPtr->bbox[2] += deltaX; 1270 rectOvalPtr->bbox[3] += deltaY; 1271 ComputeRectOvalBbox(canvas, rectOvalPtr); 1272} 1273 1274/* 1275 *-------------------------------------------------------------- 1276 * 1277 * RectOvalToPostscript -- 1278 * 1279 * This function is called to generate Postscript for rectangle and oval 1280 * items. 1281 * 1282 * Results: 1283 * The return value is a standard Tcl result. If an error occurs in 1284 * generating Postscript then an error message is left in the interp's 1285 * result, replacing whatever used to be there. If no error occurs, then 1286 * Postscript for the rectangle is appended to the result. 1287 * 1288 * Side effects: 1289 * None. 1290 * 1291 *-------------------------------------------------------------- 1292 */ 1293 1294static int 1295RectOvalToPostscript( 1296 Tcl_Interp *interp, /* Interpreter for error reporting. */ 1297 Tk_Canvas canvas, /* Information about overall canvas. */ 1298 Tk_Item *itemPtr, /* Item for which Postscript is wanted. */ 1299 int prepass) /* 1 means this is a prepass to collect font 1300 * information; 0 means final Postscript is 1301 * being created. */ 1302{ 1303 char pathCmd[500]; 1304 RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; 1305 double y1, y2; 1306 XColor *color; 1307 XColor *fillColor; 1308 Pixmap fillStipple; 1309 Tk_State state = itemPtr->state; 1310 1311 y1 = Tk_CanvasPsY(canvas, rectOvalPtr->bbox[1]); 1312 y2 = Tk_CanvasPsY(canvas, rectOvalPtr->bbox[3]); 1313 1314 /* 1315 * Generate a string that creates a path for the rectangle or oval. This 1316 * is the only part of the function's code that is type-specific. 1317 */ 1318 1319 if (rectOvalPtr->header.typePtr == &tkRectangleType) { 1320 sprintf(pathCmd, "%.15g %.15g moveto %.15g 0 rlineto 0 %.15g rlineto %.15g 0 rlineto closepath\n", 1321 rectOvalPtr->bbox[0], y1, 1322 rectOvalPtr->bbox[2]-rectOvalPtr->bbox[0], y2-y1, 1323 rectOvalPtr->bbox[0]-rectOvalPtr->bbox[2]); 1324 } else { 1325 sprintf(pathCmd, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale 1 0 moveto 0 0 1 0 360 arc\nsetmatrix\n", 1326 (rectOvalPtr->bbox[0] + rectOvalPtr->bbox[2])/2, (y1 + y2)/2, 1327 (rectOvalPtr->bbox[2] - rectOvalPtr->bbox[0])/2, (y1 - y2)/2); 1328 } 1329 1330 if (state == TK_STATE_NULL) { 1331 state = ((TkCanvas *)canvas)->canvas_state; 1332 } 1333 color = rectOvalPtr->outline.color; 1334 fillColor = rectOvalPtr->fillColor; 1335 fillStipple = rectOvalPtr->fillStipple; 1336 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 1337 if (rectOvalPtr->outline.activeColor!=NULL) { 1338 color = rectOvalPtr->outline.activeColor; 1339 } 1340 if (rectOvalPtr->activeFillColor!=NULL) { 1341 fillColor = rectOvalPtr->activeFillColor; 1342 } 1343 if (rectOvalPtr->activeFillStipple!=None) { 1344 fillStipple = rectOvalPtr->activeFillStipple; 1345 } 1346 } else if (state == TK_STATE_DISABLED) { 1347 if (rectOvalPtr->outline.disabledColor!=NULL) { 1348 color = rectOvalPtr->outline.disabledColor; 1349 } 1350 if (rectOvalPtr->disabledFillColor!=NULL) { 1351 fillColor = rectOvalPtr->disabledFillColor; 1352 } 1353 if (rectOvalPtr->disabledFillStipple!=None) { 1354 fillStipple = rectOvalPtr->disabledFillStipple; 1355 } 1356 } 1357 1358 /* 1359 * First draw the filled area of the rectangle. 1360 */ 1361 1362 if (fillColor != NULL) { 1363 Tcl_AppendResult(interp, pathCmd, NULL); 1364 if (Tk_CanvasPsColor(interp, canvas, fillColor) != TCL_OK) { 1365 return TCL_ERROR; 1366 } 1367 if (fillStipple != None) { 1368 Tcl_AppendResult(interp, "clip ", NULL); 1369 if (Tk_CanvasPsStipple(interp, canvas, fillStipple) != TCL_OK) { 1370 return TCL_ERROR; 1371 } 1372 if (color != NULL) { 1373 Tcl_AppendResult(interp, "grestore gsave\n", NULL); 1374 } 1375 } else { 1376 Tcl_AppendResult(interp, "fill\n", NULL); 1377 } 1378 } 1379 1380 /* 1381 * Now draw the outline, if there is one. 1382 */ 1383 1384 if (color != NULL) { 1385 Tcl_AppendResult(interp, pathCmd, "0 setlinejoin 2 setlinecap\n", 1386 NULL); 1387 if (Tk_CanvasPsOutline(canvas, itemPtr, 1388 &(rectOvalPtr->outline))!= TCL_OK) { 1389 return TCL_ERROR; 1390 } 1391 } 1392 return TCL_OK; 1393} 1394 1395/* 1396 * Local Variables: 1397 * mode: c 1398 * c-basic-offset: 4 1399 * fill-column: 78 1400 * End: 1401 */ 1402