ICCLIP.C
/*************************************************************************** 
     *                                                                         * 
     *  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; 
    }