fix(ui): apply compact density to title bar and tabs (#194)

Apply compact density consistently to the title bar, tabs, sidebar scrolling and drag geometry. Keep native title-bar dimensions and align the command overlay with the effective title-bar height.

Includes layout, hit-target and density-transition regressions.

Fixes #327.
This commit is contained in:
GeekMr authored and GitHub committed 2026-09-29 21:00:35 +08:00
1 parent bf2ed9af9b
commit ff03f76655
8 files changed
+194 -61

No files matched your search

+5 -5
View File
@@ -363,10 +363,6 @@ fn dock_tree(target: SplitTree<u64>, source: SplitTree<u64>, nav: SplitNav) -> S
target.joined(source, nav)
}
/// 侧栏 tab 行高与行距(与 `render_sidebar` 的 `h(px(TAB_ROW_H))`、
/// `gap_2`(8px) 同源);受约束拖拽按此步距换算让位槽位。
pub(super) const TAB_ROW_H: f32 = 34.0;
pub(super) const TAB_ROW_PITCH: f32 = TAB_ROW_H + 8.0;
/// 右侧抽屉槽位宽度 = 抽屉自身宽度。抽屉贴满右侧整条竖带(上下右都不留卡缝,
/// 左侧直接抵住终端卡),所以槽位里不再有额外的卡缝要算进来。
@@ -628,8 +624,9 @@ pub struct NebulaWorkspace {
sidebar_collapsed: bool,
/// 只折叠 TABS 分区,不影响整个左栏;与旧壳分区标题的 chevron 同义。
tabs_section_collapsed: bool,
/// 标签栏布局:默认沿用左侧栏;Top 将同一组 tab 放进 48px 标题栏。
/// 标签栏布局:默认沿用左侧栏;Top 将同一组 tab 放进标题栏。
tabs_position: nebula_settings::TabsPositionName,
density: nebula_settings::DensityName,
/// 运行时持久化的侧栏逻辑宽;布局、初始窗口和折叠动画必须同源。
sidebar_width: f32,
/// 首次手动切换后才启用折叠动画:启动帧保持静止落位(旧壳同感,
@@ -930,6 +927,7 @@ impl NebulaWorkspace {
sidebar_collapsed: false,
tabs_section_collapsed: false,
tabs_position: runtime.tabs_position,
density: runtime.density,
sidebar_width,
sidebar_fold_armed: false,
tabs_fold_armed: false,
@@ -1139,6 +1137,8 @@ impl NebulaWorkspace {
crate::gpui_shell::apply_app_icon(runtime.app_icon, cx);
self.sidebar_width = runtime.sidebar_width;
self.tabs_position = runtime.tabs_position;
self.density = runtime.density;
self.reveal_active_tab();
self.sync_settings_layout();
self.sidebar_resizing = None;
self.reveal_if_tray_disabled(cx);
@@ -16,8 +16,6 @@ const PANEL_EMPTY_HEIGHT: f32 = 196.0;
const PANEL_FIXED_HEIGHT: f32 = 146.0;
const GROUP_NAV_HEIGHT: f32 = 36.0;
const PANEL_MARGIN: f32 = 8.0;
// 覆盖层从自绘标题栏下沿开始;固定组件依赖当前将该区域定义为 34px。
const WINDOW_TITLE_BAR_HEIGHT: f32 = 34.0;
const PANEL_FOOTER_HEIGHT: f32 = 44.0;
const ROW_HEIGHT: f32 = 62.0;
const ROW_ICON_SIZE: f32 = 16.0;
@@ -559,8 +557,12 @@ impl NebulaWorkspace {
let viewport = window.viewport_size();
let panel_width =
PANEL_MAX_WIDTH.min((f32::from(viewport.width) - PANEL_MARGIN * 2.0).max(0.0));
let title_bar_height = super::window_titlebar::effective_title_bar_height(
self.density,
crate::platform::window_chrome::layout(window),
);
let available_height =
(f32::from(viewport.height) - WINDOW_TITLE_BAR_HEIGHT - PANEL_MARGIN * 2.0).max(0.0);
(f32::from(viewport.height) - title_bar_height - PANEL_MARGIN * 2.0).max(0.0);
let rows = self.command_manager_rows(cx);
self.command_manager_selected =
@@ -688,7 +690,7 @@ impl NebulaWorkspace {
.child(
v_flex()
.absolute()
.top(px(WINDOW_TITLE_BAR_HEIGHT + PANEL_MARGIN))
.top(px(title_bar_height + PANEL_MARGIN))
.right(px(PANEL_MARGIN))
.w(px(panel_width))
.h(px(panel_height))
@@ -160,3 +160,53 @@ fn closing_last_regular_tab_keeps_settings_until_it_is_closed(cx: &mut TestAppCo
cx.simulate_keystrokes("ctrl-shift-w");
assert!(cx.read(|cx| cx.windows().is_empty()));
}
#[gpui::test]
fn density_changes_real_tab_bounds_and_sidebar_drag_pitch(cx: &mut TestAppContext) {
use nebula_settings::{DensityName, TabsPositionName};
let (_directory, workspace, mut cx) = open_workspace(8, cx);
click_tab("top-tab-0", &mut cx);
for position in [TabsPositionName::Sidebar, TabsPositionName::Top] {
for (density, height, gap, title_height) in [
(DensityName::Standard, 34.0, 8.0, 48.0),
(DensityName::Compact, 32.0, 4.0, 40.0),
(DensityName::Standard, 34.0, 8.0, 48.0),
] {
workspace.update(&mut cx, |workspace, cx| {
workspace.tabs_position = position;
workspace.density = density;
workspace.sync_settings_layout();
workspace.reveal_active_tab();
cx.notify();
});
cx.run_until_parked();
let sidebar = position == TabsPositionName::Sidebar;
let first = tab_bounds(if sidebar { "sidebar-tab-0" } else { "top-tab-0" }, &mut cx);
let second = tab_bounds(if sidebar { "sidebar-tab-1" } else { "top-tab-1" }, &mut cx);
assert_eq!(f32::from(first.size.height), height);
assert_eq!(f32::from(second.size.height), height);
if sidebar {
assert_eq!(f32::from(second.top() - first.top()), height + gap);
}
let native = cx.update(|window, _| crate::platform::window_chrome::layout(window));
let title = tab_bounds("workspace-titlebar", &mut cx);
assert_eq!(
f32::from(title.size.height),
native.map_or(title_height, |layout| layout.0)
);
// Padding belongs to the tab's actual click target in either density.
let point = gpui::point(second.left() + px(8.0), second.bottom() - px(2.0));
cx.simulate_click(point, Modifiers::default());
workspace.read_with(&cx, |workspace, _| assert_eq!(workspace.active, 1));
if sidebar {
cx.simulate_mouse_down(point, gpui::MouseButton::Left, Modifiers::default());
workspace.read_with(&cx, |workspace, _| {
assert_eq!(workspace.tab_drag.as_ref().unwrap().pitch, height + gap);
});
cx.simulate_mouse_up(point, gpui::MouseButton::Left, Modifiers::default());
}
}
}
}
+10 -8
View File
@@ -187,6 +187,8 @@ impl NebulaWorkspace {
}
fn render_sidebar(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let row_height = tab_scroll::tab_row_height(self.density);
let row_pitch = self.tab_row_pitch();
let theme = cx.theme();
let muted = theme.muted_foreground;
// 数量 chip 数字:旧壳独用 ink_faint(比 ink_dim 再暗一档),chip 背
@@ -330,10 +332,10 @@ impl NebulaWorkspace {
let (dragged, shift) = match drag {
Some((src, _, _)) if ix == src => (true, 0.0),
Some((src, tgt, _)) if src < tgt && ix > src && ix <= tgt => {
(false, -TAB_ROW_PITCH)
(false, -row_pitch)
},
Some((src, tgt, _)) if src > tgt && ix >= tgt && ix < src => {
(false, TAB_ROW_PITCH)
(false, row_pitch)
},
_ => (false, 0.0),
};
@@ -359,7 +361,7 @@ impl NebulaWorkspace {
.overflow_hidden()
.gap_2()
.px_2()
.h(px(TAB_ROW_H))
.h(px(row_height))
.items_center()
// 旧壳 pill 圆角 = UI_CORNER_RADIUS_LOGICAL(8),rounded_md(6)
// 偏小一圈,选中水洗的轮廓形状会不一样。
@@ -389,7 +391,7 @@ impl NebulaWorkspace {
press_x: f32::from(event.position.x),
press_y: f32::from(event.position.y),
axis: TabDragAxis::Vertical,
pitch: TAB_ROW_PITCH,
pitch: row_pitch,
offset: 0.0,
active: false,
dock: None,
@@ -415,7 +417,7 @@ impl NebulaWorkspace {
.left(px(4.0))
.top(px(7.0))
.w(px(2.5))
.h(px(TAB_ROW_H - 14.0))
.h(px(row_height - 14.0))
.rounded_full()
.bg(color),
)
@@ -621,7 +623,7 @@ impl NebulaWorkspace {
// 仍是旧壳的 8px。
.px_2()
.pb_2()
.gap_2()
.gap(px(tab_scroll::tab_row_gap(self.density)))
// 待命阶段(未过阈值)的指针跟踪;激活后由根部罩层独占接管。
.on_mouse_move(cx.listener(|this, event, window, cx| {
this.update_tab_drag(event, window, cx);
@@ -631,7 +633,7 @@ impl NebulaWorkspace {
.id("sidebar-tabs-toggle")
.group(header_group.clone())
.w_full()
.h(px(34.0))
.h(px(row_height))
.pb_1()
// 旧壳标题文字从 panel_x + 16px 起;侧栏根已有 8px
// padding,这里再补 8px,箭头不会贴住左边缘。
@@ -1042,7 +1044,7 @@ mod tests {
.id("status-probe-row")
.debug_selector(|| "status-probe-row".to_owned())
.w(px(200.0))
.h(px(TAB_ROW_H))
.h(px(tab_scroll::tab_row_height(nebula_settings::DensityName::Standard)))
.px_2()
.overflow_hidden()
.child(div().flex_1())
@@ -14,10 +14,25 @@ use gpui::{
use crate::display::ui::widgets::{self, OverlayScrollbar};
use crate::gpui_shell::prelude::*;
use super::{NebulaWorkspace, TAB_ROW_H, TAB_ROW_PITCH};
use nebula_settings::DensityName;
use super::NebulaWorkspace;
pub(super) fn tab_row_height(density: DensityName) -> f32 {
match density {
DensityName::Standard => 34.0,
DensityName::Compact => crate::display::ui::tokens::control::MIN_HIT_TARGET,
}
}
pub(super) fn tab_row_gap(density: DensityName) -> f32 {
use crate::display::ui::tokens::space;
match density {
DensityName::Standard => space::XS,
DensityName::Compact => space::XXS,
}
}
/// 行间距(pitch − 行高)。旧壳 `gap = s(8)`。
const TAB_ROW_GAP: f32 = TAB_ROW_PITCH - TAB_ROW_H;
/// 旧壳 `tab_right_pad`:给覆盖式滚动条留的恒定沟槽,出现与否都不改行宽。
pub(super) const TAB_SCROLL_GUTTER: f32 = 9.0;
@@ -97,9 +112,18 @@ struct TabsWindow {
}
impl NebulaWorkspace {
pub(super) fn tab_row_pitch(&self) -> f32 {
tab_row_height(self.density) + tab_row_gap(self.density)
}
fn tabs_window(&self) -> TabsWindow {
let want = self.tabs.len();
let show = visible_count(want, self.tabs_viewport_h, TAB_ROW_PITCH, TAB_ROW_GAP);
let show = visible_count(
want,
self.tabs_viewport_h,
self.tab_row_pitch(),
tab_row_gap(self.density),
);
let max = max_scroll(want, show);
let scroll = clamp_scroll(self.tabs_scroll, max);
TabsWindow { scroll, show, max, want }
@@ -137,15 +161,16 @@ impl NebulaWorkspace {
if window.show == 0 || window.want <= window.show {
return None;
}
let viewport = rows_h(window.show, TAB_ROW_PITCH, TAB_ROW_GAP).max(1.0);
let content = rows_h(window.want, TAB_ROW_PITCH, TAB_ROW_GAP);
let viewport =
rows_h(window.show, self.tab_row_pitch(), tab_row_gap(self.density)).max(1.0);
let content = rows_h(window.want, self.tab_row_pitch(), tab_row_gap(self.density));
let width = self.tabs_list_width.max(1.0);
let height = self.tabs_viewport_h.max(viewport);
widgets::overlay_scrollbar(
(0.0, 0.0, width, height),
viewport,
content,
window.scroll as f32 * TAB_ROW_PITCH,
window.scroll as f32 * self.tab_row_pitch(),
1.0,
)
}
@@ -191,7 +216,7 @@ impl NebulaWorkspace {
_window: &mut Window,
cx: &mut Context<Self>,
) {
let delta_y = f32::from(event.delta.pixel_delta(px(TAB_ROW_PITCH)).y);
let delta_y = f32::from(event.delta.pixel_delta(px(self.tab_row_pitch())).y);
let rows = wheel_rows(delta_y);
if rows == 0 {
return;
@@ -254,7 +279,7 @@ impl NebulaWorkspace {
.absolute()
.size_full(),
)
.child(v_flex().w_full().gap_2().children(items))
.child(v_flex().w_full().gap(px(tab_row_gap(self.density))).children(items))
.when_some(bar.filter(|_| show_thumb), |list, bar| {
list.child(
div()
@@ -304,7 +329,10 @@ impl NebulaWorkspace {
}
// 折叠中/已折叠:裁剪高度不是 `tabs_avail`。写回去会让
// `visible_count` 按 20–40px 算出 0/1 行,展开后整列锁死。
if !self.tabs_section_collapsed && !self.tabs_fold_frozen && h >= TAB_ROW_H {
if !self.tabs_section_collapsed
&& !self.tabs_fold_frozen
&& h >= tab_row_height(self.density)
{
self.tabs_viewport_h = h;
}
self.tabs_list_width = w;
@@ -349,6 +377,24 @@ mod tests {
wheel_rows,
};
#[test]
fn compact_rows_fit_more_tabs_without_shrinking_hit_targets() {
use super::{DensityName, tab_row_gap, tab_row_height};
for (density, expected_height, expected_show) in
[(DensityName::Standard, 34.0, 2), (DensityName::Compact, 32.0, 3)]
{
let height = tab_row_height(density);
let gap = tab_row_gap(density);
let pitch = height + gap;
assert_eq!(height, expected_height);
assert!(height >= crate::display::ui::tokens::control::MIN_HIT_TARGET);
assert_eq!(rows_h(1, pitch, gap), height);
let show = visible_count(10, 104.0, pitch, gap);
assert_eq!(show, expected_show);
assert_eq!(reveal_index(9, 0, show), max_scroll(10, show));
}
}
const PITCH: f32 = 42.0;
const GAP: f32 = 8.0;
+17 -4
View File
@@ -77,7 +77,7 @@ mod title_bar_panel_control_tests {
}
#[derive(Default)]
struct TopTabGeometryProbe;
struct TopTabGeometryProbe(nebula_settings::DensityName);
impl Render for TopTabGeometryProbe {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
@@ -89,9 +89,10 @@ mod title_bar_panel_control_tests {
div()
.debug_selector(|| "top-tab-geometry-probe".to_owned())
.w(px(160.0))
.h(px(super::top_tabs::TOP_TAB_H)),
.h(px(super::tab_scroll::tab_row_height(self.0))),
)
.child(super::top_tabs::top_tab_action_slot(
self.0,
super::top_tabs::top_new_tab_control(
crate::i18n::UiLanguage::EnUs,
|_, _, _| {},
@@ -99,6 +100,7 @@ mod title_bar_panel_control_tests {
.debug_selector(|| "top-new-tab-geometry-probe".to_owned()),
))
.child(super::top_tabs::top_tab_action_slot(
self.0,
h_flex().debug_selector(|| "top-tabs-menu-geometry-probe".to_owned()).child(
super::top_tabs::top_tabs_menu_button(false, crate::i18n::UiLanguage::EnUs),
),
@@ -113,18 +115,29 @@ mod title_bar_panel_control_tests {
#[gpui::test]
fn top_tab_action_buttons_share_the_tab_vertical_center(cx: &mut TestAppContext) {
cx.update(gpui_component::init);
let (_, cx) = cx.add_window_view(|_, _| TopTabGeometryProbe);
let (probe, cx) = cx.add_window_view(|_, _| TopTabGeometryProbe::default());
for (density, height) in [
(nebula_settings::DensityName::Standard, 34.0),
(nebula_settings::DensityName::Compact, 32.0),
(nebula_settings::DensityName::Standard, 34.0),
] {
probe.update(cx, |probe, cx| {
probe.0 = density;
cx.notify();
});
cx.run_until_parked();
let tab = cx.debug_bounds("top-tab-geometry-probe").expect("tab bounds");
let new_tab = cx.debug_bounds("top-new-tab-geometry-probe").expect("new-tab bounds");
let menu = cx.debug_bounds("top-tabs-menu-geometry-probe").expect("menu bounds");
assert_eq!(f32::from(tab.size.height), 34.0);
assert_eq!(f32::from(tab.size.height), height);
assert_eq!(f32::from(new_tab.size.height), 32.0);
assert_eq!(f32::from(menu.size.height), 32.0);
assert_eq!(vertical_center(new_tab), vertical_center(tab));
assert_eq!(vertical_center(menu), vertical_center(tab));
}
}
}
#[cfg(feature = "gpui-test-support")]
mod sidebar_new_tab_tests {
+14 -10
View File
@@ -1,4 +1,4 @@
//! 48px 自定义标题栏里的横向标签布局。
//! 自定义标题栏里的横向标签布局。
//!
//! 这里只负责同一组 workspace tab 的第二种呈现;激活、关闭、重命名、排序
//! 与 dock 都调用 `NebulaWorkspace` 既有动作,不维护平行状态。
@@ -23,7 +23,6 @@ use super::{
TabDragAxis, TabPresentation, ToggleShellPicker, pane_header, title_bar_panel_controls,
};
pub(super) const TOP_TAB_H: f32 = 34.0;
/// 与顶部模式正文卡片的 `px_2` 左边距同源,让首个 tab 和终端左缘对齐。
pub(super) const TOP_TAB_LEFT_INSET: f32 = 8.0;
/// 单个 tab 的最小宽。WT 的 TabView 同一条取舍:标签**不压到读不出来**,
@@ -110,10 +109,13 @@ pub(super) fn top_tabs_menu_button(settings_active: bool, language: UiLanguage)
.tooltip(language.text(Message::ChromeMore))
}
/// 紧邻 TabView 的操作按钮占满同一条 34px 行,再在槽内居中 32px 按钮。
/// 紧邻 TabView 的操作按钮占满同一条标签行,再在槽内居中 32px 按钮。
/// 外层仍贴标题栏底边,tab 与正文相接的既有布局不变。
pub(super) fn top_tab_action_slot(child: impl gpui::IntoElement) -> gpui::Div {
h_flex().h(px(TOP_TAB_H)).items_center().child(child)
pub(super) fn top_tab_action_slot(
density: nebula_settings::DensityName,
child: impl gpui::IntoElement,
) -> gpui::Div {
h_flex().h(px(super::tab_scroll::tab_row_height(density))).items_center().child(child)
}
impl NebulaWorkspace {
@@ -130,6 +132,7 @@ impl NebulaWorkspace {
window: &mut Window,
cx: &mut Context<Self>,
) -> gpui::AnyElement {
let row_height = super::tab_scroll::tab_row_height(self.density);
let language = crate::gpui_shell::config::ui_language(cx);
let theme = cx.theme();
let muted = theme.muted_foreground;
@@ -276,7 +279,7 @@ impl NebulaWorkspace {
.group(hover_group.clone())
.relative()
.w(px(tab_w))
.h(px(TOP_TAB_H))
.h(px(row_height))
.flex_shrink_0()
.min_w_0()
.overflow_hidden()
@@ -552,7 +555,7 @@ impl NebulaWorkspace {
// 看不见的入口——tab 一多,用户根本不知道右边还有东西。
.when(overflow, |bar| {
bar.child(
div().h(px(TOP_TAB_H)).flex().items_center().child(
div().h(px(row_height)).flex().items_center().child(
title_bar_panel_controls().h_auto().child(
Button::new("top-tabs-prev")
.icon(IconName::ChevronLeft)
@@ -580,7 +583,7 @@ impl NebulaWorkspace {
.w(px(tab_viewport_w))
.flex_shrink(1.0)
.min_w_0()
.h(px(TOP_TAB_H))
.h(px(row_height))
.overflow_hidden()
// 待命拖拽在越过 4px 前由此接收移动;激活后根罩层接管。
.on_mouse_move(cx.listener(|this, event, window, cx| {
@@ -600,7 +603,7 @@ impl NebulaWorkspace {
)
.when(overflow, |bar| {
bar.child(
div().h(px(TOP_TAB_H)).flex().items_center().child(
div().h(px(row_height)).flex().items_center().child(
title_bar_panel_controls().h_auto().child(
Button::new("top-tabs-next")
.icon(IconName::ChevronRight)
@@ -622,7 +625,7 @@ impl NebulaWorkspace {
)
})
.child(
top_tab_action_slot(top_new_tab_control(language, cx.listener(
top_tab_action_slot(self.density, top_new_tab_control(language, cx.listener(
|this, _, window, cx| {
this.add_terminal(window, cx);
},
@@ -630,6 +633,7 @@ impl NebulaWorkspace {
)
.child(
top_tab_action_slot(
self.density,
top_tabs_menu_button(settings_active, language).dropdown_menu_with_anchor(
gpui::Anchor::TopRight,
move |menu, _, _| {
@@ -1,5 +1,19 @@
use super::*;
fn title_bar_height(density: nebula_settings::DensityName) -> f32 {
match density {
nebula_settings::DensityName::Standard => 48.0,
nebula_settings::DensityName::Compact => 40.0,
}
}
pub(super) fn effective_title_bar_height(
density: nebula_settings::DensityName,
native_layout: Option<(f32, f32)>,
) -> f32 {
native_layout.map_or_else(|| title_bar_height(density), |(height, _)| height)
}
/// Prepaint records the actual pane column before any titlebar paint runs. Keep
/// this cell for the workspace lifetime, so resizing and panel animations do not
/// allocate a new shared slot or duplicate the body's layout calculations.
@@ -93,9 +107,9 @@ impl NebulaWorkspace {
) -> gpui::Div {
let top_tabs = self.tabs_position == nebula_settings::TabsPositionName::Top;
let native_layout = crate::platform::window_chrome::layout(window);
let title_bar_height = effective_title_bar_height(self.density, native_layout);
let bar = TitleBar::new()
// Leave 8px above and below the existing 32px controls.
.h(px(48.0))
.h(px(title_bar_height))
.when(!settings_active, |bar| bar.bg(gpui::transparent_black()).border_b_0())
.when(settings_active, |bar| {
bar.border_b_1().border_color(crate::gpui_shell::theme::settings_hairline(cx))
@@ -103,29 +117,15 @@ impl NebulaWorkspace {
.when(top_tabs && native_layout.is_none(), |bar| {
bar.pl(px(top_tabs::TOP_TAB_LEFT_INSET))
})
.when(top_tabs, |bar| {
bar.child(self.render_top_title_bar(
settings_active,
window,
cx,
))
})
.when(!top_tabs, |bar| {
bar.child(self.render_sidebar_title_bar(
settings_active,
cx,
))
});
.when(top_tabs, |bar| bar.child(self.render_top_title_bar(settings_active, window, cx)))
.when(!top_tabs, |bar| bar.child(self.render_sidebar_title_bar(settings_active, cx)));
// AppKit owns both the control group and its geometry. Read the live
// frames so system layout, resize and full-screen transitions agree.
let bar = if let Some((height, inset)) = native_layout {
bar.h(px(height)).pl(px(inset))
} else {
bar
};
let bar = if let Some((_, inset)) = native_layout { bar.pl(px(inset)) } else { bar };
title_bar_frame()
.debug_selector(|| "workspace-titlebar".to_owned())
.when(!settings_active, |title| title.child(self.titlebar_background.element()))
.child(bar)
}
@@ -175,3 +175,19 @@ mod tests {
assert!(!cx.update(|window, cx| window.selected_text(cx).is_empty()));
}
}
#[cfg(test)]
mod density_tests {
use super::{effective_title_bar_height, title_bar_height};
use nebula_settings::DensityName;
#[test]
fn compact_title_bar_retains_space_around_controls() {
assert_eq!(title_bar_height(DensityName::Standard), 48.0);
assert_eq!(title_bar_height(DensityName::Compact), 40.0);
assert_eq!(effective_title_bar_height(DensityName::Standard, None), 48.0);
assert_eq!(effective_title_bar_height(DensityName::Compact, None), 40.0);
assert_eq!(effective_title_bar_height(DensityName::Compact, Some((34.0, 7.0))), 34.0);
assert!(title_bar_height(DensityName::Compact) >= 32.0 + 2.0 * 4.0);
}
}