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 None
} }
fn get_settings(&self) -> String;
fn settings_ui(_settings: ron::Value) -> anyhow::Result<impl SettingsUi> fn settings_ui(_settings: ron::Value) -> anyhow::Result<impl SettingsUi>
where where
Self: Sized; Self: Sized;

View File

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

View File

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

View File

@ -58,6 +58,13 @@ impl Card for RamCard {
.unwrap() .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> fn settings_ui(settings: ron::Value) -> anyhow::Result<impl SettingsUi>
where where
Self: Sized, Self: Sized,

View File

@ -4,6 +4,7 @@ use rand::RngCore;
use crate::{ use crate::{
audio::AudioMessage, audio::AudioMessage,
card::{Card, Type},
cpu::{MemCycle, Status, I8080}, cpu::{MemCycle, Status, I8080},
frontpanel::{switch::SwitchState, ActionSwitch, FrontpanelInteraction, FrontpanelState}, frontpanel::{switch::SwitchState, ActionSwitch, FrontpanelInteraction, FrontpanelState},
Options, Options,
@ -16,12 +17,21 @@ pub struct EmuState {
audio_tx: Sender<AudioMessage>, audio_tx: Sender<AudioMessage>,
options: Options, options: Options,
fp_state: FrontpanelState, fp_state: FrontpanelState,
cards: Vec<(&'static Type, Box<dyn Card>)>,
} }
impl EmuState { 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]; let mut mem = [0; 65536];
rand::thread_rng().fill_bytes(&mut mem); 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 { let mut slf = Self {
mem, mem,
cpu: I8080::new(), cpu: I8080::new(),
@ -29,6 +39,7 @@ impl EmuState {
audio_tx, audio_tx,
options, options,
fp_state: FrontpanelState::default(), fp_state: FrontpanelState::default(),
cards,
}; };
slf.apply_options(); slf.apply_options();
slf slf
@ -191,4 +202,16 @@ impl EmuState {
pub fn running(&self) -> bool { pub fn running(&self) -> bool {
self.running 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()
}
} }