cotis_layout/layout_struct.rs
1//! Layout output types consumed by pipes and renderers.
2//!
3//! The primary public types are [`RenderCommandOutput`] and its variants, plus
4//! [`TextDrawPayload`] for text fragments attached to element commands.
5//!
6//! Pipes such as `CotisLayoutToRenderListPipeForGenerics` in `cotis-pipes` walk a
7//! `RenderCommandOutput` stream and decode each element's `custom` payload into concrete draw
8//! commands.
9//!
10//! # Internal types
11//!
12//! The layout engine also defines tree and state types (`LayoutElement`, `LayoutElementConfig`,
13//! `LayoutElementInfo`, `ChildWrapping`, etc.) in crate-private submodules. These appear in the
14//! return type of [`CotisLayoutManager::get_cache_element`](crate::preamble::CotisLayoutManager::get_cache_element)
15//! for post-frame inspection but are **not stable public API** — their visibility is under review.
16//!
17//! Note: layout-internal `ChildWrapping` (`None` / `Text`) is partially
18//! unrelated to the experimental `child_wrapping` field on `cotis-defaults` layout styles.
19
20use cotis::utils::ElementId;
21use cotis_utils::math::BoundingBox;
22
23pub(crate) mod info_types;
24
25pub(crate) mod layout_tree;
26
27pub(crate) mod layout_states;
28
29/// Opens a clip region for subsequent [`RenderCommandOutput::Element`] commands.
30///
31/// Paired with [`RenderCommandClipEnd`] for the same element `id`. Pipes push and pop clip
32/// stacks based on these markers.
33#[derive(Debug, Clone)]
34#[cfg_attr(
35 feature = "serialization",
36 derive(serde::Serialize, serde::Deserialize)
37)]
38pub struct RenderCommandClipStart {
39 /// Clip bounds in screen space.
40 pub bounds: BoundingBox,
41 /// Element that owns this clip container.
42 pub id: ElementId,
43 /// Draw order relative to siblings (higher draws on top).
44 pub z_index: i32,
45}
46
47/// Closes the clip region opened by the matching [`RenderCommandClipStart`].
48#[derive(Debug, Clone)]
49#[cfg_attr(
50 feature = "serialization",
51 derive(serde::Serialize, serde::Deserialize)
52)]
53pub struct RenderCommandClipEnd {
54 /// Clip bounds in screen space (same as the matching start).
55 pub bounds: BoundingBox,
56 /// Element that owns this clip container.
57 pub id: ElementId,
58 /// Draw order relative to siblings.
59 pub z_index: i32,
60}
61
62/// One step in the layout-to-renderer command stream.
63///
64/// Emitted in depth-first tree order with z-index sorting applied per subtree root. Pipes
65/// translate each variant into renderer draw calls.
66///
67/// # Examples
68///
69/// ```
70/// use cotis::utils::ElementIdConfig;
71/// use cotis_layout::layout_struct::{
72/// RenderCommandClipEnd, RenderCommandClipStart, RenderCommandOutput,
73/// RenderCommandOutputElement,
74/// };
75/// use cotis_utils::math::BoundingBox;
76///
77/// let id = ElementIdConfig::new_empty().get_handle();
78/// let bounds = BoundingBox { x: 0.0, y: 0.0, width: 100.0, height: 50.0 };
79///
80/// let element: RenderCommandOutput<&str> = RenderCommandOutput::Element(RenderCommandOutputElement {
81/// bounds,
82/// z_index: 0,
83/// text: None,
84/// custom: "my-payload",
85/// });
86///
87/// let clip_start: RenderCommandOutput<()> = RenderCommandOutput::ClipStart(RenderCommandClipStart {
88/// bounds,
89/// id: id.clone(),
90/// z_index: 1,
91/// });
92///
93/// let clip_end: RenderCommandOutput<()> = RenderCommandOutput::ClipEnd(RenderCommandClipEnd {
94/// bounds,
95/// id,
96/// z_index: 1,
97/// });
98///
99/// assert!(matches!(element, RenderCommandOutput::Element(_)));
100/// assert!(matches!(clip_start, RenderCommandOutput::ClipStart(_)));
101/// assert!(matches!(clip_end, RenderCommandOutput::ClipEnd(_)));
102/// ```
103#[derive(Debug, Clone)]
104#[cfg_attr(
105 feature = "serialization",
106 derive(serde::Serialize, serde::Deserialize)
107)]
108#[cfg_attr(
109 feature = "serialization",
110 serde(bound(deserialize = "
111 Custom: serde::de::DeserializeOwned,
112"))
113)]
114pub enum RenderCommandOutput<Custom> {
115 /// A sized and positioned element ready for rendering.
116 Element(RenderCommandOutputElement<Custom>),
117 /// Begin clip scissor for a scroll/clip container.
118 ClipStart(RenderCommandClipStart),
119 /// End clip scissor for a scroll/clip container.
120 ClipEnd(RenderCommandClipEnd),
121}
122
123mod text_draw_payload;
124pub use text_draw_payload::TextDrawPayload;
125
126/// Render data for one layout element.
127///
128/// The `custom` field carries the user's config type (`T` from `RenderCommandOutput<T>`).
129/// When the element is a text leaf, `text` holds the substring and typography to draw.
130#[derive(Debug, Clone)]
131#[cfg_attr(
132 feature = "serialization",
133 derive(serde::Serialize, serde::Deserialize)
134)]
135#[cfg_attr(
136 feature = "serialization",
137 serde(bound(deserialize = "
138 Custom: serde::de::DeserializeOwned,
139"))
140)]
141pub struct RenderCommandOutputElement<Custom> {
142 /// Final axis-aligned bounds in screen space.
143 pub bounds: BoundingBox,
144 /// Draw order relative to siblings (higher draws on top).
145 pub z_index: i32,
146 /// Text fragment when this element is a synthetic text leaf; `None` for non-text nodes.
147 pub text: Option<TextDrawPayload>,
148 /// User config payload (e.g. [`ElementConfig`](cotis_defaults::element_configs::ElementConfig)).
149 pub custom: Custom,
150}