Persist cards

This commit is contained in:
pjht 2024-02-08 08:40:24 -06:00
parent a13ae3ba77
commit f45583892b
Signed by: pjht
GPG Key ID: 7B5F6AFBEC7EE78E
5 changed files with 53 additions and 9 deletions

View File

@ -74,6 +74,8 @@ pub trait Card {
None
}
fn get_settings(&self) -> String;
fn settings_ui(_settings: ron::Value) -> anyhow::Result<impl SettingsUi>
where
Self: Sized;

View File

@ -65,9 +65,14 @@ impl AltairEmulator {
} else {
eframe::get_value(cc.storage.unwrap(), "options").unwrap()
};
let cards = if cc.storage.unwrap().get_string("cards").is_none() {
Vec::new()
} else {
eframe::get_value(cc.storage.unwrap(), "cards").unwrap()
};
Self {
textures: Textures::new(&cc.egui_ctx),
state: EmuState::new(audio_tx, options),
state: EmuState::new(audio_tx, options, cards),
windows: HashMap::new(),
}
}
@ -117,6 +122,7 @@ impl AltairEmulator {
impl eframe::App for AltairEmulator {
fn save(&mut self, storage: &mut dyn eframe::Storage) {
eframe::set_value(storage, "options", &self.state.options());
eframe::set_value(storage, "cards", &self.state.save_cards());
}
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
ctx.set_pixels_per_point(1.0);

View File

@ -17,7 +17,7 @@ use crate::{
pub struct OptionWindow {
options: Options,
category: OptionsCategory,
card_options: Vec<(&'static str, Box<dyn SettingsUi>)>,
card_options: Vec<(&'static Type, Box<dyn SettingsUi>)>,
select_idx: Option<usize>,
}
@ -30,7 +30,7 @@ enum OptionsCategory {
impl OptionWindow {
pub fn new(ctx: &egui::Context, state: &EmuState) -> Self {
Modal::new(ctx, "options_modal").open();
let card_options = Vec::new();
let card_options: Vec<_> = state.cards().iter().map(|(typ, card)| (*typ, typ.settings_ui(ron::from_str(&card.get_settings()).unwrap()).unwrap())).collect();
let select_idx = if card_options.is_empty() {
None
} else {
@ -43,6 +43,12 @@ impl OptionWindow {
select_idx,
}
}
fn sync_settings(&self, state: &mut EmuState) {
state.update_options(self.options);
let cards = self.card_options.iter().map(|(typ, settings_ui)| (*typ, typ.new_card(ron::from_str(&settings_ui.serialize_settings()).unwrap()).unwrap())).collect();
state.set_cards(cards);
}
}
impl Window for OptionWindow {
@ -75,11 +81,11 @@ impl Window for OptionWindow {
});
let mut delete_idx = None;
frame.show(ui, |ui| {
for (i, (name, _settings_ui)) in
for (i, (typ, _settings_ui)) in
self.card_options.iter().enumerate()
{
ui.horizontal(|ui| {
ui.selectable_value(&mut self.select_idx, Some(i), *name);
ui.selectable_value(&mut self.select_idx, Some(i), typ.name());
if ui.button("-").clicked() {
delete_idx = Some(i);
}
@ -107,7 +113,7 @@ impl Window for OptionWindow {
.clicked()
{
self.card_options.push((
typ.name(),
typ,
typ.settings_ui(
ron::from_str(&typ.default_settings())
.unwrap(),
@ -131,10 +137,10 @@ impl Window for OptionWindow {
}
ui.with_layout(Layout::right_to_left(Align::Min), |ui| {
if ui.button("Apply").clicked() {
state.update_options(self.options);
self.sync_settings(state);
}
if modal.button(ui, "OK").clicked() {
state.update_options(self.options);
self.sync_settings(state);
}
modal.caution_button(ui, "Cancel");
});

View File

@ -58,6 +58,13 @@ impl Card for RamCard {
.unwrap()
}
fn get_settings(&self) -> String {
ron::to_string(&RamCardSettings {
size: self.ram.len() as u16,
start_addr: self.start_addr,
}).unwrap()
}
fn settings_ui(settings: ron::Value) -> anyhow::Result<impl SettingsUi>
where
Self: Sized,

View File

@ -4,6 +4,7 @@ use rand::RngCore;
use crate::{
audio::AudioMessage,
card::{Card, Type},
cpu::{MemCycle, Status, I8080},
frontpanel::{switch::SwitchState, ActionSwitch, FrontpanelInteraction, FrontpanelState},
Options,
@ -16,12 +17,21 @@ pub struct EmuState {
audio_tx: Sender<AudioMessage>,
options: Options,
fp_state: FrontpanelState,
cards: Vec<(&'static Type, Box<dyn Card>)>,
}
impl EmuState {
pub fn new(audio_tx: Sender<AudioMessage>, options: Options) -> Self {
pub fn new(
audio_tx: Sender<AudioMessage>,
options: Options,
cards: Vec<(String, String)>,
) -> Self {
let mut mem = [0; 65536];
rand::thread_rng().fill_bytes(&mut mem);
let cards = cards.iter().map(|(typ_name, settings)| {
let typ = Type::get(&typ_name).unwrap();
(typ, typ.new_card(ron::from_str(&settings).unwrap()).unwrap())
}).collect();
let mut slf = Self {
mem,
cpu: I8080::new(),
@ -29,6 +39,7 @@ impl EmuState {
audio_tx,
options,
fp_state: FrontpanelState::default(),
cards,
};
slf.apply_options();
slf
@ -191,4 +202,16 @@ impl EmuState {
pub fn running(&self) -> bool {
self.running
}
pub fn cards(&self) -> &[(&'static Type, Box<dyn Card>)] {
self.cards.as_ref()
}
pub fn set_cards(&mut self, cards: Vec<(&'static Type, Box<dyn Card>)>) {
self.cards = cards;
}
pub fn save_cards(&self) -> Vec<(String, String)> {
self.cards.iter().map(|(typ, card)| (typ.name().to_string(), card.get_settings())).collect()
}
}