ferrum_flow/canvas/
undo.rs1use std::collections::HashMap;
2
3use gpui::{Bounds, Pixels, Point};
4
5use crate::{
6 Edge, EdgeBuilder, EdgeId, Graph, GraphOp, Node, NodeBuilder, NodeId, Port, PortId,
7 RendererRegistry, Viewport,
8 canvas::PortLayoutCache,
9 plugin::{
10 cache_all_node_port_offset, cache_node_port_offset, is_edge_visible, is_node_visible,
11 port_offset_cached,
12 },
13};
14
15pub trait Command {
16 fn name(&self) -> &'static str;
17
18 fn execute(&mut self, ctx: &mut CommandContext);
20
21 fn undo(&mut self, ctx: &mut CommandContext);
23
24 fn to_ops(&self, ctx: &mut CommandContext) -> Vec<GraphOp>;
27}
28
29pub trait HistoryProvider {
30 fn undo(&mut self, ctx: &mut CommandContext);
31 fn redo(&mut self, ctx: &mut CommandContext);
32 fn push(&mut self, command: Box<dyn Command>, ctx: &mut CommandContext);
33 fn clear(&mut self);
34}
35
36pub struct CommandContext<'a> {
37 pub graph: &'a mut Graph,
38 pub port_offset_cache: &'a mut PortLayoutCache,
39 pub viewport: &'a mut Viewport,
40 pub renderers: &'a mut RendererRegistry,
41 pub(crate) notify: &'a mut dyn FnMut(),
42}
43const MAX_HISTORY: usize = 100;
44pub struct LocalHistory {
45 undo_stack: Vec<Box<dyn Command>>,
46 redo_stack: Vec<Box<dyn Command>>,
47}
48
49impl LocalHistory {
50 pub fn new() -> Self {
51 Self {
52 undo_stack: vec![],
53 redo_stack: vec![],
54 }
55 }
56}
57
58impl HistoryProvider for LocalHistory {
59 fn push(&mut self, mut command: Box<dyn Command>, ctx: &mut CommandContext) {
60 command.execute(ctx);
61
62 self.undo_stack.push(command);
63
64 self.redo_stack.clear();
65
66 if self.undo_stack.len() > MAX_HISTORY {
67 self.undo_stack.remove(0);
68 }
69 }
70 fn undo(&mut self, ctx: &mut CommandContext) {
71 if let Some(mut cmd) = self.undo_stack.pop() {
72 cmd.undo(ctx);
73 self.redo_stack.push(cmd);
74 }
75 }
76
77 fn redo(&mut self, ctx: &mut CommandContext) {
78 if let Some(mut cmd) = self.redo_stack.pop() {
79 cmd.execute(ctx);
80 self.undo_stack.push(cmd);
81 }
82 }
83
84 fn clear(&mut self) {
85 self.undo_stack.clear();
86 self.redo_stack.clear();
87 }
88}
89
90pub struct CompositeCommand {
91 commands: Vec<Box<dyn Command>>,
92}
93
94impl CompositeCommand {
95 pub fn new() -> Self {
96 Self {
97 commands: Vec::new(),
98 }
99 }
100 pub fn push(&mut self, command: impl Command + 'static) {
101 self.commands.push(Box::new(command));
102 }
103}
104
105impl Command for CompositeCommand {
106 fn name(&self) -> &'static str {
107 "composite"
108 }
109 fn execute(&mut self, state: &mut CommandContext) {
110 for cmd in &mut self.commands {
111 cmd.execute(state);
112 }
113 }
114
115 fn undo(&mut self, state: &mut CommandContext) {
116 for cmd in self.commands.iter_mut().rev() {
117 cmd.undo(state);
118 }
119 }
120 fn to_ops(&self, ctx: &mut CommandContext) -> Vec<GraphOp> {
121 let mut list = vec![];
122 for cmd in &self.commands {
123 list.extend(cmd.to_ops(ctx));
124 }
125
126 vec![GraphOp::Batch(list)]
127 }
128}
129
130impl<'a> CommandContext<'a> {
131 pub fn create_node(&self, node_type: &str) -> NodeBuilder {
132 self.graph.create_node(node_type)
133 }
134
135 pub fn create_edge(&self) -> EdgeBuilder {
136 self.graph.create_dege()
137 }
138
139 pub fn next_node_id(&self) -> NodeId {
140 self.graph.next_node_id()
141 }
142
143 pub fn next_port_id(&self) -> PortId {
144 self.graph.next_port_id()
145 }
146
147 pub fn next_edge_id(&self) -> EdgeId {
148 self.graph.next_edge_id()
149 }
150 pub fn add_node(&mut self, node: Node) {
151 self.graph.add_node(node);
152 }
153
154 pub fn add_port(&mut self, port: Port) {
155 self.graph.add_port(port);
156 }
157
158 pub fn remove_port(&mut self, id: &PortId) {
159 self.graph.remove_port(id);
160 }
161
162 pub fn get_node(&self, id: &NodeId) -> Option<&Node> {
163 self.graph.get_node(id)
164 }
165
166 pub fn get_node_mut(&mut self, id: &NodeId) -> Option<&mut Node> {
167 self.graph.get_node_mut(id)
168 }
169 pub fn remove_node(&mut self, id: &NodeId) {
170 self.graph.remove_node(id);
171 self.port_offset_cache.clear_node(id);
172 }
173 pub fn nodes(&self) -> &HashMap<NodeId, Node> {
174 self.graph.nodes()
175 }
176 pub fn node_order(&self) -> &Vec<NodeId> {
177 self.graph.node_order()
178 }
179
180 pub fn new_edge(&self) -> Edge {
181 self.graph.new_edge()
182 }
183
184 pub fn add_edge(&mut self, edge: Edge) {
185 self.graph.add_edge(edge);
186 }
187
188 pub fn remove_edge(&mut self, edge_id: EdgeId) {
189 self.graph.remove_edge(edge_id);
190 }
191
192 pub fn add_selected_node(&mut self, id: NodeId, shift: bool) {
193 self.graph.add_selected_node(id, shift);
194 }
195 pub fn clear_selected_node(&mut self) {
196 self.graph.clear_selected_node();
197 }
198 pub fn remove_selected_node(&mut self) -> bool {
199 self.graph.remove_selected_node()
200 }
201
202 pub fn add_selected_edge(&mut self, id: EdgeId, shift: bool) {
203 self.graph.add_selected_edge(id, shift);
204 }
205 pub fn clear_selected_edge(&mut self) {
206 self.graph.clear_selected_edge();
207 }
208 pub fn remove_selected_edge(&mut self) -> bool {
209 self.graph.remove_selected_edge()
210 }
211
212 pub fn selection_bounds(&self) -> Option<Bounds<Pixels>> {
213 self.graph.selection_bounds()
214 }
215
216 pub fn selected_nodes_with_positions(&self) -> HashMap<NodeId, Point<Pixels>> {
217 self.graph.selected_nodes_with_positions()
218 }
219
220 pub fn hit_node(&self, mouse: Point<Pixels>) -> Option<NodeId> {
221 self.graph.hit_node(mouse)
222 }
223
224 pub fn bring_node_to_front(&mut self, node_id: NodeId) {
225 self.graph.bring_node_to_front(node_id);
226 }
227
228 pub fn world_to_screen(&self, p: Point<Pixels>) -> Point<Pixels> {
229 self.viewport.world_to_screen(p)
230 }
231
232 pub fn screen_to_world(&self, p: Point<Pixels>) -> Point<Pixels> {
233 self.viewport.screen_to_world(p)
234 }
235
236 pub fn is_node_visible(&self, node_id: &NodeId) -> bool {
237 is_node_visible(self.graph, self.viewport, node_id)
238 }
239
240 pub fn is_edge_visible(&self, edge: &Edge) -> bool {
241 is_edge_visible(self.graph, self.viewport, edge)
242 }
243
244 pub fn port_offset_cached(&self, node_id: &NodeId, port_id: &PortId) -> Option<Point<Pixels>> {
245 port_offset_cached(self.port_offset_cache, node_id, port_id)
246 }
247
248 pub fn cache_all_node_port_offset(&mut self) {
249 cache_all_node_port_offset(self.graph, self.renderers, self.port_offset_cache)
250 }
251
252 pub fn cache_node_port_offset(&mut self, node_id: &NodeId) {
253 cache_node_port_offset(self.graph, self.renderers, self.port_offset_cache, node_id);
254 }
255
256 pub fn notify(&mut self) {
257 (self.notify)();
258 }
259}