Adjust scroll when using arrow keys

This commit is contained in:
Jeremy Soller 2024-02-29 16:25:54 -07:00
parent 08a7f6faed
commit 501e4f48eb
No known key found for this signature in database
GPG key ID: D02FD439211AF56F
3 changed files with 69 additions and 4 deletions

View file

@ -9,6 +9,7 @@ use cosmic::{
futures::{self, SinkExt}, futures::{self, SinkExt},
keyboard::{Event as KeyEvent, Key, Modifiers}, keyboard::{Event as KeyEvent, Key, Modifiers},
subscription::{self, Subscription}, subscription::{self, Subscription},
widget::scrollable,
window, Alignment, Event, Length, window, Alignment, Event, Length,
}, },
style, theme, style, theme,
@ -1065,6 +1066,9 @@ impl Application for App {
} }
} }
} }
tab::Command::Scroll(id, offset) => {
commands.push(scrollable::scroll_to(id, offset));
}
} }
} }
return Command::batch(commands); return Command::batch(commands);

View file

@ -10,6 +10,7 @@ use cosmic::{
keyboard::{Event as KeyEvent, Modifiers}, keyboard::{Event as KeyEvent, Modifiers},
multi_window::Application as IcedApplication, multi_window::Application as IcedApplication,
subscription::{self, Subscription}, subscription::{self, Subscription},
widget::scrollable,
window, Event, Length, Size, window, Event, Length, Size,
}, },
theme, theme,
@ -592,6 +593,9 @@ impl Application for App {
commands.push(self.update(Message::Open)); commands.push(self.update(Message::Open));
} }
} }
tab::Command::Scroll(id, offset) => {
commands.push(scrollable::scroll_to(id, offset));
}
} }
} }
return Command::batch(commands); return Command::batch(commands);

View file

