240 lines
5.5 KiB
Rust
240 lines
5.5 KiB
Rust
use super::{Graph, GraphError, GraphResult};
|
|
use crate::node::{Edge, Node, SlotIndex};
|
|
use std::fmt::Debug;
|
|
|
|
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 {
|
|
pub(crate) commands: Vec<(DynCommand, DynCommand)>,
|
|
pub(crate) 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: usize,
|
|
pub pos: glam::Vec2,
|
|
pub inputs: Vec<Option<SlotIndex>>,
|
|
}
|
|
|
|
impl Command for CreateNode {
|
|
fn undo(&self, graph: &Graph) -> GraphResult<DynCommand> {
|
|
let target = graph.nodes.vacant_key();
|
|
let undo = DeleteNode { target };
|
|
Ok(Box::new(undo))
|
|
}
|
|
|
|
fn apply(&self, graph: &mut Graph) -> GraphResult<()> {
|
|
let node = Node {
|
|
kind: self.kind,
|
|
pos: self.pos,
|
|
inputs: self.inputs.clone(),
|
|
};
|
|
|
|
graph.nodes.insert(node);
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl From<Node> for CreateNode {
|
|
fn from(node: Node) -> Self {
|
|
Self {
|
|
kind: node.kind,
|
|
pos: node.pos,
|
|
inputs: node.inputs,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct DeleteNode {
|
|
pub target: usize,
|
|
}
|
|
|
|
impl Command for DeleteNode {
|
|
fn undo(&self, graph: &Graph) -> GraphResult<DynCommand> {
|
|
let target = graph.get_node(self.target)?;
|
|
|
|
let undo = CreateNode {
|
|
kind: target.kind,
|
|
pos: target.pos,
|
|
inputs: target.inputs.clone(),
|
|
};
|
|
|
|
Ok(Box::new(undo))
|
|
}
|
|
|
|
fn apply(&self, graph: &mut Graph) -> GraphResult<()> {
|
|
graph
|
|
.nodes
|
|
.try_remove(self.target)
|
|
.ok_or(GraphError::InvalidReference)
|
|
.map(|_| ())
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct MoveNode {
|
|
pub target: usize,
|
|
pub to: glam::Vec2,
|
|
pub relative: bool,
|
|
}
|
|
|
|
impl Command for MoveNode {
|
|
fn undo(&self, graph: &Graph) -> GraphResult<DynCommand> {
|
|
let target = graph.get_node(self.target)?;
|
|
|
|
let undo = Self {
|
|
target: self.target,
|
|
to: target.pos,
|
|
relative: false,
|
|
};
|
|
|
|
Ok(Box::new(undo))
|
|
}
|
|
|
|
fn apply(&self, graph: &mut Graph) -> GraphResult<()> {
|
|
let target = graph.get_node_mut(self.target)?;
|
|
|
|
if self.relative {
|
|
target.pos += self.to;
|
|
} else {
|
|
target.pos = self.to;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct SetEdge {
|
|
pub edge: Edge,
|
|
}
|
|
|
|
impl Command for SetEdge {
|
|
fn undo(&self, graph: &Graph) -> GraphResult<DynCommand> {
|
|
let target = graph.get_node(self.edge.output.node)?;
|
|
|
|
let old_input = target
|
|
.inputs
|
|
.get(self.edge.output.slot)
|
|
.ok_or(GraphError::InvalidReference)?;
|
|
|
|
Ok(match old_input {
|
|
Some(old_input) => Box::new(SetEdge {
|
|
edge: Edge {
|
|
input: *old_input,
|
|
output: self.edge.output,
|
|
},
|
|
}),
|
|
None => Box::new(DeleteEdge {
|
|
input: self.edge.output,
|
|
}),
|
|
})
|
|
}
|
|
|
|
fn apply(&self, graph: &mut Graph) -> GraphResult<()> {
|
|
let target = graph.get_node_mut(self.edge.output.node)?;
|
|
|
|
let input = target
|
|
.inputs
|
|
.get_mut(self.edge.output.slot)
|
|
.ok_or(GraphError::InvalidReference)?;
|
|
|
|
*input = Some(self.edge.input);
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct DeleteEdge {
|
|
pub input: SlotIndex,
|
|
}
|
|
|
|
impl Command for DeleteEdge {
|
|
fn undo(&self, graph: &Graph) -> GraphResult<DynCommand> {
|
|
let target = graph.get_node(self.input.node)?;
|
|
|
|
let old_input = target
|
|
.inputs
|
|
.get(self.input.slot)
|
|
.ok_or(GraphError::InvalidReference)?
|
|
.ok_or(GraphError::MissingEdge)?;
|
|
|
|
let undo = SetEdge {
|
|
edge: Edge {
|
|
input: old_input,
|
|
output: self.input,
|
|
},
|
|
};
|
|
|
|
Ok(Box::new(undo))
|
|
}
|
|
|
|
fn apply(&self, graph: &mut Graph) -> GraphResult<()> {
|
|
let target = graph.get_node_mut(self.input.node)?;
|
|
|
|
let input = target
|
|
.inputs
|
|
.get_mut(self.input.slot)
|
|
.ok_or(GraphError::InvalidReference)?;
|
|
|
|
if input.is_none() {
|
|
Err(GraphError::MissingEdge)
|
|
} else {
|
|
*input = None;
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|