diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 131c02e9c885b66ddf32ed6d2a0dfb01d2764a49..e0870503b7c64bb23218d897bc6b4828d315c8b8 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -776,17 +776,9 @@ impl Dock { } } - pub fn panel_size(&self, panel: &dyn PanelHandle, window: &Window, cx: &App) -> Option { - self.panel_entries - .iter() - .find(|entry| entry.panel.panel_id() == panel.panel_id()) - .map(|entry| self.resolved_panel_size(entry, window, cx)) - } - - pub fn active_panel_size(&self, window: &Window, cx: &App) -> Option { + pub fn active_panel_size(&self) -> Option { if self.is_open { - self.active_panel_entry() - .map(|entry| self.resolved_panel_size(entry, window, cx)) + self.active_panel_entry().map(|entry| entry.size_state) } else { None } @@ -947,28 +939,6 @@ impl Dock { } } - fn resolved_panel_size(&self, entry: &PanelEntry, window: &Window, cx: &App) -> Pixels { - if self.position.axis() == Axis::Horizontal - && entry.panel.supports_flexible_size(window, cx) - { - if let Some(workspace) = self.workspace.upgrade() { - let workspace = workspace.read(cx); - return resolve_panel_size( - entry.size_state, - entry.panel.as_ref(), - self.position, - workspace, - window, - cx, - ); - } - } - entry - .size_state - .size - .unwrap_or_else(|| entry.panel.default_size(window, cx)) - } - pub(crate) fn load_persisted_size_state( workspace: &Workspace, panel_key: &'static str, @@ -988,41 +958,10 @@ impl Dock { } } -pub(crate) fn resolve_panel_size( - size_state: PanelSizeState, - panel: &dyn PanelHandle, - position: DockPosition, - workspace: &Workspace, - window: &Window, - cx: &App, -) -> Pixels { - if position.axis() == Axis::Horizontal && panel.supports_flexible_size(window, cx) { - let ratio = size_state - .flexible_size_ratio - .or_else(|| workspace.default_flexible_dock_ratio(position)); - - if let Some(ratio) = ratio { - return workspace - .flexible_dock_size(position, ratio, window, cx) - .unwrap_or_else(|| { - size_state - .size - .unwrap_or_else(|| panel.default_size(window, cx)) - }); - } - } - - size_state - .size - .unwrap_or_else(|| panel.default_size(window, cx)) -} - impl Render for Dock { - fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { + fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { let dispatch_context = Self::dispatch_context(); if let Some(entry) = self.visible_entry() { - let size = self.resolved_panel_size(entry, window, cx); - let position = self.position; let create_resize_handle = || { let handle = div() @@ -1091,8 +1030,10 @@ impl Render for Dock { .border_color(cx.theme().colors().border) .overflow_hidden() .map(|this| match self.position().axis() { - Axis::Horizontal => this.w(size).h_full().flex_row(), - Axis::Vertical => this.h(size).w_full().flex_col(), + // Width and height are always set on the workspace wrapper in + // render_dock, so fill whatever space the wrapper provides. + Axis::Horizontal => this.w_full().h_full().flex_row(), + Axis::Vertical => this.h_full().w_full().flex_col(), }) .map(|this| match self.position() { DockPosition::Left => this.border_r_1(), @@ -1102,8 +1043,8 @@ impl Render for Dock { .child( div() .map(|this| match self.position().axis() { - Axis::Horizontal => this.min_w(size).h_full(), - Axis::Vertical => this.min_h(size).w_full(), + Axis::Horizontal => this.w_full().h_full(), + Axis::Vertical => this.h_full().w_full(), }) .child( entry diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index fcb46039921f94e9a4a8b717f62ec9f709955f40..1d7c71c1ea4d66c65155a6491b7cf8a526256d82 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -2208,30 +2208,29 @@ impl Workspace { did_set } - pub fn flexible_dock_size( - &self, - position: DockPosition, - ratio: f32, - window: &Window, - cx: &App, - ) -> Option { - if position.axis() != Axis::Horizontal { - return None; + fn dock_size(&self, dock: &Dock, window: &Window, cx: &App) -> Option { + let panel = dock.active_panel()?; + let size_state = dock + .stored_panel_size_state(panel.as_ref()) + .unwrap_or_default(); + let position = dock.position(); + + if position.axis() == Axis::Horizontal + && panel.supports_flexible_size(window, cx) + && let Some(ratio) = size_state + .flexible_size_ratio + .or_else(|| self.default_flexible_dock_ratio(position)) + && let Some(available_width) = + self.available_width_for_horizontal_dock(position, window, cx) + { + return Some((available_width * ratio.clamp(0.0, 1.0)).max(RESIZE_HANDLE_SIZE)); } - let available_width = self.available_width_for_horizontal_dock(position, window, cx)?; - Some((available_width * ratio.clamp(0.0, 1.0)).max(RESIZE_HANDLE_SIZE)) - } - - pub fn resolved_dock_panel_size( - &self, - dock: &Dock, - panel: &dyn PanelHandle, - window: &Window, - cx: &App, - ) -> Pixels { - let size_state = dock.stored_panel_size_state(panel).unwrap_or_default(); - dock::resolve_panel_size(size_state, panel, dock.position(), self, window, cx) + Some( + size_state + .size + .unwrap_or_else(|| panel.default_size(window, cx)), + ) } pub fn flexible_dock_ratio_for_size( @@ -4908,10 +4907,7 @@ impl Workspace { if let Some(dock_entity) = active_dock { let dock = dock_entity.read(cx); - let Some(panel_size) = dock - .active_panel() - .map(|panel| self.resolved_dock_panel_size(&dock, panel.as_ref(), window, cx)) - else { + let Some(panel_size) = self.dock_size(&dock, window, cx) else { return; }; match dock.position() { @@ -7274,14 +7270,46 @@ impl Workspace { leader_border_for_pane(follower_states, &pane, window, cx) }); - Some( - div() - .flex() - .flex_none() - .overflow_hidden() - .child(dock.clone()) - .children(leader_border), - ) + let mut container = div() + .flex() + .overflow_hidden() + .flex_none() + .child(dock.clone()) + .children(leader_border); + + // Apply sizing only when the dock is open. When closed the dock is still + // included in the element tree so its focus handle remains mounted — without + // this, toggle_panel_focus cannot focus the panel when the dock is closed. + let dock = dock.read(cx); + if let Some(panel) = dock.visible_panel() { + let size_state = dock.stored_panel_size_state(panel.as_ref()); + if position.axis() == Axis::Horizontal { + if let Some(ratio) = size_state + .and_then(|state| state.flexible_size_ratio) + .or_else(|| self.default_flexible_dock_ratio(position)) + && panel.supports_flexible_size(window, cx) + { + let ratio = ratio.clamp(0.001, 0.999); + let grow = ratio / (1.0 - ratio); + let style = container.style(); + style.flex_grow = Some(grow); + style.flex_shrink = Some(1.0); + style.flex_basis = Some(relative(0.).into()); + } else { + let size = size_state + .and_then(|state| state.size) + .unwrap_or_else(|| panel.default_size(window, cx)); + container = container.w(size); + } + } else { + let size = size_state + .and_then(|state| state.size) + .unwrap_or_else(|| panel.default_size(window, cx)); + container = container.h(size); + } + } + + Some(container) } pub fn for_window(window: &Window, cx: &App) -> Option> { @@ -7351,18 +7379,17 @@ impl Workspace { } } - fn adjust_dock_size_by_px( + fn resize_dock( &mut self, - panel_size: Pixels, dock_pos: DockPosition, - px: Pixels, + new_size: Pixels, window: &mut Window, cx: &mut Context, ) { match dock_pos { - DockPosition::Left => self.resize_left_dock(panel_size + px, window, cx), - DockPosition::Right => self.resize_right_dock(panel_size + px, window, cx), - DockPosition::Bottom => self.resize_bottom_dock(panel_size + px, window, cx), + DockPosition::Left => self.resize_left_dock(new_size, window, cx), + DockPosition::Right => self.resize_right_dock(new_size, window, cx), + DockPosition::Bottom => self.resize_bottom_dock(new_size, window, cx), } } @@ -7806,14 +7833,10 @@ fn adjust_active_dock_size_by_px( return; }; let dock = active_dock.read(cx); - let Some(panel_size) = dock - .active_panel() - .map(|panel| workspace.resolved_dock_panel_size(&dock, panel.as_ref(), window, cx)) - else { + let Some(panel_size) = workspace.dock_size(&dock, window, cx) else { return; }; - let dock_pos = dock.position(); - workspace.adjust_dock_size_by_px(panel_size, dock_pos, px, window, cx); + workspace.resize_dock(dock.position(), panel_size + px, window, cx); } fn adjust_open_docks_size_by_px( @@ -7828,22 +7851,18 @@ fn adjust_open_docks_size_by_px( .filter_map(|dock_entity| { let dock = dock_entity.read(cx); if dock.is_open() { - let panel_size = dock.active_panel().map(|panel| { - workspace.resolved_dock_panel_size(&dock, panel.as_ref(), window, cx) - })?; let dock_pos = dock.position(); - Some((panel_size, dock_pos, px)) + let panel_size = workspace.dock_size(&dock, window, cx)?; + Some((dock_pos, panel_size + px)) } else { None } }) .collect::>(); - docks - .into_iter() - .for_each(|(panel_size, dock_pos, offset)| { - workspace.adjust_dock_size_by_px(panel_size, dock_pos, offset, window, cx); - }); + for (position, new_size) in docks { + workspace.resize_dock(position, new_size, window, cx); + } } impl Focusable for Workspace { @@ -12286,11 +12305,8 @@ mod tests { let dock = workspace.right_dock().read(cx); let workspace_width = workspace.bounds.size.width; - let initial_width = dock - .active_panel() - .map(|panel| { - workspace.resolved_dock_panel_size(&dock, panel.as_ref(), window, cx) - }) + let initial_width = workspace + .dock_size(&dock, window, cx) .expect("flexible dock should have an initial width"); assert_eq!(initial_width, workspace_width / 2.); @@ -12298,11 +12314,8 @@ mod tests { workspace.resize_right_dock(px(300.), window, cx); let dock = workspace.right_dock().read(cx); - let resized_width = dock - .active_panel() - .map(|panel| { - workspace.resolved_dock_panel_size(&dock, panel.as_ref(), window, cx) - }) + let resized_width = workspace + .dock_size(&dock, window, cx) .expect("flexible dock should keep its resized width"); assert_eq!(resized_width, px(300.)); @@ -12322,9 +12335,8 @@ mod tests { workspace.toggle_dock(DockPosition::Right, window, cx); let dock = workspace.right_dock().read(cx); - let reopened_width = dock - .active_panel() - .map(|panel| workspace.resolved_dock_panel_size(&dock, panel.as_ref(), window, cx)) + let reopened_width = workspace + .dock_size(&dock, window, cx) .expect("flexible dock should restore when reopened"); assert_eq!(reopened_width, resized_width); @@ -12351,9 +12363,8 @@ mod tests { ); let dock = workspace.right_dock().read(cx); - let split_width = dock - .active_panel() - .map(|panel| workspace.resolved_dock_panel_size(&dock, panel.as_ref(), window, cx)) + let split_width = workspace + .dock_size(&dock, window, cx) .expect("flexible dock should keep its user-resized proportion"); assert_eq!(split_width, px(300.)); @@ -12361,9 +12372,8 @@ mod tests { workspace.bounds.size.width = px(1600.); let dock = workspace.right_dock().read(cx); - let resized_window_width = dock - .active_panel() - .map(|panel| workspace.resolved_dock_panel_size(&dock, panel.as_ref(), window, cx)) + let resized_window_width = workspace + .dock_size(&dock, window, cx) .expect("flexible dock should preserve proportional size on window resize"); assert_eq!( @@ -12533,9 +12543,8 @@ mod tests { workspace.toggle_dock(DockPosition::Left, window, cx); let left_dock = workspace.left_dock().read(cx); - let left_width = left_dock - .active_panel() - .map(|p| workspace.resolved_dock_panel_size(&left_dock, p.as_ref(), window, cx)) + let left_width = workspace + .dock_size(&left_dock, window, cx) .expect("left dock should have an active panel"); assert_eq!( @@ -12557,9 +12566,8 @@ mod tests { ); let left_dock = workspace.left_dock().read(cx); - let left_width = left_dock - .active_panel() - .map(|p| workspace.resolved_dock_panel_size(&left_dock, p.as_ref(), window, cx)) + let left_width = workspace + .dock_size(&left_dock, window, cx) .expect("left dock should still have an active panel after vertical split"); assert_eq!( @@ -12578,15 +12586,13 @@ mod tests { workspace.toggle_dock(DockPosition::Right, window, cx); let right_dock = workspace.right_dock().read(cx); - let right_width = right_dock - .active_panel() - .map(|p| workspace.resolved_dock_panel_size(&right_dock, p.as_ref(), window, cx)) + let right_width = workspace + .dock_size(&right_dock, window, cx) .expect("right dock should have an active panel"); let left_dock = workspace.left_dock().read(cx); - let left_width = left_dock - .active_panel() - .map(|p| workspace.resolved_dock_panel_size(&left_dock, p.as_ref(), window, cx)) + let left_width = workspace + .dock_size(&left_dock, window, cx) .expect("left dock should still have an active panel"); let available_width = workspace.bounds.size.width - right_width; @@ -12650,8 +12656,8 @@ mod tests { panel_1.panel_id() ); assert_eq!( - left_dock.read(cx).active_panel_size(window, cx).unwrap(), - px(300.) + workspace.dock_size(&left_dock.read(cx), window, cx), + Some(px(300.)) ); workspace.resize_left_dock(px(1337.), window, cx); @@ -12684,7 +12690,12 @@ mod tests { panel_1.panel_id() ); assert_eq!( - right_dock.read(cx).active_panel_size(window, cx).unwrap(), + right_dock + .read(cx) + .active_panel_size() + .unwrap() + .size + .unwrap(), px(1337.) ); @@ -12722,8 +12733,8 @@ mod tests { panel_1.panel_id() ); assert_eq!( - left_dock.read(cx).active_panel_size(window, cx).unwrap(), - px(1337.) + workspace.dock_size(&left_dock.read(cx), window, cx), + Some(px(1337.)) ); // And the right dock should be closed as it no longer has any panels. assert!(!workspace.right_dock().read(cx).is_open()); @@ -12739,8 +12750,8 @@ mod tests { // since the panel orientation changed from vertical to horizontal. let bottom_dock = workspace.bottom_dock(); assert_eq!( - bottom_dock.read(cx).active_panel_size(window, cx).unwrap(), - px(300.), + workspace.dock_size(&bottom_dock.read(cx), window, cx), + Some(px(300.)) ); // Close bottom dock and move panel_1 back to the left. bottom_dock.update(cx, |bottom_dock, cx| {