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#[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}