COLORWP.C
/*************************************************************************** 
     *                                                                         * 
     *  MODULE      : ColorWP.c                                                * 
     *                                                                         * 
     *  DESCRIPTION : Window function for the colors window and related fns.   * 
     *                                                                         * 
     *  FUNCTIONS   : ColorWP ()            - Window function for colors       * 
     *                                        window.                          * 
     *                                                                         * 
     *                ComputeInverseColor() - Gets the inverse RGB of a given  * 
     *                                        RGB value                        * 
     *                                                                         * 
     *  HISTORY     : 6/21/89 - adapted from pBrush - LR                       * 
     *                                                                         * 
     ***************************************************************************/ 
     
    #include "imagedit.h" 
    #include "dialogs.h" 
 
 #include <windowsx.h> 
    #include <commdlg.h> 
     
     
    STATICFN VOID NEAR ColorInit(HWND hwnd); 
    STATICFN VOID NEAR ColorProcessCommand(HWND hwnd, INT idCtrl, INT NotifyCode); 
    STATICFN VOID NEAR ColorBoxPaint(HDC hdc); 
    STATICFN VOID NEAR DrawColorRect(HDC hdc, DWORD rgb, INT x, INT y, 
        INT cx, INT cy, HDC hdcMem, BOOL fMonoOK); 
    STATICFN VOID NEAR MyRectangle(HDC hdc, INT left, INT top, INT right, 
        INT bottom, HDC hdcMem, BOOL fMonoOK); 
    STATICFN VOID NEAR ColorBoxClicked(UINT msg, PPOINT ppt); 
    STATICFN BOOL NEAR ColorBoxHitTest(PPOINT ppt, PINT piColor, PINT pfMode); 
    STATICFN VOID NEAR ColorLRPaint(HWND hwnd, HDC hdc); 
    STATICFN VOID NEAR ColorLRDrawSamples(HDC hdc, PRECT prc, BOOL fLeft); 
    STATICFN VOID NEAR ColorLRUpdate(BOOL fLeft); 
    STATICFN VOID NEAR ColorEdit(VOID); 
    STATICFN VOID NEAR SetLeftColor(INT iColor, INT iMode); 
    STATICFN VOID NEAR SetRightColor(INT iColor, INT iMode); 
    STATICFN HBRUSH NEAR MyCreateSolidBrush(DWORD rgb); 
    STATICFN DWORD NEAR MyGetNearestColor(DWORD rgb, BOOL fMonoOK); 
    STATICFN DWORD NEAR ComputeInverseColor(DWORD rgb); 
     
    /* 
     * Width/height of a single color square. 
     */ 
    static INT gcxColorBox; 
     
    /* 
     * Vertical offset within the color box control to where to start the 
     * top row of color squares (the color squares are vertically centered 
     * within the color box control). 
     */ 
    static INT gyColorBoxStart; 
     
    /* 
     * Number of colors and image type.  These globals are used by the 
     * the color palette routines to know what mode the color palette 
     * is in. 
     */ 
    static INT gnColorPalColors; 
    static INT giColorPalType; 
     
     
     
    /**************************************************************************** 
    * ColorShow 
    * 
    * This function shows or hides the color palette. 
    * 
    * History: 
    * 
    ****************************************************************************/ 
     
    VOID ColorShow( 
        BOOL fShow) 
    { 
        if (fShow) 
            ShowWindow(ghwndColor, SW_SHOWNA); 
        else 
            ShowWindow(ghwndColor, SW_HIDE); 
    } 
     
     
     
    /************************************************************************ 
    * ColorDlgProc 
    * 
    * 
    * 
    * Arguments: 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    DIALOGPROC ColorDlgProc( 
        HWND hwnd, 
        UINT msg, 
        WPARAM wParam, 
        LPARAM lParam) 
    { 
        switch (msg) { 
            case WM_INITDIALOG: 
                ColorInit(hwnd); 
     
                /* 
                 * Return TRUE so that the dialog manager does NOT set the focus 
                 * for me.  This prevents the status window from initially having 
                 * the focus when the editor is started. 
                 */ 
                return TRUE; 
     
            case WM_ACTIVATE: 
                if (GET_WM_ACTIVATE_STATE(wParam, lParam)) 
                    gidCurrentDlg = DID_COLOR; 
     
                break; 
     
            case WM_CTLCOLORBTN: 
            case WM_CTLCOLORDLG: 
            case WM_CTLCOLORSTATIC: 
                switch (GET_WM_CTLCOLOR_TYPE(wParam, lParam, msg)) { 
                    case CTLCOLOR_BTN: 
                    case CTLCOLOR_DLG: 
                        return (BOOL)GetStockObject(LTGRAY_BRUSH); 
     
                    case CTLCOLOR_STATIC: 
                        SetBkColor(GET_WM_CTLCOLOR_HDC(wParam, lParam, msg), 
                                RGB_LIGHTGRAY); 
                        return (BOOL)GetStockObject(LTGRAY_BRUSH); 
                } 
     
                return (BOOL)NULL; 
     
            case  WM_PAINT: 
                { 
                    HDC hdc; 
                    PAINTSTRUCT ps; 
     
                    hdc = BeginPaint(hwnd, &ps); 
                    DrawMarginBorder(hwnd, hdc); 
                    EndPaint(hwnd, &ps); 
                } 
     
                break; 
     
            case WM_COMMAND: 
                ColorProcessCommand(hwnd, 
                        GET_WM_COMMAND_ID(wParam, lParam), 
                        GET_WM_COMMAND_CMD(wParam, lParam)); 
                break; 
     
            case WM_CLOSE: 
                /* 
                 * The user closed the color palette from the system menu. 
                 * Hide the window (we don't actually destroy it so 
                 * that it will appear in the same spot when they show 
                 * it again). 
                 */ 
                ColorShow(FALSE); 
                gfShowColor = FALSE; 
                break; 
     
            case WM_DESTROY: 
                { 
                    RECT rc; 
     
                    /* 
                     * Save the position of the color palette. 
                     */ 
                    GetWindowRect(hwnd, &rc); 
                    WriteWindowPos(&rc, FALSE, szColorPos); 
     
                    /* 
                     * Null out the global window handle for the color palette 
                     * for safety's sake. 
                     */ 
                    ghwndColor = NULL; 
                } 
     
                break; 
     
            default: 
                return FALSE; 
        } 
     
        return FALSE; 
    } 
     
     
     
    /************************************************************************ 
    * ColorInit 
    * 
    * 
    * 
    * Arguments: 
    * 
    * History: 
    * 
    ************************************************************************/ 
    STATICFN VOID NEAR ColorInit( 
        HWND hwnd) 
    { 
        RECT rc; 
     
        /* 
         * Get the dimension of a single color square, and the vertical 
         * offset to where the top of the squares are. 
         */ 
        GetWindowRect(GetDlgItem(hwnd, DID_COLORBOX), &rc); 
        gcxColorBox = (rc.right - rc.left) / COLORCOLS; 
        gyColorBoxStart = ((rc.right - rc.left) - (gcxColorBox * COLORCOLS)) / 2; 
    } 
     
     
     
    /************************************************************************ 
    * ColorProcessCommand 
    * 
    * 
    * Arguments: 
    *   HWND hwnd        - The window handle. 
    *   INT idCtrl       - The id of the control the WM_COMMAND is for. 
    *   INT NotifyCode   - The control's notification code. 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    STATICFN VOID NEAR ColorProcessCommand( 
        HWND hwnd, 
        INT idCtrl, 
        INT NotifyCode) 
    { 
        switch (idCtrl) { 
            case DID_COLOREDIT: 
                ColorEdit(); 
                break; 
     
            case DID_COLORDEFAULT: 
                if (gfModeLeft == MODE_COLOR) { 
                    gargbColor[giColorLeft] = gargbDefaultColor[giColorLeft]; 
                    InvalidateRect(GetDlgItem(ghwndColor, DID_COLORBOX), 
                            NULL, TRUE); 
                    SetLeftColor(giColorLeft, gfModeLeft); 
                } 
     
                break; 
        } 
    } 
     
     
     
    /************************************************************************ 
    * ColorBoxWndProc 
    * 
    * 
    * 
    * Arguments: 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    WINDOWPROC ColorBoxWndProc( 
        HWND hwnd, 
        UINT msg, 
        WPARAM wParam, 
        LPARAM lParam) 
    { 
        POINT pt; 
        HDC hdc; 
        PAINTSTRUCT ps; 
        INT iColor; 
        INT iMode; 
     
        switch (msg) { 
            case WM_PAINT: 
                hdc = BeginPaint(hwnd, &ps); 
                ColorBoxPaint(hdc); 
                EndPaint(hwnd, &ps); 
                break; 
     
            case WM_LBUTTONDOWN: 
            case WM_RBUTTONDOWN: 
                ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y); 
                ColorBoxClicked(msg, &pt); 
                break; 
     
            case WM_LBUTTONDBLCLK: 
                ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y); 
                if (ColorBoxHitTest(&pt, &iColor, &iMode)) 
                    ColorEdit(); 
     
                break; 
     
            default: 
                return DefWindowProc(hwnd, msg, wParam, lParam); 
        } 
     
        return 0; 
    } 
     
     
     
    /************************************************************************ 
    * ColorBoxPaint 
    * 
    * 
    * 
    * Arguments: 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    STATICFN VOID NEAR ColorBoxPaint( 
        HDC hdc) 
    { 
        HDC hdcMem; 
        HBITMAP hbmMem; 
        INT i; 
        INT x; 
        INT y; 
        INT cx = gcxColorBox + 1; 
        INT cy = gcxColorBox + 1; 
     
        if (giColorPalType != FT_BITMAP) { 
            x = 0; 
            y = gyColorBoxStart; 
            DrawColorRect(hdc, grgbScreen, x, y, cx, cy, NULL, FALSE); 
            y += gcxColorBox; 
            DrawColorRect(hdc, grgbInverse, x, y, cx, cy, NULL, FALSE); 
        } 
     
        if (!(hdcMem = CreateCompatibleDC(hdc))) 
            return; 
     
        /* 
         * Create a bitmap.  It will have the same number of colors as the 
         * current image. 
         */ 
        if (!(hbmMem = MyCreateBitmap(hdc, cx, cy, gnColorPalColors))) { 
            DeleteDC(hdcMem); 
            return; 
        } 
     
        SelectObject(hdcMem, hbmMem); 
     
        x = gcxColorBox * 2; 
        y = gyColorBoxStart; 
     
        for (i = 1; i <= COLORSMAX; i++) { 
            DrawColorRect(hdc, gargbCurrent[i - 1], x, y, cx, cy, hdcMem, TRUE); 
     
            if (i % COLORROWS) { 
                y += gcxColorBox; 
            } 
            else { 
                x += gcxColorBox; 
                y = gyColorBoxStart; 
            } 
        } 
     
        DeleteDC(hdcMem); 
        DeleteObject(hbmMem); 
    } 
     
     
     
    /************************************************************************ 
    * DrawColorRect 
    * 
    * 
    * 
    * Arguments: 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    STATICFN VOID NEAR DrawColorRect( 
        HDC hdc, 
        DWORD rgb, 
        INT x, 
        INT y, 
        INT cx, 
        INT cy, 
        HDC hdcMem, 
        BOOL fMonoOK) 
    { 
        HBRUSH hbr; 
        HBRUSH hbrOld; 
     
        hbr = CreateSolidBrush(rgb); 
        hbrOld = SelectObject(hdc, hbr); 
        MyRectangle(hdc, x, y, x + cx, y + cy, hdcMem, fMonoOK); 
        SelectObject(hdc, hbrOld); 
        DeleteObject(hbr); 
    } 
     
     
     
    /************************************************************************ 
    * MyRectangle 
    * 
    * 
    * 
    * Arguments: 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    STATICFN VOID NEAR MyRectangle( 
        HDC hdc, 
        INT left, 
        INT top, 
        INT right, 
        INT bottom, 
        HDC hdcMem, 
        BOOL fMonoOK) 
    { 
        HBITMAP hbmMem; 
        HBRUSH hbr; 
        HPEN hpen; 
        HBRUSH hbrOld; 
        HPEN hpenOld; 
        BOOL fDCCreated = FALSE; 
        INT cx = right - left; 
        INT cy = bottom - top; 
        INT nColors; 
     
        /* 
         * Do they want us to create the memory DC and bitmap for them? 
         */ 
        if (!hdcMem) { 
            if (!(hdcMem = CreateCompatibleDC(hdc))) 
                return; 
     
            /* 
             * Create a bitmap.  It will be monochrome if in 2 color mode 
             * and monochrome is ok, otherwise it will be 16 color. 
             */ 
            nColors = gnColorPalColors; 
            if (!fMonoOK) 
                nColors = 16; 
     
            if (!(hbmMem = MyCreateBitmap(hdc, cx, cy, nColors))) { 
                DeleteDC(hdcMem); 
                return; 
            } 
     
            SelectObject(hdcMem, hbmMem); 
            fDCCreated = TRUE; 
        } 
     
        /* 
         * Extract the current pen and brush out of the passed in DC. 
         */ 
        hbr = SelectObject(hdc, GetStockObject(NULL_BRUSH)); 
        hpen = SelectObject(hdc, GetStockObject(NULL_PEN)); 
     
        /* 
         * Select them into the memory DC. 
         */ 
        hbrOld = SelectObject(hdcMem, hbr); 
        hpenOld = SelectObject(hdcMem, hpen); 
     
        /* 
         * Draw the rectangle in the memory bitmap. 
         */ 
        Rectangle(hdcMem, 0, 0, cx, cy); 
     
        /* 
         * Unselect the pen and brush from the memory DC. 
         */ 
        SelectObject(hdcMem, hbrOld); 
        SelectObject(hdcMem, hpenOld); 
     
        /* 
         * Restore the pen and brush to the original DC. 
         */ 
        SelectObject(hdc, hbr); 
        SelectObject(hdc, hpen); 
     
        /* 
         * Blit the memory image to the passed in DC. 
         */ 
        BitBlt(hdc, left, top, cx, cy, hdcMem, 0, 0, SRCCOPY); 
     
        if (fDCCreated) { 
            DeleteDC(hdcMem); 
            DeleteObject(hbmMem); 
        } 
    } 
     
     
     
    /************************************************************************ 
    * ColorBoxClicked 
    * 
    * 
    * 
    * Arguments: 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    STATICFN VOID NEAR ColorBoxClicked( 
        UINT msg, 
        PPOINT ppt) 
    { 
        INT iColor; 
        INT iMode; 
     
        if (ColorBoxHitTest(ppt, &iColor, &iMode)) { 
            switch (msg) { 
                case WM_LBUTTONDOWN: 
                    SetLeftColor(iColor, iMode); 
                    break; 
     
                case WM_RBUTTONDOWN: 
                    SetRightColor(iColor, iMode); 
                    break; 
            } 
        } 
    } 
     
     
     
    /************************************************************************ 
    * ColorBoxHitTest 
    * 
    * 
    * 
    * Arguments: 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    STATICFN BOOL NEAR ColorBoxHitTest( 
        PPOINT ppt, 
        PINT piColor, 
        PINT pfMode) 
    { 
        INT iCol; 
        INT iRow; 
        INT iBox; 
     
        if (ppt->y < gyColorBoxStart) 
            return FALSE; 
     
        iCol = ppt->x / gcxColorBox; 
        iRow = (ppt->y - gyColorBoxStart) / gcxColorBox; 
     
        if (iCol >= (COLORSMAX / COLORROWS) + 2 || iRow >= COLORROWS) 
            return FALSE; 
     
        iBox = iRow + (iCol * COLORROWS); 
     
        switch (iBox) { 
            case 0: 
                if (giColorPalType == FT_BITMAP) 
                    return FALSE; 
     
                *piColor = 0; 
                *pfMode = MODE_SCREEN; 
                return TRUE; 
     
            case 1: 
                if (giColorPalType == FT_BITMAP) 
                    return FALSE; 
     
                *piColor = 0; 
                *pfMode = MODE_INVERSE; 
                return TRUE; 
     
            case 2: 
            case 3: 
                return FALSE; 
     
            default: 
                *piColor = iBox - (COLORROWS * 2); 
                *pfMode = MODE_COLOR; 
                return TRUE; 
        } 
    } 
     
     
     
    /************************************************************************ 
    * ColorLRWndProc 
    * 
    * 
    * 
    * Arguments: 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    WINDOWPROC ColorLRWndProc( 
        HWND hwnd, 
        UINT msg, 
        WPARAM wParam, 
        LPARAM lParam) 
    { 
        HDC hdc; 
        PAINTSTRUCT ps; 
     
        switch (msg) { 
            case WM_PAINT: 
                hdc = BeginPaint(hwnd, &ps); 
                ColorLRPaint(hwnd, hdc); 
                EndPaint(hwnd, &ps); 
                break; 
     
            default: 
                return DefWindowProc(hwnd, msg, wParam, lParam); 
        } 
     
        return 0; 
    } 
     
     
     
    /************************************************************************ 
    * ColorLRPaint 
    * 
    * 
    * 
    * Arguments: 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    STATICFN VOID NEAR ColorLRPaint( 
        HWND hwnd, 
        HDC hdc) 
    { 
        RECT rc; 
     
        GetClientRect(hwnd, &rc); 
        DrawSunkenRect(&rc, hdc); 
        ColorLRDrawSamples(hdc, &rc, TRUE); 
        ColorLRDrawSamples(hdc, &rc, FALSE); 
    } 
     
     
     
    /************************************************************************ 
    * ColorLRDrawSamples 
    * 
    * Draws the sample colors in the Color Left-Right control. 
    * 
    * Arguments: 
    *   HDC hdc    - DC to draw into. 
    *   PRECT prc  - Rectangle of color sample control.  The samples will 
    *                be centered within this with an appropriate margin. 
    *   BOOL fLeft - TRUE if the left sample is to be drawn, FALSE for the right. 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    STATICFN VOID NEAR ColorLRDrawSamples( 
        HDC hdc, 
        PRECT prc, 
        BOOL fLeft) 
    { 
        INT xLeftStart; 
        INT xRightStart; 
        INT ySolidStart; 
        INT yDitherStart; 
        INT cx; 
        INT cy; 
        HBRUSH hbrOld; 
        HPEN hpenOld; 
        BOOL fMonoOK; 
     
        /* 
         * The width and height of each square includes the border. 
         */ 
        cx = ((prc->right - prc->left) - (6 * PALETTEMARGIN)) / 2; 
        cy = ((prc->bottom - prc->top) - (4 * PALETTEMARGIN)) / 2; 
     
        xLeftStart = prc->left + (PALETTEMARGIN * 2) + 1; 
        xRightStart = xLeftStart + cx + (PALETTEMARGIN * 2); 
     
        ySolidStart = prc->top + (PALETTEMARGIN * 2) + 1; 
        yDitherStart = ySolidStart - 1 + cy; 
     
        /* 
         * Draw either the left or the right color sample. 
         */ 
        if (fLeft) { 
            fMonoOK = (gfModeLeft == MODE_COLOR) ? TRUE : FALSE; 
     
            /* 
             * Draw the solid color. 
             */ 
            hbrOld = SelectObject(hdc, ghbrLeftSolid); 
            hpenOld = SelectObject(hdc, GetStockObject(NULL_PEN)); 
            MyRectangle(hdc, xLeftStart, ySolidStart, 
                    xLeftStart + cx, yDitherStart + 1, NULL, fMonoOK); 
     
            /* 
             * Draw the true color (may be dithered). 
             */ 
            SelectObject(hdc, ghbrLeft); 
            MyRectangle(hdc, xLeftStart, yDitherStart, 
                    xLeftStart + cx, yDitherStart + cy, NULL, fMonoOK); 
        } 
        else { 
            fMonoOK = (gfModeRight == MODE_COLOR) ? TRUE : FALSE; 
     
            hbrOld = SelectObject(hdc, ghbrRightSolid); 
            hpenOld = SelectObject(hdc, GetStockObject(NULL_PEN)); 
            MyRectangle(hdc, xRightStart, ySolidStart, 
                    xRightStart + cx, yDitherStart + 1, NULL, fMonoOK); 
     
            SelectObject(hdc, ghbrRight); 
            MyRectangle(hdc, xRightStart, yDitherStart, 
                    xRightStart + cx, yDitherStart + cy, NULL, fMonoOK); 
        } 
     
        /* 
         * Now draw the outline rectangle. 
         */ 
        SelectObject(hdc, GetStockObject(BLACK_PEN)); 
        SelectObject(hdc, GetStockObject(NULL_BRUSH)); 
     
        if (fLeft) { 
            Rectangle(hdc, xLeftStart - 1, ySolidStart - 1, 
                    xLeftStart + cx, yDitherStart + cy); 
        } 
        else { 
            Rectangle(hdc, xRightStart - 1, ySolidStart - 1, 
                    xRightStart + cx, yDitherStart + cy); 
        } 
     
        /* 
         * Clean up. 
         */ 
        SelectObject(hdc, hpenOld); 
        SelectObject(hdc, hbrOld); 
    } 
     
     
     
    /************************************************************************ 
    * ColorLRUpdate 
    * 
    * Called when the left or right color has been changed.  This function 
    * will cause the specified color sample to be updated in the color palette. 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    STATICFN VOID NEAR ColorLRUpdate( 
        BOOL fLeft) 
    { 
        RECT rc; 
        HWND hwndLR; 
        HDC hdc; 
     
        hwndLR = GetDlgItem(ghwndColor, DID_COLORLR); 
        GetClientRect(hwndLR, &rc); 
        hdc = GetDC(hwndLR); 
        ColorLRDrawSamples(hdc, &rc, fLeft); 
        ReleaseDC(hwndLR, hdc); 
    } 
     
     
     
    /************************************************************************ 
    * ColorEdit 
    * 
    * This function calls the standard color chooser dialog to get a 
    * new color for the selected palette entry. 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    STATICFN VOID NEAR ColorEdit(VOID) 
    { 
        /* 
         * This array of custom colors is initialized to all white colors. 
         * The custom colors will be remembered between calls, but not 
         * between sessions. 
         */ 
        static DWORD argbCust[16] = { 
            RGB(255, 255, 255), RGB(255, 255, 255), 
            RGB(255, 255, 255), RGB(255, 255, 255), 
            RGB(255, 255, 255), RGB(255, 255, 255), 
            RGB(255, 255, 255), RGB(255, 255, 255), 
            RGB(255, 255, 255), RGB(255, 255, 255), 
            RGB(255, 255, 255), RGB(255, 255, 255), 
            RGB(255, 255, 255), RGB(255, 255, 255), 
            RGB(255, 255, 255), RGB(255, 255, 255) 
        }; 
        CHOOSECOLOR cc; 
        DWORD rgbOld; 
        BOOL fResult; 
        INT idPrevDlg; 
     
        switch (gfModeLeft) { 
            case MODE_COLOR: 
                /* 
                 * The monochrome palette cannot be edited. 
                 */ 
                if (gnColorPalColors == 2) 
                    return; 
     
                rgbOld = gargbCurrent[giColorLeft]; 
                break; 
     
            case MODE_SCREEN: 
                rgbOld = grgbScreen; 
                break; 
     
            case MODE_INVERSE: 
                rgbOld = grgbInverse; 
                break; 
        } 
     
        cc.lStructSize = sizeof(CHOOSECOLOR); 
        cc.hwndOwner = ghwndMain; 
        cc.hInstance = ghInst; 
        cc.rgbResult = rgbOld; 
        cc.lpCustColors = argbCust; 
        cc.Flags = CC_RGBINIT | CC_SHOWHELP; 
        cc.lCustData = 0; 
        cc.lpfnHook = NULL; 
        cc.lpTemplateName = NULL; 
     
        EnteringDialog(DID_COMMONFILECHOOSECOLOR, &idPrevDlg, TRUE); 
        fResult = ChooseColor(&cc); 
        EnteringDialog(idPrevDlg, NULL, FALSE); 
     
        if (fResult && rgbOld != cc.rgbResult) { 
            switch (gfModeLeft) { 
                case MODE_COLOR: 
                    gargbCurrent[giColorLeft] = cc.rgbResult; 
                    break; 
     
                case MODE_SCREEN: 
                    SetScreenColor(cc.rgbResult); 
                    break; 
     
                case MODE_INVERSE: 
                    SetScreenColor(ComputeInverseColor(cc.rgbResult)); 
                    break; 
            } 
     
            SetLeftColor(giColorLeft, gfModeLeft); 
            InvalidateRect(GetDlgItem(ghwndColor, DID_COLORBOX), NULL, TRUE); 
        } 
    } 
     
     
     
    /************************************************************************ 
    * SetLeftColor 
    * 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    STATICFN VOID NEAR SetLeftColor( 
        INT iColor, 
        INT iMode) 
    { 
        DWORD rgbSolid; 
        BOOL fEnableDefault = FALSE; 
        BOOL fEnableEdit = FALSE; 
     
        if (ghbrLeft) 
            DeleteObject(ghbrLeft); 
     
        if (ghbrLeftSolid) 
            DeleteObject(ghbrLeftSolid); 
     
        if (ghpenLeft) 
            DeleteObject(ghpenLeft); 
     
        switch (iMode) { 
            case MODE_COLOR: 
                ghbrLeft = MyCreateSolidBrush(gargbCurrent[iColor]); 
                rgbSolid = MyGetNearestColor(gargbCurrent[iColor], TRUE); 
                ghbrLeftSolid = CreateSolidBrush(rgbSolid); 
                ghpenLeft = CreatePen(PS_INSIDEFRAME, 1, rgbSolid); 
                giColorLeft = iColor; 
     
                /* 
                 * We will enable the "Default" button if the current color 
                 * on the left button is not the default color, and we are 
                 * not in monochrome mode. 
                 */ 
                if (gargbColor[giColorLeft] != gargbDefaultColor[giColorLeft] && 
                        gnColorPalColors > 2) 
                    fEnableDefault = TRUE; 
     
                /* 
                 * For non-screen colors, the Edit button will be enabled 
                 * if we are not in monochrome mode. 
                 */ 
                if (gnColorPalColors > 2) 
                    fEnableEdit = TRUE; 
     
                break; 
     
            case MODE_SCREEN: 
                ghbrLeft = CreateSolidBrush(grgbScreen); 
                ghbrLeftSolid = CreateSolidBrush(grgbScreen); 
                ghpenLeft = CreatePen(PS_INSIDEFRAME, 1, grgbScreen); 
                giColorLeft = 0; 
                fEnableEdit = TRUE; 
                break; 
     
            case MODE_INVERSE: 
                ghbrLeft = CreateSolidBrush(grgbInverse); 
                ghbrLeftSolid = CreateSolidBrush(grgbInverse); 
                ghpenLeft = CreatePen(PS_INSIDEFRAME, 1, grgbInverse); 
                giColorLeft = 0; 
                fEnableEdit = TRUE; 
                break; 
        } 
     
        EnableWindow(GetDlgItem(ghwndColor, DID_COLORDEFAULT), fEnableDefault); 
        EnableWindow(GetDlgItem(ghwndColor, DID_COLOREDIT), fEnableEdit); 
     
        gfModeLeft = iMode; 
        ColorLRUpdate(TRUE); 
    } 
     
     
     
    /************************************************************************ 
    * SetRightColor 
    * 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    STATICFN VOID NEAR SetRightColor( 
        INT iColor, 
        INT iMode) 
    { 
        DWORD rgbSolid; 
     
        if (ghbrRight) 
            DeleteObject(ghbrRight); 
     
        if (ghbrRightSolid) 
            DeleteObject(ghbrRightSolid); 
     
        if (ghpenRight) 
            DeleteObject(ghpenRight); 
     
        switch (iMode) { 
            case MODE_COLOR: 
                ghbrRight = MyCreateSolidBrush(gargbCurrent[iColor]); 
                rgbSolid = MyGetNearestColor(gargbCurrent[iColor], TRUE); 
                ghbrRightSolid = CreateSolidBrush(rgbSolid); 
                ghpenRight = CreatePen(PS_INSIDEFRAME, 1, rgbSolid); 
                giColorRight = iColor; 
                break; 
     
            case MODE_SCREEN: 
                ghbrRight = CreateSolidBrush(grgbScreen); 
ghbrRightSolid = CreateSolidBrush(grgbScreen); 
                ghpenRight = CreatePen(PS_INSIDEFRAME, 1, grgbScreen); 
                giColorRight = 0; 
                break; 
     
            case MODE_INVERSE: 
                ghbrRight = CreateSolidBrush(grgbInverse); 
                ghbrRightSolid = CreateSolidBrush(grgbInverse); 
                ghpenRight = CreatePen(PS_INSIDEFRAME, 1, grgbInverse); 
                giColorRight = 0; 
                break; 
        } 
     
        gfModeRight = iMode; 
        ColorLRUpdate(FALSE); 
    } 
     
     
     
    /************************************************************************ 
    * SetScreenColor 
    * 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    VOID SetScreenColor( 
        DWORD rgb) 
    { 
        DWORD rgbInverse; 
        HDC hdcTemp; 
        HBITMAP hbmOld; 
        HDC hdcANDTemp; 
        HBITMAP hbmANDOld; 
     
        rgb = MyGetNearestColor(rgb, FALSE); 
     
        /* 
         * Because we are about to change the screen color, separate 
         * out the XOR mask (but only for icons/cursors). 
         */ 
        if (giColorPalType != FT_BITMAP) { 
            if (gpImageCur) { 
                ImageDCSeparate(ghdcImage, gcxImage, gcyImage, ghdcANDMask, 
                        grgbScreen); 
     
                /* 
                 * Is there a pending undo buffer?  If so, it must be 
                 * changed as well or an undo that is done after a screen 
                 * color change will restore the wrong colors! 
                 */ 
                if (ghbmUndo) { 
                    /* 
                     * Create some temporary DC's to use when separating 
                     * out the undo buffer's masks.  These will be deleted 
                     * a little later. 
                     */ 
                    hdcTemp = CreateCompatibleDC(ghdcImage); 
                    hbmOld = SelectObject(hdcTemp, ghbmUndo); 
                    hdcANDTemp = CreateCompatibleDC(ghdcANDMask); 
                    hbmANDOld = SelectObject(hdcANDTemp, ghbmUndoMask); 
     
                    /* 
                     * Separate out the undo buffer's colors, before 
                     * changing the screen color.  It will be combined 
                     * later. 
                     */ 
                    ImageDCSeparate(hdcTemp, gcxImage, gcyImage, hdcANDTemp, 
                            grgbScreen); 
                } 
            } 
        } 
     
        if (ghbrScreen) 
            DeleteObject(ghbrScreen); 
     
        ghbrScreen = CreateSolidBrush(rgb); 
        grgbScreen = rgb; 
     
        if (ghbrInverse) 
            DeleteObject(ghbrInverse); 
     
        rgbInverse = ComputeInverseColor(rgb); 
        ghbrInverse = CreateSolidBrush(rgbInverse); 
        grgbInverse = rgbInverse; 
     
        /* 
         * For icons and cursors, we might need to update a few more things. 
         */ 
        if (giColorPalType != FT_BITMAP) { 
            /* 
             * Recombine the XOR and AND images now that there is a new screen 
             * color.  This updates the image DC with the new color properly. 
             */ 
            if (gpImageCur) { 
                ImageDCCombine(ghdcImage, gcxImage, gcyImage, ghdcANDMask); 
     
                /* 
                 * Is there a pending undo buffer?  If so, it has to be 
                 * recombined with the new screen color. 
                 */ 
                if (ghbmUndo) { 
                    ImageDCCombine(hdcTemp, gcxImage, gcyImage, hdcANDTemp); 
     
                    /* 
                     * Clean up the DC's that were allocated a little earlier. 
                     */ 
                    SelectObject(hdcANDTemp, hbmANDOld); 
                    DeleteDC(hdcANDTemp); 
                    SelectObject(hdcTemp, hbmOld); 
                    DeleteDC(hdcTemp); 
                } 
            } 
     
            /* 
             * Reset the colors on the mouse buttons, just in case a screen 
             * or inverse screen color was assigned to either of them. 
             */ 
            SetLeftColor(giColorLeft, gfModeLeft); 
            SetRightColor(giColorRight, gfModeRight); 
     
            InvalidateRect(GetDlgItem(ghwndColor, DID_COLORBOX), NULL, TRUE); 
        } 
     
        ViewUpdate(); 
    } 
     
     
     
    /************************************************************************ 
    * MyCreateSolidBrush 
    * 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    STATICFN HBRUSH NEAR MyCreateSolidBrush( 
        DWORD rgb) 
    { 
        HDC hdc; 
        HDC hdcMem; 
        HBRUSH hbr; 
        HBRUSH hbrOld; 
        HBITMAP hbmPat; 
        HBITMAP hbmOld; 
     
        /* 
         * First, create a brush for the given RGB value. 
         */ 
        hbr = CreateSolidBrush(rgb); 
     
        /* 
         * Create a temporary memory DC. 
         */ 
        hdc = GetDC(ghwndMain); 
        hdcMem = CreateCompatibleDC(hdc); 
     
        /* 
         * Create a temporary bitmap. 
         */ 
        hbmPat = MyCreateBitmap(hdc, 8, 8, gnColorPalColors); 
        ReleaseDC(ghwndMain, hdc); 
     
        /* 
         * Draw the (possibly) dithered pattern on the temporary bitmap. 
         */ 
        hbmOld = SelectObject(hdcMem, hbmPat); 
        hbrOld = SelectObject(hdcMem, hbr); 
        PatBlt(hdcMem, 0, 0, 8, 8, PATCOPY); 
        SelectObject(hdcMem, hbrOld); 
        SelectObject(hdcMem, hbmOld); 
        DeleteDC(hdcMem); 
     
        /* 
         * Delete the first brush. 
         */ 
        DeleteObject(hbr); 
     
        /* 
         * Now create a pattern brush out of the (dithered) bitmap. 
         */ 
        hbr = CreatePatternBrush(hbmPat); 
     
        DeleteObject(hbmPat); 
     
        /* 
         * Return the pattern brush. 
         */ 
        return hbr; 
    } 
     
     
     
    /************************************************************************ 
    * MyGetNearestColor 
    * 
    * This function returns the RGB value of the nearest color to the 
    * specified RGB value.  If fMonoOK is TRUE, it takes into account 
    * the number of colors of the current image being edited.  In other 
    * words, it will return the nearest solid color for a device that 
    * has the number of colors of the current image. 
    * 
    * Arguments: 
    *   DWORD rgb    - RGB value of the color. 
    *   BOOL fMonoOK - TRUE if the returned color should be mapped to a 
    *                  color in a monochrome palette, if the current image 
    *                  is monochrome.  A value of FALSE will return a 
    *                  color mapped to the closest color in a 16 color 
    *                  palette. 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    STATICFN DWORD NEAR MyGetNearestColor( 
        DWORD rgb, 
        BOOL fMonoOK) 
    { 
        HDC hdc; 
        HDC hdcMem; 
        DWORD rgbNearest; 
        HBITMAP hbmMem; 
        HBITMAP hbmOld; 
     
        hdc = GetDC(ghwndMain); 
        hdcMem = CreateCompatibleDC(hdc); 
        hbmMem = MyCreateBitmap(hdc, 1, 1, (fMonoOK) ? gnColorPalColors : 16); 
        hbmOld = SelectObject(hdcMem, hbmMem); 
        rgbNearest = GetNearestColor(hdcMem, rgb); 
        SelectObject(hdcMem, hbmOld); 
        DeleteObject(hbmMem); 
        DeleteDC(hdcMem); 
        ReleaseDC(ghwndMain, hdc); 
     
        return rgbNearest; 
    } 
     
     
     
    /************************************************************************ 
    * ComputeInverseColor 
    * 
    * Computes the inverse value of a given rgb color. 
    * 
    * Arguments: 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    STATICFN DWORD NEAR ComputeInverseColor( 
        DWORD rgb) 
    { 
        HBITMAP hTempBit1; 
        HBITMAP hTempBit2; 
        HDC hTempDC1; 
        HDC hTempDC2; 
        HDC hdc; 
        HANDLE hOldObj1; 
        HANDLE hOldObj2; 
        DWORD rgbInv; 
     
        hdc = GetDC(ghwndMain); 
        hTempDC1 = CreateCompatibleDC(hdc); 
        hTempDC2 = CreateCompatibleDC(hdc); 
     
        /* create two temporary 1x1, 16 color bitmaps */ 
        hTempBit1 = MyCreateBitmap(hdc, 1, 1, 16); 
        hTempBit2 = MyCreateBitmap(hdc, 1, 1, 16); 
     
        ReleaseDC(ghwndMain, hdc); 
     
        hOldObj1 = SelectObject(hTempDC1, hTempBit1); 
        hOldObj2 = SelectObject(hTempDC2, hTempBit2); 
     
        /* method for getting inverse color : set the given pixel (rgb) on 
         * one DC. Now blt it to the other DC using a SRCINVERT rop. 
         * This yields a pixel of the inverse color on the destination DC 
         */ 
        SetPixel(hTempDC1, 0, 0, rgb); 
        PatBlt(hTempDC2, 0, 0, 1, 1, WHITENESS); 
        BitBlt(hTempDC2, 0, 0, 1, 1, hTempDC1, 0, 0, SRCINVERT); 
        rgbInv = GetPixel(hTempDC2, 0, 0); 
     
        /* clean up ... */ 
        SelectObject(hTempDC1, hOldObj1); 
        SelectObject(hTempDC2, hOldObj2); 
        DeleteObject(hTempBit1); 
        DeleteObject(hTempBit2); 
        DeleteDC(hTempDC1); 
        DeleteDC(hTempDC2); 
     
        /* ...and return the inverted RGB value */ 
        return rgbInv; 
    } 
     
     
     
    /************************************************************************ 
    * SetColorPalette 
    * 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    VOID SetColorPalette( 
        INT nColors, 
        INT iType, 
        BOOL fForce) 
    { 
        /* 
         * Quit if nothing changed (unless they are forcing it to be updated). 
         */ 
        if (!fForce && nColors == gnColorPalColors && iType == giColorPalType) 
            return; 
     
        /* 
         * Set the globals that all the color palette routines use. 
         */ 
        gnColorPalColors = nColors; 
        giColorPalType = iType; 
     
        if (gnColorPalColors == 2) 
            gargbCurrent = gargbMono; 
        else 
            gargbCurrent = gargbColor; 
     
        ShowWindow(GetDlgItem(ghwndColor, DID_COLORSCREENLABEL), 
                (giColorPalType == FT_BITMAP) ? SW_HIDE : SW_SHOW); 
        ShowWindow(GetDlgItem(ghwndColor, DID_COLORINVERSELABEL), 
                (giColorPalType == FT_BITMAP) ? SW_HIDE : SW_SHOW); 
     
        SetLeftColor(1, MODE_COLOR); 
        SetRightColor(0, MODE_COLOR); 
     
        InvalidateRect(GetDlgItem(ghwndColor, DID_COLORBOX), NULL, TRUE); 
    } 
     
     
     
    /************************************************************************ 
    * RestoreDefaultColors 
    * 
    * 
    * History: 
    * 
    ************************************************************************/ 
     
    VOID RestoreDefaultColors(VOID) 
    { 
        INT i; 
     
        for (i = 0; i < COLORSMAX; i++) 
            gargbColor[i] = gargbDefaultColor[i]; 
     
        SetColorPalette(16, giColorPalType, TRUE); 
    }