use arael::vect::vect2d;
use arael_sketch_solver::Sketch;
use crate::actions::Action;
#[derive(Clone, Default)]
pub struct CursorState {
pub pos: Option<vect2d>,
pub tangent: Option<vect2d>,
}
pub struct History {
pub actions: Vec<Action>,
pub snapshots: Vec<Vec<u8>>, pub cursors: Vec<CursorState>,
pub groups: Vec<u32>, pub cursor: usize, pub next_group: u32,
pub current_group: u32,
initial_snapshot: Vec<u8>, }
impl History {
pub fn new(sketch: &Sketch) -> Self {
History {
actions: Vec::new(), snapshots: Vec::new(), cursors: Vec::new(), groups: Vec::new(),
cursor: 0, next_group: 0, current_group: 0,
initial_snapshot: bincode::serialize(sketch).unwrap(),
}
}
pub fn begin_group(&mut self) {
self.current_group = self.next_group;
self.next_group += 1;
}
pub fn push(&mut self, action: Action, sketch: &Sketch, cursor: CursorState) {
self.actions.truncate(self.cursor);
self.snapshots.truncate(self.cursor);
self.cursors.truncate(self.cursor);
self.groups.truncate(self.cursor);
self.actions.push(action);
self.snapshots.push(bincode::serialize(sketch).unwrap());
self.cursors.push(cursor);
self.groups.push(self.current_group);
self.cursor += 1;
}
pub fn can_undo(&self) -> bool { self.cursor > 0 }
pub fn can_redo(&self) -> bool { self.cursor < self.actions.len() }
pub fn undo(&mut self) -> Option<(Sketch, CursorState)> {
if self.cursor == 0 { return None; }
let group = self.groups[self.cursor - 1];
let mut group_start = self.cursor - 1;
while group_start > 0 && self.groups[group_start - 1] == group {
group_start -= 1;
}
let restored_cursor = self.cursors[group_start].clone();
while self.cursor > 0 && self.groups[self.cursor - 1] == group {
self.cursor -= 1;
}
if self.cursor == 0 {
let mut sketch: Sketch = bincode::deserialize(&self.initial_snapshot).unwrap();
sketch.solve();
Some((sketch, restored_cursor))
} else {
let mut sketch: Sketch = bincode::deserialize(&self.snapshots[self.cursor - 1]).unwrap();
sketch.solve();
Some((sketch, restored_cursor))
}
}
pub fn redo(&mut self) -> Option<(Sketch, CursorState)> {
if self.cursor >= self.actions.len() { return None; }
let group = self.groups[self.cursor];
while self.cursor < self.actions.len() && self.groups[self.cursor] == group {
self.cursor += 1;
}
let mut sketch: Sketch = bincode::deserialize(&self.snapshots[self.cursor - 1]).unwrap();
sketch.solve();
Some((sketch, self.cursors[self.cursor - 1].clone()))
}
pub fn group_list(&self) -> Vec<(u32, usize, String)> {
let mut result = Vec::new();
let mut i = 0;
while i < self.actions.len() {
let gid = self.groups[i];
let desc = self.actions[i].describe();
let mut count = 0;
while i < self.actions.len() && self.groups[i] == gid {
i += 1;
count += 1;
}
let label = if count > 1 { format!("{} (+{})", desc, count - 1) } else { desc };
result.push((gid, i, label));
}
result
}
pub fn goto(&mut self, target: usize) -> Option<(Sketch, CursorState)> {
let mut result = None;
while self.cursor > target {
result = self.undo();
if result.is_none() { break; }
}
while self.cursor < target {
result = self.redo();
if result.is_none() { break; }
}
result
}
}