diff --git a/locales/en.yml b/locales/en.yml index c343a76..5bffb87 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -154,3 +154,7 @@ settings_split_pane_up: "Split Pane Up" settings_split_pane_down: "Split Pane Down" settings_close_pane: "Close Pane" keybind_conflict: '"%{key}" is already used by "%{action}", please choose another key' +title_bar_style: "Title Bar Style" +title_bar_native: "Native" +title_bar_integrated: "Integrated" +restart_hint: " (Restart required)" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 665e86d..e151ea8 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -156,3 +156,7 @@ settings_split_pane_up: "向上拆分面板" settings_split_pane_down: "向下拆分面板" settings_close_pane: "关闭当前面板" keybind_conflict: '"%{key}" 已被「%{action}」使用,请选择其他快捷键' +title_bar_style: "标题栏样式" +title_bar_native: "原生" +title_bar_integrated: "融合" +restart_hint: " (修改后重启生效)" diff --git a/src/app/dialogs.rs b/src/app/dialogs.rs index 48e446a..0ad8ebf 100644 --- a/src/app/dialogs.rs +++ b/src/app/dialogs.rs @@ -1297,6 +1297,50 @@ impl Ashell { }) ) ) + .item( + SettingItem::new( + format!("{}{}", t!("title_bar_style"), t!("restart_hint")), + SettingField::render({ + let view = view_clone_for_general.clone(); + move |_, _window, cx| { + let current_style = view.read(cx).config.title_bar_style(); + Button::new("title-bar-style-dropdown") + .small() + .label(match current_style { + crate::session::config::TitleBarStyle::Native => t!("title_bar_native").to_string(), + crate::session::config::TitleBarStyle::Integrated => t!("title_bar_integrated").to_string(), + }) + .dropdown_menu_with_anchor(Anchor::BottomRight, { + let view = view.clone(); + move |mut menu, window, cx| { + let current_style = view.read(cx).config.title_bar_style(); + menu = menu.min_w(160.) + .item( + PopupMenuItem::new(t!("title_bar_native").to_string()) + .checked(current_style == crate::session::config::TitleBarStyle::Native) + .on_click(window.listener_for(&view, |this, _, _, cx| { + this.config.set_title_bar_style(crate::session::config::TitleBarStyle::Native); + let _ = this.config.save(); + cx.notify(); + })) + ) + .item( + PopupMenuItem::new(t!("title_bar_integrated").to_string()) + .checked(current_style == crate::session::config::TitleBarStyle::Integrated) + .on_click(window.listener_for(&view, |this, _, _, cx| { + this.config.set_title_bar_style(crate::session::config::TitleBarStyle::Integrated); + let _ = this.config.save(); + cx.notify(); + })) + ); + menu + } + }) + .into_any_element() + } + }) + ) + ) ) .group( SettingGroup::new() diff --git a/src/app/mod.rs b/src/app/mod.rs index b5c979e..5894a41 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -258,6 +258,7 @@ pub(crate) struct Ashell { pub(crate) prev_monitoring_size: Option, pub(crate) status: SharedString, pub(crate) config: ConfigStore, + pub(crate) active_title_bar_style: crate::session::config::TitleBarStyle, pub(crate) system_sampler: SystemSampler, pub(crate) recording_action: Option, pub(crate) active_dialog: Option, @@ -482,6 +483,7 @@ impl Ashell { collapsed_saved_scroll_handle: gpui::ScrollHandle::new(), prev_monitoring_size: None, status: "ready".into(), + active_title_bar_style: config.title_bar_style(), config, system_sampler, recording_action: None, diff --git a/src/app/startup.rs b/src/app/startup.rs index 0cbffeb..07a11da 100644 --- a/src/app/startup.rs +++ b/src/app/startup.rs @@ -176,21 +176,23 @@ pub(crate) fn sync_macos_launch_environment() { pub(crate) fn sync_macos_launch_environment() {} pub(crate) fn open_main_window(cx: &mut App) { - let mut window_options = WindowOptions { - titlebar: Some(gpui::TitlebarOptions { + let config = ConfigStore::load().unwrap_or_else(|_| ConfigStore::in_memory()); + + let mut window_options = WindowOptions::default(); + + if config.title_bar_style() == crate::session::config::TitleBarStyle::Integrated { + window_options.titlebar = Some(gpui::TitlebarOptions { title: None, appears_transparent: true, traffic_light_position: Some(gpui::point(px(9.0), px(9.0))), - }), - ..Default::default() - }; + }); + } #[cfg(not(target_os = "macos"))] if let Ok(img) = image::load_from_memory(include_bytes!("../../assets/icons/ashell.png")) { window_options.icon = Some(std::sync::Arc::new(img.into_rgba8())); } - let config = ConfigStore::load().unwrap_or_else(|_| ConfigStore::in_memory()); if let Some(bounds) = config.window_bounds() { window_options.window_bounds = Some(match bounds { crate::session::config::SavedWindowBounds::Fullscreen { diff --git a/src/app/ui.rs b/src/app/ui.rs index 8a0ac3c..bdfac5e 100644 --- a/src/app/ui.rs +++ b/src/app/ui.rs @@ -2464,6 +2464,21 @@ impl Render for Ashell { .size_full() .relative() .overflow_hidden() + .when( + self.active_title_bar_style == crate::session::config::TitleBarStyle::Native, + |this| { + this.child( + div() + .flex_none() + .h(px(32.)) + .w_full() + .bg(cx.theme().tab_bar) + .border_b_1() + .border_color(cx.theme().border) + .child(self.render_tab_bar(cx)), + ) + }, + ) .child(body_panel), ), ) @@ -2484,6 +2499,21 @@ impl Render for Ashell { .size_full() .relative() .overflow_hidden() + .when( + self.active_title_bar_style == crate::session::config::TitleBarStyle::Native, + |this| { + this.child( + div() + .flex_none() + .h(px(32.)) + .w_full() + .bg(cx.theme().tab_bar) + .border_b_1() + .border_color(cx.theme().border) + .child(self.render_tab_bar(cx)), + ) + }, + ) .child(body_panel), ); @@ -2526,30 +2556,32 @@ impl Render for Ashell { this.close_tab(active_id, cx); } })) - .child( - div() - .id("title-bar") - .flex() - .items_center() - .h(px(34.)) - .w_full() - .bg(cx.theme().tab_bar) - .on_double_click(|_, window, _| { - #[cfg(target_os = "macos")] - window.titlebar_double_click(); - #[cfg(not(target_os = "macos"))] - window.zoom_window(); - }) - .child(self.render_window_controls(window, cx)) - .child( - div() - .flex_1() - .min_w(px(0.)) - .h_full() - .window_control_area(WindowControlArea::Drag) - .child(self.render_tab_bar(cx)), - ), - ) + .when(self.active_title_bar_style == crate::session::config::TitleBarStyle::Integrated, |this| { + this.child( + div() + .id("title-bar") + .flex() + .items_center() + .h(px(34.)) + .w_full() + .bg(cx.theme().tab_bar) + .on_double_click(|_, window, _| { + #[cfg(target_os = "macos")] + window.titlebar_double_click(); + #[cfg(not(target_os = "macos"))] + window.zoom_window(); + }) + .child(self.render_window_controls(window, cx)) + .child( + div() + .flex_1() + .min_w(px(0.)) + .h_full() + .window_control_area(WindowControlArea::Drag) + .child(self.render_tab_bar(cx)), + ), + ) + }) .child( div().flex_1().min_h_0().child(workspace), ) diff --git a/src/session/config.rs b/src/session/config.rs index 167020c..9fcfa44 100644 --- a/src/session/config.rs +++ b/src/session/config.rs @@ -98,6 +98,14 @@ pub enum SavedWindowBounds { }, } +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)] +#[serde(rename_all = "lowercase")] +pub enum TitleBarStyle { + #[default] + Native, + Integrated, +} + #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct ConfigFile { #[serde(default = "default_follow_system_theme")] @@ -121,6 +129,8 @@ pub struct ConfigFile { #[serde(default = "default_terminal_font_family")] pub terminal_font_family: String, #[serde(default)] + pub title_bar_style: TitleBarStyle, + #[serde(default)] pub sessions: Vec, #[serde(default)] pub window_bounds: Option, @@ -406,6 +416,14 @@ impl ConfigStore { self.cache.terminal_font_family = family.to_string(); } + pub fn title_bar_style(&self) -> TitleBarStyle { + self.cache.title_bar_style + } + + pub fn set_title_bar_style(&mut self, style: TitleBarStyle) { + self.cache.title_bar_style = style; + } + pub fn show_hidden_files(&self) -> bool { self.cache.show_hidden_files }