pub trait UndoRedoCommand {
fn name(&self) -> &str;
fn do_it(&mut self);
fn undo_it(&mut self);
}
pub struct UndoBuffer {
undo_stack: Vec<Box<dyn UndoRedoCommand>>,
redo_stack: Vec<Box<dyn UndoRedoCommand>>,
max_undos: usize,
}
impl UndoBuffer {
pub fn new() -> Self {
Self {
undo_stack: Vec::new(),
redo_stack: Vec::new(),
max_undos: 200,
}
}
pub fn with_max_undos(mut self, n: usize) -> Self {
self.max_undos = n;
self
}
pub fn add(&mut self, cmd: Box<dyn UndoRedoCommand>) {
self.redo_stack.clear();
self.undo_stack.push(cmd);
if self.undo_stack.len() > self.max_undos {
self.undo_stack.remove(0);
}
}
pub fn add_and_do(&mut self, mut cmd: Box<dyn UndoRedoCommand>) {
cmd.do_it();
self.add(cmd);
}
pub fn undo(&mut self) {
if let Some(mut cmd) = self.undo_stack.pop() {
cmd.undo_it();
self.redo_stack.push(cmd);
}
}
pub fn redo(&mut self) {
if let Some(mut cmd) = self.redo_stack.pop() {
cmd.do_it();
self.undo_stack.push(cmd);
}
}
pub fn can_undo(&self) -> bool {
!self.undo_stack.is_empty()
}
pub fn can_redo(&self) -> bool {
!self.redo_stack.is_empty()
}
pub fn undo_name(&self) -> Option<&str> {
self.undo_stack.last().map(|c| c.name())
}
pub fn redo_name(&self) -> Option<&str> {
self.redo_stack.last().map(|c| c.name())
}
pub fn clear_history(&mut self) {
self.undo_stack.clear();
self.redo_stack.clear();
}
}
impl Default for UndoBuffer {
fn default() -> Self {
Self::new()
}
}
pub struct DoUndoActions {
name: String,
do_fn: Box<dyn FnMut()>,
undo_fn: Box<dyn FnMut()>,
}
impl DoUndoActions {
pub fn new(
name: impl Into<String>,
do_action: impl FnMut() + 'static,
undo_action: impl FnMut() + 'static,
) -> Self {
Self {
name: name.into(),
do_fn: Box::new(do_action),
undo_fn: Box::new(undo_action),
}
}
}
impl UndoRedoCommand for DoUndoActions {
fn name(&self) -> &str {
&self.name
}
fn do_it(&mut self) {
(self.do_fn)()
}
fn undo_it(&mut self) {
(self.undo_fn)()
}
}