    /***************************************************************************
     *                                                                         *
     *  MODULE      : ICClip.C                                                 *
     *                                                                         *
     *  DESCRIPTION : Clipboard functions for ImagEdit                         *
     *                                                                         *
     *  FUNCTIONS   : CopyImageClip ()  - Copies selected portion of image to  *
     *                                    the clipboard.                       *
     *                                                                         *
     *                PasteImageClip () - Pastes the clipboard image to        *
     *                                    selected portion of edit image.      *
     *                                                                         *
     *                                                                         *
     *  HISTORY     : 6/21/89 - created by LR                                  *
     *                                                                         *
     ***************************************************************************/
    
    #include "imagedit.h"
    #include "dialogs.h"
    #include "iehelp.h"
    
	 #include <windowsx.h>
    
    /*==========================================================================
      |ImagEdit's clipboard data is in two formats:                              |
      |        a) a standard CF_BITMAP format  and                               |
      |        b) a private ImagEdit format described below.                     |
      |                                                                          |
      |The private ImagEdit format data consists of:                             |
      |   1.  a DWORD describing screen color when image was sent to clipboard   |
      |       followed by...                                                     |
      |   2.  the DIB bits of the monochrome AND image (in ghdcANDMask).         |
      |                                                                          |
      |The CF_BITMAP format consists of the image bitmap (the combined XOR and   |
      |AND images in ghdcImage for icons and cursors).                           |
      |                                                                          |
      |This information is sufficient to re-create the image correctly during    |
      |paste even if the screen viewing color is subsequently changed.           |
      |                                                                          |
      |Both formats are created if the image being edited is an icon or a cursor.|
      |Only the CF_BITMAP format is created if a bitmap is being edited.         |
      ==========================================================================*/
    
    /****************************************************************************
     *                                                                          *
     *  FUNCTION   : BOOL PASCAL CopyImageClip(fBitmap)                         *
     *                                                                          *
     *  PURPOSE    : Copies the information from the selected area of image to  *
     *               the clipboard.                                             *
     *                                                                          *
     *  SIDE EFFECTS: may change contents of the clipboard. The "pick" or clip  *
     *                rectangle is reset to cover the entire image.             *
     *                                                                          *
     ****************************************************************************/
    
    BOOL CopyImageClip(VOID)
    {
        HCURSOR hcurOld;
        HBITMAP hStdBitmap;
        HBITMAP hPrivBitmap;
        HDC hStdDC;
        HDC hPrivDC;
        HANDLE hOldSObj;
        HANDLE hOldPObj;
        HANDLE hPriv;
        LPSTR lpPriv;
    
        hcurOld = SetCursor(hcurWait);
    
        /* create a temp. bitmap and DC for the standard clipboard format
         * along the same lines as the image bitmap
         */
        hStdDC = CreateCompatibleDC(ghdcImage);
        hStdBitmap = MyCreateBitmap(ghdcImage, gcxPick, gcyPick, 16);
        hOldSObj = SelectObject(hStdDC, hStdBitmap);
    
        /* blt the image bits into standard format DC */
        BitBlt(hStdDC, 0, 0, gcxPick, gcyPick, ghdcImage,
                grcPick.left, grcPick.top, SRCCOPY);
        SelectObject(hStdDC, hOldSObj);
    
        if (giType != FT_BITMAP) {
            /* for icons and cursors, create a temp. DC and bitmap for the AND
            * mask and blt the mask bits into it.
            */
            hPrivDC = CreateCompatibleDC(ghdcANDMask);
            hPrivBitmap = CreateCompatibleBitmap(ghdcANDMask, gcxPick, gcyPick);
            hOldPObj = SelectObject(hPrivDC, hPrivBitmap);
            BitBlt(hPrivDC, 0, 0, gcxPick, gcyPick, ghdcANDMask,
                    grcPick.left, grcPick.top, SRCCOPY);
    
            /* Allocate a buffer for the private ImagEdit format */
            hPriv = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
                    (DWORD)((gcxPick + 31) >> 3) * gcyPick + sizeof(DWORD));
            if (!hPriv) {
                DeleteDC(hStdDC);
                DeleteObject(hStdBitmap);
                DeleteDC(hPrivDC);
                DeleteObject(hPrivBitmap);
                return FALSE;
            }
    
            lpPriv = (LPSTR)GlobalLock(hPriv);
    
            /* Fill in the first DWORD with the screen color information */
            *((DWORD FAR *)lpPriv) = grgbScreen;
    
            /* Get the mask bits into the buffer */
            GetBitmapBits(hPrivBitmap, (DWORD)((gcxPick + 31) >> 3) * gcyPick,
                    (LPSTR)lpPriv + sizeof(DWORD));
    
            SelectObject(hPrivDC, hOldPObj);
            DeleteObject(hPrivBitmap);
            DeleteDC(hPrivDC);
        }
    
        /* Open clipboard and clear it of it's contents */
        if (!OpenClipboard(ghwndMain)) {
            DeleteDC(hStdDC);
            return(FALSE);
        }
        EmptyClipboard();
    
        if (giType != FT_BITMAP) {
            /* set the private ImagEdit format data into the clipboard */
            if (!SetClipboardData(ClipboardFormat, hPriv)) {
                DeleteDC(hStdDC);
                GlobalUnlock(hPriv);
                GlobalFree(hPriv);
                CloseClipboard();
                return(FALSE);
            }
            GlobalUnlock(hPriv);
        }
        /* set the standard CF_BITMAP format data in the clipboard */
        if (!SetClipboardData(CF_BITMAP, hStdBitmap)) {
            DeleteDC(hStdDC);
            GlobalFree(hPriv);  //   hPriv may not have been initialized (if giType == BITMAP).
            CloseClipboard();
            return(FALSE);
        }
    
        CloseClipboard();
        DeleteDC(hStdDC);
    
        /*
         * Reset pick rectangle to cover entire image.
         */
        PickSetRect(0, 0, gcxImage - 1, gcyImage - 1);
    
        /*
         * Erase the drag rectangle.
         */
        WorkUpdate();
    
        SetCursor(hcurOld);
    
        return TRUE;
    }
    
    
    
    /************************************************************************
    * PasteImageClip
    *
    * Pastes an image from the clipboard to the current image.
    *
    * It is assumed that this routine will not be called unless an
    * image is currently being edited.
    *
    * The pick rectangle is reset to cover the entire image if the
    * paste is successful.
    *
    * Basic outline of how Paste is done in ImagEdit.
    *
    * Find out what format is available in the clipboard:
    *    a. CF_BITMAP only
    *       --------------
    *       case 1: Pasting to an icon or cursor
    *                 * We don't have any screen color information.
    *                   Make the mask bits opaque and blt. the bitmap to
    *                   ghdcImage.
    *
    *       case 2: Pasting to a bitmap
    *                 * Blt the bitmap to the image DC.
    *
    *    b. both ImagEdit and CF_BITMAP
    *       ---------------------------
    *       case 1: Pasting to an icon or cursor
    *                 * Recover the image from the AND and screen color
    *                   data (in ImagEdit) and the combined image bitmap
    *                   (in CF_BITMAP). Use the information to make the
    *                   neccessary changes if the screen viewing color was
    *                   changed between Copy and Paste.
    *
    *       case 2: Pasting to a bitmap
    *                 * Blt the CF_BITMAP data to the image DC.
    *
    * If the destination image differs in dimensions from
    * source image, the source image is stretched or clipped to that of
    * destination, depending on preference
    *
    * History:
    *
    ************************************************************************/
    
    BOOL PasteImageClip(VOID)
    {
        HCURSOR hcurOld;
        INT cxClip;
        INT cyClip;
        INT cxTarget;
        INT cyTarget;
        INT cxSource;
        INT cySource;
        DWORD rgbClipScreen;
        BOOL fIEFormatFound;
        HANDLE hClipData;
        LPSTR lpClipData;
        BITMAP bmClip;
        HDC hdcClip;
        HBITMAP hbmClip;
        HBITMAP hbmClipOld;
        HDC hdcClipAND;
        HBITMAP hbmClipAND;
        HBITMAP hbmClipANDOld;
        HDC hdcClipAND16;
        HBITMAP hbmClipAND16;
        HBITMAP hbmClipAND16Old;
        HDC hdcTarget;
        HBITMAP hbmTarget;
        HBITMAP hbmTargetOld;
        HDC hdcTargetAND16;
        HBITMAP hbmTargetAND16;
        HBITMAP hbmTargetAND16Old;
        HDC hdcTargetAND;
        HBITMAP hbmTargetAND;
        HBITMAP hbmTargetANDOld;
    
        hcurOld = SetCursor(hcurWait);
    
        if (!OpenClipboard(ghwndMain)) {
            Message(MSG_NOCLIPBOARD);
            goto Error1;
        }
    
        if (!(hbmClip = GetClipboardData(CF_BITMAP))) {
            Message(MSG_NOCLIPBOARDFORMAT);
            goto Error2;
        }
    
        GetObject(hbmClip, sizeof(BITMAP), (LPSTR)&bmClip);
        cxClip = (INT)bmClip.bmWidth;
        cyClip = (INT)bmClip.bmHeight;
    
        /*
         * If the dimensions of the current pick rectangle don't match
         * the bitmap being pasted, ask the user if they want to stretch
         * or clip the pasted image.
         */
        cxTarget = gcxPick;
        cyTarget = gcyPick;
        cxSource = cxClip;
        cySource = cyClip;
        if (gcxPick != cxClip || gcyPick != cyClip) {
            if (DlgBox(DID_PASTEOPTIONS, (WNDPROC)PasteOptionsDlgProc) == IDCANCEL) {
                goto Error2;
            }
    
            /*
             * If clipping and the clipboard dimensions differ from the
             * selected pick rectangle, then either the target dimensions
             * or the source dimensions need to be sized down.
             */
            if (!fStretchClipboardData) {
                if (cxClip < gcxPick)
                    cxTarget = cxClip;
                else
                    cxSource = gcxPick;
    
                if (cyClip < gcyPick)
                    cyTarget = cyClip;
                else
                    cySource = gcyPick;
            }
        }
    
        /*
         * Update the undo buffer now that we are committed to the paste.
         */
        ImageUpdateUndo();
    
        /*
         * Determine if the private ImagEdit clipboard format is available.
         */
        fIEFormatFound = IsClipboardFormatAvailable(ClipboardFormat);
    
        if (giType != FT_BITMAP && fIEFormatFound) {
            /*
             * Get the AND mask bitmap and the old screen color out of
             * the private format.
             */
            hClipData = GetClipboardData(ClipboardFormat);
            lpClipData = (LPSTR)GlobalLock(hClipData);
            rgbClipScreen = *((DWORD FAR *)lpClipData);
            hdcClipAND = CreateCompatibleDC(ghdcImage);
            hbmClipAND = CreateBitmap(cxClip, cyClip, (BYTE)1, (BYTE)1,
                    (LPSTR)lpClipData + sizeof(DWORD));
            hbmClipANDOld = SelectObject(hdcClipAND, hbmClipAND);
    
            /*
             * Create a color bitmap for temporary use.
             */
            hdcClipAND16 = CreateCompatibleDC(ghdcImage);
            hbmClipAND16 = MyCreateBitmap(ghdcImage, cxSource, cySource, 16);
            hbmClipAND16Old = SelectObject(hdcClipAND16, hbmClipAND16);
    
            /*
             * Blt the AND mask onto the color bitmap.
             */
            BitBlt(hdcClipAND16, 0, 0, cxSource, cySource, hdcClipAND,
                    0, 0, SRCCOPY);
    
            /*
             * Create the color target AND mask bitmap.
             */
            hdcTargetAND16 = CreateCompatibleDC(ghdcImage);
            hbmTargetAND16 = MyCreateBitmap(ghdcImage, cxTarget, cyTarget, 16);
            hbmTargetAND16Old = SelectObject(hdcTargetAND16, hbmTargetAND16);
    
            /*
             * StretchBlt from the color AND mask bitmap to the color target
             * AND mask bitmap.  The blt must be done from a color bitmap to
             * a color bitmap, and the stretch blt mode must be set to
             * COLORONCOLOR.  All this is necessary so that the AND mask
             * stays exactly in sync with the stretch blt of the color
             * (XOR) mask.  If these steps are not done correctly, shrinking
             * an image with screen colored pixels in it can cause problems,
             * because the stretch blt will use a slightly different
             * algorithm to compress the monochrome AND mask and the color
             * XOR mask.
             */
            SetStretchBltMode(hdcTargetAND16, COLORONCOLOR);
            SetStretchBltMode(hdcClipAND16, COLORONCOLOR);     //
            StretchBlt(hdcTargetAND16, 0, 0, cxTarget, cyTarget, hdcClipAND16,
                    0, 0, cxSource, cySource, SRCCOPY);
    
            /*
             * Create the monochrome target AND mask bitmap.
             */
            hdcTargetAND = CreateCompatibleDC(ghdcImage);
            hbmTargetAND = MyCreateBitmap(ghdcImage, cxTarget, cyTarget, 2);
            hbmTargetANDOld = SelectObject(hdcTargetAND, hbmTargetAND);
    
            /*
             * Blt the color AND mask onto the monochrome AND mask.
             * The monochrome AND mask is the one that we will use
             * later.  It must be monochrome or the ImageDCSeparate
             * and ImageDCCombine functions will not work properly.
             */
            BitBlt(hdcTargetAND, 0, 0, cxTarget, cyTarget, hdcTargetAND16,
                    0, 0, SRCCOPY);
    
            /*
             * Cleanup.
             */
            SelectObject(hdcTargetAND16, hbmTargetAND16Old);
            DeleteObject(hbmTargetAND16);
            DeleteDC(hdcTargetAND16);
            SelectObject(hdcClipAND16, hbmClipAND16Old);
            DeleteObject(hbmClipAND16);
            DeleteDC(hdcClipAND16);
            SelectObject(hdcClipAND, hbmClipANDOld);
            DeleteObject(hbmClipAND);
            DeleteDC(hdcClipAND);
            GlobalUnlock(hClipData);
        }
    
        /*
         * Get the clipboard bitmap into a DC.
         */
        hdcClip = CreateCompatibleDC(ghdcImage);
        hbmClipOld = SelectObject(hdcClip, hbmClip);
    
        /*
         * Create the target bitmap.
         */
        hdcTarget = CreateCompatibleDC(ghdcImage);
        hbmTarget = MyCreateBitmap(ghdcImage, cxTarget, cyTarget, 16);
        hbmTargetOld = SelectObject(hdcTarget, hbmTarget);
    
        /*
         * StretchBlt the bitmap onto the target.
         */
        SetStretchBltMode(hdcTarget, COLORONCOLOR);
        SetStretchBltMode(hdcClip, COLORONCOLOR);     //
        StretchBlt(hdcTarget, 0, 0, cxTarget, cyTarget, hdcClip, 0, 0,
                cxSource, cySource, SRCCOPY);
    
        /*
         * Handle some special cases.
         */
        if (giType == FT_BITMAP || !fIEFormatFound) {
            /*
             * The image we are pasting into is either a bitmap, or
             * there does not exist an AND mask in the clipboard.
             */
            if (gnColors == 2) {
                /*
                 * We are pasting to a mono image.  We must convert the
                 * colors in the clipboard bitmap into monochrome.
                 */
                ImageDCMonoBlt(hdcTarget, cxTarget, cyTarget);
            }
        }
        else {
            /*
             * We are pasting into an icon or cursor image and we have
             * available an AND mask.  Is the current image monochrome?
             */
            if (gnColors == 2) {
                /*
                 * Remove the old screen/inverse colors from the image,
                 * convert it to monochrome, then put back in the
                 * current screen/inverse colors.
                 */
                ImageDCSeparate(hdcTarget, cxTarget, cyTarget, hdcTargetAND,
                        rgbClipScreen);
                ImageDCMonoBlt(hdcTarget, cxTarget, cyTarget);
                ImageDCCombine(hdcTarget, cxTarget, cyTarget, hdcTargetAND);
            }
            /*
             * Does the screen color specified in the clipboard
             * differ from the current screen color?
             */
            else if (rgbClipScreen != grgbScreen) {
                /*
                 * Remove the old screen/inverse colors, then put back
                 * in the current ones.
                 */
                ImageDCSeparate(hdcTarget, cxTarget, cyTarget, hdcTargetAND,
                        rgbClipScreen);
                ImageDCCombine(hdcTarget, cxTarget, cyTarget, hdcTargetAND);
            }
        }
    
        /*
         * Blt the clipboard image to the proper rectangle in the current image.
         */
        BitBlt(ghdcImage, grcPick.left, grcPick.top,
                cxTarget, cyTarget, hdcTarget, 0, 0, SRCCOPY);
    
        /*
         * If the current image is an icon or cursor, we must take care
         * of the AND mask also.
         */
        if (giType != FT_BITMAP) {
            /*
             * Is there an AND mask in the clipboard to use?
             */
            if (fIEFormatFound) {
                /*
                 * Blt it into the current image's AND mask.
                 */
                BitBlt(ghdcANDMask, grcPick.left, grcPick.top,
                        cxTarget, cyTarget, hdcTargetAND, 0, 0, SRCCOPY);
            }
            else {
                /*
                 * Make the AND mask opaque, because there is no
                 * screen color information.
                 */
                PatBlt(ghdcANDMask, grcPick.left, grcPick.top,
                        cxTarget, cyTarget, BLACKNESS);
            }
        }
    
        /*
         * Cleanup.
         */
        SelectObject(hdcTarget, hbmTargetOld);
        DeleteObject(hbmTarget);
        DeleteDC(hdcTarget);
    
        if (giType != FT_BITMAP && fIEFormatFound) {
            SelectObject(hdcTargetAND, hbmTargetANDOld);
            DeleteObject(hbmTargetAND);
            DeleteDC(hdcTargetAND);
        }
    
        SelectObject(hdcClip, hbmClipOld);
        DeleteDC(hdcClip);
    
        CloseClipboard();
    
        /*
         * Update the View and workspace windows.
         */
        ViewUpdate();
    
        /*
         * Reset pick rectangle to cover entire image.
         */
        PickSetRect(0, 0, gcxImage - 1, gcyImage - 1);
    
        fImageDirty = TRUE;
    
        SetCursor(hcurOld);
    
        return TRUE;
    
    Error2:
        CloseClipboard();
    
    Error1:
        SetCursor(hcurOld);
    
        return FALSE;
    }
    
    
    
    /************************************************************************
    * PasteOptionsDlgProc
    *
    * Proc for the dialog that asks the user whether they want to clip
    * or stretch the bitmap being pasted in.
    *
    * Upon return with an IDOK value, the fStretchClipboardData global
    * will be TRUE if they want to stretch, or FALSE if they want to clip.
    *
    * History:
    *
    ************************************************************************/
    
    DIALOGPROC PasteOptionsDlgProc(
        HWND hwnd,
        UINT msg,
        WPARAM wParam,
        LPARAM lParam)
    {
        switch (msg) {
            case WM_INITDIALOG:
                CheckRadioButton(hwnd, DID_PASTEOPTIONSSTRETCH,
                        DID_PASTEOPTIONSCLIP,
                        fStretchClipboardData ?
                        DID_PASTEOPTIONSSTRETCH : DID_PASTEOPTIONSCLIP);
    
                CenterWindow(hwnd);
    
                break;
    
            case WM_COMMAND:
                switch (GET_WM_COMMAND_ID(wParam, lParam)) {
                    case IDOK :
                        if (IsDlgButtonChecked(hwnd, DID_PASTEOPTIONSSTRETCH))
                            fStretchClipboardData = TRUE;
                        else
                            fStretchClipboardData = FALSE;
    
                        EndDialog(hwnd, IDOK);
                        break;
    
                    case IDCANCEL:
                        EndDialog(hwnd, IDCANCEL);
                        break;
    
                    case IDHELP:
                        WinHelp(ghwndMain, gszHelpFile, HELP_CONTEXT,
                                HELPID_PASTEOPTIONS);
                        break;
                }
    
                break;
    
            default:
                return FALSE;
        }
    
        return TRUE;
    }
    
    
    
    /************************************************************************
    * PickSetRect
    *
    * Sets the globals for the picking rectangle size.  This affects
    * what is copied into the clipboard.
    *
    * Arguments:
    *
    * History:
    *
    ************************************************************************/
    
    VOID PickSetRect(
        INT xLeft,
        INT yTop,
        INT xRight,
        INT yBottom)
    {
        SetRect(&grcPick, xLeft, yTop, xRight, yBottom);
        gcxPick = (grcPick.right - grcPick.left) + 1;
        gcyPick = (grcPick.bottom - grcPick.top) + 1;
    }
