Skip to main content

damascene_core/tree/
semantics.rs

1//! Semantic node and paint roles carried by [`El`](crate::El).
2
3use std::panic::Location;
4
5/// Semantic identity of an element. Roughly an HTML tag.
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub enum Kind {
8    /// A bare layout container with no inherent visuals.
9    Group,
10    Card,
11    Button,
12    Badge,
13    Text,
14    Heading,
15    Spacer,
16    Divider,
17    Overlay,
18    Scrim,
19    Modal,
20    /// A vertically scrollable region.
21    Scroll,
22    /// Vertically scrollable region whose children are produced lazily.
23    VirtualList,
24    /// Block whose direct children flow inline.
25    Inlines,
26    /// Forced line break inside a `Kind::Inlines` block.
27    HardBreak,
28    /// Native mathematical notation. Carries a [`crate::math::MathExpr`]
29    /// and renders through Damascene's math box layout.
30    Math,
31    /// Raster image element.
32    Image,
33    /// App-owned GPU texture composited into the paint stream. Backed
34    /// by [`crate::surface::AppTexture`] and the [`crate::tree::surface`]
35    /// builder; the backend samples the texture during paint instead
36    /// of uploading pixels.
37    ///
38    /// The texture stretches across the resolved rect with bilinear
39    /// filtering — source pixel dimensions and rendered size are
40    /// independent. See [`crate::tree::surface`] for the full sizing /
41    /// aspect-ratio contract.
42    Surface,
43    /// App-supplied vector asset. Backed by
44    /// [`crate::vector::VectorAsset`] and the [`crate::tree::vector`]
45    /// builder; callers explicitly choose painted vector rendering or
46    /// one-colour mask rendering. Unlike [`Kind::Image`] (icon-styled,
47    /// square-shaped), this is the general-purpose path for arbitrary-
48    /// aspect vector content — commit-graph curves, Gantt connectors,
49    /// custom chart marks.
50    Vector,
51    /// A backend-neutral 3D scene — closed-scope graph/model (point
52    /// scatter, small lit meshes, lines). Backed by
53    /// [`crate::scene::SceneSpec`] and the [`crate::tree::chart3d`]
54    /// builder; [`crate::draw_ops`] resolves it into a `DrawOp::Scene3D`
55    /// that the backend renders with its own scene pipelines (it does not
56    /// sample a texture from core). See `docs/SCENE3D_PLAN.md`.
57    Scene3D,
58    /// Escape hatch for app-defined components.
59    Custom(&'static str),
60}
61
62/// Semantic paint role for rect-shaped surfaces.
63///
64/// Each variant maps to a theme-applied recipe at paint time. Roles are
65/// either *decorative* (set stroke + shadow on top of whatever fill the
66/// node already carries) or *fill-providing* (default a fill from the
67/// palette when the node has none). The split matters: setting a
68/// decorative role on a node with no fill produces an "invisible
69/// surface" — only a thin border over the parent's background. For
70/// panel-shaped containers, prefer the dedicated widget (`card()`,
71/// `sidebar()`, `dialog()`, `popover()`) which bundles role + fill +
72/// stroke + radius + shadow correctly.
73#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
74pub enum SurfaceRole {
75    /// No special semantic role. Theme fallback applies.
76    #[default]
77    None,
78    /// **Decorative.** Border + small drop shadow. *Does not paint a
79    /// fill* — the node must supply one (e.g. `tokens::CARD`) or sit
80    /// inside a widget like `card()` / `sidebar()` that does.
81    Panel,
82    /// **Decorative.** Border + half-strength shadow, suggesting one
83    /// elevation step above its parent. Like `Panel`, no fill.
84    Raised,
85    /// **Fill-providing.** Slightly darker variant of `MUTED` (palette
86    /// `darken(0.08)`) with input-toned border. Use for inset bands —
87    /// search wells, segmented-control tracks, recessed list headers.
88    Sunken,
89    /// **Decorative.** Input-toned border + large drop shadow for
90    /// floating panels. Used by `popover()` and friends; bring your
91    /// own fill (typically `tokens::POPOVER`).
92    Popover,
93    /// **Fill-providing.** PRIMARY-tinted alpha 28 fill +
94    /// PRIMARY-tinted alpha 110 border. The selected item inside a
95    /// collection. Prefer the `.selected()` chainable, which sets this
96    /// role plus content color in one call.
97    Selected,
98    /// **Fill-providing.** Solid `ACCENT` fill + neutral border for
99    /// the current page / nav item. Prefer the `.current()` chainable,
100    /// which also bumps font weight and content color.
101    Current,
102    /// **Fill-providing.** Same recipe as `Sunken` — used by text
103    /// inputs and other editable surfaces.
104    Input,
105    /// **Decorative.** Destructive-toned border, no shadow. Pair with
106    /// a tint fill (e.g. `tokens::DESTRUCTIVE.with_alpha_u8(40)`) for the
107    /// classic "danger" band in a form or section header.
108    Danger,
109}
110
111impl SurfaceRole {
112    pub fn name(self) -> &'static str {
113        match self {
114            SurfaceRole::None => "none",
115            SurfaceRole::Panel => "panel",
116            SurfaceRole::Raised => "raised",
117            SurfaceRole::Sunken => "sunken",
118            SurfaceRole::Popover => "popover",
119            SurfaceRole::Selected => "selected",
120            SurfaceRole::Current => "current",
121            SurfaceRole::Input => "input",
122            SurfaceRole::Danger => "danger",
123        }
124    }
125
126    pub fn uniform_id(self) -> f32 {
127        match self {
128            SurfaceRole::None => 0.0,
129            SurfaceRole::Panel => 1.0,
130            SurfaceRole::Raised => 2.0,
131            SurfaceRole::Sunken => 3.0,
132            SurfaceRole::Popover => 4.0,
133            SurfaceRole::Selected => 5.0,
134            SurfaceRole::Current => 6.0,
135            SurfaceRole::Input => 7.0,
136            SurfaceRole::Danger => 8.0,
137        }
138    }
139}
140
141/// Interaction state, applied as a render-time visual delta.
142#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
143#[non_exhaustive]
144pub enum InteractionState {
145    #[default]
146    Default,
147    Hover,
148    Press,
149    Focus,
150    Disabled,
151    Loading,
152}
153
154/// Recorded source location for an element. Set automatically via
155/// `#[track_caller]` on every constructor.
156///
157/// `from_library` distinguishes Els constructed inside damascene's own
158/// widget closures (where the closure boundary defeats
159/// `#[track_caller]` and the recorded location lands inside damascene-core
160/// instead of at the user's call site) from Els constructed in user
161/// code. The lint pass uses this to gate user-facing findings and to
162/// walk blame attribution upward to the nearest user-source ancestor.
163/// Set explicitly via [`crate::tree::El::from_library`] at the few
164/// closure-builder sites that need it.
165#[derive(Clone, Copy, Debug, Default)]
166#[non_exhaustive]
167pub struct Source {
168    pub file: &'static str,
169    pub line: u32,
170    pub from_library: bool,
171}
172
173impl Source {
174    pub fn from_caller(loc: &'static Location<'static>) -> Self {
175        Self {
176            file: loc.file(),
177            line: loc.line(),
178            from_library: false,
179        }
180    }
181}