From ac987dc305f1a66751c188e3f8f243549bad836b Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Sat, 13 Jun 2026 16:06:52 +0700 Subject: [PATCH] fix titlebar --- Cargo.lock | 187 +++--------- crates/title_bar/Cargo.toml | 23 -- crates/title_bar/src/lib.rs | 172 ----------- crates/title_bar/src/platforms/linux.rs | 227 -------------- crates/title_bar/src/platforms/mac.rs | 6 - crates/title_bar/src/platforms/mod.rs | 4 - crates/title_bar/src/platforms/windows.rs | 147 --------- crates/ui/src/lib.rs | 2 + crates/ui/src/title_bar.rs | 352 ++++++++++++++++++++++ desktop/Cargo.toml | 1 - desktop/src/workspace.rs | 24 +- 11 files changed, 398 insertions(+), 747 deletions(-) delete mode 100644 crates/title_bar/Cargo.toml delete mode 100644 crates/title_bar/src/lib.rs delete mode 100644 crates/title_bar/src/platforms/linux.rs delete mode 100644 crates/title_bar/src/platforms/mac.rs delete mode 100644 crates/title_bar/src/platforms/mod.rs delete mode 100644 crates/title_bar/src/platforms/windows.rs create mode 100644 crates/ui/src/title_bar.rs diff --git a/Cargo.lock b/Cargo.lock index 08f173c..9b294fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,12 +128,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ahash" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0453232ace82dee0dd0b4c87a59bd90f7b53b314f3e0f61fe2ee7c8a16482289" - [[package]] name = "ahash" version = "0.8.12" @@ -886,9 +880,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" dependencies = [ "hybrid-array", ] @@ -1224,7 +1218,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" dependencies = [ - "block-buffer 0.12.0", + "block-buffer 0.12.1", "crypto-common 0.2.2", "inout 0.2.2", ] @@ -1369,7 +1363,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "gpui_util", "indexmap", @@ -1540,7 +1534,6 @@ dependencies = [ "smol", "state", "theme", - "title_bar", "tracing-subscriber", "ui", "webbrowser", @@ -1891,7 +1884,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "proc-macro2", "quote", @@ -1937,7 +1930,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ - "block-buffer 0.12.0", + "block-buffer 0.12.1", "crypto-common 0.2.2", "ctutils", ] @@ -2022,15 +2015,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "dlv-list" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68df3f2b690c1b86e65ef7830956aededf3cb0a16f898f79b9a6f421a7b6211b" -dependencies = [ - "rand 0.8.6", -] - [[package]] name = "document-features" version = "0.2.12" @@ -2286,15 +2270,6 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "file-locker" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ae8b5984a4863d8a32109a848d038bd6d914f20f010cc141375f7a183c41cf" -dependencies = [ - "nix 0.29.0", -] - [[package]] name = "filedescriptor" version = "0.8.3" @@ -2443,7 +2418,7 @@ checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" dependencies = [ "fontconfig-parser", "log", - "memmap2 0.9.10", + "memmap2", "slotmap", "tinyvec", "ttf-parser", @@ -2485,16 +2460,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "freedesktop_entry_parser" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db9c27b72f19a99a895f8ca89e2d26e4ef31013376e56fdafef697627306c3e4" -dependencies = [ - "nom 7.1.3", - "thiserror 1.0.69", -] - [[package]] name = "freetype-sys" version = "0.20.1" @@ -2865,7 +2830,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.2.2" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "accesskit", "anyhow", @@ -2947,7 +2912,7 @@ dependencies = [ [[package]] name = "gpui_linux" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "accesskit", "accesskit_unix", @@ -2998,7 +2963,7 @@ dependencies = [ [[package]] name = "gpui_macos" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "accesskit", "accesskit_macos", @@ -3043,7 +3008,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3054,7 +3019,7 @@ dependencies = [ [[package]] name = "gpui_platform" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "console_error_panic_hook", "gpui", @@ -3067,7 +3032,7 @@ dependencies = [ [[package]] name = "gpui_shared_string" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "schemars", "serde", @@ -3077,7 +3042,7 @@ dependencies = [ [[package]] name = "gpui_tokio" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "anyhow", "gpui", @@ -3088,7 +3053,7 @@ dependencies = [ [[package]] name = "gpui_util" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "anyhow", "log", @@ -3097,7 +3062,7 @@ dependencies = [ [[package]] name = "gpui_web" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "anyhow", "console_error_panic_hook", @@ -3121,7 +3086,7 @@ dependencies = [ [[package]] name = "gpui_wgpu" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "anyhow", "bytemuck", @@ -3150,7 +3115,7 @@ dependencies = [ [[package]] name = "gpui_windows" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "accesskit", "accesskit_windows", @@ -3233,15 +3198,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "hashbrown" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" -dependencies = [ - "ahash 0.4.8", -] - [[package]] name = "hashbrown" version = "0.14.5" @@ -3439,7 +3395,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "anyhow", "async-compression", @@ -3464,7 +3420,7 @@ dependencies = [ [[package]] name = "http_client_tls" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "rustls", "rustls-platform-verifier", @@ -4082,29 +4038,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4" -[[package]] -name = "linicon" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8c5653188a809616c97296180a0547a61dba205bcdcbdd261dbd022a25fd9" -dependencies = [ - "file-locker", - "freedesktop_entry_parser", - "linicon-theme", - "memmap2 0.5.10", - "thiserror 1.0.69", -] - -[[package]] -name = "linicon-theme" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4f8240c33bb08c5d8b8cdea87b683b05e61037aa76ff26bef40672cc6ecbb80" -dependencies = [ - "freedesktop_entry_parser", - "rust-ini", -] - [[package]] name = "link-section" version = "0.18.2" @@ -4322,7 +4255,7 @@ dependencies = [ [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "anyhow", "bindgen", @@ -4336,18 +4269,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" - -[[package]] -name = "memmap2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" -dependencies = [ - "libc", -] +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" [[package]] name = "memmap2" @@ -5100,16 +5024,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "ordered-multimap" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c672c7ad9ec066e428c00eb917124a06f08db19e2584de982cc34b1f4c12485" -dependencies = [ - "dlv-list", - "hashbrown 0.9.1", -] - [[package]] name = "ordered-stream" version = "0.2.0" @@ -5225,7 +5139,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "collections", "serde", @@ -6018,7 +5932,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "derive_refineable", ] @@ -6118,7 +6032,7 @@ dependencies = [ [[package]] name = "reqwest_client" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "anyhow", "bytes", @@ -6223,16 +6137,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "rust-ini" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63471c4aa97a1cf8332a5f97709a79a4234698de6a1f5087faf66f2dae810e22" -dependencies = [ - "cfg-if", - "ordered-multimap", -] - [[package]] name = "rustc-demangle" version = "0.1.27" @@ -6433,7 +6337,7 @@ dependencies = [ [[package]] name = "scheduler" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "async-task", "backtrace", @@ -6880,9 +6784,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.15.1" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "smol" @@ -7077,7 +6981,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "heapless 0.9.3", "log", @@ -7475,23 +7379,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" -[[package]] -name = "title_bar" -version = "1.0.0-beta5" -dependencies = [ - "anyhow", - "common", - "gpui", - "linicon", - "log", - "nostr-sdk", - "smallvec", - "smol", - "theme", - "ui", - "windows 0.61.3", -] - [[package]] name = "tokio" version = "1.52.3" @@ -8071,7 +7958,7 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "util" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "anyhow", "async-fs", @@ -8110,7 +7997,7 @@ dependencies = [ [[package]] name = "util_macros" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "perf", "quote", @@ -9595,7 +9482,7 @@ checksum = "8d66ca9352cbd4eecbbc40871d8a11b4ac8107cfc528a6e14d7c19c69d0e1ac9" dependencies = [ "as-raw-xcb-connection", "libc", - "memmap2 0.9.10", + "memmap2", "xkeysym", ] @@ -9859,7 +9746,7 @@ name = "zed-xim" version = "0.4.0-zed" source = "git+https://github.com/zed-industries/xim-rs.git?rev=16f35a2c881b815a2b6cdfd6687988e84f8447d8#16f35a2c881b815a2b6cdfd6687988e84f8447d8" dependencies = [ - "ahash 0.8.12", + "ahash", "hashbrown 0.14.5", "log", "x11rb", @@ -9970,7 +9857,7 @@ dependencies = [ [[package]] name = "zlog" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "anyhow", "chrono", @@ -9987,7 +9874,7 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "ztracing" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" dependencies = [ "tracing", "tracing-subscriber", @@ -9998,7 +9885,7 @@ dependencies = [ [[package]] name = "ztracing_macro" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#d989c7c5cdd057de2375a55bdc109ff61409801c" +source = "git+https://github.com/zed-industries/zed#83aa94370548b2b6bb7d8d0f4bc1ae4117c3ac7d" [[package]] name = "zune-core" diff --git a/crates/title_bar/Cargo.toml b/crates/title_bar/Cargo.toml deleted file mode 100644 index ee0cf1f..0000000 --- a/crates/title_bar/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "title_bar" -version.workspace = true -edition.workspace = true -publish.workspace = true - -[dependencies] -common = { path = "../common" } -theme = { path = "../theme" } -ui = { path = "../ui" } - -nostr-sdk.workspace = true -gpui.workspace = true -smol.workspace = true -smallvec.workspace = true -anyhow.workspace = true -log.workspace = true - -[target.'cfg(target_os = "windows")'.dependencies] -windows = { version = "0.61", features = ["Wdk_System_SystemServices"] } - -[target.'cfg(target_os = "linux")'.dependencies] -linicon = "2.3.0" diff --git a/crates/title_bar/src/lib.rs b/crates/title_bar/src/lib.rs deleted file mode 100644 index 426bd43..0000000 --- a/crates/title_bar/src/lib.rs +++ /dev/null @@ -1,172 +0,0 @@ -#[cfg(target_os = "linux")] -use gpui::MouseButton; -use gpui::prelude::FluentBuilder; -use gpui::{ - AnyElement, Context, Decorations, Hsla, InteractiveElement as _, IntoElement, ParentElement, - Pixels, Render, StatefulInteractiveElement as _, Styled, Window, WindowControlArea, px, -}; -use smallvec::{SmallVec, smallvec}; -use theme::{ActiveTheme, CLIENT_SIDE_DECORATION_ROUNDING, PlatformKind}; -use ui::h_flex; - -#[cfg(target_os = "linux")] -use crate::platforms::linux::LinuxWindowControls; -use crate::platforms::mac::TRAFFIC_LIGHT_PADDING; -use crate::platforms::windows::WindowsWindowControls; - -mod platforms; - -/// Titlebar -pub struct TitleBar { - /// Children elements of the title bar. - children: SmallVec<[AnyElement; 2]>, - - /// Whether the title bar is currently being moved. - should_move: bool, -} - -impl TitleBar { - pub fn new() -> Self { - Self { - children: smallvec![], - should_move: false, - } - } - - #[cfg(not(target_os = "windows"))] - pub fn height(&self, window: &mut Window) -> Pixels { - (1.75 * window.rem_size()).max(px(34.)) - } - - #[cfg(target_os = "windows")] - pub fn height(&self, _window: &mut Window) -> Pixels { - px(32.) - } - - pub fn titlebar_color(&self, window: &mut Window, cx: &mut Context) -> Hsla { - if cfg!(any(target_os = "linux", target_os = "freebsd")) { - if window.is_window_active() && !self.should_move { - cx.theme().title_bar - } else { - cx.theme().title_bar_inactive - } - } else { - cx.theme().title_bar - } - } - - pub fn set_children(&mut self, children: T) - where - T: IntoIterator, - { - self.children = children.into_iter().collect(); - } -} - -impl Default for TitleBar { - fn default() -> Self { - Self::new() - } -} - -impl Render for TitleBar { - fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { - let height = self.height(window); - let color = self.titlebar_color(window, cx); - let children = std::mem::take(&mut self.children); - - #[cfg(target_os = "linux")] - let supported_controls = window.window_controls(); - let decorations = window.window_decorations(); - - h_flex() - .window_control_area(WindowControlArea::Drag) - .h(height) - .w_full() - .map(|this| { - if window.is_fullscreen() { - this.px_2() - } else if cx.theme().platform.is_mac() { - this.pr_2().pl(px(TRAFFIC_LIGHT_PADDING)) - } else { - this.px_2() - } - }) - .map(|this| match decorations { - Decorations::Server => this, - Decorations::Client { tiling } => this - .when(!(tiling.top || tiling.right), |div| { - div.rounded_tr(CLIENT_SIDE_DECORATION_ROUNDING) - }) - .when(!(tiling.top || tiling.left), |div| { - div.rounded_tl(CLIENT_SIDE_DECORATION_ROUNDING) - }), - }) - .bg(color) - .border_b_1() - .border_color(cx.theme().border) - .content_stretch() - .child( - h_flex() - .id("title-bar") - .justify_between() - .w_full() - .when(cx.theme().platform.is_mac(), |this| { - this.on_click(|event, window, _| { - if event.click_count() == 2 { - window.titlebar_double_click(); - } - }) - }) - .when(cx.theme().platform.is_linux(), |this| { - this.on_click(|event, window, _| { - if event.click_count() == 2 { - window.zoom_window(); - } - }) - }) - .when(!cx.theme().platform.is_mac(), |this| this.pr_2()) - .children(children), - ) - .when(!window.is_fullscreen(), |this| match cx.theme().platform { - PlatformKind::Linux => { - #[cfg(target_os = "linux")] - if matches!(decorations, Decorations::Client { .. }) { - this.child(LinuxWindowControls::new(None)) - .when(supported_controls.window_menu, |this| { - this.on_mouse_down(MouseButton::Right, move |ev, window, _| { - window.show_window_menu(ev.position) - }) - }) - .on_mouse_move(cx.listener(move |this, _ev, window, _| { - if this.should_move { - this.should_move = false; - window.start_window_move(); - } - })) - .on_mouse_down_out(cx.listener(move |this, _ev, _window, _cx| { - this.should_move = false; - })) - .on_mouse_up( - MouseButton::Left, - cx.listener(move |this, _ev, _window, _cx| { - this.should_move = false; - }), - ) - .on_mouse_down( - MouseButton::Left, - cx.listener(move |this, _ev, _window, _cx| { - this.should_move = true; - }), - ) - } else { - this - } - #[cfg(not(target_os = "linux"))] - this - } - PlatformKind::Windows => this.child(WindowsWindowControls::new(height)), - PlatformKind::Mac => this, - }) - } -} diff --git a/crates/title_bar/src/platforms/linux.rs b/crates/title_bar/src/platforms/linux.rs deleted file mode 100644 index 1f9731d..0000000 --- a/crates/title_bar/src/platforms/linux.rs +++ /dev/null @@ -1,227 +0,0 @@ -use std::collections::HashMap; -use std::sync::OnceLock; - -use gpui::prelude::FluentBuilder; -use gpui::{ - svg, Action, App, InteractiveElement, IntoElement, MouseButton, ParentElement, RenderOnce, - SharedString, StatefulInteractiveElement, Styled, Window, -}; -use linicon::{lookup_icon, IconType}; -use theme::ActiveTheme; -use ui::{h_flex, Icon, IconName, Sizable}; - -#[derive(IntoElement)] -pub struct LinuxWindowControls { - close_window_action: Option>, -} - -impl LinuxWindowControls { - pub fn new(close_window_action: Option>) -> Self { - Self { - close_window_action, - } - } -} - -impl RenderOnce for LinuxWindowControls { - fn render(self, window: &mut Window, _cx: &mut App) -> impl IntoElement { - let supported_controls = window.window_controls(); - - h_flex() - .id("linux-window-controls") - .gap_2() - .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation()) - .when(supported_controls.minimize, |this| { - this.child(WindowControl::new( - LinuxControl::Minimize, - IconName::WindowMinimize, - )) - }) - .when(supported_controls.maximize, |this| { - this.child({ - if window.is_maximized() { - WindowControl::new(LinuxControl::Restore, IconName::WindowRestore) - } else { - WindowControl::new(LinuxControl::Maximize, IconName::WindowMaximize) - } - }) - }) - .child( - WindowControl::new(LinuxControl::Close, IconName::WindowClose) - .when_some(self.close_window_action, |this, close_action| { - this.close_action(close_action) - }), - ) - } -} - -#[derive(IntoElement)] -pub struct WindowControl { - kind: LinuxControl, - fallback: IconName, - close_action: Option>, -} - -impl WindowControl { - pub fn new(kind: LinuxControl, fallback: IconName) -> Self { - Self { - kind, - fallback, - close_action: None, - } - } - - pub fn close_action(mut self, action: Box) -> Self { - self.close_action = Some(action); - self - } - - pub fn is_gnome(&self) -> bool { - matches!(detect_desktop_environment(), DesktopEnvironment::Gnome) - } -} - -impl RenderOnce for WindowControl { - fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { - let is_gnome = self.is_gnome(); - - h_flex() - .id(self.kind.as_icon_name()) - .group("") - .justify_center() - .items_center() - .rounded_full() - .size_6() - .when(is_gnome, |this| { - this.bg(cx.theme().ghost_element_background_alt) - .hover(|this| this.bg(cx.theme().ghost_element_hover)) - .active(|this| this.bg(cx.theme().ghost_element_active)) - }) - .map(|this| { - if let Some(Some(path)) = linux_controls().get(&self.kind).cloned() { - this.child( - svg() - .external_path(SharedString::from(path)) - .size_4() - .text_color(cx.theme().text), - ) - } else { - this.child(Icon::new(self.fallback).small().text_color(cx.theme().text)) - } - }) - .on_mouse_move(|_, _window, cx| cx.stop_propagation()) - .on_click(move |_, window, cx| { - cx.stop_propagation(); - match self.kind { - LinuxControl::Minimize => window.minimize_window(), - LinuxControl::Restore => window.zoom_window(), - LinuxControl::Maximize => window.zoom_window(), - LinuxControl::Close => cx.quit(), - } - }) - } -} - -static DE: OnceLock = OnceLock::new(); -static LINUX_CONTROLS: OnceLock>> = OnceLock::new(); - -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum DesktopEnvironment { - Gnome, - Kde, - Unknown, -} - -/// Detect the current desktop environment -pub fn detect_desktop_environment() -> &'static DesktopEnvironment { - DE.get_or_init(|| { - // Try to use environment variables first - if let Ok(output) = std::env::var("XDG_CURRENT_DESKTOP") { - let desktop = output.to_lowercase(); - if desktop.contains("gnome") { - return DesktopEnvironment::Gnome; - } else if desktop.contains("kde") { - return DesktopEnvironment::Kde; - } - } - - // Fallback detection methods - if let Ok(output) = std::env::var("DESKTOP_SESSION") { - let session = output.to_lowercase(); - if session.contains("gnome") { - return DesktopEnvironment::Gnome; - } else if session.contains("kde") || session.contains("plasma") { - return DesktopEnvironment::Kde; - } - } - - DesktopEnvironment::Unknown - }) -} - -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] -pub enum LinuxControl { - Minimize, - Restore, - Maximize, - Close, -} - -impl LinuxControl { - pub fn as_icon_name(&self) -> &'static str { - match self { - LinuxControl::Close => "window-close", - LinuxControl::Minimize => "window-minimize", - LinuxControl::Maximize => "window-maximize", - LinuxControl::Restore => "window-restore", - } - } -} - -fn linux_controls() -> &'static HashMap> { - LINUX_CONTROLS.get_or_init(|| { - let mut icons = HashMap::new(); - icons.insert(LinuxControl::Close, None); - icons.insert(LinuxControl::Minimize, None); - icons.insert(LinuxControl::Maximize, None); - icons.insert(LinuxControl::Restore, None); - - let icon_names = [ - (LinuxControl::Close, vec!["window-close", "dialog-close"]), - ( - LinuxControl::Minimize, - vec!["window-minimize", "window-lower"], - ), - ( - LinuxControl::Maximize, - vec!["window-maximize", "window-expand"], - ), - ( - LinuxControl::Restore, - vec!["window-restore", "window-return"], - ), - ]; - - for (control, icon_names) in icon_names { - for icon_name in icon_names { - // Try GNOME-style naming first - let mut control_icon = lookup_icon(format!("{icon_name}-symbolic")) - .find(|icon| matches!(icon, Ok(icon) if icon.icon_type == IconType::SVG)); - - // If not found, try KDE-style naming - if control_icon.is_none() { - control_icon = lookup_icon(icon_name) - .find(|icon| matches!(icon, Ok(icon) if icon.icon_type == IconType::SVG)); - } - - if let Some(Ok(icon)) = control_icon { - icons - .entry(control) - .and_modify(|v| *v = Some(icon.path.to_string_lossy().to_string())); - } - } - } - - icons - }) -} diff --git a/crates/title_bar/src/platforms/mac.rs b/crates/title_bar/src/platforms/mac.rs deleted file mode 100644 index 526e245..0000000 --- a/crates/title_bar/src/platforms/mac.rs +++ /dev/null @@ -1,6 +0,0 @@ -/// Use pixels here instead of a rem-based size because the macOS traffic -/// lights are a static size, and don't scale with the rest of the UI. -/// -/// Magic number: There is one extra pixel of padding on the left side due to -/// the 1px border around the window on macOS apps. -pub const TRAFFIC_LIGHT_PADDING: f32 = 80.; diff --git a/crates/title_bar/src/platforms/mod.rs b/crates/title_bar/src/platforms/mod.rs deleted file mode 100644 index e0ff781..0000000 --- a/crates/title_bar/src/platforms/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg(target_os = "linux")] -pub mod linux; -pub mod mac; -pub mod windows; diff --git a/crates/title_bar/src/platforms/windows.rs b/crates/title_bar/src/platforms/windows.rs deleted file mode 100644 index f28180b..0000000 --- a/crates/title_bar/src/platforms/windows.rs +++ /dev/null @@ -1,147 +0,0 @@ -use gpui::prelude::FluentBuilder; -use gpui::{ - div, px, App, ElementId, Hsla, InteractiveElement, IntoElement, ParentElement, Pixels, - RenderOnce, Rgba, StatefulInteractiveElement, Styled, Window, WindowControlArea, -}; -use theme::ActiveTheme; -use ui::h_flex; - -#[derive(IntoElement)] -pub struct WindowsWindowControls { - button_height: Pixels, -} - -impl WindowsWindowControls { - pub fn new(button_height: Pixels) -> Self { - Self { button_height } - } - - #[cfg(not(target_os = "windows"))] - fn get_font() -> &'static str { - "Segoe Fluent Icons" - } - - #[cfg(target_os = "windows")] - fn get_font() -> &'static str { - use windows::Wdk::System::SystemServices::RtlGetVersion; - - let mut version = unsafe { std::mem::zeroed() }; - let status = unsafe { RtlGetVersion(&mut version) }; - - if status.is_ok() && version.dwBuildNumber >= 22000 { - "Segoe Fluent Icons" - } else { - "Segoe MDL2 Assets" - } - } -} - -impl RenderOnce for WindowsWindowControls { - fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement { - let close_button_hover_color = Rgba { - r: 232.0 / 255.0, - g: 17.0 / 255.0, - b: 32.0 / 255.0, - a: 1.0, - }; - - let button_hover_color = cx.theme().ghost_element_hover; - let button_active_color = cx.theme().ghost_element_active; - - div() - .id("windows-window-controls") - .font_family(Self::get_font()) - .flex() - .flex_row() - .justify_center() - .content_stretch() - .max_h(self.button_height) - .min_h(self.button_height) - .child(WindowsCaptionButton::new( - "minimize", - WindowsCaptionButtonIcon::Minimize, - button_hover_color, - button_active_color, - )) - .child(WindowsCaptionButton::new( - "maximize-or-restore", - if window.is_maximized() { - WindowsCaptionButtonIcon::Restore - } else { - WindowsCaptionButtonIcon::Maximize - }, - button_hover_color, - button_active_color, - )) - .child(WindowsCaptionButton::new( - "close", - WindowsCaptionButtonIcon::Close, - close_button_hover_color, - button_active_color, - )) - } -} - -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] -enum WindowsCaptionButtonIcon { - Minimize, - Restore, - Maximize, - Close, -} - -#[derive(IntoElement)] -struct WindowsCaptionButton { - id: ElementId, - icon: WindowsCaptionButtonIcon, - hover_background_color: Hsla, - active_background_color: Hsla, -} - -impl WindowsCaptionButton { - pub fn new( - id: impl Into, - icon: WindowsCaptionButtonIcon, - hover_background_color: impl Into, - active_background_color: impl Into, - ) -> Self { - Self { - id: id.into(), - icon, - hover_background_color: hover_background_color.into(), - active_background_color: active_background_color.into(), - } - } -} - -impl RenderOnce for WindowsCaptionButton { - fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement { - h_flex() - .id(self.id) - .justify_center() - .content_center() - .occlude() - .w(px(36.)) - .h_full() - .text_size(px(10.0)) - .hover(|style| style.bg(self.hover_background_color)) - .active(|style| style.bg(self.active_background_color)) - .map(|this| match self.icon { - WindowsCaptionButtonIcon::Close => { - this.window_control_area(WindowControlArea::Close) - } - WindowsCaptionButtonIcon::Maximize | WindowsCaptionButtonIcon::Restore => { - this.window_control_area(WindowControlArea::Max) - } - WindowsCaptionButtonIcon::Minimize => { - this.window_control_area(WindowControlArea::Min) - } - }) - .child(match self.icon { - WindowsCaptionButtonIcon::Minimize => "\u{e921}", - WindowsCaptionButtonIcon::Restore => "\u{e923}", - WindowsCaptionButtonIcon::Maximize => "\u{e922}", - WindowsCaptionButtonIcon::Close => "\u{e8bb}", - }) - } -} diff --git a/crates/ui/src/lib.rs b/crates/ui/src/lib.rs index 701a522..2cadb08 100644 --- a/crates/ui/src/lib.rs +++ b/crates/ui/src/lib.rs @@ -6,6 +6,7 @@ pub use index_path::IndexPath; pub use kbd::*; pub use root::{Root, window_paddings}; pub use styled::*; +pub use title_bar::*; pub use window_ext::*; pub use crate::Disableable; @@ -41,6 +42,7 @@ mod index_path; mod kbd; mod root; mod styled; +mod title_bar; mod window_ext; /// Initialize the UI module. diff --git a/crates/ui/src/title_bar.rs b/crates/ui/src/title_bar.rs new file mode 100644 index 0000000..79e60e0 --- /dev/null +++ b/crates/ui/src/title_bar.rs @@ -0,0 +1,352 @@ +use std::rc::Rc; + +use gpui::prelude::FluentBuilder as _; +use gpui::{ + AnyElement, App, ClickEvent, Context, Decorations, Hsla, InteractiveElement, IntoElement, + MouseButton, ParentElement, Pixels, Render, RenderOnce, StatefulInteractiveElement as _, + StyleRefinement, Styled, TitlebarOptions, Window, WindowControlArea, div, px, +}; +use smallvec::SmallVec; +use theme::ActiveTheme; + +use crate::{Icon, IconName, InteractiveElementExt as _, Sizable as _, StyledExt, h_flex}; + +pub const TITLE_BAR_HEIGHT: Pixels = px(34.); +#[cfg(target_os = "macos")] +pub const TRAFFIC_LIGHT_PADDING: f32 = 80.; + +/// TitleBar used to customize the appearance of the title bar. +/// +/// We can put some elements inside the title bar. +#[derive(IntoElement)] +#[allow(clippy::type_complexity)] +pub struct TitleBar { + style: StyleRefinement, + children: SmallVec<[AnyElement; 1]>, + on_close_window: Option>>, +} + +impl TitleBar { + /// Create a new TitleBar. + pub fn new() -> Self { + Self { + style: StyleRefinement::default(), + children: SmallVec::new(), + on_close_window: None, + } + } + + /// Returns the default title bar options for compatible with the [`crate::TitleBar`]. + pub fn title_bar_options() -> TitlebarOptions { + TitlebarOptions { + title: None, + appears_transparent: true, + traffic_light_position: Some(gpui::point(px(9.0), px(9.0))), + } + } + + /// Add custom for close window event, default is None, then click X button will call `window.remove_window()`. + /// Linux only, this will do nothing on other platforms. + pub fn on_close_window( + mut self, + f: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static, + ) -> Self { + if cfg!(target_os = "linux") { + self.on_close_window = Some(Rc::new(Box::new(f))); + } + self + } +} + +impl Default for TitleBar { + fn default() -> Self { + Self::new() + } +} + +// The Windows control buttons have a fixed width of 35px. +// +// We don't need implementation the click event for the control buttons. +// If user clicked in the bounds, the window event will be triggered. +#[derive(IntoElement, Clone)] +#[allow(clippy::type_complexity)] +enum ControlIcon { + Minimize, + Restore, + Maximize, + Close { + on_close_window: Option>>, + }, +} + +impl ControlIcon { + fn minimize() -> Self { + Self::Minimize + } + + fn restore() -> Self { + Self::Restore + } + + fn maximize() -> Self { + Self::Maximize + } + + #[allow(clippy::type_complexity)] + fn close(on_close_window: Option>>) -> Self { + Self::Close { on_close_window } + } + + fn id(&self) -> &'static str { + match self { + Self::Minimize => "minimize", + Self::Restore => "restore", + Self::Maximize => "maximize", + Self::Close { .. } => "close", + } + } + + fn icon(&self) -> IconName { + match self { + Self::Minimize => IconName::WindowMinimize, + Self::Restore => IconName::WindowRestore, + Self::Maximize => IconName::WindowMaximize, + Self::Close { .. } => IconName::WindowClose, + } + } + + fn window_control_area(&self) -> WindowControlArea { + match self { + Self::Minimize => WindowControlArea::Min, + Self::Restore | Self::Maximize => WindowControlArea::Max, + Self::Close { .. } => WindowControlArea::Close, + } + } + + fn is_close(&self) -> bool { + matches!(self, Self::Close { .. }) + } + + #[inline] + fn hover_fg(&self, cx: &App) -> Hsla { + if self.is_close() { + cx.theme().danger_foreground + } else { + cx.theme().text + } + } + + #[inline] + fn hover_bg(&self, cx: &App) -> Hsla { + if self.is_close() { + cx.theme().danger_background + } else { + cx.theme().ghost_element_hover + } + } + + #[inline] + fn active_bg(&self, cx: &mut App) -> Hsla { + if self.is_close() { + cx.theme().danger_active + } else { + cx.theme().ghost_element_active + } + } +} + +impl RenderOnce for ControlIcon { + fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement { + let is_linux = cfg!(target_os = "linux"); + let is_windows = cfg!(target_os = "windows"); + + let icon = self.clone(); + let hover_fg = self.hover_fg(cx); + let hover_bg = self.hover_bg(cx); + let active_bg = self.active_bg(cx); + + let on_close_window = match &self { + ControlIcon::Close { on_close_window } => on_close_window.clone(), + _ => None, + }; + + div() + .id(self.id()) + .flex() + .w(TITLE_BAR_HEIGHT) + .h_full() + .flex_shrink_0() + .justify_center() + .content_center() + .items_center() + .text_color(cx.theme().text) + .hover(|style| style.bg(hover_bg).text_color(hover_fg)) + .active(|style| style.bg(active_bg).text_color(hover_fg)) + .when(is_windows, |this| { + this.window_control_area(self.window_control_area()) + }) + .when(is_linux, |this| { + this.on_mouse_down(MouseButton::Left, move |_, window, cx| { + window.prevent_default(); + cx.stop_propagation(); + }) + .on_click(move |_, window, cx| { + cx.stop_propagation(); + match icon { + Self::Minimize => window.minimize_window(), + Self::Restore | Self::Maximize => window.zoom_window(), + Self::Close { .. } => { + if let Some(f) = on_close_window.clone() { + f(&ClickEvent::default(), window, cx); + } else { + window.remove_window(); + } + } + } + }) + }) + .child(Icon::new(self.icon()).small()) + } +} + +#[derive(IntoElement)] +#[allow(clippy::type_complexity)] +struct WindowControls { + on_close_window: Option>>, +} + +impl RenderOnce for WindowControls { + fn render(self, window: &mut Window, _: &mut App) -> impl IntoElement { + if cfg!(target_os = "macos") || cfg!(target_family = "wasm") { + return div().id("window-controls"); + } + + h_flex() + .id("window-controls") + .items_center() + .flex_shrink_0() + .h_full() + .child(ControlIcon::minimize()) + .child(if window.is_maximized() { + ControlIcon::restore() + } else { + ControlIcon::maximize() + }) + .child(ControlIcon::close(self.on_close_window)) + } +} + +impl Styled for TitleBar { + fn style(&mut self) -> &mut gpui::StyleRefinement { + &mut self.style + } +} + +impl ParentElement for TitleBar { + fn extend(&mut self, elements: impl IntoIterator) { + self.children.extend(elements); + } +} + +struct TitleBarState { + should_move: bool, +} + +impl Render for TitleBarState { + fn render(&mut self, _: &mut Window, _: &mut Context) -> impl IntoElement { + div() + } +} + +impl RenderOnce for TitleBar { + fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement { + let is_client_decorated = matches!(window.window_decorations(), Decorations::Client { .. }); + let is_web = cfg!(target_family = "wasm"); + let is_linux = cfg!(target_os = "linux"); + let is_macos = cfg!(target_os = "macos"); + + let state = window.use_state(cx, |_, _| TitleBarState { should_move: false }); + + div().flex_shrink_0().child( + div() + .id("title-bar") + .flex() + .flex_row() + .items_center() + .justify_between() + .h(TITLE_BAR_HEIGHT) + .map(|this| { + if window.is_fullscreen() { + this.px_2() + } else if cx.theme().platform.is_mac() { + this.pr_2().pl(px(TRAFFIC_LIGHT_PADDING)) + } else { + this.px_2() + } + }) + .border_b_1() + .border_color(cx.theme().border) + .bg(cx.theme().title_bar) + .refine_style(&self.style) + .when(is_linux, |this| { + this.on_double_click(|_, window, _| window.zoom_window()) + }) + .when(is_macos, |this| { + this.on_double_click(|_, window, _| window.titlebar_double_click()) + }) + .on_mouse_down_out(window.listener_for(&state, |state, _, _, _| { + state.should_move = false; + })) + .on_mouse_down( + MouseButton::Left, + window.listener_for(&state, |state, _, _, _| { + state.should_move = true; + }), + ) + .on_mouse_up( + MouseButton::Left, + window.listener_for(&state, |state, _, _, _| { + state.should_move = false; + }), + ) + .on_mouse_move(window.listener_for(&state, |state, _, window, _| { + if state.should_move { + state.should_move = false; + window.start_window_move(); + } + })) + .child( + h_flex() + .id("bar") + .h_full() + .justify_between() + .flex_shrink_0() + .flex_1() + .when(!is_web, |this| { + this.window_control_area(WindowControlArea::Drag) + .when(window.is_fullscreen(), |this| this.pl_3()) + .when(is_linux && is_client_decorated, |this| { + this.child( + div() + .top_0() + .left_0() + .absolute() + .size_full() + .h_full() + .on_mouse_down( + MouseButton::Right, + move |ev, window, _| { + window.show_window_menu(ev.position) + }, + ), + ) + }) + }) + .children(self.children), + ) + .child(WindowControls { + on_close_window: self.on_close_window, + }), + ) + } +} diff --git a/desktop/Cargo.toml b/desktop/Cargo.toml index db49431..5b1384c 100644 --- a/desktop/Cargo.toml +++ b/desktop/Cargo.toml @@ -29,7 +29,6 @@ icons = [ [dependencies] assets = { path = "../crates/assets" } ui = { path = "../crates/ui" } -title_bar = { path = "../crates/title_bar" } theme = { path = "../crates/theme" } common = { path = "../crates/common" } state = { path = "../crates/state" } diff --git a/desktop/src/workspace.rs b/desktop/src/workspace.rs index 6303190..d33eefa 100644 --- a/desktop/src/workspace.rs +++ b/desktop/src/workspace.rs @@ -16,13 +16,12 @@ use serde::Deserialize; use smallvec::{SmallVec, smallvec}; use state::{IMAGE_CACHE_SIZE, NostrRegistry, StateEvent}; use theme::{ActiveTheme, SIDEBAR_WIDTH, Theme, ThemeRegistry}; -use title_bar::TitleBar; use ui::avatar::Avatar; use ui::button::{Button, ButtonVariants}; use ui::dock::{ClosePanel, DockArea, DockItem, DockPlacement, PanelView}; use ui::menu::{DropdownMenu, PopupMenuItem}; use ui::notification::{Notification, NotificationKind}; -use ui::{Icon, IconName, Root, Sizable, WindowExtension, h_flex, v_flex}; +use ui::{Icon, IconName, Root, Sizable, TitleBar, WindowExtension, h_flex, v_flex}; use crate::dialogs::import::ImportIdentity; use crate::dialogs::restore::RestoreEncryption; @@ -58,9 +57,6 @@ enum Command { } pub struct Workspace { - /// App's Title Bar - titlebar: Entity, - /// App's Dock Area dock: Entity, @@ -78,7 +74,6 @@ impl Workspace { let nostr = NostrRegistry::global(cx); let signer = nostr.read(cx).signer.clone(); - let titlebar = cx.new(|_| TitleBar::new()); let dock = cx.new(|cx| DockArea::new(window, cx)); let image_cache = CoopImageCache::new(IMAGE_CACHE_SIZE, cx); @@ -259,7 +254,6 @@ impl Workspace { }); Self { - titlebar, dock, image_cache, _subscriptions: subscriptions, @@ -498,6 +492,7 @@ impl Workspace { window.open_modal(cx, move |this, _window, _cx| { this.width(px(420.)) .show_close(false) + .overlay_closable(false) .title("Import Identity") .child(import.clone()) }); @@ -845,15 +840,6 @@ impl Render for Workspace { let modal_layer = Root::render_modal_layer(window, cx); let notification_layer = Root::render_notification_layer(window, cx); - // Titlebar elements - let left = self.titlebar_left(cx).into_any_element(); - let right = self.titlebar_right(cx).into_any_element(); - - // Update title bar children - self.titlebar.update(cx, |this, _cx| { - this.set_children(vec![left, right]); - }); - div() .id(SharedString::from("workspace")) .on_action(cx.listener(Self::on_command)) @@ -867,7 +853,11 @@ impl Render for Workspace { v_flex() .size_full() // Title Bar - .child(self.titlebar.clone()) + .child( + TitleBar::new() + .child(self.titlebar_left(cx)) + .child(self.titlebar_right(cx)), + ) // Dock .child(self.dock.clone()), ),