old school music tracker
at dev 158 lines 4.7 kB view raw
1pub mod button; 2pub mod slider; 3pub mod text_in; 4// pub 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::{EventQueue, draw_buffer::DrawBuffer, pages::PageResponse}; 14 15pub(crate) trait Widget { 16 fn draw(&self, draw_buffer: &mut DrawBuffer, selected: bool); 17 /// true if the widget data was changed by the input 18 fn process_input( 19 &mut self, 20 modifiers: &Modifiers, 21 key_event: &KeyEvent, 22 events: &mut EventQueue<'_>, 23 ) -> WidgetResponse; 24 25 #[cfg(feature = "accesskit")] 26 fn build_tree(&self, tree: &mut Vec<(accesskit::NodeId, accesskit::Node)>); 27} 28 29// #[derive(Debug)] 30// pub struct WidgetResponse<R> { 31// pub standard: StandardResponse, 32// pub extra: Option<R>, 33// } 34 35// impl<R> Default for WidgetResponse<R> { 36// fn default() -> Self { 37// Self { 38// standard: StandardResponse::default(), 39// extra: None, 40// } 41// } 42// } 43 44// impl<R> WidgetResponse<R> { 45// pub fn request_redraw() -> Self { 46// Self { 47// standard: StandardResponse::RequestRedraw, 48// extra: None, 49// } 50// } 51 52// pub fn next_widget(value: u8) -> Self { 53// Self { 54// standard: StandardResponse::SwitchFocus(value), 55// extra: None, 56// } 57// } 58// } 59 60// SwitchFocus also has to request a redraw 61#[derive(Debug, Default, PartialEq, Eq)] 62pub enum WidgetResponse { 63 SwitchFocus(u8), 64 /// true if the redraw is because the widget data was changed. 65 /// This could be true even if the data didn't change. This makes the implementation of some widgets easier. 66 /// It is still useful to keep other parts of the system in sync. 67 /// 68 /// A redraw request could otherwise be made because for example a internal cursor changed 69 RequestRedraw(bool), 70 // GlobalEvent(GlobalEvent), 71 #[default] 72 None, 73} 74 75// impl<R> From<StandardResponse> for WidgetResponse<R> { 76// fn from(value: StandardResponse) -> Self { 77// Self { 78// standard: value, 79// extra: None, 80// } 81// } 82// } 83 84impl WidgetResponse { 85 pub fn to_page_resp(self, selected: &mut u8) -> PageResponse { 86 match self { 87 WidgetResponse::SwitchFocus(s) => { 88 *selected = s; 89 PageResponse::RequestRedraw 90 } 91 WidgetResponse::RequestRedraw(_) => PageResponse::RequestRedraw, 92 WidgetResponse::None => PageResponse::None, 93 } 94 } 95 96 pub fn on_change(self, f: impl FnOnce()) -> Self { 97 if self == WidgetResponse::RequestRedraw(true) { 98 f(); 99 } 100 self 101 } 102} 103 104#[derive(Debug, Default)] 105pub struct NextWidget { 106 pub left: Option<u8>, 107 pub right: Option<u8>, 108 pub up: Option<u8>, 109 pub down: Option<u8>, 110 pub tab: Option<u8>, 111 pub shift_tab: Option<u8>, 112} 113 114impl NextWidget { 115 /// supposed to be called from Widgets, that own a NextWidget after catching their custom KeyEvents to pick a return 116 pub fn process_key_event(&self, key_event: &KeyEvent, modifiers: &Modifiers) -> WidgetResponse { 117 if !key_event.state.is_pressed() { 118 return WidgetResponse::None; 119 } 120 121 #[expect( 122 non_local_definitions, 123 reason = "this is only valid with these specific Option<u8> not in general" 124 )] 125 impl From<Option<u8>> for WidgetResponse { 126 fn from(value: Option<u8>) -> Self { 127 match value { 128 Some(num) => WidgetResponse::SwitchFocus(num), 129 None => WidgetResponse::None, 130 } 131 } 132 } 133 134 if key_event.logical_key == Key::Named(NamedKey::ArrowUp) && modifiers.state().is_empty() { 135 self.up.into() 136 } else if key_event.logical_key == Key::Named(NamedKey::ArrowDown) 137 && modifiers.state().is_empty() 138 { 139 self.down.into() 140 } else if key_event.logical_key == Key::Named(NamedKey::ArrowRight) 141 && modifiers.state().is_empty() 142 { 143 self.right.into() 144 } else if key_event.logical_key == Key::Named(NamedKey::ArrowLeft) 145 && modifiers.state().is_empty() 146 { 147 self.left.into() 148 } else if key_event.logical_key == Key::Named(NamedKey::Tab) { 149 if modifiers.state() == ModifiersState::SHIFT { 150 self.shift_tab.into() 151 } else { 152 self.tab.into() 153 } 154 } else { 155 WidgetResponse::None 156 } 157 } 158}