mirror of
https://github.com/reactos/reactos.git
synced 2025-02-20 15:35:04 +00:00
[MSPAINT] Improve Zoom tool (#5798)
- Delete global zoomTo function. - Add CCanvasWindow::zoomTo and CCanvasWindow::getNewZoomRect functions. - Rename CCanvasWindow::updateScrollInfo as CCanvasWindow::updateScrollRange. - Rename CCanvasWindow::resetScrollPos as CCanvasWindow::updateScrollPos. - Draw the proper zoom rectangle on mouse move. - Revert the active tool on click when the tool was Zoom. CORE-19094
This commit is contained in:
parent
e2d3aa7f4a
commit
8f1eb03ad2
8 changed files with 113 additions and 73 deletions
|
@ -89,6 +89,49 @@ HITTEST CCanvasWindow::CanvasHitTest(POINT pt)
|
|||
return getSizeBoxHitTest(pt, &rcBase);
|
||||
}
|
||||
|
||||
VOID CCanvasWindow::getNewZoomRect(CRect& rcView, INT newZoom, CPoint ptTarget)
|
||||
{
|
||||
CRect rcImage;
|
||||
GetImageRect(rcImage);
|
||||
ImageToCanvas(rcImage);
|
||||
|
||||
// Calculate the zoom rectangle
|
||||
INT oldZoom = toolsModel.GetZoom();
|
||||
GetClientRect(rcView);
|
||||
LONG cxView = rcView.right * oldZoom / newZoom, cyView = rcView.bottom * oldZoom / newZoom;
|
||||
::SetRect(&rcView, ptTarget.x - cxView / 2, ptTarget.y - cyView / 2,
|
||||
ptTarget.x + cxView / 2, ptTarget.y + cyView / 2);
|
||||
|
||||
// Shift the rectangle if necessary
|
||||
INT dx = 0, dy = 0;
|
||||
if (rcView.left < rcImage.left)
|
||||
dx = rcImage.left - rcView.left;
|
||||
else if (rcImage.right < rcView.right)
|
||||
dx = rcImage.right - rcView.right;
|
||||
if (rcView.top < rcImage.top)
|
||||
dy = rcImage.top - rcView.top;
|
||||
else if (rcImage.bottom < rcView.bottom)
|
||||
dy = rcImage.bottom - rcView.bottom;
|
||||
rcView.OffsetRect(dx, dy);
|
||||
|
||||
rcView.IntersectRect(&rcView, &rcImage);
|
||||
}
|
||||
|
||||
VOID CCanvasWindow::zoomTo(INT newZoom, LONG left, LONG top)
|
||||
{
|
||||
POINT pt = { left, top };
|
||||
CanvasToImage(pt);
|
||||
|
||||
toolsModel.SetZoom(newZoom);
|
||||
ImageToCanvas(pt);
|
||||
pt.x += GetScrollPos(SB_HORZ);
|
||||
pt.y += GetScrollPos(SB_VERT);
|
||||
|
||||
updateScrollRange();
|
||||
updateScrollPos(pt.x, pt.y);
|
||||
Invalidate(TRUE);
|
||||
}
|
||||
|
||||
VOID CCanvasWindow::DoDraw(HDC hDC, RECT& rcClient, RECT& rcPaint)
|
||||
{
|
||||
// This is the target area we have to draw on
|
||||
|
@ -180,7 +223,7 @@ VOID CCanvasWindow::DoDraw(HDC hDC, RECT& rcClient, RECT& rcPaint)
|
|||
::DeleteDC(hdcMem0);
|
||||
}
|
||||
|
||||
VOID CCanvasWindow::updateScrollInfo()
|
||||
VOID CCanvasWindow::updateScrollRange()
|
||||
{
|
||||
CRect rcClient;
|
||||
GetClientRect(&rcClient);
|
||||
|
@ -211,16 +254,16 @@ VOID CCanvasWindow::updateScrollInfo()
|
|||
SetScrollInfo(SB_VERT, &si);
|
||||
}
|
||||
|
||||
VOID CCanvasWindow::resetScrollPos()
|
||||
VOID CCanvasWindow::updateScrollPos(INT x, INT y)
|
||||
{
|
||||
SetScrollPos(SB_HORZ, 0);
|
||||
SetScrollPos(SB_VERT, 0);
|
||||
SetScrollPos(SB_HORZ, x);
|
||||
SetScrollPos(SB_VERT, y);
|
||||
}
|
||||
|
||||
LRESULT CCanvasWindow::OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
||||
{
|
||||
if (m_hWnd)
|
||||
updateScrollInfo();
|
||||
updateScrollRange();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -251,7 +294,7 @@ VOID CCanvasWindow::OnHVScroll(WPARAM wParam, INT fnBar)
|
|||
break;
|
||||
}
|
||||
SetScrollInfo(fnBar, &si);
|
||||
updateScrollInfo();
|
||||
updateScrollRange();
|
||||
Invalidate(FALSE); // FIXME: Flicker
|
||||
}
|
||||
|
||||
|
@ -632,7 +675,7 @@ LRESULT CCanvasWindow::OnLRButtonUp(BOOL bLeftButton, UINT nMsg, WPARAM wParam,
|
|||
|
||||
m_hitCanvasSizeBox = HIT_NONE;
|
||||
toolsModel.resetTool(); // resets the point-buffer of the polygon and bezier functions
|
||||
updateScrollInfo();
|
||||
updateScrollRange();
|
||||
Invalidate(TRUE);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -42,8 +42,8 @@ public:
|
|||
|
||||
VOID cancelDrawing();
|
||||
VOID finishDrawing();
|
||||
VOID updateScrollInfo();
|
||||
VOID resetScrollPos();
|
||||
VOID updateScrollRange();
|
||||
VOID updateScrollPos(INT x = 0, INT y = 0);
|
||||
|
||||
VOID ImageToCanvas(POINT& pt);
|
||||
VOID ImageToCanvas(RECT& rc);
|
||||
|
@ -51,6 +51,8 @@ public:
|
|||
VOID CanvasToImage(RECT& rc, BOOL bZoomed = FALSE);
|
||||
VOID GetImageRect(RECT& rc);
|
||||
VOID MoveSelection(INT xDelta, INT yDelta);
|
||||
VOID getNewZoomRect(CRect& rcView, INT newZoom, CPoint ptTarget);
|
||||
VOID zoomTo(INT newZoom, LONG left = 0, LONG top = 0);
|
||||
|
||||
protected:
|
||||
HITTEST m_hitSelection;
|
||||
|
|
|
@ -43,7 +43,6 @@ enum HITTEST // hit
|
|||
|
||||
/* FUNCTIONS ********************************************************/
|
||||
|
||||
BOOL zoomTo(int newZoom, int mouseX, int mouseY);
|
||||
BOOL nearlyEqualPoints(INT x0, INT y0, INT x1, INT y1);
|
||||
BOOL OpenMailer(HWND hWnd, LPCWSTR pszPathName);
|
||||
|
||||
|
|
|
@ -241,7 +241,7 @@ HBITMAP InitializeImage(LPCWSTR name, LPWIN32_FIND_DATAW pFound, BOOL isFile)
|
|||
HBITMAP SetBitmapAndInfo(HBITMAP hBitmap, LPCWSTR name, LPWIN32_FIND_DATAW pFound, BOOL isFile)
|
||||
{
|
||||
// update image
|
||||
canvasWindow.resetScrollPos();
|
||||
canvasWindow.updateScrollPos();
|
||||
imageModel.PushImageForUndo(hBitmap);
|
||||
imageModel.ClearHistory();
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ void ImageModel::NotifyImageChanged()
|
|||
{
|
||||
if (canvasWindow.IsWindow())
|
||||
{
|
||||
canvasWindow.updateScrollInfo();
|
||||
canvasWindow.updateScrollRange();
|
||||
canvasWindow.Invalidate();
|
||||
}
|
||||
|
||||
|
|
|
@ -563,40 +563,67 @@ struct ColorTool : ToolBase
|
|||
// TOOL_ZOOM
|
||||
struct ZoomTool : ToolBase
|
||||
{
|
||||
BOOL m_bZoomed = FALSE;
|
||||
|
||||
ZoomTool() : ToolBase(TOOL_ZOOM)
|
||||
{
|
||||
}
|
||||
|
||||
BOOL getNewZoomRect(CRect& rcView, INT newZoom);
|
||||
|
||||
void OnDrawOverlayOnCanvas(HDC hdc) override
|
||||
{
|
||||
CRect rc;
|
||||
canvasWindow.GetImageRect(rc);
|
||||
canvasWindow.ImageToCanvas(rc);
|
||||
|
||||
POINT pt;
|
||||
::GetCursorPos(&pt);
|
||||
::ScreenToClient(canvasWindow, &pt);
|
||||
|
||||
// FIXME: Draw the border of the area that is to be zoomed in
|
||||
if (rc.PtInRect(pt))
|
||||
DrawXorRect(hdc, &rc);
|
||||
CRect rcView;
|
||||
INT oldZoom = toolsModel.GetZoom();
|
||||
if (oldZoom < MAX_ZOOM && getNewZoomRect(rcView, oldZoom * 2))
|
||||
DrawXorRect(hdc, &rcView);
|
||||
}
|
||||
|
||||
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
|
||||
{
|
||||
INT newZoom, oldZoom = toolsModel.GetZoom();
|
||||
if (bLeftButton)
|
||||
{
|
||||
if (toolsModel.GetZoom() < MAX_ZOOM)
|
||||
zoomTo(toolsModel.GetZoom() * 2, x, y);
|
||||
}
|
||||
newZoom = (oldZoom < MAX_ZOOM) ? (oldZoom * 2) : MIN_ZOOM;
|
||||
else
|
||||
newZoom = (oldZoom > MIN_ZOOM) ? (oldZoom / 2) : MAX_ZOOM;
|
||||
|
||||
m_bZoomed = FALSE;
|
||||
|
||||
if (oldZoom != newZoom)
|
||||
{
|
||||
if (toolsModel.GetZoom() > MIN_ZOOM)
|
||||
zoomTo(toolsModel.GetZoom() / 2, x, y);
|
||||
CRect rcView;
|
||||
if (getNewZoomRect(rcView, newZoom))
|
||||
{
|
||||
canvasWindow.zoomTo(newZoom, rcView.left, rcView.top);
|
||||
m_bZoomed = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL OnButtonUp(BOOL bLeftButton, LONG& x, LONG& y) override
|
||||
{
|
||||
if (m_bZoomed)
|
||||
toolsModel.SetActiveTool(toolsModel.GetOldActiveTool());
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
};
|
||||
|
||||
BOOL ZoomTool::getNewZoomRect(CRect& rcView, INT newZoom)
|
||||
{
|
||||
CPoint pt;
|
||||
::GetCursorPos(&pt);
|
||||
canvasWindow.ScreenToClient(&pt);
|
||||
|
||||
canvasWindow.getNewZoomRect(rcView, newZoom, pt);
|
||||
|
||||
CRect rc;
|
||||
canvasWindow.GetImageRect(rc);
|
||||
canvasWindow.ImageToCanvas(rc);
|
||||
|
||||
return rc.PtInRect(pt);
|
||||
}
|
||||
|
||||
// TOOL_PEN
|
||||
struct PenTool : SmoothDrawTool
|
||||
{
|
||||
|
|
|
@ -309,7 +309,7 @@ LRESULT CToolSettingsWindow::OnDestroy(UINT nMsg, WPARAM wParam, LPARAM lParam,
|
|||
LRESULT CToolSettingsWindow::OnVScroll(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
||||
{
|
||||
INT trackPos = MAX_ZOOM_TRACK - (INT)trackbarZoom.SendMessage(TBM_GETPOS, 0, 0);
|
||||
zoomTo(MIN_ZOOM << trackPos, 0, 0);
|
||||
canvasWindow.zoomTo(MIN_ZOOM << trackPos);
|
||||
|
||||
INT zoomRate = toolsModel.GetZoom();
|
||||
|
||||
|
|
|
@ -41,37 +41,6 @@ static HWND DoHtmlHelpW(HWND hwndCaller, LPCWSTR pszFile, UINT uCommand, DWORD_P
|
|||
return s_pHtmlHelpW(hwndCaller, pszFile, uCommand, dwData);
|
||||
}
|
||||
|
||||
BOOL
|
||||
zoomTo(int newZoom, int mouseX, int mouseY)
|
||||
{
|
||||
int x, y, w, h;
|
||||
RECT clientRectScrollbox;
|
||||
canvasWindow.GetClientRect(&clientRectScrollbox);
|
||||
|
||||
RECT clientRectImageArea;
|
||||
::SetRect(&clientRectImageArea, 0, 0, imageModel.GetWidth(), imageModel.GetHeight());
|
||||
Zoomed(clientRectImageArea);
|
||||
|
||||
w = clientRectImageArea.right * newZoom / toolsModel.GetZoom();
|
||||
h = clientRectImageArea.bottom * newZoom / toolsModel.GetZoom();
|
||||
if (!w || !h)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
w = clientRectImageArea.right * clientRectScrollbox.right / w;
|
||||
h = clientRectImageArea.bottom * clientRectScrollbox.bottom / h;
|
||||
x = max(0, min(clientRectImageArea.right - w, mouseX - w / 2)) * newZoom / toolsModel.GetZoom();
|
||||
y = max(0, min(clientRectImageArea.bottom - h, mouseY - h / 2)) * newZoom / toolsModel.GetZoom();
|
||||
|
||||
toolsModel.SetZoom(newZoom);
|
||||
|
||||
canvasWindow.Invalidate(TRUE);
|
||||
|
||||
canvasWindow.SendMessage(WM_HSCROLL, MAKEWPARAM(SB_THUMBPOSITION, x), 0);
|
||||
canvasWindow.SendMessage(WM_VSCROLL, MAKEWPARAM(SB_THUMBPOSITION, y), 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CMainWindow::alignChildrenToMainWindow()
|
||||
{
|
||||
RECT clientRect, rc;
|
||||
|
@ -216,20 +185,20 @@ LRESULT CMainWindow::OnMouseWheel(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL&
|
|||
{
|
||||
INT zDelta = (SHORT)HIWORD(wParam);
|
||||
|
||||
if (::GetAsyncKeyState(VK_CONTROL) < 0)
|
||||
if (::GetKeyState(VK_CONTROL) < 0) // Ctrl+Wheel
|
||||
{
|
||||
if (zDelta < 0)
|
||||
{
|
||||
if (toolsModel.GetZoom() > MIN_ZOOM)
|
||||
zoomTo(toolsModel.GetZoom() / 2, 0, 0);
|
||||
canvasWindow.zoomTo(toolsModel.GetZoom() / 2);
|
||||
}
|
||||
else if (zDelta > 0)
|
||||
{
|
||||
if (toolsModel.GetZoom() < MAX_ZOOM)
|
||||
zoomTo(toolsModel.GetZoom() * 2, 0, 0);
|
||||
canvasWindow.zoomTo(toolsModel.GetZoom() * 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
else // Wheel only
|
||||
{
|
||||
UINT nCount = 3;
|
||||
if (::GetAsyncKeyState(VK_SHIFT) < 0)
|
||||
|
@ -921,7 +890,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
|
|||
case IDM_IMAGEROTATEMIRROR:
|
||||
{
|
||||
CWaitCursor waitCursor;
|
||||
canvasWindow.resetScrollPos();
|
||||
canvasWindow.updateScrollPos();
|
||||
switch (mirrorRotateDialog.DoModal(mainWindow.m_hWnd))
|
||||
{
|
||||
case 1: /* flip horizontally */
|
||||
|
@ -1054,25 +1023,25 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
|
|||
break;
|
||||
|
||||
case IDM_VIEWZOOM125:
|
||||
zoomTo(125, 0, 0);
|
||||
canvasWindow.zoomTo(125);
|
||||
break;
|
||||
case IDM_VIEWZOOM25:
|
||||
zoomTo(250, 0, 0);
|
||||
canvasWindow.zoomTo(250);
|
||||
break;
|
||||
case IDM_VIEWZOOM50:
|
||||
zoomTo(500, 0, 0);
|
||||
canvasWindow.zoomTo(500);
|
||||
break;
|
||||
case IDM_VIEWZOOM100:
|
||||
zoomTo(1000, 0, 0);
|
||||
canvasWindow.zoomTo(1000);
|
||||
break;
|
||||
case IDM_VIEWZOOM200:
|
||||
zoomTo(2000, 0, 0);
|
||||
canvasWindow.zoomTo(2000);
|
||||
break;
|
||||
case IDM_VIEWZOOM400:
|
||||
zoomTo(4000, 0, 0);
|
||||
canvasWindow.zoomTo(4000);
|
||||
break;
|
||||
case IDM_VIEWZOOM800:
|
||||
zoomTo(8000, 0, 0);
|
||||
canvasWindow.zoomTo(8000);
|
||||
break;
|
||||
|
||||
case IDM_VIEWFULLSCREEN:
|
||||
|
|
Loading…
Reference in a new issue