home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / imagedit / workwp.c < prev   
Text File  |  1994-05-16  |  51KB  |  1,647 lines

  1.     /***************************************************************************
  2.      *                                                                         *
  3.      *  MODULE      : WorkWP.c                                                 *
  4.      *                                                                         *
  5.      *  DESCRIPTION : Functions controlling the workspace window.              *
  6.      *                                                                         *
  7.      *  HISTORY     : 6/21/89 LR                                               *
  8.      *                                                                         *
  9.      ***************************************************************************/
  10.     
  11.     #include "imagedit.h"
  12.     
  13.     #include <stdlib.h>
  14.     
  15.     
  16.     /*
  17.      * This structure is used in conjunction with DeltaGenInit() and DeltaGen().
  18.      */
  19.     typedef struct _DELTAGEN { /* dg */
  20.         BOOL fSwap;
  21.         INT xf;
  22.         INT yf;
  23.         INT dx;
  24.         INT dy;
  25.         INT d;
  26.         INT incx;
  27.         INT incy;
  28.         INT inc1;
  29.         INT inc2;
  30.     } DELTAGEN;
  31.     typedef DELTAGEN *PDELTAGEN;
  32.     
  33.     
  34.     STATICFN VOID NEAR WorkPaint(HWND hwnd);
  35.     STATICFN VOID WorkButtonDown(HWND hwnd, UINT msg, PPOINT ppt);
  36.     STATICFN VOID WorkButtonMouseMove(HWND hwnd, UINT msg, PPOINT ppt);
  37.     STATICFN VOID WorkButtonUp(HWND hwnd, UINT msg, PPOINT ppt);
  38.     STATICFN VOID NEAR SnapPointToGrid(PPOINT ppt);
  39.     STATICFN VOID DrawToPoint(HWND hwnd, PPOINT ppt, BOOL fBrush);
  40.     STATICFN BOOL NEAR DeltaGenInit(PDELTAGEN pdg, INT x0, INT y0,
  41.         INT xf, INT yf, PINT px, PINT py);
  42.     STATICFN BOOL NEAR DeltaGen(PDELTAGEN pdg, PINT px, PINT py);
  43.     STATICFN VOID DrawPoint(HWND hwnd, PPOINT ppt, BOOL fBrush);
  44.     STATICFN VOID NEAR RubberBandLine(BOOL fFirstTime);
  45.     STATICFN VOID NEAR RectDPDraw(HWND hwnd);
  46.     STATICFN VOID NEAR RubberBandRect(BOOL fFirstTime);
  47.     STATICFN VOID NEAR CircleDPDraw(HWND hwnd);
  48.     STATICFN VOID NEAR RubberBandCircle(BOOL fFirstTime);
  49.     STATICFN VOID NEAR MarkHotSpotPosition(INT x, INT y);
  50.     STATICFN VOID NEAR StartRubberBanding(HWND hwnd);
  51.     STATICFN VOID NEAR EndRubberBanding(HWND hwnd);
  52.     
  53.     
  54.     static BOOL fDrawing = FALSE;           // TRUE if mouse button is down.
  55.     static BOOL fLeftButtonDown;            // TRUE if left button was pressed.
  56.     static POINT ptStart;                   // Saves the starting point.
  57.     static POINT ptEnd;                     // Saves the ending point.
  58.     static POINT ptPrev;                    // Saves the previous point.
  59.     static HDC hdcRubberBand;               // DC used during rubber banding.
  60.     static BOOL fRubberBanding = FALSE;     // Tracking is in progress.
  61.     
  62.     
  63.     
  64.     /****************************************************************************
  65.      * WorkWndProc
  66.      *                                                                          *
  67.      * purpose: Processes basic create and size and paint messages for the      *
  68.      *          workspace window.
  69.      *                                                                          *
  70.      ****************************************************************************/
  71.     
  72.     WINDOWPROC WorkWndProc(
  73.         HWND hwnd,
  74.         UINT msg,
  75.         WPARAM wParam,
  76.         LPARAM lParam)
  77.     {
  78.         LPCREATESTRUCT cs;
  79.         POINT pt;
  80.     
  81.         switch (msg) {
  82.             case WM_CREATE:
  83.                 /* set up image variables */
  84.                 cs = (LPCREATESTRUCT)lParam;
  85.                 gcxWorkSpace = cs->cx;
  86.                 gcyWorkSpace = cs->cy;
  87.                 break;
  88.     
  89.             case WM_SIZE:
  90.                 gcxWorkSpace = LOWORD(lParam);
  91.                 gcyWorkSpace = HIWORD(lParam);
  92.     
  93.                 break;
  94.     
  95.             case WM_PAINT:
  96.                 WorkPaint(hwnd);
  97.                 break;
  98.     
  99.             case WM_MOUSEMOVE:
  100.                 ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y);
  101.                 WorkButtonMouseMove(hwnd, msg, &pt);
  102.                 break;
  103.     
  104.             case WM_RBUTTONDOWN:
  105.             case WM_LBUTTONDOWN:
  106.                 ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y);
  107.                 WorkButtonDown(hwnd, msg, &pt);
  108.                 break;
  109.     
  110.             case WM_LBUTTONUP:
  111.             case WM_RBUTTONUP:
  112.                 ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y);
  113.                 WorkButtonUp(hwnd, msg, &pt);
  114.                 break;
  115.     
  116.             case WM_KEYDOWN:
  117.                 switch (wParam) {
  118.                     case VK_ESCAPE:
  119.                         if (fDrawing) {
  120.                             if (fRubberBanding) {
  121.                                 EndRubberBanding(hwnd);
  122.                                 WorkUpdate();
  123.                             }
  124.     
  125.                             PropBarClearSize();
  126.                             ReleaseCapture();
  127.                             fDrawing = FALSE;
  128.                         }
  129.     
  130.                         break;
  131.                 }
  132.     
  133.                 break;
  134.     
  135.             default:
  136.                 return DefWindowProc(hwnd, msg, wParam, lParam);
  137.         }
  138.     
  139.         return 0;
  140.     }
  141.     
  142.     
  143.     
  144.     /****************************************************************************
  145.     * WorkPaint
  146.     *
  147.     * Handles WM_PAINT for the workspace window.
  148.     *
  149.     * History:
  150.     *
  151.     ****************************************************************************/
  152.     
  153.     STATICFN VOID NEAR WorkPaint(    HWND hwnd)
  154.     {
  155.         register INT i;
  156.         PAINTSTRUCT ps;
  157.         HCURSOR hcurOld;
  158.         HDC hdcTemp;
  159.         HBITMAP hbmTemp;
  160.     
  161.         hcurOld = SetCursor(hcurWait);
  162.         BeginPaint(hwnd, &ps);
  163.     
  164.         /*
  165.          * Do they want a grid and is there enough room to show the lines?
  166.          */
  167.         if (gfGrid && gZoomFactor > 1) {
  168.             /*
  169.              * Stretch the bits onto a temporary DC.
  170.              */
  171.             hdcTemp = CreateCompatibleDC(ghdcImage);
  172.             hbmTemp = CreateCompatibleBitmap(ghdcImage,
  173.                     gcxWorkSpace, gcyWorkSpace);
  174.             SelectObject(hdcTemp, hbmTemp);
  175.             StretchBlt(hdcTemp, 0, 0, gcxWorkSpace, gcyWorkSpace,
  176.                     ghdcImage, 0, 0, gcxImage, gcyImage, SRCCOPY);
  177.     
  178.             /*
  179.              * Draw the grid lines on the temp DC.
  180.              */
  181.             for (i = gZoomFactor - 1; i < gcxWorkSpace; i += gZoomFactor)
  182.                 PatBlt(hdcTemp, i, 0, 1, gcyWorkSpace, BLACKNESS);
  183.             for (i = gZoomFactor - 1; i < gcyWorkSpace; i += gZoomFactor)
  184.                 PatBlt(hdcTemp, 0, i, gcxWorkSpace, 1, BLACKNESS);
  185.     
  186.             /*
  187.              * Copy the bits to the screen.
  188.              */
  189.             BitBlt(ps.hdc, 0, 0, gcxWorkSpace, gcyWorkSpace,
  190.                     hdcTemp, 0, 0, SRCCOPY);
  191.     
  192.             DeleteDC(hdcTemp);
  193.             DeleteObject(hbmTemp);
  194.         }
  195.         else {
  196.             /*
  197.              * No grid.  Just stretch the image to the screen.
  198.              */
  199.             StretchBlt(ps.hdc, 0, 0, gcxWorkSpace, gcyWorkSpace,
  200.                     ghdcImage, 0, 0, gcxImage, gcyImage, SRCCOPY);
  201.         }
  202.     
  203.         EndPaint(hwnd, &ps);
  204.         SetCursor(hcurOld);
  205.     }
  206.     
  207.     
  208.     
  209.     /****************************************************************************
  210.     * WorkUpdate
  211.     *
  212.     * This function updates the workspace window.
  213.     *
  214.     * History:
  215.     *
  216.     ****************************************************************************/
  217.     
  218.     VOID WorkUpdate(VOID)
  219.     {
  220.         /*
  221.          * Invalidate the workspace window.  Because the image will be
  222.          * be blt'ed onto it, we do not need to force the background to
  223.          * be cleared first.
  224.          */
  225.         InvalidateRect(ghwndWork, NULL, FALSE);
  226.     }
  227.     
  228.     
  229.     
  230.     /****************************************************************************
  231.     * WorkReset
  232.     *
  233.     * This function reset the workspace window.  It should be called
  234.     * any time that a new image is loaded (because the size could
  235.     * change) or the size of the main window changes (because the
  236.     * workspace window needs to be resized to fit).
  237.     *
  238.     * History:
  239.     *
  240.     ****************************************************************************/
  241.     
  242.     VOID WorkReset(VOID)
  243.     {
  244.         RECT rcClient;
  245.         INT cx;
  246.         INT cy;
  247.         INT xScale;
  248.         INT yScale;
  249.         INT cxBorder;
  250.         INT cyBorder;
  251.     
  252.         cxBorder = GetSystemMetrics(SM_CXBORDER);
  253.         cyBorder = GetSystemMetrics(SM_CYBORDER);
  254.     
  255.         if (!gcxImage || !gcyImage) {
  256.             gZoomFactor = 1;
  257.         }
  258.         else {
  259.             GetClientRect(ghwndMain, &rcClient);
  260.             cx = rcClient.right - (2 * PALETTEMARGIN) - (2 * cxBorder);
  261.             cy = rcClient.bottom - (2 * PALETTEMARGIN) - (2 * cyBorder) -
  262.                     gcyPropBar;
  263.     
  264.             xScale = cx / gcxImage;
  265.             yScale = cy / gcyImage;
  266.     
  267.             if (xScale > 0 && yScale > 0)
  268.                 gZoomFactor = min(xScale, yScale);
  269.             else
  270.                 gZoomFactor = 1;
  271.         }
  272.     
  273.         SetWindowPos(ghwndWork, NULL,
  274.                 PALETTEMARGIN, PALETTEMARGIN + gcyPropBar,
  275.                 (gZoomFactor * gcxImage) + (2 * cxBorder),
  276.                 (gZoomFactor * gcyImage) + (2 * cyBorder),
  277.                 SWP_NOACTIVATE | SWP_NOZORDER);
  278.         WorkUpdate();
  279.     }
  280.     
  281.     
  282.     
  283.     /************************************************************************
  284.     * WorkButtonDown
  285.     *
  286.     *
  287.     *
  288.     * Arguments:
  289.     *
  290.     * History:
  291.     *
  292.     ************************************************************************/
  293.     
  294.     STATICFN VOID WorkButtonDown(
  295.         HWND hwnd,
  296.         UINT msg,
  297.         PPOINT ppt)
  298.     {
  299.         /*
  300.          * If the other button is already down, just ignore this one.
  301.          */
  302.         if (fDrawing)
  303.             return;
  304.     
  305.         SetFocus(hwnd);
  306.         fLeftButtonDown = (msg == WM_LBUTTONDOWN) ? TRUE : FALSE;
  307.     
  308.         SnapPointToGrid(ppt);
  309.         ptStart = ptPrev = ptEnd = *ppt;
  310.     
  311.         if (fLeftButtonDown) {
  312.             ghbrDraw = ghbrLeft;
  313.             ghbrDrawSolid = ghbrLeftSolid;
  314.             gfDrawMode = gfModeLeft;
  315.             ghpenDraw = ghpenLeft;
  316.         }
  317.         else {
  318.             ghbrDraw = ghbrRight;
  319.             ghbrDrawSolid = ghbrRightSolid;
  320.             gfDrawMode = gfModeRight;
  321.             ghpenDraw = ghpenRight;
  322.         }
  323.     
  324.         /*
  325.          * If this tool draws on the down-click, update the undo
  326.          * buffer now.
  327.          */
  328.         if (gaTools[gCurTool].fDrawOnDown)
  329.             ImageUpdateUndo();
  330.     
  331.         SetCapture(ghwndWork);
  332.         fDrawing = TRUE;
  333.     
  334.         (*gpfnDrawProc)(hwnd, msg, *ppt);
  335.     
  336.         PropBarSetSize(ptStart, ptEnd);
  337.     }
  338.     
  339.     
  340.     
  341.     /************************************************************************
  342.     * WorkButtonMouseMove
  343.     *
  344.     *
  345.     *
  346.     * Arguments:
  347.     *
  348.     * History:
  349.     *
  350.     ************************************************************************/
  351.     
  352.     STATICFN VOID WorkButtonMouseMove(
  353.         HWND hwnd,
  354.         UINT msg,
  355.         PPOINT ppt)
  356.     {
  357.         static POINT ptNZLast;  // Saves the last point (non-zoomed).
  358.         POINT ptNZ;
  359.     
  360.         SetCursor(gaTools[gCurTool].hcur);
  361.     
  362.         SnapPointToGrid(ppt);
  363.     
  364.         /*
  365.          * Calculate the point as it would be on the actual image
  366.          * (non-zoomed).
  367.          */
  368.         ptNZ.x = ppt->x / gZoomFactor;
  369.         ptNZ.y = ppt->y / gZoomFactor;
  370.     
  371.         /*
  372.          * Only call the drawing proc if the point changed enough to
  373.          * jump over a zoomed pixels width (it jumped a grid square).
  374.          * This prevents calling the DrawProc for a mouse move of
  375.          * a single pixel (unless the zoom factor is 1, of course).
  376.          */
  377.         if (ptNZLast.x != ptNZ.x || ptNZLast.y != ptNZ.y) {
  378.             ptEnd = *ppt;
  379.             (*gpfnDrawProc)(hwnd, msg, *ppt);
  380.             ptPrev = ptEnd;
  381.     
  382.             PropBarSetPos(ptNZ.x, ptNZ.y);
  383.     
  384.             if (fDrawing)
  385.                 PropBarSetSize(ptStart, ptEnd);
  386.     
  387.             ptNZLast = ptNZ;
  388.         }
  389.     }
  390.     
  391.     
  392.     
  393.     /************************************************************************
  394.     * WorkButtonUp
  395.     *
  396.     *
  397.     *
  398.     * Arguments:
  399.     *
  400.     * History:
  401.     *
  402.     ************************************************************************/
  403.     
  404.     STATICFN VOID WorkButtonUp(
  405.         HWND hwnd,
  406.         UINT msg,
  407.         PPOINT ppt)
  408.     {
  409.         /*
  410.          * Pass this on to the draw procs, but only if we are still drawing.
  411.          * The drawing could have been cancelled by the Escape key, in
  412.          * which case we just ignore the button up message.
  413.          */
  414.         if (fDrawing) {
  415.             SnapPointToGrid(ppt);
  416.     
  417.             /*
  418.              * If this tool draws on the up-click, update the undo
  419.              * buffer now.
  420.              */
  421.             if (gaTools[gCurTool].fDrawOnUp)
  422.                 ImageUpdateUndo();
  423.     
  424.             (*gpfnDrawProc)(hwnd, msg, *ppt);
  425.     
  426.             ReleaseCapture();
  427.             fDrawing = FALSE;
  428.         }
  429.     }
  430.     
  431.     
  432.     
  433.     /******************************************************************************
  434.      * SnapPointToGrid
  435.      *
  436.      * PURPOSE : Snap the current mouse coordinate to the nearest grid intersection.
  437.      *
  438.      * PARAMS  : PPOINT ppt : current mouse coordinates
  439.      *
  440.      *****************************************************************************/
  441.     
  442.     STATICFN VOID NEAR SnapPointToGrid(
  443.         PPOINT ppt)
  444.     {
  445.         /*
  446.          * Scale the point down (this gridizes it at the same time).
  447.          */
  448.         ppt->x = ppt->x / gZoomFactor;
  449.         ppt->y = ppt->y / gZoomFactor;
  450.     
  451.         /*
  452.          * Limit the point to within the image.
  453.          */
  454.         if (ppt->x < 0)
  455.             ppt->x = 0;
  456.     
  457.         if (ppt->y < 0)
  458.             ppt->y = 0;
  459.     
  460.         if (ppt->x >= gcxImage)
  461.             ppt->x = gcxImage - 1;
  462.     
  463.         if (ppt->y >= gcyImage)
  464.             ppt->y = gcyImage - 1;
  465.     
  466.         /*
  467.          * Finally, scale it back up to the workspace window size.
  468.          */
  469.         ppt->x *= gZoomFactor;
  470.         ppt->y *= gZoomFactor;
  471.     }
  472.     
  473.     
  474.     
  475.     /************************************************************************
  476.     * PencilDP
  477.     *
  478.     *
  479.     *
  480.     * Arguments:
  481.     *
  482.     * History:
  483.     *
  484.     ************************************************************************/
  485.     
  486.     VOID PencilDP(
  487.         HWND hwnd,
  488.         UINT msg,
  489.         POINT ptNew)
  490.     {
  491.         switch (msg) {
  492.             case WM_LBUTTONDOWN:
  493.             case WM_RBUTTONDOWN:
  494.                 DrawPoint(hwnd, &ptNew, FALSE);
  495.                 break;
  496.     
  497.             case WM_MOUSEMOVE:
  498.                 if (fDrawing)
  499.                     DrawToPoint(hwnd, &ptNew, FALSE);
  500.     
  501.                 break;
  502.         }
  503.     }
  504.     
  505.     
  506.     
  507.     /************************************************************************
  508.     * BrushDP
  509.     *
  510.     *
  511.     *
  512.     * Arguments:
  513.     *
  514.     * History:
  515.     *
  516.     ************************************************************************/
  517.     
  518.     VOID BrushDP(
  519.         HWND hwnd,
  520.         UINT msg,
  521.         POINT ptNew)
  522.     {
  523.         switch (msg) {
  524.             case WM_LBUTTONDOWN:
  525.             case WM_RBUTTONDOWN:
  526.                 DrawPoint(hwnd, &ptNew, TRUE);
  527.                 break;
  528.     
  529.             case WM_MOUSEMOVE:
  530.                 if (fDrawing)
  531.                     DrawToPoint(hwnd, &ptNew, TRUE);
  532.     
  533.                 break;
  534.         }
  535.     }
  536.     
  537.     
  538.     
  539.     /************************************************************************
  540.     * DrawToPoint
  541.     *
  542.     * This function draws from the previous point to the given point.
  543.     * This includes all points between.
  544.     *
  545.     * The global ptPrev must have been initialized prior to the  first time
  546.     * this function is called during a drawing operation.
  547.     *
  548.     * Arguments:
  549.     *
  550.     * History:
  551.     *
  552.     ************************************************************************/
  553.     
  554.     STATICFN VOID DrawToPoint(
  555.         HWND hwnd,
  556.         PPOINT ppt,
  557.         BOOL fBrush)
  558.     {
  559.         DELTAGEN dg;
  560.         BOOL fContinue;
  561.         POINT pt;
  562.         INT x;
  563.         INT y;
  564.     
  565.         x = ppt->x / gZoomFactor;
  566.         y = ppt->y / gZoomFactor;
  567.         DeltaGenInit(&dg, ptPrev.x / gZoomFactor, ptPrev.y / gZoomFactor,
  568.                 ppt->x / gZoomFactor, ppt->y / gZoomFactor, &x, &y);
  569.         do {
  570.             pt.x = x * gZoomFactor;
  571.             pt.y = y * gZoomFactor;
  572.             DrawPoint(hwnd, &pt, fBrush);
  573.             fContinue = DeltaGen(&dg, &x, &y);
  574.         } while (fContinue);
  575.     }
  576.     
  577.     
  578.     
  579.     /***************************** Public  Function ****************************\
  580.     * DeltaGenInit
  581.     *
  582.     * This routine initializes the pdg, px and py in preparation for using
  583.     * DeltaGen().  Returns fContinue.
  584.     *
  585.     * Algorithm derived from BRESENHAM line algorighm on p. 435 of Fund. of
  586.     * interactive computer graphics, Foley/VanDam, addison-wesley 1983.
  587.     *
  588.     * History:
  589.     *       3/7/89  sanfords        created
  590.     \***************************************************************************/
  591.     
  592.     STATICFN BOOL NEAR DeltaGenInit(
  593.         PDELTAGEN pdg,
  594.         INT x0,
  595.         INT y0,
  596.         INT xf,
  597.         INT yf,
  598.         PINT px,
  599.         PINT py)
  600.     {
  601.         INT nT;
  602.     
  603.         pdg->xf = xf;
  604.         pdg->yf = yf;
  605.     
  606.         if (x0 == xf && y0 == yf)
  607.             return FALSE;
  608.     
  609.         if (xf >= x0)
  610.             pdg->incx = 1;
  611.         else
  612.             pdg->incx = -1;
  613.     
  614.         if (yf >= y0)
  615.             pdg->incy = 1;
  616.         else
  617.             pdg->incy = -1;
  618.     
  619.         pdg->dx = (xf - x0) * pdg->incx;
  620.         pdg->dy = (yf - y0) * pdg->incy;
  621.     
  622.         if (pdg->dy > pdg->dx) {
  623.             nT = pdg->dy;
  624.             pdg->dy = pdg->dx;
  625.             pdg->dx = nT;
  626.             nT = pdg->incx;
  627.             pdg->incx = pdg->incy;
  628.             pdg->incy = nT;
  629.             pdg->fSwap = TRUE;
  630.         }
  631.         else {
  632.             pdg->fSwap = FALSE;
  633.         }
  634.     
  635.         pdg->inc1 = pdg->dy * 2;
  636.         pdg->inc2 = (pdg->dy - pdg->dx) * 2;
  637.         pdg->d = pdg->inc1 - pdg->dx;
  638.     
  639.         pdg->xf = xf;
  640.         pdg->yf = yf;
  641.     
  642.         *px = x0;
  643.         *py = y0;
  644.     
  645.         return TRUE;
  646.     }
  647.     
  648.     
  649.     
  650.     /***************************** Public  Function ****************************\
  651.     * DeltaGen
  652.     *
  653.     * This routine generates the next coordinates for px,py assuming that this
  654.     * point is proceeding linearly from x0,y0 to xf, yf.  It returns FALSE only
  655.     * if *px == xf and *py == yf on entry.  (ie returns fContinue)  pdg should
  656.     * have been previously set by DeltaGenInit().
  657.     *
  658.     * Algorithm derived from BRESENHAM line algorighm on p. 435 of Fund. of
  659.     * interactive computer graphics, Foley/VanDam, addison-wesley 1983.
  660.     *
  661.     * History:
  662.     *       3/7/89  sanfords        created
  663.     \***************************************************************************/
  664.     
  665.     STATICFN BOOL NEAR DeltaGen(
  666.         PDELTAGEN pdg,
  667.         PINT px,
  668.         PINT py)
  669.     {
  670.         PINT pnT;
  671.     
  672.         if ((*px == pdg->xf) && (*py == pdg->yf))
  673.             return FALSE;
  674.     
  675.         if (pdg->fSwap) {
  676.             pnT = px;
  677.             px = py;
  678.             py = pnT;
  679.         }
  680.     
  681.         *px += pdg->incx;
  682.         if (pdg->d < 0) {
  683.             pdg->d += pdg->inc1;
  684.         }
  685.         else {
  686.             *py += pdg->incy;
  687.             pdg->d += pdg->inc2;
  688.         }
  689.     
  690.         return TRUE;
  691.     }
  692.     
  693.     
  694.     
  695.     /************************************************************************
  696.     * DrawPoint
  697.     *
  698.     * This function is called to draw a point on the image.  It is used
  699.     * by the Pencil and Brush tools.
  700.     *
  701.     * Arguments:
  702.     *
  703.     * History:
  704.     *
  705.     ************************************************************************/
  706.     
  707.     STATICFN VOID DrawPoint(
  708.         HWND hwnd,
  709.         PPOINT ppt,
  710.         BOOL fBrush)
  711.     {
  712.         HDC hDC;
  713.         HBRUSH hbrOld;
  714.         INT wx;
  715.         INT wy;
  716.         INT iStartY;
  717.         INT wStep;
  718.         INT i;
  719.         INT j;
  720.         INT nBrushSize;
  721.     
  722.         if (ppt->x < 0 || ppt->y < 0)
  723.             return;
  724.     
  725.         hDC = GetDC(hwnd);
  726.     
  727.         /*
  728.          * If this is a point from the brush tool, use the current
  729.          * brush width.  Otherwise, draw a single pixel point.
  730.          */
  731.         if (fBrush)
  732.             nBrushSize = gnBrushSize;
  733.         else
  734.             nBrushSize = 1;
  735.     
  736.         /*
  737.          * Determine some starting factors, then draw the point in
  738.          * the workspace window.
  739.          */
  740.         hbrOld = SelectObject(hDC, ghbrDrawSolid);
  741.         wy = iStartY = ppt->y - (ppt->y % gZoomFactor)
  742.                 -(nBrushSize / 2) * gZoomFactor;
  743.         wx = ppt->x - (ppt->x % gZoomFactor)
  744.                 -(nBrushSize / 2) * gZoomFactor;
  745.         wStep = gZoomFactor;
  746.     
  747.         if (gfGrid && gZoomFactor > 1)
  748.             wStep -= 1;
  749.     
  750.         for (i = 0; i < nBrushSize; i++, wx += gZoomFactor) {
  751.             wy = iStartY;
  752.             for (j = 0; j < nBrushSize; j++, wy += gZoomFactor)
  753.                 PatBlt(hDC, wx, wy, wStep, wStep, PATCOPY);
  754.         }
  755.     
  756.         SelectObject(hDC, hbrOld);
  757.         ReleaseDC(hwnd, hDC);
  758.     
  759.         /*
  760.          * Set the point in the bitmap directly as an optimization.
  761.          */
  762.         wx = ppt->x / gZoomFactor;
  763.         wy = ppt->y / gZoomFactor;
  764.         if (wx < gcxImage && wy < gcyImage) {
  765.             hbrOld = SelectObject(ghdcImage, ghbrDrawSolid);
  766.             PatBlt(ghdcImage, wx - nBrushSize / 2, wy - nBrushSize / 2,
  767.                     nBrushSize, nBrushSize, PATCOPY);
  768.     
  769.             if (giType != FT_BITMAP) {
  770.                 /*
  771.                  * If in color mode, set the mask bits black.  Otherwise make
  772.                  * them white.
  773.                  */
  774.                 PatBlt(ghdcANDMask, wx - nBrushSize / 2, wy - nBrushSize / 2,
  775.                         nBrushSize, nBrushSize,
  776.                         (gfDrawMode == MODE_COLOR) ? BLACKNESS : WHITENESS);
  777.             }
  778.     
  779.             SelectObject(ghdcImage, hbrOld);
  780.     
  781.             /*
  782.              * Draw the point in the view window directly as an optimization.
  783.              */
  784.             if (ghwndView)
  785.                 ViewSetPixel(wx, wy, nBrushSize);
  786.         }
  787.     
  788.         /*
  789.          * Mark the image as changed.
  790.          */
  791.         fImageDirty = TRUE;
  792.     }
  793.     
  794.     
  795.     
  796.     /************************************************************************
  797.     * PickDP
  798.     *
  799.     * Drawing proc that selects a rectangular portion of the image.
  800.     * It updates the global picking rectangle.
  801.     *
  802.     * Arguments:
  803.     *
  804.     * History:
  805.     *
  806.     ************************************************************************/
  807.     
  808.     VOID PickDP(
  809.         HWND hwnd,
  810.         UINT msg,
  811.         POINT ptNew)
  812.     {
  813.         POINT ptTL;         // Top-Left point.
  814.         POINT ptBR;         // Bottom-Right point
  815.     
  816.         switch (msg) {
  817.             case WM_LBUTTONDOWN:
  818.             case WM_RBUTTONDOWN:
  819.                 /* erase any previous ghost rectangle */
  820.                 WorkUpdate();
  821.                 UpdateWindow(ghwndWork);
  822.     
  823.                 /*
  824.                  * Initialize the pick rectangle to cover the entire screen.
  825.                  */
  826.                 PickSetRect(0, 0, gcxImage - 1, gcyImage - 1);
  827.     
  828.                 StartRubberBanding(hwnd);
  829.                 RubberBandRect(TRUE);
  830.                 break;
  831.     
  832.             case WM_MOUSEMOVE:
  833.                 if (fRubberBanding)
  834.                     RubberBandRect(FALSE);
  835.     
  836.                 break;
  837.     
  838.             case WM_LBUTTONUP:
  839.             case WM_RBUTTONUP:
  840.                 EndRubberBanding(hwnd);
  841.     
  842.                 /*
  843.                  * Flip the points (if needed) and scale down.
  844.                  */
  845.                 ptTL = ptStart;
  846.                 ptBR = ptEnd;
  847.                 NormalizePoints(&ptTL, &ptBR);
  848.                 ptTL.x /= gZoomFactor;
  849.                 ptTL.y /= gZoomFactor;
  850.                 ptBR.x /= gZoomFactor;
  851.                 ptBR.y /= gZoomFactor;
  852.     
  853.                 PickSetRect(ptTL.x, ptTL.y, ptBR.x, ptBR.y);
  854.     
  855.                 break;
  856.         }
  857.     }
  858.     
  859.     
  860.     
  861.     /******************************************************************************
  862.      * VOID LineDP(hwnd, msg, ptNew)
  863.      *
  864.      * PURPOSE: Draw a straight line according to tracking line.
  865.      *
  866.      * PARAMS : HWND   hwnd : handle to dest. DC
  867.      *          unsigned msg  : Upper left corner of rect;
  868.      *          POINT  ptNew   : end pt. of line
  869.      *
  870.      * SIDE EFFECTS: may change bits in image DC
  871.      *
  872.      *****************************************************************************/
  873.     
  874.     VOID LineDP(
  875.         HWND hwnd,
  876.         UINT msg,
  877.         POINT ptNew)
  878.     {
  879.         INT sx;
  880.         INT sy;
  881.         INT ex;
  882.         INT ey;
  883.         HPEN hpen;
  884.         HPEN hpenOld;
  885.         HBRUSH hbrOld;
  886.     
  887.         switch (msg) {
  888.             case WM_RBUTTONDOWN:
  889.             case WM_LBUTTONDOWN:
  890.                 StartRubberBanding(hwnd);
  891.                 RubberBandLine(TRUE);
  892.                 break;
  893.     
  894.             case WM_MOUSEMOVE:
  895.                 if (fRubberBanding)
  896.                     RubberBandLine(FALSE);
  897.     
  898.                 break;
  899.     
  900.             case WM_LBUTTONUP:
  901.             case WM_RBUTTONUP:
  902.                 EndRubberBanding(hwnd);
  903.     
  904.                 /* transform selected coordinates to those of actual image */
  905.                 sx = ptStart.x / gZoomFactor;
  906.                 sy = ptStart.y / gZoomFactor;
  907.                 ex = ptEnd.x / gZoomFactor;
  908.                 ey = ptEnd.y / gZoomFactor;
  909.     
  910.                 hpenOld = SelectObject(ghdcImage, ghpenDraw);
  911.                 MoveToEx(ghdcImage, sx, sy, NULL);
  912.                 LineTo(ghdcImage, ex, ey);
  913.                 SelectObject(ghdcImage, hpenOld);
  914.     
  915.                 if (giType != FT_BITMAP) {
  916.                     /* for icons and cursors draw the line on the AND DC (memory)
  917.                      * in black (if in color mode) or white (otherwise)
  918.                      */
  919.                     hpen = CreatePen(PS_INSIDEFRAME, 1,
  920.                             (gfDrawMode == MODE_COLOR) ? RGB_BLACK : RGB_WHITE);
  921.                     hpenOld = SelectObject(ghdcANDMask, hpen);
  922.                     hbrOld = SelectObject(ghdcANDMask, GetStockObject(NULL_BRUSH));
  923.                     MoveToEx(ghdcANDMask, sx, sy, NULL);
  924.                     LineTo(ghdcANDMask, ex, ey);
  925.                     SelectObject(ghdcANDMask, hbrOld);
  926.                     SelectObject(ghdcANDMask, hpenOld);
  927.                     DeleteObject(hpen);
  928.                 }
  929.     
  930.                 /*
  931.                  * Because the LineTo function does not draw the ending
  932.                  * point, we must do it manually here.
  933.                  */
  934.                 DrawPoint(hwnd, &ptEnd, FALSE);
  935.     
  936.                 fImageDirty = TRUE;
  937.     
  938.                 ViewUpdate();
  939.     
  940.                 break;
  941.         }
  942.     }
  943.     
  944.     
  945.     
  946.     /************************************************************************
  947.     * RubberBandLine
  948.     *
  949.     * This function erases the old line and draws the new tracking line
  950.     * when using the "Line" tool.
  951.     *
  952.     * Arguments:
  953.     *   BOOL fFirstTime - TRUE if starting to track the line (it doesn't
  954.     *                     need to erase the old line).
  955.     *
  956.     * History:
  957.     *
  958.     ************************************************************************/
  959.     
  960.     STATICFN VOID NEAR RubberBandLine(
  961.         BOOL fFirstTime)
  962.     {
  963.         INT nOffset;
  964.     
  965.         /*
  966.          * Set the raster-op to invert.
  967.          */
  968.         SetROP2(hdcRubberBand, R2_NOT);
  969.     
  970.         /*
  971.          * If we are magnifying the image at all, the line needs to be
  972.          * slightly offset so that it will be draw exactly in between
  973.          * the grid lines.
  974.          */
  975.         if (gZoomFactor > 1)
  976.             nOffset = -1;
  977.         else
  978.             nOffset = 0;
  979.     
  980.         if (!fFirstTime) {
  981.             /*
  982.              * Erase the old line.
  983.              */
  984.             
  985.             MoveToEx(hdcRubberBand, ptStart.x + (gZoomFactor / 2) + nOffset,
  986.                     ptStart.y + (gZoomFactor / 2) + nOffset, NULL);
  987.             LineTo(hdcRubberBand, ptPrev.x + (gZoomFactor / 2) + nOffset,
  988.                     ptPrev.y + (gZoomFactor / 2) + nOffset);
  989.         }
  990.     
  991.         /*
  992.          * Draw the new one.
  993.          */
  994.         
  995.         MoveToEx(hdcRubberBand, ptStart.x + (gZoomFactor / 2) + nOffset,
  996.                 ptStart.y + (gZoomFactor / 2) + nOffset, NULL);
  997.         LineTo(hdcRubberBand, ptEnd.x + (gZoomFactor / 2) + nOffset,
  998.                 ptEnd.y + (gZoomFactor / 2) + nOffset);
  999.     }
  1000.     
  1001.     
  1002.     
  1003.     /******************************************************************************
  1004.      * VOID RectDP(hwnd, msg, ptNew)
  1005.      *
  1006.      * PURPOSE: Draw a rectangle (filled/hollow) in the area specified
  1007.      *
  1008.      * PARAMS : HWND   hwnd : handle to dest. DC
  1009.      *          WORD   msg  :
  1010.      *          POINT  ptNew   : end pt. of line
  1011.      *
  1012.      * SIDE EFFECTS: may change bits in image DC
  1013.      *
  1014.      *****************************************************************************/
  1015.     
  1016.     VOID RectDP(
  1017.         HWND hwnd,
  1018.         UINT msg,
  1019.         POINT ptNew)
  1020.     {
  1021.         switch (msg) {
  1022.             case WM_RBUTTONDOWN:
  1023.             case WM_LBUTTONDOWN:
  1024.                 StartRubberBanding(hwnd);
  1025.                 RubberBandRect(TRUE);
  1026.                 break;
  1027.     
  1028.             case WM_MOUSEMOVE:
  1029.                 if (fRubberBanding)
  1030.                     RubberBandRect(FALSE);
  1031.     
  1032.                 break;
  1033.     
  1034.             case WM_LBUTTONUP:
  1035.             case WM_RBUTTONUP:
  1036.                 RectDPDraw(hwnd);
  1037.                 break;
  1038.         }
  1039.     }
  1040.     
  1041.     
  1042.     
  1043.     /************************************************************************
  1044.     * RectDPDraw
  1045.     *
  1046.     * Does the final drawing of a rectangle when using the Rectangle tool.
  1047.     *
  1048.     * Arguments:
  1049.     *   HWND hwnd - Window handle to the workspace.
  1050.     *
  1051.     * History:
  1052.     *
  1053.     ************************************************************************/
  1054.     
  1055.     STATICFN VOID NEAR RectDPDraw(
  1056.         HWND hwnd)
  1057.     {
  1058.         POINT ptTL;         // Top-Left point.
  1059.         POINT ptBR;         // Bottom-Right point
  1060.         HBRUSH hbr;
  1061.         HBRUSH hbrOld;
  1062.         HPEN hpen;
  1063.         HPEN hpenOld;
  1064.         INT nOutset;
  1065.     
  1066.         EndRubberBanding(hwnd);
  1067.     
  1068.         /*
  1069.          * Flip the points (if needed) and scale down.
  1070.          */
  1071.         ptTL = ptStart;
  1072.         ptBR = ptEnd;
  1073.         NormalizePoints(&ptTL, &ptBR);
  1074.         ptTL.x /= gZoomFactor;
  1075.         ptTL.y /= gZoomFactor;
  1076.         ptBR.x /= gZoomFactor;
  1077.         ptBR.y /= gZoomFactor;
  1078.     
  1079.         if (gCurTool == TOOL_RECT) {
  1080.             hpen = ghpenDraw;
  1081.             hbr = GetStockObject(NULL_BRUSH);
  1082.             nOutset = 1;
  1083.         }
  1084.         else {
  1085.             hpen = GetStockObject(NULL_PEN);
  1086.             hbr = ghbrDraw;
  1087.             nOutset = 2;
  1088.         }
  1089.     
  1090.         hpenOld = SelectObject(ghdcImage, hpen);
  1091.         hbrOld = SelectObject(ghdcImage, hbr);
  1092.         Rectangle(ghdcImage, ptTL.x, ptTL.y,
  1093.                 ptBR.x + nOutset, ptBR.y + nOutset);
  1094.         SelectObject(ghdcImage, hpenOld);
  1095.         SelectObject(ghdcImage, hbrOld);
  1096.     
  1097.         if (giType != FT_BITMAP) {
  1098.             /* for icons and cursors draw the shape on the AND DC (memory)
  1099.              * in black (if in color mode) or white (otherwise)
  1100.              */
  1101.             if (gCurTool == TOOL_RECT) {
  1102.                 hpen = CreatePen(PS_INSIDEFRAME, 1,
  1103.                         (gfDrawMode == MODE_COLOR) ? RGB_BLACK : RGB_WHITE);
  1104.                 hbr = GetStockObject(NULL_BRUSH);
  1105.             }
  1106.             else {
  1107.                 hpen = GetStockObject(NULL_PEN);
  1108.                 hbr = GetStockObject((gfDrawMode == MODE_COLOR) ?
  1109.                         BLACK_BRUSH : WHITE_BRUSH);
  1110.             }
  1111.     
  1112.             hpenOld = SelectObject(ghdcANDMask, hpen);
  1113.             hbrOld = SelectObject(ghdcANDMask, hbr);
  1114.             Rectangle(ghdcANDMask, ptTL.x, ptTL.y,
  1115.                     ptBR.x + nOutset, ptBR.y + nOutset);
  1116.             SelectObject(ghdcANDMask, hpenOld);
  1117.             SelectObject(ghdcANDMask, hbrOld);
  1118.     
  1119.             if (gCurTool == TOOL_RECT)
  1120.                 DeleteObject(hpen);
  1121.         }
  1122.     
  1123.         fImageDirty = TRUE;
  1124.     
  1125.         ViewUpdate();
  1126.     }
  1127.     
  1128.     
  1129.     
  1130.     /******************************************************************************
  1131.      * VOID PASCAL RubberBandRect()
  1132.      *
  1133.      * PURPOSE: Draw rubberbanding rect.
  1134.      *
  1135.      * PARAMS : HANDLE hDst : handle to dest. DC
  1136.      *
  1137.      *****************************************************************************/
  1138.     
  1139.     STATICFN VOID NEAR RubberBandRect(
  1140.         BOOL fFirstTime)
  1141.     {
  1142.         POINT ptTL;         // Top-Left point.
  1143.         POINT ptBR;         // Bottom-Right point
  1144.     
  1145.         /*
  1146.          * Set the raster-op to invert.
  1147.          */
  1148.         SetROP2(hdcRubberBand, R2_NOT);
  1149.     
  1150.         if (!fFirstTime) {
  1151.             /*
  1152.              * Erase the old rectangle.
  1153.              */
  1154.             ptTL = ptStart;
  1155.             ptBR = ptPrev;
  1156.             NormalizePoints(&ptTL, &ptBR);
  1157.             Rectangle(hdcRubberBand, ptTL.x, ptTL.y,
  1158.                     ptBR.x + gZoomFactor, ptBR.y + gZoomFactor);
  1159.         }
  1160.     
  1161.     
  1162.         /*
  1163.          * Draw the new one.
  1164.          */
  1165.         ptTL = ptStart;
  1166.         ptBR = ptEnd;
  1167.         NormalizePoints(&ptTL, &ptBR);
  1168.         Rectangle(hdcRubberBand, ptTL.x, ptTL.y,
  1169.                 ptBR.x + gZoomFactor, ptBR.y + gZoomFactor);
  1170.     }
  1171.     
  1172.     
  1173.     
  1174.     /******************************************************************************
  1175.      * VOID CircleDP(hwnd, msg, ptNew)
  1176.      *
  1177.      * PURPOSE: Draw an ellipse (filled/hollow) in the area specified.
  1178.      *
  1179.      * PARAMS : HWND   hwnd : handle to dest. DC
  1180.      *          unsigned msg  : Upper left corner of rect;
  1181.      *          POINT  ptNew   : end pt. of line
  1182.      *
  1183.      * SIDE EFFECTS: may change bits in image DC
  1184.      *
  1185.      *****************************************************************************/
  1186.     
  1187.     VOID CircleDP(
  1188.         HWND hwnd,
  1189.         UINT msg,
  1190.         POINT ptNew)
  1191.     {
  1192.         switch (msg) {
  1193.             case WM_RBUTTONDOWN:
  1194.             case WM_LBUTTONDOWN:
  1195.                 StartRubberBanding(hwnd);
  1196.                 RubberBandCircle(TRUE);
  1197.                 break;
  1198.     
  1199.             case WM_MOUSEMOVE:
  1200.                 if (fRubberBanding)
  1201.                     RubberBandCircle(FALSE);
  1202.     
  1203.                 break;
  1204.     
  1205.             case WM_LBUTTONUP:
  1206.             case WM_RBUTTONUP:
  1207.                 CircleDPDraw(hwnd);
  1208.                 break;
  1209.         }
  1210.     }
  1211.     
  1212.     
  1213.     
  1214.     /************************************************************************
  1215.     * CircleDPDraw
  1216.     *
  1217.     * Does the final drawing of an ellipse when using the Ellipse tool.
  1218.     *
  1219.     * Arguments:
  1220.     *   HWND hwnd - Window handle to the workspace.
  1221.     *
  1222.     * History:
  1223.     *
  1224.     ************************************************************************/
  1225.     
  1226.     STATICFN VOID NEAR CircleDPDraw(
  1227.         HWND hwnd)
  1228.     {
  1229.         POINT ptTL;         // Top-Left point.
  1230.         POINT ptBR;         // Bottom-Right point
  1231.         HBRUSH hbr;
  1232.         HBRUSH hbrOld;
  1233.         HPEN hpen;
  1234.         HPEN hpenOld;
  1235.         INT nOutset;
  1236.     
  1237.         EndRubberBanding(hwnd);
  1238.     
  1239.         /*
  1240.          * Flip the points (if needed) and scale down.
  1241.          */
  1242.         ptTL = ptStart;
  1243.         ptBR = ptEnd;
  1244.         NormalizePoints(&ptTL, &ptBR);
  1245.         ptTL.x /= gZoomFactor;
  1246.         ptTL.y /= gZoomFactor;
  1247.         ptBR.x /= gZoomFactor;
  1248.         ptBR.y /= gZoomFactor;
  1249.     
  1250.     #ifdef WIN16
  1251.         /*
  1252.          * The win 3.x code does not properly draw an ellipse if it
  1253.          * has a NULL pen selected in (to not draw the border).  For
  1254.          * this platform, we must select in the drawing pen.  This is
  1255.          * not necessary for NT (we can use a NULL pen to avoid
  1256.          * drawing the solid border).
  1257.          */
  1258.     
  1259.         if (gCurTool == TOOL_CIRCLE)
  1260.             hbr = GetStockObject(NULL_BRUSH);
  1261.         else
  1262.             hbr = ghbrDraw;
  1263.     
  1264.         hpenOld = SelectObject(ghdcImage, ghpenDraw);
  1265.         hbrOld = SelectObject(ghdcImage, hbr);
  1266.         Ellipse(ghdcImage, ptTL.x, ptTL.y, ptBR.x + 1, ptBR.y + 1);
  1267.         SelectObject(ghdcImage, hbrOld);
  1268.         SelectObject(ghdcImage, hpenOld);
  1269.     
  1270.         if (giType != FT_BITMAP) {
  1271.             /* for icons and cursors draw the shape on the AND DC (memory)
  1272.              * in black (if in color mode) or white (otherwise)
  1273.              */
  1274.             hpen = CreatePen(PS_INSIDEFRAME, 1,
  1275.                     (gfDrawMode == MODE_COLOR) ? RGB_BLACK : RGB_WHITE);
  1276.     
  1277.             if (gCurTool == TOOL_CIRCLE)
  1278.                 hbr = GetStockObject(NULL_BRUSH);
  1279.             else
  1280.                 hbr = GetStockObject((gfDrawMode == MODE_COLOR) ?
  1281.                         BLACK_BRUSH : WHITE_BRUSH);
  1282.     
  1283.             hpenOld = SelectObject(ghdcANDMask, hpen);
  1284.             hbrOld = SelectObject(ghdcANDMask, hbr);
  1285.             Ellipse(ghdcANDMask, ptTL.x, ptTL.y, ptBR.x + 1, ptBR.y + 1);
  1286.             SelectObject(ghdcANDMask, hpenOld);
  1287.             SelectObject(ghdcANDMask, hbrOld);
  1288.             DeleteObject(hpen);
  1289.         }
  1290.     
  1291.     #else
  1292.     
  1293.         if (gCurTool == TOOL_CIRCLE) {
  1294.             hpen = ghpenDraw;
  1295.             hbr = GetStockObject(NULL_BRUSH);
  1296.             nOutset = 1;
  1297.         }
  1298.         else {
  1299.             hpen = GetStockObject(NULL_PEN);
  1300.             hbr = ghbrDraw;
  1301.             nOutset = 2;
  1302.         }
  1303.     
  1304.         hpenOld = SelectObject(ghdcImage, hpen);
  1305.         hbrOld = SelectObject(ghdcImage, hbr);
  1306.         Ellipse(ghdcImage, ptTL.x, ptTL.y, ptBR.x + nOutset, ptBR.y + nOutset);
  1307.         SelectObject(ghdcImage, hpenOld);
  1308.         SelectObject(ghdcImage, hbrOld);
  1309.     
  1310.         if (giType != FT_BITMAP) {
  1311.             /* for icons and cursors draw the shape on the AND DC (memory)
  1312.              * in black (if in color mode) or white (otherwise)
  1313.              */
  1314.             if (gCurTool == TOOL_CIRCLE) {
  1315.                 hpen = CreatePen(PS_INSIDEFRAME, 1,
  1316.                         (gfDrawMode == MODE_COLOR) ? RGB_BLACK : RGB_WHITE);
  1317.                 hbr = GetStockObject(NULL_BRUSH);
  1318.             }
  1319.             else {
  1320.                 hpen = GetStockObject(NULL_PEN);
  1321.                 hbr = GetStockObject((gfDrawMode == MODE_COLOR) ?
  1322.                         BLACK_BRUSH : WHITE_BRUSH);
  1323.             }
  1324.     
  1325.             hpenOld = SelectObject(ghdcANDMask, hpen);
  1326.             hbrOld = SelectObject(ghdcANDMask, hbr);
  1327.             Ellipse(ghdcANDMask, ptTL.x, ptTL.y, ptBR.x + nOutset, ptBR.y + nOutset);
  1328.             SelectObject(ghdcANDMask, hpenOld);
  1329.             SelectObject(ghdcANDMask, hbrOld);
  1330.     
  1331.             if (gCurTool == TOOL_CIRCLE)
  1332.                 DeleteObject(hpen);
  1333.         }
  1334.     
  1335.     #endif
  1336.     
  1337.         fImageDirty = TRUE;
  1338.     
  1339.         ViewUpdate();
  1340.     }
  1341.     
  1342.     
  1343.     
  1344.     /******************************************************************************
  1345.      * VOID PASCAL RubberBandCircle()
  1346.      *
  1347.      * PURPOSE: Draw rubberbanding circle
  1348.      *
  1349.      *
  1350.      *****************************************************************************/
  1351.     
  1352.     STATICFN VOID NEAR RubberBandCircle(
  1353.         BOOL fFirstTime)
  1354.     {
  1355.         POINT ptTL;         // Top-Left point.
  1356.         POINT ptBR;         // Bottom-Right point
  1357.     
  1358.         /*
  1359.          * Set the raster-op to invert.
  1360.          */
  1361.         SetROP2(hdcRubberBand, R2_NOT);
  1362.     
  1363.         if (!fFirstTime) {
  1364.             /*
  1365.              * Erase the old circle.
  1366.              */
  1367.             ptTL = ptStart;
  1368.             ptBR = ptPrev;
  1369.             NormalizePoints(&ptTL, &ptBR);
  1370.             Ellipse(hdcRubberBand, ptTL.x, ptTL.y,
  1371.                     ptBR.x + gZoomFactor, ptBR.y + gZoomFactor);
  1372.         }
  1373.     
  1374.     
  1375.         /*
  1376.          * Draw the new one.
  1377.          */
  1378.         ptTL = ptStart;
  1379.         ptBR = ptEnd;
  1380.         NormalizePoints(&ptTL, &ptBR);
  1381.         Ellipse(hdcRubberBand, ptTL.x, ptTL.y,
  1382.                 ptBR.x + gZoomFactor, ptBR.y + gZoomFactor);
  1383.     }
  1384.     
  1385.     
  1386.     
  1387.     /************************************************************************
  1388.     * FloodDP
  1389.     *
  1390.     *
  1391.     *
  1392.     * Arguments:
  1393.     *
  1394.     * History:
  1395.     *
  1396.     ************************************************************************/
  1397.     
  1398.     VOID FloodDP(
  1399.         HWND hwnd,
  1400.         UINT msg,
  1401.         POINT ptNew)
  1402.     {
  1403.         HDC dc;
  1404.         HDC bwdc;
  1405.         HBRUSH hbrOld;
  1406.         HBITMAP bwbit;
  1407.         HCURSOR hcurSave;
  1408.     
  1409.         switch (msg) {
  1410.             case WM_RBUTTONDOWN:
  1411.             case WM_LBUTTONDOWN:
  1412.                 hcurSave = SetCursor(hcurWait);
  1413.     
  1414.                 dc = GetDC(hwnd);
  1415.                 /* create temporary DC */
  1416.                 bwdc = CreateCompatibleDC(dc);
  1417.     
  1418.                 /* create temporary monochrome bitmap */
  1419.                 if (!(bwbit = CreateBitmap(gcxImage, gcyImage, 1, 1, NULL))) {
  1420.                     DeleteDC(bwdc);
  1421.                     ReleaseDC(hwnd, dc);
  1422.                     Message(MSG_OUTOFMEMORY);
  1423.                     return;
  1424.                 }
  1425.                 SelectObject(bwdc, bwbit);
  1426.     
  1427.                 /*  Set background color of image DC to desired floodfill color.*/
  1428.                 SetBkColor(ghdcImage,
  1429.                         GetPixel(ghdcImage, (ptNew.x / gZoomFactor),
  1430.                         (ptNew.y / gZoomFactor)));
  1431.     
  1432.                 /******* OPERATION 0 ******/
  1433.                 /* First create a monochrome mask of the image after setting background
  1434.                  * color to the floodfill color. This will make the region to be
  1435.                  * flooded white(background), and it's boundary black (foreground) in the
  1436.                  * mask.
  1437.                  */
  1438.                 BitBlt(bwdc, 0, 0, gcxImage, gcyImage, ghdcImage, 0, 0, SRCCOPY);
  1439.     
  1440.                 /******* OPERATION 1 ******/
  1441.                 /* floodfill selected region in mask (which is white bounded by black)
  1442.                  * with black.
  1443.                  */
  1444.                 SelectObject(bwdc, GetStockObject(BLACK_BRUSH));
  1445.                 ExtFloodFill(bwdc, ptNew.x / gZoomFactor,
  1446.                         ptNew.y / gZoomFactor, RGB_BLACK, FLOODFILLBORDER);
  1447.     
  1448.                 /******* OPERATION 2 ******/
  1449.                 /* Now XOR the original image on the mask , inverting the
  1450.                  * flood-filled pixels on mask (black --> white).
  1451.                  */
  1452.                 BitBlt(bwdc, 0, 0, gcxImage, gcyImage, ghdcImage, 0, 0, SRCINVERT);
  1453.     
  1454.                 /* the AND mask needs to be updated only if in screen or inverse mode */
  1455.                 if ((giType == FT_CURSOR) || (giType == FT_ICON)) {
  1456.                     if (gfDrawMode == MODE_COLOR) {
  1457.                         SetBkColor(ghdcANDMask, RGB(0, 0, 0));
  1458.                         BitBlt(ghdcANDMask, 0, 0, gcxImage, gcyImage, bwdc,
  1459.                                 0, 0, ROP_DSna);
  1460.                         SelectObject(ghdcANDMask, GetStockObject(BLACK_BRUSH));
  1461.                         BitBlt(ghdcANDMask, 0, 0, gcxImage, gcyImage, bwdc,
  1462.                                 0, 0, ROP_DSPao);
  1463.                     }
  1464.                     else {
  1465.                         SetBkColor(ghdcANDMask, RGB(0xff, 0xff, 0xff));                    BitBlt(ghdcANDMask, 0, 0, gcxImage, gcyImage, bwdc,
  1466.                                 0, 0, ROP_DSna);
  1467.                         SelectObject(ghdcANDMask, GetStockObject(WHITE_BRUSH));
  1468.                         BitBlt(ghdcANDMask, 0, 0, gcxImage, gcyImage, bwdc,
  1469.                                 0, 0, ROP_DSPao);
  1470.                     }
  1471.                 }
  1472.     
  1473.                 SetBkColor(ghdcImage, RGB_WHITE);
  1474.                 /****** OPERATION 3 ******/
  1475.                 /* The following operation turns the flooded area on-screen black,
  1476.                  * on the image, preserving the rest of the it.
  1477.                  */
  1478.                 BitBlt(ghdcImage, 0, 0, gcxImage, gcyImage, bwdc, 0, 0, ROP_DSna);
  1479.     
  1480.                 /****** OPERATION 4 ******/
  1481.                 /* Rop_DSPao ANDs the pattern (current brush which is the floodfill
  1482.                  * color) on the source making flooded area (which was white as a
  1483.                  * result of operation 2 ) the current brush color, and keeps the rest
  1484.                  * of the source black. The source is then ORed into the original image
  1485.                  * (whose flooded area is black as a result of operation 3) to get
  1486.                  * the desired end result.
  1487.                  */
  1488.                 hbrOld = SelectObject(ghdcImage, ghbrDraw);
  1489.                 BitBlt(ghdcImage, 0, 0, gcxImage, gcyImage, bwdc, 0, 0, ROP_DSPao);
  1490.                 SelectObject(ghdcImage, hbrOld);
  1491.     
  1492.                 /* clean up */
  1493.                 DeleteDC(bwdc);
  1494.                 DeleteObject(bwbit);
  1495.                 ReleaseDC(hwnd, dc);
  1496.     
  1497.                 /*
  1498.                  * Mark the image as changed.
  1499.                  */
  1500.                 fImageDirty = TRUE;
  1501.     
  1502.                 ViewUpdate();
  1503.     
  1504.                 SetCursor(hcurSave);
  1505.     
  1506.                 break;
  1507.         }
  1508.     }
  1509.     
  1510.     
  1511.     
  1512.     /******************************************************************************
  1513.      * VOID HotSpotDP(hwnd, msg, ptNew)
  1514.      *
  1515.      * PURPOSE: Sets the hotspot.
  1516.      *
  1517.      * PARAMS : HWND   hwnd : handle to dest. DC
  1518.      *          WORD   msg  :
  1519.      *          POINT  ptNew   : end pt.
  1520.      *
  1521.      *****************************************************************************/
  1522.     
  1523.     VOID HotSpotDP(
  1524.         HWND hwnd,
  1525.         UINT msg,
  1526.         POINT ptNew)
  1527.     {
  1528.         switch (msg) {
  1529.             case WM_LBUTTONDOWN:
  1530.                 PropBarSetHotSpot(ptNew.x / gZoomFactor, ptNew.y / gZoomFactor);
  1531.                 break;
  1532.     
  1533.             case WM_MOUSEMOVE:
  1534.                 if (fDrawing && fLeftButtonDown)
  1535.                     PropBarSetHotSpot(ptNew.x / gZoomFactor,
  1536.                             ptNew.y / gZoomFactor);
  1537.     
  1538.                 break;
  1539.     
  1540.             case WM_LBUTTONUP:
  1541.                 MarkHotSpotPosition(ptNew.x / gZoomFactor, ptNew.y / gZoomFactor);
  1542.                 break;
  1543.         }
  1544.     }
  1545.     
  1546.     
  1547.     
  1548.     /************************************************************************
  1549.     * MarkHotSpotPosition
  1550.     *
  1551.     * Updates the hotspot location in the currently selected cursor image.
  1552.     *
  1553.     * Arguments:
  1554.     *
  1555.     * History:
  1556.     *
  1557.     ************************************************************************/
  1558.     
  1559.     STATICFN VOID NEAR MarkHotSpotPosition(
  1560.         INT x,
  1561.         INT y)
  1562.     {
  1563.         gpImageCur->iHotspotX = x;
  1564.         gpImageCur->iHotspotY = y;
  1565.         PropBarSetHotSpot(x, y);
  1566.     
  1567.         /*
  1568.          * Mark the image as changed.
  1569.          */
  1570.         fImageDirty = TRUE;
  1571.     }
  1572.     
  1573.     
  1574.     
  1575.     /******************************************************************************
  1576.      * NormalizePoints
  1577.      *
  1578.      * PURPOSE : interchange start and end pts
  1579.      *           if start point is > end point.
  1580.      *
  1581.      *****************************************************************************/
  1582.     
  1583.     VOID NormalizePoints(
  1584.         PPOINT pptStart,
  1585.         PPOINT pptEnd)
  1586.     {
  1587.         INT n;
  1588.     
  1589.         if (pptStart->x > pptEnd->x) {
  1590.             n = pptEnd->x;
  1591.             pptEnd->x = pptStart->x;
  1592.             pptStart->x = n;
  1593.         }
  1594.     
  1595.         if (pptStart->y > pptEnd->y) {
  1596.             n = pptEnd->y;
  1597.             pptEnd->y = pptStart->y;
  1598.             pptStart->y = n;
  1599.         }
  1600.     }
  1601.     
  1602.     
  1603.     
  1604.     /******************************************************************************
  1605.      * HDC PASCAL StartRubberBanding(hwnd)
  1606.      *
  1607.      * PURPOSE: Sets up rubberbanding for all tools.
  1608.      *
  1609.      * PARAMS : HANDLE hDst : handle to box DC
  1610.      *
  1611.      * RETURNS :handle to destination display context
  1612.      *
  1613.      * SIDE EFFECTS: alters a few global flags for tracking
  1614.      *
  1615.      *****************************************************************************/
  1616.     
  1617.     STATICFN VOID NEAR StartRubberBanding(
  1618.         HWND hwnd)
  1619.     {
  1620.         hdcRubberBand = GetDC(hwnd);
  1621.     
  1622.         /*
  1623.          * Select a white pen, and a null brush (prevents drawing the
  1624.          * interior of rectangles and ellipses).
  1625.          */
  1626.         SelectObject(hdcRubberBand, GetStockObject(WHITE_PEN));
  1627.         SelectObject(hdcRubberBand, GetStockObject(NULL_BRUSH));
  1628.     
  1629.         fRubberBanding = TRUE;
  1630.     }
  1631.     
  1632.     
  1633.     
  1634.     /******************************************************************************
  1635.      * VOID PASCAL EndRubberBanding()
  1636.      *
  1637.      * PURPOSE: Stops rubberbanding rect. and cleans up
  1638.      *
  1639.      *****************************************************************************/
  1640.     
  1641.     STATICFN VOID NEAR EndRubberBanding(
  1642.         HWND hwnd)
  1643.     {
  1644.         ReleaseDC(hwnd, hdcRubberBand);
  1645.         fRubberBanding = FALSE;
  1646.     }
  1647.