From 1fcd2647ed0de5db10c01925e225f6a6b4e9b90d Mon Sep 17 00:00:00 2001 From: Ron Harel <55725807+ronharel02@users.noreply.github.com> Date: Wed, 7 May 2025 09:02:34 +0300 Subject: [PATCH] workspace: Fix inactive pane dimming (#29473) Closes #27173 Problem: Active panes nested within axes were incorrectly receiving opacity overlays, while inactive panes in nested structures would get multiple overlays applied, making them appear darker than intended. Solution: I fixed this by distinguishing between leaf panes and axes in the rendering pipeline, applying overlays only to elements that are both leaf panes and not active, ensuring consistent visual treatment regardless of their position in the hierarchy. Release Notes: - Fixed an issue where `inactive_opacity` settings would be applied to panes multiple times and even to the active pane when nested within another pane. --- crates/workspace/src/pane_group.rs | 133 ++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 40 deletions(-) diff --git a/crates/workspace/src/pane_group.rs b/crates/workspace/src/pane_group.rs index e9c1e75c60378286e69773fa8f1dde8bd05ae8b5..b275b3df96bf597c2c7f3573c4e46b1adf7ba501 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -30,6 +30,11 @@ pub struct PaneGroup { pub root: Member, } +pub struct PaneRenderResult { + pub element: gpui::AnyElement, + pub contains_active_pane: bool, +} + impl PaneGroup { pub fn with_root(root: Member) -> Self { Self { root } @@ -128,7 +133,7 @@ impl PaneGroup { window: &mut Window, cx: &mut App, ) -> impl IntoElement { - self.root.render(0, zoomed, render_cx, window, cx) + self.root.render(0, zoomed, render_cx, window, cx).element } pub fn panes(&self) -> Vec<&Entity> { @@ -398,40 +403,45 @@ impl Member { render_cx: &dyn PaneLeaderDecorator, window: &mut Window, cx: &mut App, - ) -> impl IntoElement { + ) -> PaneRenderResult { match self { Member::Pane(pane) => { if zoomed == Some(&pane.downgrade().into()) { - return div().into_any(); + return PaneRenderResult { + element: div().into_any(), + contains_active_pane: false, + }; } let decoration = render_cx.decorate(pane, cx); - - div() - .relative() - .flex_1() - .size_full() - .child( - AnyView::from(pane.clone()) - .cached(StyleRefinement::default().v_flex().size_full()), - ) - .when_some(decoration.border, |this, color| { - this.child( - div() - .absolute() - .size_full() - .left_0() - .top_0() - .border_2() - .border_color(color), + let is_active = pane == render_cx.active_pane(); + + PaneRenderResult { + element: div() + .relative() + .flex_1() + .size_full() + .child( + AnyView::from(pane.clone()) + .cached(StyleRefinement::default().v_flex().size_full()), ) - }) - .children(decoration.status_box) - .into_any() + .when_some(decoration.border, |this, color| { + this.child( + div() + .absolute() + .size_full() + .left_0() + .top_0() + .border_2() + .border_color(color), + ) + }) + .children(decoration.status_box) + .into_any(), + contains_active_pane: is_active, + } } - Member::Axis(axis) => axis - .render(basis + 1, zoomed, render_cx, window, cx) - .into_any(), + Member::Axis(axis) => axis.render(basis + 1, zoomed, render_cx, window, cx), } } @@ -752,27 +762,54 @@ impl PaneAxis { render_cx: &dyn PaneLeaderDecorator, window: &mut Window, cx: &mut App, - ) -> gpui::AnyElement { + ) -> PaneRenderResult { debug_assert!(self.members.len() == self.flexes.lock().len()); let mut active_pane_ix = None; + 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)| { + match member { + Member::Pane(pane) => { + is_leaf_pane[ix] = true; + if pane == render_cx.active_pane() { + active_pane_ix = Some(ix); + contains_active_pane = true; + } + } + Member::Axis(_) => { + is_leaf_pane[ix] = false; + } + } + + let result = member.render((basis + ix) * 10, zoomed, render_cx, window, cx); + if result.contains_active_pane { + contains_active_pane = true; + } + result.element.into_any_element() + }) + .collect::>(); - pane_axis( + let element = pane_axis( self.axis, basis, self.flexes.clone(), self.bounding_boxes.clone(), render_cx.workspace().clone(), ) - .children(self.members.iter().enumerate().map(|(ix, member)| { - if matches!(member, Member::Pane(pane) if pane == render_cx.active_pane()) { - active_pane_ix = Some(ix); - } - member - .render((basis + ix) * 10, zoomed, render_cx, window, cx) - .into_any_element() - })) + .with_is_leaf_pane_mask(is_leaf_pane) + .children(rendered_children) .with_active_pane(active_pane_ix) - .into_any_element() + .into_any_element(); + + PaneRenderResult { + element, + contains_active_pane, + } } } @@ -899,6 +936,7 @@ mod element { children: SmallVec::new(), active_pane_ix: None, workspace, + is_leaf_pane_mask: Vec::new(), } } @@ -910,6 +948,8 @@ mod element { children: SmallVec<[AnyElement; 2]>, active_pane_ix: Option, workspace: WeakEntity, + // Track which children are leaf panes (Member::Pane) vs axes (Member::Axis) + is_leaf_pane_mask: Vec, } pub struct PaneAxisLayout { @@ -921,6 +961,7 @@ mod element { bounds: Bounds, element: AnyElement, handle: Option, + is_leaf_pane: bool, } struct PaneAxisHandleLayout { @@ -934,6 +975,11 @@ mod element { self } + pub fn with_is_leaf_pane_mask(mut self, mask: Vec) -> Self { + self.is_leaf_pane_mask = mask; + self + } + fn compute_resize( flexes: &Arc>>, e: &MouseMoveEvent, @@ -1150,10 +1196,14 @@ mod element { child.prepaint_at(origin, window, cx); origin = origin.apply_along(self.axis, |val| val + child_size.along(self.axis)); + + let is_leaf_pane = self.is_leaf_pane_mask.get(ix).copied().unwrap_or(true); + layout.children.push(PaneAxisChildLayout { bounds: child_bounds, element: child, handle: None, + is_leaf_pane, }) } @@ -1215,12 +1265,15 @@ mod element { .apply_along(Axis::Horizontal, |val| val - Pixels(1.)), }; - if overlay_opacity.is_some() && self.active_pane_ix != Some(ix) { + if overlay_opacity.is_some() + && child.is_leaf_pane + && self.active_pane_ix != Some(ix) + { window.paint_quad(gpui::fill(overlay_bounds, overlay_background)); } if let Some(border) = overlay_border { - if self.active_pane_ix == Some(ix) { + if self.active_pane_ix == Some(ix) && child.is_leaf_pane { window.paint_quad(gpui::quad( overlay_bounds, 0.,