title_bar: Add on_close_window method callback for TitleBar to custom close window method for Linux. (#387)

This commit is contained in:
Jason Lee 2024-11-01 17:06:31 +08:00 committed by GitHub
parent b997eabcba
commit 80230c643f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,3 +1,5 @@
use std::rc::Rc;
use crate::{h_flex, theme::ActiveTheme, Icon, IconName, InteractiveElementExt as _, Sizable as _}; use crate::{h_flex, theme::ActiveTheme, Icon, IconName, InteractiveElementExt as _, Sizable as _};
use gpui::{ use gpui::{
div, prelude::FluentBuilder as _, px, relative, AnyElement, Div, Element, Hsla, div, prelude::FluentBuilder as _, px, relative, AnyElement, Div, Element, Hsla,
@ -5,6 +7,12 @@ use gpui::{
StatefulInteractiveElement as _, Style, Styled, WindowContext, StatefulInteractiveElement as _, Style, Styled, WindowContext,
}; };
pub const TITLE_BAR_HEIGHT: Pixels = px(35.);
#[cfg(target_os = "macos")]
const TITLE_BAR_LEFT_PADDING: Pixels = px(80.);
#[cfg(not(target_os = "macos"))]
const TITLE_BAR_LEFT_PADDING: Pixels = px(12.);
/// TitleBar used to customize the appearance of the title bar. /// TitleBar used to customize the appearance of the title bar.
/// ///
/// We can put some elements inside the title bar. /// We can put some elements inside the title bar.
@ -12,35 +20,40 @@ use gpui::{
pub struct TitleBar { pub struct TitleBar {
base: Stateful<Div>, base: Stateful<Div>,
children: Vec<AnyElement>, children: Vec<AnyElement>,
on_close_window: Option<Rc<Box<dyn Fn(&mut WindowContext)>>>,
} }
pub const TITLE_BAR_HEIGHT: Pixels = px(35.);
impl TitleBar { impl TitleBar {
pub fn new() -> Self { pub fn new() -> Self {
// Leave more space for the macOS window controls.
#[cfg(target_os = "macos")]
let pl = px(80.);
#[cfg(not(target_os = "macos"))]
let pl = px(12.);
Self { Self {
base: div().id("title-bar").pl(pl), base: div().id("title-bar").pl(TITLE_BAR_LEFT_PADDING),
children: Vec::new(), children: Vec::new(),
on_close_window: None,
} }
} }
/// Add custom for close window event, default is None, then click X button will call `cx.remove_window()`.
/// Linux only, this will do nothing on other platforms.
pub fn on_close_window(mut self, f: impl Fn(&mut WindowContext) + 'static) -> Self {
if cfg!(target_os = "linux") {
self.on_close_window = Some(Rc::new(Box::new(f)));
}
self
}
} }
// The Windows control buttons have a fixed width of 35px. // The Windows control buttons have a fixed width of 35px.
// //
// We don't need implementation the click event for the control buttons. // We don't need implementation the click event for the control buttons.
// If user clicked in the bounds, the window event will be triggered. // If user clicked in the bounds, the window event will be triggered.
#[derive(IntoElement, Clone, Copy)] #[derive(IntoElement, Clone)]
enum ControlIcon { enum ControlIcon {
Minimize, Minimize,
Restore, Restore,
Maximize, Maximize,
Close, Close {
on_close_window: Option<Rc<Box<dyn Fn(&mut WindowContext)>>>,
},
} }
impl ControlIcon { impl ControlIcon {
@ -56,8 +69,8 @@ impl ControlIcon {
Self::Maximize Self::Maximize
} }
fn close() -> Self { fn close(on_close_window: Option<Rc<Box<dyn Fn(&mut WindowContext)>>>) -> Self {
Self::Close Self::Close { on_close_window }
} }
fn id(&self) -> &'static str { fn id(&self) -> &'static str {
@ -65,7 +78,7 @@ impl ControlIcon {
Self::Minimize => "minimize", Self::Minimize => "minimize",
Self::Restore => "restore", Self::Restore => "restore",
Self::Maximize => "maximize", Self::Maximize => "maximize",
Self::Close => "close", Self::Close { .. } => "close",
} }
} }
@ -74,12 +87,12 @@ impl ControlIcon {
Self::Minimize => IconName::WindowMinimize, Self::Minimize => IconName::WindowMinimize,
Self::Restore => IconName::WindowRestore, Self::Restore => IconName::WindowRestore,
Self::Maximize => IconName::WindowMaximize, Self::Maximize => IconName::WindowMaximize,
Self::Close => IconName::WindowClose, Self::Close { .. } => IconName::WindowClose,
} }
} }
fn is_close(&self) -> bool { fn is_close(&self) -> bool {
matches!(self, Self::Close) matches!(self, Self::Close { .. })
} }
fn fg(&self, cx: &WindowContext) -> Hsla { fn fg(&self, cx: &WindowContext) -> Hsla {
@ -118,8 +131,12 @@ impl RenderOnce for ControlIcon {
let fg = self.fg(cx); let fg = self.fg(cx);
let hover_fg = self.hover_fg(cx); let hover_fg = self.hover_fg(cx);
let hover_bg = self.hover_bg(cx); let hover_bg = self.hover_bg(cx);
let icon = self; let icon = self.clone();
let is_linux = cfg!(target_os = "linux"); let is_linux = cfg!(target_os = "linux");
let on_close_window = match &icon {
ControlIcon::Close { on_close_window } => on_close_window.clone(),
_ => None,
};
div() div()
.id(self.id()) .id(self.id())
@ -136,7 +153,13 @@ impl RenderOnce for ControlIcon {
Self::Minimize => cx.minimize_window(), Self::Minimize => cx.minimize_window(),
Self::Restore => cx.zoom_window(), Self::Restore => cx.zoom_window(),
Self::Maximize => cx.zoom_window(), Self::Maximize => cx.zoom_window(),
Self::Close => cx.remove_window(), Self::Close { .. } => {
if let Some(f) = on_close_window.clone() {
f(cx);
} else {
cx.remove_window();
}
}
}) })
}) })
.hover(|style| style.bg(hover_bg).text_color(hover_fg)) .hover(|style| style.bg(hover_bg).text_color(hover_fg))
@ -146,7 +169,9 @@ impl RenderOnce for ControlIcon {
} }
#[derive(IntoElement)] #[derive(IntoElement)]
struct WindowControls {} struct WindowControls {
on_close_window: Option<Rc<Box<dyn Fn(&mut WindowContext)>>>,
}
impl RenderOnce for WindowControls { impl RenderOnce for WindowControls {
fn render(self, cx: &mut WindowContext) -> impl IntoElement { fn render(self, cx: &mut WindowContext) -> impl IntoElement {
@ -171,7 +196,7 @@ impl RenderOnce for WindowControls {
ControlIcon::maximize() ControlIcon::maximize()
}), }),
) )
.child(ControlIcon::close()) .child(ControlIcon::close(self.on_close_window))
} }
} }
@ -215,7 +240,9 @@ impl RenderOnce for TitleBar {
.flex_1() .flex_1()
.children(self.children), .children(self.children),
) )
.child(WindowControls {}), .child(WindowControls {
on_close_window: self.on_close_window,
}),
) )
.when(is_linux, |this| { .when(is_linux, |this| {
this.child( this.child(