Moving autoscroll to a subscription on fixed timer + calculating speed based off of distance to edge

This commit is contained in:
ellieplayswow 2025-02-19 11:29:19 +00:00
parent 169d8ef365
commit 9d60ca1564
2 changed files with 61 additions and 13 deletions

View file

@ -18,6 +18,7 @@ use cosmic::{
app::{self, context_drawer, message, Core, Task}, app::{self, context_drawer, message, Core, Task},
cosmic_config, cosmic_theme, executor, cosmic_config, cosmic_theme, executor,
iced::{ iced::{
self,
clipboard::dnd::DndAction, clipboard::dnd::DndAction,
event, event,
futures::{self, SinkExt}, futures::{self, SinkExt},
@ -332,6 +333,7 @@ pub enum Message {
Rename(Option<Entity>), Rename(Option<Entity>),
ReplaceResult(ReplaceResult), ReplaceResult(ReplaceResult),
RestoreFromTrash(Option<Entity>), RestoreFromTrash(Option<Entity>),
ScrollTab(f32),
SearchActivate, SearchActivate,
SearchClear, SearchClear,
SearchInput(String), SearchInput(String),
@ -550,6 +552,7 @@ pub struct App {
tab_dnd_hover: Option<(Entity, Instant)>, tab_dnd_hover: Option<(Entity, Instant)>,
nav_drag_id: DragId, nav_drag_id: DragId,
tab_drag_id: DragId, tab_drag_id: DragId,
auto_scroll_speed: Option<f32>
} }
impl App { impl App {
@ -1628,6 +1631,7 @@ impl Application for App {
tab_dnd_hover: None, tab_dnd_hover: None,
nav_drag_id: DragId::new(), nav_drag_id: DragId::new(),
tab_drag_id: DragId::new(), tab_drag_id: DragId::new(),
auto_scroll_speed: None,
}; };
let mut commands = vec![app.update_config()]; let mut commands = vec![app.update_config()];
@ -2794,6 +2798,10 @@ impl Application for App {
self.operation(Operation::Restore { items: trash_items }); self.operation(Operation::Restore { items: trash_items });
} }
} }
Message::ScrollTab(scroll_speed) => {
let entity = self.tab_model.active();
return self.update(Message::TabMessage(Some(entity), tab::Message::ScrollTab(scroll_speed)));
}
Message::SearchActivate => { Message::SearchActivate => {
return if self.search_get().is_none() { return if self.search_get().is_none() {
self.search_set_active(Some(String::new())) self.search_set_active(Some(String::new()))
@ -2931,6 +2939,9 @@ impl Application for App {
config_set!(favorites, favorites); config_set!(favorites, favorites);
commands.push(self.update_config()); commands.push(self.update_config());
} }
tab::Command::AutoScroll(scroll_speed) => {
self.auto_scroll_speed = scroll_speed;
}
tab::Command::ChangeLocation(tab_title, tab_path, selection_paths) => { tab::Command::ChangeLocation(tab_title, tab_path, selection_paths) => {
self.activate_nav_model_location(&tab_path); self.activate_nav_model_location(&tab_path);
@ -4714,6 +4725,13 @@ impl Application for App {
), ),
]; ];
if let Some(scroll_speed) = self.auto_scroll_speed {
subscriptions.push(
iced::time::every(time::Duration::from_millis(10))
.map(move |_| Message::ScrollTab(scroll_speed))
);
}
for (key, mounter) in MOUNTERS.iter() { for (key, mounter) in MOUNTERS.iter() {
subscriptions.push( subscriptions.push(
mounter.subscription().with(*key).map( mounter.subscription().with(*key).map(

View file

@ -83,7 +83,8 @@ const MAX_SEARCH_RESULTS: usize = 200;
//TODO: configurable thumbnail size? //TODO: configurable thumbnail size?
const THUMBNAIL_SIZE: u32 = (ICON_SIZE_GRID as u32) * (ICON_SCALE_MAX as u32); const THUMBNAIL_SIZE: u32 = (ICON_SIZE_GRID as u32) * (ICON_SCALE_MAX as u32);
const DRAG_SCROLL_DISTANCE: u8 = 1; const DRAG_SCROLL_DISTANCE: f32 = 15.0;
const DRAG_SCROLL_RATIO_MAXIMUM: f32 = 3.0;
//TODO: adjust for locales? //TODO: adjust for locales?
const DATE_TIME_FORMAT: &str = "%b %-d, %-Y, %-I:%M %p"; const DATE_TIME_FORMAT: &str = "%b %-d, %-Y, %-I:%M %p";
@ -1100,6 +1101,7 @@ pub enum Command {
Action(Action), Action(Action),
AddNetworkDrive, AddNetworkDrive,
AddToSidebar(PathBuf), AddToSidebar(PathBuf),
AutoScroll(Option<f32>),
ChangeLocation(String, Location, Option<Vec<PathBuf>>), ChangeLocation(String, Location, Option<Vec<PathBuf>>),
DropFiles(PathBuf, ClipboardPaste), DropFiles(PathBuf, ClipboardPaste),
EmptyTrash, EmptyTrash,
@ -1157,6 +1159,7 @@ pub enum Message {
RightClick(Option<usize>), RightClick(Option<usize>),
MiddleClick(usize), MiddleClick(usize),
Scroll(Viewport), Scroll(Viewport),
ScrollTab(f32),
ScrollToFocus, ScrollToFocus,
SearchContext(Location, SearchContextWrapper), SearchContext(Location, SearchContextWrapper),
SearchReady(bool), SearchReady(bool),
@ -2231,17 +2234,36 @@ impl Tab {
// diff_y should be NEGATIVE here when close to y=0 (above the MouseArea) // diff_y should be NEGATIVE here when close to y=0 (above the MouseArea)
// and positive when below the viewport // and positive when below the viewport
let diff_y = pos.y - drag_start_point.y; let diff_y = pos.y - drag_start_point.y;
let scroll_y: i8 = if diff_y > 0.0 { let mut scroll_y: f32 = if diff_y > 0.0 {
DRAG_SCROLL_DISTANCE as i8 DRAG_SCROLL_DISTANCE
} else if diff_y < 0.0 { } else if diff_y < 0.0 {
DRAG_SCROLL_DISTANCE as i8 * -1 DRAG_SCROLL_DISTANCE * -1.0
} else { } else {
0 0.0
}; };
// estimate distance and use that to control speed
// go up to 3x speed
let quarter_height = viewport.height / 4.0;
let cursor_y_distance = if diff_y > 0.0 {
pos.y - (viewport.y + viewport.height)
} else if diff_y < 0.0 {
pos.y - viewport.y
} else {
0.0
}.abs();
let mut speed_ratio = (cursor_y_distance / quarter_height) + 1.0;
if speed_ratio > DRAG_SCROLL_RATIO_MAXIMUM {
speed_ratio = DRAG_SCROLL_RATIO_MAXIMUM;
}
scroll_y = scroll_y * speed_ratio;
let mut new_offset = Point { let mut new_offset = Point {
x: 0.0, x: 0.0,
y: scroll_y as f32 y: scroll_y
}; };
if let Some(virtual_cursor_offset) = self.virtual_cursor_offset { if let Some(virtual_cursor_offset) = self.virtual_cursor_offset {
@ -2258,12 +2280,7 @@ impl Tab {
self.virtual_cursor_offset = Some(new_offset); self.virtual_cursor_offset = Some(new_offset);
self.last_scroll_offset = Some(new_offset); self.last_scroll_offset = Some(new_offset);
commands.push(Command::Iced( commands.push(Command::AutoScroll(Some(scroll_y)));
scrollable::scroll_by(self.scrollable_id.clone(), AbsoluteOffset {
x: 0.0,
y: scroll_y as f32
}).into(),
));
} }
else { else {
if let Some(last_scroll_offset) = self.last_scroll_offset { if let Some(last_scroll_offset) = self.last_scroll_offset {
@ -2288,8 +2305,9 @@ impl Tab {
y: 0.0 y: 0.0
}); });
} }
} }
commands.push(Command::AutoScroll(None));
} }
} }
else { else {
@ -2297,6 +2315,8 @@ impl Tab {
self.virtual_cursor_offset = None; self.virtual_cursor_offset = None;
self.last_scroll_position = Some(pos); self.last_scroll_position = Some(pos);
self.last_scroll_offset = None; self.last_scroll_offset = None;
commands.push(Command::AutoScroll(None));
} }
} }
} }
@ -2329,6 +2349,8 @@ impl Tab {
item.overlaps_drag_rect = false; item.overlaps_drag_rect = false;
} }
} }
commands.push(Command::AutoScroll(None));
} }
Message::DoubleClick(click_i_opt) => { Message::DoubleClick(click_i_opt) => {
if let Some(clicked_item) = self if let Some(clicked_item) = self
@ -2959,6 +2981,14 @@ impl Tab {
Message::Scroll(viewport) => { Message::Scroll(viewport) => {
self.scroll_opt = Some(viewport.absolute_offset()); self.scroll_opt = Some(viewport.absolute_offset());
} }
Message::ScrollTab(scroll_speed) => {
commands.push(Command::Iced(
scrollable::scroll_by(self.scrollable_id.clone(), AbsoluteOffset {
x: 0.0,
y: scroll_speed
}).into(),
));
}
Message::ScrollToFocus => { Message::ScrollToFocus => {
if let Some(offset) = self.select_focus_scroll() { if let Some(offset) = self.select_focus_scroll() {
commands.push(Command::Iced( commands.push(Command::Iced(