146 lines
4.9 KiB
Rust
146 lines
4.9 KiB
Rust
//! The titlebar duties: traffic-light pads and window controls, asserted per
|
|
//! platform — macOS draws only pads, Windows/Linux only draw their controls.
|
|
|
|
use gpui::{
|
|
AppContext as _, Entity, IntoElement, ParentElement as _, Pixels, Render, Styled as _,
|
|
TestAppContext, VisualTestContext, Window, div, px,
|
|
};
|
|
use gpui_native_layout::dock::{Dock, DockState, PanelDescriptor};
|
|
use gpui_native_layout::window_controls::TRAFFIC_LIGHT_PAD;
|
|
use gpui_native_theme::Theme;
|
|
|
|
struct Panel {
|
|
tag: &'static str,
|
|
}
|
|
|
|
impl Render for Panel {
|
|
fn render(&mut self, _window: &mut Window, _cx: &mut gpui::Context<Self>) -> impl IntoElement {
|
|
div().size_full().child(self.tag)
|
|
}
|
|
}
|
|
|
|
fn descriptor(tag: &'static str) -> PanelDescriptor {
|
|
PanelDescriptor::new(tag, tag, move |_, cx| cx.new(|_| Panel { tag }).into())
|
|
}
|
|
|
|
struct Harness {
|
|
dock: Entity<DockState>,
|
|
window_controls: bool,
|
|
traffic_light_pad: bool,
|
|
}
|
|
|
|
impl Render for Harness {
|
|
fn render(&mut self, _window: &mut Window, _cx: &mut gpui::Context<Self>) -> impl IntoElement {
|
|
div().size_full().child(
|
|
Dock::new("test-dock", self.dock.clone())
|
|
.window_controls(self.window_controls)
|
|
.traffic_light_pad(self.traffic_light_pad),
|
|
)
|
|
}
|
|
}
|
|
|
|
fn dock_window(
|
|
window_controls: bool,
|
|
traffic_light_pad: bool,
|
|
cx: &mut TestAppContext,
|
|
) -> (Entity<DockState>, VisualTestContext) {
|
|
cx.update(Theme::init);
|
|
let dock = cx.update(DockState::new);
|
|
let dock_for_window = dock.clone();
|
|
let window = cx.add_window(move |_, _| Harness {
|
|
dock: dock_for_window,
|
|
window_controls,
|
|
traffic_light_pad,
|
|
});
|
|
let mut visual = VisualTestContext::from_window(window.into(), cx);
|
|
visual.update(|window, cx| window.draw(cx).clear(cx));
|
|
(dock, visual)
|
|
}
|
|
|
|
fn bounds(visual: &mut VisualTestContext, selector: &str) -> Option<gpui::Bounds<Pixels>> {
|
|
visual.debug_bounds(Box::leak(selector.to_string().into_boxed_str()))
|
|
}
|
|
|
|
fn open(visual: &mut VisualTestContext, dock: &Entity<DockState>, tag: &'static str) {
|
|
visual.update(|window, cx| {
|
|
dock.update(cx, |dock, cx| dock.open_panel(tag, window, cx));
|
|
});
|
|
visual.update(|window, cx| window.draw(cx).clear(cx));
|
|
}
|
|
|
|
#[cfg(target_os = "macos")]
|
|
#[test]
|
|
fn the_pill_bar_pads_for_traffic_lights_when_it_leads_the_window() {
|
|
let mut cx = TestAppContext::single();
|
|
let (dock, mut visual) = dock_window(false, false, &mut cx);
|
|
cx.update(|cx| {
|
|
dock.update(cx, |dock, cx| {
|
|
dock.register_panel(descriptor("overview"), cx)
|
|
});
|
|
});
|
|
open(&mut visual, &dock, "overview");
|
|
|
|
let bar = bounds(&mut visual, "test-dock-pane-0-bar").expect("pill bar missing");
|
|
let tab = bounds(&mut visual, "test-dock-pane-0-tabs-tab-overview").expect("tab missing");
|
|
let bare_inset = tab.left() - bar.left();
|
|
|
|
let (dock, mut visual) = dock_window(false, true, &mut cx);
|
|
let _ = &dock;
|
|
cx.update(|cx| {
|
|
dock.update(cx, |dock, cx| {
|
|
dock.register_panel(descriptor("overview"), cx)
|
|
});
|
|
});
|
|
open(&mut visual, &dock, "overview");
|
|
|
|
let padded_bar = bounds(&mut visual, "test-dock-pane-0-bar").expect("padded bar missing");
|
|
let padded_tab =
|
|
bounds(&mut visual, "test-dock-pane-0-tabs-tab-overview").expect("tab missing");
|
|
let padded_inset = padded_tab.left() - padded_bar.left();
|
|
|
|
assert!(
|
|
padded_inset - bare_inset >= px(TRAFFIC_LIGHT_PAD) - px(1.),
|
|
"the pad must clear the traffic lights (bare {bare_inset:?}, padded {padded_inset:?})"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn window_controls_render_only_when_the_flag_is_set() {
|
|
let mut cx = TestAppContext::single();
|
|
let (dock, mut visual) = dock_window(false, false, &mut cx);
|
|
cx.update(|cx| {
|
|
dock.update(cx, |dock, cx| {
|
|
dock.register_panel(descriptor("overview"), cx)
|
|
});
|
|
});
|
|
open(&mut visual, &dock, "overview");
|
|
|
|
// macOS: the system traffic lights own the controls — nothing renders;
|
|
// the pad test above covers that mode.
|
|
#[cfg(not(target_os = "macos"))]
|
|
assert!(
|
|
bounds(&mut visual, "window-control-close").is_none(),
|
|
"controls must not render without the flag"
|
|
);
|
|
#[cfg(target_os = "macos")]
|
|
let _ = (&dock, &mut visual);
|
|
}
|
|
|
|
#[cfg(not(target_os = "macos"))]
|
|
#[test]
|
|
fn the_flag_hosts_the_platform_controls_in_the_bar() {
|
|
let mut cx = TestAppContext::single();
|
|
let (dock, mut visual) = dock_window(true, false, &mut cx);
|
|
cx.update(|cx| {
|
|
dock.update(cx, |dock, cx| {
|
|
dock.register_panel(descriptor("overview"), cx)
|
|
});
|
|
});
|
|
open(&mut visual, &dock, "overview");
|
|
|
|
// The maximize control exists once; its restore flip follows the
|
|
// window's maximized state, not a separate control.
|
|
assert!(bounds(&mut visual, "window-control-close").is_some());
|
|
assert!(bounds(&mut visual, "window-control-maximize").is_some());
|
|
}
|