layout: make strips the titlebar with window controls
This commit is contained in:
@@ -7,8 +7,8 @@ use gpui::prelude::FluentBuilder as _;
|
||||
use gpui::{
|
||||
AnyElement, AnyView, App, AppContext as _, Axis, Context, ElementId, Entity,
|
||||
InteractiveElement as _, IntoElement, ParentElement as _, Render, RenderOnce, Role,
|
||||
SharedString, StatefulInteractiveElement as _, StyleRefinement, Styled as _, Window, canvas,
|
||||
div, px, relative, size,
|
||||
SharedString, StatefulInteractiveElement as _, StyleRefinement, Styled as _, Window,
|
||||
WindowControlArea, canvas, div, px, relative, size,
|
||||
};
|
||||
use gpui_native_core::common::{h_flex, v_flex};
|
||||
use gpui_native_core::context_menu::ContextMenu;
|
||||
@@ -18,6 +18,7 @@ use gpui_native_icons::IconRole;
|
||||
use gpui_native_theme::{ActiveTheme as _, Size};
|
||||
|
||||
use crate::resize_handle::ResizeHandle;
|
||||
use crate::window_controls::{TRAFFIC_LIGHT_PAD, WindowControls, maximize_on_double_click};
|
||||
|
||||
/// The narrowest either side of a split can get, as a fraction of the split.
|
||||
const MIN_SPLIT_RATIO: f32 = 0.1;
|
||||
@@ -680,6 +681,10 @@ enum TreeView {
|
||||
pub struct Dock {
|
||||
id: ElementId,
|
||||
state: Entity<DockState>,
|
||||
/// The pill bar is the window's titlebar: trailing window controls.
|
||||
window_controls: bool,
|
||||
/// The pill bar leads the window: pad for the macOS traffic lights.
|
||||
traffic_light_pad: bool,
|
||||
}
|
||||
|
||||
impl Dock {
|
||||
@@ -691,14 +696,32 @@ impl Dock {
|
||||
Self {
|
||||
id: id.into(),
|
||||
state,
|
||||
window_controls: false,
|
||||
traffic_light_pad: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders the window controls in the pill bar's trailing end.
|
||||
pub fn window_controls(mut self, window_controls: bool) -> Self {
|
||||
self.window_controls = window_controls;
|
||||
self
|
||||
}
|
||||
|
||||
/// Pads the pill bar's leading edge for the macOS traffic lights.
|
||||
pub fn traffic_light_pad(mut self, traffic_light_pad: bool) -> Self {
|
||||
self.traffic_light_pad = traffic_light_pad;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for Dock {
|
||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let tree = self.state.read(cx).snapshot();
|
||||
let root = render_node(&self.id, &self.state, &tree, window, cx);
|
||||
let titlebar = Titlebar {
|
||||
window_controls: self.window_controls,
|
||||
traffic_light_pad: self.traffic_light_pad,
|
||||
};
|
||||
let root = render_node(&self.id, &self.state, &tree, &titlebar, window, cx);
|
||||
|
||||
div()
|
||||
.id(self.id.clone())
|
||||
@@ -714,16 +737,24 @@ impl RenderOnce for Dock {
|
||||
}
|
||||
}
|
||||
|
||||
/// Which titlebar duties the pane's pill bar carries.
|
||||
#[derive(Clone, Copy, Default)]
|
||||
struct Titlebar {
|
||||
window_controls: bool,
|
||||
traffic_light_pad: bool,
|
||||
}
|
||||
|
||||
fn render_node(
|
||||
dock_id: &ElementId,
|
||||
state: &Entity<DockState>,
|
||||
node: &TreeView,
|
||||
titlebar: &Titlebar,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> AnyElement {
|
||||
match node {
|
||||
TreeView::Pane(pane) => render_pane(dock_id, state, pane, cx),
|
||||
TreeView::Split(split) => render_split(dock_id, state, split, window, cx),
|
||||
TreeView::Pane(pane) => render_pane(dock_id, state, pane, titlebar, cx),
|
||||
TreeView::Split(split) => render_split(dock_id, state, split, titlebar, window, cx),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -731,6 +762,7 @@ fn render_split(
|
||||
dock_id: &ElementId,
|
||||
state: &Entity<DockState>,
|
||||
split: &SplitView,
|
||||
titlebar: &Titlebar,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> AnyElement {
|
||||
@@ -790,7 +822,7 @@ fn render_split(
|
||||
.min_w_0()
|
||||
.min_h_0()
|
||||
.overflow_hidden()
|
||||
.child(render_node(dock_id, state, &split.a, window, cx)),
|
||||
.child(render_node(dock_id, state, &split.a, titlebar, window, cx)),
|
||||
)
|
||||
.child(seam)
|
||||
.child(
|
||||
@@ -800,7 +832,7 @@ fn render_split(
|
||||
.min_w_0()
|
||||
.min_h_0()
|
||||
.overflow_hidden()
|
||||
.child(render_node(dock_id, state, &split.b, window, cx)),
|
||||
.child(render_node(dock_id, state, &split.b, titlebar, window, cx)),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
@@ -809,6 +841,7 @@ fn render_pane(
|
||||
dock_id: &ElementId,
|
||||
state: &Entity<DockState>,
|
||||
pane: &PaneView,
|
||||
titlebar: &Titlebar,
|
||||
cx: &App,
|
||||
) -> AnyElement {
|
||||
if pane.tabs.is_empty() {
|
||||
@@ -854,6 +887,7 @@ fn render_pane(
|
||||
let dock_id = dock_id.clone();
|
||||
let state = state.clone();
|
||||
let pane = pane.clone();
|
||||
let titlebar = *titlebar;
|
||||
let padding_x = metrics.dense_padding_x;
|
||||
move |_, _| {
|
||||
let selected = pane
|
||||
@@ -921,13 +955,32 @@ fn render_pane(
|
||||
}
|
||||
});
|
||||
|
||||
// Chrome-less like the future titlebar: the bar wraps the pills.
|
||||
h_flex()
|
||||
.id(SharedString::from(format!(
|
||||
"{dock_id}-pane-{}-bar",
|
||||
pane.key
|
||||
)))
|
||||
.debug_selector({
|
||||
let id = SharedString::from(format!("{dock_id}-pane-{}-bar", pane.key));
|
||||
move || id.to_string()
|
||||
})
|
||||
.flex_none()
|
||||
.w_full()
|
||||
.items_center()
|
||||
.window_control_area(WindowControlArea::Drag)
|
||||
.on_click(maximize_on_double_click())
|
||||
.when(titlebar.traffic_light_pad, |bar| {
|
||||
bar.pl(px(TRAFFIC_LIGHT_PAD))
|
||||
})
|
||||
.pr(padding_x)
|
||||
.child(tabs)
|
||||
.when(titlebar.window_controls, |bar| {
|
||||
bar.child(div().flex_1())
|
||||
.child(WindowControls::new(SharedString::from(format!(
|
||||
"{dock_id}-pane-{}-controls",
|
||||
pane.key
|
||||
))))
|
||||
})
|
||||
.into_any_element()
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user