From 1453954ef4398535f017530ce52a30d7aea0ac34 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 6 Apr 2022 09:08:44 +0200 Subject: [PATCH] Autoscroll to active tab when activating a new item --- crates/gpui/src/elements/flex.rs | 29 +++++++++++++++++++++++++++-- crates/workspace/src/pane.rs | 12 ++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/crates/gpui/src/elements/flex.rs b/crates/gpui/src/elements/flex.rs index ff98d2948b4ec538f784d92fdc34d1e3dca0bd94..f7d60e409bd3581bcb1c4bd85e2106650be3641f 100644 --- a/crates/gpui/src/elements/flex.rs +++ b/crates/gpui/src/elements/flex.rs @@ -13,6 +13,7 @@ use serde_json::json; #[derive(Default)] struct ScrollState { + scroll_to: Option, scroll_position: f32, } @@ -39,12 +40,19 @@ impl Flex { Self::new(Axis::Vertical) } - pub fn scrollable(mut self, element_id: usize, cx: &mut C) -> Self + pub fn scrollable( + mut self, + element_id: usize, + scroll_to: Option, + cx: &mut C, + ) -> Self where Tag: 'static, C: ElementStateContext, { - self.scroll_state = Some(cx.element_state::(element_id)); + let scroll_state = cx.element_state::(element_id); + scroll_state.update(cx, |scroll_state, _| scroll_state.scroll_to = scroll_to); + self.scroll_state = Some(scroll_state); self } @@ -185,6 +193,23 @@ impl Element for Flex { if let Some(scroll_state) = self.scroll_state.as_ref() { scroll_state.update(cx, |scroll_state, _| { + if let Some(scroll_to) = scroll_state.scroll_to.take() { + let visible_start = scroll_state.scroll_position; + let visible_end = visible_start + size.along(self.axis); + if let Some(child) = self.children.get(scroll_to) { + let child_start: f32 = self.children[..scroll_to] + .iter() + .map(|c| c.size().along(self.axis)) + .sum(); + let child_end = child_start + child.size().along(self.axis); + if child_start < visible_start { + scroll_state.scroll_position = child_start; + } else if child_end > visible_end { + scroll_state.scroll_position = child_end - size.along(self.axis); + } + } + } + scroll_state.scroll_position = scroll_state.scroll_position.min(-remaining_space).max(0.); }); diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 76093883c4d63f3d1d93ec6323b572ea0aef2f49..5d7f373b2f09421a1a2ce0779cf4c07fe115f080 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -100,6 +100,7 @@ pub enum Event { pub struct Pane { items: Vec>, active_item_index: usize, + autoscroll: bool, nav_history: Rc>, toolbar: ViewHandle, } @@ -141,6 +142,7 @@ impl Pane { Self { items: Vec::new(), active_item_index: 0, + autoscroll: false, nav_history: Default::default(), toolbar: cx.add_view(|_| Toolbar::new()), } @@ -388,6 +390,7 @@ impl Pane { self.focus_active_item(cx); self.activate(cx); } + self.autoscroll = true; cx.notify(); } } @@ -627,13 +630,18 @@ impl Pane { }); } - fn render_tabs(&self, cx: &mut RenderContext) -> ElementBox { + fn render_tabs(&mut self, cx: &mut RenderContext) -> ElementBox { let theme = cx.global::().theme.clone(); enum Tabs {} let pane = cx.handle(); let tabs = MouseEventHandler::new::(0, cx, |mouse_state, cx| { - let mut row = Flex::row().scrollable::(1, cx); + let autoscroll = if mem::take(&mut self.autoscroll) { + Some(self.active_item_index) + } else { + None + }; + let mut row = Flex::row().scrollable::(1, autoscroll, cx); for (ix, item) in self.items.iter().enumerate() { let is_active = ix == self.active_item_index;