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 / colorwp.c next >
Text File  |  1994-06-01  |  40KB  |  1,341 lines

  1.     /***************************************************************************
  2.      *                                                                         *
  3.      *  MODULE      : ColorWP.c                                                *
  4.      *                                                                         *
  5.      *  DESCRIPTION : Window function for the colors window and related fns.   *
  6.      *                                                                         *
  7.      *  FUNCTIONS   : ColorWP ()            - Window function for colors       *
  8.      *                                        window.                          *
  9.      *                                                                         *
  10.      *                ComputeInverseColor() - Gets the inverse RGB of a given  *
  11.      *                                        RGB value                        *
  12.      *                                                                         *
  13.      *  HISTORY     : 6/21/89 - adapted from pBrush - LR                       *
  14.      *                                                                         *
  15.      ***************************************************************************/
  16.     
  17.     #include "imagedit.h"
  18.     #include "dialogs.h"
  19.  
  20.      #include <windowsx.h>
  21.     #include <commdlg.h>
  22.     
  23.     
  24.     STATICFN VOID NEAR ColorInit(HWND hwnd);
  25.     STATICFN VOID NEAR ColorProcessCommand(HWND hwnd, INT idCtrl, INT NotifyCode);
  26.     STATICFN VOID NEAR ColorBoxPaint(HDC hdc);
  27.     STATICFN VOID NEAR DrawColorRect(HDC hdc, DWORD rgb, INT x, INT y,
  28.         INT cx, INT cy, HDC hdcMem, BOOL fMonoOK);
  29.     STATICFN VOID NEAR MyRectangle(HDC hdc, INT left, INT top, INT right,
  30.         INT bottom, HDC hdcMem, BOOL fMonoOK);
  31.     STATICFN VOID NEAR ColorBoxClicked(UINT msg, PPOINT ppt);
  32.     STATICFN BOOL NEAR ColorBoxHitTest(PPOINT ppt, PINT piColor, PINT pfMode);
  33.     STATICFN VOID NEAR ColorLRPaint(HWND hwnd, HDC hdc);
  34.     STATICFN VOID NEAR ColorLRDrawSamples(HDC hdc, PRECT prc, BOOL fLeft);
  35.     STATICFN VOID NEAR ColorLRUpdate(BOOL fLeft);
  36.     STATICFN VOID NEAR ColorEdit(VOID);
  37.     STATICFN VOID NEAR SetLeftColor(INT iColor, INT iMode);
  38.     STATICFN VOID NEAR SetRightColor(INT iColor, INT iMode);
  39.     STATICFN HBRUSH NEAR MyCreateSolidBrush(DWORD rgb);
  40.     STATICFN DWORD NEAR MyGetNearestColor(DWORD rgb, BOOL fMonoOK);
  41.     STATICFN DWORD NEAR ComputeInverseColor(DWORD rgb);
  42.     
  43.     /*
  44.      * Width/height of a single color square.
  45.      */
  46.     static INT gcxColorBox;
  47.     
  48.     /*
  49.      * Vertical offset within the color box control to where to start the
  50.      * top row of color squares (the color squares are vertically centered
  51.      * within the color box control).
  52.      */
  53.     static INT gyColorBoxStart;
  54.     
  55.     /*
  56.      * Number of colors and image type.  These globals are used by the
  57.      * the color palette routines to know what mode the color palette
  58.      * is in.
  59.      */
  60.     static INT gnColorPalColors;
  61.     static INT giColorPalType;
  62.     
  63.     
  64.     
  65.     /****************************************************************************
  66.     * ColorShow
  67.     *
  68.     * This function shows or hides the color palette.
  69.     *
  70.     * History:
  71.     *
  72.     ****************************************************************************/
  73.     
  74.     VOID ColorShow(
  75.         BOOL fShow)
  76.     {
  77.         if (fShow)
  78.             ShowWindow(ghwndColor, SW_SHOWNA);
  79.         else
  80.             ShowWindow(ghwndColor, SW_HIDE);
  81.     }
  82.     
  83.     
  84.     
  85.     /************************************************************************
  86.     * ColorDlgProc
  87.     *
  88.     *
  89.     *
  90.     * Arguments:
  91.     *
  92.     * History:
  93.     *
  94.     ************************************************************************/
  95.     
  96.     DIALOGPROC ColorDlgProc(
  97.         HWND hwnd,
  98.         UINT msg,
  99.         WPARAM wParam,
  100.         LPARAM lParam)
  101.     {
  102.         switch (msg) {
  103.             case WM_INITDIALOG:
  104.                 ColorInit(hwnd);
  105.     
  106.                 /*
  107.                  * Return TRUE so that the dialog manager does NOT set the focus
  108.                  * for me.  This prevents the status window from initially having
  109.                  * the focus when the editor is started.
  110.                  */
  111.                 return TRUE;
  112.     
  113.             case WM_ACTIVATE:
  114.                 if (GET_WM_ACTIVATE_STATE(wParam, lParam))
  115.                     gidCurrentDlg = DID_COLOR;
  116.     
  117.                 break;
  118.     
  119.             case WM_CTLCOLORBTN:
  120.             case WM_CTLCOLORDLG:
  121.             case WM_CTLCOLORSTATIC:
  122.                 switch (GET_WM_CTLCOLOR_TYPE(wParam, lParam, msg)) {
  123.                     case CTLCOLOR_BTN:
  124.                     case CTLCOLOR_DLG:
  125.                         return (BOOL)GetStockObject(LTGRAY_BRUSH);
  126.     
  127.                     case CTLCOLOR_STATIC:
  128.                         SetBkColor(GET_WM_CTLCOLOR_HDC(wParam, lParam, msg),
  129.                                 RGB_LIGHTGRAY);
  130.                         return (BOOL)GetStockObject(LTGRAY_BRUSH);
  131.                 }
  132.     
  133.                 return (BOOL)NULL;
  134.     
  135.             case  WM_PAINT:
  136.                 {
  137.                     HDC hdc;
  138.                     PAINTSTRUCT ps;
  139.     
  140.                     hdc = BeginPaint(hwnd, &ps);
  141.                     DrawMarginBorder(hwnd, hdc);
  142.                     EndPaint(hwnd, &ps);
  143.                 }
  144.     
  145.                 break;
  146.     
  147.             case WM_COMMAND:
  148.                 ColorProcessCommand(hwnd,
  149.                         GET_WM_COMMAND_ID(wParam, lParam),
  150.                         GET_WM_COMMAND_CMD(wParam, lParam));
  151.                 break;
  152.     
  153.             case WM_CLOSE:
  154.                 /*
  155.                  * The user closed the color palette from the system menu.
  156.                  * Hide the window (we don't actually destroy it so
  157.                  * that it will appear in the same spot when they show
  158.                  * it again).
  159.                  */
  160.                 ColorShow(FALSE);
  161.                 gfShowColor = FALSE;
  162.                 break;
  163.     
  164.             case WM_DESTROY:
  165.                 {
  166.                     RECT rc;
  167.     
  168.                     /*
  169.                      * Save the position of the color palette.
  170.                      */
  171.                     GetWindowRect(hwnd, &rc);
  172.                     WriteWindowPos(&rc, FALSE, szColorPos);
  173.     
  174.                     /*
  175.                      * Null out the global window handle for the color palette
  176.                      * for safety's sake.
  177.                      */
  178.                     ghwndColor = NULL;
  179.                 }
  180.     
  181.                 break;
  182.     
  183.             default:
  184.                 return FALSE;
  185.         }
  186.     
  187.         return FALSE;
  188.     }
  189.     
  190.     
  191.     
  192.     /************************************************************************
  193.     * ColorInit
  194.     *
  195.     *
  196.     *
  197.     * Arguments:
  198.     *
  199.     * History:
  200.     *
  201.     ************************************************************************/
  202.     STATICFN VOID NEAR ColorInit(
  203.         HWND hwnd)
  204.     {
  205.         RECT rc;
  206.     
  207.         /*
  208.          * Get the dimension of a single color square, and the vertical
  209.          * offset to where the top of the squares are.
  210.          */
  211.         GetWindowRect(GetDlgItem(hwnd, DID_COLORBOX), &rc);
  212.         gcxColorBox = (rc.right - rc.left) / COLORCOLS;
  213.         gyColorBoxStart = ((rc.right - rc.left) - (gcxColorBox * COLORCOLS)) / 2;
  214.     }
  215.     
  216.     
  217.     
  218.     /************************************************************************
  219.     * ColorProcessCommand
  220.     *
  221.     *
  222.     * Arguments:
  223.     *   HWND hwnd        - The window handle.
  224.     *   INT idCtrl       - The id of the control the WM_COMMAND is for.
  225.     *   INT NotifyCode   - The control's notification code.
  226.     *
  227.     * History:
  228.     *
  229.     ************************************************************************/
  230.     
  231.     STATICFN VOID NEAR ColorProcessCommand(
  232.         HWND hwnd,
  233.         INT idCtrl,
  234.         INT NotifyCode)
  235.     {
  236.         switch (idCtrl) {
  237.             case DID_COLOREDIT:
  238.                 ColorEdit();
  239.                 break;
  240.     
  241.             case DID_COLORDEFAULT:
  242.                 if (gfModeLeft == MODE_COLOR) {
  243.                     gargbColor[giColorLeft] = gargbDefaultColor[giColorLeft];
  244.                     InvalidateRect(GetDlgItem(ghwndColor, DID_COLORBOX),
  245.                             NULL, TRUE);
  246.                     SetLeftColor(giColorLeft, gfModeLeft);
  247.                 }
  248.     
  249.                 break;
  250.         }
  251.     }
  252.     
  253.     
  254.     
  255.     /************************************************************************
  256.     * ColorBoxWndProc
  257.     *
  258.     *
  259.     *
  260.     * Arguments:
  261.     *
  262.     * History:
  263.     *
  264.     ************************************************************************/
  265.     
  266.     WINDOWPROC ColorBoxWndProc(
  267.         HWND hwnd,
  268.         UINT msg,
  269.         WPARAM wParam,
  270.         LPARAM lParam)
  271.     {
  272.         POINT pt;
  273.         HDC hdc;
  274.         PAINTSTRUCT ps;
  275.         INT iColor;
  276.         INT iMode;
  277.     
  278.         switch (msg) {
  279.             case WM_PAINT:
  280.                 hdc = BeginPaint(hwnd, &ps);
  281.                 ColorBoxPaint(hdc);
  282.                 EndPaint(hwnd, &ps);
  283.                 break;
  284.     
  285.             case WM_LBUTTONDOWN:
  286.             case WM_RBUTTONDOWN:
  287.                 ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y);
  288.                 ColorBoxClicked(msg, &pt);
  289.                 break;
  290.     
  291.             case WM_LBUTTONDBLCLK:
  292.                 ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y);
  293.                 if (ColorBoxHitTest(&pt, &iColor, &iMode))
  294.                     ColorEdit();
  295.     
  296.                 break;
  297.     
  298.             default:
  299.                 return DefWindowProc(hwnd, msg, wParam, lParam);
  300.         }
  301.     
  302.         return 0;
  303.     }
  304.     
  305.     
  306.     
  307.     /************************************************************************
  308.     * ColorBoxPaint
  309.     *
  310.     *
  311.     *
  312.     * Arguments:
  313.     *
  314.     * History:
  315.     *
  316.     ************************************************************************/
  317.     
  318.     STATICFN VOID NEAR ColorBoxPaint(
  319.         HDC hdc)
  320.     {
  321.         HDC hdcMem;
  322.         HBITMAP hbmMem;
  323.         INT i;
  324.         INT x;
  325.         INT y;
  326.         INT cx = gcxColorBox + 1;
  327.         INT cy = gcxColorBox + 1;
  328.     
  329.         if (giColorPalType != FT_BITMAP) {
  330.             x = 0;
  331.             y = gyColorBoxStart;
  332.             DrawColorRect(hdc, grgbScreen, x, y, cx, cy, NULL, FALSE);
  333.             y += gcxColorBox;
  334.             DrawColorRect(hdc, grgbInverse, x, y, cx, cy, NULL, FALSE);
  335.         }
  336.     
  337.         if (!(hdcMem = CreateCompatibleDC(hdc)))
  338.             return;
  339.     
  340.         /*
  341.          * Create a bitmap.  It will have the same number of colors as the
  342.          * current image.
  343.          */
  344.         if (!(hbmMem = MyCreateBitmap(hdc, cx, cy, gnColorPalColors))) {
  345.             DeleteDC(hdcMem);
  346.             return;
  347.         }
  348.     
  349.         SelectObject(hdcMem, hbmMem);
  350.     
  351.         x = gcxColorBox * 2;
  352.         y = gyColorBoxStart;
  353.     
  354.         for (i = 1; i <= COLORSMAX; i++) {
  355.             DrawColorRect(hdc, gargbCurrent[i - 1], x, y, cx, cy, hdcMem, TRUE);
  356.     
  357.             if (i % COLORROWS) {
  358.                 y += gcxColorBox;
  359.             }
  360.             else {
  361.                 x += gcxColorBox;
  362.                 y = gyColorBoxStart;
  363.             }
  364.         }
  365.     
  366.         DeleteDC(hdcMem);
  367.         DeleteObject(hbmMem);
  368.     }
  369.     
  370.     
  371.     
  372.     /************************************************************************
  373.     * DrawColorRect
  374.     *
  375.     *
  376.     *
  377.     * Arguments:
  378.     *
  379.     * History:
  380.     *
  381.     ************************************************************************/
  382.     
  383.     STATICFN VOID NEAR DrawColorRect(
  384.         HDC hdc,
  385.         DWORD rgb,
  386.         INT x,
  387.         INT y,
  388.         INT cx,
  389.         INT cy,
  390.         HDC hdcMem,
  391.         BOOL fMonoOK)
  392.     {
  393.         HBRUSH hbr;
  394.         HBRUSH hbrOld;
  395.     
  396.         hbr = CreateSolidBrush(rgb);
  397.         hbrOld = SelectObject(hdc, hbr);
  398.         MyRectangle(hdc, x, y, x + cx, y + cy, hdcMem, fMonoOK);
  399.         SelectObject(hdc, hbrOld);
  400.         DeleteObject(hbr);
  401.     }
  402.     
  403.     
  404.     
  405.     /************************************************************************
  406.     * MyRectangle
  407.     *
  408.     *
  409.     *
  410.     * Arguments:
  411.     *
  412.     * History:
  413.     *
  414.     ************************************************************************/
  415.     
  416.     STATICFN VOID NEAR MyRectangle(
  417.         HDC hdc,
  418.         INT left,
  419.         INT top,
  420.         INT right,
  421.         INT bottom,
  422.         HDC hdcMem,
  423.         BOOL fMonoOK)
  424.     {
  425.         HBITMAP hbmMem;
  426.         HBRUSH hbr;
  427.         HPEN hpen;
  428.         HBRUSH hbrOld;
  429.         HPEN hpenOld;
  430.         BOOL fDCCreated = FALSE;
  431.         INT cx = right - left;
  432.         INT cy = bottom - top;
  433.         INT nColors;
  434.     
  435.         /*
  436.          * Do they want us to create the memory DC and bitmap for them?
  437.          */
  438.         if (!hdcMem) {
  439.             if (!(hdcMem = CreateCompatibleDC(hdc)))
  440.                 return;
  441.     
  442.             /*
  443.              * Create a bitmap.  It will be monochrome if in 2 color mode
  444.              * and monochrome is ok, otherwise it will be 16 color.
  445.              */
  446.             nColors = gnColorPalColors;
  447.             if (!fMonoOK)
  448.                 nColors = 16;
  449.     
  450.             if (!(hbmMem = MyCreateBitmap(hdc, cx, cy, nColors))) {
  451.                 DeleteDC(hdcMem);
  452.                 return;
  453.             }
  454.     
  455.             SelectObject(hdcMem, hbmMem);
  456.             fDCCreated = TRUE;
  457.         }
  458.     
  459.         /*
  460.          * Extract the current pen and brush out of the passed in DC.
  461.          */
  462.         hbr = SelectObject(hdc, GetStockObject(NULL_BRUSH));
  463.         hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
  464.     
  465.         /*
  466.          * Select them into the memory DC.
  467.          */
  468.         hbrOld = SelectObject(hdcMem, hbr);
  469.         hpenOld = SelectObject(hdcMem, hpen);
  470.     
  471.         /*
  472.          * Draw the rectangle in the memory bitmap.
  473.          */
  474.         Rectangle(hdcMem, 0, 0, cx, cy);
  475.     
  476.         /*
  477.          * Unselect the pen and brush from the memory DC.
  478.          */
  479.         SelectObject(hdcMem, hbrOld);
  480.         SelectObject(hdcMem, hpenOld);
  481.     
  482.         /*
  483.          * Restore the pen and brush to the original DC.
  484.          */
  485.         SelectObject(hdc, hbr);
  486.         SelectObject(hdc, hpen);
  487.     
  488.         /*
  489.          * Blit the memory image to the passed in DC.
  490.          */
  491.         BitBlt(hdc, left, top, cx, cy, hdcMem, 0, 0, SRCCOPY);
  492.     
  493.         if (fDCCreated) {
  494.             DeleteDC(hdcMem);
  495.             DeleteObject(hbmMem);
  496.         }
  497.     }
  498.     
  499.     
  500.     
  501.     /************************************************************************
  502.     * ColorBoxClicked
  503.     *
  504.     *
  505.     *
  506.     * Arguments:
  507.     *
  508.     * History:
  509.     *
  510.     ************************************************************************/
  511.     
  512.     STATICFN VOID NEAR ColorBoxClicked(
  513.         UINT msg,
  514.         PPOINT ppt)
  515.     {
  516.         INT iColor;
  517.         INT iMode;
  518.     
  519.         if (ColorBoxHitTest(ppt, &iColor, &iMode)) {
  520.             switch (msg) {
  521.                 case WM_LBUTTONDOWN:
  522.                     SetLeftColor(iColor, iMode);
  523.                     break;
  524.     
  525.                 case WM_RBUTTONDOWN:
  526.                     SetRightColor(iColor, iMode);
  527.                     break;
  528.             }
  529.         }
  530.     }
  531.     
  532.     
  533.     
  534.     /************************************************************************
  535.     * ColorBoxHitTest
  536.     *
  537.     *
  538.     *
  539.     * Arguments:
  540.     *
  541.     * History:
  542.     *
  543.     ************************************************************************/
  544.     
  545.     STATICFN BOOL NEAR ColorBoxHitTest(
  546.         PPOINT ppt,
  547.         PINT piColor,
  548.         PINT pfMode)
  549.     {
  550.         INT iCol;
  551.         INT iRow;
  552.         INT iBox;
  553.     
  554.         if (ppt->y < gyColorBoxStart)
  555.             return FALSE;
  556.     
  557.         iCol = ppt->x / gcxColorBox;
  558.         iRow = (ppt->y - gyColorBoxStart) / gcxColorBox;
  559.     
  560.         if (iCol >= (COLORSMAX / COLORROWS) + 2 || iRow >= COLORROWS)
  561.             return FALSE;
  562.     
  563.         iBox = iRow + (iCol * COLORROWS);
  564.     
  565.         switch (iBox) {
  566.             case 0:
  567.                 if (giColorPalType == FT_BITMAP)
  568.                     return FALSE;
  569.     
  570.                 *piColor = 0;
  571.                 *pfMode = MODE_SCREEN;
  572.                 return TRUE;
  573.     
  574.             case 1:
  575.                 if (giColorPalType == FT_BITMAP)
  576.                     return FALSE;
  577.     
  578.                 *piColor = 0;
  579.                 *pfMode = MODE_INVERSE;
  580.                 return TRUE;
  581.     
  582.             case 2:
  583.             case 3:
  584.                 return FALSE;
  585.     
  586.             default:
  587.                 *piColor = iBox - (COLORROWS * 2);
  588.                 *pfMode = MODE_COLOR;
  589.                 return TRUE;
  590.         }
  591.     }
  592.     
  593.     
  594.     
  595.     /************************************************************************
  596.     * ColorLRWndProc
  597.     *
  598.     *
  599.     *
  600.     * Arguments:
  601.     *
  602.     * History:
  603.     *
  604.     ************************************************************************/
  605.     
  606.     WINDOWPROC ColorLRWndProc(
  607.         HWND hwnd,
  608.         UINT msg,
  609.         WPARAM wParam,
  610.         LPARAM lParam)
  611.     {
  612.         HDC hdc;
  613.         PAINTSTRUCT ps;
  614.     
  615.         switch (msg) {
  616.             case WM_PAINT:
  617.                 hdc = BeginPaint(hwnd, &ps);
  618.                 ColorLRPaint(hwnd, hdc);
  619.                 EndPaint(hwnd, &ps);
  620.                 break;
  621.     
  622.             default:
  623.                 return DefWindowProc(hwnd, msg, wParam, lParam);
  624.         }
  625.     
  626.         return 0;
  627.     }
  628.     
  629.     
  630.     
  631.     /************************************************************************
  632.     * ColorLRPaint
  633.     *
  634.     *
  635.     *
  636.     * Arguments:
  637.     *
  638.     * History:
  639.     *
  640.     ************************************************************************/
  641.     
  642.     STATICFN VOID NEAR ColorLRPaint(
  643.         HWND hwnd,
  644.         HDC hdc)
  645.     {
  646.         RECT rc;
  647.     
  648.         GetClientRect(hwnd, &rc);
  649.         DrawSunkenRect(&rc, hdc);
  650.         ColorLRDrawSamples(hdc, &rc, TRUE);
  651.         ColorLRDrawSamples(hdc, &rc, FALSE);
  652.     }
  653.     
  654.     
  655.     
  656.     /************************************************************************
  657.     * ColorLRDrawSamples
  658.     *
  659.     * Draws the sample colors in the Color Left-Right control.
  660.     *
  661.     * Arguments:
  662.     *   HDC hdc    - DC to draw into.
  663.     *   PRECT prc  - Rectangle of color sample control.  The samples will
  664.     *                be centered within this with an appropriate margin.
  665.     *   BOOL fLeft - TRUE if the left sample is to be drawn, FALSE for the right.
  666.     *
  667.     * History:
  668.     *
  669.     ************************************************************************/
  670.     
  671.     STATICFN VOID NEAR ColorLRDrawSamples(
  672.         HDC hdc,
  673.         PRECT prc,
  674.         BOOL fLeft)
  675.     {
  676.         INT xLeftStart;
  677.         INT xRightStart;
  678.         INT ySolidStart;
  679.         INT yDitherStart;
  680.         INT cx;
  681.         INT cy;
  682.         HBRUSH hbrOld;
  683.         HPEN hpenOld;
  684.         BOOL fMonoOK;
  685.     
  686.         /*
  687.          * The width and height of each square includes the border.
  688.          */
  689.         cx = ((prc->right - prc->left) - (6 * PALETTEMARGIN)) / 2;
  690.         cy = ((prc->bottom - prc->top) - (4 * PALETTEMARGIN)) / 2;
  691.     
  692.         xLeftStart = prc->left + (PALETTEMARGIN * 2) + 1;
  693.         xRightStart = xLeftStart + cx + (PALETTEMARGIN * 2);
  694.     
  695.         ySolidStart = prc->top + (PALETTEMARGIN * 2) + 1;
  696.         yDitherStart = ySolidStart - 1 + cy;
  697.     
  698.         /*
  699.          * Draw either the left or the right color sample.
  700.          */
  701.         if (fLeft) {
  702.             fMonoOK = (gfModeLeft == MODE_COLOR) ? TRUE : FALSE;
  703.     
  704.             /*
  705.              * Draw the solid color.
  706.              */
  707.             hbrOld = SelectObject(hdc, ghbrLeftSolid);
  708.             hpenOld = SelectObject(hdc, GetStockObject(NULL_PEN));
  709.             MyRectangle(hdc, xLeftStart, ySolidStart,
  710.                     xLeftStart + cx, yDitherStart + 1, NULL, fMonoOK);
  711.     
  712.             /*
  713.              * Draw the true color (may be dithered).
  714.              */
  715.             SelectObject(hdc, ghbrLeft);
  716.             MyRectangle(hdc, xLeftStart, yDitherStart,
  717.                     xLeftStart + cx, yDitherStart + cy, NULL, fMonoOK);
  718.         }
  719.         else {
  720.             fMonoOK = (gfModeRight == MODE_COLOR) ? TRUE : FALSE;
  721.     
  722.             hbrOld = SelectObject(hdc, ghbrRightSolid);
  723.             hpenOld = SelectObject(hdc, GetStockObject(NULL_PEN));
  724.             MyRectangle(hdc, xRightStart, ySolidStart,
  725.                     xRightStart + cx, yDitherStart + 1, NULL, fMonoOK);
  726.     
  727.             SelectObject(hdc, ghbrRight);
  728.             MyRectangle(hdc, xRightStart, yDitherStart,
  729.                     xRightStart + cx, yDitherStart + cy, NULL, fMonoOK);
  730.         }
  731.     
  732.         /*
  733.          * Now draw the outline rectangle.
  734.          */
  735.         SelectObject(hdc, GetStockObject(BLACK_PEN));
  736.         SelectObject(hdc, GetStockObject(NULL_BRUSH));
  737.     
  738.         if (fLeft) {
  739.             Rectangle(hdc, xLeftStart - 1, ySolidStart - 1,
  740.                     xLeftStart + cx, yDitherStart + cy);
  741.         }
  742.         else {
  743.             Rectangle(hdc, xRightStart - 1, ySolidStart - 1,
  744.                     xRightStart + cx, yDitherStart + cy);
  745.         }
  746.     
  747.         /*
  748.          * Clean up.
  749.          */
  750.         SelectObject(hdc, hpenOld);
  751.         SelectObject(hdc, hbrOld);
  752.     }
  753.     
  754.     
  755.     
  756.     /************************************************************************
  757.     * ColorLRUpdate
  758.     *
  759.     * Called when the left or right color has been changed.  This function
  760.     * will cause the specified color sample to be updated in the color palette.
  761.     *
  762.     * History:
  763.     *
  764.     ************************************************************************/
  765.     
  766.     STATICFN VOID NEAR ColorLRUpdate(
  767.         BOOL fLeft)
  768.     {
  769.         RECT rc;
  770.         HWND hwndLR;
  771.         HDC hdc;
  772.     
  773.         hwndLR = GetDlgItem(ghwndColor, DID_COLORLR);
  774.         GetClientRect(hwndLR, &rc);
  775.         hdc = GetDC(hwndLR);
  776.         ColorLRDrawSamples(hdc, &rc, fLeft);
  777.         ReleaseDC(hwndLR, hdc);
  778.     }
  779.     
  780.     
  781.     
  782.     /************************************************************************
  783.     * ColorEdit
  784.     *
  785.     * This function calls the standard color chooser dialog to get a
  786.     * new color for the selected palette entry.
  787.     *
  788.     * History:
  789.     *
  790.     ************************************************************************/
  791.     
  792.     STATICFN VOID NEAR ColorEdit(VOID)
  793.     {
  794.         /*
  795.          * This array of custom colors is initialized to all white colors.
  796.          * The custom colors will be remembered between calls, but not
  797.          * between sessions.
  798.          */
  799.         static DWORD argbCust[16] = {
  800.             RGB(255, 255, 255), RGB(255, 255, 255),
  801.             RGB(255, 255, 255), RGB(255, 255, 255),
  802.             RGB(255, 255, 255), RGB(255, 255, 255),
  803.             RGB(255, 255, 255), RGB(255, 255, 255),
  804.             RGB(255, 255, 255), RGB(255, 255, 255),
  805.             RGB(255, 255, 255), RGB(255, 255, 255),
  806.             RGB(255, 255, 255), RGB(255, 255, 255),
  807.             RGB(255, 255, 255), RGB(255, 255, 255)
  808.         };
  809.         CHOOSECOLOR cc;
  810.         DWORD rgbOld;
  811.         BOOL fResult;
  812.         INT idPrevDlg;
  813.     
  814.         switch (gfModeLeft) {
  815.             case MODE_COLOR:
  816.                 /*
  817.                  * The monochrome palette cannot be edited.
  818.                  */
  819.                 if (gnColorPalColors == 2)
  820.                     return;
  821.     
  822.                 rgbOld = gargbCurrent[giColorLeft];
  823.                 break;
  824.     
  825.             case MODE_SCREEN:
  826.                 rgbOld = grgbScreen;
  827.                 break;
  828.     
  829.             case MODE_INVERSE:
  830.                 rgbOld = grgbInverse;
  831.                 break;
  832.         }
  833.     
  834.         cc.lStructSize = sizeof(CHOOSECOLOR);
  835.         cc.hwndOwner = ghwndMain;
  836.         cc.hInstance = ghInst;
  837.         cc.rgbResult = rgbOld;
  838.         cc.lpCustColors = argbCust;
  839.         cc.Flags = CC_RGBINIT | CC_SHOWHELP;
  840.         cc.lCustData = 0;
  841.         cc.lpfnHook = NULL;
  842.         cc.lpTemplateName = NULL;
  843.     
  844.         EnteringDialog(DID_COMMONFILECHOOSECOLOR, &idPrevDlg, TRUE);
  845.         fResult = ChooseColor(&cc);
  846.         EnteringDialog(idPrevDlg, NULL, FALSE);
  847.     
  848.         if (fResult && rgbOld != cc.rgbResult) {
  849.             switch (gfModeLeft) {
  850.                 case MODE_COLOR:
  851.                     gargbCurrent[giColorLeft] = cc.rgbResult;
  852.                     break;
  853.     
  854.                 case MODE_SCREEN:
  855.                     SetScreenColor(cc.rgbResult);
  856.                     break;
  857.     
  858.                 case MODE_INVERSE:
  859.                     SetScreenColor(ComputeInverseColor(cc.rgbResult));
  860.                     break;
  861.             }
  862.     
  863.             SetLeftColor(giColorLeft, gfModeLeft);
  864.             InvalidateRect(GetDlgItem(ghwndColor, DID_COLORBOX), NULL, TRUE);
  865.         }
  866.     }
  867.     
  868.     
  869.     
  870.     /************************************************************************
  871.     * SetLeftColor
  872.     *
  873.     *
  874.     * History:
  875.     *
  876.     ************************************************************************/
  877.     
  878.     STATICFN VOID NEAR SetLeftColor(
  879.         INT iColor,
  880.         INT iMode)
  881.     {
  882.         DWORD rgbSolid;
  883.         BOOL fEnableDefault = FALSE;
  884.         BOOL fEnableEdit = FALSE;
  885.     
  886.         if (ghbrLeft)
  887.             DeleteObject(ghbrLeft);
  888.     
  889.         if (ghbrLeftSolid)
  890.             DeleteObject(ghbrLeftSolid);
  891.     
  892.         if (ghpenLeft)
  893.             DeleteObject(ghpenLeft);
  894.     
  895.         switch (iMode) {
  896.             case MODE_COLOR:
  897.                 ghbrLeft = MyCreateSolidBrush(gargbCurrent[iColor]);
  898.                 rgbSolid = MyGetNearestColor(gargbCurrent[iColor], TRUE);
  899.                 ghbrLeftSolid = CreateSolidBrush(rgbSolid);
  900.                 ghpenLeft = CreatePen(PS_INSIDEFRAME, 1, rgbSolid);
  901.                 giColorLeft = iColor;
  902.     
  903.                 /*
  904.                  * We will enable the "Default" button if the current color
  905.                  * on the left button is not the default color, and we are
  906.                  * not in monochrome mode.
  907.                  */
  908.                 if (gargbColor[giColorLeft] != gargbDefaultColor[giColorLeft] &&
  909.                         gnColorPalColors > 2)
  910.                     fEnableDefault = TRUE;
  911.     
  912.                 /*
  913.                  * For non-screen colors, the Edit button will be enabled
  914.                  * if we are not in monochrome mode.
  915.                  */
  916.                 if (gnColorPalColors > 2)
  917.                     fEnableEdit = TRUE;
  918.     
  919.                 break;
  920.     
  921.             case MODE_SCREEN:
  922.                 ghbrLeft = CreateSolidBrush(grgbScreen);
  923.                 ghbrLeftSolid = CreateSolidBrush(grgbScreen);
  924.                 ghpenLeft = CreatePen(PS_INSIDEFRAME, 1, grgbScreen);
  925.                 giColorLeft = 0;
  926.                 fEnableEdit = TRUE;
  927.                 break;
  928.     
  929.             case MODE_INVERSE:
  930.                 ghbrLeft = CreateSolidBrush(grgbInverse);
  931.                 ghbrLeftSolid = CreateSolidBrush(grgbInverse);
  932.                 ghpenLeft = CreatePen(PS_INSIDEFRAME, 1, grgbInverse);
  933.                 giColorLeft = 0;
  934.                 fEnableEdit = TRUE;
  935.                 break;
  936.         }
  937.     
  938.         EnableWindow(GetDlgItem(ghwndColor, DID_COLORDEFAULT), fEnableDefault);
  939.         EnableWindow(GetDlgItem(ghwndColor, DID_COLOREDIT), fEnableEdit);
  940.     
  941.         gfModeLeft = iMode;
  942.         ColorLRUpdate(TRUE);
  943.     }
  944.     
  945.     
  946.     
  947.     /************************************************************************
  948.     * SetRightColor
  949.     *
  950.     *
  951.     * History:
  952.     *
  953.     ************************************************************************/
  954.     
  955.     STATICFN VOID NEAR SetRightColor(
  956.         INT iColor,
  957.         INT iMode)
  958.     {
  959.         DWORD rgbSolid;
  960.     
  961.         if (ghbrRight)
  962.             DeleteObject(ghbrRight);
  963.     
  964.         if (ghbrRightSolid)
  965.             DeleteObject(ghbrRightSolid);
  966.     
  967.         if (ghpenRight)
  968.             DeleteObject(ghpenRight);
  969.     
  970.         switch (iMode) {
  971.             case MODE_COLOR:
  972.                 ghbrRight = MyCreateSolidBrush(gargbCurrent[iColor]);
  973.                 rgbSolid = MyGetNearestColor(gargbCurrent[iColor], TRUE);
  974.                 ghbrRightSolid = CreateSolidBrush(rgbSolid);
  975.                 ghpenRight = CreatePen(PS_INSIDEFRAME, 1, rgbSolid);
  976.                 giColorRight = iColor;
  977.                 break;
  978.     
  979.             case MODE_SCREEN:
  980.                 ghbrRight = CreateSolidBrush(grgbScreen);
  981.                 ghbrRightSolid = CreateSolidBrush(grgbScreen);
  982.                 ghpenRight = CreatePen(PS_INSIDEFRAME, 1, grgbScreen);
  983.                 giColorRight = 0;
  984.                 break;
  985.     
  986.             case MODE_INVERSE:
  987.                 ghbrRight = CreateSolidBrush(grgbInverse);
  988.                 ghbrRightSolid = CreateSolidBrush(grgbInverse);
  989.                 ghpenRight = CreatePen(PS_INSIDEFRAME, 1, grgbInverse);
  990.                 giColorRight = 0;
  991.                 break;
  992.         }
  993.     
  994.         gfModeRight = iMode;
  995.         ColorLRUpdate(FALSE);
  996.     }
  997.     
  998.     
  999.     
  1000.     /************************************************************************
  1001.     * SetScreenColor
  1002.     *
  1003.     *
  1004.     * History:
  1005.     *
  1006.     ************************************************************************/
  1007.     
  1008.     VOID SetScreenColor(
  1009.         DWORD rgb)
  1010.     {
  1011.         DWORD rgbInverse;
  1012.         HDC hdcTemp;
  1013.         HBITMAP hbmOld;
  1014.         HDC hdcANDTemp;
  1015.         HBITMAP hbmANDOld;
  1016.     
  1017.         rgb = MyGetNearestColor(rgb, FALSE);
  1018.     
  1019.         /*
  1020.          * Because we are about to change the screen color, separate
  1021.          * out the XOR mask (but only for icons/cursors).
  1022.          */
  1023.         if (giColorPalType != FT_BITMAP) {
  1024.             if (gpImageCur) {
  1025.                 ImageDCSeparate(ghdcImage, gcxImage, gcyImage, ghdcANDMask,
  1026.                         grgbScreen);
  1027.     
  1028.                 /*
  1029.                  * Is there a pending undo buffer?  If so, it must be
  1030.                  * changed as well or an undo that is done after a screen
  1031.                  * color change will restore the wrong colors!
  1032.                  */
  1033.                 if (ghbmUndo) {
  1034.                     /*
  1035.                      * Create some temporary DC's to use when separating
  1036.                      * out the undo buffer's masks.  These will be deleted
  1037.                      * a little later.
  1038.                      */
  1039.                     hdcTemp = CreateCompatibleDC(ghdcImage);
  1040.                     hbmOld = SelectObject(hdcTemp, ghbmUndo);
  1041.                     hdcANDTemp = CreateCompatibleDC(ghdcANDMask);
  1042.                     hbmANDOld = SelectObject(hdcANDTemp, ghbmUndoMask);
  1043.     
  1044.                     /*
  1045.                      * Separate out the undo buffer's colors, before
  1046.                      * changing the screen color.  It will be combined
  1047.                      * later.
  1048.                      */
  1049.                     ImageDCSeparate(hdcTemp, gcxImage, gcyImage, hdcANDTemp,
  1050.                             grgbScreen);
  1051.                 }
  1052.             }
  1053.         }
  1054.     
  1055.         if (ghbrScreen)
  1056.             DeleteObject(ghbrScreen);
  1057.     
  1058.         ghbrScreen = CreateSolidBrush(rgb);
  1059.         grgbScreen = rgb;
  1060.     
  1061.         if (ghbrInverse)
  1062.             DeleteObject(ghbrInverse);
  1063.     
  1064.         rgbInverse = ComputeInverseColor(rgb);
  1065.         ghbrInverse = CreateSolidBrush(rgbInverse);
  1066.         grgbInverse = rgbInverse;
  1067.     
  1068.         /*
  1069.          * For icons and cursors, we might need to update a few more things.
  1070.          */
  1071.         if (giColorPalType != FT_BITMAP) {
  1072.             /*
  1073.              * Recombine the XOR and AND images now that there is a new screen
  1074.              * color.  This updates the image DC with the new color properly.
  1075.              */
  1076.             if (gpImageCur) {
  1077.                 ImageDCCombine(ghdcImage, gcxImage, gcyImage, ghdcANDMask);
  1078.     
  1079.                 /*
  1080.                  * Is there a pending undo buffer?  If so, it has to be
  1081.                  * recombined with the new screen color.
  1082.                  */
  1083.                 if (ghbmUndo) {
  1084.                     ImageDCCombine(hdcTemp, gcxImage, gcyImage, hdcANDTemp);
  1085.     
  1086.                     /*
  1087.                      * Clean up the DC's that were allocated a little earlier.
  1088.                      */
  1089.                     SelectObject(hdcANDTemp, hbmANDOld);
  1090.                     DeleteDC(hdcANDTemp);
  1091.                     SelectObject(hdcTemp, hbmOld);
  1092.                     DeleteDC(hdcTemp);
  1093.                 }
  1094.             }
  1095.     
  1096.             /*
  1097.              * Reset the colors on the mouse buttons, just in case a screen
  1098.              * or inverse screen color was assigned to either of them.
  1099.              */
  1100.             SetLeftColor(giColorLeft, gfModeLeft);
  1101.             SetRightColor(giColorRight, gfModeRight);
  1102.     
  1103.             InvalidateRect(GetDlgItem(ghwndColor, DID_COLORBOX), NULL, TRUE);
  1104.         }
  1105.     
  1106.         ViewUpdate();
  1107.     }
  1108.     
  1109.     
  1110.     
  1111.     /************************************************************************
  1112.     * MyCreateSolidBrush
  1113.     *
  1114.     *
  1115.     * History:
  1116.     *
  1117.     ************************************************************************/
  1118.     
  1119.     STATICFN HBRUSH NEAR MyCreateSolidBrush(
  1120.         DWORD rgb)
  1121.     {
  1122.         HDC hdc;
  1123.         HDC hdcMem;
  1124.         HBRUSH hbr;
  1125.         HBRUSH hbrOld;
  1126.         HBITMAP hbmPat;
  1127.         HBITMAP hbmOld;
  1128.     
  1129.         /*
  1130.          * First, create a brush for the given RGB value.
  1131.          */
  1132.         hbr = CreateSolidBrush(rgb);
  1133.     
  1134.         /*
  1135.          * Create a temporary memory DC.
  1136.          */
  1137.         hdc = GetDC(ghwndMain);
  1138.         hdcMem = CreateCompatibleDC(hdc);
  1139.     
  1140.         /*
  1141.          * Create a temporary bitmap.
  1142.          */
  1143.         hbmPat = MyCreateBitmap(hdc, 8, 8, gnColorPalColors);
  1144.         ReleaseDC(ghwndMain, hdc);
  1145.     
  1146.         /*
  1147.          * Draw the (possibly) dithered pattern on the temporary bitmap.
  1148.          */
  1149.         hbmOld = SelectObject(hdcMem, hbmPat);
  1150.         hbrOld = SelectObject(hdcMem, hbr);
  1151.         PatBlt(hdcMem, 0, 0, 8, 8, PATCOPY);
  1152.         SelectObject(hdcMem, hbrOld);
  1153.         SelectObject(hdcMem, hbmOld);
  1154.         DeleteDC(hdcMem);
  1155.     
  1156.         /*
  1157.          * Delete the first brush.
  1158.          */
  1159.         DeleteObject(hbr);
  1160.     
  1161.         /*
  1162.          * Now create a pattern brush out of the (dithered) bitmap.
  1163.          */
  1164.         hbr = CreatePatternBrush(hbmPat);
  1165.     
  1166.         DeleteObject(hbmPat);
  1167.     
  1168.         /*
  1169.          * Return the pattern brush.
  1170.          */
  1171.         return hbr;
  1172.     }
  1173.     
  1174.     
  1175.     
  1176.     /************************************************************************
  1177.     * MyGetNearestColor
  1178.     *
  1179.     * This function returns the RGB value of the nearest color to the
  1180.     * specified RGB value.  If fMonoOK is TRUE, it takes into account
  1181.     * the number of colors of the current image being edited.  In other
  1182.     * words, it will return the nearest solid color for a device that
  1183.     * has the number of colors of the current image.
  1184.     *
  1185.     * Arguments:
  1186.     *   DWORD rgb    - RGB value of the color.
  1187.     *   BOOL fMonoOK - TRUE if the returned color should be mapped to a
  1188.     *                  color in a monochrome palette, if the current image
  1189.     *                  is monochrome.  A value of FALSE will return a
  1190.     *                  color mapped to the closest color in a 16 color
  1191.     *                  palette.
  1192.     *
  1193.     * History:
  1194.     *
  1195.     ************************************************************************/
  1196.     
  1197.     STATICFN DWORD NEAR MyGetNearestColor(
  1198.         DWORD rgb,
  1199.         BOOL fMonoOK)
  1200.     {
  1201.         HDC hdc;
  1202.         HDC hdcMem;
  1203.         DWORD rgbNearest;
  1204.         HBITMAP hbmMem;
  1205.         HBITMAP hbmOld;
  1206.     
  1207.         hdc = GetDC(ghwndMain);
  1208.         hdcMem = CreateCompatibleDC(hdc);
  1209.         hbmMem = MyCreateBitmap(hdc, 1, 1, (fMonoOK) ? gnColorPalColors : 16);
  1210.         hbmOld = SelectObject(hdcMem, hbmMem);
  1211.         rgbNearest = GetNearestColor(hdcMem, rgb);
  1212.         SelectObject(hdcMem, hbmOld);
  1213.         DeleteObject(hbmMem);
  1214.         DeleteDC(hdcMem);
  1215.         ReleaseDC(ghwndMain, hdc);
  1216.     
  1217.         return rgbNearest;
  1218.     }
  1219.     
  1220.     
  1221.     
  1222.     /************************************************************************
  1223.     * ComputeInverseColor
  1224.     *
  1225.     * Computes the inverse value of a given rgb color.
  1226.     *
  1227.     * Arguments:
  1228.     *
  1229.     * History:
  1230.     *
  1231.     ************************************************************************/
  1232.     
  1233.     STATICFN DWORD NEAR ComputeInverseColor(
  1234.         DWORD rgb)
  1235.     {
  1236.         HBITMAP hTempBit1;
  1237.         HBITMAP hTempBit2;
  1238.         HDC hTempDC1;
  1239.         HDC hTempDC2;
  1240.         HDC hdc;
  1241.         HANDLE hOldObj1;
  1242.         HANDLE hOldObj2;
  1243.         DWORD rgbInv;
  1244.     
  1245.         hdc = GetDC(ghwndMain);
  1246.         hTempDC1 = CreateCompatibleDC(hdc);
  1247.         hTempDC2 = CreateCompatibleDC(hdc);
  1248.     
  1249.         /* create two temporary 1x1, 16 color bitmaps */
  1250.         hTempBit1 = MyCreateBitmap(hdc, 1, 1, 16);
  1251.         hTempBit2 = MyCreateBitmap(hdc, 1, 1, 16);
  1252.     
  1253.         ReleaseDC(ghwndMain, hdc);
  1254.     
  1255.         hOldObj1 = SelectObject(hTempDC1, hTempBit1);
  1256.         hOldObj2 = SelectObject(hTempDC2, hTempBit2);
  1257.     
  1258.         /* method for getting inverse color : set the given pixel (rgb) on
  1259.          * one DC. Now blt it to the other DC using a SRCINVERT rop.
  1260.          * This yields a pixel of the inverse color on the destination DC
  1261.          */
  1262.         SetPixel(hTempDC1, 0, 0, rgb);
  1263.         PatBlt(hTempDC2, 0, 0, 1, 1, WHITENESS);
  1264.         BitBlt(hTempDC2, 0, 0, 1, 1, hTempDC1, 0, 0, SRCINVERT);
  1265.         rgbInv = GetPixel(hTempDC2, 0, 0);
  1266.     
  1267.         /* clean up ... */
  1268.         SelectObject(hTempDC1, hOldObj1);
  1269.         SelectObject(hTempDC2, hOldObj2);
  1270.         DeleteObject(hTempBit1);
  1271.         DeleteObject(hTempBit2);
  1272.         DeleteDC(hTempDC1);
  1273.         DeleteDC(hTempDC2);
  1274.     
  1275.         /* ...and return the inverted RGB value */
  1276.         return rgbInv;
  1277.     }
  1278.     
  1279.     
  1280.     
  1281.     /************************************************************************
  1282.     * SetColorPalette
  1283.     *
  1284.     *
  1285.     * History:
  1286.     *
  1287.     ************************************************************************/
  1288.     
  1289.     VOID SetColorPalette(
  1290.         INT nColors,
  1291.         INT iType,
  1292.         BOOL fForce)
  1293.     {
  1294.         /*
  1295.          * Quit if nothing changed (unless they are forcing it to be updated).
  1296.          */
  1297.         if (!fForce && nColors == gnColorPalColors && iType == giColorPalType)
  1298.             return;
  1299.     
  1300.         /*
  1301.          * Set the globals that all the color palette routines use.
  1302.          */
  1303.         gnColorPalColors = nColors;
  1304.         giColorPalType = iType;
  1305.     
  1306.         if (gnColorPalColors == 2)
  1307.             gargbCurrent = gargbMono;
  1308.         else
  1309.             gargbCurrent = gargbColor;
  1310.     
  1311.         ShowWindow(GetDlgItem(ghwndColor, DID_COLORSCREENLABEL),
  1312.                 (giColorPalType == FT_BITMAP) ? SW_HIDE : SW_SHOW);
  1313.         ShowWindow(GetDlgItem(ghwndColor, DID_COLORINVERSELABEL),
  1314.                 (giColorPalType == FT_BITMAP) ? SW_HIDE : SW_SHOW);
  1315.     
  1316.         SetLeftColor(1, MODE_COLOR);
  1317.         SetRightColor(0, MODE_COLOR);
  1318.     
  1319.         InvalidateRect(GetDlgItem(ghwndColor, DID_COLORBOX), NULL, TRUE);
  1320.     }
  1321.     
  1322.     
  1323.     
  1324.     /************************************************************************
  1325.     * RestoreDefaultColors
  1326.     *
  1327.     *
  1328.     * History:
  1329.     *
  1330.     ************************************************************************/
  1331.     
  1332.     VOID RestoreDefaultColors(VOID)
  1333.     {
  1334.         INT i;
  1335.     
  1336.         for (i = 0; i < COLORSMAX; i++)
  1337.             gargbColor[i] = gargbDefaultColor[i];
  1338.     
  1339.         SetColorPalette(16, giColorPalType, TRUE);
  1340.     }
  1341.