@ -6,7 +6,10 @@ use cosmic::{
keyboard::Modifiers, keyboard::Modifiers,
subscription::{self, Subscription}, subscription::{self, Subscription},
//TODO: export in cosmic::widget //TODO: export in cosmic::widget
widget::{horizontal_rule, scrollable::Viewport}, widget::{
horizontal_rule,
scrollable::{AbsoluteOffset, Viewport},
},
Alignment, Alignment,
Color, Color,
ContentFit, ContentFit,
@ -385,6 +388,7 @@ pub enum Command {
FocusButton(widget::Id), FocusButton(widget::Id),
FocusTextInput(widget::Id), FocusTextInput(widget::Id),
OpenFile(PathBuf), OpenFile(PathBuf),
Scroll(widget::Id, AbsoluteOffset),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -568,7 +572,7 @@ pub struct Tab {
pub context_menu: Option<Point>, pub context_menu: Option<Point>,
pub view: View, pub view: View,
pub dialog: Option<DialogKind>, pub dialog: Option<DialogKind>,
pub scroll_opt: Option<Viewport>, pub scroll_opt: Option<AbsoluteOffset>,
pub size_opt: Option<Size>, pub size_opt: Option<Size>,
pub edit_location: Option<Location>, pub edit_location: Option<Location>,
pub edit_location_id: widget::Id, pub edit_location_id: widget::Id,
@ -576,6 +580,7 @@ pub struct Tab {
pub history: Vec<Location>, pub history: Vec<Location>,
pub config: TabConfig, pub config: TabConfig,
items_opt: Option<Vec<Item>>, items_opt: Option<Vec<Item>>,
scrollable_id: widget::Id,
select_focus: Option<usize>, select_focus: Option<usize>,
select_shift: Option<usize>, select_shift: Option<usize>,
sort_name: HeadingOptions, sort_name: HeadingOptions,
@ -600,6 +605,7 @@ impl Tab {
history, history,
config, config,
items_opt: None, items_opt: None,
scrollable_id: widget::Id::unique(),
select_focus: None, select_focus: None,
select_shift: None, select_shift: None,
sort_name, sort_name,
@ -742,6 +748,38 @@ impl Tab {
item.pos_opt.get() item.pos_opt.get()
} }
fn select_focus_scroll(&mut self) -> Option<AbsoluteOffset> {
let items = self.items_opt.as_ref()?;
let item = items.get(self.select_focus?)?;
let rect = item.rect_opt.get()?;
//TODO: move to function
let visible_rect = {
let point = match self.scroll_opt {
Some(offset) => Point::new(0.0, offset.y),
None => Point::new(0.0, 0.0),
};
let size = self.size_opt.unwrap_or_else(|| Size::new(0.0, 0.0));
Rectangle::new(point, size)
};
if rect.y < visible_rect.y {
// Scroll up to rect
self.scroll_opt = Some(AbsoluteOffset { x: 0.0, y: rect.y });
self.scroll_opt
} else if (rect.y + rect.height) > (visible_rect.y + visible_rect.height) {
// Scroll down to rect
self.scroll_opt = Some(AbsoluteOffset {
x: 0.0,
y: rect.y + rect.height - visible_rect.height,
});
self.scroll_opt
} else {
// Do not scroll
None
}
}
fn select_shift_pos_opt(&self) -> Option<(usize, usize)> { fn select_shift_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_shift?)?; let item = items.get(self.select_shift?)?;
@ -856,8 +894,12 @@ impl Tab {
} }
} else { } else {
// Select first item // Select first item
//TODO: select first in scroll
self.select_position(0, 0, mod_shift); self.select_position(0, 0, mod_shift);
} }
if let Some(offset) = self.select_focus_scroll() {
commands.push(Command::Scroll(self.scrollable_id.clone(), offset));
}
if let Some(id) = self.select_focus_id() { if let Some(id) = self.select_focus_id() {
commands.push(Command::FocusButton(id)); commands.push(Command::FocusButton(id));
} }
@ -890,8 +932,12 @@ impl Tab {
} }
} else { } else {
// Select first item // Select first item
//TODO: select first in scroll
self.select_position(0, 0, mod_shift); self.select_position(0, 0, mod_shift);
} }
if let Some(offset) = self.select_focus_scroll() {
commands.push(Command::Scroll(self.scrollable_id.clone(), offset));
}
if let Some(id) = self.select_focus_id() { if let Some(id) = self.select_focus_id() {
commands.push(Command::FocusButton(id)); commands.push(Command::FocusButton(id));
} }
@ -908,8 +954,12 @@ impl Tab {
} }
} else { } else {
// Select first item // Select first item
//TODO: select first in scroll
self.select_position(0, 0, mod_shift); self.select_position(0, 0, mod_shift);
} }
if let Some(offset) = self.select_focus_scroll() {
commands.push(Command::Scroll(self.scrollable_id.clone(), offset));
}
if let Some(id) = self.select_focus_id() { if let Some(id) = self.select_focus_id() {
commands.push(Command::FocusButton(id)); commands.push(Command::FocusButton(id));
} }
@ -927,8 +977,12 @@ impl Tab {
} }
} else { } else {
// Select first item // Select first item
//TODO: select first in scroll
self.select_position(0, 0, mod_shift); self.select_position(0, 0, mod_shift);
} }
if let Some(offset) = self.select_focus_scroll() {
commands.push(Command::Scroll(self.scrollable_id.clone(), offset));
}
if let Some(id) = self.select_focus_id() { if let Some(id) = self.select_focus_id() {
commands.push(Command::FocusButton(id)); commands.push(Command::FocusButton(id));
} }
@ -987,7 +1041,7 @@ impl Tab {
} }
} }
Message::Scroll(viewport) => { Message::Scroll(viewport) => {
self.scroll_opt = Some(viewport); self.scroll_opt = Some(viewport.absolute_offset());
} }
Message::Thumbnail(path, thumbnail_res) => { Message::Thumbnail(path, thumbnail_res) => {
if let Some(ref mut items) = self.items_opt { if let Some(ref mut items) = self.items_opt {
@ -1418,6 +1472,7 @@ impl Tab {
.on_drag(Message::Drag) .on_drag(Message::Drag)
.show_drag_rect(true), .show_drag_rect(true),
) )
.id(self.scrollable_id.clone())
.on_scroll(Message::Scroll) .on_scroll(Message::Scroll)
.width(Length::Fill) .width(Length::Fill)
.into() .into()
@ -1569,6 +1624,7 @@ impl Tab {
} }
widget::scrollable(widget::column::with_children(children).padding([0, space_m])) widget::scrollable(widget::column::with_children(children).padding([0, space_m]))
.id(self.scrollable_id.clone())
.on_scroll(Message::Scroll) .on_scroll(Message::Scroll)
.width(Length::Fill) .width(Length::Fill)
.into() .into()
@ -1613,9 +1669,10 @@ impl Tab {
let jobs = 8; let jobs = 8;
let mut subscriptions = Vec::with_capacity(jobs); let mut subscriptions = Vec::with_capacity(jobs);
//TODO: move to function
let visible_rect = { let visible_rect = {
let point = match self.scroll_opt { let point = match self.scroll_opt {
Some(viewport) => Point::new(0.0, viewport.absolute_offset().y), Some(offset) => Point::new(0.0, offset.y),
None => Point::new(0.0, 0.0), None => Point::new(0.0, 0.0),
}; };
let size = self.size_opt.unwrap_or_else(|| Size::new(0.0, 0.0)); let size = self.size_opt.unwrap_or_else(|| Size::new(0.0, 0.0));