reactos/base/applications/mspaint/imgarea.cpp
Katayama Hirofumi MZ 0839711566
[MSPAINT] Improve Undo/Redo and finishing tool (#4324)
- Fix Undo/Redo mechanism.
- Finish drawing when the tool is to be chanaged and when the file is to be saved.
- Add ToolBase::OnFinishDraw to virtualize finishing drawing.
- Extend bClearRedo parameter to ImageModel::Undo.
- Add ImageModel::DrawSelectionBackground and ImageModel::DeleteSelection methods.
- Fix some WM_PAINT message handling.
CORE-17969
2022-01-30 12:05:23 +09:00

421 lines
13 KiB
C++

/*
* PROJECT: PAINT for ReactOS
* LICENSE: LGPL
* FILE: base/applications/mspaint/imgarea.cpp
* PURPOSE: Window procedure of the main window and all children apart from
* hPalWin, hToolSettings and hSelection
* PROGRAMMERS: Benedikt Freisen
* Katayama Hirofumi MZ
*/
/* INCLUDES *********************************************************/
#include "precomp.h"
/* FUNCTIONS ********************************************************/
void
updateCanvasAndScrollbars()
{
selectionWindow.ShowWindow(SW_HIDE);
int zoomedWidth = Zoomed(imageModel.GetWidth());
int zoomedHeight = Zoomed(imageModel.GetHeight());
imageArea.MoveWindow(GRIP_SIZE, GRIP_SIZE, zoomedWidth, zoomedHeight, FALSE);
scrollboxWindow.Invalidate(TRUE);
imageArea.Invalidate(FALSE);
scrollboxWindow.SetScrollPos(SB_HORZ, 0, TRUE);
scrollboxWindow.SetScrollPos(SB_VERT, 0, TRUE);
}
void CImgAreaWindow::drawZoomFrame(int mouseX, int mouseY)
{
HDC hdc;
HPEN oldPen;
HBRUSH oldBrush;
LOGBRUSH logbrush;
int rop;
RECT clientRectScrollbox;
RECT clientRectImageArea;
int x, y, w, h;
scrollboxWindow.GetClientRect(&clientRectScrollbox);
GetClientRect(&clientRectImageArea);
w = clientRectImageArea.right * 2;
h = clientRectImageArea.bottom * 2;
if (!w || !h)
{
return;
}
w = clientRectImageArea.right * clientRectScrollbox.right / w;
h = clientRectImageArea.bottom * clientRectScrollbox.bottom / h;
x = max(0, min(clientRectImageArea.right - w, mouseX - w / 2));
y = max(0, min(clientRectImageArea.bottom - h, mouseY - h / 2));
hdc = GetDC();
oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, 0, 0));
logbrush.lbStyle = BS_HOLLOW;
oldBrush = (HBRUSH) SelectObject(hdc, CreateBrushIndirect(&logbrush));
rop = SetROP2(hdc, R2_NOT);
Rectangle(hdc, x, y, x + w, y + h);
SetROP2(hdc, rop);
DeleteObject(SelectObject(hdc, oldBrush));
DeleteObject(SelectObject(hdc, oldPen));
ReleaseDC(hdc);
}
LRESULT CImgAreaWindow::OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (!IsWindow() || !sizeboxLeftTop.IsWindow())
return 0;
int imgXRes = imageModel.GetWidth();
int imgYRes = imageModel.GetHeight();
sizeboxLeftTop.MoveWindow(
0,
0, GRIP_SIZE, GRIP_SIZE, TRUE);
sizeboxCenterTop.MoveWindow(
GRIP_SIZE + (Zoomed(imgXRes) - GRIP_SIZE) / 2,
0, GRIP_SIZE, GRIP_SIZE, TRUE);
sizeboxRightTop.MoveWindow(
GRIP_SIZE + Zoomed(imgXRes),
0, GRIP_SIZE, GRIP_SIZE, TRUE);
sizeboxLeftCenter.MoveWindow(
0,
GRIP_SIZE + (Zoomed(imgYRes) - GRIP_SIZE) / 2,
GRIP_SIZE, GRIP_SIZE, TRUE);
sizeboxRightCenter.MoveWindow(
GRIP_SIZE + Zoomed(imgXRes),
GRIP_SIZE + (Zoomed(imgYRes) - GRIP_SIZE) / 2,
GRIP_SIZE, GRIP_SIZE, TRUE);
sizeboxLeftBottom.MoveWindow(
0,
GRIP_SIZE + Zoomed(imgYRes), GRIP_SIZE, GRIP_SIZE, TRUE);
sizeboxCenterBottom.MoveWindow(
GRIP_SIZE + (Zoomed(imgXRes) - GRIP_SIZE) / 2,
GRIP_SIZE + Zoomed(imgYRes), GRIP_SIZE, GRIP_SIZE, TRUE);
sizeboxRightBottom.MoveWindow(
GRIP_SIZE + Zoomed(imgXRes),
GRIP_SIZE + Zoomed(imgYRes), GRIP_SIZE, GRIP_SIZE, TRUE);
UpdateScrollbox();
return 0;
}
LRESULT CImgAreaWindow::OnEraseBkGnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
HDC hdc = (HDC)wParam;
if (toolsModel.GetActiveTool() == TOOL_TEXT && !toolsModel.IsBackgroundTransparent() &&
::IsWindowVisible(textEditWindow))
{
// Do clipping
HWND hChild = textEditWindow;
RECT rcChild;
::GetWindowRect(hChild, &rcChild);
::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rcChild, 2);
ExcludeClipRect(hdc, rcChild.left, rcChild.top, rcChild.right, rcChild.bottom);
}
return DefWindowProc(nMsg, wParam, lParam);
}
LRESULT CImgAreaWindow::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(&ps);
int imgXRes = imageModel.GetWidth();
int imgYRes = imageModel.GetHeight();
StretchBlt(hdc, 0, 0, Zoomed(imgXRes), Zoomed(imgYRes), imageModel.GetDC(), 0, 0, imgXRes,
imgYRes, SRCCOPY);
if (showGrid && (toolsModel.GetZoom() >= 4000))
{
HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, 1, 0x00a0a0a0));
int counter;
for(counter = 0; counter <= imgYRes; counter++)
{
MoveToEx(hdc, 0, Zoomed(counter), NULL);
LineTo(hdc, Zoomed(imgXRes), Zoomed(counter));
}
for(counter = 0; counter <= imgXRes; counter++)
{
MoveToEx(hdc, Zoomed(counter), 0, NULL);
LineTo(hdc, Zoomed(counter), Zoomed(imgYRes));
}
DeleteObject(SelectObject(hdc, oldPen));
}
EndPaint(&ps);
if (selectionWindow.IsWindow())
selectionWindow.Invalidate(FALSE);
if (miniature.IsWindow())
miniature.Invalidate(FALSE);
if (textEditWindow.IsWindow())
textEditWindow.Invalidate(FALSE);
return 0;
}
LRESULT CImgAreaWindow::OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
switch (toolsModel.GetActiveTool())
{
case TOOL_FILL:
SetCursor(hCurFill);
break;
case TOOL_COLOR:
SetCursor(hCurColor);
break;
case TOOL_ZOOM:
SetCursor(hCurZoom);
break;
case TOOL_PEN:
SetCursor(hCurPen);
break;
case TOOL_AIRBRUSH:
SetCursor(hCurAirbrush);
break;
default:
SetCursor(LoadCursor(NULL, IDC_CROSS));
}
return 0;
}
LRESULT CImgAreaWindow::OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
drawing = TRUE;
SetCapture();
INT x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
toolsModel.OnButtonDown(TRUE, UnZoomed(x), UnZoomed(y), FALSE);
Invalidate(FALSE);
return 0;
}
LRESULT CImgAreaWindow::OnLButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
drawing = FALSE;
ReleaseCapture();
INT x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
toolsModel.OnButtonDown(TRUE, UnZoomed(x), UnZoomed(y), TRUE);
toolsModel.resetTool();
Invalidate(FALSE);
return 0;
}
LRESULT CImgAreaWindow::OnRButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
drawing = TRUE;
SetCapture();
INT x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
toolsModel.OnButtonDown(FALSE, UnZoomed(x), UnZoomed(y), FALSE);
Invalidate(FALSE);
return 0;
}
LRESULT CImgAreaWindow::OnRButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
drawing = FALSE;
ReleaseCapture();
INT x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
toolsModel.OnButtonDown(FALSE, UnZoomed(x), UnZoomed(y), TRUE);
toolsModel.resetTool();
Invalidate(FALSE);
return 0;
}
LRESULT CImgAreaWindow::OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (drawing)
{
drawing = FALSE;
INT x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
toolsModel.OnButtonUp(TRUE, UnZoomed(x), UnZoomed(y));
Invalidate(FALSE);
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) "");
}
ReleaseCapture();
return 0;
}
void CImgAreaWindow::cancelDrawing()
{
drawing = FALSE;
toolsModel.OnCancelDraw();
Invalidate(FALSE);
}
LRESULT CImgAreaWindow::OnCaptureChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (drawing)
cancelDrawing();
return 0;
}
LRESULT CImgAreaWindow::OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (wParam == VK_ESCAPE)
{
if (GetCapture() == m_hWnd)
{
ReleaseCapture();
}
else
{
if (drawing || ToolBase::pointSP != 0 || selectionWindow.IsWindowVisible())
cancelDrawing();
}
}
return 0;
}
LRESULT CImgAreaWindow::OnRButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (drawing)
{
drawing = FALSE;
INT x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
toolsModel.OnButtonUp(FALSE, UnZoomed(x), UnZoomed(y));
Invalidate(FALSE);
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) "");
}
ReleaseCapture();
return 0;
}
LRESULT CImgAreaWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
LONG xNow = UnZoomed(GET_X_LPARAM(lParam));
LONG yNow = UnZoomed(GET_Y_LPARAM(lParam));
if ((!drawing) || (toolsModel.GetActiveTool() <= TOOL_AIRBRUSH))
{
TRACKMOUSEEVENT tme;
if (toolsModel.GetActiveTool() == TOOL_ZOOM)
{
Invalidate(FALSE);
UpdateWindow();
drawZoomFrame(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
}
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = m_hWnd;
tme.dwHoverTime = 0;
TrackMouseEvent(&tme);
if (!drawing)
{
CString strCoord;
strCoord.Format(_T("%ld, %ld"), xNow, yNow);
SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) strCoord);
}
}
if (drawing)
{
/* values displayed in statusbar */
LONG xRel = xNow - start.x;
LONG yRel = yNow - start.y;
/* freesel, rectsel and text tools always show numbers limited to fit into image area */
if ((toolsModel.GetActiveTool() == TOOL_FREESEL) || (toolsModel.GetActiveTool() == TOOL_RECTSEL) || (toolsModel.GetActiveTool() == TOOL_TEXT))
{
if (xRel < 0)
xRel = (xNow < 0) ? -start.x : xRel;
else if (xNow > imageModel.GetWidth())
xRel = imageModel.GetWidth() - start.x;
if (yRel < 0)
yRel = (yNow < 0) ? -start.y : yRel;
else if (yNow > imageModel.GetHeight())
yRel = imageModel.GetHeight() - start.y;
}
/* rectsel and shape tools always show non-negative numbers when drawing */
if ((toolsModel.GetActiveTool() == TOOL_RECTSEL) || (toolsModel.GetActiveTool() == TOOL_SHAPE))
{
if (xRel < 0)
xRel = -xRel;
if (yRel < 0)
yRel = -yRel;
}
/* while drawing, update cursor coordinates only for tools 3, 7, 8, 9, 14 */
switch(toolsModel.GetActiveTool())
{
case TOOL_RUBBER:
case TOOL_PEN:
case TOOL_BRUSH:
case TOOL_AIRBRUSH:
case TOOL_SHAPE:
{
CString strCoord;
strCoord.Format(_T("%ld, %ld"), xNow, yNow);
SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) strCoord);
break;
}
default:
break;
}
if (wParam & MK_LBUTTON)
{
toolsModel.OnMouseMove(TRUE, xNow, yNow);
Invalidate(FALSE);
if ((toolsModel.GetActiveTool() >= TOOL_TEXT) || (toolsModel.GetActiveTool() == TOOL_RECTSEL) || (toolsModel.GetActiveTool() == TOOL_FREESEL))
{
CString strSize;
if ((toolsModel.GetActiveTool() >= TOOL_LINE) && (GetAsyncKeyState(VK_SHIFT) < 0))
yRel = xRel;
strSize.Format(_T("%ld x %ld"), xRel, yRel);
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize);
}
}
if (wParam & MK_RBUTTON)
{
toolsModel.OnMouseMove(FALSE, xNow, yNow);
Invalidate(FALSE);
if (toolsModel.GetActiveTool() >= TOOL_TEXT)
{
CString strSize;
if ((toolsModel.GetActiveTool() >= TOOL_LINE) && (GetAsyncKeyState(VK_SHIFT) < 0))
yRel = xRel;
strSize.Format(_T("%ld x %ld"), xRel, yRel);
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize);
}
}
}
return 0;
}
LRESULT CImgAreaWindow::OnMouseLeave(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) _T(""));
if (toolsModel.GetActiveTool() == TOOL_ZOOM)
Invalidate(FALSE);
return 0;
}
LRESULT CImgAreaWindow::OnImageModelDimensionsChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
updateCanvasAndScrollbars();
return 0;
}
LRESULT CImgAreaWindow::OnImageModelImageChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
Invalidate(FALSE);
return 0;
}
LRESULT CImgAreaWindow::OnMouseWheel(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
return ::SendMessage(GetParent(), nMsg, wParam, lParam);
}
LRESULT CImgAreaWindow::OnCtlColorEdit(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
HDC hdc = (HDC)wParam;
SetBkMode(hdc, TRANSPARENT);
return (LRESULT)GetStockObject(NULL_BRUSH);
}
void CImgAreaWindow::finishDrawing()
{
toolsModel.OnFinishDraw();
drawing = FALSE;
Invalidate(FALSE);
}