Persist window state across runs
This commit is contained in:
+64
-41
@@ -11,6 +11,7 @@ use fixed::{
|
||||
};
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
emulator::SimId,
|
||||
@@ -18,46 +19,62 @@ use crate::{
|
||||
memory::{MemoryClient, MemoryRef, MemoryView},
|
||||
window::{
|
||||
AppWindow,
|
||||
utils::{NumberEdit, UiExt as _},
|
||||
utils::{NumberEdit, UiData, UiExt as _},
|
||||
},
|
||||
};
|
||||
|
||||
use super::utils::{self, CellData, Object, shade};
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
struct State {
|
||||
index: usize,
|
||||
param_index: usize,
|
||||
generic_palette: bool,
|
||||
show_extents: bool,
|
||||
scale: f32,
|
||||
}
|
||||
impl Default for State {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
index: 31,
|
||||
param_index: 0,
|
||||
generic_palette: false,
|
||||
show_extents: false,
|
||||
scale: 1.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WorldWindow {
|
||||
sim_id: SimId,
|
||||
memory: Arc<MemoryClient>,
|
||||
worlds: MemoryView,
|
||||
bgmaps: MemoryView,
|
||||
index: usize,
|
||||
param_index: usize,
|
||||
generic_palette: bool,
|
||||
show_extents: bool,
|
||||
params: ImageParams<WorldParams>,
|
||||
scale: f32,
|
||||
state: UiData<State>,
|
||||
}
|
||||
|
||||
impl WorldWindow {
|
||||
pub fn new(sim_id: SimId, memory: &Arc<MemoryClient>, images: &ImageTextureLoader) -> Self {
|
||||
let initial_params = WorldParams {
|
||||
index: 31,
|
||||
generic_palette: false,
|
||||
left_color: Color32::from_rgb(0xff, 0x00, 0x00),
|
||||
right_color: Color32::from_rgb(0x00, 0xc6, 0xf0),
|
||||
};
|
||||
let state: UiData<State> = UiData::new();
|
||||
let renderer = WorldRenderer::new(sim_id, memory);
|
||||
let params = images.add(sim_id, renderer, initial_params);
|
||||
let params = images.add(
|
||||
sim_id,
|
||||
renderer,
|
||||
WorldParams {
|
||||
index: state.index,
|
||||
generic_palette: state.generic_palette,
|
||||
left_color: Color32::from_rgb(0xff, 0x00, 0x00),
|
||||
right_color: Color32::from_rgb(0x00, 0xc6, 0xf0),
|
||||
},
|
||||
);
|
||||
Self {
|
||||
sim_id,
|
||||
memory: memory.clone(),
|
||||
worlds: memory.watch(sim_id, 0x0003d800, 0x400),
|
||||
bgmaps: memory.watch(sim_id, 0x00020000, 0x20000),
|
||||
index: params.index,
|
||||
param_index: 0,
|
||||
generic_palette: params.generic_palette,
|
||||
show_extents: false,
|
||||
params,
|
||||
scale: 1.0,
|
||||
state,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +90,7 @@ impl WorldWindow {
|
||||
ui.label("Index");
|
||||
});
|
||||
row.col(|ui| {
|
||||
ui.add(NumberEdit::new(&mut self.index).range(0..32));
|
||||
ui.add(NumberEdit::new(&mut self.state.index).range(0..32));
|
||||
});
|
||||
});
|
||||
body.row(row_height, |mut row| {
|
||||
@@ -81,7 +98,7 @@ impl WorldWindow {
|
||||
ui.label("Address");
|
||||
});
|
||||
row.col(|ui| {
|
||||
let address = 0x0003d800 + self.index * 32;
|
||||
let address = 0x0003d800 + self.state.index * 32;
|
||||
let mut address_str = format!("{address:08x}");
|
||||
ui.add_enabled(
|
||||
false,
|
||||
@@ -92,7 +109,7 @@ impl WorldWindow {
|
||||
});
|
||||
let mut data = {
|
||||
let worlds = self.worlds.borrow();
|
||||
worlds.read(self.index)
|
||||
worlds.read(self.state.index)
|
||||
};
|
||||
let mut world = World::parse(&data);
|
||||
ui.section("Properties", |ui| {
|
||||
@@ -272,7 +289,7 @@ impl WorldWindow {
|
||||
});
|
||||
});
|
||||
if world.update(&mut data) {
|
||||
let address = 0x0003d800 + self.index * 32;
|
||||
let address = 0x0003d800 + self.state.index * 32;
|
||||
self.memory.write(self.sim_id, address as u32, &data);
|
||||
}
|
||||
if world.header.mode == WorldMode::HBias {
|
||||
@@ -287,10 +304,12 @@ impl WorldWindow {
|
||||
});
|
||||
row.col(|ui| {
|
||||
let max = world.height.max(8) as usize;
|
||||
ui.add(NumberEdit::new(&mut self.param_index).range(0..max));
|
||||
ui.add(
|
||||
NumberEdit::new(&mut self.state.param_index).range(0..max),
|
||||
);
|
||||
});
|
||||
});
|
||||
let base = (world.param_base + self.param_index * 2) & 0x1ffff;
|
||||
let base = (world.param_base + self.state.param_index * 2) & 0x1ffff;
|
||||
let mut param = HBiasParam::load(&self.bgmaps.borrow(), base);
|
||||
body.row(row_height, |mut row| {
|
||||
row.col(|ui| {
|
||||
@@ -337,10 +356,12 @@ impl WorldWindow {
|
||||
});
|
||||
row.col(|ui| {
|
||||
let max = world.height.max(1) as usize;
|
||||
ui.add(NumberEdit::new(&mut self.param_index).range(0..max));
|
||||
ui.add(
|
||||
NumberEdit::new(&mut self.state.param_index).range(0..max),
|
||||
);
|
||||
});
|
||||
});
|
||||
let base = (world.param_base + self.param_index * 8) & 0x1ffff;
|
||||
let base = (world.param_base + self.state.param_index * 8) & 0x1ffff;
|
||||
let mut param = AffineParam::load(&self.bgmaps.borrow(), base);
|
||||
body.row(row_height, |mut row| {
|
||||
row.col(|ui| {
|
||||
@@ -400,49 +421,49 @@ impl WorldWindow {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
self.param_index = 0;
|
||||
self.state.param_index = 0;
|
||||
}
|
||||
ui.section("Display", |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Scale");
|
||||
ui.spacing_mut().slider_width = ui.available_width();
|
||||
let slider = Slider::new(&mut self.scale, 1.0..=10.0)
|
||||
let slider = Slider::new(&mut self.state.scale, 1.0..=10.0)
|
||||
.step_by(1.0)
|
||||
.show_value(false);
|
||||
ui.add(slider);
|
||||
});
|
||||
ui.checkbox(&mut self.generic_palette, "Generic palette");
|
||||
ui.checkbox(&mut self.show_extents, "Show extents");
|
||||
ui.checkbox(&mut self.state.generic_palette, "Generic palette");
|
||||
ui.checkbox(&mut self.state.show_extents, "Show extents");
|
||||
});
|
||||
});
|
||||
self.params.write(WorldParams {
|
||||
index: self.index,
|
||||
generic_palette: self.generic_palette,
|
||||
index: self.state.index,
|
||||
generic_palette: self.state.generic_palette,
|
||||
..*self.params
|
||||
});
|
||||
}
|
||||
|
||||
fn show_world(&mut self, ui: &mut Ui) {
|
||||
let image = Image::new(self.image_url("world"))
|
||||
.fit_to_original_size(self.scale)
|
||||
.fit_to_original_size(self.state.scale)
|
||||
.texture_options(TextureOptions::NEAREST);
|
||||
let res = ui.add(image);
|
||||
if self.show_extents {
|
||||
if self.state.show_extents {
|
||||
let world = {
|
||||
let worlds = self.worlds.borrow();
|
||||
let data = worlds.read(self.index);
|
||||
let data = worlds.read(self.state.index);
|
||||
World::parse(&data)
|
||||
};
|
||||
if world.header.mode == WorldMode::Object {
|
||||
return;
|
||||
}
|
||||
|
||||
let lx1 = (world.dst_x - world.dst_parallax) as f32 * self.scale;
|
||||
let lx2 = lx1 + world.width as f32 * self.scale;
|
||||
let rx1 = (world.dst_x + world.dst_parallax) as f32 * self.scale;
|
||||
let rx2 = rx1 + world.width as f32 * self.scale;
|
||||
let y1 = world.dst_y as f32 * self.scale;
|
||||
let y2 = y1 + world.height as f32 * self.scale;
|
||||
let lx1 = (world.dst_x - world.dst_parallax) as f32 * self.state.scale;
|
||||
let lx2 = lx1 + world.width as f32 * self.state.scale;
|
||||
let rx1 = (world.dst_x + world.dst_parallax) as f32 * self.state.scale;
|
||||
let rx2 = rx1 + world.width as f32 * self.state.scale;
|
||||
let y1 = world.dst_y as f32 * self.state.scale;
|
||||
let y2 = y1 + world.height as f32 * self.state.scale;
|
||||
|
||||
let left_color = self.params.left_color;
|
||||
let right_color = self.params.right_color;
|
||||
@@ -517,6 +538,7 @@ impl AppWindow for WorldWindow {
|
||||
}
|
||||
|
||||
fn show(&mut self, ui: &mut Ui) {
|
||||
self.state.load(ui);
|
||||
CentralPanel::default().show_inside(ui, |ui| {
|
||||
ui.horizontal_top(|ui| {
|
||||
StripBuilder::new(ui)
|
||||
@@ -532,6 +554,7 @@ impl AppWindow for WorldWindow {
|
||||
});
|
||||
});
|
||||
});
|
||||
self.state.save(ui);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user