[MSPAINT] Make selection window-less (#5208)

- Delete selection.cpp and selection.h and selectionWindow.
- Extend ColorKeyedMaskBlt function.
- Implement selection resizing.
CORE-18867
This commit is contained in:
Katayama Hirofumi MZ 2023-04-01 22:01:04 +09:00 committed by GitHub
parent 3f5bcf5775
commit aac89519ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 702 additions and 829 deletions

View file

@ -20,7 +20,6 @@ list(APPEND SOURCE
palette.cpp
palettemodel.cpp
registry.cpp
selection.cpp
selectionmodel.cpp
sizebox.cpp
textedit.cpp

View file

@ -150,14 +150,25 @@ LRESULT CCanvasWindow::OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BO
if (hit == HIT_NONE || hit == HIT_BORDER)
{
if (toolsModel.GetActiveTool() == TOOL_BEZIER ||
toolsModel.GetActiveTool() == TOOL_SHAPE)
switch (toolsModel.GetActiveTool())
{
if (ToolBase::pointSP != 0)
{
toolsModel.OnCancelDraw();
case TOOL_BEZIER:
case TOOL_SHAPE:
if (ToolBase::pointSP != 0)
{
toolsModel.OnCancelDraw();
imageArea.Invalidate();
}
break;
case TOOL_FREESEL:
case TOOL_RECTSEL:
toolsModel.OnFinishDraw();
imageArea.Invalidate();
}
break;
default:
break;
}
toolsModel.resetTool(); // resets the point-buffer of the polygon and bezier functions

View file

@ -56,6 +56,5 @@ enum CANVAS_HITTEST // hit
BOOL zoomTo(int newZoom, int mouseX, int mouseY);
BOOL nearlyEqualPoints(INT x0, INT y0, INT x1, INT y1);
void placeSelWin(void);
void updateStartAndLast(LONG x, LONG y);
void updateLast(LONG x, LONG y);

View file

@ -220,9 +220,13 @@ HBITMAP DoLoadImageFile(HWND hwnd, LPCTSTR name, BOOL fIsMainFile)
return hBitmap;
}
HBITMAP Rotate90DegreeBlt(HDC hDC1, INT cx, INT cy, BOOL bRight)
HBITMAP Rotate90DegreeBlt(HDC hDC1, INT cx, INT cy, BOOL bRight, BOOL bMono)
{
HBITMAP hbm2 = CreateDIBWithProperties(cy, cx);
HBITMAP hbm2;
if (bMono)
hbm2 = ::CreateBitmap(cy, cx, 1, 1, NULL);
else
hbm2 = CreateDIBWithProperties(cy, cx);
if (!hbm2)
return NULL;

View file

@ -28,7 +28,7 @@ void ShowFileLoadError(LPCTSTR name);
HBITMAP SetBitmapAndInfo(HBITMAP hBitmap, LPCTSTR name, DWORD dwFileSize, BOOL isFile);
HBITMAP Rotate90DegreeBlt(HDC hDC1, INT cx, INT cy, BOOL bRight);
HBITMAP Rotate90DegreeBlt(HDC hDC1, INT cx, INT cy, BOOL bRight, BOOL bMono);
HBITMAP SkewDIB(HDC hDC1, HBITMAP hbm, INT nDegree, BOOL bVertical);

View file

@ -290,33 +290,76 @@ Text(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF fg, COLORREF bg, LPCT
BOOL
ColorKeyedMaskBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight,
HDC hdcSrc, int nXSrc, int nYSrc, HBITMAP hbmMask, int xMask, int yMask,
DWORD dwRop, COLORREF keyColor)
HDC hdcSrc, int nXSrc, int nYSrc, int nSrcWidth, int nSrcHeight,
HBITMAP hbmMask, COLORREF keyColor)
{
HDC hTempDC;
HDC hTempDC2;
HBITMAP hTempBm;
HBRUSH hTempBrush;
HBITMAP hTempMask;
HDC hTempDC1, hTempDC2;
HBITMAP hbmTempColor, hbmTempMask;
HGDIOBJ hbmOld1, hbmOld2;
if (hbmMask == NULL)
{
if (keyColor == CLR_INVALID)
{
::StretchBlt(hdcDest, nXDest, nYDest, nWidth, nHeight,
hdcSrc, nXSrc, nYSrc, nSrcWidth, nSrcHeight, SRCCOPY);
}
else
{
::GdiTransparentBlt(hdcDest, nXDest, nYDest, nWidth, nHeight,
hdcSrc, nXSrc, nYSrc, nSrcWidth, nSrcHeight, keyColor);
}
return TRUE;
}
else if (nWidth == nSrcWidth && nHeight == nSrcHeight && keyColor == CLR_INVALID)
{
::MaskBlt(hdcDest, nXDest, nYDest, nWidth, nHeight,
hdcSrc, nXSrc, nYSrc, hbmMask, 0, 0, MAKEROP4(SRCCOPY, 0xAA0029));
return TRUE;
}
hTempDC1 = ::CreateCompatibleDC(hdcDest);
hTempDC2 = ::CreateCompatibleDC(hdcDest);
hbmTempMask = ::CreateBitmap(nWidth, nHeight, 1, 1, NULL);
hbmTempColor = CreateColorDIB(nWidth, nHeight, RGB(255, 255, 255));
// hbmTempMask <-- hbmMask (stretched)
hbmOld1 = ::SelectObject(hTempDC1, hbmMask);
hbmOld2 = ::SelectObject(hTempDC2, hbmTempMask);
::StretchBlt(hTempDC2, 0, 0, nWidth, nHeight, hTempDC1, 0, 0, nSrcWidth, nSrcHeight, SRCCOPY);
::SelectObject(hTempDC2, hbmOld2);
::SelectObject(hTempDC1, hbmOld1);
hbmOld1 = ::SelectObject(hTempDC1, hbmTempColor);
if (keyColor == CLR_INVALID)
{
// hbmTempColor <-- hdcSrc (stretched)
::StretchBlt(hTempDC1, 0, 0, nWidth, nHeight,
hdcSrc, nXSrc, nYSrc, nSrcWidth, nSrcHeight, SRCCOPY);
// hdcDest <-- hbmTempColor (masked)
::MaskBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hTempDC1, 0, 0,
hbmTempMask, 0, 0, MAKEROP4(SRCCOPY, 0xAA0029));
}
else
{
// hbmTempColor <-- hdcDest
::BitBlt(hTempDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
// hbmTempColor <-- hdcSrc (color key)
::GdiTransparentBlt(hTempDC1, 0, 0, nWidth, nHeight,
hdcSrc, nXSrc, nYSrc, nSrcWidth, nSrcHeight, keyColor);
// hdcDest <-- hbmTempColor (masked)
::MaskBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hTempDC1, 0, 0,
hbmTempMask, 0, 0, MAKEROP4(SRCCOPY, 0xAA0029));
}
::SelectObject(hTempDC1, hbmOld1);
::DeleteObject(hbmTempColor);
::DeleteObject(hbmTempMask);
::DeleteDC(hTempDC2);
::DeleteDC(hTempDC1);
hTempDC = CreateCompatibleDC(hdcSrc);
hTempDC2 = CreateCompatibleDC(hdcSrc);
hTempBm = CreateCompatibleBitmap(hTempDC, nWidth, nHeight);
SelectObject(hTempDC, hTempBm);
hTempBrush = CreateSolidBrush(keyColor);
SelectObject(hTempDC, hTempBrush);
BitBlt(hTempDC, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY);
PatBlt(hTempDC, 0, 0, nWidth, nHeight, PATINVERT);
hTempMask = CreateBitmap(nWidth, nHeight, 1, 1, NULL);
SelectObject(hTempDC2, hTempMask);
BitBlt(hTempDC2, 0, 0, nWidth, nHeight, hTempDC, 0, 0, SRCCOPY);
SelectObject(hTempDC, hbmMask);
BitBlt(hTempDC2, 0, 0, nWidth, nHeight, hTempDC, xMask, yMask, SRCAND);
MaskBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, hTempMask, xMask, yMask, dwRop);
DeleteDC(hTempDC);
DeleteDC(hTempDC2);
DeleteObject(hTempBm);
DeleteObject(hTempBrush);
DeleteObject(hTempMask);
return TRUE;
}

View file

@ -34,7 +34,7 @@ void RectSel(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2);
void Text(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF fg, COLORREF bg, LPCTSTR lpchText, HFONT font, LONG style);
extern BOOL
BOOL
ColorKeyedMaskBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight,
HDC hdcSrc, int nXSrc, int nYSrc, HBITMAP hbmMask, int xMask, int yMask,
DWORD dwRop, COLORREF keyColor);
HDC hdcSrc, int nXSrc, int nYSrc, int nSrcWidth, int nSrcHeight,
HBITMAP hbmMask, COLORREF keyColor);

View file

@ -52,6 +52,5 @@ extern CToolBox toolBoxContainer;
extern CToolSettingsWindow toolSettingsWindow;
extern CPaletteWindow paletteWindow;
extern CCanvasWindow canvasWindow;
extern CSelectionWindow selectionWindow;
extern CImgAreaWindow imageArea;
extern CTextEditWindow textEditWindow;

View file

@ -64,7 +64,7 @@ void ImageModel::Undo(BOOL bClearRedo)
{
int oldWidth = GetWidth();
int oldHeight = GetHeight();
selectionWindow.ShowWindow(SW_HIDE);
selectionModel.m_bShow = FALSE;
currInd = (currInd + HISTORYSIZE - 1) % HISTORYSIZE;
SelectObject(hDrawingDC, hBms[currInd]);
undoSteps--;
@ -85,7 +85,7 @@ void ImageModel::Redo()
{
int oldWidth = GetWidth();
int oldHeight = GetHeight();
selectionWindow.ShowWindow(SW_HIDE);
selectionModel.m_bShow = FALSE;
currInd = (currInd + 1) % HISTORYSIZE;
SelectObject(hDrawingDC, hBms[currInd]);
redoSteps--;
@ -264,7 +264,7 @@ void ImageModel::RotateNTimes90Degrees(int iN)
case 1:
case 3:
DeleteObject(hBms[(currInd + 1) % HISTORYSIZE]);
hBms[(currInd + 1) % HISTORYSIZE] = Rotate90DegreeBlt(hDrawingDC, GetWidth(), GetHeight(), iN == 1);
hBms[(currInd + 1) % HISTORYSIZE] = Rotate90DegreeBlt(hDrawingDC, GetWidth(), GetHeight(), iN == 1, FALSE);
currInd = (currInd + 1) % HISTORYSIZE;
if (undoSteps < HISTORYSIZE - 1)
undoSteps++;
@ -282,23 +282,15 @@ void ImageModel::RotateNTimes90Degrees(int iN)
NotifyImageChanged();
}
void ImageModel::DrawSelectionBackground(COLORREF rgbBG)
{
if (toolsModel.GetActiveTool() == TOOL_FREESEL)
selectionModel.DrawBackgroundPoly(hDrawingDC, rgbBG);
else
selectionModel.DrawBackgroundRect(hDrawingDC, rgbBG);
}
void ImageModel::DeleteSelection()
{
if (selectionWindow.IsWindowVisible())
ResetToPrevious();
CopyPrevious();
if (selectionWindow.IsWindowVisible())
Undo(TRUE);
DrawSelectionBackground(paletteModel.GetBgColor());
selectionWindow.ShowWindow(SW_HIDE);
if (!selectionModel.m_bShow)
return;
selectionModel.TakeOff();
selectionModel.m_bShow = FALSE;
selectionModel.ClearColor();
selectionModel.ClearMask();
NotifyImageChanged();
}

View file

@ -45,7 +45,6 @@ public:
void FlipHorizontally();
void FlipVertically();
void RotateNTimes90Degrees(int iN);
void DrawSelectionBackground(COLORREF rgbBG);
void DeleteSelection();
void Bound(POINT& pt);
};

View file

