diff --git a/petri/src/lib.rs b/petri/src/lib.rs index 2c1428f..63f5501 100644 --- a/petri/src/lib.rs +++ b/petri/src/lib.rs @@ -18,7 +18,7 @@ pub struct Chunk { pub contents: Box<[[Cell; CHUNK_SIZE]; CHUNK_SIZE]>, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct Rule { base: SubRule, #[serde(skip)] @@ -61,6 +61,12 @@ pub enum RuleCellTo { Copy(usize), } +impl std::default::Default for SubRule { + fn default() -> Self { + Self::new() + } +} + impl SubRule { fn new() -> Self { Self { @@ -113,17 +119,6 @@ impl Rule { pub const SHRINK_UP: ResizeParam = (0, -1, 0, 1); pub const SHRINK_DOWN: ResizeParam = (0, -1, 0, 0); - pub fn new() -> Self { - Self { - enabled: false, - base: SubRule::new(), - variants: Vec::new(), - flip_h: false, - flip_v: false, - rotate: false, - } - } - pub fn get(&self, x: usize, y: usize) -> (RuleCellFrom, RuleCellTo) { self.base.get(x, y) } @@ -264,7 +259,7 @@ impl Chunk { } pub fn get_cell(&self, x: usize, y: usize) -> Cell { - self.contents[x][y].clone() + self.contents[x][y] } fn set_cell(&mut self, x: usize, y: usize, cell: Cell) { @@ -285,7 +280,7 @@ impl Dish { (RuleCellFrom::One(Cell(0)), RuleCellTo::One(Cell(1))), ], }, - ..Rule::new() + ..Rule::default() }, Rule { enabled: true, @@ -300,7 +295,7 @@ impl Dish { ], }, flip_h: true, - ..Rule::new() + ..Rule::default() }, ]; @@ -371,7 +366,7 @@ impl Dish { let py = y.wrapping_add_unsigned(dy) as usize; match variant.get(dx, dy).1 { RuleCellTo::One(rule_cell) => { - self.set_cell(px, py, rule_cell.clone()); + self.set_cell(px, py, rule_cell); } RuleCellTo::GroupRandom(group_id) => { let group = &self.cell_groups[group_id]; diff --git a/uscope/src/main.rs b/uscope/src/main.rs index 9df2a37..f36c2b6 100644 --- a/uscope/src/main.rs +++ b/uscope/src/main.rs @@ -100,92 +100,96 @@ impl eframe::App for UScope { for _ in 0..self.speed { self.dish.fire_blindly(); } - SidePanel::left("left_panel").show(ctx, |ui| { - ui.heading("Simulation"); - ui.label("speed"); - ui.add(Slider::new(&mut self.speed, 0..=5000)); - ui.checkbox(&mut self.show_grid, "show grid"); - ui.horizontal(|ui| { - if ui.button("Save").clicked() { - self.save_universe(); - } - if ui.button("Open").clicked() { - self.open_universe(); - } - }); - ui.separator(); - - ui.heading("Cells"); - for (i, cell) in self.cell_types.iter_mut().enumerate() { + SidePanel::left("left_panel") + .min_width(100.) + .show(ctx, |ui| { + ui.heading("Simulation"); + ui.label("speed"); + ui.add(Slider::new(&mut self.speed, 0..=5000)); + ui.checkbox(&mut self.show_grid, "show grid"); ui.horizontal(|ui| { - ui.set_width(120.); - ui.radio_value(&mut self.brush.0, i as u16, ""); - ui.text_edit_singleline(&mut cell.name); - ui.color_edit_button_srgba(&mut cell.color); - }); - } - - if ui.button("add cell").clicked() { - let h = random::(); - let s = random::() * 0.5 + 0.5; - let v = random::() * 0.5 + 0.5; - let color = Hsva::new(h, s, v, 1.).into(); - let name = format!("cell #{}", self.cell_types.len()); - self.cell_types.push(CellData { name, color }) - } - if ui.button("fill").clicked() { - self.dish.chunk.contents.fill([self.brush; CHUNK_SIZE]); - } - ui.separator(); - - ui.heading("Groups"); - for group in &mut self.dish.cell_groups { - let (rect, _response) = ui.allocate_exact_size(Vec2::splat(CSIZE), Sense::click()); - draw_group(ui, rect, group, &self.cell_types); - ui.menu_button("edit", |ui| { - let mut void = group.contains(&None); - if ui.checkbox(&mut void, "void").changed() { - if void { - group.push(None); - } else { - group.retain(|c| c.is_some()); - } + if ui.button("Save").clicked() { + self.save_universe(); } - for (i, celldata) in self.cell_types.iter().enumerate() { - let mut included = group.contains(&Some(Cell(i as u16))); - if ui.checkbox(&mut included, &celldata.name).changed() { - if included { - group.push(Some(Cell(i as u16))); - } else { - group.retain(|c| c != &Some(Cell(i as u16))); - } - } + if ui.button("Open").clicked() { + self.open_universe(); } }); - } - if ui.button("add group").clicked() { - self.dish.cell_groups.push(Vec::new()); - } - - ui.heading("Rules"); - ScrollArea::vertical().show(ui, |ui| { - let mut to_remove = None; - for (i, rule) in self.dish.rules.iter_mut().enumerate() { - ui.separator(); - rule_editor(ui, rule, &self.cell_types, &self.dish.cell_groups); - if ui.button("delete").clicked() { - to_remove = Some(i); - } - } - if let Some(i) = to_remove { - self.dish.rules.remove(i); - } ui.separator(); - if ui.button("add rule").clicked() { - self.dish.rules.push(Rule::new()); - } + + ScrollArea::vertical().show(ui, |ui| { + ui.heading("Cells"); + for (i, cell) in self.cell_types.iter_mut().enumerate() { + ui.horizontal(|ui| { + ui.set_width(120.); + ui.radio_value(&mut self.brush.0, i as u16, ""); + ui.text_edit_singleline(&mut cell.name); + ui.color_edit_button_srgba(&mut cell.color); + }); + } + + if ui.button("add cell").clicked() { + let h = random::(); + let s = random::() * 0.5 + 0.5; + let v = random::() * 0.5 + 0.5; + let color = Hsva::new(h, s, v, 1.).into(); + let name = format!("cell #{}", self.cell_types.len()); + self.cell_types.push(CellData { name, color }) + } + if ui.button("fill").clicked() { + self.dish.chunk.contents.fill([self.brush; CHUNK_SIZE]); + } + ui.separator(); + + ui.heading("Groups"); + for group in &mut self.dish.cell_groups { + let (rect, _response) = + ui.allocate_exact_size(Vec2::splat(CSIZE), Sense::click()); + draw_group(ui, rect, group, &self.cell_types); + ui.menu_button("edit", |ui| { + let mut void = group.contains(&None); + if ui.checkbox(&mut void, "void").changed() { + if void { + group.push(None); + } else { + group.retain(|c| c.is_some()); + } + } + for (i, celldata) in self.cell_types.iter().enumerate() { + let mut included = group.contains(&Some(Cell(i as u16))); + if ui.checkbox(&mut included, &celldata.name).changed() { + if included { + group.push(Some(Cell(i as u16))); + } else { + group.retain(|c| c != &Some(Cell(i as u16))); + } + } + } + }); + } + if ui.button("add group").clicked() { + self.dish.cell_groups.push(Vec::new()); + } + + ui.heading("Rules"); + + let mut to_remove = None; + for (i, rule) in self.dish.rules.iter_mut().enumerate() { + ui.separator(); + rule_editor(ui, rule, &self.cell_types, &self.dish.cell_groups); + if ui.button("delete").clicked() { + to_remove = Some(i); + } + } + if let Some(i) = to_remove { + self.dish.rules.remove(i); + } + ui.separator(); + if ui.button("add rule").clicked() { + self.dish.rules.push(Rule::default()); + } + }); }); - }); CentralPanel::default().show(ctx, |ui| { let bounds = ui.available_rect_before_wrap(); let painter = ui.painter_at(bounds); @@ -505,7 +509,11 @@ fn rule_cell_edit_to( } fn draw_group(ui: &mut Ui, rect: Rect, group: &[Option], cells: &[CellData]) { - let group_size = group.len(); + let mut group_size = group.len(); + let has_void = group.contains(&None); + if has_void { + group_size -= 1; + } let radius_per_color = (CSIZE * 0.7) / (group_size as f32); for (i, cell) in group.iter().flatten().enumerate() { let color = cells[cell.id()].color; @@ -513,7 +521,7 @@ fn draw_group(ui: &mut Ui, rect: Rect, group: &[Option], cells: &[CellData ui.painter_at(rect) .circle_filled(rect.center(), radius, color); } - if group.contains(&None) { + if has_void { ui.painter_at(rect) .line_segment([rect.min, rect.max], (1., Color32::WHITE)); }