Continue work on front panel refactor
This commit is contained in:
parent
8221544efb
commit
1ff2990f2e
984
Cargo.lock
generated
984
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -8,8 +8,8 @@ edition = "2021"
|
||||
[dependencies]
|
||||
bitflags = "2.3.3"
|
||||
device_query = "1.1.3"
|
||||
eframe = { version = "0.22.0", features = ["ron", "persistence"] }
|
||||
egui-modal = "0.2.4"
|
||||
eframe = { version = "0.25.0", features = ["ron", "persistence"] }
|
||||
egui-modal = "0.3.2"
|
||||
enum_dispatch = "0.3.12"
|
||||
env_logger = "0.10.0"
|
||||
ihex = "3.0.0"
|
||||
|
@ -1 +1,481 @@
|
||||
use std::path::Path;
|
||||
|
||||
use eframe::{
|
||||
egui::{self, TextureOptions, Ui, Widget, Id, Painter},
|
||||
epaint::{vec2, Pos2, Rect, TextureHandle, pos2, Color32},
|
||||
};
|
||||
|
||||
use self::switch::SwitchState;
|
||||
|
||||
pub mod led;
|
||||
pub mod switch;
|
||||
|
||||
|
||||
const NULL_UV: Rect = Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0));
|
||||
const NULL_TINT: Color32 = Color32::WHITE;
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
struct FrontpanelState {
|
||||
ad_sws: u16,
|
||||
power: bool,
|
||||
runstop: SwitchState,
|
||||
single_step: SwitchState,
|
||||
exam: SwitchState,
|
||||
dep: SwitchState,
|
||||
reset: SwitchState,
|
||||
prot: SwitchState,
|
||||
aux1: SwitchState,
|
||||
aux2: SwitchState,
|
||||
}
|
||||
|
||||
pub struct Frontpanel<'a> {
|
||||
id: Id,
|
||||
textures: &'a Textures,
|
||||
}
|
||||
|
||||
impl<'a> Frontpanel<'a> {
|
||||
pub fn new(id: Id, textures: &'a Textures) -> Self {
|
||||
Self {
|
||||
id,
|
||||
textures,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for Frontpanel<'_> {
|
||||
fn ui(self, ui: &mut Ui) -> egui::Response {
|
||||
let mut state: FrontpanelState = ui.data(|data| data.get_temp(self.id).unwrap_or_default());
|
||||
let sw_textures = switch::Textures::new(
|
||||
self.textures.sw_up.clone(),
|
||||
self.textures.sw_neut.clone(),
|
||||
self.textures.sw_down.clone(),
|
||||
);
|
||||
let led_textures =
|
||||
led::Textures::new(self.textures.led_on.clone(), self.textures.led_off.clone());
|
||||
let resp = ui.allocate_response(
|
||||
(800.0, 333.0).into(),
|
||||
egui::Sense {
|
||||
click: false,
|
||||
drag: false,
|
||||
focusable: false,
|
||||
},
|
||||
);
|
||||
let fp_rect = resp.rect;
|
||||
dbg!(fp_rect);
|
||||
let painter = Painter::new(ui.ctx().clone(), ui.layer_id(), ui.clip_rect().intersect(resp.rect));
|
||||
painter.image(self.textures.fp.id(), painter.clip_rect(), NULL_UV, NULL_TINT);
|
||||
let x_scale = painter.clip_rect().width() / 800.0;
|
||||
let y_scale = painter.clip_rect().height() / 333.0;
|
||||
for led in &LEDS {
|
||||
let mut pos = led.pos;
|
||||
pos.x *= x_scale;
|
||||
pos.y *= y_scale;
|
||||
pos += fp_rect.left_top().to_vec2();
|
||||
let led_data = 0xAAAA;
|
||||
let led_on = (led_data & led.mask) > 0;
|
||||
ui.allocate_ui_at_rect(
|
||||
Rect::from_center_size(pos, vec2(16.0, 16.0)),
|
||||
|ui| {
|
||||
ui.add(led::Led::new(led_on, &led_textures));
|
||||
},
|
||||
);
|
||||
};
|
||||
// 0: Power
|
||||
// 1..17: A/D left to right
|
||||
// 17..25: Action left to right
|
||||
for (i, switch) in SWITCHES.iter().enumerate() {
|
||||
let mut pos = switch.pos;
|
||||
pos.x *= x_scale;
|
||||
pos.y *= y_scale;
|
||||
pos += fp_rect.left_top().to_vec2();
|
||||
if i == 0 {
|
||||
ui.allocate_ui_at_rect(
|
||||
Rect::from_center_size(pos, vec2(32.0, 32.0)),
|
||||
|ui| {
|
||||
ui.add(switch::ToggleSwitch::new(&mut state.power, &sw_textures));
|
||||
},
|
||||
);
|
||||
}
|
||||
if (1..17).contains(&i) {
|
||||
let bit_mask = 1 << (16 - i);
|
||||
let mut sw_state = state.ad_sws & bit_mask > 0;
|
||||
ui.allocate_ui_at_rect(
|
||||
Rect::from_center_size(pos, vec2(32.0, 32.0)),
|
||||
|ui| {
|
||||
ui.add(switch::ToggleSwitch::new(&mut sw_state, &sw_textures));
|
||||
},
|
||||
);
|
||||
state.ad_sws = (state.ad_sws & !(bit_mask)) | ((sw_state as u16) << (16 - i));
|
||||
}
|
||||
if (17..25).contains(&i) {
|
||||
let state = match i {
|
||||
17 => &mut state.runstop,
|
||||
18 => &mut state.single_step,
|
||||
19 => &mut state.exam,
|
||||
20 => &mut state.dep,
|
||||
21 => &mut state.reset,
|
||||
22 => &mut state.prot,
|
||||
23 => &mut state.aux1,
|
||||
24 => &mut state.aux2,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
ui.allocate_ui_at_rect(
|
||||
Rect::from_center_size(pos, vec2(32.0, 32.0)),
|
||||
|ui| {
|
||||
ui.add(switch::ThreePosSwitch::new(state, &sw_textures));
|
||||
},
|
||||
);
|
||||
}
|
||||
// todo!();
|
||||
}
|
||||
ui.data_mut(|data| data.insert_temp(self.id, state));
|
||||
resp
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Textures {
|
||||
fp: TextureHandle,
|
||||
sw_up: TextureHandle,
|
||||
sw_neut: TextureHandle,
|
||||
sw_down: TextureHandle,
|
||||
led_off: TextureHandle,
|
||||
led_on: TextureHandle,
|
||||
}
|
||||
|
||||
impl Textures {
|
||||
pub fn new(ctx: &egui::Context) -> Self {
|
||||
Self {
|
||||
fp: Self::load_texture(
|
||||
ctx,
|
||||
"fp",
|
||||
"/home/pjht/projects/altair_emu/resources/altair800.png",
|
||||
)
|
||||
.unwrap(),
|
||||
sw_up: Self::load_texture(
|
||||
ctx,
|
||||
"sw_up",
|
||||
"/home/pjht/projects/altair_emu/resources/Togup.png",
|
||||
)
|
||||
.unwrap(),
|
||||
sw_neut: Self::load_texture(
|
||||
ctx,
|
||||
"sw_neut",
|
||||
"/home/pjht/projects/altair_emu/resources/Togneut.png",
|
||||
)
|
||||
.unwrap(),
|
||||
sw_down: Self::load_texture(
|
||||
ctx,
|
||||
"sw_down",
|
||||
"/home/pjht/projects/altair_emu/resources/Togdown.png",
|
||||
)
|
||||
.unwrap(),
|
||||
led_off: Self::load_texture(
|
||||
ctx,
|
||||
"led_off",
|
||||
"/home/pjht/projects/altair_emu/resources/Led_off.png",
|
||||
)
|
||||
.unwrap(),
|
||||
led_on: Self::load_texture(
|
||||
ctx,
|
||||
"led_on",
|
||||
"/home/pjht/projects/altair_emu/resources/Led_on.png",
|
||||
)
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn load_texture(
|
||||
ctx: &egui::Context,
|
||||
name: impl Into<String>,
|
||||
path: impl AsRef<Path>,
|
||||
) -> Result<TextureHandle, image::ImageError> {
|
||||
let image = image::io::Reader::open(path.as_ref())?.decode()?;
|
||||
let image = egui::ColorImage::from_rgba_unmultiplied(
|
||||
[image.width() as _, image.height() as _],
|
||||
image.to_rgba8().as_flat_samples().as_slice(),
|
||||
);
|
||||
Ok(ctx.load_texture(name, image, TextureOptions::LINEAR))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct SwitchInfo {
|
||||
pos: Pos2,
|
||||
}
|
||||
|
||||
static SWITCHES: [SwitchInfo; 25] = [
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(43.0, 234.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(183.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(228.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(257.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(285.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(330.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(359.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(388.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(433.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(461.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(491.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(536.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(564.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(593.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(638.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(667.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(696.0, 175.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(190.0, 234.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(248.0, 234.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(305.0, 234.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(363.0, 234.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(420.0, 234.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(478.0, 234.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(535.0, 234.0),
|
||||
},
|
||||
SwitchInfo {
|
||||
pos: Pos2::new(593.0, 234.0),
|
||||
},
|
||||
];
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum LedSource {
|
||||
Protect,
|
||||
Iff,
|
||||
Run,
|
||||
CpuStatus,
|
||||
Data,
|
||||
Address,
|
||||
}
|
||||
|
||||
struct LedInfo {
|
||||
pos: Pos2,
|
||||
source: LedSource,
|
||||
mask: u16,
|
||||
}
|
||||
|
||||
static LEDS: [LedInfo; 36] = [
|
||||
LedInfo {
|
||||
pos: Pos2::new(118.0, 58.0),
|
||||
source: LedSource::Protect,
|
||||
mask: 0xFF,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(89.0, 58.0),
|
||||
source: LedSource::Iff,
|
||||
mask: 0xFF,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(89.0, 117.0),
|
||||
source: LedSource::Run,
|
||||
mask: 0x0,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(118.0, 117.0),
|
||||
source: LedSource::Iff,
|
||||
mask: 0x0,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(149.0, 58.0),
|
||||
source: LedSource::CpuStatus,
|
||||
mask: 0x80,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(179.0, 58.0),
|
||||
source: LedSource::CpuStatus,
|
||||
mask: 0x40,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(209.0, 58.0),
|
||||
source: LedSource::CpuStatus,
|
||||
mask: 0x20,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(239.0, 58.0),
|
||||
source: LedSource::CpuStatus,
|
||||
mask: 0x10,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(269.0, 58.0),
|
||||
source: LedSource::CpuStatus,
|
||||
mask: 0x8,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(299.0, 58.0),
|
||||
source: LedSource::CpuStatus,
|
||||
mask: 0x4,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(329.0, 58.0),
|
||||
source: LedSource::CpuStatus,
|
||||
mask: 0x2,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(359.0, 58.0),
|
||||
source: LedSource::CpuStatus,
|
||||
mask: 0x1,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(461.0, 58.0),
|
||||
source: LedSource::Data,
|
||||
mask: 0x80,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(491.0, 58.0),
|
||||
source: LedSource::Data,
|
||||
mask: 0x40,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(536.0, 58.0),
|
||||
source: LedSource::Data,
|
||||
mask: 0x20,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(564.0, 58.0),
|
||||
source: LedSource::Data,
|
||||
mask: 0x10,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(593.0, 58.0),
|
||||
source: LedSource::Data,
|
||||
mask: 0x8,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(638.0, 58.0),
|
||||
source: LedSource::Data,
|
||||
mask: 0x4,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(667.0, 58.0),
|
||||
source: LedSource::Data,
|
||||
mask: 0x2,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(696.0, 58.0),
|
||||
source: LedSource::Data,
|
||||
mask: 0x1,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(182.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x8000,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(227.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x4000,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(256.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x2000,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(285.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x1000,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(330.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x800,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(359.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x400,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(388.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x200,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(433.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x100,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(461.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x80,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(490.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x40,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(536.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x20,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(564.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x10,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(593.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x8,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(638.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x4,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(667.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x2,
|
||||
},
|
||||
LedInfo {
|
||||
pos: Pos2::new(696.0, 117.0),
|
||||
source: LedSource::Address,
|
||||
mask: 0x1,
|
||||
},
|
||||
];
|
||||
|
54
src/frontpanel/led.rs
Normal file
54
src/frontpanel/led.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use eframe::{
|
||||
egui::{Sense, Widget},
|
||||
epaint::{pos2, vec2, Color32, Rect, TextureHandle},
|
||||
};
|
||||
|
||||
const NULL_UV: Rect = Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0));
|
||||
const NULL_TINT: Color32 = Color32::WHITE;
|
||||
|
||||
pub struct Textures {
|
||||
led_on: TextureHandle,
|
||||
led_off: TextureHandle,
|
||||
}
|
||||
|
||||
impl Textures {
|
||||
pub fn new(led_on: TextureHandle, led_off: TextureHandle) -> Self {
|
||||
Self { led_on, led_off }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Led<'a> {
|
||||
on: bool,
|
||||
textures: &'a Textures,
|
||||
}
|
||||
|
||||
impl<'a> Led<'a> {
|
||||
pub fn new(on: bool, textures: &'a Textures) -> Self {
|
||||
Self { on, textures }
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for Led<'_> {
|
||||
fn ui(self, ui: &mut eframe::egui::Ui) -> eframe::egui::Response {
|
||||
let (resp, painter) = ui.allocate_painter(
|
||||
(16.0, 16.0).into(),
|
||||
Sense {
|
||||
click: false,
|
||||
drag: false,
|
||||
focusable: false,
|
||||
},
|
||||
);
|
||||
let texture = if self.on {
|
||||
self.textures.led_on.id()
|
||||
} else {
|
||||
self.textures.led_off.id()
|
||||
};
|
||||
painter.image(
|
||||
texture,
|
||||
Rect::from_min_size(painter.clip_rect().left_top(), vec2(16.0, 16.0)),
|
||||
NULL_UV,
|
||||
NULL_TINT,
|
||||
);
|
||||
resp
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
use eframe::{
|
||||
egui::{Id, Sense, Widget},
|
||||
epaint::{pos2, vec2, Color32, Rect, TextureHandle},
|
||||
egui::{Sense, Widget},
|
||||
epaint::{pos2, vec2, Color32, Rect, TextureHandle, TextureId},
|
||||
};
|
||||
|
||||
const NULL_UV: Rect = Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0));
|
||||
@ -20,6 +20,22 @@ impl Textures {
|
||||
sw_down,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_for_state(&self, state: SwitchState) -> TextureId {
|
||||
match state {
|
||||
SwitchState::Up => self.sw_up.id(),
|
||||
SwitchState::Neut => self.sw_neut.id(),
|
||||
SwitchState::Down => self.sw_down.id(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_for_bool(&self, state: bool) -> TextureId {
|
||||
if state {
|
||||
self.sw_up.id()
|
||||
} else {
|
||||
self.sw_down.id()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
@ -29,51 +45,76 @@ pub enum SwitchState {
|
||||
Down,
|
||||
}
|
||||
|
||||
pub struct Switch<'a> {
|
||||
impl Default for SwitchState {
|
||||
fn default() -> Self {
|
||||
Self::Neut
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ThreePosSwitch<'a> {
|
||||
state: &'a mut SwitchState,
|
||||
textures: &'a Textures,
|
||||
}
|
||||
|
||||
impl<'a> Switch<'a> {
|
||||
impl<'a> ThreePosSwitch<'a> {
|
||||
pub fn new(state: &'a mut SwitchState, textures: &'a Textures) -> Self {
|
||||
Self { state, textures }
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for Switch<'_> {
|
||||
impl Widget for ThreePosSwitch<'_> {
|
||||
fn ui(self, ui: &mut eframe::egui::Ui) -> eframe::egui::Response {
|
||||
let (resp, painter) = ui.allocate_painter((32.0, 32.0).into(), Sense::click());
|
||||
let id = Id::new((
|
||||
painter.clip_rect().left_top().x as u32,
|
||||
painter.clip_rect().left_top().y as u32,
|
||||
));
|
||||
let texture = match self.state {
|
||||
SwitchState::Up => self.textures.sw_up.id(),
|
||||
SwitchState::Neut => self.textures.sw_neut.id(),
|
||||
SwitchState::Down => self.textures.sw_down.id(),
|
||||
};
|
||||
let (resp, painter) = ui.allocate_painter((32.0, 32.0).into(), Sense::drag());
|
||||
painter.image(
|
||||
texture,
|
||||
self.textures.get_for_state(*self.state),
|
||||
Rect::from_min_size(painter.clip_rect().left_top(), vec2(32.0, 32.0)),
|
||||
NULL_UV,
|
||||
NULL_TINT,
|
||||
);
|
||||
let pointer_state = ui.ctx().input(|inp| inp.pointer.clone());
|
||||
let interact_pos = pointer_state.interact_pos();
|
||||
dbg!(interact_pos);
|
||||
let interacted = interact_pos.map(|interact_pos| {
|
||||
Rect::from_center_size(interact_pos, (10.0, 24.0).into()).contains(painter.clip_rect().left_top())
|
||||
}).unwrap_or(false);
|
||||
let newstate = if interacted {
|
||||
if interact_pos.unwrap().y > painter.clip_rect().left_top().y {
|
||||
SwitchState::Down
|
||||
} else {
|
||||
SwitchState::Up
|
||||
if resp.drag_started() {
|
||||
let interact_pos = resp.interact_pointer_pos().unwrap();
|
||||
let sw_center = painter.clip_rect().left_top() + vec2(15.0, 16.0);
|
||||
if Rect::from_center_size(interact_pos, (10.0, 24.0).into()).contains(sw_center) {
|
||||
if interact_pos.y > sw_center.y {
|
||||
*self.state = SwitchState::Down;
|
||||
} else {
|
||||
*self.state = SwitchState::Up;
|
||||
};
|
||||
}
|
||||
} else {
|
||||
SwitchState::Neut
|
||||
};
|
||||
*self.state = newstate;
|
||||
} else if resp.drag_released() {
|
||||
*self.state = SwitchState::Neut;
|
||||
}
|
||||
resp
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ToggleSwitch<'a> {
|
||||
state: &'a mut bool,
|
||||
textures: &'a Textures,
|
||||
}
|
||||
|
||||
impl<'a> ToggleSwitch<'a> {
|
||||
pub fn new(state: &'a mut bool, textures: &'a Textures) -> Self {
|
||||
Self { state, textures }
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for ToggleSwitch<'_> {
|
||||
fn ui(self, ui: &mut eframe::egui::Ui) -> eframe::egui::Response {
|
||||
let (resp, painter) = ui.allocate_painter((32.0, 32.0).into(), Sense::drag());
|
||||
painter.image(
|
||||
self.textures.get_for_bool(*self.state),
|
||||
Rect::from_min_size(painter.clip_rect().left_top(), vec2(32.0, 32.0)),
|
||||
NULL_UV,
|
||||
NULL_TINT,
|
||||
);
|
||||
if resp.drag_started() {
|
||||
let interact_pos = resp.interact_pointer_pos().unwrap();
|
||||
let sw_center = painter.clip_rect().left_top() + vec2(15.0, 16.0);
|
||||
if Rect::from_center_size(interact_pos, (10.0, 24.0).into()).contains(sw_center) {
|
||||
*self.state = !*self.state;
|
||||
}
|
||||
}
|
||||
resp
|
||||
}
|
||||
}
|
||||
|
27
src/main.rs
27
src/main.rs
@ -11,9 +11,9 @@ use std::{
|
||||
};
|
||||
|
||||
use cpu::{MemCycle, Status, I8080};
|
||||
use device_query::{DeviceState, Keycode};
|
||||
use device_query::DeviceState;
|
||||
use eframe::{
|
||||
egui::{self, menu, Button, Pos2, Rect, TextureHandle, TextureOptions, Ui},
|
||||
egui::{self, menu, Button, Id, Label, Pos2, Rect, TextureHandle, TextureOptions, Ui},
|
||||
NativeOptions,
|
||||
};
|
||||
use egui_modal::Modal;
|
||||
@ -24,7 +24,7 @@ use rfd::FileDialog;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use soloud::{audio, AudioExt, LoadExt, Soloud};
|
||||
|
||||
use crate::frontpanel::switch;
|
||||
use crate::frontpanel::{switch, Frontpanel};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum AudioMessage {
|
||||
@ -182,7 +182,7 @@ struct Options {
|
||||
}
|
||||
|
||||
struct AltairEmulator {
|
||||
textures: Textures,
|
||||
textures: frontpanel::Textures,
|
||||
ad_sws: u16,
|
||||
power: bool,
|
||||
runstop: SwitchState,
|
||||
@ -253,7 +253,7 @@ impl AltairEmulator {
|
||||
// 20: 004
|
||||
// 21: 005
|
||||
Self {
|
||||
textures: Textures::new(&cc.egui_ctx),
|
||||
textures: frontpanel::Textures::new(&cc.egui_ctx),
|
||||
ad_sws: 0x0,
|
||||
power: false,
|
||||
runstop: SwitchState::Neut,
|
||||
@ -315,7 +315,7 @@ impl eframe::App for AltairEmulator {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
fn image_topleft(pos: impl Into<Pos2>, texture: &TextureHandle, ui: &mut Ui) {
|
||||
ui.allocate_ui_at_rect(Rect::from_min_size(pos.into(), texture.size_vec2()), |ui| {
|
||||
ui.image(texture, texture.size_vec2());
|
||||
ui.image(texture);
|
||||
});
|
||||
}
|
||||
|
||||
@ -323,13 +323,13 @@ impl eframe::App for AltairEmulator {
|
||||
ui.allocate_ui_at_rect(
|
||||
Rect::from_center_size(pos.into(), texture.size_vec2()),
|
||||
|ui| {
|
||||
ui.image(texture, texture.size_vec2());
|
||||
ui.image(texture);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
ctx.set_pixels_per_point(1.0);
|
||||
frame.set_window_size((800.0, 333.0).into());
|
||||
// frame.set_window_size((800.0, 333.0).into());
|
||||
let mut disable_fp_sws = self.option_window.is_some();
|
||||
egui::TopBottomPanel::top("menu").show(ctx, |ui| {
|
||||
menu::bar(ui, |ui| {
|
||||
@ -378,6 +378,11 @@ impl eframe::App for AltairEmulator {
|
||||
});
|
||||
});
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.add(Label::new("Hello"));
|
||||
ui.add(Frontpanel::new(Id::new("frontpanel"), &self.textures));
|
||||
ui.add(Frontpanel::new(Id::new("frontpanel2"), &self.textures));
|
||||
// dbg!(ui.input(|input| input.pointer.latest_pos()));
|
||||
// dbg!(ui.input(|input| input.pointer.latest_pos()));
|
||||
// let (_, fp_rect) = ui.allocate_space((800.0, 333.0).into());
|
||||
// image_topleft(fp_rect.left_top(), &self.textures.fp, ui);
|
||||
// for led in &LEDS {
|
||||
@ -728,12 +733,6 @@ impl eframe::App for AltairEmulator {
|
||||
// self.cpu.finish_m_cycle(data);
|
||||
// self.update_fp();
|
||||
// }
|
||||
let sw_texts = switch::Textures::new(
|
||||
self.textures.sw_up.clone(),
|
||||
self.textures.sw_neut.clone(),
|
||||
self.textures.sw_down.clone(),
|
||||
);
|
||||
ui.add(switch::Switch::new(&mut self.dep, &sw_texts));
|
||||
});
|
||||
|
||||
let old_fan_enabled = self.options.fan_enabled;
|
||||
|
Loading…
Reference in New Issue
Block a user