Detailed changes
@@ -943,6 +943,10 @@
"button": true,
// Where to dock the agent panel. Can be 'left', 'right' or 'bottom'.
"dock": "right",
+ // Whether the agent panel should use flexible (proportional) sizing.
+ //
+ // Default: true
+ "flexible": true,
// Where to position the sidebar. Can be 'left', 'right', or 'follow_agent'.
"sidebar_side": "follow_agent",
// Default width when the agent panel is docked to the left or right.
@@ -1651,6 +1655,10 @@
"shell": "system",
// Where to dock terminals panel. Can be `left`, `right`, `bottom`.
"dock": "bottom",
+ // Whether the terminal panel should use flexible (proportional) sizing.
+ //
+ // Default: true
+ "flexible": true,
// Default width when the terminal is docked to the left or right.
"default_width": 640,
// Default height when the terminal is docked to the bottom.
@@ -571,6 +571,7 @@ mod tests {
enabled: true,
button: true,
dock: DockPosition::Right,
+ flexible: true,
default_width: px(300.),
default_height: px(600.),
default_model: None,
@@ -27,6 +27,7 @@ pub struct AgentSettings {
pub enabled: bool,
pub button: bool,
pub dock: DockPosition,
+ pub flexible: bool,
pub sidebar_side: SidebarDockPosition,
pub default_width: Pixels,
pub default_height: Pixels,
@@ -424,6 +425,7 @@ impl Settings for AgentSettings {
sidebar_side: agent.sidebar_side.unwrap(),
default_width: px(agent.default_width.unwrap()),
default_height: px(agent.default_height.unwrap()),
+ flexible: agent.flexible.unwrap(),
default_model: Some(agent.default_model.unwrap()),
inline_assistant_model: agent.inline_assistant_model,
inline_assistant_use_streaming_tools: agent
@@ -3157,10 +3157,23 @@ impl Panel for AgentPanel {
}
}
- fn supports_flexible_size(&self, _window: &Window, _cx: &App) -> bool {
+ fn supports_flexible_size(&self) -> bool {
true
}
+ fn has_flexible_size(&self, _window: &Window, cx: &App) -> bool {
+ AgentSettings::get_global(cx).flexible
+ }
+
+ fn set_flexible_size(&mut self, flexible: bool, _window: &mut Window, cx: &mut Context<Self>) {
+ settings::update_settings_file(self.fs.clone(), cx, move |settings, _| {
+ settings
+ .agent
+ .get_or_insert_default()
+ .set_flexible_size(flexible);
+ });
+ }
+
fn set_active(&mut self, active: bool, window: &mut Window, cx: &mut Context<Self>) {
if active
&& matches!(self.active_view, ActiveView::Uninitialized)
@@ -647,6 +647,7 @@ mod tests {
enabled: true,
button: true,
dock: DockPosition::Right,
+ flexible: true,
default_width: px(300.),
default_height: px(600.),
default_model: None,
@@ -881,6 +881,7 @@ impl VsCodeSettings {
scroll_multiplier: None,
toolbar: None,
show_count_badge: None,
+ flexible: None,
})
}
@@ -109,6 +109,10 @@ pub struct AgentSettingsContent {
///
/// Default: right
pub dock: Option<DockPosition>,
+ /// Whether the agent panel should use flexible (proportional) sizing.
+ ///
+ /// Default: true
+ pub flexible: Option<bool>,
/// Where to position the sidebar.
///
/// Default: follow_agent
@@ -230,6 +234,10 @@ impl AgentSettingsContent {
self.sidebar_side = Some(position);
}
+ pub fn set_flexible_size(&mut self, flexible: bool) {
+ self.flexible = Some(flexible);
+ }
+
pub fn set_model(&mut self, language_model: LanguageModelSelection) {
self.default_model = Some(language_model)
}
@@ -129,6 +129,10 @@ pub struct TerminalSettingsContent {
/// Default: true
pub button: Option<bool>,
pub dock: Option<TerminalDockPosition>,
+ /// Whether the terminal panel should use flexible (proportional) sizing.
+ ///
+ /// Default: true
+ pub flexible: Option<bool>,
/// Default width when the terminal is docked to the left or right.
///
/// Default: 640
@@ -40,6 +40,7 @@ pub struct TerminalSettings {
pub keep_selection_on_copy: bool,
pub button: bool,
pub dock: TerminalDockPosition,
+ pub flexible: bool,
pub default_width: Pixels,
pub default_height: Pixels,
pub detect_venv: VenvSettings,
@@ -110,6 +111,7 @@ impl settings::Settings for TerminalSettings {
dock: user_content.dock.unwrap(),
default_width: px(user_content.default_width.unwrap()),
default_height: px(user_content.default_height.unwrap()),
+ flexible: user_content.flexible.unwrap(),
detect_venv: project_content.detect_venv.unwrap(),
scroll_multiplier: user_content.scroll_multiplier.unwrap(),
max_scroll_history_lines: user_content.max_scroll_history_lines,
@@ -1574,6 +1574,20 @@ impl Panel for TerminalPanel {
}
}
+ fn supports_flexible_size(&self) -> bool {
+ true
+ }
+
+ fn has_flexible_size(&self, _window: &Window, cx: &App) -> bool {
+ TerminalSettings::get_global(cx).flexible
+ }
+
+ fn set_flexible_size(&mut self, flexible: bool, _window: &mut Window, cx: &mut Context<Self>) {
+ settings::update_settings_file(self.fs.clone(), cx, move |settings, _| {
+ settings.terminal.get_or_insert_default().flexible = Some(flexible);
+ });
+ }
+
fn is_zoomed(&self, _window: &Window, cx: &App) -> bool {
self.active_pane.read(cx).is_zoomed()
}
@@ -42,9 +42,19 @@ pub trait Panel: Focusable + EventEmitter<PanelEvent> + Render + Sized {
PanelSizeState::default()
}
fn size_state_changed(&mut self, _window: &mut Window, _cx: &mut Context<Self>) {}
- fn supports_flexible_size(&self, _window: &Window, _cx: &App) -> bool {
+ fn supports_flexible_size(&self) -> bool {
false
}
+ fn has_flexible_size(&self, _window: &Window, _cx: &App) -> bool {
+ false
+ }
+ fn set_flexible_size(
+ &mut self,
+ _flexible: bool,
+ _window: &mut Window,
+ _cx: &mut Context<Self>,
+ ) {
+ }
fn icon(&self, window: &Window, cx: &App) -> Option<ui::IconName>;
fn icon_tooltip(&self, window: &Window, cx: &App) -> Option<&'static str>;
fn toggle_action(&self) -> Box<dyn Action>;
@@ -89,7 +99,9 @@ pub trait PanelHandle: Send + Sync {
fn default_size(&self, window: &Window, cx: &App) -> Pixels;
fn initial_size_state(&self, window: &Window, cx: &App) -> PanelSizeState;
fn size_state_changed(&self, window: &mut Window, cx: &mut App);
- fn supports_flexible_size(&self, window: &Window, cx: &App) -> bool;
+ fn supports_flexible_size(&self, cx: &App) -> bool;
+ fn has_flexible_size(&self, window: &Window, cx: &App) -> bool;
+ fn set_flexible_size(&self, flexible: bool, window: &mut Window, cx: &mut App);
fn icon(&self, window: &Window, cx: &App) -> Option<ui::IconName>;
fn icon_tooltip(&self, window: &Window, cx: &App) -> Option<&'static str>;
fn toggle_action(&self, window: &Window, cx: &App) -> Box<dyn Action>;
@@ -176,8 +188,16 @@ where
self.update(cx, |this, cx| this.size_state_changed(window, cx))
}
- fn supports_flexible_size(&self, window: &Window, cx: &App) -> bool {
- self.read(cx).supports_flexible_size(window, cx)
+ fn supports_flexible_size(&self, cx: &App) -> bool {
+ self.read(cx).supports_flexible_size()
+ }
+
+ fn has_flexible_size(&self, window: &Window, cx: &App) -> bool {
+ self.read(cx).has_flexible_size(window, cx)
+ }
+
+ fn set_flexible_size(&self, flexible: bool, window: &mut Window, cx: &mut App) {
+ self.update(cx, |this, cx| this.set_flexible_size(flexible, window, cx))
}
fn icon(&self, window: &Window, cx: &App) -> Option<ui::IconName> {
@@ -292,7 +312,7 @@ impl DockPosition {
pub struct PanelSizeState {
pub size: Option<Pixels>,
#[serde(default)]
- pub flexible_size_ratio: Option<f32>,
+ pub flex: Option<f32>,
}
struct PanelEntry {
@@ -840,10 +860,48 @@ impl Dock {
}
}
+ pub fn toggle_panel_flexible_size(
+ &mut self,
+ panel: &dyn PanelHandle,
+ current_size: Option<Pixels>,
+ current_flex: Option<f32>,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ let Some(entry) = self
+ .panel_entries
+ .iter_mut()
+ .find(|entry| entry.panel.panel_id() == panel.panel_id())
+ else {
+ return;
+ };
+ let currently_flexible = entry.panel.has_flexible_size(window, cx);
+ if currently_flexible {
+ entry.size_state.size = current_size;
+ } else {
+ entry.size_state.flex = current_flex;
+ }
+ let panel_key = entry.panel.panel_key();
+ let size_state = entry.size_state;
+ let workspace = self.workspace.clone();
+ entry
+ .panel
+ .set_flexible_size(!currently_flexible, window, cx);
+ entry.panel.size_state_changed(window, cx);
+ cx.defer(move |cx| {
+ if let Some(workspace) = workspace.upgrade() {
+ workspace.update(cx, |workspace, cx| {
+ workspace.persist_panel_size_state(panel_key, size_state, cx);
+ });
+ }
+ });
+ cx.notify();
+ }
+
pub fn resize_active_panel(
&mut self,
size: Option<Pixels>,
- ratio: Option<f32>,
+ flex: Option<f32>,
window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -852,8 +910,9 @@ impl Dock {
{
let size = size.map(|size| size.max(RESIZE_HANDLE_SIZE).round());
- if entry.panel.supports_flexible_size(window, cx) {
- entry.size_state.flexible_size_ratio = ratio;
+ let use_flex = entry.panel.has_flexible_size(window, cx);
+ if use_flex {
+ entry.size_state.flex = flex;
} else {
entry.size_state.size = size;
}
@@ -876,7 +935,7 @@ impl Dock {
pub fn resize_all_panels(
&mut self,
size: Option<Pixels>,
- ratio: Option<f32>,
+ flex: Option<f32>,
window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -884,8 +943,9 @@ impl Dock {
for entry in &mut self.panel_entries {
let size = size.map(|size| size.max(RESIZE_HANDLE_SIZE).round());
- if entry.panel.supports_flexible_size(window, cx) {
- entry.size_state.flexible_size_ratio = ratio;
+ let use_flex = entry.panel.has_flexible_size(window, cx);
+ if use_flex {
+ entry.size_state.flex = flex;
} else {
entry.size_state.size = size;
}
@@ -925,7 +985,8 @@ impl Dock {
pub fn clamp_panel_size(&mut self, max_size: Pixels, window: &Window, cx: &mut App) {
let max_size = (max_size - RESIZE_HANDLE_SIZE).abs();
for entry in &mut self.panel_entries {
- if entry.panel.supports_flexible_size(window, cx) {
+ let use_flexible = entry.panel.has_flexible_size(window, cx);
+ if use_flexible {
continue;
}
@@ -1087,6 +1148,8 @@ impl Render for PanelButtons {
DockPosition::Bottom | DockPosition::Right => (Corner::BottomRight, Corner::TopRight),
};
+ let dock_entity = self.dock.clone();
+ let workspace = dock.workspace.clone();
let mut buttons: Vec<_> = dock
.panel_entries
.iter()
@@ -1102,6 +1165,10 @@ impl Render for PanelButtons {
.log_err()?;
let name = entry.panel.persistent_name();
let panel = entry.panel.clone();
+ let supports_flexible = panel.supports_flexible_size(cx);
+ let currently_flexible = panel.has_flexible_size(window, cx);
+ let dock_for_menu = dock_entity.clone();
+ let workspace_for_menu = workspace.clone();
let is_active_button = Some(i) == active_index && is_open;
let (action, tooltip) = if is_active_button {
@@ -1130,20 +1197,76 @@ impl Render for PanelButtons {
];
ContextMenu::build(window, cx, |mut menu, _, cx| {
+ let mut has_position_entries = false;
for position in POSITIONS {
- if position != dock_position
- && panel.position_is_valid(position, cx)
- {
+ if panel.position_is_valid(position, cx) {
+ let is_current = position == dock_position;
let panel = panel.clone();
- menu = menu.entry(
+ menu = menu.toggleable_entry(
format!("Dock {}", position.label()),
+ is_current,
+ IconPosition::Start,
None,
move |window, cx| {
- panel.set_position(position, window, cx);
+ if !is_current {
+ panel.set_position(position, window, cx);
+ }
},
- )
+ );
+ has_position_entries = true;
}
}
+ if supports_flexible {
+ if has_position_entries {
+ menu = menu.separator();
+ }
+ let panel_for_flex = panel.clone();
+ let dock_for_flex = dock_for_menu.clone();
+ let workspace_for_flex = workspace_for_menu.clone();
+ menu = menu.toggleable_entry(
+ "Flex Width",
+ currently_flexible,
+ IconPosition::Start,
+ None,
+ move |window, cx| {
+ if !currently_flexible {
+ if let Some(ws) = workspace_for_flex.upgrade() {
+ ws.update(cx, |workspace, cx| {
+ workspace.toggle_dock_panel_flexible_size(
+ &dock_for_flex,
+ panel_for_flex.as_ref(),
+ window,
+ cx,
+ );
+ });
+ }
+ }
+ },
+ );
+ let panel_for_fixed = panel.clone();
+ let dock_for_fixed = dock_for_menu.clone();
+ let workspace_for_fixed = workspace_for_menu.clone();
+ menu = menu.toggleable_entry(
+ "Fixed Width",
+ !currently_flexible,
+ IconPosition::Start,
+ None,
+ move |window, cx| {
+ if currently_flexible {
+ if let Some(ws) = workspace_for_fixed.upgrade() {
+ ws.update(cx, |workspace, cx| {
+ workspace.toggle_dock_panel_flexible_size(
+ &dock_for_fixed,
+ panel_for_fixed.as_ref(),
+ window,
+ cx,
+ );
+ });
+ }
+ }
+ },
+ );
+ }
menu
})
})
@@ -1290,14 +1413,27 @@ pub mod test {
fn initial_size_state(&self, _window: &Window, _: &App) -> PanelSizeState {
PanelSizeState {
size: None,
- flexible_size_ratio: None,
+ flex: None,
}
}
- fn supports_flexible_size(&self, _window: &Window, _: &App) -> bool {
+ fn supports_flexible_size(&self) -> bool {
self.flexible
}
+ fn has_flexible_size(&self, _window: &Window, _: &App) -> bool {
+ self.flexible
+ }
+
+ fn set_flexible_size(
+ &mut self,
+ flexible: bool,
+ _window: &mut Window,
+ _cx: &mut Context<Self>,
+ ) {
+ self.flexible = flexible;
+ }
+
fn icon(&self, _window: &Window, _: &App) -> Option<ui::IconName> {
None
}
@@ -150,7 +150,7 @@ pub use workspace_settings::{
};
use zed_actions::{Spawn, feedback::FileBugReport, theme::ToggleMode};
-use crate::{item::ItemBufferKind, notifications::NotificationId};
+use crate::{dock::PanelSizeState, item::ItemBufferKind, notifications::NotificationId};
use crate::{
persistence::{
SerializedAxis,
@@ -2201,6 +2201,22 @@ impl Workspace {
did_set
}
+ pub fn toggle_dock_panel_flexible_size(
+ &self,
+ dock: &Entity<Dock>,
+ panel: &dyn PanelHandle,
+ window: &mut Window,
+ cx: &mut App,
+ ) {
+ let position = dock.read(cx).position();
+ let current_size = self.dock_size(&dock.read(cx), window, cx);
+ let current_flex =
+ current_size.and_then(|size| self.dock_flex_for_size(position, size, window, cx));
+ dock.update(cx, |dock, cx| {
+ dock.toggle_panel_flexible_size(panel, current_size, current_flex, window, cx);
+ });
+ }
+
fn dock_size(&self, dock: &Dock, window: &Window, cx: &App) -> Option<Pixels> {
let panel = dock.active_panel()?;
let size_state = dock
@@ -2208,15 +2224,30 @@ impl Workspace {
.unwrap_or_default();
let position = dock.position();
+ let use_flex = panel.has_flexible_size(window, cx);
+
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)
+ && use_flex
+ && let Some(flex) = size_state.flex.or_else(|| self.default_dock_flex(position))
{
- return Some((available_width * ratio.clamp(0.0, 1.0)).max(RESIZE_HANDLE_SIZE));
+ let workspace_width = self.bounds.size.width;
+ if workspace_width <= Pixels::ZERO {
+ return None;
+ }
+ let flex = flex.max(0.001);
+ let opposite = self.opposite_dock_panel_and_size_state(position, window, cx);
+ if let Some(opposite_flex) = opposite.as_ref().and_then(|(_, s)| s.flex) {
+ // Both docks are flex items sharing the full workspace width.
+ let total_flex = flex + 1.0 + opposite_flex;
+ return Some((flex / total_flex * workspace_width).max(RESIZE_HANDLE_SIZE));
+ } else {
+ // Opposite dock is fixed-width; flex items share (W - fixed).
+ let opposite_fixed = opposite
+ .map(|(panel, s)| s.size.unwrap_or_else(|| panel.default_size(window, cx)))
+ .unwrap_or_default();
+ let available = (workspace_width - opposite_fixed).max(RESIZE_HANDLE_SIZE);
+ return Some((flex / (flex + 1.0) * available).max(RESIZE_HANDLE_SIZE));
+ }
}
Some(
@@ -2226,7 +2257,7 @@ impl Workspace {
)
}
- pub fn flexible_dock_ratio_for_size(
+ pub fn dock_flex_for_size(
&self,
position: DockPosition,
size: Pixels,
@@ -2237,45 +2268,55 @@ impl Workspace {
return None;
}
- let available_width = self.available_width_for_horizontal_dock(position, window, cx)?;
- let available_width = available_width.max(RESIZE_HANDLE_SIZE);
- Some((size / available_width).clamp(0.0, 1.0))
+ let workspace_width = self.bounds.size.width;
+ if workspace_width <= Pixels::ZERO {
+ return None;
+ }
+
+ let opposite = self.opposite_dock_panel_and_size_state(position, window, cx);
+ if let Some(opposite_flex) = opposite.as_ref().and_then(|(_, s)| s.flex) {
+ let size = size.clamp(px(0.), workspace_width - px(1.));
+ Some((size * (1.0 + opposite_flex) / (workspace_width - size)).max(0.0))
+ } else {
+ let opposite_width = opposite
+ .map(|(panel, s)| s.size.unwrap_or_else(|| panel.default_size(window, cx)))
+ .unwrap_or_default();
+ let available = (workspace_width - opposite_width).max(RESIZE_HANDLE_SIZE);
+ let remaining = (available - size).max(px(1.));
+ Some((size / remaining).max(0.0))
+ }
}
- fn available_width_for_horizontal_dock(
+ fn opposite_dock_panel_and_size_state(
&self,
position: DockPosition,
window: &Window,
cx: &App,
- ) -> Option<Pixels> {
- let workspace_width = self.bounds.size.width;
- if workspace_width <= Pixels::ZERO {
- return None;
- }
-
+ ) -> Option<(Arc<dyn PanelHandle>, PanelSizeState)> {
let opposite_position = match position {
DockPosition::Left => DockPosition::Right,
DockPosition::Right => DockPosition::Left,
DockPosition::Bottom => return None,
};
- let opposite_width = self
- .dock_at_position(opposite_position)
- .read(cx)
- .stored_active_panel_size(window, cx)
- .unwrap_or(Pixels::ZERO);
-
- Some((workspace_width - opposite_width).max(RESIZE_HANDLE_SIZE))
+ let opposite_dock = self.dock_at_position(opposite_position).read(cx);
+ let panel = opposite_dock.visible_panel()?;
+ let mut size_state = opposite_dock
+ .stored_panel_size_state(panel.as_ref())
+ .unwrap_or_default();
+ if size_state.flex.is_none() && panel.has_flexible_size(window, cx) {
+ size_state.flex = self.default_dock_flex(opposite_position);
+ }
+ Some((panel.clone(), size_state))
}
- pub fn default_flexible_dock_ratio(&self, position: DockPosition) -> Option<f32> {
+ pub fn default_dock_flex(&self, position: DockPosition) -> Option<f32> {
if position.axis() != Axis::Horizontal {
return None;
}
let pane = self.last_active_center_pane.clone()?.upgrade()?;
- let pane_fraction = self.center.width_fraction_for_pane(&pane).unwrap_or(1.0);
- Some((pane_fraction / (1.0 + pane_fraction)).clamp(0.0, 1.0))
+ Some(self.center.width_fraction_for_pane(&pane).unwrap_or(1.0))
}
pub fn is_edited(&self) -> bool {
@@ -2301,7 +2342,7 @@ impl Workspace {
load_legacy_panel_size(T::panel_key(), dock_position, self, cx).map(|size| {
let state = dock::PanelSizeState {
size: Some(size),
- flexible_size_ratio: None,
+ flex: None,
};
self.persist_panel_size_state(T::panel_key(), state, cx);
state
@@ -7277,13 +7318,16 @@ impl Workspace {
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 use_flexible = panel.has_flexible_size(window, cx);
+ let flex_grow = if use_flexible {
+ size_state
+ .and_then(|state| state.flex)
+ .or_else(|| self.default_dock_flex(position))
+ } else {
+ None
+ };
+ if let Some(grow) = flex_grow {
+ let grow = grow.max(0.001);
let style = container.style();
style.flex_grow = Some(grow);
style.flex_shrink = Some(1.0);
@@ -7399,15 +7443,15 @@ impl Workspace {
}
});
- let ratio = self.flexible_dock_ratio_for_size(DockPosition::Left, size, window, cx);
+ let flex_grow = self.dock_flex_for_size(DockPosition::Left, size, window, cx);
self.left_dock.update(cx, |left_dock, cx| {
if WorkspaceSettings::get_global(cx)
.resize_all_panels_in_dock
.contains(&DockPosition::Left)
{
- left_dock.resize_all_panels(Some(size), ratio, window, cx);
+ left_dock.resize_all_panels(Some(size), flex_grow, window, cx);
} else {
- left_dock.resize_active_panel(Some(size), ratio, window, cx);
+ left_dock.resize_active_panel(Some(size), flex_grow, window, cx);
}
});
}
@@ -7423,15 +7467,15 @@ impl Workspace {
size = workspace_width - left_dock_size
}
});
- let ratio = self.flexible_dock_ratio_for_size(DockPosition::Right, size, window, cx);
+ let flex_grow = self.dock_flex_for_size(DockPosition::Right, size, window, cx);
self.right_dock.update(cx, |right_dock, cx| {
if WorkspaceSettings::get_global(cx)
.resize_all_panels_in_dock
.contains(&DockPosition::Right)
{
- right_dock.resize_all_panels(Some(size), ratio, window, cx);
+ right_dock.resize_all_panels(Some(size), flex_grow, window, cx);
} else {
- right_dock.resize_active_panel(Some(size), ratio, window, cx);
+ right_dock.resize_active_panel(Some(size), flex_grow, window, cx);
}
});
}
@@ -12346,8 +12390,11 @@ mod tests {
assert_eq!(
right_dock
.stored_panel_size_state(flexible_panel.as_ref())
- .and_then(|size_state| size_state.flexible_size_ratio),
- Some(resized_width.to_f64() as f32 / workspace.bounds.size.width.to_f64() as f32)
+ .and_then(|size_state| size_state.flex),
+ Some(
+ resized_width.to_f64() as f32
+ / (workspace.bounds.size.width - resized_width).to_f64() as f32
+ )
);
});
@@ -12481,9 +12528,7 @@ mod tests {
persisted.size, None,
"flexible panel should not persist a redundant pixel size"
);
- let original_ratio = persisted
- .flexible_size_ratio
- .expect("flexible panel ratio should be persisted");
+ let original_ratio = persisted.flex.expect("panel's flex should be persisted");
// Remove the panel and re-add: both size and ratio should be restored.
workspace.update_in(cx, |workspace, window, cx| {
@@ -12504,9 +12549,9 @@ mod tests {
"re-added flexible panel should not have a persisted pixel size"
);
assert_eq!(
- size_state.flexible_size_ratio,
+ size_state.flex,
Some(original_ratio),
- "re-added flexible panel should restore persisted ratio"
+ "re-added flexible panel should restore persisted flex"
);
});
}
@@ -12599,6 +12644,64 @@ mod tests {
"flexible left panel should shrink proportionally as the right dock takes space"
);
});
+
+ // Step 4: Toggle the right dock's panel to flexible. Now both docks use
+ // flex sizing and the workspace width is divided among left-flex, center
+ // (implicit flex 1.0), and right-flex.
+ workspace.update_in(cx, |workspace, window, cx| {
+ let right_dock = workspace.right_dock().clone();
+ let right_panel = right_dock
+ .read(cx)
+ .visible_panel()
+ .expect("right dock should have a visible panel")
+ .clone();
+ workspace.toggle_dock_panel_flexible_size(
+ &right_dock,
+ right_panel.as_ref(),
+ window,
+ cx,
+ );
+
+ let right_dock = right_dock.read(cx);
+ let right_panel = right_dock
+ .visible_panel()
+ .expect("right dock should still have a visible panel");
+ assert!(
+ right_panel.has_flexible_size(window, cx),
+ "right panel should now be flexible"
+ );
+
+ let right_size_state = right_dock
+ .stored_panel_size_state(right_panel.as_ref())
+ .expect("right panel should have a stored size state after toggling");
+ let right_flex = right_size_state
+ .flex
+ .expect("right panel should have a flex value after toggling");
+
+ let left_dock = workspace.left_dock().read(cx);
+ let left_width = workspace
+ .dock_size(&left_dock, window, cx)
+ .expect("left dock should still have an active panel");
+ let right_width = workspace
+ .dock_size(&right_dock, window, cx)
+ .expect("right dock should still have an active panel");
+
+ let left_flex = workspace
+ .default_dock_flex(DockPosition::Left)
+ .expect("left dock should have a default flex");
+
+ let total_flex = left_flex + 1.0 + right_flex;
+ let expected_left = left_flex / total_flex * workspace.bounds.size.width;
+ let expected_right = right_flex / total_flex * workspace.bounds.size.width;
+ assert_eq!(
+ left_width, expected_left,
+ "flexible left panel should share workspace width via flex ratios"
+ );
+ assert_eq!(
+ right_width, expected_right,
+ "flexible right panel should share workspace width via flex ratios"
+ );
+ });
}
struct TestModal(FocusHandle);