This repository has no description
1use crate::{ColoredObject, Fill, Filter, ObjectSizes, Region, Toggleable};
2use std::{collections::HashMap, fmt::Display};
3
4#[derive(Debug, Clone, Default)]
5// #[wasm_bindgen(getter_with_clone)]
6pub struct Layer {
7 pub object_sizes: ObjectSizes,
8 pub objects: HashMap<String, ColoredObject>,
9 pub name: String,
10 pub hidden: bool,
11 pub _render_cache: Option<svg::node::element::Group>,
12}
13
14impl Layer {
15 pub fn new(name: impl Display) -> Self {
16 Layer {
17 object_sizes: ObjectSizes::default(),
18 objects: HashMap::new(),
19 name: format!("{}", name),
20 _render_cache: None,
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 // Flush the render cache.
46 pub fn flush(&mut self) {
47 self._render_cache = None;
48 }
49
50 // Remove all objects.
51 pub fn clear(&mut self) {
52 self.objects.clear();
53 self.flush();
54 }
55
56 pub fn replace(&mut self, with: Layer) {
57 self.objects.clone_from(&with.objects);
58 self.flush();
59 }
60
61 pub fn remove_all_objects_in(&mut self, region: &Region) {
62 self.objects.retain(|_, ColoredObject { object, .. }| {
63 !object.region().within(region)
64 })
65 }
66
67 pub fn paint_all_objects(&mut self, fill: Fill) {
68 for obj in self.objects.values_mut() {
69 obj.fill = Some(fill);
70 }
71 self.flush();
72 }
73
74 pub fn filter_all_objects(&mut self, filter: Filter) {
75 for obj in self.objects.values_mut() {
76 obj.filters.push(filter)
77 }
78 self.flush();
79 }
80
81 pub fn move_all_objects(&mut self, dx: i32, dy: i32) {
82 self.objects
83 .iter_mut()
84 .for_each(|(_, ColoredObject { object, .. })| {
85 object.translate(dx, dy)
86 });
87 self.flush();
88 }
89
90 pub fn add(&mut self, name: impl Display, object: impl Into<ColoredObject>) {
91 let name_str = format!("{}", name);
92
93 if self.objects.contains_key(&name_str) {
94 panic!("object {} already exists in layer {}", name_str, self.name);
95 }
96
97 self.set(name_str, object);
98 }
99
100 pub fn add_anon(&mut self, object: impl Into<ColoredObject>) {
101 self.add(format!("anon-{}", self.objects.len()), object);
102 }
103
104 pub fn set(&mut self, name: impl Display, object: impl Into<ColoredObject>) {
105 let name_str = format!("{}", name);
106
107 self.objects.insert(name_str, object.into());
108 self.flush();
109 }
110
111 pub fn filter_object(
112 &mut self,
113 name: &str,
114 filter: Filter,
115 ) -> Result<(), String> {
116 self.objects
117 .get_mut(name)
118 .ok_or(format!("Object '{}' not found", name))?
119 .filters
120 .push(filter);
121
122 self.flush();
123 Ok(())
124 }
125
126 pub fn remove_object(&mut self, name: &str) {
127 self.objects.remove(name);
128 self.flush();
129 }
130
131 pub fn replace_object(&mut self, name: &str, object: ColoredObject) {
132 self.remove_object(name);
133 self.add(name, object);
134 }
135
136 pub fn add_objects(
137 &mut self,
138 objects: impl IntoIterator<Item = ColoredObject>,
139 ) {
140 for obj in objects {
141 self.add_anon(obj);
142 }
143 }
144
145 /// Returns the effective region the layer occupies, by merging all its objects' regions.
146 pub fn region(&self) -> Region {
147 self.objects
148 .values()
149 .map(|object| object.region())
150 .fold(Region::default(), |acc, region| acc.merge(®ion))
151 }
152}
153
154impl ColoredObject {
155 pub fn add_to(self, layer: &mut Layer) {
156 layer.add_anon(self);
157 }
158
159 pub fn set_in(self, layer: &mut Layer, name: impl Display) {
160 layer.set(name, self);
161 }
162}