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