mirror of
https://github.com/herdrdev/herdr.git
synced 2026-09-22 00:01:06 +00:00
fix: reveal newly focused spaces in the sidebar
This commit is contained in:
@@ -57,6 +57,7 @@ impl ClientShellState {
|
||||
workspace_scroll: &mut self.workspace_scroll,
|
||||
agent_scroll: &mut self.agent_scroll,
|
||||
tab_scroll: &mut self.tab_scroll,
|
||||
reveal_focused_workspace: &mut self.reveal_focused_workspace,
|
||||
reveal_focused_tab: &mut self.reveal_focused_tab,
|
||||
sidebar_collapsed: self.sidebar_collapsed,
|
||||
sidebar_section_split: self.sidebar_section_split,
|
||||
|
||||
@@ -200,6 +200,7 @@ pub(super) struct ShellRenderState<'a> {
|
||||
pub(super) workspace_scroll: &'a mut usize,
|
||||
pub(super) agent_scroll: &'a mut usize,
|
||||
pub(super) tab_scroll: &'a mut usize,
|
||||
pub(super) reveal_focused_workspace: &'a mut bool,
|
||||
pub(super) reveal_focused_tab: &'a mut bool,
|
||||
pub(super) sidebar_collapsed: bool,
|
||||
pub(super) sidebar_section_split: f32,
|
||||
|
||||
@@ -53,6 +53,29 @@ pub(super) fn list_scroll_metrics(
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn list_scroll_start_to_reveal(
|
||||
row_heights: &[u16],
|
||||
gaps_after: &[u16],
|
||||
body_height: u16,
|
||||
requested_start: usize,
|
||||
target: usize,
|
||||
) -> usize {
|
||||
let mut metrics = list_scroll_metrics(row_heights, gaps_after, body_height, requested_start);
|
||||
let mut start = metrics
|
||||
.max_offset_from_bottom
|
||||
.saturating_sub(metrics.offset_from_bottom);
|
||||
if target < start {
|
||||
return target;
|
||||
}
|
||||
while target >= start.saturating_add(metrics.viewport_rows)
|
||||
&& start < metrics.max_offset_from_bottom
|
||||
{
|
||||
start = start.saturating_add(1);
|
||||
metrics = list_scroll_metrics(row_heights, gaps_after, body_height, start);
|
||||
}
|
||||
start
|
||||
}
|
||||
|
||||
pub(super) fn render_list_scrollbar(
|
||||
buffer: &mut Buffer,
|
||||
track: Rect,
|
||||
|
||||
@@ -246,12 +246,32 @@ pub(crate) fn render_sidebar(
|
||||
.map_or(0, |next| u16::from(!next.indented) * config.spaces.row_gap)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let metrics = super::scroll::list_scroll_metrics(
|
||||
let mut metrics = super::scroll::list_scroll_metrics(
|
||||
&row_heights,
|
||||
&gaps,
|
||||
body.height,
|
||||
*state.workspace_scroll,
|
||||
);
|
||||
if !body.is_empty() && std::mem::take(state.reveal_focused_workspace) {
|
||||
if let Some(target) = entries
|
||||
.iter()
|
||||
.position(|entry| snapshot.workspaces[entry.index].focused)
|
||||
{
|
||||
*state.workspace_scroll = super::scroll::list_scroll_start_to_reveal(
|
||||
&row_heights,
|
||||
&gaps,
|
||||
body.height,
|
||||
*state.workspace_scroll,
|
||||
target,
|
||||
);
|
||||
metrics = super::scroll::list_scroll_metrics(
|
||||
&row_heights,
|
||||
&gaps,
|
||||
body.height,
|
||||
*state.workspace_scroll,
|
||||
);
|
||||
}
|
||||
}
|
||||
hits.workspace_max_scroll = metrics.max_offset_from_bottom;
|
||||
hits.workspace_scroll_metrics = Some(metrics);
|
||||
*state.workspace_scroll = metrics
|
||||
|
||||
@@ -880,6 +880,7 @@ pub(crate) struct ClientShellState {
|
||||
pub(super) agent_scroll: usize,
|
||||
pub(super) tab_scroll: usize,
|
||||
pub(super) mobile_switcher_scroll: usize,
|
||||
pub(super) reveal_focused_workspace: bool,
|
||||
pub(super) reveal_mobile_workspace: bool,
|
||||
pub(super) mobile_switcher_suspended: bool,
|
||||
pub(super) reveal_focused_tab: bool,
|
||||
@@ -1021,6 +1022,7 @@ impl ClientShellState {
|
||||
agent_scroll: 0,
|
||||
tab_scroll: 0,
|
||||
mobile_switcher_scroll: 0,
|
||||
reveal_focused_workspace: true,
|
||||
reveal_mobile_workspace: false,
|
||||
mobile_switcher_suspended: false,
|
||||
reveal_focused_tab: true,
|
||||
@@ -1242,6 +1244,7 @@ impl ClientShellState {
|
||||
self.agent_scroll = 0;
|
||||
self.tab_scroll = 0;
|
||||
self.mobile_switcher_scroll = 0;
|
||||
self.reveal_focused_workspace = true;
|
||||
self.reveal_mobile_workspace = false;
|
||||
self.mobile_switcher_suspended = false;
|
||||
self.reveal_focused_tab = true;
|
||||
@@ -1317,6 +1320,14 @@ impl ClientShellState {
|
||||
})
|
||||
|| render::tab_bar_status_width(current) != render::tab_bar_status_width(&snapshot)
|
||||
});
|
||||
if self
|
||||
.snapshot
|
||||
.as_deref()
|
||||
.and_then(|current| current.focused_workspace_id.as_deref())
|
||||
!= snapshot.focused_workspace_id.as_deref()
|
||||
{
|
||||
self.reveal_focused_workspace = true;
|
||||
}
|
||||
if tab_layout_changed
|
||||
|| self
|
||||
.snapshot
|
||||
|
||||
@@ -46,6 +46,53 @@ fn tab_overflow_controls_scroll_the_client_owned_tab_bar() {
|
||||
assert!(state.hits.tabs.iter().any(|(_, tab_id)| tab_id == "tab_8"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn focused_workspace_change_reveals_new_workspace_in_full_sidebar() {
|
||||
let mut initial = snapshot();
|
||||
let template = initial.workspaces[0].clone();
|
||||
initial.workspaces = (1..=12)
|
||||
.map(|number| ClientShellWorkspace {
|
||||
workspace_id: format!("ws_{number}"),
|
||||
number,
|
||||
label: format!("space-{number}"),
|
||||
branch: None,
|
||||
focused: number == 1,
|
||||
..template.clone()
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut state = ClientShellState::new(ClientShellConfig::from_config(&Config::default()));
|
||||
state.set_snapshot(Box::new(initial));
|
||||
state.set_pane_surface(surface());
|
||||
state.compose(106, 20).expect("full sidebar");
|
||||
assert!(state.hits.workspace_max_scroll > 0);
|
||||
assert!(state
|
||||
.hits
|
||||
.workspaces
|
||||
.iter()
|
||||
.all(|hit| hit.workspace_id != "ws_12"));
|
||||
|
||||
let mut update = state.snapshot.as_deref().expect("snapshot").clone();
|
||||
update.revision = 2;
|
||||
update.focused_workspace_id = Some("ws_12".into());
|
||||
for workspace in &mut update.workspaces {
|
||||
workspace.focused = workspace.workspace_id == "ws_12";
|
||||
}
|
||||
let mut updated_surface = surface();
|
||||
updated_surface.projection_revision = 2;
|
||||
state.set_snapshot(Box::new(update));
|
||||
state.set_pane_surface(updated_surface);
|
||||
state.compose(106, 2).expect("zero-height workspace body");
|
||||
assert!(state.reveal_focused_workspace);
|
||||
state.compose(106, 20).expect("updated full sidebar");
|
||||
|
||||
assert!(state
|
||||
.hits
|
||||
.workspaces
|
||||
.iter()
|
||||
.any(|hit| hit.workspace_id == "ws_12"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn client_owned_sidebar_dividers_resize_live() {
|
||||
let mut state = ClientShellState::new(ClientShellConfig::from_config(&Config::default()));
|
||||
|
||||
Reference in New Issue
Block a user