Skip to main content

ferrum_flow/canvas/
undo.rs

1use std::collections::HashMap;
2
3use gpui::{Bounds, Pixels, Point};
4
5use crate::{Edge, EdgeId, Graph, Node, NodeBuilder, NodeId, Port, PortId, Viewport};
6
7pub trait Command {
8    fn name(&self) -> &'static str;
9    fn execute(&mut self, ctx: &mut CanvasState);
10    fn undo(&mut self, ctx: &mut CanvasState);
11}
12
13pub struct CanvasState<'a> {
14    pub graph: &'a mut Graph,
15    pub viewport: &'a mut Viewport,
16}
17
18const MAX_HISTORY: usize = 100;
19
20pub struct History {
21    undo_stack: Vec<Box<dyn Command>>,
22    redo_stack: Vec<Box<dyn Command>>,
23}
24
25impl History {
26    pub fn new() -> Self {
27        Self {
28            undo_stack: Vec::new(),
29            redo_stack: Vec::new(),
30        }
31    }
32
33    pub fn execute(&mut self, mut command: Box<dyn Command>, state: &mut CanvasState) {
34        command.execute(state);
35
36        self.undo_stack.push(command);
37        if self.undo_stack.len() > MAX_HISTORY {
38            self.undo_stack.remove(0);
39        }
40        self.redo_stack.clear();
41    }
42
43    pub fn undo(&mut self, state: &mut CanvasState) {
44        if let Some(mut cmd) = self.undo_stack.pop() {
45            cmd.undo(state);
46            self.redo_stack.push(cmd);
47        }
48    }
49
50    pub fn redo(&mut self, state: &mut CanvasState) {
51        if let Some(mut cmd) = self.redo_stack.pop() {
52            cmd.execute(state);
53            self.undo_stack.push(cmd);
54        }
55    }
56}
57
58pub struct CompositeCommand {
59    commands: Vec<Box<dyn Command>>,
60}
61
62impl CompositeCommand {
63    pub fn new() -> Self {
64        Self {
65            commands: Vec::new(),
66        }
67    }
68    pub fn push(&mut self, command: impl Command + 'static) {
69        self.commands.push(Box::new(command));
70    }
71}
72
73impl Command for CompositeCommand {
74    fn name(&self) -> &'static str {
75        "composite"
76    }
77    fn execute(&mut self, state: &mut CanvasState) {
78        for cmd in &mut self.commands {
79            cmd.execute(state);
80        }
81    }
82
83    fn undo(&mut self, state: &mut CanvasState) {
84        for cmd in self.commands.iter_mut().rev() {
85            cmd.undo(state);
86        }
87    }
88}
89
90impl<'a> CanvasState<'a> {
91    pub fn create_node(&self, node_type: &str) -> NodeBuilder {
92        self.graph.create_node(node_type)
93    }
94
95    pub fn next_node_id(&self) -> NodeId {
96        self.graph.next_node_id()
97    }
98
99    pub fn next_port_id(&self) -> PortId {
100        self.graph.next_port_id()
101    }
102
103    pub fn next_edge_id(&self) -> EdgeId {
104        self.graph.next_edge_id()
105    }
106    pub fn add_node(&mut self, node: Node) {
107        self.graph.add_node(node);
108    }
109
110    pub fn add_point(&mut self, port: Port) {
111        self.graph.add_point(port);
112    }
113
114    pub fn get_node(&self, id: &NodeId) -> Option<&Node> {
115        self.graph.get_node(id)
116    }
117
118    pub fn get_node_mut(&mut self, id: &NodeId) -> Option<&mut Node> {
119        self.graph.get_node_mut(id)
120    }
121    pub fn remove_node(&mut self, id: &NodeId) {
122        self.graph.remove_node(id);
123    }
124    pub fn nodes(&self) -> &HashMap<NodeId, Node> {
125        self.graph.nodes()
126    }
127    pub fn node_order(&self) -> &Vec<NodeId> {
128        self.graph.node_order()
129    }
130
131    pub fn new_edge(&self) -> Edge {
132        self.graph.new_edge()
133    }
134
135    pub fn add_edge(&mut self, edge: Edge) {
136        self.graph.add_edge(edge);
137    }
138
139    pub fn remove_edge(&mut self, edge_id: EdgeId) {
140        self.graph.remove_edge(edge_id);
141    }
142
143    pub fn add_selected_node(&mut self, id: NodeId, shift: bool) {
144        self.graph.add_selected_node(id, shift);
145    }
146    pub fn clear_selected_node(&mut self) {
147        self.graph.clear_selected_node();
148    }
149    pub fn remove_selected_node(&mut self) -> bool {
150        self.graph.remove_selected_node()
151    }
152
153    pub fn add_selected_edge(&mut self, id: EdgeId, shift: bool) {
154        self.graph.add_selected_edge(id, shift);
155    }
156    pub fn clear_selected_edge(&mut self) {
157        self.graph.clear_selected_edge();
158    }
159    pub fn remove_selected_edge(&mut self) -> bool {
160        self.graph.remove_selected_edge()
161    }
162
163    pub fn selection_bounds(&self) -> Option<Bounds<Pixels>> {
164        self.graph.selection_bounds()
165    }
166
167    pub fn selected_nodes_with_positions(&self) -> HashMap<NodeId, Point<Pixels>> {
168        self.graph.selected_nodes_with_positions()
169    }
170
171    pub fn hit_node(&self, mouse: Point<Pixels>) -> Option<NodeId> {
172        self.graph.hit_node(mouse)
173    }
174
175    pub fn bring_node_to_front(&mut self, node_id: NodeId) {
176        self.graph.bring_node_to_front(node_id);
177    }
178
179    pub fn world_to_screen(&self, p: Point<Pixels>) -> Point<Pixels> {
180        self.viewport.world_to_screen(p)
181    }
182
183    pub fn screen_to_world(&self, p: Point<Pixels>) -> Point<Pixels> {
184        self.viewport.screen_to_world(p)
185    }
186}