diff --git a/base/applications/mspaint/canvas.cpp b/base/applications/mspaint/canvas.cpp index 60aa29929b5..e19c4e6e306 100644 --- a/base/applications/mspaint/canvas.cpp +++ b/base/applications/mspaint/canvas.cpp @@ -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; } diff --git a/base/applications/mspaint/canvas.h b/base/applications/mspaint/canvas.h index 193d7603abd..21a6e11ecfa 100644 --- a/base/applications/mspaint/canvas.h +++ b/base/applications/mspaint/canvas.h @@ -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; diff --git a/base/applications/mspaint/common.h b/base/applications/mspaint/common.h index d2e862b0114..3dda6703441 100644 --- a/base/applications/mspaint/common.h +++ b/base/applications/mspaint/common.h @@ -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); diff --git a/base/applications/mspaint/dib.cpp b/base/applications/mspaint/dib.cpp index 7b458138618..eede3325c55 100644 --- a/base/applications/mspaint/dib.cpp +++ b/base/applications/mspaint/dib.cpp @@ -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(); diff --git a/base/applications/mspaint/history.cpp b/base/applications/mspaint/history.cpp index 05990df42b8..2d28cb5def2 100644 --- a/base/applications/mspaint/history.cpp +++ b/base/applications/mspaint/history.cpp @@ -16,7 +16,7 @@ void ImageModel::NotifyImageChanged() { if (canvasWindow.IsWindow()) { - canvasWindow.updateScrollInfo(); + canvasWindow.updateScrollRange(); canvasWindow.Invalidate(); } diff --git a/base/applications/mspaint/mouse.cpp b/base/applications/mspaint/mouse.cpp index dc9ce6b89a2..c7c19e16544 100644 --- a/base/applications/mspaint/mouse.cpp +++ b/base/applications/mspaint/mouse.cpp @@ -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 { diff --git a/base/applications/mspaint/toolsettings.cpp b/base/applications/mspaint/toolsettings.cpp index 182862ec305..745f2afe3e0 100644 --- a/base/applications/mspaint/toolsettings.cpp +++ b/base/applications/mspaint/toolsettings.cpp @@ -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(); diff --git a/base/applications/mspaint/winproc.cpp b/base/applications/mspaint/winproc.cpp index 58bf4a98909..c1cbff31b8c 100644 --- a/base/applications/mspaint/winproc.cpp +++ b/base/applications/mspaint/winproc.cpp @@ -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: