[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_whereHit(HIT_NONE)
, m_ptOrig { -1, -1 }
, m_hbmCached(NULL)
{
m_ahbmCached[0] = m_ahbmCached[1] = NULL;
::SetRectEmpty(&m_rcNew);
}
CCanvasWindow::~CCanvasWindow()
{
if (m_hbmCached)
::DeleteObject(m_hbmCached);
if (m_ahbmCached[0])
::DeleteObject(m_ahbmCached[0]);
if (m_ahbmCached[1])
::DeleteObject(m_ahbmCached[1]);
}
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)
{
// We use a memory bitmap to reduce flickering
HDC hdcMem = ::CreateCompatibleDC(hDC);
m_hbmCached = CachedBufferDIB(m_hbmCached, rcClient.right, rcClient.bottom);
HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_hbmCached);
HDC hdcMem0 = ::CreateCompatibleDC(hDC);
m_ahbmCached[0] = CachedBufferDIB(m_ahbmCached[0], rcClient.right, rcClient.bottom);
HGDIOBJ hbm0Old = ::SelectObject(hdcMem0, m_ahbmCached[0]);
// Fill the background
::FillRect(hdcMem, &rcPaint, (HBRUSH)(COLOR_APPWORKSPACE + 1));
// Fill the background on hdcMem0
::FillRect(hdcMem0, &rcPaint, (HBRUSH)(COLOR_APPWORKSPACE + 1));
// Draw the sizeboxes if necessary
RECT rcBase = GetBaseRect();
if (!selectionModel.m_bShow)
drawSizeBoxes(hdcMem, &rcBase, FALSE, &rcPaint);
drawSizeBoxes(hdcMem0, &rcBase, FALSE, &rcPaint);
// Draw the image
// Calculate image size
CRect rcImage;
GetImageRect(rcImage);
ImageToCanvas(rcImage);
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
if (showGrid && toolsModel.GetZoom() >= 4000)
// hdcMem1 <-- imageModel
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++)
{
POINT pt0 = { 0, counter }, pt1 = { sizeImage.cx, counter };
ImageToCanvas(pt0);
ImageToCanvas(pt1);
::MoveToEx(hdcMem, pt0.x, pt0.y, NULL);
::LineTo(hdcMem, pt1.x, pt1.y);
::MoveToEx(hdcMem0, pt0.x, pt0.y, NULL);
::LineTo(hdcMem0, pt1.x, pt1.y);
}
for (INT counter = 0; counter < sizeImage.cx; counter++)
{
POINT pt0 = { counter, 0 }, pt1 = { counter, sizeImage.cy };
ImageToCanvas(pt0);
ImageToCanvas(pt1);
::MoveToEx(hdcMem, pt0.x, pt0.y, NULL);
::LineTo(hdcMem, pt1.x, pt1.y);
::MoveToEx(hdcMem0, pt0.x, pt0.y, NULL);
::LineTo(hdcMem0, pt1.x, pt1.y);
}
::DeleteObject(::SelectObject(hdcMem, oldPen));
::DeleteObject(::SelectObject(hdcMem0, oldPen));
}
// Draw selection
if (selectionModel.m_bShow)
{
RECT rcSelection = selectionModel.m_rc;
ImageToCanvas(rcSelection);
// Draw overlay #2 on hdcMem0
toolsModel.OnDrawOverlayOnCanvas(hdcMem0);
::InflateRect(&rcSelection, GRIP_SIZE, GRIP_SIZE);
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
// Draw new frame on hdcMem0 if any
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,
rcPaint.left, 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);
::DeleteDC(hdcMem);
// Clean up hdcMem0
::SelectObject(hdcMem0, hbm0Old);
::DeleteDC(hdcMem0);
}
VOID CCanvasWindow::Update(HWND hwndFrom)
@ -383,15 +387,15 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
{
CString strCoord;
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)
{
// values displayed in statusbar
LONG xRel = pt.x - start.x;
LONG yRel = pt.y - start.y;
LONG xRel = pt.x - g_ptStart.x;
LONG yRel = pt.y - g_ptStart.y;
switch (toolsModel.GetActiveTool())
{
@ -400,13 +404,13 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
case TOOL_RECTSEL:
case TOOL_TEXT:
if (xRel < 0)
xRel = (pt.x < 0) ? -start.x : xRel;
xRel = (pt.x < 0) ? -g_ptStart.x : xRel;
else if (pt.x > imageModel.GetWidth())
xRel = imageModel.GetWidth() - start.x;
xRel = imageModel.GetWidth() - g_ptStart.x;
if (yRel < 0)
yRel = (pt.y < 0) ? -start.y : yRel;
yRel = (pt.y < 0) ? -g_ptStart.y : yRel;
else if (pt.y > imageModel.GetHeight())
yRel = imageModel.GetHeight() - start.y;
yRel = imageModel.GetHeight() - g_ptStart.y;
break;
// 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;
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;
}
default:
@ -444,7 +448,7 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
if ((toolsModel.GetActiveTool() >= TOOL_LINE) && (GetAsyncKeyState(VK_SHIFT) < 0))
yRel = xRel;
strSize.Format(_T("%ld x %ld"), xRel, yRel);
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize);
::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))
yRel = xRel;
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;
@ -514,7 +518,7 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
// Display new size
CString strSize;
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 };
switch (m_whereHit)
@ -556,7 +560,7 @@ LRESULT CCanvasWindow::OnLRButtonUp(BOOL bLeftButton, UINT nMsg, WPARAM wParam,
m_drawing = FALSE;
toolsModel.OnButtonUp(bLeftButton, pt.x, pt.y);
Invalidate(FALSE);
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) "");
::SendMessage(g_hStatusBar, SB_SETTEXT, 2, (LPARAM)_T(""));
return 0;
}
else if (m_hitSelection != HIT_NONE && bLeftButton)
@ -603,7 +607,7 @@ LRESULT CCanvasWindow::OnLRButtonUp(BOOL bLeftButton, UINT nMsg, WPARAM wParam,
}
::SetRectEmpty(&m_rcNew);
imageSaved = FALSE;
g_imageSaved = FALSE;
m_whereHit = HIT_NONE;
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())
{
case TOOL_FILL:
::SetCursor(::LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_FILL)));
::SetCursor(::LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDC_FILL)));
break;
case TOOL_COLOR:
::SetCursor(::LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_COLOR)));
::SetCursor(::LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDC_COLOR)));
break;
case TOOL_ZOOM:
::SetCursor(::LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_ZOOM)));
::SetCursor(::LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDC_ZOOM)));
break;
case TOOL_PEN:
::SetCursor(::LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_PEN)));
::SetCursor(::LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDC_PEN)));
break;
case TOOL_AIRBRUSH:
::SetCursor(::LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_AIRBRUSH)));
::SetCursor(::LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDC_AIRBRUSH)));
break;
default:
::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)
{
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM)_T(""));
::SendMessage(g_hStatusBar, SB_SETTEXT, 2, (LPARAM)_T(""));
return 0;
}
@ -800,3 +804,9 @@ LRESULT CCanvasWindow::OnCtlColorEdit(UINT nMsg, WPARAM wParam, LPARAM lParam, B
SetBkMode((HDC)wParam, TRANSPARENT);
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_CAPTURECHANGED, OnCaptureChanged)
MESSAGE_HANDLER(WM_CTLCOLOREDIT, OnCtlColorEdit)
MESSAGE_HANDLER(WM_PALETTEMODELCOLORCHANGED, OnPaletteModelColorChanged)
END_MSG_MAP()
CCanvasWindow();
@ -55,7 +56,7 @@ protected:
CANVAS_HITTEST m_hitSelection;
CANVAS_HITTEST m_whereHit;
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;
CANVAS_HITTEST CanvasHitTest(POINT pt);
@ -87,6 +88,7 @@ protected:
LRESULT OnCancelMode(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 OnPaletteModelColorChanged(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);

View file

@ -20,7 +20,6 @@
#define WM_TOOLSMODELSETTINGSCHANGED (WM_APP + 1)
#define WM_TOOLSMODELZOOMCHANGED (WM_APP + 2)
#define WM_PALETTEMODELCOLORCHANGED (WM_APP + 3)
#define WM_PALETTEMODELPALETTECHANGED (WM_APP + 4)
/* this simplifies checking and unchecking menu items */
#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_ATTRIBUTESEDIT2, newHeight, FALSE);
if (isAFile)
if (g_isAFile)
{
TCHAR date[100];
TCHAR temp[100];
GetDateFormat(LOCALE_USER_DEFAULT, 0, &fileTime, NULL, date, _countof(date));
GetTimeFormat(LOCALE_USER_DEFAULT, 0, &fileTime, NULL, temp, _countof(temp));
GetDateFormat(LOCALE_USER_DEFAULT, 0, &g_fileTime, NULL, date, _countof(date));
GetTimeFormat(LOCALE_USER_DEFAULT, 0, &g_fileTime, NULL, temp, _countof(temp));
_tcscat(date, _T(" "));
_tcscat(date, temp);
CString strSize;
strSize.Format(IDS_FILESIZE, fileSize);
strSize.Format(IDS_FILESIZE, g_fileSize);
SetDlgItemText(IDD_ATTRIBUTESTEXT6, date);
SetDlgItemText(IDD_ATTRIBUTESTEXT7, strSize);
}
@ -240,9 +240,9 @@ LRESULT CStretchSkewDialog::OnOk(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&
CString strrcAngle;
BOOL tr1, tr2, tr3, tr4;
strrcIntNumbers.LoadString(hProgInstance, IDS_INTNUMBERS);
strrcPercentage.LoadString(hProgInstance, IDS_PERCENTAGE);
strrcAngle.LoadString(hProgInstance, IDS_ANGLE);
strrcIntNumbers.LoadString(g_hinstExe, IDS_INTNUMBERS);
strrcPercentage.LoadString(g_hinstExe, IDS_PERCENTAGE);
strrcAngle.LoadString(g_hinstExe, IDS_ANGLE);
percentage.x = GetDlgItemInt(IDD_STRETCHSKEWEDITHSTRETCH, &tr1, FALSE);
percentage.y = GetDlgItemInt(IDD_STRETCHSKEWEDITVSTRETCH, &tr2, FALSE);
@ -347,11 +347,11 @@ void CFontsDialog::InitToolbar()
SendMessage(hwndToolbar, TB_SETBUTTONWIDTH, 0, MAKELPARAM(20, 20));
TBADDBITMAP AddBitmap;
AddBitmap.hInst = hProgInstance;
AddBitmap.hInst = g_hinstExe;
AddBitmap.nID = IDB_FONTSTOOLBAR;
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,
LR_CREATEDIBSECTION);
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)
{
LPTOOLTIPTEXT pToolTip = reinterpret_cast<LPTOOLTIPTEXT>(lParam);
pToolTip->hinst = hProgInstance;
pToolTip->hinst = g_hinstExe;
switch (pnmhdr->idFrom)
{
case IDM_BOLD: pToolTip->lpszText = MAKEINTRESOURCE(IDS_BOLD); break;

View file

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

View file

@ -23,8 +23,8 @@ HWND CFullscreenWindow::DoCreate()
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_SMALL, (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(g_hinstExe, MAKEINTRESOURCE(IDI_APPICON)));
return 0;
}

View file

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

View file

@ -22,103 +22,103 @@ void ImageModel::NotifyImageChanged()
}
ImageModel::ImageModel()
: hDrawingDC(::CreateCompatibleDC(NULL))
, currInd(0)
, undoSteps(0)
, redoSteps(0)
: m_hDrawingDC(::CreateCompatibleDC(NULL))
, m_currInd(0)
, m_undoSteps(0)
, m_redoSteps(0)
{
ZeroMemory(hBms, sizeof(hBms));
ZeroMemory(m_hBms, sizeof(m_hBms));
hBms[0] = CreateDIBWithProperties(1, 1);
::SelectObject(hDrawingDC, hBms[0]);
m_hBms[0] = CreateColorDIB(1, 1, RGB(255, 255, 255));
m_hbmOld = ::SelectObject(m_hDrawingDC, m_hBms[0]);
imageSaved = TRUE;
g_imageSaved = TRUE;
}
ImageModel::~ImageModel()
{
::DeleteDC(hDrawingDC);
::DeleteDC(m_hDrawingDC);
for (size_t i = 0; i < HISTORYSIZE; ++i)
{
if (hBms[i])
::DeleteObject(hBms[i]);
if (m_hBms[i])
::DeleteObject(m_hBms[i]);
}
}
void ImageModel::Undo(BOOL bClearRedo)
{
ATLTRACE("%s: %d\n", __FUNCTION__, undoSteps);
ATLTRACE("%s: %d\n", __FUNCTION__, m_undoSteps);
if (!CanUndo())
return;
selectionModel.m_bShow = FALSE;
selectionModel.HideSelection();
// Select previous item
currInd = (currInd + HISTORYSIZE - 1) % HISTORYSIZE;
::SelectObject(hDrawingDC, hBms[currInd]);
m_currInd = (m_currInd + HISTORYSIZE - 1) % HISTORYSIZE;
::SelectObject(m_hDrawingDC, m_hBms[m_currInd]);
undoSteps--;
m_undoSteps--;
if (bClearRedo)
redoSteps = 0;
else if (redoSteps < HISTORYSIZE - 1)
redoSteps++;
m_redoSteps = 0;
else if (m_redoSteps < HISTORYSIZE - 1)
m_redoSteps++;
NotifyImageChanged();
}
void ImageModel::Redo()
{
ATLTRACE("%s: %d\n", __FUNCTION__, redoSteps);
ATLTRACE("%s: %d\n", __FUNCTION__, m_redoSteps);
if (!CanRedo())
return;
selectionModel.m_bShow = FALSE;
selectionModel.HideSelection();
// Select next item
currInd = (currInd + 1) % HISTORYSIZE;
::SelectObject(hDrawingDC, hBms[currInd]);
m_currInd = (m_currInd + 1) % HISTORYSIZE;
::SelectObject(m_hDrawingDC, m_hBms[m_currInd]);
redoSteps--;
if (undoSteps < HISTORYSIZE - 1)
undoSteps++;
m_redoSteps--;
if (m_undoSteps < HISTORYSIZE - 1)
m_undoSteps++;
NotifyImageChanged();
}
void ImageModel::ResetToPrevious()
{
ATLTRACE("%s: %d\n", __FUNCTION__, currInd);
ATLTRACE("%s: %d\n", __FUNCTION__, m_currInd);
// Revert current item with previous item
::DeleteObject(hBms[currInd]);
hBms[currInd] = CopyDIBImage(hBms[(currInd + HISTORYSIZE - 1) % HISTORYSIZE]);
::SelectObject(hDrawingDC, hBms[currInd]);
::DeleteObject(m_hBms[m_currInd]);
m_hBms[m_currInd] = CopyDIBImage(m_hBms[(m_currInd + HISTORYSIZE - 1) % HISTORYSIZE]);
::SelectObject(m_hDrawingDC, m_hBms[m_currInd]);
NotifyImageChanged();
}
void ImageModel::ClearHistory()
{
undoSteps = 0;
redoSteps = 0;
m_undoSteps = 0;
m_redoSteps = 0;
}
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
::DeleteObject(hBms[(currInd + 1) % HISTORYSIZE]);
hBms[(currInd + 1) % HISTORYSIZE] = (hbm ? hbm : CopyDIBImage(hBms[currInd]));
currInd = (currInd + 1) % HISTORYSIZE;
::SelectObject(hDrawingDC, hBms[currInd]);
::DeleteObject(m_hBms[(m_currInd + 1) % HISTORYSIZE]);
m_hBms[(m_currInd + 1) % HISTORYSIZE] = (hbm ? hbm : CopyDIBImage(m_hBms[m_currInd]));
m_currInd = (m_currInd + 1) % HISTORYSIZE;
::SelectObject(m_hDrawingDC, m_hBms[m_currInd]);
if (undoSteps < HISTORYSIZE - 1)
undoSteps++;
redoSteps = 0;
if (m_undoSteps < HISTORYSIZE - 1)
m_undoSteps++;
m_redoSteps = 0;
imageSaved = FALSE;
g_imageSaved = FALSE;
NotifyImageChanged();
}
@ -136,7 +136,7 @@ void ImageModel::Crop(int nWidth, int nHeight, int nOffsetX, int nOffsetY)
return;
// Select the HBITMAP by memory DC
HDC hdcMem = ::CreateCompatibleDC(hDrawingDC);
HDC hdcMem = ::CreateCompatibleDC(m_hDrawingDC);
HGDIOBJ hbmOld = ::SelectObject(hdcMem, hbmCropped);
// Fill background of the HBITMAP
@ -146,7 +146,7 @@ void ImageModel::Crop(int nWidth, int nHeight, int nOffsetX, int nOffsetY)
::DeleteObject(hbrBack);
// 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
::SelectObject(hdcMem, hbmOld);
@ -160,12 +160,12 @@ void ImageModel::Crop(int nWidth, int nHeight, int nOffsetX, int nOffsetY)
void ImageModel::SaveImage(LPCTSTR lpFileName)
{
SaveDIBToFile(hBms[currInd], lpFileName, hDrawingDC);
SaveDIBToFile(m_hBms[m_currInd], lpFileName, m_hDrawingDC);
}
BOOL ImageModel::IsImageSaved() const
{
return imageSaved;
return g_imageSaved;
}
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;
if (oldWidth != newWidth || oldHeight != newHeight)
{
HBITMAP hbm0 = CopyDIBImage(hBms[currInd], newWidth, newHeight);
HBITMAP hbm0 = CopyDIBImage(m_hBms[m_currInd], newWidth, newHeight);
PushImageForUndo(hbm0);
}
if (nSkewDegX)
{
HBITMAP hbm1 = SkewDIB(hDrawingDC, hBms[currInd], nSkewDegX, FALSE);
HBITMAP hbm1 = SkewDIB(m_hDrawingDC, m_hBms[m_currInd], nSkewDegX, FALSE);
PushImageForUndo(hbm1);
}
if (nSkewDegY)
{
HBITMAP hbm2 = SkewDIB(hDrawingDC, hBms[currInd], nSkewDegY, TRUE);
HBITMAP hbm2 = SkewDIB(m_hDrawingDC, m_hBms[m_currInd], nSkewDegY, TRUE);
PushImageForUndo(hbm2);
}
NotifyImageChanged();
@ -194,31 +194,31 @@ void ImageModel::StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSk
int ImageModel::GetWidth() const
{
return GetDIBWidth(hBms[currInd]);
return GetDIBWidth(m_hBms[m_currInd]);
}
int ImageModel::GetHeight() const
{
return GetDIBHeight(hBms[currInd]);
return GetDIBHeight(m_hBms[m_currInd]);
}
void ImageModel::InvertColors()
{
RECT rect = {0, 0, GetWidth(), GetHeight()};
PushImageForUndo();
InvertRect(hDrawingDC, &rect);
InvertRect(m_hDrawingDC, &rect);
NotifyImageChanged();
}
HDC ImageModel::GetDC()
{
return hDrawingDC;
return m_hDrawingDC;
}
void ImageModel::FlipHorizontally()
{
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);
NotifyImageChanged();
}
@ -226,7 +226,7 @@ void ImageModel::FlipHorizontally()
void ImageModel::FlipVertically()
{
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);
NotifyImageChanged();
}
@ -238,7 +238,7 @@ void ImageModel::RotateNTimes90Degrees(int iN)
case 1:
case 3:
{
HBITMAP hbm = Rotate90DegreeBlt(hDrawingDC, GetWidth(), GetHeight(), iN == 1, FALSE);
HBITMAP hbm = Rotate90DegreeBlt(m_hDrawingDC, GetWidth(), GetHeight(), iN == 1, FALSE);
if (hbm)
PushImageForUndo(hbm);
break;
@ -246,28 +246,25 @@ void ImageModel::RotateNTimes90Degrees(int iN)
case 2:
{
PushImageForUndo();
StretchBlt(hDrawingDC, GetWidth() - 1, GetHeight() - 1, -GetWidth(), -GetHeight(),
hDrawingDC, 0, 0, GetWidth(), GetHeight(), SRCCOPY);
StretchBlt(m_hDrawingDC, GetWidth() - 1, GetHeight() - 1, -GetWidth(), -GetHeight(),
m_hDrawingDC, 0, 0, GetWidth(), GetHeight(), SRCCOPY);
break;
}
}
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
{
pt.x = max(0, min(pt.x, GetWidth()));
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();
HDC GetDC();
BOOL CanUndo() const { return undoSteps > 0; }
BOOL CanRedo() const { return redoSteps > 0; }
BOOL CanUndo() const { return m_undoSteps > 0; }
BOOL CanRedo() const { return m_redoSteps > 0; }
void PushImageForUndo(HBITMAP hbm = NULL);
void ResetToPrevious(void);
void Undo(BOOL bClearRedo = FALSE);
@ -31,18 +31,19 @@ public:
void StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX = 0, int nSkewDegY = 0);
int GetWidth() const;
int GetHeight() const;
HBITMAP CopyBitmap();
void InvertColors();
void FlipHorizontally();
void FlipVertically();
void RotateNTimes90Degrees(int iN);
void DeleteSelection();
void Bound(POINT& pt) const;
void NotifyImageChanged();
protected:
HDC hDrawingDC; // The device context for this class
int currInd; // The current index
int undoSteps; // The undo-able count
int redoSteps; // The redo-able count
HBITMAP hBms[HISTORYSIZE]; // A rotation buffer of HBITMAPs
HDC m_hDrawingDC; // The device context for this class
int m_currInd; // The current index in m_hBms
int m_undoSteps; // The undo-able count
int m_redoSteps; // The redo-able count
HBITMAP m_hBms[HISTORYSIZE]; // A rotation buffer of HBITMAPs
HGDIOBJ m_hbmOld;
};

