diff --git a/base/applications/mspaint/history.cpp b/base/applications/mspaint/history.cpp index c0f347d0aa9..2f7480b5f45 100644 --- a/base/applications/mspaint/history.cpp +++ b/base/applications/mspaint/history.cpp @@ -12,6 +12,14 @@ ImageModel imageModel; /* FUNCTIONS ********************************************************/ +void IMAGE_PART::clear() +{ + ::DeleteObject(m_hbmImage); + m_hbmImage = NULL; + m_rcPart.SetRectEmpty(); + m_bPartial = FALSE; +} + void ImageModel::NotifyImageChanged() { if (canvasWindow.IsWindow()) @@ -30,7 +38,7 @@ ImageModel::ImageModel() , m_undoSteps(0) , m_redoSteps(0) { - ZeroMemory(m_hBms, sizeof(m_hBms)); + ZeroMemory(m_historyItems, sizeof(m_historyItems)); m_hbmMaster = CreateColorDIB(1, 1, RGB(255, 255, 255)); m_hbmOld = ::SelectObject(m_hDrawingDC, m_hbmMaster); @@ -46,6 +54,23 @@ ImageModel::~ImageModel() ClearHistory(); } +void ImageModel::SwapPart() +{ + IMAGE_PART& part = m_historyItems[m_currInd]; + if (!part.m_bPartial) + { + Swap(m_hbmMaster, part.m_hbmImage); + return; + } + + HBITMAP hbmMaster = LockBitmap(); + HBITMAP hbmPart = getSubImage(hbmMaster, part.m_rcPart); + putSubImage(hbmMaster, part.m_rcPart, part.m_hbmImage); + ::DeleteObject(part.m_hbmImage); + part.m_hbmImage = hbmPart; + UnlockBitmap(hbmMaster); +} + void ImageModel::Undo(BOOL bClearRedo) { ATLTRACE("%s: %d\n", __FUNCTION__, m_undoSteps); @@ -55,11 +80,8 @@ void ImageModel::Undo(BOOL bClearRedo) selectionModel.HideSelection(); m_currInd = (m_currInd + HISTORYSIZE - 1) % HISTORYSIZE; // Go previous - ATLASSERT(m_hbmMaster != NULL); - ATLASSERT(m_hBms[m_currInd] != NULL); - - Swap(m_hbmMaster, m_hBms[m_currInd]); + SwapPart(); ::SelectObject(m_hDrawingDC, m_hbmMaster); // Re-select m_undoSteps--; @@ -80,9 +102,7 @@ void ImageModel::Redo() selectionModel.HideSelection(); ATLASSERT(m_hbmMaster != NULL); - ATLASSERT(m_hBms[m_currInd] != NULL); - - Swap(m_hbmMaster, m_hBms[m_currInd]); + SwapPart(); m_currInd = (m_currInd + 1) % HISTORYSIZE; // Go next ::SelectObject(m_hDrawingDC, m_hbmMaster); // Re-select @@ -97,11 +117,7 @@ void ImageModel::ClearHistory() { for (int i = 0; i < HISTORYSIZE; ++i) { - if (m_hBms[i]) - { - ::DeleteObject(m_hBms[i]); - m_hBms[i] = NULL; - } + m_historyItems[i].clear(); } m_undoSteps = 0; @@ -130,12 +146,35 @@ void ImageModel::PushImageForUndo(HBITMAP hbm) return; } - ::DeleteObject(m_hBms[m_currInd]); - m_hBms[m_currInd] = m_hbmMaster; + IMAGE_PART& part = m_historyItems[m_currInd]; + part.clear(); + part.m_hbmImage = m_hbmMaster; m_hbmMaster = hbm; - m_currInd = (m_currInd + 1) % HISTORYSIZE; // Go next ::SelectObject(m_hDrawingDC, m_hbmMaster); // Re-select + PushDone(); +} + +void ImageModel::PushImageForUndo(const RECT& rcPartial) +{ + ATLTRACE("%s: %d\n", __FUNCTION__, m_currInd); + + IMAGE_PART& part = m_historyItems[m_currInd]; + part.clear(); + part.m_bPartial = TRUE; + part.m_rcPart = rcPartial; + + HBITMAP hbmMaster = LockBitmap(); + part.m_hbmImage = getSubImage(hbmMaster, rcPartial); + UnlockBitmap(hbmMaster); + + PushDone(); +} + +void ImageModel::PushDone() +{ + m_currInd = (m_currInd + 1) % HISTORYSIZE; // Go next + if (m_undoSteps < HISTORYSIZE - 1) m_undoSteps++; m_redoSteps = 0; diff --git a/base/applications/mspaint/history.h b/base/applications/mspaint/history.h index e827a430b35..87c98515136 100644 --- a/base/applications/mspaint/history.h +++ b/base/applications/mspaint/history.h @@ -10,6 +10,15 @@ /* HISTORYSIZE = number of possible undo-steps + 1 */ #define HISTORYSIZE 11 +struct IMAGE_PART +{ + CRect m_rcPart; + HBITMAP m_hbmImage; + BOOL m_bPartial; + + void clear(); +}; + class ImageModel { public: @@ -21,6 +30,7 @@ public: BOOL CanRedo() const { return m_redoSteps > 0; } void PushImageForUndo(); void PushImageForUndo(HBITMAP hbm); + void PushImageForUndo(const RECT& rcPartial); void Undo(BOOL bClearRedo = FALSE); void Redo(void); void ClearHistory(void); @@ -49,6 +59,9 @@ protected: 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 + IMAGE_PART m_historyItems[HISTORYSIZE]; // A ring buffer of IMAGE_PARTs HGDIOBJ m_hbmOld; + + void SwapPart(); + void PushDone(); }; diff --git a/base/applications/mspaint/mouse.cpp b/base/applications/mspaint/mouse.cpp index d650259f6cb..2aa17872c81 100644 --- a/base/applications/mspaint/mouse.cpp +++ b/base/applications/mspaint/mouse.cpp @@ -291,7 +291,12 @@ struct TwoPointDrawTool : ToolBase BOOL OnButtonUp(BOOL bLeftButton, LONG& x, LONG& y) override { - imageModel.PushImageForUndo(); + CRect rcPartial(g_ptStart, g_ptEnd); + rcPartial.NormalizeRect(); + SIZE size = toolsModel.GetToolSize(); + rcPartial.InflateRect((size.cx + 1) / 2, (size.cy + 1) / 2); + imageModel.PushImageForUndo(rcPartial); + OnDrawOverlayOnImage(m_hdc); m_bDrawing = FALSE; imageModel.NotifyImageChanged(); diff --git a/base/applications/mspaint/toolsmodel.cpp b/base/applications/mspaint/toolsmodel.cpp index 42ee980c2b3..c19a1152c24 100644 --- a/base/applications/mspaint/toolsmodel.cpp +++ b/base/applications/mspaint/toolsmodel.cpp @@ -202,6 +202,47 @@ void ToolsModel::SetRubberRadius(int nRubberRadius) NotifyToolSettingsChanged(); } +SIZE ToolsModel::GetToolSize() const +{ + SIZE size; + switch (m_activeTool) + { + case TOOL_FREESEL: + case TOOL_RECTSEL: + case TOOL_COLOR: + case TOOL_ZOOM: + case TOOL_TEXT: + case TOOL_FILL: + size.cx = size.cy = 1; + break; + case TOOL_LINE: + case TOOL_BEZIER: + case TOOL_RECT: + case TOOL_RRECT: + case TOOL_SHAPE: + case TOOL_ELLIPSE: + size.cx = size.cy = GetLineWidth(); + break; + case TOOL_AIRBRUSH: + size.cx = size.cy = GetAirBrushRadius() * 2; + break; + case TOOL_RUBBER: + size.cx = size.cy = GetRubberRadius() * 2; + break; + case TOOL_BRUSH: + size.cx = size.cy = GetBrushWidth(); + break; + case TOOL_PEN: + size.cx = size.cy = GetPenWidth(); + break; + } + if (size.cx < 1) + size.cx = 1; + if (size.cy < 1) + size.cy = 1; + return size; +} + BOOL ToolsModel::IsBackgroundTransparent() const { return m_transpBg; diff --git a/base/applications/mspaint/toolsmodel.h b/base/applications/mspaint/toolsmodel.h index a5737010d9b..1bc5ee256c0 100644 --- a/base/applications/mspaint/toolsmodel.h +++ b/base/applications/mspaint/toolsmodel.h @@ -124,6 +124,8 @@ public: void SetRubberRadius(int nRubberRadius); void MakeRubberThickerOrThinner(BOOL bThinner); + SIZE GetToolSize() const; + BOOL IsBackgroundTransparent() const; void SetBackgroundTransparent(BOOL bTransparent);