1use super::AccessLabel;
9use kas::event::Key;
10use kas::prelude::*;
11use kas::theme::{Background, FrameStyle};
12use std::fmt::Debug;
13
14#[impl_self]
15mod Button {
16 #[widget]
24 #[layout(
25 frame!(self.inner)
26 .with_style(FrameStyle::Button)
27 .with_background(self.bg)
28 .align(AlignHints::CENTER)
29 )]
30 pub struct Button<W: Widget> {
31 core: widget_core!(),
32 key: Option<Key>,
33 bg: Background,
34 #[widget]
35 pub inner: W,
36 on_press: Option<Box<dyn Fn(&mut EventCx, &W::Data)>>,
37 }
38
39 impl Self {
40 #[inline]
42 pub fn new(inner: W) -> Self {
43 Button {
44 core: Default::default(),
45 key: Default::default(),
46 bg: Background::Default,
47 inner,
48 on_press: None,
49 }
50 }
51
52 #[inline]
54 #[must_use]
55 pub fn with(mut self, f: impl Fn(&mut EventCx, &W::Data) + 'static) -> Self {
56 debug_assert!(self.on_press.is_none());
57 self.on_press = Some(Box::new(f));
58 self
59 }
60
61 #[inline]
63 #[must_use]
64 pub fn with_msg<M>(self, msg: M) -> Self
65 where
66 M: Clone + Debug + 'static,
67 {
68 self.with(move |cx, _| cx.push(msg.clone()))
69 }
70
71 #[inline]
77 pub fn new_msg<M: Clone + Debug + 'static>(inner: W, msg: M) -> Self {
78 Self::new(inner).with_msg(msg)
79 }
80
81 #[must_use]
83 pub fn with_access_key(mut self, key: Key) -> Self {
84 debug_assert!(self.key.is_none());
85 self.key = Some(key);
86 self
87 }
88
89 #[inline]
93 #[must_use]
94 pub fn with_background(mut self, bg: Background) -> Self {
95 self.bg = bg;
96 self
97 }
98 }
99
100 impl Layout for Self {
101 fn draw(&self, mut draw: DrawCx) {
102 if let Some(key) = self.key.as_ref() {
103 let _ = draw.access_key(self.id_ref(), key);
104 }
105 kas::MacroDefinedLayout::draw(self, draw);
106 }
107 }
108
109 impl Tile for Self {
110 fn navigable(&self) -> bool {
111 true
112 }
113
114 fn role(&self, _: &mut dyn RoleCx) -> Role<'_> {
115 Role::Button
116 }
117
118 fn probe(&self, _: Coord) -> Id {
119 self.id()
120 }
121 }
122
123 impl Events for Self {
124 const REDRAW_ON_MOUSE_OVER: bool = true;
125
126 type Data = W::Data;
127
128 fn handle_event(&mut self, cx: &mut EventCx, data: &W::Data, event: Event) -> IsUsed {
129 event.on_click(cx, self.id(), |cx| {
130 if let Some(f) = self.on_press.as_ref() {
131 f(cx, data);
132 }
133 })
134 }
135
136 fn handle_messages(&mut self, cx: &mut EventCx, data: &W::Data) {
137 if let Some(kas::messages::Activate(code)) = cx.try_pop() {
138 if let Some(f) = self.on_press.as_ref() {
139 f(cx, data);
140 }
141 cx.depress_with_key(&self, code);
142 }
143 }
144 }
145
146 impl Button<AccessLabel> {
147 pub fn label(label: impl Into<AccessString>) -> Self {
153 Button::new(AccessLabel::new(label))
154 }
155
156 pub fn label_msg<M>(label: impl Into<AccessString>, msg: M) -> Self
162 where
163 M: Clone + Debug + 'static,
164 {
165 Button::new_msg(AccessLabel::new(label), msg)
166 }
167 }
168}