use winit::keyboard::{Key, NamedKey}; use crate::{ GlobalEvent, coordinates::{CharPosition, CharRect}, draw_buffer::DrawBuffer, widgets::{NextWidget, Widget, WidgetResponse, button::Button}, }; use super::{Dialog, DialogResponse}; pub struct ConfirmDialog { text: &'static str, text_pos: CharPosition, // computed from the string length rect: CharRect, ok: (Button, Option GlobalEvent>), cancel: (Button, Option GlobalEvent>), selected: u8, } impl ConfirmDialog { const DIALOG_ID: u64 = 600_000_000; const OK_RECT: CharRect = CharRect::new(29, 31, 41, 50); const CANCEL_RECT: CharRect = CharRect::new(29, 31, 30, 39); const OK: u8 = 1; const CANCEL: u8 = 2; pub fn new( text: &'static str, ok_event: Option GlobalEvent>, cancel_event: Option GlobalEvent>, ) -> Self { let width = (u8::try_from(text.len()).unwrap() + 10).max(22); let per_side = width / 2; Self { text, text_pos: CharPosition::new(40 - per_side + 5, 27), selected: Self::OK, ok: ( Button::new( " Ok", Self::OK_RECT, NextWidget { left: Some(Self::CANCEL), right: Some(Self::CANCEL), tab: Some(Self::CANCEL), shift_tab: Some(Self::CANCEL), ..Default::default() }, #[cfg(feature = "accesskit")] accesskit::NodeId(Self::DIALOG_ID + u64::from(Self::OK) * 20), ), ok_event, ), cancel: ( Button::new( "Cancel", Self::CANCEL_RECT, NextWidget { left: Some(Self::OK), right: Some(Self::OK), tab: Some(Self::OK), shift_tab: Some(Self::OK), ..Default::default() }, #[cfg(feature = "accesskit")] accesskit::NodeId(Self::DIALOG_ID + u64::from(Self::CANCEL) * 20), ), cancel_event, ), rect: CharRect::new(25, 32, 40 - per_side, 40 + per_side), } } } impl Dialog for ConfirmDialog { fn draw(&self, draw_buffer: &mut DrawBuffer) { draw_buffer.draw_rect(2, self.rect); draw_buffer.draw_out_border(self.rect, 3, 3, 2); draw_buffer.draw_string(self.text, self.text_pos, 0, 2); self.ok.0.draw(draw_buffer, self.selected == Self::OK); self.cancel .0 .draw(draw_buffer, self.selected == Self::CANCEL); } fn process_input( &mut self, key_event: &winit::event::KeyEvent, modifiers: &winit::event::Modifiers, events: &mut crate::EventQueue<'_>, ) -> DialogResponse { if key_event.logical_key == Key::Named(NamedKey::Escape) && modifiers.state().is_empty() { return DialogResponse::Close; } let response = match self.selected { Self::OK => { let resp = self.ok.0.process_input(modifiers, key_event, events); if resp == WidgetResponse::RequestRedraw(true) { if let Some(event) = self.ok.1.take() { events.push(event()); } return DialogResponse::Close; } resp } Self::CANCEL => { let resp = self.cancel.0.process_input(modifiers, key_event, events); if resp == WidgetResponse::RequestRedraw(true) { if let Some(event) = self.cancel.1.take() { events.push(event()); } return DialogResponse::Close; } resp } _ => unreachable!(), }; match response { WidgetResponse::SwitchFocus(i) => { self.selected = i; DialogResponse::RequestRedraw } // always false here, because otherwise we return earlier, but it doesn't matter WidgetResponse::RequestRedraw(_) => DialogResponse::RequestRedraw, WidgetResponse::None => DialogResponse::None, } } #[cfg(feature = "accesskit")] fn build_tree( &self, tree: &mut Vec<(accesskit::NodeId, accesskit::Node)>, ) -> crate::AccessResponse { use accesskit::{Node, Role}; use crate::AccessResponse; let mut root_node = Node::new(Role::Dialog); AccessResponse { root: todo!(), selected: todo!(), } } }