From 0b6e813ef2b5b6105760196793a9f9decf247795 Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Sun, 18 Oct 2026 17:26:33 +0900 Subject: [PATCH 1/2] Preserve the original image before resizing for paste operations so that undo restores the original image size and content. --- src/WinIMergeLib/ImgMergeBuffer.hpp | 47 +++++++++++++++++++++++++---- src/WinIMergeLib/ImgMergeWindow.hpp | 3 +- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/WinIMergeLib/ImgMergeBuffer.hpp b/src/WinIMergeLib/ImgMergeBuffer.hpp index fa2f0e7..935d8e6 100644 --- a/src/WinIMergeLib/ImgMergeBuffer.hpp +++ b/src/WinIMergeLib/ImgMergeBuffer.hpp @@ -17,6 +17,7 @@ #pragma once +#include #include "ImgDiffBuffer.hpp" struct UndoRecord @@ -143,9 +144,7 @@ class CImgMergeBuffer : public CImgDiffBuffer m_bRO[i] = false; } - virtual ~CImgMergeBuffer() - { - } + virtual ~CImgMergeBuffer() = default; bool NewImages(int nImages, int nPages, int width, int height) { @@ -178,6 +177,30 @@ class CImgMergeBuffer : public CImgDiffBuffer } bool Resize(int pane, int width, int height) + { + return Resize(pane, width, height, true); + } + + bool ResizeForPaste(int pane, int width, int height) + { + if (pane < 0 || pane >= m_nImages) + return false; + if (!m_pasteResizeOld[pane]) + m_pasteResizeOld[pane] = std::make_unique(m_imgOrig32[pane]); + return Resize(pane, width, height, false); + } + + void CancelPasteResize(int pane) + { + if (pane < 0 || pane >= m_nImages || !m_pasteResizeOld[pane]) + return; + m_imgOrig32[pane] = *m_pasteResizeOld[pane]; + m_pasteResizeOld[pane].reset(); + CompareImages(); + } + +private: + bool Resize(int pane, int width, int height, bool recordUndo) { if (width == m_imgOrig32[pane].width() && height == m_imgOrig32[pane].height()) return false; @@ -192,13 +215,21 @@ class CImgMergeBuffer : public CImgDiffBuffer Image *newbitmap = new Image(m_imgOrig32[pane]); - m_undoRecords.push_back(pane, oldbitmap, newbitmap); + if (recordUndo) + m_undoRecords.push_back(pane, oldbitmap, newbitmap); + else + { + delete oldbitmap; + delete newbitmap; + } CompareImages(); return true; } +public: + bool GetReadOnly(int pane) const { if (pane < 0 || pane >= m_nImages) @@ -471,8 +502,9 @@ class CImgMergeBuffer : public CImgDiffBuffer virtual bool CloseImages() override { + m_undoRecords.clear(); for (int i = 0; i < m_nImages; ++i) - m_undoRecords.clear(); + m_pasteResizeOld[i].reset(); return CImgDiffBuffer::CloseImages(); } @@ -481,7 +513,9 @@ class CImgMergeBuffer : public CImgDiffBuffer if (pane < 0 || pane >= m_nImages) return; - Image *oldbitmap = new Image(m_imgOrig32[pane]); + Image *oldbitmap = m_pasteResizeOld[pane].release(); + if (!oldbitmap) + oldbitmap = new Image(m_imgOrig32[pane]); { TemporaryTransformation tmp(*this); PasteImageInternal(pane, x, y, image); @@ -690,6 +724,7 @@ class CImgMergeBuffer : public CImgDiffBuffer private: bool m_bRO[3]; + std::unique_ptr m_pasteResizeOld[3]; UndoRecords m_undoRecords; }; diff --git a/src/WinIMergeLib/ImgMergeWindow.hpp b/src/WinIMergeLib/ImgMergeWindow.hpp index 593378e..91d2f92 100644 --- a/src/WinIMergeLib/ImgMergeWindow.hpp +++ b/src/WinIMergeLib/ImgMergeWindow.hpp @@ -796,7 +796,7 @@ class CImgMergeWindow : public IImgMergeWindow image.convertTo32Bits(); int maxwidth = (std::max)(m_buffer.GetImageWidth(pane), static_cast(image.getWidth())); int maxheight = (std::max)(m_buffer.GetImageHeight(pane), static_cast(image.getHeight())); - m_buffer.Resize(pane, maxwidth, maxheight); + m_buffer.ResizeForPaste(pane, maxwidth, maxheight); imgWindow.SetOverlappedImage(image); imgWindow.Invalidate(); return true; @@ -832,6 +832,7 @@ class CImgMergeWindow : public IImgMergeWindow return false; for (int pane = 0; pane < m_nImages; ++pane) { + m_buffer.CancelPasteResize(pane); m_imgWindow[pane].DeleteRectangleSelection(); m_imgWindow[pane].DeleteOverlappedImage(); } From 0aa443d1a575ec954a21e49d4bd13adb03c2cada Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Sun, 18 Oct 2026 18:20:44 +0900 Subject: [PATCH 2/2] Fix image paste cancellation and undo handling --- src/WinIMergeLib/ImgMergeBuffer.hpp | 56 +++++++++-------------------- src/WinIMergeLib/ImgMergeWindow.hpp | 25 ++++++++++--- 2 files changed, 37 insertions(+), 44 deletions(-) diff --git a/src/WinIMergeLib/ImgMergeBuffer.hpp b/src/WinIMergeLib/ImgMergeBuffer.hpp index 935d8e6..2de3e6e 100644 --- a/src/WinIMergeLib/ImgMergeBuffer.hpp +++ b/src/WinIMergeLib/ImgMergeBuffer.hpp @@ -17,7 +17,6 @@ #pragma once -#include #include "ImgDiffBuffer.hpp" struct UndoRecord @@ -177,30 +176,6 @@ class CImgMergeBuffer : public CImgDiffBuffer } bool Resize(int pane, int width, int height) - { - return Resize(pane, width, height, true); - } - - bool ResizeForPaste(int pane, int width, int height) - { - if (pane < 0 || pane >= m_nImages) - return false; - if (!m_pasteResizeOld[pane]) - m_pasteResizeOld[pane] = std::make_unique(m_imgOrig32[pane]); - return Resize(pane, width, height, false); - } - - void CancelPasteResize(int pane) - { - if (pane < 0 || pane >= m_nImages || !m_pasteResizeOld[pane]) - return; - m_imgOrig32[pane] = *m_pasteResizeOld[pane]; - m_pasteResizeOld[pane].reset(); - CompareImages(); - } - -private: - bool Resize(int pane, int width, int height, bool recordUndo) { if (width == m_imgOrig32[pane].width() && height == m_imgOrig32[pane].height()) return false; @@ -215,21 +190,13 @@ class CImgMergeBuffer : public CImgDiffBuffer Image *newbitmap = new Image(m_imgOrig32[pane]); - if (recordUndo) - m_undoRecords.push_back(pane, oldbitmap, newbitmap); - else - { - delete oldbitmap; - delete newbitmap; - } + m_undoRecords.push_back(pane, oldbitmap, newbitmap); CompareImages(); return true; } -public: - bool GetReadOnly(int pane) const { if (pane < 0 || pane >= m_nImages) @@ -351,6 +318,12 @@ class CImgMergeBuffer : public CImgDiffBuffer { if (pane < 0 || pane >= m_nImages || m_bRO[pane]) return false; + left = (std::max)(left, 0); + top = (std::max)(top, 0); + right = (std::min)(right, static_cast(m_imgOrig32[pane].width())); + bottom = (std::min)(bottom, static_cast(m_imgOrig32[pane].height())); + if (right <= left || bottom <= top) + return false; Image *oldbitmap = new Image(m_imgOrig32[pane]); @@ -503,8 +476,6 @@ class CImgMergeBuffer : public CImgDiffBuffer virtual bool CloseImages() override { m_undoRecords.clear(); - for (int i = 0; i < m_nImages; ++i) - m_pasteResizeOld[i].reset(); return CImgDiffBuffer::CloseImages(); } @@ -513,11 +484,17 @@ class CImgMergeBuffer : public CImgDiffBuffer if (pane < 0 || pane >= m_nImages) return; - Image *oldbitmap = m_pasteResizeOld[pane].release(); - if (!oldbitmap) - oldbitmap = new Image(m_imgOrig32[pane]); + Image *oldbitmap = new Image(m_imgOrig32[pane]); { TemporaryTransformation tmp(*this); + int width = (std::max)(static_cast(m_imgOrig32[pane].width()), x + static_cast(image.width())); + int height = (std::max)(static_cast(m_imgOrig32[pane].height()), y + static_cast(image.height())); + if (width != static_cast(m_imgOrig32[pane].width()) || height != static_cast(m_imgOrig32[pane].height())) + { + Image tmpImage = m_imgOrig32[pane]; + m_imgOrig32[pane].setSize(width, height); + PasteImageInternal(pane, 0, 0, tmpImage); + } PasteImageInternal(pane, x, y, image); } Image *newbitmap = new Image(m_imgOrig32[pane]); @@ -724,7 +701,6 @@ class CImgMergeBuffer : public CImgDiffBuffer private: bool m_bRO[3]; - std::unique_ptr m_pasteResizeOld[3]; UndoRecords m_undoRecords; }; diff --git a/src/WinIMergeLib/ImgMergeWindow.hpp b/src/WinIMergeLib/ImgMergeWindow.hpp index 91d2f92..b5efe5d 100644 --- a/src/WinIMergeLib/ImgMergeWindow.hpp +++ b/src/WinIMergeLib/ImgMergeWindow.hpp @@ -364,13 +364,17 @@ class CImgMergeWindow : public IImgMergeWindow void SetCurrentPage(int pane, int page) override { + CommitOverlappedImages(); m_buffer.SetCurrentPage(pane, page); + UpdateScrollBars(); Invalidate(); } void SetCurrentPageAll(int page) override { + CommitOverlappedImages(); m_buffer.SetCurrentPageAll(page); + UpdateScrollBars(); Invalidate(); } @@ -650,18 +654,21 @@ class CImgMergeWindow : public IImgMergeWindow void CopyDiff(int diffIndex, int srcPane, int dstPane) override { + CommitOverlappedImages(); m_buffer.CopyDiff(diffIndex, srcPane, dstPane); Invalidate(); } void CopyDiffAll(int srcPane, int dstPane) override { + CommitOverlappedImages(); m_buffer.CopyDiffAll(srcPane, dstPane); Invalidate(); } int CopyDiff3Way(int dstPane) override { + CommitOverlappedImages(); int result = m_buffer.CopyDiff3Way(dstPane); Invalidate(); return result; @@ -759,6 +766,7 @@ class CImgMergeWindow : public IImgMergeWindow int pane = GetActivePane(); if (pane < 0 || !m_imgWindow[pane].IsRectanlgeSelectionVisible()) return false; + CommitOverlappedImages(); Image image; RECT rc = ConvertToRealRect(pane, m_imgWindow[pane].GetRectangleSelection(), false); m_buffer.CopySubImage(pane, rc.left, rc.top, rc.right, rc.bottom, image); @@ -778,6 +786,12 @@ class CImgMergeWindow : public IImgMergeWindow return false; RECT rc = ConvertToRealRect(pane, m_imgWindow[pane].GetRectangleSelection(), false); Cancel(); + rc.left = (std::max)(rc.left, 0L); + rc.top = (std::max)(rc.top, 0L); + rc.right = (std::min)(rc.right, static_cast(m_buffer.GetImageWidth(pane))); + rc.bottom = (std::min)(rc.bottom, static_cast(m_buffer.GetImageHeight(pane))); + if (rc.right <= rc.left || rc.bottom <= rc.top) + return false; bool result = m_buffer.DeleteRectangle(pane, rc.left, rc.top, rc.right, rc.bottom); if (result) Invalidate(); @@ -794,9 +808,6 @@ class CImgMergeWindow : public IImgMergeWindow fipImageEx image; image.pasteFromClipboard(); image.convertTo32Bits(); - int maxwidth = (std::max)(m_buffer.GetImageWidth(pane), static_cast(image.getWidth())); - int maxheight = (std::max)(m_buffer.GetImageHeight(pane), static_cast(image.getHeight())); - m_buffer.ResizeForPaste(pane, maxwidth, maxheight); imgWindow.SetOverlappedImage(image); imgWindow.Invalidate(); return true; @@ -832,10 +843,10 @@ class CImgMergeWindow : public IImgMergeWindow return false; for (int pane = 0; pane < m_nImages; ++pane) { - m_buffer.CancelPasteResize(pane); m_imgWindow[pane].DeleteRectangleSelection(); m_imgWindow[pane].DeleteOverlappedImage(); } + UpdateScrollBars(); Invalidate(); return true; } @@ -1708,6 +1719,12 @@ class CImgMergeWindow : public IImgMergeWindow Invalidate(); } + void CommitOverlappedImages() + { + for (int pane = 0; pane < m_nImages; ++pane) + PasteAndDeleteOverlappedImage(pane); + } + void PasteAndDeleteOverlappedImage(int pane) { PasteOverlappedImage(pane);