@ -21,7 +21,6 @@ LRESULT CImgAreaWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL&
m_hCurZoom = LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_ZOOM));
m_hCurPen = LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_PEN));
m_hCurAirbrush = LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_AIRBRUSH));
return 0;
}
@ -71,49 +70,61 @@ LRESULT CImgAreaWindow::OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
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);
return TRUE; // Don't fill background
}
LRESULT CImgAreaWindow::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
RECT rcClient;
GetClientRect(&rcClient);
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);
// We use a memory bitmap to reduce flickering
HDC hdcMem = ::CreateCompatibleDC(hdc);
HBITMAP hbm = ::CreateCompatibleBitmap(hdc, rcClient.right, rcClient.bottom);
HGDIOBJ hbmOld = ::SelectObject(hdcMem, hbm);
// Draw the image
SIZE size = { imageModel.GetWidth(), imageModel.GetHeight() };
StretchBlt(hdcMem, 0, 0, ::Zoomed(size.cx), ::Zoomed(size.cy),
imageModel.GetDC(), 0, 0, size.cx, size.cy, SRCCOPY);
// Draw the grid
if (showGrid && (toolsModel.GetZoom() >= 4000))
{
HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, 1, 0x00a0a0a0));
int counter;
for(counter = 0; counter <= imgYRes; counter++)
HPEN oldPen = (HPEN) SelectObject(hdcMem, CreatePen(PS_SOLID, 1, 0x00a0a0a0));
for (int counter = 0; counter <= size.cy; counter++)
{
MoveToEx(hdc, 0, Zoomed(counter), NULL);
LineTo(hdc, Zoomed(imgXRes), Zoomed(counter));
::MoveToEx(hdcMem, 0, ::Zoomed(counter), NULL);
::LineTo(hdcMem, ::Zoomed(size.cx), ::Zoomed(counter));
}
for(counter = 0; counter <= imgXRes; counter++)
for (int counter = 0; counter <= size.cx; counter++)
{
MoveToEx(hdc, Zoomed(counter), 0, NULL);
LineTo(hdc, Zoomed(counter), Zoomed(imgYRes));
::MoveToEx(hdcMem, ::Zoomed(counter), 0, NULL);
::LineTo(hdcMem, ::Zoomed(counter), ::Zoomed(size.cy));
}
DeleteObject(SelectObject(hdc, oldPen));
::DeleteObject(::SelectObject(hdcMem, oldPen));
}
// Draw selection
if (selectionModel.m_bShow)
{
RECT rc = selectionModel.m_rc;
Zoomed(rc);
::InflateRect(&rc, GRIP_SIZE, GRIP_SIZE);
drawSizeBoxes(hdcMem, &rc, TRUE, &ps.rcPaint);
::InflateRect(&rc, -GRIP_SIZE, -GRIP_SIZE);
selectionModel.DrawSelection(hdcMem, &rc, paletteModel.GetBgColor(),
toolsModel.IsBackgroundTransparent());
}
// Transfer bits
::BitBlt(hdc, 0, 0, rcClient.right, rcClient.bottom, hdcMem, 0, 0, SRCCOPY);
::SelectObject(hdcMem, hbmOld);
EndPaint(&ps);
if (selectionWindow.IsWindow())
selectionWindow.Invalidate(FALSE);
if (miniature.IsWindow())
miniature.Invalidate(FALSE);
if (textEditWindow.IsWindow())
@ -121,8 +132,57 @@ LRESULT CImgAreaWindow::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& b
return 0;
}
CANVAS_HITTEST CImgAreaWindow::SelectionHitTest(POINT ptZoomed)
{
if (!selectionModel.m_bShow)
return HIT_NONE;
RECT rcSelection = selectionModel.m_rc;
Zoomed(rcSelection);
::InflateRect(&rcSelection, GRIP_SIZE, GRIP_SIZE);
return getSizeBoxHitTest(ptZoomed, &rcSelection);
}
void CImgAreaWindow::StartSelectionDrag(CANVAS_HITTEST hit, POINT ptUnZoomed)
{
m_hitSelection = hit;
selectionModel.m_ptHit = ptUnZoomed;
selectionModel.TakeOff();
SetCapture();
Invalidate(FALSE);
}
void CImgAreaWindow::SelectionDragging(POINT ptUnZoomed)
{
selectionModel.Dragging(m_hitSelection, ptUnZoomed);
Invalidate(FALSE);
}
void CImgAreaWindow::EndSelectionDrag(POINT ptUnZoomed)
{
selectionModel.Dragging(m_hitSelection, ptUnZoomed);
m_hitSelection = HIT_NONE;
Invalidate(FALSE);
}
LRESULT CImgAreaWindow::OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
POINT pt;
::GetCursorPos(&pt);
ScreenToClient(&pt);
CANVAS_HITTEST hit = SelectionHitTest(pt);
if (hit != HIT_NONE)
{
if (!setCursorOnSizeBox(hit))
::SetCursor(::LoadCursor(NULL, IDC_SIZEALL));
return 0;
}
UnZoomed(pt);
switch (toolsModel.GetActiveTool())
{
case TOOL_FILL:
@ -148,20 +208,31 @@ LRESULT CImgAreaWindow::OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, BOO
LRESULT CImgAreaWindow::OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
CANVAS_HITTEST hit = SelectionHitTest(pt);
if (hit != HIT_NONE)
{
UnZoomed(pt);
StartSelectionDrag(hit, pt);
return 0;
}
UnZoomed(pt);
drawing = TRUE;
SetCapture();
INT x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
toolsModel.OnButtonDown(TRUE, UnZoomed(x), UnZoomed(y), FALSE);
toolsModel.OnButtonDown(TRUE, pt.x, pt.y, FALSE);
Invalidate(FALSE);
return 0;
}
LRESULT CImgAreaWindow::OnLButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
UnZoomed(pt);
drawing = FALSE;
ReleaseCapture();
INT x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
toolsModel.OnButtonDown(TRUE, UnZoomed(x), UnZoomed(y), TRUE);
toolsModel.OnButtonDown(TRUE, pt.x, pt.y, TRUE);
toolsModel.resetTool();
Invalidate(FALSE);
return 0;
@ -169,20 +240,22 @@ LRESULT CImgAreaWindow::OnLButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam,
LRESULT CImgAreaWindow::OnRButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
UnZoomed(pt);
drawing = TRUE;
SetCapture();
INT x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
toolsModel.OnButtonDown(FALSE, UnZoomed(x), UnZoomed(y), FALSE);
toolsModel.OnButtonDown(FALSE, pt.x, pt.y, FALSE);
Invalidate(FALSE);
return 0;
}
LRESULT CImgAreaWindow::OnRButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
UnZoomed(pt);
drawing = FALSE;
ReleaseCapture();
INT x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
toolsModel.OnButtonDown(FALSE, UnZoomed(x), UnZoomed(y), TRUE);
toolsModel.OnButtonDown(FALSE, pt.x, pt.y, TRUE);
toolsModel.resetTool();
Invalidate(FALSE);
return 0;
@ -190,20 +263,28 @@ LRESULT CImgAreaWindow::OnRButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam,
LRESULT CImgAreaWindow::OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
UnZoomed(pt);
if (drawing)
{
drawing = FALSE;
INT x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
toolsModel.OnButtonUp(TRUE, UnZoomed(x), UnZoomed(y));
toolsModel.OnButtonUp(TRUE, pt.x, pt.y);
Invalidate(FALSE);
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) "");
}
else if (m_hitSelection != HIT_NONE)
{
EndSelectionDrag(pt);
}
ReleaseCapture();
return 0;
}
void CImgAreaWindow::cancelDrawing()
{
selectionModel.ClearColor();
selectionModel.ClearMask();
m_hitSelection = HIT_NONE;
drawing = FALSE;
toolsModel.OnCancelDraw();
Invalidate(FALSE);
@ -226,7 +307,7 @@ LRESULT CImgAreaWindow::OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL&
}
else
{
if (drawing || ToolBase::pointSP != 0 || selectionWindow.IsWindowVisible())
if (drawing || ToolBase::pointSP != 0 || selectionModel.m_bShow)
cancelDrawing();
}
}
@ -235,22 +316,34 @@ LRESULT CImgAreaWindow::OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL&
LRESULT CImgAreaWindow::OnRButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
UnZoomed(pt);
if (drawing)
{
drawing = FALSE;
INT x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
toolsModel.OnButtonUp(FALSE, UnZoomed(x), UnZoomed(y));
toolsModel.OnButtonUp(FALSE, pt.x, pt.y);
Invalidate(FALSE);
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) "");
}
else if (m_hitSelection != HIT_NONE)
{
EndSelectionDrag(pt);
}
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));
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
UnZoomed(pt);
if (m_hitSelection != HIT_NONE)
{
SelectionDragging(pt);
return 0;
}
if ((!drawing) || (toolsModel.GetActiveTool() <= TOOL_AIRBRUSH))
{
TRACKMOUSEEVENT tme;
@ -271,26 +364,26 @@ LRESULT CImgAreaWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOO
if (!drawing)
{
CString strCoord;
strCoord.Format(_T("%ld, %ld"), xNow, yNow);
strCoord.Format(_T("%ld, %ld"), pt.x, pt.y);
SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) strCoord);
}
}
if (drawing)
{
/* values displayed in statusbar */
LONG xRel = xNow - start.x;
LONG yRel = yNow - start.y;
LONG xRel = pt.x - start.x;
LONG yRel = pt.y - 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 = (pt.x < 0) ? -start.x : xRel;
else if (pt.x > 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;
yRel = (pt.y < 0) ? -start.y : yRel;
else if (pt.y > 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))
@ -310,7 +403,7 @@ LRESULT CImgAreaWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOO
case TOOL_SHAPE:
{
CString strCoord;
strCoord.Format(_T("%ld, %ld"), xNow, yNow);
strCoord.Format(_T("%ld, %ld"), pt.x, pt.y);
SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) strCoord);
break;
}
@ -319,7 +412,7 @@ LRESULT CImgAreaWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOO
}
if (wParam & MK_LBUTTON)
{
toolsModel.OnMouseMove(TRUE, xNow, yNow);
toolsModel.OnMouseMove(TRUE, pt.x, pt.y);
Invalidate(FALSE);
if ((toolsModel.GetActiveTool() >= TOOL_TEXT) || (toolsModel.GetActiveTool() == TOOL_RECTSEL) || (toolsModel.GetActiveTool() == TOOL_FREESEL))
{
@ -332,7 +425,7 @@ LRESULT CImgAreaWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOO
}
if (wParam & MK_RBUTTON)
{
toolsModel.OnMouseMove(FALSE, xNow, yNow);
toolsModel.OnMouseMove(FALSE, pt.x, pt.y);
Invalidate(FALSE);
if (toolsModel.GetActiveTool() >= TOOL_TEXT)
{

View file

@ -13,9 +13,15 @@
class CImgAreaWindow : public CWindowImpl<CImgAreaWindow>
{
public:
CImgAreaWindow() : drawing(FALSE) { }
CImgAreaWindow()
: drawing(FALSE)
, m_hitSelection(HIT_NONE)
{
}
BOOL drawing;
CANVAS_HITTEST m_hitSelection;
void cancelDrawing();
void finishDrawing();
@ -71,4 +77,8 @@ private:
LRESULT OnCtlColorEdit(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
void drawZoomFrame(int mouseX, int mouseY);
CANVAS_HITTEST SelectionHitTest(POINT ptZoomed);
void StartSelectionDrag(CANVAS_HITTEST hit, POINT ptUnZoomed);
void SelectionDragging(POINT ptUnZoomed);
void EndSelectionDrag(POINT ptUnZoomed);
};

View file

@ -16,20 +16,6 @@ POINT ToolBase::pointStack[256] = { { 0 } };
/* FUNCTIONS ********************************************************/
void
placeSelWin()
{
CRect rc;
rc.left = Zoomed(selectionModel.GetDestRectLeft());
rc.top = Zoomed(selectionModel.GetDestRectTop());
rc.right = rc.left + Zoomed(selectionModel.GetDestRectWidth());
rc.bottom = rc.top + Zoomed(selectionModel.GetDestRectHeight());
::InflateRect(&rc, GRIP_SIZE, GRIP_SIZE);
selectionWindow.MoveWindow(rc.left, rc.top, rc.Width(), rc.Height(), TRUE);
selectionWindow.BringWindowToTop();
imageArea.InvalidateRect(NULL, FALSE);
}
void
regularize(LONG x0, LONG y0, LONG& x1, LONG& y1)
{
@ -82,8 +68,11 @@ void ToolBase::reset()
pointSP = 0;
start.x = start.y = last.x = last.y = -1;
selectionModel.ResetPtStack();
if (selectionWindow.IsWindow())
selectionWindow.ShowWindow(SW_HIDE);
if (selectionModel.m_bShow)
{
selectionModel.Landing();
selectionModel.m_bShow = FALSE;
}
}
void ToolBase::OnCancelDraw()
@ -121,12 +110,14 @@ struct FreeSelTool : ToolBase
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick)
{
selectionModel.Landing();
if (bLeftButton)
{
imageModel.CopyPrevious();
selectionWindow.ShowWindow(SW_HIDE);
selectionModel.m_bShow = FALSE;
selectionModel.ResetPtStack();
selectionModel.PushToPtStack(x, y);
POINT pt = { x, y };
selectionModel.PushToPtStack(pt);
}
m_bLeftButton = bLeftButton;
}
@ -137,7 +128,7 @@ struct FreeSelTool : ToolBase
{
POINT pt = { x, y };
imageModel.Bound(pt);
selectionModel.PushToPtStack(pt.x, pt.y);
selectionModel.PushToPtStack(pt);
imageModel.ResetToPrevious();
selectionModel.DrawFramePoly(m_hdc);
}
@ -150,28 +141,25 @@ struct FreeSelTool : ToolBase
imageModel.ResetToPrevious();
if (selectionModel.PtStackSize() > 2)
{
selectionModel.CalculateBoundingBoxAndContents(m_hdc);
placeSelWin();
selectionWindow.IsMoved(FALSE);
selectionWindow.ShowWindow(SW_SHOWNOACTIVATE);
selectionModel.BuildMaskFromPtStack();
selectionModel.TakeOff();
selectionModel.m_bShow = TRUE;
}
else
{
imageModel.Undo(TRUE);
selectionWindow.IsMoved(FALSE);
selectionModel.ResetPtStack();
selectionWindow.ShowWindow(SW_HIDE);
selectionModel.m_bShow = FALSE;
}
imageArea.Invalidate(FALSE);
}
}
void OnFinishDraw()
{
if (m_bLeftButton)
{
selectionWindow.IsMoved(FALSE);
selectionWindow.ForceRefreshSelectionContents();
}
imageArea.Invalidate(FALSE);
m_bLeftButton = FALSE;
ToolBase::OnFinishDraw();
}
@ -181,7 +169,6 @@ struct FreeSelTool : ToolBase
if (m_bLeftButton)
imageModel.Undo(TRUE);
m_bLeftButton = FALSE;
selectionWindow.IsMoved(FALSE);
ToolBase::OnCancelDraw();
}
};
@ -197,11 +184,12 @@ struct RectSelTool : ToolBase
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick)
{
selectionModel.Landing();
if (bLeftButton)
{
imageModel.CopyPrevious();
selectionWindow.ShowWindow(SW_HIDE);
selectionModel.SetSrcRectSizeToZero();
selectionModel.m_bShow = FALSE;
::SetRectEmpty(&selectionModel.m_rc);
}
m_bLeftButton = bLeftButton;
}
@ -213,7 +201,7 @@ struct RectSelTool : ToolBase
imageModel.ResetToPrevious();
POINT pt = { x, y };
imageModel.Bound(pt);
selectionModel.SetSrcAndDestRectFromPoints(start, pt);
selectionModel.SetRectFromPoints(start, pt);
RectSel(m_hdc, start.x, start.y, pt.x, pt.y);
}
}
@ -225,23 +213,16 @@ struct RectSelTool : ToolBase
imageModel.ResetToPrevious();
if (start.x == x && start.y == y)
imageModel.Undo(TRUE);
selectionModel.CalculateContents(m_hdc);
placeSelWin();
selectionWindow.IsMoved(FALSE);
if (selectionModel.IsSrcRectSizeNonzero())
selectionWindow.ShowWindow(SW_SHOWNOACTIVATE);
else
selectionWindow.ShowWindow(SW_HIDE);
selectionModel.m_bShow = !selectionModel.m_rc.IsRectEmpty();
imageArea.Invalidate(FALSE);
}
}
void OnFinishDraw()
{
if (m_bLeftButton)
{
selectionWindow.IsMoved(FALSE);
selectionWindow.ForceRefreshSelectionContents();
}
imageArea.Invalidate(FALSE);
m_bLeftButton = FALSE;
ToolBase::OnFinishDraw();
}
@ -251,7 +232,6 @@ struct RectSelTool : ToolBase
if (m_bLeftButton)
imageModel.Undo(TRUE);
m_bLeftButton = FALSE;
selectionWindow.IsMoved(FALSE);
ToolBase::OnCancelDraw();
}
};
@ -430,7 +410,7 @@ struct TextTool : ToolBase
imageModel.ResetToPrevious();
POINT pt = { x, y };
imageModel.Bound(pt);
selectionModel.SetSrcAndDestRectFromPoints(start, pt);
selectionModel.SetRectFromPoints(start, pt);
RectSel(m_hdc, start.x, start.y, pt.x, pt.y);
}
@ -452,6 +432,10 @@ struct TextTool : ToolBase
{
imageModel.Undo(TRUE);
POINT pt = { x, y };
imageModel.Bound(pt);
selectionModel.SetRectFromPoints(start, pt);
BOOL bTextBoxShown = ::IsWindowVisible(textEditWindow);
if (bTextBoxShown && textEditWindow.GetWindowTextLength() > 0)
{
@ -466,6 +450,13 @@ struct TextTool : ToolBase
imageModel.CopyPrevious();
Text(m_hdc, rc.left, rc.top, rc.right, rc.bottom, m_fg, m_bg, szText,
textEditWindow.GetFont(), style);
if (selectionModel.m_rc.IsRectEmpty())
{
textEditWindow.ShowWindow(SW_HIDE);
textEditWindow.SetWindowText(NULL);
return;
}
}
if (registrySettings.ShowTextTool)
@ -476,45 +467,35 @@ struct TextTool : ToolBase
fontsDialog.ShowWindow(SW_SHOWNOACTIVATE);
}
if (!bTextBoxShown || selectionModel.IsSrcRectSizeNonzero())
RECT rc = selectionModel.m_rc;
// Enlarge if tool small
INT cxMin = CX_MINTEXTEDIT, cyMin = CY_MINTEXTEDIT;
if (selectionModel.m_rc.IsRectEmpty())
{
RECT rc;
selectionModel.GetRect(&rc);
// Enlarge if tool small
INT cxMin = CX_MINTEXTEDIT, cyMin = CY_MINTEXTEDIT;
if (selectionModel.IsSrcRectSizeNonzero())
{
if (rc.right - rc.left < cxMin)
rc.right = rc.left + cxMin;
if (rc.bottom - rc.top < cyMin)
rc.bottom = rc.top + cyMin;
}
else
{
SetRect(&rc, x, y, x + cxMin, y + cyMin);
}
if (!textEditWindow.IsWindow())
textEditWindow.Create(imageArea);
textEditWindow.SetWindowText(NULL);
textEditWindow.ValidateEditRect(&rc);
textEditWindow.ShowWindow(SW_SHOWNOACTIVATE);
textEditWindow.SetFocus();
SetRect(&rc, x, y, x + cxMin, y + cyMin);
}
else
{
textEditWindow.ShowWindow(SW_HIDE);
textEditWindow.SetWindowText(NULL);
if (rc.right - rc.left < cxMin)
rc.right = rc.left + cxMin;
if (rc.bottom - rc.top < cyMin)
rc.bottom = rc.top + cyMin;
}
if (!textEditWindow.IsWindow())
textEditWindow.Create(imageArea);
textEditWindow.SetWindowText(NULL);
textEditWindow.ValidateEditRect(&rc);
textEditWindow.ShowWindow(SW_SHOWNOACTIVATE);
textEditWindow.SetFocus();
}
void OnFinishDraw()
{
toolsModel.OnButtonDown(TRUE, -1, -1, TRUE);
toolsModel.OnButtonUp(TRUE, -1, -1);
selectionWindow.IsMoved(FALSE);
ToolBase::OnFinishDraw();
}
};

