[MSPAINT] Establish Undo/Redo management (#5347)

- Painting the canvas is done by overlaying the multiple layers.
- Drawing each overlay is implemented as polymorphism of OOP.
- Refine the Undo/Redo mechanism.
- Some adjustments.
CORE-17969
This commit is contained in:
Katayama Hirofumi MZ 2023-06-17 21:15:35 +09:00 committed by GitHub
parent b7071f67a8
commit e8c7e30030
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 721 additions and 504 deletions

View file

@ -17,15 +17,17 @@ CCanvasWindow::CCanvasWindow()
, m_hitSelection(HIT_NONE) , m_hitSelection(HIT_NONE)
, m_whereHit(HIT_NONE) , m_whereHit(HIT_NONE)
, m_ptOrig { -1, -1 } , m_ptOrig { -1, -1 }
, m_hbmCached(NULL)
{ {
m_ahbmCached[0] = m_ahbmCached[1] = NULL;
::SetRectEmpty(&m_rcNew); ::SetRectEmpty(&m_rcNew);
} }
CCanvasWindow::~CCanvasWindow() CCanvasWindow::~CCanvasWindow()
{ {
if (m_hbmCached) if (m_ahbmCached[0])
::DeleteObject(m_hbmCached); ::DeleteObject(m_ahbmCached[0]);
if (m_ahbmCached[1])
::DeleteObject(m_ahbmCached[1]);
} }
VOID CCanvasWindow::drawZoomFrame(INT mouseX, INT mouseY) VOID CCanvasWindow::drawZoomFrame(INT mouseX, INT mouseY)
@ -101,78 +103,80 @@ CANVAS_HITTEST CCanvasWindow::CanvasHitTest(POINT pt)
VOID CCanvasWindow::DoDraw(HDC hDC, RECT& rcClient, RECT& rcPaint) VOID CCanvasWindow::DoDraw(HDC hDC, RECT& rcClient, RECT& rcPaint)
{ {
// We use a memory bitmap to reduce flickering // We use a memory bitmap to reduce flickering
HDC hdcMem = ::CreateCompatibleDC(hDC); HDC hdcMem0 = ::CreateCompatibleDC(hDC);
m_hbmCached = CachedBufferDIB(m_hbmCached, rcClient.right, rcClient.bottom); m_ahbmCached[0] = CachedBufferDIB(m_ahbmCached[0], rcClient.right, rcClient.bottom);
HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_hbmCached); HGDIOBJ hbm0Old = ::SelectObject(hdcMem0, m_ahbmCached[0]);
// Fill the background // Fill the background on hdcMem0
::FillRect(hdcMem, &rcPaint, (HBRUSH)(COLOR_APPWORKSPACE + 1)); ::FillRect(hdcMem0, &rcPaint, (HBRUSH)(COLOR_APPWORKSPACE + 1));
// Draw the sizeboxes if necessary // Draw the sizeboxes if necessary
RECT rcBase = GetBaseRect(); RECT rcBase = GetBaseRect();
if (!selectionModel.m_bShow) if (!selectionModel.m_bShow)
drawSizeBoxes(hdcMem, &rcBase, FALSE, &rcPaint); drawSizeBoxes(hdcMem0, &rcBase, FALSE, &rcPaint);
// Draw the image // Calculate image size
CRect rcImage; CRect rcImage;
GetImageRect(rcImage); GetImageRect(rcImage);
ImageToCanvas(rcImage);
SIZE sizeImage = { imageModel.GetWidth(), imageModel.GetHeight() }; SIZE sizeImage = { imageModel.GetWidth(), imageModel.GetHeight() };
StretchBlt(hdcMem, rcImage.left, rcImage.top, rcImage.Width(), rcImage.Height(),
imageModel.GetDC(), 0, 0, sizeImage.cx, sizeImage.cy, SRCCOPY);
// Draw the grid // hdcMem1 <-- imageModel
if (showGrid && toolsModel.GetZoom() >= 4000) HDC hdcMem1 = ::CreateCompatibleDC(hDC);
m_ahbmCached[1] = CachedBufferDIB(m_ahbmCached[1], sizeImage.cx, sizeImage.cy);
HGDIOBJ hbm1Old = ::SelectObject(hdcMem1, m_ahbmCached[1]);
BitBlt(hdcMem1, 0, 0, sizeImage.cx, sizeImage.cy, imageModel.GetDC(), 0, 0, SRCCOPY);
// Draw overlay #1 on hdcMem1
toolsModel.OnDrawOverlayOnImage(hdcMem1);
// Transfer the bits with stretch (hdcMem0 <-- hdcMem1)
ImageToCanvas(rcImage);
::StretchBlt(hdcMem0, rcImage.left, rcImage.top, rcImage.Width(), rcImage.Height(),
hdcMem1, 0, 0, sizeImage.cx, sizeImage.cy, SRCCOPY);
// Clean up hdcMem1
::SelectObject(hdcMem1, hbm1Old);
::DeleteDC(hdcMem1);
// Draw the grid on hdcMem0
if (g_showGrid && toolsModel.GetZoom() >= 4000)
{ {
HPEN oldPen = (HPEN) SelectObject(hdcMem, CreatePen(PS_SOLID, 1, RGB(160, 160, 160))); HPEN oldPen = (HPEN) ::SelectObject(hdcMem0, ::CreatePen(PS_SOLID, 1, RGB(160, 160, 160)));
for (INT counter = 0; counter < sizeImage.cy; counter++) for (INT counter = 0; counter < sizeImage.cy; counter++)
{ {
POINT pt0 = { 0, counter }, pt1 = { sizeImage.cx, counter }; POINT pt0 = { 0, counter }, pt1 = { sizeImage.cx, counter };
ImageToCanvas(pt0); ImageToCanvas(pt0);
ImageToCanvas(pt1); ImageToCanvas(pt1);
::MoveToEx(hdcMem, pt0.x, pt0.y, NULL); ::MoveToEx(hdcMem0, pt0.x, pt0.y, NULL);
::LineTo(hdcMem, pt1.x, pt1.y); ::LineTo(hdcMem0, pt1.x, pt1.y);
} }
for (INT counter = 0; counter < sizeImage.cx; counter++) for (INT counter = 0; counter < sizeImage.cx; counter++)
{ {
POINT pt0 = { counter, 0 }, pt1 = { counter, sizeImage.cy }; POINT pt0 = { counter, 0 }, pt1 = { counter, sizeImage.cy };
ImageToCanvas(pt0); ImageToCanvas(pt0);
ImageToCanvas(pt1); ImageToCanvas(pt1);
::MoveToEx(hdcMem, pt0.x, pt0.y, NULL); ::MoveToEx(hdcMem0, pt0.x, pt0.y, NULL);
::LineTo(hdcMem, pt1.x, pt1.y); ::LineTo(hdcMem0, pt1.x, pt1.y);
} }
::DeleteObject(::SelectObject(hdcMem, oldPen)); ::DeleteObject(::SelectObject(hdcMem0, oldPen));
} }
// Draw selection // Draw overlay #2 on hdcMem0
if (selectionModel.m_bShow) toolsModel.OnDrawOverlayOnCanvas(hdcMem0);
{
RECT rcSelection = selectionModel.m_rc;
ImageToCanvas(rcSelection);
::InflateRect(&rcSelection, GRIP_SIZE, GRIP_SIZE); // Draw new frame on hdcMem0 if any
drawSizeBoxes(hdcMem, &rcSelection, TRUE, &rcPaint);
::InflateRect(&rcSelection, -GRIP_SIZE, -GRIP_SIZE);
INT iSaveDC = ::SaveDC(hdcMem);
::IntersectClipRect(hdcMem, rcImage.left, rcImage.top, rcImage.right, rcImage.bottom);
selectionModel.DrawSelection(hdcMem, &rcSelection, paletteModel.GetBgColor(),
toolsModel.IsBackgroundTransparent());
::RestoreDC(hdcMem, iSaveDC);
}
// Draw new frame if any
if (m_whereHit != HIT_NONE && !::IsRectEmpty(&m_rcNew)) if (m_whereHit != HIT_NONE && !::IsRectEmpty(&m_rcNew))
DrawXorRect(hdcMem, &m_rcNew); DrawXorRect(hdcMem0, &m_rcNew);
// Transfer the bits // Transfer the bits (hDC <-- hdcMem0)
::BitBlt(hDC, ::BitBlt(hDC,
rcPaint.left, rcPaint.top, rcPaint.left, rcPaint.top,
rcPaint.right - rcPaint.left, rcPaint.bottom - rcPaint.top, rcPaint.right - rcPaint.left, rcPaint.bottom - rcPaint.top,
hdcMem, rcPaint.left, rcPaint.top, SRCCOPY); hdcMem0, rcPaint.left, rcPaint.top, SRCCOPY);
::SelectObject(hdcMem, hbmOld); // Clean up hdcMem0
::DeleteDC(hdcMem); ::SelectObject(hdcMem0, hbm0Old);
::DeleteDC(hdcMem0);
} }
VOID CCanvasWindow::Update(HWND hwndFrom) VOID CCanvasWindow::Update(HWND hwndFrom)
@ -383,15 +387,15 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
{ {
CString strCoord; CString strCoord;
strCoord.Format(_T("%ld, %ld"), pt.x, pt.y); strCoord.Format(_T("%ld, %ld"), pt.x, pt.y);
SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) strCoord); ::SendMessage(g_hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) strCoord);
} }
} }
if (m_drawing) if (m_drawing)
{ {
// values displayed in statusbar // values displayed in statusbar
LONG xRel = pt.x - start.x; LONG xRel = pt.x - g_ptStart.x;
LONG yRel = pt.y - start.y; LONG yRel = pt.y - g_ptStart.y;
switch (toolsModel.GetActiveTool()) switch (toolsModel.GetActiveTool())
{ {
@ -400,13 +404,13 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
case TOOL_RECTSEL: case TOOL_RECTSEL:
case TOOL_TEXT: case TOOL_TEXT:
if (xRel < 0) if (xRel < 0)
xRel = (pt.x < 0) ? -start.x : xRel; xRel = (pt.x < 0) ? -g_ptStart.x : xRel;
else if (pt.x > imageModel.GetWidth()) else if (pt.x > imageModel.GetWidth())
xRel = imageModel.GetWidth() - start.x; xRel = imageModel.GetWidth() - g_ptStart.x;
if (yRel < 0) if (yRel < 0)
yRel = (pt.y < 0) ? -start.y : yRel; yRel = (pt.y < 0) ? -g_ptStart.y : yRel;
else if (pt.y > imageModel.GetHeight()) else if (pt.y > imageModel.GetHeight())
yRel = imageModel.GetHeight() - start.y; yRel = imageModel.GetHeight() - g_ptStart.y;
break; break;
// while drawing, update cursor coordinates only for tools 3, 7, 8, 9, 14 // while drawing, update cursor coordinates only for tools 3, 7, 8, 9, 14
@ -418,7 +422,7 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
{ {
CString strCoord; CString strCoord;
strCoord.Format(_T("%ld, %ld"), pt.x, pt.y); strCoord.Format(_T("%ld, %ld"), pt.x, pt.y);
SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) strCoord); ::SendMessage(g_hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) strCoord);
break; break;
} }
default: default:
@ -444,7 +448,7 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
if ((toolsModel.GetActiveTool() >= TOOL_LINE) && (GetAsyncKeyState(VK_SHIFT) < 0)) if ((toolsModel.GetActiveTool() >= TOOL_LINE) && (GetAsyncKeyState(VK_SHIFT) < 0))
yRel = xRel; yRel = xRel;
strSize.Format(_T("%ld x %ld"), xRel, yRel); strSize.Format(_T("%ld x %ld"), xRel, yRel);
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize); ::SendMessage(g_hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize);
} }
} }
@ -458,7 +462,7 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
if ((toolsModel.GetActiveTool() >= TOOL_LINE) && (GetAsyncKeyState(VK_SHIFT) < 0)) if ((toolsModel.GetActiveTool() >= TOOL_LINE) && (GetAsyncKeyState(VK_SHIFT) < 0))
yRel = xRel; yRel = xRel;
strSize.Format(_T("%ld x %ld"), xRel, yRel); strSize.Format(_T("%ld x %ld"), xRel, yRel);
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize); ::SendMessage(g_hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize);
} }
} }
return 0; return 0;
@ -514,7 +518,7 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
// Display new size // Display new size
CString strSize; CString strSize;
strSize.Format(_T("%d x %d"), cxImage, cyImage); strSize.Format(_T("%d x %d"), cxImage, cyImage);
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize); ::SendMessage(g_hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize);
CRect rc = { 0, 0, cxImage, cyImage }; CRect rc = { 0, 0, cxImage, cyImage };
switch (m_whereHit) switch (m_whereHit)
@ -556,7 +560,7 @@ LRESULT CCanvasWindow::OnLRButtonUp(BOOL bLeftButton, UINT nMsg, WPARAM wParam,
m_drawing = FALSE; m_drawing = FALSE;
toolsModel.OnButtonUp(bLeftButton, pt.x, pt.y); toolsModel.OnButtonUp(bLeftButton, pt.x, pt.y);
Invalidate(FALSE); Invalidate(FALSE);
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) ""); ::SendMessage(g_hStatusBar, SB_SETTEXT, 2, (LPARAM)_T(""));
return 0; return 0;
} }
else if (m_hitSelection != HIT_NONE && bLeftButton) else if (m_hitSelection != HIT_NONE && bLeftButton)
@ -603,7 +607,7 @@ LRESULT CCanvasWindow::OnLRButtonUp(BOOL bLeftButton, UINT nMsg, WPARAM wParam,
} }
::SetRectEmpty(&m_rcNew); ::SetRectEmpty(&m_rcNew);
imageSaved = FALSE; g_imageSaved = FALSE;
m_whereHit = HIT_NONE; m_whereHit = HIT_NONE;
toolsModel.resetTool(); // resets the point-buffer of the polygon and bezier functions toolsModel.resetTool(); // resets the point-buffer of the polygon and bezier functions
@ -654,19 +658,19 @@ LRESULT CCanvasWindow::OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
switch (toolsModel.GetActiveTool()) switch (toolsModel.GetActiveTool())
{ {
case TOOL_FILL: case TOOL_FILL:
::SetCursor(::LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_FILL))); ::SetCursor(::LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDC_FILL)));
break; break;
case TOOL_COLOR: case TOOL_COLOR:
::SetCursor(::LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_COLOR))); ::SetCursor(::LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDC_COLOR)));
break; break;
case TOOL_ZOOM: case TOOL_ZOOM:
::SetCursor(::LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_ZOOM))); ::SetCursor(::LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDC_ZOOM)));
break; break;
case TOOL_PEN: case TOOL_PEN:
::SetCursor(::LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_PEN))); ::SetCursor(::LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDC_PEN)));
break; break;
case TOOL_AIRBRUSH: case TOOL_AIRBRUSH:
::SetCursor(::LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_AIRBRUSH))); ::SetCursor(::LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDC_AIRBRUSH)));
break; break;
default: default:
::SetCursor(::LoadCursor(NULL, IDC_CROSS)); ::SetCursor(::LoadCursor(NULL, IDC_CROSS));
@ -710,7 +714,7 @@ LRESULT CCanvasWindow::OnMouseWheel(UINT nMsg, WPARAM wParam, LPARAM lParam, BOO
LRESULT CCanvasWindow::OnCaptureChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) LRESULT CCanvasWindow::OnCaptureChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{ {
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM)_T("")); ::SendMessage(g_hStatusBar, SB_SETTEXT, 2, (LPARAM)_T(""));
return 0; return 0;
} }
@ -800,3 +804,9 @@ LRESULT CCanvasWindow::OnCtlColorEdit(UINT nMsg, WPARAM wParam, LPARAM lParam, B
SetBkMode((HDC)wParam, TRANSPARENT); SetBkMode((HDC)wParam, TRANSPARENT);
return (LRESULT)GetStockObject(NULL_BRUSH); return (LRESULT)GetStockObject(NULL_BRUSH);
} }
LRESULT CCanvasWindow::OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
imageModel.NotifyImageChanged();
return 0;
}

View file

@ -33,6 +33,7 @@ public:
MESSAGE_HANDLER(WM_CANCELMODE, OnCancelMode) MESSAGE_HANDLER(WM_CANCELMODE, OnCancelMode)
MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
MESSAGE_HANDLER(WM_CTLCOLOREDIT, OnCtlColorEdit) MESSAGE_HANDLER(WM_CTLCOLOREDIT, OnCtlColorEdit)
MESSAGE_HANDLER(WM_PALETTEMODELCOLORCHANGED, OnPaletteModelColorChanged)
END_MSG_MAP() END_MSG_MAP()
CCanvasWindow(); CCanvasWindow();
@ -55,7 +56,7 @@ protected:
CANVAS_HITTEST m_hitSelection; CANVAS_HITTEST m_hitSelection;
CANVAS_HITTEST m_whereHit; CANVAS_HITTEST m_whereHit;
POINT m_ptOrig; // The origin of drag start POINT m_ptOrig; // The origin of drag start
HBITMAP m_hbmCached; // The cached buffer bitmap HBITMAP m_ahbmCached[2]; // The cached buffer bitmaps
CRect m_rcNew; CRect m_rcNew;
CANVAS_HITTEST CanvasHitTest(POINT pt); CANVAS_HITTEST CanvasHitTest(POINT pt);
@ -87,6 +88,7 @@ protected:
LRESULT OnCancelMode(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnCancelMode(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnCaptureChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnCaptureChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnCtlColorEdit(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnCtlColorEdit(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnLRButtonDown(BOOL bLeftButton, UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnLRButtonDown(BOOL bLeftButton, UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnLRButtonDblClk(BOOL bLeftButton, UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnLRButtonDblClk(BOOL bLeftButton, UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

View file

@ -20,7 +20,6 @@
#define WM_TOOLSMODELSETTINGSCHANGED (WM_APP + 1) #define WM_TOOLSMODELSETTINGSCHANGED (WM_APP + 1)
#define WM_TOOLSMODELZOOMCHANGED (WM_APP + 2) #define WM_TOOLSMODELZOOMCHANGED (WM_APP + 2)
#define WM_PALETTEMODELCOLORCHANGED (WM_APP + 3) #define WM_PALETTEMODELCOLORCHANGED (WM_APP + 3)
#define WM_PALETTEMODELPALETTECHANGED (WM_APP + 4)
/* this simplifies checking and unchecking menu items */ /* this simplifies checking and unchecking menu items */
#define CHECKED_IF(a) ((a) ? (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND)) #define CHECKED_IF(a) ((a) ? (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND))

View file

@ -83,16 +83,16 @@ LRESULT CAttributesDialog::OnInitDialog(UINT nMsg, WPARAM wParam, LPARAM lParam,
SetDlgItemInt(IDD_ATTRIBUTESEDIT1, newWidth, FALSE); SetDlgItemInt(IDD_ATTRIBUTESEDIT1, newWidth, FALSE);
SetDlgItemInt(IDD_ATTRIBUTESEDIT2, newHeight, FALSE); SetDlgItemInt(IDD_ATTRIBUTESEDIT2, newHeight, FALSE);
if (isAFile) if (g_isAFile)
{ {
TCHAR date[100]; TCHAR date[100];
TCHAR temp[100]; TCHAR temp[100];
GetDateFormat(LOCALE_USER_DEFAULT, 0, &fileTime, NULL, date, _countof(date)); GetDateFormat(LOCALE_USER_DEFAULT, 0, &g_fileTime, NULL, date, _countof(date));
GetTimeFormat(LOCALE_USER_DEFAULT, 0, &fileTime, NULL, temp, _countof(temp)); GetTimeFormat(LOCALE_USER_DEFAULT, 0, &g_fileTime, NULL, temp, _countof(temp));
_tcscat(date, _T(" ")); _tcscat(date, _T(" "));
_tcscat(date, temp); _tcscat(date, temp);
CString strSize; CString strSize;
strSize.Format(IDS_FILESIZE, fileSize); strSize.Format(IDS_FILESIZE, g_fileSize);
SetDlgItemText(IDD_ATTRIBUTESTEXT6, date); SetDlgItemText(IDD_ATTRIBUTESTEXT6, date);
SetDlgItemText(IDD_ATTRIBUTESTEXT7, strSize); SetDlgItemText(IDD_ATTRIBUTESTEXT7, strSize);
} }
@ -240,9 +240,9 @@ LRESULT CStretchSkewDialog::OnOk(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&
CString strrcAngle; CString strrcAngle;
BOOL tr1, tr2, tr3, tr4; BOOL tr1, tr2, tr3, tr4;
strrcIntNumbers.LoadString(hProgInstance, IDS_INTNUMBERS); strrcIntNumbers.LoadString(g_hinstExe, IDS_INTNUMBERS);
strrcPercentage.LoadString(hProgInstance, IDS_PERCENTAGE); strrcPercentage.LoadString(g_hinstExe, IDS_PERCENTAGE);
strrcAngle.LoadString(hProgInstance, IDS_ANGLE); strrcAngle.LoadString(g_hinstExe, IDS_ANGLE);
percentage.x = GetDlgItemInt(IDD_STRETCHSKEWEDITHSTRETCH, &tr1, FALSE); percentage.x = GetDlgItemInt(IDD_STRETCHSKEWEDITHSTRETCH, &tr1, FALSE);
percentage.y = GetDlgItemInt(IDD_STRETCHSKEWEDITVSTRETCH, &tr2, FALSE); percentage.y = GetDlgItemInt(IDD_STRETCHSKEWEDITVSTRETCH, &tr2, FALSE);
@ -347,11 +347,11 @@ void CFontsDialog::InitToolbar()
SendMessage(hwndToolbar, TB_SETBUTTONWIDTH, 0, MAKELPARAM(20, 20)); SendMessage(hwndToolbar, TB_SETBUTTONWIDTH, 0, MAKELPARAM(20, 20));
TBADDBITMAP AddBitmap; TBADDBITMAP AddBitmap;
AddBitmap.hInst = hProgInstance; AddBitmap.hInst = g_hinstExe;
AddBitmap.nID = IDB_FONTSTOOLBAR; AddBitmap.nID = IDB_FONTSTOOLBAR;
SendMessage(hwndToolbar, TB_ADDBITMAP, 4, (LPARAM)&AddBitmap); SendMessage(hwndToolbar, TB_ADDBITMAP, 4, (LPARAM)&AddBitmap);
HIMAGELIST himl = ImageList_LoadImage(hProgInstance, MAKEINTRESOURCE(IDB_FONTSTOOLBAR), HIMAGELIST himl = ImageList_LoadImage(g_hinstExe, MAKEINTRESOURCE(IDB_FONTSTOOLBAR),
16, 8, RGB(255, 0, 255), IMAGE_BITMAP, 16, 8, RGB(255, 0, 255), IMAGE_BITMAP,
LR_CREATEDIBSECTION); LR_CREATEDIBSECTION);
SendMessage(hwndToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl); SendMessage(hwndToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl);
@ -511,7 +511,7 @@ LRESULT CFontsDialog::OnNotify(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
if (pnmhdr->code == TTN_NEEDTEXT) if (pnmhdr->code == TTN_NEEDTEXT)
{ {
LPTOOLTIPTEXT pToolTip = reinterpret_cast<LPTOOLTIPTEXT>(lParam); LPTOOLTIPTEXT pToolTip = reinterpret_cast<LPTOOLTIPTEXT>(lParam);
pToolTip->hinst = hProgInstance; pToolTip->hinst = g_hinstExe;
switch (pnmhdr->idFrom) switch (pnmhdr->idFrom)
{ {
case IDM_BOLD: pToolTip->lpszText = MAKEINTRESOURCE(IDS_BOLD); break; case IDM_BOLD: pToolTip->lpszText = MAKEINTRESOURCE(IDS_BOLD); break;

View file

@ -9,10 +9,10 @@
#include "precomp.h" #include "precomp.h"
#include <math.h> #include <math.h>
INT fileSize = 0; INT g_fileSize = 0;
float g_xDpi = 96; float g_xDpi = 96;
float g_yDpi = 96; float g_yDpi = 96;
SYSTEMTIME fileTime; SYSTEMTIME g_fileTime;
/* FUNCTIONS ********************************************************/ /* FUNCTIONS ********************************************************/
@ -114,15 +114,15 @@ BOOL SaveDIBToFile(HBITMAP hBitmap, LPCTSTR FileName, HDC hDC)
// update time and size // update time and size
FILETIME ft; FILETIME ft;
FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft); FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft);
FileTimeToSystemTime(&ft, &fileTime); FileTimeToSystemTime(&ft, &g_fileTime);
fileSize = find.nFileSizeLow; g_fileSize = find.nFileSizeLow;
// TODO: update hRes and vRes // TODO: update hRes and vRes
registrySettings.SetMostRecentFile(FileName); registrySettings.SetMostRecentFile(FileName);
isAFile = TRUE; g_isAFile = TRUE;
imageSaved = TRUE; g_imageSaved = TRUE;
return TRUE; return TRUE;
} }
@ -150,33 +150,33 @@ HBITMAP SetBitmapAndInfo(HBITMAP hBitmap, LPCTSTR name, DWORD dwFileSize, BOOL i
g_yDpi = GetDeviceCaps(hScreenDC, LOGPIXELSY); g_yDpi = GetDeviceCaps(hScreenDC, LOGPIXELSY);
ReleaseDC(NULL, hScreenDC); ReleaseDC(NULL, hScreenDC);
ZeroMemory(&fileTime, sizeof(fileTime)); ZeroMemory(&g_fileTime, sizeof(g_fileTime));
} }
// update image // update image
imageModel.PushImageForUndo(hBitmap); imageModel.PushImageForUndo(hBitmap);
imageModel.ClearHistory(); imageModel.ClearHistory();
// update fileSize // update g_fileSize
fileSize = dwFileSize; g_fileSize = dwFileSize;
// update filepathname // update g_szFileName
if (name && name[0]) if (name && name[0])
GetFullPathName(name, _countof(filepathname), filepathname, NULL); GetFullPathName(name, _countof(g_szFileName), g_szFileName, NULL);
else else
LoadString(hProgInstance, IDS_DEFAULTFILENAME, filepathname, _countof(filepathname)); LoadString(g_hinstExe, IDS_DEFAULTFILENAME, g_szFileName, _countof(g_szFileName));
// set title // set title
CString strTitle; CString strTitle;
strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(filepathname)); strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(g_szFileName));
mainWindow.SetWindowText(strTitle); mainWindow.SetWindowText(strTitle);
// update file info and recent // update file info and recent
isAFile = isFile; g_isAFile = isFile;
if (isAFile) if (g_isAFile)
registrySettings.SetMostRecentFile(filepathname); registrySettings.SetMostRecentFile(g_szFileName);
imageSaved = TRUE; g_imageSaved = TRUE;
return hBitmap; return hBitmap;
} }
@ -204,7 +204,7 @@ HBITMAP DoLoadImageFile(HWND hwnd, LPCTSTR name, BOOL fIsMainFile)
{ {
FILETIME ft; FILETIME ft;
FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft); FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft);
FileTimeToSystemTime(&ft, &fileTime); FileTimeToSystemTime(&ft, &g_fileTime);
return SetBitmapAndInfo(NULL, name, dwFileSize, TRUE); return SetBitmapAndInfo(NULL, name, dwFileSize, TRUE);
} }
} }
@ -233,7 +233,7 @@ HBITMAP DoLoadImageFile(HWND hwnd, LPCTSTR name, BOOL fIsMainFile)
{ {
FILETIME ft; FILETIME ft;
FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft); FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft);
FileTimeToSystemTime(&ft, &fileTime); FileTimeToSystemTime(&ft, &g_fileTime);
SetBitmapAndInfo(hBitmap, name, dwFileSize, TRUE); SetBitmapAndInfo(hBitmap, name, dwFileSize, TRUE);
} }

View file

@ -158,7 +158,7 @@ Airbrush(HDC hdc, LONG x, LONG y, COLORREF color, LONG r)
{ {
for (LONG dx = -r; dx <= r; dx++) for (LONG dx = -r; dx <= r; dx++)
{ {
if ((dx * dx + dy * dy <= r * r) && (rand() % 4 == 0)) if ((dx * dx + dy * dy <= r * r) && (rand() % r == 0))
::SetPixelV(hdc, x + dx, y + dy, color); ::SetPixelV(hdc, x + dx, y + dy, color);
} }
} }

View file

@ -23,8 +23,8 @@ HWND CFullscreenWindow::DoCreate()
LRESULT CFullscreenWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) LRESULT CFullscreenWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{ {
SendMessage(WM_SETICON, ICON_BIG, (LPARAM) LoadIcon(hProgInstance, MAKEINTRESOURCE(IDI_APPICON))); SendMessage(WM_SETICON, ICON_BIG, (LPARAM) LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDI_APPICON)));
SendMessage(WM_SETICON, ICON_SMALL, (LPARAM) LoadIcon(hProgInstance, MAKEINTRESOURCE(IDI_APPICON))); SendMessage(WM_SETICON, ICON_SMALL, (LPARAM) LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDI_APPICON)));
return 0; return 0;
} }

View file

@ -10,18 +10,16 @@
/* VARIABLES declared in main.cpp ***********************************/ /* VARIABLES declared in main.cpp ***********************************/
extern BOOL askBeforeEnlarging; extern BOOL g_askBeforeEnlarging;
extern POINT start; extern POINT g_ptStart, g_ptEnd;
extern POINT last;
extern HINSTANCE hProgInstance; extern HINSTANCE g_hinstExe;
extern TCHAR filepathname[MAX_LONG_PATH]; extern TCHAR g_szFileName[MAX_LONG_PATH];
extern BOOL isAFile; extern BOOL g_isAFile;
extern BOOL imageSaved; extern BOOL g_imageSaved;
extern BOOL g_showGrid;
extern BOOL showGrid;
extern CMainWindow mainWindow; extern CMainWindow mainWindow;
@ -40,11 +38,11 @@ extern ToolsModel toolsModel;
extern SelectionModel selectionModel; extern SelectionModel selectionModel;
extern PaletteModel paletteModel; extern PaletteModel paletteModel;
extern HWND hStatusBar; extern HWND g_hStatusBar;
extern float g_xDpi; extern float g_xDpi;
extern float g_yDpi; extern float g_yDpi;
extern INT fileSize; extern INT g_fileSize;
extern SYSTEMTIME fileTime; extern SYSTEMTIME g_fileTime;
extern CFullscreenWindow fullscreenWindow; extern CFullscreenWindow fullscreenWindow;
extern CMiniatureWindow miniature; extern CMiniatureWindow miniature;

View file

@ -22,103 +22,103 @@ void ImageModel::NotifyImageChanged()
} }
ImageModel::ImageModel() ImageModel::ImageModel()
: hDrawingDC(::CreateCompatibleDC(NULL)) : m_hDrawingDC(::CreateCompatibleDC(NULL))
, currInd(0) , m_currInd(0)
, undoSteps(0) , m_undoSteps(0)
, redoSteps(0) , m_redoSteps(0)
{ {
ZeroMemory(hBms, sizeof(hBms)); ZeroMemory(m_hBms, sizeof(m_hBms));
hBms[0] = CreateDIBWithProperties(1, 1); m_hBms[0] = CreateColorDIB(1, 1, RGB(255, 255, 255));
::SelectObject(hDrawingDC, hBms[0]); m_hbmOld = ::SelectObject(m_hDrawingDC, m_hBms[0]);
imageSaved = TRUE; g_imageSaved = TRUE;
} }
ImageModel::~ImageModel() ImageModel::~ImageModel()
{ {
::DeleteDC(hDrawingDC); ::DeleteDC(m_hDrawingDC);
for (size_t i = 0; i < HISTORYSIZE; ++i) for (size_t i = 0; i < HISTORYSIZE; ++i)
{ {
if (hBms[i]) if (m_hBms[i])
::DeleteObject(hBms[i]); ::DeleteObject(m_hBms[i]);
} }
} }
void ImageModel::Undo(BOOL bClearRedo) void ImageModel::Undo(BOOL bClearRedo)
{ {
ATLTRACE("%s: %d\n", __FUNCTION__, undoSteps); ATLTRACE("%s: %d\n", __FUNCTION__, m_undoSteps);
if (!CanUndo()) if (!CanUndo())
return; return;
selectionModel.m_bShow = FALSE; selectionModel.HideSelection();
// Select previous item // Select previous item
currInd = (currInd + HISTORYSIZE - 1) % HISTORYSIZE; m_currInd = (m_currInd + HISTORYSIZE - 1) % HISTORYSIZE;
::SelectObject(hDrawingDC, hBms[currInd]); ::SelectObject(m_hDrawingDC, m_hBms[m_currInd]);
undoSteps--; m_undoSteps--;
if (bClearRedo) if (bClearRedo)
redoSteps = 0; m_redoSteps = 0;
else if (redoSteps < HISTORYSIZE - 1) else if (m_redoSteps < HISTORYSIZE - 1)
redoSteps++; m_redoSteps++;
NotifyImageChanged(); NotifyImageChanged();
} }
void ImageModel::Redo() void ImageModel::Redo()
{ {
ATLTRACE("%s: %d\n", __FUNCTION__, redoSteps); ATLTRACE("%s: %d\n", __FUNCTION__, m_redoSteps);
if (!CanRedo()) if (!CanRedo())
return; return;
selectionModel.m_bShow = FALSE; selectionModel.HideSelection();
// Select next item // Select next item
currInd = (currInd + 1) % HISTORYSIZE; m_currInd = (m_currInd + 1) % HISTORYSIZE;
::SelectObject(hDrawingDC, hBms[currInd]); ::SelectObject(m_hDrawingDC, m_hBms[m_currInd]);
redoSteps--; m_redoSteps--;
if (undoSteps < HISTORYSIZE - 1) if (m_undoSteps < HISTORYSIZE - 1)
undoSteps++; m_undoSteps++;
NotifyImageChanged(); NotifyImageChanged();
} }
void ImageModel::ResetToPrevious() void ImageModel::ResetToPrevious()
{ {
ATLTRACE("%s: %d\n", __FUNCTION__, currInd); ATLTRACE("%s: %d\n", __FUNCTION__, m_currInd);
// Revert current item with previous item // Revert current item with previous item
::DeleteObject(hBms[currInd]); ::DeleteObject(m_hBms[m_currInd]);
hBms[currInd] = CopyDIBImage(hBms[(currInd + HISTORYSIZE - 1) % HISTORYSIZE]); m_hBms[m_currInd] = CopyDIBImage(m_hBms[(m_currInd + HISTORYSIZE - 1) % HISTORYSIZE]);
::SelectObject(hDrawingDC, hBms[currInd]); ::SelectObject(m_hDrawingDC, m_hBms[m_currInd]);
NotifyImageChanged(); NotifyImageChanged();
} }
void ImageModel::ClearHistory() void ImageModel::ClearHistory()
{ {
undoSteps = 0; m_undoSteps = 0;
redoSteps = 0; m_redoSteps = 0;
} }
void ImageModel::PushImageForUndo(HBITMAP hbm) void ImageModel::PushImageForUndo(HBITMAP hbm)
{ {
ATLTRACE("%s: %d\n", __FUNCTION__, currInd); ATLTRACE("%s: %d\n", __FUNCTION__, m_currInd);
// Go to the next item with an HBITMAP or current item // Go to the next item with an HBITMAP or current item
::DeleteObject(hBms[(currInd + 1) % HISTORYSIZE]); ::DeleteObject(m_hBms[(m_currInd + 1) % HISTORYSIZE]);
hBms[(currInd + 1) % HISTORYSIZE] = (hbm ? hbm : CopyDIBImage(hBms[currInd])); m_hBms[(m_currInd + 1) % HISTORYSIZE] = (hbm ? hbm : CopyDIBImage(m_hBms[m_currInd]));
currInd = (currInd + 1) % HISTORYSIZE; m_currInd = (m_currInd + 1) % HISTORYSIZE;
::SelectObject(hDrawingDC, hBms[currInd]); ::SelectObject(m_hDrawingDC, m_hBms[m_currInd]);
if (undoSteps < HISTORYSIZE - 1) if (m_undoSteps < HISTORYSIZE - 1)
undoSteps++; m_undoSteps++;
redoSteps = 0; m_redoSteps = 0;
imageSaved = FALSE; g_imageSaved = FALSE;
NotifyImageChanged(); NotifyImageChanged();
} }
@ -136,7 +136,7 @@ void ImageModel::Crop(int nWidth, int nHeight, int nOffsetX, int nOffsetY)
return; return;
// Select the HBITMAP by memory DC // Select the HBITMAP by memory DC
HDC hdcMem = ::CreateCompatibleDC(hDrawingDC); HDC hdcMem = ::CreateCompatibleDC(m_hDrawingDC);
HGDIOBJ hbmOld = ::SelectObject(hdcMem, hbmCropped); HGDIOBJ hbmOld = ::SelectObject(hdcMem, hbmCropped);
// Fill background of the HBITMAP // Fill background of the HBITMAP
@ -146,7 +146,7 @@ void ImageModel::Crop(int nWidth, int nHeight, int nOffsetX, int nOffsetY)
::DeleteObject(hbrBack); ::DeleteObject(hbrBack);
// Copy the old content // Copy the old content
::BitBlt(hdcMem, -nOffsetX, -nOffsetY, GetWidth(), GetHeight(), hDrawingDC, 0, 0, SRCCOPY); ::BitBlt(hdcMem, -nOffsetX, -nOffsetY, GetWidth(), GetHeight(), m_hDrawingDC, 0, 0, SRCCOPY);
// Clean up // Clean up
::SelectObject(hdcMem, hbmOld); ::SelectObject(hdcMem, hbmOld);
@ -160,12 +160,12 @@ void ImageModel::Crop(int nWidth, int nHeight, int nOffsetX, int nOffsetY)
void ImageModel::SaveImage(LPCTSTR lpFileName) void ImageModel::SaveImage(LPCTSTR lpFileName)
{ {
SaveDIBToFile(hBms[currInd], lpFileName, hDrawingDC); SaveDIBToFile(m_hBms[m_currInd], lpFileName, m_hDrawingDC);
} }
BOOL ImageModel::IsImageSaved() const BOOL ImageModel::IsImageSaved() const
{ {
return imageSaved; return g_imageSaved;
} }
void ImageModel::StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX, int nSkewDegY) void ImageModel::StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX, int nSkewDegY)
@ -176,17 +176,17 @@ void ImageModel::StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSk
INT newHeight = oldHeight * nStretchPercentY / 100; INT newHeight = oldHeight * nStretchPercentY / 100;
if (oldWidth != newWidth || oldHeight != newHeight) if (oldWidth != newWidth || oldHeight != newHeight)
{ {
HBITMAP hbm0 = CopyDIBImage(hBms[currInd], newWidth, newHeight); HBITMAP hbm0 = CopyDIBImage(m_hBms[m_currInd], newWidth, newHeight);
PushImageForUndo(hbm0); PushImageForUndo(hbm0);
} }
if (nSkewDegX) if (nSkewDegX)
{ {
HBITMAP hbm1 = SkewDIB(hDrawingDC, hBms[currInd], nSkewDegX, FALSE); HBITMAP hbm1 = SkewDIB(m_hDrawingDC, m_hBms[m_currInd], nSkewDegX, FALSE);
PushImageForUndo(hbm1); PushImageForUndo(hbm1);
} }
if (nSkewDegY) if (nSkewDegY)
{ {
HBITMAP hbm2 = SkewDIB(hDrawingDC, hBms[currInd], nSkewDegY, TRUE); HBITMAP hbm2 = SkewDIB(m_hDrawingDC, m_hBms[m_currInd], nSkewDegY, TRUE);
PushImageForUndo(hbm2); PushImageForUndo(hbm2);
} }
NotifyImageChanged(); NotifyImageChanged();
@ -194,31 +194,31 @@ void ImageModel::StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSk
int ImageModel::GetWidth() const int ImageModel::GetWidth() const
{ {
return GetDIBWidth(hBms[currInd]); return GetDIBWidth(m_hBms[m_currInd]);
} }
int ImageModel::GetHeight() const int ImageModel::GetHeight() const
{ {
return GetDIBHeight(hBms[currInd]); return GetDIBHeight(m_hBms[m_currInd]);
} }
void ImageModel::InvertColors() void ImageModel::InvertColors()
{ {
RECT rect = {0, 0, GetWidth(), GetHeight()}; RECT rect = {0, 0, GetWidth(), GetHeight()};
PushImageForUndo(); PushImageForUndo();
InvertRect(hDrawingDC, &rect); InvertRect(m_hDrawingDC, &rect);
NotifyImageChanged(); NotifyImageChanged();
} }
HDC ImageModel::GetDC() HDC ImageModel::GetDC()
{ {
return hDrawingDC; return m_hDrawingDC;
} }
void ImageModel::FlipHorizontally() void ImageModel::FlipHorizontally()
{ {
PushImageForUndo(); PushImageForUndo();
StretchBlt(hDrawingDC, GetWidth() - 1, 0, -GetWidth(), GetHeight(), GetDC(), 0, 0, StretchBlt(m_hDrawingDC, GetWidth() - 1, 0, -GetWidth(), GetHeight(), GetDC(), 0, 0,
GetWidth(), GetHeight(), SRCCOPY); GetWidth(), GetHeight(), SRCCOPY);
NotifyImageChanged(); NotifyImageChanged();
} }
@ -226,7 +226,7 @@ void ImageModel::FlipHorizontally()
void ImageModel::FlipVertically() void ImageModel::FlipVertically()
{ {
PushImageForUndo(); PushImageForUndo();
StretchBlt(hDrawingDC, 0, GetHeight() - 1, GetWidth(), -GetHeight(), GetDC(), 0, 0, StretchBlt(m_hDrawingDC, 0, GetHeight() - 1, GetWidth(), -GetHeight(), GetDC(), 0, 0,
GetWidth(), GetHeight(), SRCCOPY); GetWidth(), GetHeight(), SRCCOPY);
NotifyImageChanged(); NotifyImageChanged();
} }
@ -238,7 +238,7 @@ void ImageModel::RotateNTimes90Degrees(int iN)
case 1: case 1:
case 3: case 3:
{ {
HBITMAP hbm = Rotate90DegreeBlt(hDrawingDC, GetWidth(), GetHeight(), iN == 1, FALSE); HBITMAP hbm = Rotate90DegreeBlt(m_hDrawingDC, GetWidth(), GetHeight(), iN == 1, FALSE);
if (hbm) if (hbm)
PushImageForUndo(hbm); PushImageForUndo(hbm);
break; break;
@ -246,28 +246,25 @@ void ImageModel::RotateNTimes90Degrees(int iN)
case 2: case 2:
{ {
PushImageForUndo(); PushImageForUndo();
StretchBlt(hDrawingDC, GetWidth() - 1, GetHeight() - 1, -GetWidth(), -GetHeight(), StretchBlt(m_hDrawingDC, GetWidth() - 1, GetHeight() - 1, -GetWidth(), -GetHeight(),
hDrawingDC, 0, 0, GetWidth(), GetHeight(), SRCCOPY); m_hDrawingDC, 0, 0, GetWidth(), GetHeight(), SRCCOPY);
break; break;
} }
} }
NotifyImageChanged(); NotifyImageChanged();
} }
void ImageModel::DeleteSelection()
{
if (!selectionModel.m_bShow)
return;
selectionModel.TakeOff();
selectionModel.m_bShow = FALSE;
selectionModel.ClearColor();
selectionModel.ClearMask();
NotifyImageChanged();
}
void ImageModel::Bound(POINT& pt) const void ImageModel::Bound(POINT& pt) const
{ {
pt.x = max(0, min(pt.x, GetWidth())); pt.x = max(0, min(pt.x, GetWidth()));
pt.y = max(0, min(pt.y, GetHeight())); pt.y = max(0, min(pt.y, GetHeight()));
} }
HBITMAP ImageModel::CopyBitmap()
{
// NOTE: An app cannot select a bitmap into more than one device context at a time.
::SelectObject(m_hDrawingDC, m_hbmOld); // De-select
HBITMAP ret = CopyDIBImage(m_hBms[m_currInd]);
m_hbmOld = ::SelectObject(m_hDrawingDC, m_hBms[m_currInd]); // Re-select
return ret;
}

View file

@ -18,8 +18,8 @@ public:
virtual ~ImageModel(); virtual ~ImageModel();
HDC GetDC(); HDC GetDC();
BOOL CanUndo() const { return undoSteps > 0; } BOOL CanUndo() const { return m_undoSteps > 0; }
BOOL CanRedo() const { return redoSteps > 0; } BOOL CanRedo() const { return m_redoSteps > 0; }
void PushImageForUndo(HBITMAP hbm = NULL); void PushImageForUndo(HBITMAP hbm = NULL);
void ResetToPrevious(void); void ResetToPrevious(void);
void Undo(BOOL bClearRedo = FALSE); void Undo(BOOL bClearRedo = FALSE);
@ -31,18 +31,19 @@ public:
void StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX = 0, int nSkewDegY = 0); void StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX = 0, int nSkewDegY = 0);
int GetWidth() const; int GetWidth() const;
int GetHeight() const; int GetHeight() const;
HBITMAP CopyBitmap();
void InvertColors(); void InvertColors();
void FlipHorizontally(); void FlipHorizontally();
void FlipVertically(); void FlipVertically();
void RotateNTimes90Degrees(int iN); void RotateNTimes90Degrees(int iN);
void DeleteSelection();
void Bound(POINT& pt) const; void Bound(POINT& pt) const;
void NotifyImageChanged(); void NotifyImageChanged();
protected: protected:
HDC hDrawingDC; // The device context for this class HDC m_hDrawingDC; // The device context for this class
int currInd; // The current index int m_currInd; // The current index in m_hBms
int undoSteps; // The undo-able count int m_undoSteps; // The undo-able count
int redoSteps; // The redo-able count int m_redoSteps; // The redo-able count
HBITMAP hBms[HISTORYSIZE]; // A rotation buffer of HBITMAPs HBITMAP m_hBms[HISTORYSIZE]; // A rotation buffer of HBITMAPs
HGDIOBJ m_hbmOld;
}; };

View file

@ -8,15 +8,13 @@
#include "precomp.h" #include "precomp.h"
POINT start; POINT g_ptStart, g_ptEnd;
POINT last; BOOL g_askBeforeEnlarging = FALSE; // TODO: initialize from registry
HINSTANCE g_hinstExe = NULL;
BOOL askBeforeEnlarging = FALSE; // TODO: initialize from registry TCHAR g_szFileName[MAX_LONG_PATH] = { 0 };
HINSTANCE hProgInstance = NULL; BOOL g_isAFile = FALSE;
TCHAR filepathname[MAX_LONG_PATH] = { 0 }; BOOL g_imageSaved = FALSE;
BOOL isAFile = FALSE; BOOL g_showGrid = FALSE;
BOOL imageSaved = FALSE;
BOOL showGrid = FALSE;
CMainWindow mainWindow; CMainWindow mainWindow;
@ -81,7 +79,7 @@ BOOL CMainWindow::GetOpenFileName(IN OUT LPTSTR pszFile, INT cchMaxFile)
{ {
// The "All Files" item text // The "All Files" item text
CString strAllPictureFiles; CString strAllPictureFiles;
strAllPictureFiles.LoadString(hProgInstance, IDS_ALLPICTUREFILES); strAllPictureFiles.LoadString(g_hinstExe, IDS_ALLPICTUREFILES);
// Get the import filter // Get the import filter
CSimpleArray<GUID> aguidFileTypesI; CSimpleArray<GUID> aguidFileTypesI;
@ -92,7 +90,7 @@ BOOL CMainWindow::GetOpenFileName(IN OUT LPTSTR pszFile, INT cchMaxFile)
ZeroMemory(&ofn, sizeof(ofn)); ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn); ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = m_hWnd; ofn.hwndOwner = m_hWnd;
ofn.hInstance = hProgInstance; ofn.hInstance = g_hinstExe;
ofn.lpstrFilter = strFilter; ofn.lpstrFilter = strFilter;
ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY; ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY;
ofn.lpstrDefExt = L"png"; ofn.lpstrDefExt = L"png";
@ -119,7 +117,7 @@ BOOL CMainWindow::GetSaveFileName(IN OUT LPTSTR pszFile, INT cchMaxFile)
ZeroMemory(&sfn, sizeof(sfn)); ZeroMemory(&sfn, sizeof(sfn));
sfn.lStructSize = sizeof(sfn); sfn.lStructSize = sizeof(sfn);
sfn.hwndOwner = m_hWnd; sfn.hwndOwner = m_hWnd;
sfn.hInstance = hProgInstance; sfn.hInstance = g_hinstExe;
sfn.lpstrFilter = strFilter; sfn.lpstrFilter = strFilter;
sfn.Flags = OFN_EXPLORER | OFN_OVERWRITEPROMPT | OFN_ENABLEHOOK; sfn.Flags = OFN_EXPLORER | OFN_OVERWRITEPROMPT | OFN_ENABLEHOOK;
sfn.lpfnHook = OFNHookProc; sfn.lpfnHook = OFNHookProc;
@ -170,10 +168,10 @@ BOOL CMainWindow::ChooseColor(IN OUT COLORREF *prgbColor)
HWND CMainWindow::DoCreate() HWND CMainWindow::DoCreate()
{ {
::LoadString(hProgInstance, IDS_DEFAULTFILENAME, filepathname, _countof(filepathname)); ::LoadString(g_hinstExe, IDS_DEFAULTFILENAME, g_szFileName, _countof(g_szFileName));
CString strTitle; CString strTitle;
strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(filepathname)); strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(g_szFileName));
RECT& rc = registrySettings.WindowPlacement.rcNormalPosition; RECT& rc = registrySettings.WindowPlacement.rcNormalPosition;
return Create(HWND_DESKTOP, rc, strTitle, WS_OVERLAPPEDWINDOW, WS_EX_ACCEPTFILES); return Create(HWND_DESKTOP, rc, strTitle, WS_OVERLAPPEDWINDOW, WS_EX_ACCEPTFILES);
@ -188,7 +186,7 @@ _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, INT nC
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif #endif
hProgInstance = hInstance; g_hinstExe = hInstance;
// Initialize common controls library // Initialize common controls library
INITCOMMONCONTROLSEX iccx; INITCOMMONCONTROLSEX iccx;

View file

@ -38,7 +38,7 @@ HWND CMiniatureWindow::DoCreate(HWND hwndParent)
}; };
TCHAR strTitle[100]; TCHAR strTitle[100];
::LoadString(hProgInstance, IDS_MINIATURETITLE, strTitle, _countof(strTitle)); ::LoadString(g_hinstExe, IDS_MINIATURETITLE, strTitle, _countof(strTitle));
DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME; DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME;
return Create(hwndParent, rc, strTitle, style, WS_EX_PALETTEWINDOW); return Create(hwndParent, rc, strTitle, style, WS_EX_PALETTEWINDOW);

View file

