#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; ihDC, 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 ); } /***************************************************************************/