[MSPAINT] Restrict drawing direction on Shift key (#5726)

- While holding down the Shift key, drawing lines with the
  pen/brush is limited to either of 8 directions (horizontal/vertical/diagonal).
- s/abs/labs/
CORE-19094
This commit is contained in:
Katayama Hirofumi MZ 2023-09-26 22:47:23 +09:00 committed by GitHub
parent d1e9fe13de
commit 389d04650f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 189 additions and 65 deletions

View file

@ -45,6 +45,7 @@ enum HITTEST // hit
BOOL zoomTo(int newZoom, int mouseX, int mouseY);
BOOL nearlyEqualPoints(INT x0, INT y0, INT x1, INT y1);
void updateStartAndLast(LONG x, LONG y);
void updateLast(LONG x, LONG y);
BOOL OpenMailer(HWND hWnd, LPCWSTR pszPathName);
#define DEG2RAD(degree) (((degree) * M_PI) / 180)
#define RAD2DEG(radian) ((LONG)(((radian) * 180) / M_PI))

View file

@ -6,7 +6,6 @@
*/
#include "precomp.h"
#include <math.h>
INT g_fileSize = 0;
float g_xDpi = 96;
@ -339,10 +338,6 @@ HBITMAP Rotate90DegreeBlt(HDC hDC1, INT cx, INT cy, BOOL bRight, BOOL bMono)
return hbm2;
}
#ifndef M_PI
#define M_PI 3.14159265
#endif
HBITMAP SkewDIB(HDC hDC1, HBITMAP hbm, INT nDegree, BOOL bVertical, BOOL bMono)
{
CWaitCursor waitCursor;

View file

@ -115,7 +115,7 @@ Fill(HDC hdc, LONG x, LONG y, COLORREF color)
void
Erase(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF color, LONG radius)
{
LONG b = max(1, max(abs(x2 - x1), abs(y2 - y1)));
LONG b = max(1, max(labs(x2 - x1), labs(y2 - y1)));
HBRUSH hbr = ::CreateSolidBrush(color);
for (LONG a = 0; a <= b; a++)
@ -132,7 +132,7 @@ Erase(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF color, LONG radius)
void
Replace(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF fg, COLORREF bg, LONG radius)
{
LONG b = max(1, max(abs(x2 - x1), abs(y2 - y1)));
LONG b = max(1, max(labs(x2 - x1), labs(y2 - y1)));
for (LONG a = 0; a <= b; a++)
{
@ -169,7 +169,7 @@ Brush(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF color, LONG style)
HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, 1, color));
HBRUSH oldBrush = (HBRUSH) SelectObject(hdc, CreateSolidBrush(color));
LONG a, b;
b = max(1, max(abs(x2 - x1), abs(y2 - y1)));
b = max(1, max(labs(x2 - x1), labs(y2 - y1)));
switch (style)
{
case 0:

View file

@ -18,28 +18,28 @@ POINT ToolBase::s_pointStack[256] = { { 0 } };
void
regularize(LONG x0, LONG y0, LONG& x1, LONG& y1)
{
if (abs(x1 - x0) >= abs(y1 - y0))
y1 = y0 + (y1 > y0 ? abs(x1 - x0) : -abs(x1 - x0));
if (labs(x1 - x0) >= labs(y1 - y0))
y1 = y0 + (y1 > y0 ? labs(x1 - x0) : -labs(x1 - x0));
else
x1 = x0 + (x1 > x0 ? abs(y1 - y0) : -abs(y1 - y0));
x1 = x0 + (x1 > x0 ? labs(y1 - y0) : -labs(y1 - y0));
}
void
roundTo8Directions(LONG x0, LONG y0, LONG& x1, LONG& y1)
{
if (abs(x1 - x0) >= abs(y1 - y0))
if (labs(x1 - x0) >= labs(y1 - y0))
{
if (abs(y1 - y0) * 5 < abs(x1 - x0) * 2)
if (labs(y1 - y0) * 5 < labs(x1 - x0) * 2)
y1 = y0;
else
y1 = y0 + (y1 > y0 ? abs(x1 - x0) : -abs(x1 - x0));
y1 = y0 + (y1 > y0 ? labs(x1 - x0) : -labs(x1 - x0));
}
else
{
if (abs(x1 - x0) * 5 < abs(y1 - y0) * 2)
if (labs(x1 - x0) * 5 < labs(y1 - y0) * 2)
x1 = x0;
else
x1 = x0 + (x1 > x0 ? abs(y1 - y0) : -abs(y1 - y0));
x1 = x0 + (x1 > x0 ? labs(y1 - y0) : -labs(y1 - y0));
}
}
@ -50,18 +50,6 @@ BOOL nearlyEqualPoints(INT x0, INT y0, INT x1, INT y1)
return (abs(x1 - x0) <= cxThreshold) && (abs(y1 - y0) <= cyThreshold);
}
void updateStartAndLast(LONG x, LONG y)
{
g_ptStart.x = g_ptEnd.x = x;
g_ptStart.y = g_ptEnd.y = y;
}
void updateLast(LONG x, LONG y)
{
g_ptEnd.x = x;
g_ptEnd.y = y;
}
void ToolBase::reset()
{
s_pointSP = 0;
@ -153,7 +141,7 @@ struct FreeSelTool : ToolBase
m_bLeftButton = bLeftButton;
}
void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnMouseMove(BOOL bLeftButton, LONG& x, LONG& y) override
{
if (bLeftButton)
{
@ -162,9 +150,10 @@ struct FreeSelTool : ToolBase
selectionModel.PushToPtStack(pt);
imageModel.NotifyImageChanged();
}
return TRUE;
}
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnButtonUp(BOOL bLeftButton, LONG& x, LONG& y) override
{
if (bLeftButton)
{
@ -186,6 +175,7 @@ struct FreeSelTool : ToolBase
canvasWindow.ClientToScreen(&pt);
mainWindow.TrackPopupMenu(pt, 0);
}
return TRUE;
}
void OnFinishDraw() override
@ -246,7 +236,7 @@ struct RectSelTool : ToolBase
m_bLeftButton = bLeftButton;
}
void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnMouseMove(BOOL bLeftButton, LONG& x, LONG& y) override
{
if (bLeftButton)
{
@ -255,9 +245,10 @@ struct RectSelTool : ToolBase
selectionModel.SetRectFromPoints(g_ptStart, pt);
imageModel.NotifyImageChanged();
}
return TRUE;
}
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnButtonUp(BOOL bLeftButton, LONG& x, LONG& y) override
{
POINT pt = { x, y };
if (bLeftButton)
@ -272,6 +263,7 @@ struct RectSelTool : ToolBase
canvasWindow.ClientToScreen(&pt);
mainWindow.TrackPopupMenu(pt, 0);
}
return TRUE;
}
void OnFinishDraw() override
@ -305,26 +297,22 @@ struct TwoPointDrawTool : ToolBase
{
m_bLeftButton = bLeftButton;
m_bDrawing = TRUE;
g_ptStart.x = g_ptEnd.x = x;
g_ptStart.y = g_ptEnd.y = y;
imageModel.NotifyImageChanged();
}
void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnMouseMove(BOOL bLeftButton, LONG& x, LONG& y) override
{
g_ptEnd.x = x;
g_ptEnd.y = y;
imageModel.NotifyImageChanged();
return TRUE;
}
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnButtonUp(BOOL bLeftButton, LONG& x, LONG& y) override
{
g_ptEnd.x = x;
g_ptEnd.y = y;
imageModel.PushImageForUndo();
OnDrawOverlayOnImage(m_hdc);
m_bDrawing = FALSE;
imageModel.NotifyImageChanged();
return TRUE;
}
void OnFinishDraw() override
@ -340,8 +328,101 @@ struct TwoPointDrawTool : ToolBase
}
};
typedef enum DIRECTION
{
NO_DIRECTION = -1,
DIRECTION_HORIZONTAL,
DIRECTION_VERTICAL,
DIRECTION_DIAGONAL_RIGHT_DOWN,
DIRECTION_DIAGONAL_RIGHT_UP,
} DIRECTION;
#define THRESHOULD_DEG 15
static DIRECTION
GetDirection(LONG x0, LONG y0, LONG x1, LONG y1)
{
LONG dx = x1 - x0, dy = y1 - y0;
if (labs(dx) <= 8 && labs(dy) <= 8)
return NO_DIRECTION;
double radian = atan2((double)dy, (double)dx);
if (radian < DEG2RAD(-180 + THRESHOULD_DEG))
{
ATLTRACE("DIRECTION_HORIZONTAL: %ld\n", RAD2DEG(radian));
return DIRECTION_HORIZONTAL;
}
if (radian < DEG2RAD(-90 - THRESHOULD_DEG))
{
ATLTRACE("DIRECTION_DIAGONAL_RIGHT_DOWN: %ld\n", RAD2DEG(radian));
return DIRECTION_DIAGONAL_RIGHT_DOWN;
}
if (radian < DEG2RAD(-90 + THRESHOULD_DEG))
{
ATLTRACE("DIRECTION_VERTICAL: %ld\n", RAD2DEG(radian));
return DIRECTION_VERTICAL;
}
if (radian < DEG2RAD(-THRESHOULD_DEG))
{
ATLTRACE("DIRECTION_DIAGONAL_RIGHT_UP: %ld\n", RAD2DEG(radian));
return DIRECTION_DIAGONAL_RIGHT_UP;
}
if (radian < DEG2RAD(+THRESHOULD_DEG))
{
ATLTRACE("DIRECTION_HORIZONTAL: %ld\n", RAD2DEG(radian));
return DIRECTION_HORIZONTAL;
}
if (radian < DEG2RAD(+90 - THRESHOULD_DEG))
{
ATLTRACE("DIRECTION_DIAGONAL_RIGHT_DOWN: %ld\n", RAD2DEG(radian));
return DIRECTION_DIAGONAL_RIGHT_DOWN;
}
if (radian < DEG2RAD(+90 + THRESHOULD_DEG))
{
ATLTRACE("DIRECTION_VERTICAL: %ld\n", RAD2DEG(radian));
return DIRECTION_VERTICAL;
}
if (radian < DEG2RAD(+180 - THRESHOULD_DEG))
{
ATLTRACE("DIRECTION_DIAGONAL_RIGHT_UP: %ld\n", RAD2DEG(radian));
return DIRECTION_DIAGONAL_RIGHT_UP;
}
ATLTRACE("DIRECTION_HORIZONTAL: %ld\n", RAD2DEG(radian));
return DIRECTION_HORIZONTAL;
}
static void
RestrictDrawDirection(DIRECTION dir, LONG x0, LONG y0, LONG& x1, LONG& y1)
{
switch (dir)
{
case NO_DIRECTION:
default:
return;
case DIRECTION_HORIZONTAL:
y1 = y0;
break;
case DIRECTION_VERTICAL:
x1 = x0;
break;
case DIRECTION_DIAGONAL_RIGHT_DOWN:
y1 = y0 + (x1 - x0);
break;
case DIRECTION_DIAGONAL_RIGHT_UP:
x1 = x0 - (y1 - y0);
break;
}
}
struct SmoothDrawTool : ToolBase
{
DIRECTION m_direction = NO_DIRECTION;
SmoothDrawTool(TOOLTYPE type) : ToolBase(type)
{
}
@ -350,22 +431,51 @@ struct SmoothDrawTool : ToolBase
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
{
m_direction = NO_DIRECTION;
imageModel.PushImageForUndo();
g_ptStart.x = g_ptEnd.x = x;
g_ptStart.y = g_ptEnd.y = y;
imageModel.NotifyImageChanged();
}
void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnMouseMove(BOOL bLeftButton, LONG& x, LONG& y) override
{
if (::GetKeyState(VK_SHIFT) < 0) // Shift key is pressed
{
if (m_direction == NO_DIRECTION)
{
m_direction = GetDirection(g_ptStart.x, g_ptStart.y, x, y);
if (m_direction == NO_DIRECTION)
return FALSE;
}
RestrictDrawDirection(m_direction, g_ptStart.x, g_ptStart.y, x, y);
}
else
{
if (m_direction != NO_DIRECTION)
{
m_direction = NO_DIRECTION;
draw(bLeftButton, x, y);
g_ptStart.x = g_ptEnd.x = x;
g_ptStart.y = g_ptEnd.y = y;
return TRUE;
}
}
draw(bLeftButton, x, y);
imageModel.NotifyImageChanged();
return TRUE;
}
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnButtonUp(BOOL bLeftButton, LONG& x, LONG& y) override
{
if (m_direction != NO_DIRECTION)
{
RestrictDrawDirection(m_direction, g_ptStart.x, g_ptStart.y, x, y);
}
draw(bLeftButton, x, y);
OnFinishDraw();
return TRUE;
}
void OnFinishDraw() override
@ -375,7 +485,8 @@ struct SmoothDrawTool : ToolBase
void OnCancelDraw() override
{
OnButtonUp(FALSE, 0, 0);
LONG x = 0, y = 0;
OnButtonUp(FALSE, x, y);
imageModel.Undo(TRUE);
ToolBase::OnCancelDraw();
}
@ -435,15 +546,17 @@ struct ColorTool : ToolBase
paletteModel.SetBgColor(rgbColor);
}
void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnMouseMove(BOOL bLeftButton, LONG& x, LONG& y) override
{
fetchColor(bLeftButton, x, y);
return TRUE;
}
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnButtonUp(BOOL bLeftButton, LONG& x, LONG& y) override
{
fetchColor(bLeftButton, x, y);
toolsModel.SetActiveTool(toolsModel.GetOldActiveTool());
return TRUE;
}
};
@ -550,9 +663,10 @@ struct TextTool : ToolBase
UpdatePoint(x, y);
}
void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnMouseMove(BOOL bLeftButton, LONG& x, LONG& y) override
{
UpdatePoint(x, y);
return TRUE;
}
void draw(HDC hdc)
@ -578,7 +692,7 @@ struct TextTool : ToolBase
selectionModel.HideSelection();
}
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnButtonUp(BOOL bLeftButton, LONG& x, LONG& y) override
{
POINT pt = { x, y };
imageModel.Clamp(pt);
@ -595,7 +709,7 @@ struct TextTool : ToolBase
if (::IsRectEmpty(&selectionModel.m_rc))
{
quit();
return;
return TRUE;
}
}
@ -630,6 +744,7 @@ struct TextTool : ToolBase
textEditWindow.ValidateEditRect(&rc);
textEditWindow.ShowWindow(SW_SHOWNOACTIVATE);
textEditWindow.SetFocus();
return TRUE;
}
void OnFinishDraw() override
@ -720,23 +835,25 @@ struct BezierTool : ToolBase
imageModel.NotifyImageChanged();
}
void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnMouseMove(BOOL bLeftButton, LONG& x, LONG& y) override
{
s_pointStack[s_pointSP].x = x;
s_pointStack[s_pointSP].y = y;
imageModel.NotifyImageChanged();
return TRUE;
}
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnButtonUp(BOOL bLeftButton, LONG& x, LONG& y) override
{
s_pointStack[s_pointSP].x = x;
s_pointStack[s_pointSP].y = y;
if (s_pointSP >= 3)
{
OnFinishDraw();
return;
return TRUE;
}
imageModel.NotifyImageChanged();
return TRUE;
}
void OnCancelDraw() override
@ -822,7 +939,7 @@ struct ShapeTool : ToolBase
imageModel.NotifyImageChanged();
}
void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnMouseMove(BOOL bLeftButton, LONG& x, LONG& y) override
{
if ((s_pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
roundTo8Directions(s_pointStack[s_pointSP - 1].x, s_pointStack[s_pointSP - 1].y, x, y);
@ -831,9 +948,10 @@ struct ShapeTool : ToolBase
s_pointStack[s_pointSP].y = y;
imageModel.NotifyImageChanged();
return TRUE;
}
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
BOOL OnButtonUp(BOOL bLeftButton, LONG& x, LONG& y) override
{
if ((s_pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
roundTo8Directions(s_pointStack[s_pointSP - 1].x, s_pointStack[s_pointSP - 1].y, x, y);
@ -842,7 +960,7 @@ struct ShapeTool : ToolBase
if (nearlyEqualPoints(x, y, s_pointStack[0].x, s_pointStack[0].y))
{
OnFinishDraw();
return;
return TRUE;
}
else
{
@ -855,6 +973,7 @@ struct ShapeTool : ToolBase
s_pointSP--;
imageModel.NotifyImageChanged();
return TRUE;
}
void OnCancelDraw() override

View file

@ -21,6 +21,8 @@
#include <commdlg.h>
#include <commctrl.h>
#include <stdlib.h>
#define _USE_MATH_DEFINES /* for M_PI */
#include <math.h>
#include <shellapi.h>
#include <htmlhelp.h>
#include "atlimagedx.h"

View file

@ -189,24 +189,31 @@ void ToolsModel::NotifyZoomChanged()
void ToolsModel::OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick)
{
m_pToolObject->beginEvent();
updateStartAndLast(x, y);
m_pToolObject->OnButtonDown(bLeftButton, x, y, bDoubleClick);
g_ptStart.x = g_ptEnd.x = x;
g_ptStart.y = g_ptEnd.y = y;
m_pToolObject->endEvent();
}
void ToolsModel::OnMouseMove(BOOL bLeftButton, LONG x, LONG y)
{
m_pToolObject->beginEvent();
m_pToolObject->OnMouseMove(bLeftButton, x, y);
updateLast(x, y);
if (m_pToolObject->OnMouseMove(bLeftButton, x, y))
{
g_ptEnd.x = x;
g_ptEnd.y = y;
}
m_pToolObject->endEvent();
}
void ToolsModel::OnButtonUp(BOOL bLeftButton, LONG x, LONG y)
{
m_pToolObject->beginEvent();
m_pToolObject->OnButtonUp(bLeftButton, x, y);
updateLast(x, y);
if (m_pToolObject->OnButtonUp(bLeftButton, x, y))
{
g_ptEnd.x = x;
g_ptEnd.y = y;
}
m_pToolObject->endEvent();
}

View file

@ -42,8 +42,8 @@ struct ToolBase
virtual ~ToolBase() { }
virtual void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) { }
virtual void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) { }
virtual void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) { }
virtual BOOL OnMouseMove(BOOL bLeftButton, LONG& x, LONG& y) { return TRUE; }
virtual BOOL OnButtonUp(BOOL bLeftButton, LONG& x, LONG& y) { return TRUE; }
virtual void OnCancelDraw();
virtual void OnFinishDraw();