@ -53,25 +53,25 @@ BOOL nearlyEqualPoints(INT x0, INT y0, INT x1, INT y1)
void updateStartAndLast(LONG x, LONG y) void updateStartAndLast(LONG x, LONG y)
{ {
start.x = last.x = x; g_ptStart.x = g_ptEnd.x = x;
start.y = last.y = y; g_ptStart.y = g_ptEnd.y = y;
} }
void updateLast(LONG x, LONG y) void updateLast(LONG x, LONG y)
{ {
last.x = x; g_ptEnd.x = x;
last.y = y; g_ptEnd.y = y;
} }
void ToolBase::reset() void ToolBase::reset()
{ {
pointSP = 0; pointSP = 0;
start.x = start.y = last.x = last.y = -1; g_ptStart.x = g_ptStart.y = g_ptEnd.x = g_ptEnd.y = -1;
selectionModel.ResetPtStack(); selectionModel.ResetPtStack();
if (selectionModel.m_bShow) if (selectionModel.m_bShow)
{ {
selectionModel.Landing(); selectionModel.Landing();
selectionModel.m_bShow = FALSE; selectionModel.HideSelection();
} }
} }
@ -99,24 +99,54 @@ void ToolBase::endEvent()
m_hdc = NULL; m_hdc = NULL;
} }
void ToolBase::OnDrawSelectionOnCanvas(HDC hdc)
{
if (!selectionModel.m_bShow)
return;
RECT rcSelection = selectionModel.m_rc;
canvasWindow.ImageToCanvas(rcSelection);
::InflateRect(&rcSelection, GRIP_SIZE, GRIP_SIZE);
drawSizeBoxes(hdc, &rcSelection, TRUE);
}
/* TOOLS ********************************************************/ /* TOOLS ********************************************************/
// TOOL_FREESEL // TOOL_FREESEL
struct FreeSelTool : ToolBase struct FreeSelTool : ToolBase
{ {
BOOL m_bLeftButton; BOOL m_bLeftButton = FALSE;
FreeSelTool() : ToolBase(TOOL_FREESEL), m_bLeftButton(FALSE) FreeSelTool() : ToolBase(TOOL_FREESEL)
{ {
} }
void OnDrawOverlayOnImage(HDC hdc) override
{
if (!selectionModel.IsLanded())
{
selectionModel.DrawBackgroundPoly(hdc, selectionModel.m_rgbBack);
selectionModel.DrawSelection(hdc, paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent());
}
if (canvasWindow.m_drawing)
{
selectionModel.DrawFramePoly(hdc);
}
}
void OnDrawOverlayOnCanvas(HDC hdc) override
{
OnDrawSelectionOnCanvas(hdc);
}
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
{ {
selectionModel.Landing(); selectionModel.Landing();
if (bLeftButton) if (bLeftButton)
{ {
imageModel.PushImageForUndo(); selectionModel.HideSelection();
selectionModel.m_bShow = FALSE;
selectionModel.ResetPtStack(); selectionModel.ResetPtStack();
POINT pt = { x, y }; POINT pt = { x, y };
selectionModel.PushToPtStack(pt); selectionModel.PushToPtStack(pt);
@ -131,8 +161,7 @@ struct FreeSelTool : ToolBase
POINT pt = { x, y }; POINT pt = { x, y };
imageModel.Bound(pt); imageModel.Bound(pt);
selectionModel.PushToPtStack(pt); selectionModel.PushToPtStack(pt);
imageModel.ResetToPrevious(); imageModel.NotifyImageChanged();
selectionModel.DrawFramePoly(m_hdc);
} }
} }
@ -140,16 +169,13 @@ struct FreeSelTool : ToolBase
{ {
if (bLeftButton) if (bLeftButton)
{ {
imageModel.ResetToPrevious();
if (selectionModel.PtStackSize() > 2) if (selectionModel.PtStackSize() > 2)
{ {
selectionModel.BuildMaskFromPtStack(); selectionModel.BuildMaskFromPtStack();
selectionModel.TakeOff();
selectionModel.m_bShow = TRUE; selectionModel.m_bShow = TRUE;
} }
else else
{ {
imageModel.Undo(TRUE);
selectionModel.ResetPtStack(); selectionModel.ResetPtStack();
selectionModel.m_bShow = FALSE; selectionModel.m_bShow = FALSE;
} }
@ -159,15 +185,13 @@ struct FreeSelTool : ToolBase
void OnFinishDraw() override void OnFinishDraw() override
{ {
m_bLeftButton = FALSE; selectionModel.Landing();
ToolBase::OnFinishDraw(); ToolBase::OnFinishDraw();
} }
void OnCancelDraw() override void OnCancelDraw() override
{ {
if (m_bLeftButton) selectionModel.HideSelection();
imageModel.Undo(TRUE);
m_bLeftButton = FALSE;
ToolBase::OnCancelDraw(); ToolBase::OnCancelDraw();
} }
}; };
@ -175,20 +199,39 @@ struct FreeSelTool : ToolBase
// TOOL_RECTSEL // TOOL_RECTSEL
struct RectSelTool : ToolBase struct RectSelTool : ToolBase
{ {
BOOL m_bLeftButton; BOOL m_bLeftButton = FALSE;
RectSelTool() : ToolBase(TOOL_RECTSEL), m_bLeftButton(FALSE) RectSelTool() : ToolBase(TOOL_RECTSEL)
{ {
} }
void OnDrawOverlayOnImage(HDC hdc) override
{
if (!selectionModel.IsLanded())
{
selectionModel.DrawBackgroundRect(hdc, selectionModel.m_rgbBack);
selectionModel.DrawSelection(hdc, paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent());
}
if (canvasWindow.m_drawing)
{
RECT rc = selectionModel.m_rc;
if (!::IsRectEmpty(&rc))
RectSel(hdc, rc.left, rc.top, rc.right, rc.bottom);
}
}
void OnDrawOverlayOnCanvas(HDC hdc) override
{
OnDrawSelectionOnCanvas(hdc);
}
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
{ {
selectionModel.Landing(); selectionModel.Landing();
if (bLeftButton) if (bLeftButton)
{ {
imageModel.PushImageForUndo(); selectionModel.HideSelection();
selectionModel.m_bShow = FALSE;
::SetRectEmpty(&selectionModel.m_rc);
} }
m_bLeftButton = bLeftButton; m_bLeftButton = bLeftButton;
} }
@ -197,11 +240,10 @@ struct RectSelTool : ToolBase
{ {
if (bLeftButton) if (bLeftButton)
{ {
imageModel.ResetToPrevious();
POINT pt = { x, y }; POINT pt = { x, y };
imageModel.Bound(pt); imageModel.Bound(pt);
selectionModel.SetRectFromPoints(start, pt); selectionModel.SetRectFromPoints(g_ptStart, pt);
RectSel(m_hdc, start.x, start.y, pt.x, pt.y); imageModel.NotifyImageChanged();
} }
} }
@ -209,9 +251,9 @@ struct RectSelTool : ToolBase
{ {
if (bLeftButton) if (bLeftButton)
{ {
imageModel.ResetToPrevious(); POINT pt = { x, y };
if (start.x == x && start.y == y) imageModel.Bound(pt);
imageModel.Undo(TRUE); selectionModel.SetRectFromPoints(g_ptStart, pt);
selectionModel.m_bShow = !selectionModel.m_rc.IsRectEmpty(); selectionModel.m_bShow = !selectionModel.m_rc.IsRectEmpty();
imageModel.NotifyImageChanged(); imageModel.NotifyImageChanged();
} }
@ -219,22 +261,68 @@ struct RectSelTool : ToolBase
void OnFinishDraw() override void OnFinishDraw() override
{ {
m_bLeftButton = FALSE; selectionModel.Landing();
ToolBase::OnFinishDraw(); ToolBase::OnFinishDraw();
} }
void OnCancelDraw() override void OnCancelDraw() override
{ {
if (m_bLeftButton) selectionModel.HideSelection();
imageModel.Undo(TRUE);
m_bLeftButton = FALSE;
ToolBase::OnCancelDraw(); ToolBase::OnCancelDraw();
} }
}; };
struct GenericDrawTool : ToolBase struct TwoPointDrawTool : ToolBase
{ {
GenericDrawTool(TOOLTYPE type) : ToolBase(type) BOOL m_bLeftButton = FALSE;
BOOL m_bDrawing = FALSE;
TwoPointDrawTool(TOOLTYPE type) : ToolBase(type)
{
}
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
{
m_bLeftButton = bLeftButton;
m_bDrawing = TRUE;
g_ptStart.x = g_ptEnd.x = x;
g_ptStart.y = g_ptEnd.y = y;
imageModel.NotifyImageChanged();
}
void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
{
g_ptEnd.x = x;
g_ptEnd.y = y;
imageModel.NotifyImageChanged();
}
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
{
g_ptEnd.x = x;
g_ptEnd.y = y;
imageModel.PushImageForUndo();
OnDrawOverlayOnImage(m_hdc);
m_bDrawing = FALSE;
imageModel.NotifyImageChanged();
}
void OnFinishDraw() override
{
m_bDrawing = FALSE;
ToolBase::OnFinishDraw();
}
void OnCancelDraw() override
{
m_bDrawing = FALSE;
ToolBase::OnCancelDraw();
}
};
struct SmoothDrawTool : ToolBase
{
SmoothDrawTool(TOOLTYPE type) : ToolBase(type)
{ {
} }
@ -243,7 +331,9 @@ struct GenericDrawTool : ToolBase
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
{ {
imageModel.PushImageForUndo(); imageModel.PushImageForUndo();
draw(bLeftButton, x, y); g_ptStart.x = g_ptEnd.x = x;
g_ptStart.y = g_ptEnd.y = y;
imageModel.NotifyImageChanged();
} }
void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
@ -255,7 +345,12 @@ struct GenericDrawTool : ToolBase
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
{ {
draw(bLeftButton, x, y); draw(bLeftButton, x, y);
imageModel.NotifyImageChanged(); OnFinishDraw();
}
void OnFinishDraw() override
{
ToolBase::OnFinishDraw();
} }
void OnCancelDraw() override void OnCancelDraw() override
@ -267,18 +362,20 @@ struct GenericDrawTool : ToolBase
}; };
// TOOL_RUBBER // TOOL_RUBBER
struct RubberTool : GenericDrawTool struct RubberTool : SmoothDrawTool
{ {
RubberTool() : GenericDrawTool(TOOL_RUBBER) RubberTool() : SmoothDrawTool(TOOL_RUBBER)
{ {
} }
void draw(BOOL bLeftButton, LONG x, LONG y) override void draw(BOOL bLeftButton, LONG x, LONG y) override
{ {
if (bLeftButton) if (bLeftButton)
Erase(m_hdc, last.x, last.y, x, y, m_bg, toolsModel.GetRubberRadius()); Erase(m_hdc, g_ptEnd.x, g_ptEnd.y, x, y, m_bg, toolsModel.GetRubberRadius());
else else
Replace(m_hdc, last.x, last.y, x, y, m_fg, m_bg, toolsModel.GetRubberRadius()); Replace(m_hdc, g_ptEnd.x, g_ptEnd.y, x, y, m_fg, m_bg, toolsModel.GetRubberRadius());
g_ptEnd.x = x;
g_ptEnd.y = y;
} }
}; };
@ -354,38 +451,42 @@ struct ZoomTool : ToolBase
}; };
// TOOL_PEN // TOOL_PEN
struct PenTool : GenericDrawTool struct PenTool : SmoothDrawTool
{ {
PenTool() : GenericDrawTool(TOOL_PEN) PenTool() : SmoothDrawTool(TOOL_PEN)
{ {
} }
void draw(BOOL bLeftButton, LONG x, LONG y) override void draw(BOOL bLeftButton, LONG x, LONG y) override
{ {
COLORREF rgb = bLeftButton ? m_fg : m_bg; COLORREF rgb = bLeftButton ? m_fg : m_bg;
Line(m_hdc, last.x, last.y, x, y, rgb, 1); Line(m_hdc, g_ptEnd.x, g_ptEnd.y, x, y, rgb, 1);
::SetPixelV(m_hdc, x, y, rgb); ::SetPixelV(m_hdc, x, y, rgb);
g_ptEnd.x = x;
g_ptEnd.y = y;
} }
}; };
// TOOL_BRUSH // TOOL_BRUSH
struct BrushTool : GenericDrawTool struct BrushTool : SmoothDrawTool
{ {
BrushTool() : GenericDrawTool(TOOL_BRUSH) BrushTool() : SmoothDrawTool(TOOL_BRUSH)
{ {
} }
void draw(BOOL bLeftButton, LONG x, LONG y) override void draw(BOOL bLeftButton, LONG x, LONG y) override
{ {
COLORREF rgb = bLeftButton ? m_fg : m_bg; COLORREF rgb = bLeftButton ? m_fg : m_bg;
Brush(m_hdc, last.x, last.y, x, y, rgb, toolsModel.GetBrushStyle()); Brush(m_hdc, g_ptEnd.x, g_ptEnd.y, x, y, rgb, toolsModel.GetBrushStyle());
g_ptEnd.x = x;
g_ptEnd.y = y;
} }
}; };
// TOOL_AIRBRUSH // TOOL_AIRBRUSH
struct AirBrushTool : GenericDrawTool struct AirBrushTool : SmoothDrawTool
{ {
AirBrushTool() : GenericDrawTool(TOOL_AIRBRUSH) AirBrushTool() : SmoothDrawTool(TOOL_AIRBRUSH)
{ {
} }
@ -403,13 +504,22 @@ struct TextTool : ToolBase
{ {
} }
void OnDrawOverlayOnImage(HDC hdc) override
{
if (canvasWindow.m_drawing)
{
RECT rc = selectionModel.m_rc;
if (!::IsRectEmpty(&rc))
RectSel(hdc, rc.left, rc.top, rc.right, rc.bottom);
}
}
void UpdatePoint(LONG x, LONG y) void UpdatePoint(LONG x, LONG y)
{ {
imageModel.ResetToPrevious();
POINT pt = { x, y }; POINT pt = { x, y };
imageModel.Bound(pt); imageModel.Bound(pt);
selectionModel.SetRectFromPoints(start, pt); selectionModel.SetRectFromPoints(g_ptStart, pt);
RectSel(m_hdc, start.x, start.y, pt.x, pt.y); imageModel.NotifyImageChanged();
} }
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
@ -417,7 +527,6 @@ struct TextTool : ToolBase
if (!textEditWindow.IsWindow()) if (!textEditWindow.IsWindow())
textEditWindow.Create(canvasWindow); textEditWindow.Create(canvasWindow);
imageModel.PushImageForUndo();
UpdatePoint(x, y); UpdatePoint(x, y);
} }
@ -426,30 +535,40 @@ struct TextTool : ToolBase
UpdatePoint(x, y); UpdatePoint(x, y);
} }
void draw(HDC hdc)
{
CString szText;
textEditWindow.GetWindowText(szText);
RECT rc;
textEditWindow.InvalidateEditRect();
textEditWindow.GetEditRect(&rc);
::InflateRect(&rc, -GRIP_SIZE / 2, -GRIP_SIZE / 2);
// Draw the text
INT style = (toolsModel.IsBackgroundTransparent() ? 0 : 1);
imageModel.PushImageForUndo();
Text(hdc, rc.left, rc.top, rc.right, rc.bottom, m_fg, m_bg, szText,
textEditWindow.GetFont(), style);
}
void quit()
{
if (textEditWindow.IsWindow())
textEditWindow.ShowWindow(SW_HIDE);
selectionModel.HideSelection();
}
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
{ {
imageModel.Undo(TRUE);
POINT pt = { x, y }; POINT pt = { x, y };
imageModel.Bound(pt); imageModel.Bound(pt);
selectionModel.SetRectFromPoints(start, pt); selectionModel.SetRectFromPoints(g_ptStart, pt);
BOOL bTextBoxShown = ::IsWindowVisible(textEditWindow); BOOL bTextBoxShown = ::IsWindowVisible(textEditWindow);
if (bTextBoxShown && textEditWindow.GetWindowTextLength() > 0) if (bTextBoxShown && textEditWindow.GetWindowTextLength() > 0)
{ {
CString szText; draw(m_hdc);
textEditWindow.GetWindowText(szText);
RECT rc;
textEditWindow.InvalidateEditRect();
textEditWindow.GetEditRect(&rc);
::InflateRect(&rc, -GRIP_SIZE / 2, -GRIP_SIZE / 2);
// Draw the text
INT style = (toolsModel.IsBackgroundTransparent() ? 0 : 1);
imageModel.PushImageForUndo();
Text(m_hdc, rc.left, rc.top, rc.right, rc.bottom, m_fg, m_bg, szText,
textEditWindow.GetFont(), style);
if (selectionModel.m_rc.IsRectEmpty()) if (selectionModel.m_rc.IsRectEmpty())
{ {
@ -494,201 +613,224 @@ struct TextTool : ToolBase
void OnFinishDraw() override void OnFinishDraw() override
{ {
toolsModel.OnButtonDown(TRUE, -1, -1, TRUE); draw(m_hdc);
toolsModel.OnButtonUp(TRUE, -1, -1); quit();
ToolBase::OnFinishDraw(); ToolBase::OnFinishDraw();
} }
void OnCancelDraw() override
{
quit();
ToolBase::OnCancelDraw();
}
}; };
// TOOL_LINE // TOOL_LINE
struct LineTool : GenericDrawTool struct LineTool : TwoPointDrawTool
{ {
LineTool() : GenericDrawTool(TOOL_LINE) LineTool() : TwoPointDrawTool(TOOL_LINE)
{ {
} }
void draw(BOOL bLeftButton, LONG x, LONG y) override void OnDrawOverlayOnImage(HDC hdc) override
{ {
imageModel.ResetToPrevious(); if (!m_bDrawing)
return;
if (GetAsyncKeyState(VK_SHIFT) < 0) if (GetAsyncKeyState(VK_SHIFT) < 0)
roundTo8Directions(start.x, start.y, x, y); roundTo8Directions(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y);
COLORREF rgb = bLeftButton ? m_fg : m_bg; COLORREF rgb = m_bLeftButton ? m_fg : m_bg;
Line(m_hdc, start.x, start.y, x, y, rgb, toolsModel.GetLineWidth()); Line(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, rgb, toolsModel.GetLineWidth());
} }
}; };
// TOOL_BEZIER // TOOL_BEZIER
struct BezierTool : ToolBase struct BezierTool : ToolBase
{ {
BOOL m_bLeftButton; BOOL m_bLeftButton = FALSE;
BOOL m_bDrawing = FALSE;
BezierTool() : ToolBase(TOOL_BEZIER), m_bLeftButton(FALSE) BezierTool() : ToolBase(TOOL_BEZIER)
{ {
} }
void draw(BOOL bLeftButton) void OnDrawOverlayOnImage(HDC hdc)
{ {
COLORREF rgb = (bLeftButton ? m_fg : m_bg); if (!m_bDrawing)
return;
COLORREF rgb = (m_bLeftButton ? m_fg : m_bg);
switch (pointSP) switch (pointSP)
{ {
case 1: case 1:
Line(m_hdc, pointStack[0].x, pointStack[0].y, pointStack[1].x, pointStack[1].y, rgb, Line(hdc, pointStack[0].x, pointStack[0].y, pointStack[1].x, pointStack[1].y, rgb,
toolsModel.GetLineWidth()); toolsModel.GetLineWidth());
break; break;
case 2: case 2:
Bezier(m_hdc, pointStack[0], pointStack[2], pointStack[2], pointStack[1], rgb, toolsModel.GetLineWidth()); Bezier(hdc, pointStack[0], pointStack[2], pointStack[2], pointStack[1], rgb, toolsModel.GetLineWidth());
break; break;
case 3: case 3:
Bezier(m_hdc, pointStack[0], pointStack[2], pointStack[3], pointStack[1], rgb, toolsModel.GetLineWidth()); Bezier(hdc, pointStack[0], pointStack[2], pointStack[3], pointStack[1], rgb, toolsModel.GetLineWidth());
break; break;
} }
m_bLeftButton = bLeftButton;
} }
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
{ {
pointStack[pointSP].x = x; m_bLeftButton = bLeftButton;
pointStack[pointSP].y = y;
if (pointSP == 0) if (!m_bDrawing)
{ {
imageModel.PushImageForUndo(); m_bDrawing = TRUE;
pointSP++; pointStack[pointSP].x = pointStack[pointSP + 1].x = x;
pointStack[pointSP].y = pointStack[pointSP + 1].y = y;
++pointSP;
} }
else
{
++pointSP;
pointStack[pointSP].x = x;
pointStack[pointSP].y = y;
}
imageModel.NotifyImageChanged();
} }
void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
{ {
imageModel.ResetToPrevious();
pointStack[pointSP].x = x; pointStack[pointSP].x = x;
pointStack[pointSP].y = y; pointStack[pointSP].y = y;
draw(bLeftButton); imageModel.NotifyImageChanged();
} }
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
{ {
imageModel.ResetToPrevious(); pointStack[pointSP].x = x;
draw(bLeftButton); pointStack[pointSP].y = y;
pointSP++; if (pointSP >= 3)
if (pointSP == 4) {
pointSP = 0; OnFinishDraw();
return;
}
imageModel.NotifyImageChanged(); imageModel.NotifyImageChanged();
} }
void OnCancelDraw() override void OnCancelDraw() override
{ {
OnButtonUp(FALSE, 0, 0); m_bDrawing = FALSE;
imageModel.Undo(TRUE);
ToolBase::OnCancelDraw(); ToolBase::OnCancelDraw();
} }
void OnFinishDraw() override void OnFinishDraw() override
{ {
if (pointSP) imageModel.PushImageForUndo();
{ OnDrawOverlayOnImage(m_hdc);
imageModel.ResetToPrevious(); m_bDrawing = FALSE;
--pointSP;
draw(m_bLeftButton);
}
ToolBase::OnFinishDraw(); ToolBase::OnFinishDraw();
} }
}; };
// TOOL_RECT // TOOL_RECT
struct RectTool : GenericDrawTool struct RectTool : TwoPointDrawTool
{ {
RectTool() : GenericDrawTool(TOOL_RECT) RectTool() : TwoPointDrawTool(TOOL_RECT)
{ {
} }
void draw(BOOL bLeftButton, LONG x, LONG y) override void OnDrawOverlayOnImage(HDC hdc) override
{ {
imageModel.ResetToPrevious(); if (!m_bDrawing)
return;
if (GetAsyncKeyState(VK_SHIFT) < 0) if (GetAsyncKeyState(VK_SHIFT) < 0)
regularize(start.x, start.y, x, y); regularize(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y);
if (bLeftButton) if (m_bLeftButton)
Rect(m_hdc, start.x, start.y, x, y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle()); Rect(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
else else
Rect(m_hdc, start.x, start.y, x, y, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle()); Rect(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
} }
}; };
// TOOL_SHAPE // TOOL_SHAPE
struct ShapeTool : ToolBase struct ShapeTool : ToolBase
{ {
BOOL m_bLeftButton; BOOL m_bLeftButton = FALSE;
BOOL m_bClosed = FALSE;
ShapeTool() : ToolBase(TOOL_SHAPE), m_bLeftButton(FALSE) ShapeTool() : ToolBase(TOOL_SHAPE)
{ {
} }
void draw(BOOL bLeftButton, LONG x, LONG y, BOOL bClosed = FALSE) void OnDrawOverlayOnImage(HDC hdc)
{ {
if (pointSP + 1 >= 2) if (pointSP <= 0)
{ return;
if (bLeftButton)
Poly(m_hdc, pointStack, pointSP + 1, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), bClosed, FALSE); if (m_bLeftButton)
else Poly(hdc, pointStack, pointSP + 1, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), m_bClosed, FALSE);
Poly(m_hdc, pointStack, pointSP + 1, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), bClosed, FALSE); else
} Poly(hdc, pointStack, pointSP + 1, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), m_bClosed, FALSE);
m_bLeftButton = bLeftButton;
} }
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
{ {
m_bLeftButton = bLeftButton;
m_bClosed = FALSE;
pointStack[pointSP].x = x; pointStack[pointSP].x = x;
pointStack[pointSP].y = y; pointStack[pointSP].y = y;
if (pointSP == 0 && !bDoubleClick) if (pointSP && bDoubleClick)
{
OnFinishDraw();
return;
}
if (pointSP == 0)
{ {
imageModel.PushImageForUndo();
draw(bLeftButton, x, y);
pointSP++; pointSP++;
pointStack[pointSP].x = x;
pointStack[pointSP].y = y;
} }
else
{ imageModel.NotifyImageChanged();
draw(bLeftButton, x, y, bDoubleClick);
imageModel.NotifyImageChanged();
}
} }
void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
{ {
imageModel.ResetToPrevious();
pointStack[pointSP].x = x; pointStack[pointSP].x = x;
pointStack[pointSP].y = y; pointStack[pointSP].y = y;
if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0)) if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 1].y, x, y); roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 1].y, x, y);
draw(bLeftButton, x, y, FALSE);
imageModel.NotifyImageChanged();
} }
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
{ {
imageModel.ResetToPrevious();
if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0)) if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 1].y, x, y); roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 1].y, x, y);
m_bClosed = FALSE;
if (nearlyEqualPoints(x, y, pointStack[0].x, pointStack[0].y)) if (nearlyEqualPoints(x, y, pointStack[0].x, pointStack[0].y))
{ {
pointSP--; OnFinishDraw();
draw(bLeftButton, x, y, TRUE); return;
pointSP = 0;
} }
else else
{ {
pointSP++; pointSP++;
pointStack[pointSP].x = x; pointStack[pointSP].x = x;
pointStack[pointSP].y = y; pointStack[pointSP].y = y;
draw(bLeftButton, x, y, FALSE);
} }
if (pointSP == _countof(pointStack)) if (pointSP == _countof(pointStack))
pointSP--; pointSP--;
imageModel.NotifyImageChanged();
} }
void OnCancelDraw() override void OnCancelDraw() override
{ {
imageModel.Undo(TRUE);
ToolBase::OnCancelDraw(); ToolBase::OnCancelDraw();
} }
@ -696,49 +838,57 @@ struct ShapeTool : ToolBase
{ {
if (pointSP) if (pointSP)
{ {
imageModel.ResetToPrevious();
--pointSP; --pointSP;
draw(m_bLeftButton, -1, -1, TRUE); m_bClosed = TRUE;
imageModel.PushImageForUndo();
OnDrawOverlayOnImage(m_hdc);
} }
m_bClosed = FALSE;
pointSP = 0;
ToolBase::OnFinishDraw(); ToolBase::OnFinishDraw();
} }
}; };
// TOOL_ELLIPSE // TOOL_ELLIPSE
struct EllipseTool : GenericDrawTool struct EllipseTool : TwoPointDrawTool
{ {
EllipseTool() : GenericDrawTool(TOOL_ELLIPSE) EllipseTool() : TwoPointDrawTool(TOOL_ELLIPSE)
{ {
} }
void draw(BOOL bLeftButton, LONG x, LONG y) override void OnDrawOverlayOnImage(HDC hdc) override
{ {
imageModel.ResetToPrevious(); if (!m_bDrawing)
return;
if (GetAsyncKeyState(VK_SHIFT) < 0) if (GetAsyncKeyState(VK_SHIFT) < 0)
regularize(start.x, start.y, x, y); regularize(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y);
if (bLeftButton) if (m_bLeftButton)
Ellp(m_hdc, start.x, start.y, x, y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle()); Ellp(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
else else
Ellp(m_hdc, start.x, start.y, x, y, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle()); Ellp(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
} }
}; };
// TOOL_RRECT // TOOL_RRECT
struct RRectTool : GenericDrawTool struct RRectTool : TwoPointDrawTool
{ {
RRectTool() : GenericDrawTool(TOOL_RRECT) RRectTool() : TwoPointDrawTool(TOOL_RRECT)
{ {
} }
void draw(BOOL bLeftButton, LONG x, LONG y) override void OnDrawOverlayOnImage(HDC hdc) override
{ {
imageModel.ResetToPrevious(); if (!m_bDrawing)
return;
if (GetAsyncKeyState(VK_SHIFT) < 0) if (GetAsyncKeyState(VK_SHIFT) < 0)
regularize(start.x, start.y, x, y); regularize(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y);
if (bLeftButton) if (m_bLeftButton)
RRect(m_hdc, start.x, start.y, x, y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle()); RRect(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
else else
RRect(m_hdc, start.x, start.y, x, y, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle()); RRect(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
} }
}; };

View file

@ -181,13 +181,7 @@ LRESULT CPaletteWindow::OnRButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam,
LRESULT CPaletteWindow::OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) LRESULT CPaletteWindow::OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{ {
InvalidateRect(NULL, FALSE); Invalidate(FALSE);
return 0;
}
LRESULT CPaletteWindow::OnPaletteModelPaletteChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
InvalidateRect(NULL, FALSE);
return 0; return 0;
} }

View file

@ -27,7 +27,6 @@ public:
MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
MESSAGE_HANDLER(WM_PALETTEMODELCOLORCHANGED, OnPaletteModelColorChanged) MESSAGE_HANDLER(WM_PALETTEMODELCOLORCHANGED, OnPaletteModelColorChanged)
MESSAGE_HANDLER(WM_PALETTEMODELPALETTECHANGED, OnPaletteModelPaletteChanged)
END_MSG_MAP() END_MSG_MAP()
CPaletteWindow(); CPaletteWindow();
@ -45,7 +44,6 @@ protected:
LRESULT OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnLButtonUp(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 OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnPaletteModelPaletteChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
protected: protected:
INT DoHitTest(INT xPos, INT yPos) const; INT DoHitTest(INT xPos, INT yPos) const;

View file

@ -106,5 +106,5 @@ void PaletteModel::NotifyColorChanged()
void PaletteModel::NotifyPaletteChanged() void PaletteModel::NotifyPaletteChanged()
{ {
if (paletteWindow.IsWindow()) if (paletteWindow.IsWindow())
paletteWindow.SendMessage(WM_PALETTEMODELPALETTECHANGED); paletteWindow.Invalidate(FALSE);
} }

View file

@ -21,6 +21,7 @@ SelectionModel::SelectionModel()
, m_bShow(FALSE) , m_bShow(FALSE)
{ {
::SetRectEmpty(&m_rc); ::SetRectEmpty(&m_rc);
::SetRectEmpty(&m_rcOld);
m_ptHit.x = m_ptHit.y = -1; m_ptHit.x = m_ptHit.y = -1;
} }
@ -57,25 +58,13 @@ void SelectionModel::PushToPtStack(POINT pt)
#undef GROW_COUNT #undef GROW_COUNT
} }
void SelectionModel::ShiftPtStack(BOOL bPlus) void SelectionModel::ShiftPtStack(INT dx, INT dy)
{ {
if (bPlus) for (INT i = 0; i < m_iPtSP; ++i)
{ {
for (INT i = 0; i < m_iPtSP; ++i) POINT& pt = m_ptStack[i];
{ pt.x += dx;
POINT& pt = m_ptStack[i]; pt.y += dy;
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;
}
} }
} }
@ -93,16 +82,16 @@ void SelectionModel::BuildMaskFromPtStack()
rc.right += 1; rc.right += 1;
rc.bottom += 1; rc.bottom += 1;
m_rc = rc; m_rc = m_rcOld = rc;
ShiftPtStack(FALSE);
ClearMask(); ClearMask();
ShiftPtStack(-m_rcOld.left, -m_rcOld.top);
HDC hdcMem = ::CreateCompatibleDC(NULL); HDC hdcMem = ::CreateCompatibleDC(NULL);
m_hbmMask = ::CreateBitmap(rc.Width(), rc.Height(), 1, 1, NULL); m_hbmMask = ::CreateBitmap(rc.Width(), rc.Height(), 1, 1, NULL);
HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_hbmMask); HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_hbmMask);
FillRect(hdcMem, &rc, (HBRUSH)::GetStockObject(BLACK_BRUSH)); ::FillRect(hdcMem, &rc, (HBRUSH)::GetStockObject(BLACK_BRUSH));
HGDIOBJ hPenOld = ::SelectObject(hdcMem, GetStockObject(NULL_PEN)); HGDIOBJ hPenOld = ::SelectObject(hdcMem, GetStockObject(NULL_PEN));
HGDIOBJ hbrOld = ::SelectObject(hdcMem, GetStockObject(WHITE_BRUSH)); HGDIOBJ hbrOld = ::SelectObject(hdcMem, GetStockObject(WHITE_BRUSH));
::Polygon(hdcMem, m_ptStack, m_iPtSP); ::Polygon(hdcMem, m_ptStack, m_iPtSP);
@ -110,34 +99,39 @@ void SelectionModel::BuildMaskFromPtStack()
::SelectObject(hdcMem, hPenOld); ::SelectObject(hdcMem, hPenOld);
::SelectObject(hdcMem, hbmOld); ::SelectObject(hdcMem, hbmOld);
::DeleteDC(hdcMem); ::DeleteDC(hdcMem);
ShiftPtStack(+m_rcOld.left, +m_rcOld.top);
} }
void SelectionModel::DrawBackgroundPoly(HDC hDCImage, COLORREF crBg) void SelectionModel::DrawBackgroundPoly(HDC hDCImage, COLORREF crBg)
{ {
ShiftPtStack(TRUE); if (::IsRectEmpty(&m_rcOld))
return;
HGDIOBJ hPenOld = ::SelectObject(hDCImage, ::GetStockObject(NULL_PEN)); HGDIOBJ hPenOld = ::SelectObject(hDCImage, ::GetStockObject(NULL_PEN));
HGDIOBJ hbrOld = ::SelectObject(hDCImage, ::CreateSolidBrush(crBg)); HGDIOBJ hbrOld = ::SelectObject(hDCImage, ::CreateSolidBrush(crBg));
::Polygon(hDCImage, m_ptStack, m_iPtSP); ::Polygon(hDCImage, m_ptStack, m_iPtSP);
::DeleteObject(::SelectObject(hDCImage, hbrOld)); ::DeleteObject(::SelectObject(hDCImage, hbrOld));
::SelectObject(hDCImage, hPenOld); ::SelectObject(hDCImage, hPenOld);
ShiftPtStack(FALSE);
} }
void SelectionModel::DrawBackgroundRect(HDC hDCImage, COLORREF crBg) void SelectionModel::DrawBackgroundRect(HDC hDCImage, COLORREF crBg)
{ {
Rect(hDCImage, m_rc.left, m_rc.top, m_rc.right, m_rc.bottom, crBg, crBg, 0, 1); if (::IsRectEmpty(&m_rcOld))
return;
Rect(hDCImage, m_rcOld.left, m_rcOld.top, m_rcOld.right, m_rcOld.bottom, crBg, crBg, 0, 1);
} }
void SelectionModel::DrawSelection(HDC hDCImage, LPCRECT prc, COLORREF crBg, BOOL bBgTransparent) void SelectionModel::DrawSelection(HDC hDCImage, COLORREF crBg, BOOL bBgTransparent)
{ {
CRect rc = *prc; CRect rc = m_rc;
if (::IsRectEmpty(&rc)) if (::IsRectEmpty(&rc))
return; return;
BITMAP bm; BITMAP bm;
GetObject(m_hbmColor, sizeof(BITMAP), &bm); if (!GetObject(m_hbmColor, sizeof(BITMAP), &bm))
return;
COLORREF keyColor = (bBgTransparent ? crBg : CLR_INVALID); COLORREF keyColor = (bBgTransparent ? crBg : CLR_INVALID);
@ -161,23 +155,23 @@ void SelectionModel::GetSelectionContents(HDC hDCImage)
::DeleteDC(hMemDC); ::DeleteDC(hMemDC);
} }
BOOL SelectionModel::IsLanded() const
{
return !m_hbmColor;
}
BOOL SelectionModel::TakeOff() BOOL SelectionModel::TakeOff()
{ {
if (m_hbmColor || ::IsRectEmpty(&m_rc)) if (!IsLanded() || ::IsRectEmpty(&m_rc))
return FALSE; return FALSE;
HDC hDCImage = imageModel.GetDC(); m_rgbBack = paletteModel.GetBgColor();
GetSelectionContents(hDCImage); GetSelectionContents(imageModel.GetDC());
if (toolsModel.GetActiveTool() == TOOL_FREESEL) if (toolsModel.GetActiveTool() == TOOL_RECTSEL)
{
DrawBackgroundPoly(hDCImage, paletteModel.GetBgColor());
}
else
{
ClearMask(); ClearMask();
DrawBackgroundRect(hDCImage, paletteModel.GetBgColor());
} m_rcOld = m_rc;
imageModel.NotifyImageChanged(); imageModel.NotifyImageChanged();
return TRUE; return TRUE;
@ -185,16 +179,23 @@ BOOL SelectionModel::TakeOff()
void SelectionModel::Landing() void SelectionModel::Landing()
{ {
if (!m_hbmColor) if (IsLanded() && !m_bShow)
{
imageModel.NotifyImageChanged();
return; return;
}
DrawSelection(imageModel.GetDC(), &m_rc, paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent()); m_bShow = FALSE;
::SetRectEmpty(&m_rc); if (!::EqualRect(m_rc, m_rcOld) && !::IsRectEmpty(m_rc) && !::IsRectEmpty(m_rcOld))
ClearMask(); {
ClearColor(); imageModel.PushImageForUndo();
imageModel.PushImageForUndo(); canvasWindow.m_drawing = FALSE;
toolsModel.OnDrawOverlayOnImage(imageModel.GetDC());
}
HideSelection();
} }
void SelectionModel::InsertFromHBITMAP(HBITMAP hBm, INT x, INT y) void SelectionModel::InsertFromHBITMAP(HBITMAP hBm, INT x, INT y)
@ -349,11 +350,11 @@ void SelectionModel::StretchSkew(int nStretchPercentX, int nStretchPercentY, int
imageModel.NotifyImageChanged(); imageModel.NotifyImageChanged();
} }
HBITMAP SelectionModel::GetBitmap() HBITMAP SelectionModel::CopyBitmap()
{ {
if (m_hbmColor == NULL) if (m_hbmColor == NULL)
GetSelectionContents(imageModel.GetDC()); GetSelectionContents(imageModel.GetDC());
return m_hbmColor; return CopyDIBImage(m_hbmColor);
} }
int SelectionModel::PtStackSize() const int SelectionModel::PtStackSize() const
@ -435,15 +436,29 @@ void SelectionModel::ClearColor()
} }
} }
void SelectionModel::CancelSelection() void SelectionModel::HideSelection()
{
m_bShow = FALSE;
ClearColor();
ClearMask();
::SetRectEmpty(&m_rc);
::SetRectEmpty(&m_rcOld);
imageModel.NotifyImageChanged();
}
void SelectionModel::DeleteSelection()
{ {
if (!m_bShow) if (!m_bShow)
return; return;
imageModel.PushImageForUndo(); TakeOff();
if (m_bShow)
imageModel.Undo(TRUE);
m_bShow = FALSE; imageModel.PushImageForUndo();
imageModel.NotifyImageChanged(); if (toolsModel.GetActiveTool() == TOOL_FREESEL)
DrawBackgroundPoly(imageModel.GetDC(), paletteModel.GetBgColor());
else
DrawBackgroundRect(imageModel.GetDC(), paletteModel.GetBgColor());
HideSelection();
} }

