#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 "imgbrush.h" #include "imgwell.h" #include "imgtools.h" #include "t_text.h" #include "toolbox.h" #include "imgcolor.h" #include "undo.h" #include "props.h" #include "colorsrc.h" #ifdef _DEBUG #undef THIS_FILE static CHAR BASED_CODE THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNAMIC(CImgTool, CObject) IMPLEMENT_DYNAMIC(CRubberTool, CImgTool) IMPLEMENT_DYNAMIC(CClosedFormTool, CRubberTool) IMPLEMENT_DYNAMIC(CFreehandTool, CImgTool) IMPLEMENT_DYNAMIC(CSketchTool, CFreehandTool) IMPLEMENT_DYNAMIC(CBrushTool, CFreehandTool) IMPLEMENT_DYNAMIC(CPencilTool, CFreehandTool) IMPLEMENT_DYNAMIC(CEraserTool, CFreehandTool) IMPLEMENT_DYNAMIC(CAirBrushTool, CFreehandTool) IMPLEMENT_DYNAMIC(CLineTool, CRubberTool) IMPLEMENT_DYNAMIC(CRectTool, CClosedFormTool) IMPLEMENT_DYNAMIC(CRoundRectTool, CClosedFormTool) IMPLEMENT_DYNAMIC(CEllipseTool, CClosedFormTool) IMPLEMENT_DYNAMIC(CPickColorTool, CImgTool) IMPLEMENT_DYNAMIC(CFloodTool, CImgTool) IMPLEMENT_DYNAMIC(CSelectTool, CImgTool) IMPLEMENT_DYNAMIC(CZoomTool, CImgTool) #include "memtrace.h" extern CRect rcDragBrush; extern HDC hRubberDC; BOOL g_bBrushVisible; BOOL g_bPickingColor; UINT g_nStrokeWidth = 1; /***************************************************************************/ // // Drawing Tool Classes // CRectTool g_rectTool; CRoundRectTool g_roundRectTool; CEllipseTool g_ellipseTool; CLineTool g_lineTool; CSelectTool g_selectTool; CBrushTool g_brushTool; CSketchTool g_sketchTool; CPencilTool g_pencilTool; CEraserTool g_eraserTool; CAirBrushTool g_airBrushTool; CFloodTool g_floodTool; CPickColorTool g_pickColorTool; CZoomTool g_zoomTool; /***************************************************************************/ CImgTool* CImgTool::c_pHeadImgTool = NULL; CImgTool* CImgTool::c_pCurrentImgTool = &g_pencilTool; CImgTool* CImgTool::c_pPreviousImgTool = &g_pencilTool; BOOL CImgTool::c_bDragging = FALSE; int CImgTool::c_nHideCount = 0; /***************************************************************************/ CImgTool::CImgTool() { m_bUsesBrush = FALSE; m_bIsUndoable = TRUE; m_bCanBePrevTool = TRUE; m_bToggleWithPrev = FALSE; m_bFilled = FALSE; m_bBorder = TRUE; m_bMultPtOpInProgress = FALSE; m_eDrawDirection = eFREEHAND; m_nStrokeWidth = 0; m_nStrokeShape = roundBrush; m_nCursorID = LOWORD(IDC_CROSSHAIR); m_nCmdID = NULL; // Link into the list of tools... m_pNextImgTool = c_pHeadImgTool; c_pHeadImgTool = this; } /******************************************************************************/ eDRAWCONSTRAINTDIRECTION CImgTool::DetermineDrawDirection(MTI *pmti) { eDRAWCONSTRAINTDIRECTION eDrawDirection; // 45 is dominant, test first if ( (pmti->pt.x > pmti->ptPrev.x) && (pmti->pt.y > pmti->ptPrev.y) ) { eDrawDirection = eSOUTH_EAST; } else { if ( (pmti->pt.x > pmti->ptPrev.x) && (pmti->pt.y < pmti->ptPrev.y) ) { eDrawDirection = eNORTH_EAST; } else { if ( (pmti->pt.x < pmti->ptPrev.x) && (pmti->pt.y > pmti->ptPrev.y) ) { eDrawDirection = eSOUTH_WEST; } else { if ( (pmti->pt.x < pmti->ptPrev.x) && (pmti->pt.y < pmti->ptPrev.y) ) { eDrawDirection = eNORTH_WEST; } else { // Horizontal is the next dominant, test before vertical if (pmti->ptPrev.x != pmti->pt.x) { eDrawDirection = eEAST_WEST; pmti->pt.y = pmti->ptPrev.y; } else { if (pmti->ptPrev.y != pmti->pt.y) { eDrawDirection = eNORTH_SOUTH; pmti->pt.x = pmti->ptPrev.x; } else { // we should never fall into here, but in any case... eDrawDirection = eFREEHAND; } } } } } } return eDrawDirection; } /******************************************************************************/ void CImgTool::AdjustPointsForConstraint(MTI *pmti) { } /******************************************************************************/ void CImgTool::PreProcessPoints(MTI *pmti) { if (pmti != NULL) { if ((GetKeyState(VK_SHIFT) & 0x8000) != 0) //still in constrain mode { switch (m_eDrawDirection) { case eEAST_WEST: case eNORTH_SOUTH: case eNORTH_WEST: case eSOUTH_EAST: case eNORTH_EAST: case eSOUTH_WEST: AdjustPointsForConstraint(pmti); break; default: // not in constraint mode yet If shift down, check for // mode and save mode else nothing. Default is freehand m_eDrawDirection = DetermineDrawDirection(pmti); AdjustPointsForConstraint(pmti); break; } } else { // shift not down m_eDrawDirection = eFREEHAND; } } } /***************************************************************************/ void CImgTool::HideDragger(CImgWnd* pImgWnd) { ASSERT(c_pCurrentImgTool != NULL); if (c_nHideCount == 0) c_pCurrentImgTool->OnShowDragger(pImgWnd, FALSE); c_nHideCount++; } /***************************************************************************/ void CImgTool::ShowDragger(CImgWnd* pImgWnd) { ASSERT(c_pCurrentImgTool != NULL); if (--c_nHideCount == 0) c_pCurrentImgTool->OnShowDragger(pImgWnd, TRUE); } /***************************************************************************/ void CImgTool::Select(UINT nCmdID) { CImgTool* p = FromID(nCmdID); if (p) { p->Select(); } } /***************************************************************************/ void CImgTool::Select() { ASSERT(this != NULL); if (this == c_pCurrentImgTool && m_bToggleWithPrev) { SelectPrevious(); return; } if (g_bCustomBrush) { g_bCustomBrush = FALSE; SetCombineMode(combineColor); } HideBrush(); if (c_pCurrentImgTool->m_bCanBePrevTool && c_pCurrentImgTool != this) c_pPreviousImgTool = c_pCurrentImgTool; // Make sure to Deactivate the old one BEFORE activating the new one, so // globals (like g_nStrokeWidth) get set correctly if (c_pCurrentImgTool != NULL) c_pCurrentImgTool->OnActivate(FALSE); c_pCurrentImgTool = this; OnActivate(TRUE); if (c_pCurrentImgTool != this) { // Some tools may give up activation... ASSERT(!m_bCanBePrevTool); return; } SetCombineMode(combineColor); if (g_pImgToolWnd) { g_pImgToolWnd->SelectTool( (WORD)m_nCmdID ); if (g_pImgToolWnd->m_hWnd) g_pImgToolWnd->InvalidateOptions(); } CImgWnd::SetToolCursor(); } /***************************************************************************/ CImgTool* CImgTool::FromID(UINT nCmdID) { CImgTool* pImgTool = c_pHeadImgTool; while (pImgTool != NULL && pImgTool->m_nCmdID != nCmdID) pImgTool = pImgTool->m_pNextImgTool; return pImgTool; } /***************************************************************************/ void CImgTool::SetStrokeWidth(UINT nNewStrokeWidth) { if (nNewStrokeWidth == m_nStrokeWidth) return; HideBrush(); g_bCustomBrush = FALSE; m_nStrokeWidth = nNewStrokeWidth; g_pImgToolWnd->InvalidateOptions(); extern MTI mti; if (mti.fLeft || mti.fRight) OnDrag(CImgWnd::GetCurrent(), &mti); } /***************************************************************************/ void CImgTool::SetStrokeShape(UINT nNewStrokeShape) { if (m_nStrokeShape == nNewStrokeShape) return; HideBrush(); g_bCustomBrush = FALSE; m_nStrokeShape = nNewStrokeShape; g_pImgToolWnd->InvalidateOptions(FALSE); } /***************************************************************************/ void CImgTool::OnActivate(BOOL bActivate) { if (bActivate) OnShowDragger(CImgWnd::GetCurrent(), TRUE); } /***************************************************************************/ void CImgTool::OnEnter(CImgWnd* pImgWnd, MTI* pmti) { // No default action } /***************************************************************************/ void CImgTool::OnLeave(CImgWnd* pImgWnd, MTI* pmti) { // No default action } /***************************************************************************/ void CImgTool::OnShowDragger(CImgWnd* pImgWnd, BOOL bShowDragger) { // No default action } /***************************************************************************/ void CImgTool::OnStartDrag(CImgWnd* pImgWnd, MTI* pmti) { c_bDragging = TRUE; } /***************************************************************************/ void CImgTool::OnEndDrag(CImgWnd* pImgWnd, MTI* pmti) { c_bDragging = FALSE; if (m_bIsUndoable) DirtyImg(pImgWnd->m_pImg); } /***************************************************************************/ void CImgTool::OnDrag(CImgWnd* pImgWnd, MTI* pmti) { ASSERT(c_bDragging); } /***************************************************************************/ void CImgTool::OnMove(CImgWnd* pImgWnd, MTI* pmti) { // ASSERT(!c_bDragging); if (UsesBrush()) { fDraggingBrush = TRUE; pImgWnd->ShowBrush(pmti->pt); } SetStatusBarPosition(pmti->pt); } /***************************************************************************/ void CImgTool::OnTimer(CImgWnd* pImgWnd, MTI* pmti) { // Tools should not have started a timer unless it overrides this! ASSERT(FALSE); } /***************************************************************************/ void CImgTool::OnCancel(CImgWnd* pImgWnd) { c_bDragging = FALSE; } /***************************************************************************/ void CImgTool::OnPaintOptions(CDC* pDC, const CRect& paintRect, const CRect& optionsRect) { } /***************************************************************************/ void CImgTool::PaintStdPattern(CDC* pDC, const CRect& paintRect, const CRect& optionsRect) { CBrush brush; CPalette *pcPaletteOld = NULL; CPalette *pcPaletteOld2 = NULL; CDC dc; if (!dc.CreateCompatibleDC(pDC)) return; CBitmap bitmap, * pOldBitmap; if (!bitmap.CreateCompatibleBitmap(pDC, 8, 8)) return; pOldBitmap = dc.SelectObject(&bitmap); if (theApp.m_pPalette) { pcPaletteOld = pDC->SelectPalette( theApp.m_pPalette, FALSE ); pDC->RealizePalette(); pcPaletteOld2 = dc.SelectPalette( theApp.m_pPalette, FALSE ); dc.RealizePalette(); } CBrush* pOldBrush = NULL; COLORREF rgb = crLeft; if (pImgCur->m_pBitmapObj->m_nColors == 0) { BOOL MonoRect(CDC* pDC, const CRect& rect, COLORREF rgb, BOOL bFrame); MonoRect(&dc, CRect(0, 0, 9, 9), rgb, FALSE); } else { brush.CreateSolidBrush(rgb); pOldBrush = dc.SelectObject(&brush); dc.PatBlt(0, 0, 8, 8, PATCOPY); dc.SelectObject(pOldBrush); brush.DeleteObject(); } // Draw a black grid... for (int i = 0; i < 9; i++) { pDC->PatBlt(optionsRect.left + 2 + i * 7, optionsRect.top + 3, 1, 8 * 7 + 1, BLACKNESS); pDC->PatBlt(optionsRect.left + 2, optionsRect.top + 3 + i * 7, 8 * 7 + 1, 1, BLACKNESS); } // Fill in the boxes... COLORREF curColor = (COLORREF)0xffffffff; for (int y = 0; y < 8; y++) { for (int x = 0; x < 8; x++) { COLORREF color = dc.GetPixel(x, y) | 0x02000000L; if (color != curColor) { if (pOldBrush != NULL) pDC->SelectObject(pOldBrush); brush.DeleteObject(); brush.CreateSolidBrush(color); pOldBrush = pDC->SelectObject(&brush); curColor = color; } pDC->PatBlt(optionsRect.left + 2 + 1 + x * 7, optionsRect.top + 3 + 1 + y * 7, 6, 6, PATCOPY); } } ASSERT(pOldBrush != NULL); pDC->SelectObject(pOldBrush); dc.SelectObject(pOldBitmap); if (pcPaletteOld) pDC->SelectPalette(pcPaletteOld, FALSE); if (pcPaletteOld2) dc.SelectPalette(pcPaletteOld2, FALSE); } /***************************************************************************/ void CImgTool::ClickStdPattern(CImgToolWnd* pWnd, const CRect& optionsRect, const CPoint& clickPoint) { CImgTool::OnClickOptions(pWnd, optionsRect, clickPoint); } /***************************************************************************/ void CImgTool::PaintStdBrushes(CDC* pDC, const CRect& paintRect, const CRect& optionsRect) { int cxBrush = optionsRect.Width() / 3; int cyBrush = optionsRect.Height() / 4; for (UINT nBrushShape = 0; nBrushShape < 4; nBrushShape++) { int x = 0; for (UINT nStrokeWidth = 8 - (nBrushShape == 0); (int)nStrokeWidth > 0; nStrokeWidth -= 3, x += cxBrush) { CRect rect; rect.left = optionsRect.left + x; rect.top = optionsRect.top + cyBrush * nBrushShape; rect.right = rect.left + cxBrush; rect.bottom = rect.top + cyBrush; rect.InflateRect(-3, -3); if ((paintRect & rect).IsRectEmpty()) continue; BOOL bCur = (nStrokeWidth == m_nStrokeWidth && nBrushShape == m_nStrokeShape); CBrush* pOldBrush = pDC->SelectObject(GetSysBrush(bCur ? COLOR_HIGHLIGHT : COLOR_BTNFACE)); if ((nStrokeWidth & 1) != 0) { // Adjust hilight rect so brush will be centered rect.right -= 1; rect.bottom -= 1; } pDC->PatBlt(rect.left + 1, rect.top - 1, rect.Width() - 2, rect.Height() + 2, PATCOPY); pDC->SelectObject(pOldBrush); CPoint pt(optionsRect.left + (cxBrush - nStrokeWidth) / 2 + x, optionsRect.top + (cyBrush - nStrokeWidth) / 2 + nBrushShape * cyBrush); pOldBrush = pDC->SelectObject(GetSysBrush(bCur ? COLOR_HIGHLIGHTTEXT : COLOR_BTNTEXT)); BrushLine(pDC, pt, pt, nStrokeWidth, nBrushShape); pDC->SelectObject(pOldBrush); } } } /***************************************************************************/ void CImgTool::OnClickOptions(CImgToolWnd* pWnd, const CRect& optionsRect, const CPoint& clickPoint) { MessageBeep(0); } /******************************************************************************/ void CImgTool::OnUpdateColors (CImgWnd* pImgWnd) { } /******************************************************************************/ BOOL CImgTool::CanEndMultiptOperation(MTI* pmti ) { return (! m_bMultPtOpInProgress); // if not in progress (FALSE) => can end (TRUE) } /******************************************************************************/ void CImgTool::EndMultiptOperation(BOOL bAbort) { m_bMultPtOpInProgress = FALSE; } /******************************************************************************/ BOOL CImgTool::IsToolModal(void) { return(IsDragging() || m_bMultPtOpInProgress || m_bToggleWithPrev); } /******************************************************************************/ BOOL CImgTool::IsUndoable() { if (m_bMultPtOpInProgress) { return FALSE; // cannot undo in the middle of a multi-point operation. } else { return m_bIsUndoable; } } /******************************************************************************/ void CImgTool::ClickStdBrushes(CImgToolWnd* pWnd, const CRect& optionsRect, const CPoint& clickPoint) { HideBrush(); g_bCustomBrush = FALSE; m_nStrokeWidth = 2 + 3 * (2 - (clickPoint.x / (optionsRect.Width() / 3))); m_nStrokeShape = clickPoint.y / (optionsRect.Height() / 4); if (m_nStrokeShape == 0) m_nStrokeWidth -= 1; pWnd->InvalidateOptions(FALSE); } /******************************************************************************/ UINT CImgTool::GetCursorID() { return m_nCursorID; } /******************************************************************************/ CRect CRubberTool::rcPrev; // UINT CRubberTool::m_nStrokeWidth; CRubberTool::CRubberTool() { } /******************************************************************************/ void CRubberTool::OnPaintOptions(CDC* pDC, const CRect& paintRect, const CRect& optionsRect) { if (m_bFilled) { PaintStdPattern(pDC, paintRect, optionsRect); return; } #define nLineWidths 5 int cyEach = (optionsRect.Height() - 4) / nLineWidths; for (int i = 0; i < nLineWidths; i++) { UINT cyHeight = i + 1; CBrush* pOldBrush; BOOL bCur = (cyHeight == GetStrokeWidth()); pOldBrush = pDC->SelectObject( GetSysBrush(bCur ? COLOR_HIGHLIGHT : COLOR_BTNFACE)); pDC->PatBlt(optionsRect.left + 2, optionsRect.top + 3 + i * cyEach, optionsRect.Width() - 4, cyEach - 2, PATCOPY); pDC->SelectObject(pOldBrush); pOldBrush = pDC->SelectObject(GetSysBrush(bCur ? COLOR_HIGHLIGHTTEXT : COLOR_BTNTEXT)); pDC->PatBlt(optionsRect.left + 6, optionsRect.top + 2 + cyEach * i + (cyEach - cyHeight) / 2, optionsRect.Width() - 12, cyHeight, PATCOPY); pDC->SelectObject(pOldBrush); } } /******************************************************************************/ void CRubberTool::OnClickOptions( CImgToolWnd* pWnd, const CRect& optionsRect, const CPoint& clickPoint ) { if (m_bFilled) { CImgTool::OnClickOptions( pWnd, optionsRect, clickPoint ); return; } m_nStrokeWidth = 1 + clickPoint.y / ((optionsRect.Height() - 4) / nLineWidths); // fix for rounding errors if (m_nStrokeWidth > nLineWidths) { m_nStrokeWidth = nLineWidths; } pWnd->InvalidateOptions(FALSE); } /******************************************************************************/ void CClosedFormTool::OnPaintOptions( CDC* pDC, const CRect& paintRect, const CRect& optionsRect ) { // Option 0 is Outlined Shape (border and no fill) // Option 1 is Filled Shape with border // Option 2 is Filled Shape NO border #define NUM_CLOSED_FORM_OPTIONS 3 //number of options high //*DK* Select Palette into DC CBrush* pOldBrush; CRect cRectOptionSel; // selection rectangle CRect cRectOption; //rectangle int cyEach = (optionsRect.Height() - 4) / NUM_CLOSED_FORM_OPTIONS; // max height of each option int cyHeight = cyEach - cyEach/2; //rectangle is 1/2 max height int bCurrSelected = FALSE; BOOL bFilled = CImgTool::GetCurrent()->IsFilled(); BOOL bBorder = CImgTool::GetCurrent()->HasBorder(); int i; for (i = 0; i < NUM_CLOSED_FORM_OPTIONS; i++) { // Setup the Rectangles for painting and for selection //Selection Rectangle cRectOptionSel.SetRect(optionsRect.left + 2, optionsRect.top + 3 + (i * cyEach), (optionsRect.left + 2) + optionsRect.Width() - 4, (optionsRect.top + 3 + (i* cyEach)) + cyEach - 2); //Option Rectangle cRectOption.SetRect(optionsRect.left + 6, optionsRect.top + 2 + i * cyEach + (cyEach - cyHeight) / 2, (optionsRect.left + 6) + optionsRect.Width() - 12, (optionsRect.top + 2 + i * cyEach + (cyEach - cyHeight) / 2) + cyHeight); // Determine the Selection state for the current item. bCurrSelected = FALSE; switch (i) { case 0: //Outlined Shape (border, no fill) if (! bFilled && bBorder) { bCurrSelected = TRUE; } break; case 1: // Filled Shape (border and fill) if ( (bFilled) && (bBorder) ) { bCurrSelected = TRUE; } break; case 2: // Filled Shape No Border (no border, fill) if (bFilled && ! bBorder) { bCurrSelected = TRUE; } break; default: bCurrSelected = FALSE; break; } // Draw the selection State // If selected, use COLOR_HIGHLIGHT else use CMP_COLOR_LTGRAY pOldBrush = pDC->SelectObject( GetSysBrush( bCurrSelected ? COLOR_HIGHLIGHT : COLOR_BTNFACE ) ); pDC->PatBlt( cRectOptionSel.left, cRectOptionSel.top, cRectOptionSel.Width(),cRectOptionSel.Height(), PATCOPY ); pDC->SelectObject(pOldBrush); CBrush* pborderBrush; CBrush* pfillBrush; pborderBrush = GetSysBrush(bCurrSelected ? COLOR_BTNHIGHLIGHT : COLOR_BTNTEXT); pfillBrush = GetSysBrush(COLOR_BTNSHADOW); // Draw the Option switch (i) { case 0: //Outlined Shape (no border, no fill) pDC->FrameRect(&cRectOption, pborderBrush); break; case 1: // Filled Shape (border and fill) // using fillrect then frame rect instead of rectangle, since // don't have getsyspen facility in this program. pDC->FillRect(&cRectOption, pfillBrush); pDC->FrameRect(&cRectOption, pborderBrush); break; case 2: // Filled Shape No Border (no border, fill) pDC->FillRect(&cRectOption, pfillBrush); break; default: break; } } } /******************************************************************************/ // clickpoint is from top of optionsrect (i.e. clickpoint if from 0 to optionsrect.height() // and thus clickpoint is always less than optionsrec.top void CClosedFormTool::OnClickOptions(CImgToolWnd* pWnd, const CRect& optionsRect, const CPoint& clickPoint) { int cyEach = (optionsRect.Height() - 4) / NUM_CLOSED_FORM_OPTIONS; // max height of each option // BOOL bCurrSelected = FALSE; int i; for (i = 0; i < NUM_CLOSED_FORM_OPTIONS; i++) { if ( clickPoint.y < 3 + ((i+1) * cyEach) ) { // bCurrSelected = TRUE; switch (i) { default: // default is same as initial case 0: //Outlined Shape (border, no fill) m_bFilled = FALSE; m_bBorder = TRUE; break; case 1: // Filled Shape (border and fill) m_bFilled = TRUE; m_bBorder = TRUE; break; case 2: // Filled Shape No Border (no border, fill) m_bFilled = TRUE; m_bBorder = FALSE; break; } break; // point found, break out of loop test } } pWnd->InvalidateOptions(FALSE); } /******************************************************************************/ void CRubberTool::OnStartDrag(CImgWnd* pImgWnd, MTI* pmti) { CImgTool::OnStartDrag(pImgWnd, pmti); SetupRubber(pImgWnd->m_pImg); OnDrag(pImgWnd, pmti); } /******************************************************************************/ void CRubberTool::OnEndDrag(CImgWnd* pImgWnd, MTI* pmti) { OnDrag(pImgWnd, pmti); CRect rc(pmti->ptDown.x, pmti->ptDown.y, pmti->pt.x, pmti->pt.y); Render(CDC::FromHandle(pImgWnd->m_pImg->hDC), rc, pmti->fLeft, TRUE, pmti->fCtrlDown); InvalImgRect(pImgWnd->m_pImg, &rc); CommitImgRect(pImgWnd->m_pImg, &rc); pImgWnd->FinishUndo(rc); ClearStatusBarSize(); CImgTool::OnEndDrag(pImgWnd, pmti); } /******************************************************************************/ void CRubberTool::OnDrag(CImgWnd* pImgWnd, MTI* pmti) { HPALETTE hpalOld = NULL; if (theApp.m_pPalette && theApp.m_pPalette->m_hObject) { hpalOld = SelectPalette( hRubberDC, (HPALETTE)theApp.m_pPalette->m_hObject, FALSE ); // Background ?? RealizePalette( hRubberDC ); } BitBlt(pImgWnd->m_pImg->hDC, rcPrev.left , rcPrev.top, rcPrev.Width(), rcPrev.Height(), hRubberDC, rcPrev.left , rcPrev.top, SRCCOPY); if (hpalOld != NULL) SelectPalette( hRubberDC, hpalOld, FALSE ); // Background ?? InvalImgRect(pImgWnd->m_pImg, &rcPrev); PreProcessPoints(pmti); CRect rc(pmti->ptDown.x, pmti->ptDown.y, pmti->pt.x, pmti->pt.y); Render(CDC::FromHandle(pImgWnd->m_pImg->hDC), rc, pmti->fLeft, FALSE, pmti->fCtrlDown); InvalImgRect(pImgWnd->m_pImg, &rc); rcPrev = rc; if (m_nCmdID != IDMB_POLYGONTOOL) { CSize size( pmti->pt - pmti->ptDown ); if (size.cx < 0) size.cx -= 1; else size.cx += 1; if (size.cy < 0) size.cy -= 1; else size.cy += 1; SetStatusBarPosition( pmti->ptDown ); SetStatusBarSize ( size ); } } /******************************************************************************/ void CRubberTool::AdjustPointsForConstraint(MTI *pmti) { if (pmti != NULL) { int iWidthHeight = min( abs(pmti->ptDown.x - pmti->pt.x), abs(pmti->ptDown.y - pmti->pt.y)); // Set the x value if (pmti->pt.x < pmti->ptDown.x) { pmti->pt.x = pmti->ptDown.x - iWidthHeight; } else { pmti->pt.x = pmti->ptDown.x + iWidthHeight; } // Set the y value if (pmti->pt.y < pmti->ptDown.y) { pmti->pt.y = pmti->ptDown.y - iWidthHeight; } else { pmti->pt.y = pmti->ptDown.y + iWidthHeight; } } } /******************************************************************************/ void CRubberTool::Render( CDC* pDC, CRect& rect, BOOL bLeft, BOOL bCommit, BOOL bCtrlDown ) { int sx; int sy; int ex; int ey; HBRUSH hBr = NULL; HPEN hPen = NULL; HPEN hOldPen = NULL; HBRUSH hOldBr = NULL; CPoint pt1; CPoint pt2; HDC hDC = pDC->m_hDC; enum SHAPE { rectangle, roundRect, ellipse } shape; switch (m_nCmdID) { default: ASSERT(FALSE); case IDMB_RECTTOOL: shape = rectangle; break; case IDMB_FRECTTOOL: shape = rectangle; break; case IDMB_RNDRECTTOOL: shape = roundRect; break; case IDMB_FRNDRECTTOOL: shape = roundRect; break; case IDMB_ELLIPSETOOL: shape = ellipse; break; case IDMB_FELLIPSETOOL: shape = ellipse; break; } FixRect(&rect); pt1.x = rect.left; pt1.y = rect.top; pt2.x = rect.right; pt2.y = rect.bottom; StandardiseCoords(&pt1, &pt2); sx = pt1.x; sy = pt1.y; ex = pt2.x; ey = pt2.y; SetupPenBrush(hDC, bLeft, TRUE, bCtrlDown); CRect rc(sx, sy, ex, ey); switch (shape) { case rectangle: Rectangle(hDC, sx, sy, ex, ey); break; case roundRect: RoundRect(hDC, sx, sy, ex, ey, 16, 16); // The below draws an RoundRect with a mask first then bitblt // MyRoundRect(hDC, sx, sy, ex, ey, 16, 16, m_bFilled); // // if border and fill, draw border after fill // if ( (m_bBorder) && (m_bFilled) ) // { // MyRoundRect(hDC, sx, sy, ex, ey, 16, 16, !m_bFilled); // } break; case ellipse: Ellipse(hDC, sx, sy, ex, ey); // The below draws an Elipse with a mask first then bitblt // Mylipse(hDC, sx, sy, ex, ey, m_bFilled); // // if border and fill, draw border after fill // if ( (m_bBorder) && (m_bFilled) ) // { // Mylipse(hDC, sx, sy, ex, ey, !m_bFilled); // } break; } SetupPenBrush(hDC, bLeft, FALSE, bCtrlDown); } void CRubberTool::OnActivate( BOOL bActivate ) { if (bActivate) { m_nStrokeWidth = g_nStrokeWidth; } else { g_nStrokeWidth = m_nStrokeWidth; } CImgTool::OnActivate( bActivate ); } /******************************************************************************/ /*bSetup is true to setup, False to Cleanup */ BOOL CImgTool::SetupPenBrush(HDC hDC, BOOL bLeft, BOOL bSetup, BOOL bCtrlDown) { COLORREF colorBorder; COLORREF colorFill; if (bCtrlDown && crTrans != TRANS_COLOR_NONE) { if (HasBorder ()) { colorBorder = bLeft ? crTrans : crRight; colorFill = bLeft ? crRight : crTrans; } else { colorBorder = bLeft ? crRight : crTrans; colorFill = bLeft ? crTrans : crRight; } } else { if (HasBorder()) { colorBorder = bLeft ? crLeft : crRight; colorFill = bLeft ? crRight: crLeft; } else { colorBorder = bLeft ? crRight : crLeft; colorFill = bLeft ? crLeft: crRight; } } static HBRUSH hBr = NULL; static HPEN hPen = NULL; static HPEN hOldPen = NULL; static HBRUSH hOldBr = NULL; static BOOL bCurrentlySetup = FALSE; BOOL bRC = TRUE; if (bSetup) { if (! bCurrentlySetup) { bCurrentlySetup = TRUE; // select null objects into DC. Depending on drawing mode, // either or both will be re-selected in to override hPen = NULL; hBr = NULL; hOldPen = (HPEN)SelectObject( hDC, GetStockObject( NULL_PEN ) ); hOldBr = (HBRUSH)SelectObject( hDC, GetStockObject( NULL_BRUSH ) ); if (m_bFilled) { hBr = CreateSolidBrush( colorFill ); SelectObject( hDC, hBr ); } if (m_bBorder) { hPen = CreatePen( PS_INSIDEFRAME, m_nStrokeWidth, colorBorder ); SelectObject(hDC, hPen); } else { //simulate no border by drawing the border the same as the fill. // since GDI does not draw small elipses, roundrects correctly // with NULL brush for no border. // Note the width is 2 so we will dither correctly hPen = CreatePen(PS_INSIDEFRAME, 2, colorFill); SelectObject(hDC, hPen); } } else { // Error: Will lose allocated Brush/Pen bRC = FALSE; } } else { if (bCurrentlySetup) { bCurrentlySetup = FALSE; SelectObject(hDC, hOldPen); if (hPen != NULL) { DeleteObject(hPen); } SelectObject(hDC, hOldBr); if (hBr != NULL) { DeleteObject( hBr ); } } else { // Error: Cannot Free/cleanup Brush/Pen -- Never allocated. bRC = FALSE; } } return bRC; } #if 0 // unused code /******************************************************************************/ /*bSetup is true to setup, False to Cleanup */ BOOL CRubberTool::SetupMaskPenBrush(HDC hDC, BOOL bLeft, BOOL bSetup) { BOOL bRC = TRUE; static HBRUSH hBr = NULL; static HPEN hPen = NULL; static HPEN hOldPen = NULL; static HBRUSH hOldBr = NULL; static BOOL bCurrentlySetup = FALSE; if (bSetup) { if (bCurrentlySetup) { // Error: Will lose allocated Brush/Pen bRC = FALSE; } else { bCurrentlySetup = TRUE; // draw the shape on the mask: // select null objects into DC. Depending on drawing mode, // either or both will be re-selected in to override hPen = NULL; hBr = NULL; hOldPen = (HPEN)SelectObject(hDC, GetStockObject(NULL_PEN)); hOldBr = (HBRUSH)SelectObject(hDC, GetStockObject(NULL_BRUSH)); if (m_bFilled) { SelectObject(hDC, GetStockObject( BLACK_BRUSH )); } if (m_bBorder) { hPen = CreatePen(PS_INSIDEFRAME, m_nStrokeWidth, (COLORREF)0L ); SelectObject(hDC, hPen); } } } else { if (bCurrentlySetup) { bCurrentlySetup = FALSE; SelectObject(hDC, hOldPen); if (hPen != NULL) { DeleteObject(hPen); } SelectObject(hDC, hOldBr); if (hBr != NULL) { DeleteObject(hBr); } } else { // Error: Cannot Free/cleanup Brush/Pen -- Never allocated. bRC = FALSE; } } return bRC; } #endif // unused code /******************************************************************************/ CRect CFreehandTool::c_undoRect; /***************************************************************************/ CFreehandTool::CFreehandTool() { m_bUsesBrush = TRUE; } /******************************************************************************/ void CFreehandTool::OnStartDrag(CImgWnd* pImgWnd, MTI* pmti) { CImgTool::OnStartDrag(pImgWnd, pmti); c_undoRect.TopLeft() = c_undoRect.BottomRight() = pmti->pt; OnDrag(pImgWnd, pmti); } /******************************************************************************/ void CFreehandTool::OnEndDrag(CImgWnd* pImgWnd, MTI* pmti) { if (g_bCustomBrush) { c_undoRect.left -= theImgBrush.m_size.cx + theImgBrush.m_handle.cx; c_undoRect.top -= theImgBrush.m_size.cy + theImgBrush.m_handle.cy; c_undoRect.right += theImgBrush.m_size.cx - theImgBrush.m_handle.cx; c_undoRect.bottom += theImgBrush.m_size.cy - theImgBrush.m_handle.cy; } else { // HACK: +1s are to cover bug in slanted line brushes c_undoRect.left -= m_nStrokeWidth / 2 + 1; c_undoRect.top -= m_nStrokeWidth / 2 + 1; c_undoRect.right += (m_nStrokeWidth + 1) / 2 + 1; c_undoRect.bottom += (m_nStrokeWidth + 1) / 2 + 1; } pImgWnd->FinishUndo(c_undoRect); CImgTool::OnEndDrag(pImgWnd, pmti); } /******************************************************************************/ CSketchTool::CSketchTool() { m_nCursorID = IDC_BRUSH; m_nCmdID = IDMZ_BRUSHTOOL; m_bCanBePrevTool = FALSE; } /******************************************************************************/ void CSketchTool::OnDrag( CImgWnd* pImgWnd, MTI* pmti ) { fDraggingBrush = FALSE; DrawBrush( pImgWnd->m_pImg, pmti->pt, pmti->fLeft ); if (pmti->pt.x < c_undoRect.left) c_undoRect.left = pmti->pt.x; else if (pmti->pt.x > c_undoRect.right) c_undoRect.right = pmti->pt.x; if (pmti->pt.y < c_undoRect.top) c_undoRect.top = pmti->pt.y; else if (pmti->pt.y > c_undoRect.bottom) c_undoRect.bottom = pmti->pt.y; SetStatusBarPosition( pmti->pt ); } /******************************************************************************/ void CSketchTool::OnCancel(CImgWnd* pImgWnd) { HideBrush(); g_bCustomBrush = FALSE; SelectPrevious(); CImgTool::OnCancel( pImgWnd ); } /******************************************************************************/ CBrushTool::CBrushTool() { m_nCursorID = IDC_BRUSH; m_nCmdID = IDMB_CBRUSHTOOL; m_nStrokeWidth = 4; } /***************************************************************************/ void CBrushTool::OnPaintOptions( CDC* pDC, const CRect& paintRect, const CRect& optionsRect ) { PaintStdBrushes(pDC, paintRect, optionsRect); } /***************************************************************************/ void CBrushTool::OnClickOptions(CImgToolWnd* pWnd, const CRect& optionsRect, const CPoint& clickPoint) { ClickStdBrushes(pWnd, optionsRect, clickPoint); } /***************************************************************************/ void CBrushTool::OnDrag(CImgWnd* pImgWnd, MTI* pmti) { g_bCustomBrush = FALSE; CPoint pt1, pt2; fDraggingBrush = FALSE; pt1 = pmti->ptPrev; pt2 = pmti->pt; // use transparent color if defined if (pmti->fCtrlDown && crTrans != TRANS_COLOR_NONE) { DrawImgLine( pImgWnd->m_pImg, pt1, pt2, crTrans, m_nStrokeWidth, m_nStrokeShape, TRUE); } else { DrawImgLine( pImgWnd->m_pImg, pt1, pt2, pmti->fLeft ? crLeft : crRight, m_nStrokeWidth, m_nStrokeShape, TRUE); } if (pmti->pt.x < c_undoRect.left) c_undoRect.left = pmti->pt.x; else if (pmti->pt.x > c_undoRect.right) c_undoRect.right = pmti->pt.x; if (pmti->pt.y < c_undoRect.top) c_undoRect.top = pmti->pt.y; else if (pmti->pt.y > c_undoRect.bottom) c_undoRect.bottom = pmti->pt.y; SetStatusBarPosition(pmti->pt); } /***************************************************************************/ void CBrushTool::OnMove(CImgWnd* pImgWnd, MTI* pmti) { g_bCustomBrush = FALSE; CImgTool::OnMove(pImgWnd, pmti); } /***************************************************************************/ CPencilTool::CPencilTool() { m_nCursorID = IDC_PENCIL; m_nCmdID = IDMB_PENCILTOOL; m_bUsesBrush = FALSE; m_nStrokeWidth = 1; } /***************************************************************************/ void CPencilTool::OnStartDrag(CImgWnd* pImgWnd, MTI* pmti) { CFreehandTool::OnStartDrag(pImgWnd, pmti); m_eDrawDirection = eFREEHAND; // initialize to not have a direction } /***************************************************************************/ void CPencilTool::OnDrag(CImgWnd* pImgWnd, MTI* pmti) { g_bCustomBrush = FALSE; fDraggingBrush = FALSE; PreProcessPoints(pmti); // use transparent color if defined if (pmti->fCtrlDown && crTrans != TRANS_COLOR_NONE) { DrawImgLine (pImgWnd->m_pImg, pmti->ptPrev, pmti->pt, crTrans, m_nStrokeWidth, m_nStrokeShape, TRUE); } else { DrawImgLine(pImgWnd->m_pImg, pmti->ptPrev, pmti->pt, pmti->fLeft ? crLeft : crRight, m_nStrokeWidth, m_nStrokeShape, TRUE); } if (pmti->pt.x < c_undoRect.left) c_undoRect.left = pmti->pt.x; else if (pmti->pt.x > c_undoRect.right) c_undoRect.right = pmti->pt.x; if (pmti->pt.y < c_undoRect.top) c_undoRect.top = pmti->pt.y; else if (pmti->pt.y > c_undoRect.bottom) c_undoRect.bottom = pmti->pt.y; SetStatusBarPosition(pmti->pt); } /***************************************************************************/ void CPencilTool::OnEndDrag(CImgWnd* pImgWnd, MTI* pmti) { c_undoRect.right += 1; c_undoRect.bottom += 1; pImgWnd->FinishUndo(c_undoRect); CImgTool::OnEndDrag(pImgWnd, pmti); // Bypass CFreehandTool } /******************************************************************************/ void CPencilTool::AdjustPointsForConstraint(MTI *pmti) { eDRAWCONSTRAINTDIRECTION eDrawDirection = DetermineDrawDirection(pmti); int iWidthHeight = min( abs(pmti->ptPrev.x - pmti->pt.x), abs(pmti->ptPrev.y - pmti->pt.y)); switch (m_eDrawDirection) { case eEAST_WEST: pmti->pt.y = pmti->ptPrev.y; break; case eNORTH_SOUTH: pmti->pt.x = pmti->ptPrev.x; break; case eNORTH_WEST: case eSOUTH_EAST: // Set the SE movement if ( (pmti->pt.x > pmti->ptPrev.x) || (pmti->pt.y > pmti->ptPrev.y) ) { pmti->pt.x = pmti->ptPrev.x + iWidthHeight; pmti->pt.y = pmti->ptPrev.y + iWidthHeight; } else { // Set the NW movement if ( (pmti->pt.x < pmti->ptPrev.x) || (pmti->pt.y < pmti->ptPrev.y) ) { pmti->pt.x = pmti->ptPrev.x - iWidthHeight; pmti->pt.y = pmti->ptPrev.y - iWidthHeight; } else { //invalid movement, set to last known position pmti->pt.x = pmti->ptPrev.x; pmti->pt.y = pmti->ptPrev.y; } } break; case eNORTH_EAST: case eSOUTH_WEST: // Set the NE movement if ( (pmti->pt.x > pmti->ptPrev.x) || (pmti->pt.y < pmti->ptPrev.y) ) { pmti->pt.x = pmti->ptPrev.x + iWidthHeight; pmti->pt.y = pmti->ptPrev.y - iWidthHeight; } else { // Set the SW movement if ( (pmti->pt.x < pmti->ptPrev.x) || (pmti->pt.y > pmti->ptPrev.y) ) { pmti->pt.x = pmti->ptPrev.x - iWidthHeight; pmti->pt.y = pmti->ptPrev.y + iWidthHeight; } else { //invalid movement, set to last known position pmti->pt.x = pmti->ptPrev.x; pmti->pt.y = pmti->ptPrev.y; } } break; default: // not in constraint mode yet => do nothing. // Default is freehand break; } } /***************************************************************************/ CEraserTool::CEraserTool() { m_nCmdID = IDMB_ERASERTOOL; m_nStrokeWidth = 8; m_nStrokeShape = squareBrush; m_nCursorID = NULL; } /***************************************************************************/ void CEraserTool::OnPaintOptions( CDC* pDC, const CRect& paintRect, const CRect& optionsRect ) { CRect rect; int cxOctant = (optionsRect.Width() + 1); int cyOctant = (optionsRect.Height() + 1) / 4; rect.left = optionsRect.left; rect.top = optionsRect.top; rect.right = rect.left + cxOctant; rect.bottom = rect.top + cyOctant; for (UINT nSize = 4; nSize <= 10; nSize += 2) { CBrush* pOldBrush; if (nSize == m_nStrokeWidth) { pOldBrush = pDC->SelectObject(GetSysBrush(COLOR_HIGHLIGHT)); pDC->PatBlt(rect.left + (cxOctant - 14) / 2, rect.top + (cyOctant - 14) / 2, 14, 14, PATCOPY); pDC->SelectObject(pOldBrush); } pOldBrush = pDC->SelectObject(GetSysBrush(nSize == m_nStrokeWidth ? COLOR_HIGHLIGHTTEXT : COLOR_BTNTEXT)); pDC->PatBlt(rect.left + (cxOctant - nSize) / 2, rect.top + (cyOctant - nSize) / 2, nSize, nSize, PATCOPY); pDC->SelectObject(pOldBrush); rect.top += cyOctant; rect.bottom += cyOctant; } } /***************************************************************************/ void CEraserTool::OnClickOptions(CImgToolWnd* pWnd, const CRect& optionsRect, const CPoint& clickPoint) { int iOptionNumber; int cyOctant = (optionsRect.Height() + 1) / 4; iOptionNumber = (clickPoint.y / cyOctant); if (iOptionNumber > 3) // there are 4 options, numbered 0,1,2,3 { iOptionNumber = 3; } m_nStrokeWidth = 4 + 2 * iOptionNumber; // int cyOctant = (optionsRect.Height() + 1) / 4; // m_nStrokeWidth = 4 + 2 * (clickPoint.y / cyOctant); pWnd->InvalidateOptions(); } void CEraserTool::OnDrag(CImgWnd* pImgWnd, MTI* pmti) { if (pmti->fLeft) { COLORREF crRealLeftColor = crLeft; COLORREF crRealRightColor = crRight; crLeft = crRight; g_bCustomBrush = FALSE; fDraggingBrush = FALSE; DrawImgLine(pImgWnd->m_pImg, pmti->ptPrev, pmti->pt, crRight, m_nStrokeWidth, squareBrush, TRUE); crLeft = crRealLeftColor; crRight = crRealRightColor; } else { // Just erase pixels that match the drawing color... g_bCustomBrush = FALSE; fDraggingBrush = FALSE; HideBrush(); CDC* pImageDC = CDC::FromHandle(pImgWnd->m_pImg->hDC); CRect rc; // Call with NULL DC to get the CRect to use DrawDCLine(NULL, pmti->ptPrev, pmti->pt, RGB(255, 255, 255), m_nStrokeWidth, squareBrush, rc); CTempBitmap monoBitmap; CDC monoDc; // Create the mono DC and bitmap if (!monoDc.CreateCompatibleDC(NULL) || !monoBitmap.CreateBitmap(rc.Width(), rc.Height(), 1, 1, NULL)) { theApp.SetGdiEmergency(); return; } // Select the bitmap and change the window origin so the mono DC has // the same coordinate system as the image CBitmap* pOldMonoBitmap = monoDc.SelectObject(&monoBitmap); monoDc.SetWindowOrg(rc.left, rc.top); // Clear the mono DC and then draw the area that will be changed monoDc.PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), BLACKNESS); DrawDCLine(monoDc.m_hDC, pmti->ptPrev, pmti->pt, RGB(255, 255, 255), m_nStrokeWidth, squareBrush, rc); DebugShowBitmap(monoDc.m_hDC, rc.left, rc.top, rc.Width(), rc.Height()); // Select the proper palette, and make sure the brush origin is set // correctly for pattern brushes CPalette* pcPaletteOld = theImgBrush.SetBrushPalette(pImageDC, FALSE); pImageDC->SetBrushOrg(0, 0); CBrush rightBrush; rightBrush.CreateSolidBrush(crRight); if (!QuickColorToMono(&monoDc, rc.left, rc.top, rc.Width(), rc.Height(), pImageDC, rc.left, rc.top, SRCAND, crLeft)) { // We will get her for DDB's (in which case we could be using a // dithered brush) or for high color images (so no palette problems) // Create the brush to erase CBrush leftBrush; leftBrush.CreateSolidBrush(crLeft); leftBrush.UnrealizeObject(); //#define DPSxna 0x00820c49L // #define PSDPxax 0x00B8074AL // XOR with the pattern so black is where the pattern was CBrush* pOldBrush = pImageDC->SelectObject(&leftBrush); pImageDC->PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATINVERT); DebugShowBitmap(pImageDC->m_hDC, rc.left, rc.top, rc.Width(), rc.Height()); // Color to mono bitblt to get the final mask // The ROP will take all pixels in the source that match the pattern // and and them with the white pixels in the dest theImgBrush.ColorToMonoBitBlt(&monoDc, rc.left, rc.top, rc.Width(), rc.Height(), pImageDC, rc.left, rc.top, SRCAND, RGB(0, 0, 0)); DebugShowBitmap(monoDc.m_hDC, rc.left, rc.top, rc.Width(), rc.Height()); // XOR again to put the original back pImageDC->PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATINVERT); DebugShowBitmap(pImageDC->m_hDC, rc.left, rc.top, rc.Width(), rc.Height()); pImageDC->SelectObject(pOldBrush); } // Copy the pattern back into the image where the bitmap has white CBrush *pOldBrush = pImageDC->SelectObject(&rightBrush); COLORREF crNewBk, crNewText; GetMonoBltColors(pImageDC->m_hDC, NULL, crNewBk, crNewText); COLORREF crOldBk = pImageDC->SetBkColor(crNewBk); COLORREF crOldText = pImageDC->SetTextColor(crNewText); pImageDC->BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &monoDc, rc.left, rc.top, DSPDxax); pImageDC->SetBkColor(crOldBk); pImageDC->SetTextColor(crOldText); DebugShowBitmap(pImageDC->m_hDC, rc.left, rc.top, rc.Width(), rc.Height()); // Clean up stuff we have selected pImageDC->SelectObject(pOldBrush); monoDc.SelectObject(pOldMonoBitmap); if (pcPaletteOld) pImageDC->SelectPalette(pcPaletteOld, FALSE); InvalImgRect(pImgWnd->m_pImg, &rc); CommitImgRect(pImgWnd->m_pImg, &rc); } if (pmti->pt.x < c_undoRect.left) c_undoRect.left = pmti->pt.x; else if (pmti->pt.x > c_undoRect.right) c_undoRect.right = pmti->pt.x; if (pmti->pt.y < c_undoRect.top) c_undoRect.top = pmti->pt.y; else if (pmti->pt.y > c_undoRect.bottom) c_undoRect.bottom = pmti->pt.y; SetStatusBarPosition(pmti->pt); fDraggingBrush = TRUE; pImgWnd->ShowBrush(pmti->pt); } /***************************************************************************/ void CEraserTool::OnMove(CImgWnd* pImgWnd, MTI* pmti) { COLORREF crRealLeftColor; COLORREF crRealRightColor; crRealLeftColor = crLeft; crRealRightColor = crRight; crLeft = crRight; g_bCustomBrush = FALSE; CImgTool::OnMove(pImgWnd, pmti); crLeft = crRealLeftColor; crRight = crRealRightColor; } /***************************************************************************/ void CEraserTool::OnEndDrag(CImgWnd* pImgWnd, MTI* pmti) { c_undoRect.left -= m_nStrokeWidth / 2; c_undoRect.top -= m_nStrokeWidth / 2; c_undoRect.right += (m_nStrokeWidth + 1) / 2; c_undoRect.bottom += (m_nStrokeWidth + 1) / 2; pImgWnd->FinishUndo(c_undoRect); CImgTool::OnEndDrag(pImgWnd, pmti); // Bypass CFreehandTool } /***************************************************************************/ void CEraserTool::OnShowDragger(CImgWnd* pImgWnd, BOOL bShow) { if (bShow && g_bBrushVisible) { CClientDC dc(pImgWnd); CRect imageRect; pImgWnd->GetImageRect(imageRect); dc.IntersectClipRect(&imageRect); BOOL bGrid = pImgWnd->IsGridVisible(); CRect rect = rcDragBrush; pImgWnd->ImageToClient(rect); dc.PatBlt(rect.left, rect.top, rect.Width() + bGrid, 1, BLACKNESS); dc.PatBlt(rect.left, rect.top + 1, 1, rect.Height() - 2 + bGrid, BLACKNESS); dc.PatBlt(rect.right - 1 + bGrid, rect.top + 1, 1, rect.Height() - 2 + bGrid, BLACKNESS); dc.PatBlt(rect.left, rect.bottom - 1 + bGrid, rect.Width() + bGrid, 1, BLACKNESS); } } /***************************************************************************/ UINT CEraserTool::GetCursorID() { CPoint point; GetCursorPos(&point); CRect rc; CPBView* pcbView = (CPBView*)((CFrameWnd*)AfxGetMainWnd())->GetActiveView(); CImgWnd* pImgWnd = pcbView->m_pImgWnd; pImgWnd->ScreenToClient(&point); pImgWnd->GetClientRect(&rc); if (!rc.PtInRect(point)) { // Return crosshair outside the client rect of the image window return LOWORD(IDC_CROSSHAIR); } pImgWnd->ClientToImage(point); if (point.x > pImgWnd->m_pImg->cxWidth || point.y > pImgWnd->m_pImg->cyHeight) { // Return crosshair outside the drawing area return LOWORD(IDC_CROSSHAIR); } return m_nCursorID; } /***************************************************************************/ CImageWell CAirBrushTool::c_imageWell(IDB_AIROPT, CSize(24, 24)); CAirBrushTool::CAirBrushTool() { m_nCmdID = IDMB_AIRBSHTOOL; m_nStrokeWidth = 8; m_nCursorID = IDCUR_AIRBRUSH; m_bUsesBrush = FALSE; m_bFilled = TRUE; } /***************************************************************************/ void CAirBrushTool::OnPaintOptions( CDC* pDC, const CRect& paintRect, const CRect& optionsRect ) { CPoint pt(optionsRect.left + (optionsRect.Width() / 2 - 24) / 2, optionsRect.top + (optionsRect.Height() / 2 - 24) / 2); c_imageWell.Open(); pDC->SetTextColor(GetSysColor( m_nStrokeWidth == 8 ? COLOR_HIGHLIGHTTEXT : COLOR_BTNTEXT)); pDC->SetBkColor(GetSysColor( m_nStrokeWidth == 8 ? COLOR_HIGHLIGHT : COLOR_BTNFACE)); c_imageWell.DrawImage(pDC, pt, 0, SRCCOPY); pt.x += optionsRect.Width() / 2; pDC->SetTextColor(GetSysColor( m_nStrokeWidth == 16 ? COLOR_HIGHLIGHTTEXT : COLOR_BTNTEXT)); pDC->SetBkColor(GetSysColor( m_nStrokeWidth == 16 ? COLOR_HIGHLIGHT : COLOR_BTNFACE)); c_imageWell.DrawImage(pDC, pt, 1, SRCCOPY); pt.x = optionsRect.left + (optionsRect.Width() - 24) / 2; pDC->SetTextColor(GetSysColor( m_nStrokeWidth == 24 ? COLOR_HIGHLIGHTTEXT : COLOR_BTNTEXT)); pDC->SetBkColor(GetSysColor( m_nStrokeWidth == 24 ? COLOR_HIGHLIGHT : COLOR_BTNFACE)); pt.y += optionsRect.Height() / 2; c_imageWell.DrawImage(pDC, pt, 2, SRCCOPY); c_imageWell.Close(); } /***************************************************************************/ void CAirBrushTool::OnClickOptions(CImgToolWnd* pWnd, const CRect& optionsRect, const CPoint& clickPoint) { UINT nNewStrokeWidth; if (clickPoint.y > optionsRect.Height() / 2) nNewStrokeWidth = 24; else if (clickPoint.x > optionsRect.Width() / 2) nNewStrokeWidth = 16; else nNewStrokeWidth = 8; if (nNewStrokeWidth != m_nStrokeWidth) SetStrokeWidth(nNewStrokeWidth); } /***************************************************************************/ void CAirBrushTool::OnStartDrag(CImgWnd* pImgWnd, MTI* pmti) { pImgWnd->SetTimer(1, 0, NULL); // FUTURE: rate should be adjustable CFreehandTool::OnStartDrag(pImgWnd, pmti); } /***************************************************************************/ void CAirBrushTool::OnDrag(CImgWnd* pImgWnd, MTI* pmti) { CPoint pt; CRect rect; fDraggingBrush = FALSE; int nDiam = (m_nStrokeWidth + 1) & ~1; // nDiam must be even if (nDiam < 4) nDiam = 4; int nRadius = nDiam / 2; int nRadiusSquared = (nDiam / 2) * (nDiam / 2); // Start a bounding rect for changes made in the following loop rect.left = rect.right = pmti->pt.x; rect.top = rect.bottom = pmti->pt.y; m_bCtrlDown = pmti->fCtrlDown; // save it for the timer SetupPenBrush(pImgWnd->m_pImg->hDC, !pmti->fLeft, TRUE, m_bCtrlDown); for (int i = 0; i < 10; i++) { // Loop here until we randomly pick a point inside a circle // centered around the mouse with a diameter of m_nStrokeWidth... #ifdef _DEBUG int nTrys = 0; #endif do { #ifdef _DEBUG if (nTrys++ > 10) { TRACE(TEXT("The airbrush is clogged!\n")); break; } #endif pt = pmti->pt; pt.x += (rand() % (nDiam + 1)) - nRadius; pt.y += (rand() % (nDiam + 1)) - nRadius; } while (((pt.x - pmti->pt.x) * (pt.x - pmti->pt.x) + (pt.y - pmti->pt.y) * (pt.y - pmti->pt.y)) > nRadiusSquared); PatBlt(pImgWnd->m_pImg->hDC, pt.x, pt.y, 1, 1, PATCOPY); if (pt.x < rect.left) rect.left = pt.x; else if (pt.x + 1 > rect.right) rect.right = pt.x + 1; if (pt.y < rect.top) rect.top = pt.y; else if (pt.y + 1 > rect.bottom) rect.bottom = pt.y + 1; } SetupPenBrush(pImgWnd->m_pImg->hDC, !pmti->fLeft, FALSE, m_bCtrlDown); c_undoRect |= rect; InvalImgRect(pImgWnd->m_pImg, &rect); CommitImgRect(pImgWnd->m_pImg, &rect); SetStatusBarPosition(pmti->pt); } /***************************************************************************/ void CAirBrushTool::OnEndDrag(CImgWnd* pImgWnd, MTI* pmti) { ::KillTimer(pImgWnd->GetSafeHwnd(), 1); CFreehandTool::OnEndDrag(pImgWnd, pmti); } /***************************************************************************/ void CAirBrushTool::OnTimer(CImgWnd* pImgWnd, MTI* pmti) { pmti->fCtrlDown = m_bCtrlDown; OnDrag(pImgWnd, pmti); } /***************************************************************************/ void CAirBrushTool::OnCancel(CImgWnd* pImgWnd) { ::KillTimer(pImgWnd->GetSafeHwnd(), 1); CImgTool::OnCancel(pImgWnd); } /***************************************************************************/ CLineTool::CLineTool() { m_bUsesBrush = FALSE; m_nStrokeWidth = 1; m_nCmdID = IDMB_LINETOOL; } /***************************************************************************/ void CLineTool::Render(CDC* pDC, CRect& rect, BOOL bLeft, BOOL bCommit, BOOL bCtrlDown) { COLORREF color; // use transparent color if defined if (bCtrlDown && crTrans != TRANS_COLOR_NONE) { color = crTrans; } else { color = bLeft ? crLeft : crRight; } int sx = rect.left; int sy = rect.top; int ex = rect.right; int ey = rect.bottom; DrawImgLine( pImgCur, rect.TopLeft(), rect.BottomRight(), color, m_nStrokeWidth, m_nStrokeShape, FALSE ); CRect rc; if (sx < ex) { rc.left = sx; rc.right = ex + 1; } else { rc.left = ex; rc.right = sx + 1; } if (sy < ey) { rc.top = sy; rc.bottom = ey + 1; } else { rc.top = ey; rc.bottom = sy + 1; } rc.left -= m_nStrokeWidth; rc.top -= m_nStrokeWidth; rc.right += m_nStrokeWidth; rc.bottom += m_nStrokeWidth; rect = rc; } /******************************************************************************/ // Given an x and y coordinate, we can calculate the angle from the x axis in // the right triangle using the Tan(a) algorithm. Where // tan(a) = opposite/adjacent or y/x. // // In order to constrain the line drawing, we need to determine the angle // from the x axis and constrain it to the nearest 45 degree line (0 degree, // 45 degree, 90 degree,....). // // Thus we can use the following rule : // // 0 Degrees <= Angle < 45/2 Degrees Constrained to 0 Degrees // 45/2 Degrees <= Angle < 45+45/2 Degrees Constrained to 45 Degrees // 45+45/2 Degrees <= Angle < 90 Degrees Constrained to 90 Degrees // // // We can translate this rule into the below using tan(angle) = y/x and the // fact that Tan(0) = 0, Tan(22.5) = .414, tan(67.5) = 2.414, tan(90) = infinity // // 0 <= y/x < .414 Constrained to 0 Degrees // .414 <= y/x < 2.414 Constrained to 45 Degrees // 2.414 <= y/x Constrained to 90 Degrees // // For more precision, we will multiply everything by 1000 to give us finally // the following table // // 0 <= (1000*y)/x < 414 Constrained to 0 Degrees // 414 <= (1000*y)/x < 2414 Constrained to 45 Degrees // 2414 <= (1000*y)/x Constrained to 90 Degrees void CLineTool::AdjustPointsForConstraint(MTI *pmti) { if (pmti != NULL) { int iAngle = 0; long lcy = abs( (pmti->ptDown).y - (pmti->pt).y ); long lcx = abs( (pmti->ptDown).x - (pmti->pt).x ); long lResult; if (lcx != 0) { lResult = (lcy*1000)/lcx; } else { lResult = 2414; // default to 90 degrees if x value is 0. } if (lResult >= 2414) { iAngle = 90; } else { if (lResult >= 414) { iAngle = 45; } else { iAngle = 0; } } // int iWidthHeight = min( abs(pmti->ptDown.x - pmti->pt.x), // abs(pmti->ptDown.y - pmti->pt.y)); int iWidthHeight = ( abs(pmti->ptDown.x - pmti->pt.x) + abs(pmti->ptDown.y - pmti->pt.y) ) / 2 ; switch (iAngle) { default: //if for some reason, angle is not valid case, use 0 case 0: pmti->pt.y = pmti->ptDown.y; break; case 45: if (pmti->pt.x < pmti->ptDown.x) { pmti->pt.x = pmti->ptDown.x - iWidthHeight; } else { pmti->pt.x = pmti->ptDown.x + iWidthHeight; } if (pmti->pt.y < pmti->ptDown.y) { pmti->pt.y = pmti->ptDown.y - iWidthHeight; } else { pmti->pt.y = pmti->ptDown.y + iWidthHeight; } break; case 90: pmti->pt.x = pmti->ptDown.x; break; } } } /***************************************************************************/ CRectTool::CRectTool() { m_nCmdID = IDMB_RECTTOOL; } /***************************************************************************/ CRoundRectTool::CRoundRectTool() { m_nCmdID = IDMB_RNDRECTTOOL; } /***************************************************************************/ CEllipseTool::CEllipseTool() { m_nCmdID = IDMB_ELLIPSETOOL; } /***************************************************************************/ CPickColorTool::CPickColorTool() { m_bIsUndoable = FALSE; m_bCanBePrevTool = FALSE; m_bToggleWithPrev = TRUE; m_Color = ::GetSysColor( COLOR_BTNFACE ); m_nCursorID = IDC_EYEDROP; m_nCmdID = IDMY_PICKCOLOR; } /***************************************************************************/ void CPickColorTool::OnActivate(BOOL bActivate) { g_bPickingColor = bActivate; m_Color = ::GetSysColor( COLOR_BTNFACE ); CImgTool::OnActivate(bActivate); } /***************************************************************************/ void CPickColorTool::OnStartDrag(CImgWnd* pImgWnd, MTI* pmti) { CImgTool::OnStartDrag(pImgWnd, pmti); OnDrag(pImgWnd, pmti); } /***************************************************************************/ void CPickColorTool::OnDrag(CImgWnd* pImgWnd, MTI* pmti) { COLORREF cr = GetPixel(pImgWnd->m_pImg->hDC, pmti->pt.x, pmti->pt.y); BYTE red = GetRValue( cr ); BYTE green = GetGValue( cr ); BYTE blue = GetBValue( cr ); if (theApp.m_bPaletted) m_Color = PALETTERGB( red, green, blue ); else m_Color = RGB( red, green, blue ); if (g_pImgToolWnd && g_pImgToolWnd->m_hWnd && IsWindow(g_pImgToolWnd->m_hWnd) ) g_pImgToolWnd->InvalidateOptions(); } /***************************************************************************/ void CPickColorTool::OnEndDrag(CImgWnd* pImgWnd, MTI* pmti) { if (pmti->fCtrlDown) // pick transparent color { SetTransColor (m_Color); } else if (pmti->fLeft) SetDrawColor ( m_Color ); else SetEraseColor( m_Color ); m_Color = ::GetSysColor( COLOR_BTNFACE ); if (g_pImgToolWnd && g_pImgToolWnd->m_hWnd && IsWindow(g_pImgToolWnd->m_hWnd) ) g_pImgToolWnd->InvalidateOptions(); SelectPrevious(); CImgTool::OnEndDrag( pImgWnd, pmti ); } /***************************************************************************/ void CPickColorTool::OnCancel(CImgWnd* pImgWnd) { SelectPrevious(); CImgTool::OnCancel(pImgWnd); } /***************************************************************************/ void CPickColorTool::OnPaintOptions( CDC* pDC, const CRect& paintRect, const CRect& optionsRect ) { CPalette* pOldPal = NULL; if (theApp.m_pPalette) { pOldPal = pDC->SelectPalette( theApp.m_pPalette, FALSE ); pDC->RealizePalette(); } CBrush br; if (br.CreateSolidBrush( m_Color )) { pDC->FillRect( &paintRect, &br ); br.DeleteObject(); } if (pOldPal) pDC->SelectPalette( pOldPal, FALSE ); } /***************************************************************************/ CFloodTool::CFloodTool() { m_nCursorID = IDC_FLOOD; m_nCmdID = IDMB_FILLTOOL; m_bFilled = TRUE; } /***************************************************************************/ void CFloodTool::OnPaintOptions(CDC* pDC, const CRect& paintRect, const CRect& optionsRect) { // PaintStdPattern(pDC, paintRect, optionsRect); } /***************************************************************************/ void CFloodTool::OnClickOptions(CImgToolWnd* pWnd, const CRect& optionsRect, const CPoint& clickPoint) { CImgTool::OnClickOptions(pWnd, optionsRect, clickPoint); } /***************************************************************************/ void CFloodTool::OnStartDrag(CImgWnd* pImgWnd, MTI* pmti) { CImgTool::OnStartDrag( pImgWnd, pmti ); CPalette *pcPaletteOld = NULL; IMG* pimg = pImgWnd->m_pImg; CDC* pDC = CDC::FromHandle( pimg->hDC ); CBrush brush; CBrush* pOldBrush = NULL; COLORREF color; if (pmti->fCtrlDown && crTrans != TRANS_COLOR_NONE) { color = crTrans; } else { color = pmti->fLeft ? crLeft : crRight; } if (theApp.m_pPalette) { pcPaletteOld = pDC->SelectPalette( theApp.m_pPalette, FALSE ); pDC->RealizePalette(); } if (brush.CreateSolidBrush( color )) { pOldBrush = pDC->SelectObject( &brush ); COLORREF crFillThis = pDC->GetPixel( pmti->pt.x, pmti->pt.y ); BYTE iRed = GetRValue( crFillThis ); BYTE iGreen = GetGValue( crFillThis ); BYTE iBlue = GetBValue( crFillThis ); if (theApp.m_bPaletted) crFillThis = PALETTERGB( iRed, iGreen, iBlue ); else crFillThis = RGB( iRed, iGreen, iBlue ); pDC->ExtFloodFill( pmti->pt.x, pmti->pt.y, crFillThis, FLOODFILLSURFACE ); pDC->SelectObject( pOldBrush ); InvalImgRect ( pimg, NULL ); CommitImgRect( pimg, NULL ); } else { theApp.SetGdiEmergency(); } if (pcPaletteOld) pDC->SelectPalette( pcPaletteOld, FALSE ); } /***************************************************************************/ void CFloodTool::OnEndDrag(CImgWnd* pImgWnd, MTI* pmti) { pImgWnd->FinishUndo(CRect(0, 0, pImgWnd->m_pImg->cxWidth, pImgWnd->m_pImg->cyHeight)); CImgTool::OnEndDrag(pImgWnd, pmti); } /***************************************************************************/ CRect CSelectTool::c_selectRect; CImageWell CSelectTool::c_imageWell(IDB_SELOPT, CSize(37, 23)); CSelectTool::CSelectTool() { m_bIsUndoable = FALSE; m_nCmdID = IDMB_PICKTOOL; m_bCanBePrevTool = FALSE; } /***************************************************************************/ void CSelectTool::OnPaintOptions( CDC* pDC, const CRect& paintRect, const CRect& optionsRect ) { CPoint pt(optionsRect.left + (optionsRect.Width() - 37) / 2, optionsRect.top + (optionsRect.Height() / 2 - 23) / 2); CRect selRect(pt.x - 3, pt.y - 3, pt.x + 37 + 3, pt.y + 23 + 3); CBrush* pOldBrush; pOldBrush = pDC->SelectObject( GetSysBrush(theImgBrush.m_bOpaque ? COLOR_HIGHLIGHT : COLOR_BTNFACE)); pDC->PatBlt(selRect.left, selRect.top, selRect.Width(), selRect.Height(), PATCOPY); pDC->SelectObject(pOldBrush); selRect.OffsetRect(0, optionsRect.Height() / 2); pOldBrush = pDC->SelectObject(GetSysBrush(theImgBrush.m_bOpaque ? COLOR_BTNFACE : COLOR_HIGHLIGHT)); pDC->PatBlt(selRect.left, selRect.top, selRect.Width(), selRect.Height(), PATCOPY); pDC->SelectObject(pOldBrush); c_imageWell.Open(); c_imageWell.DrawImage(pDC, pt, 0); pt.y += optionsRect.Height() / 2; c_imageWell.DrawImage(pDC, pt, 1); c_imageWell.Close(); } /***************************************************************************/ void CSelectTool::OnClickOptions(CImgToolWnd* pWnd, const CRect& optionsRect, const CPoint& clickPoint) { BOOL bNewOpaque = clickPoint.y < optionsRect.Height() / 2; if (bNewOpaque != theImgBrush.m_bOpaque) { HideBrush(); theImgBrush.m_bOpaque = bNewOpaque; theImgBrush.RecalcMask(crRight); CImgWnd::GetCurrent()->MoveBrush(theImgBrush.m_rcSelection); pWnd->InvalidateOptions(); } } /***************************************************************************/ void CSelectTool::InvertSelectRect(CImgWnd* pImgWnd) { if (c_selectRect.IsRectEmpty()) return; CClientDC dc( pImgWnd ); CBrush* pOldBrush = NULL; int iLineWidth = pImgWnd->GetZoom(); if (g_brSelectHorz.m_hObject != NULL) pOldBrush = dc.SelectObject( &g_brSelectHorz ); else pOldBrush = (CBrush*)dc.SelectStockObject( BLACK_BRUSH ); CRect invertRect = c_selectRect; pImgWnd->ImageToClient( invertRect ); int iWidth = invertRect.Width(); int iHeight = invertRect.Height(); dc.PatBlt( invertRect.left, invertRect.top, iWidth - iLineWidth, iLineWidth, PATINVERT ); dc.PatBlt( invertRect.left, invertRect.top + iHeight - iLineWidth, iWidth - iLineWidth, iLineWidth, PATINVERT ); if (g_brSelectVert.m_hObject != NULL) dc.SelectObject( &g_brSelectVert ); dc.PatBlt( invertRect.left, invertRect.top + iLineWidth * 2, iLineWidth, iHeight - iLineWidth * 3, PATINVERT ); dc.PatBlt( invertRect.right - iLineWidth, invertRect.top, iLineWidth, iHeight, PATINVERT ); if (pOldBrush != NULL) dc.SelectObject( pOldBrush ); } /***************************************************************************/ void CSelectTool::OnShowDragger(CImgWnd* pImgWnd, BOOL bShow) { if (!bShow) { InvertSelectRect(pImgWnd); c_selectRect.SetRect(0, 0, 0, 0); } } /***************************************************************************/ void CSelectTool::OnActivate(BOOL bActivate) { if (!bActivate) { if (theImgBrush.m_pImg != NULL) { if (! theImgBrush.m_bFirstDrag) CommitSelection(TRUE); InvalImgRect(theImgBrush.m_pImg, NULL); // erase selection tracker theImgBrush.m_pImg = NULL; } } CImgTool::OnActivate(bActivate); } /***************************************************************************/ void CSelectTool::OnStartDrag(CImgWnd* pImgWnd, MTI* pmti) { CImgTool::OnStartDrag(pImgWnd, pmti); CommitSelection(TRUE); pImgWnd->EraseTracker(); theImgBrush.m_bMakingSelection = TRUE; } /***************************************************************************/ void CSelectTool::OnDrag(CImgWnd* pImgWnd, MTI* pmti) { CRect newSelectRect(pmti->ptDown.x, pmti->ptDown.y, pmti->pt.x, pmti->pt.y); FixRect(&newSelectRect); newSelectRect.right += 1; newSelectRect.bottom += 1; if (newSelectRect.left < 0) newSelectRect.left = 0; if (newSelectRect.top < 0) newSelectRect.top = 0; if (newSelectRect.right > pImgWnd->GetImg()->cxWidth) newSelectRect.right = pImgWnd->GetImg()->cxWidth; if (newSelectRect.bottom > pImgWnd->GetImg()->cyHeight) newSelectRect.bottom = pImgWnd->GetImg()->cyHeight; if (newSelectRect != c_selectRect) { InvertSelectRect(pImgWnd); c_selectRect = newSelectRect; InvertSelectRect(pImgWnd); } SetStatusBarPosition(pmti->ptDown); SetStatusBarSize(c_selectRect.Size()); } /***************************************************************************/ void CSelectTool::OnEndDrag(CImgWnd* pImgWnd, MTI* pmti) { InvertSelectRect(pImgWnd); c_selectRect.SetRect(0, 0, 0, 0); CRect rcPick; theImgBrush.m_bMakingSelection = FALSE; if (pmti->ptDown.x > pmti->pt.x) { rcPick.left = pmti->pt.x; rcPick.right = pmti->ptDown.x; } else { rcPick.left = pmti->ptDown.x; rcPick.right = pmti->pt.x; } if (pmti->ptDown.y > pmti->pt.y) { rcPick.top = pmti->pt.y; rcPick.bottom = pmti->ptDown.y; } else { rcPick.top = pmti->ptDown.y; rcPick.bottom = pmti->pt.y; } if (rcPick.left < 0) rcPick.left = 0; if (rcPick.top < 0) rcPick.top = 0; if (rcPick.right > pImgWnd->m_pImg->cxWidth - 1) rcPick.right = pImgWnd->m_pImg->cxWidth - 1; if (rcPick.bottom > pImgWnd->m_pImg->cyHeight - 1) rcPick.bottom = pImgWnd->m_pImg->cyHeight - 1; if (rcPick.Width() == 0 || rcPick.Height() == 0) { theImgBrush.TopLeftHandle(); theImgBrush.m_bMoveSel = theImgBrush.m_bSmearSel = FALSE; g_bCustomBrush = FALSE; SetCombineMode(combineColor); InvalImgRect(pImgWnd->m_pImg, NULL); // redraw selection theImgBrush.m_pImg = NULL; } else { rcPick.right += 1; rcPick.bottom += 1; pImgWnd->MakeBrush(pImgWnd->m_pImg->hDC, rcPick ); } ClearStatusBarSize(); CImgTool::OnEndDrag(pImgWnd, pmti); if (pmti->fRight && !pmti->fLeft) { CPoint pt = pmti->pt; pImgWnd->OnRButtonDownInSel(&pt); } } /***************************************************************************/ void CSelectTool::OnCancel(CImgWnd* pImgWnd) { if (! theImgBrush.m_bMakingSelection && CWnd::GetCapture() != pImgWnd) { // We were not selecting or dragging, just cancel the select tool... CommitSelection(TRUE); theImgBrush.TopLeftHandle(); theImgBrush.m_bMoveSel = theImgBrush.m_bSmearSel = FALSE; g_bCustomBrush = FALSE; SetCombineMode(combineColor); if (theImgBrush.m_pImg != NULL) InvalImgRect(theImgBrush.m_pImg, NULL); // redraw selection theImgBrush.m_pImg = NULL; CImgTool::OnCancel(pImgWnd); return; } if (!theImgBrush.m_bMakingSelection && CWnd::GetCapture() == pImgWnd) { HideBrush(); if (!theImgBrush.m_bMoveSel && !theImgBrush.m_bSmearSel) { if (g_bCustomBrush) { theImgBrush.TopLeftHandle(); g_bCustomBrush = FALSE; SetCombineMode(combineColor); } else { if (theImgBrush.m_pImg) CommitSelection(TRUE); InvalImgRect(pImgWnd->m_pImg, NULL); // erase the dragger } } } InvertSelectRect(pImgWnd); c_selectRect.SetRect(0, 0, 0, 0); theImgBrush.TopLeftHandle(); g_bCustomBrush = FALSE; theImgBrush.m_pImg = NULL; theImgBrush.m_bMoveSel = theImgBrush.m_bSmearSel = FALSE; theImgBrush.m_bMakingSelection = FALSE; InvalImgRect(pImgWnd->m_pImg, NULL); CImgTool::OnCancel(pImgWnd); } /***************************************************************************/ BOOL CSelectTool::IsToolModal(void) { if (theImgBrush.m_pImg) { return(TRUE); } return(CImgTool::IsToolModal()); } /***************************************************************************/ UINT CSelectTool::GetCursorID() { CPoint point; GetCursorPos(&point); CImgWnd* pImgWnd = (CImgWnd*)CWnd::WindowFromPoint(point); if (pImgWnd->IsKindOf(RUNTIME_CLASS(CImgWnd)) && pImgWnd->GetImg() == pImgCur && theImgBrush.m_pImg != NULL) { pImgWnd->ScreenToClient(&point); pImgWnd->ClientToImage(point); if (theImgBrush.m_rcSelection.PtInRect(point)) return IDCUR_MOVE; } return m_nCursorID; } /***************************************************************************/ CRect CZoomTool::c_zoomRect; CImgWnd* CZoomTool::c_pImgWnd; CImageWell CZoomTool::c_imageWell(IDB_ZOOMOPT, CSize(23, 9)); /***************************************************************************/ CZoomTool::CZoomTool() { m_bIsUndoable = FALSE; m_bCanBePrevTool = FALSE; m_bToggleWithPrev = TRUE; m_nCursorID = IDC_ZOOMIN; m_nCmdID = IDMB_ZOOMTOOL; } /***************************************************************************/ void CZoomTool::OnPaintOptions( CDC* pDC, const CRect& paintRect, const CRect& optionsRect ) { int nCurZoom = CImgWnd::GetCurrent()->GetZoom(); int dy = optionsRect.Height() / 4; CPoint pt(optionsRect.left + (optionsRect.Width() - 23) / 2, optionsRect.top + optionsRect.Height() / dy); c_imageWell.Open(); if (nCurZoom == 1) { CBrush* pOldBrush; pOldBrush = pDC->SelectObject(GetSysBrush(COLOR_HIGHLIGHT)); pDC->PatBlt(pt.x - 8, pt.y - 2, 23 + 16, 9 + 4, PATCOPY); pDC->SelectObject(pOldBrush); } pDC->SetTextColor(GetSysColor( nCurZoom == 1 ? COLOR_HIGHLIGHTTEXT : COLOR_BTNTEXT)); pDC->SetBkColor(GetSysColor( nCurZoom == 1 ? COLOR_HIGHLIGHT : COLOR_BTNFACE)); c_imageWell.DrawImage(pDC, pt, 0, SRCCOPY); pt.y += dy; if (nCurZoom == 2) { CBrush* pOldBrush; pOldBrush = pDC->SelectObject(GetSysBrush(COLOR_HIGHLIGHT)); pDC->PatBlt(pt.x - 8, pt.y - 2, 23 + 16, 9 + 4, PATCOPY); pDC->SelectObject(pOldBrush); } pDC->SetTextColor(GetSysColor( nCurZoom == 2 ? COLOR_HIGHLIGHTTEXT : COLOR_BTNTEXT)); pDC->SetBkColor(GetSysColor( nCurZoom == 2 ? COLOR_HIGHLIGHT : COLOR_BTNFACE)); c_imageWell.DrawImage(pDC, pt, 1, SRCCOPY); pt.y += dy; if (nCurZoom == 6) { CBrush* pOldBrush; pOldBrush = pDC->SelectObject(GetSysBrush(COLOR_HIGHLIGHT)); pDC->PatBlt(pt.x - 8, pt.y - 2, 23 + 16, 9 + 4, PATCOPY); pDC->SelectObject(pOldBrush); } pDC->SetTextColor(GetSysColor( nCurZoom == 6 ? COLOR_HIGHLIGHTTEXT : COLOR_BTNTEXT)); pDC->SetBkColor(GetSysColor( nCurZoom == 6 ? COLOR_HIGHLIGHT : COLOR_BTNFACE)); c_imageWell.DrawImage(pDC, pt, 2, SRCCOPY); pt.y += dy; if (nCurZoom == 8) { CBrush* pOldBrush; pOldBrush = pDC->SelectObject(GetSysBrush(COLOR_HIGHLIGHT)); pDC->PatBlt(pt.x - 8, pt.y - 2, 23 + 16, 9 + 4, PATCOPY); pDC->SelectObject(pOldBrush); } pDC->SetTextColor(GetSysColor( nCurZoom == 8 ? COLOR_HIGHLIGHTTEXT : COLOR_BTNTEXT)); pDC->SetBkColor(GetSysColor( nCurZoom == 8 ? COLOR_HIGHLIGHT : COLOR_BTNFACE));; c_imageWell.DrawImage(pDC, pt, 3, SRCCOPY); c_imageWell.Close(); } /***************************************************************************/ void CZoomTool::OnClickOptions(CImgToolWnd* pWnd, const CRect& optionsRect, const CPoint& clickPoint) { int nNewZoom = clickPoint.y / (optionsRect.Height() / 4) + 1; if (nNewZoom >= 3) nNewZoom *= 2; if (nNewZoom != CImgWnd::GetCurrent()->GetZoom()) { CImgWnd::GetCurrent()->SetZoom(nNewZoom); CImgWnd::GetCurrent()->CheckScrollBars(); pWnd->InvalidateOptions(); } SelectPrevious(); } /***************************************************************************/ void CZoomTool::OnLeave(CImgWnd* pImgWnd, MTI* pmti) { InvertZoomRect(); c_zoomRect.SetRect(0, 0, 0, 0); } /***************************************************************************/ void CZoomTool::OnShowDragger(CImgWnd* pImgWnd, BOOL bShow) { InvertZoomRect(); } /***************************************************************************/ void CZoomTool::InvertZoomRect() { if (c_zoomRect.IsRectEmpty()) return; CClientDC dc(c_pImgWnd); CBrush* pOldBrush = (CBrush*)dc.SelectStockObject(NULL_BRUSH); dc.SetROP2(R2_NOT); CRect invertRect = c_zoomRect; c_pImgWnd->ImageToClient(invertRect); dc.Rectangle(&invertRect); dc.SelectObject(pOldBrush); } /***************************************************************************/ void CZoomTool::OnMove(CImgWnd* pImgWnd, MTI* pmti) { if (pImgWnd->GetZoom() > 1) return; CRect viewRect; pImgWnd->GetClientRect(&viewRect); int nPrevZoom = pImgWnd->GetPrevZoom(); CRect newZoomRect; CSize viewSize = viewRect.Size(); if (viewSize.cx > pImgWnd->m_pImg->cxWidth * nPrevZoom) viewSize.cx = pImgWnd->m_pImg->cxWidth * nPrevZoom; if (viewSize.cy > pImgWnd->m_pImg->cyHeight * nPrevZoom) viewSize.cy = pImgWnd->m_pImg->cyHeight * nPrevZoom; newZoomRect.left = pmti->pt.x; newZoomRect.top = pmti->pt.y; newZoomRect.right = newZoomRect.left + viewSize.cx / nPrevZoom; newZoomRect.bottom = newZoomRect.top + viewSize.cy / nPrevZoom; newZoomRect.OffsetRect(-newZoomRect.Width() / 2, -newZoomRect.Height() / 2); int xAdjust = 0; int yAdjust = 0; if (newZoomRect.left < 0) xAdjust = -newZoomRect.left; else if ((xAdjust = pImgWnd->m_pImg->cxWidth - newZoomRect.right) > 0) xAdjust = 0; if (newZoomRect.top < 0) yAdjust = -newZoomRect.top; else if ((yAdjust = pImgWnd->m_pImg->cyHeight - newZoomRect.bottom) > 0) yAdjust = 0; newZoomRect.OffsetRect(xAdjust, yAdjust); if (newZoomRect != c_zoomRect) { InvertZoomRect(); c_pImgWnd = pImgWnd; c_zoomRect = newZoomRect; InvertZoomRect(); } } /***************************************************************************/ void CZoomTool::OnStartDrag(CImgWnd* pImgWnd, MTI* pmti) { CImgTool::OnStartDrag(pImgWnd, pmti); c_pImgWnd = pImgWnd; InvertZoomRect(); if (pImgWnd->GetZoom() == 1) { pImgWnd->SetZoom( pImgWnd->GetPrevZoom() ); pImgWnd->CheckScrollBars(); pImgWnd->SetScroll(-c_zoomRect.left - 1, -c_zoomRect.top - 1); } else { pImgWnd->SetZoom(1); pImgWnd->CheckScrollBars(); } c_zoomRect.SetRect(0, 0, 0, 0); } /***************************************************************************/ void CZoomTool::OnEndDrag(CImgWnd* pImgWnd, MTI* pmti) { SelectPrevious(); CImgTool::OnEndDrag(pImgWnd, pmti); } /***************************************************************************/ void CZoomTool::OnCancel(CImgWnd* pImgWnd) { InvertZoomRect(); c_zoomRect.SetRect(0, 0, 0, 0); SelectPrevious(); CImgTool::OnCancel(pImgWnd); } /***************************************************************************/