[MSPAINT] Define SelectionBaseTool and use it (#6034)

Refactoring and arrangement for selection handling.
- Move some selection-related codes in canvas.cpp to mouse.cpp.
- Add SelectionBaseTool structure for FreeSelTool and RectSelTool.
CORE-19094
This commit is contained in:
Katayama Hirofumi MZ 2023-11-24 15:44:16 +09:00 committed by GitHub
parent 898fb5f414
commit f710e5a260
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 212 additions and 262 deletions

View file

@ -13,7 +13,6 @@ CCanvasWindow canvasWindow;
CCanvasWindow::CCanvasWindow()
: m_drawing(FALSE)
, m_hitSelection(HIT_NONE)
, m_hitCanvasSizeBox(HIT_NONE)
, m_ptOrig { -1, -1 }
{
@ -316,25 +315,11 @@ LRESULT CCanvasWindow::OnButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOO
HITTEST hitSelection = selectionModel.hitTest(pt);
if (hitSelection != HIT_NONE)
{
selectionModel.m_nSelectionBrush = 0; // Selection Brush is OFF
if (bLeftButton)
{
CanvasToImage(pt);
if (::GetKeyState(VK_CONTROL) < 0) // Ctrl+Click is Selection Clone
{
imageModel.SelectionClone();
}
else if (::GetKeyState(VK_SHIFT) < 0) // Shift+Dragging is Selection Brush
{
selectionModel.m_nSelectionBrush = 1; // Selection Brush is ON
}
StartSelectionDrag(hitSelection, pt);
}
else
{
ClientToScreen(&pt);
mainWindow.TrackPopupMenu(pt, 0);
}
m_drawing = TRUE;
CanvasToImage(pt);
SetCapture();
toolsModel.OnButtonDown(bLeftButton, pt.x, pt.y, FALSE);
Invalidate();
return 0;
}
@ -370,7 +355,7 @@ LRESULT CCanvasWindow::OnButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOO
m_drawing = TRUE;
SetCapture();
toolsModel.OnButtonDown(bLeftButton, pt.x, pt.y, FALSE);
Invalidate(FALSE);
Invalidate();
return 0;
}
@ -395,7 +380,7 @@ LRESULT CCanvasWindow::OnButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam, B
toolsModel.OnButtonDown(nMsg == WM_LBUTTONDBLCLK, pt.x, pt.y, TRUE);
toolsModel.resetTool();
Invalidate(FALSE);
Invalidate();
return 0;
}
@ -418,12 +403,6 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
if (toolsModel.GetActiveTool() == TOOL_ZOOM)
Invalidate();
if (m_hitSelection != HIT_NONE)
{
SelectionDragging(pt);
return 0;
}
if (!m_drawing || toolsModel.GetActiveTool() <= TOOL_AIRBRUSH)
{
TRACKMOUSEEVENT tme = { sizeof(tme) };
@ -444,7 +423,7 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
}
}
if (m_drawing)
if (m_drawing || toolsModel.IsSelection())
{
toolsModel.DrawWithMouseTool(pt, wParam);
return 0;
@ -549,11 +528,6 @@ LRESULT CCanvasWindow::OnButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL&
::SendMessageW(g_hStatusBar, SB_SETTEXT, 2, (LPARAM)L"");
return 0;
}
else if (m_hitSelection != HIT_NONE && bLeftButton)
{
EndSelectionDrag(pt);
return 0;
}
if (m_hitCanvasSizeBox == HIT_NONE || !bLeftButton)
return 0;
@ -728,7 +702,6 @@ VOID CCanvasWindow::cancelDrawing()
{
selectionModel.ClearColorImage();
selectionModel.ClearMaskImage();
m_hitSelection = HIT_NONE;
m_drawing = FALSE;
toolsModel.OnEndDraw(TRUE);
Invalidate(FALSE);
@ -741,35 +714,6 @@ VOID CCanvasWindow::finishDrawing()
Invalidate(FALSE);
}
VOID CCanvasWindow::StartSelectionDrag(HITTEST hit, POINT ptImage)
{
m_hitSelection = hit;
selectionModel.m_ptHit = ptImage;
selectionModel.TakeOff();
SetCapture();
Invalidate(FALSE);
}
VOID CCanvasWindow::SelectionDragging(POINT ptImage)
{
if (selectionModel.m_nSelectionBrush)
{
imageModel.SelectionClone(selectionModel.m_nSelectionBrush == 1);
selectionModel.m_nSelectionBrush = 2; // Selection Brush is ON and drawn
}
selectionModel.Dragging(m_hitSelection, ptImage);
Invalidate(FALSE);
}
VOID CCanvasWindow::EndSelectionDrag(POINT ptImage)
{
selectionModel.Dragging(m_hitSelection, ptImage);
m_hitSelection = HIT_NONE;
Invalidate(FALSE);
}
LRESULT CCanvasWindow::OnCtlColorEdit(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
SetTextColor((HDC)wParam, paletteModel.GetFgColor());

View file

@ -56,7 +56,6 @@ public:
VOID zoomTo(INT newZoom, LONG left = 0, LONG top = 0);
protected:
HITTEST m_hitSelection;
HITTEST m_hitCanvasSizeBox;
POINT m_ptOrig; // The origin of drag start
HBITMAP m_ahbmCached[2]; // The cached buffer bitmaps
@ -67,10 +66,6 @@ protected:
VOID DoDraw(HDC hDC, RECT& rcClient, RECT& rcPaint);
VOID OnHVScroll(WPARAM wParam, INT fnBar);
VOID StartSelectionDrag(HITTEST hit, POINT ptImage);
VOID SelectionDragging(POINT ptImage);
VOID EndSelectionDrag(POINT ptImage);
LRESULT OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnHScroll(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnVScroll(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

View file

@ -963,29 +963,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
textEditWindow.PostMessage(WM_UNDO, 0, 0);
break;
}
if (selectionModel.m_bShow)
{
if (toolsModel.IsSelection())
{
canvasWindow.cancelDrawing();
if (toolsModel.GetActiveTool() == TOOL_FREESEL ||
toolsModel.GetActiveTool() == TOOL_RECTSEL)
{
imageModel.Undo();
if (selectionModel.m_nSelectionBrush == 2) // Selection Brush is drawn
{
imageModel.Undo();
selectionModel.m_nSelectionBrush = 0;
}
}
break;
}
}
if (ToolBase::s_pointSP != 0) // drawing something?
{
canvasWindow.cancelDrawing();
break;
}
canvasWindow.finishDrawing();
imageModel.Undo();
break;
case IDM_EDITREDO:
@ -994,11 +972,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
// There is no "WM_REDO" in EDIT control
break;
}
if (ToolBase::s_pointSP != 0) // drawing something?
{
canvasWindow.finishDrawing();
break;
}
canvasWindow.finishDrawing();
imageModel.Redo();
break;
case IDM_EDITCOPY:

View file

@ -121,170 +121,6 @@ void ToolBase::pushToPtStack(LONG x, LONG y)
/* TOOLS ********************************************************/
// TOOL_FREESEL
struct FreeSelTool : ToolBase
{
BOOL m_bLeftButton = FALSE;
void OnDrawOverlayOnImage(HDC hdc) override
{
if (!selectionModel.IsLanded())
selectionModel.DrawSelection(hdc, paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent());
if (canvasWindow.m_drawing)
{
selectionModel.DrawFramePoly(hdc);
}
}
void OnDrawOverlayOnCanvas(HDC hdc) override
{
selectionModel.drawFrameOnCanvas(hdc);
}
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
{
selectionModel.Landing();
if (bLeftButton)
{
selectionModel.HideSelection();
selectionModel.ResetPtStack();
POINT pt = { x, y };
selectionModel.PushToPtStack(pt);
}
m_bLeftButton = bLeftButton;
}
BOOL OnMouseMove(BOOL bLeftButton, LONG& x, LONG& y) override
{
if (bLeftButton)
{
POINT pt = { x, y };
imageModel.Clamp(pt);
selectionModel.PushToPtStack(pt);
imageModel.NotifyImageChanged();
}
return TRUE;
}
BOOL OnButtonUp(BOOL bLeftButton, LONG& x, LONG& y) override
{
if (bLeftButton)
{
if (selectionModel.PtStackSize() > 2)
{
selectionModel.BuildMaskFromPtStack();
selectionModel.m_bShow = TRUE;
}
else
{
selectionModel.ResetPtStack();
selectionModel.m_bShow = FALSE;
}
imageModel.NotifyImageChanged();
}
else
{
POINT pt = { x, y };
canvasWindow.ClientToScreen(&pt);
mainWindow.TrackPopupMenu(pt, 0);
}
return TRUE;
}
void OnEndDraw(BOOL bCancel) override
{
if (bCancel)
selectionModel.HideSelection();
else
selectionModel.Landing();
ToolBase::OnEndDraw(bCancel);
}
void OnSpecialTweak(BOOL bMinus) override
{
selectionModel.StretchSelection(bMinus);
}
};
// TOOL_RECTSEL
struct RectSelTool : ToolBase
{
BOOL m_bLeftButton = FALSE;
void OnDrawOverlayOnImage(HDC hdc) override
{
if (!selectionModel.IsLanded())
selectionModel.DrawSelection(hdc, paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent());
if (canvasWindow.m_drawing)
{
CRect& rc = selectionModel.m_rc;
if (!rc.IsRectEmpty())
RectSel(hdc, rc.left, rc.top, rc.right, rc.bottom);
}
}
void OnDrawOverlayOnCanvas(HDC hdc) override
{
selectionModel.drawFrameOnCanvas(hdc);
}
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
{
selectionModel.Landing();
if (bLeftButton)
{
selectionModel.HideSelection();
}
m_bLeftButton = bLeftButton;
}
BOOL OnMouseMove(BOOL bLeftButton, LONG& x, LONG& y) override
{
if (bLeftButton)
{
POINT pt = { x, y };
imageModel.Clamp(pt);
selectionModel.SetRectFromPoints(g_ptStart, pt);
imageModel.NotifyImageChanged();
}
return TRUE;
}
BOOL OnButtonUp(BOOL bLeftButton, LONG& x, LONG& y) override
{
POINT pt = { x, y };
if (bLeftButton)
{
imageModel.Clamp(pt);
selectionModel.SetRectFromPoints(g_ptStart, pt);
selectionModel.m_bShow = !selectionModel.m_rc.IsRectEmpty();
imageModel.NotifyImageChanged();
}
else
{
canvasWindow.ClientToScreen(&pt);
mainWindow.TrackPopupMenu(pt, 0);
}
return TRUE;
}
void OnEndDraw(BOOL bCancel) override
{
if (bCancel)
selectionModel.HideSelection();
else
selectionModel.Landing();
ToolBase::OnEndDraw(bCancel);
}
void OnSpecialTweak(BOOL bMinus) override
{
selectionModel.StretchSelection(bMinus);
}
};
struct TwoPointDrawTool : ToolBase
{
BOOL m_bLeftButton = FALSE;
@ -491,6 +327,208 @@ struct SmoothDrawTool : ToolBase
}
};
struct SelectionBaseTool : SmoothDrawTool
{
BOOL m_bLeftButton = FALSE;
BOOL m_bCtrlKey = FALSE;
BOOL m_bShiftKey = FALSE;
BOOL m_bDrawing = FALSE;
HITTEST m_hitSelection = HIT_NONE;
BOOL isRectSelect() const
{
return (toolsModel.GetActiveTool() == TOOL_RECTSEL);
}
void OnDrawOverlayOnImage(HDC hdc) override
{
if (!selectionModel.IsLanded())
selectionModel.DrawSelection(hdc, paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent());
}
void OnDrawOverlayOnCanvas(HDC hdc) override
{
selectionModel.drawFrameOnCanvas(hdc);
}
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
{
m_bLeftButton = bLeftButton;
m_bCtrlKey = (::GetKeyState(VK_CONTROL) < 0);
m_bShiftKey = (::GetKeyState(VK_SHIFT) < 0);
m_bDrawing = FALSE;
m_hitSelection = HIT_NONE;
POINT pt = { x, y };
if (!m_bLeftButton) // Show context menu on Right-click
{
canvasWindow.ImageToCanvas(pt);
canvasWindow.ClientToScreen(&pt);
mainWindow.TrackPopupMenu(pt, 0);
return;
}
POINT ptCanvas = pt;
canvasWindow.ImageToCanvas(ptCanvas);
HITTEST hit = selectionModel.hitTest(ptCanvas);
if (hit != HIT_NONE) // Dragging of selection started?
{
if (m_bCtrlKey || m_bShiftKey)
imageModel.SelectionClone();
m_hitSelection = hit;
selectionModel.m_ptHit = pt;
selectionModel.TakeOff();
imageModel.NotifyImageChanged();
return;
}
selectionModel.Landing();
m_bDrawing = TRUE;
imageModel.Clamp(pt);
if (isRectSelect())
{
selectionModel.SetRectFromPoints(g_ptStart, pt);
}
else
{
selectionModel.ResetPtStack();
selectionModel.PushToPtStack(pt);
}
imageModel.NotifyImageChanged();
}
BOOL OnMouseMove(BOOL bLeftButton, LONG& x, LONG& y) override
{
POINT pt = { x, y };
if (!m_bLeftButton)
return TRUE;
if (m_hitSelection != HIT_NONE) // Now dragging selection?
{
if (m_bShiftKey)
imageModel.SelectionClone(m_bShiftKey);
selectionModel.Dragging(m_hitSelection, pt);
imageModel.NotifyImageChanged();
return TRUE;
}
imageModel.Clamp(pt);
if (isRectSelect())
selectionModel.SetRectFromPoints(g_ptStart, pt);
else
selectionModel.PushToPtStack(pt);
imageModel.NotifyImageChanged();
return TRUE;
}
BOOL OnButtonUp(BOOL bLeftButton, LONG& x, LONG& y) override
{
POINT pt = { x, y };
m_bDrawing = FALSE;
if (!m_bLeftButton)
return TRUE;
if (m_hitSelection != HIT_NONE) // Dragging of selection ended?
{
selectionModel.Dragging(m_hitSelection, pt);
m_hitSelection = HIT_NONE;
imageModel.NotifyImageChanged();
return TRUE;
}
imageModel.Clamp(pt);
if (isRectSelect())
{
selectionModel.SetRectFromPoints(g_ptStart, pt);
selectionModel.m_bShow = !selectionModel.m_rc.IsRectEmpty();
}
else
{
if (selectionModel.PtStackSize() > 2)
{
selectionModel.BuildMaskFromPtStack();
selectionModel.m_bShow = TRUE;
}
else
{
selectionModel.ResetPtStack();
selectionModel.m_bShow = FALSE;
}
}
imageModel.NotifyImageChanged();
return TRUE;
}
void OnEndDraw(BOOL bCancel) override
{
if (bCancel)
selectionModel.HideSelection();
else
selectionModel.Landing();
m_hitSelection = HIT_NONE;
ToolBase::OnEndDraw(bCancel);
}
void OnSpecialTweak(BOOL bMinus) override
{
selectionModel.StretchSelection(bMinus);
}
};
// TOOL_FREESEL
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
{
SelectionBaseTool::OnDrawOverlayOnImage(hdc);
if (!selectionModel.m_bShow && m_bDrawing)
selectionModel.DrawFramePoly(hdc);
}
};
// TOOL_RECTSEL
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
{
SelectionBaseTool::OnDrawOverlayOnImage(hdc);
if (!selectionModel.m_bShow && m_bDrawing)
{
CRect& rc = selectionModel.m_rc;
if (!rc.IsRectEmpty())
RectSel(hdc, rc.left, rc.top, rc.right, rc.bottom);
}
}
};
// TOOL_RUBBER
struct RubberTool : SmoothDrawTool
{

View file

@ -23,7 +23,6 @@ public:
CRect m_rc; // in image pixel coordinates
POINT m_ptHit; // in image pixel coordinates
CRect m_rcOld; // in image pixel coordinates
INT m_nSelectionBrush = 0;
SelectionModel();
~SelectionModel();