This repository has no description
1use itertools::Itertools;
2
3use crate::{Fill, Filter, Object, ObjectSizes, Point, Region, Toggleable};
4use std::{collections::HashMap, fmt::Display};
5
6#[derive(Debug, Clone, Default)]
7// #[wasm_bindgen(getter_with_clone)]
8pub struct Layer {
9 pub object_sizes: ObjectSizes,
10 pub objects: HashMap<String, Object>,
11 pub name: String,
12 pub hidden: bool,
13}
14
15impl Layer {
16 pub fn new(name: impl Display) -> Self {
17 Layer {
18 object_sizes: ObjectSizes::default(),
19 objects: HashMap::new(),
20 name: format!("{}", name),
21 hidden: false,
22 }
23 }
24
25 pub fn hide(&mut self) {
26 self.hidden = true;
27 }
28
29 pub fn show(&mut self) {
30 self.hidden = false;
31 }
32
33 pub fn toggle(&mut self) {
34 self.hidden.toggle();
35 }
36
37 pub fn object(&mut self, name: &str) -> &mut Object {
38 self.safe_object(name).unwrap()
39 }
40
41 pub fn safe_object(&mut self, name: &str) -> Option<&mut Object> {
42 self.objects.get_mut(name)
43 }
44
45 // Useful to be able to guarantee a stable order when rendering.
46 pub fn objects_sorted(&self) -> impl Iterator<Item = (&String, &Object)> {
47 self.objects
48 .iter()
49 .sorted_by_cached_key(|&(id, _)| id.clone())
50 }
51
52 // Useful to be able to guarantee a stable order when rendering.
53 pub fn objects_sorted_mut(
54 &mut self,
55 ) -> impl Iterator<Item = (&String, &mut Object)> {
56 self.objects
57 .iter_mut()
58 .sorted_by_cached_key(|&(id, _)| id.clone())
59 }
60
61 pub fn objects_in(
62 &mut self,
63 region: Region,
64 ) -> impl Iterator<Item = (&String, &mut Object)> {
65 self.objects
66 .iter_mut()
67 .filter(move |(_, obj)| obj.shape.region().within(®ion))
68 }
69
70 pub fn object_at(&mut self, point: Point) -> Option<&mut Object> {
71 self.objects
72 .values_mut()
73 .find(|obj| obj.shape.region().start == point)
74 }
75
76 pub fn has_object_that(&self, pred: impl Fn(&Object) -> bool) -> bool {
77 self.objects.values().any(|obj| pred(obj))
78 }
79
80 // Remove all objects.
81 pub fn clear(&mut self) {
82 self.objects.clear();
83 }
84
85 pub fn replace(&mut self, with: Layer) {
86 self.objects.clone_from(&with.objects);
87 }
88
89 pub fn remove_all_objects_in(&mut self, region: &Region) {
90 self.objects.retain(|_, Object { shape: object, .. }| {
91 !object.region().within(region)
92 })
93 }
94
95 pub fn paint_all_objects(&mut self, fill: Fill) {
96 for obj in self.objects.values_mut() {
97 obj.fill = Some(fill);
98 }
99 }
100
101 pub fn filter_all_objects(&mut self, filter: Filter) {
102 for obj in self.objects.values_mut() {
103 obj.filters.push(filter)
104 }
105 }
106
107 pub fn move_all_objects(&mut self, dx: i32, dy: i32) {
108 self.objects
109 .iter_mut()
110 .for_each(|(_, Object { shape: object, .. })| {
111 object.translate(dx, dy)
112 });
113 }
114
115 pub fn add(&mut self, name: impl Display, object: impl Into<Object>) {
116 let name_str = format!("{}", name);
117
118 if self.objects.contains_key(&name_str) {
119 panic!("object {} already exists in layer {}", name_str, self.name);
120 }
121
122 self.set(name_str, object);
123 }
124
125 pub fn add_anon(&mut self, object: impl Into<Object>) {
126 self.add(format!("anon-{}", self.objects.len()), object);
127 }
128
129 pub fn add_many(
130 &mut self,
131 objects: impl IntoIterator<Item = (impl Display, Object)>,
132 ) {
133 for (name, obj) in objects {
134 self.add(name, obj);
135 }
136 }
137
138 pub fn add_many_anon(&mut self, objects: impl IntoIterator<Item = Object>) {
139 for obj in objects {
140 self.add_anon(obj);
141 }
142 }
143
144 pub fn set(&mut self, name: impl Display, object: impl Into<Object>) {
145 let name_str = format!("{}", name);
146
147 self.objects.insert(name_str, object.into());
148 }
149
150 pub fn filter_object(
151 &mut self,
152 name: &str,
153 filter: Filter,
154 ) -> Result<(), String> {
155 self.objects
156 .get_mut(name)
157 .ok_or(format!("Object '{}' not found", name))?
158 .filters
159 .push(filter);
160
161 Ok(())
162 }
163
164 pub fn remove_object(&mut self, name: &str) {
165 self.objects.remove(name);
166 }
167
168 pub fn replace_object(&mut self, name: &str, object: Object) {
169 self.remove_object(name);
170 self.add(name, object);
171 }
172
173 pub fn add_objects(&mut self, objects: impl IntoIterator<Item = Object>) {
174 for obj in objects {
175 self.add_anon(obj);
176 }
177 }
178
179 pub fn objects_with_tag(
180 &mut self,
181 tag: impl Display,
182 ) -> impl Iterator<Item = (&String, &mut Object)> {
183 let tag_str = format!("{}", tag);
184 self.objects
185 .iter_mut()
186 .filter(move |(_, obj)| obj.has_tag(&tag_str))
187 }
188
189 pub fn tag_objects(
190 &mut self,
191 tag: impl Display,
192 objects: impl Fn(&String, &Object) -> bool,
193 ) {
194 let tag_str = format!("{}", tag);
195 for (_, obj) in
196 self.objects.iter_mut().filter(|(id, obj)| objects(id, obj))
197 {
198 obj.tag(&tag_str);
199 }
200 }
201
202 /// Returns the effective region the layer occupies, by merging all its objects' regions.
203 pub fn region(&self) -> Region {
204 self.objects
205 .values()
206 .map(|object| object.region())
207 .fold(Region::default(), |acc, region| acc.merge(®ion))
208 }
209}
210
211impl Object {
212 pub fn add_to(self, layer: &mut Layer) {
213 layer.add_anon(self);
214 }
215
216 pub fn set_in(self, layer: &mut Layer, name: impl Display) {
217 layer.set(name, self);
218 }
219}