old school music tracker
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}