mirror of
https://github.com/reactos/reactos.git
synced 2024-12-03 00:13:32 +08:00
[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:
parent
ab0119c61f
commit
b8598e095d
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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:
|
||||||
|
@ -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() { }
|
||||||
|
Loading…
Reference in New Issue
Block a user