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