Work on card settings UI

This commit is contained in:
pjht 2024-02-07 11:18:38 -06:00
parent 235d3c3600
commit e322c4084c
Signed by: pjht
GPG Key ID: CA239FC6934E6F3A
3 changed files with 84 additions and 33 deletions

View File

@ -1,36 +1,11 @@
use anyhow::anyhow; use anyhow::anyhow;
use eframe::egui::Ui; use eframe::egui::Ui;
use serde::Deserialize;
#[derive(Deserialize, Debug)]
pub struct Config<'a> {
#[serde(rename = "type")]
typ: &'a str,
#[serde(flatten)]
settings: ron::Value,
}
impl Config<'_> {
pub fn to_card(&self) -> anyhow::Result<Box<dyn Card>> {
inventory::iter::<Type>
.into_iter()
.find(|card_type| card_type.name == self.typ)
.ok_or_else(|| anyhow!("Invalid card type {}", self.typ))?
.new_card(self.settings.clone())
}
pub fn to_settings_ui(&self) -> anyhow::Result<Box<dyn SettingsUi>> {
inventory::iter::<Type>
.into_iter()
.find(|card_type| card_type.name == self.typ)
.ok_or_else(|| anyhow!("Invalid card type {}", self.typ))?
.settings_ui(self.settings.clone())
}
}
pub struct Type { pub struct Type {
name: &'static str, name: &'static str,
new: fn(settings: ron::Value) -> anyhow::Result<Box<dyn Card>>, new: fn(settings: ron::Value) -> anyhow::Result<Box<dyn Card>>,
settings_ui: fn(settings: ron::Value) -> anyhow::Result<Box<dyn SettingsUi>>, settings_ui: fn(settings: ron::Value) -> anyhow::Result<Box<dyn SettingsUi>>,
default_settings: fn() -> String,
} }
impl Type { impl Type {
@ -39,16 +14,32 @@ impl Type {
name, name,
new: T::new_dyn, new: T::new_dyn,
settings_ui: T::settings_ui_dyn, settings_ui: T::settings_ui_dyn,
default_settings: T::default_settings,
} }
} }
fn new_card(&self, settings: ron::Value) -> anyhow::Result<Box<dyn Card>> { pub fn new_card(&self, settings: ron::Value) -> anyhow::Result<Box<dyn Card>> {
(self.new)(settings) (self.new)(settings)
} }
fn settings_ui(&self, settings: ron::Value) -> anyhow::Result<Box<dyn SettingsUi>> { pub fn settings_ui(&self, settings: ron::Value) -> anyhow::Result<Box<dyn SettingsUi>> {
(self.settings_ui)(settings) (self.settings_ui)(settings)
} }
pub fn default_settings(&self) -> String {
(self.default_settings)()
}
pub fn get(name: &str) -> anyhow::Result<&'static Self> {
inventory::iter::<Type>
.into_iter()
.find(|card_type| card_type.name == name)
.ok_or_else(|| anyhow!("Invalid card type {}", name))
}
pub fn name(&self) -> &'static str {
self.name
}
} }
inventory::collect!(Type); inventory::collect!(Type);
@ -66,6 +57,10 @@ pub trait Card {
Ok(Box::new(card)) Ok(Box::new(card))
} }
fn default_settings() -> String
where
Self: Sized;
fn read_mem(&mut self, _address: u16) -> Option<u8> { fn read_mem(&mut self, _address: u16) -> Option<u8> {
None None
} }

View File

@ -1,11 +1,23 @@
use eframe::egui::{self, Slider}; use eframe::{
egui::{
self, CentralPanel, DragValue, Layout, Margin, SidePanel, Slider, Style, TopBottomPanel,
},
emath::Align,
};
use egui_modal::Modal; use egui_modal::Modal;
use crate::{state::EmuState, window::Window, Options}; use crate::{
card::{SettingsUi, Type},
state::EmuState,
window::Window,
Options,
};
pub struct OptionWindow { pub struct OptionWindow {
options: Options, options: Options,
category: OptionsCategory, category: OptionsCategory,
card_options: Vec<(&'static str, Box<dyn SettingsUi>)>,
select_idx: Option<usize>,
} }
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
@ -17,9 +29,17 @@ 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 ramcard_type = Type::get("RAM card").unwrap();
let def_opts = ramcard_type.default_settings();
let settings_ui = ramcard_type
.settings_ui(ron::from_str(&def_opts).unwrap())
.unwrap();
let card_options = vec![(ramcard_type.name(), settings_ui)];
Self { Self {
options: state.options(), options: state.options(),
category: OptionsCategory::General, category: OptionsCategory::General,
card_options,
select_idx: Some(0),
} }
} }
} }
@ -38,12 +58,37 @@ impl Window for OptionWindow {
ui.checkbox(&mut self.options.mute, "Mute"); ui.checkbox(&mut self.options.mute, "Mute");
ui.checkbox(&mut self.options.fan_enabled, "Fan enabled"); ui.checkbox(&mut self.options.fan_enabled, "Fan enabled");
ui.add(Slider::new(&mut self.options.volume, 0.0..=100.0).text("Volume")); ui.add(Slider::new(&mut self.options.volume, 0.0..=100.0).text("Volume"));
ui.separator();
} }
OptionsCategory::Cards => { OptionsCategory::Cards => {
ui.heading("TODO"); TopBottomPanel::top("card_opts").show_inside(ui, |ui| {
SidePanel::left("card_opts_left")
.show_separator_line(false)
.show_inside(ui, |ui| {
let frame =
egui::Frame::canvas(&Style::default()).outer_margin(Margin {
left: 0.0,
right: 0.0,
top: 0.0,
bottom: 10.0,
});
frame.show(ui, |ui| {
for (i, (name, _settings_ui)) in
self.card_options.iter().enumerate()
{
ui.selectable_value(&mut self.select_idx, Some(i), *name);
}
});
});
CentralPanel::default().show_inside(ui, |ui| {
if let Some(select_idx) = self.select_idx {
self.card_options[select_idx].1.draw_ui(ui);
};
});
});
} }
} }
modal.buttons(ui, |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); state.update_options(self.options);
} }

View File

@ -1,7 +1,10 @@
use eframe::egui::{DragValue, Ui}; use eframe::egui::{DragValue, Ui};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{card::{Card, SettingsUi}, register}; use crate::{
card::{Card, SettingsUi},
register,
};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct RamCardSettings { pub struct RamCardSettings {
@ -47,6 +50,14 @@ impl Card for RamCard {
Some(()) Some(())
} }
fn default_settings() -> String {
ron::to_string(&RamCardSettings {
size: 4096,
start_addr: 0,
})
.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,