View file

@ -97,8 +97,8 @@ void PaletteModel::NotifyColorChanged()
{
if (paletteWindow.IsWindow())
paletteWindow.SendMessage(WM_PALETTEMODELCOLORCHANGED);
if (selectionWindow.IsWindow())
selectionWindow.SendMessage(WM_PALETTEMODELCOLORCHANGED);
if (imageArea.IsWindow())
imageArea.SendMessage(WM_PALETTEMODELCOLORCHANGED);
if (textEditWindow.IsWindow())
textEditWindow.SendMessage(WM_PALETTEMODELCOLORCHANGED);
}

View file

@ -43,7 +43,6 @@
#include "palette.h"
#include "palettemodel.h"
#include "registry.h"
#include "selection.h"
#include "selectionmodel.h"
#include "sizebox.h"
#include "canvas.h"

View file

@ -1,237 +0,0 @@
/*
* PROJECT: PAINT for ReactOS
* LICENSE: LGPL
* FILE: base/applications/mspaint/selection.cpp
* PURPOSE: Window procedure of the selection window
* PROGRAMMERS: Benedikt Freisen
* Katayama Hirofumi MZ
*/
#include "precomp.h"
CSelectionWindow selectionWindow;
/* FUNCTIONS ********************************************************/
const LPCTSTR CSelectionWindow::m_lpszCursorLUT[9] = { /* action to mouse cursor lookup table */
IDC_SIZEALL,
IDC_SIZENWSE, IDC_SIZENS, IDC_SIZENESW,
IDC_SIZEWE, IDC_SIZEWE,
IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE
};
void CSelectionWindow::ForceRefreshSelectionContents()
{
if (::IsWindowVisible(selectionWindow))
{
imageModel.ResetToPrevious();
imageModel.DrawSelectionBackground(m_rgbBack);
selectionModel.DrawSelection(imageModel.GetDC(), paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent());
}
}
int CSelectionWindow::IdentifyCorner(int iXPos, int iYPos, int iWidth, int iHeight)
{
return 0;
}
LRESULT CSelectionWindow::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(&ps);
if (!m_bMoving)
{
RECT rcClient;
GetClientRect(&rcClient);
drawSizeBoxes(hDC, &rcClient, TRUE, &ps.rcPaint);
}
EndPaint(&ps);
return 0;
}
LRESULT CSelectionWindow::OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// do nothing => transparent background
return TRUE;
}
LRESULT CSelectionWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
m_bMoving = FALSE;
m_iAction = ACTION_MOVE;
/* update the system selection color */
Invalidate();
return 0;
}
LRESULT CSelectionWindow::OnSysColorChange(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
/* update the system selection color */
Invalidate();
return 0;
}
LRESULT CSelectionWindow::OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
RECT rcClient;
GetClientRect(&rcClient);
POINT pt;
::GetCursorPos(&pt);
ScreenToClient(&pt);
if (!setCursorOnSizeBox(getSizeBoxHitTest(pt, &rcClient)))
::SetCursor(::LoadCursor(NULL, IDC_SIZEALL));
return 0;
}
LRESULT CSelectionWindow::OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
m_ptPos.x = GET_X_LPARAM(lParam);
m_ptPos.y = GET_Y_LPARAM(lParam);
m_ptDelta.x = 0;
m_ptDelta.y = 0;
SetCapture();
if (m_iAction != ACTION_MOVE)
SetCursor(LoadCursor(NULL, m_lpszCursorLUT[m_iAction]));
m_bMoving = TRUE;
imageArea.InvalidateRect(NULL, FALSE);
imageArea.SendMessage(WM_PAINT, 0, 0);
m_rgbBack = paletteModel.GetBgColor();
return 0;
}
LRESULT CSelectionWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (m_bMoving)
{
imageModel.ResetToPrevious();
imageModel.DrawSelectionBackground(m_rgbBack);
m_ptFrac.x += GET_X_LPARAM(lParam) - m_ptPos.x;
m_ptFrac.y += GET_Y_LPARAM(lParam) - m_ptPos.y;
m_ptDelta.x += UnZoomed(m_ptFrac.x);
m_ptDelta.y += UnZoomed(m_ptFrac.y);
if (toolsModel.GetZoom() < 1000)
{
m_ptFrac.x = 0;
m_ptFrac.y = 0;
}
else
{
m_ptFrac.x -= Zoomed(UnZoomed(m_ptFrac.x));
m_ptFrac.y -= Zoomed(UnZoomed(m_ptFrac.y));
}
selectionModel.ModifyDestRect(m_ptDelta, m_iAction);
CString strSize;
strSize.Format(_T("%ld x %ld"), selectionModel.GetDestRectWidth(), selectionModel.GetDestRectHeight());
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize);
if (m_iAction != ACTION_MOVE)
selectionModel.DrawSelectionStretched(imageModel.GetDC());
else
selectionModel.DrawSelection(imageModel.GetDC(), paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent());
imageArea.InvalidateRect(NULL, FALSE);
imageArea.SendMessage(WM_PAINT, 0, 0);
m_ptPos.x = GET_X_LPARAM(lParam);
m_ptPos.y = GET_Y_LPARAM(lParam);
}
else
{
int w = Zoomed(selectionModel.GetDestRectWidth()) + 2 * GRIP_SIZE;
int h = Zoomed(selectionModel.GetDestRectHeight()) + 2 * GRIP_SIZE;
m_ptPos.x = GET_X_LPARAM(lParam);
m_ptPos.y = GET_Y_LPARAM(lParam);
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) NULL);
m_iAction = IdentifyCorner(m_ptPos.x, m_ptPos.y, w, h);
if (m_iAction != ACTION_MOVE)
SetCursor(LoadCursor(NULL, m_lpszCursorLUT[m_iAction]));
}
return 0;
}
LRESULT CSelectionWindow::OnMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
m_bMoved = TRUE;
return 0;
}
LRESULT CSelectionWindow::OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (m_bMoving)
{
m_bMoving = FALSE;
ReleaseCapture();
if (m_iAction != ACTION_MOVE && toolsModel.GetActiveTool() != TOOL_TEXT)
{
imageModel.Undo();
imageModel.DrawSelectionBackground(m_rgbBack);
selectionModel.ScaleContentsToFit();
imageModel.CopyPrevious();
}
placeSelWin();
}
return 0;
}
LRESULT CSelectionWindow::OnCaptureChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (m_bMoving)
{
m_bMoving = FALSE;
if (m_iAction == ACTION_MOVE)
{
if (toolsModel.GetActiveTool() == TOOL_RECTSEL)
imageArea.cancelDrawing();
else
placeSelWin();
}
else
{
m_iAction = ACTION_MOVE;
}
ShowWindow(SW_HIDE);
}
return 0;
}
LRESULT CSelectionWindow::OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (wParam == VK_ESCAPE)
{
if (GetCapture() == m_hWnd)
{
ReleaseCapture();
}
}
return 0;
}
LRESULT CSelectionWindow::OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
return 0;
}
LRESULT CSelectionWindow::OnToolsModelSettingsChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
return 0;
}
LRESULT CSelectionWindow::OnSelectionModelRefreshNeeded(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
ForceRefreshSelectionContents();
return 0;
}
LRESULT CSelectionWindow::OnMouseWheel(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
return ::SendMessage(GetParent(), nMsg, wParam, lParam);
}
LRESULT CSelectionWindow::OnToolsModelZoomChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
placeSelWin();
return 0;
}

View file

