|
|
1.1 root 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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.