feat: add PageUp and PageDown bindings

This commit is contained in:
Gene Wood 2026-06-22 14:37:41 -07:00 committed by GitHub
parent 53a33dbe74
commit 65f5f454be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 121 additions and 0 deletions

View file

@ -155,6 +155,8 @@ pub enum Action {
HistoryPrevious, HistoryPrevious,
ItemDown, ItemDown,
ItemLeft, ItemLeft,
ItemPageDown,
ItemPageUp,
ItemRight, ItemRight,
ItemUp, ItemUp,
LocationUp, LocationUp,
@ -228,6 +230,8 @@ impl Action {
Self::HistoryPrevious => Message::TabMessage(entity_opt, tab::Message::GoPrevious), Self::HistoryPrevious => Message::TabMessage(entity_opt, tab::Message::GoPrevious),
Self::ItemDown => Message::TabMessage(entity_opt, tab::Message::ItemDown), Self::ItemDown => Message::TabMessage(entity_opt, tab::Message::ItemDown),
Self::ItemLeft => Message::TabMessage(entity_opt, tab::Message::ItemLeft), Self::ItemLeft => Message::TabMessage(entity_opt, tab::Message::ItemLeft),
Self::ItemPageDown => Message::TabMessage(entity_opt, tab::Message::ItemPageDown),
Self::ItemPageUp => Message::TabMessage(entity_opt, tab::Message::ItemPageUp),
Self::ItemRight => Message::TabMessage(entity_opt, tab::Message::ItemRight), Self::ItemRight => Message::TabMessage(entity_opt, tab::Message::ItemRight),
Self::ItemUp => Message::TabMessage(entity_opt, tab::Message::ItemUp), Self::ItemUp => Message::TabMessage(entity_opt, tab::Message::ItemUp),
Self::LocationUp => Message::TabMessage(entity_opt, tab::Message::LocationUp), Self::LocationUp => Message::TabMessage(entity_opt, tab::Message::LocationUp),

View file

@ -30,12 +30,16 @@ pub fn key_binds(mode: &tab::Mode) -> HashMap<KeyBind, Action> {
bind!([], Key::Named(Named::F5), Reload); bind!([], Key::Named(Named::F5), Reload);
bind!([], Key::Named(Named::Home), SelectFirst); bind!([], Key::Named(Named::Home), SelectFirst);
bind!([], Key::Named(Named::End), SelectLast); bind!([], Key::Named(Named::End), SelectLast);
bind!([], Key::Named(Named::PageDown), ItemPageDown);
bind!([], Key::Named(Named::PageUp), ItemPageUp);
bind!([Shift], Key::Named(Named::ArrowDown), ItemDown); bind!([Shift], Key::Named(Named::ArrowDown), ItemDown);
bind!([Shift], Key::Named(Named::ArrowLeft), ItemLeft); bind!([Shift], Key::Named(Named::ArrowLeft), ItemLeft);
bind!([Shift], Key::Named(Named::ArrowRight), ItemRight); bind!([Shift], Key::Named(Named::ArrowRight), ItemRight);
bind!([Shift], Key::Named(Named::ArrowUp), ItemUp); bind!([Shift], Key::Named(Named::ArrowUp), ItemUp);
bind!([Shift], Key::Named(Named::Home), SelectFirst); bind!([Shift], Key::Named(Named::Home), SelectFirst);
bind!([Shift], Key::Named(Named::End), SelectLast); bind!([Shift], Key::Named(Named::End), SelectLast);
bind!([Shift], Key::Named(Named::PageDown), ItemPageDown);
bind!([Shift], Key::Named(Named::PageUp), ItemPageUp);
bind!([Ctrl, Shift], Key::Character("n".into()), NewFolder); bind!([Ctrl, Shift], Key::Character("n".into()), NewFolder);
bind!([], Key::Named(Named::Enter), Open); bind!([], Key::Named(Named::Enter), Open);
bind!([Ctrl], Key::Character(" ".into()), Preview); bind!([Ctrl], Key::Character(" ".into()), Preview);

View file

@ -1724,6 +1724,8 @@ pub enum Message {
GoPrevious, GoPrevious,
ItemDown, ItemDown,
ItemLeft, ItemLeft,
ItemPageDown,
ItemPageUp,
ItemRight, ItemRight,
ItemUp, ItemUp,
Location(Location), Location(Location),
@ -3173,6 +3175,23 @@ impl Tab {
} }
} }
fn rows_per_page(&self) -> usize {
let viewport_height = self
.item_view_size_opt
.get()
.map_or(0.0, |s| s.height);
let row_height = self
.select_focus
.and_then(|i| self.items_opt.as_ref()?.get(i))
.and_then(|item| item.rect_opt.get())
.map_or(0.0, |r| r.height);
if row_height > 0.0 && viewport_height > 0.0 {
(viewport_height / row_height).floor() as usize
} else {
1
}
}
fn select_range_start_pos_opt(&self) -> Option<(usize, usize)> { fn select_range_start_pos_opt(&self) -> Option<(usize, usize)> {
let items = self.items_opt.as_ref()?; let items = self.items_opt.as_ref()?;
let item = items.get(self.select_range.map(|r| r.0)?)?; let item = items.get(self.select_range.map(|r| r.0)?)?;
@ -3870,6 +3889,100 @@ impl Tab {
} }
} }
} }
Message::ItemPageDown => {
self.dehighlight_all();
if let Some((row, col)) =
self.select_focus_pos_opt().or(self.select_last_pos_opt())
{
if self.select_focus.is_none() {
self.select_position(row, col, mod_shift);
}
let rows_per_page = self.rows_per_page().max(1);
let target_row = row.saturating_add(rows_per_page);
if !self.select_position(target_row, col, mod_shift) {
// Fall back to the last item at or before target_row
let best = self
.items_opt
.as_ref()
.and_then(|items| {
items
.iter()
.filter_map(|item| item.pos_opt.get())
.filter(|(r, _)| *r <= target_row)
.max()
});
if let Some((best_row, best_col)) = best {
self.select_position(best_row, best_col, mod_shift);
}
}
} else {
self.select_position(0, 0, mod_shift);
}
if let Some(offset) = self.select_focus_scroll() {
commands.push(Command::Iced(
scrollable::scroll_to(
self.scrollable_id.clone(),
AbsoluteOffset {
x: Some(offset.x),
y: Some(offset.y),
},
)
.into(),
));
}
if let Some(id) = self.select_focus_id() {
commands.push(Command::Iced(widget::button::focus(id).into()));
}
}
Message::ItemPageUp => {
self.dehighlight_all();
if let Some((row, col)) =
self.select_focus_pos_opt().or(self.select_first_pos_opt())
{
if self.select_focus.is_none() {
self.select_position(row, col, mod_shift);
}
let rows_per_page = self.rows_per_page().max(1);
let target_row = row.saturating_sub(rows_per_page);
if !self.select_position(target_row, col, mod_shift) {
// Fall back to the first item at or after target_row
let best = self
.items_opt
.as_ref()
.and_then(|items| {
items
.iter()
.filter_map(|item| item.pos_opt.get())
.filter(|(r, _)| *r >= target_row)
.min()
});
if let Some((best_row, best_col)) = best {
self.select_position(best_row, best_col, mod_shift);
}
}
} else {
self.select_position(0, 0, mod_shift);
}
if let Some(offset) = self.select_focus_scroll() {
commands.push(Command::Iced(
scrollable::scroll_to(
self.scrollable_id.clone(),
AbsoluteOffset {
x: Some(offset.x),
y: Some(offset.y),
},
)
.into(),
));
}
if let Some(id) = self.select_focus_id() {
commands.push(Command::Iced(widget::button::focus(id).into()));
}
}
Message::ItemLeft => { Message::ItemLeft => {
self.dehighlight_all(); self.dehighlight_all();
if self.gallery { if self.gallery {