This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

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 pub fn objects_sorted_owned( 46 &self, 47 ) -> impl Iterator<Item = (String, Object)> + '_ { 48 self.objects 49 .iter() 50 .sorted_by_cached_key(|&(id, _)| id.clone()) 51 .map(|(id, obj)| (id.clone(), obj.clone())) 52 } 53 54 // Useful to be able to guarantee a stable order when rendering. 55 pub fn objects_sorted(&self) -> impl Iterator<Item = (&String, &Object)> { 56 self.objects 57 .iter() 58 .sorted_by_cached_key(|&(id, _)| id.clone()) 59 } 60 61 // Useful to be able to guarantee a stable order when rendering. 62 pub fn objects_sorted_mut( 63 &mut self, 64 ) -> impl Iterator<Item = (&String, &mut Object)> { 65 self.objects 66 .iter_mut() 67 .sorted_by_cached_key(|&(id, _)| id.clone()) 68 } 69 70 pub fn objects_in( 71 &mut self, 72 region: Region, 73 ) -> impl Iterator<Item = (&String, &mut Object)> { 74 self.objects 75 .iter_mut() 76 .filter(move |(_, obj)| obj.shape.region().within(&region)) 77 } 78 79 pub fn object_at(&mut self, point: Point) -> Option<&mut Object> { 80 self.find_object_mut(|o| o.position() == point.as_corner()) 81 } 82 83 pub fn has_object_that(&self, pred: impl Fn(&Object) -> bool) -> bool { 84 self.objects.values().any(|obj| pred(obj)) 85 } 86 87 pub fn find_object_mut( 88 &mut self, 89 pred: impl Fn(&Object) -> bool, 90 ) -> Option<&mut Object> { 91 self.objects.values_mut().find(|obj| pred(obj)) 92 } 93 94 pub fn find_object(&self, pred: impl Fn(&Object) -> bool) -> Option<&Object> { 95 self.objects.values().find(|obj| pred(obj)) 96 } 97 98 // Remove all objects. 99 pub fn clear(&mut self) { 100 self.objects.clear(); 101 } 102 103 pub fn replace(&mut self, with: Layer) { 104 self.objects.clone_from(&with.objects); 105 } 106 107 pub fn remove_all_objects_in(&mut self, region: &Region) { 108 self.objects.retain(|_, Object { shape: object, .. }| { 109 !object.region().within(region) 110 }) 111 } 112 113 pub fn paint_all_objects(&mut self, fill: Fill) { 114 for obj in self.objects.values_mut() { 115 obj.fill = Some(fill); 116 } 117 } 118 119 pub fn filter_all_objects(&mut self, filter: Filter) { 120 for obj in self.objects.values_mut() { 121 obj.filters.push(filter) 122 } 123 } 124 125 pub fn move_all_objects(&mut self, dx: i32, dy: i32) { 126 self.objects 127 .iter_mut() 128 .for_each(|(_, Object { shape: object, .. })| { 129 object.translate(dx, dy) 130 }); 131 } 132 133 pub fn add(&mut self, name: impl Display, object: impl Into<Object>) { 134 let name_str = format!("{}", name); 135 136 if self.objects.contains_key(&name_str) { 137 panic!("object {} already exists in layer {}", name_str, self.name); 138 } 139 140 self.set(name_str, object); 141 } 142 143 pub fn add_anon(&mut self, object: impl Into<Object>) { 144 self.add(format!("anon-{}", self.objects.len()), object); 145 } 146 147 pub fn add_many( 148 &mut self, 149 objects: impl IntoIterator<Item = (impl Display, Object)>, 150 ) { 151 for (name, obj) in objects { 152 self.add(name, obj); 153 } 154 } 155 156 pub fn add_many_anon(&mut self, objects: impl IntoIterator<Item = Object>) { 157 for obj in objects { 158 self.add_anon(obj); 159 } 160 } 161 162 pub fn set(&mut self, name: impl Display, object: impl Into<Object>) { 163 let name_str = format!("{}", name); 164 165 self.objects.insert(name_str, object.into()); 166 } 167 168 pub fn filter_object( 169 &mut self, 170 name: &str, 171 filter: Filter, 172 ) -> Result<(), String> { 173 self.objects 174 .get_mut(name) 175 .ok_or(format!("Object '{}' not found", name))? 176 .filters 177 .push(filter); 178 179 Ok(()) 180 } 181 182 pub fn remove_object(&mut self, name: &str) { 183 self.objects.remove(name); 184 } 185 186 pub fn replace_object(&mut self, name: &str, object: Object) { 187 self.remove_object(name); 188 self.add(name, object); 189 } 190 191 pub fn add_objects(&mut self, objects: impl IntoIterator<Item = Object>) { 192 for obj in objects { 193 self.add_anon(obj); 194 } 195 } 196 197 pub fn objects_with_tag( 198 &mut self, 199 tag: impl Display, 200 ) -> impl Iterator<Item = (&String, &mut Object)> { 201 let tag_str = format!("{}", tag); 202 self.objects 203 .iter_mut() 204 .filter(move |(_, obj)| obj.has_tag(&tag_str)) 205 } 206 207 pub fn tag_objects( 208 &mut self, 209 tag: impl Display, 210 objects: impl Fn(&String, &Object) -> bool, 211 ) { 212 let tag_str = format!("{}", tag); 213 for (_, obj) in 214 self.objects.iter_mut().filter(|(id, obj)| objects(id, obj)) 215 { 216 obj.tag(&tag_str); 217 } 218 } 219 220 /// Returns the effective region the layer occupies, by merging all its objects' regions. 221 pub fn region(&self) -> Region { 222 self.objects 223 .values() 224 .map(|object| object.region()) 225 .fold(Region::default(), |acc, region| acc.merge(&region)) 226 } 227} 228 229impl Object { 230 pub fn add_to(self, layer: &mut Layer) { 231 layer.add_anon(self); 232 } 233 234 pub fn set_in(self, layer: &mut Layer, name: impl Display) { 235 layer.set(name, self); 236 } 237}