View file

@ -18,9 +18,11 @@ private:
int m_iPtSP; int m_iPtSP;
public: public:
COLORREF m_rgbBack = RGB(255, 255, 255);
BOOL m_bShow; BOOL m_bShow;
CRect m_rc; // in image pixel coordinates CRect m_rc; // in image pixel coordinates
POINT m_ptHit; // in image pixel coordinates POINT m_ptHit; // in image pixel coordinates
CRect m_rcOld; // in image pixel coordinates
SelectionModel(); SelectionModel();
~SelectionModel(); ~SelectionModel();
@ -33,13 +35,16 @@ public:
BOOL TakeOff(); BOOL TakeOff();
void Landing(); void Landing();
BOOL IsLanded() const;
void HideSelection();
void DeleteSelection();
HBITMAP GetBitmap(); HBITMAP CopyBitmap();
void GetSelectionContents(HDC hDCImage); void GetSelectionContents(HDC hDCImage);
void DrawFramePoly(HDC hDCImage); void DrawFramePoly(HDC hDCImage);
void DrawBackgroundPoly(HDC hDCImage, COLORREF crBg); void DrawBackgroundPoly(HDC hDCImage, COLORREF crBg);
void DrawBackgroundRect(HDC hDCImage, COLORREF crBg); void DrawBackgroundRect(HDC hDCImage, COLORREF crBg);
void DrawSelection(HDC hDCImage, LPCRECT prc, COLORREF crBg = 0, BOOL bBgTransparent = FALSE); void DrawSelection(HDC hDCImage, COLORREF crBg = 0, BOOL bBgTransparent = FALSE);
void InsertFromHBITMAP(HBITMAP hBm, INT x = 0, INT y = 0); void InsertFromHBITMAP(HBITMAP hBm, INT x = 0, INT y = 0);
// operation // operation
@ -48,7 +53,6 @@ public:
void RotateNTimes90Degrees(int iN); void RotateNTimes90Degrees(int iN);
void StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX, int nSkewDegY); void StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX, int nSkewDegY);
void CancelSelection();
void Dragging(CANVAS_HITTEST hit, POINT pt); void Dragging(CANVAS_HITTEST hit, POINT pt);
void ClearMask(); void ClearMask();
void ClearColor(); void ClearColor();
@ -57,5 +61,5 @@ private:
SelectionModel(const SelectionModel&); SelectionModel(const SelectionModel&);
SelectionModel& operator=(const SelectionModel&); SelectionModel& operator=(const SelectionModel&);
void ShiftPtStack(BOOL bPlus); void ShiftPtStack(INT dx, INT dy);
}; };

View file

