home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tkisrc04.zip / tk / os2 / tkRectOval.c < prev    next >
C/C++ Source or Header  |  1998-08-07  |  31KB  |  1,031 lines

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