diff --git a/src/audio.rs b/src/audio.rs index 362ea4f..26c3a0a 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -49,14 +49,6 @@ enum FanState { } impl FanState { - /// Returns `true` if the fan state is [`Off`]. - /// - /// [`Off`]: FanState::Off - #[must_use] - fn is_off(&self) -> bool { - matches!(self, Self::Off) - } - /// Returns `true` if the fan state is [`Starting`]. /// /// [`Starting`]: FanState::Starting @@ -72,14 +64,6 @@ impl FanState { fn is_on(&self) -> bool { matches!(self, Self::On) } - - /// Returns `true` if the fan state is [`Stopping`]. - /// - /// [`Stopping`]: FanState::Stopping - #[must_use] - fn is_stopping(&self) -> bool { - matches!(self, Self::Stopping { .. }) - } } impl AudioThread { diff --git a/src/frontpanel.rs b/src/frontpanel.rs index 8c1d0c3..c230916 100644 --- a/src/frontpanel.rs +++ b/src/frontpanel.rs @@ -1,7 +1,7 @@ use std::path::Path; use eframe::{ - egui::{self, Sense, TextureOptions, Ui, Widget}, + egui::{self, KeyboardShortcut, Modifiers, Sense, TextureOptions, Ui, Widget, Key}, epaint::{vec2, Pos2, Rect, TextureHandle}, }; @@ -26,7 +26,7 @@ pub enum ActionSwitch { #[derive(Clone, Copy, Debug)] pub enum FrontpanelInteraction { - ActionSwClicked(ActionSwitch, SwitchState), + ActionSwChanged(ActionSwitch, SwitchState), AdChanged(u16), PowerChanged(bool), } @@ -119,12 +119,9 @@ impl Widget for &mut Frontpanel<'_> { led::Textures::new(self.textures.led_on.clone(), self.textures.led_off.clone()); let resp = ui.allocate_response( vec2(800.0, 333.0), - Sense { - click: false, - drag: false, - focusable: false, - }, + Sense::click(), ); + resp.request_focus(); let fp_rect = resp.rect; ui.allocate_ui_at_rect(fp_rect, |ui| { ui.image(&self.textures.fp); @@ -152,8 +149,12 @@ impl Widget for &mut Frontpanel<'_> { ui.allocate_ui_at_rect(Rect::from_center_size(pos, vec2(11.0, 25.0)), |ui| { let mut power_inv = !self.state.power; if ui - .add(switch::ToggleSwitch::new(&mut power_inv, &sw_textures)) - .drag_started() + .add(switch::ToggleSwitch::new( + &mut power_inv, + &sw_textures, + Some(KeyboardShortcut::new(Modifiers::NONE, Key::Q)), + )) + .changed() { self.state.power = !power_inv; self.interaction = @@ -165,9 +166,18 @@ impl Widget for &mut Frontpanel<'_> { let bit_mask = 1 << (16 - i); let mut sw_state = self.state.ad_sws & bit_mask > 0; ui.allocate_ui_at_rect(Rect::from_center_size(pos, vec2(11.0, 25.0)), |ui| { + let key_offset = (i - 1) % 8; + let key = (b'1' + key_offset as u8) as char; + let key = Key::from_name(&key.to_string()).unwrap(); + let mods = if (i - 1) >= 8 { + Modifiers::SHIFT + } else { + Modifiers::NONE + }; + let shortcut = KeyboardShortcut::new(mods, key); if ui - .add(switch::ToggleSwitch::new(&mut sw_state, &sw_textures)) - .drag_started() + .add(switch::ToggleSwitch::new(&mut sw_state, &sw_textures, Some(shortcut))) + .changed() { self.state.ad_sws = (self.state.ad_sws & !(bit_mask)) | ((sw_state as u16) << (16 - i)); @@ -189,9 +199,16 @@ impl Widget for &mut Frontpanel<'_> { _ => unreachable!(), }; ui.allocate_ui_at_rect(Rect::from_center_size(pos, vec2(11.0, 25.0)), |ui| { + let sw_offset = i - 17; + let up_key = ["W", "E", "R", "T", "Y", "U", "I", "O"][sw_offset]; + let down_key = ["S", "D", "F", "G", "H", "J", "K", "L"][sw_offset]; + let up_key = Key::from_name(up_key).unwrap(); + let down_key = Key::from_name(down_key).unwrap(); + let up_shortcut = KeyboardShortcut::new(Modifiers::NONE, up_key); + let down_shortcut = KeyboardShortcut::new(Modifiers::NONE, down_key); if ui - .add(switch::ThreePosSwitch::new(state, &sw_textures)) - .drag_started() + .add(switch::ThreePosSwitch::new(state, &sw_textures, Some(up_shortcut), Some(down_shortcut))) + .changed() { let sw = match i { 17 => ActionSwitch::RunStop, @@ -205,12 +222,15 @@ impl Widget for &mut Frontpanel<'_> { _ => unreachable!(), }; self.interaction = - Some(FrontpanelInteraction::ActionSwClicked(sw, *state)); + Some(FrontpanelInteraction::ActionSwChanged(sw, *state)); }; }); } } }); + // if ui.input_mut(|input| input.consume_shortcut(&KeyboardShortcut::new(Modifiers::NONE, Key::Q))) { + // dbg!(); + // } resp } } diff --git a/src/frontpanel/switch.rs b/src/frontpanel/switch.rs index b176e39..59bf3a0 100644 --- a/src/frontpanel/switch.rs +++ b/src/frontpanel/switch.rs @@ -1,5 +1,5 @@ use eframe::{ - egui::{Sense, Widget}, + egui::{KeyboardShortcut, Sense, Widget}, epaint::{pos2, vec2, Color32, Rect, TextureHandle, TextureId}, }; @@ -54,11 +54,13 @@ impl Default for SwitchState { pub struct ThreePosSwitch<'a> { state: &'a mut SwitchState, textures: &'a Textures, + up_shortcut: Option, + down_shortcut: Option, } impl<'a> ThreePosSwitch<'a> { - pub fn new(state: &'a mut SwitchState, textures: &'a Textures) -> Self { - Self { state, textures } + pub fn new(state: &'a mut SwitchState, textures: &'a Textures, up_shortcut: Option, down_shortcut: Option) -> Self { + Self { state, textures, up_shortcut, down_shortcut } } } @@ -71,6 +73,18 @@ impl Widget for ThreePosSwitch<'_> { NULL_UV, NULL_TINT, ); + let up_shortcut_pressed = self.up_shortcut.map_or(false, |shortcut| { + ui.input_mut(|input| input.key_pressed(shortcut.logical_key) && shortcut.modifiers == input.modifiers) + }); + let down_shortcut_pressed = self.down_shortcut.map_or(false, |shortcut| { + ui.input_mut(|input| input.key_pressed(shortcut.logical_key) && shortcut.modifiers == input.modifiers) + }); + let up_shortcut_released = self.up_shortcut.map_or(false, |shortcut| { + ui.input_mut(|input| input.key_released(shortcut.logical_key) && shortcut.modifiers == input.modifiers) + }); + let down_shortcut_released = self.down_shortcut.map_or(false, |shortcut| { + ui.input_mut(|input| input.key_released(shortcut.logical_key) && shortcut.modifiers == input.modifiers) + }); if resp.drag_started() { let interact_pos = resp.interact_pointer_pos().unwrap(); let sw_center = painter.clip_rect().left_top() + vec2(5.0, 12.0); @@ -80,7 +94,17 @@ impl Widget for ThreePosSwitch<'_> { *self.state = SwitchState::Up; }; resp.mark_changed(); - } else if resp.drag_released() { + } else if up_shortcut_pressed { + *self.state = SwitchState::Up; + resp.mark_changed(); + } else if down_shortcut_pressed { + *self.state = SwitchState::Down; + resp.mark_changed(); + } else if resp.drag_released() || up_shortcut_released || down_shortcut_released { + *self.state = SwitchState::Neut; + resp.mark_changed(); + } + if *self.state != SwitchState::Neut && !resp.dragged() && ui.input(|input| input.keys_down.is_empty()) { *self.state = SwitchState::Neut; resp.mark_changed(); } @@ -91,11 +115,20 @@ impl Widget for ThreePosSwitch<'_> { pub struct ToggleSwitch<'a> { state: &'a mut bool, textures: &'a Textures, + press_shortcut: Option, } impl<'a> ToggleSwitch<'a> { - pub fn new(state: &'a mut bool, textures: &'a Textures) -> Self { - Self { state, textures } + pub fn new( + state: &'a mut bool, + textures: &'a Textures, + press_shortcut: Option, + ) -> Self { + Self { + state, + textures, + press_shortcut, + } } } @@ -108,7 +141,10 @@ impl Widget for ToggleSwitch<'_> { NULL_UV, NULL_TINT, ); - if resp.drag_started() { + let shortcut_pressed = self.press_shortcut.map_or(false, |press_shortcut| { + ui.input_mut(|input| input.consume_shortcut(&press_shortcut)) + }); + if resp.drag_started() || shortcut_pressed { *self.state = !*self.state; resp.mark_changed(); } diff --git a/src/main.rs b/src/main.rs index e00bd84..cd2cd28 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,16 +4,16 @@ mod cpu; mod frontpanel; mod ram; -use std::{path::Path, sync::mpsc::Sender}; +use std::sync::mpsc::Sender; use audio::{AudioMessage, AudioThread}; use cpu::{MemCycle, Status, I8080}; -use device_query::DeviceState; use eframe::{ - egui::{self, menu, Button, Label, TextureHandle, TextureOptions}, + egui::{self, menu, Button}, NativeOptions, }; use egui_modal::Modal; +use frontpanel::Textures; use rand::RngCore; use rfd::FileDialog; use serde::{Deserialize, Serialize}; @@ -36,16 +36,13 @@ struct Options { } struct AltairEmulator { - textures: frontpanel::Textures, + textures: Textures, mem: [u8; 65536], cpu: I8080, running: bool, audio_tx: Sender, options: Options, option_window: Option, - device_state: DeviceState, - kbd_newdown: bool, - kbd_olddown: bool, fp_state: FrontpanelState, } @@ -88,16 +85,13 @@ impl AltairEmulator { // 20: 004 // 21: 005 Self { - textures: frontpanel::Textures::new(&cc.egui_ctx), + textures: Textures::new(&cc.egui_ctx), mem, cpu, running: false, audio_tx, options, option_window: None, - device_state: DeviceState::new(), - kbd_newdown: false, - kbd_olddown: false, fp_state: FrontpanelState::new(), } } @@ -210,18 +204,22 @@ impl eframe::App for AltairEmulator { if let Some(interaction) = interaction { self.audio_tx.send(AudioMessage::PlaySwitchClick).unwrap(); match interaction { - FrontpanelInteraction::ActionSwClicked(sw, state) => { + FrontpanelInteraction::ActionSwChanged(sw, state) => { if self.fp_state.power() { match sw { frontpanel::ActionSwitch::RunStop => { if state == SwitchState::Up { + println!("STOP RUN"); self.running = false; - } else { + } else if state == SwitchState::Down { + println!("START RUN"); self.running = true; } } frontpanel::ActionSwitch::SingleStep => { - self.run_cpu_cycle(); + if state == SwitchState::Up { + self.run_cpu_cycle(); + } } frontpanel::ActionSwitch::Examine => { if state == SwitchState::Up { @@ -231,7 +229,7 @@ impl eframe::App for AltairEmulator { self.cpu .finish_m_cycle((self.fp_state.ad_sws() >> 8) as u8); self.update_fp(); - } else { + } else if state == SwitchState::Down { // Assume M1 self.cpu.finish_m_cycle(0x0); // NOP self.update_fp(); @@ -243,7 +241,7 @@ impl eframe::App for AltairEmulator { self.mem[self.cpu.get_mem_cycle().address() as usize] = self.fp_state.ad_sws() as u8; self.update_fp(); - } else { + } else if state == SwitchState::Down { // Assume M1 self.cpu.finish_m_cycle(0x0); // NOP self.mem[self.cpu.get_mem_cycle().address() as usize] = @@ -282,358 +280,6 @@ impl eframe::App for AltairEmulator { if self.running { self.run_cpu_cycle(); } - // 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 { - // let led_data = match led.source { - // LedSource::Protect => 0x0, - // LedSource::Iff => 0x0, - // LedSource::Run => 0x0, - // LedSource::CpuStatus => u16::from(self.fp_status.bits()), - // LedSource::Data => u16::from(self.fp_data), - // LedSource::Address => self.fp_address, - // }; - // let led_on = (led_data & led.mask) > 0; - // let texture = if led_on { - // &self.textures.led_on - // } else { - // &self.textures.led_off - // }; - // image_center(led.pos + fp_rect.left_top().to_vec2(), texture, ui); - // } - // let pointer_state = ctx.input(|inp| inp.pointer.clone()); - // let interact_pos = pointer_state.interact_pos(); - // let mut switch_clicked = false; - // fn bool_to_texture(state: bool, textures: &Textures) -> &TextureHandle { - // if state { - // &textures.sw_up - // } else { - // &textures.sw_down - // } - // } - // fn state_to_texture(state: SwitchState, textures: &Textures) -> &TextureHandle { - // match state { - // SwitchState::Up => &textures.sw_up, - // SwitchState::Neut => &textures.sw_neut, - // SwitchState::Down => &textures.sw_down, - // } - // } - // for (i, switch) in SWITCHES.iter().enumerate() { - // let pos = switch.pos + fp_rect.left_top().to_vec2(); - // let texture = match i { - // 0 => bool_to_texture(!self.power, &self.textures), - // (1..=16) => { - // bool_to_texture((self.ad_sws & (1 << (16 - i))) > 0, &self.textures) - // } - // 17 => state_to_texture(self.runstop, &self.textures), - // 18 => state_to_texture(self.single_step, &self.textures), - // 19 => state_to_texture(self.exam, &self.textures), - // 20 => state_to_texture(self.dep, &self.textures), - // 21 => state_to_texture(self.reset, &self.textures), - // 22 => state_to_texture(self.prot, &self.textures), - // 23 => state_to_texture(self.aux1, &self.textures), - // 24 => state_to_texture(self.aux2, &self.textures), - // _ => unreachable!(), - // }; - // image_center(pos, texture, ui); - // let interacted = interact_pos.map(|interact_pos| { - // Rect::from_center_size(interact_pos, (10.0, 24.0).into()).contains(pos) - // && !disable_fp_sws - // }); - // if pointer_state.primary_clicked() && interacted.unwrap() { - // match i { - // 0 => { - // switch_clicked = true; - // self.power = !self.power; - // if self.options.fan_enabled { - // self.fan_audio_tx.send(self.power).unwrap(); - // } - // if self.power { - // self.cpu = I8080::new(); - // self.update_fp(); - // } else { - // self.running = false; - // self.fp_status = Status::empty(); - // self.fp_data = 0; - // self.fp_address = 0; - // } - // } - // (1..=16) => { - // switch_clicked = true; - // if (self.ad_sws & (1 << (16 - i))) > 0 { - // self.ad_sws &= !(1 << (16 - i)); - // } else { - // self.ad_sws |= 1 << (16 - i); - // } - // } - // _ => (), - // } - // } - // if pointer_state.primary_down() && interacted.unwrap() { - // if (17..=24).contains(&i) && self.mouse_newdown { - // switch_clicked = true; - // } - // let newstate = if interact_pos.unwrap().y > pos.y { - // SwitchState::Down - // } else { - // SwitchState::Up - // }; - // match i { - // 17 => self.runstop = newstate, - // 18 => self.single_step = newstate, - // 19 => self.exam = newstate, - // 20 => self.dep = newstate, - // 21 => self.reset = newstate, - // 22 => self.prot = newstate, - // 23 => self.aux1 = newstate, - // 24 => self.aux2 = newstate, - // _ => (), - // } - // } else { - // match i { - // 17 => self.runstop = SwitchState::Neut, - // 18 => self.single_step = SwitchState::Neut, - // 19 => self.exam = SwitchState::Neut, - // 20 => self.dep = SwitchState::Neut, - // 21 => self.reset = SwitchState::Neut, - // 22 => self.prot = SwitchState::Neut, - // 23 => self.aux1 = SwitchState::Neut, - // 24 => self.aux2 = SwitchState::Neut, - // _ => (), - // } - // } - // } - // if !disable_fp_sws { - // let mut kbd_ad = None; - // let pressed_keys = self.device_state.query_keymap(); - // if pressed_keys - // .iter() - // .filter(|&&k| k != Keycode::LShift && k != Keycode::RShift) - // .count() - // != 0 - // { - // if self.kbd_newdown { - // self.kbd_olddown = true; - // self.kbd_newdown = false; - // } else if !self.kbd_newdown && !self.kbd_olddown { - // self.kbd_newdown = true; - // } - // } else { - // self.kbd_newdown = false; - // self.kbd_olddown = false; - // } - // if self.kbd_newdown { - // if pressed_keys.contains(&Keycode::W) - // || pressed_keys.contains(&Keycode::E) - // || pressed_keys.contains(&Keycode::R) - // || pressed_keys.contains(&Keycode::T) - // || pressed_keys.contains(&Keycode::Y) - // || pressed_keys.contains(&Keycode::U) - // || pressed_keys.contains(&Keycode::I) - // || pressed_keys.contains(&Keycode::O) - // || pressed_keys.contains(&Keycode::S) - // || pressed_keys.contains(&Keycode::D) - // || pressed_keys.contains(&Keycode::F) - // || pressed_keys.contains(&Keycode::G) - // || pressed_keys.contains(&Keycode::H) - // || pressed_keys.contains(&Keycode::J) - // || pressed_keys.contains(&Keycode::K) - // || pressed_keys.contains(&Keycode::L) - // { - // switch_clicked = true; - // } - // if pressed_keys.contains(&Keycode::LShift) - // || pressed_keys.contains(&Keycode::RShift) - // { - // if pressed_keys.contains(&Keycode::Key1) { - // kbd_ad = Some(15); - // } else if pressed_keys.contains(&Keycode::Key2) { - // kbd_ad = Some(14); - // } else if pressed_keys.contains(&Keycode::Key3) { - // kbd_ad = Some(13); - // } else if pressed_keys.contains(&Keycode::Key4) { - // kbd_ad = Some(12); - // } else if pressed_keys.contains(&Keycode::Key5) { - // kbd_ad = Some(11); - // } else if pressed_keys.contains(&Keycode::Key6) { - // kbd_ad = Some(10); - // } else if pressed_keys.contains(&Keycode::Key7) { - // kbd_ad = Some(9); - // } else if pressed_keys.contains(&Keycode::Key8) { - // kbd_ad = Some(8); - // } - // } else { - // if pressed_keys.contains(&Keycode::Key1) { - // kbd_ad = Some(7); - // } else if pressed_keys.contains(&Keycode::Key2) { - // kbd_ad = Some(6); - // } else if pressed_keys.contains(&Keycode::Key3) { - // kbd_ad = Some(5); - // } else if pressed_keys.contains(&Keycode::Key4) { - // kbd_ad = Some(4); - // } else if pressed_keys.contains(&Keycode::Key5) { - // kbd_ad = Some(3); - // } else if pressed_keys.contains(&Keycode::Key6) { - // kbd_ad = Some(2); - // } else if pressed_keys.contains(&Keycode::Key7) { - // kbd_ad = Some(1); - // } else if pressed_keys.contains(&Keycode::Key8) { - // kbd_ad = Some(0); - // } - // if pressed_keys.contains(&Keycode::Q) { - // switch_clicked = true; - // self.power = !self.power; - // if self.options.fan_enabled { - // self.fan_audio_tx.send(self.power).unwrap(); - // } - // if self.power { - // self.cpu = I8080::new(); - // self.update_fp(); - // } else { - // self.running = false; - // self.fp_status = Status::empty(); - // self.fp_data = 0; - // self.fp_address = 0; - // } - // } - // } - // } - // if pressed_keys.contains(&Keycode::W) { - // self.runstop = SwitchState::Up; - // } - // if pressed_keys.contains(&Keycode::E) { - // self.single_step = SwitchState::Up; - // } - // if pressed_keys.contains(&Keycode::R) { - // self.exam = SwitchState::Up; - // } - // if pressed_keys.contains(&Keycode::T) { - // self.dep = SwitchState::Up; - // } - // if pressed_keys.contains(&Keycode::Y) { - // self.reset = SwitchState::Up; - // } - // if pressed_keys.contains(&Keycode::U) { - // self.prot = SwitchState::Up; - // } - // if pressed_keys.contains(&Keycode::I) { - // self.aux1 = SwitchState::Up; - // } - // if pressed_keys.contains(&Keycode::O) { - // self.aux2 = SwitchState::Up; - // } - // if pressed_keys.contains(&Keycode::S) { - // self.runstop = SwitchState::Down; - // } - // if pressed_keys.contains(&Keycode::D) { - // self.single_step = SwitchState::Down; - // } - // if pressed_keys.contains(&Keycode::F) { - // self.exam = SwitchState::Down; - // } - // if pressed_keys.contains(&Keycode::G) { - // self.dep = SwitchState::Down; - // } - // if pressed_keys.contains(&Keycode::H) { - // self.reset = SwitchState::Down; - // } - // if pressed_keys.contains(&Keycode::J) { - // self.prot = SwitchState::Down; - // } - // if pressed_keys.contains(&Keycode::K) { - // self.aux1 = SwitchState::Down; - // } - // if pressed_keys.contains(&Keycode::L) { - // self.aux2 = SwitchState::Down; - // } - // if let Some(kbd_ad) = kbd_ad { - // switch_clicked = true; - // if (self.ad_sws & (1 << kbd_ad)) > 0 { - // self.ad_sws &= !(1 << kbd_ad); - // } else { - // self.ad_sws |= 1 << kbd_ad; - // } - // } - // } - // if switch_clicked { - // self.main_audio_tx - // .send(AudioMessage::PlaySwitchClick) - // .unwrap(); - // } - // if pointer_state.primary_down() { - // if self.mouse_newdown { - // self.mouse_olddown = true; - // self.mouse_newdown = false; - // } else if !self.mouse_newdown && !self.mouse_olddown { - // self.mouse_newdown = true; - // } - // } else { - // self.mouse_newdown = false; - // self.mouse_olddown = false; - // } - // if switch_clicked && self.power { - // if !self.running { - // if self.exam == SwitchState::Up { - // // Assume M1 - // self.cpu.finish_m_cycle(0xC3); // JMP - // self.cpu.finish_m_cycle(self.ad_sws as u8); - // self.cpu.finish_m_cycle((self.ad_sws >> 8) as u8); - // self.update_fp(); - // } - // if self.exam == SwitchState::Down { - // // Assume M1 - // self.cpu.finish_m_cycle(0x0); // NOP - // self.update_fp(); - // } - // if self.dep == SwitchState::Up { - // // Assume M1 - // self.mem[self.cpu.get_mem_cycle().address() as usize] = self.ad_sws as u8; - // self.update_fp(); - // } - // if self.dep == SwitchState::Down { - // // Assume M1 - // self.cpu.finish_m_cycle(0x0); // NOP - // self.mem[self.cpu.get_mem_cycle().address() as usize] = self.ad_sws as u8; - // self.update_fp(); - // } - // } - // if self.runstop == SwitchState::Up { - // self.running = false; - // } - // if self.runstop == SwitchState::Down { - // self.running = true; - // } - // if self.reset == SwitchState::Up { - // self.cpu.reset(); - // self.update_fp(); - // } - // } - // if ((switch_clicked && self.single_step != SwitchState::Neut) || self.running) - // && self.power - // { - // let cycle = self.cpu.get_mem_cycle(); - // let data = match cycle { - // MemCycle::Fetch(a) | MemCycle::Read(a) | MemCycle::StackRead(a) => { - // self.mem[a as usize] - // } - // MemCycle::Write(a, d) | MemCycle::StackWrite(a, d) => { - // self.mem[a as usize] = d; - // 0 - // } - // MemCycle::In(_) => 0, - // MemCycle::Out(_, _) => 0, - // MemCycle::Inta(_) => todo!(), - // MemCycle::Hlta(_) => { - // self.running = false; - // 0 - // } - // MemCycle::IntaHlt(_) => todo!(), - // }; - // self.cpu.finish_m_cycle(data); - // self.update_fp(); - // } }); let old_fan_enabled = self.options.fan_enabled; @@ -703,68 +349,3 @@ impl OptionWindow { !modal.is_open() } } - -struct Textures { - fp: TextureHandle, - sw_up: TextureHandle, - sw_neut: TextureHandle, - sw_down: TextureHandle, - led_off: TextureHandle, - led_on: TextureHandle, -} - -impl Textures { - 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, - path: impl AsRef, - ) -> Result { - 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)) - } -}