@ -61,7 +61,7 @@ void CTextEditWindow::FixEditPos(LPCTSTR pszOldText)
SelectObject(hDC, m_hFontZoomed); SelectObject(hDC, m_hFontZoomed);
TEXTMETRIC tm; TEXTMETRIC tm;
GetTextMetrics(hDC, &tm); GetTextMetrics(hDC, &tm);
szText += TEXT("x"); // This is a trick to enable the last newlines szText += TEXT("x"); // This is a trick to enable the g_ptEnd newlines
const UINT uFormat = DT_LEFT | DT_TOP | DT_EDITCONTROL | DT_NOPREFIX | DT_NOCLIP | const UINT uFormat = DT_LEFT | DT_TOP | DT_EDITCONTROL | DT_NOPREFIX | DT_NOCLIP |
DT_EXPANDTABS | DT_WORDBREAK; DT_EXPANDTABS | DT_WORDBREAK;
DrawText(hDC, szText, -1, &rcText, uFormat | DT_CALCRECT); DrawText(hDC, szText, -1, &rcText, uFormat | DT_CALCRECT);
@ -235,7 +235,7 @@ HWND CTextEditWindow::Create(HWND hwndParent)
const DWORD style = ES_LEFT | ES_MULTILINE | ES_WANTRETURN | ES_AUTOVSCROLL | const DWORD style = ES_LEFT | ES_MULTILINE | ES_WANTRETURN | ES_AUTOVSCROLL |
WS_CHILD | WS_THICKFRAME; WS_CHILD | WS_THICKFRAME;
HWND hwnd = ::CreateWindowEx(0, WC_EDIT, NULL, style, 0, 0, 0, 0, HWND hwnd = ::CreateWindowEx(0, WC_EDIT, NULL, style, 0, 0, 0, 0,
hwndParent, NULL, hProgInstance, NULL); hwndParent, NULL, g_hinstExe, NULL);
if (hwnd) if (hwnd)
{ {
#undef SubclassWindow // Don't use this macro #undef SubclassWindow // Don't use this macro

View file

@ -13,6 +13,20 @@ CToolBox toolBoxContainer;
/* FUNCTIONS ********************************************************/ /* FUNCTIONS ********************************************************/
LRESULT CALLBACK
CPaintToolBar::ToolBarWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
WNDPROC oldWndProc = (WNDPROC)::GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (uMsg == WM_LBUTTONUP)
{
// We have to detect clicking on toolbar even if no change of pressed button
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
INT id = (INT)SendMessage(hwnd, TB_HITTEST, 0, (LPARAM)&pt);
::PostMessage(::GetParent(hwnd), WM_TOOLBARHIT, id, 0);
}
return ::CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);
}
BOOL CPaintToolBar::DoCreate(HWND hwndParent) BOOL CPaintToolBar::DoCreate(HWND hwndParent)
{ {
// NOTE: The horizontal line above the toolbar is hidden by CCS_NODIVIDER style. // NOTE: The horizontal line above the toolbar is hidden by CCS_NODIVIDER style.
@ -25,7 +39,7 @@ BOOL CPaintToolBar::DoCreate(HWND hwndParent)
HIMAGELIST hImageList = ImageList_Create(16, 16, ILC_COLOR24 | ILC_MASK, 16, 0); HIMAGELIST hImageList = ImageList_Create(16, 16, ILC_COLOR24 | ILC_MASK, 16, 0);
SendMessage(TB_SETIMAGELIST, 0, (LPARAM)hImageList); SendMessage(TB_SETIMAGELIST, 0, (LPARAM)hImageList);
HBITMAP hbmIcons = (HBITMAP)::LoadImage(hProgInstance, MAKEINTRESOURCE(IDB_TOOLBARICONS), HBITMAP hbmIcons = (HBITMAP)::LoadImage(g_hinstExe, MAKEINTRESOURCE(IDB_TOOLBARICONS),
IMAGE_BITMAP, 256, 16, 0); IMAGE_BITMAP, 256, 16, 0);
ImageList_AddMasked(hImageList, hbmIcons, RGB(255, 0, 255)); ImageList_AddMasked(hImageList, hbmIcons, RGB(255, 0, 255));
::DeleteObject(hbmIcons); ::DeleteObject(hbmIcons);
@ -38,7 +52,7 @@ BOOL CPaintToolBar::DoCreate(HWND hwndParent)
tbbutton.fsStyle = TBSTYLE_CHECKGROUP; tbbutton.fsStyle = TBSTYLE_CHECKGROUP;
for (INT i = 0; i < NUM_TOOLS; i++) for (INT i = 0; i < NUM_TOOLS; i++)
{ {
::LoadString(hProgInstance, IDS_TOOLTIP1 + i, szToolTip, _countof(szToolTip)); ::LoadString(g_hinstExe, IDS_TOOLTIP1 + i, szToolTip, _countof(szToolTip));
tbbutton.iString = (INT_PTR)szToolTip; tbbutton.iString = (INT_PTR)szToolTip;
tbbutton.fsState = TBSTATE_ENABLED | ((i % 2 == 1) ? TBSTATE_WRAP : 0); tbbutton.fsState = TBSTATE_ENABLED | ((i % 2 == 1) ? TBSTATE_WRAP : 0);
tbbutton.idCommand = ID_FREESEL + i; tbbutton.idCommand = ID_FREESEL + i;
@ -49,6 +63,8 @@ BOOL CPaintToolBar::DoCreate(HWND hwndParent)
SendMessage(TB_CHECKBUTTON, ID_PEN, MAKELPARAM(TRUE, 0)); SendMessage(TB_CHECKBUTTON, ID_PEN, MAKELPARAM(TRUE, 0));
SendMessage(TB_SETMAXTEXTROWS, 0, 0); SendMessage(TB_SETMAXTEXTROWS, 0, 0);
SendMessage(TB_SETBUTTONSIZE, 0, MAKELPARAM(CXY_TB_BUTTON, CXY_TB_BUTTON)); SendMessage(TB_SETBUTTONSIZE, 0, MAKELPARAM(CXY_TB_BUTTON, CXY_TB_BUTTON));
SetWindowLongPtr(GWLP_USERDATA, SetWindowLongPtr(GWLP_WNDPROC, (LONG_PTR)ToolBarWndProc));
return TRUE; return TRUE;
} }
@ -114,7 +130,7 @@ LRESULT CToolBox::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHand
LRESULT CToolBox::OnToolsModelToolChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) LRESULT CToolBox::OnToolsModelToolChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{ {
selectionModel.m_bShow = FALSE; selectionModel.HideSelection();
toolsModel.resetTool(); // resets the point-buffer of the polygon and bezier functions toolsModel.resetTool(); // resets the point-buffer of the polygon and bezier functions
// Check the toolbar button // Check the toolbar button
@ -168,3 +184,10 @@ LRESULT CToolBox::OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHa
::ReleaseCapture(); ::ReleaseCapture();
return 0; return 0;
} }
LRESULT CToolBox::OnToolBarHit(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// See also: CPaintToolBar::ToolBarWndProc
selectionModel.Landing();
return 0;
}

View file

@ -15,10 +15,13 @@
#define CX_TOOLBAR (TOOLBAR_COLUMNS * CXY_TB_BUTTON) #define CX_TOOLBAR (TOOLBAR_COLUMNS * CXY_TB_BUTTON)
#define CY_TOOLBAR (TOOLBAR_ROWS * CXY_TB_BUTTON) #define CY_TOOLBAR (TOOLBAR_ROWS * CXY_TB_BUTTON)
#define WM_TOOLBARHIT (WM_APP + 1)
class CPaintToolBar : public CWindow class CPaintToolBar : public CWindow
{ {
public: public:
BOOL DoCreate(HWND hwndParent); BOOL DoCreate(HWND hwndParent);
static LRESULT CALLBACK ToolBarWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
}; };
class CToolBox : public CWindowImpl<CToolBox> class CToolBox : public CWindowImpl<CToolBox>
@ -34,6 +37,7 @@ public:
MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
MESSAGE_HANDLER(WM_TOOLSMODELTOOLCHANGED, OnToolsModelToolChanged) MESSAGE_HANDLER(WM_TOOLSMODELTOOLCHANGED, OnToolsModelToolChanged)
MESSAGE_HANDLER(WM_TOOLBARHIT, OnToolBarHit)
END_MSG_MAP() END_MSG_MAP()
BOOL DoCreate(HWND hwndParent); BOOL DoCreate(HWND hwndParent);
@ -48,4 +52,5 @@ private:
LRESULT OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnToolsModelToolChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnToolsModelToolChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnToolBarHit(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
}; };

View file

@ -200,11 +200,14 @@ VOID CToolSettingsWindow::drawAirBrush(HDC hdc, LPCRECT prc)
if (bHigh) if (bHigh)
{ {
::FillRect(hdc, &rc, ::GetSysColorBrush(COLOR_HIGHLIGHT)); ::FillRect(hdc, &rc, ::GetSysColorBrush(COLOR_HIGHLIGHT));
Airbrush(hdc, x, y, ::GetSysColor(COLOR_HIGHLIGHTTEXT), s_AirRadius[i]);
for (int k = 0; k < 3; ++k)
Airbrush(hdc, x, y, ::GetSysColor(COLOR_HIGHLIGHTTEXT), s_AirRadius[i]);
} }
else else
{ {
Airbrush(hdc, x, y, ::GetSysColor(COLOR_WINDOWTEXT), s_AirRadius[i]); for (int k = 0; k < 3; ++k)
Airbrush(hdc, x, y, ::GetSysColor(COLOR_WINDOWTEXT), s_AirRadius[i]);
} }
} }
} }
@ -258,9 +261,9 @@ VOID CToolSettingsWindow::drawBox(HDC hdc, LPCRECT prc)
LRESULT CToolSettingsWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, WINBOOL& bHandled) LRESULT CToolSettingsWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, WINBOOL& bHandled)
{ {
/* preloading the draw transparent/nontransparent icons for later use */ /* preloading the draw transparent/nontransparent icons for later use */
m_hNontranspIcon = (HICON)LoadImage(hProgInstance, MAKEINTRESOURCE(IDI_NONTRANSPARENT), m_hNontranspIcon = (HICON)LoadImage(g_hinstExe, MAKEINTRESOURCE(IDI_NONTRANSPARENT),
IMAGE_ICON, CX_TRANS_ICON, CY_TRANS_ICON, LR_DEFAULTCOLOR); IMAGE_ICON, CX_TRANS_ICON, CY_TRANS_ICON, LR_DEFAULTCOLOR);
m_hTranspIcon = (HICON)LoadImage(hProgInstance, MAKEINTRESOURCE(IDI_TRANSPARENT), m_hTranspIcon = (HICON)LoadImage(g_hinstExe, MAKEINTRESOURCE(IDI_TRANSPARENT),
IMAGE_ICON, CX_TRANS_ICON, CY_TRANS_ICON, LR_DEFAULTCOLOR); IMAGE_ICON, CX_TRANS_ICON, CY_TRANS_ICON, LR_DEFAULTCOLOR);
RECT trackbarZoomPos = {1, 1, 1 + 40, 1 + 64}; RECT trackbarZoomPos = {1, 1, 1 + 40, 1 + 64};

View file

@ -28,7 +28,7 @@ ToolsModel::ToolsModel()
ToolsModel::~ToolsModel() ToolsModel::~ToolsModel()
{ {
for (size_t i = 0; i < TOOL_MAX + 1; ++i) for (size_t i = 0; i < _countof(m_tools); ++i)
delete m_tools[i]; delete m_tools[i];
} }
@ -87,9 +87,6 @@ void ToolsModel::SetActiveTool(TOOLTYPE nActiveTool)
{ {
OnFinishDraw(); OnFinishDraw();
if (m_activeTool == nActiveTool)
return;
switch (m_activeTool) switch (m_activeTool)
{ {
case TOOL_FREESEL: case TOOL_FREESEL:
@ -225,6 +222,16 @@ void ToolsModel::OnFinishDraw()
m_pToolObject->endEvent(); m_pToolObject->endEvent();
} }
void ToolsModel::OnDrawOverlayOnImage(HDC hdc)
{
m_pToolObject->OnDrawOverlayOnImage(hdc);
}
void ToolsModel::OnDrawOverlayOnCanvas(HDC hdc)
{
m_pToolObject->OnDrawOverlayOnCanvas(hdc);
}
void ToolsModel::resetTool() void ToolsModel::resetTool()
{ {
m_pToolObject->reset(); m_pToolObject->reset();

View file

@ -39,34 +39,27 @@ struct ToolBase
static INT pointSP; static INT pointSP;
static POINT pointStack[256]; static POINT pointStack[256];
ToolBase(TOOLTYPE tool) : m_tool(tool), m_hdc(NULL) ToolBase(TOOLTYPE tool) : m_tool(tool), m_hdc(NULL) { }
{ virtual ~ToolBase() { }
}
virtual ~ToolBase() virtual void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) { }
{ virtual void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) { }
} virtual void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) { }
virtual void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick)
{
}
virtual void OnMouseMove(BOOL bLeftButton, LONG x, LONG y)
{
}
virtual void OnButtonUp(BOOL bLeftButton, LONG x, LONG y)
{
}
virtual void OnCancelDraw(); virtual void OnCancelDraw();
virtual void OnFinishDraw(); virtual void OnFinishDraw();
virtual void OnDrawOverlayOnImage(HDC hdc) { }
virtual void OnDrawOverlayOnCanvas(HDC hdc) { }
void beginEvent(); void beginEvent();
void endEvent(); void endEvent();
void reset(); void reset();
static ToolBase* createToolObject(TOOLTYPE type); static ToolBase* createToolObject(TOOLTYPE type);
protected:
void OnDrawSelectionOnCanvas(HDC hdc);
}; };
class ToolsModel class ToolsModel
@ -112,6 +105,8 @@ public:
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y); void OnButtonUp(BOOL bLeftButton, LONG x, LONG y);
void OnCancelDraw(); void OnCancelDraw();
void OnFinishDraw(); void OnFinishDraw();
void OnDrawOverlayOnImage(HDC hdc);
void OnDrawOverlayOnCanvas(HDC hdc);
void resetTool(); void resetTool();
void selectAll(); void selectAll();

View file

