This repository has no description
1use super::shapes::Shape;
2use crate::{Angle, Fill, Filter, Region, Transformation};
3use itertools::Itertools;
4use std::fmt::Display;
5#[cfg(feature = "web")]
6use wasm_bindgen::prelude::*;
7
8use super::{Color, fill::FillOperations};
9
10impl Shape {
11 pub fn filled(self, fill: Fill) -> Object {
12 Object::from((self, Some(fill)))
13 }
14
15 pub fn colored(self, color: Color) -> Object {
16 Object::from((self, None)).colored(color)
17 }
18
19 pub fn filtered(self, filter: Filter) -> Object {
20 Object::from((self, None)).filtered(filter)
21 }
22
23 pub fn transform(self, transformation: Transformation) -> Object {
24 Object::from((self, None)).transformed(transformation)
25 }
26}
27
28#[derive(Debug, Clone)]
29pub struct Object {
30 pub shape: Shape,
31 pub fill: Option<Fill>,
32 pub filters: Vec<Filter>,
33 pub transformations: Vec<Transformation>,
34 pub tags: Vec<String>,
35 pub clip_to: Option<Region>,
36}
37
38impl Object {
39 pub fn filtered(mut self, filter: Filter) -> Self {
40 self.filters.push(filter);
41 self
42 }
43
44 pub fn transformed(mut self, transformation: Transformation) -> Self {
45 self.transformations.push(transformation);
46 self
47 }
48
49 pub fn filled(mut self, fill: Fill) -> Self {
50 self.fill = Some(fill);
51 self
52 }
53
54 pub fn colored(mut self, color: Color) -> Self {
55 self.fill = Some(Fill::Solid(color));
56 self
57 }
58
59 pub fn opacified(mut self, opacity: f32) -> Self {
60 if let Some(fill) = &mut self.fill {
61 *fill = fill.opacify(opacity);
62 }
63 self
64 }
65
66 pub fn clipped_to(mut self, region: impl Into<Region>) -> Self {
67 self.clip_to = Some(region.into());
68 self
69 }
70
71 pub fn clear_filters(&mut self) {
72 self.filters.clear();
73 }
74
75 pub fn refill(&mut self, fill: Fill) {
76 self.fill = Some(fill);
77 }
78
79 pub fn recolor(&mut self, color: Color) {
80 self.fill = Some(Fill::Solid(color))
81 }
82
83 pub fn filter(&mut self, filter: Filter) {
84 self.filters.push(filter)
85 }
86
87 pub fn rotate(&mut self, angle: Angle) {
88 self.transformations
89 .push(Transformation::Rotate(angle.degrees()))
90 }
91
92 pub fn set_rotation(&mut self, angle: Angle) {
93 self.transformations
94 .retain(|t| !matches!(t, Transformation::Rotate(_)));
95 self.transformations
96 .push(Transformation::Rotate(angle.degrees()))
97 }
98
99 pub fn region(&self) -> Region {
100 self.shape.region()
101 }
102
103 pub fn tag(&mut self, tag: impl Display) {
104 self.tags.push(format!("{tag}"));
105 }
106
107 pub fn remove_tag(&mut self, tag: impl Display) {
108 let tag_str = format!("{tag}");
109 self.tags.retain(|t| t != &tag_str);
110 }
111
112 pub fn tagged(mut self, tag: impl Display) -> Self {
113 self.tags.push(format!("{tag}"));
114 self
115 }
116
117 pub fn has_tag(&self, tag: impl Display) -> bool {
118 let tag_str = format!("{tag}");
119 self.tags.iter().any(|t| t == &tag_str)
120 }
121}
122
123impl std::fmt::Display for Object {
124 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
125 let Object {
126 shape: object,
127 fill,
128 filters,
129 transformations,
130 tags,
131 clip_to,
132 } = self;
133
134 if fill.is_some() {
135 write!(f, "{:?} {:?}", fill.unwrap(), object)?;
136 } else {
137 write!(f, "transparent {:?}", object)?;
138 }
139
140 if !filters.is_empty() {
141 write!(f, " with filters {:?}", filters)?;
142 }
143
144 if !transformations.is_empty() {
145 write!(f, " with transformations {:?}", transformations)?;
146 }
147
148 if !tags.is_empty() {
149 write!(f, "{}", tags.iter().map(|t| format!("#{t}")).join(" "))?;
150 }
151
152 if let Some(clip_to) = clip_to {
153 write!(f, " (clipped to {:?})", clip_to)?;
154 }
155
156 Ok(())
157 }
158}
159
160impl From<Shape> for Object {
161 fn from(value: Shape) -> Self {
162 Object {
163 shape: value,
164 fill: None,
165 filters: vec![],
166 transformations: vec![],
167 tags: vec![],
168 clip_to: None,
169 }
170 }
171}
172
173impl From<(Shape, Option<Fill>)> for Object {
174 fn from((object, fill): (Shape, Option<Fill>)) -> Self {
175 Object {
176 shape: object,
177 fill,
178 filters: vec![],
179 transformations: vec![],
180 tags: vec![],
181 clip_to: None,
182 }
183 }
184}
185
186#[cfg_attr(feature = "web", wasm_bindgen)]
187#[derive(Debug, Clone, Copy)]
188pub struct ObjectSizes {
189 pub empty_shape_stroke_width: f32,
190 pub small_circle_radius: f32,
191 pub dot_radius: f32,
192 pub default_line_width: f32,
193}
194
195impl Default for ObjectSizes {
196 fn default() -> Self {
197 Self {
198 empty_shape_stroke_width: 0.5,
199 small_circle_radius: 5.0,
200 dot_radius: 2.0,
201 default_line_width: 2.0,
202 }
203 }
204}