1use gpui::{AnyElement, Interactivity, Stateful};
2use smallvec::SmallVec;
3
4use crate::components::title_bar::windows_window_controls::WindowsWindowControls;
5use crate::prelude::*;
6
7#[derive(IntoElement)]
8pub struct TitleBar {
9 platform_style: PlatformStyle,
10 content: Stateful<Div>,
11 children: SmallVec<[AnyElement; 2]>,
12}
13
14impl TitleBar {
15 pub fn height(cx: &mut WindowContext) -> Pixels {
16 (1.75 * cx.rem_size()).max(px(32.))
17 }
18
19 pub fn new(id: impl Into<ElementId>) -> Self {
20 Self {
21 platform_style: PlatformStyle::platform(),
22 content: div().id(id.into()),
23 children: SmallVec::new(),
24 }
25 }
26
27 /// Sets the platform style.
28 pub fn platform_style(mut self, style: PlatformStyle) -> Self {
29 self.platform_style = style;
30 self
31 }
32
33 fn top_padding(&self, cx: &WindowContext) -> Pixels {
34 if self.platform_style == PlatformStyle::Windows && cx.is_maximized() {
35 // todo(windows): get padding from win32 api, need HWND from window context somehow
36 // should be GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi) * 2
37 px(8.)
38 } else {
39 px(0.)
40 }
41 }
42}
43
44impl InteractiveElement for TitleBar {
45 fn interactivity(&mut self) -> &mut Interactivity {
46 self.content.interactivity()
47 }
48}
49
50impl StatefulInteractiveElement for TitleBar {}
51
52impl ParentElement for TitleBar {
53 fn extend(&mut self, elements: impl Iterator<Item = AnyElement>) {
54 self.children.extend(elements)
55 }
56}
57
58impl RenderOnce for TitleBar {
59 fn render(self, cx: &mut WindowContext) -> impl IntoElement {
60 let height = Self::height(cx);
61 let top_padding = self.top_padding(cx);
62
63 h_flex()
64 .id("titlebar")
65 .w_full()
66 .pt(top_padding)
67 .h(height)
68 .map(|this| {
69 if cx.is_fullscreen() {
70 this.pl_2()
71 } else if self.platform_style == PlatformStyle::Mac {
72 // Use pixels here instead of a rem-based size because the macOS traffic
73 // lights are a static size, and don't scale with the rest of the UI.
74 this.pl(px(80.))
75 } else {
76 this.pl_2()
77 }
78 })
79 .bg(cx.theme().colors().title_bar_background)
80 .content_stretch()
81 .child(
82 self.content
83 .id("titlebar-content")
84 .flex()
85 .flex_row()
86 .justify_between()
87 .w_full()
88 .children(self.children),
89 )
90 .when(self.platform_style == PlatformStyle::Windows, |title_bar| {
91 let button_height = Self::height(cx) - top_padding;
92
93 title_bar.child(WindowsWindowControls::new(button_height))
94 })
95 }
96}