home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / tcl / tk3.3b1 / tkRectOval.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-26  |  30.4 KB  |  1,000 lines

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