[MSPAINT] Improve Undo/Redo handling of selection (#6035)

Consistent behavior of the application.
- Add ShiftPtStack and BuildMaskFromPtStack
  helper functions.
- Move some codes of selectionModel to
  mouse.cpp.
CORE-19226
This commit is contained in:
Katayama Hirofumi MZ 2023-11-25 13:44:31 +09:00 committed by GitHub
parent ab0119c61f
commit b8598e095d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 134 additions and 205 deletions

View File

@ -648,9 +648,9 @@ LRESULT CCanvasWindow::OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
LRESULT CCanvasWindow::OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) LRESULT CCanvasWindow::OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{ {
if (wParam == VK_ESCAPE && ::GetCapture() == m_hWnd) if (wParam == VK_ESCAPE)
{ {
cancelDrawing(); OnEndDraw(TRUE);
::ReleaseCapture(); ::ReleaseCapture();
m_nMouseDownMsg = 0; m_nMouseDownMsg = 0;
m_hitCanvasSizeBox = HIT_NONE; m_hitCanvasSizeBox = HIT_NONE;
@ -698,19 +698,10 @@ LRESULT CCanvasWindow::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
return 0; return 0;
} }
VOID CCanvasWindow::cancelDrawing() VOID CCanvasWindow::OnEndDraw(BOOL bCancel)
{ {
selectionModel.ClearColorImage();
selectionModel.ClearMaskImage();
m_drawing = FALSE;
toolsModel.OnEndDraw(TRUE);
Invalidate(FALSE);
}
VOID CCanvasWindow::finishDrawing()
{
toolsModel.OnEndDraw(FALSE);
m_drawing = FALSE; m_drawing = FALSE;
toolsModel.OnEndDraw(bCancel);
Invalidate(FALSE); Invalidate(FALSE);
} }

View File

@ -42,8 +42,7 @@ public:
BOOL m_drawing; BOOL m_drawing;
VOID cancelDrawing(); VOID OnEndDraw(BOOL bCancel);
VOID finishDrawing();
VOID updateScrollRange(); VOID updateScrollRange();
VOID updateScrollPos(INT x = 0, INT y = 0); VOID updateScrollPos(INT x = 0, INT y = 0);

View File

@ -164,8 +164,13 @@ void ImageModel::PushImageForUndo(const RECT& rcPartial)
part.m_bPartial = TRUE; part.m_bPartial = TRUE;
part.m_rcPart = rcPartial; part.m_rcPart = rcPartial;
CRect rcImage = { 0, 0, GetWidth(), GetHeight() };
CRect& rc = part.m_rcPart;
if (!rc.IntersectRect(rc, rcImage))
rc.SetRect(-1, -1, 0, 0);
HBITMAP hbmMaster = LockBitmap(); HBITMAP hbmMaster = LockBitmap();
part.m_hbmImage = getSubImage(hbmMaster, rcPartial); part.m_hbmImage = getSubImage(hbmMaster, rc);
UnlockBitmap(hbmMaster); UnlockBitmap(hbmMaster);
PushDone(); PushDone();
@ -351,16 +356,3 @@ void ImageModel::UnlockBitmap(HBITMAP hbmLocked)
m_hbmMaster = hbmLocked; m_hbmMaster = hbmLocked;
m_hbmOld = ::SelectObject(m_hDrawingDC, m_hbmMaster); // Re-select m_hbmOld = ::SelectObject(m_hDrawingDC, m_hbmMaster); // Re-select
} }
void ImageModel::SelectionClone(BOOL bUndoable)
{
if (!selectionModel.m_bShow || selectionModel.m_rc.IsRectEmpty())
return;
if (bUndoable)
PushImageForUndo();
selectionModel.DrawSelection(m_hDrawingDC, paletteModel.GetBgColor(),
toolsModel.IsBackgroundTransparent());
NotifyImageChanged();
}

View File

@ -51,7 +51,6 @@ public:
void NotifyImageChanged(); void NotifyImageChanged();
BOOL IsBlackAndWhite(); BOOL IsBlackAndWhite();
void PushBlackAndWhite(); void PushBlackAndWhite();
void SelectionClone(BOOL bUndoable = TRUE);
protected: protected:
HDC m_hDrawingDC; // The device context for this class HDC m_hDrawingDC; // The device context for this class

