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, PartialEq)]
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 Image {
74 pub fn into_weak(&self, z_index: usize) -> WeakImage {
75 WeakImage {
76 href: self.href,
77 transform: WeakTransform::from(self.transform),
78 opacity: self.opacity,
79 width: self.view_box.width(),
80 height: self.view_box.height(),
81 x: self.view_box.x(),
82 y: self.view_box.y(),
83 z_index,
84 }
85 }
86}
87
88#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
89pub struct WeakImages(HashMap<Uuid, WeakImage>);
90
91#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
92pub struct WeakPathPressures(HashMap<Uuid, Vec<f32>>);
93
94impl Deref for WeakPathPressures {
95 type Target = HashMap<Uuid, Vec<f32>>;
96
97 fn deref(&self) -> &Self::Target {
98 &self.0
99 }
100}
101
102impl DerefMut for WeakPathPressures {
103 fn deref_mut(&mut self) -> &mut Self::Target {
104 &mut self.0
105 }
106}
107
108impl Deref for WeakImages {
109 type Target = HashMap<Uuid, WeakImage>;
110
111 fn deref(&self) -> &Self::Target {
112 &self.0
113 }
114}
115
116impl DerefMut for WeakImages {
117 fn deref_mut(&mut self) -> &mut Self::Target {
118 &mut self.0
119 }
120}
121
122#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
124pub struct WeakImage {
125 pub href: Uuid,
126 pub transform: WeakTransform,
127 pub opacity: f32,
128 pub width: f32,
129 pub height: f32,
130 pub x: f32,
131 pub y: f32,
132 pub z_index: usize,
133}
134
135impl PartialEq for WeakImage {
136 fn eq(&self, other: &Self) -> bool {
137 self.href == other.href
138 && self.transform == other.transform
139 && self.opacity == other.opacity
140 && self.z_index == other.z_index
141 }
142}
143
144impl WeakImage {
145 pub fn transform(&mut self, transform: Transform) {
146 if transform.is_identity() {
147 return;
148 }
149 if let Some(view_box) = NonZeroRect::from_xywh(self.x, self.y, self.width, self.height) {
150 if let Some(ts_view_box) = view_box.transform(transform) {
151 self.x = ts_view_box.x();
152 self.y = ts_view_box.y();
153 self.width = ts_view_box.width();
154 self.height = ts_view_box.height();
155 }
156 }
157 }
158}
159
160#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Copy)]
161pub struct WeakTransform {
162 pub sx: f32,
163 pub kx: f32,
164 pub ky: f32,
165 pub sy: f32,
166 pub tx: f32,
167 pub ty: f32,
168}
169
170impl Default for WeakTransform {
171 fn default() -> Self {
172 Self { sx: 1.0, kx: 0.0, ky: 0.0, sy: 1.0, tx: 0.0, ty: 0.0 }
173 }
174}
175
176impl From<WeakTransform> for usvg::Transform {
177 fn from(wt: WeakTransform) -> Self {
178 usvg::Transform { sx: wt.sx, kx: wt.kx, ky: wt.ky, sy: wt.sy, tx: wt.tx, ty: wt.ty }
179 }
180}
181
182impl From<usvg::Transform> for WeakTransform {
183 fn from(t: usvg::Transform) -> Self {
184 WeakTransform { sx: t.sx, kx: t.kx, ky: t.ky, sy: t.sy, tx: t.tx, ty: t.ty }
185 }
186}
187
188impl Identifier for ManipulatorGroupId {
189 fn new() -> Self {
190 ManipulatorGroupId
191 }
192}
193#[derive(Clone, PartialEq, Eq, Hash, Debug)]
194pub struct ManipulatorGroupId;
195
196impl Element {
197 pub fn opacity_changed(&self) -> bool {
198 match self {
199 Element::Path(p) => p.diff_state.opacity_changed,
200 Element::Image(i) => i.diff_state.opacity_changed,
201 Element::Text(_) => todo!(),
202 }
203 }
204 pub fn delete_changed(&self) -> bool {
205 match self {
206 Element::Path(p) => p.diff_state.delete_changed,
207 Element::Image(i) => i.diff_state.delete_changed,
208 Element::Text(_) => todo!(),
209 }
210 }
211 pub fn data_changed(&self) -> bool {
212 match self {
213 Element::Path(p) => p.diff_state.data_changed,
214 Element::Image(i) => i.diff_state.data_changed,
215 Element::Text(_) => todo!(),
216 }
217 }
218 pub fn deleted(&self) -> bool {
219 match self {
220 Element::Path(p) => p.deleted,
221 Element::Image(i) => i.deleted,
222 Element::Text(_) => todo!(),
223 }
224 }
225 pub fn transformed(&self) -> Option<Transform> {
226 match self {
227 Element::Path(p) => p.diff_state.transformed,
228 Element::Image(i) => i.diff_state.transformed,
229 Element::Text(_) => todo!(),
230 }
231 }
232 pub fn transform(&mut self, transform: Transform) {
233 match self {
234 Element::Path(path) => {
235 path.diff_state.transformed = Some(transform);
236 path.transform = path.transform.post_concat(transform);
237 path.data.apply_transform(u_transform_to_bezier(&transform));
238 }
239 Element::Image(img) => {
240 img.diff_state.transformed = Some(transform);
241 img.transform = img.transform.post_concat(transform);
242 if let Some(new_vbox) = img.view_box.transform(transform) {
243 img.view_box = new_vbox;
244 }
245 }
246 Element::Text(_) => todo!(),
247 }
248 }
249
250 pub fn get_transform(&self) -> Transform {
251 match self {
252 Element::Path(path) => path.transform,
253 Element::Image(img) => img.transform,
254 Element::Text(_) => todo!(),
255 }
256 }
257
258 pub fn opacity(&self) -> f32 {
259 match self {
260 Element::Path(path) => path.opacity,
261 Element::Image(image) => image.opacity,
262 Element::Text(_) => todo!(),
263 }
264 }
265}