home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / demo / winddemo.sit / iconwind.c.bin / iconwind.c
Encoding:
C/C++ Source or Header  |  1989-05-02  |  25.8 KB  |  985 lines  |  [TEXT/KAHL]

  1. /*
  2.  * iconwindow.c - a custom Window Definition procedure.
  3.  *
  4.  * The window implemented here behaves just like a standard window,
  5.  * but with one twist:
  6.  * if the window is less than a certain size, it is drawn differently.
  7.  *
  8.  * A small window (called "collapsed" here) has its title box below the window
  9.  * contents (rather than above).  The title is drawn in a smaller font and
  10.  * on a separate line from the close and zoom boxes.
  11.  *
  12.  * A collapsed window's grow region occupies the entire window contents.
  13.  * It has no grow icon.
  14.  *
  15.  * To use this WDEF, create a window with a ProcID of 4120
  16.  * (16 x iconwind's ID of 257, +8 for zooming) or 4112
  17.  * (if you don't want zooming).
  18.  *
  19.  * Brad Needham
  20.  * 2239 SE 74th Ave.
  21.  * Hillsboro, OR 97123    USA
  22.  */
  23.  
  24. #include <MemoryMgr.h>
  25. #include <Quickdraw.h>
  26. #include <WindowMgr.h>
  27. #include <FontMgr.h>
  28.  
  29. /*
  30.  * SMALLWIDTH,
  31.  * SMALLHEIGHT    - largest dimensions of a collapsed-state window's portRect.
  32.  *  Any window larger than this (in both dimensions) is drawn in its
  33.  *  uncollapsed state.
  34.  *
  35.  * NOTE: don't change these numbers -- the applications need to use them
  36.  * to tell whether a window is collapsed or not.
  37.  */
  38.  
  39. #define SMALLWIDTH    63
  40. #define SMALLHEIGHT    15
  41.  
  42. /*
  43.  * TITLEFONT
  44.  * TITLESTYLE
  45.  * TITLEFSIZE    - The look of the title in a collapsed window.
  46.  *                  These values are the same ones the finder uses.
  47.  *
  48.  * NOTE: If you change these constants, you will need to recalculate piles
  49.  * of hard-coded numbers in this file.
  50.  */
  51.  
  52. #define TITLEFONT geneva
  53. #define TITLESTYLE ((Style) 0)
  54. #define TITLEFSIZE 9
  55.  
  56. /*
  57.  * SMALLCHANGE - largest difference from the "Standard State"
  58.  * window size and position that is still considered the "Standard State".
  59.  *
  60.  * A window that has moved or resized more than this number of pixels
  61.  * goes into the "User State".
  62.  *
  63.  * This number comes from Inside Macintosh IV, page 10.
  64.  */
  65.  
  66. #define SMALLCHANGE 7
  67.  
  68. #define BOXWIDSMALL     9    /* pixels width (and height) of a close/zoom-box */
  69. #define BOXWIDBIG    11    /* ditto in a normal-size window */
  70. #define BOXHMARGIN     2    /* horizontal margin around a small box */
  71.  
  72. /*
  73.  * struct wdims - interesting areas of a window.
  74.  *     wcalcdims() calculates these values.
  75.  */
  76.  
  77. struct wdims {
  78.     Rect contrect;    /* bounds of the content region */
  79.     Rect titlerect;    /* the title bar (and it's frame) */
  80.     Rect textclip;    /* a clip rectangle for the title string */
  81.     Point titleref;    /* starting point for drawing the title text */
  82.     Rect closerect;    /* the close box and frame */
  83.     Rect zoomrect;    /* the zoom box and frame */
  84.     Rect growrect;    /* the grow rectangle */
  85. };
  86.  
  87. /*
  88.  * main() - the entry-point to our custom window definition.
  89.  *
  90.  * Because the WDEF must be a pure-code resource,
  91.  * we can't use any global or static data,
  92.  * which forces us to recalculate a lot of information each time we're called.
  93.  */
  94.  
  95. pascal long
  96. main(varcode, windp, op, parm)
  97. int varcode;        /* window variation code */
  98. WindowPeek windp;    /* the window to operate on */
  99. int op;                /* the operation to perform */
  100. long parm;            /* the parameter of the operation (if any) */
  101. {
  102.     long retval;        /* the value to return */
  103.     long wfindhit();
  104.     
  105.     retval = 0L;
  106.      
  107.     switch(op) {
  108.     case wNew:                /* do our custom initialization */
  109.         winit(windp, varcode);
  110.         break;
  111.     case wDispose:            /* do our custom disposal */
  112.         wcleanup(windp);
  113.         break;
  114.     case wCalcRgns:            /* calculate the important window regions */
  115.         wregions(windp);
  116.         break;
  117.     case wDraw:                /* draw an interesting piece (if visible) */
  118.         if (windp->visible) {
  119.             if ((int) parm == 0) {
  120.                 wdrawframe(windp);
  121.             } else {
  122.                 wtoggle_box(windp, (int) parm);
  123.             }
  124.         }
  125.         break;
  126.     case wHit:                /* see which region the mouse is in */
  127.         retval = wfindhit(windp, LoWord(parm), HiWord(parm));
  128.         break;
  129.     case wGrow:                /* draw the window's growing image */
  130.         woutline(windp, (Rect *) parm);
  131.         break;
  132.     case wDrawGIcon:        /* draw the size box */
  133.         wgicon(windp);
  134.         break;
  135.     }
  136.     return(retval);
  137. }
  138.  
  139. /*
  140.  * winit() - initialize the given window.
  141.  */
  142.  
  143. winit(windp, varcode)
  144. WindowPeek windp;
  145. int varcode;            /* the window's variation code */
  146. {
  147.     GrafPtr myport;        /* the window manager port */
  148.     WStateData *wsp;
  149.     
  150.     GetPort(&myport);
  151.  
  152.     /*
  153.      * If the user has requested a zoomable window,
  154.      * we need to allocate the zoom information.
  155.      */
  156.     
  157.     if (varcode & 0x8) {
  158.         windp->dataHandle = NewHandle((Size) sizeof(WStateData));
  159.     } else {
  160.         windp->dataHandle = (Handle) 0;
  161.     }
  162.     
  163.     /*
  164.      * If the allocation failed or the user didn't ask for zooming,
  165.      * Leave spareFlag alone (zero), indicating we don't zoom.
  166.      * Otherwise, set the spareFlag to indicate we're a zoomable window.
  167.      */
  168.     
  169.     if (!windp->dataHandle) {
  170.         return;
  171.     }
  172.     windp->spareFlag = 1;
  173.     
  174.     /*
  175.      * The default Standard State is a little less than the bounds
  176.      * of the screen. (This code should be modded to support multiple screens.)
  177.      *
  178.      * The userState is the user's port, mapped into global coordinates.
  179.      */
  180.  
  181.     HLock(windp->dataHandle);
  182.     wsp = (WStateData *) *(windp->dataHandle);
  183.     
  184.     wsp->stdState = myport->portRect;
  185.     wsp->stdState.top += 38;        /* space for the menubar and title bar */
  186.     InsetRect(&wsp->stdState, 3, 3);
  187.     
  188.     wsp->userState = windp->port.portRect;
  189.     OffsetRect(&wsp->userState,
  190.       -windp->port.portBits.bounds.left,
  191.       -windp->port.portBits.bounds.top);
  192.     
  193.     HUnlock(windp->dataHandle);
  194. }
  195.  
  196. /*
  197.  * wcleanup() - dispose of the special parts of the window.
  198.  */
  199.  
  200. wcleanup(windp)
  201. WindowPeek windp;
  202. {
  203.     if (windp->spareFlag != 0) {
  204.         DisposHandle(windp->dataHandle);
  205.     }
  206. }
  207.  
  208. /*
  209.  * wregions() - calculate the window's structure and content regions
  210.  * based on the current GrafPort's portRect.
  211.  * These regions are in global coordinates.
  212.  *
  213.  * Calling this routine can change the userState (unzoomed state) of the window.
  214.  */
  215.  
  216. wregions(windp)
  217. WindowPeek windp;
  218. {
  219.     struct wdims dim;    /* dimensions of the window */
  220.     WStateData *wsp;    /* the window's zoomed and unzoomed state */
  221.     int v;                /* a temporary vertical position */
  222.     
  223.     /*
  224.      * If we can zoom and we are in the un-zoomed ("User") state,
  225.      * record the new un-zoomed size and position of the window.
  226.      */
  227.  
  228.     if (windp->spareFlag && zoompart(windp) == wInZoomOut) {
  229.         HLock(windp->dataHandle);
  230.         wsp = (WStateData *) *(windp->dataHandle);
  231.         
  232.         wsp->userState = windp->port.portRect;
  233.         OffsetRect(&wsp->userState,
  234.           -windp->port.portBits.bounds.left,
  235.           -windp->port.portBits.bounds.top);
  236.         
  237.         HUnlock(windp->dataHandle);
  238.     }
  239.  
  240.     wcalcdims(windp, (Rect *) 0, &dim);
  241.     
  242.     /*
  243.      * The content region calculation is straightforward.
  244.      * The Structure region calculation depends on whether the window
  245.      * is collapsed or not.
  246.      */
  247.     
  248.     RectRgn(windp->contRgn, &dim.contrect);
  249.  
  250.     OpenRgn();
  251.     if (is_smallrect(&dim.contrect)) {
  252.     
  253.         /*
  254.          * A collapsed window has a 1-pixel frame around the content box
  255.          * with a title box below the content box.
  256.          *
  257.          * Since the content box can be either larger or smaller than
  258.          * the title box, the enclosing region for one case is
  259.          * a little different than that for the other.
  260.          */
  261.         
  262.         if (dim.titlerect.right >= dim.contrect.right + 1) {
  263.             v = dim.titlerect.top;
  264.         } else {
  265.             v = dim.titlerect.top + 1;
  266.         }
  267.         
  268.         MoveTo(dim.contrect.left - 1, dim.contrect.top - 1);
  269.         LineTo(dim.contrect.right + 1, dim.contrect.top - 1);
  270.         LineTo(dim.contrect.right + 1, v);
  271.         LineTo(dim.titlerect.right, v);
  272.         LineTo(dim.titlerect.right, dim.titlerect.bottom);
  273.         LineTo(dim.titlerect.left, dim.titlerect.bottom);
  274.         LineTo(dim.titlerect.left, v);
  275.         LineTo(dim.contrect.left - 1, v);
  276.         LineTo(dim.contrect.left - 1, dim.contrect.top - 1);
  277.  
  278.     } else {
  279.     
  280.         /*
  281.          * A standard window is rectangular, but it has a 1-pixel shadow
  282.          * to its right and bottom.
  283.          */
  284.          
  285.         MoveTo(dim.titlerect.left, dim.titlerect.top);
  286.         LineTo(dim.titlerect.right, dim.titlerect.top);
  287.         LineTo(dim.titlerect.right, dim.titlerect.top + 1);
  288.         LineTo(dim.titlerect.right + 1, dim.titlerect.top + 1);
  289.         LineTo(dim.titlerect.right + 1, dim.contrect.bottom + 2);
  290.         LineTo(dim.titlerect.left + 1, dim.contrect.bottom + 2);
  291.         LineTo(dim.titlerect.left + 1, dim.contrect.bottom + 1);
  292.         LineTo(dim.titlerect.left, dim.contrect.bottom + 1);
  293.         LineTo(dim.titlerect.left, dim.titlerect.top);
  294.     }
  295.     CloseRgn(windp->strucRgn);
  296. }
  297.  
  298. /*
  299.  * wdrawframe() - draw the window frame in the current (window manager's) port.
  300.  * Assumes the window is visible.
  301.  */
  302.  
  303. wdrawframe(windp)
  304. WindowPeek windp;
  305. {
  306.     GrafPtr myport;        /* the current port */
  307.     struct wdims dim;    /* dimensions of the window */
  308.     int oldfont;        /* the original font to restore */
  309.     Style oldface;        /* its Style */
  310.     int oldsize;        /* its font size */
  311.     RgnHandle oldclip;    /* the original clipRgn to restore */
  312.     int v;                /* a temporary vertical coordinate */
  313.     Rect tmprect;        /* a temporary rectangle */
  314.     
  315.     wcalcdims(windp, (Rect *) 0, &dim);
  316.  
  317.     GetPort(&myport);
  318.     
  319.     if (is_smallrect(&dim.contrect)) {
  320.         
  321.         /*
  322.          * For a collapsed window,
  323.          * Always draw the border and the window title.
  324.          */
  325.         
  326.         tmprect = dim.contrect;
  327.         InsetRect(&tmprect, -1, -1);
  328.         FrameRect(&tmprect);
  329.         FrameRect(&dim.titlerect);
  330.         
  331.         tmprect = dim.titlerect;
  332.         InsetRect(&tmprect, 1, 1);
  333.         EraseRect(&tmprect);
  334.  
  335.         oldfont = myport->txFont;
  336.         oldface = myport->txFace;
  337.         oldsize = myport->txSize;
  338.         TextFont(TITLEFONT);
  339.         TextFace(TITLESTYLE);
  340.         TextSize(TITLEFSIZE);
  341.         
  342.         HLock((Handle) windp->titleHandle);
  343.         
  344.         MoveTo(dim.titleref.h, dim.titleref.v);
  345.         DrawString(*(windp->titleHandle));
  346.         
  347.         HUnlock((Handle) windp->titleHandle);
  348.         
  349.         TextFont(oldfont);
  350.         TextFace(oldface);
  351.         TextSize(oldsize);
  352.         
  353.         /*
  354.          * If the window is active,
  355.          * draw the close/zoom boxes (if they exist) and the selection lines.
  356.          */
  357.         
  358.         if (windp->hilited) {
  359.         
  360.             if (windp->goAwayFlag) {
  361.                 FrameRect(&dim.closerect);
  362.             }
  363.             
  364.             if (windp->spareFlag != 0) {
  365.                 FrameRect(&dim.zoomrect);
  366.                 MoveTo(dim.zoomrect.left,
  367.                   (dim.zoomrect.top + dim.zoomrect.bottom + 1) / 2);
  368.                 LineTo((dim.zoomrect.left + dim.zoomrect.right + 1) / 2,
  369.                   (dim.zoomrect.top + dim.zoomrect.bottom + 1) / 2);
  370.                 LineTo((dim.zoomrect.left + dim.zoomrect.right + 1) / 2,
  371.                   dim.zoomrect.top);
  372.             }
  373.             
  374.             for (v = dim.closerect.bottom - 1; v >= dim.closerect.top; v -= 2) {
  375.                 if (windp->goAwayFlag) {
  376.                     MoveTo(dim.closerect.right + BOXHMARGIN, v);
  377.                 } else {
  378.                     MoveTo(dim.closerect.left, v);
  379.                 }
  380.                 if (windp->spareFlag != 0) {
  381.                     LineTo(dim.zoomrect.left - BOXHMARGIN - 1, v);
  382.                 } else {
  383.                     LineTo(dim.zoomrect.right - 1, v);
  384.                 }
  385.             }
  386.         }
  387.     } else {
  388.         
  389.         /*
  390.          * For a standard (non-collapsed) window,
  391.          * Draw the border, the shadow, and the (clipped) window title.
  392.          */
  393.  
  394.         tmprect = dim.contrect;
  395.         InsetRect(&tmprect, -1, -1);
  396.         UnionRect(&tmprect, &dim.titlerect, &tmprect);
  397.         FrameRect(&tmprect);
  398.         
  399.         tmprect = dim.titlerect;
  400.         InsetRect(&tmprect, 1, 1);
  401.         EraseRect(&tmprect);
  402.         
  403.         MoveTo(dim.titlerect.left, dim.titlerect.bottom - 1);
  404.         LineTo(dim.titlerect.right - 1, dim.titlerect.bottom - 1);
  405.         
  406.         MoveTo(dim.titlerect.left + 1, dim.contrect.bottom + 1);
  407.         LineTo(dim.titlerect.right, dim.contrect.bottom + 1);
  408.         LineTo(dim.titlerect.right, dim.titlerect.top + 1);
  409.  
  410.         /*
  411.          * The window's title has to be clipped, in case it's too long for the
  412.          * window width.
  413.          */
  414.         
  415.         oldclip = NewRgn();
  416.         if (oldclip) {
  417.             GetClip(oldclip);
  418.             RectRgn(myport->clipRgn, &dim.textclip);
  419.             SectRgn(oldclip, myport->clipRgn, myport->clipRgn);
  420.         }
  421.         
  422.         HLock((Handle) windp->titleHandle);
  423.         MoveTo(dim.titleref.h, dim.titleref.v);
  424.         DrawString(*(windp->titleHandle));
  425.         HUnlock((Handle) windp->titleHandle);
  426.         
  427.         if (oldclip) {
  428.             SetClip(oldclip);
  429.             DisposeRgn(oldclip);
  430.         }
  431.         
  432.         /*
  433.          * If the window is active,
  434.          * draw the close/zoom boxes (if they exist) and the selection lines.
  435.          */
  436.         
  437.         if (windp->hilited) {
  438.         
  439.             if (windp->goAwayFlag) {
  440.                 FrameRect(&dim.closerect);
  441.             }
  442.             
  443.             if (windp->spareFlag != 0) {
  444.                 FrameRect(&dim.zoomrect);
  445.                 MoveTo(dim.zoomrect.left,
  446.                   (dim.zoomrect.top + dim.zoomrect.bottom + 1) / 2);
  447.                 LineTo((dim.zoomrect.left + dim.zoomrect.right + 1) / 2,
  448.                   (dim.zoomrect.top + dim.zoomrect.bottom) / 2 + 1);
  449.                 LineTo((dim.zoomrect.left + dim.zoomrect.right + 1) / 2,
  450.                   dim.zoomrect.top);
  451.             }
  452.             
  453.             for (v = dim.closerect.bottom - 1; v >= dim.closerect.top; v -= 2) {
  454.                 MoveTo(dim.titlerect.left + 2, v);
  455.                 if (windp->goAwayFlag) {
  456.                     LineTo(dim.closerect.left - 1 - 1, v);
  457.                     MoveTo(dim.closerect.right + 1, v);
  458.                 }
  459.                 LineTo(dim.textclip.left - 6 - 1, v);
  460.             
  461.                 MoveTo(dim.textclip.right + 5, v);
  462.                 if (windp->spareFlag != 0) {
  463.                     LineTo(dim.zoomrect.left - 1 - 1, v);
  464.                     MoveTo(dim.zoomrect.right + 1, v);
  465.                 }
  466.                 LineTo(dim.titlerect.right - 2 - 1, v);
  467.             }
  468.         }
  469.     }
  470. }
  471.  
  472. /*
  473.  * wgicon() - draw the grow icon (and scrollbar outlines, if necessary)
  474.  * for the given window.
  475.  *
  476.  * Remember we want to draw in the window's port rather than the managers port.
  477.  */
  478.  
  479. wgicon(windp)
  480. WindowPeek windp;
  481. {
  482.     GrafPtr oldport;    /* the original port to restore */
  483.     Rect windrect;        /* the content Rect of the window (in local coords) */
  484.     Rect iconrect;        /* the bounds of the grow icon */
  485.     BitMap bm;            /* a temporary bitmap containing the pattern to draw */
  486.     unsigned int block[16];    /* the 16 X 16 bit bitmap bm points to */
  487.     Rect tmprect;        /* a temporary rectangle */
  488.     
  489.     GetPort(&oldport);
  490.     SetPort(&windp->port);
  491.     
  492.     bm.baseAddr = (QDPtr) &block[0];
  493.     bm.rowBytes = 2;
  494.     bm.bounds.top = 0;
  495.     bm.bounds.left = 0;
  496.     bm.bounds.right = 16;
  497.     bm.bounds.bottom = 16;
  498.     
  499.     windrect = windp->port.portRect;
  500.     
  501.     if (is_smallrect(&windrect)) {
  502.     
  503.         /*
  504.          * Collapsed windows have no grow icon or scrollbars,
  505.          * so we draw nothing.
  506.          */
  507.  
  508.     } else {
  509.  
  510.         /*
  511.          * A Standard window.
  512.          *
  513.          * Draw (or erase) the Grow icon, depending on whether the window
  514.          * is active or not.
  515.          */
  516.         
  517.         iconrect.right = windrect.right + 1;
  518.         iconrect.bottom = windrect.bottom + 1;
  519.         iconrect.left = iconrect.right - 16;
  520.         iconrect.top = iconrect.bottom - 16;
  521.         
  522.         if (windp->hilited) {
  523.             block[0]  = 0xFFFF;
  524.             block[1]  = 0x8001;
  525.             block[2]  = 0x8001;
  526.             block[3]  = 0x9FC1;
  527.             block[4]  = 0x9041;
  528.             block[5]  = 0x907D;
  529.             block[6]  = 0x9045;
  530.             block[7]  = 0x9045;
  531.             block[8]  = 0x9045;
  532.             block[9]  = 0x9FC5;
  533.             block[10] = 0x8405;
  534.             block[11] = 0x8405;
  535.             block[12] = 0x8405;
  536.             block[13] = 0x87FD;
  537.             block[14] = 0x8001;
  538.             block[15] = 0xFFFF;
  539.             CopyBits(&bm, &windp->port.portBits, &bm.bounds, &iconrect,
  540.               srcCopy, (RgnHandle) 0);
  541.         } else {
  542.             tmprect = iconrect;
  543.             InsetRect(&tmprect, 1, 1);
  544.             EraseRect(&iconrect);
  545.         }
  546.         
  547.         /*
  548.          * Finally, draw the lines enclosing the scrollbars.
  549.          *
  550.          * (Personally, I'd prefer the application to draw these lines
  551.          * instead, depending on whether the window contains horizontal and
  552.          * vertical scrollbars.  This routine draws them to duplicate
  553.          * the flawed, but standard, behavior.)
  554.          */
  555.         
  556.         MoveTo(iconrect.left, windrect.top);
  557.         LineTo(iconrect.left, windrect.bottom - 1);
  558.         MoveTo(windrect.left, iconrect.top);
  559.         LineTo(windrect.right - 1, iconrect.top);
  560.     }
  561.     
  562.     SetPort(oldport);
  563. }
  564.  
  565. /*
  566.  * wfindhit() - see what part of the window the mouse hit.
  567.  */
  568.  
  569. long
  570. wfindhit(windp, h, v)
  571. WindowPeek windp;
  572. int h, v;            /* (global) coords of the mouse-down */
  573. {
  574.     long retval;        /* the region ID to return */
  575.     struct wdims dim;    /* dimensions of the window */
  576.     Point pt;            /* the mouse-down point */
  577.         
  578.     wcalcdims(windp, (Rect *) 0, &dim);
  579.     pt.h = h;
  580.     pt.v = v;
  581.     
  582.     retval = (long) wNoHit;
  583.     
  584.     if (!windp->visible) {
  585.         /* if we're invisible, nothing can be hit */
  586.  
  587.     } else if (PtInRect(pt, &dim.contrect)) {
  588.         if (windp->hilited && PtInRect(pt, &dim.growrect)) {
  589.             retval = (long) wInGrow;
  590.         } else {
  591.             retval = (long) wInContent;
  592.         }
  593.     } else if (PtInRect(pt, &dim.titlerect)) {
  594.         retval = (long) wInDrag;
  595.         if (windp->hilited) {
  596.             if (windp->goAwayFlag && PtInRect(pt, &dim.closerect)) {
  597.                 retval = (long) wInGoAway;
  598.             } else if (windp->spareFlag != 0 && PtInRect(pt, &dim.zoomrect)) {
  599.                 retval = (long) zoompart(windp);
  600.             }
  601.         }
  602.     }
  603.     return(retval);
  604. }
  605.  
  606. /*
  607.  * wtoggle_box() - toggle the drawn state of the given region (close or zoom).
  608.  */
  609.  
  610. wtoggle_box(windp, part)
  611. WindowPeek windp;
  612. int part;                /* the region to toggle (e.g., wInGoAway) */
  613. {
  614.     GrafPtr myport;        /* the window manager port */
  615.     struct wdims dim;    /* dimensions of the window */
  616.     BitMap bm;            /* a temporary bitmap containing the pattern to Xor */
  617.     unsigned int block[16];    /* the 16 X 16 bit bitmap bm points to */
  618.     Rect xrect;            /* the (inset) box to Xor into */
  619.         
  620.     GetPort(&myport);
  621.     
  622.     wcalcdims(windp, (Rect *) 0, &dim);
  623.     
  624.     if (part == wInZoomOut || part == wInZoomIn) {
  625.         xrect = dim.zoomrect;
  626.     } else {
  627.         xrect = dim.closerect;
  628.     }
  629.     InsetRect(&xrect, 1, 1);
  630.     
  631.     bm.baseAddr = (QDPtr) &block[0];
  632.     bm.rowBytes = 2;
  633.     bm.bounds.top = 0;
  634.     bm.bounds.left = 0;
  635.     bm.bounds.right = xrect.right - xrect.left;
  636.     bm.bounds.bottom = xrect.bottom - xrect.top;
  637.     
  638.     if (is_smallrect(&dim.contrect)) {
  639.         if (part == wInZoomOut || part == wInZoomIn) {
  640.             block[0] = 0x1800;
  641.             block[1] = 0x5C00;
  642.             block[2] = 0x2000;
  643.             block[3] = 0xCE00;
  644.             block[4] = 0xD000;
  645.             block[5] = 0x5400;
  646.             block[6] = 0x1000;
  647.         } else {
  648.             block[0] = 0x1000;
  649.             block[1] = 0x5400;
  650.             block[2] = 0x2800;
  651.             block[3] = 0xC600;
  652.             block[4] = 0x2800;
  653.             block[5] = 0x5400;
  654.             block[6] = 0x1000;
  655.         }
  656.     } else {
  657.         if (part == wInZoomOut || part == wInZoomIn) {
  658.             block[0] = 0x0C00;
  659.             block[1] = 0x4D00;
  660.             block[2] = 0x2E00;
  661.             block[3] = 0x0400;
  662.             block[4] = 0xE780;
  663.             block[5] = 0xFC00;
  664.             block[6] = 0x2A00;
  665.             block[7] = 0x4900;
  666.             block[8] = 0x0800;
  667.         } else {
  668.             block[0] = 0x0800;
  669.             block[1] = 0x4900;
  670.             block[2] = 0x2A00;
  671.             block[3] = 0x0000;
  672.             block[4] = 0xE380;
  673.             block[5] = 0x0000;
  674.             block[6] = 0x2A00;
  675.             block[7] = 0x4900;
  676.             block[8] = 0x0800;
  677.         }
  678.     }
  679.     CopyBits(&bm, &myport->portBits, &bm.bounds, &xrect, srcXor, (RgnHandle) 0);
  680. }
  681.  
  682. /*
  683.  * woutline() - given a hypothetical content region rectangle for a window,
  684.  *   draw the outline of that window, using the passed content region.
  685.  *
  686.  * This routine is called when growing a window.
  687.  */
  688.  
  689. woutline(windp, contp)
  690. WindowPeek windp;
  691. Rect *contp;        /* points to a hypothetical, global-coord, content Rect */
  692. {
  693.     struct wdims dim;    /* dimensions of the window */
  694.     Rect tmprect;
  695.     
  696.     wcalcdims(windp, contp, &dim);
  697.     
  698.     if (is_smallrect(&dim.contrect)) {
  699.     
  700.         /*
  701.          * For a collapsed window,
  702.          * draw a frame inside the title box and another around the contents.
  703.          * Because we're XORing, we have to avoid drawing any pixel twice.
  704.          */
  705.         
  706.         FrameRect(&dim.titlerect);
  707.         MoveTo(dim.contrect.left - 1, dim.contrect.bottom - 1);
  708.         LineTo(dim.contrect.left - 1, dim.contrect.top - 1);
  709.         LineTo(dim.contrect.right, dim.contrect.top - 1);
  710.         LineTo(dim.contrect.right, dim.contrect.bottom - 1);
  711.         
  712.         if (dim.contrect.left < dim.titlerect.left) {
  713.             MoveTo(dim.contrect.left - 1, dim.contrect.bottom);
  714.             LineTo(dim.titlerect.left - 1, dim.contrect.bottom);
  715.             MoveTo(dim.titlerect.right, dim.contrect.bottom);
  716.             LineTo(dim.contrect.right, dim.contrect.bottom);
  717.         }
  718.     } else {
  719.     
  720.         /*
  721.          * For a Standard window,
  722.          * frame the whole window and title box,
  723.          * then draw the inner edges of the scrollbars.
  724.          */
  725.         
  726.         tmprect = dim.titlerect;
  727.         tmprect.bottom = dim.contrect.bottom + 1;
  728.         FrameRect(&tmprect);
  729.         MoveTo(dim.titlerect.left + 1, dim.titlerect.bottom - 1);
  730.         LineTo(dim.titlerect.right - 2, dim.titlerect.bottom - 1);
  731.         
  732.         MoveTo(dim.contrect.right - 15, dim.contrect.top);
  733.         LineTo(dim.contrect.right - 15, dim.contrect.bottom - 1);
  734.         MoveTo(dim.contrect.left, dim.contrect.bottom - 15);
  735.         LineTo(dim.contrect.right - 1, dim.contrect.bottom - 15);
  736.     }
  737. }
  738.  
  739. /*
  740.  * is_smallrect() - "the given rectangle is small"
  741.  * I.e., if the given Rect were a window's portRect,
  742.  * that window would be in its collapsed state.
  743.  */
  744.  
  745. int        /* "it's small" */
  746. is_smallrect(rp)
  747. Rect *rp;            /* pointer to the Rect of interest */
  748. {
  749.     if (rp->right - rp->left <= SMALLWIDTH ||
  750.       rp->bottom - rp->top <= SMALLHEIGHT) {
  751.           return(TRUE);
  752.     }
  753.     return(FALSE);
  754. }
  755.  
  756. /*
  757.  * zoompart() - return the "zoom in" or "zoom out" window part hit,
  758.  * based on the size and position of the window vs the window's Standard State.
  759.  */
  760.  
  761. int        /* wInZoomIn vs wInZoomOut */
  762. zoompart(windp)
  763. WindowPeek windp;
  764. {
  765.     Rect *zrp;        /* the window's zoomed (Standard State) Rect */
  766.     Rect globwport;    /* the window's portRect in global coordinates */
  767.     int delta;        /* temporary difference of two measurements */
  768.     int retval;        /* the part to return */
  769.     
  770.     /*
  771.      * If this isn't a zoomable window,
  772.      *   we shouldn't even get here -- return "nowhere".
  773.      *
  774.      * If any dimension or side of the window has moved more than SMALLCHANGE,
  775.      * the window is in the user state -- return "zoom out".
  776.      * Otherwise the window's zoomed out -- return "zoom in".
  777.      */
  778.     
  779.     if (windp->spareFlag == 0) {
  780.         return(wNoHit);
  781.     }
  782.     
  783.     HLock(windp->dataHandle);
  784.  
  785.     zrp = &((WStateData *) *(windp->dataHandle))->stdState;
  786.     
  787.     globwport = windp->port.portRect;
  788.     OffsetRect(&globwport,
  789.       -windp->port.portBits.bounds.left,
  790.       -windp->port.portBits.bounds.top);
  791.     
  792.     delta = globwport.left - zrp->left;
  793.     if (delta < 0) delta = -delta;
  794.     if (delta > SMALLCHANGE) {
  795.         retval = wInZoomOut;
  796.         goto known;
  797.     }
  798.  
  799.     delta = globwport.top - zrp->top;
  800.     if (delta < 0) delta = -delta;
  801.     if (delta > SMALLCHANGE) {
  802.         retval = wInZoomOut;
  803.         goto known;
  804.     }
  805.  
  806.     delta = globwport.right - globwport.left;
  807.     if (delta < 0) return(wInZoomOut);
  808.     delta -= zrp->right - zrp->left;
  809.     if (delta < 0) delta = -delta;
  810.     if (delta > SMALLCHANGE) {
  811.         retval = wInZoomOut;
  812.         goto known;
  813.     }
  814.  
  815.     delta = globwport.bottom - globwport.top;
  816.     if (delta < 0) return(wInZoomOut);
  817.     delta -= zrp->bottom - zrp->top;
  818.     if (delta < 0) delta = -delta;
  819.     if (delta > SMALLCHANGE) {
  820.         retval = wInZoomOut;
  821.         goto known;
  822.     }
  823.     
  824.     /*
  825.      * The window hasn't changed much from the zoomed state,
  826.      * so we're zooming in.
  827.      */
  828.     
  829.     retval = wInZoomIn;
  830.  
  831. known:
  832.     HUnlock(windp->dataHandle);
  833.     
  834.     return(retval);
  835. }
  836.  
  837. /*
  838.  * wcalcdims() - calculate the interesting dimensions of the given window.
  839.  *
  840.  * If growrectp isn't NIL, use that (rather than the window's port) as the
  841.  * location and size of the window.
  842.  */
  843.  
  844. wcalcdims(windp, growrectp, dimp)
  845. WindowPeek windp;        /* the window to calculate for */
  846. Rect *growrectp;        /* (global-coord) hypothetical Rect for the window */
  847. struct wdims *dimp;        /* where to put the results */
  848. {
  849.     GrafPtr myport;        /* the current port (the window manager's) */
  850.     int boxwidth;        /* width/height of a close/zoom box */
  851.     FontInfo finfo;        /* info about the title font */
  852.     int lheight;        /* height of one text line of the title */
  853.     int titlewidth;        /* width (pixels) of the title */
  854.     int trectwidth;        /* width of the title box */
  855.     int oldfont;
  856.     Style oldface;
  857.     int oldsize;
  858.     
  859.     GetPort(&myport);
  860.  
  861.     /*
  862.      * the content rectangle is just the window's Rect, in global coordinates.
  863.      */
  864.     
  865.     if (growrectp) {
  866.         dimp->contrect = *growrectp;
  867.     } else {
  868.         dimp->contrect = windp->port.portRect;
  869.         OffsetRect(&dimp->contrect,
  870.           -windp->port.portBits.bounds.left,
  871.           -windp->port.portBits.bounds.top);
  872.     }
  873.     
  874.     if (is_smallrect(&dimp->contrect)) {
  875.         
  876.         /*
  877.          * Calculate everything for the collapsed type of window:
  878.          *
  879.          * The growrect occupies the whole contents.
  880.          *
  881.          * The Title box, beneath the frame, contains
  882.          * - The title, centered on the first line
  883.          * - the closebox, zoombox, and active marking lines on the second line.
  884.          */
  885.         
  886.         boxwidth = BOXWIDSMALL;
  887.         
  888.         dimp->growrect = dimp->contrect;
  889.          
  890.         oldfont = myport->txFont;
  891.         oldface = myport->txFace;
  892.         oldsize = myport->txSize;
  893.         TextFont(TITLEFONT);
  894.         TextFace(TITLESTYLE);
  895.         TextSize(TITLEFSIZE);
  896.         
  897.         GetFontInfo(&finfo);
  898.         HLock((Handle) windp->titleHandle);
  899.         titlewidth = StringWidth(*(windp->titleHandle));
  900.         HUnlock((Handle) windp->titleHandle);
  901.  
  902.         TextFont(oldfont);
  903.         TextFace(oldface);
  904.         TextSize(oldsize);
  905.         
  906.         lheight = finfo.ascent + finfo.descent + finfo.leading;
  907.         
  908.         trectwidth = 1 + BOXHMARGIN + titlewidth + BOXHMARGIN + 1;
  909.         if (trectwidth < 50) trectwidth = 50;
  910.         
  911.         dimp->titlerect.top = dimp->contrect.bottom;
  912.         dimp->titlerect.bottom = dimp->titlerect.top + lheight * 2 + 1;
  913.         
  914.         dimp->titlerect.left =
  915.           (dimp->contrect.right + dimp->contrect.left) / 2 -
  916.           trectwidth / 2;
  917.         dimp->titlerect.right = dimp->titlerect.left + trectwidth;
  918.         
  919.         dimp->titleref.h = (dimp->titlerect.right + dimp->titlerect.left) / 2
  920.          - titlewidth / 2;
  921.         dimp->titleref.v = dimp->titlerect.top + 1 + finfo.leading + finfo.ascent;
  922.         
  923.         dimp->textclip = dimp->titlerect;
  924.         
  925.         dimp->closerect.bottom = dimp->titlerect.bottom - 2;
  926.         dimp->closerect.left = dimp->titlerect.left + 1 + BOXHMARGIN;
  927.         dimp->closerect.top = dimp->closerect.bottom - boxwidth;
  928.         dimp->closerect.right = dimp->closerect.left + boxwidth;
  929.         
  930.         dimp->zoomrect.top = dimp->closerect.top;
  931.         dimp->zoomrect.bottom = dimp->closerect.bottom;
  932.         dimp->zoomrect.right = dimp->titlerect.right - 1 - BOXHMARGIN;
  933.         dimp->zoomrect.left = dimp->zoomrect.right - boxwidth;
  934.         
  935.     } else {
  936.     
  937.         /*
  938.          * Calculate everything for the normal type of window:
  939.          *
  940.          * The grow region is in the lower righthand corner of the window.
  941.          *
  942.          * The Title box, above the frame, contains
  943.          * - The title, centered and possibly clipped.
  944.          * - the closebox, zoombox, and active marking lines.
  945.          */
  946.  
  947.         boxwidth = BOXWIDBIG;
  948.         
  949.         dimp->growrect.right = dimp->contrect.right;
  950.         dimp->growrect.bottom = dimp->contrect.bottom;
  951.         dimp->growrect.left = dimp->growrect.right - 15;
  952.         dimp->growrect.top = dimp->growrect.bottom - 15;
  953.         
  954.         dimp->titlerect.bottom = dimp->contrect.top;
  955.         dimp->titlerect.top = dimp->titlerect.bottom - 19;
  956.         
  957.         dimp->titlerect.left = dimp->contrect.left - 1;
  958.         dimp->titlerect.right = dimp->contrect.right + 1;
  959.         
  960.         dimp->closerect.bottom = dimp->titlerect.bottom - 4;
  961.         dimp->closerect.left = dimp->titlerect.left + 9;
  962.         dimp->closerect.top = dimp->closerect.bottom - boxwidth;
  963.         dimp->closerect.right = dimp->closerect.left + boxwidth;
  964.         
  965.         dimp->zoomrect.top = dimp->closerect.top;
  966.         dimp->zoomrect.bottom = dimp->closerect.bottom;
  967.         dimp->zoomrect.right = dimp->titlerect.right - 9;
  968.         dimp->zoomrect.left = dimp->zoomrect.right - boxwidth;        
  969.         
  970.         dimp->titleref.h = (dimp->titlerect.right + dimp->titlerect.left) / 2
  971.           - windp->titleWidth / 2;
  972.         if (dimp->titleref.h < dimp->titlerect.left + 33) {
  973.             dimp->titleref.h = dimp->titlerect.left + 33;
  974.         }
  975.         dimp->titleref.v = dimp->closerect.bottom - 1;
  976.         
  977.         dimp->textclip = dimp->titlerect;
  978.         dimp->textclip.left = dimp->titleref.h;
  979.         dimp->textclip.right = dimp->textclip.left + windp->titleWidth;
  980.         if (dimp->textclip.right > dimp->titlerect.right - 33) {
  981.             dimp->textclip.right = dimp->titlerect.right - 33;
  982.         }
  983.     }
  984. }
  985.