This repository has no description
1use crate::{
2 ColoredObject, Fill, Filter, ObjectSizes, Point, Region, Toggleable,
3};
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, ColoredObject>,
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 ColoredObject {
38 self.safe_object(name).unwrap()
39 }
40
41 pub fn safe_object(&mut self, name: &str) -> Option<&mut ColoredObject> {
42 self.objects.get_mut(name)
43 }
44
45 pub fn objects_in(
46 &mut self,
47 region: Region,
48 ) -> impl Iterator<Item = (&String, &mut ColoredObject)> {
49 self.objects
50 .iter_mut()
51 .filter(move |(_, obj)| obj.object.region().within(®ion))
52 }
53
54 pub fn object_at(&mut self, point: Point) -> Option<&mut ColoredObject> {
55 self.objects
56 .values_mut()
57 .find(|obj| obj.object.region().start == point)
58 }
59
60 // Remove all objects.
61 pub fn clear(&mut self) {
62 self.objects.clear();
63 }
64
65 pub fn replace(&mut self, with: Layer) {
66 self.objects.clone_from(&with.objects);
67 }
68
69 pub fn remove_all_objects_in(&mut self, region: &Region) {
70 self.objects.retain(|_, ColoredObject { object, .. }| {
71 !object.region().within(region)
72 })
73 }
74
75 pub fn paint_all_objects(&mut self, fill: Fill) {
76 for obj in self.objects.values_mut() {
77 obj.fill = Some(fill);
78 }
79 }
80
81 pub fn filter_all_objects(&mut self, filter: Filter) {
82 for obj in self.objects.values_mut() {
83 obj.filters.push(filter)
84 }
85 }
86
87 pub fn move_all_objects(&mut self, dx: i32, dy: i32) {
88 self.objects
89 .iter_mut()
90 .for_each(|(_, ColoredObject { object, .. })| {
91 object.translate(dx, dy)
92 });
93 }
94
95 pub fn add(&mut self, name: impl Display, object: impl Into<ColoredObject>) {
96 let name_str = format!("{}", name);
97
98 if self.objects.contains_key(&name_str) {
99 panic!("object {} already exists in layer {}", name_str, self.name);
100 }
101
102 self.set(name_str, object);
103 }
104
105 pub fn add_anon(&mut self, object: impl Into<ColoredObject>) {
106 self.add(format!("anon-{}", self.objects.len()), object);
107 }
108
109 pub fn set(&mut self, name: impl Display, object: impl Into<ColoredObject>) {
110 let name_str = format!("{}", name);
111
112 self.objects.insert(name_str, object.into());
113 }
114
115 pub fn filter_object(
116 &mut self,
117 name: &str,
118 filter: Filter,
119 ) -> Result<(), String> {
120 self.objects
121 .get_mut(name)
122 .ok_or(format!("Object '{}' not found", name))?
123 .filters
124 .push(filter);
125
126 Ok(())
127 }
128
129 pub fn remove_object(&mut self, name: &str) {
130 self.objects.remove(name);
131 }
132
133 pub fn replace_object(&mut self, name: &str, object: ColoredObject) {
134 self.remove_object(name);
135 self.add(name, object);
136 }
137
138 pub fn add_objects(
139 &mut self,
140 objects: impl IntoIterator<Item = ColoredObject>,
141 ) {
142 for obj in objects {
143 self.add_anon(obj);
144 }
145 }
146
147 pub fn objects_with_tag(
148 &mut self,
149 tag: impl Display,
150 ) -> impl Iterator<Item = (&String, &mut ColoredObject)> {
151 let tag_str = format!("{}", tag);
152 self.objects
153 .iter_mut()
154 .filter(move |(_, obj)| obj.has_tag(&tag_str))
155 }
156
157 pub fn tag_objects(
158 &mut self,
159 tag: impl Display,
160 objects: impl Fn(&String, &ColoredObject) -> bool,
161 ) {
162 let tag_str = format!("{}", tag);
163 for (_, obj) in
164 self.objects.iter_mut().filter(|(id, obj)| objects(id, obj))
165 {
166 obj.tag(&tag_str);
167 }
168 }
169
170 /// Returns the effective region the layer occupies, by merging all its objects' regions.
171 pub fn region(&self) -> Region {
172 self.objects
173 .values()
174 .map(|object| object.region())
175 .fold(Region::default(), |acc, region| acc.merge(®ion))
176 }
177}
178
179impl ColoredObject {
180 pub fn add_to(self, layer: &mut Layer) {
181 layer.add_anon(self);
182 }
183
184 pub fn set_in(self, layer: &mut Layer, name: impl Display) {
185 layer.set(name, self);
186 }
187}