Files
2026-04-05 18:52:19 +08:00

228 lines
9.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Ink;
using System.Windows.Input;
// Added for UIElement
namespace Ink_Canvas.Helpers
{
public partial class TimeMachine
{
private readonly List<TimeMachineHistory> _currentStrokeHistory = new List<TimeMachineHistory>();
private int _currentIndex = -1;
public delegate void OnUndoStateChange(bool status);
public event OnUndoStateChange OnUndoStateChanged;
public delegate void OnRedoStateChange(bool status);
public event OnRedoStateChange OnRedoStateChanged;
public void CommitStrokeUserInputHistory(StrokeCollection stroke)
{
if (_currentIndex + 1 < _currentStrokeHistory.Count)
{
_currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex);
}
_currentStrokeHistory.Add(new TimeMachineHistory(stroke, TimeMachineHistoryType.UserInput, false));
_currentIndex = _currentStrokeHistory.Count - 1;
NotifyUndoRedoState();
}
public void CommitStrokeShapeHistory(StrokeCollection strokeToBeReplaced, StrokeCollection generatedStroke)
{
if (_currentIndex + 1 < _currentStrokeHistory.Count)
{
_currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex);
}
_currentStrokeHistory.Add(new TimeMachineHistory(generatedStroke,
TimeMachineHistoryType.ShapeRecognition,
false,
strokeToBeReplaced));
_currentIndex = _currentStrokeHistory.Count - 1;
NotifyUndoRedoState();
}
public void CommitStrokeManipulationHistory(Dictionary<Stroke, Tuple<StylusPointCollection, StylusPointCollection>> stylusPointDictionary)
{
if (_currentIndex + 1 < _currentStrokeHistory.Count)
{
_currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex);
}
_currentStrokeHistory.Add(
new TimeMachineHistory(stylusPointDictionary,
TimeMachineHistoryType.Manipulation));
_currentIndex = _currentStrokeHistory.Count - 1;
NotifyUndoRedoState();
}
public void CommitStrokeDrawingAttributesHistory(Dictionary<Stroke, Tuple<DrawingAttributes, DrawingAttributes>> drawingAttributes)
{
if (_currentIndex + 1 < _currentStrokeHistory.Count)
{
_currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex);
}
_currentStrokeHistory.Add(
new TimeMachineHistory(drawingAttributes,
TimeMachineHistoryType.DrawingAttributes));
_currentIndex = _currentStrokeHistory.Count - 1;
NotifyUndoRedoState();
}
public void CommitStrokeEraseHistory(StrokeCollection stroke, StrokeCollection sourceStroke = null)
{
if (_currentIndex + 1 < _currentStrokeHistory.Count)
{
_currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex);
}
_currentStrokeHistory.Add(new TimeMachineHistory(stroke, TimeMachineHistoryType.Clear, true, sourceStroke));
_currentIndex = _currentStrokeHistory.Count - 1;
NotifyUndoRedoState();
}
public void ClearStrokeHistory()
{
_currentStrokeHistory.Clear();
_currentIndex = -1;
NotifyUndoRedoState();
}
public TimeMachineHistory Undo()
{
if (_currentIndex < 0 || _currentIndex >= _currentStrokeHistory.Count)
{
return null;
}
var item = _currentStrokeHistory[_currentIndex];
item.StrokeHasBeenCleared = !item.StrokeHasBeenCleared;
_currentIndex--;
OnUndoStateChanged?.Invoke(CanUndo);
OnRedoStateChanged?.Invoke(CanRedo);
return item;
}
public TimeMachineHistory Redo()
{
if (_currentStrokeHistory.Count == 0 || _currentIndex >= _currentStrokeHistory.Count - 1)
{
return null;
}
var item = _currentStrokeHistory[++_currentIndex];
item.StrokeHasBeenCleared = !item.StrokeHasBeenCleared;
NotifyUndoRedoState();
return item;
}
public TimeMachineHistory[] ExportTimeMachineHistory()
{
if (_currentIndex + 1 < _currentStrokeHistory.Count)
{
_currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex);
}
return _currentStrokeHistory.ToArray();
}
public bool ImportTimeMachineHistory(TimeMachineHistory[] sourceHistory)
{
_currentStrokeHistory.Clear();
_currentStrokeHistory.AddRange(sourceHistory);
_currentIndex = _currentStrokeHistory.Count - 1;
NotifyUndoRedoState();
return true;
}
private void NotifyUndoRedoState()
{
OnUndoStateChanged?.Invoke(CanUndo);
OnRedoStateChanged?.Invoke(CanRedo);
}
/// <summary>当前历史是否允许撤销。</summary>
public bool CanUndo => _currentIndex > -1;
/// <summary>当前历史是否允许重做。</summary>
public bool CanRedo => _currentStrokeHistory.Count > 0 && _currentStrokeHistory.Count - _currentIndex - 1 > 0;
}
public class TimeMachineHistory
{
public TimeMachineHistoryType CommitType;
public bool StrokeHasBeenCleared;
public StrokeCollection CurrentStroke;
public StrokeCollection ReplacedStroke;
//这里说一下 Tuple的 Value1 是初始值 ; Value 2 是改变值
public Dictionary<Stroke, Tuple<StylusPointCollection, StylusPointCollection>> StylusPointDictionary;
public Dictionary<Stroke, Tuple<DrawingAttributes, DrawingAttributes>> DrawingAttributes;
public UIElement InsertedElement; // 新增
public TimeMachineHistory(StrokeCollection currentStroke, TimeMachineHistoryType commitType, bool strokeHasBeenCleared)
{
CommitType = commitType;
CurrentStroke = currentStroke;
StrokeHasBeenCleared = strokeHasBeenCleared;
ReplacedStroke = null;
}
public TimeMachineHistory(Dictionary<Stroke, Tuple<StylusPointCollection, StylusPointCollection>> stylusPointDictionary, TimeMachineHistoryType commitType)
{
CommitType = commitType;
StylusPointDictionary = stylusPointDictionary;
}
public TimeMachineHistory(Dictionary<Stroke, Tuple<DrawingAttributes, DrawingAttributes>> drawingAttributes, TimeMachineHistoryType commitType)
{
CommitType = commitType;
DrawingAttributes = drawingAttributes;
}
public TimeMachineHistory(StrokeCollection currentStroke, TimeMachineHistoryType commitType, bool strokeHasBeenCleared, StrokeCollection replacedStroke)
{
CommitType = commitType;
CurrentStroke = currentStroke;
StrokeHasBeenCleared = strokeHasBeenCleared;
ReplacedStroke = replacedStroke;
}
public TimeMachineHistory(UIElement element, TimeMachineHistoryType commitType) // 新增
{
CommitType = commitType;
InsertedElement = element;
}
}
public enum TimeMachineHistoryType
{
UserInput,
ShapeRecognition,
Clear,
Manipulation,
DrawingAttributes,
ElementInsert // 新增
}
public partial class TimeMachine // 新增partial,便于扩展
{
public void CommitElementInsertHistory(UIElement element)
{
if (_currentIndex + 1 < _currentStrokeHistory.Count)
{
_currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex);
}
_currentStrokeHistory.Add(new TimeMachineHistory(element, TimeMachineHistoryType.ElementInsert));
_currentIndex = _currentStrokeHistory.Count - 1;
NotifyUndoRedoState();
}
public void CommitElementRemoveHistory(UIElement element)
{
if (_currentIndex + 1 < _currentStrokeHistory.Count)
{
_currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex);
}
var history = new TimeMachineHistory(element, TimeMachineHistoryType.ElementInsert);
history.StrokeHasBeenCleared = true; // 标记为已清除
_currentStrokeHistory.Add(history);
_currentIndex = _currentStrokeHistory.Count - 1;
NotifyUndoRedoState();
}
}
}