old school music tracker
at main 138 lines 3.7 kB view raw
1pub mod button; 2pub mod slider; 3pub mod text_in; 4pub mod text_in_scroll; 5pub mod toggle; 6pub mod toggle_button; 7 8use winit::{ 9 event::{KeyEvent, Modifiers}, 10 keyboard::{Key, ModifiersState, NamedKey}, 11}; 12 13use crate::{app::EventQueue, draw_buffer::DrawBuffer}; 14 15pub(crate) trait Widget { 16 type Response; 17 fn draw(&self, draw_buffer: &mut DrawBuffer, selected: bool); 18 /// returns a Some(usize) if the next widget gets selected 19 fn process_input( 20 &mut self, 21 modifiers: &Modifiers, 22 key_event: &KeyEvent, 23 events: &mut EventQueue<'_>, 24 ) -> WidgetResponse<Self::Response>; 25} 26 27#[derive(Debug)] 28pub struct WidgetResponse<R> { 29 pub standard: StandardResponse, 30 pub extra: Option<R>, 31} 32 33impl<R> Default for WidgetResponse<R> { 34 fn default() -> Self { 35 Self { 36 standard: StandardResponse::default(), 37 extra: None, 38 } 39 } 40} 41 42impl<R> WidgetResponse<R> { 43 pub fn request_redraw() -> Self { 44 Self { 45 standard: StandardResponse::RequestRedraw, 46 extra: None, 47 } 48 } 49 50 pub fn next_widget(value: usize) -> Self { 51 Self { 52 standard: StandardResponse::SwitchFocus(value), 53 extra: None, 54 } 55 } 56} 57 58// SwitchFocus also has to request a redraw 59#[derive(Debug, Default)] 60pub enum StandardResponse { 61 SwitchFocus(usize), 62 RequestRedraw, 63 // GlobalEvent(GlobalEvent), 64 #[default] 65 None, 66} 67 68impl<R> From<StandardResponse> for WidgetResponse<R> { 69 fn from(value: StandardResponse) -> Self { 70 Self { 71 standard: value, 72 extra: None, 73 } 74 } 75} 76 77#[derive(Debug, Default)] 78pub struct NextWidget { 79 pub left: Option<usize>, 80 pub right: Option<usize>, 81 pub up: Option<usize>, 82 pub down: Option<usize>, 83 pub tab: Option<usize>, 84 pub shift_tab: Option<usize>, 85} 86 87impl NextWidget { 88 /// supposed to be called from Widgets, that own a NextWidget after catching their custom KeyEvents to pick a return 89 pub fn process_key_event<R>( 90 &self, 91 key_event: &KeyEvent, 92 modifiers: &Modifiers, 93 ) -> WidgetResponse<R> { 94 if !key_event.state.is_pressed() { 95 return WidgetResponse::default(); 96 } 97 98 #[expect( 99 non_local_definitions, 100 reason = "this is only valid with these specific Option<usize> not in general" 101 )] 102 impl<R> From<Option<usize>> for WidgetResponse<R> { 103 fn from(value: Option<usize>) -> Self { 104 Self { 105 standard: match value { 106 Some(num) => StandardResponse::SwitchFocus(num), 107 None => StandardResponse::None, 108 }, 109 extra: None, 110 } 111 } 112 } 113 114 if key_event.logical_key == Key::Named(NamedKey::ArrowUp) && modifiers.state().is_empty() { 115 self.up.into() 116 } else if key_event.logical_key == Key::Named(NamedKey::ArrowDown) 117 && modifiers.state().is_empty() 118 { 119 self.down.into() 120 } else if key_event.logical_key == Key::Named(NamedKey::ArrowRight) 121 && modifiers.state().is_empty() 122 { 123 self.right.into() 124 } else if key_event.logical_key == Key::Named(NamedKey::ArrowLeft) 125 && modifiers.state().is_empty() 126 { 127 self.left.into() 128 } else if key_event.logical_key == Key::Named(NamedKey::Tab) { 129 if modifiers.state() == ModifiersState::SHIFT { 130 self.shift_tab.into() 131 } else { 132 self.tab.into() 133 } 134 } else { 135 WidgetResponse::default() 136 } 137 } 138}