Skip to content

Commit ee60345

Browse files
authored
[MSPAINT] Zooming and cursor shape (reactos#9125)
reactos#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.
1 parent b793243 commit ee60345

7 files changed

Lines changed: 68 additions & 20 deletions

File tree

base/applications/mspaint/canvas.cpp

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@ CCanvasWindow canvasWindow;
1313
/* FUNCTIONS ********************************************************/
1414

1515
HCURSOR
16-
CStyledCursor::CreateStyledCursor(BrushStyle style, INT radius, COLORREF color, BOOL is_rubber)
16+
CStyledCursor::CreateStyledCursor(BrushStyle style, INT zoom, INT radius, COLORREF color, BOOL is_rubber)
1717
{
1818
const INT diameter = 2 * radius;
19-
if (diameter <= 2)
19+
if (diameter * zoom / DEFAULT_ZOOM <= 2)
2020
{
2121
HCURSOR hCursor = ::LoadCursor(NULL, IDC_CROSS);
2222
return hCursor ? CopyCursor(hCursor) : NULL;
2323
}
2424

2525
const INT crosshair1 = 6, crosshair2 = crosshair1 - 2;
2626
const INT width = diameter + 2 * crosshair1, height = diameter + 2 * crosshair1;
27-
const DWORD hotX = width / 2, hotY = height / 2;
27+
DWORD hotX = width / 2, hotY = height / 2;
2828

2929
HDC hdcScreen = ::GetDC(NULL);
3030
if (!hdcScreen)
@@ -116,6 +116,20 @@ CStyledCursor::CreateStyledCursor(BrushStyle style, INT radius, COLORREF color,
116116
::ReleaseDC(NULL, hdcScreen);
117117
::DeleteDC(hdcMem);
118118

119+
if (zoom != DEFAULT_ZOOM)
120+
{
121+
INT newWidth = width * zoom / DEFAULT_ZOOM;
122+
INT newHeight = height * zoom / DEFAULT_ZOOM;
123+
HBITMAP hbmMaskNew = CopyMonoImage(hbmMask, newWidth, newHeight, STRETCH_DELETESCANS);
124+
HBITMAP hbmColorNew = CopyDIBImage(hbmColor, newWidth, newHeight, STRETCH_DELETESCANS);
125+
::DeleteObject(hbmMask);
126+
::DeleteObject(hbmColor);
127+
hbmMask = hbmMaskNew;
128+
hbmColor = hbmColorNew;
129+
hotX = width * zoom / (2 * DEFAULT_ZOOM);
130+
hotY = height * zoom / (2 * DEFAULT_ZOOM);
131+
}
132+
119133
ICONINFO ii = { FALSE, hotX, hotY, hbmMask, hbmColor };
120134
HCURSOR hCursor = (HCURSOR)::CreateIconIndirect(&ii);
121135

@@ -125,9 +139,13 @@ CStyledCursor::CreateStyledCursor(BrushStyle style, INT radius, COLORREF color,
125139
return hCursor;
126140
}
127141

128-
void CStyledCursor::SetStyle(BrushStyle style, INT radius, COLORREF color, BOOL is_rubber)
142+
void CStyledCursor::SetStyle(BrushStyle style, INT zoom, INT radius, COLORREF color, BOOL is_rubber)
129143
{
130-
if (m_hCursor && m_style == style && m_radius == radius && m_color == color &&
144+
if (m_hCursor &&
145+
m_style == style &&
146+
m_zoom == zoom &&
147+
m_radius == radius &&
148+
m_color == color &&
131149
m_is_rubber == is_rubber)
132150
{
133151
return;
@@ -136,8 +154,9 @@ void CStyledCursor::SetStyle(BrushStyle style, INT radius, COLORREF color, BOOL
136154
if (m_hCursor)
137155
DestroyCursor(m_hCursor);
138156

139-
m_hCursor = CreateStyledCursor(style, radius, color, is_rubber);
157+
m_hCursor = CreateStyledCursor(style, zoom, radius, color, is_rubber);
140158
m_style = style;
159+
m_zoom = zoom;
141160
m_radius = radius;
142161
m_color = color;
143162
m_is_rubber = is_rubber;
@@ -775,14 +794,17 @@ LRESULT CCanvasWindow::OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
775794
break;
776795
case TOOL_RUBBER:
777796
{
778-
m_hRubberCursor.SetStyle(BrushStyleSquare, toolsModel.GetRubberRadius(),
797+
m_hRubberCursor.SetStyle(BrushStyleSquare,
798+
toolsModel.GetZoom(),
799+
toolsModel.GetRubberRadius(),
779800
paletteModel.GetBgColor(), TRUE);
780801
m_hRubberCursor.SetCursor();
781802
break;
782803
}
783804
case TOOL_BRUSH:
784805
{
785806
m_hBrushCursor.SetStyle(toolsModel.GetBrushStyle(),
807+
toolsModel.GetZoom(),
786808
toolsModel.GetBrushWidth() / 2,
787809
paletteModel.GetFgColor(), FALSE);
788810
m_hBrushCursor.SetCursor();

base/applications/mspaint/canvas.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class CStyledCursor
1919
::DestroyCursor(m_hCursor);
2020
}
2121

22-
void SetStyle(BrushStyle style, INT radius, COLORREF color, BOOL is_rubber);
22+
void SetStyle(BrushStyle style, INT zoom, INT radius, COLORREF color, BOOL is_rubber);
2323

2424
void SetCursor()
2525
{
@@ -32,11 +32,12 @@ class CStyledCursor
3232
protected:
3333
HCURSOR m_hCursor = NULL;
3434
BrushStyle m_style;
35+
INT m_zoom = -1;
3536
INT m_radius = -1;
3637
COLORREF m_color = CLR_INVALID;
3738
BOOL m_is_rubber = FALSE;
3839

39-
static HCURSOR CreateStyledCursor(BrushStyle style, INT radius, COLORREF color, BOOL is_rubber);
40+
static HCURSOR CreateStyledCursor(BrushStyle style, INT zoom, INT radius, COLORREF color, BOOL is_rubber);
4041
};
4142

4243
class CCanvasWindow : public CWindowImpl<CCanvasWindow>

base/applications/mspaint/dib.cpp

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ CreateColorDIB(int width, int height, COLORREF rgb)
8484
return ret;
8585
}
8686

87-
HBITMAP CopyMonoImage(HBITMAP hbm, INT cx, INT cy)
87+
HBITMAP CopyMonoImage(HBITMAP hbm, INT cx, INT cy, INT stretchMode)
8888
{
8989
BITMAP bm;
9090
if (!::GetObjectW(hbm, sizeof(bm), &bm))
@@ -96,14 +96,41 @@ HBITMAP CopyMonoImage(HBITMAP hbm, INT cx, INT cy)
9696
cy = bm.bmHeight;
9797
}
9898

99+
HDC hdc1 = ::CreateCompatibleDC(NULL);
100+
HDC hdc2 = ::CreateCompatibleDC(NULL);
99101
HBITMAP hbmNew = ::CreateBitmap(cx, cy, 1, 1, NULL);
100-
if (!hbmNew)
102+
HGDIOBJ hbm1Old = ::SelectObject(hdc1, hbm);
103+
HGDIOBJ hbm2Old = ::SelectObject(hdc2, hbmNew);
104+
::SetStretchBltMode(hdc2, stretchMode);
105+
::StretchBlt(hdc2, 0, 0, cx, cy, hdc1, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
106+
::SelectObject(hdc1, hbm1Old);
107+
::SelectObject(hdc2, hbm2Old);
108+
::DeleteDC(hdc1);
109+
::DeleteDC(hdc2);
110+
return hbmNew;
111+
}
112+
113+
HBITMAP CopyDIBImage(HBITMAP hbm, INT cx, INT cy, INT stretchMode)
114+
{
115+
if (stretchMode == STRETCH_HALFTONE)
116+
return (HBITMAP)CopyImage(hbm, IMAGE_BITMAP, cx, cy, LR_CREATEDIBSECTION);
117+
118+
BITMAP bm;
119+
if (!::GetObjectW(hbm, sizeof(bm), &bm))
101120
return NULL;
102121

122+
if (cx == 0 || cy == 0)
123+
{
124+
cx = bm.bmWidth;
125+
cy = bm.bmHeight;
126+
}
127+
103128
HDC hdc1 = ::CreateCompatibleDC(NULL);
104129
HDC hdc2 = ::CreateCompatibleDC(NULL);
130+
HBITMAP hbmNew = CreateDIBWithProperties(cx, cy);
105131
HGDIOBJ hbm1Old = ::SelectObject(hdc1, hbm);
106132
HGDIOBJ hbm2Old = ::SelectObject(hdc2, hbmNew);
133+
::SetStretchBltMode(hdc2, stretchMode);
107134
::StretchBlt(hdc2, 0, 0, cx, cy, hdc1, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
108135
::SelectObject(hdc1, hbm1Old);
109136
::SelectObject(hdc2, hbm2Old);

base/applications/mspaint/dib.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,8 @@ HBITMAP CreateColorDIB(int width, int height, COLORREF rgb);
1414
HBITMAP CachedBufferDIB(HBITMAP hbm, int minimalWidth, int minimalHeight);
1515
HBITMAP ConvertToBlackAndWhite(HBITMAP hbm);
1616

17-
HBITMAP CopyMonoImage(HBITMAP hbm, INT cx = 0, INT cy = 0);
18-
19-
static inline HBITMAP CopyDIBImage(HBITMAP hbm, INT cx = 0, INT cy = 0)
20-
{
21-
return (HBITMAP)CopyImage(hbm, IMAGE_BITMAP, cx, cy, LR_COPYRETURNORG | LR_CREATEDIBSECTION);
22-
}
17+
HBITMAP CopyMonoImage(HBITMAP hbm, INT cx = 0, INT cy = 0, INT stretchMode = STRETCH_HALFTONE);
18+
HBITMAP CopyDIBImage(HBITMAP hbm, INT cx = 0, INT cy = 0, INT stretchMode = STRETCH_HALFTONE);
2319

2420
int GetDIBWidth(HBITMAP hbm);
2521
int GetDIBHeight(HBITMAP hbm);

base/applications/mspaint/precomp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#define GRIP_SIZE 3
4444
#define MIN_ZOOM 125
4545
#define MAX_ZOOM 8000
46+
#define DEFAULT_ZOOM 1000
4647

4748
#define MAX_LONG_PATH 512
4849

base/applications/mspaint/toolsmodel.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ ToolsModel::ToolsModel()
2121
m_airBrushRadius = 5;
2222
m_rubberRadius = 4;
2323
m_transpBg = FALSE;
24-
m_zoom = 1000;
24+
m_zoom = DEFAULT_ZOOM;
2525
m_pToolObject = GetOrCreateTool(m_activeTool);
2626
}
2727

@@ -276,6 +276,7 @@ void ToolsModel::SetZoom(int nZoom)
276276
{
277277
m_zoom = nZoom;
278278
NotifyZoomChanged();
279+
SendSetCursor();
279280
}
280281

281282
void ToolsModel::NotifyToolChanged()

base/applications/mspaint/toolsmodel.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,12 @@ extern ToolsModel toolsModel;
150150

151151
static inline int Zoomed(int xy)
152152
{
153-
return xy * toolsModel.GetZoom() / 1000;
153+
return MulDiv(xy, toolsModel.GetZoom(), DEFAULT_ZOOM);
154154
}
155155

156156
static inline int UnZoomed(int xy)
157157
{
158-
return xy * 1000 / toolsModel.GetZoom();
158+
return MulDiv(xy, DEFAULT_ZOOM, toolsModel.GetZoom());
159159
}
160160

161161
static inline void Zoomed(POINT& pt)

0 commit comments

Comments
 (0)