1use std::collections::HashMap;
4
5use serde::{Deserialize, Serialize};
6
7use crate::{CanvasError, CanvasResult, Element, ElementId};
8
9#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11pub struct Scene {
12 elements: HashMap<ElementId, Element>,
14 root_elements: Vec<ElementId>,
16 selected: Vec<ElementId>,
18 pub viewport_width: f32,
20 pub viewport_height: f32,
22 pub zoom: f32,
24 pub pan_x: f32,
26 pub pan_y: f32,
28}
29
30impl Scene {
31 #[must_use]
33 pub fn new(width: f32, height: f32) -> Self {
34 Self {
35 elements: HashMap::new(),
36 root_elements: Vec::new(),
37 selected: Vec::new(),
38 viewport_width: width,
39 viewport_height: height,
40 zoom: 1.0,
41 pan_x: 0.0,
42 pan_y: 0.0,
43 }
44 }
45
46 pub fn add_element(&mut self, element: Element) -> ElementId {
48 let id = element.id;
49 if element.parent.is_none() {
50 self.root_elements.push(id);
51 }
52 self.elements.insert(id, element);
53 id
54 }
55
56 pub fn remove_element(&mut self, id: &ElementId) -> CanvasResult<Element> {
62 self.root_elements.retain(|&eid| eid != *id);
63 self.selected.retain(|&eid| eid != *id);
64 self.elements
65 .remove(id)
66 .ok_or_else(|| CanvasError::ElementNotFound(id.to_string()))
67 }
68
69 #[must_use]
71 pub fn get_element(&self, id: ElementId) -> Option<&Element> {
72 self.elements.get(&id)
73 }
74
75 pub fn get_element_mut(&mut self, id: ElementId) -> Option<&mut Element> {
77 self.elements.get_mut(&id)
78 }
79
80 pub fn elements(&self) -> impl Iterator<Item = &Element> {
82 self.elements.values()
83 }
84
85 pub fn elements_mut(&mut self) -> impl Iterator<Item = &mut Element> {
87 self.elements.values_mut()
88 }
89
90 pub fn root_elements(&self) -> impl Iterator<Item = &Element> {
92 self.root_elements
93 .iter()
94 .filter_map(|id| self.elements.get(id))
95 }
96
97 pub fn set_viewport(&mut self, width: f32, height: f32) {
99 self.viewport_width = width;
100 self.viewport_height = height;
101 }
102
103 #[must_use]
106 pub fn element_at(&self, x: f32, y: f32) -> Option<ElementId> {
107 let canvas_x = (x - self.pan_x) / self.zoom;
108 let canvas_y = (y - self.pan_y) / self.zoom;
109
110 self.elements
111 .values()
112 .filter(|e| e.interactive && e.contains_point(canvas_x, canvas_y))
113 .max_by_key(|e| e.transform.z_index)
114 .map(|e| e.id)
115 }
116
117 pub fn select(&mut self, id: ElementId) -> CanvasResult<()> {
123 if let Some(element) = self.elements.get_mut(&id) {
124 element.selected = true;
125 if !self.selected.contains(&id) {
126 self.selected.push(id);
127 }
128 Ok(())
129 } else {
130 Err(CanvasError::ElementNotFound(id.to_string()))
131 }
132 }
133
134 pub fn deselect_all(&mut self) {
136 for id in &self.selected {
137 if let Some(element) = self.elements.get_mut(id) {
138 element.selected = false;
139 }
140 }
141 self.selected.clear();
142 }
143
144 pub fn selected_elements(&self) -> impl Iterator<Item = &Element> {
146 self.selected.iter().filter_map(|id| self.elements.get(id))
147 }
148
149 #[must_use]
151 pub fn element_count(&self) -> usize {
152 self.elements.len()
153 }
154
155 #[must_use]
157 pub fn is_empty(&self) -> bool {
158 self.elements.is_empty()
159 }
160
161 pub fn clear(&mut self) {
163 self.elements.clear();
164 self.root_elements.clear();
165 self.selected.clear();
166 }
167
168 pub fn to_json(&self) -> CanvasResult<String> {
174 serde_json::to_string(self).map_err(CanvasError::Serialization)
175 }
176
177 pub fn from_json(json: &str) -> CanvasResult<Self> {
183 serde_json::from_str(json).map_err(CanvasError::Serialization)
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190 use crate::{ElementKind, Transform};
191
192 #[test]
193 fn test_scene_add_remove() {
194 let mut scene = Scene::new(800.0, 600.0);
195 assert!(scene.is_empty());
196
197 let element = Element::new(ElementKind::Text {
198 content: "Hello".to_string(),
199 font_size: 16.0,
200 color: "#000000".to_string(),
201 });
202 let id = scene.add_element(element);
203
204 assert_eq!(scene.element_count(), 1);
205 assert!(scene.get_element(id).is_some());
206
207 scene.remove_element(&id).expect("should remove");
208 assert!(scene.is_empty());
209 }
210
211 #[test]
212 fn test_element_at() {
213 let mut scene = Scene::new(800.0, 600.0);
214
215 let element = Element::new(ElementKind::Text {
216 content: "Test".to_string(),
217 font_size: 16.0,
218 color: "#000000".to_string(),
219 })
220 .with_transform(Transform {
221 x: 100.0,
222 y: 100.0,
223 width: 200.0,
224 height: 50.0,
225 rotation: 0.0,
226 z_index: 0,
227 });
228
229 scene.add_element(element);
230
231 assert!(scene.element_at(150.0, 125.0).is_some());
233
234 assert!(scene.element_at(50.0, 50.0).is_none());
236 }
237}