CommandHistory
This commit is contained in:
parent
bb72e6d753
commit
180cd516ea
|
@ -1,13 +1,63 @@
|
|||
use super::{Graph, GraphError, GraphResult};
|
||||
use crate::node::{Edge, Node, NodeKind, SlotIndex};
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub trait Command {
|
||||
pub trait Command: Debug {
|
||||
fn undo(&self, graph: &Graph) -> GraphResult<DynCommand>;
|
||||
fn apply(&self, graph: &mut Graph) -> GraphResult<()>;
|
||||
}
|
||||
|
||||
pub type DynCommand = Box<dyn Command>;
|
||||
|
||||
pub struct CommandHistory {
|
||||
commands: Vec<(DynCommand, DynCommand)>,
|
||||
cursor: usize,
|
||||
}
|
||||
|
||||
impl CommandHistory {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
commands: Vec::new(),
|
||||
cursor: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, graph: &mut Graph, cmd: DynCommand) -> GraphResult<()> {
|
||||
let undo = cmd.undo(graph)?;
|
||||
cmd.apply(graph)?;
|
||||
|
||||
// Discard redo history on new push
|
||||
if self.cursor < self.commands.len() {
|
||||
self.commands.truncate(self.cursor);
|
||||
}
|
||||
|
||||
self.commands.push((cmd, undo));
|
||||
self.cursor += 1;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn undo(&mut self, graph: &mut Graph) -> GraphResult<bool> {
|
||||
if self.cursor > 0 {
|
||||
self.cursor -= 1;
|
||||
self.commands[self.cursor].1.apply(graph)?;
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn redo(&mut self, graph: &mut Graph) -> GraphResult<bool> {
|
||||
if self.cursor < self.commands.len() {
|
||||
self.commands[self.cursor].0.apply(graph)?;
|
||||
self.cursor += 1;
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CreateNode {
|
||||
pub kind: NodeKind,
|
||||
|
@ -171,7 +221,7 @@ impl Command for DeleteEdge {
|
|||
.get_mut(self.input.slot)
|
||||
.ok_or(GraphError::InvalidReference)?;
|
||||
|
||||
if input.is_some() {
|
||||
if input.is_none() {
|
||||
Err(GraphError::MissingEdge)
|
||||
} else {
|
||||
*input = None;
|
||||
|
@ -185,6 +235,58 @@ mod tests {
|
|||
use super::*;
|
||||
use crate::node::AtomOp;
|
||||
|
||||
impl CommandHistory {
|
||||
pub fn push_multi(
|
||||
&mut self,
|
||||
graph: &mut Graph,
|
||||
cmds: impl IntoIterator<Item = DynCommand>,
|
||||
) -> GraphResult<()> {
|
||||
for cmd in cmds {
|
||||
println!("{:#?}", cmd);
|
||||
self.push(graph, cmd)?;
|
||||
println!("{:#?}", graph);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn rewind(&mut self, graph: &mut Graph) -> GraphResult<()> {
|
||||
while self.cursor > 0 {
|
||||
self.cursor -= 1;
|
||||
let undo = &self.commands[self.cursor].1;
|
||||
println!("{:#?}", undo);
|
||||
undo.apply(graph)?;
|
||||
println!("{:#?}", graph);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn three_node_add_cmds() -> Vec<DynCommand> {
|
||||
vec![
|
||||
Box::new(CreateNode::from(Node::literal(1.0))),
|
||||
Box::new(CreateNode::from(Node::literal(2.0))),
|
||||
Box::new(CreateNode::from(Node {
|
||||
kind: NodeKind::Op(AtomOp::Add),
|
||||
pos: glam::Vec2::ZERO,
|
||||
inputs: vec![None; 2],
|
||||
})),
|
||||
Box::new(SetEdge {
|
||||
edge: Edge {
|
||||
input: SlotIndex { node: 0, slot: 0 },
|
||||
output: SlotIndex { node: 2, slot: 0 },
|
||||
},
|
||||
}),
|
||||
Box::new(SetEdge {
|
||||
edge: Edge {
|
||||
input: SlotIndex { node: 1, slot: 0 },
|
||||
output: SlotIndex { node: 2, slot: 1 },
|
||||
},
|
||||
}),
|
||||
]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_node() -> GraphResult<()> {
|
||||
let mut graph = Graph::new();
|
||||
|
@ -207,39 +309,30 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn set_edge() -> GraphResult<()> {
|
||||
fn three_node_add() -> GraphResult<()> {
|
||||
let mut graph = Graph::new();
|
||||
|
||||
CreateNode::from(Node::literal(1.0)).apply(&mut graph)?;
|
||||
CreateNode::from(Node::literal(2.0)).apply(&mut graph)?;
|
||||
|
||||
CreateNode::from(Node {
|
||||
kind: NodeKind::Op(AtomOp::Add),
|
||||
pos: glam::Vec2::ZERO,
|
||||
inputs: vec![None; 2],
|
||||
})
|
||||
.apply(&mut graph)?;
|
||||
|
||||
SetEdge {
|
||||
edge: Edge {
|
||||
input: SlotIndex { node: 0, slot: 0 },
|
||||
output: SlotIndex { node: 2, slot: 0 },
|
||||
},
|
||||
}
|
||||
.apply(&mut graph)?;
|
||||
|
||||
SetEdge {
|
||||
edge: Edge {
|
||||
input: SlotIndex { node: 1, slot: 0 },
|
||||
output: SlotIndex { node: 2, slot: 1 },
|
||||
},
|
||||
}
|
||||
.apply(&mut graph)?;
|
||||
let cmds = three_node_add_cmds();
|
||||
|
||||
println!("{:#?}", graph);
|
||||
for cmd in cmds.into_iter() {
|
||||
println!("{:#?}", cmd);
|
||||
cmd.apply(&mut graph)?;
|
||||
println!("{:#?}", graph);
|
||||
}
|
||||
|
||||
graph.topological_order()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn three_node_add_rewind() -> GraphResult<()> {
|
||||
let mut graph = Graph::new();
|
||||
let mut history = CommandHistory::new();
|
||||
let cmds = three_node_add_cmds();
|
||||
history.push_multi(&mut graph, cmds)?;
|
||||
graph.topological_order()?;
|
||||
history.rewind(&mut graph)?;
|
||||
assert_eq!(graph.nodes.len(), 0);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue