Persist cards
This commit is contained in:
parent
a13ae3ba77
commit
f45583892b
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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");
|
||||||
});
|
});
|
||||||
|
@ -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,
|
||||||
|
25
src/state.rs
25
src/state.rs
@ -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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user