From 250dff71071a1d3a613d869e03fe856422c2caa6 Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Tue, 27 Jul 2021 17:17:34 +0800 Subject: [PATCH] correct Delete operation behavior --- Core/FileOperation.cs | 30 +++++++++++++++++------------- Core/Util.cs | 10 ++++++++-- UI/TASViewer.cs | 16 +++++++++++++--- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/Core/FileOperation.cs b/Core/FileOperation.cs index 861ca6a..6562d2b 100644 --- a/Core/FileOperation.cs +++ b/Core/FileOperation.cs @@ -89,7 +89,7 @@ namespace BallanceTASEditor.Core.FileOperation { removedItems.Clear(); oldPointer = mPointer; oldPointerIndex = mPointerIndex; - removeStartNode = absoluteRange.start == 1 ? null : mMem.FastGetNode(mPointer, mPointerIndex, absoluteRange.start - 1); + removeStartNode = absoluteRange.start == 0 ? null : mMem.FastGetNode(mPointer, mPointerIndex, absoluteRange.start - 1); // find proper pointer after remove first. but we do not apply it in there. // if state is true, it mean the deleted content is placed before pointer previously. we should consider pointer data and we should correct them. @@ -100,25 +100,25 @@ namespace BallanceTASEditor.Core.FileOperation { // otherwise we only need to minus index with the length of removed content. if (absoluteRange.Within(mPointerIndex)) { // this contains 3 situation - // if full delete, mPointer is null and mPointerIndex is invalid(with wrong data: 0) + // if full delete, mPointer is null and mPointerIndex is invalid(with wrong data: -1) // if delete from head, mPointer and mPointerIndex all are valid. but it is the tail of removed content // otherwise, just find the head of removed content and shift to it. - if (absoluteRange.start == 1 && absoluteRange.end == mMem.Count) { + if (absoluteRange.start == 0 && absoluteRange.end == mMem.Count - 1) { // fully remove newPointer = null; - newPointerIndex = 0; - } else if (absoluteRange.start == 1) { + newPointerIndex = -1; + } else if (absoluteRange.start == 0) { // remove from head - newPointerIndex = absoluteRange.end + 1; - newPointer = mMem.FastGetNode(mPointer, mPointerIndex, newPointerIndex); + newPointerIndex = 0; + newPointer = mMem.FastGetNode(mPointer, mPointerIndex, absoluteRange.end + 1); } else { // simple remove newPointerIndex = absoluteRange.start - 1; - newPointer = mMem.FastGetNode(mPointer, mPointerIndex, newPointerIndex); + newPointer = mMem.FastGetNode(mPointer, mPointerIndex, absoluteRange.start - 1); } } else { newPointer = mPointer; - newPointerIndex = mPointerIndex - absoluteRange.GetCount() + 1; + newPointerIndex = mPointerIndex - absoluteRange.GetCount(); } } else { // not affected situation @@ -128,8 +128,8 @@ namespace BallanceTASEditor.Core.FileOperation { // the real remove operation foreach (var item in mMem.IterateWithSelectionRange(absoluteRange, mPointer, mPointerIndex)) { - removedItems.AddLast(item); // backups node first; mMem.Remove(item); + removedItems.AddLast(item); // backups node; } // apply gotten new pointer @@ -140,10 +140,12 @@ namespace BallanceTASEditor.Core.FileOperation { public override void Undo(ref LinkedList mMem, ref LinkedListNode mPointer, ref long mPointerIndex) { base.Undo(ref mMem, ref mPointer, ref mPointerIndex); - if (mPointer == null) return; + // may recovered from empty list + //if (mPointer == null) return; // re-insert data foreach (var item in removedItems.IterateFullReversed()) { + removedItems.Remove(item); if (removeStartNode == null) { // insert at first mMem.AddFirst(item); @@ -395,11 +397,13 @@ namespace BallanceTASEditor.Core.FileOperation { // if we use overwrite mode, we need re-add lost data if (isOverwritten) { if (isInsertBefore) { - foreach (var item in data.IterateFull()) { + foreach (var item in oldItems.IterateFull()) { + oldItems.Remove(item); mMem.AddBefore(addStartNode, item); } } else { - foreach (var item in data.IterateFullReversed()) { + foreach (var item in oldItems.IterateFullReversed()) { + oldItems.Remove(item); mMem.AddAfter(addStartNode, item); } } diff --git a/Core/Util.cs b/Core/Util.cs index a0762bf..beb5865 100644 --- a/Core/Util.cs +++ b/Core/Util.cs @@ -33,21 +33,27 @@ namespace BallanceTASEditor.Core { // for (int i = 0; i < count; i++) list.RemoveAt(index); //} + // remove safety. because it store the next node. public static IEnumerable> IterateFullReversed(this LinkedList ls) { var pos = ls.Last; + LinkedListNode cacheNextNode; while (pos != null) { + cacheNextNode = pos.Previous; yield return pos; - pos = pos.Previous; + pos = cacheNextNode; } } + // remove safety. because it store the next node. public static IEnumerable> IterateFull(this LinkedList ls) { var pos = ls.First; + LinkedListNode cacheNextNode; while(pos != null) { + cacheNextNode = pos.Next; yield return pos; - pos = pos.Next; + pos = cacheNextNode; } } diff --git a/UI/TASViewer.cs b/UI/TASViewer.cs index 6210014..7fa4f19 100644 --- a/UI/TASViewer.cs +++ b/UI/TASViewer.cs @@ -191,14 +191,24 @@ namespace BallanceTASEditor.UI { case OperationEnum.DeleteAfter: case OperationEnum.DeleteBefore: { var pos = mSelectionHelp.GetPoint(); - pos += oper == OperationEnum.DeleteBefore ? -1 : 1; - if (pos < 0 || pos > mFile.mFrameCount) return; - mFile.Remove(new SelectionRange(pos, pos)); + if (oper == OperationEnum.DeleteBefore) pos -= 1; // delete after mean delete current selected item + if (pos < 0 || pos >= mFile.mFrameCount) return; // only delete before need shift selection + // delete before couldn't cause empty list, so we just need to directly shift if (oper == OperationEnum.DeleteBefore) mSelectionHelp.ShiftTo(false); + // also, if we use delete after and delete the tail of item list, we also need to shift pos(use `else if` to prevent double shift) + else if (oper == OperationEnum.DeleteAfter && pos == mFile.mFrameCount) { + // but delete after may cause empty list error(delete the item within only 1 item list) + // so we need prevent this situation + if (mFile.mFrameCount == 1) mSelectionHelp.Reset(); //yes, reset selection to prevent error + else mSelectionHelp.ShiftTo(false); //no, shift selection. + } + // do real operation + mFile.Remove(new SelectionRange(pos, pos)); + updateSliderRange(); RefreshDisplay(); }