mirror of
https://github.com/reactos/reactos.git
synced 2026-06-22 02:12:49 +08:00
[MSPAINT] Zooming and cursor shape (#9125)
#8974 implemented custom mouse cursor shapes. However, the custom cursor shape didn't consider zooming. This PR applies zooming to the custom cursor shapes. JIRA issue: CORE-20520 - Enhance CStyledCursor for zooming. - Enhance CopyMonoImage and CopyDIBImage for stretch mode. - Add DEFAULT_ZOOM constant (1000). - Send WM_SETCURSOR message on ToolsModel::SetZoom. - Improve accuracy of Zoomed and UnZoomed functions by using MulDiv function.
This commit is contained in:
committed by
GitHub
parent
b7932431e7
commit
ee60345493
@@ -13,10 +13,10 @@ CCanvasWindow canvasWindow;
|
||||
/* FUNCTIONS ********************************************************/
|
||||
|
||||
HCURSOR
|
||||
CStyledCursor::CreateStyledCursor(BrushStyle style, INT radius, COLORREF color, BOOL is_rubber)
|
||||
CStyledCursor::CreateStyledCursor(BrushStyle style, INT zoom, INT radius, COLORREF color, BOOL is_rubber)
|
||||
{
|
||||
const INT diameter = 2 * radius;
|
||||
if (diameter <= 2)
|
||||
if (diameter * zoom / DEFAULT_ZOOM <= 2)
|
||||
{
|
||||
HCURSOR hCursor = ::LoadCursor(NULL, IDC_CROSS);
|
||||
return hCursor ? CopyCursor(hCursor) : NULL;
|
||||
@@ -24,7 +24,7 @@ CStyledCursor::CreateStyledCursor(BrushStyle style, INT radius, COLORREF color,
|
||||
|
||||
const INT crosshair1 = 6, crosshair2 = crosshair1 - 2;
|
||||
const INT width = diameter + 2 * crosshair1, height = diameter + 2 * crosshair1;
|
||||
const DWORD hotX = width / 2, hotY = height / 2;
|
||||
DWORD hotX = width / 2, hotY = height / 2;
|
||||
|
||||
HDC hdcScreen = ::GetDC(NULL);
|
||||
if (!hdcScreen)
|
||||
@@ -116,6 +116,20 @@ CStyledCursor::CreateStyledCursor(BrushStyle style, INT radius, COLORREF color,
|
||||
::ReleaseDC(NULL, hdcScreen);
|
||||
::DeleteDC(hdcMem);
|
||||
|
||||
if (zoom != DEFAULT_ZOOM)
|
||||
{
|
||||
INT newWidth = width * zoom / DEFAULT_ZOOM;
|
||||
INT newHeight = height * zoom / DEFAULT_ZOOM;
|
||||
HBITMAP hbmMaskNew = CopyMonoImage(hbmMask, newWidth, newHeight, STRETCH_DELETESCANS);
|
||||
HBITMAP hbmColorNew = CopyDIBImage(hbmColor, newWidth, newHeight, STRETCH_DELETESCANS);
|
||||
::DeleteObject(hbmMask);
|
||||
::DeleteObject(hbmColor);
|
||||
hbmMask = hbmMaskNew;
|
||||
hbmColor = hbmColorNew;
|
||||
hotX = width * zoom / (2 * DEFAULT_ZOOM);
|
||||
hotY = height * zoom / (2 * DEFAULT_ZOOM);
|
||||
}
|
||||
|
||||
ICONINFO ii = { FALSE, hotX, hotY, hbmMask, hbmColor };
|
||||
HCURSOR hCursor = (HCURSOR)::CreateIconIndirect(&ii);
|
||||
|
||||
@@ -125,9 +139,13 @@ CStyledCursor::CreateStyledCursor(BrushStyle style, INT radius, COLORREF color,
|
||||
return hCursor;
|
||||
}
|
||||
|
||||
void CStyledCursor::SetStyle(BrushStyle style, INT radius, COLORREF color, BOOL is_rubber)
|
||||
void CStyledCursor::SetStyle(BrushStyle style, INT zoom, INT radius, COLORREF color, BOOL is_rubber)
|
||||
{
|
||||
if (m_hCursor && m_style == style && m_radius == radius && m_color == color &&
|
||||
if (m_hCursor &&
|
||||
m_style == style &&
|
||||
m_zoom == zoom &&
|
||||
m_radius == radius &&
|
||||
m_color == color &&
|
||||
m_is_rubber == is_rubber)
|
||||
{
|
||||
return;
|
||||
@@ -136,8 +154,9 @@ void CStyledCursor::SetStyle(BrushStyle style, INT radius, COLORREF color, BOOL
|
||||
if (m_hCursor)
|
||||
DestroyCursor(m_hCursor);
|
||||
|
||||
m_hCursor = CreateStyledCursor(style, radius, color, is_rubber);
|
||||
m_hCursor = CreateStyledCursor(style, zoom, radius, color, is_rubber);
|
||||
m_style = style;
|
||||
m_zoom = zoom;
|
||||
m_radius = radius;
|
||||
m_color = color;
|
||||
m_is_rubber = is_rubber;
|
||||
@@ -775,7 +794,9 @@ LRESULT CCanvasWindow::OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
|
||||
break;
|
||||
case TOOL_RUBBER:
|
||||
{
|
||||
m_hRubberCursor.SetStyle(BrushStyleSquare, toolsModel.GetRubberRadius(),
|
||||
m_hRubberCursor.SetStyle(BrushStyleSquare,
|
||||
toolsModel.GetZoom(),
|
||||
toolsModel.GetRubberRadius(),
|
||||
paletteModel.GetBgColor(), TRUE);
|
||||
m_hRubberCursor.SetCursor();
|
||||
break;
|
||||
@@ -783,6 +804,7 @@ LRESULT CCanvasWindow::OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
|
||||
case TOOL_BRUSH:
|
||||
{
|
||||
m_hBrushCursor.SetStyle(toolsModel.GetBrushStyle(),
|
||||
toolsModel.GetZoom(),
|
||||
toolsModel.GetBrushWidth() / 2,
|
||||
paletteModel.GetFgColor(), FALSE);
|
||||
m_hBrushCursor.SetCursor();
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
::DestroyCursor(m_hCursor);
|
||||
}
|
||||
|
||||
void SetStyle(BrushStyle style, INT radius, COLORREF color, BOOL is_rubber);
|
||||
void SetStyle(BrushStyle style, INT zoom, INT radius, COLORREF color, BOOL is_rubber);
|
||||
|
||||
void SetCursor()
|
||||
{
|
||||
@@ -32,11 +32,12 @@ public:
|
||||
protected:
|
||||
HCURSOR m_hCursor = NULL;
|
||||
BrushStyle m_style;
|
||||
INT m_zoom = -1;
|
||||
INT m_radius = -1;
|
||||
COLORREF m_color = CLR_INVALID;
|
||||
BOOL m_is_rubber = FALSE;
|
||||
|
||||
static HCURSOR CreateStyledCursor(BrushStyle style, INT radius, COLORREF color, BOOL is_rubber);
|
||||
static HCURSOR CreateStyledCursor(BrushStyle style, INT zoom, INT radius, COLORREF color, BOOL is_rubber);
|
||||
};
|
||||
|
||||
class CCanvasWindow : public CWindowImpl<CCanvasWindow>
|
||||
|
||||
@@ -84,7 +84,7 @@ CreateColorDIB(int width, int height, COLORREF rgb)
|
||||
return ret;
|
||||
}
|
||||
|
||||
HBITMAP CopyMonoImage(HBITMAP hbm, INT cx, INT cy)
|
||||
HBITMAP CopyMonoImage(HBITMAP hbm, INT cx, INT cy, INT stretchMode)
|
||||
{
|
||||
BITMAP bm;
|
||||
if (!::GetObjectW(hbm, sizeof(bm), &bm))
|
||||
@@ -96,14 +96,41 @@ HBITMAP CopyMonoImage(HBITMAP hbm, INT cx, INT cy)
|
||||
cy = bm.bmHeight;
|
||||
}
|
||||
|
||||
HDC hdc1 = ::CreateCompatibleDC(NULL);
|
||||
HDC hdc2 = ::CreateCompatibleDC(NULL);
|
||||
HBITMAP hbmNew = ::CreateBitmap(cx, cy, 1, 1, NULL);
|
||||
if (!hbmNew)
|
||||
HGDIOBJ hbm1Old = ::SelectObject(hdc1, hbm);
|
||||
HGDIOBJ hbm2Old = ::SelectObject(hdc2, hbmNew);
|
||||
::SetStretchBltMode(hdc2, stretchMode);
|
||||
::StretchBlt(hdc2, 0, 0, cx, cy, hdc1, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
|
||||
::SelectObject(hdc1, hbm1Old);
|
||||
::SelectObject(hdc2, hbm2Old);
|
||||
::DeleteDC(hdc1);
|
||||
::DeleteDC(hdc2);
|
||||
return hbmNew;
|
||||
}
|
||||
|
||||
HBITMAP CopyDIBImage(HBITMAP hbm, INT cx, INT cy, INT stretchMode)
|
||||
{
|
||||
if (stretchMode == STRETCH_HALFTONE)
|
||||
return (HBITMAP)CopyImage(hbm, IMAGE_BITMAP, cx, cy, LR_CREATEDIBSECTION);
|
||||
|
||||
BITMAP bm;
|
||||
if (!::GetObjectW(hbm, sizeof(bm), &bm))
|
||||
return NULL;
|
||||
|
||||
if (cx == 0 || cy == 0)
|
||||
{
|
||||
cx = bm.bmWidth;
|
||||
cy = bm.bmHeight;
|
||||
}
|
||||
|
||||
HDC hdc1 = ::CreateCompatibleDC(NULL);
|
||||
HDC hdc2 = ::CreateCompatibleDC(NULL);
|
||||
HBITMAP hbmNew = CreateDIBWithProperties(cx, cy);
|
||||
HGDIOBJ hbm1Old = ::SelectObject(hdc1, hbm);
|
||||
HGDIOBJ hbm2Old = ::SelectObject(hdc2, hbmNew);
|
||||
::SetStretchBltMode(hdc2, stretchMode);
|
||||
::StretchBlt(hdc2, 0, 0, cx, cy, hdc1, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
|
||||
::SelectObject(hdc1, hbm1Old);
|
||||
::SelectObject(hdc2, hbm2Old);
|
||||
|
||||
@@ -14,12 +14,8 @@ HBITMAP CreateColorDIB(int width, int height, COLORREF rgb);
|
||||
HBITMAP CachedBufferDIB(HBITMAP hbm, int minimalWidth, int minimalHeight);
|
||||
HBITMAP ConvertToBlackAndWhite(HBITMAP hbm);
|
||||
|
||||
HBITMAP CopyMonoImage(HBITMAP hbm, INT cx = 0, INT cy = 0);
|
||||
|
||||
static inline HBITMAP CopyDIBImage(HBITMAP hbm, INT cx = 0, INT cy = 0)
|
||||
{
|
||||
return (HBITMAP)CopyImage(hbm, IMAGE_BITMAP, cx, cy, LR_COPYRETURNORG | LR_CREATEDIBSECTION);
|
||||
}
|
||||
HBITMAP CopyMonoImage(HBITMAP hbm, INT cx = 0, INT cy = 0, INT stretchMode = STRETCH_HALFTONE);
|
||||
HBITMAP CopyDIBImage(HBITMAP hbm, INT cx = 0, INT cy = 0, INT stretchMode = STRETCH_HALFTONE);
|
||||
|
||||
int GetDIBWidth(HBITMAP hbm);
|
||||
int GetDIBHeight(HBITMAP hbm);
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#define GRIP_SIZE 3
|
||||
#define MIN_ZOOM 125
|
||||
#define MAX_ZOOM 8000
|
||||
#define DEFAULT_ZOOM 1000
|
||||
|
||||
#define MAX_LONG_PATH 512
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ ToolsModel::ToolsModel()
|
||||
m_airBrushRadius = 5;
|
||||
m_rubberRadius = 4;
|
||||
m_transpBg = FALSE;
|
||||
m_zoom = 1000;
|
||||
m_zoom = DEFAULT_ZOOM;
|
||||
m_pToolObject = GetOrCreateTool(m_activeTool);
|
||||
}
|
||||
|
||||
@@ -276,6 +276,7 @@ void ToolsModel::SetZoom(int nZoom)
|
||||
{
|
||||
m_zoom = nZoom;
|
||||
NotifyZoomChanged();
|
||||
SendSetCursor();
|
||||
}
|
||||
|
||||
void ToolsModel::NotifyToolChanged()
|
||||
|
||||
@@ -150,12 +150,12 @@ extern ToolsModel toolsModel;
|
||||
|
||||
static inline int Zoomed(int xy)
|
||||
{
|
||||
return xy * toolsModel.GetZoom() / 1000;
|
||||
return MulDiv(xy, toolsModel.GetZoom(), DEFAULT_ZOOM);
|
||||
}
|
||||
|
||||
static inline int UnZoomed(int xy)
|
||||
{
|
||||
return xy * 1000 / toolsModel.GetZoom();
|
||||
return MulDiv(xy, DEFAULT_ZOOM, toolsModel.GetZoom());
|
||||
}
|
||||
|
||||
static inline void Zoomed(POINT& pt)
|
||||
|
||||
Reference in New Issue
Block a user