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