]>
Commit | Line | Data |
---|---|---|
6a5fa4e0 MG |
1 | /* |
2 | * tkRectOval.c -- | |
3 | * | |
4 | * This file implements rectangle and oval items for canvas | |
5 | * widgets. | |
6 | * | |
7 | * Copyright 1991-1992 Regents of the University of California. | |
8 | * Permission to use, copy, modify, and distribute this | |
9 | * software and its documentation for any purpose and without | |
10 | * fee is hereby granted, provided that the above copyright | |
11 | * notice appear in all copies. The University of California | |
12 | * makes no representations about the suitability of this | |
13 | * software for any purpose. It is provided "as is" without | |
14 | * express or implied warranty. | |
15 | */ | |
16 | ||
17 | #ifndef lint | |
18 | static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkRectOval.c,v 1.15 92/08/24 09:23:58 ouster Exp $ SPRITE (Berkeley)"; | |
19 | #endif | |
20 | ||
21 | #include <stdio.h> | |
22 | #include <math.h> | |
23 | #include "tkconfig.h" | |
24 | #include "tkint.h" | |
25 | #include "tkcanvas.h" | |
26 | ||
27 | /* | |
28 | * The structure below defines the record for each rectangle/oval item. | |
29 | */ | |
30 | ||
31 | typedef struct RectOvalItem { | |
32 | Tk_Item header; /* Generic stuff that's the same for all | |
33 | * types. MUST BE FIRST IN STRUCTURE. */ | |
34 | double bbox[4]; /* Coordinates of bounding box for rectangle | |
35 | * or oval (x1, y1, x2, y2). Item includes | |
36 | * x1 and x2 but not y1 and y2. */ | |
37 | int width; /* Width of outline. */ | |
38 | XColor *outlineColor; /* Color for outline. */ | |
39 | XColor *fillColor; /* Color for filling rectangle/oval. */ | |
40 | Pixmap fillStipple; /* Stipple bitmap for filling item. */ | |
41 | GC outlineGC; /* Graphics context for outline. */ | |
42 | GC fillGC; /* Graphics context for filling item. */ | |
43 | } RectOvalItem; | |
44 | ||
45 | /* | |
46 | * Information used for parsing configuration specs: | |
47 | */ | |
48 | ||
49 | static Tk_ConfigSpec configSpecs[] = { | |
50 | {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, | |
51 | (char *) NULL, Tk_Offset(RectOvalItem, fillColor), TK_CONFIG_NULL_OK}, | |
52 | {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL, | |
53 | "black", Tk_Offset(RectOvalItem, outlineColor), TK_CONFIG_NULL_OK}, | |
54 | {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, | |
55 | (char *) NULL, Tk_Offset(RectOvalItem, fillStipple), TK_CONFIG_NULL_OK}, | |
56 | {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, | |
57 | (char *) NULL, 0, TK_CONFIG_NULL_OK, &tkCanvasTagsOption}, | |
58 | {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, | |
59 | "1", Tk_Offset(RectOvalItem, width), TK_CONFIG_DONT_SET_DEFAULT}, | |
60 | {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, | |
61 | (char *) NULL, 0, 0} | |
62 | }; | |
63 | ||
64 | /* | |
65 | * Prototypes for procedures defined in this file: | |
66 | */ | |
67 | ||
68 | static void ComputeRectOvalBbox _ANSI_ARGS_((Tk_Canvas *canvasPtr, | |
69 | RectOvalItem *rectOvalPtr)); | |
70 | static int ConfigureRectOval _ANSI_ARGS_(( | |
71 | Tk_Canvas *canvasPtr, Tk_Item *itemPtr, int argc, | |
72 | char **argv, int flags)); | |
73 | static int CreateRectOval _ANSI_ARGS_((Tk_Canvas *canvasPtr, | |
74 | struct Tk_Item *itemPtr, int argc, char **argv)); | |
75 | static void DeleteRectOval _ANSI_ARGS_((Tk_Item *itemPtr)); | |
76 | static void DisplayRectOval _ANSI_ARGS_((Tk_Canvas *canvasPtr, | |
77 | Tk_Item *itemPtr, Drawable dst)); | |
78 | static int OvalToArea _ANSI_ARGS_((Tk_Canvas *canvasPtr, | |
79 | Tk_Item *itemPtr, double *areaPtr)); | |
80 | static double OvalToPoint _ANSI_ARGS_((Tk_Canvas *canvasPtr, | |
81 | Tk_Item *itemPtr, double *pointPtr)); | |
82 | static int RectOvalCoords _ANSI_ARGS_((Tk_Canvas *canvasPtr, | |
83 | Tk_Item *itemPtr, int argc, char **argv)); | |
84 | static int RectToArea _ANSI_ARGS_((Tk_Canvas *canvasPtr, | |
85 | Tk_Item *itemPtr, double *areaPtr)); | |
86 | static double RectToPoint _ANSI_ARGS_((Tk_Canvas *canvasPtr, | |
87 | Tk_Item *itemPtr, double *pointPtr)); | |
88 | static void ScaleRectOval _ANSI_ARGS_((Tk_Canvas *canvasPtr, | |
89 | Tk_Item *itemPtr, double originX, double originY, | |
90 | double scaleX, double scaleY)); | |
91 | static void TranslateRectOval _ANSI_ARGS_((Tk_Canvas *canvasPtr, | |
92 | Tk_Item *itemPtr, double deltaX, double deltaY)); | |
93 | ||
94 | /* | |
95 | * The structures below defines the rectangle and oval item types | |
96 | * by means of procedures that can be invoked by generic item code. | |
97 | */ | |
98 | ||
99 | Tk_ItemType TkRectangleType = { | |
100 | "rectangle", /* name */ | |
101 | sizeof(RectOvalItem), /* itemSize */ | |
102 | CreateRectOval, /* createProc */ | |
103 | configSpecs, /* configSpecs */ | |
104 | ConfigureRectOval, /* configureProc */ | |
105 | RectOvalCoords, /* coordProc */ | |
106 | DeleteRectOval, /* deleteProc */ | |
107 | DisplayRectOval, /* displayProc */ | |
108 | 0, /* alwaysRedraw */ | |
109 | RectToPoint, /* pointProc */ | |
110 | RectToArea, /* areaProc */ | |
111 | (Tk_ItemPostscriptProc *) NULL, /* postscriptProc */ | |
112 | ScaleRectOval, /* scaleProc */ | |
113 | TranslateRectOval, /* translateProc */ | |
114 | (Tk_ItemIndexProc *) NULL, /* indexProc */ | |
115 | (Tk_ItemCursorProc *) NULL, /* cursorProc */ | |
116 | (Tk_ItemSelectionProc *) NULL, /* selectionProc */ | |
117 | (Tk_ItemInsertProc *) NULL, /* insertProc */ | |
118 | (Tk_ItemDCharsProc *) NULL, /* dTextProc */ | |
119 | (Tk_ItemType *) NULL /* nextPtr */ | |
120 | }; | |
121 | ||
122 | Tk_ItemType TkOvalType = { | |
123 | "oval", /* name */ | |
124 | sizeof(RectOvalItem), /* itemSize */ | |
125 | CreateRectOval, /* createProc */ | |
126 | configSpecs, /* configSpecs */ | |
127 | ConfigureRectOval, /* configureProc */ | |
128 | RectOvalCoords, /* coordProc */ | |
129 | DeleteRectOval, /* deleteProc */ | |
130 | DisplayRectOval, /* displayProc */ | |
131 | 0, /* alwaysRedraw */ | |
132 | OvalToPoint, /* pointProc */ | |
133 | OvalToArea, /* areaProc */ | |
134 | (Tk_ItemPostscriptProc *) NULL, /* postscriptProc */ | |
135 | ScaleRectOval, /* scaleProc */ | |
136 | TranslateRectOval, /* translateProc */ | |
137 | (Tk_ItemIndexProc *) NULL, /* indexProc */ | |
138 | (Tk_ItemCursorProc *) NULL, /* cursorProc */ | |
139 | (Tk_ItemSelectionProc *) NULL, /* selectionProc */ | |
140 | (Tk_ItemInsertProc *) NULL, /* insertProc */ | |
141 | (Tk_ItemDCharsProc *) NULL, /* dTextProc */ | |
142 | (Tk_ItemType *) NULL /* nextPtr */ | |
143 | }; | |
144 | \f | |
145 | /* | |
146 | *-------------------------------------------------------------- | |
147 | * | |
148 | * CreateRectOval -- | |
149 | * | |
150 | * This procedure is invoked to create a new rectangle | |
151 | * or oval item in a canvas. | |
152 | * | |
153 | * Results: | |
154 | * A standard Tcl return value. If an error occurred in | |
155 | * creating the item, then an error message is left in | |
156 | * canvasPtr->interp->result; in this case itemPtr is | |
157 | * left uninitialized, so it can be safely freed by the | |
158 | * caller. | |
159 | * | |
160 | * Side effects: | |
161 | * A new rectangle or oval item is created. | |
162 | * | |
163 | *-------------------------------------------------------------- | |
164 | */ | |
165 | ||
166 | static int | |
167 | CreateRectOval(canvasPtr, itemPtr, argc, argv) | |
168 | register Tk_Canvas *canvasPtr; /* Canvas to hold new item. */ | |
169 | Tk_Item *itemPtr; /* Record to hold new item; header | |
170 | * has been initialized by caller. */ | |
171 | int argc; /* Number of arguments in argv. */ | |
172 | char **argv; /* Arguments describing rectangle. */ | |
173 | { | |
174 | register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; | |
175 | ||
176 | if (argc < 4) { | |
177 | Tcl_AppendResult(canvasPtr->interp, "wrong # args: should be \"", | |
178 | Tk_PathName(canvasPtr->tkwin), "\" create ", | |
179 | itemPtr->typePtr->name, " x1 y1 x2 y2 ?options?", | |
180 | (char *) NULL); | |
181 | return TCL_ERROR; | |
182 | } | |
183 | ||
184 | /* | |
185 | * Carry out initialization that is needed in order to clean | |
186 | * up after errors during the the remainder of this procedure. | |
187 | */ | |
188 | ||
189 | rectOvalPtr->width = 1; | |
190 | rectOvalPtr->outlineColor = NULL; | |
191 | rectOvalPtr->fillColor = NULL; | |
192 | rectOvalPtr->fillStipple = None; | |
193 | rectOvalPtr->outlineGC = None; | |
194 | rectOvalPtr->fillGC = None; | |
195 | ||
196 | /* | |
197 | * Process the arguments to fill in the item record. | |
198 | */ | |
199 | ||
200 | if ((TkGetCanvasCoord(canvasPtr, argv[0], &rectOvalPtr->bbox[0]) != TCL_OK) | |
201 | || (TkGetCanvasCoord(canvasPtr, argv[1], | |
202 | &rectOvalPtr->bbox[1]) != TCL_OK) | |
203 | || (TkGetCanvasCoord(canvasPtr, argv[2], | |
204 | &rectOvalPtr->bbox[2]) != TCL_OK) | |
205 | || (TkGetCanvasCoord(canvasPtr, argv[3], | |
206 | &rectOvalPtr->bbox[3]) != TCL_OK)) { | |
207 | return TCL_ERROR; | |
208 | } | |
209 | ||
210 | if (ConfigureRectOval(canvasPtr, itemPtr, argc-4, argv+4, 0) != TCL_OK) { | |
211 | DeleteRectOval(itemPtr); | |
212 | return TCL_ERROR; | |
213 | } | |
214 | return TCL_OK; | |
215 | } | |
216 | \f | |
217 | /* | |
218 | *-------------------------------------------------------------- | |
219 | * | |
220 | * RectOvalCoords -- | |
221 | * | |
222 | * This procedure is invoked to process the "coords" widget | |
223 | * command on rectangles and ovals. See the user documentation | |
224 | * for details on what it does. | |
225 | * | |
226 | * Results: | |
227 | * Returns TCL_OK or TCL_ERROR, and sets canvasPtr->interp->result. | |
228 | * | |
229 | * Side effects: | |
230 | * The coordinates for the given item may be changed. | |
231 | * | |
232 | *-------------------------------------------------------------- | |
233 | */ | |
234 | ||
235 | static int | |
236 | RectOvalCoords(canvasPtr, itemPtr, argc, argv) | |
237 | register Tk_Canvas *canvasPtr; /* Canvas containing item. */ | |
238 | Tk_Item *itemPtr; /* Item whose coordinates are to be | |
239 | * read or modified. */ | |
240 | int argc; /* Number of coordinates supplied in | |
241 | * argv. */ | |
242 | char **argv; /* Array of coordinates: x1, y1, | |
243 | * x2, y2, ... */ | |
244 | { | |
245 | register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; | |
246 | char buffer[500]; | |
247 | ||
248 | if (argc == 0) { | |
249 | sprintf(buffer, "%g %g %g %g", rectOvalPtr->bbox[0], | |
250 | rectOvalPtr->bbox[1], rectOvalPtr->bbox[2], | |
251 | rectOvalPtr->bbox[3]); | |
252 | Tcl_SetResult(canvasPtr->interp, buffer, TCL_VOLATILE); | |
253 | } else if (argc == 4) { | |
254 | if ((TkGetCanvasCoord(canvasPtr, argv[0], | |
255 | &rectOvalPtr->bbox[0]) != TCL_OK) | |
256 | || (TkGetCanvasCoord(canvasPtr, argv[1], | |
257 | &rectOvalPtr->bbox[1]) != TCL_OK) | |
258 | || (TkGetCanvasCoord(canvasPtr, argv[2], | |
259 | &rectOvalPtr->bbox[2]) != TCL_OK) | |
260 | || (TkGetCanvasCoord(canvasPtr, argv[3], | |
261 | &rectOvalPtr->bbox[3]) != TCL_OK)) { | |
262 | return TCL_ERROR; | |
263 | } | |
264 | ComputeRectOvalBbox(canvasPtr, rectOvalPtr); | |
265 | } else { | |
266 | sprintf(canvasPtr->interp->result, | |
267 | "wrong # coordinates: expected 0 or 4, got %d", | |
268 | argc); | |
269 | return TCL_ERROR; | |
270 | } | |
271 | return TCL_OK; | |
272 | } | |
273 | \f | |
274 | /* | |
275 | *-------------------------------------------------------------- | |
276 | * | |
277 | * ConfigureRectOval -- | |
278 | * | |
279 | * This procedure is invoked to configure various aspects | |
280 | * of a rectangle or oval item, such as its border and | |
281 | * background colors. | |
282 | * | |
283 | * Results: | |
284 | * A standard Tcl result code. If an error occurs, then | |
285 | * an error message is left in canvasPtr->interp->result. | |
286 | * | |
287 | * Side effects: | |
288 | * Configuration information, such as colors and stipple | |
289 | * patterns, may be set for itemPtr. | |
290 | * | |
291 | *-------------------------------------------------------------- | |
292 | */ | |
293 | ||
294 | static int | |
295 | ConfigureRectOval(canvasPtr, itemPtr, argc, argv, flags) | |
296 | Tk_Canvas *canvasPtr; /* Canvas containing itemPtr. */ | |
297 | Tk_Item *itemPtr; /* Rectangle item to reconfigure. */ | |
298 | int argc; /* Number of elements in argv. */ | |
299 | char **argv; /* Arguments describing things to configure. */ | |
300 | int flags; /* Flags to pass to Tk_ConfigureWidget. */ | |
301 | { | |
302 | register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; | |
303 | XGCValues gcValues; | |
304 | GC newGC; | |
305 | unsigned long mask; | |
306 | ||
307 | if (Tk_ConfigureWidget(canvasPtr->interp, canvasPtr->tkwin, | |
308 | configSpecs, argc, argv, (char *) rectOvalPtr, flags) != TCL_OK) { | |
309 | return TCL_ERROR; | |
310 | } | |
311 | ||
312 | /* | |
313 | * A few of the options require additional processing, such as | |
314 | * graphics contexts. | |
315 | */ | |
316 | ||
317 | if (rectOvalPtr->outlineColor == NULL) { | |
318 | newGC = None; | |
319 | } else { | |
320 | gcValues.foreground = rectOvalPtr->outlineColor->pixel; | |
321 | gcValues.cap_style = CapProjecting; | |
322 | if (rectOvalPtr->width < 0) { | |
323 | rectOvalPtr->width = 1; | |
324 | } | |
325 | gcValues.line_width = rectOvalPtr->width; | |
326 | mask = GCForeground|GCCapStyle|GCLineWidth; | |
327 | newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues); | |
328 | } | |
329 | if (rectOvalPtr->outlineGC != None) { | |
330 | Tk_FreeGC(rectOvalPtr->outlineGC); | |
331 | } | |
332 | rectOvalPtr->outlineGC = newGC; | |
333 | ||
334 | if (rectOvalPtr->fillColor == NULL) { | |
335 | newGC = None; | |
336 | } else { | |
337 | gcValues.foreground = rectOvalPtr->fillColor->pixel; | |
338 | if (rectOvalPtr->fillStipple != None) { | |
339 | gcValues.stipple = rectOvalPtr->fillStipple; | |
340 | gcValues.fill_style = FillStippled; | |
341 | mask = GCForeground|GCStipple|GCFillStyle; | |
342 | } else { | |
343 | mask = GCForeground; | |
344 | } | |
345 | newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues); | |
346 | } | |
347 | if (rectOvalPtr->fillGC != None) { | |
348 | Tk_FreeGC(rectOvalPtr->fillGC); | |
349 | } | |
350 | rectOvalPtr->fillGC = newGC; | |
351 | ComputeRectOvalBbox(canvasPtr, rectOvalPtr); | |
352 | ||
353 | return TCL_OK; | |
354 | } | |
355 | \f | |
356 | /* | |
357 | *-------------------------------------------------------------- | |
358 | * | |
359 | * DeleteRectOval -- | |
360 | * | |
361 | * This procedure is called to clean up the data structure | |
362 | * associated with a rectangle or oval item. | |
363 | * | |
364 | * Results: | |
365 | * None. | |
366 | * | |
367 | * Side effects: | |
368 | * Resources associated with itemPtr are released. | |
369 | * | |
370 | *-------------------------------------------------------------- | |
371 | */ | |
372 | ||
373 | static void | |
374 | DeleteRectOval(itemPtr) | |
375 | Tk_Item *itemPtr; /* Item that is being deleted. */ | |
376 | { | |
377 | register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; | |
378 | ||
379 | if (rectOvalPtr->outlineColor != NULL) { | |
380 | Tk_FreeColor(rectOvalPtr->outlineColor); | |
381 | } | |
382 | if (rectOvalPtr->fillColor != NULL) { | |
383 | Tk_FreeColor(rectOvalPtr->fillColor); | |
384 | } | |
385 | if (rectOvalPtr->fillStipple != None) { | |
386 | Tk_FreeBitmap(rectOvalPtr->fillStipple); | |
387 | } | |
388 | if (rectOvalPtr->outlineGC != None) { | |
389 | Tk_FreeGC(rectOvalPtr->outlineGC); | |
390 | } | |
391 | if (rectOvalPtr->fillGC != None) { | |
392 | Tk_FreeGC(rectOvalPtr->fillGC); | |
393 | } | |
394 | } | |
395 | \f | |
396 | /* | |
397 | *-------------------------------------------------------------- | |
398 | * | |
399 | * ComputeRectOvalBbox -- | |
400 | * | |
401 | * This procedure is invoked to compute the bounding box of | |
402 | * all the pixels that may be drawn as part of a rectangle | |
403 | * or oval. | |
404 | * | |
405 | * Results: | |
406 | * None. | |
407 | * | |
408 | * Side effects: | |
409 | * The fields x1, y1, x2, and y2 are updated in the header | |
410 | * for itemPtr. | |
411 | * | |
412 | *-------------------------------------------------------------- | |
413 | */ | |
414 | ||
415 | /* ARGSUSED */ | |
416 | static void | |
417 | ComputeRectOvalBbox(canvasPtr, rectOvalPtr) | |
418 | Tk_Canvas *canvasPtr; /* Canvas that contains item. */ | |
419 | register RectOvalItem *rectOvalPtr; /* Item whose bbox is to be | |
420 | * recomputed. */ | |
421 | { | |
422 | int bloat; | |
423 | ||
424 | /* | |
425 | * Make sure that the first coordinates are the lowest ones. | |
426 | */ | |
427 | ||
428 | if (rectOvalPtr->bbox[1] > rectOvalPtr->bbox[3]) { | |
429 | double tmp; | |
430 | tmp = rectOvalPtr->bbox[3]; | |
431 | rectOvalPtr->bbox[3] = rectOvalPtr->bbox[1]; | |
432 | rectOvalPtr->bbox[1] = tmp; | |
433 | } | |
434 | if (rectOvalPtr->bbox[0] > rectOvalPtr->bbox[2]) { | |
435 | double tmp; | |
436 | tmp = rectOvalPtr->bbox[2]; | |
437 | rectOvalPtr->bbox[2] = rectOvalPtr->bbox[0]; | |
438 | rectOvalPtr->bbox[0] = tmp; | |
439 | } | |
440 | ||
441 | bloat = (rectOvalPtr->width+1)/2 + 1; | |
442 | rectOvalPtr->header.x1 = rectOvalPtr->bbox[0] - bloat; | |
443 | rectOvalPtr->header.y1 = rectOvalPtr->bbox[1] - bloat; | |
444 | rectOvalPtr->header.x2 = rectOvalPtr->bbox[2] + bloat; | |
445 | rectOvalPtr->header.y2 = rectOvalPtr->bbox[3] + bloat; | |
446 | } | |
447 | \f | |
448 | /* | |
449 | *-------------------------------------------------------------- | |
450 | * | |
451 | * DisplayRectOval -- | |
452 | * | |
453 | * This procedure is invoked to draw a rectangle or oval | |
454 | * item in a given drawable. | |
455 | * | |
456 | * Results: | |
457 | * None. | |
458 | * | |
459 | * Side effects: | |
460 | * ItemPtr is drawn in drawable using the transformation | |
461 | * information in canvasPtr. | |
462 | * | |
463 | *-------------------------------------------------------------- | |
464 | */ | |
465 | ||
466 | static void | |
467 | DisplayRectOval(canvasPtr, itemPtr, drawable) | |
468 | register Tk_Canvas *canvasPtr; /* Canvas that contains item. */ | |
469 | Tk_Item *itemPtr; /* Item to be displayed. */ | |
470 | Drawable drawable; /* Pixmap or window in which to draw | |
471 | * item. */ | |
472 | { | |
473 | register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; | |
474 | Display *display = Tk_Display(canvasPtr->tkwin); | |
475 | int x1, y1, x2, y2; | |
476 | ||
477 | /* | |
478 | * Compute the screen coordinates of the bounding box for the item. | |
479 | * Make sure that the bbox is at least one pixel large, since some | |
480 | * X servers will die if it isn't. | |
481 | */ | |
482 | ||
483 | x1 = SCREEN_X(canvasPtr, rectOvalPtr->bbox[0]); | |
484 | y1 = SCREEN_Y(canvasPtr, rectOvalPtr->bbox[1]); | |
485 | x2 = SCREEN_X(canvasPtr, rectOvalPtr->bbox[2]); | |
486 | y2 = SCREEN_Y(canvasPtr, rectOvalPtr->bbox[3]); | |
487 | if (x2 <= x1) { | |
488 | x2 = x1+1; | |
489 | } | |
490 | if (y2 <= y1) { | |
491 | y2 = y1+1; | |
492 | } | |
493 | ||
494 | /* | |
495 | * Display filled box first (if wanted), then outline. | |
496 | */ | |
497 | ||
498 | if (rectOvalPtr->fillGC != None) { | |
499 | if (rectOvalPtr->header.typePtr == &TkRectangleType) { | |
500 | XFillRectangle(display, drawable, rectOvalPtr->fillGC, | |
501 | x1, y1, (unsigned int) (x2-x1), (unsigned int) (y2-y1)); | |
502 | } else { | |
503 | XFillArc(display, drawable, rectOvalPtr->fillGC, | |
504 | x1, y1, (x2-x1), (y2-y1), 0, 360*64); | |
505 | } | |
506 | } | |
507 | if (rectOvalPtr->outlineGC != None) { | |
508 | if (rectOvalPtr->header.typePtr == &TkRectangleType) { | |
509 | XDrawRectangle(display, drawable, rectOvalPtr->outlineGC, | |
510 | x1, y1, (x2-x1-1), (y2-y1-1)); | |
511 | } else { | |
512 | XDrawArc(display, drawable, rectOvalPtr->outlineGC, | |
513 | x1, y1, (x2-x1-1), (y2-y1-1), 0, 360*64); | |
514 | } | |
515 | } | |
516 | } | |
517 | \f | |
518 | /* | |
519 | *-------------------------------------------------------------- | |
520 | * | |
521 | * RectToPoint -- | |
522 | * | |
523 | * Computes the distance from a given point to a given | |
524 | * rectangle, in canvas units. | |
525 | * | |
526 | * Results: | |
527 | * The return value is 0 if the point whose x and y coordinates | |
528 | * are coordPtr[0] and coordPtr[1] is inside the rectangle. If the | |
529 | * point isn't inside the rectangle then the return value is the | |
530 | * distance from the point to the rectangle. If itemPtr is filled, | |
531 | * then anywhere in the interior is considered "inside"; if | |
532 | * itemPtr isn't filled, then "inside" means only the area | |
533 | * occupied by the outline. | |
534 | * | |
535 | * Side effects: | |
536 | * None. | |
537 | * | |
538 | *-------------------------------------------------------------- | |
539 | */ | |
540 | ||
541 | /* ARGSUSED */ | |
542 | static double | |
543 | RectToPoint(canvasPtr, itemPtr, pointPtr) | |
544 | Tk_Canvas *canvasPtr; /* Canvas containing item. */ | |
545 | Tk_Item *itemPtr; /* Item to check against point. */ | |
546 | double *pointPtr; /* Pointer to x and y coordinates. */ | |
547 | { | |
548 | register RectOvalItem *rectPtr = (RectOvalItem *) itemPtr; | |
549 | double xDiff, yDiff, x1, y1, x2, y2, inc, tmp; | |
550 | ||
551 | /* | |
552 | * Generate a new larger rectangle that includes the border | |
553 | * width, if there is one. | |
554 | */ | |
555 | ||
556 | x1 = rectPtr->bbox[0]; | |
557 | y1 = rectPtr->bbox[1]; | |
558 | x2 = rectPtr->bbox[2]; | |
559 | y2 = rectPtr->bbox[3]; | |
560 | if (rectPtr->outlineGC != None) { | |
561 | inc = rectPtr->width/2.0; | |
562 | x1 -= inc; | |
563 | y1 -= inc; | |
564 | x2 += inc; | |
565 | y2 += inc; | |
566 | } | |
567 | ||
568 | /* | |
569 | * If the point is inside the rectangle, handle specially: | |
570 | * distance is 0 if rectangle is filled, otherwise compute | |
571 | * distance to nearest edge of rectangle and subtract width | |
572 | * of edge. | |
573 | */ | |
574 | ||
575 | if ((pointPtr[0] >= x1) && (pointPtr[0] < x2) | |
576 | && (pointPtr[1] >= y1) && (pointPtr[1] < y2)) { | |
577 | if ((rectPtr->fillGC != None) || (rectPtr->outlineGC == None)) { | |
578 | return 0.0; | |
579 | } | |
580 | xDiff = pointPtr[0] - x1; | |
581 | tmp = x2 - pointPtr[0]; | |
582 | if (tmp < xDiff) { | |
583 | xDiff = tmp; | |
584 | } | |
585 | yDiff = pointPtr[1] - y1; | |
586 | tmp = y2 - pointPtr[1]; | |
587 | if (tmp < yDiff) { | |
588 | yDiff = tmp; | |
589 | } | |
590 | if (yDiff < xDiff) { | |
591 | xDiff = yDiff; | |
592 | } | |
593 | xDiff -= rectPtr->width; | |
594 | if (xDiff < 0.0) { | |
595 | return 0.0; | |
596 | } | |
597 | return xDiff; | |
598 | } | |
599 | ||
600 | /* | |
601 | * Point is outside rectangle. | |
602 | */ | |
603 | ||
604 | if (pointPtr[0] < x1) { | |
605 | xDiff = x1 - pointPtr[0]; | |
606 | } else if (pointPtr[0] > x2) { | |
607 | xDiff = pointPtr[0] - x2; | |
608 | } else { | |
609 | xDiff = 0; | |
610 | } | |
611 | ||
612 | if (pointPtr[1] < y1) { | |
613 | yDiff = y1 - pointPtr[1]; | |
614 | } else if (pointPtr[1] > y2) { | |
615 | yDiff = pointPtr[1] - y2; | |
616 | } else { | |
617 | yDiff = 0; | |
618 | } | |
619 | ||
620 | return hypot(xDiff, yDiff); | |
621 | } | |
622 | \f | |
623 | /* | |
624 | *-------------------------------------------------------------- | |
625 | * | |
626 | * OvalToPoint -- | |
627 | * | |
628 | * Computes the distance from a given point to a given | |
629 | * oval, in canvas units. | |
630 | * | |
631 | * Results: | |
632 | * The return value is 0 if the point whose x and y coordinates | |
633 | * are coordPtr[0] and coordPtr[1] is inside the oval. If the | |
634 | * point isn't inside the oval then the return value is the | |
635 | * distance from the point to the oval. If itemPtr is filled, | |
636 | * then anywhere in the interior is considered "inside"; if | |
637 | * itemPtr isn't filled, then "inside" means only the area | |
638 | * occupied by the outline. | |
639 | * | |
640 | * Side effects: | |
641 | * None. | |
642 | * | |
643 | *-------------------------------------------------------------- | |
644 | */ | |
645 | ||
646 | /* ARGSUSED */ | |
647 | static double | |
648 | OvalToPoint(canvasPtr, itemPtr, pointPtr) | |
649 | Tk_Canvas *canvasPtr; /* Canvas containing item. */ | |
650 | Tk_Item *itemPtr; /* Item to check against point. */ | |
651 | double *pointPtr; /* Pointer to x and y coordinates. */ | |
652 | { | |
653 | register RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr; | |
654 | double width; | |
655 | int filled; | |
656 | ||
657 | width = ovalPtr->width; | |
658 | filled = ovalPtr->fillGC != None; | |
659 | if (ovalPtr->outlineGC == None) { | |
660 | width = 0.0; | |
661 | filled = 1; | |
662 | } | |
663 | return TkOvalToPoint(ovalPtr->bbox, width, filled, pointPtr); | |
664 | } | |
665 | \f | |
666 | /* | |
667 | *-------------------------------------------------------------- | |
668 | * | |
669 | * RectToArea -- | |
670 | * | |
671 | * This procedure is called to determine whether an item | |
672 | * lies entirely inside, entirely outside, or overlapping | |
673 | * a given rectangle. | |
674 | * | |
675 | * Results: | |
676 | * -1 is returned if the item is entirely outside the area | |
677 | * given by rectPtr, 0 if it overlaps, and 1 if it is entirely | |
678 | * inside the given area. | |
679 | * | |
680 | * Side effects: | |
681 | * None. | |
682 | * | |
683 | *-------------------------------------------------------------- | |
684 | */ | |
685 | ||
686 | /* ARGSUSED */ | |
687 | static int | |
688 | RectToArea(canvasPtr, itemPtr, areaPtr) | |
689 | Tk_Canvas *canvasPtr; /* Canvas containing item. */ | |
690 | Tk_Item *itemPtr; /* Item to check against rectangle. */ | |
691 | double *areaPtr; /* Pointer to array of four coordinates | |
692 | * (x1, y1, x2, y2) describing rectangular | |
693 | * area. */ | |
694 | { | |
695 | register RectOvalItem *rectPtr = (RectOvalItem *) itemPtr; | |
696 | double halfWidth; | |
697 | ||
698 | halfWidth = rectPtr->width/2.0; | |
699 | if (rectPtr->outlineGC == None) { | |
700 | halfWidth = 0.0; | |
701 | } | |
702 | ||
703 | if ((areaPtr[2] <= (rectPtr->bbox[0] - halfWidth)) | |
704 | || (areaPtr[0] >= (rectPtr->bbox[2] + halfWidth)) | |
705 | || (areaPtr[3] <= (rectPtr->bbox[1] - halfWidth)) | |
706 | || (areaPtr[1] >= (rectPtr->bbox[3] + halfWidth))) { | |
707 | return -1; | |
708 | } | |
709 | if ((rectPtr->fillGC == None) && (rectPtr->outlineGC != None) | |
710 | && (areaPtr[0] >= (rectPtr->bbox[0] + halfWidth)) | |
711 | && (areaPtr[1] >= (rectPtr->bbox[1] + halfWidth)) | |
712 | && (areaPtr[2] <= (rectPtr->bbox[2] - halfWidth)) | |
713 | && (areaPtr[3] <= (rectPtr->bbox[3] - halfWidth))) { | |
714 | return -1; | |
715 | } | |
716 | if ((areaPtr[0] <= (rectPtr->bbox[0] - halfWidth)) | |
717 | && (areaPtr[1] <= (rectPtr->bbox[1] - halfWidth)) | |
718 | && (areaPtr[2] >= (rectPtr->bbox[2] + halfWidth)) | |
719 | && (areaPtr[3] >= (rectPtr->bbox[3] + halfWidth))) { | |
720 | return 1; | |
721 | } | |
722 | return 0; | |
723 | } | |
724 | \f | |
725 | /* | |
726 | *-------------------------------------------------------------- | |
727 | * | |
728 | * OvalToArea -- | |
729 | * | |
730 | * This procedure is called to determine whether an item | |
731 | * lies entirely inside, entirely outside, or overlapping | |
732 | * a given rectangular area. | |
733 | * | |
734 | * Results: | |
735 | * -1 is returned if the item is entirely outside the area | |
736 | * given by rectPtr, 0 if it overlaps, and 1 if it is entirely | |
737 | * inside the given area. | |
738 | * | |
739 | * Side effects: | |
740 | * None. | |
741 | * | |
742 | *-------------------------------------------------------------- | |
743 | */ | |
744 | ||
745 | /* ARGSUSED */ | |
746 | static int | |
747 | OvalToArea(canvasPtr, itemPtr, areaPtr) | |
748 | Tk_Canvas *canvasPtr; /* Canvas containing item. */ | |
749 | Tk_Item *itemPtr; /* Item to check against oval. */ | |
750 | double *areaPtr; /* Pointer to array of four coordinates | |
751 | * (x1, y1, x2, y2) describing rectangular | |
752 | * area. */ | |
753 | { | |
754 | register RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr; | |
755 | double oval[4], halfWidth; | |
756 | int result; | |
757 | ||
758 | /* | |
759 | * Expand the oval to include the width of the outline, if any. | |
760 | */ | |
761 | ||
762 | halfWidth = ovalPtr->width/2.0; | |
763 | if (ovalPtr->outlineGC == None) { | |
764 | halfWidth = 0.0; | |
765 | } | |
766 | oval[0] = ovalPtr->bbox[0] - halfWidth; | |
767 | oval[1] = ovalPtr->bbox[1] - halfWidth; | |
768 | oval[2] = ovalPtr->bbox[2] + halfWidth; | |
769 | oval[3] = ovalPtr->bbox[3] + halfWidth; | |
770 | ||
771 | result = TkOvalToArea(oval, areaPtr); | |
772 | ||
773 | /* | |
774 | * If the rectangle appears to overlap the oval and the oval | |
775 | * isn't filled, do one more check to see if perhaps all four | |
776 | * of the rectangle's corners are totally inside the oval's | |
777 | * unfilled center, in which case we should return "outside". | |
778 | */ | |
779 | ||
780 | if ((result == 0) && (ovalPtr->outlineGC != NULL) | |
781 | && (ovalPtr->fillGC == NULL)) { | |
782 | double centerX, centerY, width, height; | |
783 | double xDelta1, yDelta1, xDelta2, yDelta2; | |
784 | ||
785 | centerX = (ovalPtr->bbox[0] + ovalPtr->bbox[2])/2.0; | |
786 | centerY = (ovalPtr->bbox[1] + ovalPtr->bbox[3])/2.0; | |
787 | width = (ovalPtr->bbox[2] - ovalPtr->bbox[0])/2.0 - halfWidth; | |
788 | height = (ovalPtr->bbox[3] - ovalPtr->bbox[1])/2.0 - halfWidth; | |
789 | xDelta1 = (areaPtr[0] - centerX)/width; | |
790 | xDelta1 *= xDelta1; | |
791 | yDelta1 = (areaPtr[1] - centerY)/height; | |
792 | yDelta1 *= yDelta1; | |
793 | xDelta2 = (areaPtr[2] - centerX)/width; | |
794 | xDelta2 *= xDelta2; | |
795 | yDelta2 = (areaPtr[3] - centerY)/height; | |
796 | yDelta2 *= yDelta2; | |
797 | if (((xDelta1 + yDelta1) < 1.0) | |
798 | && ((xDelta1 + yDelta2) < 1.0) | |
799 | && ((xDelta2 + yDelta1) < 1.0) | |
800 | && ((xDelta2 + yDelta2) < 1.0)) { | |
801 | return -1; | |
802 | } | |
803 | } | |
804 | return result; | |
805 | } | |
806 | \f | |
807 | /* | |
808 | *-------------------------------------------------------------- | |
809 | * | |
810 | * ScaleRectOval -- | |
811 | * | |
812 | * This procedure is invoked to rescale a rectangle or oval | |
813 | * item. | |
814 | * | |
815 | * Results: | |
816 | * None. | |
817 | * | |
818 | * Side effects: | |
819 | * The rectangle or oval referred to by itemPtr is rescaled | |
820 | * so that the following transformation is applied to all | |
821 | * point coordinates: | |
822 | * x' = originX + scaleX*(x-originX) | |
823 | * y' = originY + scaleY*(y-originY) | |
824 | * | |
825 | *-------------------------------------------------------------- | |
826 | */ | |
827 | ||
828 | static void | |
829 | ScaleRectOval(canvasPtr, itemPtr, originX, originY, scaleX, scaleY) | |
830 | Tk_Canvas *canvasPtr; /* Canvas containing rectangle. */ | |
831 | Tk_Item *itemPtr; /* Rectangle to be scaled. */ | |
832 | double originX, originY; /* Origin about which to scale rect. */ | |
833 | double scaleX; /* Amount to scale in X direction. */ | |
834 | double scaleY; /* Amount to scale in Y direction. */ | |
835 | { | |
836 | register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; | |
837 | ||
838 | rectOvalPtr->bbox[0] = originX + scaleX*(rectOvalPtr->bbox[0] - originX); | |
839 | rectOvalPtr->bbox[1] = originY + scaleY*(rectOvalPtr->bbox[1] - originY); | |
840 | rectOvalPtr->bbox[2] = originX + scaleX*(rectOvalPtr->bbox[2] - originX); | |
841 | rectOvalPtr->bbox[3] = originY + scaleY*(rectOvalPtr->bbox[3] - originY); | |
842 | ComputeRectOvalBbox(canvasPtr, rectOvalPtr); | |
843 | } | |
844 | \f | |
845 | /* | |
846 | *-------------------------------------------------------------- | |
847 | * | |
848 | * TranslateRectOval -- | |
849 | * | |
850 | * This procedure is called to move a rectangle or oval by a | |
851 | * given amount. | |
852 | * | |
853 | * Results: | |
854 | * None. | |
855 | * | |
856 | * Side effects: | |
857 | * The position of the rectangle or oval is offset by | |
858 | * (xDelta, yDelta), and the bounding box is updated in the | |
859 | * generic part of the item structure. | |
860 | * | |
861 | *-------------------------------------------------------------- | |
862 | */ | |
863 | ||
864 | static void | |
865 | TranslateRectOval(canvasPtr, itemPtr, deltaX, deltaY) | |
866 | Tk_Canvas *canvasPtr; /* Canvas containing item. */ | |
867 | Tk_Item *itemPtr; /* Item that is being moved. */ | |
868 | double deltaX, deltaY; /* Amount by which item is to be | |
869 | * moved. */ | |
870 | { | |
871 | register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; | |
872 | ||
873 | rectOvalPtr->bbox[0] += deltaX; | |
874 | rectOvalPtr->bbox[1] += deltaY; | |
875 | rectOvalPtr->bbox[2] += deltaX; | |
876 | rectOvalPtr->bbox[3] += deltaY; | |
877 | ComputeRectOvalBbox(canvasPtr, rectOvalPtr); | |
878 | } |