old school music tracker
at dev 149 lines 4.9 kB view raw
1use winit::keyboard::{Key, NamedKey}; 2 3use crate::{ 4 GlobalEvent, 5 coordinates::{CharPosition, CharRect}, 6 draw_buffer::DrawBuffer, 7 widgets::{NextWidget, Widget, WidgetResponse, button::Button}, 8}; 9 10use super::{Dialog, DialogResponse}; 11 12pub struct ConfirmDialog { 13 text: &'static str, 14 text_pos: CharPosition, 15 // computed from the string length 16 rect: CharRect, 17 ok: (Button, Option<fn() -> GlobalEvent>), 18 cancel: (Button, Option<fn() -> GlobalEvent>), 19 selected: u8, 20} 21 22impl ConfirmDialog { 23 const DIALOG_ID: u64 = 600_000_000; 24 25 const OK_RECT: CharRect = CharRect::new(29, 31, 41, 50); 26 const CANCEL_RECT: CharRect = CharRect::new(29, 31, 30, 39); 27 const OK: u8 = 1; 28 const CANCEL: u8 = 2; 29 pub fn new( 30 text: &'static str, 31 ok_event: Option<fn() -> GlobalEvent>, 32 cancel_event: Option<fn() -> GlobalEvent>, 33 ) -> Self { 34 let width = (u8::try_from(text.len()).unwrap() + 10).max(22); 35 let per_side = width / 2; 36 Self { 37 text, 38 text_pos: CharPosition::new(40 - per_side + 5, 27), 39 selected: Self::OK, 40 ok: ( 41 Button::new( 42 " Ok", 43 Self::OK_RECT, 44 NextWidget { 45 left: Some(Self::CANCEL), 46 right: Some(Self::CANCEL), 47 tab: Some(Self::CANCEL), 48 shift_tab: Some(Self::CANCEL), 49 ..Default::default() 50 }, 51 #[cfg(feature = "accesskit")] 52 accesskit::NodeId(Self::DIALOG_ID + u64::from(Self::OK) * 20), 53 ), 54 ok_event, 55 ), 56 cancel: ( 57 Button::new( 58 "Cancel", 59 Self::CANCEL_RECT, 60 NextWidget { 61 left: Some(Self::OK), 62 right: Some(Self::OK), 63 tab: Some(Self::OK), 64 shift_tab: Some(Self::OK), 65 ..Default::default() 66 }, 67 #[cfg(feature = "accesskit")] 68 accesskit::NodeId(Self::DIALOG_ID + u64::from(Self::CANCEL) * 20), 69 ), 70 cancel_event, 71 ), 72 rect: CharRect::new(25, 32, 40 - per_side, 40 + per_side), 73 } 74 } 75} 76 77impl Dialog for ConfirmDialog { 78 fn draw(&self, draw_buffer: &mut DrawBuffer) { 79 draw_buffer.draw_rect(2, self.rect); 80 draw_buffer.draw_out_border(self.rect, 3, 3, 2); 81 draw_buffer.draw_string(self.text, self.text_pos, 0, 2); 82 self.ok.0.draw(draw_buffer, self.selected == Self::OK); 83 self.cancel 84 .0 85 .draw(draw_buffer, self.selected == Self::CANCEL); 86 } 87 88 fn process_input( 89 &mut self, 90 key_event: &winit::event::KeyEvent, 91 modifiers: &winit::event::Modifiers, 92 events: &mut crate::EventQueue<'_>, 93 ) -> DialogResponse { 94 if key_event.logical_key == Key::Named(NamedKey::Escape) && modifiers.state().is_empty() { 95 return DialogResponse::Close; 96 } 97 98 let response = match self.selected { 99 Self::OK => { 100 let resp = self.ok.0.process_input(modifiers, key_event, events); 101 if resp == WidgetResponse::RequestRedraw(true) { 102 if let Some(event) = self.ok.1.take() { 103 events.push(event()); 104 } 105 return DialogResponse::Close; 106 } 107 resp 108 } 109 Self::CANCEL => { 110 let resp = self.cancel.0.process_input(modifiers, key_event, events); 111 if resp == WidgetResponse::RequestRedraw(true) { 112 if let Some(event) = self.cancel.1.take() { 113 events.push(event()); 114 } 115 return DialogResponse::Close; 116 } 117 resp 118 } 119 _ => unreachable!(), 120 }; 121 122 match response { 123 WidgetResponse::SwitchFocus(i) => { 124 self.selected = i; 125 DialogResponse::RequestRedraw 126 } 127 // always false here, because otherwise we return earlier, but it doesn't matter 128 WidgetResponse::RequestRedraw(_) => DialogResponse::RequestRedraw, 129 WidgetResponse::None => DialogResponse::None, 130 } 131 } 132 133 #[cfg(feature = "accesskit")] 134 fn build_tree( 135 &self, 136 tree: &mut Vec<(accesskit::NodeId, accesskit::Node)>, 137 ) -> crate::AccessResponse { 138 use accesskit::{Node, Role}; 139 140 use crate::AccessResponse; 141 142 let mut root_node = Node::new(Role::Dialog); 143 144 AccessResponse { 145 root: todo!(), 146 selected: todo!(), 147 } 148 } 149}