parent
5052594789
commit
5a9c2a1363
After Width: | Height: | Size: 383 B |
@ -0,0 +1,60 @@
|
|||||||
|
use crate::{
|
||||||
|
time::Duration,
|
||||||
|
ui::{
|
||||||
|
component::{Component, Event, EventCtx, TimerToken},
|
||||||
|
geometry::Rect,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Timeout {
|
||||||
|
time_ms: u32,
|
||||||
|
timer: Option<TimerToken>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum TimeoutMsg {
|
||||||
|
TimedOut,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Timeout {
|
||||||
|
pub fn new(time_ms: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
time_ms,
|
||||||
|
timer: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Timeout {
|
||||||
|
type Msg = TimeoutMsg;
|
||||||
|
|
||||||
|
fn place(&mut self, _bounds: Rect) -> Rect {
|
||||||
|
Rect::zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||||
|
match event {
|
||||||
|
// Set up timer.
|
||||||
|
Event::Attach => {
|
||||||
|
self.timer = Some(ctx.request_timer(Duration::from_millis(self.time_ms)));
|
||||||
|
None
|
||||||
|
}
|
||||||
|
// Fire.
|
||||||
|
Event::Timer(token) if Some(token) == self.timer => {
|
||||||
|
self.timer = None;
|
||||||
|
Some(TimeoutMsg::TimedOut)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint(&mut self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ui_debug")]
|
||||||
|
impl crate::trace::Trace for Timeout {
|
||||||
|
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||||
|
t.open("Timeout");
|
||||||
|
t.int(self.time_ms as i64);
|
||||||
|
t.close();
|
||||||
|
}
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
pub mod obj;
|
pub mod obj;
|
||||||
pub mod result;
|
pub mod result;
|
||||||
|
pub mod util;
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
use crate::{
|
||||||
|
error::Error,
|
||||||
|
micropython::{
|
||||||
|
iter::{Iter, IterBuf},
|
||||||
|
obj::Obj,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use cstr_core::cstr;
|
||||||
|
use heapless::Vec;
|
||||||
|
|
||||||
|
pub fn iter_into_array<T, const N: usize>(iterable: Obj) -> Result<[T; N], Error>
|
||||||
|
where
|
||||||
|
T: TryFrom<Obj, Error = Error>,
|
||||||
|
{
|
||||||
|
let err = Error::ValueError(cstr!("Invalid iterable length"));
|
||||||
|
let mut vec = Vec::<T, N>::new();
|
||||||
|
let mut iter_buf = IterBuf::new();
|
||||||
|
for item in Iter::try_from_obj_with_buf(iterable, &mut iter_buf)? {
|
||||||
|
vec.push(item.try_into()?).map_err(|_| err)?;
|
||||||
|
}
|
||||||
|
// Returns error if array.len() != N
|
||||||
|
vec.into_array().map_err(|_| err)
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
use crate::ui::{
|
||||||
|
component::{Component, Event, EventCtx},
|
||||||
|
geometry::{Grid, GridCellSpan, Rect},
|
||||||
|
model_tt::{
|
||||||
|
component::button::{Button, ButtonMsg},
|
||||||
|
theme,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const NUMBERS: [u32; 5] = [12, 18, 20, 24, 33];
|
||||||
|
const LABELS: [&str; 5] = ["12", "18", "20", "24", "33"];
|
||||||
|
const CELLS: [(usize, usize); 5] = [(0, 0), (0, 2), (0, 4), (1, 1), (1, 3)];
|
||||||
|
|
||||||
|
pub struct SelectWordCount {
|
||||||
|
button: [Button<&'static str>; NUMBERS.len()],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SelectWordCountMsg {
|
||||||
|
Selected(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SelectWordCount {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
SelectWordCount {
|
||||||
|
button: LABELS.map(Button::with_text),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for SelectWordCount {
|
||||||
|
type Msg = SelectWordCountMsg;
|
||||||
|
|
||||||
|
fn place(&mut self, bounds: Rect) -> Rect {
|
||||||
|
let (_, bounds) = bounds.split_bottom(theme::button_rows(2));
|
||||||
|
let grid = Grid::new(bounds, 2, 6).with_spacing(theme::BUTTON_SPACING);
|
||||||
|
for (btn, (x, y)) in self.button.iter_mut().zip(CELLS) {
|
||||||
|
btn.place(grid.cells(GridCellSpan {
|
||||||
|
from: (x, y),
|
||||||
|
to: (x, y + 1),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
bounds
|
||||||
|
}
|
||||||
|
|
||||||
|
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||||
|
for (i, btn) in self.button.iter_mut().enumerate() {
|
||||||
|
if let Some(ButtonMsg::Clicked) = btn.event(ctx, event) {
|
||||||
|
return Some(SelectWordCountMsg::Selected(NUMBERS[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint(&mut self) {
|
||||||
|
for btn in self.button.iter_mut() {
|
||||||
|
btn.paint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||||
|
for btn in self.button.iter() {
|
||||||
|
btn.bounds(sink)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ui_debug")]
|
||||||
|
impl crate::trace::Trace for SelectWordCount {
|
||||||
|
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||||
|
t.open("SelectWordCount");
|
||||||
|
t.close();
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Loading…
Reference in new issue