1205 lines
36 KiB
C++
1205 lines
36 KiB
C++
|
|
#include "stdafx.h"
|
|
#include "global.h"
|
|
#include "pbrush.h"
|
|
#include "pbrusdoc.h"
|
|
#include "pbrusfrm.h"
|
|
#include "pbrusvw.h"
|
|
#include "minifwnd.h"
|
|
#include "bmobject.h"
|
|
#include "imgsuprt.h"
|
|
#include "imgwnd.h"
|
|
#include "imgcolor.h"
|
|
#include "imgbrush.h"
|
|
#include "imgwell.h"
|
|
#include "imgtools.h"
|
|
#include "tedit.h"
|
|
#include "t_text.h"
|
|
#include "t_fhsel.h"
|
|
#include "toolbox.h"
|
|
#include "props.h"
|
|
#include "undo.h"
|
|
#include "srvritem.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static CHAR BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#include "memtrace.h"
|
|
|
|
BOOL GetMFDimensions(
|
|
HANDLE hMF, /* handle to the CF_METAFILEPICT object from clipbrd */
|
|
HDC hDC, /* display context */
|
|
long *pWidth, /* width of picture in pixels, OUT param */
|
|
long *pHeight, /* height of picture in pixels, OUT param */
|
|
long *pcXPelsPerMeter, /* horizontal resolution, OUT param */
|
|
long *pcYPelsPerMeter, /* vertical resolution, OUT param */
|
|
IMG* pImg)
|
|
;
|
|
BOOL PlayMetafileIntoDC(
|
|
HANDLE hMF,
|
|
RECT *pRect,
|
|
HDC hDC)
|
|
;
|
|
|
|
/***************************************************************************/
|
|
|
|
void CImgWnd::OnDestroyClipboard()
|
|
{
|
|
if (m_hPoints)
|
|
{
|
|
::GlobalFree( m_hPoints );
|
|
m_hPoints = NULL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
void CImgWnd::CopyBMAndPal(HBITMAP *pBM, CPalette ** ppPal)
|
|
{
|
|
IMG* pImg = m_pImg;
|
|
|
|
CRect copyRect;
|
|
|
|
if (theImgBrush.m_pImg == NULL)
|
|
{
|
|
HideBrush();
|
|
copyRect.SetRect(0, 0, pImg->cxWidth, pImg->cyHeight);
|
|
}
|
|
else
|
|
{
|
|
copyRect = rcDragBrush;
|
|
copyRect.right -= 1;
|
|
copyRect.bottom -= 1;
|
|
}
|
|
|
|
BOOL bRegion = (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL);
|
|
|
|
#ifdef FHSELCLIP
|
|
if (bRegion)
|
|
{
|
|
if (! m_wClipboardFormat)
|
|
m_wClipboardFormat = RegisterClipboardFormat( TEXT("MSPaintFreehand") );
|
|
|
|
if (theImgBrush.m_bFirstDrag)
|
|
// PickupSelection(); but no way to tell if we do it twice...
|
|
PrepareForBrushChange( TRUE, FALSE );
|
|
|
|
CFreehandSelectTool* pTool = (CFreehandSelectTool*)CImgTool::GetCurrent();
|
|
|
|
ASSERT( pTool );
|
|
|
|
if (m_wClipboardFormat && pTool)
|
|
{
|
|
CPoint* pptArray;
|
|
int iEntries;
|
|
BOOL bData = pTool->CopyPointsToMemArray( &pptArray, &iEntries );
|
|
|
|
if (bData && iEntries)
|
|
{
|
|
HGLOBAL hMem = ::GlobalAlloc( GHND | GMEM_MOVEABLE | GMEM_DDESHARE,
|
|
iEntries * sizeof( POINT )
|
|
+ sizeof( short ));
|
|
if (hMem)
|
|
{
|
|
short* pShort = (short*)::GlobalLock( hMem );
|
|
|
|
*pShort++ = iEntries;
|
|
|
|
LPPOINT pPts = (LPPOINT)pShort;
|
|
|
|
for (int iPt = 0; iPt < iEntries; iPt++, pPts++)
|
|
{
|
|
pPts->x = pptArray[iPt].x - pTool->m_cRectBounding.left;
|
|
pPts->y = pptArray[iPt].y - pTool->m_cRectBounding.top;
|
|
}
|
|
|
|
::GlobalUnlock( hMem );
|
|
|
|
if (m_hPoints)
|
|
{
|
|
::GlobalFree( m_hPoints );
|
|
m_hPoints = NULL;
|
|
}
|
|
|
|
m_hPoints = SetClipboardData( m_wClipboardFormat, hMem );
|
|
}
|
|
else
|
|
theApp.SetMemoryEmergency();
|
|
|
|
delete [] pptArray;
|
|
}
|
|
}
|
|
else
|
|
theApp.SetGdiEmergency();
|
|
}
|
|
#endif // FHSELCLIP
|
|
|
|
if ( theImgBrush.m_pImg )
|
|
{
|
|
CPalette* ppalOld = SetImgPalette( &theImgBrush.m_dc );
|
|
|
|
// Copy the selection...
|
|
CRect rc( 0, 0, theImgBrush.m_size.cx, theImgBrush.m_size.cy );
|
|
|
|
*pBM = CopyDC( &theImgBrush.m_dc, &rc );
|
|
|
|
if (ppalOld)
|
|
theImgBrush.m_dc.SelectPalette( ppalOld, TRUE );
|
|
}
|
|
else
|
|
// Copy the whole image...
|
|
*pBM = CopyDC( CDC::FromHandle( m_pImg->hDC ), ©Rect );
|
|
|
|
if (theApp.m_pPalette && (*ppPal=new CPalette)!=NULL)
|
|
{
|
|
LOGPALETTE256 logPal;
|
|
|
|
logPal.palVersion = 0x300;
|
|
logPal.palNumEntries = (WORD)theApp.m_pPalette->GetPaletteEntries( 0, 256,
|
|
&logPal.palPalEntry[0]);
|
|
|
|
if ( logPal.palNumEntries )
|
|
{
|
|
theApp.m_pPalette->GetPaletteEntries( 0, logPal.palNumEntries,
|
|
&logPal.palPalEntry[0] );
|
|
|
|
(*ppPal)->CreatePalette( (LPLOGPALETTE)&logPal );
|
|
}
|
|
}
|
|
}
|
|
|
|
void CImgWnd::CmdCopy()
|
|
{
|
|
if (TextToolProcessed( ID_EDIT_COPY ))
|
|
{
|
|
return;
|
|
}
|
|
|
|
CBitmapObj* pResObject = new CBitmapObj;
|
|
if (pResObject)
|
|
{
|
|
IMG* pImgStruct = new IMG;
|
|
|
|
if (pImgStruct)
|
|
{
|
|
if (FillBitmapObj(c_pImgWndCur, pResObject, pImgStruct))
|
|
{
|
|
pImgStruct->m_pFirstImgWnd = NULL;
|
|
pImgStruct->m_pBitmapObj = pResObject;
|
|
|
|
HDC hDCSave = pImgStruct->hDC;
|
|
|
|
pImgStruct->hDC = NULL;
|
|
pImgStruct->hMaskDC = NULL;
|
|
|
|
pImgStruct->hMaskBitmap = NULL;
|
|
pImgStruct->hMaskBitmapOld = NULL;
|
|
|
|
pImgStruct->hBitmap = NULL;
|
|
pImgStruct->m_pPalette = NULL;
|
|
CopyBMAndPal(&pImgStruct->hBitmap, &pImgStruct->m_pPalette);
|
|
|
|
if (pImgStruct->hBitmap)
|
|
{
|
|
pImgStruct->hDC = CreateCompatibleDC(hDCSave);
|
|
if (pImgStruct->hDC)
|
|
{
|
|
pImgStruct->hBitmapOld = (HBITMAP)SelectObject(
|
|
pImgStruct->hDC, pImgStruct->hBitmap);
|
|
pImgStruct->m_hPalOld = pImgStruct->m_pPalette
|
|
? SelectPalette(pImgStruct->hDC,
|
|
(HPALETTE)pImgStruct->m_pPalette->m_hObject, FALSE)
|
|
: NULL;
|
|
|
|
// get a server item suitable to generate the clipboard data
|
|
CPBView* pView = (CPBView*)
|
|
((CFrameWnd*)AfxGetMainWnd())->GetActiveView();
|
|
CPBSrvrItem* pItem = new CPBSrvrItem(pView->GetDocument(),
|
|
pResObject);
|
|
|
|
if (pItem)
|
|
{
|
|
pItem->CopyToClipboard(FALSE);
|
|
|
|
delete pItem;
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the IMG and all it contains will get cleaned up when
|
|
// pResObject is deleted, but only if FillBitmapObj succeeded
|
|
delete pImgStruct;
|
|
}
|
|
}
|
|
|
|
delete pResObject;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
void CImgWnd::CmdCut()
|
|
{
|
|
if (TextToolProcessed( ID_EDIT_CUT ))
|
|
return;
|
|
|
|
// BOGUS:
|
|
// CmdCopy doesn't just copy -- it can change the state of the selection
|
|
// this forces the CmdClear to act in the context of the new state
|
|
// save off a flag for CmdClear to special-case like 'first-drag'
|
|
BOOL *pFlag;
|
|
if (theImgBrush.m_pImg && theImgBrush.m_bFirstDrag)
|
|
{
|
|
pFlag = &theImgBrush.m_bCuttingFromImage;
|
|
}
|
|
else
|
|
pFlag = NULL;
|
|
|
|
CmdCopy();
|
|
|
|
TRY
|
|
{
|
|
if (pFlag)
|
|
*pFlag = TRUE;
|
|
|
|
CmdClear();
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
// don't leave the flag set
|
|
if (pFlag)
|
|
*pFlag = FALSE;
|
|
|
|
THROW_LAST();
|
|
}
|
|
END_CATCH_ALL
|
|
|
|
// normal execution path
|
|
if (pFlag)
|
|
*pFlag = FALSE;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
void CImgWnd::CmdPaste()
|
|
{
|
|
if (TextToolProcessed( ID_EDIT_PASTE ))
|
|
return;
|
|
|
|
CancelToolMode(FALSE);
|
|
|
|
CommitSelection(TRUE);
|
|
|
|
HideBrush();
|
|
SetupRubber( m_pImg );
|
|
EraseTracker();
|
|
theImgBrush.m_pImg = NULL;
|
|
DrawTracker();
|
|
SetUndo( m_pImg );
|
|
|
|
if (! PasteImageClip())
|
|
AfxMessageBox( IDS_ERROR_CLIPBOARD, MB_OK | MB_ICONHAND );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
HBITMAP CImgWnd::CopyDC( CDC* pImgDC, CRect* prcClip )
|
|
{
|
|
// BLOCK: copy the image to hStdBitmap for the clipboard
|
|
CDC dc;
|
|
CBitmap bm;
|
|
CBitmap* pOldStdBitmap;
|
|
int cxWidth = prcClip->Width();
|
|
int cyHeight = prcClip->Height();
|
|
|
|
if (! dc.CreateCompatibleDC ( pImgDC )
|
|
|| ! bm.CreateCompatibleBitmap( pImgDC, cxWidth, cyHeight ))
|
|
{
|
|
theApp.SetGdiEmergency();
|
|
return FALSE;
|
|
}
|
|
|
|
pOldStdBitmap = dc.SelectObject( &bm );
|
|
|
|
CPalette* pOldPalette = SetImgPalette( &dc );
|
|
|
|
dc.BitBlt( 0, 0, cxWidth, cyHeight, pImgDC, prcClip->left, prcClip->top, SRCCOPY );
|
|
dc.SelectObject( pOldStdBitmap );
|
|
|
|
if (pOldPalette)
|
|
dc.SelectPalette( pOldPalette, FALSE );
|
|
|
|
// return the standard format (bitmap) data
|
|
return (HBITMAP)bm.Detach();
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
BOOL CImgWnd::IsPasteAvailable()
|
|
{
|
|
BOOL bPasteIsAvailable = FALSE;
|
|
BOOL bBitmapAvailable = IsClipboardFormatAvailable( CF_BITMAP );
|
|
BOOL bDIBAvailable = IsClipboardFormatAvailable( CF_DIB );
|
|
BOOL bTextAvailable = IsClipboardFormatAvailable( CF_TEXT );
|
|
BOOL bMFAvailable = IsClipboardFormatAvailable( CF_METAFILEPICT );
|
|
|
|
if (CImgTool::GetCurrentID() == IDMX_TEXTTOOL)
|
|
{
|
|
CTextTool* pTextTool = (CTextTool*)CImgTool::GetCurrent();
|
|
|
|
if (pTextTool != NULL
|
|
&& pTextTool->GetTextEditField() != NULL)
|
|
bPasteIsAvailable = bTextAvailable;
|
|
}
|
|
else
|
|
{
|
|
bPasteIsAvailable = bBitmapAvailable || bDIBAvailable || bMFAvailable;
|
|
}
|
|
|
|
return bPasteIsAvailable;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
BOOL CImgWnd::IsSelectionAvailable( void )
|
|
{
|
|
if (CImgTool::GetCurrentID() == IDMX_TEXTTOOL)
|
|
{
|
|
CTextTool* pTextTool = (CTextTool*)CImgTool::GetCurrent();
|
|
|
|
if (pTextTool != NULL
|
|
&& pTextTool->IsKindOf( RUNTIME_CLASS( CTextTool ) ))
|
|
{
|
|
CTedit* pTextEdit = pTextTool->GetTextEditField();
|
|
|
|
if (pTextEdit != NULL
|
|
&& pTextEdit->IsKindOf( RUNTIME_CLASS( CTedit ) ))
|
|
{
|
|
DWORD dwSel = pTextEdit->GetEditWindow()->GetSel();
|
|
BOOL bReturn = (HIWORD( dwSel) != LOWORD( dwSel ));
|
|
|
|
if (! bReturn)
|
|
bReturn = (pTextEdit->GetEditWindow()->GetWindowTextLength()
|
|
!= (int)LOWORD( dwSel ));
|
|
|
|
return bReturn;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CImgTool::GetCurrentID() == IDMB_PICKTOOL
|
|
|| CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL)
|
|
{
|
|
return (theImgBrush.m_pImg != NULL && ! g_bCustomBrush);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
int PASCAL CheckPastedSize(int nWidth, int nHeight, IMG* pImg)
|
|
{
|
|
int nRet = IDNO;
|
|
|
|
// If the image is a bitmap and the bitmap in the clipboard is larger,
|
|
// then give the suer the option2 of growing the image...
|
|
if (nWidth > pImg->cxWidth
|
|
|| nHeight > pImg->cyHeight)
|
|
{
|
|
CSize size( max(nWidth, pImg->cxWidth),
|
|
max(nHeight, pImg->cyHeight) );
|
|
|
|
theUndo.BeginUndo( TEXT("Resize Bitmap") );
|
|
VERIFY( pImg->m_pBitmapObj->SetSizeProp( P_Size, size ) );
|
|
|
|
theUndo.EndUndo();
|
|
|
|
// PSS says users don't want to see this dialog
|
|
#if 0
|
|
// WARNING!!! MB_SYSTEMMODAL is _necessary_. No message boxes should
|
|
// be run while the clipboard is opened. Loss of focus to other apps
|
|
// can be disasterous! The clipboard will be hung or if the clipboard
|
|
// is closed, the contents could be changed by another app.
|
|
|
|
nRet = AfxMessageBox( IDS_ENLAGEBITMAPFORCLIP,
|
|
MB_YESNOCANCEL | MB_ICONQUESTION | MB_SYSTEMMODAL );
|
|
switch (nRet)
|
|
{
|
|
case IDYES:
|
|
{
|
|
CSize size( max(nWidth, pImg->cxWidth),
|
|
max(nHeight, pImg->cyHeight) );
|
|
|
|
theUndo.BeginUndo( TEXT("Resize Bitmap") );
|
|
VERIFY( pImg->m_pBitmapObj->SetSizeProp( P_Size, size ) );
|
|
|
|
theUndo.EndUndo();
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return(nRet);
|
|
}
|
|
|
|
struct CStgMedium : public STGMEDIUM
|
|
{
|
|
CStgMedium()
|
|
{
|
|
ZeroMemory(this, sizeof(*this));
|
|
}
|
|
|
|
~CStgMedium()
|
|
{
|
|
ReleaseStgMedium(this);
|
|
}
|
|
};
|
|
|
|
HGLOBAL
|
|
_GetClipboardData (CLIPFORMAT cf, TYMED tymed, STGMEDIUM *pMedium)
|
|
{
|
|
IDataObject *pdo = NULL;
|
|
HANDLE hRet = NULL;
|
|
|
|
if (SUCCEEDED(OleGetClipboard (&pdo)))
|
|
{
|
|
FORMATETC fmt = { 0 };
|
|
|
|
fmt.cfFormat = cf;
|
|
fmt.lindex = -1;
|
|
fmt.tymed = tymed;
|
|
fmt.dwAspect = DVASPECT_CONTENT;
|
|
|
|
pMedium->tymed = tymed;
|
|
|
|
if (SUCCEEDED(pdo->GetData (&fmt, pMedium)))
|
|
{
|
|
hRet = pMedium->hGlobal;
|
|
}
|
|
else
|
|
{
|
|
ReleaseStgMedium(pMedium);
|
|
}
|
|
|
|
pdo->Release ();
|
|
}
|
|
else
|
|
{
|
|
TRACE( TEXT("Cannot open clipboard!\n") );
|
|
}
|
|
|
|
return hRet;
|
|
}
|
|
|
|
BOOL CImgWnd::PasteImageClip()
|
|
{
|
|
CWaitCursor wait;
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// Find out what format is available on the clipboard. if it is
|
|
// A. CF_BITMAP only - Set the mask bits opaque and blt the bitmap
|
|
// into ICimageDC
|
|
// In both cases, if the destination bitmap differs in size from
|
|
// source bitmap, user is asked if he/she wants the src bitmap
|
|
// stretched/clipped to new size
|
|
/////////////////////////////////////////////////////////////////////////
|
|
if (! m_wClipboardFormat)
|
|
m_wClipboardFormat = (WORD)RegisterClipboardFormat( TEXT("MSPaintFreehand") );
|
|
|
|
|
|
// Enumerate the cliboard contents to determine what is available.
|
|
// If a CF_BITMAP is seen, set a flag and proceed. If a SDKPAINT
|
|
// private format is seen, stop looking further
|
|
BOOL bBitmapAvailable = FALSE;
|
|
#ifdef FHSELCLIP
|
|
BOOL bPrivateAvailable = FALSE;
|
|
#endif // FHSELCLIP
|
|
BOOL bPaletteAvailable = FALSE;
|
|
BOOL bDIBAvailable = FALSE;
|
|
BOOL bMFAvailable = FALSE;
|
|
WORD wClipFmt = 0;
|
|
|
|
BITMAP bmData;
|
|
LONG cXPelsPerMeter = 0;
|
|
LONG cYPelsPerMeter = 0;
|
|
BOOL bResizedBitmap = FALSE;
|
|
CPalette* ppalClipboard = NULL;
|
|
CBitmap* pbmClipboard = NULL;
|
|
LPSTR lpDib = NULL;
|
|
HPALETTE hPal = NULL;
|
|
HBITMAP hBitmap = NULL;
|
|
HGLOBAL hDIB = NULL;
|
|
HGLOBAL hMF = NULL;
|
|
|
|
CStgMedium stgMedium;
|
|
|
|
BOOL bGotClip = FALSE;
|
|
|
|
hPal = (HPALETTE)_GetClipboardData( CF_PALETTE, TYMED_GDI, &stgMedium );
|
|
if (hPal)
|
|
{
|
|
bPaletteAvailable = TRUE;
|
|
ppalClipboard = CPalette::FromHandle( hPal );
|
|
|
|
ReleaseStgMedium(&stgMedium);
|
|
}
|
|
|
|
if (!bGotClip)
|
|
{
|
|
hDIB = (HGLOBAL)_GetClipboardData( CF_DIB, TYMED_HGLOBAL, &stgMedium );
|
|
|
|
if (hDIB)
|
|
{
|
|
lpDib = (LPSTR)::GlobalLock( hDIB );
|
|
|
|
if (lpDib)
|
|
{
|
|
bmData.bmWidth = DIBWidth ( lpDib );
|
|
bmData.bmHeight = DIBHeight( lpDib );
|
|
|
|
if (bmData.bmWidth && bmData.bmHeight)
|
|
{
|
|
bDIBAvailable = TRUE;
|
|
bPaletteAvailable = FALSE;
|
|
|
|
PBITMAPINFOHEADER pbmih = (PBITMAPINFOHEADER) lpDib;
|
|
|
|
if (pbmih->biSize >= sizeof(BITMAPINFOHEADER))
|
|
{
|
|
cXPelsPerMeter = pbmih->biXPelsPerMeter;
|
|
cYPelsPerMeter = pbmih->biYPelsPerMeter;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#ifdef _DEBUG
|
|
TRACE1( "Loaded the DIB %s.\n", (bDIBAvailable? TEXT("Yes"): TEXT("No")) );
|
|
#endif
|
|
|
|
bGotClip = bDIBAvailable;
|
|
}
|
|
|
|
if (!bGotClip)
|
|
{
|
|
hBitmap = (HBITMAP)_GetClipboardData( CF_BITMAP, TYMED_GDI, &stgMedium );
|
|
|
|
if (hBitmap)
|
|
{
|
|
pbmClipboard = CBitmap::FromHandle( hBitmap );
|
|
|
|
if (pbmClipboard->GetObject( sizeof( BITMAP ), &bmData ))
|
|
{
|
|
bBitmapAvailable = TRUE;
|
|
|
|
DIBSECTION ds;
|
|
|
|
if (pbmClipboard->GetObject( sizeof( ds ), &ds ))
|
|
{
|
|
cXPelsPerMeter = ds.dsBmih.biXPelsPerMeter;
|
|
cYPelsPerMeter = ds.dsBmih.biYPelsPerMeter;
|
|
}
|
|
|
|
if (bPaletteAvailable)
|
|
{
|
|
if (!ppalClipboard)
|
|
bBitmapAvailable = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
TRACE1( "Loaded the Bitmap %s.\n", (bBitmapAvailable? TEXT("Yes"): TEXT("No")) );
|
|
#endif
|
|
|
|
bGotClip = bBitmapAvailable;
|
|
}
|
|
|
|
if (!bGotClip)
|
|
{
|
|
hMF = (HGLOBAL)_GetClipboardData(CF_METAFILEPICT, TYMED_MFPICT, &stgMedium);
|
|
if (hMF)
|
|
{
|
|
CDC dcMF;
|
|
|
|
if (dcMF.CreateCompatibleDC( NULL ))
|
|
{
|
|
if (GetMFDimensions(hMF, dcMF.m_hDC, &bmData.bmWidth,
|
|
&bmData.bmHeight, &cXPelsPerMeter, &cYPelsPerMeter, m_pImg))
|
|
{
|
|
bMFAvailable = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
bGotClip = bMFAvailable;
|
|
}
|
|
|
|
if (!bGotClip)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
switch (CheckPastedSize(bmData.bmWidth, bmData.bmHeight, m_pImg))
|
|
{
|
|
default:
|
|
return TRUE;
|
|
|
|
case IDYES:
|
|
bResizedBitmap = TRUE;
|
|
break;
|
|
|
|
case IDNO:
|
|
break;
|
|
}
|
|
|
|
CDC stdDC;
|
|
BOOL bOkay = FALSE;
|
|
CBitmap* pbmOld = NULL;
|
|
CPalette* ppalOld = NULL;
|
|
|
|
if (bBitmapAvailable)
|
|
{
|
|
CBitmap bmClipboard;
|
|
CBitmap* pbmOldCopy = NULL;
|
|
CPalette* ppalOldCopy = NULL;
|
|
CDC* pdcCopy = NULL;
|
|
|
|
if (! stdDC.CreateCompatibleDC( NULL ))
|
|
{
|
|
theApp.SetGdiEmergency();
|
|
goto LReturn;
|
|
}
|
|
|
|
pbmOld = stdDC.SelectObject( pbmClipboard );
|
|
|
|
if (! pbmOld)
|
|
{
|
|
theApp.SetGdiEmergency();
|
|
goto LReturn;
|
|
}
|
|
|
|
if (ppalClipboard)
|
|
{
|
|
ppalOld = stdDC.SelectPalette( ppalClipboard, FALSE );
|
|
stdDC.RealizePalette();
|
|
}
|
|
|
|
// duplicate the bitmap
|
|
if (! bmClipboard.CreateBitmap( bmData.bmWidth, bmData.bmHeight,
|
|
bmData.bmPlanes, bmData.bmBitsPixel, NULL ))
|
|
{
|
|
theApp.SetMemoryEmergency();
|
|
goto LReturn;
|
|
}
|
|
|
|
pdcCopy = new CDC;
|
|
|
|
if (pdcCopy == NULL)
|
|
{
|
|
theApp.SetMemoryEmergency();
|
|
goto LReturn;
|
|
}
|
|
|
|
if (! pdcCopy->CreateCompatibleDC( NULL ))
|
|
{
|
|
delete pdcCopy;
|
|
theApp.SetGdiEmergency();
|
|
goto LReturn;
|
|
}
|
|
|
|
pbmOldCopy = pdcCopy->SelectObject( &bmClipboard );
|
|
|
|
if (ppalClipboard)
|
|
{
|
|
ppalOldCopy = pdcCopy->SelectPalette( ppalClipboard, FALSE );
|
|
pdcCopy->RealizePalette();
|
|
}
|
|
|
|
pdcCopy->BitBlt( 0, 0, bmData.bmWidth, bmData.bmHeight, &stdDC, 0, 0, SRCCOPY );
|
|
|
|
if (ppalOldCopy)
|
|
pdcCopy->SelectPalette( ppalOldCopy, FALSE );
|
|
|
|
pdcCopy->SelectObject( pbmOldCopy );
|
|
delete pdcCopy;
|
|
|
|
stdDC.SelectObject( &bmClipboard );
|
|
|
|
// Unload the bitmap
|
|
stdDC.SelectObject( pbmOld );
|
|
pbmOld = NULL;
|
|
|
|
if (ppalOld)
|
|
{
|
|
stdDC.SelectPalette( ppalOld, FALSE );
|
|
ppalOld = NULL;
|
|
}
|
|
|
|
// if we still do not know the image resolution, use the display resolution
|
|
if (cXPelsPerMeter == 0 && cYPelsPerMeter == 0)
|
|
{
|
|
cXPelsPerMeter = MulDiv(::GetDeviceCaps(stdDC, LOGPIXELSX),10000, 254);
|
|
cYPelsPerMeter = MulDiv(::GetDeviceCaps(stdDC, LOGPIXELSY),10000, 254);
|
|
}
|
|
|
|
stdDC.DeleteDC();
|
|
// Now we convert our nice DDB to a DIB and back so we can
|
|
// convert color bitmaps to monochrome nicely and deal with
|
|
// palette differences...
|
|
DWORD dwSize;
|
|
|
|
lpDib = (LPSTR) DibFromBitmap(
|
|
(HBITMAP)bmClipboard.GetSafeHandle(),
|
|
BI_RGB,
|
|
0,
|
|
ppalClipboard,
|
|
NULL,
|
|
dwSize,
|
|
cXPelsPerMeter,
|
|
cYPelsPerMeter );
|
|
}
|
|
|
|
if (bMFAvailable)
|
|
{
|
|
CDC dcMF;
|
|
|
|
if (dcMF.CreateCompatibleDC(CDC::FromHandle(m_pImg->hDC)))
|
|
{
|
|
CBitmap bmMF;
|
|
|
|
if (bmMF.CreateCompatibleBitmap(CDC::FromHandle(m_pImg->hDC),
|
|
bmData.bmWidth, bmData.bmHeight))
|
|
{
|
|
dcMF.SelectObject(&bmMF);
|
|
//not needed for DIBSection!!!
|
|
if (ppalClipboard)
|
|
{
|
|
dcMF.SelectPalette(ppalClipboard, FALSE);
|
|
}
|
|
|
|
CRect rc(0, 0, bmData.bmWidth, bmData.bmHeight);
|
|
|
|
PlayMetafileIntoDC(hMF, &rc, dcMF.m_hDC);
|
|
|
|
// Select out the bitmap and palette
|
|
dcMF.DeleteDC();
|
|
|
|
DWORD dwSize;
|
|
|
|
lpDib = (LPSTR) DibFromBitmap(
|
|
(HBITMAP)bmMF.m_hObject, BI_RGB, 0,
|
|
ppalClipboard, NULL, dwSize,
|
|
cXPelsPerMeter, cYPelsPerMeter );
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lpDib)
|
|
{
|
|
CPalette* ppalDib = CreateDIBPalette( lpDib );
|
|
|
|
ppalDib = FixupDibPalette( lpDib, ppalDib );
|
|
|
|
HBITMAP hbmDib = DIBToBitmap( lpDib, theApp.m_pPalette, m_pImg->hDC );
|
|
|
|
if (bDIBAvailable)
|
|
::GlobalUnlock( hDIB );
|
|
else
|
|
FreeDib( lpDib );
|
|
|
|
if (hbmDib != NULL
|
|
&& stdDC.CreateCompatibleDC( CDC::FromHandle( m_pImg->hDC ) ))
|
|
{
|
|
CRect rtBrush( 0, 0, bmData.bmWidth, bmData.bmHeight );
|
|
BOOL bBrushMade = FALSE;
|
|
CBitmap bmDib;
|
|
|
|
bmDib.Attach( hbmDib );
|
|
|
|
pbmOld = stdDC.SelectObject( &bmDib );
|
|
|
|
if (m_pImg->m_pPalette)
|
|
{
|
|
ppalOld = stdDC.SelectPalette( m_pImg->m_pPalette, FALSE );
|
|
stdDC.RealizePalette();
|
|
}
|
|
|
|
#ifdef FHSELCLIP
|
|
if (bPrivateAvailable)
|
|
{
|
|
HGLOBAL hPts = (HGLOBAL)_GetClipboardData( m_wClipboardFormat );
|
|
|
|
if (hPts)
|
|
{
|
|
short* lpShort = (short*)::GlobalLock( hPts );
|
|
|
|
if (lpShort)
|
|
{
|
|
BOOL bError = FALSE;
|
|
int iEntries = *lpShort++;
|
|
LPPOINT lpPts = (LPPOINT)lpShort;
|
|
|
|
CImgTool::Select( IDMB_PICKRGNTOOL );
|
|
CFreehandSelectTool* pTool = (CFreehandSelectTool*)CImgTool::GetCurrent();
|
|
|
|
if (pTool)
|
|
{
|
|
if (pTool->CreatePolyRegion( GetZoom(), lpPts, iEntries )
|
|
&& MakeBrush( stdDC.m_hDC, rtBrush ))
|
|
{
|
|
bBrushMade = TRUE;
|
|
}
|
|
}
|
|
::GlobalUnlock( hPts );
|
|
}
|
|
}
|
|
}
|
|
#endif // FHSELCLIP
|
|
|
|
if (! bBrushMade)
|
|
{
|
|
if (CImgTool::GetCurrentID() != IDMB_PICKTOOL)
|
|
CImgTool::Select( IDMB_PICKTOOL );
|
|
|
|
bBrushMade = MakeBrush( stdDC.m_hDC, rtBrush );
|
|
}
|
|
|
|
if (bBrushMade)
|
|
{
|
|
// We have to "move" the brush so it appears...
|
|
CRect rect( 0, 0, theImgBrush.m_rcSelection.Width(),
|
|
theImgBrush.m_rcSelection.Height() );
|
|
|
|
if (! bResizedBitmap)
|
|
{
|
|
// Move the brush so that it is in the upper-left corner of
|
|
// the view (in case it's scrolled)...
|
|
rect.OffsetRect( -m_xScroll, -m_yScroll );
|
|
}
|
|
MoveBrush( rect );
|
|
|
|
DirtyImg( m_pImg );
|
|
|
|
theImgBrush.m_bFirstDrag = FALSE;
|
|
|
|
bOkay = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TRACE( TEXT("Paste: MakeBrush failed!\n") );
|
|
}
|
|
if (ppalOld)
|
|
{
|
|
ppalOld = stdDC.SelectPalette( ppalOld, FALSE );
|
|
ppalOld = NULL;
|
|
}
|
|
|
|
stdDC.SelectObject( pbmOld );
|
|
pbmOld = NULL;
|
|
bmDib.Detach();
|
|
}
|
|
|
|
if (hbmDib != NULL)
|
|
::DeleteObject( hbmDib );
|
|
|
|
if (ppalDib != NULL)
|
|
delete ppalDib;
|
|
}
|
|
LReturn:
|
|
if (pbmOld != NULL)
|
|
stdDC.SelectObject( pbmOld );
|
|
|
|
if (ppalOld != NULL)
|
|
stdDC.SelectPalette( ppalOld, FALSE );
|
|
|
|
return bOkay;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/* very similar to PasteImageClip, but this will paste into an existing */
|
|
/* selection (theImgBrush), resizing it if necessary, and not moving it */
|
|
/***************************************************************************/
|
|
|
|
BOOL CImgWnd::PasteImageFile( LPSTR lpDib )
|
|
{
|
|
CDC stdDC;
|
|
CRect cRectSelection = theImgBrush.m_rcSelection;
|
|
BOOL bOkay = FALSE;
|
|
|
|
if (lpDib == NULL)
|
|
return bOkay;
|
|
|
|
int iWidth = (int)DIBWidth ( lpDib );
|
|
int iHeight = (int)DIBHeight( lpDib );
|
|
|
|
if (CImgTool::GetCurrentID()==IDMB_PICKTOOL && theImgBrush.m_bFirstDrag)
|
|
{
|
|
if (iWidth < theImgBrush.m_size.cx)
|
|
{
|
|
cRectSelection.right = cRectSelection.left + iWidth - 1;
|
|
}
|
|
if (iHeight < theImgBrush.m_size.cy)
|
|
{
|
|
cRectSelection.bottom = cRectSelection.top + iHeight - 1;
|
|
}
|
|
|
|
// If the image is a bitmap and the bitmap in the clipboard is larger,
|
|
// then give the user the option of growing the image...
|
|
if (iWidth > theImgBrush.m_size.cx
|
|
|| iHeight > theImgBrush.m_size.cy)
|
|
{
|
|
cRectSelection.right = cRectSelection.left + iWidth - 1;
|
|
cRectSelection.bottom = cRectSelection.top + iHeight - 1;
|
|
|
|
// PSS says users don't want to see this dialog
|
|
#if 0
|
|
switch (AfxMessageBox( IDS_ENLAGEBITMAPFORCLIP,
|
|
MB_YESNOCANCEL | MB_ICONQUESTION ))
|
|
{
|
|
default:
|
|
return bOkay;
|
|
break;
|
|
|
|
case IDYES:
|
|
cRectSelection.right = cRectSelection.left + iWidth - 1;
|
|
cRectSelection.bottom = cRectSelection.top + iHeight - 1;
|
|
break;
|
|
|
|
case IDNO:
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int xPos = -m_xScroll;
|
|
int yPos = -m_yScroll;
|
|
|
|
switch (CheckPastedSize(iWidth, iHeight, m_pImg))
|
|
{
|
|
case IDYES:
|
|
xPos = yPos = 0;
|
|
break;
|
|
|
|
case IDNO:
|
|
break;
|
|
|
|
default:
|
|
return(bOkay);
|
|
}
|
|
|
|
CImgTool::Select(IDMB_PICKTOOL);
|
|
cRectSelection = CRect(xPos, yPos, xPos+iWidth, yPos+iHeight);
|
|
}
|
|
|
|
MakeBrush( m_pImg->hDC, cRectSelection );
|
|
// MakeBrush sets this
|
|
theImgBrush.m_bFirstDrag = FALSE;
|
|
|
|
if (! stdDC.CreateCompatibleDC( CDC::FromHandle( m_pImg->hDC ) ))
|
|
{
|
|
theApp.SetGdiEmergency();
|
|
return bOkay;
|
|
}
|
|
|
|
CPalette* ppalDib = CreateDIBPalette( lpDib );
|
|
|
|
ppalDib = FixupDibPalette( lpDib, ppalDib );
|
|
|
|
HBITMAP hbmDib = DIBToBitmap( lpDib, theApp.m_pPalette, m_pImg->hDC );
|
|
|
|
SetUndo( m_pImg );
|
|
|
|
if (hbmDib != NULL)
|
|
{
|
|
CBitmap bmDib;
|
|
CPalette* ppalOld = NULL;
|
|
CBitmap* pbmOld = NULL;
|
|
|
|
bmDib.Attach( hbmDib );
|
|
|
|
pbmOld = stdDC.SelectObject( &bmDib );
|
|
|
|
if (m_pImg->m_pPalette)
|
|
{
|
|
ppalOld = stdDC.SelectPalette( m_pImg->m_pPalette, FALSE );
|
|
stdDC.RealizePalette();
|
|
}
|
|
|
|
if (MakeBrush( stdDC.m_hDC, CRect( CPoint( 0, 0 ), cRectSelection.Size() ) ))
|
|
{
|
|
theImgBrush.m_bFirstDrag = FALSE;
|
|
|
|
// We have to "move" the brush so it appears...
|
|
MoveBrush( cRectSelection );
|
|
|
|
DirtyImg( m_pImg );
|
|
|
|
bOkay = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TRACE( TEXT("Paste: MakeBrush failed!\n") );
|
|
}
|
|
|
|
if (ppalOld != NULL)
|
|
{
|
|
ppalOld = stdDC.SelectPalette( ppalOld, FALSE );
|
|
}
|
|
|
|
stdDC.SelectObject( pbmOld );
|
|
bmDib.Detach();
|
|
|
|
::DeleteObject( hbmDib );
|
|
}
|
|
|
|
if (ppalDib != NULL)
|
|
delete ppalDib;
|
|
|
|
return bOkay;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
// Stolen from PBrush
|
|
//
|
|
/****************************Module*Header******************************\
|
|
* Module Name: metafile.c *
|
|
* Routines to paste a metafile as a bitmap. *
|
|
* Copyright (c) 1987 - 1991 Microsoft Corporation *
|
|
\***********************************************************************/
|
|
|
|
/* Computes dimensions of a metafile picture in pixels */
|
|
BOOL GetMFDimensions(
|
|
HANDLE hMF, /* handle to the CF_METAFILEPICT object from clipbrd */
|
|
HDC hDC, /* display context */
|
|
long *pWidth, /* width of picture in pixels, OUT param */
|
|
long *pHeight, /* height of picture in pixels, OUT param */
|
|
long *pcXPelsPerMeter, /* horizontal resolution, OUT param */
|
|
long *pcYPelsPerMeter, /* vertical resolution, OUT param */
|
|
IMG* pImg)
|
|
{
|
|
METAFILEPICT FAR *lpMfp, Picture;
|
|
int MapModeOld=0;
|
|
RECT Rect;
|
|
long xScale, yScale, Scale;
|
|
int hRes, vRes; /* horz and vert resolution, in pixels */
|
|
int hSize, vSize; /* horz and vert size, in mm */
|
|
int fResult = FALSE;
|
|
|
|
if (!hMF || !(lpMfp = (METAFILEPICT FAR *)GlobalLock(hMF)))
|
|
return FALSE;
|
|
/* copy metafile picture hdr */
|
|
Picture = *lpMfp;
|
|
GlobalUnlock(hMF);
|
|
|
|
/* Do not modify given DC's attributes */
|
|
SaveDC(hDC);
|
|
|
|
/* set the mapping mode */
|
|
MapModeOld = SetMapMode(hDC, Picture.mm);
|
|
if (Picture.mm != MM_ISOTROPIC && Picture.mm != MM_ANISOTROPIC)
|
|
{
|
|
/* For modes other than ISOTROPIC and ANISOTROPIC the picture
|
|
* dimensions are given in logical units.
|
|
/* Convert logical units to pixels. */
|
|
Rect.left = 0; Rect.right = Picture.xExt;
|
|
Rect.top = 0; Rect.bottom = Picture.yExt;
|
|
if (!LPtoDP(hDC, (LPPOINT)&Rect, 2))
|
|
goto Error;
|
|
*pWidth = Rect.right - Rect.left + 1;
|
|
*pHeight = Rect.bottom - Rect.top + 1;
|
|
fResult = TRUE;
|
|
}
|
|
else /* ISOTROPIC or ANISOTROPIC mode,
|
|
* using the xExt and yExt, determine pixel width and height of
|
|
* the image */
|
|
{
|
|
hRes = GetDeviceCaps(hDC, HORZRES);
|
|
vRes = GetDeviceCaps(hDC, VERTRES);
|
|
hSize = GetDeviceCaps(hDC, HORZSIZE);
|
|
vSize = GetDeviceCaps(hDC, VERTSIZE);
|
|
*pcXPelsPerMeter = hRes * 1000 / hSize;
|
|
*pcYPelsPerMeter = vRes * 1000 / vSize;
|
|
if (Picture.xExt == 0) /* assume default size, aspect ratio */
|
|
{
|
|
*pWidth = pImg->cxWidth;
|
|
*pHeight = pImg->cyHeight;
|
|
}
|
|
else if (Picture.xExt > 0) /* use suggested size in HIMETRIC units */
|
|
{
|
|
// convert suggested extents(in .01 mm units) for picture to pixel units.
|
|
|
|
// xPixelsPermm = hRes/hSize;, yPixelsPermm = vRes/vSize;
|
|
// Use Pixels Per logical unit.
|
|
// *pWidth = Picture.xExt*xPixelsPermm/100;
|
|
// *pHeight = Picture.yExt*yPixelsPermm/100;
|
|
*pWidth = ((long)Picture.xExt * hRes/hSize/100);
|
|
*pHeight = ((long)Picture.yExt * vRes/vSize/100);
|
|
}
|
|
else if (Picture.xExt < 0) /* use suggested aspect ratio, default size */
|
|
{
|
|
// 1 log unit = .01 mm.
|
|
// (# of log units in imageWid pixels)/xExt;
|
|
xScale = 100L * (long) pImg->cxWidth *
|
|
hSize/hRes/-Picture.xExt;
|
|
// (# of log units in imageHgt pixels)/yExt;
|
|
yScale = 100L * (long) pImg->cyHeight *
|
|
vSize/vRes/-Picture.yExt;
|
|
// choose the minimum to accomodate the entire image
|
|
Scale = min(xScale, yScale);
|
|
// use scaled Pixels Per log unit.
|
|
*pWidth = ((long)-Picture.xExt * Scale *
|
|
hRes/hSize / 100);
|
|
*pHeight = ((long)-Picture.yExt * Scale *
|
|
vRes/vSize / 100);
|
|
}
|
|
fResult = TRUE;
|
|
}
|
|
|
|
Error:
|
|
if (MapModeOld)
|
|
SetMapMode(hDC, MapModeOld); /* select the old mapping mode */
|
|
RestoreDC(hDC, -1);
|
|
return fResult;
|
|
}
|
|
|
|
BOOL PlayMetafileIntoDC(
|
|
HANDLE hMF,
|
|
RECT *pRect,
|
|
HDC hDC)
|
|
{
|
|
HBRUSH hbrBackground;
|
|
METAFILEPICT FAR *lpMfp;
|
|
|
|
if (!(lpMfp = (METAFILEPICT FAR *)GlobalLock(hMF)))
|
|
return FALSE;
|
|
|
|
SaveDC(hDC);
|
|
|
|
/* Setup background color for the bitmap */
|
|
hbrBackground = CreateSolidBrush(crRight);
|
|
|
|
if (hbrBackground)
|
|
{
|
|
FillRect(hDC, pRect, hbrBackground);
|
|
DeleteObject(hbrBackground);
|
|
}
|
|
|
|
SetMapMode(hDC, lpMfp->mm);
|
|
if (lpMfp->mm == MM_ISOTROPIC || lpMfp->mm == MM_ANISOTROPIC)
|
|
SetViewportExtEx(hDC, pRect->right-pRect->left, pRect->bottom-pRect->top,
|
|
NULL);
|
|
PlayMetaFile(hDC, lpMfp->hMF);
|
|
GlobalUnlock(hMF);
|
|
RestoreDC(hDC, -1);
|
|
return TRUE;
|
|
}
|
|
|