mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-05-30 12:48:46 +00:00
core(eckhart): Update Vertical Menu
Leave event processing to the Vertical Menu Disable scrolling when the menu fits the screen
This commit is contained in:
parent
3ff6b55520
commit
941875c254
@ -421,10 +421,13 @@ impl<'a> DeviceMenuScreen<'a> {
|
|||||||
Subscreen::Submenu(ref mut submenu_index) => {
|
Subscreen::Submenu(ref mut submenu_index) => {
|
||||||
match self.submenus[*submenu_index].items[idx].action {
|
match self.submenus[*submenu_index].items[idx].action {
|
||||||
Some(Action::GoTo(menu)) => {
|
Some(Action::GoTo(menu)) => {
|
||||||
self.menu_screen.as_mut().unwrap().update_menu(ctx);
|
|
||||||
unwrap!(self.parent_subscreens.push(self.active_subscreen));
|
unwrap!(self.parent_subscreens.push(self.active_subscreen));
|
||||||
self.set_active_subscreen(menu);
|
self.set_active_subscreen(menu);
|
||||||
self.place(self.bounds);
|
self.place(self.bounds);
|
||||||
|
if let Some(screen) = self.menu_screen.as_mut() {
|
||||||
|
screen.initialize_screen(ctx);
|
||||||
|
}
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
Some(Action::Return(msg)) => return Some(msg),
|
Some(Action::Return(msg)) => return Some(msg),
|
||||||
None => {}
|
None => {}
|
||||||
@ -438,10 +441,13 @@ impl<'a> DeviceMenuScreen<'a> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn go_back(&mut self) -> Option<DeviceMenuMsg> {
|
fn go_back(&mut self, ctx: &mut EventCtx) -> Option<DeviceMenuMsg> {
|
||||||
if let Some(parent) = self.parent_subscreens.pop() {
|
if let Some(parent) = self.parent_subscreens.pop() {
|
||||||
self.set_active_subscreen(parent);
|
self.set_active_subscreen(parent);
|
||||||
self.place(self.bounds);
|
self.place(self.bounds);
|
||||||
|
if let Some(screen) = self.menu_screen.as_mut() {
|
||||||
|
screen.initialize_screen(ctx);
|
||||||
|
}
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(DeviceMenuMsg::Close)
|
Some(DeviceMenuMsg::Close)
|
||||||
@ -483,7 +489,7 @@ impl<'a> Component for DeviceMenuScreen<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(VerticalMenuScreenMsg::Back) => {
|
Some(VerticalMenuScreenMsg::Back) => {
|
||||||
return self.go_back();
|
return self.go_back(ctx);
|
||||||
}
|
}
|
||||||
Some(VerticalMenuScreenMsg::Close) => {
|
Some(VerticalMenuScreenMsg::Close) => {
|
||||||
return Some(DeviceMenuMsg::Close);
|
return Some(DeviceMenuMsg::Close);
|
||||||
@ -493,7 +499,7 @@ impl<'a> Component for DeviceMenuScreen<'a> {
|
|||||||
}
|
}
|
||||||
Subscreen::AboutScreen => {
|
Subscreen::AboutScreen => {
|
||||||
if let Some(TextScreenMsg::Cancelled) = self.about_screen.event(ctx, event) {
|
if let Some(TextScreenMsg::Cancelled) = self.about_screen.event(ctx, event) {
|
||||||
return self.go_back();
|
return self.go_back(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ impl SelectWordScreen {
|
|||||||
share_words_vec: [TString<'static>; MAX_WORD_QUIZ_ITEMS],
|
share_words_vec: [TString<'static>; MAX_WORD_QUIZ_ITEMS],
|
||||||
description: TString<'static>,
|
description: TString<'static>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut menu = VerticalMenu::empty().with_separators().with_fit_area();
|
let mut menu = VerticalMenu::empty().with_separators().with_content_fit();
|
||||||
|
|
||||||
for word in share_words_vec {
|
for word in share_words_vec {
|
||||||
menu = menu.item(
|
menu = menu.item(
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::ui::{
|
use crate::ui::{
|
||||||
component::{Component, Event, EventCtx},
|
component::{Component, Event, EventCtx},
|
||||||
|
event::TouchEvent,
|
||||||
geometry::{Insets, Offset, Rect},
|
geometry::{Insets, Offset, Rect},
|
||||||
shape::{Bar, Renderer},
|
shape::{Bar, Renderer},
|
||||||
};
|
};
|
||||||
@ -19,19 +20,19 @@ type VerticalMenuButtons = Vec<Button, MENU_MAX_ITEMS>;
|
|||||||
pub struct VerticalMenu {
|
pub struct VerticalMenu {
|
||||||
/// Bounds the sliding window of the menu.
|
/// Bounds the sliding window of the menu.
|
||||||
bounds: Rect,
|
bounds: Rect,
|
||||||
/// Full bounds of the menu, including off-screen items.
|
|
||||||
virtual_bounds: Rect,
|
|
||||||
/// Menu items.
|
/// Menu items.
|
||||||
buttons: VerticalMenuButtons,
|
buttons: VerticalMenuButtons,
|
||||||
/// Whether to show separators between buttons.
|
/// Full height of the menu, including overflowing items.
|
||||||
separators: bool,
|
total_height: i16,
|
||||||
/// Vertical offset of the current view.
|
/// Vertical offset of the current view.
|
||||||
offset_y: i16,
|
offset_y: i16,
|
||||||
/// Maximum vertical offset.
|
/// Maximum vertical offset.
|
||||||
max_offset: i16,
|
offset_y_max: i16,
|
||||||
/// Adapt padding to fit entire area. If the area is too small, the padding
|
/// Adapt padding to fit entire area. If the area is too small, the padding
|
||||||
/// will be reduced to min value.
|
/// will be reduced to min value.
|
||||||
fit_area: bool,
|
content_fit: bool,
|
||||||
|
/// Whether to show separators between buttons.
|
||||||
|
separators: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum VerticalMenuMsg {
|
pub enum VerticalMenuMsg {
|
||||||
@ -45,13 +46,13 @@ impl VerticalMenu {
|
|||||||
|
|
||||||
fn new(buttons: VerticalMenuButtons) -> Self {
|
fn new(buttons: VerticalMenuButtons) -> Self {
|
||||||
Self {
|
Self {
|
||||||
virtual_bounds: Rect::zero(),
|
|
||||||
bounds: Rect::zero(),
|
bounds: Rect::zero(),
|
||||||
buttons,
|
buttons,
|
||||||
separators: false,
|
total_height: 0,
|
||||||
offset_y: 0,
|
offset_y: 0,
|
||||||
max_offset: 0,
|
offset_y_max: 0,
|
||||||
fit_area: false,
|
separators: false,
|
||||||
|
content_fit: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,8 +65,8 @@ impl VerticalMenu {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_fit_area(mut self) -> Self {
|
pub fn with_content_fit(mut self) -> Self {
|
||||||
self.fit_area = true;
|
self.content_fit = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,18 +75,19 @@ impl VerticalMenu {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn area(&self) -> Rect {
|
/// Check if the menu fits its area without scrolling.
|
||||||
self.bounds
|
pub fn fits_area(&self) -> bool {
|
||||||
|
self.total_height <= self.bounds.height()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scroll the menu to the desired offset.
|
/// Scroll the menu to the desired offset.
|
||||||
pub fn set_offset(&mut self, offset_y: i16) {
|
pub fn set_offset(&mut self, offset_y: i16) {
|
||||||
self.offset_y = offset_y.max(0).min(self.max_offset);
|
self.offset_y = offset_y.max(0).min(self.offset_y_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Chcek if the menu is on the bottom.
|
/// Chcek if the menu is on the bottom.
|
||||||
pub fn is_max_offset(&self) -> bool {
|
pub fn is_max_offset(&self) -> bool {
|
||||||
self.offset_y == self.max_offset
|
self.offset_y == self.offset_y_max
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current sliding window offset.
|
/// Get the current sliding window offset.
|
||||||
@ -93,7 +95,10 @@ impl VerticalMenu {
|
|||||||
self.offset_y
|
self.offset_y
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update menu buttons based on the current offset.
|
/// Update state of menu buttons based on the current offset.
|
||||||
|
/// Enable only buttons that are fully visible in the menu area.
|
||||||
|
/// Meaningful only if the menu is scrollable.
|
||||||
|
/// If the menu fits its area, all buttons are enabled.
|
||||||
pub fn update_menu(&mut self, ctx: &mut EventCtx) {
|
pub fn update_menu(&mut self, ctx: &mut EventCtx) {
|
||||||
for button in self.buttons.iter_mut() {
|
for button in self.buttons.iter_mut() {
|
||||||
let in_bounds = button
|
let in_bounds = button
|
||||||
@ -107,19 +112,35 @@ impl VerticalMenu {
|
|||||||
|
|
||||||
fn set_max_offset(&mut self) {
|
fn set_max_offset(&mut self) {
|
||||||
// Calculate the overflow of the menu area
|
// Calculate the overflow of the menu area
|
||||||
let menu_overflow = (self.virtual_bounds.height() - self.bounds.height()).max(0);
|
let menu_overflow = (self.total_height - self.bounds.height()).max(0);
|
||||||
|
|
||||||
// Find the first button from the top that would completely fit in the menu area
|
// Find the first button from the top that would completely fit in the menu area
|
||||||
// in the bottom position
|
// in the bottom position
|
||||||
for button in &self.buttons {
|
for button in &self.buttons {
|
||||||
let offset = button.area().top_left().y - self.area().top_left().y;
|
let offset = button.area().top_left().y - self.bounds.top_left().y;
|
||||||
if offset > menu_overflow {
|
if offset > menu_overflow {
|
||||||
self.max_offset = offset;
|
self.offset_y_max = offset;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.max_offset = menu_overflow;
|
self.offset_y_max = menu_overflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift position of touch events in the menu area by an offset of the current
|
||||||
|
// sliding window position
|
||||||
|
fn shift_touch_event(&self, event: Event) -> Event {
|
||||||
|
match event {
|
||||||
|
Event::Touch(t) => {
|
||||||
|
let o = Offset::y(self.offset_y);
|
||||||
|
Event::Touch(match t {
|
||||||
|
TouchEvent::TouchStart(p) => TouchEvent::TouchStart(p.ofs(o)),
|
||||||
|
TouchEvent::TouchMove(p) => TouchEvent::TouchMove(p.ofs(o)),
|
||||||
|
TouchEvent::TouchEnd(p) => TouchEvent::TouchEnd(p.ofs(o)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => event,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_buttons<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
fn render_buttons<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||||
@ -156,8 +177,8 @@ impl Component for VerticalMenu {
|
|||||||
// Crop the menu area
|
// Crop the menu area
|
||||||
self.bounds = bounds.inset(Self::SIDE_INSETS);
|
self.bounds = bounds.inset(Self::SIDE_INSETS);
|
||||||
|
|
||||||
// Determine padding dynamically if `fit_area` is enabled
|
// Determine padding dynamically if `content_fit` is enabled
|
||||||
let padding = if self.fit_area {
|
let padding = if self.content_fit {
|
||||||
let mut content_height = 0;
|
let mut content_height = 0;
|
||||||
for button in self.buttons.iter_mut() {
|
for button in self.buttons.iter_mut() {
|
||||||
content_height += button.content_height();
|
content_height += button.content_height();
|
||||||
@ -182,12 +203,8 @@ impl Component for VerticalMenu {
|
|||||||
top_left = top_left + Offset::y(button_height);
|
top_left = top_left + Offset::y(button_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate virtual bounds of all buttons combined
|
// Calculate height of all buttons combined
|
||||||
let total_height = top_left.y - self.bounds.top_left().y;
|
self.total_height = top_left.y - self.bounds.top_left().y;
|
||||||
self.virtual_bounds = Rect::from_top_left_and_size(
|
|
||||||
self.bounds.top_left(),
|
|
||||||
Offset::new(self.bounds.width(), total_height),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Calculate maximum offset for scrolling
|
// Calculate maximum offset for scrolling
|
||||||
self.set_max_offset();
|
self.set_max_offset();
|
||||||
@ -196,8 +213,10 @@ impl Component for VerticalMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||||
|
// Shif touch events by the scroll offset
|
||||||
|
let event_shifted = self.shift_touch_event(event);
|
||||||
for (i, button) in self.buttons.iter_mut().enumerate() {
|
for (i, button) in self.buttons.iter_mut().enumerate() {
|
||||||
if let Some(ButtonMsg::Clicked) = button.event(ctx, event) {
|
if let Some(ButtonMsg::Clicked) = button.event(ctx, event_shifted) {
|
||||||
return Some(VerticalMenuMsg::Selected(i));
|
return Some(VerticalMenuMsg::Selected(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,12 @@ use crate::{
|
|||||||
strutil::TString,
|
strutil::TString,
|
||||||
ui::{
|
ui::{
|
||||||
component::{
|
component::{
|
||||||
base::AttachType,
|
|
||||||
swipe_detect::{SwipeConfig, SwipeSettings},
|
swipe_detect::{SwipeConfig, SwipeSettings},
|
||||||
Component, Event, EventCtx, SwipeDetect,
|
Component, Event, EventCtx, SwipeDetect,
|
||||||
},
|
},
|
||||||
event::{SwipeEvent, TouchEvent},
|
event::SwipeEvent,
|
||||||
flow::Swipable,
|
flow::Swipable,
|
||||||
geometry::{Alignment2D, Direction, Offset, Rect},
|
geometry::{Alignment2D, Direction, Rect},
|
||||||
shape::{Renderer, ToifImage},
|
shape::{Renderer, ToifImage},
|
||||||
util::Pager,
|
util::Pager,
|
||||||
},
|
},
|
||||||
@ -22,6 +21,8 @@ pub struct VerticalMenuScreen {
|
|||||||
menu: VerticalMenu,
|
menu: VerticalMenu,
|
||||||
/// Base position of the menu sliding window to scroll around
|
/// Base position of the menu sliding window to scroll around
|
||||||
offset_base: i16,
|
offset_base: i16,
|
||||||
|
/// Used to enable swipe detection only when the menu does not fit its area
|
||||||
|
swipe_enabled: bool,
|
||||||
/// Swipe detector
|
/// Swipe detector
|
||||||
swipe: SwipeDetect,
|
swipe: SwipeDetect,
|
||||||
/// Swipe configuration
|
/// Swipe configuration
|
||||||
@ -37,11 +38,13 @@ pub enum VerticalMenuScreenMsg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VerticalMenuScreen {
|
impl VerticalMenuScreen {
|
||||||
|
const TOUCH_SENSITIVITY_DIVIDER: i16 = 15;
|
||||||
pub fn new(menu: VerticalMenu) -> Self {
|
pub fn new(menu: VerticalMenu) -> Self {
|
||||||
Self {
|
Self {
|
||||||
header: Header::new(TString::empty()),
|
header: Header::new(TString::empty()),
|
||||||
menu,
|
menu,
|
||||||
offset_base: 0,
|
offset_base: 0,
|
||||||
|
swipe_enabled: false,
|
||||||
swipe: SwipeDetect::new(),
|
swipe: SwipeDetect::new(),
|
||||||
swipe_config: SwipeConfig::new()
|
swipe_config: SwipeConfig::new()
|
||||||
.with_swipe(Direction::Up, SwipeSettings::default())
|
.with_swipe(Direction::Up, SwipeSettings::default())
|
||||||
@ -54,32 +57,23 @@ impl VerticalMenuScreen {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shift position of touch events in the menu area by an offset of the current
|
/// Update swipe detection and buttons state based on menu size
|
||||||
// sliding window position
|
pub fn initialize_screen(&mut self, ctx: &mut EventCtx) {
|
||||||
fn shift_touch_event(&self, event: Event) -> Option<Event> {
|
if !self.menu.fits_area() {
|
||||||
match event {
|
// Enable swipe
|
||||||
Event::Touch(touch_event) => {
|
self.swipe_enabled = true;
|
||||||
let shifted_event = match touch_event {
|
self.swipe_config = SwipeConfig::new()
|
||||||
TouchEvent::TouchStart(point) if self.menu.area().contains(point) => Some(
|
.with_swipe(Direction::Up, SwipeSettings::default())
|
||||||
TouchEvent::TouchStart(point.ofs(Offset::y(self.menu.get_offset()))),
|
.with_swipe(Direction::Down, SwipeSettings::default());
|
||||||
),
|
ctx.enable_swipe();
|
||||||
TouchEvent::TouchMove(point) if self.menu.area().contains(point) => Some(
|
|
||||||
TouchEvent::TouchMove(point.ofs(Offset::y(self.menu.get_offset()))),
|
|
||||||
),
|
|
||||||
TouchEvent::TouchEnd(point) if self.menu.area().contains(point) => Some(
|
|
||||||
TouchEvent::TouchEnd(point.ofs(Offset::y(self.menu.get_offset()))),
|
|
||||||
),
|
|
||||||
_ => None, // Ignore touch events outside the bounds
|
|
||||||
};
|
|
||||||
shifted_event.map(Event::Touch)
|
|
||||||
}
|
|
||||||
_ => None, // Ignore other events
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Update menu buttons based on the current offset.
|
// Update the menu buttons state
|
||||||
pub fn update_menu(&mut self, ctx: &mut EventCtx) {
|
self.menu.update_menu(ctx);
|
||||||
self.menu.update_menu(ctx);
|
} else {
|
||||||
|
// Disable swipe
|
||||||
|
self.swipe_enabled = false;
|
||||||
|
ctx.disable_swipe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,49 +87,58 @@ impl Component for VerticalMenuScreen {
|
|||||||
|
|
||||||
let (header_area, menu_area) = bounds.split_top(Header::HEADER_HEIGHT);
|
let (header_area, menu_area) = bounds.split_top(Header::HEADER_HEIGHT);
|
||||||
|
|
||||||
self.menu.place(menu_area);
|
|
||||||
self.header.place(header_area);
|
self.header.place(header_area);
|
||||||
|
self.menu.place(menu_area);
|
||||||
|
|
||||||
bounds
|
bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||||
// Update the menu when the screen is attached
|
// Update the screen after the menu fit is calculated
|
||||||
if let Event::Attach(AttachType::Initial) = event {
|
// This is needed to enable swipe detection only when the menu does not fit
|
||||||
self.update_menu(ctx);
|
if let Event::Attach(_) = event {
|
||||||
|
self.initialize_screen(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.swipe.event(ctx, event, self.swipe_config) {
|
// Handle swipe events if swipe is enabled (menu does not fit)
|
||||||
Some(SwipeEvent::Start(_)) => {
|
if self.swipe_enabled {
|
||||||
// Lock the base position to scroll around
|
// Handle swipe events from the standalone swipe detector or ones coming from
|
||||||
self.offset_base = self.menu.get_offset();
|
// the flow. These two are mutually exclusive and should not be triggered at the
|
||||||
}
|
// same time.
|
||||||
|
let swipe_event = self
|
||||||
|
.swipe
|
||||||
|
.event(ctx, event, self.swipe_config)
|
||||||
|
.or(match event {
|
||||||
|
Event::Swipe(e) => Some(e),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
|
||||||
Some(SwipeEvent::End(_)) => {
|
match swipe_event {
|
||||||
// Lock the base position to scroll around
|
Some(SwipeEvent::Start(_) | SwipeEvent::End(_)) => {
|
||||||
self.offset_base = self.menu.get_offset();
|
// Lock the base position to scroll around
|
||||||
}
|
self.offset_base = self.menu.get_offset();
|
||||||
|
|
||||||
Some(SwipeEvent::Move(dir, delta)) => {
|
|
||||||
// Decrease the sensitivity of the swipe
|
|
||||||
let delta = delta / 10;
|
|
||||||
// Scroll the menu based on the swipe direction
|
|
||||||
match dir {
|
|
||||||
Direction::Up => {
|
|
||||||
self.menu.set_offset(self.offset_base + delta);
|
|
||||||
self.menu.update_menu(ctx);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Direction::Down => {
|
|
||||||
self.menu.set_offset(self.offset_base - delta);
|
|
||||||
self.menu.update_menu(ctx);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
Some(SwipeEvent::Move(dir, delta)) => {
|
||||||
|
// Decrease the sensitivity of the swipe
|
||||||
|
let delta = delta / Self::TOUCH_SENSITIVITY_DIVIDER;
|
||||||
|
// Scroll the menu based on the swipe direction
|
||||||
|
match dir {
|
||||||
|
Direction::Up => {
|
||||||
|
self.menu.set_offset(self.offset_base + delta);
|
||||||
|
self.menu.update_menu(ctx);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Direction::Down => {
|
||||||
|
self.menu.set_offset(self.offset_base - delta);
|
||||||
|
self.menu.update_menu(ctx);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
_ => {}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(msg) = self.header.event(ctx, event) {
|
if let Some(msg) = self.header.event(ctx, event) {
|
||||||
match msg {
|
match msg {
|
||||||
@ -145,11 +148,8 @@ impl Component for VerticalMenuScreen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shift touch events in the menu area by the current sliding window position
|
if let Some(VerticalMenuMsg::Selected(i)) = self.menu.event(ctx, event) {
|
||||||
if let Some(shifted) = self.shift_touch_event(event) {
|
return Some(VerticalMenuScreenMsg::Selected(i));
|
||||||
if let Some(VerticalMenuMsg::Selected(i)) = self.menu.event(ctx, shifted) {
|
|
||||||
return Some(VerticalMenuScreenMsg::Selected(i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
@ -159,15 +159,12 @@ impl Component for VerticalMenuScreen {
|
|||||||
self.header.render(target);
|
self.header.render(target);
|
||||||
self.menu.render(target);
|
self.menu.render(target);
|
||||||
|
|
||||||
// Render the down arrow if the menu can be scrolled down
|
// Render the down arrow if the menu overflows and can be scrolled further down
|
||||||
if !self.menu.is_max_offset() {
|
if !self.menu.fits_area() && !self.menu.is_max_offset() {
|
||||||
ToifImage::new(
|
ToifImage::new(SCREEN.bottom_center(), theme::ICON_CHEVRON_DOWN_MINI.toif)
|
||||||
self.menu.area().bottom_center(),
|
.with_align(Alignment2D::BOTTOM_CENTER)
|
||||||
theme::ICON_CHEVRON_DOWN_MINI.toif,
|
.with_fg(theme::GREY_LIGHT)
|
||||||
)
|
.render(target);
|
||||||
.with_align(Alignment2D::BOTTOM_CENTER)
|
|
||||||
.with_fg(theme::GREY_LIGHT)
|
|
||||||
.render(target);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user