diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index da961ded454aa4433366e6ce742694f7bad29a89..ef659b26d2d7a155fda126c4d947520c146bb3ae 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -3186,7 +3186,7 @@ impl Panel for AgentPanel { cx.notify(); } - fn render_center_element( + fn render_flex_content( &mut self, window: &mut Window, cx: &mut Context, @@ -3194,11 +3194,11 @@ impl Panel for AgentPanel { Some(self.render_content(window, cx).into_any_element()) } - fn has_center_element(&self, _window: &Window, _: &App) -> bool { + fn has_flex_content(&self, _window: &Window, _: &App) -> bool { true } - fn has_main_element(&self, window: &Window, cx: &App) -> bool { + fn has_panel_content(&self, window: &Window, cx: &App) -> bool { sidebar_is_open(window, cx) } } diff --git a/crates/debugger_ui/src/session/running.rs b/crates/debugger_ui/src/session/running.rs index 1df442ef88fada109b6b7ad6e3bb5cf63f0ea453..8dc923780b55a62df4a5e1120bffbdf0acd05541 100644 --- a/crates/debugger_ui/src/session/running.rs +++ b/crates/debugger_ui/src/session/running.rs @@ -115,6 +115,8 @@ impl Render for RunningState { } else if let Some(active) = active { self.panes .render( + None, + None, None, &ActivePaneDecorator::new(active, &self.workspace), window, diff --git a/crates/terminal_view/src/terminal_panel.rs b/crates/terminal_view/src/terminal_panel.rs index 93b9e651191e791da8bbda35600c3db001b46d90..479683e923d839b476c56b6a8dfdaa3bd995b75c 100644 --- a/crates/terminal_view/src/terminal_panel.rs +++ b/crates/terminal_view/src/terminal_panel.rs @@ -1362,6 +1362,8 @@ impl Render for TerminalPanel { .update(cx, |workspace, cx| { registrar.size_full().child(self.center.render( workspace.zoomed_item(), + None, + None, &workspace::PaneRenderContext { follower_states: &HashMap::default(), active_call: workspace.active_call(), diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 0c35f5d17333c4b0b7d7466d3af57b2717a2bf2a..2af8d2e161a8b79effb63a0c25ae6fae5b68c8ed 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -59,17 +59,17 @@ pub trait Panel: Focusable + EventEmitter + Render + Sized { fn enabled(&self, _cx: &App) -> bool { true } - fn render_center_element( + fn render_flex_content( &mut self, _window: &mut Window, _cx: &mut Context, ) -> Option { None } - fn has_center_element(&self, _window: &Window, _cx: &App) -> bool { + fn has_flex_content(&self, _window: &Window, _cx: &App) -> bool { false } - fn has_main_element(&self, _window: &Window, _cx: &App) -> bool { + fn has_panel_content(&self, _window: &Window, _cx: &App) -> bool { true } } @@ -96,9 +96,9 @@ pub trait PanelHandle: Send + Sync { fn to_any(&self) -> AnyView; fn activation_priority(&self, cx: &App) -> u32; fn enabled(&self, cx: &App) -> bool; - fn center_element(&self, window: &Window, cx: &mut App) -> Option; - fn has_center_element(&self, window: &Window, cx: &App) -> bool; - fn has_main_element(&self, window: &Window, cx: &App) -> bool; + fn flex_content(&self, window: &Window, cx: &mut App) -> Option; + fn has_flex_content(&self, window: &Window, cx: &App) -> bool; + fn has_panel_content(&self, window: &Window, cx: &App) -> bool; fn move_to_next_position(&self, window: &mut Window, cx: &mut App) { let current_position = self.position(window, cx); let next_position = [ @@ -204,19 +204,19 @@ where self.read(cx).enabled(cx) } - fn center_element(&self, window: &Window, cx: &mut App) -> Option { - if !self.read(cx).has_center_element(window, cx) { + fn flex_content(&self, window: &Window, cx: &mut App) -> Option { + if !self.read(cx).has_flex_content(window, cx) { return None; } Some(cx.new(|_| PanelCenterView(self.clone())).into()) } - fn has_center_element(&self, window: &Window, cx: &App) -> bool { - self.read(cx).has_center_element(window, cx) + fn has_flex_content(&self, window: &Window, cx: &App) -> bool { + self.read(cx).has_flex_content(window, cx) } - fn has_main_element(&self, window: &Window, cx: &App) -> bool { - self.read(cx).has_main_element(window, cx) + fn has_panel_content(&self, window: &Window, cx: &App) -> bool { + self.read(cx).has_panel_content(window, cx) } } @@ -225,7 +225,7 @@ struct PanelCenterView(Entity); impl Render for PanelCenterView { fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { self.0.update(cx, |this, cx| { - this.render_center_element(window, cx) + this.render_flex_content(window, cx) .unwrap_or_else(|| gpui::Empty.into_any_element()) }) } @@ -732,9 +732,9 @@ impl Dock { Some(&entry.panel) } - pub fn visible_panel_center_element(&self, window: &Window, cx: &mut App) -> Option { + pub fn visible_panel_flex_element(&self, window: &Window, cx: &mut App) -> Option { let entry = self.visible_entry()?; - entry.panel.center_element(window, cx) + entry.panel.flex_content(window, cx) } pub fn active_panel(&self) -> Option<&Arc> { @@ -832,7 +832,7 @@ impl Render for Dock { let dispatch_context = Self::dispatch_context(); if let Some(entry) = self .visible_entry() - .filter(|entry| entry.panel.has_main_element(window, cx)) + .filter(|entry| entry.panel.has_panel_content(window, cx)) { let size = entry.panel.size(window, cx); diff --git a/crates/workspace/src/pane_group.rs b/crates/workspace/src/pane_group.rs index c27e1d302355aeac6eac75f9d6e8531f78370997..05ab37a1364e3071bf9e2475821920cb861bdf2c 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -27,6 +27,7 @@ const VERTICAL_MIN_SIZE: f32 = 100.; #[derive(Clone)] pub struct PaneGroup { pub root: Member, + pub state: PaneGroupState, pub is_center: bool, } @@ -39,15 +40,13 @@ impl PaneGroup { pub fn with_root(root: Member) -> Self { Self { root, + state: PaneGroupState::default(), is_center: false, } } pub fn new(pane: Entity) -> Self { - Self { - root: Member::Pane(pane), - is_center: false, - } + Self::with_root(Member::Pane(pane)) } pub fn set_is_center(&mut self, is_center: bool) { @@ -65,6 +64,7 @@ impl PaneGroup { Member::Pane(pane) => { if pane == old_pane { self.root = Member::new_axis(old_pane.clone(), new_pane.clone(), direction); + self.state.reset_flexes(); true } else { false @@ -174,6 +174,7 @@ impl PaneGroup { Member::Axis(axis) => { if let Some(last_pane) = axis.remove(pane)? { self.root = last_pane; + self.state.reset_flexes(); } Ok(true) } @@ -222,11 +223,46 @@ impl PaneGroup { pub fn render( &self, zoomed: Option<&AnyWeakView>, + left_content: Option, + right_content: Option, render_cx: &dyn PaneLeaderDecorator, window: &mut Window, cx: &mut App, ) -> impl IntoElement { - self.root.render(0, zoomed, render_cx, window, cx).element + let mut state = self.state.0.borrow_mut(); + if left_content.is_some() { + state.left_entry_is_active = true; + state.left_entry.get_or_insert(PaneAxisStateEntry { + flex: 1.0, + bounding_box: None, + }); + } else { + state.left_entry_is_active = false; + } + + if right_content.is_some() { + state.right_entry_is_active = true; + state.right_entry.get_or_insert(PaneAxisStateEntry { + flex: 1.0, + bounding_box: None, + }); + } else { + state.right_entry_is_active = false; + } + drop(state); + + self.root + .render( + 0, + zoomed, + left_content, + right_content, + Some(self.state.clone()), + render_cx, + window, + cx, + ) + .element } pub fn panes(&self) -> Vec<&Entity> { @@ -510,10 +546,66 @@ impl Member { &self, basis: usize, zoomed: Option<&AnyWeakView>, + left_content: Option, + right_content: Option, + pane_group_state: Option, render_cx: &dyn PaneLeaderDecorator, window: &mut Window, cx: &mut App, ) -> PaneRenderResult { + if let Some(pane_group_state) = pane_group_state + && (left_content.is_some() || right_content.is_some()) + { + return match self { + Member::Axis(axis) if axis.axis == Axis::Horizontal => axis.render( + basis + 1, + zoomed, + Some(pane_group_state), + left_content, + right_content, + render_cx, + window, + cx, + ), + _ => { + let mut active_pane_ix = 0; + if left_content.is_some() { + active_pane_ix += 1; + } + if right_content.is_some() { + active_pane_ix += 1; + } + + let inner = self.render(0, zoomed, None, None, None, render_cx, window, cx); + + let mut children = Vec::new(); + children.extend(left_content.map(|content| content.into_any_element())); + children.push(inner.element); + children.extend(right_content.map(|content| content.into_any_element())); + + let element = pane_axis( + Axis::Horizontal, + 0, + PaneAxisState::with_flexes(vec![ + children.len() as f32 + - pane_group_state.total_flex(); + 1 + ]), + Some(pane_group_state), + render_cx.workspace().clone(), + ) + .with_active_pane(Some(active_pane_ix)) + .with_is_leaf_pane_mask(vec![true, matches!(self, Member::Pane(_)), true]) + .children(children) + .into_any_element(); + PaneRenderResult { + element, + contains_active_pane: inner.contains_active_pane, + } + } + }; + } + match self { Member::Pane(pane) => { if zoomed == Some(&pane.downgrade().into()) { @@ -551,7 +643,9 @@ impl Member { contains_active_pane: is_active, } } - Member::Axis(axis) => axis.render(basis + 1, zoomed, render_cx, window, cx), + Member::Axis(axis) => { + axis.render(basis + 1, zoomed, None, None, None, render_cx, window, cx) + } } } @@ -582,56 +676,116 @@ impl Member { #[derive(Debug, Clone)] pub struct PaneAxisState(Rc>); +#[derive(Default, Debug, Clone)] +pub struct PaneGroupState(Rc>); + #[derive(Debug)] struct PaneAxisStateInner { - flexes: Vec, - bounding_boxes: Vec>>, + entries: Vec, +} + +#[derive(Default, Debug)] +struct PaneGroupStateInner { + left_entry: Option, + left_entry_is_active: bool, + right_entry: Option, + right_entry_is_active: bool, +} + +#[derive(Clone, Copy, Debug)] +struct PaneAxisStateEntry { + flex: f32, + bounding_box: Option>, +} + +impl PaneGroupState { + fn total_flex(&self) -> f32 { + let state = self.0.borrow(); + state.left_entry.as_ref().map_or(0., |e| e.flex) + + state.right_entry.as_ref().map_or(0., |e| e.flex) + } + + fn reset_flexes(&self) { + let mut state = self.0.borrow_mut(); + if let Some(left_entry) = state.left_entry.as_mut() { + left_entry.flex = 1.0; + left_entry.bounding_box = None; + } + if let Some(right_entry) = state.right_entry.as_mut() { + right_entry.flex = 1.0; + right_entry.bounding_box = None; + } + } } impl PaneAxisState { pub fn new(member_count: usize) -> Self { Self(Rc::new(RefCell::new(PaneAxisStateInner { - flexes: vec![1.; member_count], - bounding_boxes: vec![None; member_count], + entries: vec![ + PaneAxisStateEntry { + flex: 1., + bounding_box: None + }; + member_count + ], }))) } fn with_flexes(flexes: Vec) -> Self { - let member_count = flexes.len(); Self(Rc::new(RefCell::new(PaneAxisStateInner { - flexes, - bounding_boxes: vec![None; member_count], + entries: flexes + .into_iter() + .map(|flex| PaneAxisStateEntry { + flex, + bounding_box: None, + }) + .collect(), }))) } pub fn flexes(&self) -> Vec { - self.0.borrow().flexes.clone() + self.0.borrow().entries.iter().map(|e| e.flex).collect() } pub fn len(&self) -> usize { - self.0.borrow().flexes.len() + self.0.borrow().entries.len() } fn resize(&self, len: usize) { let mut inner = self.0.borrow_mut(); - inner.flexes.clear(); - inner.flexes.resize(len, 1.); - inner.bounding_boxes.clear(); - inner.bounding_boxes.resize(len, None); + inner.entries.clear(); + inner.entries.resize( + len, + PaneAxisStateEntry { + flex: 1., + bounding_box: None, + }, + ); } fn reset_flexes(&self) { let mut inner = self.0.borrow_mut(); - inner.flexes.iter_mut().for_each(|f| *f = 1.); - inner.bounding_boxes.iter_mut().for_each(|f| *f = None); + inner.entries.iter_mut().for_each(|e| { + e.flex = 1.; + e.bounding_box = None; + }); } - fn bounding_boxes(&self) -> Vec>> { - self.0.borrow().bounding_boxes.clone() + fn bounding_box_at(&self, index: usize) -> Option> { + self.0 + .borrow() + .entries + .get(index) + .and_then(|e| e.bounding_box) } - fn bounding_box_at(&self, index: usize) -> Option> { - self.0.borrow().bounding_boxes[index] + fn bounds(&self) -> Option> { + self.0 + .borrow() + .entries + .iter() + .filter_map(|e| e.bounding_box) + .reduce(|acc, e| acc.union(&e)) } } @@ -778,14 +932,7 @@ impl PaneAxis { amount: Pixels, bounds: &Bounds, ) -> Option { - let container_size = self - .state - .bounding_boxes() - .iter() - .filter_map(|e| *e) - .reduce(|acc, e| acc.union(&e)) - .unwrap_or(*bounds) - .size; + let container_size = self.state.bounds().unwrap_or(*bounds).size; let found_pane = self .members @@ -818,7 +965,6 @@ impl PaneAxis { Axis::Vertical => px(VERTICAL_MIN_SIZE), }; let mut state = self.state.0.borrow_mut(); - let flexes = &mut state.flexes; let ix = if found_pane { self.members.iter().position(|m| { @@ -838,46 +984,48 @@ impl PaneAxis { let ix = ix.unwrap_or(0); - let size = move |ix, flexes: &[f32]| { - container_size.along(axis) * (flexes[ix] / flexes.len() as f32) + let size = move |ix: usize, state: &PaneAxisStateInner| { + container_size.along(axis) * (state.entries[ix].flex / state.entries.len() as f32) }; // Don't allow resizing to less than the minimum size, if elements are already too small - if min_size - px(1.) > size(ix, flexes.as_slice()) { + if min_size - px(1.) > size(ix, &state) { return Some(true); } - let flex_changes = |pixel_dx, target_ix, next: isize, flexes: &[f32]| { - let flex_change = flexes.len() as f32 * pixel_dx / container_size.along(axis); - let current_target_flex = flexes[target_ix] + flex_change; - let next_target_flex = flexes[(target_ix as isize + next) as usize] - flex_change; + let flex_changes = |pixel_dx, target_ix: usize, next: isize, state: &PaneAxisStateInner| { + let flex_change = state.entries.len() as f32 * pixel_dx / container_size.along(axis); + let current_target_flex = state.entries[target_ix].flex + flex_change; + let next_target_flex = + state.entries[(target_ix as isize + next) as usize].flex - flex_change; (current_target_flex, next_target_flex) }; - let apply_changes = - |current_ix: usize, proposed_current_pixel_change: Pixels, flexes: &mut [f32]| { - let next_target_size = Pixels::max( - size(current_ix + 1, flexes) - proposed_current_pixel_change, - min_size, - ); - let current_target_size = Pixels::max( - size(current_ix, flexes) + size(current_ix + 1, flexes) - next_target_size, - min_size, - ); + let apply_changes = |current_ix: usize, + proposed_current_pixel_change: Pixels, + state: &mut PaneAxisStateInner| { + let next_target_size = Pixels::max( + size(current_ix + 1, state) - proposed_current_pixel_change, + min_size, + ); + let current_target_size = Pixels::max( + size(current_ix, state) + size(current_ix + 1, state) - next_target_size, + min_size, + ); - let current_pixel_change = current_target_size - size(current_ix, flexes); + let current_pixel_change = current_target_size - size(current_ix, state); - let (current_target_flex, next_target_flex) = - flex_changes(current_pixel_change, current_ix, 1, flexes); + let (current_target_flex, next_target_flex) = + flex_changes(current_pixel_change, current_ix, 1, state); - flexes[current_ix] = current_target_flex; - flexes[current_ix + 1] = next_target_flex; - }; + state.entries[current_ix].flex = current_target_flex; + state.entries[current_ix + 1].flex = next_target_flex; + }; - if ix + 1 == flexes.len() { - apply_changes(ix - 1, -1.0 * amount, flexes.as_mut_slice()); + if ix + 1 == state.entries.len() { + apply_changes(ix - 1, -1.0 * amount, &mut *state); } else { - apply_changes(ix, amount, flexes.as_mut_slice()); + apply_changes(ix, amount, &mut *state); } Some(true) } @@ -920,10 +1068,8 @@ impl PaneAxis { fn pane_at_pixel_position(&self, coordinate: Point) -> Option<&Entity> { debug_assert!(self.members.len() == self.state.len()); - let bounding_boxes = self.state.bounding_boxes(); - for (idx, member) in self.members.iter().enumerate() { - if let Some(coordinates) = bounding_boxes[idx] + if let Some(coordinates) = self.state.bounding_box_at(idx) && coordinates.contains(&coordinate) { return match member { @@ -939,6 +1085,9 @@ impl PaneAxis { &self, basis: usize, zoomed: Option<&AnyWeakView>, + pane_group_state: Option, + left_content: Option, + right_content: Option, render_cx: &dyn PaneLeaderDecorator, window: &mut Window, cx: &mut App, @@ -948,11 +1097,10 @@ impl PaneAxis { let mut contains_active_pane = false; let mut is_leaf_pane = vec![false; self.members.len()]; - let rendered_children = self - .members - .iter() - .enumerate() - .map(|(ix, member)| { + let rendered_children = left_content + .map(|view| view.into_any_element()) + .into_iter() + .chain(self.members.iter().enumerate().map(|(ix, member)| { match member { Member::Pane(pane) => { is_leaf_pane[ix] = true; @@ -966,18 +1114,29 @@ impl PaneAxis { } } - let result = member.render((basis + ix) * 10, zoomed, render_cx, window, cx); + let result = member.render( + (basis + ix) * 10, + zoomed, + None, + None, + None, + render_cx, + window, + cx, + ); if result.contains_active_pane { contains_active_pane = true; } result.element.into_any_element() - }) + })) + .chain(right_content.map(|view| view.into_any_element())) .collect::>(); let element = pane_axis( self.axis, basis, self.state.clone(), + pane_group_state, render_cx.workspace().clone(), ) .with_is_leaf_pane_mask(is_leaf_pane) @@ -992,6 +1151,35 @@ impl PaneAxis { } } +impl PaneAxisStateInner { + pub fn entries<'a>( + &'a mut self, + pane_group_state: Option<&'a mut PaneGroupStateInner>, + ) -> Vec<&'a mut PaneAxisStateEntry> { + let mut entries = Vec::new(); + if let Some(pane_group_state) = pane_group_state { + if let Some(left) = pane_group_state + .left_entry + .as_mut() + .filter(|_| pane_group_state.left_entry_is_active) + { + entries.push(left); + } + entries.extend(self.entries.iter_mut()); + if let Some(right) = pane_group_state + .right_entry + .as_mut() + .filter(|_| pane_group_state.right_entry_is_active) + { + entries.push(right); + } + } else { + entries.extend(self.entries.iter_mut()); + } + entries + } +} + #[derive(Clone, Copy, Debug, Deserialize, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum SplitDirection { @@ -1103,6 +1291,7 @@ pub mod element { use crate::Workspace; use crate::WorkspaceSettings; + use crate::pane_group::{PaneAxisStateEntry, PaneGroupState}; use super::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, PaneAxisState, VERTICAL_MIN_SIZE}; @@ -1112,12 +1301,14 @@ pub mod element { axis: Axis, basis: usize, state: PaneAxisState, + pane_group_state: Option, workspace: WeakEntity, ) -> PaneAxisElement { PaneAxisElement { axis, basis, state, + pane_group_state, children: SmallVec::new(), active_pane_ix: None, workspace, @@ -1129,6 +1320,7 @@ pub mod element { axis: Axis, basis: usize, state: PaneAxisState, + pane_group_state: Option, children: SmallVec<[AnyElement; 2]>, active_pane_ix: Option, workspace: WeakEntity, @@ -1165,6 +1357,7 @@ pub mod element { } fn compute_resize( + pane_group_state: Option<&PaneGroupState>, state: &PaneAxisState, e: &MouseMoveEvent, ix: usize, @@ -1175,37 +1368,42 @@ pub mod element { window: &mut Window, cx: &mut App, ) { + let mut state = state.0.borrow_mut(); + let mut group_state = pane_group_state.as_ref().map(|state| state.0.borrow_mut()); + let group_state = group_state.as_deref_mut(); + let mut entries = state.entries(group_state); + let min_size = match axis { Axis::Horizontal => px(HORIZONTAL_MIN_SIZE), Axis::Vertical => px(VERTICAL_MIN_SIZE), }; - let mut inner = state.0.borrow_mut(); - let flexes = &mut inner.flexes; - debug_assert!(flex_values_in_bounds(flexes.as_slice())); + debug_assert!(flex_values_in_bounds(&entries)); // Math to convert a flex value to a pixel value - let size = move |ix, flexes: &[f32]| { - container_size.along(axis) * (flexes[ix] / flexes.len() as f32) + let size = move |ix: usize, state: &[&mut PaneAxisStateEntry]| { + container_size.along(axis) * (state[ix].flex / state.len() as f32) }; // Don't allow resizing to less than the minimum size, if elements are already too small - if min_size - px(1.) > size(ix, flexes.as_slice()) { + if min_size - px(1.) > size(ix, &entries) { return; } // This is basically a "bucket" of pixel changes that need to be applied in response to this // mouse event. Probably a small, fractional number like 0.5 or 1.5 pixels let mut proposed_current_pixel_change = - (e.position - child_start).along(axis) - size(ix, flexes.as_slice()); + (e.position - child_start).along(axis) - size(ix, &entries); // This takes a pixel change, and computes the flex changes that correspond to this pixel change // as well as the next one, for some reason - let flex_changes = |pixel_dx, target_ix, next: isize, flexes: &[f32]| { - let flex_change = pixel_dx / container_size.along(axis); - let current_target_flex = flexes[target_ix] + flex_change; - let next_target_flex = flexes[(target_ix as isize + next) as usize] - flex_change; - (current_target_flex, next_target_flex) - }; + let flex_changes = + |pixel_dx, target_ix: usize, next: isize, entries: &[&mut PaneAxisStateEntry]| { + let flex_change = pixel_dx / container_size.along(axis); + let current_target_flex = entries[target_ix].flex + flex_change; + let next_target_flex = + entries[(target_ix as isize + next) as usize].flex - flex_change; + (current_target_flex, next_target_flex) + }; // Generate the list of flex successors, from the current index. // If you're dragging column 3 forward, out of 6 columns, then this code will produce [4, 5, 6] @@ -1213,7 +1411,7 @@ pub mod element { let mut successors = iter::from_fn({ let forward = proposed_current_pixel_change > px(0.); let mut ix_offset = 0; - let len = flexes.len(); + let len = entries.len(); move || { let result = if forward { (ix + 1 + ix_offset < len).then(|| ix + ix_offset) @@ -1234,24 +1432,22 @@ pub mod element { }; let next_target_size = Pixels::max( - size(current_ix + 1, flexes.as_slice()) - proposed_current_pixel_change, + size(current_ix + 1, &entries) - proposed_current_pixel_change, min_size, ); let current_target_size = Pixels::max( - size(current_ix, flexes.as_slice()) + size(current_ix + 1, flexes.as_slice()) - - next_target_size, + size(current_ix, &entries) + size(current_ix + 1, &entries) - next_target_size, min_size, ); - let current_pixel_change = - current_target_size - size(current_ix, flexes.as_slice()); + let current_pixel_change = current_target_size - size(current_ix, &entries); let (current_target_flex, next_target_flex) = - flex_changes(current_pixel_change, current_ix, 1, flexes.as_slice()); + flex_changes(current_pixel_change, current_ix, 1, &entries); - flexes[current_ix] = current_target_flex; - flexes[current_ix + 1] = next_target_flex; + entries[current_ix].flex = current_target_flex; + entries[current_ix + 1].flex = next_target_flex; proposed_current_pixel_change -= current_pixel_change; } @@ -1344,24 +1540,28 @@ pub mod element { (state.clone(), state) }, ); - let flexes = self.state.flexes(); + let mut state = self.state.0.borrow_mut(); + let mut group_state = self.pane_group_state.as_ref().map(|s| s.0.borrow_mut()); + let group_state = group_state.as_deref_mut(); + let mut entries = state.entries(group_state); + let len = self.children.len(); - debug_assert!(flexes.len() == len); - debug_assert!(flex_values_in_bounds(flexes.as_slice())); + debug_assert!(entries.len() == len); + debug_assert!(flex_values_in_bounds(&entries)); let total_flex = len as f32; let mut origin = bounds.origin; let space_per_flex = bounds.size.along(self.axis) / total_flex; - self.state.0.borrow_mut().bounding_boxes.clear(); + // self.state.0.borrow_mut().bounding_boxes.clear(); let mut layout = PaneAxisLayout { dragged_handle, children: Vec::new(), }; for (ix, mut child) in mem::take(&mut self.children).into_iter().enumerate() { - let child_flex = flexes[ix]; + let child_flex = entries[ix].flex; let child_size = bounds .size @@ -1373,11 +1573,7 @@ pub mod element { size: child_size, }; - self.state - .0 - .borrow_mut() - .bounding_boxes - .push(Some(child_bounds)); + entries[ix].bounding_box = Some(child_bounds); child.layout_as_root(child_size.into(), window, cx); child.prepaint_at(origin, window, cx); @@ -1498,6 +1694,7 @@ pub mod element { window.on_mouse_event({ let dragged_handle = layout.dragged_handle.clone(); let state = self.state.clone(); + let group_state = self.pane_group_state.clone(); let workspace = self.workspace.clone(); let handle_hitbox = handle.hitbox.clone(); move |e: &MouseDownEvent, phase, window, cx| { @@ -1505,6 +1702,9 @@ pub mod element { dragged_handle.replace(Some(ix)); if e.click_count >= 2 { state.reset_flexes(); + if let Some(group_state) = group_state.as_ref() { + group_state.reset_flexes(); + } workspace .update(cx, |this, cx| this.serialize_workspace(window, cx)) .log_err(); @@ -1519,12 +1719,14 @@ pub mod element { let workspace = self.workspace.clone(); let dragged_handle = layout.dragged_handle.clone(); let state = self.state.clone(); + let group_state = self.pane_group_state.clone(); let child_bounds = child.bounds; let axis = self.axis; move |e: &MouseMoveEvent, phase, window, cx| { let dragged_handle = dragged_handle.borrow(); if phase.bubble() && *dragged_handle == Some(ix) { Self::compute_resize( + group_state.as_ref(), &state, e, ix, @@ -1558,7 +1760,7 @@ pub mod element { } } - fn flex_values_in_bounds(flexes: &[f32]) -> bool { - (flexes.iter().copied().sum::() - flexes.len() as f32).abs() < 0.001 + fn flex_values_in_bounds(inner: &[&mut PaneAxisStateEntry]) -> bool { + (inner.iter().map(|e| e.flex).sum::() - inner.len() as f32).abs() < 0.001 } } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 3b66f44410a32f92d8d7042e867edebff3ec13f0..db3bb33e6c51bff676fc61821aa6c56e6b807b73 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -51,12 +51,12 @@ use futures::{ future::{Shared, try_join_all}, }; use gpui::{ - Action, AnyElement, AnyEntity, AnyView, AnyWeakView, App, AsyncApp, AsyncWindowContext, Axis, - Bounds, Context, CursorStyle, Decorations, DragMoveEvent, Entity, EntityId, EventEmitter, - FocusHandle, Focusable, Global, HitboxBehavior, Hsla, KeyContext, Keystroke, ManagedView, - MouseButton, PathPromptOptions, Point, PromptLevel, Render, ResizeEdge, Size, Stateful, - Subscription, SystemWindowTabController, Task, Tiling, WeakEntity, WindowBounds, WindowHandle, - WindowId, WindowOptions, actions, canvas, point, relative, size, transparent_black, + Action, AnyElement, AnyEntity, AnyView, AnyWeakView, App, AsyncApp, AsyncWindowContext, Bounds, + Context, CursorStyle, Decorations, DragMoveEvent, Entity, EntityId, EventEmitter, FocusHandle, + Focusable, Global, HitboxBehavior, Hsla, KeyContext, Keystroke, ManagedView, MouseButton, + PathPromptOptions, Point, PromptLevel, Render, ResizeEdge, Size, Stateful, Subscription, + SystemWindowTabController, Task, Tiling, WeakEntity, WindowBounds, WindowHandle, WindowId, + WindowOptions, actions, canvas, point, relative, size, transparent_black, }; pub use history_manager::*; pub use item::{ @@ -1336,7 +1336,6 @@ pub struct Workspace { last_open_dock_positions: Vec, removing: bool, _panels_task: Option>>, - center_element_state: PaneAxisState, } impl EventEmitter for Workspace {} @@ -1742,7 +1741,6 @@ impl Workspace { scheduled_tasks: Vec::new(), last_open_dock_positions: Vec::new(), removing: false, - center_element_state: PaneAxisState::new(0), } } @@ -7003,27 +7001,33 @@ impl Workspace { window: &mut Window, cx: &mut App, ) -> AnyElement { - let left_visible_panel = if self.zoomed_position != Some(DockPosition::Left) { - self.left_dock.read(cx).visible_panel().cloned() - } else { - None - }; - let left_center_element = - left_visible_panel.and_then(|panel| panel.center_element(window, cx)); - - let right_visible_panel = if self.zoomed_position != Some(DockPosition::Right) { - self.right_dock.read(cx).visible_panel().cloned() - } else { - None - }; - let right_center_element = - right_visible_panel.and_then(|panel| panel.center_element(window, cx)); + let left_panel_flex_content = (self.zoomed_position != Some(DockPosition::Left)) + .then(|| { + self.left_dock + .read(cx) + .visible_panel() + .cloned() + .and_then(|panel| panel.flex_content(window, cx)) + }) + .flatten(); + let right_panel_flex_content = (self.zoomed_position != Some(DockPosition::Right)) + .then(|| { + self.right_dock + .read(cx) + .visible_panel() + .cloned() + .and_then(|panel| panel.flex_content(window, cx)) + }) + .flatten(); let center_pane_group = h_flex() + .size_full() .flex_1() .when_some(paddings.0, |this, p| this.child(p.border_r_1())) .child(self.center.render( self.zoomed.as_ref(), + left_panel_flex_content, + right_panel_flex_content, &PaneRenderContext { follower_states: &self.follower_states, active_call: self.active_call(), @@ -7038,59 +7042,9 @@ impl Workspace { .when_some(paddings.1, |this, p| this.child(p.border_l_1())) .into_any_element(); - if left_center_element.is_none() && right_center_element.is_none() { - return h_flex() - .flex_1() - .child(center_pane_group) - .into_any_element(); - } - - let member_count = - 1 + left_center_element.is_some() as usize + right_center_element.is_some() as usize; - - if self.center_element_state.len() != member_count { - self.center_element_state = PaneAxisState::new(member_count); - } - - let axis_element = pane_axis( - Axis::Horizontal, - 0, - self.center_element_state.clone(), - self.weak_self.clone(), - ); - - let axis_element = if let Some(left_element) = left_center_element { - axis_element.child( - div() - .flex_1() - .size_full() - .overflow_hidden() - .child(left_element), - ) - } else { - axis_element - }; - - let axis_element = axis_element.child(center_pane_group); - - let axis_element = if let Some(right_element) = right_center_element { - axis_element.child( - div() - .flex_1() - .size_full() - .overflow_hidden() - .child(right_element), - ) - } else { - axis_element - }; - - div() - .flex() - .flex_row() + h_flex() .flex_1() - .size_full() - .child(axis_element) + .child(center_pane_group) .into_any_element() }