Windows2000/private/windows/shell/accesory/mspaint/imgtools.cpp
2020-09-30 17:12:32 +02:00

3016 lines
76 KiB
C++

#include "stdafx.h"
#include "global.h"
#include "pbrush.h"
#include "pbrusdoc.h"
#include "pbrusfrm.h"
#include "pbrusvw.h"
#include "minifwnd.h"
#include "bmobject.h"
#include "imgsuprt.h"
#include "imgwnd.h"
#include "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;
}
}
}
}
}
}
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)
{
pImgWnd->KillTimer(1);
CFreehandTool::OnEndDrag(pImgWnd, pmti);
}
void CAirBrushTool::OnTimer(CImgWnd* pImgWnd, MTI* pmti)
{
pmti->fCtrlDown = m_bCtrlDown;
OnDrag(pImgWnd, pmti);
}
void CAirBrushTool::OnCancel(CImgWnd* pImgWnd)
{
pImgWnd->KillTimer(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);
}