mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-23 06:48:16 +00:00
feat(core/rust): Add experimental LinearLayout
This commit is contained in:
parent
3dd3d7f87b
commit
8c47b94b79
@ -3,7 +3,7 @@ use core::ops::Deref;
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display::{self, Color, Font},
|
||||
geometry::{Align, Point, Rect},
|
||||
geometry::{Alignment, Point, Rect},
|
||||
};
|
||||
|
||||
pub struct LabelStyle {
|
||||
@ -22,45 +22,45 @@ impl<T> Label<T>
|
||||
where
|
||||
T: Deref<Target = [u8]>,
|
||||
{
|
||||
pub fn new(origin: Point, align: Align, text: T, style: LabelStyle) -> Self {
|
||||
pub fn new(origin: Point, align: Alignment, text: T, style: LabelStyle) -> Self {
|
||||
let width = display::text_width(&text, style.font);
|
||||
let height = display::line_height();
|
||||
let area = match align {
|
||||
// `origin` is the top-left point.
|
||||
Align::Left => Rect {
|
||||
Alignment::Start => Rect {
|
||||
x0: origin.x,
|
||||
y0: origin.y,
|
||||
x1: origin.x + width,
|
||||
y1: origin.y + height,
|
||||
},
|
||||
// `origin` is the top-right point.
|
||||
Align::Right => Rect {
|
||||
x0: origin.x - width,
|
||||
y0: origin.y,
|
||||
x1: origin.x,
|
||||
y1: origin.y + height,
|
||||
},
|
||||
// `origin` is the top-centered point.
|
||||
Align::Center => Rect {
|
||||
Alignment::Center => Rect {
|
||||
x0: origin.x - width / 2,
|
||||
y0: origin.y,
|
||||
x1: origin.x + width / 2,
|
||||
y1: origin.y + height,
|
||||
},
|
||||
// `origin` is the top-right point.
|
||||
Alignment::End => Rect {
|
||||
x0: origin.x - width,
|
||||
y0: origin.y,
|
||||
x1: origin.x,
|
||||
y1: origin.y + height,
|
||||
},
|
||||
};
|
||||
Self { area, style, text }
|
||||
}
|
||||
|
||||
pub fn left_aligned(origin: Point, text: T, style: LabelStyle) -> Self {
|
||||
Self::new(origin, Align::Left, text, style)
|
||||
Self::new(origin, Alignment::Start, text, style)
|
||||
}
|
||||
|
||||
pub fn right_aligned(origin: Point, text: T, style: LabelStyle) -> Self {
|
||||
Self::new(origin, Align::Right, text, style)
|
||||
Self::new(origin, Alignment::End, text, style)
|
||||
}
|
||||
|
||||
pub fn centered(origin: Point, text: T, style: LabelStyle) -> Self {
|
||||
Self::new(origin, Align::Center, text, style)
|
||||
Self::new(origin, Alignment::Center, text, style)
|
||||
}
|
||||
|
||||
pub fn text(&self) -> &T {
|
||||
|
@ -22,6 +22,13 @@ impl Offset {
|
||||
Self::new(0, 0)
|
||||
}
|
||||
|
||||
pub fn on_axis(axis: Axis, a: i32) -> Self {
|
||||
match axis {
|
||||
Axis::Horizontal => Self::new(a, 0),
|
||||
Axis::Vertical => Self::new(0, a),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn abs(self) -> Self {
|
||||
Self::new(self.x.abs(), self.y.abs())
|
||||
}
|
||||
@ -109,6 +116,10 @@ impl Rect {
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn zero() -> Self {
|
||||
Self::new(Point::zero(), Point::zero())
|
||||
}
|
||||
|
||||
pub fn from_top_left_and_size(p0: Point, size: Offset) -> Self {
|
||||
Self::new(p0, p0 + size)
|
||||
}
|
||||
@ -231,10 +242,32 @@ impl Rect {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Align {
|
||||
Left,
|
||||
Right,
|
||||
pub enum Alignment {
|
||||
Start,
|
||||
Center,
|
||||
End,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Axis {
|
||||
Horizontal,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
impl Axis {
|
||||
pub fn main<T>(self, x: T, y: T) -> T {
|
||||
match self {
|
||||
Axis::Horizontal => x,
|
||||
Axis::Vertical => y,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cross(self) -> Self {
|
||||
match self {
|
||||
Axis::Horizontal => Axis::Vertical,
|
||||
Axis::Vertical => Axis::Horizontal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Grid {
|
||||
@ -275,3 +308,88 @@ impl Grid {
|
||||
self.row_col(index / self.cols, index % self.cols)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct LinearLayout {
|
||||
axis: Axis,
|
||||
align: Alignment,
|
||||
spacing: i32,
|
||||
}
|
||||
|
||||
impl LinearLayout {
|
||||
pub fn horizontal() -> Self {
|
||||
Self {
|
||||
axis: Axis::Horizontal,
|
||||
align: Alignment::Start,
|
||||
spacing: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vertical() -> Self {
|
||||
Self {
|
||||
axis: Axis::Vertical,
|
||||
align: Alignment::Start,
|
||||
spacing: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn align_at_start(mut self) -> Self {
|
||||
self.align = Alignment::Start;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn align_at_center(mut self) -> Self {
|
||||
self.align = Alignment::Center;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn align_at_end(mut self) -> Self {
|
||||
self.align = Alignment::End;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_spacing(mut self, spacing: i32) -> Self {
|
||||
self.spacing = spacing;
|
||||
self
|
||||
}
|
||||
|
||||
/// Arranges all `items` by parameters configured in `self` into `area`.
|
||||
/// Does not change the size of the items (only the position), but it needs
|
||||
/// to iterate (and ask for the size) twice.
|
||||
pub fn arrange(&self, area: Rect, items: &mut [impl Dimensions]) {
|
||||
let item_sum: i32 = items
|
||||
.iter_mut()
|
||||
.map(|i| {
|
||||
let size = i.get_size();
|
||||
self.axis.main(size.x, size.y)
|
||||
})
|
||||
.sum();
|
||||
let spacing_count = items.len().saturating_sub(1);
|
||||
let spacing_sum = spacing_count as i32 * self.spacing;
|
||||
let total_size = item_sum + spacing_sum;
|
||||
|
||||
let available_space = match self.axis {
|
||||
Axis::Horizontal => area.width(),
|
||||
Axis::Vertical => area.height(),
|
||||
};
|
||||
let mut cursor = match self.align {
|
||||
Alignment::Start => 0,
|
||||
Alignment::Center => available_space / 2 - total_size / 2,
|
||||
Alignment::End => available_space - total_size,
|
||||
};
|
||||
|
||||
for item in items {
|
||||
let top_left = area.top_left() + Offset::on_axis(self.axis, cursor);
|
||||
let size = item.get_size();
|
||||
item.set_area(Rect::from_top_left_and_size(top_left, size));
|
||||
cursor += self.axis.main(size.x, size.y);
|
||||
cursor += self.spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Types that have a size and a position.
|
||||
pub trait Dimensions {
|
||||
fn get_size(&mut self) -> Offset;
|
||||
fn set_area(&mut self, area: Rect);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user