Skip to main content

scena/scene/
labels.rs

1use crate::diagnostics::LookupError;
2use crate::material::Color;
3
4use super::{LabelKey, NodeKey, NodeKind, Scene, Transform};
5
6#[derive(Debug, Clone, PartialEq)]
7pub struct LabelDesc {
8    text: String,
9    rasterization: LabelRasterization,
10    billboard: LabelBillboard,
11    color: Color,
12    size: f32,
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum LabelRasterization {
17    Sdf,
18    Msdf,
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum LabelBillboard {
23    ScreenAligned,
24}
25
26impl Scene {
27    pub fn add_label(
28        &mut self,
29        parent: NodeKey,
30        label: LabelDesc,
31        transform: Transform,
32    ) -> Result<LabelKey, LookupError> {
33        let label_key = self.labels.insert(label);
34        if let Err(error) = self.insert_node(parent, NodeKind::Label(label_key), transform) {
35            self.labels.remove(label_key);
36            return Err(error);
37        }
38        Ok(label_key)
39    }
40
41    pub fn label(&self, label: LabelKey) -> Option<&LabelDesc> {
42        self.labels.get(label)
43    }
44
45    pub fn set_label_text(
46        &mut self,
47        label: LabelKey,
48        text: impl Into<String>,
49    ) -> Result<(), LookupError> {
50        let label = self
51            .labels
52            .get_mut(label)
53            .ok_or(LookupError::LabelNotFound(label))?;
54        let text = text.into();
55        if label.text != text {
56            label.text = text;
57            self.structure_revision = self.structure_revision.saturating_add(1);
58        }
59        Ok(())
60    }
61}
62
63impl LabelDesc {
64    pub fn sdf(text: impl Into<String>) -> Self {
65        Self::new(text, LabelRasterization::Sdf)
66    }
67
68    pub fn msdf(text: impl Into<String>) -> Self {
69        Self::new(text, LabelRasterization::Msdf)
70    }
71
72    pub fn text(&self) -> &str {
73        &self.text
74    }
75
76    pub const fn rasterization(&self) -> LabelRasterization {
77        self.rasterization
78    }
79
80    pub const fn billboard(&self) -> LabelBillboard {
81        self.billboard
82    }
83
84    pub const fn color(&self) -> Color {
85        self.color
86    }
87
88    pub const fn size(&self) -> f32 {
89        self.size
90    }
91
92    pub fn with_color(mut self, color: Color) -> Self {
93        self.color = color;
94        self
95    }
96
97    pub fn with_size(mut self, size: f32) -> Self {
98        self.size = positive_or(size, 1.0);
99        self
100    }
101
102    pub const fn with_billboard(mut self, billboard: LabelBillboard) -> Self {
103        self.billboard = billboard;
104        self
105    }
106
107    fn new(text: impl Into<String>, rasterization: LabelRasterization) -> Self {
108        Self {
109            text: text.into(),
110            rasterization,
111            billboard: LabelBillboard::ScreenAligned,
112            color: Color::WHITE,
113            size: 1.0,
114        }
115    }
116}
117
118fn positive_or(value: f32, fallback: f32) -> f32 {
119    if !value.is_finite() || value <= 0.0 {
120        fallback
121    } else {
122        value
123    }
124}