From bc3550d9915ce09920faba381c461beb55c30176 Mon Sep 17 00:00:00 2001 From: Alex Viscreanu Date: Tue, 5 Nov 2024 16:26:07 +0100 Subject: [PATCH] workspace: Add settings to dim inactive panes and highlight active pane (#18968) Closes #12529 Closes #8639 Release Notes: - Added option to dim inactive panes ([#12529](https://github.com/zed-industries/zed/issues/12529)) - Added option to highlight active pane with a border ([#8639](https://github.com/zed-industries/zed/issues/8639)) BREAKING: `active_pane_magnification` value is no longer used, it should be migrated to `active_pane_modifiers.magnification` ![panes](https://github.com/user-attachments/assets/b19959bc-4c06-4320-be36-412113143af5) > note: don't know much rust, so I wouldn't be surprised if stuff can be done much better, happy to update things after the review. Also, wasn't sure about introducing the new object in the settings, but it felt better than adding two more keys to the root, let me know what you think and if there's a better way to do this. Also happy to get feedback on the text itself, as I didn't spend much thinking how to document this. --- assets/settings/default.json | 14 ++++-- crates/workspace/src/pane_group.rs | 58 +++++++++++++++++++--- crates/workspace/src/workspace_settings.rs | 34 ++++++++++--- docs/src/configuring-zed.md | 20 +++++++- 4 files changed, 108 insertions(+), 18 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index 363f8e874b5571ec1e26ef94bfe56631f7365b3a..a32abbbcd6ae1b8fbe91ab7cb42a4447ebecbcf2 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -68,9 +68,17 @@ "ui_font_size": 16, // How much to fade out unused code. "unnecessary_code_fade": 0.3, - // The factor to grow the active pane by. Defaults to 1.0 - // which gives the same size as all other panes. - "active_pane_magnification": 1.0, + // Active pane styling settings. + "active_pane_modifiers": { + // The factor to grow the active pane by. Defaults to 1.0 + // which gives the same size as all other panes. + "magnification": 1.0, + // Inset border size of the active pane, in pixels. + "border_size": 0.0, + // Opacity of the inactive panes. 0 means transparent, 1 means opaque. + // Values are clamped to the [0.0, 1.0] range. + "inactive_opacity": 1.0 + }, // The direction that you want to split panes horizontally. Defaults to "up" "pane_split_direction_horizontal": "up", // The direction that you want to split panes horizontally. Defaults to "left" diff --git a/crates/workspace/src/pane_group.rs b/crates/workspace/src/pane_group.rs index 605e0abb75db0427a88d1b8f899bb327c48cb9bb..53d49fe6070b81adb40ed47234ab0d0b09467741 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -867,12 +867,10 @@ mod element { debug_assert!(flexes.len() == len); debug_assert!(flex_values_in_bounds(flexes.as_slice())); - let magnification_value = WorkspaceSettings::get(None, cx).active_pane_magnification; - let active_pane_magnification = if magnification_value == 1. { - None - } else { - Some(magnification_value) - }; + let active_pane_magnification = WorkspaceSettings::get(None, cx) + .active_pane_modifiers + .magnification + .and_then(|val| if val == 1.0 { None } else { Some(val) }); let total_flex = if let Some(flex) = active_pane_magnification { self.children.len() as f32 - 1. + flex @@ -910,6 +908,7 @@ mod element { origin, size: child_size, }; + bounding_boxes.push(Some(child_bounds)); child.layout_as_root(child_size.into(), cx); child.prepaint_at(origin, cx); @@ -944,7 +943,54 @@ mod element { child.element.paint(cx); } + let overlay_opacity = WorkspaceSettings::get(None, cx) + .active_pane_modifiers + .inactive_opacity + .map(|val| val.clamp(0.0, 1.0)) + .and_then(|val| (val <= 1.).then_some(val)); + + let mut overlay_background = cx.theme().colors().editor_background; + if let Some(opacity) = overlay_opacity { + overlay_background.fade_out(opacity); + } + + let overlay_border = WorkspaceSettings::get(None, cx) + .active_pane_modifiers + .border_size + .and_then(|val| (val >= 0.).then_some(val)); + for (ix, child) in &mut layout.children.iter_mut().enumerate() { + if overlay_opacity.is_some() || overlay_border.is_some() { + // the overlay has to be painted in origin+1px with size width-1px + // in order to accommodate the divider between panels + let overlay_bounds = Bounds { + origin: child + .bounds + .origin + .apply_along(Axis::Horizontal, |val| val + Pixels(1.)), + size: child + .bounds + .size + .apply_along(Axis::Horizontal, |val| val - Pixels(1.)), + }; + + if overlay_opacity.is_some() && self.active_pane_ix != Some(ix) { + cx.paint_quad(gpui::fill(overlay_bounds, overlay_background)); + } + + if let Some(border) = overlay_border { + if self.active_pane_ix == Some(ix) { + cx.paint_quad(gpui::quad( + overlay_bounds, + 0., + gpui::transparent_black(), + border, + cx.theme().colors().border_selected, + )); + } + } + } + if let Some(handle) = child.handle.as_mut() { let cursor_style = match self.axis { Axis::Vertical => CursorStyle::ResizeRow, diff --git a/crates/workspace/src/workspace_settings.rs b/crates/workspace/src/workspace_settings.rs index 52827c6941ae7d495b64ae9a9e7731ed2e3fbd0e..0d872425c1f487aa95e23e4675148f5964083ae7 100644 --- a/crates/workspace/src/workspace_settings.rs +++ b/crates/workspace/src/workspace_settings.rs @@ -7,7 +7,7 @@ use settings::{Settings, SettingsSources}; #[derive(Deserialize)] pub struct WorkspaceSettings { - pub active_pane_magnification: f32, + pub active_pane_modifiers: ActivePanelModifiers, pub pane_split_direction_horizontal: PaneSplitDirectionHorizontal, pub pane_split_direction_vertical: PaneSplitDirectionVertical, pub centered_layout: CenteredLayoutSettings, @@ -21,6 +21,30 @@ pub struct WorkspaceSettings { pub command_aliases: HashMap, } +#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct ActivePanelModifiers { + /// Scale by which to zoom the active pane. + /// When set to 1.0, the active pane has the same size as others, + /// but when set to a larger value, the active pane takes up more space. + /// + /// Default: `1.0` + pub magnification: Option, + /// Size of the border surrounding the active pane. + /// When set to 0, the active pane doesn't have any border. + /// The border is drawn inset. + /// + /// Default: `0.0` + pub border_size: Option, + /// Opacity of inactive panels. + /// When set to 1.0, the inactive panes have the same opacity as the active one. + /// If set to 0, the inactive panes content will not be visible at all. + /// Values are clamped to the [0.0, 1.0] range. + /// + /// Default: `1.0` + pub inactive_opacity: Option, +} + #[derive(Copy, Clone, Default, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum CloseWindowWhenNoItems { @@ -57,12 +81,8 @@ pub enum RestoreOnStartupBehavior { #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)] pub struct WorkspaceSettingsContent { - /// Scale by which to zoom the active pane. - /// When set to 1.0, the active pane has the same size as others, - /// but when set to a larger value, the active pane takes up more space. - /// - /// Default: `1.0` - pub active_pane_magnification: Option, + /// Active pane styling settings. + pub active_pane_modifiers: Option, // Direction to split horizontally. // // Default: "up" diff --git a/docs/src/configuring-zed.md b/docs/src/configuring-zed.md index 11c6fdc09d9faa6452c468c9080778286159ddc2..d123f2deac3c16626882b3ce4dc6e579d6ad3651 100644 --- a/docs/src/configuring-zed.md +++ b/docs/src/configuring-zed.md @@ -29,10 +29,26 @@ Extensions that provide language servers may also provide default settings for t # Settings -## Active Pane Magnification +## Active Pane Modifiers + +Styling settings applied to the active pane. + +### Magnification - Description: Scale by which to zoom the active pane. When set to `1.0`, the active pane has the same size as others, but when set to a larger value, the active pane takes up more space. -- Setting: `active_pane_magnification` +- Setting: `magnification` +- Default: `1.0` + +### Border size + +- Description: Size of the border surrounding the active pane. When set to 0, the active pane doesn't have any border. The border is drawn inset. +- Setting: `border_size` +- Default: `0.0` + +### Inactive Opacity + +- Description: Opacity of inactive panels. When set to 1.0, the inactive panes have the same opacity as the active one. If set to 0, the inactive panes content will not be visible at all. Values are clamped to the [0.0, 1.0] range. +- Setting: `inactive_opacity` - Default: `1.0` **Options**