From 6c8391ab1893d29822e9472de3899b9bfbbfe908 Mon Sep 17 00:00:00 2001 From: matejcik Date: Thu, 30 Jan 2025 13:03:27 +0100 Subject: [PATCH] feat(core/rust): introduce Pager --- core/embed/rust/src/ui/util.rs | 132 +++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/core/embed/rust/src/ui/util.rs b/core/embed/rust/src/ui/util.rs index a4c0e4801e..9a6b26c813 100644 --- a/core/embed/rust/src/ui/util.rs +++ b/core/embed/rust/src/ui/util.rs @@ -160,6 +160,138 @@ macro_rules! include_res { } pub(crate) use include_res; +/// Pager helper for keeping track of the current page and total number of +/// pages. +/// +/// Page numbers are zero-based, so the values can be directly used for indexing +/// arrays, etc. It always holds that `current < total`, and `total > 0`. +#[derive(Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))] +pub struct Pager { + /// Zero-based index of the current page. + current: u16, + /// Total number of pages. + total: u16, +} + +impl Pager { + /// Create a new pager with the given total number of pages. + pub fn new(total: u16) -> Self { + debug_assert!(total > 0); + Self { current: 0, total } + } + + /// Create a new pager with a single page. + pub fn single_page() -> Self { + Self::new(1) + } + + /// Create a new pager with the given current page index. + pub fn with_current(mut self, current: u16) -> Self { + self.set_current(current); + self + } + + /// Limit the size of the pager to the given number of pages. + pub fn with_limit(mut self, limit: u16) -> Self { + self.total = self.total.min(limit); + // update current to be within bounds + self.set_current(self.current); + self + } + + /// Get the current page index. + pub fn current(&self) -> u16 { + self.current + } + + /// Get the total number of pages. + pub fn total(&self) -> u16 { + self.total + } + + /// Set the current page index. + pub fn set_current(&mut self, idx: u16) { + self.current = idx.min(self.last()); + } + + /// Get the last page index. + pub fn last(&self) -> u16 { + self.total.saturating_sub(1) + } + + /// Check if the current page is the first one. + pub fn is_first(&self) -> bool { + self.current == 0 + } + + /// Check if the current page is the last one. + pub fn is_last(&self) -> bool { + self.current == self.last() + } + + /// Check if the pager has a single page. + pub fn is_single(&self) -> bool { + self.total == 1 + } + + /// Check if there is a previous page for the current page. + pub fn has_prev(&self) -> bool { + !self.is_first() + } + + /// Check if there is a next page for the current page. + pub fn has_next(&self) -> bool { + !self.is_last() + } + + /// Get the index of the next page. + pub fn next(&self) -> u16 { + self.current.saturating_add(1).min(self.last()) + } + + /// Get the index of the previous page. + pub fn prev(&self) -> u16 { + self.current.saturating_sub(1) + } + + /// Go to the next page. + /// + /// Returns true if this resulted in a move. False if we are already at the + /// last page. + pub fn goto_next(&mut self) -> bool { + let has_next = self.has_next(); + self.current = self.next(); + has_next + } + + /// Go to the previous page. + /// + /// Returns true if this resulted in a move. False if we are already at the + /// first page. + pub fn goto_prev(&mut self) -> bool { + let has_prev = self.has_prev(); + self.current = self.prev(); + has_prev + } + + /// Go to the first page. + pub fn goto_first(&mut self) { + self.current = 0; + } + + /// Go to the last page. + pub fn goto_last(&mut self) { + self.current = self.last(); + } +} + +impl Default for Pager { + fn default() -> Self { + Self::single_page() + } +} + #[cfg(test)] mod tests { use crate::strutil;