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