gpui_engine/layout.rs
1//! Layout identity and the contract between the facade and a layout engine.
2//!
3//! A layout engine owns its tree. The facade refers to nodes only through the
4//! opaque [`LayoutId`], so no layout-solver type crosses this boundary and an
5//! alternative engine can back the same tree.
6
7use crate::EngineLayoutStyle;
8use gpui_types::{AvailableSpace, Bounds, Pixels, Size};
9use std::any::Any;
10
11/// A unique identifier for a layout node, generated when a layout is requested.
12///
13/// The value is opaque to callers; only the engine that produced it interprets
14/// it.
15#[repr(transparent)]
16#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
17pub struct LayoutId(pub u64);
18
19/// The handles a facade supplies for the duration of one layout pass.
20///
21/// The engine forwards these from [`LayoutEngine::compute_layout`] to the
22/// measure callbacks the facade registered, and never reads them itself. The
23/// facade erases its window as the two halves its callback reassembles rather
24/// than as a single handle, because a window that borrows per-frame state is
25/// not `'static`, which erasing through `Any` would require.
26pub struct MeasureHandles<'a> {
27 /// The two halves of the facade's window.
28 pub window: (&'a mut dyn Any, &'a mut dyn Any),
29 /// The facade's application handle.
30 pub app: &'a mut dyn Any,
31}
32
33/// The handles a custom measure callback receives from the engine.
34///
35/// The facade supplies a context whose `handles` return its window and
36/// application; the engine only forwards the context to the callback stored
37/// when the node was created.
38pub trait MeasureContext {
39 /// Returns the facade's handles for this pass.
40 fn handles(&mut self) -> MeasureHandles<'_>;
41}
42
43/// A type-erased measure callback supplied to
44/// [`LayoutEngine::request_measured_layout`].
45pub type BoxedMeasureFn = Box<
46 dyn FnMut(Size<Option<Pixels>>, Size<AvailableSpace>, &mut dyn MeasureContext) -> Size<Pixels>,
47>;
48
49/// A layout solver.
50///
51/// The facade drives the whole frame lifecycle through this trait, so the layout
52/// implementation can be swapped without the authoring layer naming it.
53pub trait LayoutEngine {
54 /// Discards every node and cached bounds, ready for a fresh frame.
55 fn clear(&mut self);
56
57 /// Adds a leaf or container node built from `style`.
58 fn request_layout(
59 &mut self,
60 style: &EngineLayoutStyle,
61 rem_size: Pixels,
62 scale_factor: f32,
63 children: &[LayoutId],
64 ) -> LayoutId;
65
66 /// Adds a leaf whose size is resolved by `measure` during layout.
67 fn request_measured_layout(
68 &mut self,
69 style: &EngineLayoutStyle,
70 rem_size: Pixels,
71 scale_factor: f32,
72 measure: BoxedMeasureFn,
73 ) -> LayoutId;
74
75 /// Treats any `auto` dimension of `id`'s style as filling `size`.
76 fn stretch_auto_size_to_fill(&mut self, id: LayoutId, size: Size<Pixels>, scale_factor: f32);
77
78 /// Computes the layout of `id` within `available_space`, invoking stored
79 /// measure callbacks with `context`.
80 fn compute_layout(
81 &mut self,
82 id: LayoutId,
83 available_space: Size<AvailableSpace>,
84 scale_factor: f32,
85 context: &mut dyn MeasureContext,
86 );
87
88 /// Returns the pixel-snapped bounds of `id` relative to the window.
89 fn layout_bounds(&mut self, id: LayoutId, scale_factor: f32) -> Bounds<Pixels>;
90}