From a657c5e409ece1ba843ac44dbb964fe3ad49f002 Mon Sep 17 00:00:00 2001 From: Jason Rodney Hansen Date: Sat, 22 Mar 2025 15:05:34 -0600 Subject: [PATCH] Simplify and fix box selection and autoscroll --- src/app.rs | 1 - src/mouse_area.rs | 79 +++++------------------------------------------ src/tab.rs | 43 +++++++++----------------- 3 files changed, 21 insertions(+), 102 deletions(-) diff --git a/src/app.rs b/src/app.rs index cf1991d..d5cba63 100644 --- a/src/app.rs +++ b/src/app.rs @@ -15,7 +15,6 @@ use cosmic::iced::{ #[cfg(feature = "wayland")] use cosmic::iced_winit::commands::overlap_notify::overlap_notify; use cosmic::{ - action, app::{self, context_drawer, Core, Task}, cosmic_config, cosmic_theme, executor, iced::{ diff --git a/src/mouse_area.rs b/src/mouse_area.rs index f26de40..d263b34 100644 --- a/src/mouse_area.rs +++ b/src/mouse_area.rs @@ -49,7 +49,6 @@ pub struct MouseArea<'a, Message> { on_enter: Option>>, on_exit: Option>>, show_drag_rect: bool, - cursor_offset: Option, } impl<'a, Message> MouseArea<'a, Message> { @@ -185,11 +184,6 @@ impl<'a, Message> MouseArea<'a, Message> { self } - pub fn cursor_offset(mut self, offset: Option) -> Self { - self.cursor_offset = offset; - self - } - /// Sets the widget's unique identifier. #[must_use] pub fn with_id(mut self, id: Id) -> Self { @@ -221,8 +215,6 @@ impl<'a, Message, F> OnEnterExit<'a, Message> for F where F: Fn() -> Message + ' struct State { last_position: Option, last_virtual_position: Option, - last_in_bounds_position: Option, - last_cursor_offset: Option, drag_initiated: Option, modifiers: Modifiers, prev_click: Option<(mouse::Click, Instant)>, @@ -300,7 +292,6 @@ impl<'a, Message> MouseArea<'a, Message> { on_exit: None, on_scroll: None, show_drag_rect: false, - cursor_offset: None, } } } @@ -431,6 +422,7 @@ where let mut bg_color = cosmic.accent_color(); //TODO: get correct alpha bg_color.alpha = 0.2; + renderer.start_layer(*viewport); renderer.fill_quad( Quad { bounds, @@ -443,6 +435,7 @@ where }, Color::from(bg_color), ); + renderer.end_layer(); } } } @@ -515,65 +508,7 @@ fn update( } } - // check if offset differs to calculate virtual position - let mut need_to_recalculate = false; - match (state.last_cursor_offset, widget.cursor_offset) { - // check if offset has changed between updates - (Some(last_cursor_offset), Some(cursor_offset)) => { - if last_cursor_offset != cursor_offset { - state.last_cursor_offset = Some(cursor_offset); - need_to_recalculate = true; - } - } - - // we've started moving out of bounds - (None, Some(cursor_offset)) => { - state.last_cursor_offset = Some(cursor_offset); - need_to_recalculate = true; - } - - // we've moved inbounds - (Some(_), None) => { - state.last_cursor_offset = None; - } - _ => {} - } - - if need_to_recalculate { - // if we have a cursor_offset, we need to calculate our "virtual" position - // (where we think the ABSOLUTE cursor is) - we'll take the last in bounds position and - // clamp it to the layout bounds - if let Some(offset) = widget.cursor_offset { - if let Some(in_bounds_pos) = state.last_in_bounds_position { - let mut new_virtual_pos = Point { - x: in_bounds_pos.x + offset.x, - y: in_bounds_pos.y + offset.y, - }; - - // clamp to the viewport - new_virtual_pos.x = if new_virtual_pos.x > (layout_bounds.width + layout_bounds.x) { - layout_bounds.width + layout_bounds.x - } else if new_virtual_pos.x < 0.0 { - 0.0 - } else { - new_virtual_pos.x - }; - - new_virtual_pos.y = if new_virtual_pos.y > (layout_bounds.height + layout_bounds.y) - { - layout_bounds.height + layout_bounds.y - } else if new_virtual_pos.y < 0.0 { - 0.0 - } else { - new_virtual_pos.y - }; - - state.last_virtual_position = Some(new_virtual_pos); - } - } - } - - if let Event::Mouse(mouse::Event::CursorMoved { .. }) = event { + if let Event::Mouse(mouse::Event::CursorMoved { position }) = event { let position_in = cursor.position_in(layout_bounds); match (position_in, state.last_position) { (None, Some(_)) => { @@ -590,10 +525,10 @@ fn update( } state.last_position = position_in; - // set the last in bounds position to be the ABSOLUTE version of position_in - if position_in.is_some() { - state.last_in_bounds_position = cursor.position_over(layout_bounds); - } + state.last_virtual_position = Some(Point::new( + viewport.x - layout_bounds.x + position.x, + viewport.y - layout_bounds.y + position.y, + )); } if state.drag_initiated.is_none() && !cursor.is_over(layout_bounds) { diff --git a/src/tab.rs b/src/tab.rs index 0e0ece4..4193a09 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -1160,7 +1160,6 @@ pub enum Message { DoubleClick(Option), ClickRelease(Option), CursorMoved(Point), - MouseAreaResized(Size, Rectangle), DragEnd(Option), Config(TabConfig), ContextAction(Action), @@ -1824,10 +1823,10 @@ pub struct Tab { search_context: Option, global_cursor_position: Option, current_drag_rect: Option, - viewport_rect: Option, virtual_cursor_offset: Option, last_scroll_position: Option, last_scroll_offset: Option, + scroll_bounds_opt: Option, } fn calculate_dir_size(path: &Path, controller: Controller) -> Result { @@ -1914,10 +1913,10 @@ impl Tab { search_context: None, global_cursor_position: None, current_drag_rect: None, - viewport_rect: None, virtual_cursor_offset: None, last_scroll_position: None, last_scroll_offset: None, + scroll_bounds_opt: None, } } @@ -2217,6 +2216,7 @@ impl Tab { self.items_opt = None; //TODO: remember scroll by location? self.scroll_opt = None; + self.scroll_bounds_opt = None; self.select_focus = None; self.search_context = None; if let Some(history_i) = history_i_opt { @@ -2281,21 +2281,23 @@ impl Tab { // we're currently dragging if self.current_drag_rect.is_some() { - if let Some(viewport) = self.viewport_rect { - if !viewport.contains(pos) { - if pos.y < viewport.y || pos.y > (viewport.y + viewport.height) { - // if our mouse is above the scrollable viewport, we want to scroll up + if let Some(scroll_bounds) = self.scroll_bounds_opt { + if !scroll_bounds.contains(pos) { + if pos.y < scroll_bounds.y + || pos.y > (scroll_bounds.y + scroll_bounds.height) + { + // if our mouse is above the scroll bounds, we want to scroll up let drag_start_point = Point { - x: viewport.x, - y: viewport.y, + x: scroll_bounds.x, + y: scroll_bounds.y, }; // 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 scroll bounds let diff_y = pos.y - drag_start_point.y; let scroll_y: f32 = if diff_y > 0.0 { DRAG_SCROLL_DISTANCE } else if diff_y < 0.0 { - DRAG_SCROLL_DISTANCE * -1.0 + -DRAG_SCROLL_DISTANCE } else { 0.0 }; @@ -2334,20 +2336,6 @@ impl Tab { } } } - Message::MouseAreaResized(_size, viewport) => { - // if we have a scroll position, we want to subtract it from the viewport - // so that we don't desync when swapping - if let Some(scroll_pos) = self.scroll_opt { - self.viewport_rect = Some(Rectangle { - x: viewport.x - scroll_pos.x, - y: viewport.y - scroll_pos.y, - width: viewport.width, - height: viewport.height, - }); - } else { - self.viewport_rect = Some(viewport); - } - } Message::DragEnd(_) => { self.clicked = None; self.virtual_cursor_offset = None; @@ -3005,6 +2993,7 @@ impl Tab { } Message::Scroll(viewport) => { + self.scroll_bounds_opt = Some(viewport.bounds()); self.scroll_opt = Some(viewport.absolute_offset()); } Message::ScrollTab(scroll_speed) => { @@ -4314,8 +4303,6 @@ impl Tab { .on_drag_end(|_| Message::DragEnd(None)) .show_drag_rect(true) .on_release(|_| Message::ClickRelease(None)) - .on_resize(Message::MouseAreaResized) - .cursor_offset(self.virtual_cursor_offset) .into(), true, ) @@ -4649,8 +4636,6 @@ impl Tab { .on_drag_end(|_| Message::DragEnd(None)) .show_drag_rect(true) .on_release(|_| Message::ClickRelease(None)) - .on_resize(Message::MouseAreaResized) - .cursor_offset(self.virtual_cursor_offset) .into(), true, )