View file

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

View file

@ -38,7 +38,7 @@ HWND CMiniatureWindow::DoCreate(HWND hwndParent)
};
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;
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)
{
start.x = last.x = x;
start.y = last.y = y;
g_ptStart.x = g_ptEnd.x = x;
g_ptStart.y = g_ptEnd.y = y;
}
void updateLast(LONG x, LONG y)
{
last.x = x;
last.y = y;
g_ptEnd.x = x;
g_ptEnd.y = y;
}
void ToolBase::reset()
{
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();
if (selectionModel.m_bShow)
{
selectionModel.Landing();
selectionModel.m_bShow = FALSE;
selectionModel.HideSelection();
}
}
@ -99,24 +99,54 @@ void ToolBase::endEvent()
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 ********************************************************/
// TOOL_FREESEL
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
{
selectionModel.Landing();
if (bLeftButton)
{
imageModel.PushImageForUndo();
selectionModel.m_bShow = FALSE;
selectionModel.HideSelection();
selectionModel.ResetPtStack();
POINT pt = { x, y };
selectionModel.PushToPtStack(pt);
@ -131,8 +161,7 @@ struct FreeSelTool : ToolBase
POINT pt = { x, y };
imageModel.Bound(pt);
selectionModel.PushToPtStack(pt);
imageModel.ResetToPrevious();
selectionModel.DrawFramePoly(m_hdc);
imageModel.NotifyImageChanged();
}
}
@ -140,16 +169,13 @@ struct FreeSelTool : ToolBase
{
if (bLeftButton)
{
imageModel.ResetToPrevious();
if (selectionModel.PtStackSize() > 2)
{
selectionModel.BuildMaskFromPtStack();
selectionModel.TakeOff();
selectionModel.m_bShow = TRUE;
}
else
{
imageModel.Undo(TRUE);
selectionModel.ResetPtStack();
selectionModel.m_bShow = FALSE;
}
@ -159,15 +185,13 @@ struct FreeSelTool : ToolBase
void OnFinishDraw() override
{
m_bLeftButton = FALSE;
selectionModel.Landing();
ToolBase::OnFinishDraw();
}
void OnCancelDraw() override
{
if (m_bLeftButton)
imageModel.Undo(TRUE);
m_bLeftButton = FALSE;
selectionModel.HideSelection();
ToolBase::OnCancelDraw();
}
};
@ -175,20 +199,39 @@ struct FreeSelTool : ToolBase
// TOOL_RECTSEL
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
{
selectionModel.Landing();
if (bLeftButton)
{
imageModel.PushImageForUndo();
selectionModel.m_bShow = FALSE;
::SetRectEmpty(&selectionModel.m_rc);
selectionModel.HideSelection();
}
m_bLeftButton = bLeftButton;
}
@ -197,11 +240,10 @@ struct RectSelTool : ToolBase
{
if (bLeftButton)
{
imageModel.ResetToPrevious();
POINT pt = { x, y };
imageModel.Bound(pt);
selectionModel.SetRectFromPoints(start, pt);
RectSel(m_hdc, start.x, start.y, pt.x, pt.y);
selectionModel.SetRectFromPoints(g_ptStart, pt);
imageModel.NotifyImageChanged();
}
}
@ -209,9 +251,9 @@ struct RectSelTool : ToolBase
{
if (bLeftButton)
{
imageModel.ResetToPrevious();
if (start.x == x && start.y == y)
imageModel.Undo(TRUE);
POINT pt = { x, y };
imageModel.Bound(pt);
selectionModel.SetRectFromPoints(g_ptStart, pt);
selectionModel.m_bShow = !selectionModel.m_rc.IsRectEmpty();
imageModel.NotifyImageChanged();
}
@ -219,22 +261,68 @@ struct RectSelTool : ToolBase
void OnFinishDraw() override
{
m_bLeftButton = FALSE;
selectionModel.Landing();
ToolBase::OnFinishDraw();
}
void OnCancelDraw() override
{
if (m_bLeftButton)
imageModel.Undo(TRUE);
m_bLeftButton = FALSE;
selectionModel.HideSelection();
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
{
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
@ -255,7 +345,12 @@ struct GenericDrawTool : ToolBase
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
{
draw(bLeftButton, x, y);
imageModel.NotifyImageChanged();
OnFinishDraw();
}
void OnFinishDraw() override
{
ToolBase::OnFinishDraw();
}
void OnCancelDraw() override
@ -267,18 +362,20 @@ struct GenericDrawTool : ToolBase
};
// 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
{
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
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
struct PenTool : GenericDrawTool
struct PenTool : SmoothDrawTool
{
PenTool() : GenericDrawTool(TOOL_PEN)
PenTool() : SmoothDrawTool(TOOL_PEN)
{
}
void draw(BOOL bLeftButton, LONG x, LONG y) override
{
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);
g_ptEnd.x = x;
g_ptEnd.y = y;
}
};
// 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
{
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
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)
{
imageModel.ResetToPrevious();
POINT pt = { x, y };
imageModel.Bound(pt);
selectionModel.SetRectFromPoints(start, pt);
RectSel(m_hdc, start.x, start.y, pt.x, pt.y);
selectionModel.SetRectFromPoints(g_ptStart, pt);
imageModel.NotifyImageChanged();
}
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
@ -417,7 +527,6 @@ struct TextTool : ToolBase
if (!textEditWindow.IsWindow())
textEditWindow.Create(canvasWindow);
imageModel.PushImageForUndo();
UpdatePoint(x, y);
}
@ -426,30 +535,40 @@ struct TextTool : ToolBase
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
{
imageModel.Undo(TRUE);
POINT pt = { x, y };
imageModel.Bound(pt);
selectionModel.SetRectFromPoints(start, pt);
selectionModel.SetRectFromPoints(g_ptStart, pt);
BOOL bTextBoxShown = ::IsWindowVisible(textEditWindow);
if (bTextBoxShown && textEditWindow.GetWindowTextLength() > 0)
{
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(m_hdc, rc.left, rc.top, rc.right, rc.bottom, m_fg, m_bg, szText,
textEditWindow.GetFont(), style);
draw(m_hdc);
if (selectionModel.m_rc.IsRectEmpty())
{
@ -494,201 +613,224 @@ struct TextTool : ToolBase
void OnFinishDraw() override
{
toolsModel.OnButtonDown(TRUE, -1, -1, TRUE);
toolsModel.OnButtonUp(TRUE, -1, -1);
draw(m_hdc);
quit();
ToolBase::OnFinishDraw();
}
void OnCancelDraw() override
{
quit();
ToolBase::OnCancelDraw();
}
};
// 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)
roundTo8Directions(start.x, start.y, x, y);
COLORREF rgb = bLeftButton ? m_fg : m_bg;
Line(m_hdc, start.x, start.y, x, y, rgb, toolsModel.GetLineWidth());
roundTo8Directions(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y);
COLORREF rgb = m_bLeftButton ? m_fg : m_bg;
Line(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, rgb, toolsModel.GetLineWidth());
}
};
// TOOL_BEZIER
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)
{
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());
break;
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;
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;
}
m_bLeftButton = bLeftButton;
}
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
{
pointStack[pointSP].x = x;
pointStack[pointSP].y = y;
m_bLeftButton = bLeftButton;
if (pointSP == 0)
if (!m_bDrawing)
{
imageModel.PushImageForUndo();
pointSP++;
m_bDrawing = TRUE;
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
{
imageModel.ResetToPrevious();
pointStack[pointSP].x = x;
pointStack[pointSP].y = y;
draw(bLeftButton);
imageModel.NotifyImageChanged();
}
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
{
imageModel.ResetToPrevious();
draw(bLeftButton);
pointSP++;
if (pointSP == 4)
pointSP = 0;
pointStack[pointSP].x = x;
pointStack[pointSP].y = y;
if (pointSP >= 3)
{
OnFinishDraw();
return;
}
imageModel.NotifyImageChanged();
}
void OnCancelDraw() override
{
OnButtonUp(FALSE, 0, 0);
imageModel.Undo(TRUE);
m_bDrawing = FALSE;
ToolBase::OnCancelDraw();
}
void OnFinishDraw() override
{
if (pointSP)
{
imageModel.ResetToPrevious();
--pointSP;
draw(m_bLeftButton);
}
imageModel.PushImageForUndo();
OnDrawOverlayOnImage(m_hdc);
m_bDrawing = FALSE;
ToolBase::OnFinishDraw();
}
};
// 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)
regularize(start.x, start.y, x, y);
if (bLeftButton)
Rect(m_hdc, start.x, start.y, x, y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
regularize(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y);
if (m_bLeftButton)
Rect(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
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
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 (bLeftButton)
Poly(m_hdc, pointStack, pointSP + 1, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), bClosed, FALSE);
else
Poly(m_hdc, pointStack, pointSP + 1, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), bClosed, FALSE);
}
m_bLeftButton = bLeftButton;
if (pointSP <= 0)
return;
if (m_bLeftButton)
Poly(hdc, pointStack, pointSP + 1, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), m_bClosed, FALSE);
else
Poly(hdc, pointStack, pointSP + 1, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), m_bClosed, FALSE);
}
void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override
{
m_bLeftButton = bLeftButton;
m_bClosed = FALSE;
pointStack[pointSP].x = x;
pointStack[pointSP].y = y;
if (pointSP == 0 && !bDoubleClick)
if (pointSP && bDoubleClick)
{
OnFinishDraw();
return;
}
if (pointSP == 0)
{
imageModel.PushImageForUndo();
draw(bLeftButton, x, y);
pointSP++;
pointStack[pointSP].x = x;
pointStack[pointSP].y = y;
}
else
{
draw(bLeftButton, x, y, bDoubleClick);
imageModel.NotifyImageChanged();
}
imageModel.NotifyImageChanged();
}
void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
{
imageModel.ResetToPrevious();
pointStack[pointSP].x = x;
pointStack[pointSP].y = y;
if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
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
{
imageModel.ResetToPrevious();
if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 1].y, x, y);
m_bClosed = FALSE;
if (nearlyEqualPoints(x, y, pointStack[0].x, pointStack[0].y))
{
pointSP--;
draw(bLeftButton, x, y, TRUE);
pointSP = 0;
OnFinishDraw();
return;
}
else
{
pointSP++;
pointStack[pointSP].x = x;
pointStack[pointSP].y = y;
draw(bLeftButton, x, y, FALSE);
}
if (pointSP == _countof(pointStack))
pointSP--;
imageModel.NotifyImageChanged();
}
void OnCancelDraw() override
{
imageModel.Undo(TRUE);
ToolBase::OnCancelDraw();
}
@ -696,49 +838,57 @@ struct ShapeTool : ToolBase
{
if (pointSP)
{
imageModel.ResetToPrevious();
--pointSP;
draw(m_bLeftButton, -1, -1, TRUE);
m_bClosed = TRUE;
imageModel.PushImageForUndo();
OnDrawOverlayOnImage(m_hdc);
}
m_bClosed = FALSE;
pointSP = 0;
ToolBase::OnFinishDraw();
}
};
// 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)
regularize(start.x, start.y, x, y);
if (bLeftButton)
Ellp(m_hdc, start.x, start.y, x, y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
regularize(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y);
if (m_bLeftButton)
Ellp(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
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
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)
regularize(start.x, start.y, x, y);
if (bLeftButton)
RRect(m_hdc, start.x, start.y, x, y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
regularize(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y);
if (m_bLeftButton)
RRect(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
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)
{
InvalidateRect(NULL, FALSE);
return 0;
}
LRESULT CPaletteWindow::OnPaletteModelPaletteChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
InvalidateRect(NULL, FALSE);
Invalidate(FALSE);
return 0;
}

View file

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

View file

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

View file

@ -21,6 +21,7 @@ SelectionModel::SelectionModel()
, m_bShow(FALSE)
{
::SetRectEmpty(&m_rc);
::SetRectEmpty(&m_rcOld);
m_ptHit.x = m_ptHit.y = -1;
}
@ -57,25 +58,13 @@ void SelectionModel::PushToPtStack(POINT pt)
#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 += 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;
}
POINT& pt = m_ptStack[i];
pt.x += dx;
pt.y += dy;
}
}
@ -93,16 +82,16 @@ void SelectionModel::BuildMaskFromPtStack()
rc.right += 1;
rc.bottom += 1;
m_rc = rc;
ShiftPtStack(FALSE);
m_rc = m_rcOld = rc;
ClearMask();
ShiftPtStack(-m_rcOld.left, -m_rcOld.top);
HDC hdcMem = ::CreateCompatibleDC(NULL);
m_hbmMask = ::CreateBitmap(rc.Width(), rc.Height(), 1, 1, NULL);
HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_hbmMask);
FillRect(hdcMem, &rc, (HBRUSH)::GetStockObject(BLACK_BRUSH));
::FillRect(hdcMem, &rc, (HBRUSH)::GetStockObject(BLACK_BRUSH));
HGDIOBJ hPenOld = ::SelectObject(hdcMem, GetStockObject(NULL_PEN));
HGDIOBJ hbrOld = ::SelectObject(hdcMem, GetStockObject(WHITE_BRUSH));
::Polygon(hdcMem, m_ptStack, m_iPtSP);
@ -110,34 +99,39 @@ void SelectionModel::BuildMaskFromPtStack()
::SelectObject(hdcMem, hPenOld);
::SelectObject(hdcMem, hbmOld);
::DeleteDC(hdcMem);
ShiftPtStack(+m_rcOld.left, +m_rcOld.top);
}
void SelectionModel::DrawBackgroundPoly(HDC hDCImage, COLORREF crBg)
{
ShiftPtStack(TRUE);
if (::IsRectEmpty(&m_rcOld))
return;
HGDIOBJ hPenOld = ::SelectObject(hDCImage, ::GetStockObject(NULL_PEN));
HGDIOBJ hbrOld = ::SelectObject(hDCImage, ::CreateSolidBrush(crBg));
::Polygon(hDCImage, m_ptStack, m_iPtSP);
::DeleteObject(::SelectObject(hDCImage, hbrOld));
::SelectObject(hDCImage, hPenOld);
ShiftPtStack(FALSE);
}
void SelectionModel::DrawBackgroundRect(HDC hDCImage, COLORREF crBg)
{
Rect(hDCImage, m_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))
return;
BITMAP bm;
GetObject(m_hbmColor, sizeof(BITMAP), &bm);
if (!GetObject(m_hbmColor, sizeof(BITMAP), &bm))
return;
COLORREF keyColor = (bBgTransparent ? crBg : CLR_INVALID);
@ -161,23 +155,23 @@ void SelectionModel::GetSelectionContents(HDC hDCImage)
::DeleteDC(hMemDC);
}
BOOL SelectionModel::IsLanded() const
{
return !m_hbmColor;
}
BOOL SelectionModel::TakeOff()
{
if (m_hbmColor || ::IsRectEmpty(&m_rc))
if (!IsLanded() || ::IsRectEmpty(&m_rc))
return FALSE;
HDC hDCImage = imageModel.GetDC();
GetSelectionContents(hDCImage);
m_rgbBack = paletteModel.GetBgColor();
GetSelectionContents(imageModel.GetDC());
if (toolsModel.GetActiveTool() == TOOL_FREESEL)
{
DrawBackgroundPoly(hDCImage, paletteModel.GetBgColor());
}
else
{
if (toolsModel.GetActiveTool() == TOOL_RECTSEL)
ClearMask();
DrawBackgroundRect(hDCImage, paletteModel.GetBgColor());
}
m_rcOld = m_rc;
imageModel.NotifyImageChanged();
return TRUE;
@ -185,16 +179,23 @@ BOOL SelectionModel::TakeOff()
void SelectionModel::Landing()
{
if (!m_hbmColor)
if (IsLanded() && !m_bShow)
{
imageModel.NotifyImageChanged();
return;
}
DrawSelection(imageModel.GetDC(), &m_rc, paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent());
m_bShow = FALSE;
::SetRectEmpty(&m_rc);
ClearMask();
ClearColor();
if (!::EqualRect(m_rc, m_rcOld) && !::IsRectEmpty(m_rc) && !::IsRectEmpty(m_rcOld))
{
imageModel.PushImageForUndo();
imageModel.PushImageForUndo();
canvasWindow.m_drawing = FALSE;
toolsModel.OnDrawOverlayOnImage(imageModel.GetDC());
}
HideSelection();
}
void SelectionModel::InsertFromHBITMAP(HBITMAP hBm, INT x, INT y)
@ -349,11 +350,11 @@ void SelectionModel::StretchSkew(int nStretchPercentX, int nStretchPercentY, int
imageModel.NotifyImageChanged();
}
HBITMAP SelectionModel::GetBitmap()
HBITMAP SelectionModel::CopyBitmap()
{
if (m_hbmColor == NULL)
GetSelectionContents(imageModel.GetDC());
return m_hbmColor;
return CopyDIBImage(m_hbmColor);
}
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)
return;
imageModel.PushImageForUndo();
if (m_bShow)
imageModel.Undo(TRUE);
TakeOff();
m_bShow = FALSE;
imageModel.NotifyImageChanged();
imageModel.PushImageForUndo();
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;
public:
COLORREF m_rgbBack = RGB(255, 255, 255);
BOOL m_bShow;
CRect m_rc; // in image pixel coordinates
POINT m_ptHit; // in image pixel coordinates
CRect m_rcOld; // in image pixel coordinates
SelectionModel();
~SelectionModel();
@ -33,13 +35,16 @@ public:
BOOL TakeOff();
void Landing();
BOOL IsLanded() const;
void HideSelection();
void DeleteSelection();
HBITMAP GetBitmap();
HBITMAP CopyBitmap();
void GetSelectionContents(HDC hDCImage);
void DrawFramePoly(HDC hDCImage);
void DrawBackgroundPoly(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);
// operation
@ -48,7 +53,6 @@ public:
void RotateNTimes90Degrees(int iN);
void StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX, int nSkewDegY);
void CancelSelection();
void Dragging(CANVAS_HITTEST hit, POINT pt);
void ClearMask();
void ClearColor();
@ -57,5 +61,5 @@ private:
SelectionModel(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);
TEXTMETRIC 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 |
DT_EXPANDTABS | DT_WORDBREAK;
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 |
WS_CHILD | WS_THICKFRAME;
HWND hwnd = ::CreateWindowEx(0, WC_EDIT, NULL, style, 0, 0, 0, 0,
hwndParent, NULL, hProgInstance, NULL);
hwndParent, NULL, g_hinstExe, NULL);
if (hwnd)
{
#undef SubclassWindow // Don't use this macro

View file

@ -13,6 +13,20 @@ CToolBox toolBoxContainer;
/* 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)
{
// 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);
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);
ImageList_AddMasked(hImageList, hbmIcons, RGB(255, 0, 255));
::DeleteObject(hbmIcons);
@ -38,7 +52,7 @@ BOOL CPaintToolBar::DoCreate(HWND hwndParent)
tbbutton.fsStyle = TBSTYLE_CHECKGROUP;
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.fsState = TBSTATE_ENABLED | ((i % 2 == 1) ? TBSTATE_WRAP : 0);
tbbutton.idCommand = ID_FREESEL + i;
@ -49,6 +63,8 @@ BOOL CPaintToolBar::DoCreate(HWND hwndParent)
SendMessage(TB_CHECKBUTTON, ID_PEN, MAKELPARAM(TRUE, 0));
SendMessage(TB_SETMAXTEXTROWS, 0, 0);
SendMessage(TB_SETBUTTONSIZE, 0, MAKELPARAM(CXY_TB_BUTTON, CXY_TB_BUTTON));
SetWindowLongPtr(GWLP_USERDATA, SetWindowLongPtr(GWLP_WNDPROC, (LONG_PTR)ToolBarWndProc));
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)
{
selectionModel.m_bShow = FALSE;
selectionModel.HideSelection();
toolsModel.resetTool(); // resets the point-buffer of the polygon and bezier functions
// Check the toolbar button
@ -168,3 +184,10 @@ LRESULT CToolBox::OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHa
::ReleaseCapture();
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 CY_TOOLBAR (TOOLBAR_ROWS * CXY_TB_BUTTON)
#define WM_TOOLBARHIT (WM_APP + 1)
class CPaintToolBar : public CWindow
{
public:
BOOL DoCreate(HWND hwndParent);
static LRESULT CALLBACK ToolBarWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
};
class CToolBox : public CWindowImpl<CToolBox>
@ -34,6 +37,7 @@ public:
MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
MESSAGE_HANDLER(WM_TOOLSMODELTOOLCHANGED, OnToolsModelToolChanged)
MESSAGE_HANDLER(WM_TOOLBARHIT, OnToolBarHit)
END_MSG_MAP()
BOOL DoCreate(HWND hwndParent);
@ -48,4 +52,5 @@ private:
LRESULT OnMouseMove(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 OnToolBarHit(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
};

View file

@ -200,11 +200,14 @@ VOID CToolSettingsWindow::drawAirBrush(HDC hdc, LPCRECT prc)
if (bHigh)
{
::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
{
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)
{
/* 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);
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);
RECT trackbarZoomPos = {1, 1, 1 + 40, 1 + 64};

View file

@ -28,7 +28,7 @@ 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];
}
@ -87,9 +87,6 @@ void ToolsModel::SetActiveTool(TOOLTYPE nActiveTool)
{
OnFinishDraw();
if (m_activeTool == nActiveTool)
return;
switch (m_activeTool)
{
case TOOL_FREESEL:
@ -225,6 +222,16 @@ void ToolsModel::OnFinishDraw()
m_pToolObject->endEvent();
}
void ToolsModel::OnDrawOverlayOnImage(HDC hdc)
{
m_pToolObject->OnDrawOverlayOnImage(hdc);
}
void ToolsModel::OnDrawOverlayOnCanvas(HDC hdc)
{
m_pToolObject->OnDrawOverlayOnCanvas(hdc);
}
void ToolsModel::resetTool()
{
m_pToolObject->reset();

View file

@ -39,34 +39,27 @@ struct ToolBase
static INT pointSP;
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 OnFinishDraw();
virtual void OnDrawOverlayOnImage(HDC hdc) { }
virtual void OnDrawOverlayOnCanvas(HDC hdc) { }
void beginEvent();
void endEvent();
void reset();
static ToolBase* createToolObject(TOOLTYPE type);
protected:
void OnDrawSelectionOnCanvas(HDC hdc);
};
class ToolsModel
@ -112,6 +105,8 @@ public:
void OnButtonUp(BOOL bLeftButton, LONG x, LONG y);
void OnCancelDraw();
void OnFinishDraw();
void OnDrawOverlayOnImage(HDC hdc);
void OnDrawOverlayOnCanvas(HDC hdc);
void resetTool();
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 FN_HtmlHelpW s_pHtmlHelpW = NULL;
HWND hStatusBar = NULL;
HWND g_hStatusBar = NULL;
/* FUNCTIONS ********************************************************/
@ -79,9 +79,9 @@ void CMainWindow::alignChildrenToMainWindow()
GetClientRect(&clientRect);
RECT rcSpace = clientRect;
if (::IsWindowVisible(hStatusBar))
if (::IsWindowVisible(g_hStatusBar))
{
::GetWindowRect(hStatusBar, &rc);
::GetWindowRect(g_hStatusBar, &rc);
rcSpace.bottom -= rc.bottom - rc.top;
}
@ -142,18 +142,18 @@ void CMainWindow::saveImage(BOOL overwrite)
{
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;
strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(filepathname));
strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(g_szFileName));
SetWindowText(strTitle);
isAFile = TRUE;
g_isAFile = TRUE;
}
}
@ -168,13 +168,13 @@ void CMainWindow::InsertSelectionFromHBITMAP(HBITMAP bitmap, HWND window)
{
BOOL shouldEnlarge = TRUE;
if (askBeforeEnlarging)
if (g_askBeforeEnlarging)
{
TCHAR programname[20];
TCHAR shouldEnlargePromptText[100];
LoadString(hProgInstance, IDS_PROGRAMNAME, programname, _countof(programname));
LoadString(hProgInstance, IDS_ENLARGEPROMPTTEXT, shouldEnlargePromptText, _countof(shouldEnlargePromptText));
LoadString(g_hinstExe, IDS_PROGRAMNAME, programname, _countof(programname));
LoadString(g_hinstExe, IDS_ENLARGEPROMPTTEXT, shouldEnlargePromptText, _countof(shouldEnlargePromptText));
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)
{
// 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);
// Create the status bar
DWORD style = SBARS_SIZEGRIP | WS_CHILD | (registrySettings.ShowStatusBar ? WS_VISIBLE : 0);
hStatusBar = ::CreateWindowEx(0, STATUSCLASSNAME, NULL, style, 0, 0, 0, 0, m_hWnd,
NULL, hProgInstance, NULL);
::SendMessage(hStatusBar, SB_SETMINHEIGHT, 21, 0);
g_hStatusBar = ::CreateWindowEx(0, STATUSCLASSNAME, NULL, style, 0, 0, 0, 0, m_hWnd,
NULL, g_hinstExe, NULL);
::SendMessage(g_hStatusBar, SB_SETMINHEIGHT, 21, 0);
// Create the tool box
toolBoxContainer.DoCreate(m_hWnd);
@ -305,8 +305,8 @@ LRESULT CMainWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHa
}
// Set icon
SendMessage(WM_SETICON, ICON_BIG, (LPARAM) LoadIcon(hProgInstance, MAKEINTRESOURCE(IDI_APPICON)));
SendMessage(WM_SETICON, ICON_SMALL, (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(g_hinstExe, MAKEINTRESOURCE(IDI_APPICON)));
return 0;
}
@ -347,7 +347,7 @@ BOOL CMainWindow::ConfirmSave()
strProgramName.LoadString(IDS_PROGRAMNAME);
CString strSavePromptText;
strSavePromptText.Format(IDS_SAVEPROMPTTEXT, PathFindFileName(filepathname));
strSavePromptText.Format(IDS_SAVEPROMPTTEXT, PathFindFileName(g_szFileName));
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)
{
LPCTSTR dotext = PathFindExtensionW(filepathname);
LPCTSTR dotext = PathFindExtensionW(g_szFileName);
BOOL isBMP = FALSE;
if (_tcsicmp(dotext, _T(".bmp")) == 0 ||
_tcsicmp(dotext, _T(".dib")) == 0 ||
@ -383,9 +383,9 @@ void CMainWindow::ProcessFileMenu(HMENU hPopupMenu)
isBMP = TRUE;
}
EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERPLANE, ENABLED_IF(isAFile && isBMP));
EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERCENTERED, ENABLED_IF(isAFile && isBMP));
EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERSTRETCHED, ENABLED_IF(isAFile && isBMP));
EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERPLANE, ENABLED_IF(g_isAFile && isBMP));
EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERCENTERED, ENABLED_IF(g_isAFile && isBMP));
EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERSTRETCHED, ENABLED_IF(g_isAFile && isBMP));
for (INT iItem = 0; iItem < MAX_RECENT_FILES; ++iItem)
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 */
CheckMenuItem(menu, IDM_VIEWTOOLBOX, CHECKED_IF(::IsWindowVisible(toolBoxContainer)));
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)));
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));
break;
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)
{
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(hStatusBar, SB_SETPARTS, 3, (LPARAM)&test);
::SendMessage(g_hStatusBar, WM_SIZE, 0, 0);
::SendMessage(g_hStatusBar, SB_SETPARTS, 3, (LPARAM)&test);
}
alignChildrenToMainWindow();
return 0;
@ -508,9 +508,11 @@ LRESULT CMainWindow::OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
}
else if (selectionModel.m_bShow)
{
selectionModel.Landing();
selectionModel.m_bShow = FALSE;
imageModel.NotifyImageChanged();
selectionModel.HideSelection();
}
else
{
canvasWindow.cancelDrawing();
}
break;
@ -551,11 +553,11 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
{
case IDM_HELPINFO:
{
HICON paintIcon = LoadIcon(hProgInstance, MAKEINTRESOURCE(IDI_APPICON));
HICON paintIcon = LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDI_APPICON));
TCHAR infotitle[100];
TCHAR infotext[200];
LoadString(hProgInstance, IDS_INFOTITLE, infotitle, _countof(infotitle));
LoadString(hProgInstance, IDS_INFOTEXT, infotext, _countof(infotext));
LoadString(g_hinstExe, IDS_INFOTITLE, infotitle, _countof(infotitle));
LoadString(g_hinstExe, IDS_INFOTEXT, infotext, _countof(infotext));
ShellAbout(m_hWnd, infotitle, infotext, paintIcon);
DeleteObject(paintIcon);
break;
@ -620,13 +622,13 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
GlobalFree(pd.hDevNames);
break;
case IDM_FILEASWALLPAPERPLANE:
RegistrySettings::SetWallpaper(filepathname, RegistrySettings::TILED);
RegistrySettings::SetWallpaper(g_szFileName, RegistrySettings::TILED);
break;
case IDM_FILEASWALLPAPERCENTERED:
RegistrySettings::SetWallpaper(filepathname, RegistrySettings::CENTERED);
RegistrySettings::SetWallpaper(g_szFileName, RegistrySettings::CENTERED);
break;
case IDM_FILEASWALLPAPERSTRETCHED:
RegistrySettings::SetWallpaper(filepathname, RegistrySettings::STRETCHED);
RegistrySettings::SetWallpaper(g_szFileName, RegistrySettings::STRETCHED);
break;
case IDM_FILE1:
case IDM_FILE2:
@ -640,7 +642,10 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
}
case IDM_EDITUNDO:
if (toolsModel.GetActiveTool() == TOOL_TEXT && ::IsWindowVisible(textEditWindow))
{
textEditWindow.PostMessage(WM_UNDO, 0, 0);
break;
}
if (selectionModel.m_bShow)
{
if (toolsModel.GetActiveTool() == TOOL_RECTSEL ||
@ -668,10 +673,19 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
imageModel.Redo();
break;
case IDM_EDITCOPY:
// FIXME: We should use CF_DIB in the future
if (OpenClipboard())
{
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();
}
break;
@ -695,7 +709,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
{
case TOOL_FREESEL:
case TOOL_RECTSEL:
imageModel.DeleteSelection();
selectionModel.DeleteSelection();
break;
case TOOL_TEXT:
@ -723,7 +737,11 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
{
TCHAR szFileName[MAX_LONG_PATH] = _T("");
if (GetSaveFileName(szFileName, _countof(szFileName)))
SaveDIBToFile(selectionModel.GetBitmap(), szFileName, imageModel.GetDC());
{
HBITMAP hbm = selectionModel.CopyBitmap();
SaveDIBToFile(hbm, szFileName, imageModel.GetDC());
::DeleteObject(hbm);
}
break;
}
case IDM_EDITPASTEFROM:
@ -827,8 +845,8 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
toolsModel.SetBackgroundTransparent(!toolsModel.IsBackgroundTransparent());
break;
case IDM_IMAGECROP:
imageModel.PushImageForUndo(CopyDIBImage(selectionModel.GetBitmap()));
imageModel.DeleteSelection();
imageModel.PushImageForUndo(selectionModel.CopyBitmap());
selectionModel.HideSelection();
break;
case IDM_VIEWTOOLBOX:
@ -842,8 +860,8 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
alignChildrenToMainWindow();
break;
case IDM_VIEWSTATUSBAR:
registrySettings.ShowStatusBar = !::IsWindowVisible(hStatusBar);
::ShowWindow(hStatusBar, (registrySettings.ShowStatusBar ? SW_SHOWNOACTIVATE : SW_HIDE));
registrySettings.ShowStatusBar = !::IsWindowVisible(g_hStatusBar);
::ShowWindow(g_hStatusBar, (registrySettings.ShowStatusBar ? SW_SHOWNOACTIVATE : SW_HIDE));
alignChildrenToMainWindow();
break;
case IDM_FORMATICONBAR:
@ -859,7 +877,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
}
break;
case IDM_VIEWSHOWGRID:
showGrid = !showGrid;
g_showGrid = !g_showGrid;
canvasWindow.Invalidate(FALSE);
break;
case IDM_VIEWSHOWMINIATURE: