pub struct Button<'a, K> {
pub frame: Rectangle,
pub spec: ButtonSpec<'a, K>,
/* private fields */
}Expand description
Reusable button view that owns its highlight state.
Fields§
§frame: RectangleOuter frame for the button.
spec: ButtonSpec<'a, K>Immutable button configuration.
Implementations§
Source§impl<'a, K: Copy> Button<'a, K>
impl<'a, K: Copy> Button<'a, K>
Sourcepub const fn new(frame: Rectangle, spec: ButtonSpec<'a, K>) -> Self
pub const fn new(frame: Rectangle, spec: ButtonSpec<'a, K>) -> Self
Creates a button from a frame and spec.
Examples found in repository?
examples/buttons.rs (lines 16-24)
11fn main() {
12 let mut canvas = support::NullCanvas::new(Size::new(320, 240));
13 let theme = support::theme();
14 let i18n = support::i18n();
15
16 let mut primary = Button::new(
17 Rectangle::new(Point::new(16, 16), Size::new(132, 56)),
18 ButtonSpec {
19 key: 1_u8,
20 icon: Some("+"),
21 label: Localized::new("button.add", "Add device"),
22 kind: ButtonKind::Primary,
23 },
24 );
25 let secondary = Button::new(
26 Rectangle::new(Point::new(16, 84), Size::new(132, 48)),
27 ButtonSpec {
28 key: 2_u8,
29 icon: None,
30 label: Localized::new("button.more", "More"),
31 kind: ButtonKind::Secondary,
32 },
33 );
34 let destructive = Button::new(
35 Rectangle::new(Point::new(16, 144), Size::new(132, 48)),
36 ButtonSpec {
37 key: 3_u8,
38 icon: None,
39 label: Localized::new("button.delete", "Delete"),
40 kind: ButtonKind::Destructive,
41 },
42 );
43
44 primary.draw(&mut canvas, &theme, &i18n);
45 secondary.draw(&mut canvas, &theme, &i18n);
46 destructive.draw(&mut canvas, &theme, &i18n);
47
48 let _ = primary.handle_touch(TouchEvent::new(Point::new(24, 24), TouchPhase::Start, 1));
49 let response = primary.handle_touch(TouchEvent::new(Point::new(24, 24), TouchPhase::End, 2));
50 let _pressed = response.action == Some(1);
51
52 let _ = Rgb565::BLACK;
53}More examples
src/stack_header.rs (lines 102-113)
101pub(super) fn back_button<'a>(header: Rectangle) -> Button<'a, NavHeaderAction> {
102 Button::new(
103 Rectangle::new(
104 header.top_left + Point::new(16, 12),
105 Size::new(BACK_BUTTON_WIDTH, header.size.height.saturating_sub(24)),
106 ),
107 ButtonSpec {
108 key: NavHeaderAction::Back,
109 icon: None,
110 label: Localized::new("", ""),
111 kind: ButtonKind::Ghost,
112 },
113 )
114}src/alert/view.rs (lines 130-138)
127 fn buttons(&self, panel: Rectangle) -> [Button<'a, u8>; N] {
128 core::array::from_fn(|index| {
129 let action = self.spec.actions[index];
130 Button::new(
131 button_frames::<N>(panel)[index],
132 ButtonSpec {
133 key: action.id,
134 icon: None,
135 label: action.label,
136 kind: button_kind(action.role),
137 },
138 )
139 })
140 }src/alert_host/presented.rs (lines 152-160)
148 fn buttons(&self, panel: Rectangle) -> Vec<Button<'a, u8>, MAX_ACTIONS> {
149 let count = self.actions.len().max(1);
150 let mut buttons = Vec::new();
151 for (index, action) in self.actions.iter().enumerate() {
152 let _ = buttons.push(Button::new(
153 button_frame(panel, count, index),
154 ButtonSpec {
155 key: action.id,
156 icon: None,
157 label: action.label,
158 kind: button_kind(action.role),
159 },
160 ));
161 }
162 buttons
163 }Sourcepub fn clear_touch_state(&mut self)
pub fn clear_touch_state(&mut self)
Clears transient touch state.
Examples found in repository?
src/button/mod.rs (line 168)
156 fn start_touch(&mut self, touch: TouchEvent) -> ButtonTouchResponse<K> {
157 let was_highlighted = self.highlighted;
158 if touch.within(self.frame) {
159 self.touch_active = true;
160 self.highlighted = true;
161 return ButtonTouchResponse {
162 action: None,
163 captured: true,
164 redraw: !was_highlighted,
165 };
166 }
167
168 self.clear_touch_state();
169 ButtonTouchResponse {
170 action: None,
171 captured: false,
172 redraw: was_highlighted,
173 }
174 }
175
176 fn move_touch(&mut self, touch: TouchEvent) -> ButtonTouchResponse<K> {
177 if !self.touch_active {
178 return ButtonTouchResponse {
179 action: None,
180 captured: false,
181 redraw: false,
182 };
183 }
184
185 let highlighted = touch.within(self.frame);
186 let redraw = highlighted != self.highlighted;
187 self.highlighted = highlighted;
188 ButtonTouchResponse {
189 action: None,
190 captured: true,
191 redraw,
192 }
193 }
194
195 fn finish_touch(&mut self, touch: TouchEvent) -> ButtonTouchResponse<K> {
196 if !self.touch_active {
197 return ButtonTouchResponse {
198 action: None,
199 captured: false,
200 redraw: false,
201 };
202 }
203
204 let action = (self.highlighted && touch.within(self.frame)).then_some(self.spec.key);
205 let redraw = self.highlighted;
206 self.clear_touch_state();
207 ButtonTouchResponse {
208 action,
209 captured: true,
210 redraw,
211 }
212 }
213
214 fn cancel_touch(&mut self) -> ButtonTouchResponse<K> {
215 if !self.touch_active {
216 return ButtonTouchResponse {
217 action: None,
218 captured: false,
219 redraw: false,
220 };
221 }
222
223 let redraw = self.highlighted;
224 self.clear_touch_state();
225 ButtonTouchResponse {
226 action: None,
227 captured: true,
228 redraw,
229 }
230 }Sourcepub const fn is_highlighted(&self) -> bool
pub const fn is_highlighted(&self) -> bool
Returns whether the button is highlighted.
Sourcepub fn draw<D>(&self, display: &mut D, theme: &FsTheme, i18n: &I18n<'a>)where
D: DrawTarget<Color = Rgb565>,
pub fn draw<D>(&self, display: &mut D, theme: &FsTheme, i18n: &I18n<'a>)where
D: DrawTarget<Color = Rgb565>,
Draws the button using its current internal highlight state.
Examples found in repository?
examples/buttons.rs (line 44)
11fn main() {
12 let mut canvas = support::NullCanvas::new(Size::new(320, 240));
13 let theme = support::theme();
14 let i18n = support::i18n();
15
16 let mut primary = Button::new(
17 Rectangle::new(Point::new(16, 16), Size::new(132, 56)),
18 ButtonSpec {
19 key: 1_u8,
20 icon: Some("+"),
21 label: Localized::new("button.add", "Add device"),
22 kind: ButtonKind::Primary,
23 },
24 );
25 let secondary = Button::new(
26 Rectangle::new(Point::new(16, 84), Size::new(132, 48)),
27 ButtonSpec {
28 key: 2_u8,
29 icon: None,
30 label: Localized::new("button.more", "More"),
31 kind: ButtonKind::Secondary,
32 },
33 );
34 let destructive = Button::new(
35 Rectangle::new(Point::new(16, 144), Size::new(132, 48)),
36 ButtonSpec {
37 key: 3_u8,
38 icon: None,
39 label: Localized::new("button.delete", "Delete"),
40 kind: ButtonKind::Destructive,
41 },
42 );
43
44 primary.draw(&mut canvas, &theme, &i18n);
45 secondary.draw(&mut canvas, &theme, &i18n);
46 destructive.draw(&mut canvas, &theme, &i18n);
47
48 let _ = primary.handle_touch(TouchEvent::new(Point::new(24, 24), TouchPhase::Start, 1));
49 let response = primary.handle_touch(TouchEvent::new(Point::new(24, 24), TouchPhase::End, 2));
50 let _pressed = response.action == Some(1);
51
52 let _ = Rgb565::BLACK;
53}Sourcepub fn handle_touch(&mut self, touch: TouchEvent) -> ButtonTouchResponse<K>
pub fn handle_touch(&mut self, touch: TouchEvent) -> ButtonTouchResponse<K>
Updates touch tracking and returns button interaction output.
Examples found in repository?
examples/buttons.rs (line 48)
11fn main() {
12 let mut canvas = support::NullCanvas::new(Size::new(320, 240));
13 let theme = support::theme();
14 let i18n = support::i18n();
15
16 let mut primary = Button::new(
17 Rectangle::new(Point::new(16, 16), Size::new(132, 56)),
18 ButtonSpec {
19 key: 1_u8,
20 icon: Some("+"),
21 label: Localized::new("button.add", "Add device"),
22 kind: ButtonKind::Primary,
23 },
24 );
25 let secondary = Button::new(
26 Rectangle::new(Point::new(16, 84), Size::new(132, 48)),
27 ButtonSpec {
28 key: 2_u8,
29 icon: None,
30 label: Localized::new("button.more", "More"),
31 kind: ButtonKind::Secondary,
32 },
33 );
34 let destructive = Button::new(
35 Rectangle::new(Point::new(16, 144), Size::new(132, 48)),
36 ButtonSpec {
37 key: 3_u8,
38 icon: None,
39 label: Localized::new("button.delete", "Delete"),
40 kind: ButtonKind::Destructive,
41 },
42 );
43
44 primary.draw(&mut canvas, &theme, &i18n);
45 secondary.draw(&mut canvas, &theme, &i18n);
46 destructive.draw(&mut canvas, &theme, &i18n);
47
48 let _ = primary.handle_touch(TouchEvent::new(Point::new(24, 24), TouchPhase::Start, 1));
49 let response = primary.handle_touch(TouchEvent::new(Point::new(24, 24), TouchPhase::End, 2));
50 let _pressed = response.action == Some(1);
51
52 let _ = Rgb565::BLACK;
53}Sourcepub fn draw_state<D>(
&self,
display: &mut D,
theme: &FsTheme,
i18n: &I18n<'a>,
highlighted: bool,
)where
D: DrawTarget<Color = Rgb565>,
pub fn draw_state<D>(
&self,
display: &mut D,
theme: &FsTheme,
i18n: &I18n<'a>,
highlighted: bool,
)where
D: DrawTarget<Color = Rgb565>,
Draws the button using an explicit highlight state.
Examples found in repository?
More examples
src/alert/view.rs (lines 118-123)
62 pub fn draw_state<D>(&self, display: &mut D, panel: Rectangle, theme: &FsTheme, i18n: &I18n<'a>)
63 where
64 D: embedded_graphics::draw_target::DrawTarget<Color = Rgb565>,
65 {
66 let layout = alert_layout_in_panel::<N>(panel, i18n.text(self.spec.message));
67 RoundedRectangle::with_equal_corners(
68 Rectangle::new(panel.top_left + Point::new(6, 8), panel.size),
69 Size::new(22, 22),
70 )
71 .into_styled(PrimitiveStyle::with_fill(theme.dim))
72 .draw(display)
73 .ok();
74
75 let panel_style = PrimitiveStyleBuilder::new()
76 .fill_color(theme.surface)
77 .stroke_color(theme.surface_alt)
78 .stroke_width(2)
79 .build();
80 RoundedRectangle::with_equal_corners(panel, Size::new(22, 22))
81 .into_styled(panel_style)
82 .draw(display)
83 .ok();
84
85 let title_style = MonoTextStyleBuilder::new()
86 .font(&FONT_9X18_BOLD)
87 .text_color(kind_color(self.spec.kind, theme))
88 .build();
89 let message_style = MonoTextStyleBuilder::new()
90 .font(&FONT_7X14)
91 .text_color(theme.text_secondary)
92 .build();
93 let text_style = TextStyleBuilder::new()
94 .alignment(Alignment::Center)
95 .baseline(Baseline::Middle)
96 .build();
97
98 Text::with_text_style(
99 i18n.text(self.spec.title),
100 panel.center() + Point::new(0, -40),
101 title_style,
102 text_style,
103 )
104 .draw(display)
105 .ok();
106 for (index, line) in layout.message_lines.iter().enumerate() {
107 Text::with_text_style(
108 line,
109 Point::new(panel.center().x, message_top(panel) + (index as i32 * 18)),
110 message_style,
111 text_style,
112 )
113 .draw(display)
114 .ok();
115 }
116
117 for button in self.buttons(panel) {
118 button.draw_state(
119 display,
120 theme,
121 i18n,
122 self.touch_state.is_highlighted(&button),
123 );
124 }
125 }src/alert_host/presented.rs (lines 139-144)
79 pub(super) fn draw<D>(
80 &self,
81 display: &mut D,
82 panel: Rectangle,
83 theme: &FsTheme,
84 i18n: &I18n<'a>,
85 ) where
86 D: UiCanvas,
87 {
88 let layout = alert_layout_in_panel::<1>(panel, i18n.text(self.message));
89 RoundedRectangle::with_equal_corners(
90 Rectangle::new(panel.top_left + Point::new(6, 8), panel.size),
91 Size::new(22, 22),
92 )
93 .into_styled(PrimitiveStyle::with_fill(theme.dim))
94 .draw(display)
95 .ok();
96 RoundedRectangle::with_equal_corners(panel, Size::new(22, 22))
97 .into_styled(
98 PrimitiveStyleBuilder::new()
99 .fill_color(theme.surface)
100 .stroke_color(theme.surface_alt)
101 .stroke_width(2)
102 .build(),
103 )
104 .draw(display)
105 .ok();
106
107 let title_style = MonoTextStyleBuilder::new()
108 .font(&FONT_9X18_BOLD)
109 .text_color(kind_color(self.kind, theme))
110 .build();
111 let message_style = MonoTextStyleBuilder::new()
112 .font(&FONT_7X14)
113 .text_color(theme.text_secondary)
114 .build();
115 let text_style = TextStyleBuilder::new()
116 .alignment(Alignment::Center)
117 .baseline(Baseline::Middle)
118 .build();
119
120 Text::with_text_style(
121 i18n.text(self.title),
122 panel.center() + Point::new(0, -40),
123 title_style,
124 text_style,
125 )
126 .draw(display)
127 .ok();
128 for (index, line) in layout.message_lines.iter().enumerate() {
129 Text::with_text_style(
130 line,
131 Point::new(panel.center().x, message_top(panel) + (index as i32 * 18)),
132 message_style,
133 text_style,
134 )
135 .draw(display)
136 .ok();
137 }
138 for button in self.buttons(panel) {
139 button.draw_state(
140 display,
141 theme,
142 i18n,
143 self.touch_state.is_highlighted(&button),
144 );
145 }
146 }src/stack_view.rs (line 167)
120 pub fn draw_chrome<D>(
121 &self,
122 display: &mut D,
123 theme: &FsTheme,
124 i18n: &I18n<'a>,
125 touch: &ButtonTouchState<NavHeaderAction>,
126 ) where
127 D: DrawTarget<Color = Rgb565>,
128 {
129 let shell = PrimitiveStyleBuilder::new()
130 .fill_color(theme.surface_alt)
131 .stroke_color(theme.surface)
132 .stroke_width(2)
133 .build();
134 self.frame.into_styled(shell).draw(display).ok();
135
136 self.header
137 .into_styled(PrimitiveStyle::with_fill(theme.surface))
138 .draw(display)
139 .ok();
140 Line::new(
141 self.header.top_left + Point::new(0, self.header.size.height as i32),
142 self.header.bottom_right().unwrap_or(self.header.top_left),
143 )
144 .into_styled(PrimitiveStyle::with_stroke(theme.surface_alt, 2))
145 .draw(display)
146 .ok();
147
148 let title_style = MonoTextStyleBuilder::new()
149 .font(&FONT_9X18_BOLD)
150 .text_color(theme.text_primary)
151 .build();
152 let back_style = MonoTextStyleBuilder::new()
153 .font(&FONT_7X14)
154 .text_color(theme.text_primary)
155 .build();
156 let text_style = TextStyleBuilder::new()
157 .alignment(Alignment::Center)
158 .baseline(Baseline::Middle)
159 .build();
160 let settled_back_button = self.back_title.is_some() && self.secondary_title.is_none();
161
162 if settled_back_button {
163 let button = self
164 .back_button
165 .as_ref()
166 .expect("settled stacked headers include a back button");
167 button.draw_state(display, theme, i18n, touch.is_highlighted(button));
168 let arrow = MonoTextStyleBuilder::new()
169 .font(&FONT_7X14)
170 .text_color(theme.text_primary)
171 .build();
172 Text::with_text_style(
173 "<",
174 button.frame.top_left + Point::new(18, (button.frame.size.height / 2) as i32),
175 arrow,
176 TextStyleBuilder::new()
177 .alignment(Alignment::Center)
178 .baseline(Baseline::Middle)
179 .build(),
180 )
181 .draw(display)
182 .ok();
183 }
184
185 let mut header = display.clipped(&self.header);
186 if settled_back_button {
187 let title = self
188 .back_title
189 .expect("settled stacked headers include a back title");
190 Text::with_text_style(
191 i18n.text(title),
192 back_title_center(self.back_button.as_ref()),
193 back_style,
194 text_style,
195 )
196 .draw(&mut header)
197 .ok();
198 }
199 draw_title(
200 &mut header,
201 i18n.text(self.active_title.title),
202 self.active_title.center,
203 title_style,
204 text_style,
205 );
206 if let Some(title) = self.secondary_title {
207 draw_title(
208 &mut header,
209 i18n.text(title.title),
210 title.center,
211 title_style,
212 text_style,
213 );
214 }
215 }Trait Implementations§
impl<'a, K: Copy> Copy for Button<'a, K>
impl<'a, K: Eq> Eq for Button<'a, K>
impl<'a, K> StructuralPartialEq for Button<'a, K>
Auto Trait Implementations§
impl<'a, K> Freeze for Button<'a, K>where
K: Freeze,
impl<'a, K> RefUnwindSafe for Button<'a, K>where
K: RefUnwindSafe,
impl<'a, K> Send for Button<'a, K>where
K: Send,
impl<'a, K> Sync for Button<'a, K>where
K: Sync,
impl<'a, K> Unpin for Button<'a, K>where
K: Unpin,
impl<'a, K> UnsafeUnpin for Button<'a, K>where
K: UnsafeUnpin,
impl<'a, K> UnwindSafe for Button<'a, K>where
K: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CheckedAs for T
impl<T> CheckedAs for T
Source§fn checked_as<Dst>(self) -> Option<Dst>where
T: CheckedCast<Dst>,
fn checked_as<Dst>(self) -> Option<Dst>where
T: CheckedCast<Dst>,
Casts the value.
Source§impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere
Src: CheckedCast<Dst>,
impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere
Src: CheckedCast<Dst>,
Source§fn checked_cast_from(src: Src) -> Option<Dst>
fn checked_cast_from(src: Src) -> Option<Dst>
Casts the value.
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> OverflowingAs for T
impl<T> OverflowingAs for T
Source§fn overflowing_as<Dst>(self) -> (Dst, bool)where
T: OverflowingCast<Dst>,
fn overflowing_as<Dst>(self) -> (Dst, bool)where
T: OverflowingCast<Dst>,
Casts the value.
Source§impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere
Src: OverflowingCast<Dst>,
impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere
Src: OverflowingCast<Dst>,
Source§fn overflowing_cast_from(src: Src) -> (Dst, bool)
fn overflowing_cast_from(src: Src) -> (Dst, bool)
Casts the value.
Source§impl<T> SaturatingAs for T
impl<T> SaturatingAs for T
Source§fn saturating_as<Dst>(self) -> Dstwhere
T: SaturatingCast<Dst>,
fn saturating_as<Dst>(self) -> Dstwhere
T: SaturatingCast<Dst>,
Casts the value.
Source§impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere
Src: SaturatingCast<Dst>,
impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere
Src: SaturatingCast<Dst>,
Source§fn saturating_cast_from(src: Src) -> Dst
fn saturating_cast_from(src: Src) -> Dst
Casts the value.
Source§impl<T> UnwrappedAs for T
impl<T> UnwrappedAs for T
Source§fn unwrapped_as<Dst>(self) -> Dstwhere
T: UnwrappedCast<Dst>,
fn unwrapped_as<Dst>(self) -> Dstwhere
T: UnwrappedCast<Dst>,
Casts the value.
Source§impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere
Src: UnwrappedCast<Dst>,
impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere
Src: UnwrappedCast<Dst>,
Source§fn unwrapped_cast_from(src: Src) -> Dst
fn unwrapped_cast_from(src: Src) -> Dst
Casts the value.
Source§impl<T> WrappingAs for T
impl<T> WrappingAs for T
Source§fn wrapping_as<Dst>(self) -> Dstwhere
T: WrappingCast<Dst>,
fn wrapping_as<Dst>(self) -> Dstwhere
T: WrappingCast<Dst>,
Casts the value.
Source§impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere
Src: WrappingCast<Dst>,
impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere
Src: WrappingCast<Dst>,
Source§fn wrapping_cast_from(src: Src) -> Dst
fn wrapping_cast_from(src: Src) -> Dst
Casts the value.