mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 02:17:35 +03:00
windows: Fix title bar height when maximized (#9449)
screenshots and description incoming ## title bar when window is maximized | before | after | | --- | --- | | ![image](https://github.com/zed-industries/zed/assets/1284289/075a943d-54db-4b71-9fa0-15f823255182) | ![image](https://github.com/zed-industries/zed/assets/1284289/39a1d381-fcfd-4651-aab4-231a8ec3bd99) | ## ~~caption buttons at 200%~~ ~~buttons are now properly responsive at different scales~~ ~~closes #9438~~ ~~proper scale factor handling in follow up PR (possibly #9440)~~ <details> <summary>out of date image</summary> ![scale-factor](https://github.com/zed-industries/zed/assets/1284289/299d37b8-0d2e-4f2e-81db-2fff6fc59a62) </details> should be fixed by https://github.com/zed-industries/zed/pull/9456 Release Notes: - N/A
This commit is contained in:
parent
3dadfe4787
commit
d5e0817fbc
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -10626,6 +10626,7 @@ dependencies = [
|
||||
"story",
|
||||
"strum",
|
||||
"theme",
|
||||
"windows 0.53.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -134,33 +134,37 @@ impl WindowsWindowInner {
|
||||
return false;
|
||||
}
|
||||
|
||||
fn get_titlebar_rect(&self) -> anyhow::Result<RECT> {
|
||||
let top_and_bottom_borders = 2;
|
||||
let scale_factor = self.scale_factor.get();
|
||||
let theme = unsafe { OpenThemeData(self.hwnd, w!("WINDOW")) };
|
||||
let title_bar_size = unsafe {
|
||||
GetThemePartSize(
|
||||
theme,
|
||||
HDC::default(),
|
||||
WP_CAPTION.0,
|
||||
CS_ACTIVE.0,
|
||||
None,
|
||||
TS_TRUE,
|
||||
)
|
||||
}?;
|
||||
unsafe { CloseThemeData(theme) }?;
|
||||
|
||||
let mut height =
|
||||
(title_bar_size.cy as f32 * scale_factor).round() as i32 + top_and_bottom_borders;
|
||||
pub(crate) fn title_bar_padding(&self) -> Pixels {
|
||||
// using USER_DEFAULT_SCREEN_DPI because GPUI handles the scale with the scale factor
|
||||
let padding = unsafe { GetSystemMetricsForDpi(SM_CXPADDEDBORDER, USER_DEFAULT_SCREEN_DPI) };
|
||||
px(padding as f32)
|
||||
}
|
||||
|
||||
pub(crate) fn title_bar_top_offset(&self) -> Pixels {
|
||||
if self.is_maximized() {
|
||||
let dpi = unsafe { GetDpiForWindow(self.hwnd) };
|
||||
height += unsafe { (GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi) * 2) as i32 };
|
||||
self.title_bar_padding() * 2
|
||||
} else {
|
||||
px(0.)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn title_bar_height(&self) -> Pixels {
|
||||
// todo(windows) this is hard set to match the ui title bar
|
||||
// in the future the ui title bar component will report the size
|
||||
px(32.) + self.title_bar_top_offset()
|
||||
}
|
||||
|
||||
pub(crate) fn caption_button_width(&self) -> Pixels {
|
||||
// todo(windows) this is hard set to match the ui title bar
|
||||
// in the future the ui title bar component will report the size
|
||||
px(36.)
|
||||
}
|
||||
|
||||
fn get_titlebar_rect(&self) -> anyhow::Result<RECT> {
|
||||
let height = self.title_bar_height();
|
||||
let mut rect = RECT::default();
|
||||
unsafe { GetClientRect(self.hwnd, &mut rect) }?;
|
||||
rect.bottom = rect.top + height;
|
||||
rect.bottom = rect.top + ((height.0 as f32 * self.scale_factor.get()).round() as i32);
|
||||
Ok(rect)
|
||||
}
|
||||
|
||||
@ -923,7 +927,8 @@ impl WindowsWindowInner {
|
||||
let titlebar_rect = self.get_titlebar_rect();
|
||||
if let Ok(titlebar_rect) = titlebar_rect {
|
||||
if cursor_point.y < titlebar_rect.bottom {
|
||||
let caption_btn_width = unsafe { GetSystemMetricsForDpi(SM_CXSIZE, dpi) };
|
||||
let caption_btn_width =
|
||||
(self.caption_button_width().0 * self.scale_factor.get()) as i32;
|
||||
if cursor_point.x >= titlebar_rect.right - caption_btn_width {
|
||||
return LRESULT(HTCLOSE as _);
|
||||
} else if cursor_point.x >= titlebar_rect.right - caption_btn_width * 2 {
|
||||
|
@ -23,6 +23,9 @@ story = { workspace = true, optional = true }
|
||||
strum = { version = "0.25.0", features = ["derive"] }
|
||||
theme.workspace = true
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows.workspace = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
stories = ["dep:itertools", "dep:story"]
|
||||
|
@ -10,12 +10,40 @@ pub struct TitleBar {
|
||||
content: Stateful<Div>,
|
||||
children: SmallVec<[AnyElement; 2]>,
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn title_bar_top_padding(_cx: &WindowContext) -> Pixels {
|
||||
px(0.)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn title_bar_top_padding(cx: &WindowContext) -> Pixels {
|
||||
use windows::Win32::UI::{
|
||||
HiDpi::GetSystemMetricsForDpi,
|
||||
WindowsAndMessaging::{SM_CXPADDEDBORDER, USER_DEFAULT_SCREEN_DPI},
|
||||
};
|
||||
|
||||
// this top padding is not dependent on the title bar style and is instead a quirk of maximized windows on Windows
|
||||
// https://devblogs.microsoft.com/oldnewthing/20150304-00/?p=44543
|
||||
let padding = unsafe { GetSystemMetricsForDpi(SM_CXPADDEDBORDER, USER_DEFAULT_SCREEN_DPI) };
|
||||
if cx.is_maximized() {
|
||||
px((padding * 2) as f32)
|
||||
} else {
|
||||
px(0.)
|
||||
}
|
||||
}
|
||||
|
||||
impl TitleBar {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn height(cx: &mut WindowContext) -> Pixels {
|
||||
(1.75 * cx.rem_size()).max(px(32.))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn height(_cx: &mut WindowContext) -> Pixels {
|
||||
// todo(windows) instead of hard coded size report the actual size to the Windows platform API
|
||||
px(32.)
|
||||
}
|
||||
|
||||
pub fn new(id: impl Into<ElementId>) -> Self {
|
||||
Self {
|
||||
platform_style: PlatformStyle::platform(),
|
||||
@ -29,16 +57,6 @@ impl TitleBar {
|
||||
self.platform_style = style;
|
||||
self
|
||||
}
|
||||
|
||||
fn top_padding(&self, cx: &WindowContext) -> Pixels {
|
||||
if self.platform_style == PlatformStyle::Windows && cx.is_maximized() {
|
||||
// todo(windows): get padding from win32 api, need HWND from window context somehow
|
||||
// should be GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi) * 2
|
||||
px(8.)
|
||||
} else {
|
||||
px(0.)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InteractiveElement for TitleBar {
|
||||
@ -58,13 +76,11 @@ impl ParentElement for TitleBar {
|
||||
impl RenderOnce for TitleBar {
|
||||
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
||||
let height = Self::height(cx);
|
||||
let top_padding = self.top_padding(cx);
|
||||
|
||||
h_flex()
|
||||
.id("titlebar")
|
||||
.w_full()
|
||||
.pt(top_padding)
|
||||
.h(height)
|
||||
.pt(title_bar_top_padding(cx))
|
||||
.h(height + title_bar_top_padding(cx))
|
||||
.map(|this| {
|
||||
if cx.is_fullscreen() {
|
||||
this.pl_2()
|
||||
@ -88,9 +104,7 @@ impl RenderOnce for TitleBar {
|
||||
.children(self.children),
|
||||
)
|
||||
.when(self.platform_style == PlatformStyle::Windows, |title_bar| {
|
||||
let button_height = Self::height(cx) - top_padding;
|
||||
|
||||
title_bar.child(WindowsWindowControls::new(button_height))
|
||||
title_bar.child(WindowsWindowControls::new(height))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -98,9 +98,11 @@ impl WindowsCaptionButton {
|
||||
|
||||
impl RenderOnce for WindowsCaptionButton {
|
||||
fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
|
||||
// todo(windows): get padding from win32 api, need HWND from window context somehow
|
||||
// should be GetSystemMetricsForDpi(SM_CXSIZE, dpi)
|
||||
let width = px(36.0);
|
||||
// todo(windows) report this width to the Windows platform API
|
||||
// NOTE: this is intentionally hard coded. An option to use the 'native' size
|
||||
// could be added when the width is reported to the Windows platform API
|
||||
// as this could change between future Windows versions.
|
||||
let width = px(36.);
|
||||
|
||||
h_flex()
|
||||
.id(self.id)
|
||||
|
Loading…
Reference in New Issue
Block a user