save & load groups, add copy rule cells

This commit is contained in:
Crispy 2024-05-03 22:27:56 +02:00
parent f23c06f5d7
commit ac9685b2d5
2 changed files with 64 additions and 24 deletions

View file

@ -362,7 +362,7 @@ impl Dish {
let mut old_state = Vec::new(); let mut old_state = Vec::new();
for dy in 0..height { for dy in 0..height {
for dx in 0..width { for dx in 0..width {
old_state.push(self.get_cell(dx, dy).unwrap()); old_state.push(self.get_cell(x + dx, y + dy).unwrap());
} }
} }

View file

@ -10,10 +10,7 @@ use eframe::{
epaint::Hsva, epaint::Hsva,
NativeOptions, NativeOptions,
}; };
use egui::{ use egui::PointerButton;
menu::{SubMenu, SubMenuButton},
popup, Layout, PointerButton,
};
use native_dialog::FileDialog; use native_dialog::FileDialog;
use rand::prelude::*; use rand::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -68,6 +65,7 @@ impl UScope {
let out = json!({ let out = json!({
"cell_types": self.cell_types, "cell_types": self.cell_types,
"rules": self.dish.rules, "rules": self.dish.rules,
"groups": self.dish.cell_groups,
}); });
let out = serde_json::to_string(&out).ok()?; let out = serde_json::to_string(&out).ok()?;
let mut file = File::create(path).ok()?; let mut file = File::create(path).ok()?;
@ -85,9 +83,11 @@ impl UScope {
let s = fs::read_to_string(path).ok()?; let s = fs::read_to_string(path).ok()?;
let data: Value = serde_json::from_str(&s).ok()?; let data: Value = serde_json::from_str(&s).ok()?;
let cell_types = serde_json::from_value(data["cell_types"].clone()).ok()?; let cell_types = serde_json::from_value(data["cell_types"].clone()).ok()?;
let groups = serde_json::from_value(data["groups"].clone()).ok()?;
let rules = serde_json::from_value(data["rules"].clone()).ok()?; let rules = serde_json::from_value(data["rules"].clone()).ok()?;
self.cell_types = cell_types; self.cell_types = cell_types;
self.dish.rules = rules; self.dish.rules = rules;
self.dish.cell_groups = groups;
self.dish.update_rules(); self.dish.update_rules();
} }
Some(()) Some(())
@ -215,6 +215,8 @@ fn paint_chunk(painter: Painter, chunk: &Chunk, cells: &[CellData], grid: bool)
} }
const CSIZE: f32 = 24.; const CSIZE: f32 = 24.;
const RESIZE_BUTTON_WIDTH: f32 = 8.;
const OUTLINE: (f32, Color32) = (2., Color32::GRAY); const OUTLINE: (f32, Color32) = (2., Color32::GRAY);
fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<Cell>]) { fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<Cell>]) {
ui.checkbox(&mut rule.enabled, "enable rule"); ui.checkbox(&mut rule.enabled, "enable rule");
@ -233,31 +235,41 @@ fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<C
let cells_y = rule.height(); let cells_y = rule.height();
let cells_x = rule.width(); let cells_x = rule.width();
let margin = 8.;
let patt_width = CSIZE * cells_x as f32; let patt_width = CSIZE * cells_x as f32;
let patt_height = CSIZE * cells_y as f32; let patt_height = CSIZE * cells_y as f32;
let (_, bounds) = ui.allocate_space(Vec2::new( let (_, bounds) = ui.allocate_space(Vec2::new(
patt_width * 2. + margin * 4. + CSIZE, patt_width * 2. + RESIZE_BUTTON_WIDTH * 4. + CSIZE,
patt_height + margin * 2., patt_height + RESIZE_BUTTON_WIDTH * 2.,
)); ));
let from_cells_rect = Rect::from_min_size( let from_cells_rect = Rect::from_min_size(
bounds.min + Vec2::splat(margin), bounds.min + Vec2::splat(RESIZE_BUTTON_WIDTH),
Vec2::new(patt_width, patt_height), Vec2::new(patt_width, patt_height),
); );
let to_cells_rect = Rect::from_min_size( let to_cells_rect = Rect::from_min_size(
bounds.min + Vec2::splat(margin) + Vec2::X * (patt_width + margin * 2. + CSIZE), bounds.min
+ Vec2::splat(RESIZE_BUTTON_WIDTH)
+ Vec2::X * (patt_width + RESIZE_BUTTON_WIDTH * 2. + CSIZE),
Vec2::new(patt_width, patt_height), Vec2::new(patt_width, patt_height),
); );
let mut overlay_lines = Vec::new();
for x in 0..cells_x { for x in 0..cells_x {
for y in 0..cells_y { for y in 0..cells_y {
let (left, right) = rule.get_mut(x, y); let (left, right) = rule.get_mut(x, y);
let changed_left = let changed_left =
rule_cell_edit_from(ui, from_cells_rect.min, left, x, y, cells, groups); rule_cell_edit_from(ui, from_cells_rect.min, left, x, y, cells, groups);
let changed_right = let changed_right = rule_cell_edit_to(
rule_cell_edit_to(ui, to_cells_rect.min, right, x, y, cells, groups); ui,
to_cells_rect.min,
right,
(x, y),
cells,
groups,
(cells_x, cells_y),
&mut overlay_lines,
);
if changed_left || changed_right { if changed_left || changed_right {
rule.generate_variants(); rule.generate_variants();
} }
@ -286,7 +298,12 @@ fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<C
result.clicked() result.clicked()
}; };
if resize_box(bounds.min.x, bounds.min.y + margin, margin, patt_height) { if resize_box(
bounds.min.x,
bounds.min.y + RESIZE_BUTTON_WIDTH,
RESIZE_BUTTON_WIDTH,
patt_height,
) {
if delete_mode { if delete_mode {
rule.resize(Rule::SHRINK_LEFT); rule.resize(Rule::SHRINK_LEFT);
} else { } else {
@ -295,8 +312,8 @@ fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<C
} }
if resize_box( if resize_box(
from_cells_rect.max.x, from_cells_rect.max.x,
bounds.min.y + margin, bounds.min.y + RESIZE_BUTTON_WIDTH,
margin, RESIZE_BUTTON_WIDTH,
patt_height, patt_height,
) { ) {
if delete_mode { if delete_mode {
@ -305,7 +322,12 @@ fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<C
rule.resize(Rule::EXTEND_RIGHT); rule.resize(Rule::EXTEND_RIGHT);
} }
} }
if resize_box(bounds.min.x + margin, bounds.min.y, patt_width, margin) { if resize_box(
bounds.min.x + RESIZE_BUTTON_WIDTH,
bounds.min.y,
patt_width,
RESIZE_BUTTON_WIDTH,
) {
if delete_mode { if delete_mode {
rule.resize(Rule::SHRINK_UP); rule.resize(Rule::SHRINK_UP);
} else { } else {
@ -313,10 +335,10 @@ fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<C
} }
} }
if resize_box( if resize_box(
bounds.min.x + margin, bounds.min.x + RESIZE_BUTTON_WIDTH,
bounds.max.y - margin, bounds.max.y - RESIZE_BUTTON_WIDTH,
patt_width, patt_width,
margin, RESIZE_BUTTON_WIDTH,
) { ) {
if delete_mode { if delete_mode {
rule.resize(Rule::SHRINK_DOWN); rule.resize(Rule::SHRINK_DOWN);
@ -324,6 +346,10 @@ fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<C
rule.resize(Rule::EXTEND_DOWN); rule.resize(Rule::EXTEND_DOWN);
} }
} }
for (a, b) in overlay_lines {
ui.painter().line_segment([a, b], (2., Color32::WHITE));
}
} }
fn rule_cell_edit_from( fn rule_cell_edit_from(
@ -394,10 +420,11 @@ fn rule_cell_edit_to(
ui: &mut Ui, ui: &mut Ui,
origin: Pos2, origin: Pos2,
rule: &mut RuleCellTo, rule: &mut RuleCellTo,
x: usize, (x, y): (usize, usize),
y: usize,
cells: &[CellData], cells: &[CellData],
groups: &[Vec<Cell>], groups: &[Vec<Cell>],
(rule_width, rule_height): (usize, usize),
overlay_lines: &mut Vec<(Pos2, Pos2)>,
) -> bool { ) -> bool {
let mut changed = false; let mut changed = false;
let rect = Rect::from_min_size( let rect = Rect::from_min_size(
@ -420,7 +447,15 @@ fn rule_cell_edit_to(
let group = &groups[*group_id]; let group = &groups[*group_id];
draw_group(ui, rect, group, cells); draw_group(ui, rect, group, cells);
} }
RuleCellTo::Copy(_) => todo!(), RuleCellTo::Copy(index) => {
let this = rect.center();
let x = *index % rule_width;
let y = *index / rule_width;
let target = origin + Vec2::from((x as f32, y as f32)) * CSIZE
- Vec2::X * (CSIZE * (rule_width as f32 + 1.) + RESIZE_BUTTON_WIDTH * 2.)
+ Vec2::splat(CSIZE) * 0.5;
overlay_lines.push((this, target));
}
} }
if cycle_colors { if cycle_colors {
@ -436,7 +471,10 @@ fn rule_cell_edit_to(
*group_id %= groups.len(); *group_id %= groups.len();
changed = true; changed = true;
} }
RuleCellTo::Copy(_) => todo!(), RuleCellTo::Copy(index) => {
*index = (*index + 1) % (rule_width * rule_height);
changed = true;
}
} }
} }
@ -450,9 +488,11 @@ fn rule_cell_edit_to(
*rule = RuleCellTo::GroupRandom(0); *rule = RuleCellTo::GroupRandom(0);
} }
RuleCellTo::GroupRandom(_) => { RuleCellTo::GroupRandom(_) => {
*rule = RuleCellTo::Copy(0);
}
RuleCellTo::Copy(_) => {
*rule = RuleCellTo::None; *rule = RuleCellTo::None;
} }
RuleCellTo::Copy(_) => todo!(),
} }
} }
changed changed