mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-03-30 15:05:43 +00:00
chore(core/rust): delete model_1 code - it should use model_r
[no changelog]
This commit is contained in:
parent
a480bf0f18
commit
f8c432e955
32
ci/build.yml
32
ci/build.yml
@ -133,22 +133,6 @@ core fw btconly production build:
|
|||||||
- firmware-T2T1-btconly-production-*.*.*-$CI_COMMIT_SHORT_SHA.bin
|
- firmware-T2T1-btconly-production-*.*.*-$CI_COMMIT_SHORT_SHA.bin
|
||||||
expire_in: 1 week
|
expire_in: 1 week
|
||||||
|
|
||||||
core fw btconly t1 build:
|
|
||||||
stage: build
|
|
||||||
<<: *gitlab_caching
|
|
||||||
needs: []
|
|
||||||
variables:
|
|
||||||
BITCOIN_ONLY: "1"
|
|
||||||
TREZOR_MODEL: "1"
|
|
||||||
script:
|
|
||||||
- nix-shell --run "poetry run make -C core build_firmware"
|
|
||||||
- cp core/build/firmware/firmware.bin firmware-T1B1-btconly-t1-$CORE_VERSION-$CI_COMMIT_SHORT_SHA.bin
|
|
||||||
artifacts:
|
|
||||||
name: "$CI_JOB_NAME-$CI_COMMIT_SHORT_SHA"
|
|
||||||
paths:
|
|
||||||
- firmware-T1B1-btconly-t1-*.*.*-$CI_COMMIT_SHORT_SHA.bin
|
|
||||||
expire_in: 1 week
|
|
||||||
|
|
||||||
# Non-frozen emulator build. This means you still need Python files
|
# Non-frozen emulator build. This means you still need Python files
|
||||||
# present which get interpreted.
|
# present which get interpreted.
|
||||||
core unix regular build:
|
core unix regular build:
|
||||||
@ -289,22 +273,6 @@ core unix frozen debug build arm:
|
|||||||
tags:
|
tags:
|
||||||
- docker_darwin_arm
|
- docker_darwin_arm
|
||||||
|
|
||||||
core unix frozen btconly debug t1 build:
|
|
||||||
stage: build
|
|
||||||
<<: *gitlab_caching
|
|
||||||
needs: []
|
|
||||||
variables:
|
|
||||||
BITCOIN_ONLY: "1"
|
|
||||||
TREZOR_MODEL: "1"
|
|
||||||
script:
|
|
||||||
- nix-shell --run "poetry run make -C core build_unix_frozen"
|
|
||||||
- mv core/build/unix/trezor-emu-core core/build/unix/trezor-emu-core-bitcoinonly
|
|
||||||
artifacts:
|
|
||||||
name: "$CI_JOB_NAME-$CI_COMMIT_SHORT_SHA"
|
|
||||||
paths:
|
|
||||||
- core/build/unix # most of it needed by test_rust
|
|
||||||
expire_in: 1 week
|
|
||||||
|
|
||||||
core macos frozen regular build:
|
core macos frozen regular build:
|
||||||
stage: build
|
stage: build
|
||||||
<<: *gitlab_caching
|
<<: *gitlab_caching
|
||||||
|
11
ci/test.yml
11
ci/test.yml
@ -47,17 +47,6 @@ core unit asan test:
|
|||||||
- nix-shell --run "poetry run make -C core clean build_unix | ts -s"
|
- nix-shell --run "poetry run make -C core clean build_unix | ts -s"
|
||||||
- nix-shell --run "poetry run make -C core test_rust | ts -s"
|
- nix-shell --run "poetry run make -C core test_rust | ts -s"
|
||||||
|
|
||||||
core unit t1 test:
|
|
||||||
stage: test
|
|
||||||
<<: *gitlab_caching
|
|
||||||
needs:
|
|
||||||
- core unix frozen btconly debug t1 build
|
|
||||||
variables:
|
|
||||||
BITCOIN_ONLY: "1"
|
|
||||||
TREZOR_MODEL: "1"
|
|
||||||
script:
|
|
||||||
- nix-shell --run "poetry run make -C core test_rust | ts -s"
|
|
||||||
|
|
||||||
# Device tests for Core. Running device tests and also comparing screens
|
# Device tests for Core. Running device tests and also comparing screens
|
||||||
# with the expected UI result.
|
# with the expected UI result.
|
||||||
# See artifacts for a comprehensive report of UI.
|
# See artifacts for a comprehensive report of UI.
|
||||||
|
@ -715,7 +715,9 @@ def cargo_build():
|
|||||||
else:
|
else:
|
||||||
profile = ''
|
profile = ''
|
||||||
|
|
||||||
features = ['micropython', 'protobuf', f'model_t{TREZOR_MODEL.lower()}']
|
# T1 does not have its own Rust feature, it shares it with TR
|
||||||
|
model_feature = 'model_tr' if TREZOR_MODEL == '1' else f'model_t{TREZOR_MODEL.lower()}'
|
||||||
|
features = ['micropython', 'protobuf', model_feature]
|
||||||
if BITCOIN_ONLY == '1':
|
if BITCOIN_ONLY == '1':
|
||||||
features.append('bitcoin_only')
|
features.append('bitcoin_only')
|
||||||
features.append('ui')
|
features.append('ui')
|
||||||
|
@ -667,7 +667,9 @@ RUST_LIB = 'trezor_lib'
|
|||||||
RUST_LIBPATH = f'{RUST_LIBDIR}/lib{RUST_LIB}.a'
|
RUST_LIBPATH = f'{RUST_LIBDIR}/lib{RUST_LIB}.a'
|
||||||
|
|
||||||
def cargo_build():
|
def cargo_build():
|
||||||
features = ['micropython', 'protobuf', f'model_t{TREZOR_MODEL.lower()}']
|
# T1 does not have its own Rust feature, it shares it with TR
|
||||||
|
model_feature = 'model_tr' if TREZOR_MODEL == '1' else f'model_t{TREZOR_MODEL.lower()}'
|
||||||
|
features = ['micropython', 'protobuf', model_feature]
|
||||||
if BITCOIN_ONLY == '1':
|
if BITCOIN_ONLY == '1':
|
||||||
features.append('bitcoin_only')
|
features.append('bitcoin_only')
|
||||||
features.append('ui')
|
features.append('ui')
|
||||||
|
@ -9,7 +9,6 @@ build = "build.rs"
|
|||||||
default = ["model_tt"]
|
default = ["model_tt"]
|
||||||
bitcoin_only = []
|
bitcoin_only = []
|
||||||
model_tt = ["touch", "jpeg"]
|
model_tt = ["touch", "jpeg"]
|
||||||
model_t1 = ["buttons"]
|
|
||||||
model_tr = ["buttons"]
|
model_tr = ["buttons"]
|
||||||
micropython = []
|
micropython = []
|
||||||
protobuf = ["micropython"]
|
protobuf = ["micropython"]
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
//! Reexporting the `constant` module according to the
|
//! Reexporting the `constant` module according to the
|
||||||
//! current feature (Trezor model)
|
//! current feature (Trezor model)
|
||||||
|
|
||||||
#[cfg(all(
|
|
||||||
feature = "model_t1",
|
|
||||||
not(feature = "model_tr"),
|
|
||||||
not(feature = "model_tt")
|
|
||||||
))]
|
|
||||||
pub use super::model_t1::constant::*;
|
|
||||||
#[cfg(all(feature = "model_tr", not(feature = "model_tt")))]
|
#[cfg(all(feature = "model_tr", not(feature = "model_tt")))]
|
||||||
pub use super::model_tr::constant::*;
|
pub use super::model_tr::constant::*;
|
||||||
#[cfg(feature = "model_tt")]
|
#[cfg(feature = "model_tt")]
|
||||||
|
@ -13,8 +13,6 @@ mod util;
|
|||||||
#[cfg(feature = "micropython")]
|
#[cfg(feature = "micropython")]
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
|
|
||||||
#[cfg(feature = "model_t1")]
|
|
||||||
pub mod model_t1;
|
|
||||||
#[cfg(feature = "model_tr")]
|
#[cfg(feature = "model_tr")]
|
||||||
pub mod model_tr;
|
pub mod model_tr;
|
||||||
#[cfg(feature = "model_tt")]
|
#[cfg(feature = "model_tt")]
|
||||||
|
@ -1,190 +0,0 @@
|
|||||||
use crate::ui::{
|
|
||||||
component::{Component, Event, EventCtx},
|
|
||||||
display::{self, Color, Font},
|
|
||||||
event::{ButtonEvent, PhysicalButton},
|
|
||||||
geometry::{Offset, Point, Rect},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::theme;
|
|
||||||
|
|
||||||
pub enum ButtonMsg {
|
|
||||||
Clicked,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub enum ButtonPos {
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ButtonPos {
|
|
||||||
fn hit(&self, b: &PhysicalButton) -> bool {
|
|
||||||
matches!(
|
|
||||||
(self, b),
|
|
||||||
(Self::Left, PhysicalButton::Left) | (Self::Right, PhysicalButton::Right)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Button<T> {
|
|
||||||
area: Rect,
|
|
||||||
pos: ButtonPos,
|
|
||||||
baseline: Point,
|
|
||||||
content: ButtonContent<T>,
|
|
||||||
styles: ButtonStyleSheet,
|
|
||||||
state: State,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: AsRef<str>> Button<T> {
|
|
||||||
pub fn new(pos: ButtonPos, content: ButtonContent<T>, styles: ButtonStyleSheet) -> Self {
|
|
||||||
Self {
|
|
||||||
pos,
|
|
||||||
content,
|
|
||||||
styles,
|
|
||||||
baseline: Point::zero(),
|
|
||||||
area: Rect::zero(),
|
|
||||||
state: State::Released,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_text(pos: ButtonPos, text: T, styles: ButtonStyleSheet) -> Self {
|
|
||||||
Self::new(pos, ButtonContent::Text(text), styles)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_icon(pos: ButtonPos, image: &'static [u8], styles: ButtonStyleSheet) -> Self {
|
|
||||||
Self::new(pos, ButtonContent::Icon(image), styles)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn content(&self) -> &ButtonContent<T> {
|
|
||||||
&self.content
|
|
||||||
}
|
|
||||||
|
|
||||||
fn style(&self) -> &ButtonStyle {
|
|
||||||
match self.state {
|
|
||||||
State::Released => self.styles.normal,
|
|
||||||
State::Pressed => self.styles.active,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set(&mut self, ctx: &mut EventCtx, state: State) {
|
|
||||||
if self.state != state {
|
|
||||||
self.state = state;
|
|
||||||
ctx.request_paint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn placement(
|
|
||||||
area: Rect,
|
|
||||||
pos: ButtonPos,
|
|
||||||
content: &ButtonContent<T>,
|
|
||||||
styles: &ButtonStyleSheet,
|
|
||||||
) -> (Rect, Point) {
|
|
||||||
let border_width = if styles.normal.border_horiz { 2 } else { 0 };
|
|
||||||
let content_width = match content {
|
|
||||||
ButtonContent::Text(text) => styles.normal.font.text_width(text.as_ref()) - 1,
|
|
||||||
ButtonContent::Icon(_icon) => todo!(),
|
|
||||||
};
|
|
||||||
let button_width = content_width + 2 * border_width;
|
|
||||||
let area = match pos {
|
|
||||||
ButtonPos::Left => area.split_left(button_width).0,
|
|
||||||
ButtonPos::Right => area.split_right(button_width).1,
|
|
||||||
};
|
|
||||||
|
|
||||||
let start_of_baseline = area.bottom_left() + Offset::new(border_width, -2);
|
|
||||||
|
|
||||||
(area, start_of_baseline)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Component for Button<T>
|
|
||||||
where
|
|
||||||
T: AsRef<str>,
|
|
||||||
{
|
|
||||||
type Msg = ButtonMsg;
|
|
||||||
|
|
||||||
fn place(&mut self, bounds: Rect) -> Rect {
|
|
||||||
let (area, baseline) = Self::placement(bounds, self.pos, &self.content, &self.styles);
|
|
||||||
self.area = area;
|
|
||||||
self.baseline = baseline;
|
|
||||||
self.area
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
|
||||||
match event {
|
|
||||||
Event::Button(ButtonEvent::ButtonPressed(which)) if self.pos.hit(&which) => {
|
|
||||||
self.set(ctx, State::Pressed);
|
|
||||||
}
|
|
||||||
Event::Button(ButtonEvent::ButtonReleased(which)) if self.pos.hit(&which) => {
|
|
||||||
if matches!(self.state, State::Pressed) {
|
|
||||||
self.set(ctx, State::Released);
|
|
||||||
return Some(ButtonMsg::Clicked);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn paint(&mut self) {
|
|
||||||
let style = self.style();
|
|
||||||
|
|
||||||
match &self.content {
|
|
||||||
ButtonContent::Text(text) => {
|
|
||||||
let background_color = style.text_color.negate();
|
|
||||||
if style.border_horiz {
|
|
||||||
display::rect_fill_rounded1(self.area, background_color, theme::BG);
|
|
||||||
} else {
|
|
||||||
display::rect_fill(self.area, background_color)
|
|
||||||
}
|
|
||||||
|
|
||||||
display::text(
|
|
||||||
self.baseline,
|
|
||||||
text.as_ref(),
|
|
||||||
style.font,
|
|
||||||
style.text_color,
|
|
||||||
background_color,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
ButtonContent::Icon(_image) => {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
|
||||||
impl<T> crate::trace::Trace for Button<T>
|
|
||||||
where
|
|
||||||
T: AsRef<str> + crate::trace::Trace,
|
|
||||||
{
|
|
||||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
|
||||||
t.open("Button");
|
|
||||||
match &self.content {
|
|
||||||
ButtonContent::Text(text) => t.field("text", text),
|
|
||||||
ButtonContent::Icon(_) => t.symbol("icon"),
|
|
||||||
}
|
|
||||||
t.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
|
||||||
enum State {
|
|
||||||
Released,
|
|
||||||
Pressed,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ButtonContent<T> {
|
|
||||||
Text(T),
|
|
||||||
Icon(&'static [u8]),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ButtonStyleSheet {
|
|
||||||
pub normal: &'static ButtonStyle,
|
|
||||||
pub active: &'static ButtonStyle,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ButtonStyle {
|
|
||||||
pub font: Font,
|
|
||||||
pub text_color: Color,
|
|
||||||
pub border_horiz: bool,
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
use super::button::{Button, ButtonMsg::Clicked};
|
|
||||||
use crate::ui::{
|
|
||||||
component::{Child, Component, Event, EventCtx},
|
|
||||||
display::Font,
|
|
||||||
geometry::Rect,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub enum DialogMsg<T> {
|
|
||||||
Content(T),
|
|
||||||
LeftClicked,
|
|
||||||
RightClicked,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Dialog<T, U> {
|
|
||||||
content: Child<T>,
|
|
||||||
left_btn: Option<Child<Button<U>>>,
|
|
||||||
right_btn: Option<Child<Button<U>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U> Dialog<T, U>
|
|
||||||
where
|
|
||||||
T: Component,
|
|
||||||
U: AsRef<str>,
|
|
||||||
{
|
|
||||||
pub fn new(content: T, left: Option<Button<U>>, right: Option<Button<U>>) -> Self {
|
|
||||||
Self {
|
|
||||||
content: Child::new(content),
|
|
||||||
left_btn: left.map(Child::new),
|
|
||||||
right_btn: right.map(Child::new),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inner(&self) -> &T {
|
|
||||||
self.content.inner()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U> Component for Dialog<T, U>
|
|
||||||
where
|
|
||||||
T: Component,
|
|
||||||
U: AsRef<str>,
|
|
||||||
{
|
|
||||||
type Msg = DialogMsg<T::Msg>;
|
|
||||||
|
|
||||||
fn place(&mut self, bounds: Rect) -> Rect {
|
|
||||||
let button_height = Font::BOLD.line_height() + 2;
|
|
||||||
let (content_area, button_area) = bounds.split_bottom(button_height);
|
|
||||||
self.content.place(content_area);
|
|
||||||
self.left_btn.as_mut().map(|b| b.place(button_area));
|
|
||||||
self.right_btn.as_mut().map(|b| b.place(button_area));
|
|
||||||
bounds
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
|
||||||
if let Some(msg) = self.content.event(ctx, event) {
|
|
||||||
Some(DialogMsg::Content(msg))
|
|
||||||
} else if let Some(Clicked) = self.left_btn.as_mut().and_then(|b| b.event(ctx, event)) {
|
|
||||||
Some(DialogMsg::LeftClicked)
|
|
||||||
} else if let Some(Clicked) = self.right_btn.as_mut().and_then(|b| b.event(ctx, event)) {
|
|
||||||
Some(DialogMsg::RightClicked)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn paint(&mut self) {
|
|
||||||
self.content.paint();
|
|
||||||
if let Some(b) = self.left_btn.as_mut() {
|
|
||||||
b.paint();
|
|
||||||
}
|
|
||||||
if let Some(b) = self.right_btn.as_mut() {
|
|
||||||
b.paint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
|
||||||
impl<T, U> crate::trace::Trace for Dialog<T, U>
|
|
||||||
where
|
|
||||||
T: crate::trace::Trace,
|
|
||||||
U: crate::trace::Trace + AsRef<str>,
|
|
||||||
{
|
|
||||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
|
||||||
t.open("Dialog");
|
|
||||||
t.field("content", &self.content);
|
|
||||||
if let Some(label) = &self.left_btn {
|
|
||||||
t.field("left", label);
|
|
||||||
}
|
|
||||||
if let Some(label) = &self.right_btn {
|
|
||||||
t.field("right", label);
|
|
||||||
}
|
|
||||||
t.close();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
use super::theme;
|
|
||||||
use crate::ui::{
|
|
||||||
component::{Child, Component, Event, EventCtx},
|
|
||||||
display::{self, Font},
|
|
||||||
geometry::{Insets, Offset, Rect},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Frame<T, U> {
|
|
||||||
area: Rect,
|
|
||||||
title: U,
|
|
||||||
content: Child<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U> Frame<T, U>
|
|
||||||
where
|
|
||||||
T: Component,
|
|
||||||
U: AsRef<str>,
|
|
||||||
{
|
|
||||||
pub fn new(title: U, content: T) -> Self {
|
|
||||||
Self {
|
|
||||||
title,
|
|
||||||
area: Rect::zero(),
|
|
||||||
content: Child::new(content),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inner(&self) -> &T {
|
|
||||||
self.content.inner()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U> Component for Frame<T, U>
|
|
||||||
where
|
|
||||||
T: Component,
|
|
||||||
U: AsRef<str>,
|
|
||||||
{
|
|
||||||
type Msg = T::Msg;
|
|
||||||
|
|
||||||
fn place(&mut self, bounds: Rect) -> Rect {
|
|
||||||
const TITLE_SPACE: i16 = 4;
|
|
||||||
|
|
||||||
let (title_area, content_area) = bounds.split_top(Font::BOLD.line_height());
|
|
||||||
let content_area = content_area.inset(Insets::top(TITLE_SPACE));
|
|
||||||
|
|
||||||
self.area = title_area;
|
|
||||||
self.content.place(content_area);
|
|
||||||
bounds
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
|
||||||
self.content.event(ctx, event)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn paint(&mut self) {
|
|
||||||
display::text(
|
|
||||||
self.area.bottom_left() - Offset::y(2),
|
|
||||||
self.title.as_ref(),
|
|
||||||
Font::BOLD,
|
|
||||||
theme::FG,
|
|
||||||
theme::BG,
|
|
||||||
);
|
|
||||||
display::dotted_line(self.area.bottom_left(), self.area.width(), theme::FG);
|
|
||||||
self.content.paint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
|
||||||
impl<T, U> crate::trace::Trace for Frame<T, U>
|
|
||||||
where
|
|
||||||
T: crate::trace::Trace,
|
|
||||||
U: crate::trace::Trace + AsRef<str>,
|
|
||||||
{
|
|
||||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
|
||||||
t.open("Frame");
|
|
||||||
t.field("title", &self.title);
|
|
||||||
t.field("content", &self.content);
|
|
||||||
t.close();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
mod button;
|
|
||||||
mod dialog;
|
|
||||||
mod frame;
|
|
||||||
mod page;
|
|
||||||
|
|
||||||
use super::theme;
|
|
||||||
|
|
||||||
pub use button::{Button, ButtonContent, ButtonMsg, ButtonPos, ButtonStyle, ButtonStyleSheet};
|
|
||||||
pub use dialog::{Dialog, DialogMsg};
|
|
||||||
pub use frame::Frame;
|
|
||||||
pub use page::ButtonPage;
|
|
@ -1,227 +0,0 @@
|
|||||||
use crate::ui::{
|
|
||||||
component::{Component, ComponentExt, Event, EventCtx, Never, Pad, PageMsg, Paginate},
|
|
||||||
display::{self, Color, Font},
|
|
||||||
geometry::{Insets, Offset, Point, Rect},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{theme, Button, ButtonMsg, ButtonPos};
|
|
||||||
|
|
||||||
pub struct ButtonPage<T> {
|
|
||||||
content: T,
|
|
||||||
scrollbar: ScrollBar,
|
|
||||||
pad: Pad,
|
|
||||||
prev: Button<&'static str>,
|
|
||||||
next: Button<&'static str>,
|
|
||||||
cancel: Button<&'static str>,
|
|
||||||
confirm: Button<&'static str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> ButtonPage<T>
|
|
||||||
where
|
|
||||||
T: Paginate,
|
|
||||||
T: Component,
|
|
||||||
{
|
|
||||||
pub fn new(content: T, background: Color) -> Self {
|
|
||||||
Self {
|
|
||||||
content,
|
|
||||||
scrollbar: ScrollBar::vertical(),
|
|
||||||
pad: Pad::with_background(background),
|
|
||||||
prev: Button::with_text(ButtonPos::Left, "BACK", theme::button_cancel()),
|
|
||||||
next: Button::with_text(ButtonPos::Right, "NEXT", theme::button_default()),
|
|
||||||
cancel: Button::with_text(ButtonPos::Left, "CANCEL", theme::button_cancel()),
|
|
||||||
confirm: Button::with_text(ButtonPos::Right, "CONFIRM", theme::button_default()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn change_page(&mut self, ctx: &mut EventCtx, page: usize) {
|
|
||||||
// Change the page in the content, clear the background under it and make sure
|
|
||||||
// it gets completely repainted.
|
|
||||||
self.content.change_page(page);
|
|
||||||
self.content.request_complete_repaint(ctx);
|
|
||||||
self.pad.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Component for ButtonPage<T>
|
|
||||||
where
|
|
||||||
T: Component,
|
|
||||||
T: Paginate,
|
|
||||||
{
|
|
||||||
type Msg = PageMsg<T::Msg, bool>;
|
|
||||||
|
|
||||||
fn place(&mut self, bounds: Rect) -> Rect {
|
|
||||||
let button_height = Font::BOLD.line_height() + 2;
|
|
||||||
let (content_area, button_area) = bounds.split_bottom(button_height);
|
|
||||||
let (content_area, scrollbar_area) = content_area.split_right(ScrollBar::WIDTH);
|
|
||||||
let content_area = content_area.inset(Insets::top(1));
|
|
||||||
self.pad.place(bounds);
|
|
||||||
self.content.place(content_area);
|
|
||||||
let page_count = self.content.page_count();
|
|
||||||
self.scrollbar.set_count_and_active_page(page_count, 0);
|
|
||||||
self.scrollbar.place(scrollbar_area);
|
|
||||||
self.prev.place(button_area);
|
|
||||||
self.next.place(button_area);
|
|
||||||
self.cancel.place(button_area);
|
|
||||||
self.confirm.place(button_area);
|
|
||||||
bounds
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
|
||||||
ctx.set_page_count(self.scrollbar.page_count);
|
|
||||||
if self.scrollbar.has_previous_page() {
|
|
||||||
if let Some(ButtonMsg::Clicked) = self.prev.event(ctx, event) {
|
|
||||||
// Scroll up.
|
|
||||||
self.scrollbar.go_to_previous_page();
|
|
||||||
self.change_page(ctx, self.scrollbar.active_page);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
} else if let Some(ButtonMsg::Clicked) = self.cancel.event(ctx, event) {
|
|
||||||
return Some(PageMsg::Controls(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.scrollbar.has_next_page() {
|
|
||||||
if let Some(ButtonMsg::Clicked) = self.next.event(ctx, event) {
|
|
||||||
// Scroll down.
|
|
||||||
self.scrollbar.go_to_next_page();
|
|
||||||
self.change_page(ctx, self.scrollbar.active_page);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
} else if let Some(ButtonMsg::Clicked) = self.confirm.event(ctx, event) {
|
|
||||||
return Some(PageMsg::Controls(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(msg) = self.content.event(ctx, event) {
|
|
||||||
return Some(PageMsg::Content(msg));
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn paint(&mut self) {
|
|
||||||
self.pad.paint();
|
|
||||||
self.content.paint();
|
|
||||||
self.scrollbar.paint();
|
|
||||||
if self.scrollbar.has_previous_page() {
|
|
||||||
self.prev.paint();
|
|
||||||
} else {
|
|
||||||
self.cancel.paint();
|
|
||||||
}
|
|
||||||
if self.scrollbar.has_next_page() {
|
|
||||||
self.next.paint();
|
|
||||||
} else {
|
|
||||||
self.confirm.paint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
|
||||||
impl<T> crate::trace::Trace for ButtonPage<T>
|
|
||||||
where
|
|
||||||
T: crate::trace::Trace,
|
|
||||||
{
|
|
||||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
|
||||||
t.open("ButtonPage");
|
|
||||||
t.field("active_page", &self.scrollbar.active_page);
|
|
||||||
t.field("page_count", &self.scrollbar.page_count);
|
|
||||||
t.field("content", &self.content);
|
|
||||||
t.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ScrollBar {
|
|
||||||
area: Rect,
|
|
||||||
page_count: usize,
|
|
||||||
active_page: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ScrollBar {
|
|
||||||
pub const WIDTH: i16 = 8;
|
|
||||||
pub const DOT_SIZE: Offset = Offset::new(4, 4);
|
|
||||||
pub const DOT_INTERVAL: i16 = 6;
|
|
||||||
|
|
||||||
pub fn vertical() -> Self {
|
|
||||||
Self {
|
|
||||||
area: Rect::zero(),
|
|
||||||
page_count: 0,
|
|
||||||
active_page: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_count_and_active_page(&mut self, page_count: usize, active_page: usize) {
|
|
||||||
self.page_count = page_count;
|
|
||||||
self.active_page = active_page;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has_next_page(&self) -> bool {
|
|
||||||
self.active_page < self.page_count - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has_previous_page(&self) -> bool {
|
|
||||||
self.active_page > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn go_to_next_page(&mut self) {
|
|
||||||
self.active_page = self.active_page.saturating_add(1).min(self.page_count - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn go_to_previous_page(&mut self) {
|
|
||||||
self.active_page = self.active_page.saturating_sub(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn paint_dot(&self, active: bool, top_left: Point) {
|
|
||||||
let sides = [
|
|
||||||
Rect::from_top_left_and_size(top_left + Offset::x(1), Offset::new(2, 1)),
|
|
||||||
Rect::from_top_left_and_size(top_left + Offset::y(1), Offset::new(1, 2)),
|
|
||||||
Rect::from_top_left_and_size(
|
|
||||||
top_left + Offset::new(1, Self::DOT_SIZE.y - 1),
|
|
||||||
Offset::new(2, 1),
|
|
||||||
),
|
|
||||||
Rect::from_top_left_and_size(
|
|
||||||
top_left + Offset::new(Self::DOT_SIZE.x - 1, 1),
|
|
||||||
Offset::new(1, 2),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
for side in sides {
|
|
||||||
display::rect_fill(side, theme::FG)
|
|
||||||
}
|
|
||||||
if active {
|
|
||||||
display::rect_fill(
|
|
||||||
Rect::from_top_left_and_size(top_left, Self::DOT_SIZE).inset(Insets::uniform(1)),
|
|
||||||
theme::FG,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Component for ScrollBar {
|
|
||||||
type Msg = Never;
|
|
||||||
|
|
||||||
fn place(&mut self, bounds: Rect) -> Rect {
|
|
||||||
self.area = bounds;
|
|
||||||
self.area
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn paint(&mut self) {
|
|
||||||
let count = self.page_count as i16;
|
|
||||||
let interval = {
|
|
||||||
let available_height = self.area.height();
|
|
||||||
let naive_height = count * Self::DOT_INTERVAL;
|
|
||||||
if naive_height > available_height {
|
|
||||||
available_height / count
|
|
||||||
} else {
|
|
||||||
Self::DOT_INTERVAL
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut dot = Point::new(
|
|
||||||
self.area.center().x - Self::DOT_SIZE.x / 2,
|
|
||||||
self.area.center().y - (count / 2) * interval,
|
|
||||||
);
|
|
||||||
for i in 0..self.page_count {
|
|
||||||
self.paint_dot(i == self.active_page, dot);
|
|
||||||
dot.y += interval
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
use crate::ui::geometry::{Offset, Point, Rect};
|
|
||||||
|
|
||||||
pub const WIDTH: i16 = 128;
|
|
||||||
pub const HEIGHT: i16 = 64;
|
|
||||||
pub const LINE_SPACE: i16 = 1;
|
|
||||||
pub const FONT_BPP: i16 = 1;
|
|
||||||
|
|
||||||
pub const fn size() -> Offset {
|
|
||||||
Offset::new(WIDTH, HEIGHT)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn screen() -> Rect {
|
|
||||||
Rect::from_top_left_and_size(Point::zero(), size())
|
|
||||||
}
|
|
@ -1,244 +0,0 @@
|
|||||||
use core::convert::TryInto;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
error::Error,
|
|
||||||
micropython::{buffer::StrBuffer, map::Map, module::Module, obj::Obj, qstr::Qstr, util},
|
|
||||||
ui::{
|
|
||||||
component::{
|
|
||||||
base::Component,
|
|
||||||
paginated::{PageMsg, Paginate},
|
|
||||||
text::paragraphs::{Paragraph, Paragraphs},
|
|
||||||
FormattedText,
|
|
||||||
},
|
|
||||||
layout::{
|
|
||||||
obj::{ComponentMsgObj, LayoutObj},
|
|
||||||
result::{CANCELLED, CONFIRMED},
|
|
||||||
util::upy_disable_animation,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
component::{Button, ButtonPage, ButtonPos, Frame},
|
|
||||||
theme,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl<T> ComponentMsgObj for ButtonPage<T>
|
|
||||||
where
|
|
||||||
T: Component + Paginate,
|
|
||||||
{
|
|
||||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
|
||||||
match msg {
|
|
||||||
PageMsg::Content(_) => Err(Error::TypeError),
|
|
||||||
PageMsg::Controls(true) => Ok(CONFIRMED.as_obj()),
|
|
||||||
PageMsg::Controls(false) => Ok(CANCELLED.as_obj()),
|
|
||||||
PageMsg::GoBack => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U> ComponentMsgObj for Frame<T, U>
|
|
||||||
where
|
|
||||||
T: ComponentMsgObj,
|
|
||||||
U: AsRef<str>,
|
|
||||||
{
|
|
||||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
|
||||||
self.inner().msg_try_into_obj(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
|
||||||
let block = |_args: &[Obj], kwargs: &Map| {
|
|
||||||
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
|
||||||
let action: Option<StrBuffer> = kwargs.get(Qstr::MP_QSTR_action)?.try_into_option()?;
|
|
||||||
let description: Option<StrBuffer> =
|
|
||||||
kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?;
|
|
||||||
let verb: Option<StrBuffer> = kwargs.get(Qstr::MP_QSTR_verb)?.try_into_option()?;
|
|
||||||
let verb_cancel: Option<StrBuffer> =
|
|
||||||
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| Button::with_text(ButtonPos::Left, label, theme::button_cancel()));
|
|
||||||
let _right =
|
|
||||||
verb.map(|label| Button::with_text(ButtonPos::Right, label, theme::button_default()));
|
|
||||||
|
|
||||||
let obj = LayoutObj::new(Frame::new(
|
|
||||||
title,
|
|
||||||
ButtonPage::new(
|
|
||||||
FormattedText::new(theme::TEXT_NORMAL, theme::FORMATTED, format)
|
|
||||||
.with("action", action.unwrap_or_default())
|
|
||||||
.with("description", description.unwrap_or_default()),
|
|
||||||
theme::BG,
|
|
||||||
),
|
|
||||||
))?;
|
|
||||||
Ok(obj.into())
|
|
||||||
};
|
|
||||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" fn new_confirm_text(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
|
||||||
let block = |_args: &[Obj], kwargs: &Map| {
|
|
||||||
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
|
||||||
let data: StrBuffer = kwargs.get(Qstr::MP_QSTR_data)?.try_into()?;
|
|
||||||
let description: Option<StrBuffer> =
|
|
||||||
kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?;
|
|
||||||
|
|
||||||
let obj = LayoutObj::new(Frame::new(
|
|
||||||
title,
|
|
||||||
ButtonPage::new(
|
|
||||||
Paragraphs::new([
|
|
||||||
Paragraph::new(&theme::TEXT_NORMAL, description.unwrap_or_default()),
|
|
||||||
Paragraph::new(&theme::TEXT_BOLD, data),
|
|
||||||
]),
|
|
||||||
theme::BG,
|
|
||||||
),
|
|
||||||
))?;
|
|
||||||
Ok(obj.into())
|
|
||||||
};
|
|
||||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub static mp_module_trezorui2: Module = obj_module! {
|
|
||||||
Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorui2.to_obj(),
|
|
||||||
|
|
||||||
/// CONFIRMED: object
|
|
||||||
Qstr::MP_QSTR_CONFIRMED => CONFIRMED.as_obj(),
|
|
||||||
|
|
||||||
/// CANCELLED: object
|
|
||||||
Qstr::MP_QSTR_CANCELLED => CANCELLED.as_obj(),
|
|
||||||
|
|
||||||
/// def disable_animation(disable: bool) -> None:
|
|
||||||
/// """Disable animations, debug builds only."""
|
|
||||||
Qstr::MP_QSTR_disable_animation => obj_fn_1!(upy_disable_animation).as_obj(),
|
|
||||||
|
|
||||||
/// def confirm_action(
|
|
||||||
/// *,
|
|
||||||
/// title: str,
|
|
||||||
/// action: str | None = None,
|
|
||||||
/// description: str | None = None,
|
|
||||||
/// verb: str | None = None,
|
|
||||||
/// verb_cancel: str | None = None,
|
|
||||||
/// hold: bool | None = None,
|
|
||||||
/// reverse: bool = False,
|
|
||||||
/// ) -> object:
|
|
||||||
/// """Confirm action."""
|
|
||||||
Qstr::MP_QSTR_confirm_action => obj_fn_kw!(0, new_confirm_action).as_obj(),
|
|
||||||
|
|
||||||
/// def confirm_text(
|
|
||||||
/// *,
|
|
||||||
/// title: str,
|
|
||||||
/// data: str,
|
|
||||||
/// description: str | None,
|
|
||||||
/// ) -> object:
|
|
||||||
/// """Confirm text."""
|
|
||||||
Qstr::MP_QSTR_confirm_text => obj_fn_kw!(0, new_confirm_text).as_obj(),
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::{
|
|
||||||
trace::Trace,
|
|
||||||
ui::{
|
|
||||||
component::Component,
|
|
||||||
model_t1::{
|
|
||||||
component::{Dialog, DialogMsg},
|
|
||||||
constant,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
fn trace(val: &impl Trace) -> String {
|
|
||||||
let mut t = Vec::new();
|
|
||||||
val.trace(&mut t);
|
|
||||||
String::from_utf8(t).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U> ComponentMsgObj for Dialog<T, U>
|
|
||||||
where
|
|
||||||
T: ComponentMsgObj,
|
|
||||||
U: AsRef<str>,
|
|
||||||
{
|
|
||||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
|
||||||
match msg {
|
|
||||||
DialogMsg::Content(c) => self.inner().msg_try_into_obj(c),
|
|
||||||
DialogMsg::LeftClicked => Ok(CANCELLED.as_obj()),
|
|
||||||
DialogMsg::RightClicked => Ok(CONFIRMED.as_obj()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn trace_example_layout() {
|
|
||||||
let mut layout = Dialog::new(
|
|
||||||
FormattedText::new(
|
|
||||||
theme::TEXT_NORMAL,
|
|
||||||
theme::FORMATTED,
|
|
||||||
"Testing text layout, with some text, and some more text. And {param}",
|
|
||||||
)
|
|
||||||
.with("param", "parameters!"),
|
|
||||||
Some(Button::with_text(
|
|
||||||
ButtonPos::Left,
|
|
||||||
"Left",
|
|
||||||
theme::button_cancel(),
|
|
||||||
)),
|
|
||||||
Some(Button::with_text(
|
|
||||||
ButtonPos::Right,
|
|
||||||
"Right",
|
|
||||||
theme::button_default(),
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
layout.place(constant::screen());
|
|
||||||
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 mut layout = Frame::new(
|
|
||||||
"Please confirm",
|
|
||||||
Dialog::new(
|
|
||||||
FormattedText::new(
|
|
||||||
theme::TEXT_NORMAL,
|
|
||||||
theme::FORMATTED,
|
|
||||||
"Testing text layout, with some text, and some more text. And {param}",
|
|
||||||
)
|
|
||||||
.with("param", "parameters!"),
|
|
||||||
Some(Button::with_text(
|
|
||||||
ButtonPos::Left,
|
|
||||||
"Left",
|
|
||||||
theme::button_cancel(),
|
|
||||||
)),
|
|
||||||
Some(Button::with_text(
|
|
||||||
ButtonPos::Right,
|
|
||||||
"Right",
|
|
||||||
theme::button_default(),
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
layout.place(constant::screen());
|
|
||||||
assert_eq!(
|
|
||||||
trace(&layout),
|
|
||||||
r#"<Frame 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 > > >"#
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
pub mod component;
|
|
||||||
pub mod constant;
|
|
||||||
pub mod theme;
|
|
||||||
|
|
||||||
#[cfg(feature = "micropython")]
|
|
||||||
pub mod layout;
|
|
@ -1,55 +0,0 @@
|
|||||||
use crate::ui::{
|
|
||||||
component::text::{formatted::FormattedFonts, TextStyle},
|
|
||||||
display::{Color, Font},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::component::{ButtonStyle, ButtonStyleSheet};
|
|
||||||
|
|
||||||
// Color palette.
|
|
||||||
pub const WHITE: Color = Color::rgb(255, 255, 255);
|
|
||||||
pub const BLACK: Color = Color::rgb(0, 0, 0);
|
|
||||||
pub const GREY_LIGHT: Color = WHITE; // Word/page break characters.
|
|
||||||
pub const FG: Color = WHITE; // Default foreground (text & icon) color.
|
|
||||||
pub const BG: Color = BLACK; // Default background color.
|
|
||||||
|
|
||||||
pub fn button_default() -> ButtonStyleSheet {
|
|
||||||
ButtonStyleSheet {
|
|
||||||
normal: &ButtonStyle {
|
|
||||||
font: Font::BOLD,
|
|
||||||
text_color: BG,
|
|
||||||
border_horiz: true,
|
|
||||||
},
|
|
||||||
active: &ButtonStyle {
|
|
||||||
font: Font::BOLD,
|
|
||||||
text_color: FG,
|
|
||||||
border_horiz: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn button_cancel() -> ButtonStyleSheet {
|
|
||||||
ButtonStyleSheet {
|
|
||||||
normal: &ButtonStyle {
|
|
||||||
font: Font::BOLD,
|
|
||||||
text_color: FG,
|
|
||||||
border_horiz: false,
|
|
||||||
},
|
|
||||||
active: &ButtonStyle {
|
|
||||||
font: Font::BOLD,
|
|
||||||
text_color: BG,
|
|
||||||
border_horiz: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const TEXT_NORMAL: TextStyle = TextStyle::new(Font::NORMAL, FG, BG, FG, FG);
|
|
||||||
pub const TEXT_DEMIBOLD: TextStyle = TextStyle::new(Font::DEMIBOLD, FG, BG, FG, FG);
|
|
||||||
pub const TEXT_BOLD: TextStyle = TextStyle::new(Font::BOLD, FG, BG, FG, FG);
|
|
||||||
pub const TEXT_MONO: TextStyle = TextStyle::new(Font::MONO, FG, BG, FG, FG);
|
|
||||||
|
|
||||||
pub const FORMATTED: FormattedFonts = FormattedFonts {
|
|
||||||
normal: Font::NORMAL,
|
|
||||||
demibold: Font::DEMIBOLD,
|
|
||||||
bold: Font::BOLD,
|
|
||||||
mono: Font::MONO,
|
|
||||||
};
|
|
@ -3,37 +3,6 @@ CONFIRMED: object
|
|||||||
CANCELLED: object
|
CANCELLED: object
|
||||||
|
|
||||||
|
|
||||||
# rust/src/ui/model_t1/layout.rs
|
|
||||||
def disable_animation(disable: bool) -> None:
|
|
||||||
"""Disable animations, debug builds only."""
|
|
||||||
|
|
||||||
|
|
||||||
# rust/src/ui/model_t1/layout.rs
|
|
||||||
def confirm_action(
|
|
||||||
*,
|
|
||||||
title: str,
|
|
||||||
action: str | None = None,
|
|
||||||
description: str | None = None,
|
|
||||||
verb: str | None = None,
|
|
||||||
verb_cancel: str | None = None,
|
|
||||||
hold: bool | None = None,
|
|
||||||
reverse: bool = False,
|
|
||||||
) -> object:
|
|
||||||
"""Confirm action."""
|
|
||||||
|
|
||||||
|
|
||||||
# rust/src/ui/model_t1/layout.rs
|
|
||||||
def confirm_text(
|
|
||||||
*,
|
|
||||||
title: str,
|
|
||||||
data: str,
|
|
||||||
description: str | None,
|
|
||||||
) -> object:
|
|
||||||
"""Confirm text."""
|
|
||||||
CONFIRMED: object
|
|
||||||
CANCELLED: object
|
|
||||||
|
|
||||||
|
|
||||||
# rust/src/ui/model_tr/layout.rs
|
# rust/src/ui/model_tr/layout.rs
|
||||||
def disable_animation(disable: bool) -> None:
|
def disable_animation(disable: bool) -> None:
|
||||||
"""Disable animations, debug builds only."""
|
"""Disable animations, debug builds only."""
|
||||||
|
108
docs/ci/jobs.md
108
docs/ci/jobs.md
@ -54,7 +54,7 @@ or contain `[no changelog]` in the commit message.
|
|||||||
## BUILD stage - [build.yml](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml)
|
## BUILD stage - [build.yml](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml)
|
||||||
All builds are published as artifacts so they can be downloaded and used.
|
All builds are published as artifacts so they can be downloaded and used.
|
||||||
|
|
||||||
Consists of **27 jobs** below:
|
Consists of **25 jobs** below:
|
||||||
|
|
||||||
### [core fw regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L20)
|
### [core fw regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L20)
|
||||||
Build of Core into firmware. Regular version.
|
Build of Core into firmware. Regular version.
|
||||||
@ -74,72 +74,68 @@ Build of Core into firmware. Bitcoin-only version.
|
|||||||
|
|
||||||
### [core fw btconly production build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L117)
|
### [core fw btconly production build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L117)
|
||||||
|
|
||||||
### [core fw btconly t1 build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L136)
|
### [core unix regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L138)
|
||||||
|
|
||||||
### [core unix regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L154)
|
|
||||||
Non-frozen emulator build. This means you still need Python files
|
Non-frozen emulator build. This means you still need Python files
|
||||||
present which get interpreted.
|
present which get interpreted.
|
||||||
|
|
||||||
### [core unix regular asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L166)
|
### [core unix regular asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L150)
|
||||||
|
|
||||||
### [core unix frozen regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L185)
|
### [core unix frozen regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L169)
|
||||||
Build of Core into UNIX emulator. Something you can run on your laptop.
|
Build of Core into UNIX emulator. Something you can run on your laptop.
|
||||||
Frozen version. That means you do not need any other files to run it,
|
Frozen version. That means you do not need any other files to run it,
|
||||||
it is just a single binary file that you can execute directly.
|
it is just a single binary file that you can execute directly.
|
||||||
|
|
||||||
### [core unix frozen btconly debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L202)
|
### [core unix frozen btconly debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L186)
|
||||||
Build of Core into UNIX emulator. Something you can run on your laptop.
|
Build of Core into UNIX emulator. Something you can run on your laptop.
|
||||||
Frozen version. That means you do not need any other files to run it,
|
Frozen version. That means you do not need any other files to run it,
|
||||||
it is just a single binary file that you can execute directly.
|
it is just a single binary file that you can execute directly.
|
||||||
See [Emulator](../core/emulator/index.md) for more info.
|
See [Emulator](../core/emulator/index.md) for more info.
|
||||||
Debug mode enabled, Bitcoin-only version.
|
Debug mode enabled, Bitcoin-only version.
|
||||||
|
|
||||||
### [core unix frozen btconly debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L218)
|
### [core unix frozen btconly debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L202)
|
||||||
|
|
||||||
### [core unix frozen debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L241)
|
### [core unix frozen debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L225)
|
||||||
Build of Core into UNIX emulator. Something you can run on your laptop.
|
Build of Core into UNIX emulator. Something you can run on your laptop.
|
||||||
Frozen version. That means you do not need any other files to run it,
|
Frozen version. That means you do not need any other files to run it,
|
||||||
it is just a single binary file that you can execute directly.
|
it is just a single binary file that you can execute directly.
|
||||||
**Are you looking for a Trezor T emulator? This is most likely it.**
|
**Are you looking for a Trezor T emulator? This is most likely it.**
|
||||||
|
|
||||||
### [core unix frozen debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L254)
|
### [core unix frozen debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L238)
|
||||||
|
|
||||||
### [core unix frozen debug build arm](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L270)
|
### [core unix frozen debug build arm](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L254)
|
||||||
|
|
||||||
### [core unix frozen btconly debug t1 build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L292)
|
### [core macos frozen regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L276)
|
||||||
|
|
||||||
### [core macos frozen regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L308)
|
### [crypto build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L301)
|
||||||
|
|
||||||
### [crypto build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L333)
|
|
||||||
Build of our cryptographic library, which is then incorporated into the other builds.
|
Build of our cryptographic library, which is then incorporated into the other builds.
|
||||||
|
|
||||||
### [legacy fw regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L362)
|
### [legacy fw regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L330)
|
||||||
|
|
||||||
### [legacy fw regular debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L378)
|
### [legacy fw regular debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L346)
|
||||||
|
|
||||||
### [legacy fw btconly build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L395)
|
### [legacy fw btconly build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L363)
|
||||||
|
|
||||||
### [legacy fw btconly debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L414)
|
### [legacy fw btconly debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L382)
|
||||||
|
|
||||||
### [legacy emu regular debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L435)
|
### [legacy emu regular debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L403)
|
||||||
Regular version (not only Bitcoin) of above.
|
Regular version (not only Bitcoin) of above.
|
||||||
**Are you looking for a Trezor One emulator? This is most likely it.**
|
**Are you looking for a Trezor One emulator? This is most likely it.**
|
||||||
|
|
||||||
### [legacy emu regular debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L450)
|
### [legacy emu regular debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L418)
|
||||||
|
|
||||||
### [legacy emu regular debug build arm](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L468)
|
### [legacy emu regular debug build arm](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L436)
|
||||||
|
|
||||||
### [legacy emu btconly debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L494)
|
### [legacy emu btconly debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L462)
|
||||||
Build of Legacy into UNIX emulator. Use keyboard arrows to emulate button presses.
|
Build of Legacy into UNIX emulator. Use keyboard arrows to emulate button presses.
|
||||||
Bitcoin-only version.
|
Bitcoin-only version.
|
||||||
|
|
||||||
### [legacy emu btconly debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L511)
|
### [legacy emu btconly debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L479)
|
||||||
|
|
||||||
---
|
---
|
||||||
## TEST stage - [test.yml](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml)
|
## TEST stage - [test.yml](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml)
|
||||||
All the tests run test cases on the freshly built emulators from the previous `BUILD` stage.
|
All the tests run test cases on the freshly built emulators from the previous `BUILD` stage.
|
||||||
|
|
||||||
Consists of **34 jobs** below:
|
Consists of **33 jobs** below:
|
||||||
|
|
||||||
### [core unit python test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L15)
|
### [core unit python test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L15)
|
||||||
Python unit tests, checking core functionality.
|
Python unit tests, checking core functionality.
|
||||||
@ -149,80 +145,78 @@ Rust unit tests.
|
|||||||
|
|
||||||
### [core unit asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L33)
|
### [core unit asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L33)
|
||||||
|
|
||||||
### [core unit t1 test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L50)
|
### [core device test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L54)
|
||||||
|
|
||||||
### [core device test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L65)
|
|
||||||
Device tests for Core. Running device tests and also comparing screens
|
Device tests for Core. Running device tests and also comparing screens
|
||||||
with the expected UI result.
|
with the expected UI result.
|
||||||
See artifacts for a comprehensive report of UI.
|
See artifacts for a comprehensive report of UI.
|
||||||
See [docs/tests/ui-tests](../tests/ui-tests.md) for more info.
|
See [docs/tests/ui-tests](../tests/ui-tests.md) for more info.
|
||||||
|
|
||||||
### [core device asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L94)
|
### [core device asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L83)
|
||||||
|
|
||||||
### [core btconly device test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L113)
|
### [core btconly device test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L102)
|
||||||
Device tests excluding altcoins, only for BTC.
|
Device tests excluding altcoins, only for BTC.
|
||||||
|
|
||||||
### [core btconly device asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L133)
|
### [core btconly device asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L122)
|
||||||
|
|
||||||
### [core monero test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L154)
|
### [core monero test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L143)
|
||||||
Monero tests.
|
Monero tests.
|
||||||
|
|
||||||
### [core monero asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L173)
|
### [core monero asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L162)
|
||||||
|
|
||||||
### [core u2f test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L195)
|
### [core u2f test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L184)
|
||||||
Tests for U2F and HID.
|
Tests for U2F and HID.
|
||||||
|
|
||||||
### [core u2f asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L214)
|
### [core u2f asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L203)
|
||||||
|
|
||||||
### [core fido2 test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L232)
|
### [core fido2 test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L221)
|
||||||
FIDO2 device tests.
|
FIDO2 device tests.
|
||||||
|
|
||||||
### [core fido2 asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L255)
|
### [core fido2 asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L244)
|
||||||
|
|
||||||
### [core click test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L275)
|
### [core click test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L264)
|
||||||
Click tests.
|
Click tests.
|
||||||
See [docs/tests/click-tests](../tests/click-tests.md) for more info.
|
See [docs/tests/click-tests](../tests/click-tests.md) for more info.
|
||||||
|
|
||||||
### [core click asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L292)
|
### [core click asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L281)
|
||||||
|
|
||||||
### [core upgrade test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L313)
|
### [core upgrade test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L302)
|
||||||
Upgrade tests.
|
Upgrade tests.
|
||||||
See [docs/tests/upgrade-tests](../tests/upgrade-tests.md) for more info.
|
See [docs/tests/upgrade-tests](../tests/upgrade-tests.md) for more info.
|
||||||
|
|
||||||
### [core upgrade asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L332)
|
### [core upgrade asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L321)
|
||||||
|
|
||||||
### [core persistence test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L354)
|
### [core persistence test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L343)
|
||||||
Persistence tests.
|
Persistence tests.
|
||||||
|
|
||||||
### [core persistence asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L370)
|
### [core persistence asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L359)
|
||||||
|
|
||||||
### [core hwi test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L388)
|
### [core hwi test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L377)
|
||||||
|
|
||||||
### [crypto test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L406)
|
### [crypto test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L395)
|
||||||
|
|
||||||
### [legacy device test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L437)
|
### [legacy device test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L426)
|
||||||
|
|
||||||
### [legacy asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L464)
|
### [legacy asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L453)
|
||||||
|
|
||||||
### [legacy btconly test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L476)
|
### [legacy btconly test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L465)
|
||||||
|
|
||||||
### [legacy btconly asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L496)
|
### [legacy btconly asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L485)
|
||||||
|
|
||||||
### [legacy upgrade test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L511)
|
### [legacy upgrade test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L500)
|
||||||
|
|
||||||
### [legacy upgrade asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L530)
|
### [legacy upgrade asan test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L519)
|
||||||
|
|
||||||
### [legacy hwi test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L551)
|
### [legacy hwi test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L540)
|
||||||
|
|
||||||
### [python test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L570)
|
### [python test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L559)
|
||||||
|
|
||||||
### [python support test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L589)
|
### [python support test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L578)
|
||||||
|
|
||||||
### [storage test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L599)
|
### [storage test](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L588)
|
||||||
|
|
||||||
### [core unix memory profiler](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L623)
|
### [core unix memory profiler](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L612)
|
||||||
|
|
||||||
### [connect test core](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L647)
|
### [connect test core](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml#L636)
|
||||||
|
|
||||||
---
|
---
|
||||||
## TEST-HW stage - [test-hw.yml](https://github.com/trezor/trezor-firmware/blob/master/ci/test-hw.yml)
|
## TEST-HW stage - [test-hw.yml](https://github.com/trezor/trezor-firmware/blob/master/ci/test-hw.yml)
|
||||||
|
Loading…
Reference in New Issue
Block a user