GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
feat(label): StyledLabel::into_prim + LabelPrim — emit a measured label as a display-list Text prim
Phase 6ak support. StyledLabel measures text (builds a glyphon buffer for its
width) and, until now, could only be drawn via the legacy `draw()` into a
TextItem list. Add the source-retaining fields (src_text/src_size/src_family and
a prim_layout for the vertical/boxed case) and `into_prim(x, y) -> LabelPrim` so
a caller on the display-list path can measure-then-emit: the engine reshapes the
text through the shared cache, and the vertical bar's per-char centered wrap
rides the boxed-text TextLayout. LabelPrim mirrors PaintCtx::text_with /
text_boxed args. Re-exported through display/mod.rs and widget/mod.rs.
The legacy draw() path is untouched, so nothing else changes.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/widget/display/label.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++
src/widget/display/mod.rs | 2 +-
src/widget/mod.rs | 2 +-
3 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/src/widget/display/label.rs b/src/widget/display/label.rs
index 04ffa5a..ba43333 100644
--- a/src/widget/display/label.rs
+++ b/src/widget/display/label.rs
@@ -153,6 +153,26 @@ pub struct StyledLabel {
pub g_color: glyphon::Color,
pub strikethrough: bool,
pub strikethrough_color: Option<[f32; 4]>,
+ // Source retained so the label can be re-emitted as a display-list Text prim (Phase 6ak):
+ // the (possibly vertical-transformed) text, its size, family, and the box layout for the
+ // vertical case (per-char lines + centered wrap). `buffer` above is kept for the legacy
+ // draw()/width measurement path.
+ src_text: String,
+ src_size: f32,
+ src_family: String,
+ prim_layout: Option<crate::scene::paint::TextLayout>,
+}
+
+/// The data to emit a [`StyledLabel`] as a display-list `Prim::Text`: what
+/// [`StyledLabel::into_prim`] returns, matching `PaintCtx::text_with` / `text_boxed` args.
+pub struct LabelPrim {
+ pub text: String,
+ pub size: f32,
+ pub x: f32,
+ pub y: f32,
+ pub color: [u8; 3],
+ pub font: Option<String>,
+ pub layout: Option<crate::scene::paint::TextLayout>,
}
impl StyledLabel {
@@ -186,6 +206,21 @@ impl StyledLabel {
(color[1] * 255.0) as u8,
(color[2] * 255.0) as u8,
);
+ // Vertical text is boxed: the per-char-newline `final_text` wrapped to the bar
+ // thickness and centered — the same set_size + center-align the buffer path applied.
+ let prim_layout = if is_vert {
+ let bar_thickness = crate::BAR_THICKNESS.load(std::sync::atomic::Ordering::Relaxed) as f32;
+ Some(crate::scene::paint::TextLayout {
+ // Effectively unbounded height (the legacy vertical path used height None);
+ // align_v Top means no vertical offset, so only set_size's height sees this.
+ wrap_width: Some(bar_thickness),
+ box_height: 100_000.0,
+ align_h: crate::scene::paint::AlignH::Center,
+ align_v: crate::scene::paint::AlignV::Top,
+ })
+ } else {
+ None
+ };
Self {
buffer,
w,
@@ -193,6 +228,30 @@ impl StyledLabel {
g_color,
strikethrough: false,
strikethrough_color: None,
+ src_text: final_text,
+ src_size: size,
+ src_family: family.to_string(),
+ prim_layout,
+ }
+ }
+
+ /// Consume the label and return the data to emit it as a display-list `Prim::Text`
+ /// (Phase 6ak): the source text, size, family, and — for vertical bars — the box layout.
+ /// `x, y` are the draw position; vertical labels pin `y` to 0 (as `draw` did).
+ pub fn into_prim(self, x: f32, y: f32) -> LabelPrim {
+ let is_vert = crate::IS_VERTICAL.load(std::sync::atomic::Ordering::Relaxed);
+ LabelPrim {
+ text: self.src_text,
+ size: self.src_size,
+ x,
+ y: if is_vert { 0.0 } else { y },
+ color: [
+ (self.color[0] * 255.0) as u8,
+ (self.color[1] * 255.0) as u8,
+ (self.color[2] * 255.0) as u8,
+ ],
+ font: Some(self.src_family),
+ layout: self.prim_layout,
}
}
diff --git a/src/widget/display/mod.rs b/src/widget/display/mod.rs
index 7ed2505..061b52f 100644
--- a/src/widget/display/mod.rs
+++ b/src/widget/display/mod.rs
@@ -25,7 +25,7 @@ pub(crate) use self::text_label::make_widget_text_buffer;
pub use self::sidebar::Sidebar;
pub use self::panel::Panel;
pub use self::node::Node;
-pub use self::label::{Label, SectionHeader, StyledLabel};
+pub use self::label::{Label, SectionHeader, StyledLabel, LabelPrim};
pub use self::svg::Svg;
pub use self::float3::Float3;
pub use self::progress_bar::ProgressBar;
diff --git a/src/widget/mod.rs b/src/widget/mod.rs
index 47043ff..a454d13 100644
--- a/src/widget/mod.rs
+++ b/src/widget/mod.rs
@@ -846,7 +846,7 @@ pub use self::container::{
SplitBox, SplitDirection
};
pub use self::display::{
- TextLabel, Label, SectionHeader, StyledLabel, TextItem, Svg, UsageBar,
+ TextLabel, Label, SectionHeader, StyledLabel, LabelPrim, TextItem, Svg, UsageBar,
LayoutPreview, FontPreview, InfoBox, StatusDot, InteractiveListItem,
GraphNode, Graph, Float3, ProgressBar, StatusBar, Splitter, Node, Separator,
DotStatus, PreviewLayoutMode, Sidebar, Panel, PreviewState, ImagePreviewData, serialize_widgets,