Cargo.lock 🔗
@@ -14404,6 +14404,7 @@ dependencies = [
"settings",
"strum 0.27.1",
"theme",
+ "title_bar",
"ui",
"ui_input",
"workspace",
localcc created
Cargo.lock | 1
crates/settings_ui/Cargo.toml | 1
crates/settings_ui/src/settings_ui.rs | 141 +++++++++++++++++-----------
3 files changed, 85 insertions(+), 58 deletions(-)
@@ -14404,6 +14404,7 @@ dependencies = [
"settings",
"strum 0.27.1",
"theme",
+ "title_bar",
"ui",
"ui_input",
"workspace",
@@ -39,6 +39,7 @@ workspace-hack.workspace = true
workspace.workspace = true
zed_actions.workspace = true
log.workspace = true
+title_bar.workspace = true
[dev-dependencies]
assets.workspace = true
@@ -29,6 +29,7 @@ use std::{
rc::Rc,
sync::{Arc, LazyLock, RwLock, atomic::AtomicBool},
};
+use title_bar::platform_title_bar::PlatformTitleBar;
use ui::{
ContextMenu, Divider, DividerColor, DropdownMenu, DropdownStyle, IconButtonShape, KeyBinding,
KeybindingHint, PopoverMenu, Switch, SwitchColor, Tooltip, TreeViewItem, WithScrollbar,
@@ -36,7 +37,7 @@ use ui::{
};
use ui_input::{NumberField, NumberFieldType};
use util::{ResultExt as _, paths::PathStyle, rel_path::RelPath};
-use workspace::{OpenOptions, OpenVisible, Workspace};
+use workspace::{OpenOptions, OpenVisible, Workspace, client_side_decorations};
use zed_actions::OpenSettingsEditor;
use crate::components::SettingsEditor;
@@ -515,6 +516,7 @@ pub fn open_settings_editor(
}),
focus: true,
show: true,
+ is_movable: true,
kind: gpui::WindowKind::Floating,
window_background: cx.theme().window_background_appearance(),
window_min_size: Some(size(px(900.), px(750.))), // 4:3 Aspect Ratio
@@ -548,6 +550,7 @@ fn sub_page_stack_mut() -> std::sync::RwLockWriteGuard<'static, Vec<SubPage>> {
}
pub struct SettingsWindow {
+ title_bar: Option<Entity<PlatformTitleBar>>,
original_window: Option<WindowHandle<Workspace>>,
files: Vec<(SettingsUiFile, FocusHandle)>,
worktree_root_dirs: HashMap<WorktreeId, String>,
@@ -915,7 +918,14 @@ impl SettingsWindow {
})
.detach();
+ let title_bar = if !cfg!(target_os = "macos") {
+ Some(cx.new(|cx| PlatformTitleBar::new("settings-title-bar", cx)))
+ } else {
+ None
+ };
+
let mut this = Self {
+ title_bar,
original_window,
worktree_root_dirs: HashMap::default(),
files: vec![],
@@ -1427,7 +1437,8 @@ impl SettingsWindow {
v_flex()
.w_64()
.p_2p5()
- .pt_10()
+ .when(cfg!(target_os = "macos"), |c| c.pt_10())
+ .h_full()
.flex_none()
.border_r_1()
.key_context("NavigationMenu")
@@ -1508,7 +1519,8 @@ impl SettingsWindow {
.child(self.render_search(window, cx))
.child(
v_flex()
- .flex_grow()
+ .flex_1()
+ .overflow_hidden()
.track_focus(&self.navbar_focus_handle.focus_handle(cx))
.tab_group()
.tab_index(NAVBAR_GROUP_TAB_INDEX)
@@ -1558,9 +1570,10 @@ impl SettingsWindow {
.child(
h_flex()
.w_full()
+ .h_8()
.p_2()
.pb_0p5()
- .flex_none()
+ .flex_shrink_0()
.border_t_1()
.border_color(cx.theme().colors().border_variant)
.children(
@@ -2024,60 +2037,71 @@ impl Render for SettingsWindow {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let ui_font = theme::setup_ui_font(window, cx);
- div()
- .id("settings-window")
- .key_context("SettingsWindow")
- .track_focus(&self.focus_handle)
- .on_action(cx.listener(|this, _: &OpenCurrentFile, _, cx| {
- this.open_current_settings_file(cx);
- }))
- .on_action(|_: &Minimize, window, _cx| {
- window.minimize_window();
- })
- .on_action(cx.listener(|this, _: &search::FocusSearch, window, cx| {
- this.search_bar.focus_handle(cx).focus(window);
- }))
- .on_action(cx.listener(|this, _: &ToggleFocusNav, window, cx| {
- if this
- .navbar_focus_handle
- .focus_handle(cx)
- .contains_focused(window, cx)
- {
- this.open_and_scroll_to_navbar_entry(this.navbar_entry, window, cx);
- } else {
- this.focus_and_scroll_to_nav_entry(this.navbar_entry, window, cx);
- }
- }))
- .on_action(
- cx.listener(|this, FocusFile(file_index): &FocusFile, window, _| {
- this.focus_file_at_index(*file_index as usize, window);
- }),
- )
- .on_action(cx.listener(|this, _: &FocusNextFile, window, cx| {
- let next_index = usize::min(
- this.focused_file_index(window, cx) + 1,
- this.files.len().saturating_sub(1),
- );
- this.focus_file_at_index(next_index, window);
- }))
- .on_action(cx.listener(|this, _: &FocusPreviousFile, window, cx| {
- let prev_index = this.focused_file_index(window, cx).saturating_sub(1);
- this.focus_file_at_index(prev_index, window);
- }))
- .on_action(|_: &menu::SelectNext, window, _| {
- window.focus_next();
- })
- .on_action(|_: &menu::SelectPrevious, window, _| {
- window.focus_prev();
- })
- .flex()
- .flex_row()
- .size_full()
- .font(ui_font)
- .bg(cx.theme().colors().background)
- .text_color(cx.theme().colors().text)
- .child(self.render_nav(window, cx))
- .child(self.render_page(window, cx))
+ client_side_decorations(
+ v_flex()
+ .text_color(cx.theme().colors().text)
+ .size_full()
+ .children(self.title_bar.clone())
+ .child(
+ div()
+ .id("settings-window")
+ .key_context("SettingsWindow")
+ .track_focus(&self.focus_handle)
+ .on_action(cx.listener(|this, _: &OpenCurrentFile, _, cx| {
+ this.open_current_settings_file(cx);
+ }))
+ .on_action(|_: &Minimize, window, _cx| {
+ window.minimize_window();
+ })
+ .on_action(cx.listener(|this, _: &search::FocusSearch, window, cx| {
+ this.search_bar.focus_handle(cx).focus(window);
+ }))
+ .on_action(cx.listener(|this, _: &ToggleFocusNav, window, cx| {
+ if this
+ .navbar_focus_handle
+ .focus_handle(cx)
+ .contains_focused(window, cx)
+ {
+ this.open_and_scroll_to_navbar_entry(this.navbar_entry, window, cx);
+ } else {
+ this.focus_and_scroll_to_nav_entry(this.navbar_entry, window, cx);
+ }
+ }))
+ .on_action(cx.listener(
+ |this, FocusFile(file_index): &FocusFile, window, _| {
+ this.focus_file_at_index(*file_index as usize, window);
+ },
+ ))
+ .on_action(cx.listener(|this, _: &FocusNextFile, window, cx| {
+ let next_index = usize::min(
+ this.focused_file_index(window, cx) + 1,
+ this.files.len().saturating_sub(1),
+ );
+ this.focus_file_at_index(next_index, window);
+ }))
+ .on_action(cx.listener(|this, _: &FocusPreviousFile, window, cx| {
+ let prev_index = this.focused_file_index(window, cx).saturating_sub(1);
+ this.focus_file_at_index(prev_index, window);
+ }))
+ .on_action(|_: &menu::SelectNext, window, _| {
+ window.focus_next();
+ })
+ .on_action(|_: &menu::SelectPrevious, window, _| {
+ window.focus_prev();
+ })
+ .flex()
+ .flex_row()
+ .flex_1()
+ .min_h_0()
+ .font(ui_font)
+ .bg(cx.theme().colors().background)
+ .text_color(cx.theme().colors().text)
+ .child(self.render_nav(window, cx))
+ .child(self.render_page(window, cx)),
+ ),
+ window,
+ cx,
+ )
}
}
@@ -2485,6 +2509,7 @@ mod test {
}
let mut settings_window = SettingsWindow {
+ title_bar: None,
original_window: None,
worktree_root_dirs: HashMap::default(),
files: Vec::default(),