@ -17,7 +17,7 @@ typedef HWND (WINAPI *FN_HtmlHelpW)(HWND, LPCWSTR, UINT, DWORD_PTR);
static HINSTANCE s_hHHCTRL_OCX = NULL; // HtmlHelpW needs "hhctrl.ocx" static HINSTANCE s_hHHCTRL_OCX = NULL; // HtmlHelpW needs "hhctrl.ocx"
static FN_HtmlHelpW s_pHtmlHelpW = NULL; static FN_HtmlHelpW s_pHtmlHelpW = NULL;
HWND hStatusBar = NULL; HWND g_hStatusBar = NULL;
/* FUNCTIONS ********************************************************/ /* FUNCTIONS ********************************************************/
@ -79,9 +79,9 @@ void CMainWindow::alignChildrenToMainWindow()
GetClientRect(&clientRect); GetClientRect(&clientRect);
RECT rcSpace = clientRect; RECT rcSpace = clientRect;
if (::IsWindowVisible(hStatusBar)) if (::IsWindowVisible(g_hStatusBar))
{ {
::GetWindowRect(hStatusBar, &rc); ::GetWindowRect(g_hStatusBar, &rc);
rcSpace.bottom -= rc.bottom - rc.top; rcSpace.bottom -= rc.bottom - rc.top;
} }
@ -142,18 +142,18 @@ void CMainWindow::saveImage(BOOL overwrite)
{ {
canvasWindow.finishDrawing(); canvasWindow.finishDrawing();
if (isAFile && overwrite) if (g_isAFile && overwrite)
{ {
imageModel.SaveImage(filepathname); imageModel.SaveImage(g_szFileName);
} }
else if (GetSaveFileName(filepathname, _countof(filepathname))) else if (GetSaveFileName(g_szFileName, _countof(g_szFileName)))
{ {
imageModel.SaveImage(filepathname); imageModel.SaveImage(g_szFileName);
CString strTitle; CString strTitle;
strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(filepathname)); strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(g_szFileName));
SetWindowText(strTitle); SetWindowText(strTitle);
isAFile = TRUE; g_isAFile = TRUE;
} }
} }
@ -168,13 +168,13 @@ void CMainWindow::InsertSelectionFromHBITMAP(HBITMAP bitmap, HWND window)
{ {
BOOL shouldEnlarge = TRUE; BOOL shouldEnlarge = TRUE;
if (askBeforeEnlarging) if (g_askBeforeEnlarging)
{ {
TCHAR programname[20]; TCHAR programname[20];
TCHAR shouldEnlargePromptText[100]; TCHAR shouldEnlargePromptText[100];
LoadString(hProgInstance, IDS_PROGRAMNAME, programname, _countof(programname)); LoadString(g_hinstExe, IDS_PROGRAMNAME, programname, _countof(programname));
LoadString(hProgInstance, IDS_ENLARGEPROMPTTEXT, shouldEnlargePromptText, _countof(shouldEnlargePromptText)); LoadString(g_hinstExe, IDS_ENLARGEPROMPTTEXT, shouldEnlargePromptText, _countof(shouldEnlargePromptText));
switch (MessageBox(shouldEnlargePromptText, programname, MB_YESNOCANCEL | MB_ICONQUESTION)) switch (MessageBox(shouldEnlargePromptText, programname, MB_YESNOCANCEL | MB_ICONQUESTION))
{ {
@ -276,14 +276,14 @@ LRESULT CMainWindow::OnDropFiles(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL&
LRESULT CMainWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) LRESULT CMainWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{ {
// Loading and setting the window menu from resource // Loading and setting the window menu from resource
m_hMenu = ::LoadMenu(hProgInstance, MAKEINTRESOURCE(ID_MENU)); m_hMenu = ::LoadMenu(g_hinstExe, MAKEINTRESOURCE(ID_MENU));
SetMenu(m_hMenu); SetMenu(m_hMenu);
// Create the status bar // Create the status bar
DWORD style = SBARS_SIZEGRIP | WS_CHILD | (registrySettings.ShowStatusBar ? WS_VISIBLE : 0); DWORD style = SBARS_SIZEGRIP | WS_CHILD | (registrySettings.ShowStatusBar ? WS_VISIBLE : 0);
hStatusBar = ::CreateWindowEx(0, STATUSCLASSNAME, NULL, style, 0, 0, 0, 0, m_hWnd, g_hStatusBar = ::CreateWindowEx(0, STATUSCLASSNAME, NULL, style, 0, 0, 0, 0, m_hWnd,
NULL, hProgInstance, NULL); NULL, g_hinstExe, NULL);
::SendMessage(hStatusBar, SB_SETMINHEIGHT, 21, 0); ::SendMessage(g_hStatusBar, SB_SETMINHEIGHT, 21, 0);
// Create the tool box // Create the tool box
toolBoxContainer.DoCreate(m_hWnd); toolBoxContainer.DoCreate(m_hWnd);
@ -305,8 +305,8 @@ LRESULT CMainWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHa
} }
// Set icon // Set icon
SendMessage(WM_SETICON, ICON_BIG, (LPARAM) LoadIcon(hProgInstance, MAKEINTRESOURCE(IDI_APPICON))); SendMessage(WM_SETICON, ICON_BIG, (LPARAM) LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDI_APPICON)));
SendMessage(WM_SETICON, ICON_SMALL, (LPARAM) LoadIcon(hProgInstance, MAKEINTRESOURCE(IDI_APPICON))); SendMessage(WM_SETICON, ICON_SMALL, (LPARAM) LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDI_APPICON)));
return 0; return 0;
} }
@ -347,7 +347,7 @@ BOOL CMainWindow::ConfirmSave()
strProgramName.LoadString(IDS_PROGRAMNAME); strProgramName.LoadString(IDS_PROGRAMNAME);
CString strSavePromptText; CString strSavePromptText;
strSavePromptText.Format(IDS_SAVEPROMPTTEXT, PathFindFileName(filepathname)); strSavePromptText.Format(IDS_SAVEPROMPTTEXT, PathFindFileName(g_szFileName));
switch (MessageBox(strSavePromptText, strProgramName, MB_YESNOCANCEL | MB_ICONQUESTION)) switch (MessageBox(strSavePromptText, strProgramName, MB_YESNOCANCEL | MB_ICONQUESTION))
{ {
@ -374,7 +374,7 @@ LRESULT CMainWindow::OnClose(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHan
void CMainWindow::ProcessFileMenu(HMENU hPopupMenu) void CMainWindow::ProcessFileMenu(HMENU hPopupMenu)
{ {
LPCTSTR dotext = PathFindExtensionW(filepathname); LPCTSTR dotext = PathFindExtensionW(g_szFileName);
BOOL isBMP = FALSE; BOOL isBMP = FALSE;
if (_tcsicmp(dotext, _T(".bmp")) == 0 || if (_tcsicmp(dotext, _T(".bmp")) == 0 ||
_tcsicmp(dotext, _T(".dib")) == 0 || _tcsicmp(dotext, _T(".dib")) == 0 ||
@ -383,9 +383,9 @@ void CMainWindow::ProcessFileMenu(HMENU hPopupMenu)
isBMP = TRUE; isBMP = TRUE;
} }
EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERPLANE, ENABLED_IF(isAFile && isBMP)); EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERPLANE, ENABLED_IF(g_isAFile && isBMP));
EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERCENTERED, ENABLED_IF(isAFile && isBMP)); EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERCENTERED, ENABLED_IF(g_isAFile && isBMP));
EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERSTRETCHED, ENABLED_IF(isAFile && isBMP)); EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERSTRETCHED, ENABLED_IF(g_isAFile && isBMP));
for (INT iItem = 0; iItem < MAX_RECENT_FILES; ++iItem) for (INT iItem = 0; iItem < MAX_RECENT_FILES; ++iItem)
RemoveMenu(hPopupMenu, IDM_FILE1 + iItem, MF_BYCOMMAND); RemoveMenu(hPopupMenu, IDM_FILE1 + iItem, MF_BYCOMMAND);
@ -445,11 +445,11 @@ LRESULT CMainWindow::OnInitMenuPopup(UINT nMsg, WPARAM wParam, LPARAM lParam, BO
case 2: /* View menu */ case 2: /* View menu */
CheckMenuItem(menu, IDM_VIEWTOOLBOX, CHECKED_IF(::IsWindowVisible(toolBoxContainer))); CheckMenuItem(menu, IDM_VIEWTOOLBOX, CHECKED_IF(::IsWindowVisible(toolBoxContainer)));
CheckMenuItem(menu, IDM_VIEWCOLORPALETTE, CHECKED_IF(::IsWindowVisible(paletteWindow))); CheckMenuItem(menu, IDM_VIEWCOLORPALETTE, CHECKED_IF(::IsWindowVisible(paletteWindow)));
CheckMenuItem(menu, IDM_VIEWSTATUSBAR, CHECKED_IF(::IsWindowVisible(hStatusBar))); CheckMenuItem(menu, IDM_VIEWSTATUSBAR, CHECKED_IF(::IsWindowVisible(g_hStatusBar)));
CheckMenuItem(menu, IDM_FORMATICONBAR, CHECKED_IF(::IsWindowVisible(fontsDialog))); CheckMenuItem(menu, IDM_FORMATICONBAR, CHECKED_IF(::IsWindowVisible(fontsDialog)));
EnableMenuItem(menu, IDM_FORMATICONBAR, ENABLED_IF(toolsModel.GetActiveTool() == TOOL_TEXT)); EnableMenuItem(menu, IDM_FORMATICONBAR, ENABLED_IF(toolsModel.GetActiveTool() == TOOL_TEXT));
CheckMenuItem(menu, IDM_VIEWSHOWGRID, CHECKED_IF(showGrid)); CheckMenuItem(menu, IDM_VIEWSHOWGRID, CHECKED_IF(g_showGrid));
CheckMenuItem(menu, IDM_VIEWSHOWMINIATURE, CHECKED_IF(registrySettings.ShowThumbnail)); CheckMenuItem(menu, IDM_VIEWSHOWMINIATURE, CHECKED_IF(registrySettings.ShowThumbnail));
break; break;
case 3: /* Image menu */ case 3: /* Image menu */
@ -474,10 +474,10 @@ LRESULT CMainWindow::OnInitMenuPopup(UINT nMsg, WPARAM wParam, LPARAM lParam, BO
LRESULT CMainWindow::OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) LRESULT CMainWindow::OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{ {
int test[] = { LOWORD(lParam) - 260, LOWORD(lParam) - 140, LOWORD(lParam) - 20 }; int test[] = { LOWORD(lParam) - 260, LOWORD(lParam) - 140, LOWORD(lParam) - 20 };
if (::IsWindow(hStatusBar)) if (::IsWindow(g_hStatusBar))
{ {
::SendMessage(hStatusBar, WM_SIZE, 0, 0); ::SendMessage(g_hStatusBar, WM_SIZE, 0, 0);
::SendMessage(hStatusBar, SB_SETPARTS, 3, (LPARAM)&test); ::SendMessage(g_hStatusBar, SB_SETPARTS, 3, (LPARAM)&test);
} }
alignChildrenToMainWindow(); alignChildrenToMainWindow();
return 0; return 0;
@ -508,9 +508,11 @@ LRESULT CMainWindow::OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
} }
else if (selectionModel.m_bShow) else if (selectionModel.m_bShow)
{ {
selectionModel.Landing(); selectionModel.HideSelection();
selectionModel.m_bShow = FALSE; }
imageModel.NotifyImageChanged(); else
{
canvasWindow.cancelDrawing();
} }
break; break;
@ -551,11 +553,11 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
{ {
case IDM_HELPINFO: case IDM_HELPINFO:
{ {
HICON paintIcon = LoadIcon(hProgInstance, MAKEINTRESOURCE(IDI_APPICON)); HICON paintIcon = LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDI_APPICON));
TCHAR infotitle[100]; TCHAR infotitle[100];
TCHAR infotext[200]; TCHAR infotext[200];
LoadString(hProgInstance, IDS_INFOTITLE, infotitle, _countof(infotitle)); LoadString(g_hinstExe, IDS_INFOTITLE, infotitle, _countof(infotitle));
LoadString(hProgInstance, IDS_INFOTEXT, infotext, _countof(infotext)); LoadString(g_hinstExe, IDS_INFOTEXT, infotext, _countof(infotext));
ShellAbout(m_hWnd, infotitle, infotext, paintIcon); ShellAbout(m_hWnd, infotitle, infotext, paintIcon);
DeleteObject(paintIcon); DeleteObject(paintIcon);
break; break;
@ -620,13 +622,13 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
GlobalFree(pd.hDevNames); GlobalFree(pd.hDevNames);
break; break;
case IDM_FILEASWALLPAPERPLANE: case IDM_FILEASWALLPAPERPLANE:
RegistrySettings::SetWallpaper(filepathname, RegistrySettings::TILED); RegistrySettings::SetWallpaper(g_szFileName, RegistrySettings::TILED);
break; break;
case IDM_FILEASWALLPAPERCENTERED: case IDM_FILEASWALLPAPERCENTERED:
RegistrySettings::SetWallpaper(filepathname, RegistrySettings::CENTERED); RegistrySettings::SetWallpaper(g_szFileName, RegistrySettings::CENTERED);
break; break;
case IDM_FILEASWALLPAPERSTRETCHED: case IDM_FILEASWALLPAPERSTRETCHED:
RegistrySettings::SetWallpaper(filepathname, RegistrySettings::STRETCHED); RegistrySettings::SetWallpaper(g_szFileName, RegistrySettings::STRETCHED);
break; break;
case IDM_FILE1: case IDM_FILE1:
case IDM_FILE2: case IDM_FILE2:
@ -640,7 +642,10 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
} }
case IDM_EDITUNDO: case IDM_EDITUNDO:
if (toolsModel.GetActiveTool() == TOOL_TEXT && ::IsWindowVisible(textEditWindow)) if (toolsModel.GetActiveTool() == TOOL_TEXT && ::IsWindowVisible(textEditWindow))
{
textEditWindow.PostMessage(WM_UNDO, 0, 0);
break; break;
}
if (selectionModel.m_bShow) if (selectionModel.m_bShow)
{ {
if (toolsModel.GetActiveTool() == TOOL_RECTSEL || if (toolsModel.GetActiveTool() == TOOL_RECTSEL ||
@ -668,10 +673,19 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
imageModel.Redo(); imageModel.Redo();
break; break;
case IDM_EDITCOPY: case IDM_EDITCOPY:
// FIXME: We should use CF_DIB in the future
if (OpenClipboard()) if (OpenClipboard())
{ {
EmptyClipboard(); EmptyClipboard();
SetClipboardData(CF_BITMAP, CopyDIBImage(selectionModel.GetBitmap())); if (selectionModel.m_bShow)
{
selectionModel.TakeOff();
SetClipboardData(CF_BITMAP, selectionModel.CopyBitmap());
}
else
{
SetClipboardData(CF_BITMAP, imageModel.CopyBitmap());
}
CloseClipboard(); CloseClipboard();
} }
break; break;
@ -695,7 +709,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
{ {
case TOOL_FREESEL: case TOOL_FREESEL:
case TOOL_RECTSEL: case TOOL_RECTSEL:
imageModel.DeleteSelection(); selectionModel.DeleteSelection();
break; break;
case TOOL_TEXT: case TOOL_TEXT:
@ -723,7 +737,11 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
{ {
TCHAR szFileName[MAX_LONG_PATH] = _T(""); TCHAR szFileName[MAX_LONG_PATH] = _T("");
if (GetSaveFileName(szFileName, _countof(szFileName))) if (GetSaveFileName(szFileName, _countof(szFileName)))
SaveDIBToFile(selectionModel.GetBitmap(), szFileName, imageModel.GetDC()); {
HBITMAP hbm = selectionModel.CopyBitmap();
SaveDIBToFile(hbm, szFileName, imageModel.GetDC());
::DeleteObject(hbm);
}
break; break;
} }
case IDM_EDITPASTEFROM: case IDM_EDITPASTEFROM:
@ -827,8 +845,8 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
toolsModel.SetBackgroundTransparent(!toolsModel.IsBackgroundTransparent()); toolsModel.SetBackgroundTransparent(!toolsModel.IsBackgroundTransparent());
break; break;
case IDM_IMAGECROP: case IDM_IMAGECROP:
imageModel.PushImageForUndo(CopyDIBImage(selectionModel.GetBitmap())); imageModel.PushImageForUndo(selectionModel.CopyBitmap());
imageModel.DeleteSelection(); selectionModel.HideSelection();
break; break;
case IDM_VIEWTOOLBOX: case IDM_VIEWTOOLBOX:
@ -842,8 +860,8 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
alignChildrenToMainWindow(); alignChildrenToMainWindow();
break; break;
case IDM_VIEWSTATUSBAR: case IDM_VIEWSTATUSBAR:
registrySettings.ShowStatusBar = !::IsWindowVisible(hStatusBar); registrySettings.ShowStatusBar = !::IsWindowVisible(g_hStatusBar);
::ShowWindow(hStatusBar, (registrySettings.ShowStatusBar ? SW_SHOWNOACTIVATE : SW_HIDE)); ::ShowWindow(g_hStatusBar, (registrySettings.ShowStatusBar ? SW_SHOWNOACTIVATE : SW_HIDE));
alignChildrenToMainWindow(); alignChildrenToMainWindow();
break; break;
case IDM_FORMATICONBAR: case IDM_FORMATICONBAR:
@ -859,7 +877,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
} }
break; break;
case IDM_VIEWSHOWGRID: case IDM_VIEWSHOWGRID:
showGrid = !showGrid; g_showGrid = !g_showGrid;
canvasWindow.Invalidate(FALSE); canvasWindow.Invalidate(FALSE);
break; break;
case IDM_VIEWSHOWMINIATURE: case IDM_VIEWSHOWMINIATURE: