Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3166 lines
86 KiB

#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 "undo.h"
#include "props.h"
#include "cmpmsg.h"
#include "imgdlgs.h"
#include "ferr.h"
#include "thumnail.h"
#ifdef _DEBUG
#undef THIS_FILE
static CHAR BASED_CODE THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNAMIC(CImgWnd, CWnd)
#include "memtrace.h"
/***************************************************************************/
// helper fns
static CTedit *_GetTextEdit()
{
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 )))
{
return pTextEdit;
}
}
}
return NULL;
}
BOOL IsUserEditingText()
{
return (_GetTextEdit() != NULL);
}
BOOL TextToolProcessed( UINT nMessage )
{
CTedit *pTextEdit = _GetTextEdit();
if (pTextEdit)
{
pTextEdit->SendMessage( WM_COMMAND, nMessage );
return TRUE;
}
return FALSE;
}
/***************************************************************************/
BEGIN_MESSAGE_MAP(CImgWnd, CWnd)
ON_WM_CREATE()
#if 0
ON_WM_DESTROY()
#endif
ON_WM_SETFOCUS()
ON_WM_KILLFOCUS()
ON_WM_PAINT()
ON_WM_SIZE()
ON_WM_HSCROLL()
ON_WM_VSCROLL()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONDBLCLK()
ON_WM_LBUTTONUP()
ON_WM_RBUTTONDOWN()
ON_WM_RBUTTONDBLCLK()
ON_WM_RBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_KEYDOWN()
ON_WM_KEYUP()
ON_WM_TIMER()
ON_WM_CANCELMODE()
ON_WM_WINDOWPOSCHANGING()
ON_WM_DESTROYCLIPBOARD()
ON_WM_PALETTECHANGED()
ON_WM_SETCURSOR()
ON_WM_MOUSEWHEEL ()
END_MESSAGE_MAP()
/***************************************************************************/
CRect rcDragBrush;
CImgBrush theBackupBrush;
CImgWnd* g_pMouseImgWnd = NULL;
CImgWnd* g_pDragBrushWnd = NULL;
// Current Image Viewer
CImgWnd* CImgWnd::c_pImgWndCur = NULL;
CDragger* CImgWnd::c_pResizeDragger = NULL;
CTracker::STATE CImgWnd::c_dragState = CTracker::nil;
// Mouse Tracking Information
MTI mti;
BOOL bIgnoreMouse;
/***************************************************************************/
CImgWnd::CImgWnd(IMG* pImg)
{
m_pNextImgWnd = NULL;
m_nZoom = 1;
m_nZoomPrev = 4;
m_xScroll = 0;
m_yScroll = 0;
m_LineX = 1;
m_LineY = 1;
m_ptDispPos.x = -1;
m_ptDispPos.y = -1;
c_pImgWndCur = this;
m_pwndThumbNailView = NULL;
m_wClipboardFormat = 0;
m_hPoints = NULL;
m_WheelDelta = 0;
ASSERT(pImg != NULL);
m_pImg = pImg;
m_pImg->m_nLastChanged = -1;
}
/***************************************************************************/
CImgWnd::CImgWnd(CImgWnd *pImgWnd)
{
m_pImg = pImgWnd->m_pImg;
m_pNextImgWnd = pImgWnd->m_pNextImgWnd;
m_nZoom = pImgWnd->m_nZoom;
m_nZoomPrev = pImgWnd->m_nZoomPrev;
m_xScroll = pImgWnd->m_xScroll,
m_yScroll = pImgWnd->m_yScroll;
m_ptDispPos = pImgWnd->m_ptDispPos;
m_pwndThumbNailView = NULL;
m_wClipboardFormat = 0;
m_hPoints = NULL;
}
/***************************************************************************/
CImgWnd::~CImgWnd()
{
if (c_pImgWndCur == this)
c_pImgWndCur = NULL;
if (g_pMouseImgWnd == this)
g_pMouseImgWnd = NULL;
HideBrush();
fDraggingBrush = FALSE;
g_bBrushVisible = FALSE;
if (g_pDragBrushWnd == this)
{
g_pDragBrushWnd = NULL;
}
if (m_hPoints)
{
::GlobalFree( m_hPoints );
m_hPoints = NULL;
}
}
/***************************************************************************/
BOOL CImgWnd::Create( DWORD dwStyle, const RECT& rect,
CWnd* pParentWnd, UINT nID)
{
static CString sImgWndClass;
if (sImgWndClass.IsEmpty())
sImgWndClass = AfxRegisterWndClass( CS_DBLCLKS );
ASSERT( ! sImgWndClass.IsEmpty() );
dwStyle |= WS_CLIPSIBLINGS;
return CWnd::Create( sImgWndClass, NULL, dwStyle, rect, pParentWnd, nID );
}
/***************************************************************************/
int CImgWnd::OnCreate( LPCREATESTRUCT lpCreateStruct )
{
if (m_pImg)
AddImgWnd( m_pImg, this );
return CWnd::OnCreate(lpCreateStruct);
}
/***************************************************************************/
#if 0
void CImgWnd::OnDestroy()
{
if (c_pImgWndCur == this)
c_pImgWndCur = NULL;
HideBrush();
fDraggingBrush = FALSE;
CWnd::OnDestroy();
}
#endif
/***************************************************************************/
void CImgWnd::OnPaletteChanged(CWnd *pPaletteWnd)
{
#if 0
// obviously this never gets hit or somebody would have realized by now...
CImgWnd::OnPaletteChanged(pPaletteWnd);
#endif
Invalidate();
}
/***************************************************************************/
BOOL CImgWnd::OnSetCursor(CWnd *pWnd, UINT nHitTest, UINT message)
{
if (nHitTest==HTCLIENT && pWnd->m_hWnd==m_hWnd)
{
// We do our own cursor stuff in our own client area, but not in the
// text box
return(TRUE);
}
return((BOOL)Default());
}
/***************************************************************************/
void CImgWnd::OnWindowPosChanging( WINDOWPOS FAR* lpwndpos )
{
CWnd::OnWindowPosChanging( lpwndpos );
}
/***************************************************************************/
// Image View Painting Functions
//
void CImgWnd::OnPaint()
{
CPaintDC dc(this);
if (dc.m_hDC == NULL)
{
theApp.SetGdiEmergency();
return;
}
if (m_pImg == NULL)
return;
if (g_pMouseImgWnd == this)
CImgTool::HideDragger( this );
CPalette* ppalOld = SetImgPalette( &dc, FALSE );
DrawBackground( &dc, (CRect*)&dc.m_ps.rcPaint );
DrawImage ( &dc, (CRect*)&dc.m_ps.rcPaint );
DrawTracker ( &dc, (CRect*)&dc.m_ps.rcPaint );
if (g_pMouseImgWnd == this)
CImgTool::ShowDragger( this );
if (m_pwndThumbNailView != NULL)
m_pwndThumbNailView->RefreshImage();
if (ppalOld)
dc.SelectPalette( ppalOld, FALSE );
}
/***************************************************************************/
BOOL CImgWnd::OnCmdMsg( UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo )
{
if (nCode == CN_COMMAND)
{
switch (nID)
{
case IDMX_VS_PAGEUP:
SendMessage( WM_VSCROLL, SB_PAGEUP, 0L );
return TRUE;
case IDMX_VS_PAGEDOWN:
SendMessage( WM_VSCROLL, SB_PAGEDOWN, 0L );
return TRUE;
case IDMX_HS_PAGEUP:
SendMessage( WM_HSCROLL, SB_PAGEUP, 0L );
return TRUE;
case IDMX_HS_PAGEDOWN:
SendMessage( WM_HSCROLL, SB_PAGEDOWN, 0L );
return TRUE;
}
CImgTool* pImgTool = CImgTool::FromID( nID );
if (pImgTool != NULL)
{
pImgTool->Select();
return TRUE;
}
}
return CWnd::OnCmdMsg( nID, nCode, pExtra, pHandlerInfo );
}
void CImgWnd::GetDrawRects(const CRect* pPaintRect, const CRect* pReqDestRect,
CRect& srcRect, CRect& destRect)
{
// Find the sub-rectangle of srcRect that corresponds to
// the pPaintRect sub-rectangle of destRect.
srcRect = *pPaintRect;
srcRect.right += m_nZoom - 1;
srcRect.bottom += m_nZoom - 1;
ClientToImage( srcRect );
srcRect.left = max(0, srcRect.left);
srcRect.top = max(0, srcRect.top );
srcRect.right = min(m_pImg->cxWidth , srcRect.right );
srcRect.bottom = min(m_pImg->cyHeight, srcRect.bottom);
if (pReqDestRect == NULL)
{
destRect = srcRect;
ImageToClient( destRect );
}
else
{
destRect = *pReqDestRect;
}
}
/***************************************************************************/
// Draw the actual image 'a bitmap'. Drawing is
// optimized to only deal with the pixels inside paintRect. This function
// reduces flashing by drawing the image and optional grid in an off-screen
// bitmap and then transfering that bitmap to the screen.
//
void CImgWnd::DrawImage( CDC* pDC, const CRect* pPaintRect,
CRect* pDestRect, BOOL bDoGrid )
{
ASSERT( pDC != NULL );
ASSERT( m_pImg != NULL );
CRect destRect;
CRect srcRect;
GetDrawRects(pPaintRect, pDestRect, srcRect, destRect);
if (srcRect.Width() <= 0 || srcRect.Height() <= 0)
{
// Nothing to paint...
return;
}
if (! IsGridVisible() && m_nZoom == 1)
{
// Optimize the easy case... (Can't speed up magnified views
// because of the bogus hack we have to do in StretchCopy.)
if (theApp.m_pPalette
&& ((m_pImg->cPlanes * m_pImg->cBitCount) == 1))
{
pDC->SetTextColor( PALETTEINDEX( 0 ) );
pDC->SetBkColor ( PALETTEINDEX( 1 ) );
}
BitBlt(pDC->m_hDC, destRect.left , destRect.top,
destRect.Width(), destRect.Height(),
m_pImg->hDC, srcRect.left , srcRect.top, SRCCOPY);
return;
}
CDC tempDC;
CBitmap tempBitmap;
CBitmap* pOldTempBitmap;
if (! tempDC.CreateCompatibleDC(pDC)
|| ! tempBitmap.CreateCompatibleBitmap(pDC, destRect.Width() + 1,
destRect.Height() + 1))
{
theApp.SetGdiEmergency(FALSE);
return;
}
pOldTempBitmap = tempDC.SelectObject(&tempBitmap);
ASSERT(pOldTempBitmap != NULL);
CPalette* pOldPalette = SetImgPalette( &tempDC, FALSE ); // Background ??
// If we're zoomed in, use COLORONCOLOR for easy pixel-by-pixel editing
// Otherwise use HALFTONE for nice appearance
if (m_nZoom < 2)
{
tempDC.SetStretchBltMode(HALFTONE);
}
else
{
tempDC.SetStretchBltMode(COLORONCOLOR);
}
if (m_pImg->cPlanes * m_pImg->cBitCount == 1)
{
tempDC.SetTextColor( RGB( 0x00, 0x00, 0x00 ));
tempDC.SetBkColor ( RGB( 0xFF, 0xFF, 0xFF ));
}
// Bitmaps...
StretchCopy(tempDC.m_hDC, 0, 0, destRect.Width(), destRect.Height(),
m_pImg->hDC, srcRect.left, srcRect.top,
srcRect.Width(), srcRect.Height());
// Draw the grid...
if (IsGridVisible() && bDoGrid)
DrawGrid( &tempDC, srcRect, destRect );
// Transfer to the screen...
pDC->BitBlt(destRect.left, destRect.top, destRect.Width(),
destRect.Height(), &tempDC, 0, 0, SRCCOPY);
// Cleanup...
if (pOldPalette)
tempDC.SelectPalette( pOldPalette, FALSE ); // Background ??
tempDC.SelectObject(pOldTempBitmap);
}
/***************************************************************************/
// Draw a border and bevel around the image and fill the rest of
// the window with gray. If pPaintRect is not NULL, painting is
// optimized to only draw with the rectangle.
//
void CImgWnd::DrawBackground(CDC* pDC, const CRect* pPaintRect)
{
ASSERT( pDC != NULL );
CRect clientRect;
if (pPaintRect == NULL)
{
// Draw everything...
GetClientRect( &clientRect );
pPaintRect = &clientRect;
}
CRect srcRect;
CRect imageRect;
GetDrawRects(pPaintRect, NULL, srcRect, imageRect);
// Erase area around image, border, and bevel...
CBrush* pOldBrush = pDC->SelectObject( GetSysBrush( COLOR_APPWORKSPACE ) );
if (imageRect.top > pPaintRect->top)
{
// Top...
pDC->PatBlt(pPaintRect->left, pPaintRect->top, pPaintRect->Width(),
imageRect.top - pPaintRect->top, PATCOPY);
}
if (imageRect.left > pPaintRect->left)
{
// Left...
pDC->PatBlt(pPaintRect->left, imageRect.top,
imageRect.left - pPaintRect->left, imageRect.Height(), PATCOPY);
}
if (imageRect.right < pPaintRect->right)
{
// Right...
pDC->PatBlt(imageRect.right, imageRect.top,
pPaintRect->right - imageRect.right, imageRect.Height(), PATCOPY);
}
if (imageRect.bottom < pPaintRect->bottom)
{
// Bottom...
pDC->PatBlt(pPaintRect->left, imageRect.bottom, pPaintRect->Width(),
pPaintRect->bottom - imageRect.bottom, PATCOPY);
}
pDC->SelectObject(pOldBrush);
}
/***************************************************************************/
void CImgWnd::SetImg(IMG* pImg)
{
m_pNextImgWnd = pImg->m_pFirstImgWnd;
pImg->m_pFirstImgWnd = this;
m_pImg = pImg;
}
/***************************************************************************/
CPalette* CImgWnd::SetImgPalette( CDC* pdc, BOOL bForce )
{
CPalette* ppal = NULL;
// If we do not realize as a background brush when in-place, we can get
// an infinite recursion of the container and us trying to realize the
// palette
if (theApp.m_pwndInPlaceFrame)
{
bForce = TRUE;
}
if (theApp.m_pPalette
&& theApp.m_pPalette->m_hObject)
{
ppal = pdc->SelectPalette( theApp.m_pPalette, bForce );
pdc->RealizePalette();
}
return ppal;
}
/***************************************************************************/
HPALETTE CImgWnd::SetImgPalette( HDC hdc, BOOL bForce )
{
HPALETTE hpal = NULL;
// If we do not realize as a background brush when in-place, we can get
// an infinite recursion of the container and us trying to realize the
// palette
if (theApp.m_pwndInPlaceFrame)
{
bForce = TRUE;
}
if (theApp.m_pPalette
&& theApp.m_pPalette->m_hObject)
{
hpal = ::SelectPalette( hdc, (HPALETTE)theApp.m_pPalette->m_hObject, bForce );
::RealizePalette( hdc );
}
return hpal;
}
/***************************************************************************/
void CImgWnd::SetZoom(int nZoom)
{
if (m_nZoom > 1)
m_nZoomPrev = m_nZoom;
CommitSelection(TRUE);
if (nZoom > 1)
{
// deselect the text tool if it's around
CImgTool* pImgTool = CImgTool::GetCurrent();
if (pImgTool != NULL && CImgTool::GetCurrentID() == IDMX_TEXTTOOL)
{
CImgTool::Select(IDMB_PENCILTOOL);
}
}
HideBrush();
SetupRubber( m_pImg );
EraseTracker();
theImgBrush.m_pImg = NULL;
DrawTracker();
CPBView* pView = (CPBView*)GetParent();
if (pView != NULL && pView->IsKindOf( RUNTIME_CLASS( CPBView ) ))
if (nZoom == 1)
pView->HideThumbNailView();
else
pView->ShowThumbNailView();
Invalidate(FALSE);
m_nZoom = nZoom;
}
/***************************************************************************/
void CImgWnd::SetScroll(int xPos, int yPos)
{
if (xPos > 0)
xPos = 0;
else
if (xPos < -m_pImg->cxWidth)
xPos = -m_pImg->cxWidth;
if (yPos > 0)
yPos = 0;
else
if (yPos < -m_pImg->cyHeight)
yPos = -m_pImg->cyHeight;
m_xScroll = xPos;
m_yScroll = yPos;
Invalidate( FALSE );
CheckScrollBars();
}
/***************************************************************************/
void CImgWnd::CheckScrollBars()
{
// Tacky recursion blocker is required because this is called from
// the OnSize handler and turning scroll bars on or off changes
// the size of our window...
static BOOL bInHere = FALSE;
if (bInHere)
return;
bInHere = TRUE;
int cxVScrollBar = GetSystemMetrics( SM_CXVSCROLL );
int cyHScrollBar = GetSystemMetrics( SM_CYHSCROLL );
// Figure the client area size if there were no scroll bars...
CRect clientRect;
GetClientRect( &clientRect );
int cxWidth = clientRect.Width();
int cyHeight = clientRect.Height();
BOOL hHasHBar = ((GetStyle() & WS_HSCROLL) != 0);
BOOL bHasVBar = ((GetStyle() & WS_VSCROLL) != 0);
if (hHasHBar)
cyHeight += cyHScrollBar;
if (bHasVBar)
cxWidth += cxVScrollBar;
// Figure the size of the thing we are scrolling (the subject)...
CSize subjectSize;
GetImgSize( m_pImg, subjectSize );
int iTrackerSize = 2 * CTracker::HANDLE_SIZE;
subjectSize.cx = (subjectSize.cx * m_nZoom ) + iTrackerSize;
subjectSize.cy = (subjectSize.cy * m_nZoom ) + iTrackerSize;
m_LineX = (subjectSize.cx + 31) / 32;
m_LineY = (subjectSize.cy + 31) / 32;
// Nasty loop takes care of case where we only need a vertical
// scroll bar because we added a horizontal scroll bar and
// vice versa... (Will only ever loop twice.)
BOOL bNeedHBar = FALSE;
BOOL bNeedVBar = FALSE;
BOOL bChange;
do {
bChange = FALSE;
if (! bNeedVBar && subjectSize.cy > cyHeight)
{
bChange = TRUE;
bNeedVBar = TRUE;
cxWidth -= cxVScrollBar;
}
if (! bNeedHBar && subjectSize.cx > cxWidth)
{
bChange = TRUE;
bNeedHBar = TRUE;
cyHeight -= cyHScrollBar;
}
} while (bChange);
SetRedraw( FALSE );
SCROLLINFO si;
si.cbSize = sizeof( si );
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
si.nMin = 0;
// We subtract 1 because subjectSize is the size we want, so the range
// should be 0 to subjectSize-1
si.nMax = (subjectSize.cx - 1) / m_nZoom;
si.nPage = cxWidth / m_nZoom;
si.nPos = -m_xScroll;
SetScrollInfo( SB_HORZ, &si, FALSE );
si.nMax = (subjectSize.cy - 1) / m_nZoom;
si.nPage = cyHeight / m_nZoom;
si.nPos = -m_yScroll;
SetScrollInfo( SB_VERT, &si, FALSE );
si.fMask = SIF_POS;
GetScrollInfo( SB_HORZ, &si );
if ( -m_xScroll != si.nPos )
m_xScroll = -si.nPos ;
GetScrollInfo( SB_VERT, &si );
if ( -m_yScroll != si.nPos )
m_yScroll = -si.nPos;
SetRedraw ( TRUE );
Invalidate( FALSE );
bInHere = FALSE;
}
/***************************************************************************/
void CImgWnd::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar*)
{
OnScroll(FALSE, nSBCode, nPos);
}
/***************************************************************************/
void CImgWnd::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar*)
{
OnScroll(TRUE, nSBCode, nPos);
}
/***************************************************************************/
void CImgWnd::OnScroll(BOOL bVert, UINT nSBCode, UINT nPos)
{
SCROLLINFO ScrollInfo;
ScrollInfo.cbSize = sizeof( ScrollInfo );
ScrollInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
GetScrollInfo( (bVert? SB_VERT: SB_HORZ), &ScrollInfo );
int iScroll = ScrollInfo.nPage/4;
int iNewPos = ScrollInfo.nPos;
switch (nSBCode)
{
case SB_TOP:
iNewPos = 0;
break;
case SB_BOTTOM:
iNewPos = ScrollInfo.nMax;
break;
case SB_LINEDOWN:
iNewPos += iScroll;
break;
case SB_LINEUP:
iNewPos -= iScroll;
break;
case SB_PAGEDOWN:
iNewPos += iScroll * 4;
break;
case SB_PAGEUP:
iNewPos -= iScroll * 4;
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
iNewPos = nPos;
break;
}
if (iNewPos < ScrollInfo.nMin)
iNewPos = 0;
else
if (iNewPos > ScrollInfo.nMax-(int)ScrollInfo.nPage+1)
iNewPos = ScrollInfo.nMax-(int)ScrollInfo.nPage+1;
iScroll = -(iNewPos - ScrollInfo.nPos);
Invalidate(FALSE);
if (bVert)
m_yScroll = -iNewPos;
else
m_xScroll = -iNewPos;
ScrollInfo.fMask = SIF_POS;
ScrollInfo.nPos = iNewPos;
SetScrollInfo( (bVert? SB_VERT: SB_HORZ), &ScrollInfo, TRUE );
}
/***************************************************************************/
BOOL CImgWnd::OnMouseWheel (UINT nFlags, short zDelta, CPoint pt)
{
//
// Don't handle zoom and datazoom.
//
if (nFlags & (MK_SHIFT | MK_CONTROL))
{
return FALSE;
}
int nBar;
int *pScroll;
if (GetWindowLong(GetSafeHwnd(), GWL_STYLE) & WS_VSCROLL)
{
nBar = SB_VERT;
pScroll = &m_yScroll;
}
else
{
nBar = SB_HORZ;
pScroll = &m_xScroll;
}
SCROLLINFO ScrollInfo;
ScrollInfo.cbSize = sizeof( ScrollInfo );
ScrollInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
GetScrollInfo( nBar, &ScrollInfo );
m_WheelDelta -= zDelta;
if (abs(m_WheelDelta) >= WHEEL_DELTA)
{
int iScroll = ScrollInfo.nPage/4 * (m_WheelDelta/WHEEL_DELTA);
int iNewPos = ScrollInfo.nPos + iScroll;
if (iNewPos < ScrollInfo.nMin)
iNewPos = 0;
else if (iNewPos > ScrollInfo.nMax-(int)ScrollInfo.nPage+1)
iNewPos = ScrollInfo.nMax-(int)ScrollInfo.nPage+1;
Invalidate(FALSE);
*pScroll = -iNewPos;
ScrollInfo.fMask = SIF_POS;
ScrollInfo.nPos = iNewPos;
SetScrollInfo( nBar, &ScrollInfo, TRUE );
m_WheelDelta= m_WheelDelta % WHEEL_DELTA;
CImgTool* pImgTool = CImgTool::GetCurrent();
mti.ptPrev = mti.pt;
mti.pt = pt;
pImgTool->OnMove (this, &mti);
}
return TRUE;
}
/***************************************************************************/
void CImgWnd::PrepareForBrushChange(BOOL bPickup, BOOL bErase)
{
if (theImgBrush.m_pImg != NULL
&& theImgBrush.m_bFirstDrag)
{
if (bPickup)
PickupSelection();
SetUndo(m_pImg);
theImgBrush.m_bLastDragWasFirst = TRUE;
theImgBrush.m_bFirstDrag = FALSE;
theImgBrush.m_rcDraggedFrom = rcDragBrush;
if (CImgTool::GetCurrentID() == IDMX_TEXTTOOL)
{
HideBrush();
bErase = FALSE;
}
if (bErase)
{
// Clear the background...
HideBrush();
FillImgRect( m_pImg->hDC, &theImgBrush.m_rcDraggedFrom, crRight );
CommitImgRect(m_pImg, &theImgBrush.m_rcDraggedFrom);
InvalImgRect (m_pImg, &theImgBrush.m_rcDraggedFrom);
FinishUndo(theImgBrush.m_rcDraggedFrom);
MoveBrush(theImgBrush.m_rcSelection);
}
}
}
/***************************************************************************/
void CImgWnd::OnCancelMode()
{
CmdCancel();
}
/***************************************************************************/
void CImgWnd::CmdCancel()
{
// This will:
// Erase the size indicator on the status bar.
// Reset the mouse cursor to an arrow.
// Release the capture.
// Cancel (and undo) any drawing operation in progress.
// Cancel the Pick Color command if it's active.
// If there's a selection, will set to whole image and select prev tool
ClearStatusBarSize();
mti.fLeft = mti.fRight = FALSE;
if (c_pResizeDragger != NULL)
{
EndResizeOperation();
bIgnoreMouse = TRUE;
return;
}
CImgTool* pImgTool = CImgTool::GetCurrent();
if (GetCapture() == this || pImgTool->IsMultPtOpInProgress())
{
// Cancel dragging or multi-point operation in progress
BOOL bWasMakingSelection = theImgBrush.m_bMakingSelection;
ZoomedInDP(WM_CANCEL, 0, CPoint(0, 0));
SetCursor(LoadCursor(NULL, IDC_ARROW + 11));
if (! bWasMakingSelection)
CancelPainting();
bIgnoreMouse = TRUE;
}
else
if (pImgTool->IsToggle()
|| CImgTool::GetCurrentID() == IDMB_PICKTOOL
|| CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL
|| CImgTool::GetCurrentID() == IDMZ_BRUSHTOOL
|| CImgTool::GetCurrentID() == IDMB_POLYGONTOOL
|| CImgTool::GetCurrentID() == IDMX_TEXTTOOL)
{
pImgTool->OnCancel( this );
}
if (GetKeyState( VK_LBUTTON ) < 0 || GetKeyState( VK_RBUTTON) < 0 )
bIgnoreMouse = TRUE;
SetToolCursor();
}
/***************************************************************************/
void CImgWnd::CmdSel2Bsh()
{
if (! g_bCustomBrush)
{
if (theImgBrush.m_pImg == NULL)
{
// No selection, turn the whole image into a brush!
MakeBrush( m_pImg->hDC, CRect( 0, 0, m_pImg->cxWidth,
m_pImg->cyHeight ) );
}
if (theImgBrush.m_bFirstDrag)
{
// Time to pick up the bits!
ASSERT(theImgBrush.m_pImg == m_pImg);
PickupSelection();
}
InvalImgRect(theImgBrush.m_pImg, NULL); // erase the selection tracker
CImgTool::Select(IDMZ_BRUSHTOOL);
SetCombineMode(combineMatte);
g_bCustomBrush = TRUE;
theImgBrush.m_pImg = NULL;
theImgBrush.CenterHandle();
}
else
if (CImgTool::GetCurrentID() == IDMZ_BRUSHTOOL)
{
CImgTool::GetCurrent()->OnCancel(this);
}
}
/***************************************************************************/
// Coordinate Translation and Calculation Functions
//
//
// Convert a point or rect in image view client coordinates to image
// coordinates taking magnification and scrolling into account.
//
void CImgWnd::ClientToImage(CPoint& point)
{
int iHandleSize = CTracker::HANDLE_SIZE;
point.x = (point.x - iHandleSize) / m_nZoom - m_xScroll;
point.y = (point.y - iHandleSize) / m_nZoom - m_yScroll;
}
/***************************************************************************/
void CImgWnd::ClientToImage(CRect& rect)
{
ClientToImage(rect.TopLeft());
ClientToImage(rect.BottomRight());
}
/***************************************************************************/
// Convert a point or rect in image coordinates to image view client
// coordinates taking magnification and scrolling into account.
//
void CImgWnd::ImageToClient(CPoint& point)
{
int iHandleSize = CTracker::HANDLE_SIZE;
point.x = (point.x + m_xScroll) * m_nZoom + iHandleSize;
point.y = (point.y + m_yScroll) * m_nZoom + iHandleSize;
}
/***************************************************************************/
void CImgWnd::ImageToClient(CRect& rect)
{
ImageToClient(rect.TopLeft());
ImageToClient(rect.BottomRight());
}
/***************************************************************************/
// Return a rectangle in image view coordinates surrounding the image
// taking magnification, scrolling, and the grid into account.
void CImgWnd::GetImageRect( CRect& imageRect )
{
imageRect.SetRect( 0, 0, m_pImg->cxWidth, m_pImg->cyHeight );
ImageToClient( imageRect );
if (IsGridVisible())
{
imageRect.right += 1;
imageRect.bottom += 1;
}
}
/***************************************************************************/
CRect CImgWnd::GetDrawingRect( void )
{
CRect rectImage;
CRect rectClient;
GetImageRect ( rectImage );
GetClientRect( &rectClient );
rectImage &= rectClient;
rectImage.InflateRect( CTracker::HANDLE_SIZE, CTracker::HANDLE_SIZE );
return ( rectImage );
}
/***************************************************************************/
void CImgWnd::OnSetFocus(CWnd* pOldWnd)
{
if (m_pImg == NULL)
{
// Time to die... (Our img was deleted, so we'll be disappearing
// soon. Don't bother to do any of the rest of this function...
return;
}
Invalidate();
BringWindowToTop(); // so updates happen here first
if (c_pImgWndCur != this
&& c_pImgWndCur != NULL)
c_pImgWndCur->EraseTracker();
c_pImgWndCur = this;
SelectImg( m_pImg );
UpdateWindow();
CWnd::OnSetFocus( pOldWnd );
DrawTracker();
}
/***************************************************************************/
void CImgWnd::OnKillFocus(CWnd* pNewWnd)
{
Invalidate();
if (theImgBrush.m_pImg == NULL)
HideBrush();
if (GetCapture() == this)
CmdCancel();
CWnd::OnKillFocus(pNewWnd);
}
/***************************************************************************/
void CImgWnd::OnSize(UINT nType, int cx, int cy)
{
CheckScrollBars();
CWnd::OnSize(nType, cx, cy);
}
/***************************************************************************/
BOOL CImgWnd::OnMouseDown(UINT nFlags)
{
if (GetFocus() != this)
{
SetFocus();
SetActiveWindow();
}
if ((nFlags & (MK_LBUTTON | MK_RBUTTON)) == (MK_LBUTTON | MK_RBUTTON))
{
ClearStatusBarSize();
BOOL bWasMakingSelection = theImgBrush.m_bMakingSelection;
ZoomedInDP(WM_CANCEL, 0, CPoint(0, 0));
SetCursor(LoadCursor(NULL, IDC_ARROW + 11));
if (! bWasMakingSelection)
CancelPainting();
bIgnoreMouse = TRUE;
return FALSE;
}
return TRUE;
}
/***************************************************************************/
BOOL CImgWnd::OnMouseMessage( UINT nFlags )
{
if (bIgnoreMouse /*|| GetFocus() != this*/)
{
if ((nFlags & (MK_LBUTTON | MK_RBUTTON)) == 0)
{
bIgnoreMouse = FALSE;
SetToolCursor();
}
else
{
SetCursor( LoadCursor( NULL, IDC_ARROW ) );
}
return FALSE;
}
if ((CImgTool::GetCurrentID() != IDMB_PICKTOOL)
&& (CImgTool::GetCurrentID() != IDMB_PICKRGNTOOL))
SetupRubber(m_pImg);
const MSG* pMsg = GetCurrentMessage();
mti.fCtrlDown = (nFlags & MK_CONTROL);
ZoomedInDP( pMsg->message, (DWORD)pMsg->wParam, CPoint( (DWORD)pMsg->lParam ) );
return TRUE;
}
/***************************************************************************/
void CImgWnd::OnLButtonDown( UINT nFlags, CPoint point )
{
CWnd::OnLButtonDown( nFlags, point );
if (OnMouseDown( nFlags ))
{
OnMouseMessage( nFlags );
}
}
/***************************************************************************/
void CImgWnd::OnLButtonDblClk(UINT nFlags, CPoint point)
{
CRect rect;
GetImageRect(rect);
// When inside the image, a double click is the same as a single click
OnLButtonDown(nFlags, point);
}
/***************************************************************************/
void CImgWnd::OnLButtonUp(UINT nFlags, CPoint point)
{
CWnd::OnLButtonUp(nFlags, point);
OnMouseMessage(nFlags);
}
/***************************************************************************/
void CImgWnd::OnRButtonDown(UINT nFlags, CPoint point)
{
CWnd::OnRButtonDown(nFlags, point);
if (OnMouseDown(nFlags))
{
OnMouseMessage(nFlags);
}
}
/***************************************************************************/
void CImgWnd::OnRButtonDblClk(UINT nFlags, CPoint point)
{
// A right button double click is the same as a right button single click
OnRButtonDown(nFlags, point);
}
/***************************************************************************/
void CImgWnd::OnRButtonUp(UINT nFlags, CPoint point)
{
CWnd::OnRButtonUp(nFlags, point);
OnMouseMessage(nFlags);
}
/***************************************************************************/
void CImgWnd::OnMouseMove(UINT nFlags, CPoint point)
{
CWnd::OnMouseMove(nFlags, point);
if (g_pMouseImgWnd != this
&& g_pMouseImgWnd != NULL)
{
CImgTool::GetCurrent()->OnLeave( g_pMouseImgWnd, &mti );
g_pMouseImgWnd = NULL;
}
ClientToImage( point );
m_ptDispPos = point;
if (g_pMouseImgWnd == NULL)
{
MTI mtiEnter;
mtiEnter.pt = point;
mtiEnter.ptDown = point;
mtiEnter.ptPrev = point;
mtiEnter.fLeft = FALSE;
mtiEnter.fRight = FALSE;
mtiEnter.fCtrlDown = FALSE;
CImgTool::GetCurrent()->OnEnter( g_pMouseImgWnd, &mtiEnter );
g_pMouseImgWnd = this;
}
OnMouseMessage( nFlags );
}
/***************************************************************************/
void CImgWnd::OnTimer(UINT nIDEvent)
{
OnMouseMessage( 0 );
}
/***************************************************************************/
void CImgWnd::SetToolCursor()
{
UINT nCursorID = CImgTool::GetCurrent()->GetCursorID();
HCURSOR hCursor = NULL;
if (nCursorID != 0)
{
hCursor = LoadCursor(nCursorID < 32512 ?
AfxGetResourceHandle() : NULL, MAKEINTRESOURCE( nCursorID ));
}
SetCursor(hCursor);
}
/***************************************************************************/
void CImgWnd::EndResizeOperation()
{
ReleaseCapture();
delete c_pResizeDragger;
c_pResizeDragger = NULL;
c_dragState = CTracker::nil;
ClearStatusBarSize();
}
/***************************************************************************/
void CImgWnd::ResizeMouseHandler(unsigned code, CPoint imagePt)
{
CRect imageRect = c_pResizeDragger->m_rect;
ClientToImage(imageRect);
switch (code)
{
case WM_CANCEL:
EndResizeOperation();
return;
case WM_LBUTTONUP:
// resizing whole bitmap
if (m_pImg != theImgBrush.m_pImg
&& m_pwndThumbNailView)
{
m_pwndThumbNailView->Invalidate();
}
EndResizeOperation();
if (theImgBrush.m_pImg == NULL)
{
// User was resizing the whole image...
CPBView* pView = (CPBView*)((CFrameWnd*)AfxGetMainWnd())->GetActiveView();
CPBDoc* pDoc = (pView == NULL)? NULL: pView->GetDocument();
if (pDoc != NULL)
{
theUndo.BeginUndo( TEXT("Property Edit") );
if (GetKeyState( VK_SHIFT ) < 0)
pDoc->m_pBitmapObj->SetIntProp( P_Shrink, 1 );
theApp.m_sizeBitmap = imageRect.Size();
pDoc->m_pBitmapObj->SetSizeProp( P_Size, theApp.m_sizeBitmap );
pDoc->m_pBitmapObj->SetIntProp ( P_Shrink, 0 );
theUndo.EndUndo();
}
}
else
{
// User was resizing the selection...
HideBrush();
theImgBrush.SetSize( imageRect.Size(), TRUE );
MoveBrush( imageRect );
}
return;
case WM_MOUSEMOVE:
switch (c_dragState)
{
default:
ASSERT(FALSE);
case CTracker::resizingTop:
imageRect.top = imagePt.y;
if (imageRect.top >= imageRect.bottom)
imageRect.top = imageRect.bottom - 1;
break;
case CTracker::resizingLeft:
imageRect.left = imagePt.x;
if (imageRect.left >= imageRect.right)
imageRect.left = imageRect.right - 1;
break;
case CTracker::resizingRight:
imageRect.right = imagePt.x;
if (imageRect.right <= imageRect.left)
imageRect.right = imageRect.left + 1;
break;
case CTracker::resizingBottom:
imageRect.bottom = imagePt.y;
if (imageRect.bottom <= imageRect.top)
imageRect.bottom = imageRect.top + 1;
break;
case CTracker::resizingTopLeft:
imageRect.left = imagePt.x;
imageRect.top = imagePt.y;
if (imageRect.top >= imageRect.bottom)
imageRect.top = imageRect.bottom - 1;
if (imageRect.left >= imageRect.right)
imageRect.left = imageRect.right - 1;
break;
case CTracker::resizingTopRight:
imageRect.top = imagePt.y;
imageRect.right = imagePt.x;
if (imageRect.top >= imageRect.bottom)
imageRect.top = imageRect.bottom - 1;
if (imageRect.right <= imageRect.left)
imageRect.right = imageRect.left + 1;
break;
case CTracker::resizingBottomLeft:
imageRect.left = imagePt.x;
imageRect.bottom = imagePt.y;
if (imageRect.left >= imageRect.right)
imageRect.left = imageRect.right - 1;
if (imageRect.bottom <= imageRect.top)
imageRect.bottom = imageRect.top + 1;
break;
case CTracker::resizingBottomRight:
imageRect.right = imagePt.x;
imageRect.bottom = imagePt.y;
if (imageRect.right <= imageRect.left)
imageRect.right = imageRect.left + 1;
if (imageRect.bottom <= imageRect.top)
imageRect.bottom = imageRect.top + 1;
break;
}
if (theImgBrush.m_pImg == NULL && m_pImg->m_bTileGrid)
{
// Snap to tile grid...
int cxTile = m_pImg->m_cxTile;
if (cxTile != 1 && cxTile <= m_pImg->cxWidth)
{
imageRect.right = ((imageRect.right + cxTile / 2) /
cxTile) * cxTile;
}
int cyTile = m_pImg->m_cyTile;
if (cyTile != 1 && cyTile <= m_pImg->cyHeight)
{
imageRect.bottom = ((imageRect.bottom + cyTile / 2) /
cyTile) * cyTile;
}
}
SetStatusBarSize(imageRect.Size());
ImageToClient(imageRect);
c_pResizeDragger->Move(imageRect, TRUE);
break;
}
}
/***************************************************************************/
void CImgWnd::StartSelectionDrag(unsigned code, CPoint newPt)
{
theImgBrush.CopyTo(theBackupBrush);
newPt.x /= m_nZoom;
newPt.y /= m_nZoom;
mti.pt = mti.ptDown = mti.ptPrev = newPt;
SetCapture();
SetCombineMode(theImgBrush.m_bOpaque ? combineReplace : combineMatte);
if (theImgBrush.m_bFirstDrag)
{
ASSERT(theImgBrush.m_pImg == m_pImg);
PickupSelection();
}
else
if (! theImgBrush.m_bOpaque)
theImgBrush.RecalcMask( crRight );
theImgBrush.TopLeftHandle();
theImgBrush.m_dragOffset = mti.pt - theImgBrush.m_rcSelection.TopLeft();
EraseTracker();
if (GetKeyState(VK_CONTROL) < 0)
{
// Copy the selection and start moving...
if (theImgBrush.m_bFirstDrag)
{
// The first time, the bits are already in
// the bitmap, so just copy them to the
// selection (which has already been done).
theImgBrush.m_bFirstDrag = FALSE;
theImgBrush.m_bLastDragWasFirst = TRUE;
}
else
{
CommitSelection(TRUE);
}
theImgBrush.m_bMoveSel = TRUE;
}
else
if (GetKeyState(VK_SHIFT) < 0)
{
// Start a smear operation...
HideBrush();
if (theImgBrush.m_bLastDragWasFirst)
CommitSelection(TRUE);
SetUndo(m_pImg);
theImgBrush.m_bSmearSel = TRUE;
theImgBrush.m_bFirstDrag = FALSE;
theImgBrush.m_bLastDragWasFirst = TRUE;
}
else
{
// Start a move operation...
theImgBrush.m_bMoveSel = TRUE;
}
g_bCustomBrush = TRUE;
}
/***************************************************************************/
void CImgWnd::CancelSelectionDrag()
{
if (!theImgBrush.m_bSmearSel && !theImgBrush.m_bMoveSel)
{
TRACE(TEXT("Extraneous CancelSelectionDrag!\n"));
return;
}
ReleaseCapture();
theImgBrush.m_rcSelection = theImgBrush.m_rcDraggedFrom;
theImgBrush.m_bMoveSel = theImgBrush.m_bSmearSel = FALSE;
g_bCustomBrush = FALSE;
SetCombineMode(combineColor);
theBackupBrush.CopyTo(theImgBrush);
rcDragBrush = theImgBrush.m_rcSelection;
rcDragBrush.right += 1;
rcDragBrush.bottom += 1;
CancelPainting();
InvalImgRect(theImgBrush.m_pImg, NULL); // draw selection tracker
// "Opaque" mode may have changed...
if ((CImgTool::GetCurrentID() == IDMB_PICKTOOL)
|| (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL))
g_pImgToolWnd->InvalidateOptions(FALSE);
// Cancel all the way now...
theImgBrush.m_pImg = NULL;
}
/***************************************************************************/
void CImgWnd::SelectionDragHandler(unsigned code, CPoint newPt)
{
switch (code)
{
case WM_CANCEL:
CancelSelectionDrag();
break;
case WM_MOUSEMOVE:
if (theImgBrush.m_bMoveSel)
PrepareForBrushChange(FALSE);
mti.ptPrev = mti.pt;
mti.pt = newPt;
theImgBrush.m_rcSelection.OffsetRect(
-theImgBrush.m_rcSelection.TopLeft()
+ (CSize)mti.pt - theImgBrush.m_dragOffset);
// Make sure the selection stays at least along the edge
// of the actual image so we don't lose the tracker...
if (theImgBrush.m_rcSelection.left > m_pImg->cxWidth)
theImgBrush.m_rcSelection.OffsetRect(-theImgBrush.m_rcSelection.left + m_pImg->cxWidth, 0);
if (theImgBrush.m_rcSelection.top > m_pImg->cyHeight)
theImgBrush.m_rcSelection.OffsetRect(0, -theImgBrush.m_rcSelection.top + m_pImg->cyHeight);
if (theImgBrush.m_rcSelection.right < 0)
theImgBrush.m_rcSelection.OffsetRect(-theImgBrush.m_rcSelection.right, 0);
if (theImgBrush.m_rcSelection.bottom < 0)
theImgBrush.m_rcSelection.OffsetRect(0, -theImgBrush.m_rcSelection.bottom);
if (theImgBrush.m_bSmearSel)
DrawBrush(m_pImg, theImgBrush.m_rcSelection.TopLeft(), TRUE);
else
ShowBrush(theImgBrush.m_rcSelection.TopLeft());
break;
case WM_LBUTTONUP:
theImgBrush.m_bLastDragWasASmear = theImgBrush.m_bSmearSel;
if (theImgBrush.m_bSmearSel)
{
IMG* pImg = m_pImg;
CommitSelection(FALSE);
FinishUndo(CRect(0, 0, pImg->cxWidth, pImg->cyHeight));
}
ReleaseCapture();
theImgBrush.m_bMoveSel = theImgBrush.m_bSmearSel = FALSE;
g_bCustomBrush = FALSE;
SetCombineMode(combineColor);
InvalImgRect(theImgBrush.m_pImg, NULL); // draw selection tracker
break;
}
}
/******************************************************************************/
BOOL CImgWnd::PtInTracker( CPoint cptLocation )
{
CRect selRect = theImgBrush.m_rcSelection;
BOOL bPtInTracker = FALSE;
selRect.left *= m_nZoom;
selRect.top *= m_nZoom;
selRect.right *= m_nZoom;
selRect.bottom *= m_nZoom;
selRect.InflateRect( CTracker::HANDLE_SIZE, CTracker::HANDLE_SIZE );
bPtInTracker = selRect.PtInRect( cptLocation );
return bPtInTracker;
}
/******************************************************************************/
void CImgWnd::OnRButtonDownInSel(CPoint *pcPointDown)
{
CMenu cMenuPopup;
BOOL bRC = cMenuPopup.LoadMenu(IDR_SELECTION_POPUP);
ASSERT(bRC);
if (bRC)
{
CMenu *pcContextMenu = cMenuPopup.GetSubMenu(0);
ASSERT(pcContextMenu != NULL);
if (pcContextMenu != NULL)
{
CPoint cPointDown = *pcPointDown;
ImageToClient(cPointDown);
ClientToScreen(&cPointDown);
CRect cRectClient;
GetClientRect(&cRectClient);
ClientToScreen(&cRectClient);
// the frame actually has a clue about what items to enable...
CWnd *notify = GetParentFrame();
if (!notify)
notify = GetParent(); // oh well...
pcContextMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
cPointDown.x, cPointDown.y, notify, &cRectClient);
}
}
}
/***************************************************************************/
void CImgWnd::ZoomedInDP(unsigned code, unsigned mouseKeys, CPoint newPt)
{
CPoint clientPt = newPt;
CPoint imagePt = clientPt;
ClientToImage( imagePt );
if (c_pResizeDragger != NULL)
{
ResizeMouseHandler( code, imagePt );
return;
}
int iHandleSize = CTracker::HANDLE_SIZE;
newPt.x -= iHandleSize + m_xScroll * m_nZoom;
newPt.y -= iHandleSize + m_yScroll * m_nZoom;
// AdjustPointForGrid(&newPt);
IMG* pImg = m_pImg;
int cxImage = pImg->cxWidth;
int cyImage = pImg->cyHeight;
CRect imageRect;
GetImageRect( imageRect );
// Check for selection manipulations...
if (GetCapture() != this
&& c_pImgWndCur == this
&& theImgBrush.m_pImg == m_pImg)
{
CRect selRect = theImgBrush.m_rcSelection;
BOOL bPtInTracker = FALSE;
selRect.left *= m_nZoom;
selRect.top *= m_nZoom;
selRect.right *= m_nZoom;
selRect.bottom *= m_nZoom;
selRect.InflateRect( CTracker::HANDLE_SIZE, CTracker::HANDLE_SIZE );
bPtInTracker = PtInTracker(newPt);
if (bPtInTracker)
{
// Mouse is within the outer border of the tracker...
// We don't set the rubber for every mouse message when the
// selection tool is active, but we'd better set it up now!
if (pRubberImg != m_pImg)
SetupRubber(m_pImg);
ClearStatusBarPosition();
CTracker::STATE state;
selRect.InflateRect( -CTracker::HANDLE_SIZE,
-CTracker::HANDLE_SIZE );
state = CTracker::HitTest(selRect, newPt, CTracker::nil);
if (bPtInTracker && state == CTracker::nil)
{
// Actually inside the selection...
SetCursor(theApp.LoadCursor(IDCUR_MOVE));
if (code == WM_LBUTTONDOWN || code == WM_LBUTTONDBLCLK)
{
StartSelectionDrag(code, newPt);
}
else
{
if (code == WM_RBUTTONDOWN || code == WM_RBUTTONDBLCLK)
// some of the menu commands don't work for free form selections
OnRButtonDownInSel( &imagePt );
}
}
else
{
// In the tracker frame...
SetCursor(HCursorFromTrackerState(state));
if (code == WM_LBUTTONDOWN || code == WM_LBUTTONDBLCLK)
{
// Start a resize operation...
SetCapture();
PrepareForBrushChange();
ASSERT(c_pResizeDragger == NULL);
CRect rect = theImgBrush.m_rcSelection;
ImageToClient(rect);
c_pResizeDragger = new CDragger(this, &rect);
ASSERT(c_pResizeDragger != NULL);
c_dragState = state;
}
}
return;
}
}
if (! imageRect.PtInRect( clientPt )
&& code != WM_CANCEL
&& GetCapture() == NULL)
{
// The mouse is not inside the image and we're not in any
// special mode, so hide the brush...
if (g_pDragBrushWnd == this
&& theImgBrush.m_pImg == NULL)
HideBrush();
CRect selRect = imageRect;
selRect.InflateRect( CTracker::HANDLE_SIZE, CTracker::HANDLE_SIZE );
if (theImgBrush.m_pImg != NULL || ! selRect.PtInRect( clientPt ))
{
// The mouse is not in the whole image tracker
if (WM_LBUTTONDOWN == code)
{
if (CImgTool::GetCurrentID() != IDMX_TEXTTOOL)
{
CmdCancel ();
}
}
else
{
SetCursor( LoadCursor(NULL, IDC_ARROW ));
}
return;
}
// The mouse is in the whole image tracker, so set the cursor
// as appropriate
CTracker::STATE state = CTracker::nil;
if (c_pImgWndCur == this)
state = CTracker::HitTest(imageRect, clientPt, CTracker::nil);
switch (state)
{
case CTracker::resizingTop:
case CTracker::resizingLeft:
case CTracker::resizingTopLeft:
case CTracker::resizingTopRight:
case CTracker::resizingBottomLeft:
state = CTracker::nil;
break;
}
SetCursor( HCursorFromTrackerState( state ) );
// Handle mouse messages for tracker...
if (state != CTracker::nil
&& (code == WM_LBUTTONDOWN || code == WM_LBUTTONDBLCLK))
{
SetCapture();
ASSERT( c_pResizeDragger == NULL );
c_pResizeDragger = new CDragger( this, &imageRect );
ASSERT( c_pResizeDragger != NULL );
c_dragState = state;
}
return;
}
newPt.x /= m_nZoom;
newPt.y /= m_nZoom;
if (! CImgTool::IsDragging())
SetStatusBarPosition( m_ptDispPos );
// Moving the selection??
if (theImgBrush.m_bMoveSel
|| theImgBrush.m_bSmearSel)
{
SelectionDragHandler( code, newPt );
return;
}
AdjustPointForGrid( &newPt );
// Dispatch the event off to the current tool...
CImgTool* pImgTool = CImgTool::GetCurrent();
switch (code)
{
case WM_CANCEL:
ReleaseCapture();
pImgTool->OnCancel(this);
mti.fLeft = mti.fRight = FALSE;
break;
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
// We don't set the rubber for every mouse message when the
// selection tool is active, but we'd better set it up now!
if (pRubberImg != m_pImg)
SetupRubber( m_pImg );
mti.fLeft = (code == WM_LBUTTONDOWN || code == WM_LBUTTONDBLCLK);
mti.fRight = (code == WM_RBUTTONDOWN || code == WM_RBUTTONDBLCLK);
mti.pt = mti.ptDown = mti.ptPrev = newPt;
// if in the polygon tool, double clicks will end operation
if (CImgTool::GetCurrentID() == IDMB_POLYGONTOOL
&& ((code == WM_LBUTTONDBLCLK) || (code == WM_RBUTTONDBLCLK)))
{
mti.ptPrev = mti.pt;
mti.pt = newPt;
pImgTool->EndMultiptOperation(); // end the multipt operation
pImgTool->OnEndDrag( this, &mti );
mti.fLeft = FALSE;
mti.fRight = FALSE;
break;
}
SetCapture();
if (CImgTool::GetCurrentID() != IDMB_PICKRGNTOOL)
HideBrush();
if (pImgTool->IsUndoable())
SetUndo(m_pImg);
pImgTool->OnStartDrag( this, &mti );
break;
case WM_LBUTTONUP:
case WM_RBUTTONUP:
mti.ptPrev = mti.pt;
mti.pt = newPt;
if (GetCapture() != this)
break;
ReleaseCapture();
pImgTool->CanEndMultiptOperation( &mti );
pImgTool->OnEndDrag( this, &mti );
if (code == WM_LBUTTONUP)
{
mti.fLeft = FALSE;
}
if (code == WM_RBUTTONUP)
{
mti.fRight = FALSE;
}
break;
case WM_MOUSEMOVE:
mti.ptPrev = mti.pt;
mti.pt = newPt;
if (mti.fLeft || mti.fRight)
pImgTool->OnDrag(this, &mti);
else
pImgTool->OnMove(this, &mti);
break;
case WM_TIMER:
pImgTool->OnTimer( this, &mti );
break;
}
UpdateWindow(); // For immediate feedback in active window
SetToolCursor();
}
/***************************************************************************/
void CImgWnd::FinishUndo(const CRect& rectUndo)
{
if ( EnsureUndoSize(m_pImg) )
m_pImg->m_pBitmapObj->FinishUndo(&rectUndo);
else
{
TRACE(TEXT("Problem: Can NOT ensure undo capability!\n"));
MessageBeep(0);
}
}
/***************************************************************************/
void CImgWnd::CancelPainting()
{
if (g_hUndoImgBitmap == NULL)
return; // nothing to cancel!
IMG* pimg;
HDC hTempDC;
HBITMAP hOldBM;
HPALETTE hOldPalette = NULL;
pimg = m_pImg;
if ((hTempDC = CreateCompatibleDC( pimg->hDC )) == NULL)
{
TRACE(TEXT("Not enough memory to undo!\n"));
MessageBeep(0);
return;
}
HideBrush();
if (g_hUndoPalette)
{
if (pimg->m_hPalOld)
{
::SelectPalette( pimg->hDC, pimg->m_hPalOld, FALSE );
pimg->m_hPalOld = NULL;
}
if (pimg->m_pPalette)
pimg->m_pPalette->DeleteObject();
pimg->m_pPalette->Attach( g_hUndoPalette );
g_hUndoPalette = NULL;
pimg->m_hPalOld = ::SelectPalette( pimg->hDC,
(HPALETTE)pimg->m_pPalette->GetSafeHandle(), FALSE );
::RealizePalette( pimg->hDC );
}
hOldBM = (HBITMAP)SelectObject( hTempDC, g_hUndoImgBitmap );
if (pimg->m_pPalette)
{
hOldPalette = ::SelectPalette( hTempDC,
(HPALETTE)pimg->m_pPalette->GetSafeHandle(), FALSE );
::RealizePalette( hTempDC );
}
ASSERT( hOldBM != NULL );
BitBlt( pimg->hDC, 0, 0, pimg->cxWidth, pimg->cyHeight, hTempDC, 0, 0, SRCCOPY );
if (hOldPalette != NULL)
::SelectPalette( hTempDC, hOldPalette, FALSE );
SelectObject( hTempDC, hOldBM );
DeleteDC ( hTempDC );
InvalImgRect ( m_pImg, NULL );
CommitImgRect( m_pImg, NULL );
}
#ifdef GRIDOPTIONS
/***************************************************************************/
void CImgWnd::CmdGridOptions()
{
CImgGridDlg dlg;
dlg.m_bPixelGrid = theApp.m_bShowGrid;
dlg.m_bTileGrid = m_pImg->m_bTileGrid;
dlg.m_nWidth = m_pImg->m_cxTile;
dlg.m_nHeight = m_pImg->m_cyTile;
if (dlg.DoModal() != IDOK)
return;
// Hide the current is dependant on the state of the grid...
BOOL bOldShowGrid = theApp.m_bShowGrid;
theApp.m_bShowGrid = dlg.m_bPixelGrid;
m_pImg->m_bTileGrid = dlg.m_bTileGrid;
m_pImg->m_cxTile = dlg.m_nWidth;
m_pImg->m_cyTile = dlg.m_nHeight;
InvalImgRect(m_pImg, NULL);
if (bOldShowGrid != theApp.m_bShowGrid)
{
if (c_pImgWndCur != NULL)
c_pImgWndCur->Invalidate(FALSE); // Redraw tracker
}
}
#endif // GRIDOPTIONS
/***************************************************************************/
void CImgWnd::CmdShowGrid()
{
// Hide the current cross hair since the width of the lines
// is dependant on the state of the grid...
theApp.m_bShowGrid = ! theApp.m_bShowGrid;
InvalImgRect(m_pImg, NULL);
if (c_pImgWndCur != NULL)
c_pImgWndCur->Invalidate(FALSE); // Redraw tracker
}
/***************************************************************************/
// Draw a grid over the image already in the bitmap in pDC. Drawing
// is optimized by restricting it to destRect.
//
void CImgWnd::DrawGrid(CDC* pDC, const CRect& srcRect, CRect& destRect)
{
ASSERT(pDC != NULL);
ASSERT(m_pImg != NULL);
pDC->SetTextColor(RGB(192, 192, 192));
pDC->SetBkColor(RGB(128, 128, 128));
CBrush* pOldBrush = pDC->SelectObject(GetHalftoneBrush());
CRect gridRect(0, 0, m_pImg->cxWidth * m_nZoom + 1,
m_pImg->cyHeight * m_nZoom + 1);
for (int x = gridRect.left; x <= gridRect.right; x += m_nZoom)
pDC->PatBlt(x, gridRect.top, 1, gridRect.Height(), PATCOPY);
for (int y = gridRect.top; y <= gridRect.bottom; y += m_nZoom)
pDC->PatBlt(gridRect.left, y, gridRect.Width(), 1, PATCOPY);
if (m_pImg->m_bTileGrid)
{
pDC->SetTextColor(RGB(0, 0, 255));
pDC->SetBkColor(RGB(0, 0, 128));
int nWidth = destRect.Width();
int nHeight = destRect.Height();
int nStep;
if (m_pImg->m_cxTile > 1 && m_pImg->m_cxTile <= m_pImg->cxWidth)
{
nStep = m_nZoom * m_pImg->m_cxTile;
for (x = (m_pImg->m_cxTile - srcRect.left % m_pImg->m_cxTile -
m_pImg->m_cxTile) * m_nZoom; x <= nWidth; x += nStep)
{
pDC->PatBlt(x, 0, 1, nHeight, PATCOPY);
}
}
if (m_pImg->m_cyTile > 1 && m_pImg->m_cyTile <= m_pImg->cyHeight)
{
nStep = m_nZoom * m_pImg->m_cyTile;
for (y = (m_pImg->m_cyTile - srcRect.top % m_pImg->m_cyTile -
m_pImg->m_cyTile) * m_nZoom; y <= nHeight; y += nStep)
{
pDC->PatBlt(0, y, nWidth, 1, PATCOPY);
}
}
}
pDC->SelectObject(pOldBrush);
destRect.right += 1;
destRect.bottom += 1;
}
#ifdef GRIDOPTIONS
/***************************************************************************/
void CImgWnd::CmdShowTileGrid()
{
extern BOOL g_bDefaultTileGrid;
// If neither grid is visible, show both. Otherwise leave the pixel
// grid alone and toggle the tile grid.
if (! theApp.m_bShowGrid)
{
m_pImg->m_bTileGrid = TRUE;
theApp.m_bShowGrid = TRUE;
}
else
{
m_pImg->m_bTileGrid = !m_pImg->m_bTileGrid;
}
g_bDefaultTileGrid = m_pImg->m_bTileGrid;
InvalImgRect(m_pImg, NULL);
if (c_pImgWndCur != NULL)
c_pImgWndCur->Invalidate(FALSE); // Redraw tracker
}
#endif // GRIDOPTIONS
/***************************************************************************/
void CImgWnd::MoveBrush( const CRect& newSelRect )
{
if (! theImgBrush.m_pImg)
return;
theImgBrush.m_rcSelection = newSelRect;
InvalImgRect( theImgBrush.m_pImg, NULL );
theImgBrush.m_handle.cx = theImgBrush.m_handle.cy = 0;
BOOL bOldCustomBrush = g_bCustomBrush;
g_bCustomBrush = TRUE;
int wOldCombineMode = wCombineMode;
SetCombineMode( theImgBrush.m_bOpaque ? combineReplace : combineMatte );
ShowBrush( theImgBrush.m_rcSelection.TopLeft() );
g_bCustomBrush = bOldCustomBrush;
SetCombineMode( wOldCombineMode );
}
/***************************************************************************/
BOOL CImgWnd::MakeBrush( HDC hSourceDC, CRect rcSource )
{
int cxWidth;
int cyHeight;
int iToolID = CImgTool::GetCurrentID();
if (rcSource.IsRectEmpty())
{
ASSERT( FALSE );
return FALSE;
}
theImgBrush.m_size = rcSource.Size();
cxWidth = theImgBrush.m_size.cx;
cyHeight = theImgBrush.m_size.cy;
if (theImgBrush.m_hbmOld)
::SelectObject( theImgBrush.m_dc.m_hDC, theImgBrush.m_hbmOld );
if (theImgBrush.m_hbmMaskOld)
::SelectObject( theImgBrush.m_dc.m_hDC, theImgBrush.m_hbmMaskOld );
theImgBrush.m_hbmOld = NULL;
theImgBrush.m_hbmMaskOld = NULL;
theImgBrush.m_dc.DeleteDC();
theImgBrush.m_bitmap.DeleteObject();
theImgBrush.m_maskDC.DeleteDC();
theImgBrush.m_maskBitmap.DeleteObject();
CDC* pdcSource = CDC::FromHandle( hSourceDC );
CDC* pdcBitmap = CDC::FromHandle( m_pImg->hDC );
if (! theImgBrush.m_bitmap.CreateCompatibleBitmap( pdcBitmap, cxWidth, cyHeight )
|| ! theImgBrush.m_dc.CreateCompatibleDC ( pdcBitmap )
|| ! theImgBrush.m_maskBitmap.CreateBitmap ( cxWidth, cyHeight, 1, 1, NULL)
|| ! theImgBrush.m_maskDC.CreateCompatibleDC ( pdcBitmap ))
{
theApp.SetGdiEmergency();
return FALSE;
}
theImgBrush.m_pImg = m_pImg;
theImgBrush.m_hbmOld = (HBITMAP)((theImgBrush.m_dc.SelectObject(
&theImgBrush.m_bitmap ))->GetSafeHandle());
theImgBrush.m_hbmMaskOld = (HBITMAP)((theImgBrush.m_maskDC.SelectObject(
&theImgBrush.m_maskBitmap ))->GetSafeHandle());
CPalette* pcOldPalette = SetImgPalette( &theImgBrush.m_dc, FALSE );
if (iToolID == IDMB_PICKRGNTOOL)
{
// Using StretchBlt to ensure palette mapping occurs
TRY {
CBrush cBrushWhite( PALETTERGB( 0xff, 0xff, 0xff ) );
CRect cRectTmp( 0, 0, cxWidth, cyHeight );
theImgBrush.m_dc.FillRect( &cRectTmp, &cBrushWhite );
}
CATCH(CResourceException, e)
{
theApp.SetGdiEmergency();
return FALSE;
}
END_CATCH
if (theImgBrush.m_cRgnPolyFreeHandSel.GetSafeHandle())
theImgBrush.m_dc.FillRgn( &theImgBrush.m_cRgnPolyFreeHandSel,
CBrush::FromHandle( (HBRUSH)::GetStockObject( BLACK_BRUSH ) ) );
theImgBrush.m_dc.StretchBlt( 0, 0, cxWidth, cyHeight,
pdcSource,
rcSource.left, rcSource.top,
cxWidth, cyHeight, SRCERASE);
}
else
{
// Using StretchBlt to ensure palette mapping occurs
theImgBrush.m_dc.StretchBlt( 0, 0, cxWidth, cyHeight,
pdcSource,
rcSource.left, rcSource.top,
cxWidth, cyHeight, SRCCOPY );
}
theImgBrush.RecalcMask( crRight );
if (pcOldPalette)
theImgBrush.m_dc.SelectPalette( pcOldPalette, FALSE );
theImgBrush.m_rcSelection = rcSource;
rcSource.right += 1;
rcSource.bottom += 1;
InvalImgRect( m_pImg, NULL ); // Redraw selection tracker
rcDragBrush = rcSource;
g_bBrushVisible = TRUE;
g_pDragBrushWnd = this;
theImgBrush.m_bFirstDrag = TRUE;
theImgBrush.m_bLastDragWasFirst = FALSE;
return TRUE;
}
/***************************************************************************/
void CImgWnd::CmdClear()
{
if (TextToolProcessed( ID_EDIT_CLEAR ))
return;
HPALETTE hOldPalette = NULL;
HBRUSH hNewBrush, hOldBrush;
IMG* pImg = m_pImg;
if ((hNewBrush = CreateSolidBrush( crRight )) == NULL)
{
theApp.SetGdiEmergency();
return;
}
HideBrush();
CRect clearRect;
if (theImgBrush.m_pImg == NULL)
clearRect.SetRect(0, 0, pImg->cxWidth, pImg->cyHeight);
else
{
clearRect = rcDragBrush;
clearRect.right -= 1;
clearRect.bottom -= 1;
}
BOOL bUndo = FALSE;
if (!theImgBrush.m_pImg || theImgBrush.m_bFirstDrag
|| theImgBrush.m_bCuttingFromImage)
{
bUndo = TRUE;
SetUndo(m_pImg);
if (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL)
{
int iPoints;
CPoint* pptArray;
BOOL bData = ((CFreehandSelectTool*)CImgTool::GetCurrent())->CopyPointsToMemArray( &pptArray, &iPoints );
if (bData && iPoints)
{
HRGN hrgn = ::CreatePolygonRgn( pptArray, iPoints, ALTERNATE );
if (hrgn)
::FillRgn( pImg->hDC, hrgn, hNewBrush );
delete [] pptArray;
}
else
{
DeleteObject ( hNewBrush );
theApp.SetMemoryEmergency();
return;
}
}
else
{
hOldBrush = (HBRUSH)SelectObject(pImg->hDC, hNewBrush);
PatBlt( pImg->hDC, clearRect.left,
clearRect.top,
clearRect.Width(),
clearRect.Height(), PATCOPY );
SelectObject( pImg->hDC, hOldBrush );
}
}
InvalImgRect ( m_pImg, &clearRect );
CommitImgRect( m_pImg, &clearRect );
if (bUndo)
FinishUndo(clearRect);
DirtyImg ( m_pImg );
DeleteObject ( hNewBrush );
// If we have a selection, nuke it since it's useless now...
if (theImgBrush.m_pImg != NULL)
{
if (theImgBrush.m_bLastDragWasFirst)
{
theImgBrush.m_bLastDragWasFirst = FALSE;
FinishUndo(theImgBrush.m_rcDraggedFrom);
}
theImgBrush.m_handle.cx = 0;
theImgBrush.m_handle.cy = 0;
theImgBrush.m_bMoveSel = theImgBrush.m_bSmearSel = FALSE;
g_bCustomBrush = FALSE;
SetCombineMode(combineColor);
InvalImgRect(theImgBrush.m_pImg, NULL); // redraw selection
theImgBrush.m_pImg = NULL;
}
}
/***************************************************************************/
void CImgWnd::CmdFlipBshH()
{
IMG* pImg = m_pImg;
HideBrush();
CRect flipRect;
if (theImgBrush.m_pImg == NULL && !g_bCustomBrush)
{
flipRect.SetRect(0, 0, pImg->cxWidth, pImg->cyHeight);
}
else
{
flipRect = rcDragBrush;
flipRect.right -= 1;
flipRect.bottom -= 1;
}
if ( theImgBrush.m_pImg != NULL
&& ! theImgBrush.m_bFirstDrag || g_bCustomBrush)
{
CPalette* ppal = SetImgPalette( &theImgBrush.m_dc, FALSE );
//
// Don't do halftone blts when just moving bits around
//
theImgBrush.m_dc.SetStretchBltMode (COLORONCOLOR);
StretchCopy(theImgBrush.m_dc.m_hDC, 0, 0,
theImgBrush.m_size.cx,
theImgBrush.m_size.cy,
theImgBrush.m_dc.m_hDC,
theImgBrush.m_size.cx - 1, 0,
-theImgBrush.m_size.cx,
theImgBrush.m_size.cy);
StretchCopy(theImgBrush.m_maskDC.m_hDC, 0, 0,
theImgBrush.m_size.cx,
theImgBrush.m_size.cy,
theImgBrush.m_maskDC.m_hDC,
theImgBrush.m_size.cx - 1, 0,
-theImgBrush.m_size.cx,
theImgBrush.m_size.cy);
if (ppal)
theImgBrush.m_dc.SelectPalette( ppal, FALSE ); // Background ??
MoveBrush(theImgBrush.m_rcSelection);
}
else
{
SetUndo(m_pImg);
SetStretchBltMode (pImg->hDC, COLORONCOLOR);
StretchCopy(pImg->hDC, flipRect.left,
flipRect.top,
flipRect.Width(),
flipRect.Height(),
pImg->hDC, flipRect.left + flipRect.Width() - 1,
flipRect.top,
-flipRect.Width(),
flipRect.Height());
InvalImgRect (m_pImg, &flipRect);
CommitImgRect(m_pImg, &flipRect);
FinishUndo (flipRect);
DirtyImg (m_pImg);
}
}
/***************************************************************************/
void CImgWnd::CmdFlipBshV()
{
IMG* pImg = m_pImg;
HideBrush();
CRect flipRect;
if (theImgBrush.m_pImg == NULL && !g_bCustomBrush)
{
flipRect.SetRect(0, 0, pImg->cxWidth, pImg->cyHeight);
}
else
{
flipRect = rcDragBrush;
flipRect.right -= 1;
flipRect.bottom -= 1;
}
if ( theImgBrush.m_pImg != NULL
&& ! theImgBrush.m_bFirstDrag || g_bCustomBrush)
{
CPalette* ppal = SetImgPalette( &theImgBrush.m_dc, FALSE ); // Background ??
theImgBrush.m_dc.SetStretchBltMode (COLORONCOLOR);
StretchCopy(theImgBrush.m_dc.m_hDC, 0, 0,
theImgBrush.m_size.cx,
theImgBrush.m_size.cy,
theImgBrush.m_dc.m_hDC, 0,
theImgBrush.m_size.cy - 1,
theImgBrush.m_size.cx,
-theImgBrush.m_size.cy);
StretchCopy(theImgBrush.m_maskDC.m_hDC, 0, 0,
theImgBrush.m_size.cx,
theImgBrush.m_size.cy,
theImgBrush.m_maskDC.m_hDC, 0,
theImgBrush.m_size.cy - 1,
theImgBrush.m_size.cx,
-theImgBrush.m_size.cy);
if (ppal)
theImgBrush.m_dc.SelectPalette( ppal, FALSE ); // Background ??
MoveBrush(theImgBrush.m_rcSelection);
}
else
{
SetUndo(m_pImg);
SetStretchBltMode (pImg->hDC, COLORONCOLOR);
StretchCopy(pImg->hDC, flipRect.left, flipRect.top,
flipRect.Width(), flipRect.Height(),
pImg->hDC, flipRect.left, flipRect.top + flipRect.Height() - 1,
flipRect.Width(), -flipRect.Height());
InvalImgRect (m_pImg, &flipRect);
CommitImgRect(m_pImg, &flipRect);
FinishUndo (flipRect);
DirtyImg (m_pImg);
}
}
/***************************************************************************/
void CImgWnd::CmdDoubleBsh()
{
if (!g_bCustomBrush && theImgBrush.m_pImg == NULL)
{
MessageBeep(0);
return;
}
PrepareForBrushChange(TRUE, FALSE);
CRect rc = theImgBrush.m_rcSelection;
rc.left -= theImgBrush.m_size.cx / 2;
rc.right = rc.left + theImgBrush.m_size.cx * 2;
rc.top -= theImgBrush.m_size.cy / 2;
rc.bottom = rc.top + theImgBrush.m_size.cy * 2;
HideBrush();
theImgBrush.SetSize( CSize( theImgBrush.m_size.cx * 2,
theImgBrush.m_size.cy * 2 ) );
MoveBrush(rc);
if (g_bCustomBrush)
theImgBrush.CenterHandle();
}
/***************************************************************************/
void CImgWnd::CmdHalfBsh()
{
if (! g_bCustomBrush
&& ! theImgBrush.m_pImg)
{
MessageBeep(0);
return;
}
PrepareForBrushChange( TRUE, FALSE );
CRect rc = theImgBrush.m_rcSelection;
rc.left += theImgBrush.m_size.cx / 4;
rc.right = rc.left + (theImgBrush.m_size.cx + 1) / 2;
rc.top += theImgBrush.m_size.cy / 4;
rc.bottom = rc.top + (theImgBrush.m_size.cy + 1) / 2;
HideBrush();
theImgBrush.SetSize( CSize( (theImgBrush.m_size.cx + 1) / 2,
(theImgBrush.m_size.cy + 1) / 2 ) );
MoveBrush( rc );
if (g_bCustomBrush)
theImgBrush.CenterHandle();
}
/***************************************************************************/
CPalette* CImgWnd::FixupDibPalette( LPSTR lpDib, CPalette* ppalDib )
{
CPBView* pView = (CPBView*)GetParent();
CPBDoc* pDoc = pView->GetDocument();
if (pDoc == NULL || lpDib == NULL || ppalDib == NULL || pDoc->m_pBitmapObj->m_pImg == NULL)
return ppalDib;
IMG* pImg = pDoc->m_pBitmapObj->m_pImg;
int iColorBits = pImg->cBitCount * pImg->cPlanes;
BOOL bFixupDib = TRUE;
BOOL bSwapPalette = TRUE;
// only if dealing with palettes
if (iColorBits != 8)
return ppalDib;
CPalette* ppalPic = theApp.m_pPalette;
CPalette* ppalNew = NULL;
BOOL bMergedPalette = FALSE;
if (ppalPic)
{
int iAdds;
if ( ppalNew = MergePalettes( ppalPic, ppalDib, iAdds ) )
bMergedPalette = TRUE;
if (ppalNew)
{
if (! iAdds)
{
bSwapPalette = FALSE;
if ( bMergedPalette )
{
delete ppalNew;
ppalNew = FALSE;
bMergedPalette = FALSE;
}
ppalNew = ppalPic;
}
}
else
{
bSwapPalette = FALSE;
if ( bMergedPalette )
{
delete ppalNew;
ppalNew = FALSE;
bMergedPalette = FALSE;
}
ppalNew = ppalPic;
}
}
else
{
if ( bMergedPalette )
{
delete ppalNew;
ppalNew = FALSE;
bMergedPalette = FALSE;
}
ppalNew = ppalDib;
bFixupDib = FALSE;
}
if (bFixupDib)
{
LOGPALETTE256 palette;
COLORREF crCurColor;
UINT uColorIndex;
int iDibColors = DIBNumColors( lpDib );
BOOL bWinStyleDIB = IS_WIN30_DIB( lpDib );
LPBITMAPINFO lpDibInfo = (LPBITMAPINFO)lpDib;
LPBITMAPCOREINFO lpCoreInfo = (LPBITMAPCOREINFO)lpDib;
palette.palVersion = 0x300;
palette.palNumEntries = (WORD)ppalNew->GetPaletteEntries( 0, 256,
&palette.palPalEntry[0] );
ppalNew->GetPaletteEntries( 0, palette.palNumEntries,
&palette.palPalEntry[0] );
for (int iLoop = 0; iLoop < iDibColors; iLoop++)
{
if (bWinStyleDIB)
{
crCurColor = PALETTERGB( lpDibInfo->bmiColors[iLoop].rgbRed,
lpDibInfo->bmiColors[iLoop].rgbGreen,
lpDibInfo->bmiColors[iLoop].rgbBlue );
}
else
{
crCurColor = PALETTERGB( lpCoreInfo->bmciColors[iLoop].rgbtRed,
lpCoreInfo->bmciColors[iLoop].rgbtGreen,
lpCoreInfo->bmciColors[iLoop].rgbtBlue );
}
uColorIndex = ppalNew->GetNearestPaletteIndex( crCurColor );
if (bWinStyleDIB)
{
lpDibInfo->bmiColors[iLoop].rgbRed = palette.palPalEntry[uColorIndex].peRed;
lpDibInfo->bmiColors[iLoop].rgbGreen = palette.palPalEntry[uColorIndex].peGreen;
lpDibInfo->bmiColors[iLoop].rgbBlue = palette.palPalEntry[uColorIndex].peBlue;
}
else
{
lpCoreInfo->bmciColors[iLoop].rgbtRed = palette.palPalEntry[uColorIndex].peRed;
lpCoreInfo->bmciColors[iLoop].rgbtGreen = palette.palPalEntry[uColorIndex].peGreen;
lpCoreInfo->bmciColors[iLoop].rgbtBlue = palette.palPalEntry[uColorIndex].peBlue;
}
}
if (! bSwapPalette)
{
if ( bMergedPalette )
{
delete ppalNew;
bMergedPalette = FALSE;
}
ppalNew = NULL;
}
}
if (bSwapPalette)
{
if (pImg->m_hPalOld)
{
::SelectPalette( pImg->hDC, pImg->m_hPalOld, FALSE );
pImg->m_hPalOld = NULL;
}
if (pImg->m_pPalette)
delete pImg->m_pPalette;
pImg->m_pPalette = ppalNew;
pImg->m_hPalOld = ::SelectPalette( pImg->hDC,
(HPALETTE)ppalNew->GetSafeHandle(), FALSE );
::RealizePalette( pImg->hDC );
InvalImgRect( pImg, NULL );
// Return NULL since we swapped the new palette into the pImg!
ppalNew = NULL;
theApp.m_pPalette = pImg->m_pPalette;
//
// now that we changed the app palette update the DIB Section
// color table too.
//
DWORD rgb[256];
int i,n;
n = theApp.m_pPalette->GetPaletteEntries(0, 256, (LPPALETTEENTRY)rgb);
for (i=0; i<n; i++)
rgb[i] = RGB(GetBValue(rgb[i]),GetGValue(rgb[i]),GetRValue(rgb[i]));
SetDIBColorTable(pImg->hDC, 0, n, (LPRGBQUAD)rgb);
}
// Delete any orphaned ppalDib pointers.
if ( ppalDib && ppalDib != ppalNew )
delete ppalDib;
return ppalNew;
}
/***************************************************************************/
void CImgWnd::ShowBrush(CPoint ptHandle)
{
IMG * pimg = m_pImg;
HideBrush();
COLORREF crRealLeftColor;
COLORREF crRealRightColor;
int nStrokeWidth = CImgTool::GetCurrent()->GetStrokeWidth();
int nStrokeShape = CImgTool::GetCurrent()->GetStrokeShape();
if (CImgTool::GetCurrentID() == IDMB_ERASERTOOL)
{
crRealRightColor = crRight;
crRealLeftColor = crLeft;
crLeft = crRight;
}
g_pDragBrushWnd = this;
if (g_bCustomBrush)
{
int nCombineMode = (theImgBrush.m_bOpaque) ? combineReplace : combineMatte;
rcDragBrush.SetRect(ptHandle.x, ptHandle.y,
ptHandle.x + theImgBrush.m_size.cx,
ptHandle.y + theImgBrush.m_size.cy);
rcDragBrush -= (CPoint)theImgBrush.m_handle;
theImgBrush.m_rcSelection = rcDragBrush;
rcDragBrush.right += 1;
rcDragBrush.bottom += 1;
if (CImgTool::GetCurrentID() == IDMX_TEXTTOOL)
{
// extern CTextTool g_textTool;
// g_textTool.Render(CDC::FromHandle(pimg->hDC),
// rcDragBrush, TRUE, FALSE);
}
else
{
switch (nCombineMode)
{
case combineColor:
theImgBrush.BltColor(pimg, rcDragBrush.TopLeft(), crLeft);
break;
case combineMatte:
theImgBrush.BltMatte(pimg, rcDragBrush.TopLeft());
break;
case combineReplace:
theImgBrush.BltReplace(pimg, rcDragBrush.TopLeft());
break;
}
}
InvalImgRect(m_pImg, &rcDragBrush);
}
else
{
DrawImgLine(m_pImg, ptHandle, ptHandle, crLeft,
nStrokeWidth, nStrokeShape, FALSE);
rcDragBrush.left = ptHandle.x - nStrokeWidth / 2;
rcDragBrush.top = ptHandle.y - nStrokeWidth / 2;
rcDragBrush.right = rcDragBrush.left + nStrokeWidth;
rcDragBrush.bottom = rcDragBrush.top + nStrokeWidth;
}
if (CImgTool::GetCurrentID() == IDMB_ERASERTOOL)
{
crLeft = crRealLeftColor;
crRight = crRealRightColor;
}
g_bBrushVisible = TRUE;
}
/***************************************************************************/
void CImgWnd::CmdSmallBrush()
{
if (CImgTool::GetCurrent()->GetStrokeWidth() != 0)
CImgTool::GetCurrent()->SetStrokeWidth(1);
}
/***************************************************************************/
void CImgWnd::CmdSmallerBrush()
{
if (theImgBrush.m_pImg != NULL || g_bCustomBrush)
{
CmdHalfBsh();
return;
}
UINT nStrokeWidth = CImgTool::GetCurrent()->GetStrokeWidth();
if (nStrokeWidth > 1)
CImgTool::GetCurrent()->SetStrokeWidth(nStrokeWidth - 1);
}
/***************************************************************************/
void CImgWnd::CmdLargerBrush()
{
if (theImgBrush.m_pImg != NULL || g_bCustomBrush)
{
CmdDoubleBsh();
return;
}
UINT nStrokeWidth = CImgTool::GetCurrent()->GetStrokeWidth();
CImgTool::GetCurrent()->SetStrokeWidth(nStrokeWidth + 1);
}
/***************************************************************************/
void CImgWnd::CmdOK()
{
if (GetCapture() != NULL)
{
MessageBeep(0);
return;
}
}
/***************************************************************************/
// Draw the tracker for this view (if it's the active one) into pDC.
// If pDC is NULL, one will be provided. Optimize drawing by limiting
// it to pPaintRect. If pPaintRect is NULL, draw the whole tracker.
//
void CImgWnd::DrawTracker( CDC* pDC, const CRect* pPaintRect )
{
BOOL bDrawTrackerRgn = FALSE;
if (c_pImgWndCur != this
|| theImgBrush.m_bMoveSel
|| theImgBrush.m_bSmearSel
|| theImgBrush.m_bMakingSelection)
{
// This is not the active view, or the user is doing something
// to prevent the tracker from appearing.
return;
}
BOOL bReleaseDC = FALSE;
CRect clientRect;
if (pDC == NULL)
{
pDC = GetDC();
if (pDC == NULL)
{
theApp.SetGdiEmergency(FALSE);
return;
}
bReleaseDC = TRUE;
}
if (pPaintRect == NULL)
{
GetClientRect(&clientRect);
pPaintRect = &clientRect;
}
CRect trackerRect;
GetImageRect( trackerRect );
trackerRect.InflateRect( CTracker::HANDLE_SIZE, CTracker::HANDLE_SIZE );
CTracker::EDGES edges = (CTracker::EDGES)(CTracker::right | CTracker::bottom);
if (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL)
{
bDrawTrackerRgn = TRUE;
}
if (m_pImg == theImgBrush.m_pImg)
{
edges = CTracker::all;
trackerRect = theImgBrush.m_rcSelection;
trackerRect.left *= m_nZoom;
trackerRect.top *= m_nZoom;
trackerRect.right *= m_nZoom;
trackerRect.bottom *= m_nZoom;
trackerRect.InflateRect( CTracker::HANDLE_SIZE,
CTracker::HANDLE_SIZE);
trackerRect.OffsetRect( CTracker::HANDLE_SIZE + m_xScroll * m_nZoom,
CTracker::HANDLE_SIZE + m_yScroll * m_nZoom);
if (IsGridVisible())
{
trackerRect.right += 1;
trackerRect.bottom += 1;
}
}
CTracker::DrawBorder (pDC, trackerRect, edges );
CTracker::DrawHandles(pDC, trackerRect, edges );
if (bReleaseDC)
ReleaseDC(pDC);
}
/***************************************************************************/
// Erase the tracker from this window. Handles whole image as well
// as selection trackers.
//
void CImgWnd::EraseTracker()
{
if (m_pImg == NULL)
return;
CClientDC dc(this);
if (dc.m_hDC == NULL)
{
theApp.SetGdiEmergency(FALSE);
return;
}
CRect trackerRect;
if (m_pImg == theImgBrush.m_pImg)
{
// Tracker is a selection within the image
trackerRect = theImgBrush.m_rcSelection;
ImageToClient(trackerRect);
trackerRect.InflateRect(CTracker::HANDLE_SIZE, CTracker::HANDLE_SIZE);
if (IsGridVisible())
{
trackerRect.right += 1;
trackerRect.bottom += 1;
}
InvalidateRect( &trackerRect, FALSE );
}
else
{
// Tracker is around entire image
GetImageRect(trackerRect);
trackerRect.InflateRect(CTracker::HANDLE_SIZE, CTracker::HANDLE_SIZE);
DrawBackground(&dc, &trackerRect);
}
}
/***************************************************************************/
void CImgWnd::CmdTglOpaque()
{
HideBrush();
theImgBrush.m_bOpaque = !theImgBrush.m_bOpaque;
theImgBrush.RecalcMask( crRight );
MoveBrush( theImgBrush.m_rcSelection );
if ((CImgTool::GetCurrentID() == IDMB_PICKTOOL)
|| (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL))
g_pImgToolWnd->InvalidateOptions( FALSE );
}
/***************************************************************************/
void CImgWnd::CmdInvertColors()
{
IMG* pImg = m_pImg;
HideBrush();
CRect invertRect;
if (theImgBrush.m_pImg == NULL && !g_bCustomBrush)
{
invertRect.SetRect(0, 0, pImg->cxWidth, pImg->cyHeight);
}
else
{
invertRect = rcDragBrush;
invertRect.right -= 1;
invertRect.bottom -= 1;
}
if (theImgBrush.m_pImg != NULL && ! theImgBrush.m_bFirstDrag || g_bCustomBrush)
{
CPalette* ppal = SetImgPalette( &theImgBrush.m_dc, FALSE );
theImgBrush.m_dc.PatBlt(0, 0, theImgBrush.m_size.cx,
theImgBrush.m_size.cy, DSTINVERT);
if (ppal)
theImgBrush.m_dc.SelectPalette( ppal, FALSE ); // Background ??
theImgBrush.RecalcMask( crRight );
MoveBrush( theImgBrush.m_rcSelection );
}
else
{
SetUndo( m_pImg );
PatBlt( pImg->hDC, invertRect.left, invertRect.top,
invertRect.Width(), invertRect.Height(), DSTINVERT );
InvalImgRect ( m_pImg, &invertRect );
CommitImgRect( m_pImg, &invertRect );
FinishUndo( invertRect );
DirtyImg( m_pImg );
}
}
/***************************************************************************/
void CImgWnd::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags )
{
CWnd::OnKeyDown( nChar, nRepCnt, nFlags );
}
/***************************************************************************/
void CImgWnd::OnKeyUp( UINT nChar, UINT nRepCnt, UINT nFlags )
{
CWnd::OnKeyUp( nChar, nRepCnt, nFlags );
}
/***************************************************************************/