lb_rs/model/svg/
element.rs

1use std::collections::HashMap;
2use std::ops::{Deref, DerefMut};
3
4use bezier_rs::{Identifier, Subpath};
5use serde::{Deserialize, Serialize};
6
7use usvg::{self, Fill, ImageKind, NonZeroRect, Text, Transform, Visibility};
8use uuid::Uuid;
9
10use super::buffer::u_transform_to_bezier;
11use super::diff::DiffState;
12
13#[derive(Clone)]
14pub enum Element {
15    Path(Path),
16    Image(Box<Image>),
17    Text(Text),
18}
19
20#[derive(Clone)]
21pub struct Path {
22    pub data: Subpath<ManipulatorGroupId>,
23    pub visibility: Visibility,
24    pub fill: Option<Fill>,
25    pub stroke: Option<Stroke>,
26    pub transform: Transform,
27    pub diff_state: DiffState,
28    pub deleted: bool,
29    pub opacity: f32,
30}
31
32#[derive(Clone, Copy, Debug)]
33pub struct Stroke {
34    pub color: DynamicColor,
35    pub opacity: f32,
36    pub width: f32,
37}
38
39impl Default for Stroke {
40    fn default() -> Self {
41        Self { color: Default::default(), opacity: 1.0, width: 1.0 }
42    }
43}
44
45#[derive(Clone, Copy, PartialEq, Serialize, Deserialize, Debug)]
46pub struct DynamicColor {
47    pub light: Color,
48    pub dark: Color,
49}
50
51#[derive(Clone, Copy, PartialEq, Serialize, Deserialize, Debug)]
52pub struct Color {
53    pub red: u8,
54    pub green: u8,
55    pub blue: u8,
56}
57
58impl Color {
59    pub fn new_rgb(red: u8, green: u8, blue: u8) -> Self {
60        Self { red, green, blue }
61    }
62
63    pub fn black() -> Self {
64        Self::new_rgb(0, 0, 0)
65    }
66
67    pub fn white() -> Self {
68        Self::new_rgb(255, 255, 255)
69    }
70}
71
72impl Default for DynamicColor {
73    fn default() -> Self {
74        Self { light: Color::black(), dark: Color::white() }
75    }
76}
77
78impl PartialEq for Path {
79    fn eq(&self, other: &Self) -> bool {
80        self.data.len() == other.data.len()
81            && self.visibility == other.visibility
82            && self.transform == other.transform
83            && self.deleted == other.deleted
84    }
85}
86
87#[derive(Clone)]
88pub struct Image {
89    pub data: ImageKind,
90    pub visibility: Visibility,
91    pub transform: Transform,
92    pub view_box: NonZeroRect,
93    pub opacity: f32,
94    pub href: Uuid,
95    pub diff_state: DiffState,
96    pub deleted: bool,
97}
98
99impl Image {
100    pub fn into_weak(&self, z_index: usize) -> WeakImage {
101        WeakImage {
102            href: self.href,
103            transform: WeakTransform::from(self.transform),
104            opacity: self.opacity,
105            width: self.view_box.width(),
106            height: self.view_box.height(),
107            x: self.view_box.x(),
108            y: self.view_box.y(),
109            z_index,
110        }
111    }
112}
113
114#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
115pub struct WeakImages(HashMap<Uuid, WeakImage>);
116
117#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
118pub struct WeakPathPressures(HashMap<Uuid, Vec<f32>>);
119
120impl Deref for WeakPathPressures {
121    type Target = HashMap<Uuid, Vec<f32>>;
122
123    fn deref(&self) -> &Self::Target {
124        &self.0
125    }
126}
127
128impl DerefMut for WeakPathPressures {
129    fn deref_mut(&mut self) -> &mut Self::Target {
130        &mut self.0
131    }
132}
133
134impl Deref for WeakImages {
135    type Target = HashMap<Uuid, WeakImage>;
136
137    fn deref(&self) -> &Self::Target {
138        &self.0
139    }
140}
141
142impl DerefMut for WeakImages {
143    fn deref_mut(&mut self) -> &mut Self::Target {
144        &mut self.0
145    }
146}
147
148/// image that only contains a ref to the data but not the data itself.
149#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
150pub struct WeakImage {
151    pub href: Uuid,
152    pub transform: WeakTransform,
153    pub opacity: f32,
154    pub width: f32,
155    pub height: f32,
156    pub x: f32,
157    pub y: f32,
158    pub z_index: usize,
159}
160
161impl PartialEq for WeakImage {
162    fn eq(&self, other: &Self) -> bool {
163        self.href == other.href
164            && self.transform == other.transform
165            && self.opacity == other.opacity
166            && self.z_index == other.z_index
167    }
168}
169
170impl WeakImage {
171    pub fn transform(&mut self, transform: Transform) {
172        if transform.is_identity() {
173            return;
174        }
175        if let Some(view_box) = NonZeroRect::from_xywh(self.x, self.y, self.width, self.height) {
176            if let Some(ts_view_box) = view_box.transform(transform) {
177                self.x = ts_view_box.x();
178                self.y = ts_view_box.y();
179                self.width = ts_view_box.width();
180                self.height = ts_view_box.height();
181            }
182        }
183    }
184}
185
186#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Copy)]
187pub struct WeakTransform {
188    pub sx: f32,
189    pub kx: f32,
190    pub ky: f32,
191    pub sy: f32,
192    pub tx: f32,
193    pub ty: f32,
194}
195
196impl Default for WeakTransform {
197    fn default() -> Self {
198        Self { sx: 1.0, kx: 0.0, ky: 0.0, sy: 1.0, tx: 0.0, ty: 0.0 }
199    }
200}
201
202impl From<WeakTransform> for usvg::Transform {
203    fn from(wt: WeakTransform) -> Self {
204        usvg::Transform { sx: wt.sx, kx: wt.kx, ky: wt.ky, sy: wt.sy, tx: wt.tx, ty: wt.ty }
205    }
206}
207
208impl From<usvg::Transform> for WeakTransform {
209    fn from(t: usvg::Transform) -> Self {
210        WeakTransform { sx: t.sx, kx: t.kx, ky: t.ky, sy: t.sy, tx: t.tx, ty: t.ty }
211    }
212}
213
214impl Identifier for ManipulatorGroupId {
215    fn new() -> Self {
216        ManipulatorGroupId
217    }
218}
219#[derive(Clone, PartialEq, Eq, Hash, Debug)]
220pub struct ManipulatorGroupId;
221
222impl Element {
223    pub fn opacity_changed(&self) -> bool {
224        match self {
225            Element::Path(p) => p.diff_state.opacity_changed,
226            Element::Image(i) => i.diff_state.opacity_changed,
227            Element::Text(_) => todo!(),
228        }
229    }
230    pub fn delete_changed(&self) -> bool {
231        match self {
232            Element::Path(p) => p.diff_state.delete_changed,
233            Element::Image(i) => i.diff_state.delete_changed,
234            Element::Text(_) => todo!(),
235        }
236    }
237    pub fn data_changed(&self) -> bool {
238        match self {
239            Element::Path(p) => p.diff_state.data_changed,
240            Element::Image(i) => i.diff_state.data_changed,
241            Element::Text(_) => todo!(),
242        }
243    }
244    pub fn mark_data_change(&mut self) {
245        match self {
246            Element::Path(p) => p.diff_state.data_changed = true,
247            Element::Image(i) => i.diff_state.data_changed = true,
248            Element::Text(_) => todo!(),
249        }
250    }
251    pub fn deleted(&self) -> bool {
252        match self {
253            Element::Path(p) => p.deleted,
254            Element::Image(i) => i.deleted,
255            Element::Text(_) => todo!(),
256        }
257    }
258    pub fn transformed(&self) -> Option<Transform> {
259        match self {
260            Element::Path(p) => p.diff_state.transformed,
261            Element::Image(i) => i.diff_state.transformed,
262            Element::Text(_) => todo!(),
263        }
264    }
265    pub fn transform(&mut self, transform: Transform) {
266        match self {
267            Element::Path(path) => {
268                path.diff_state.transformed = Some(transform);
269                path.transform = path.transform.post_concat(transform);
270                path.data.apply_transform(u_transform_to_bezier(&transform));
271            }
272            Element::Image(img) => {
273                img.diff_state.transformed = Some(transform);
274                img.transform = img.transform.post_concat(transform);
275                if let Some(new_vbox) = img.view_box.transform(transform) {
276                    img.view_box = new_vbox;
277                }
278            }
279            Element::Text(_) => todo!(),
280        }
281    }
282
283    pub fn get_transform(&self) -> Transform {
284        match self {
285            Element::Path(path) => path.transform,
286            Element::Image(img) => img.transform,
287            Element::Text(_) => todo!(),
288        }
289    }
290
291    pub fn opacity(&self) -> f32 {
292        match self {
293            Element::Path(path) => path.opacity,
294            Element::Image(image) => image.opacity,
295            Element::Text(_) => todo!(),
296        }
297    }
298
299    pub fn stroke(&self) -> Option<Stroke> {
300        match self {
301            Element::Path(path) => path.stroke,
302            Element::Image(_) => None,
303            Element::Text(_) => todo!(),
304        }
305    }
306
307    pub fn set_stroke(&mut self, stroke: Stroke) {
308        match self {
309            Element::Path(path) => path.stroke = Some(stroke),
310            Element::Image(_) => {}
311            Element::Text(_) => {}
312        }
313        self.mark_data_change();
314    }
315}