pub mod button; pub mod slider; pub mod text_in; // pub mod text_in_scroll; pub mod toggle; pub mod toggle_button; use winit::{ event::{KeyEvent, Modifiers}, keyboard::{Key, ModifiersState, NamedKey}, }; use crate::{EventQueue, draw_buffer::DrawBuffer, pages::PageResponse}; pub(crate) trait Widget { fn draw(&self, draw_buffer: &mut DrawBuffer, selected: bool); /// true if the widget data was changed by the input fn process_input( &mut self, modifiers: &Modifiers, key_event: &KeyEvent, events: &mut EventQueue<'_>, ) -> WidgetResponse; #[cfg(feature = "accesskit")] fn build_tree(&self, tree: &mut Vec<(accesskit::NodeId, accesskit::Node)>); } // #[derive(Debug)] // pub struct WidgetResponse { // pub standard: StandardResponse, // pub extra: Option, // } // impl Default for WidgetResponse { // fn default() -> Self { // Self { // standard: StandardResponse::default(), // extra: None, // } // } // } // impl WidgetResponse { // pub fn request_redraw() -> Self { // Self { // standard: StandardResponse::RequestRedraw, // extra: None, // } // } // pub fn next_widget(value: u8) -> Self { // Self { // standard: StandardResponse::SwitchFocus(value), // extra: None, // } // } // } // SwitchFocus also has to request a redraw #[derive(Debug, Default, PartialEq, Eq)] pub enum WidgetResponse { SwitchFocus(u8), /// true if the redraw is because the widget data was changed. /// This could be true even if the data didn't change. This makes the implementation of some widgets easier. /// It is still useful to keep other parts of the system in sync. /// /// A redraw request could otherwise be made because for example a internal cursor changed RequestRedraw(bool), // GlobalEvent(GlobalEvent), #[default] None, } // impl From for WidgetResponse { // fn from(value: StandardResponse) -> Self { // Self { // standard: value, // extra: None, // } // } // } impl WidgetResponse { pub fn to_page_resp(self, selected: &mut u8) -> PageResponse { match self { WidgetResponse::SwitchFocus(s) => { *selected = s; PageResponse::RequestRedraw } WidgetResponse::RequestRedraw(_) => PageResponse::RequestRedraw, WidgetResponse::None => PageResponse::None, } } pub fn on_change(self, f: impl FnOnce()) -> Self { if self == WidgetResponse::RequestRedraw(true) { f(); } self } } #[derive(Debug, Default)] pub struct NextWidget { pub left: Option, pub right: Option, pub up: Option, pub down: Option, pub tab: Option, pub shift_tab: Option, } impl NextWidget { /// supposed to be called from Widgets, that own a NextWidget after catching their custom KeyEvents to pick a return pub fn process_key_event(&self, key_event: &KeyEvent, modifiers: &Modifiers) -> WidgetResponse { if !key_event.state.is_pressed() { return WidgetResponse::None; } #[expect( non_local_definitions, reason = "this is only valid with these specific Option not in general" )] impl From> for WidgetResponse { fn from(value: Option) -> Self { match value { Some(num) => WidgetResponse::SwitchFocus(num), None => WidgetResponse::None, } } } if key_event.logical_key == Key::Named(NamedKey::ArrowUp) && modifiers.state().is_empty() { self.up.into() } else if key_event.logical_key == Key::Named(NamedKey::ArrowDown) && modifiers.state().is_empty() { self.down.into() } else if key_event.logical_key == Key::Named(NamedKey::ArrowRight) && modifiers.state().is_empty() { self.right.into() } else if key_event.logical_key == Key::Named(NamedKey::ArrowLeft) && modifiers.state().is_empty() { self.left.into() } else if key_event.logical_key == Key::Named(NamedKey::Tab) { if modifiers.state() == ModifiersState::SHIFT { self.shift_tab.into() } else { self.tab.into() } } else { WidgetResponse::None } } }