1use serde::{Deserialize, Serialize};
4
5use crate::{Element, ElementId, ElementKind, Scene, Transform};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct ElementDocument {
10 pub id: String,
12 pub kind: ElementKind,
14 #[serde(default = "ElementDocument::default_transform")]
16 pub transform: Transform,
17 #[serde(default = "ElementDocument::default_interactive")]
19 pub interactive: bool,
20 #[serde(default)]
22 pub selected: bool,
23}
24
25impl From<&Element> for ElementDocument {
26 fn from(element: &Element) -> Self {
27 Self {
28 id: element.id.to_string(),
29 kind: element.kind.clone(),
30 transform: element.transform,
31 interactive: element.interactive,
32 selected: element.selected,
33 }
34 }
35}
36
37impl ElementDocument {
38 fn default_transform() -> Transform {
39 Transform::default()
40 }
41
42 const fn default_interactive() -> bool {
43 true
44 }
45
46 pub fn into_element(self) -> Result<Element, String> {
52 let mut element = Element::new(self.kind).with_transform(self.transform);
53 element.interactive = self.interactive;
54 element.selected = self.selected;
55 let id = ElementId::parse(&self.id).map_err(|e| e.to_string())?;
56 element.id = id;
57 Ok(element)
58 }
59}
60
61#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
63pub struct ViewportDocument {
64 pub width: f32,
66 pub height: f32,
68 #[serde(default = "ViewportDocument::default_zoom")]
70 pub zoom: f32,
71 #[serde(default)]
73 pub pan_x: f32,
74 #[serde(default)]
76 pub pan_y: f32,
77}
78
79impl ViewportDocument {
80 const fn default_zoom() -> f32 {
81 1.0
82 }
83}
84
85impl From<&Scene> for ViewportDocument {
86 fn from(scene: &Scene) -> Self {
87 Self {
88 width: scene.viewport_width,
89 height: scene.viewport_height,
90 zoom: scene.zoom,
91 pan_x: scene.pan_x,
92 pan_y: scene.pan_y,
93 }
94 }
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct SceneDocument {
100 pub session_id: String,
102 pub viewport: ViewportDocument,
104 pub elements: Vec<ElementDocument>,
106 pub timestamp: u64,
108}
109
110impl SceneDocument {
111 pub fn from_scene(session_id: impl Into<String>, scene: &Scene, timestamp: u64) -> Self {
113 let mut elements: Vec<_> = scene.elements().map(ElementDocument::from).collect();
114 elements.sort_by_key(|doc| doc.transform.z_index);
115 Self {
116 session_id: session_id.into(),
117 viewport: ViewportDocument::from(scene),
118 elements,
119 timestamp,
120 }
121 }
122
123 pub fn into_scene(self) -> Result<Scene, String> {
129 let mut scene = Scene::new(self.viewport.width, self.viewport.height);
130 scene.zoom = self.viewport.zoom;
131 scene.pan_x = self.viewport.pan_x;
132 scene.pan_y = self.viewport.pan_y;
133
134 for element_doc in self.elements {
135 let element = element_doc.into_element()?;
136 scene.add_element(element);
137 }
138
139 Ok(scene)
140 }
141}