old school music tracker
1use winit::keyboard::{Key, NamedKey};
2
3use crate::{
4 app::EventQueue,
5 coordinates::{CharPosition, CharRect},
6 draw_buffer::DrawBuffer,
7};
8
9use super::{NextWidget, StandardResponse, Widget, WidgetResponse};
10
11pub struct Button<R> {
12 text: &'static str,
13 rect: CharRect,
14 pressed: bool,
15 next_widget: NextWidget,
16 callback: fn() -> R,
17}
18
19impl<R> Widget for Button<R> {
20 type Response = R;
21 fn draw(&self, buffer: &mut DrawBuffer, selected: bool) {
22 self.draw_overwrite_pressed(buffer, selected, false);
23 }
24
25 fn process_input(
26 &mut self,
27 modifiers: &winit::event::Modifiers,
28 key_event: &winit::event::KeyEvent,
29 _: &mut EventQueue<'_>,
30 ) -> WidgetResponse<R> {
31 if key_event.logical_key == Key::Named(NamedKey::Space)
32 || key_event.logical_key == Key::Named(NamedKey::Enter)
33 {
34 if !key_event.repeat {
35 if key_event.state.is_pressed() {
36 self.pressed = true;
37 return WidgetResponse::default();
38 } else {
39 // only call the callback on a release event if the button was pressed in before
40 // meaning if the user pressed the key, then changed focus to another button and then releases
41 // no button should be triggered
42 let response = if self.pressed {
43 Some((self.callback)())
44 } else {
45 None
46 };
47 self.pressed = false;
48 return WidgetResponse {
49 standard: StandardResponse::RequestRedraw,
50 extra: response,
51 };
52 }
53 }
54 // if focus is changed stop being pressed
55 } else {
56 return self.next_widget.process_key_event(key_event, modifiers);
57 }
58 WidgetResponse::default()
59 }
60}
61
62impl<R> Button<R> {
63 const TOPLEFT_COLOR: u8 = 3;
64 const BOTRIGHT_COLOR: u8 = 1;
65
66 pub fn new(text: &'static str, rect: CharRect, next_widget: NextWidget, cb: fn() -> R) -> Self {
67 // is 3 rows high, because bot and top are inclusive
68 assert!(
69 rect.bot() - rect.top() >= 2,
70 "buttons needs to be at least 3 rows high"
71 );
72 Button {
73 text,
74 rect,
75 callback: cb,
76 pressed: false,
77 next_widget,
78 }
79 }
80
81 /// pressed = argument || self.pressed
82 pub fn draw_overwrite_pressed(&self, buffer: &mut DrawBuffer, selected: bool, pressed: bool) {
83 // let string_offset = {
84 // let half_string = self.text.len() / 2;
85 // if self.text.len() % 2 == 0 {
86 // half_string - 1
87 // } else {
88 // half_string
89 // }
90 // };
91
92 // fill behind the text
93 buffer.draw_rect(
94 DrawBuffer::BACKGROUND_COLOR,
95 CharRect::new(
96 self.rect.top() + 1,
97 self.rect.bot() - 1,
98 self.rect.left() + 1,
99 self.rect.right() - 1,
100 ),
101 );
102
103 let box_colors = match pressed || self.pressed {
104 true => (Self::BOTRIGHT_COLOR, Self::TOPLEFT_COLOR),
105 false => (Self::TOPLEFT_COLOR, Self::BOTRIGHT_COLOR),
106 };
107
108 buffer.draw_in_box(
109 self.rect,
110 DrawBuffer::BACKGROUND_COLOR,
111 box_colors.0,
112 box_colors.1,
113 1,
114 );
115
116 let text_color = match selected {
117 true => 11,
118 false => 0,
119 };
120 buffer.draw_string(
121 self.text,
122 CharPosition::new(
123 // ((self.rect.right() - self.rect.left()) / 2 + self.rect.left()) - string_offset,
124 self.rect.left() + 2,
125 (self.rect.bot() - self.rect.top()) / 2 + self.rect.top(),
126 ),
127 text_color,
128 DrawBuffer::BACKGROUND_COLOR,
129 )
130 }
131}