diff --git a/assets/settings/default.json b/assets/settings/default.json index e34062dd5a..0f20e7d629 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -47,11 +47,20 @@ // 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, + // Centered layout related settings. + "centered_layout": { + // The relative width of the left padding of the central pane from the + // workspace when the centered layout is used. + "left_padding": 0.2, + // The relative width of the right padding of the central pane from the + // workspace when the centered layout is used. + "right_padding": 0.2 + }, // The key to use for adding multiple cursors // Currently "alt" or "cmd_or_ctrl" (also aliased as // "cmd" and "ctrl") are supported. "multi_cursor_modifier": "alt", - // Whether to enable vim modes and key bindings + // Whether to enable vim modes and key bindings. "vim_mode": false, // Whether to show the informational hover box when moving the mouse // over symbols in the editor. diff --git a/crates/workspace/src/persistence.rs b/crates/workspace/src/persistence.rs index 77cadc25c5..bdc29bddfd 100644 --- a/crates/workspace/src/persistence.rs +++ b/crates/workspace/src/persistence.rs @@ -138,6 +138,7 @@ define_connection! { // window_height: Option, // WindowBounds::Fixed RectF height // display: Option, // Display id // fullscreen: Option, // Is the window fullscreen? + // centered_layout: Option, // Is the Centered Layout mode activated? // ) // // pane_groups( @@ -280,6 +281,10 @@ define_connection! { sql!( ALTER TABLE workspaces ADD COLUMN fullscreen INTEGER; //bool ), + // Add centered_layout field to workspace + sql!( + ALTER TABLE workspaces ADD COLUMN centered_layout INTEGER; //bool + ), // Add preview field to items sql!( ALTER TABLE items ADD COLUMN preview INTEGER; //bool @@ -299,12 +304,13 @@ impl WorkspaceDb { // Note that we re-assign the workspace_id here in case it's empty // and we've grabbed the most recent workspace - let (workspace_id, workspace_location, bounds, display, fullscreen, docks): ( + let (workspace_id, workspace_location, bounds, display, fullscreen, centered_layout, docks): ( WorkspaceId, WorkspaceLocation, Option, Option, Option, + Option, DockStructure, ) = self .select_row_bound(sql! { @@ -318,6 +324,7 @@ impl WorkspaceDb { window_height, display, fullscreen, + centered_layout, left_dock_visible, left_dock_active_panel, left_dock_zoom, @@ -344,6 +351,7 @@ impl WorkspaceDb { .log_err()?, bounds: bounds.map(|bounds| bounds.0), fullscreen: fullscreen.unwrap_or(false), + centered_layout: centered_layout.unwrap_or(false), display, docks, }) @@ -678,6 +686,14 @@ impl WorkspaceDb { WHERE workspace_id = ?1 } } + + query! { + pub(crate) async fn set_centered_layout(workspace_id: WorkspaceId, centered_layout: bool) -> Result<()> { + UPDATE workspaces + SET centered_layout = ?2 + WHERE workspace_id = ?1 + } + } } #[cfg(test)] @@ -764,6 +780,7 @@ mod tests { display: Default::default(), docks: Default::default(), fullscreen: false, + centered_layout: false, }; let workspace_2 = SerializedWorkspace { @@ -774,6 +791,7 @@ mod tests { display: Default::default(), docks: Default::default(), fullscreen: false, + centered_layout: false, }; db.save_workspace(workspace_1.clone()).await; @@ -873,6 +891,7 @@ mod tests { display: Default::default(), docks: Default::default(), fullscreen: false, + centered_layout: false, }; db.save_workspace(workspace.clone()).await; @@ -902,6 +921,7 @@ mod tests { display: Default::default(), docks: Default::default(), fullscreen: false, + centered_layout: false, }; let mut workspace_2 = SerializedWorkspace { @@ -912,6 +932,7 @@ mod tests { display: Default::default(), docks: Default::default(), fullscreen: false, + centered_layout: false, }; db.save_workspace(workspace_1.clone()).await; @@ -949,6 +970,7 @@ mod tests { display: Default::default(), docks: Default::default(), fullscreen: false, + centered_layout: false, }; db.save_workspace(workspace_3.clone()).await; @@ -983,6 +1005,7 @@ mod tests { display: Default::default(), docks: Default::default(), fullscreen: false, + centered_layout: false, } } diff --git a/crates/workspace/src/persistence/model.rs b/crates/workspace/src/persistence/model.rs index 9dffa3c27e..b8f35447dc 100644 --- a/crates/workspace/src/persistence/model.rs +++ b/crates/workspace/src/persistence/model.rs @@ -71,6 +71,7 @@ pub(crate) struct SerializedWorkspace { pub(crate) center_group: SerializedPaneGroup, pub(crate) bounds: Option>, pub(crate) fullscreen: bool, + pub(crate) centered_layout: bool, pub(crate) display: Option, pub(crate) docks: DockStructure, } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 1f53f3230f..7053ba1384 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -26,7 +26,7 @@ use futures::{ Future, FutureExt, StreamExt, }; use gpui::{ - actions, canvas, impl_actions, point, size, Action, AnyElement, AnyView, AnyWeakView, + actions, canvas, impl_actions, point, relative, size, Action, AnyElement, AnyView, AnyWeakView, AppContext, AsyncAppContext, AsyncWindowContext, Bounds, DevicePixels, DragMoveEvent, Entity as _, EntityId, EventEmitter, FocusHandle, FocusableView, Global, KeyContext, Keystroke, LayoutId, ManagedView, Model, ModelContext, PathPromptOptions, Point, PromptLevel, Render, @@ -78,9 +78,9 @@ use theme::{ActiveTheme, SystemAppearance, ThemeSettings}; pub use toolbar::{Toolbar, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView}; pub use ui; use ui::{ - div, Context as _, Div, Element, ElementContext, FluentBuilder as _, InteractiveElement as _, - IntoElement, Label, ParentElement as _, Pixels, SharedString, Styled as _, ViewContext, - VisualContext as _, WindowContext, + div, h_flex, Context as _, Div, Element, ElementContext, FluentBuilder, + InteractiveElement as _, IntoElement, Label, ParentElement as _, Pixels, SharedString, + Styled as _, ViewContext, VisualContext as _, WindowContext, }; use util::ResultExt; use uuid::Uuid; @@ -133,6 +133,7 @@ actions!( ToggleLeftDock, ToggleRightDock, ToggleBottomDock, + ToggleCenteredLayout, CloseAllDocks, ] ); @@ -581,6 +582,7 @@ pub struct Workspace { _schedule_serialize: Option>, pane_history_timestamp: Arc, bounds: Bounds, + centered_layout: bool, bounds_save_task_queued: Option>, } @@ -600,6 +602,9 @@ struct FollowerState { } impl Workspace { + const DEFAULT_PADDING: f32 = 0.2; + const MAX_PADDING: f32 = 0.4; + pub fn new( workspace_id: WorkspaceId, project: Model, @@ -867,6 +872,7 @@ impl Workspace { workspace_actions: Default::default(), // This data will be incorrect, but it will be overwritten by the time it needs to be used. bounds: Default::default(), + centered_layout: false, bounds_save_task_queued: None, } } @@ -956,12 +962,19 @@ impl Workspace { let mut options = cx.update(|cx| (app_state.build_window_options)(display, cx))?; options.bounds = bounds; options.fullscreen = fullscreen; + let centered_layout = serialized_workspace + .as_ref() + .map(|w| w.centered_layout) + .unwrap_or(false); cx.open_window(options, { let app_state = app_state.clone(); let project_handle = project_handle.clone(); move |cx| { cx.new_view(|cx| { - Workspace::new(workspace_id, project_handle, app_state, cx) + let mut workspace = + Workspace::new(workspace_id, project_handle, app_state, cx); + workspace.centered_layout = centered_layout; + workspace }) } })? @@ -3541,6 +3554,7 @@ impl Workspace { display: Default::default(), docks, fullscreen: cx.is_fullscreen(), + centered_layout: self.centered_layout, }; return cx.spawn(|_| persistence::DB.save_workspace(serialized_workspace)); } @@ -3704,6 +3718,7 @@ impl Workspace { workspace.reopen_closed_item(cx).detach(); }), ) + .on_action(cx.listener(Workspace::toggle_centered_layout)) } #[cfg(any(test, feature = "test-support"))] @@ -3772,6 +3787,21 @@ impl Workspace { self.modal_layer .update(cx, |modal_layer, cx| modal_layer.toggle_modal(cx, build)) } + + pub fn toggle_centered_layout(&mut self, _: &ToggleCenteredLayout, cx: &mut ViewContext) { + self.centered_layout = !self.centered_layout; + cx.background_executor() + .spawn(DB.set_centered_layout(self.database_id, self.centered_layout)) + .detach_and_log_err(cx); + cx.notify(); + } + + fn adjust_padding(padding: Option) -> f32 { + padding + .unwrap_or(Self::DEFAULT_PADDING) + .min(Self::MAX_PADDING) + .max(0.0) + } } fn window_bounds_env_override() -> Option> { @@ -3916,7 +3946,27 @@ impl Render for Workspace { fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { let mut context = KeyContext::default(); context.add("Workspace"); - + let centered_layout = self.centered_layout + && self.center.panes().len() == 1 + && self.active_item(cx).is_some(); + let render_padding = |size| { + (size > 0.0).then(|| { + div() + .h_full() + .w(relative(size)) + .bg(cx.theme().colors().editor_background) + .border_color(cx.theme().colors().pane_group_border) + }) + }; + let paddings = if centered_layout { + let settings = WorkspaceSettings::get_global(cx).centered_layout; + ( + render_padding(Self::adjust_padding(settings.left_padding)), + render_padding(Self::adjust_padding(settings.right_padding)), + ) + } else { + (None, None) + }; let (ui_font, ui_font_size) = { let theme_settings = ThemeSettings::get_global(cx); ( @@ -4009,15 +4059,25 @@ impl Render for Workspace { .flex_col() .flex_1() .overflow_hidden() - .child(self.center.render( - &self.project, - &self.follower_states, - self.active_call(), - &self.active_pane, - self.zoomed.as_ref(), - &self.app_state, - cx, - )) + .child( + h_flex() + .h_full() + .when_some(paddings.0, |this, p| { + this.child(p.border_r_1()) + }) + .child(self.center.render( + &self.project, + &self.follower_states, + self.active_call(), + &self.active_pane, + self.zoomed.as_ref(), + &self.app_state, + cx, + )) + .when_some(paddings.1, |this, p| { + this.child(p.border_l_1()) + }), + ) .children( self.zoomed_position .ne(&Some(DockPosition::Bottom)) diff --git a/crates/workspace/src/workspace_settings.rs b/crates/workspace/src/workspace_settings.rs index dbc9c52bcd..0b7bc949f6 100644 --- a/crates/workspace/src/workspace_settings.rs +++ b/crates/workspace/src/workspace_settings.rs @@ -7,6 +7,7 @@ use settings::{Settings, SettingsSources}; #[derive(Deserialize)] pub struct WorkspaceSettings { pub active_pane_magnification: f32, + pub centered_layout: CenteredLayoutSettings, pub confirm_quit: bool, pub show_call_status_icon: bool, pub autosave: AutosaveSetting, @@ -31,6 +32,8 @@ pub struct WorkspaceSettingsContent { /// /// Default: `1.0` pub active_pane_magnification: Option, + // Centered layout related settings. + pub centered_layout: Option, /// Whether or not to prompt the user to confirm before closing the application. /// /// Default: false @@ -75,6 +78,21 @@ pub enum AutosaveSetting { OnWindowChange, } +#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct CenteredLayoutSettings { + /// The relative width of the left padding of the central pane from the + /// workspace when the centered layout is used. + /// + /// Default: 0.2 + pub left_padding: Option, + // The relative width of the right padding of the central pane from the + // workspace when the centered layout is used. + /// + /// Default: 0.2 + pub right_padding: Option, +} + impl Settings for WorkspaceSettings { const KEY: Option<&'static str> = None; diff --git a/docs/src/configuring_zed.md b/docs/src/configuring_zed.md index 8984db86e5..9df7ac3f5d 100644 --- a/docs/src/configuring_zed.md +++ b/docs/src/configuring_zed.md @@ -142,6 +142,24 @@ For example, to disable ligatures for a given font you can add the following to `boolean` values +## Centered Layout + +- Description: Configuration for the centered layout mode. +- Setting: `centered_layout` +- Default: + +```json +"centered_layout": { + "left_padding": 0.2, + "right_padding": 0.2, +} +``` + +**Options** + +The `left_padding` and `right_padding` options define the relative width of the +left and right padding of the central pane from the workspace when the centered layout mode is activated. Valid values range is from `0` to `0.45`. + ## Copilot - Description: Copilot-specific settings.