View File

@ -406,7 +406,7 @@ void CMainWindow::alignChildrenToMainWindow()
void CMainWindow::saveImage(BOOL overwrite) void CMainWindow::saveImage(BOOL overwrite)
{ {
canvasWindow.finishDrawing(); canvasWindow.OnEndDraw(FALSE);
// Is the extension not supported? // Is the extension not supported?
PWCHAR pchDotExt = PathFindExtensionW(g_szFileName); PWCHAR pchDotExt = PathFindExtensionW(g_szFileName);
@ -606,7 +606,7 @@ LRESULT CMainWindow::OnDestroy(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
BOOL CMainWindow::ConfirmSave() BOOL CMainWindow::ConfirmSave()
{ {
canvasWindow.finishDrawing(); canvasWindow.OnEndDraw(FALSE);
if (imageModel.IsImageSaved()) if (imageModel.IsImageSaved())
return TRUE; return TRUE;
@ -693,8 +693,6 @@ BOOL CMainWindow::CanUndo() const
return (BOOL)textEditWindow.SendMessage(EM_CANUNDO); return (BOOL)textEditWindow.SendMessage(EM_CANUNDO);
if (selectionModel.m_bShow && toolsModel.IsSelection()) if (selectionModel.m_bShow && toolsModel.IsSelection())
return TRUE; return TRUE;
if (ToolBase::s_pointSP != 0)
return TRUE;
return imageModel.CanUndo(); return imageModel.CanUndo();
} }
@ -702,8 +700,6 @@ BOOL CMainWindow::CanRedo() const
{ {
if (toolsModel.GetActiveTool() == TOOL_TEXT && ::IsWindowVisible(textEditWindow)) if (toolsModel.GetActiveTool() == TOOL_TEXT && ::IsWindowVisible(textEditWindow))
return FALSE; // There is no "WM_REDO" in EDIT control return FALSE; // There is no "WM_REDO" in EDIT control
if (ToolBase::s_pointSP != 0)
return TRUE;
return imageModel.CanRedo(); return imageModel.CanRedo();
} }
@ -802,29 +798,11 @@ LRESULT CMainWindow::OnGetMinMaxInfo(UINT nMsg, WPARAM wParam, LPARAM lParam, BO
LRESULT CMainWindow::OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) LRESULT CMainWindow::OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{ {
HWND hwndCapture;
switch (wParam) switch (wParam)
{ {
case VK_ESCAPE: case VK_ESCAPE:
hwndCapture = GetCapture(); canvasWindow.PostMessage(nMsg, wParam, lParam);
if (hwndCapture)
{
if (canvasWindow.m_hWnd == hwndCapture ||
fullscreenWindow.m_hWnd == hwndCapture)
{
::SendMessageW(hwndCapture, nMsg, wParam, lParam);
}
}
else if (selectionModel.m_bShow)
{
selectionModel.HideSelection();
}
else
{
canvasWindow.cancelDrawing();
}
break; break;
case VK_LEFT: case VK_LEFT:
selectionModel.moveSelection(-1, 0); selectionModel.moveSelection(-1, 0);
break; break;
@ -932,7 +910,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
GlobalFree(pd.hDevNames); GlobalFree(pd.hDevNames);
break; break;
case IDM_FILESEND: case IDM_FILESEND:
canvasWindow.finishDrawing(); canvasWindow.OnEndDraw(FALSE);
if (!OpenMailer(m_hWnd, g_szFileName)) if (!OpenMailer(m_hWnd, g_szFileName))
{ {
ShowError(IDS_CANTSENDMAIL); ShowError(IDS_CANTSENDMAIL);
@ -963,7 +941,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
textEditWindow.PostMessage(WM_UNDO, 0, 0); textEditWindow.PostMessage(WM_UNDO, 0, 0);
break; break;
} }
canvasWindow.finishDrawing(); canvasWindow.OnEndDraw(FALSE);
imageModel.Undo(); imageModel.Undo();
break; break;
case IDM_EDITREDO: case IDM_EDITREDO:
@ -972,7 +950,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
// There is no "WM_REDO" in EDIT control // There is no "WM_REDO" in EDIT control
break; break;
} }
canvasWindow.finishDrawing(); canvasWindow.OnEndDraw(FALSE);
imageModel.Redo(); imageModel.Redo();
break; break;
case IDM_EDITCOPY: case IDM_EDITCOPY:
@ -1087,7 +1065,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
break; break;
case TOOL_TEXT: case TOOL_TEXT:
canvasWindow.cancelDrawing(); canvasWindow.OnEndDraw(TRUE);
break; break;
default: default:
break; break;

View File

@ -9,9 +9,11 @@
#include "precomp.h" #include "precomp.h"
#include <atlalloc.h> #include <atlalloc.h>
SIZE_T ToolBase::s_pointSP = 0; static SIZE_T s_pointSP = 0;
static SIZE_T s_maxPointSP = 0; static CHeapPtr<POINT, CLocalAllocator> s_pointsAllocated;
static CHeapPtr<POINT, CLocalAllocator> s_pointStack; static POINT s_staticPointStack[512]; // 512 is enough
static SIZE_T s_maxPointSP = _countof(s_staticPointStack);
static LPPOINT s_pointStack = s_staticPointStack;
static POINT g_ptStart, g_ptEnd; static POINT g_ptStart, g_ptEnd;
/* FUNCTIONS ********************************************************/ /* FUNCTIONS ********************************************************/
@ -69,13 +71,50 @@ void getBoundaryOfPtStack(RECT& rcBoundary, INT cPoints, const POINT *pPoints)
rcBoundary = rc; rcBoundary = rc;
} }
void ShiftPtStack(INT dx, INT dy)
{
for (SIZE_T i = 0; i < s_pointSP; ++i)
{
POINT& pt = s_pointStack[i];
pt.x += dx;
pt.y += dy;
}
}
void BuildMaskFromPtStack()
{
CRect rc;
getBoundaryOfPtStack(rc, s_pointSP, s_pointStack);
ShiftPtStack(-rc.left, -rc.top);
HDC hdcMem = ::CreateCompatibleDC(NULL);
HBITMAP hbmMask = ::CreateBitmap(rc.Width(), rc.Height(), 1, 1, NULL);
HGDIOBJ hbmOld = ::SelectObject(hdcMem, hbmMask);
::FillRect(hdcMem, &rc, (HBRUSH)::GetStockObject(BLACK_BRUSH));
HGDIOBJ hPenOld = ::SelectObject(hdcMem, GetStockObject(NULL_PEN));
HGDIOBJ hbrOld = ::SelectObject(hdcMem, GetStockObject(WHITE_BRUSH));
::Polygon(hdcMem, s_pointStack, s_pointSP);
::SelectObject(hdcMem, hbrOld);
::SelectObject(hdcMem, hPenOld);
::SelectObject(hdcMem, hbmOld);
::DeleteDC(hdcMem);
selectionModel.setMask(rc, hbmMask);
}
void ToolBase::reset() void ToolBase::reset()
{ {
if (s_pointStack != s_staticPointStack)
{
s_pointsAllocated.Free();
s_pointStack = s_staticPointStack;
s_maxPointSP = _countof(s_staticPointStack);
}
s_pointSP = 0; s_pointSP = 0;
g_ptEnd = g_ptStart = { -1, -1 }; g_ptEnd = g_ptStart = { -1, -1 };
selectionModel.ResetPtStack();
if (selectionModel.m_bShow) if (selectionModel.m_bShow)
{ {
selectionModel.Landing(); selectionModel.Landing();
@ -103,16 +142,20 @@ void ToolBase::endEvent()
void ToolBase::pushToPtStack(LONG x, LONG y) void ToolBase::pushToPtStack(LONG x, LONG y)
{ {
if (s_pointSP >= s_maxPointSP) if (s_pointSP + 1 >= s_maxPointSP)
{ {
SIZE_T newMax = s_maxPointSP + 512; SIZE_T newMax = s_maxPointSP + 512;
SIZE_T cbNew = newMax * sizeof(POINT); SIZE_T cbNew = newMax * sizeof(POINT);
if (!s_pointStack.ReallocateBytes(cbNew)) if (!s_pointsAllocated.ReallocateBytes(cbNew))
{ {
ATLTRACE("%d, %d, %d\n", (INT)s_pointSP, (INT)s_maxPointSP, (INT)cbNew); ATLTRACE("%d, %d, %d\n", (INT)s_pointSP, (INT)s_maxPointSP, (INT)cbNew);
return; return;
} }
if (s_pointStack == s_staticPointStack)
CopyMemory(s_pointsAllocated, s_staticPointStack, s_pointSP * sizeof(POINT));
s_pointStack = s_pointsAllocated;
s_maxPointSP = newMax; s_maxPointSP = newMax;
} }
@ -327,12 +370,13 @@ struct SmoothDrawTool : ToolBase
} }
}; };
struct SelectionBaseTool : SmoothDrawTool struct SelectionBaseTool : ToolBase
{ {
BOOL m_bLeftButton = FALSE; BOOL m_bLeftButton = FALSE;
BOOL m_bCtrlKey = FALSE; BOOL m_bCtrlKey = FALSE;
BOOL m_bShiftKey = FALSE; BOOL m_bShiftKey = FALSE;
BOOL m_bDrawing = FALSE; BOOL m_bDrawing = FALSE;
BOOL m_bNoDrawBack = FALSE;
HITTEST m_hitSelection = HIT_NONE; HITTEST m_hitSelection = HIT_NONE;
BOOL isRectSelect() const BOOL isRectSelect() const
@ -342,13 +386,19 @@ struct SelectionBaseTool : SmoothDrawTool
void OnDrawOverlayOnImage(HDC hdc) override void OnDrawOverlayOnImage(HDC hdc) override
{ {
if (!selectionModel.IsLanded()) if (selectionModel.IsLanded() || !selectionModel.m_bShow)
selectionModel.DrawSelection(hdc, paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent()); return;
if (!m_bNoDrawBack)
selectionModel.DrawBackground(hdc, selectionModel.m_rgbBack);
selectionModel.DrawSelection(hdc, paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent());
} }
void OnDrawOverlayOnCanvas(HDC hdc) override void OnDrawOverlayOnCanvas(HDC hdc) override
{ {
selectionModel.drawFrameOnCanvas(hdc); if (m_bDrawing || selectionModel.m_bShow)
selectionModel.drawFrameOnCanvas(hdc);
} }
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
@ -374,12 +424,14 @@ struct SelectionBaseTool : SmoothDrawTool
if (hit != HIT_NONE) // Dragging of selection started? if (hit != HIT_NONE) // Dragging of selection started?
{ {
if (m_bCtrlKey || m_bShiftKey) if (m_bCtrlKey || m_bShiftKey)
imageModel.SelectionClone(); {
imageModel.PushImageForUndo();
toolsModel.OnDrawOverlayOnImage(imageModel.GetDC());
}
m_hitSelection = hit; m_hitSelection = hit;
selectionModel.m_ptHit = pt; selectionModel.m_ptHit = pt;
selectionModel.TakeOff(); selectionModel.TakeOff();
m_bNoDrawBack |= (m_bCtrlKey || m_bShiftKey);
imageModel.NotifyImageChanged(); imageModel.NotifyImageChanged();
return; return;
} }
@ -394,8 +446,8 @@ struct SelectionBaseTool : SmoothDrawTool
} }
else else
{ {
selectionModel.ResetPtStack(); s_pointSP = 0;
selectionModel.PushToPtStack(pt); pushToPtStack(pt.x, pt.y);
} }
imageModel.NotifyImageChanged(); imageModel.NotifyImageChanged();
@ -411,18 +463,22 @@ struct SelectionBaseTool : SmoothDrawTool
if (m_hitSelection != HIT_NONE) // Now dragging selection? if (m_hitSelection != HIT_NONE) // Now dragging selection?
{ {
if (m_bShiftKey) if (m_bShiftKey)
imageModel.SelectionClone(m_bShiftKey); toolsModel.OnDrawOverlayOnImage(imageModel.GetDC());
selectionModel.Dragging(m_hitSelection, pt); selectionModel.Dragging(m_hitSelection, pt);
imageModel.NotifyImageChanged(); imageModel.NotifyImageChanged();
return TRUE; return TRUE;
} }
if (isRectSelect() && ::GetKeyState(VK_SHIFT) < 0)
regularize(g_ptStart.x, g_ptStart.y, pt.x, pt.y);
imageModel.Clamp(pt); imageModel.Clamp(pt);
if (isRectSelect()) if (isRectSelect())
selectionModel.SetRectFromPoints(g_ptStart, pt); selectionModel.SetRectFromPoints(g_ptStart, pt);
else else
selectionModel.PushToPtStack(pt); pushToPtStack(pt.x, pt.y);
imageModel.NotifyImageChanged(); imageModel.NotifyImageChanged();
return TRUE; return TRUE;
@ -438,13 +494,20 @@ struct SelectionBaseTool : SmoothDrawTool
if (m_hitSelection != HIT_NONE) // Dragging of selection ended? if (m_hitSelection != HIT_NONE) // Dragging of selection ended?
{ {
if (m_bShiftKey)
toolsModel.OnDrawOverlayOnImage(imageModel.GetDC());
selectionModel.Dragging(m_hitSelection, pt); selectionModel.Dragging(m_hitSelection, pt);
m_hitSelection = HIT_NONE; m_hitSelection = HIT_NONE;
imageModel.NotifyImageChanged(); imageModel.NotifyImageChanged();
return TRUE; return TRUE;
} }
if (isRectSelect() && ::GetKeyState(VK_SHIFT) < 0)
regularize(g_ptStart.x, g_ptStart.y, pt.x, pt.y);
imageModel.Clamp(pt); imageModel.Clamp(pt);
if (isRectSelect()) if (isRectSelect())
{ {
selectionModel.SetRectFromPoints(g_ptStart, pt); selectionModel.SetRectFromPoints(g_ptStart, pt);
@ -452,18 +515,19 @@ struct SelectionBaseTool : SmoothDrawTool
} }
else else
{ {
if (selectionModel.PtStackSize() > 2) if (s_pointSP > 2)
{ {
selectionModel.BuildMaskFromPtStack(); BuildMaskFromPtStack();
selectionModel.m_bShow = TRUE; selectionModel.m_bShow = TRUE;
} }
else else
{ {
selectionModel.ResetPtStack(); s_pointSP = 0;
selectionModel.m_bShow = FALSE; selectionModel.m_bShow = FALSE;
} }
} }
m_bNoDrawBack = FALSE;
imageModel.NotifyImageChanged(); imageModel.NotifyImageChanged();
return TRUE; return TRUE;
} }
@ -475,6 +539,7 @@ struct SelectionBaseTool : SmoothDrawTool
else else
selectionModel.Landing(); selectionModel.Landing();
m_bDrawing = FALSE;
m_hitSelection = HIT_NONE; m_hitSelection = HIT_NONE;
ToolBase::OnEndDraw(bCancel); ToolBase::OnEndDraw(bCancel);
} }
@ -488,34 +553,21 @@ struct SelectionBaseTool : SmoothDrawTool
// TOOL_FREESEL // TOOL_FREESEL
struct FreeSelTool : SelectionBaseTool struct FreeSelTool : SelectionBaseTool
{ {
void OnDraw(HDC hdc, BOOL bLeftButton, POINT pt0, POINT pt1) override
{
if (m_bShiftKey && !m_bCtrlKey)
{
// TODO:
}
}
void OnDrawOverlayOnImage(HDC hdc) override void OnDrawOverlayOnImage(HDC hdc) override
{ {
SelectionBaseTool::OnDrawOverlayOnImage(hdc); SelectionBaseTool::OnDrawOverlayOnImage(hdc);
if (!selectionModel.m_bShow && m_bDrawing) if (!selectionModel.m_bShow && m_bDrawing)
selectionModel.DrawFramePoly(hdc); {
/* Draw the freehand selection inverted/xored */
Poly(hdc, s_pointStack, s_pointSP, 0, 0, 2, 0, FALSE, TRUE);
}
} }
}; };
// TOOL_RECTSEL // TOOL_RECTSEL
struct RectSelTool : SelectionBaseTool struct RectSelTool : SelectionBaseTool
{ {
void OnDraw(HDC hdc, BOOL bLeftButton, POINT pt0, POINT pt1) override
{
if (m_bShiftKey && !m_bCtrlKey)
{
// TODO:
}
}
void OnDrawOverlayOnImage(HDC hdc) override void OnDrawOverlayOnImage(HDC hdc) override
{ {
SelectionBaseTool::OnDrawOverlayOnImage(hdc); SelectionBaseTool::OnDrawOverlayOnImage(hdc);

View File

@ -15,8 +15,6 @@ SelectionModel selectionModel;
SelectionModel::SelectionModel() SelectionModel::SelectionModel()
: m_hbmColor(NULL) : m_hbmColor(NULL)
, m_hbmMask(NULL) , m_hbmMask(NULL)
, m_ptStack(NULL)
, m_iPtSP(0)
, m_rgbBack(RGB(255, 255, 255)) , m_rgbBack(RGB(255, 255, 255))
, m_bShow(FALSE) , m_bShow(FALSE)
, m_bContentChanged(FALSE) , m_bContentChanged(FALSE)
@ -30,69 +28,6 @@ SelectionModel::~SelectionModel()
{ {
ClearColorImage(); ClearColorImage();
ClearMaskImage(); ClearMaskImage();
ResetPtStack();
}
void SelectionModel::ResetPtStack()
{
if (m_ptStack)
{
free(m_ptStack);
m_ptStack = NULL;
}
m_iPtSP = 0;
}
void SelectionModel::PushToPtStack(POINT pt)
{
#define GROW_COUNT 256
if (m_iPtSP % GROW_COUNT == 0)
{
INT nNewCount = m_iPtSP + GROW_COUNT;
LPPOINT pptNew = (LPPOINT)realloc(m_ptStack, sizeof(POINT) * nNewCount);
if (pptNew == NULL)
return;
m_ptStack = pptNew;
}
m_ptStack[m_iPtSP] = pt;
m_iPtSP++;
#undef GROW_COUNT
}
void SelectionModel::ShiftPtStack(INT dx, INT dy)
{
for (INT i = 0; i < m_iPtSP; ++i)
{
POINT& pt = m_ptStack[i];
pt.x += dx;
pt.y += dy;
}
}
void SelectionModel::BuildMaskFromPtStack()
{
CRect rc;
getBoundaryOfPtStack(rc, m_iPtSP, m_ptStack);
m_rc = m_rcOld = rc;
ClearMaskImage();
ShiftPtStack(-m_rcOld.left, -m_rcOld.top);
HDC hdcMem = ::CreateCompatibleDC(NULL);
m_hbmMask = ::CreateBitmap(rc.Width(), rc.Height(), 1, 1, NULL);
HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_hbmMask);
::FillRect(hdcMem, &rc, (HBRUSH)::GetStockObject(BLACK_BRUSH));
HGDIOBJ hPenOld = ::SelectObject(hdcMem, GetStockObject(NULL_PEN));
HGDIOBJ hbrOld = ::SelectObject(hdcMem, GetStockObject(WHITE_BRUSH));
::Polygon(hdcMem, m_ptStack, m_iPtSP);
::SelectObject(hdcMem, hbrOld);
::SelectObject(hdcMem, hPenOld);
::SelectObject(hdcMem, hbmOld);
::DeleteDC(hdcMem);
ShiftPtStack(+m_rcOld.left, +m_rcOld.top);
} }
void SelectionModel::DrawBackgroundPoly(HDC hDCImage, COLORREF crBg) void SelectionModel::DrawBackgroundPoly(HDC hDCImage, COLORREF crBg)
@ -100,11 +35,11 @@ void SelectionModel::DrawBackgroundPoly(HDC hDCImage, COLORREF crBg)
if (m_rcOld.IsRectEmpty()) if (m_rcOld.IsRectEmpty())
return; return;
HGDIOBJ hPenOld = ::SelectObject(hDCImage, ::GetStockObject(NULL_PEN)); HGDIOBJ hbrOld = ::SelectObject(hDCImage, ::GetStockObject(DC_BRUSH));
HGDIOBJ hbrOld = ::SelectObject(hDCImage, ::CreateSolidBrush(crBg)); ::SetDCBrushColor(hDCImage, crBg);
::Polygon(hDCImage, m_ptStack, m_iPtSP); ::MaskBlt(hDCImage, m_rcOld.left, m_rcOld.top, m_rcOld.Width(), m_rcOld.Height(),
::DeleteObject(::SelectObject(hDCImage, hbrOld)); hDCImage, m_rcOld.left, m_rcOld.top, m_hbmMask, 0, 0, MAKEROP4(PATCOPY, SRCCOPY));
::SelectObject(hDCImage, hPenOld); ::SelectObject(hDCImage, hbrOld);
} }
void SelectionModel::DrawBackgroundRect(HDC hDCImage, COLORREF crBg) void SelectionModel::DrawBackgroundRect(HDC hDCImage, COLORREF crBg)
@ -115,12 +50,12 @@ void SelectionModel::DrawBackgroundRect(HDC hDCImage, COLORREF crBg)
Rect(hDCImage, m_rcOld.left, m_rcOld.top, m_rcOld.right, m_rcOld.bottom, crBg, crBg, 0, 1); Rect(hDCImage, m_rcOld.left, m_rcOld.top, m_rcOld.right, m_rcOld.bottom, crBg, crBg, 0, 1);
} }
void SelectionModel::DrawBackground(HDC hDCImage) void SelectionModel::DrawBackground(HDC hDCImage, COLORREF crBg)
{ {
if (toolsModel.GetActiveTool() == TOOL_FREESEL) if (toolsModel.GetActiveTool() == TOOL_FREESEL)
DrawBackgroundPoly(hDCImage, paletteModel.GetBgColor()); DrawBackgroundPoly(hDCImage, crBg);
else else
DrawBackgroundRect(hDCImage, paletteModel.GetBgColor()); DrawBackgroundRect(hDCImage, crBg);
} }
void SelectionModel::DrawSelection(HDC hDCImage, COLORREF crBg, BOOL bBgTransparent) void SelectionModel::DrawSelection(HDC hDCImage, COLORREF crBg, BOOL bBgTransparent)
@ -143,6 +78,15 @@ void SelectionModel::DrawSelection(HDC hDCImage, COLORREF crBg, BOOL bBgTranspar
DeleteDC(hMemDC); DeleteDC(hMemDC);
} }
void SelectionModel::setMask(const CRect& rc, HBITMAP hbmMask)
{
if (m_hbmMask)
::DeleteObject(m_hbmMask);
m_hbmMask = hbmMask;
m_rc = m_rcOld = rc;
}
HBITMAP SelectionModel::GetSelectionContents() HBITMAP SelectionModel::GetSelectionContents()
{ {
if (m_hbmColor) if (m_hbmColor)
@ -178,17 +122,6 @@ BOOL SelectionModel::TakeOff()
// Save the selection area // Save the selection area
m_rcOld = m_rc; m_rcOld = m_rc;
if (toolsModel.GetActiveTool() == TOOL_RECTSEL)
{
imageModel.PushImageForUndo();
selectionModel.DrawBackgroundRect(imageModel.GetDC(), selectionModel.m_rgbBack);
}
else if (toolsModel.GetActiveTool() == TOOL_FREESEL)
{
imageModel.PushImageForUndo();
selectionModel.DrawBackgroundPoly(imageModel.GetDC(), selectionModel.m_rgbBack);
}
imageModel.NotifyImageChanged(); imageModel.NotifyImageChanged();
return TRUE; return TRUE;
} }
@ -201,12 +134,12 @@ void SelectionModel::Landing()
return; return;
} }
m_bShow = FALSE;
if (m_bContentChanged || if (m_bContentChanged ||
(!m_rc.EqualRect(m_rcOld) && !m_rc.IsRectEmpty() && !m_rcOld.IsRectEmpty())) (!m_rc.EqualRect(m_rcOld) && !m_rc.IsRectEmpty() && !m_rcOld.IsRectEmpty()))
{ {
imageModel.PushImageForUndo(); CRect rc;
rc.UnionRect(m_rc, m_rcOld);
imageModel.PushImageForUndo(rc);
canvasWindow.m_drawing = FALSE; canvasWindow.m_drawing = FALSE;
toolsModel.OnDrawOverlayOnImage(imageModel.GetDC()); toolsModel.OnDrawOverlayOnImage(imageModel.GetDC());
@ -397,17 +330,6 @@ void SelectionModel::StretchSkew(int nStretchPercentX, int nStretchPercentY, int
NotifyContentChanged(); NotifyContentChanged();
} }
int SelectionModel::PtStackSize() const
{
return m_iPtSP;
}
void SelectionModel::DrawFramePoly(HDC hDCImage)
{
/* draw the freehand selection inverted/xored */
Poly(hDCImage, m_ptStack, m_iPtSP, 0, 0, 2, 0, FALSE, TRUE);
}
void SelectionModel::SetRectFromPoints(const POINT& ptFrom, const POINT& ptTo) void SelectionModel::SetRectFromPoints(const POINT& ptFrom, const POINT& ptTo)
{ {
m_rc = CRect(ptFrom, ptTo); m_rc = CRect(ptFrom, ptTo);
@ -491,7 +413,7 @@ void SelectionModel::DeleteSelection()
TakeOff(); TakeOff();
imageModel.PushImageForUndo(); imageModel.PushImageForUndo();
DrawBackground(imageModel.GetDC()); DrawBackground(imageModel.GetDC(), paletteModel.GetBgColor());
HideSelection(); HideSelection();
} }

View File

@ -13,8 +13,6 @@ class SelectionModel
private: private:
HBITMAP m_hbmColor; HBITMAP m_hbmColor;
HBITMAP m_hbmMask; HBITMAP m_hbmMask;
POINT *m_ptStack;
int m_iPtSP;
public: public:
COLORREF m_rgbBack; COLORREF m_rgbBack;
@ -27,11 +25,8 @@ public:
SelectionModel(); SelectionModel();
~SelectionModel(); ~SelectionModel();
void ResetPtStack();
void PushToPtStack(POINT pt);
int PtStackSize() const;
void SetRectFromPoints(const POINT& ptFrom, const POINT& ptTo); void SetRectFromPoints(const POINT& ptFrom, const POINT& ptTo);
void BuildMaskFromPtStack(); void setMask(const CRect& rc, HBITMAP hbmMask);
BOOL TakeOff(); BOOL TakeOff();
void Landing(); void Landing();
@ -43,8 +38,7 @@ public:
void moveSelection(INT xDelta, INT yDelta); void moveSelection(INT xDelta, INT yDelta);
HBITMAP GetSelectionContents(); HBITMAP GetSelectionContents();
void DrawFramePoly(HDC hDCImage); void DrawBackground(HDC hDCImage, COLORREF crBg);
void DrawBackground(HDC hDCImage);
void DrawBackgroundPoly(HDC hDCImage, COLORREF crBg); void DrawBackgroundPoly(HDC hDCImage, COLORREF crBg);
void DrawBackgroundRect(HDC hDCImage, COLORREF crBg); void DrawBackgroundRect(HDC hDCImage, COLORREF crBg);
void DrawSelection(HDC hDCImage, COLORREF crBg = 0, BOOL bBgTransparent = FALSE); void DrawSelection(HDC hDCImage, COLORREF crBg = 0, BOOL bBgTransparent = FALSE);

View File

@ -209,6 +209,9 @@ SIZE ToolsModel::GetToolSize() const
{ {
case TOOL_FREESEL: case TOOL_FREESEL:
case TOOL_RECTSEL: case TOOL_RECTSEL:
size.cx = selectionModel.m_rc.Width();
size.cy = selectionModel.m_rc.Height();
break;
case TOOL_COLOR: case TOOL_COLOR:
case TOOL_ZOOM: case TOOL_ZOOM:
case TOOL_TEXT: case TOOL_TEXT:

View File

@ -42,7 +42,6 @@ struct ToolBase
{ {
HDC m_hdc; HDC m_hdc;
COLORREF m_fg, m_bg; COLORREF m_fg, m_bg;
static SIZE_T s_pointSP;
ToolBase() : m_hdc(NULL) { } ToolBase() : m_hdc(NULL) { }
virtual ~ToolBase() { } virtual ~ToolBase() { }