You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
220 lines
7.0 KiB
220 lines
7.0 KiB
use core::convert::{TryFrom, TryInto};
|
|
|
|
use crate::{
|
|
error::Error,
|
|
micropython::{buffer::Buffer, map::Map, obj::Obj, qstr::Qstr},
|
|
ui::{
|
|
component::{text::paragraphs::Paragraphs, Child, FormattedText, Paginated, PaginatedMsg},
|
|
display,
|
|
layout::obj::LayoutObj,
|
|
},
|
|
util,
|
|
};
|
|
|
|
use super::{
|
|
component::{Button, ButtonPage, Title},
|
|
theme,
|
|
};
|
|
|
|
impl<T> TryFrom<PaginatedMsg<T, bool>> for Obj {
|
|
type Error = Error;
|
|
|
|
fn try_from(val: PaginatedMsg<T, bool>) -> Result<Self, Self::Error> {
|
|
match val {
|
|
PaginatedMsg::Content(_) => 2.try_into(),
|
|
PaginatedMsg::Controls(c) => Ok(c.into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
extern "C" fn ui_layout_new_confirm_action(
|
|
n_args: usize,
|
|
args: *const Obj,
|
|
kwargs: *const Map,
|
|
) -> Obj {
|
|
let block = |_args: &[Obj], kwargs: &Map| {
|
|
let title: Buffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
|
let action: Option<Buffer> = kwargs.get(Qstr::MP_QSTR_action)?.try_into_option()?;
|
|
let description: Option<Buffer> =
|
|
kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?;
|
|
let verb: Option<Buffer> = kwargs.get(Qstr::MP_QSTR_verb)?.try_into_option()?;
|
|
let verb_cancel: Option<Buffer> =
|
|
kwargs.get(Qstr::MP_QSTR_verb_cancel)?.try_into_option()?;
|
|
let reverse: bool = kwargs.get(Qstr::MP_QSTR_reverse)?.try_into()?;
|
|
|
|
let format = match (&action, &description, reverse) {
|
|
(Some(_), Some(_), false) => "{bold}{action}\n\r{normal}{description}",
|
|
(Some(_), Some(_), true) => "{normal}{description}\n\r{bold}{action}",
|
|
(Some(_), None, _) => "{bold}{action}",
|
|
(None, Some(_), _) => "{normal}{description}",
|
|
_ => "",
|
|
};
|
|
|
|
let left = verb_cancel
|
|
.map(|label| |area, pos| Button::with_text(area, pos, label, theme::button_cancel()));
|
|
let right = verb
|
|
.map(|label| |area, pos| Button::with_text(area, pos, label, theme::button_default()));
|
|
|
|
let obj = LayoutObj::new(Child::new(Title::new(display::screen(), title, |area| {
|
|
Paginated::<ButtonPage<_>>::new(
|
|
area,
|
|
|area| {
|
|
FormattedText::new::<theme::T1DefaultText>(area, format)
|
|
.with(b"action", action.unwrap_or("".into()))
|
|
.with(b"description", description.unwrap_or("".into()))
|
|
},
|
|
theme::BG,
|
|
)
|
|
})))?;
|
|
Ok(obj.into())
|
|
};
|
|
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
|
}
|
|
|
|
#[no_mangle]
|
|
extern "C" fn ui_layout_new_confirm_text(
|
|
n_args: usize,
|
|
args: *const Obj,
|
|
kwargs: *const Map,
|
|
) -> Obj {
|
|
let block = |_args: &[Obj], kwargs: &Map| {
|
|
let title: Buffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
|
let data: Buffer = kwargs.get(Qstr::MP_QSTR_data)?.try_into()?;
|
|
let description: Option<Buffer> =
|
|
kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?;
|
|
|
|
let obj = LayoutObj::new(Child::new(Title::new(display::screen(), title, |area| {
|
|
Paginated::<ButtonPage<_>>::new(
|
|
area,
|
|
|area| {
|
|
Paragraphs::new(area)
|
|
.add::<theme::T1DefaultText>(
|
|
theme::FONT_NORMAL,
|
|
description.unwrap_or("".into()),
|
|
)
|
|
.add::<theme::T1DefaultText>(theme::FONT_BOLD, data)
|
|
},
|
|
theme::BG,
|
|
)
|
|
})))?;
|
|
Ok(obj.into())
|
|
};
|
|
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::{
|
|
trace::{Trace, Tracer},
|
|
ui::model_t1::component::{Dialog, DialogMsg},
|
|
};
|
|
|
|
use super::*;
|
|
|
|
impl Tracer for Vec<u8> {
|
|
fn int(&mut self, i: i64) {
|
|
self.string(&i.to_string());
|
|
}
|
|
|
|
fn bytes(&mut self, b: &[u8]) {
|
|
self.extend(b)
|
|
}
|
|
|
|
fn string(&mut self, s: &str) {
|
|
self.extend(s.as_bytes())
|
|
}
|
|
|
|
fn symbol(&mut self, name: &str) {
|
|
self.extend(name.as_bytes())
|
|
}
|
|
|
|
fn open(&mut self, name: &str) {
|
|
self.extend(b"<");
|
|
self.extend(name.as_bytes());
|
|
self.extend(b" ");
|
|
}
|
|
|
|
fn field(&mut self, name: &str, value: &dyn Trace) {
|
|
self.extend(name.as_bytes());
|
|
self.extend(b":");
|
|
value.trace(self);
|
|
self.extend(b" ");
|
|
}
|
|
|
|
fn close(&mut self) {
|
|
self.extend(b">")
|
|
}
|
|
}
|
|
|
|
fn trace(val: &impl Trace) -> String {
|
|
let mut t = Vec::new();
|
|
val.trace(&mut t);
|
|
String::from_utf8(t).unwrap()
|
|
}
|
|
|
|
impl<T> TryFrom<DialogMsg<T>> for Obj
|
|
where
|
|
Obj: TryFrom<T>,
|
|
Error: From<<T as TryInto<Obj>>::Error>,
|
|
{
|
|
type Error = Error;
|
|
|
|
fn try_from(val: DialogMsg<T>) -> Result<Self, Self::Error> {
|
|
match val {
|
|
DialogMsg::Content(c) => Ok(c.try_into()?),
|
|
DialogMsg::LeftClicked => 1.try_into(),
|
|
DialogMsg::RightClicked => 2.try_into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn trace_example_layout() {
|
|
let layout = Child::new(Dialog::new(
|
|
display::screen(),
|
|
|area| {
|
|
FormattedText::new::<theme::T1DefaultText>(
|
|
area,
|
|
"Testing text layout, with some text, and some more text. And {param}",
|
|
)
|
|
.with(b"param", b"parameters!")
|
|
},
|
|
Some(|area, pos| Button::with_text(area, pos, "Left", theme::button_cancel())),
|
|
Some(|area, pos| Button::with_text(area, pos, "Right", theme::button_default())),
|
|
));
|
|
assert_eq!(
|
|
trace(&layout),
|
|
r#"<Dialog content:<Text content:Testing text layout,
|
|
with some text, and
|
|
some more text. And p-
|
|
arameters! > left:<Button text:Left > right:<Button text:Right > >"#
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn trace_layout_title() {
|
|
let layout = Child::new(Title::new(display::screen(), "Please confirm", |area| {
|
|
Dialog::new(
|
|
area,
|
|
|area| {
|
|
FormattedText::new::<theme::T1DefaultText>(
|
|
area,
|
|
"Testing text layout, with some text, and some more text. And {param}",
|
|
)
|
|
.with(b"param", b"parameters!")
|
|
},
|
|
Some(|area, pos| Button::with_text(area, pos, "Left", theme::button_cancel())),
|
|
Some(|area, pos| Button::with_text(area, pos, "Right", theme::button_default())),
|
|
)
|
|
}));
|
|
assert_eq!(
|
|
trace(&layout),
|
|
r#"<Title title:Please confirm content:<Dialog content:<Text content:Testing text layout,
|
|
with some text, and
|
|
some more text. And p-
|
|
arameters! > left:<Button text:Left > right:<Button text:Right > > >"#
|
|
)
|
|
}
|
|
}
|