1use std::{
2 collections::HashMap,
3 ops::{Deref, DerefMut},
4};
5
6use bezier_rs::{Identifier, Subpath};
7use serde::{Deserialize, Serialize};
8
9use usvg::{self, Color, Fill, ImageKind, NonZeroRect, Text, Transform, Visibility};
10use uuid::Uuid;
11
12use super::{buffer::u_transform_to_bezier, diff::DiffState};
13
14#[derive(Clone)]
15pub enum Element {
16 Path(Path),
17 Image(Image),
18 Text(Text),
19}
20
21#[derive(Clone)]
22pub struct Path {
23 pub data: Subpath<ManipulatorGroupId>,
24 pub visibility: Visibility,
25 pub fill: Option<Fill>,
26 pub stroke: Option<Stroke>,
27 pub transform: Transform,
28 pub diff_state: DiffState,
29 pub deleted: bool,
30 pub opacity: f32,
31}
32
33#[derive(Clone, Copy)]
34pub struct Stroke {
35 pub color: DynamicColor,
36 pub opacity: f32,
37 pub width: f32,
38}
39
40#[derive(Clone, Copy)]
41pub struct DynamicColor {
42 pub light: usvg::Color,
43 pub dark: usvg::Color,
44}
45
46impl Default for DynamicColor {
47 fn default() -> Self {
48 Self { light: Color::black(), dark: Color::white() }
49 }
50}
51
52impl PartialEq for Path {
53 fn eq(&self, other: &Self) -> bool {
54 self.data.len() == other.data.len()
55 && self.visibility == other.visibility
56 && self.transform == other.transform
57 && self.deleted == other.deleted
58 }
59}
60
61#[derive(Clone)]
62pub struct Image {
63 pub data: ImageKind,
64 pub visibility: Visibility,
65 pub transform: Transform,
66 pub view_box: NonZeroRect,
67 pub opacity: f32,
68 pub href: Uuid,
69 pub diff_state: DiffState,
70 pub deleted: bool,
71}
72
73impl From<Transform> for WeakTransform {
74 fn from(value: Transform) -> Self {
75 WeakTransform {
76 sx: value.sx,
77 kx: value.kx,
78 ky: value.ky,
79 sy: value.sy,
80 tx: value.tx,
81 ty: value.ty,
82 }
83 }
84}
85
86impl Image {
87 pub fn into_weak(&self, z_index: usize) -> WeakImage {
88 WeakImage {
89 href: self.href,
90 transform: WeakTransform::from(self.transform),
91 opacity: self.opacity,
92 width: self.view_box.width(),
93 height: self.view_box.height(),
94 x: self.view_box.x(),
95 y: self.view_box.y(),
96 z_index,
97 }
98 }
99}
100
101#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
102pub struct WeakImages(HashMap<Uuid, WeakImage>);
103
104impl Deref for WeakImages {
105 type Target = HashMap<Uuid, WeakImage>;
106
107 fn deref(&self) -> &Self::Target {
108 &self.0
109 }
110}
111
112impl DerefMut for WeakImages {
113 fn deref_mut(&mut self) -> &mut Self::Target {
114 &mut self.0
115 }
116}
117
118#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
120pub struct WeakImage {
121 pub href: Uuid,
122 pub transform: WeakTransform,
123 pub opacity: f32,
124 pub width: f32,
125 pub height: f32,
126 pub x: f32,
127 pub y: f32,
128 pub z_index: usize,
129}
130
131impl PartialEq for WeakImage {
132 fn eq(&self, other: &Self) -> bool {
133 self.href == other.href
134 && self.transform == other.transform
135 && self.opacity == other.opacity
136 && self.z_index == other.z_index
137 }
138}
139
140impl WeakImage {
141 pub fn transform(&mut self, transform: Transform) {
142 if transform.is_identity() {
143 return;
144 }
145 if let Some(view_box) = NonZeroRect::from_xywh(self.x, self.y, self.width, self.height) {
146 if let Some(ts_view_box) = view_box.transform(transform) {
147 self.x = ts_view_box.x();
148 self.y = ts_view_box.y();
149 self.width = ts_view_box.width();
150 self.height = ts_view_box.height();
151 }
152 }
153 }
154}
155
156#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Copy)]
157pub struct WeakTransform {
158 pub sx: f32,
159 pub kx: f32,
160 pub ky: f32,
161 pub sy: f32,
162 pub tx: f32,
163 pub ty: f32,
164}
165
166impl Identifier for ManipulatorGroupId {
167 fn new() -> Self {
168 ManipulatorGroupId
169 }
170}
171#[derive(Clone, PartialEq, Eq, Hash, Debug)]
172pub struct ManipulatorGroupId;
173
174impl Element {
175 pub fn opacity_changed(&self) -> bool {
176 match self {
177 Element::Path(p) => p.diff_state.opacity_changed,
178 Element::Image(i) => i.diff_state.opacity_changed,
179 Element::Text(_) => todo!(),
180 }
181 }
182 pub fn delete_changed(&self) -> bool {
183 match self {
184 Element::Path(p) => p.diff_state.delete_changed,
185 Element::Image(i) => i.diff_state.delete_changed,
186 Element::Text(_) => todo!(),
187 }
188 }
189 pub fn data_changed(&self) -> bool {
190 match self {
191 Element::Path(p) => p.diff_state.data_changed,
192 Element::Image(i) => i.diff_state.data_changed,
193 Element::Text(_) => todo!(),
194 }
195 }
196 pub fn deleted(&self) -> bool {
197 match self {
198 Element::Path(p) => p.deleted,
199 Element::Image(i) => i.deleted,
200 Element::Text(_) => todo!(),
201 }
202 }
203 pub fn transformed(&self) -> Option<Transform> {
204 match self {
205 Element::Path(p) => p.diff_state.transformed,
206 Element::Image(i) => i.diff_state.transformed,
207 Element::Text(_) => todo!(),
208 }
209 }
210 pub fn transform(&mut self, transform: Transform) {
211 match self {
212 Element::Path(path) => {
213 path.diff_state.transformed = Some(transform);
214 path.transform = path.transform.post_concat(transform);
215 path.data.apply_transform(u_transform_to_bezier(&transform));
216 }
217 Element::Image(img) => {
218 img.diff_state.transformed = Some(transform);
219 img.transform = img.transform.post_concat(transform);
220 if let Some(new_vbox) = img.view_box.transform(transform) {
221 img.view_box = new_vbox;
222 }
223 }
224 Element::Text(_) => todo!(),
225 }
226 }
227
228 pub fn get_transform(&self) -> Transform {
229 match self {
230 Element::Path(path) => path.transform,
231 Element::Image(img) => img.transform,
232 Element::Text(_) => todo!(),
233 }
234 }
235
236 pub fn opacity(&self) -> f32 {
237 match self {
238 Element::Path(path) => path.opacity,
239 Element::Image(image) => image.opacity,
240 Element::Text(_) => todo!(),
241 }
242 }
243}