Pane tabs: Scroll entire new tab into view (#36827)
The state of the child bounds is not up-to-date when `scroll_to_item` gets triggered, causing the new tab to not scroll completely into view. Closes #36317 Release Notes: - Fix an issue where a new tab is only partially visible on creation.
This commit is contained in:
@@ -1384,6 +1384,10 @@ impl Element for Div {
|
||||
(child_max - child_min).into()
|
||||
};
|
||||
|
||||
if let Some(scroll_handle) = self.interactivity.tracked_scroll_handle.as_ref() {
|
||||
scroll_handle.scroll_to_active_item();
|
||||
}
|
||||
|
||||
self.interactivity.prepaint(
|
||||
global_id,
|
||||
inspector_id,
|
||||
@@ -2986,8 +2990,7 @@ where
|
||||
}
|
||||
|
||||
/// Represents an element that can be scrolled *to* in its parent element.
|
||||
///
|
||||
/// Contrary to [ScrollHandle::scroll_to_item], an anchored element does not have to be an immediate child of the parent.
|
||||
/// Contrary to [ScrollHandle::scroll_to_active_item], an anchored element does not have to be an immediate child of the parent.
|
||||
#[derive(Clone)]
|
||||
pub struct ScrollAnchor {
|
||||
handle: ScrollHandle,
|
||||
@@ -3022,6 +3025,7 @@ struct ScrollHandleState {
|
||||
child_bounds: Vec<Bounds<Pixels>>,
|
||||
scroll_to_bottom: bool,
|
||||
overflow: Point<Overflow>,
|
||||
active_item: Option<usize>,
|
||||
}
|
||||
|
||||
/// A handle to the scrollable aspects of an element.
|
||||
@@ -3081,32 +3085,44 @@ impl ScrollHandle {
|
||||
self.0.borrow().child_bounds.get(ix).cloned()
|
||||
}
|
||||
|
||||
/// scroll_to_item scrolls the minimal amount to ensure that the child is
|
||||
/// fully visible
|
||||
/// Update [ScrollHandleState]'s active item for scrolling to in prepaint
|
||||
pub fn scroll_to_item(&self, ix: usize) {
|
||||
let state = self.0.borrow();
|
||||
let mut state = self.0.borrow_mut();
|
||||
state.active_item = Some(ix);
|
||||
}
|
||||
|
||||
let Some(bounds) = state.child_bounds.get(ix) else {
|
||||
/// Scrolls the minimal amount to ensure that the child is
|
||||
/// fully visible
|
||||
fn scroll_to_active_item(&self) {
|
||||
let mut state = self.0.borrow_mut();
|
||||
|
||||
let Some(active_item_index) = state.active_item else {
|
||||
return;
|
||||
};
|
||||
let active_item = match state.child_bounds.get(active_item_index) {
|
||||
Some(bounds) => {
|
||||
let mut scroll_offset = state.offset.borrow_mut();
|
||||
|
||||
let mut scroll_offset = state.offset.borrow_mut();
|
||||
if state.overflow.y == Overflow::Scroll {
|
||||
if bounds.top() + scroll_offset.y < state.bounds.top() {
|
||||
scroll_offset.y = state.bounds.top() - bounds.top();
|
||||
} else if bounds.bottom() + scroll_offset.y > state.bounds.bottom() {
|
||||
scroll_offset.y = state.bounds.bottom() - bounds.bottom();
|
||||
}
|
||||
}
|
||||
|
||||
if state.overflow.y == Overflow::Scroll {
|
||||
if bounds.top() + scroll_offset.y < state.bounds.top() {
|
||||
scroll_offset.y = state.bounds.top() - bounds.top();
|
||||
} else if bounds.bottom() + scroll_offset.y > state.bounds.bottom() {
|
||||
scroll_offset.y = state.bounds.bottom() - bounds.bottom();
|
||||
if state.overflow.x == Overflow::Scroll {
|
||||
if bounds.left() + scroll_offset.x < state.bounds.left() {
|
||||
scroll_offset.x = state.bounds.left() - bounds.left();
|
||||
} else if bounds.right() + scroll_offset.x > state.bounds.right() {
|
||||
scroll_offset.x = state.bounds.right() - bounds.right();
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
if state.overflow.x == Overflow::Scroll {
|
||||
if bounds.left() + scroll_offset.x < state.bounds.left() {
|
||||
scroll_offset.x = state.bounds.left() - bounds.left();
|
||||
} else if bounds.right() + scroll_offset.x > state.bounds.right() {
|
||||
scroll_offset.x = state.bounds.right() - bounds.right();
|
||||
}
|
||||
}
|
||||
None => Some(active_item_index),
|
||||
};
|
||||
state.active_item = active_item;
|
||||
}
|
||||
|
||||
/// Scrolls to the bottom.
|
||||
|
||||
Reference in New Issue
Block a user