mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-05-13 12:28:47 +00:00
feat(eckhart): improve pagination of ActionBar
- Single mode now handles pagination with the right_button shown at the last page - new PaginateOnly mode to only render navigation buttons without cancel/confirm buttons
This commit is contained in:
parent
f592548f2c
commit
a7c6fdc754
@ -171,6 +171,10 @@ impl Button {
|
|||||||
self.touch_expand = Some(expand);
|
self.touch_expand = Some(expand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_content_offset(&mut self, offset: Offset) {
|
||||||
|
self.content_offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn content(&self) -> &ButtonContent {
|
pub fn content(&self) -> &ButtonContent {
|
||||||
&self.content
|
&self.content
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
super::component::{Button, ButtonContent, ButtonMsg, ButtonStyleSheet},
|
super::component::{Button, ButtonMsg},
|
||||||
theme, HoldToConfirmAnim,
|
theme, HoldToConfirmAnim,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -17,20 +17,22 @@ use super::{
|
|||||||
pub struct ActionBar {
|
pub struct ActionBar {
|
||||||
/// Behavior based on `Mode`
|
/// Behavior based on `Mode`
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
/// Right or single button, can have text or icon
|
/// Right or single confirm button, can have text or icon
|
||||||
right_button: Button,
|
right_button: Option<Button>,
|
||||||
/// Optional left button, can be shorter than the right one
|
/// Left cancel button, can be shorter than the right one
|
||||||
left_button: Option<Button>,
|
left_button: Option<Button>,
|
||||||
|
/// Area of the action bar
|
||||||
area: Rect,
|
area: Rect,
|
||||||
/// Whether the left button is short (default: true)
|
|
||||||
left_short: bool,
|
|
||||||
// Storage of original button content for paginated component
|
|
||||||
left_original: Option<(ButtonContent, ButtonStyleSheet)>,
|
|
||||||
right_original: Option<(ButtonContent, ButtonStyleSheet)>,
|
|
||||||
/// Hold to confirm animation
|
/// Hold to confirm animation
|
||||||
htc_anim: Option<HoldToConfirmAnim>,
|
htc_anim: Option<HoldToConfirmAnim>,
|
||||||
/// Timeout
|
/// Timeout
|
||||||
timeout: Option<Timeout>,
|
timeout: Option<Timeout>,
|
||||||
|
/// Pager for paginated content
|
||||||
|
pager: Pager,
|
||||||
|
/// Left button for paginated content
|
||||||
|
prev_button: Button,
|
||||||
|
/// Right button for paginated content
|
||||||
|
next_button: Button,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ActionBarMsg {
|
pub enum ActionBarMsg {
|
||||||
@ -45,13 +47,16 @@ pub enum ActionBarMsg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Describes the behavior of the action bar
|
/// Describes the behavior of the action bar
|
||||||
|
#[derive(PartialEq)]
|
||||||
enum Mode {
|
enum Mode {
|
||||||
/// Single confirm button taking full width
|
/// Single confirm button
|
||||||
Single,
|
Single,
|
||||||
/// Cancel and confirm button; Up/Down navigation for paginated content
|
/// Cancel and confirm button
|
||||||
Double { pager: Pager },
|
Double { left_short: bool },
|
||||||
/// Automatic confirmation after a timeout
|
/// Automatic confirmation after a timeout
|
||||||
Timeout,
|
Timeout,
|
||||||
|
/// Only show pagination buttons, no confirm or cancel
|
||||||
|
PaginateOnly,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActionBar {
|
impl ActionBar {
|
||||||
@ -62,16 +67,14 @@ impl ActionBar {
|
|||||||
const BUTTON_CONTENT_OFFSET: Offset = Offset::x(12); // [px]
|
const BUTTON_CONTENT_OFFSET: Offset = Offset::x(12); // [px]
|
||||||
const BUTTON_EXPAND_TOUCH: Insets = Insets::top(Self::ACTION_BAR_HEIGHT);
|
const BUTTON_EXPAND_TOUCH: Insets = Insets::top(Self::ACTION_BAR_HEIGHT);
|
||||||
|
|
||||||
const PAGINATE_LEFT_CONTENT: ButtonContent = ButtonContent::Icon(theme::ICON_CHEVRON_UP);
|
/// Create action bar with single button confirming the layout. The
|
||||||
const PAGINATE_RIGHT_CONTENT: ButtonContent = ButtonContent::Icon(theme::ICON_CHEVRON_DOWN);
|
/// component automatically shows navigation up/down buttons for
|
||||||
const PAGINATE_STYLESHEET: &'static ButtonStyleSheet = &theme::button_default();
|
/// paginated content.
|
||||||
|
|
||||||
/// Create action bar with single button confirming the layout
|
|
||||||
pub fn new_single(button: Button) -> Self {
|
pub fn new_single(button: Button) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
Mode::Single,
|
Mode::Single,
|
||||||
None,
|
None,
|
||||||
button.with_expanded_touch_area(Self::BUTTON_EXPAND_TOUCH),
|
Some(button.with_expanded_touch_area(Self::BUTTON_EXPAND_TOUCH)),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -81,7 +84,7 @@ impl ActionBar {
|
|||||||
Self::new(
|
Self::new(
|
||||||
Mode::Timeout,
|
Mode::Timeout,
|
||||||
None,
|
None,
|
||||||
button.initially_enabled(false),
|
Some(button.initially_enabled(false)),
|
||||||
Some(Timeout::new(timeout_ms)),
|
Some(Timeout::new(timeout_ms)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -91,16 +94,16 @@ impl ActionBar {
|
|||||||
/// content.
|
/// content.
|
||||||
pub fn new_double(left: Button, right: Button) -> Self {
|
pub fn new_double(left: Button, right: Button) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
Mode::Double {
|
Mode::Double { left_short: true },
|
||||||
pager: Pager::single_page(),
|
|
||||||
},
|
|
||||||
Some(
|
Some(
|
||||||
left.with_expanded_touch_area(Self::BUTTON_EXPAND_TOUCH)
|
left.with_expanded_touch_area(Self::BUTTON_EXPAND_TOUCH)
|
||||||
.with_content_offset(Self::BUTTON_CONTENT_OFFSET),
|
.with_content_offset(Self::BUTTON_CONTENT_OFFSET),
|
||||||
),
|
),
|
||||||
|
Some(
|
||||||
right
|
right
|
||||||
.with_expanded_touch_area(Self::BUTTON_EXPAND_TOUCH)
|
.with_expanded_touch_area(Self::BUTTON_EXPAND_TOUCH)
|
||||||
.with_content_offset(Self::BUTTON_CONTENT_OFFSET.neg()),
|
.with_content_offset(Self::BUTTON_CONTENT_OFFSET.neg()),
|
||||||
|
),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -112,8 +115,17 @@ impl ActionBar {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_left_short(mut self, left_short: bool) -> Self {
|
/// Create action bar with only pagination buttons. The component in this
|
||||||
self.left_short = left_short;
|
/// mode can only return `ActionBarMsg::Prev` and `ActionBarMsg::Next`
|
||||||
|
/// messages.
|
||||||
|
pub fn new_paginate_only() -> Self {
|
||||||
|
Self::new(Mode::PaginateOnly, None, None, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_left_short(mut self) -> Self {
|
||||||
|
if let Mode::Double { ref mut left_short } = self.mode {
|
||||||
|
*left_short = true;
|
||||||
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,102 +133,82 @@ impl ActionBar {
|
|||||||
if let Some(btn) = &mut self.left_button {
|
if let Some(btn) = &mut self.left_button {
|
||||||
btn.set_expanded_touch_area(expand);
|
btn.set_expanded_touch_area(expand);
|
||||||
}
|
}
|
||||||
self.right_button.set_expanded_touch_area(expand);
|
if let Some(btn) = &mut self.right_button {
|
||||||
|
btn.set_expanded_touch_area(expand);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn touch_area(&self) -> Rect {
|
pub fn touch_area(&self) -> Rect {
|
||||||
let right_area = self.right_button.touch_area();
|
let right_area = self
|
||||||
|
.right_button
|
||||||
|
.as_ref()
|
||||||
|
.map_or(Rect::zero(), |right| right.touch_area());
|
||||||
self.left_button
|
self.left_button
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(right_area, |left| right_area.union(left.touch_area()))
|
.map_or(right_area, |left| right_area.union(left.touch_area()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates the pager of the component. This is used to show and process the
|
||||||
|
/// navigation buttons.
|
||||||
pub fn update(&mut self, new_pager: Pager) {
|
pub fn update(&mut self, new_pager: Pager) {
|
||||||
// TODO: review `clone()` of `left_content`/`right_content`
|
let old_is_last = self.pager.is_last();
|
||||||
if let Mode::Double { pager } = &mut self.mode {
|
|
||||||
let old_is_last = pager.is_last();
|
|
||||||
let new_is_last = new_pager.is_last();
|
let new_is_last = new_pager.is_last();
|
||||||
*pager = new_pager;
|
let old_is_first = self.pager.is_first();
|
||||||
// Update left button - show original content/style only on first page
|
let new_is_first = new_pager.is_first();
|
||||||
if let Some(btn) = &mut self.left_button {
|
|
||||||
if pager.is_first() {
|
|
||||||
let (content, style) = unwrap!(self.left_original.clone());
|
|
||||||
btn.set_content(content);
|
|
||||||
btn.set_stylesheet(style);
|
|
||||||
} else {
|
|
||||||
btn.set_content(Self::PAGINATE_LEFT_CONTENT);
|
|
||||||
btn.set_stylesheet(*Self::PAGINATE_STYLESHEET);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update right button - show original content/style only on last page
|
self.pager = new_pager;
|
||||||
if pager.is_last() {
|
if (old_is_last != new_is_last) || (new_is_first != old_is_first) {
|
||||||
let (content, style) = unwrap!(self.right_original.clone());
|
|
||||||
self.right_button.set_content(content);
|
|
||||||
self.right_button.set_stylesheet(style);
|
|
||||||
} else {
|
|
||||||
self.right_button.set_content(Self::PAGINATE_RIGHT_CONTENT);
|
|
||||||
self.right_button.set_stylesheet(*Self::PAGINATE_STYLESHEET);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're entering or leaving the last page and left_short is true,
|
|
||||||
// we need to update the button placement
|
|
||||||
if self.left_short && (old_is_last != new_is_last) {
|
|
||||||
self.place_buttons(self.area);
|
self.place_buttons(self.area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
left_button: Option<Button>,
|
left_button: Option<Button>,
|
||||||
right_button: Button,
|
right_button: Option<Button>,
|
||||||
timeout: Option<Timeout>,
|
timeout: Option<Timeout>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let (left_original, right_original) = match mode {
|
let htc_anim = if let Some(ref right_button) = right_button {
|
||||||
Mode::Double { .. } => (
|
right_button
|
||||||
left_button
|
|
||||||
.as_ref()
|
|
||||||
.map(|b| (b.content().clone(), *b.style_sheet())),
|
|
||||||
Some((right_button.content().clone(), *right_button.style_sheet())),
|
|
||||||
),
|
|
||||||
_ => (None, None),
|
|
||||||
};
|
|
||||||
|
|
||||||
let htc_anim = right_button
|
|
||||||
.long_press()
|
.long_press()
|
||||||
.filter(|_| !animation_disabled())
|
.filter(|_| !animation_disabled())
|
||||||
.map(|dur| {
|
.map(|dur| {
|
||||||
HoldToConfirmAnim::new()
|
HoldToConfirmAnim::new()
|
||||||
.with_duration(dur)
|
.with_duration(dur)
|
||||||
.with_header_overlay(TR::instructions__continue_holding.into())
|
.with_header_overlay(TR::instructions__continue_holding.into())
|
||||||
});
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
mode,
|
mode,
|
||||||
right_button,
|
right_button,
|
||||||
left_button,
|
left_button,
|
||||||
area: Rect::zero(),
|
area: Rect::zero(),
|
||||||
left_short: true,
|
|
||||||
left_original,
|
|
||||||
right_original,
|
|
||||||
htc_anim,
|
htc_anim,
|
||||||
timeout,
|
timeout,
|
||||||
|
pager: Pager::default(),
|
||||||
|
prev_button: Button::with_icon(theme::ICON_CHEVRON_UP)
|
||||||
|
.styled(theme::button_default())
|
||||||
|
.with_expanded_touch_area(Self::BUTTON_EXPAND_TOUCH)
|
||||||
|
.with_content_offset(Self::BUTTON_CONTENT_OFFSET),
|
||||||
|
next_button: Button::with_icon(theme::ICON_CHEVRON_DOWN)
|
||||||
|
.styled(theme::button_default())
|
||||||
|
.with_expanded_touch_area(Self::BUTTON_EXPAND_TOUCH)
|
||||||
|
.with_content_offset(Self::BUTTON_CONTENT_OFFSET.neg()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle event of the right button at the last page, this includes:
|
/// Handle event of the `right_button` at the last page.
|
||||||
/// - Single button mode
|
///
|
||||||
/// - Double button mode at single page component
|
|
||||||
/// - Double button mode at last page of paginated component
|
|
||||||
/// The function takes care about triggering the correct action to
|
/// The function takes care about triggering the correct action to
|
||||||
/// HoldToConfirm or returning the correct message out of the ActionBar.
|
/// HoldToConfirm or returning the correct message out of the ActionBar.
|
||||||
fn event_right_button_at_last_page(
|
fn event_right_button(&mut self, ctx: &mut EventCtx, msg: ButtonMsg) -> Option<ActionBarMsg> {
|
||||||
&mut self,
|
let is_hold = self
|
||||||
ctx: &mut EventCtx,
|
.right_button
|
||||||
msg: ButtonMsg,
|
.as_ref()
|
||||||
) -> Option<ActionBarMsg> {
|
.is_some_and(|btn| btn.long_press().is_some());
|
||||||
let is_hold = self.right_button.long_press().is_some();
|
|
||||||
match (msg, is_hold) {
|
match (msg, is_hold) {
|
||||||
(ButtonMsg::Pressed, true) => {
|
(ButtonMsg::Pressed, true) => {
|
||||||
if let Some(htc_anim) = &mut self.htc_anim {
|
if let Some(htc_anim) = &mut self.htc_anim {
|
||||||
@ -255,22 +247,61 @@ impl ActionBar {
|
|||||||
|
|
||||||
fn place_buttons(&mut self, bounds: Rect) {
|
fn place_buttons(&mut self, bounds: Rect) {
|
||||||
match &self.mode {
|
match &self.mode {
|
||||||
Mode::Single | Mode::Timeout => {
|
Mode::Timeout => {
|
||||||
self.right_button.place(bounds);
|
self.right_button.place(bounds);
|
||||||
}
|
}
|
||||||
Mode::Double { pager } => {
|
Mode::Single => {
|
||||||
let (left_area, right_area) = if self.left_short && pager.is_last() {
|
let (left_area, right_area) = if !self.pager.is_first() {
|
||||||
// Small left button when on last page
|
self.next_button
|
||||||
|
.set_content_offset(Self::BUTTON_CONTENT_OFFSET.neg());
|
||||||
|
// Small `prev_button` when not on first page
|
||||||
let (left, rest) = bounds.split_left(Self::LEFT_SMALL_BUTTON_WIDTH);
|
let (left, rest) = bounds.split_left(Self::LEFT_SMALL_BUTTON_WIDTH);
|
||||||
let (_, right) = rest.split_left(Self::SPACER_WIDTH);
|
let (_, right) = rest.split_left(Self::SPACER_WIDTH);
|
||||||
(left, right)
|
(left, right)
|
||||||
} else {
|
} else {
|
||||||
// Standard equal-sized buttons
|
self.next_button.set_content_offset(Offset::zero());
|
||||||
|
(Rect::zero(), bounds)
|
||||||
|
};
|
||||||
|
self.right_button.place(right_area);
|
||||||
|
self.prev_button.place(left_area);
|
||||||
|
self.next_button.place(right_area);
|
||||||
|
}
|
||||||
|
Mode::Double { left_short } => {
|
||||||
|
let (left_area, right_area) = if *left_short && self.pager.is_last() {
|
||||||
|
// Small left button
|
||||||
|
let (left, rest) = bounds.split_left(Self::LEFT_SMALL_BUTTON_WIDTH);
|
||||||
|
let (_, right) = rest.split_left(Self::SPACER_WIDTH);
|
||||||
|
(left, right)
|
||||||
|
} else {
|
||||||
|
// Equal-sized buttons
|
||||||
let (left, _, right) = bounds.split_center(Self::SPACER_WIDTH);
|
let (left, _, right) = bounds.split_center(Self::SPACER_WIDTH);
|
||||||
(left, right)
|
(left, right)
|
||||||
};
|
};
|
||||||
self.left_button.place(left_area);
|
self.left_button.place(left_area);
|
||||||
self.right_button.place(right_area);
|
self.right_button.place(right_area);
|
||||||
|
self.prev_button.place(left_area);
|
||||||
|
self.next_button.place(right_area);
|
||||||
|
}
|
||||||
|
Mode::PaginateOnly => {
|
||||||
|
let (left_area, right_area) = if self.pager.is_first() {
|
||||||
|
// Only `next_button`
|
||||||
|
self.next_button.set_content_offset(Offset::zero());
|
||||||
|
(Rect::zero(), bounds)
|
||||||
|
} else if self.pager.is_last() {
|
||||||
|
// Only `prev_button`
|
||||||
|
self.prev_button.set_content_offset(Offset::zero());
|
||||||
|
(bounds, Rect::zero())
|
||||||
|
} else {
|
||||||
|
// Equal-sized `next_button` and `prev_button`
|
||||||
|
let (left, _, right) = bounds.split_center(Self::SPACER_WIDTH);
|
||||||
|
self.prev_button
|
||||||
|
.set_content_offset(Self::BUTTON_CONTENT_OFFSET);
|
||||||
|
self.next_button
|
||||||
|
.set_content_offset(Self::BUTTON_CONTENT_OFFSET.neg());
|
||||||
|
(left, right)
|
||||||
|
};
|
||||||
|
self.prev_button.place(left_area);
|
||||||
|
self.next_button.place(right_area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,42 +331,78 @@ impl Component for ActionBar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Mode::Single => {
|
Mode::Single => {
|
||||||
|
if self.pager.is_single() {
|
||||||
// Only handle confirm button
|
// Only handle confirm button
|
||||||
if let Some(msg) = self.right_button.event(ctx, event) {
|
if let Some(msg) = self.right_button.event(ctx, event) {
|
||||||
return self.event_right_button_at_last_page(ctx, msg);
|
return self.event_right_button(ctx, msg);
|
||||||
}
|
}
|
||||||
}
|
} else if self.pager.is_first() && !self.pager.is_single() {
|
||||||
Mode::Double { pager } => {
|
// First page of multiple: next_button
|
||||||
if pager.is_single() {
|
if let Some(ButtonMsg::Clicked) = self.next_button.event(ctx, event) {
|
||||||
// Single page - show back and confirm
|
|
||||||
if let Some(ButtonMsg::Clicked) = self.left_button.event(ctx, event) {
|
|
||||||
return Some(ActionBarMsg::Cancelled);
|
|
||||||
}
|
|
||||||
if let Some(msg) = self.right_button.event(ctx, event) {
|
|
||||||
return self.event_right_button_at_last_page(ctx, msg);
|
|
||||||
}
|
|
||||||
} else if pager.is_first() && !pager.is_single() {
|
|
||||||
// First page of multiple - go back and next page
|
|
||||||
if let Some(ButtonMsg::Clicked) = self.left_button.event(ctx, event) {
|
|
||||||
return Some(ActionBarMsg::Cancelled);
|
|
||||||
}
|
|
||||||
if let Some(ButtonMsg::Clicked) = self.right_button.event(ctx, event) {
|
|
||||||
return Some(ActionBarMsg::Next);
|
return Some(ActionBarMsg::Next);
|
||||||
}
|
}
|
||||||
} else if pager.is_last() && !pager.is_single() {
|
} else if !self.pager.is_last() && !self.pager.is_single() {
|
||||||
// Last page - enable up button, show confirm
|
// Middle pages: prev_button and next_button
|
||||||
if let Some(ButtonMsg::Clicked) = self.left_button.event(ctx, event) {
|
if let Some(ButtonMsg::Clicked) = self.prev_button.event(ctx, event) {
|
||||||
|
return Some(ActionBarMsg::Prev);
|
||||||
|
}
|
||||||
|
if let Some(ButtonMsg::Clicked) = self.next_button.event(ctx, event) {
|
||||||
|
return Some(ActionBarMsg::Next);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Last page: prev_button and right_button
|
||||||
|
if let Some(ButtonMsg::Clicked) = self.prev_button.event(ctx, event) {
|
||||||
return Some(ActionBarMsg::Prev);
|
return Some(ActionBarMsg::Prev);
|
||||||
}
|
}
|
||||||
if let Some(msg) = self.right_button.event(ctx, event) {
|
if let Some(msg) = self.right_button.event(ctx, event) {
|
||||||
return self.event_right_button_at_last_page(ctx, msg);
|
return self.event_right_button(ctx, msg);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
// Middle pages - navigations up/down
|
}
|
||||||
|
Mode::Double { .. } => {
|
||||||
|
if self.pager.is_single() {
|
||||||
|
// Single page: left_button and right_button
|
||||||
if let Some(ButtonMsg::Clicked) = self.left_button.event(ctx, event) {
|
if let Some(ButtonMsg::Clicked) = self.left_button.event(ctx, event) {
|
||||||
|
return Some(ActionBarMsg::Cancelled);
|
||||||
|
}
|
||||||
|
if let Some(msg) = self.right_button.event(ctx, event) {
|
||||||
|
return self.event_right_button(ctx, msg);
|
||||||
|
}
|
||||||
|
} else if self.pager.is_first() && !self.pager.is_single() {
|
||||||
|
// First page of multiple: left_button and next_button
|
||||||
|
if let Some(ButtonMsg::Clicked) = self.left_button.event(ctx, event) {
|
||||||
|
return Some(ActionBarMsg::Cancelled);
|
||||||
|
}
|
||||||
|
if let Some(ButtonMsg::Clicked) = self.next_button.event(ctx, event) {
|
||||||
|
return Some(ActionBarMsg::Next);
|
||||||
|
}
|
||||||
|
} else if !self.pager.is_last() && !self.pager.is_single() {
|
||||||
|
// Middle pages: prev_button and next_button
|
||||||
|
if let Some(ButtonMsg::Clicked) = self.prev_button.event(ctx, event) {
|
||||||
return Some(ActionBarMsg::Prev);
|
return Some(ActionBarMsg::Prev);
|
||||||
}
|
}
|
||||||
if let Some(ButtonMsg::Clicked) = self.right_button.event(ctx, event) {
|
if let Some(ButtonMsg::Clicked) = self.next_button.event(ctx, event) {
|
||||||
|
return Some(ActionBarMsg::Next);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Last page: prev_button and right_button
|
||||||
|
if let Some(ButtonMsg::Clicked) = self.prev_button.event(ctx, event) {
|
||||||
|
return Some(ActionBarMsg::Prev);
|
||||||
|
}
|
||||||
|
if let Some(msg) = self.right_button.event(ctx, event) {
|
||||||
|
return self.event_right_button(ctx, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Mode::PaginateOnly => {
|
||||||
|
// Only handle navigation, no confirm/cancel regardless of page
|
||||||
|
if !self.pager.is_first() && !self.pager.is_single() {
|
||||||
|
if let Some(ButtonMsg::Clicked) = self.prev_button.event(ctx, event) {
|
||||||
|
return Some(ActionBarMsg::Prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !self.pager.is_last() && !self.pager.is_single() {
|
||||||
|
if let Some(ButtonMsg::Clicked) = self.next_button.event(ctx, event) {
|
||||||
return Some(ActionBarMsg::Next);
|
return Some(ActionBarMsg::Next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -345,16 +412,32 @@ impl Component for ActionBar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||||
if let Some(btn) = &self.left_button {
|
let show_divider = match self.mode {
|
||||||
let pos_divider = btn.area().right_center();
|
Mode::Single => !self.pager.is_first(),
|
||||||
|
Mode::Double { .. } => true,
|
||||||
|
Mode::Timeout => false,
|
||||||
|
Mode::PaginateOnly => !self.pager.is_first() && !self.pager.is_last(),
|
||||||
|
};
|
||||||
|
if show_divider {
|
||||||
|
let pos_divider = self.prev_button.area().right_center();
|
||||||
shape::ToifImage::new(pos_divider, theme::ICON_DASH_VERTICAL.toif)
|
shape::ToifImage::new(pos_divider, theme::ICON_DASH_VERTICAL.toif)
|
||||||
.with_align(Alignment2D::CENTER_LEFT)
|
.with_align(Alignment2D::CENTER_LEFT)
|
||||||
.with_fg(theme::GREY_EXTRA_DARK)
|
.with_fg(theme::GREY_EXTRA_DARK)
|
||||||
.render(target);
|
.render(target);
|
||||||
btn.render(target);
|
|
||||||
}
|
}
|
||||||
|
if self.pager.is_first() {
|
||||||
|
self.left_button.render(target);
|
||||||
|
} else {
|
||||||
|
self.prev_button.render(target);
|
||||||
|
}
|
||||||
|
if self.pager.is_last() {
|
||||||
self.right_button.render(target);
|
self.right_button.render(target);
|
||||||
self.htc_anim.render(target);
|
} else {
|
||||||
|
self.next_button.render(target);
|
||||||
|
}
|
||||||
|
if let Some(htc_anim) = &self.htc_anim {
|
||||||
|
htc_anim.render(target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,6 +448,8 @@ impl crate::trace::Trace for ActionBar {
|
|||||||
if let Some(btn) = &self.left_button {
|
if let Some(btn) = &self.left_button {
|
||||||
t.child("left_button", btn);
|
t.child("left_button", btn);
|
||||||
}
|
}
|
||||||
t.child("right_button", &self.right_button);
|
if let Some(btn) = &self.right_button {
|
||||||
|
t.child("right_button", btn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,9 +155,9 @@ pub const fn button_default() -> ButtonStyleSheet {
|
|||||||
},
|
},
|
||||||
disabled: &ButtonStyle {
|
disabled: &ButtonStyle {
|
||||||
font: fonts::FONT_SATOSHI_MEDIUM_26,
|
font: fonts::FONT_SATOSHI_MEDIUM_26,
|
||||||
text_color: GREY_LIGHT,
|
text_color: GREY,
|
||||||
button_color: BG,
|
button_color: BG,
|
||||||
icon_color: GREY_LIGHT,
|
icon_color: GREY,
|
||||||
background_color: BG,
|
background_color: BG,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user