use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use bezier_rs::{Identifier, Subpath};
use serde::{Deserialize, Serialize};
use usvg::{self, Fill, ImageKind, NonZeroRect, Text, Transform, Visibility};
use uuid::Uuid;
use super::buffer::u_transform_to_bezier;
use super::diff::DiffState;
#[derive(Clone)]
pub enum Element {
Path(Path),
Image(Box<Image>),
Text(Text),
}
#[derive(Clone)]
pub struct Path {
pub data: Subpath<ManipulatorGroupId>,
pub visibility: Visibility,
pub fill: Option<Fill>,
pub stroke: Option<Stroke>,
pub transform: Transform,
pub diff_state: DiffState,
pub deleted: bool,
pub opacity: f32,
}
#[derive(Clone, Copy, Debug)]
pub struct Stroke {
pub color: DynamicColor,
pub opacity: f32,
pub width: f32,
}
impl Default for Stroke {
fn default() -> Self {
Self { color: Default::default(), opacity: 1.0, width: 1.0 }
}
}
#[derive(Clone, Copy, PartialEq, Serialize, Deserialize, Debug)]
pub struct DynamicColor {
pub light: Color,
pub dark: Color,
}
#[derive(Clone, Copy, PartialEq, Serialize, Deserialize, Debug)]
pub struct Color {
pub red: u8,
pub green: u8,
pub blue: u8,
}
impl Color {
pub fn new_rgb(red: u8, green: u8, blue: u8) -> Self {
Self { red, green, blue }
}
pub fn black() -> Self {
Self::new_rgb(0, 0, 0)
}
pub fn white() -> Self {
Self::new_rgb(255, 255, 255)
}
}
impl Default for DynamicColor {
fn default() -> Self {
Self { light: Color::black(), dark: Color::white() }
}
}
impl PartialEq for Path {
fn eq(&self, other: &Self) -> bool {
self.data.len() == other.data.len()
&& self.visibility == other.visibility
&& self.transform == other.transform
&& self.deleted == other.deleted
}
}
#[derive(Clone)]
pub struct Image {
pub data: ImageKind,
pub visibility: Visibility,
pub transform: Transform,
pub view_box: NonZeroRect,
pub opacity: f32,
pub href: Uuid,
pub diff_state: DiffState,
pub deleted: bool,
}
impl Image {
pub fn into_weak(&self, z_index: usize) -> WeakImage {
WeakImage {
href: self.href,
transform: WeakTransform::from(self.transform),
opacity: self.opacity,
width: self.view_box.width(),
height: self.view_box.height(),
x: self.view_box.x(),
y: self.view_box.y(),
z_index,
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
pub struct WeakImages(HashMap<Uuid, WeakImage>);
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
pub struct WeakPathPressures(HashMap<Uuid, Vec<f32>>);
impl Deref for WeakPathPressures {
type Target = HashMap<Uuid, Vec<f32>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for WeakPathPressures {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Deref for WeakImages {
type Target = HashMap<Uuid, WeakImage>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for WeakImages {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct WeakImage {
pub href: Uuid,
pub transform: WeakTransform,
pub opacity: f32,
pub width: f32,
pub height: f32,
pub x: f32,
pub y: f32,
pub z_index: usize,
}
impl PartialEq for WeakImage {
fn eq(&self, other: &Self) -> bool {
self.href == other.href
&& self.transform == other.transform
&& self.opacity == other.opacity
&& self.z_index == other.z_index
}
}
impl WeakImage {
pub fn transform(&mut self, transform: Transform) {
if transform.is_identity() {
return;
}
if let Some(view_box) = NonZeroRect::from_xywh(self.x, self.y, self.width, self.height) {
if let Some(ts_view_box) = view_box.transform(transform) {
self.x = ts_view_box.x();
self.y = ts_view_box.y();
self.width = ts_view_box.width();
self.height = ts_view_box.height();
}
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Copy)]
pub struct WeakTransform {
pub sx: f32,
pub kx: f32,
pub ky: f32,
pub sy: f32,
pub tx: f32,
pub ty: f32,
}
impl Default for WeakTransform {
fn default() -> Self {
Self { sx: 1.0, kx: 0.0, ky: 0.0, sy: 1.0, tx: 0.0, ty: 0.0 }
}
}
impl From<WeakTransform> for usvg::Transform {
fn from(wt: WeakTransform) -> Self {
usvg::Transform { sx: wt.sx, kx: wt.kx, ky: wt.ky, sy: wt.sy, tx: wt.tx, ty: wt.ty }
}
}
impl From<usvg::Transform> for WeakTransform {
fn from(t: usvg::Transform) -> Self {
WeakTransform { sx: t.sx, kx: t.kx, ky: t.ky, sy: t.sy, tx: t.tx, ty: t.ty }
}
}
impl Identifier for ManipulatorGroupId {
fn new() -> Self {
ManipulatorGroupId
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct ManipulatorGroupId;
impl Element {
pub fn opacity_changed(&self) -> bool {
match self {
Element::Path(p) => p.diff_state.opacity_changed,
Element::Image(i) => i.diff_state.opacity_changed,
Element::Text(_) => todo!(),
}
}
pub fn delete_changed(&self) -> bool {
match self {
Element::Path(p) => p.diff_state.delete_changed,
Element::Image(i) => i.diff_state.delete_changed,
Element::Text(_) => todo!(),
}
}
pub fn data_changed(&self) -> bool {
match self {
Element::Path(p) => p.diff_state.data_changed,
Element::Image(i) => i.diff_state.data_changed,
Element::Text(_) => todo!(),
}
}
pub fn mark_data_change(&mut self) {
match self {
Element::Path(p) => p.diff_state.data_changed = true,
Element::Image(i) => i.diff_state.data_changed = true,
Element::Text(_) => todo!(),
}
}
pub fn deleted(&self) -> bool {
match self {
Element::Path(p) => p.deleted,
Element::Image(i) => i.deleted,
Element::Text(_) => todo!(),
}
}
pub fn transformed(&self) -> Option<Transform> {
match self {
Element::Path(p) => p.diff_state.transformed,
Element::Image(i) => i.diff_state.transformed,
Element::Text(_) => todo!(),
}
}
pub fn transform(&mut self, transform: Transform) {
match self {
Element::Path(path) => {
path.diff_state.transformed = Some(transform);
path.transform = path.transform.post_concat(transform);
path.data.apply_transform(u_transform_to_bezier(&transform));
}
Element::Image(img) => {
img.diff_state.transformed = Some(transform);
img.transform = img.transform.post_concat(transform);
if let Some(new_vbox) = img.view_box.transform(transform) {
img.view_box = new_vbox;
}
}
Element::Text(_) => todo!(),
}
}
pub fn get_transform(&self) -> Transform {
match self {
Element::Path(path) => path.transform,
Element::Image(img) => img.transform,
Element::Text(_) => todo!(),
}
}
pub fn opacity(&self) -> f32 {
match self {
Element::Path(path) => path.opacity,
Element::Image(image) => image.opacity,
Element::Text(_) => todo!(),
}
}
pub fn stroke(&self) -> Option<Stroke> {
match self {
Element::Path(path) => path.stroke,
Element::Image(_) => None,
Element::Text(_) => todo!(),
}
}
pub fn set_stroke(&mut self, stroke: Stroke) {
match self {
Element::Path(path) => path.stroke = Some(stroke),
Element::Image(_) => {}
Element::Text(_) => {}
}
self.mark_data_change();
}
}