@@ -558,10 +558,10 @@ pub struct SettingsWindow {
/// Index into navbar_entries
navbar_entry: usize,
navbar_entries: Vec<NavBarEntry>,
- list_handle: UniformListScrollHandle,
+ navbar_scroll_handle: UniformListScrollHandle,
search_matches: Vec<Vec<bool>>,
content_handles: Vec<Vec<Entity<NonFocusableHandle>>>,
- scroll_handle: ScrollHandle,
+ page_scroll_handle: ScrollHandle,
focus_handle: FocusHandle,
navbar_focus_handle: Entity<NonFocusableHandle>,
content_focus_handle: Entity<NonFocusableHandle>,
@@ -923,12 +923,12 @@ impl SettingsWindow {
pages: vec![],
navbar_entries: vec![],
navbar_entry: 0,
- list_handle: UniformListScrollHandle::default(),
+ navbar_scroll_handle: UniformListScrollHandle::default(),
search_bar,
search_task: None,
search_matches: vec![],
content_handles: vec![],
- scroll_handle: ScrollHandle::new(),
+ page_scroll_handle: ScrollHandle::new(),
focus_handle: cx.focus_handle(),
navbar_focus_handle: NonFocusableHandle::new(
NAVBAR_CONTAINER_TAB_INDEX,
@@ -1471,7 +1471,7 @@ impl SettingsWindow {
let Some(previous_root_index) = root_index else {
return;
};
- this.focus_and_scroll_to_nav_entry(previous_root_index, window);
+ this.focus_and_scroll_to_nav_entry(previous_root_index, window, cx);
}),
)
.on_action(cx.listener(|this, _: &FocusNextRootNavEntry, window, cx| {
@@ -1491,16 +1491,16 @@ impl SettingsWindow {
let Some(next_root_index) = root_index else {
return;
};
- this.focus_and_scroll_to_nav_entry(next_root_index, window);
+ this.focus_and_scroll_to_nav_entry(next_root_index, window, cx);
}))
- .on_action(cx.listener(|this, _: &FocusFirstNavEntry, window, _| {
+ .on_action(cx.listener(|this, _: &FocusFirstNavEntry, window, cx| {
if let Some((first_entry_index, _)) = this.visible_navbar_entries().next() {
- this.focus_and_scroll_to_nav_entry(first_entry_index, window);
+ this.focus_and_scroll_to_nav_entry(first_entry_index, window, cx);
}
}))
- .on_action(cx.listener(|this, _: &FocusLastNavEntry, window, _| {
+ .on_action(cx.listener(|this, _: &FocusLastNavEntry, window, cx| {
if let Some((last_entry_index, _)) = this.visible_navbar_entries().last() {
- this.focus_and_scroll_to_nav_entry(last_entry_index, window);
+ this.focus_and_scroll_to_nav_entry(last_entry_index, window, cx);
}
}))
.border_color(cx.theme().colors().border)
@@ -1551,9 +1551,9 @@ impl SettingsWindow {
}),
)
.size_full()
- .track_scroll(self.list_handle.clone()),
+ .track_scroll(self.navbar_scroll_handle.clone()),
)
- .vertical_scrollbar_for(self.list_handle.clone(), window, cx),
+ .vertical_scrollbar_for(self.navbar_scroll_handle.clone(), window, cx),
)
.child(
h_flex()
@@ -1592,7 +1592,7 @@ impl SettingsWindow {
return;
};
self.focus_content_element(first_item_index, window, cx);
- self.scroll_handle.set_offset(point(px(0.), px(0.)));
+ self.page_scroll_handle.set_offset(point(px(0.), px(0.)));
} else {
let entry_item_index = self.navbar_entries[navbar_entry_index]
.item_index
@@ -1603,10 +1603,23 @@ impl SettingsWindow {
else {
return;
};
- self.scroll_handle
+ self.page_scroll_handle
.scroll_to_top_of_item(selected_item_index);
self.focus_content_element(entry_item_index, window, cx);
}
+
+ // Page scroll handle updates the active item index
+ // in it's next paint call after using scroll_handle.scroll_to_top_of_item
+ // The call after that updates the offset of the scroll handle. So to
+ // ensure the scroll handle doesn't lag behind we need to render three frames
+ // back to back.
+ cx.on_next_frame(window, |_, window, cx| {
+ cx.on_next_frame(window, |_, _, cx| {
+ cx.notify();
+ });
+ cx.notify();
+ });
+ cx.notify();
}
fn is_nav_entry_visible(&self, nav_entry_index: usize) -> bool {
@@ -1614,16 +1627,22 @@ impl SettingsWindow {
.any(|(index, _)| index == nav_entry_index)
}
- fn focus_and_scroll_to_nav_entry(&self, nav_entry_index: usize, window: &mut Window) {
+ fn focus_and_scroll_to_nav_entry(
+ &self,
+ nav_entry_index: usize,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
let Some(position) = self
.visible_navbar_entries()
.position(|(index, _)| index == nav_entry_index)
else {
return;
};
- self.list_handle
+ self.navbar_scroll_handle
.scroll_to_item(position, gpui::ScrollStrategy::Top);
window.focus(&self.navbar_entries[nav_entry_index].focus_handle);
+ cx.notify();
}
fn visible_page_items(&self) -> impl Iterator<Item = (usize, &SettingsPageItem)> {
@@ -1670,7 +1689,7 @@ impl SettingsWindow {
.id("settings-ui-page")
.size_full()
.overflow_y_scroll()
- .track_scroll(&self.scroll_handle);
+ .track_scroll(&self.page_scroll_handle);
let items: Vec<_> = items.collect();
let items_len = items.len();
@@ -1785,7 +1804,7 @@ impl SettingsWindow {
.px_8()
.bg(cx.theme().colors().editor_background)
.child(page_header)
- .vertical_scrollbar_for(self.scroll_handle.clone(), window, cx)
+ .vertical_scrollbar_for(self.page_scroll_handle.clone(), window, cx)
.track_focus(&self.content_focus_handle.focus_handle(cx))
.child(
div()
@@ -2026,7 +2045,7 @@ impl Render for SettingsWindow {
{
this.open_and_scroll_to_navbar_entry(this.navbar_entry, window, cx);
} else {
- this.focus_and_scroll_to_nav_entry(this.navbar_entry, window);
+ this.focus_and_scroll_to_nav_entry(this.navbar_entry, window, cx);
}
}))
.on_action(
@@ -2474,11 +2493,11 @@ mod test {
search_bar: cx.new(|cx| Editor::single_line(window, cx)),
navbar_entry: selected_idx.expect("Must have a selected navbar entry"),
navbar_entries: Vec::default(),
- list_handle: UniformListScrollHandle::default(),
+ navbar_scroll_handle: UniformListScrollHandle::default(),
search_matches: vec![],
content_handles: vec![],
search_task: None,
- scroll_handle: ScrollHandle::new(),
+ page_scroll_handle: ScrollHandle::new(),
focus_handle: cx.focus_handle(),
navbar_focus_handle: NonFocusableHandle::new(
NAVBAR_CONTAINER_TAB_INDEX,