use crate::*;
use eframe::egui;
use log::info;
pub fn run_single_plane_sim<T>(logic: T)
where
T: PedalMapper<Pedals = ThreePedals> + ActionLogic<false> + 'static,
{
run_sim(logic);
}
pub fn run_double_plane_sim<T>(logic: T)
where
T: PedalMapper<Pedals = SixPedals> + ActionLogic<true> + 'static,
{
run_sim(logic);
}
fn run_sim<const IS_TWO_PLANE: bool, PEDALS, T>(logic: T)
where
T: PedalMapper<Pedals = PEDALS> + ActionLogic<IS_TWO_PLANE> + 'static,
PEDALS: Pedals + 'static,
{
let native_options = eframe::NativeOptions::default();
eframe::run_native(
"X-Ray Simulator",
native_options,
Box::new(|cc| Box::new(Simulator::<IS_TWO_PLANE, PEDALS, T>::new(cc, logic))),
);
}
struct Simulator<const IS_TWO_PLANE: bool, PEDALS: Pedals, T>
where
T: PedalMapper<Pedals = PEDALS> + ActionLogic<IS_TWO_PLANE>,
{
logic: T,
controller: Controller<IS_TWO_PLANE>,
pedal_states: PEDALS::STATES,
}
impl<const IS_TWO_PLANE: bool, PEDALS: Pedals, T> Simulator<IS_TWO_PLANE, PEDALS, T>
where
T: PedalMapper<Pedals = PEDALS> + ActionLogic<IS_TWO_PLANE>,
{
fn new(_cc: &eframe::CreationContext, logic: T) -> Self {
Self {
logic,
controller: Controller {
frontal: Plane::frontal(),
lateral: Plane::lateral(),
},
pedal_states: PEDALS::STATES::default(),
}
}
}
impl<const IS_TWO_PLANE: bool, PEDALS: Pedals, T> eframe::App for Simulator<IS_TWO_PLANE, PEDALS, T>
where
T: PedalMapper<Pedals = PEDALS> + ActionLogic<IS_TWO_PLANE>,
{
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::SidePanel::right("right_panel").show(ctx, |ui| {
indicators(ui, &self.controller.frontal);
if IS_TWO_PLANE {
ui.separator();
indicators(ui, &self.controller.lateral);
}
});
egui::CentralPanel::default().show(ctx, |ui| {
let mut queue = Vec::new();
for (index, &pedal_enum) in PEDALS::variants().iter().enumerate() {
let pedal = &mut self.pedal_states[index];
let label = format!("{pedal_enum:?}");
if ui.checkbox(pedal, &label).changed() {
if *pedal {
info!("{label} was pressed");
if let Some(request) = self.logic.on_press(pedal_enum) {
queue.push(request);
}
} else {
info!("{label} was released");
if let Some(request) = self.logic.on_release(pedal_enum) {
queue.push(request);
}
}
}
}
for request in queue {
self.logic.handle_request(request, &mut self.controller);
}
});
}
}
fn indicators(ui: &mut egui::Ui, plane: &Plane) {
ui.heading(format!("{:?} Plane", plane.projection()));
ui.horizontal(|ui| {
if plane.active() {
ui.strong("Active");
ui.spinner();
} else {
ui.weak("Inactive");
}
});
ui.horizontal(|ui| {
ui.label("Dose");
let (low, high) = ("Low", "High");
match plane.dose() {
Dose::Low => {
ui.strong(low);
ui.weak(high)
}
Dose::High => {
ui.weak(low);
ui.strong(high)
}
};
});
ui.horizontal(|ui| {
ui.label("Mode");
let (video, image) = ("Video", "Image");
match plane.mode() {
Mode::Video => {
ui.strong(video);
ui.weak(image)
}
Mode::Image => {
ui.weak(video);
ui.strong(image)
}
};
});
}