Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
16 kB · 465 lines
Rust
at dev
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466use winit::keyboard::{Key, NamedKey};
use crate::{ EventQueue, GlobalEvent, PlaybackType, coordinates::{CharPosition, CharRect, FONT_SIZE16, PixelRect}, draw_buffer::DrawBuffer, pages::PagesEnum,};
use super::{Dialog, DialogResponse};
enum Action { Menu(Menu), Page(PagesEnum), Playback(PlaybackType), // const data. Allows Recursing this inside the GlobalEvent Event(fn() -> GlobalEvent), // TODO: should be removed when it's all implemented NotYetImplemented,}
// Main missing, because it cant be opened from a menu#[derive(Clone, Copy)]enum Menu { File, Playback, Sample, Instrument, Settings,}
pub struct PageMenu { name: &'static str, rect: CharRect, selected: u8, pressed: bool, buttons: &'static [(&'static str, Action)], #[cfg(feature = "accesskit")] node_id: accesskit::NodeId,}
impl PageMenu { const BACKGROUND_COLOR: u8 = 2; const TOPLEFT_COLOR: u8 = 3; const BOTRIGHT_COLOR: u8 = 1; const fn new( name: &'static str, pos: CharPosition, width: u8, buttons: &'static [(&'static str, Action)], #[cfg(feature = "accesskit")] node_id: accesskit::NodeId, ) -> Self { let rect = CharRect::new( pos.y(), // TODO: const trait pos.y() + 5 + (3 * buttons.len() as u8), pos.x(), pos.x() + width + 3, );
Self { name, rect, selected: 0, pressed: false, buttons, #[cfg(feature = "accesskit")] node_id, } } fn draw_button_corners(rect: CharRect, draw_buffer: &mut DrawBuffer) { // let framebuffer = &mut draw_buffer.framebuffer; let pixel_rect = PixelRect::from(rect); // draw top right corner for y in 0..FONT_SIZE16 { for x in y..FONT_SIZE16 { draw_buffer.set( pixel_rect.top() + y, pixel_rect.right() - FONT_SIZE16 + x + 1, Self::BOTRIGHT_COLOR, ); } } // draw botleft corner for y in 0..FONT_SIZE16 { for x in 0..(FONT_SIZE16 - y) { draw_buffer.set( pixel_rect.bot() - y, pixel_rect.left() + x, Self::BOTRIGHT_COLOR, ); } } }
fn draw(&self, has_child: bool, draw_buffer: &mut DrawBuffer) { let top_left = self.rect.top_left(); let top = top_left.y(); let left = top_left.x();
draw_buffer.draw_rect(Self::BACKGROUND_COLOR, self.rect); draw_buffer.draw_string(self.name, top_left + CharPosition::new(7, 2), 3, 2); // self.draw_outer_box(draw_buffer); draw_buffer.draw_out_border(self.rect, Self::TOPLEFT_COLOR, Self::TOPLEFT_COLOR, 2); draw_buffer.draw_out_border( CharRect::new( self.rect.top() + 1, self.rect.bot() - 1, self.rect.left() + 1, self.rect.right() - 1, ), Self::BOTRIGHT_COLOR, Self::BOTRIGHT_COLOR, 1, ); for (num, (name, _)) in self.buttons.iter().enumerate() { let num = u8::try_from(num).unwrap(); let text_color = match self.selected == num { true => 11, false => 0, };
draw_buffer.draw_string( name, top_left + CharPosition::new(4, (3 * num) + 5), text_color, Self::BACKGROUND_COLOR, ); let top = top + (3 * num) + 4; let (top_left, bot_right) = match (self.pressed || has_child) && self.selected == num { true => (Self::BOTRIGHT_COLOR, Self::TOPLEFT_COLOR), false => (Self::TOPLEFT_COLOR, Self::BOTRIGHT_COLOR), }; let rect = CharRect::new(top, top + 2, left + 2, left + self.rect.width() - 2); draw_buffer.draw_out_border(rect, top_left, bot_right, 1); Self::draw_button_corners(rect, draw_buffer); } }
fn process_input( &mut self, key_event: &winit::event::KeyEvent, events: &mut EventQueue<'_>, ) -> (DialogResponse, Option<Menu>) { if key_event.logical_key == Key::Named(NamedKey::Enter) { if key_event.state.is_pressed() { self.pressed = true; return (DialogResponse::RequestRedraw, None); } else if self.pressed { self.pressed = false; match &self.buttons[usize::from(self.selected)].1 { Action::Menu(menu) => { return (DialogResponse::RequestRedraw, Some(*menu)); } Action::Page(page) => { events.push(GlobalEvent::GoToPage(*page)); return (DialogResponse::Close, None); } Action::NotYetImplemented => { eprintln!("Not yet implementes"); return (DialogResponse::RequestRedraw, None); } Action::Event(global_event) => { events.push(global_event()); return (DialogResponse::Close, None); } Action::Playback(p) => { events.push(GlobalEvent::Playback(*p)); return (DialogResponse::Close, None); } } } }
if key_event.state.is_pressed() { if key_event.logical_key == Key::Named(NamedKey::ArrowUp) && self.selected > 0 { self.selected -= 1; self.pressed = false; return (DialogResponse::RequestRedraw, None); } else if key_event.logical_key == Key::Named(NamedKey::ArrowDown) && usize::from(self.selected) < self.buttons.len() - 1 { self.selected += 1; self.pressed = false; return (DialogResponse::RequestRedraw, None); } }
(DialogResponse::None, None) }
#[cfg(feature = "accesskit")] #[expect(unused)] fn build_tree( &self, tree: &mut Vec<(accesskit::NodeId, accesskit::Node)>, ) -> crate::AccessResponse { use accesskit::{Action, Node, NodeId, Rect, Role};
use crate::AccessResponse; let mut root = Node::new(Role::Dialog); root.set_label(self.name); root.set_bounds(dbg!(Rect::from(self.rect))); let selected = NodeId(u64::from(self.selected) + self.node_id.0 + 1);
// root of the sub_menu. Will be set as the child of the selected button // let sub_menu = self.sub_menu.as_ref().map(|m| { // let resp = m.build_tree(tree);
// selected = resp.selected;
// resp.root // });
for (num, (name, _)) in self.buttons.iter().enumerate() { let mut node = Node::new(Role::Button); node.add_action(Action::Click); node.set_keyboard_shortcut("Enter"); node.set_label(*name); if usize::from(self.selected) == num { node.set_selected(true); // if let Some(id) = sub_menu { // node.push_child(id); // } } let id = NodeId(u64::try_from(num).unwrap() + self.node_id.0 + 1); tree.push((id, node)); root.push_child(id); }
tree.push((self.node_id, root)); AccessResponse { root: self.node_id, selected, } }}
pub struct MainMenu { main: PageMenu, child: Option<PageMenu>,}
impl Dialog for MainMenu { fn draw(&self, draw_buffer: &mut DrawBuffer) { self.main.draw(self.child.is_some(), draw_buffer); if let Some(child) = &self.child { // the child never has a child child.draw(false, draw_buffer); } }
fn process_input( &mut self, key_event: &winit::event::KeyEvent, _modifiers: &winit::event::Modifiers, events: &mut EventQueue<'_>, ) -> DialogResponse { // check for close dialog if key_event.state.is_pressed() && key_event.logical_key == Key::Named(NamedKey::Escape) { if self.child.is_some() { self.child = None; events.push(GlobalEvent::ConstRedraw); return DialogResponse::RequestRedraw; } else { return DialogResponse::Close; } }
if let Some(child) = &mut self.child { let (resp, open_child) = child.process_input(key_event, events); assert!(open_child.is_none(), "the child can't open a child"); resp } else { let (resp, open_child) = self.main.process_input(key_event, events); if let Some(open_child) = open_child { assert!( resp == DialogResponse::RequestRedraw, "child open is always in combination with redraw" ); let child = match open_child { Menu::File => PageMenu::file(), Menu::Playback => PageMenu::playback(), Menu::Sample => PageMenu::sample(), Menu::Instrument => PageMenu::instrument(), Menu::Settings => PageMenu::settings(), }; self.child = Some(child); } resp } }
#[cfg(feature = "accesskit")] fn build_tree( &self, _tree: &mut Vec<(accesskit::NodeId, accesskit::Node)>, ) -> crate::AccessResponse { todo!("look at PageMenu commented out stuff"); }}
impl MainMenu { pub fn new() -> Self { Self { main: PageMenu::main(), child: None, } }}
impl PageMenu { pub const fn main() -> Self { Self::new( "Main Menu", CharPosition::new(6, 11), 29, &[ ("File Menu...", Action::Menu(Menu::File)), ("Playback Menu...", Action::Menu(Menu::Playback)), ( "View Patterns (F2)", Action::Page(PagesEnum::Pattern), ), ("Sample Menu...", Action::Menu(Menu::Sample)), ("Instrument Menu...", Action::Menu(Menu::Instrument)), ( "View Orders/Panning (F11)", Action::Page(PagesEnum::OrderList), ), ( "View Variables (F12)", Action::Page(PagesEnum::SongDirectoryConfig), ), ("Message Editor (Shift-F9)", Action::NotYetImplemented), ("Settings Menu...", Action::Menu(Menu::Settings)), ("Help! (F1)", Action::Page(PagesEnum::Help)), ], #[cfg(feature = "accesskit")] accesskit::NodeId(1_000_000_000), ) }
pub const fn file() -> Self { Self::new( "File Menu", CharPosition::new(25, 13), 26, &[ ("Load... (F9)", Action::NotYetImplemented), ("New... (Ctrl-N)", Action::NotYetImplemented), ("Save Current (Ctrl-S)", Action::NotYetImplemented), ("Save As... (F10)", Action::NotYetImplemented), ("Export... (Shift-F10)", Action::NotYetImplemented), ("Message Log (Ctrl-F11)", Action::NotYetImplemented), ( "Quit (Ctrl-Q)", Action::Event(|| GlobalEvent::CloseRequested), ), ], #[cfg(feature = "accesskit")] accesskit::NodeId(1_000_000_100), ) }
pub const fn playback() -> Self { Self::new( "Playback Menu", CharPosition::new(25, 13), 31, &[ ("Show Infopage (F5)", Action::NotYetImplemented), ( "Play Song (Ctrl-F5)", Action::Playback(PlaybackType::Song), ), ( "Play Pattern (F6)", Action::Playback(PlaybackType::Pattern), ), ( "Play from Order (Shift-F6)", Action::Playback(PlaybackType::FromOrder), ), ("Play from Mark/Cursor (F7)", Action::NotYetImplemented), ( "Stop (F8)", Action::Playback(PlaybackType::Stop), ), ("Reinit Soundcard (Ctrl-I)", Action::NotYetImplemented), ("Driver Screen (Shift-F5)", Action::NotYetImplemented), ("Calculate Length (Ctrl-P)", Action::NotYetImplemented), ], #[cfg(feature = "accesskit")] accesskit::NodeId(1_000_000_200), ) }
pub const fn sample() -> Self { Self::new( "Sample Menu", CharPosition::new(25, 20), 29, &[ ( "Sample List (F3)", Action::Page(PagesEnum::SampleList), ), ("Sample Library (Ctrl-F3)", Action::NotYetImplemented), ], #[cfg(feature = "accesskit")] accesskit::NodeId(1_000_000_300), ) }
pub const fn instrument() -> Self { Self::new( "Instrument Menu", CharPosition::new(20, 23), 33, &[ ("Instrument List (F4)", Action::NotYetImplemented), ("Instrument Library (Ctrl-F4)", Action::NotYetImplemented), ], #[cfg(feature = "accesskit")] accesskit::NodeId(1_000_000_400), ) }
pub const fn settings() -> Self { Self::new( "Settings Menu", CharPosition::new(22, 25), 38, &[ ( "Preferences (Shift-F5)", Action::NotYetImplemented, ), ( "MIDI Configuration (Shift-F1)", Action::NotYetImplemented, ), ( "System Configuration (Ctrl-F1)", Action::NotYetImplemented, ), ( "Palette Editor (Ctrl-F12)", Action::NotYetImplemented, ), ( "Font Editor (Shift-F12)", Action::NotYetImplemented, ), ( "Toggle Fullscreen (Ctrl-Alt-Enter)", Action::NotYetImplemented, ), ], #[cfg(feature = "accesskit")] accesskit::NodeId(1_000_000_500), ) }}