@ -1,75 +0,0 @@
/*
* PROJECT: PAINT for ReactOS
* LICENSE: LGPL
* FILE: base/applications/mspaint/selection.h
* PURPOSE: Window procedure of the selection window
* PROGRAMMERS: Benedikt Freisen
* Katayama Hirofumi MZ
*/
#pragma once
class CSelectionWindow : public CWindowImpl<CSelectionWindow>
{
public:
CSelectionWindow() : m_bMoved(FALSE)
{
}
BOOL IsMoved() const { return m_bMoved; }
void IsMoved(BOOL bMoved) { m_bMoved = bMoved; }
void ForceRefreshSelectionContents();
DECLARE_WND_CLASS_EX(_T("Selection"), CS_DBLCLKS, COLOR_BTNFACE)
BEGIN_MSG_MAP(CSelectionWindow)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_SYSCOLORCHANGE, OnSysColorChange)
MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
MESSAGE_HANDLER(WM_MOUSEWHEEL, OnMouseWheel)
MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
MESSAGE_HANDLER(WM_MOVE, OnMove)
MESSAGE_HANDLER(WM_PALETTEMODELCOLORCHANGED, OnPaletteModelColorChanged)
MESSAGE_HANDLER(WM_TOOLSMODELSETTINGSCHANGED, OnToolsModelSettingsChanged)
MESSAGE_HANDLER(WM_TOOLSMODELZOOMCHANGED, OnToolsModelZoomChanged)
MESSAGE_HANDLER(WM_SELECTIONMODELREFRESHNEEDED, OnSelectionModelRefreshNeeded)
MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
END_MSG_MAP()
LRESULT OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnSysColorChange(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnMouseWheel(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnToolsModelSettingsChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnToolsModelZoomChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnSelectionModelRefreshNeeded(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnCaptureChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
private:
static const LPCTSTR m_lpszCursorLUT[9];
BOOL m_bMoved;
BOOL m_bMoving;
int m_iAction;
POINT m_ptPos;
POINT m_ptFrac;
POINT m_ptDelta;
COLORREF m_rgbBack;
int IdentifyCorner(int iXPos, int iYPos, int iWidth, int iHeight);
};
void ForceRefreshSelectionContents();

View file

@ -14,225 +14,295 @@ SelectionModel selectionModel;
/* FUNCTIONS ********************************************************/
SelectionModel::SelectionModel()
: m_hDC(CreateCompatibleDC(NULL))
, m_hBm(NULL)
, m_hMask(NULL)
: m_hbmColor(NULL)
, m_hbmMask(NULL)
, m_ptStack(NULL)
, m_iPtSP(0)
, m_bShow(FALSE)
{
SetRectEmpty(&m_rcSrc);
SetRectEmpty(&m_rcDest);
::SetRectEmpty(&m_rc);
m_ptHit.x = m_ptHit.y = -1;
}
SelectionModel::~SelectionModel()
{
DeleteDC(m_hDC);
ClearColor();
ClearMask();
ResetPtStack();
if (m_hBm)
{
DeleteObject(m_hBm);
}
if (m_hMask)
{
DeleteObject(m_hMask);
}
}
void SelectionModel::ResetPtStack()
{
if (m_ptStack != NULL)
HeapFree(GetProcessHeap(), 0, m_ptStack);
m_ptStack = NULL;
if (m_ptStack)
{
free(m_ptStack);
m_ptStack = NULL;
}
m_iPtSP = 0;
}
void SelectionModel::PushToPtStack(LONG x, LONG y)
void SelectionModel::PushToPtStack(POINT pt)
{
if (m_iPtSP % 1024 == 0)
#define GROW_COUNT 256
if (m_iPtSP % GROW_COUNT == 0)
{
if (m_ptStack)
m_ptStack = (POINT*) HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, m_ptStack, sizeof(POINT) * (m_iPtSP + 1024));
else
m_ptStack = (POINT*) HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(POINT) * 1024);
INT nNewCount = m_iPtSP + GROW_COUNT;
LPPOINT pptNew = (LPPOINT)realloc(m_ptStack, sizeof(POINT) * nNewCount);
if (pptNew == NULL)
return;
m_ptStack = pptNew;
}
m_ptStack[m_iPtSP].x = x;
m_ptStack[m_iPtSP].y = y;
m_ptStack[m_iPtSP] = pt;
m_iPtSP++;
#undef GROW_COUNT
}
void SelectionModel::CalculateBoundingBoxAndContents(HDC hDCImage)
void SelectionModel::ShiftPtStack(BOOL bPlus)
{
int i;
m_rcSrc.left = m_rcSrc.top = MAXLONG;
m_rcSrc.right = m_rcSrc.bottom = 0;
for (i = 0; i < m_iPtSP; i++)
if (bPlus)
{
if (m_ptStack[i].x < m_rcSrc.left)
m_rcSrc.left = m_ptStack[i].x;
if (m_ptStack[i].y < m_rcSrc.top)
m_rcSrc.top = m_ptStack[i].y;
if (m_ptStack[i].x > m_rcSrc.right)
m_rcSrc.right = m_ptStack[i].x;
if (m_ptStack[i].y > m_rcSrc.bottom)
m_rcSrc.bottom = m_ptStack[i].y;
}
m_rcSrc.right += 1;
m_rcSrc.bottom += 1;
m_rcDest.left = m_rcSrc.left;
m_rcDest.top = m_rcSrc.top;
m_rcDest.right = m_rcSrc.right;
m_rcDest.bottom = m_rcSrc.bottom;
if (m_iPtSP > 1)
{
DeleteObject(m_hMask);
m_hMask = CreateBitmap(RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), 1, 1, NULL);
DeleteObject(SelectObject(m_hDC, m_hMask));
POINT *m_ptStackCopy = (POINT*) HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(POINT) * m_iPtSP);
for (i = 0; i < m_iPtSP; i++)
for (INT i = 0; i < m_iPtSP; ++i)
{
m_ptStackCopy[i].x = m_ptStack[i].x - m_rcSrc.left;
m_ptStackCopy[i].y = m_ptStack[i].y - m_rcSrc.top;
POINT& pt = m_ptStack[i];
pt.x += m_rc.left;
pt.y += m_rc.top;
}
}
else
{
for (INT i = 0; i < m_iPtSP; ++i)
{
POINT& pt = m_ptStack[i];
pt.x -= m_rc.left;
pt.y -= m_rc.top;
}
Poly(m_hDC, m_ptStackCopy, m_iPtSP, 0x00ffffff, 0x00ffffff, 1, 2, TRUE, FALSE);
HeapFree(GetProcessHeap(), 0, m_ptStackCopy);
SelectObject(m_hDC, m_hBm = CreateDIBWithProperties(RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc)));
imageModel.ResetToPrevious();
MaskBlt(m_hDC, 0, 0, RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), hDCImage, m_rcSrc.left,
m_rcSrc.top, m_hMask, 0, 0, MAKEROP4(SRCCOPY, WHITENESS));
}
}
void SelectionModel::CalculateContents(HDC hDCImage)
void SelectionModel::BuildMaskFromPtStack()
{
DeleteObject(m_hMask);
m_hMask = CreateBitmap(RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), 1, 1, NULL);
DeleteObject(SelectObject(m_hDC, m_hMask));
Rect(m_hDC, 0, 0, RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), 0x00ffffff, 0x00ffffff, 1, 2);
SelectObject(m_hDC, m_hBm = CreateDIBWithProperties(RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc)));
BitBlt(m_hDC, 0, 0, RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), hDCImage, m_rcSrc.left,
m_rcSrc.top, SRCCOPY);
CRect rc = { MAXLONG, MAXLONG, 0, 0 };
for (INT i = 0; i < m_iPtSP; ++i)
{
POINT& pt = m_ptStack[i];
rc.left = min(pt.x, rc.left);
rc.top = min(pt.y, rc.top);
rc.right = max(pt.x, rc.right);
rc.bottom = max(pt.y, rc.bottom);
}
rc.right += 1;
rc.bottom += 1;
m_rc = rc;
ShiftPtStack(FALSE);
ClearMask();
HDC hdcMem = ::CreateCompatibleDC(NULL);
m_hbmMask = ::CreateBitmap(rc.Width(), rc.Height(), 1, 1, NULL);
HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_hbmMask);
FillRect(hdcMem, &rc, (HBRUSH)::GetStockObject(BLACK_BRUSH));
HGDIOBJ hPenOld = ::SelectObject(hdcMem, GetStockObject(NULL_PEN));
HGDIOBJ hbrOld = ::SelectObject(hdcMem, GetStockObject(WHITE_BRUSH));
::Polygon(hdcMem, m_ptStack, m_iPtSP);
::SelectObject(hdcMem, hbrOld);
::SelectObject(hdcMem, hPenOld);
::SelectObject(hdcMem, hbmOld);
::DeleteDC(hdcMem);
}
void SelectionModel::DrawBackgroundPoly(HDC hDCImage, COLORREF crBg)
{
Poly(hDCImage, m_ptStack, m_iPtSP, crBg, crBg, 1, 2, TRUE, FALSE);
ShiftPtStack(TRUE);
HGDIOBJ hPenOld = ::SelectObject(hDCImage, ::GetStockObject(NULL_PEN));
HGDIOBJ hbrOld = ::SelectObject(hDCImage, ::CreateSolidBrush(crBg));
::Polygon(hDCImage, m_ptStack, m_iPtSP);
::DeleteObject(::SelectObject(hDCImage, hbrOld));
::SelectObject(hDCImage, hPenOld);
ShiftPtStack(FALSE);
}
void SelectionModel::DrawBackgroundRect(HDC hDCImage, COLORREF crBg)
{
Rect(hDCImage, m_rcSrc.left, m_rcSrc.top, m_rcSrc.right, m_rcSrc.bottom, crBg, crBg, 0, 1);
Rect(hDCImage, m_rc.left, m_rc.top, m_rc.right, m_rc.bottom, crBg, crBg, 0, 1);
}
void SelectionModel::DrawSelection(HDC hDCImage, COLORREF crBg, BOOL bBgTransparent)
void SelectionModel::DrawSelection(HDC hDCImage, LPCRECT prc, COLORREF crBg, BOOL bBgTransparent)
{
if (!bBgTransparent)
MaskBlt(hDCImage, m_rcDest.left, m_rcDest.top, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest),
m_hDC, 0, 0, m_hMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND));
CRect rc = *prc;
if (::IsRectEmpty(&rc))
return;
BITMAP bm;
GetObject(m_hbmColor, sizeof(BITMAP), &bm);
COLORREF keyColor = (bBgTransparent ? crBg : CLR_INVALID);
HDC hMemDC = CreateCompatibleDC(hDCImage);
HGDIOBJ hbmOld = SelectObject(hMemDC, m_hbmColor);
ColorKeyedMaskBlt(hDCImage, rc.left, rc.top, rc.Width(), rc.Height(),
hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, m_hbmMask, keyColor);
SelectObject(hMemDC, hbmOld);
DeleteDC(hMemDC);
}
void SelectionModel::GetSelectionContents(HDC hDCImage)
{
ClearColor();
HDC hMemDC = ::CreateCompatibleDC(NULL);
m_hbmColor = CreateColorDIB(m_rc.Width(), m_rc.Height(), RGB(255, 255, 255));
HGDIOBJ hbmOld = ::SelectObject(hMemDC, m_hbmColor);
::BitBlt(hMemDC, 0, 0, m_rc.Width(), m_rc.Height(), hDCImage, m_rc.left, m_rc.top, SRCCOPY);
::SelectObject(hMemDC, hbmOld);
::DeleteDC(hMemDC);
}
BOOL SelectionModel::TakeOff()
{
if (m_hbmColor || ::IsRectEmpty(&m_rc))
return FALSE;
HDC hDCImage = imageModel.GetDC();
GetSelectionContents(hDCImage);
if (toolsModel.GetActiveTool() == TOOL_FREESEL)
{
DrawBackgroundPoly(hDCImage, paletteModel.GetBgColor());
}
else
ColorKeyedMaskBlt(hDCImage, m_rcDest.left, m_rcDest.top, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest),
m_hDC, 0, 0, m_hMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND), crBg);
{
ClearMask();
DrawBackgroundRect(hDCImage, paletteModel.GetBgColor());
}
imageArea.Invalidate(FALSE);
return TRUE;
}
void SelectionModel::DrawSelectionStretched(HDC hDCImage)
void SelectionModel::Landing()
{
StretchBlt(hDCImage, m_rcDest.left, m_rcDest.top, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), m_hDC, 0, 0, GetDIBWidth(m_hBm), GetDIBHeight(m_hBm), SRCCOPY);
}
if (!m_hbmColor)
return;
void SelectionModel::ScaleContentsToFit()
{
HDC hTempDC;
HBITMAP hTempBm;
hTempDC = CreateCompatibleDC(m_hDC);
hTempBm = CreateDIBWithProperties(RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest));
SelectObject(hTempDC, hTempBm);
SelectObject(m_hDC, m_hBm);
StretchBlt(hTempDC, 0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), m_hDC, 0, 0,
GetDIBWidth(m_hBm), GetDIBHeight(m_hBm), SRCCOPY);
DeleteObject(m_hBm);
m_hBm = hTempBm;
hTempBm = CreateBitmap(RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), 1, 1, NULL);
SelectObject(hTempDC, hTempBm);
SelectObject(m_hDC, m_hMask);
StretchBlt(hTempDC, 0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), m_hDC, 0, 0,
GetDIBWidth(m_hMask), GetDIBHeight(m_hMask), SRCCOPY);
DeleteObject(m_hMask);
m_hMask = hTempBm;
SelectObject(m_hDC, m_hBm);
DeleteDC(hTempDC);
DrawSelection(imageModel.GetDC(), &m_rc, paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent());
::SetRectEmpty(&m_rc);
ClearMask();
ClearColor();
imageModel.CopyPrevious();
}
void SelectionModel::InsertFromHBITMAP(HBITMAP hBm, INT x, INT y)
{
HDC hTempDC;
HBITMAP hTempMask;
m_hbmColor = CopyDIBImage(hBm);
::DeleteObject(m_hbmColor);
m_hBm = CopyDIBImage(hBm);
DeleteObject(SelectObject(m_hDC, m_hBm));
m_rc.left = x;
m_rc.top = y;
m_rc.right = m_rc.left + GetDIBWidth(hBm);
m_rc.bottom = m_rc.top + GetDIBHeight(hBm);
SetRectEmpty(&m_rcSrc);
m_rcDest.left = x;
m_rcDest.top = y;
m_rcDest.right = m_rcDest.left + GetDIBWidth(m_hBm);
m_rcDest.bottom = m_rcDest.top + GetDIBHeight(m_hBm);
hTempDC = CreateCompatibleDC(m_hDC);
hTempMask = CreateBitmap(RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), 1, 1, NULL);
SelectObject(hTempDC, hTempMask);
Rect(hTempDC, 0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), 0x00ffffff, 0x00ffffff, 1, 1);
DeleteObject(m_hMask);
m_hMask = hTempMask;
DeleteDC(hTempDC);
ClearMask();
}
void SelectionModel::FlipHorizontally()
{
SelectObject(m_hDC, m_hMask);
StretchBlt(m_hDC, RECT_WIDTH(m_rcDest) - 1, 0, -RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), m_hDC,
0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
SelectObject(m_hDC, m_hBm);
StretchBlt(m_hDC, RECT_WIDTH(m_rcDest) - 1, 0, -RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), m_hDC,
0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
TakeOff();
HDC hdcMem = ::CreateCompatibleDC(NULL);
if (m_hbmMask)
{
::SelectObject(hdcMem, m_hbmMask);
::StretchBlt(hdcMem, m_rc.Width() - 1, 0, -m_rc.Width(), m_rc.Height(),
hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
}
if (m_hbmColor)
{
::SelectObject(hdcMem, m_hbmColor);
::StretchBlt(hdcMem, m_rc.Width() - 1, 0, -m_rc.Width(), m_rc.Height(),
hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
}
::DeleteDC(hdcMem);
NotifyRefreshNeeded();
}
void SelectionModel::FlipVertically()
{
SelectObject(m_hDC, m_hMask);
StretchBlt(m_hDC, 0, RECT_HEIGHT(m_rcDest) - 1, RECT_WIDTH(m_rcDest), -RECT_HEIGHT(m_rcDest), m_hDC,
0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
SelectObject(m_hDC, m_hBm);
StretchBlt(m_hDC, 0, RECT_HEIGHT(m_rcDest) - 1, RECT_WIDTH(m_rcDest), -RECT_HEIGHT(m_rcDest), m_hDC,
0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
TakeOff();
HDC hdcMem = ::CreateCompatibleDC(NULL);
if (m_hbmMask)
{
::SelectObject(hdcMem, m_hbmMask);
::StretchBlt(hdcMem, 0, m_rc.Height() - 1, m_rc.Width(), -m_rc.Height(),
hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
}
if (m_hbmColor)
{
::SelectObject(hdcMem, m_hbmColor);
::StretchBlt(hdcMem, 0, m_rc.Height() - 1, m_rc.Width(), -m_rc.Height(),
hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
}
::DeleteDC(hdcMem);
NotifyRefreshNeeded();
}
void SelectionModel::RotateNTimes90Degrees(int iN)
{
HBITMAP hbm;
HGDIOBJ hbmOld;
HDC hdcMem = ::CreateCompatibleDC(NULL);
switch (iN)
{
case 1:
case 3:
imageModel.DeleteSelection();
imageModel.CopyPrevious();
SelectObject(m_hDC, m_hBm);
hbm = Rotate90DegreeBlt(m_hDC, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), iN == 1);
InsertFromHBITMAP(hbm, m_rcDest.left, m_rcDest.top);
DeleteObject(hbm);
selectionWindow.ShowWindow(SW_SHOWNOACTIVATE);
selectionWindow.ForceRefreshSelectionContents();
placeSelWin();
break;
case 2:
SelectObject(m_hDC, m_hMask);
StretchBlt(m_hDC, RECT_WIDTH(m_rcDest) - 1, RECT_HEIGHT(m_rcDest) - 1, -RECT_WIDTH(m_rcDest), -RECT_HEIGHT(m_rcDest), m_hDC,
0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
SelectObject(m_hDC, m_hBm);
StretchBlt(m_hDC, RECT_WIDTH(m_rcDest) - 1, RECT_HEIGHT(m_rcDest) - 1, -RECT_WIDTH(m_rcDest), -RECT_HEIGHT(m_rcDest), m_hDC,
0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
break;
case 1:
case 3:
TakeOff();
if (m_hbmColor)
{
hbmOld = ::SelectObject(hdcMem, m_hbmColor);
hbm = Rotate90DegreeBlt(hdcMem, m_rc.Width(), m_rc.Height(), iN == 1, FALSE);
::SelectObject(hdcMem, hbmOld);
::DeleteObject(m_hbmColor);
m_hbmColor = hbm;
}
if (m_hbmMask)
{
hbmOld = ::SelectObject(hdcMem, m_hbmMask);
hbm = Rotate90DegreeBlt(hdcMem, m_rc.Width(), m_rc.Height(), iN == 1, TRUE);
::SelectObject(hdcMem, hbmOld);
::DeleteObject(m_hbmMask);
m_hbmMask = hbm;
}
break;
case 2:
TakeOff();
if (m_hbmColor)
{
hbmOld = ::SelectObject(hdcMem, m_hbmColor);
::StretchBlt(hdcMem, m_rc.Width() - 1, m_rc.Height() - 1, -m_rc.Width(), -m_rc.Height(),
hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
::SelectObject(hdcMem, hbmOld);
}
if (m_hbmMask)
{
hbmOld = ::SelectObject(hdcMem, m_hbmMask);
::StretchBlt(hdcMem, m_rc.Width() - 1, m_rc.Height() - 1, -m_rc.Width(), -m_rc.Height(),
hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
::SelectObject(hdcMem, hbmOld);
}
break;
}
::DeleteDC(hdcMem);
NotifyRefreshNeeded();
}
@ -241,47 +311,47 @@ void SelectionModel::StretchSkew(int nStretchPercentX, int nStretchPercentY, int
if (nStretchPercentX == 100 && nStretchPercentY == 100 && nSkewDegX == 0 && nSkewDegY == 0)
return;
imageModel.DeleteSelection();
imageModel.CopyPrevious();
TakeOff();
INT oldWidth = RECT_WIDTH(m_rcDest);
INT oldHeight = RECT_HEIGHT(m_rcDest);
INT oldWidth = m_rc.Width();
INT oldHeight = m_rc.Height();
INT newWidth = oldWidth * nStretchPercentX / 100;
INT newHeight = oldHeight * nStretchPercentY / 100;
if (oldWidth != newWidth || oldHeight != newHeight)
{
SelectObject(m_hDC, m_hBm);
HBITMAP hbm0 = CopyDIBImage(m_hBm, newWidth, newHeight);
InsertFromHBITMAP(hbm0, m_rcDest.left, m_rcDest.top);
DeleteObject(hbm0);
HBITMAP hbm0 = CopyDIBImage(m_hbmColor, newWidth, newHeight);
InsertFromHBITMAP(hbm0, m_rc.left, m_rc.top);
::DeleteObject(hbm0);
}
HDC hDC = ::CreateCompatibleDC(NULL);
if (nSkewDegX)
{
SelectObject(m_hDC, m_hBm);
HBITMAP hbm1 = SkewDIB(m_hDC, m_hBm, nSkewDegX, FALSE);
InsertFromHBITMAP(hbm1, m_rcDest.left, m_rcDest.top);
DeleteObject(hbm1);
::SelectObject(hDC, m_hbmColor);
HBITMAP hbm1 = SkewDIB(hDC, m_hbmColor, nSkewDegX, FALSE);
InsertFromHBITMAP(hbm1, m_rc.left, m_rc.top);
::DeleteObject(hbm1);
}
if (nSkewDegY)
{
SelectObject(m_hDC, m_hBm);
HBITMAP hbm2 = SkewDIB(m_hDC, m_hBm, nSkewDegY, TRUE);
InsertFromHBITMAP(hbm2, m_rcDest.left, m_rcDest.top);
DeleteObject(hbm2);
::SelectObject(hDC, m_hbmColor);
HBITMAP hbm2 = SkewDIB(hDC, m_hbmColor, nSkewDegY, TRUE);
InsertFromHBITMAP(hbm2, m_rc.left, m_rc.top);
::DeleteObject(hbm2);
}
selectionWindow.ShowWindow(SW_SHOWNOACTIVATE);
selectionWindow.ForceRefreshSelectionContents();
placeSelWin();
::DeleteDC(hDC);
m_bShow = TRUE;
NotifyRefreshNeeded();
}
HBITMAP SelectionModel::GetBitmap() const
{
return m_hBm;
return m_hbmColor;
}
int SelectionModel::PtStackSize() const
@ -291,114 +361,92 @@ int SelectionModel::PtStackSize() const
void SelectionModel::DrawFramePoly(HDC hDCImage)
{
Poly(hDCImage, m_ptStack, m_iPtSP, 0, 0, 2, 0, FALSE, TRUE); /* draw the freehand selection inverted/xored */
/* draw the freehand selection inverted/xored */
Poly(hDCImage, m_ptStack, m_iPtSP, 0, 0, 2, 0, FALSE, TRUE);
}
void SelectionModel::SetSrcAndDestRectFromPoints(const POINT& ptFrom, const POINT& ptTo)
void SelectionModel::SetRectFromPoints(const POINT& ptFrom, const POINT& ptTo)
{
m_rcDest.left = m_rcSrc.left = min(ptFrom.x, ptTo.x);
m_rcDest.top = m_rcSrc.top = min(ptFrom.y, ptTo.y);
m_rcDest.right = m_rcSrc.right = max(ptFrom.x, ptTo.x);
m_rcDest.bottom = m_rcSrc.bottom = max(ptFrom.y, ptTo.y);
m_rc.left = min(ptFrom.x, ptTo.x);
m_rc.top = min(ptFrom.y, ptTo.y);
m_rc.right = max(ptFrom.x, ptTo.x);
m_rc.bottom = max(ptFrom.y, ptTo.y);
}
void SelectionModel::SetSrcRectSizeToZero()
void SelectionModel::Dragging(CANVAS_HITTEST hit, POINT pt)
{
m_rcSrc.right = m_rcSrc.left;
m_rcSrc.bottom = m_rcSrc.top;
}
BOOL SelectionModel::IsSrcRectSizeNonzero() const
{
return (RECT_WIDTH(m_rcSrc) != 0) && (RECT_HEIGHT(m_rcSrc) != 0);
}
void SelectionModel::ModifyDestRect(POINT& ptDelta, int iAction)
{
POINT ptDeltaUsed;
switch (iAction)
switch (hit)
{
case ACTION_MOVE: /* move selection */
ptDeltaUsed.x = ptDelta.x;
ptDeltaUsed.y = ptDelta.y;
OffsetRect(&m_rcDest, ptDeltaUsed.x, ptDeltaUsed.y);
case HIT_NONE:
break;
case ACTION_RESIZE_TOP_LEFT: /* resize at upper left corner */
ptDeltaUsed.x = min(ptDelta.x, RECT_WIDTH(m_rcDest) - 1);
ptDeltaUsed.y = min(ptDelta.y, RECT_HEIGHT(m_rcDest) - 1);
m_rcDest.left += ptDeltaUsed.x;
m_rcDest.top += ptDeltaUsed.y;
case HIT_UPPER_LEFT:
m_rc.left += pt.x - m_ptHit.x;
m_rc.top += pt.y - m_ptHit.y;
break;
case ACTION_RESIZE_TOP: /* resize at top edge */
ptDeltaUsed.x = ptDelta.x;
ptDeltaUsed.y = min(ptDelta.y, RECT_HEIGHT(m_rcDest) - 1);
m_rcDest.top += ptDeltaUsed.y;
case HIT_UPPER_CENTER:
m_rc.top += pt.y - m_ptHit.y;
break;
case ACTION_RESIZE_TOP_RIGHT: /* resize at upper right corner */
ptDeltaUsed.x = max(ptDelta.x, -(RECT_WIDTH(m_rcDest) - 1));
ptDeltaUsed.y = min(ptDelta.y, RECT_HEIGHT(m_rcDest) - 1);
m_rcDest.top += ptDeltaUsed.y;
m_rcDest.right += ptDeltaUsed.x;
case HIT_UPPER_RIGHT:
m_rc.right += pt.x - m_ptHit.x;
m_rc.top += pt.y - m_ptHit.y;
break;
case ACTION_RESIZE_LEFT: /* resize at left edge */
ptDeltaUsed.x = min(ptDelta.x, RECT_WIDTH(m_rcDest) - 1);
ptDeltaUsed.y = ptDelta.y;
m_rcDest.left += ptDeltaUsed.x;
case HIT_MIDDLE_LEFT:
m_rc.left += pt.x - m_ptHit.x;
break;
case ACTION_RESIZE_RIGHT: /* resize at right edge */
ptDeltaUsed.x = max(ptDelta.x, -(RECT_WIDTH(m_rcDest) - 1));
ptDeltaUsed.y = ptDelta.y;
m_rcDest.right += ptDeltaUsed.x;
case HIT_MIDDLE_RIGHT:
m_rc.right += pt.x - m_ptHit.x;
break;
case ACTION_RESIZE_BOTTOM_LEFT: /* resize at lower left corner */
ptDeltaUsed.x = min(ptDelta.x, RECT_WIDTH(m_rcDest) - 1);
ptDeltaUsed.y = max(ptDelta.y, -(RECT_HEIGHT(m_rcDest) - 1));
m_rcDest.left += ptDeltaUsed.x;
m_rcDest.bottom += ptDeltaUsed.y;
case HIT_LOWER_LEFT:
m_rc.left += pt.x - m_ptHit.x;
m_rc.bottom += pt.y - m_ptHit.y;
break;
case ACTION_RESIZE_BOTTOM: /* resize at bottom edge */
ptDeltaUsed.x = ptDelta.x;
ptDeltaUsed.y = max(ptDelta.y, -(RECT_HEIGHT(m_rcDest) - 1));
m_rcDest.bottom += ptDeltaUsed.y;
case HIT_LOWER_CENTER:
m_rc.bottom += pt.y - m_ptHit.y;
break;
case ACTION_RESIZE_BOTTOM_RIGHT: /* resize at lower right corner */
ptDeltaUsed.x = max(ptDelta.x, -(RECT_WIDTH(m_rcDest) - 1));
ptDeltaUsed.y = max(ptDelta.y, -(RECT_HEIGHT(m_rcDest) - 1));
m_rcDest.right += ptDeltaUsed.x;
m_rcDest.bottom += ptDeltaUsed.y;
case HIT_LOWER_RIGHT:
m_rc.right += pt.x - m_ptHit.x;
m_rc.bottom += pt.y - m_ptHit.y;
break;
case HIT_BORDER:
case HIT_INNER:
OffsetRect(&m_rc, pt.x - m_ptHit.x, pt.y - m_ptHit.y);
break;
}
ptDelta.x -= ptDeltaUsed.x;
ptDelta.y -= ptDeltaUsed.y;
}
LONG SelectionModel::GetDestRectWidth() const
{
return m_rcDest.right - m_rcDest.left;
}
LONG SelectionModel::GetDestRectHeight() const
{
return m_rcDest.bottom - m_rcDest.top;
}
LONG SelectionModel::GetDestRectLeft() const
{
return m_rcDest.left;
}
LONG SelectionModel::GetDestRectTop() const
{
return m_rcDest.top;
m_ptHit = pt;
}
void SelectionModel::NotifyRefreshNeeded()
{
selectionWindow.SendMessage(WM_SELECTIONMODELREFRESHNEEDED);
imageArea.Invalidate(FALSE);
}
void SelectionModel::GetRect(LPRECT prc) const
void SelectionModel::ClearMask()
{
*prc = m_rcDest;
if (m_hbmMask)
{
::DeleteObject(m_hbmMask);
m_hbmMask = NULL;
}
}
void SelectionModel::ClearColor()
{
if (m_hbmColor)
{
::DeleteObject(m_hbmColor);
m_hbmColor = NULL;
}
}
void SelectionModel::CancelSelection()
{
if (!m_bShow)
return;
imageModel.CopyPrevious();
if (m_bShow)
imageModel.Undo(TRUE);
m_bShow = FALSE;
imageArea.Invalidate(FALSE);
}

View file

@ -9,66 +9,54 @@
#pragma once
/* DEFINES **********************************************************/
#define ACTION_MOVE 0
#define ACTION_RESIZE_TOP_LEFT 1
#define ACTION_RESIZE_TOP 2
#define ACTION_RESIZE_TOP_RIGHT 3
#define ACTION_RESIZE_LEFT 4
#define ACTION_RESIZE_RIGHT 5
#define ACTION_RESIZE_BOTTOM_LEFT 6
#define ACTION_RESIZE_BOTTOM 7
#define ACTION_RESIZE_BOTTOM_RIGHT 8
/* CLASSES **********************************************************/
class SelectionModel
{
private:
HDC m_hDC;
RECT m_rcSrc;
RECT m_rcDest;
HBITMAP m_hBm;
HBITMAP m_hMask;
HBITMAP m_hbmColor;
HBITMAP m_hbmMask;
POINT *m_ptStack;
int m_iPtSP;
// void NotifySelectionChanging();
// void NotifySelectionChanged();
void NotifyRefreshNeeded();
public:
BOOL m_bShow;
CRect m_rc; // in image pixel coordinates
POINT m_ptHit; // in image pixel coordinates
SelectionModel();
~SelectionModel();
void ResetPtStack();
void PushToPtStack(LONG x, LONG y);
void CalculateBoundingBoxAndContents(HDC hDCImage);
void CalculateContents(HDC hDCImage);
void PushToPtStack(POINT pt);
int PtStackSize() const;
void SetRectFromPoints(const POINT& ptFrom, const POINT& ptTo);
void BuildMaskFromPtStack();
BOOL TakeOff();
void Landing();
HBITMAP GetBitmap() const;
void GetSelectionContents(HDC hDCImage);
void DrawFramePoly(HDC hDCImage);
void DrawBackgroundPoly(HDC hDCImage, COLORREF crBg);
void DrawBackgroundRect(HDC hDCImage, COLORREF crBg);
void DrawSelection(HDC hDCImage, COLORREF crBg = 0, BOOL bBgTransparent = FALSE);
void DrawSelectionStretched(HDC hDCImage);
void ScaleContentsToFit();
void DrawSelection(HDC hDCImage, LPCRECT prc, COLORREF crBg = 0, BOOL bBgTransparent = FALSE);
void InsertFromHBITMAP(HBITMAP hBm, INT x = 0, INT y = 0);
// operation
void FlipHorizontally();
void FlipVertically();
void RotateNTimes90Degrees(int iN);
void StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX = 0, int nSkewDegY = 0);
HBITMAP GetBitmap() const;
int PtStackSize() const;
void DrawFramePoly(HDC hDCImage);
void SetSrcAndDestRectFromPoints(const POINT& ptFrom, const POINT& ptTo);
void SetSrcRectSizeToZero();
BOOL IsSrcRectSizeNonzero() const;
void ModifyDestRect(POINT& ptDelta, int iAction);
LONG GetDestRectWidth() const;
LONG GetDestRectHeight() const;
LONG GetDestRectLeft() const;
LONG GetDestRectTop() const;
void GetRect(LPRECT prc) const;
void StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX, int nSkewDegY);
void CancelSelection();
void NotifyRefreshNeeded();
void Dragging(CANVAS_HITTEST hit, POINT pt);
void ClearMask();
void ClearColor();
private:
SelectionModel(const SelectionModel&);
SelectionModel& operator=(const SelectionModel&);
void ShiftPtStack(BOOL bPlus);
};

View file

@ -114,7 +114,7 @@ LRESULT CToolBox::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHand
LRESULT CToolBox::OnToolsModelToolChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
selectionWindow.ShowWindow(SW_HIDE);
selectionModel.m_bShow = FALSE;
toolsModel.resetTool(); // resets the point-buffer of the polygon and bezier functions
// Check the toolbar button

View file

@ -141,8 +141,8 @@ void ToolsModel::SetBackgroundTransparent(BOOL bTransparent)
{
m_transpBg = bTransparent;
NotifyToolSettingsChanged();
if (selectionWindow.IsWindow())
selectionWindow.ForceRefreshSelectionContents();
if (imageArea.IsWindow())
imageArea.Invalidate(FALSE);
}
int ToolsModel::GetZoom() const
@ -172,8 +172,6 @@ void ToolsModel::NotifyToolSettingsChanged()
{
if (toolSettingsWindow.IsWindow())
toolSettingsWindow.SendMessage(WM_TOOLSMODELSETTINGSCHANGED);
if (selectionWindow.IsWindow())
selectionWindow.SendMessage(WM_TOOLSMODELSETTINGSCHANGED);
if (textEditWindow.IsWindow())
textEditWindow.SendMessage(WM_TOOLSMODELSETTINGSCHANGED);
}
@ -184,8 +182,8 @@ void ToolsModel::NotifyZoomChanged()
toolSettingsWindow.SendMessage(WM_TOOLSMODELZOOMCHANGED);
if (textEditWindow.IsWindow())
textEditWindow.SendMessage(WM_TOOLSMODELZOOMCHANGED);
if (selectionWindow.IsWindow())
selectionWindow.SendMessage(WM_TOOLSMODELZOOMCHANGED);
if (imageArea.IsWindow())
imageArea.SendMessage(WM_TOOLSMODELZOOMCHANGED);
}
void ToolsModel::OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick)

View file

@ -132,3 +132,31 @@ static inline int UnZoomed(int xy)
{
return xy * 1000 / toolsModel.GetZoom();
}
static inline void Zoomed(POINT& pt)
{
pt.x = Zoomed(pt.x);
pt.y = Zoomed(pt.y);
}
static inline void Zoomed(RECT& rc)
{
rc.left = Zoomed(rc.left);
rc.top = Zoomed(rc.top);
rc.right = Zoomed(rc.right);
rc.bottom = Zoomed(rc.bottom);
}
static inline void UnZoomed(POINT& pt)
{
pt.x = UnZoomed(pt.x);
pt.y = UnZoomed(pt.y);
}
static inline void UnZoomed(RECT& rc)
{
rc.left = UnZoomed(rc.left);
rc.top = UnZoomed(rc.top);
rc.right = UnZoomed(rc.right);
rc.bottom = UnZoomed(rc.bottom);
}

View file

@ -182,11 +182,9 @@ void CMainWindow::InsertSelectionFromHBITMAP(HBITMAP bitmap, HWND window)
toolBoxContainer.SendMessage(WM_COMMAND, ID_RECTSEL);
imageModel.CopyPrevious();
selectionModel.InsertFromHBITMAP(bitmap);
placeSelWin();
selectionWindow.ShowWindow(SW_SHOW);
selectionWindow.ForceRefreshSelectionContents();
selectionModel.InsertFromHBITMAP(bitmap, 0, 0);
selectionModel.m_bShow = TRUE;
imageArea.Invalidate(FALSE);
}
LRESULT CMainWindow::OnMouseWheel(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
@ -279,9 +277,6 @@ LRESULT CMainWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHa
// Creating the window inside the canvas
imageArea.Create(canvasWindow, rcEmpty, NULL, WS_CHILD | WS_VISIBLE);
// Create selection window (initially hidden)
selectionWindow.Create(imageArea, rcEmpty, NULL, WS_CHILD | BS_OWNERDRAW);
// Create and show the miniature if necessary
if (registrySettings.ShowThumbnail)
{
@ -407,7 +402,7 @@ LRESULT CMainWindow::OnInitMenuPopup(UINT nMsg, WPARAM wParam, LPARAM lParam, BO
{
HMENU menu = (HMENU)wParam;
BOOL trueSelection =
(::IsWindowVisible(selectionWindow) &&
(selectionModel.m_bShow &&
((toolsModel.GetActiveTool() == TOOL_FREESEL) || (toolsModel.GetActiveTool() == TOOL_RECTSEL)));
switch (lParam)
@ -438,7 +433,7 @@ LRESULT CMainWindow::OnInitMenuPopup(UINT nMsg, WPARAM wParam, LPARAM lParam, BO
CheckMenuItem(menu, IDM_VIEWSHOWMINIATURE, CHECKED_IF(registrySettings.ShowThumbnail));
break;
case 3: /* Image menu */
EnableMenuItem(menu, IDM_IMAGECROP, ENABLED_IF(::IsWindowVisible(selectionWindow)));
EnableMenuItem(menu, IDM_IMAGECROP, ENABLED_IF(selectionModel.m_bShow));
CheckMenuItem(menu, IDM_IMAGEDRAWOPAQUE, CHECKED_IF(!toolsModel.IsBackgroundTransparent()));
break;
}
@ -484,7 +479,6 @@ LRESULT CMainWindow::OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
if (hwndCapture)
{
if (canvasWindow.m_hWnd == hwndCapture ||
selectionWindow.m_hWnd == hwndCapture ||
imageArea.m_hWnd == hwndCapture ||
fullscreenWindow.m_hWnd == hwndCapture)
{
@ -610,7 +604,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
case IDM_EDITUNDO:
if (toolsModel.GetActiveTool() == TOOL_TEXT && ::IsWindowVisible(textEditWindow))
break;
if (selectionWindow.IsWindowVisible())
if (selectionModel.m_bShow)
{
if (toolsModel.GetActiveTool() == TOOL_RECTSEL ||
toolsModel.GetActiveTool() == TOOL_FREESEL)
@ -736,31 +730,31 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
switch (mirrorRotateDialog.DoModal(mainWindow.m_hWnd))
{
case 1: /* flip horizontally */
if (::IsWindowVisible(selectionWindow))
if (selectionModel.m_bShow)
selectionModel.FlipHorizontally();
else
imageModel.FlipHorizontally();
break;
case 2: /* flip vertically */
if (::IsWindowVisible(selectionWindow))
if (selectionModel.m_bShow)
selectionModel.FlipVertically();
else
imageModel.FlipVertically();
break;
case 3: /* rotate 90 degrees */
if (::IsWindowVisible(selectionWindow))
if (selectionModel.m_bShow)
selectionModel.RotateNTimes90Degrees(1);
else
imageModel.RotateNTimes90Degrees(1);
break;
case 4: /* rotate 180 degrees */
if (::IsWindowVisible(selectionWindow))
if (selectionModel.m_bShow)
selectionModel.RotateNTimes90Degrees(2);
else
imageModel.RotateNTimes90Degrees(2);
break;
case 5: /* rotate 270 degrees */
if (::IsWindowVisible(selectionWindow))
if (selectionModel.m_bShow)
selectionModel.RotateNTimes90Degrees(3);
else
imageModel.RotateNTimes90Degrees(3);
@ -779,7 +773,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
{
if (stretchSkewDialog.DoModal(mainWindow.m_hWnd))
{
if (::IsWindowVisible(selectionWindow))
if (selectionModel.m_bShow)
{
selectionModel.StretchSkew(stretchSkewDialog.percentage.x, stretchSkewDialog.percentage.y,
stretchSkewDialog.angle.x, stretchSkewDialog.angle.y);