Skip to main content

w_gui/
element.rs

1use std::sync::Arc;
2
3use serde::{Deserialize, Serialize};
4
5pub type ElementId = String;
6
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
8#[serde(tag = "type", content = "data")]
9pub enum Value {
10    Float(f64),
11    Bool(bool),
12    Color3([f32; 3]),
13    Color4([f32; 4]),
14    Vec2([f32; 2]),
15    Vec3([f32; 3]),
16    Int(i64),
17    String(String),
18    Enum {
19        selected: usize,
20        options: Vec<String>,
21    },
22    /// Transient: true for one frame when clicked
23    Button(bool),
24    /// Progress value (0.0 to 1.0)
25    Progress(f64),
26    /// Stat card value with optional subvalue
27    StatValue {
28        value: String,
29        subvalue: Option<String>,
30    },
31    /// Status indicator state
32    StatusValue {
33        active: bool,
34        #[serde(skip_serializing_if = "Option::is_none")]
35        active_text: Option<String>,
36        #[serde(skip_serializing_if = "Option::is_none")]
37        inactive_text: Option<String>,
38        #[serde(skip_serializing_if = "Option::is_none")]
39        active_color: Option<String>,
40        #[serde(skip_serializing_if = "Option::is_none")]
41        inactive_color: Option<String>,
42    },
43    /// Mini chart data
44    ChartValue {
45        values: Vec<f32>,
46        #[serde(skip_serializing_if = "Option::is_none")]
47        current: Option<f32>,
48        #[serde(skip_serializing_if = "Option::is_none")]
49        unit: Option<String>,
50    },
51    /// Grid container data
52    GridValue {
53        cols: usize,
54        children: Vec<String>,
55    },
56    /// Plot data for larger charts
57    PlotValue {
58        series: Vec<PlotSeries>,
59        #[serde(skip_serializing_if = "Option::is_none")]
60        x_label: Option<String>,
61        #[serde(skip_serializing_if = "Option::is_none")]
62        y_label: Option<String>,
63    },
64    /// Null value for container elements
65    Null,
66}
67
68/// A data series for plotting
69#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
70pub struct PlotSeries {
71    pub name: String,
72    pub values: Vec<f32>,
73    pub color: String,
74    /// Whether this series should use relative autoscaling
75    /// When true, the series is scaled independently
76    /// When false, the series uses the plot's shared scale
77    #[serde(default = "default_autoscale")]
78    pub autoscale: bool,
79}
80
81fn default_autoscale() -> bool {
82    true
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
86#[serde(tag = "type", content = "data")]
87pub enum ElementKind {
88    Slider,
89    Checkbox,
90    ColorPicker3,
91    ColorPicker4,
92    TextInput,
93    Dropdown,
94    Button,
95    Label,
96    Separator,
97    /// Section header for grouping
98    Section,
99    /// Progress bar with percentage
100    ProgressBar,
101    /// Stat card display
102    Stat,
103    /// Status indicator with colored dot
104    Status,
105    /// Mini sparkline chart
106    MiniChart,
107    /// Grid layout container
108    Grid,
109    /// Larger plot/chart for data visualization
110    Plot,
111    /// Compact key-value display
112    KeyValue,
113    /// Compact button for dense UIs
114    ButtonCompact,
115    /// Horizontal layout container
116    Horizontal,
117    /// Inline button without label column (for horizontal layouts)
118    ButtonInline,
119    /// Inline text input without label column (for horizontal layouts)
120    TextInputInline,
121}
122
123#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
124pub struct ElementMeta {
125    #[serde(skip_serializing_if = "Option::is_none")]
126    pub min: Option<f64>,
127    #[serde(skip_serializing_if = "Option::is_none")]
128    pub max: Option<f64>,
129    #[serde(skip_serializing_if = "Option::is_none")]
130    pub step: Option<f64>,
131    /// Accent color for the element
132    #[serde(skip_serializing_if = "Option::is_none")]
133    pub accent: Option<AccentColor>,
134    /// Subtitle or secondary text
135    #[serde(skip_serializing_if = "Option::is_none")]
136    pub subtitle: Option<String>,
137    /// Number of columns for grid layout
138    #[serde(skip_serializing_if = "Option::is_none")]
139    pub cols: Option<usize>,
140    /// Child element IDs for grid layout
141    #[serde(skip_serializing_if = "Option::is_none")]
142    pub children: Option<Vec<String>>,
143}
144
145#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
146pub struct ElementDecl {
147    pub id: ElementId,
148    pub kind: ElementKind,
149    pub label: String,
150    pub value: Value,
151    pub meta: ElementMeta,
152    pub window: Arc<str>,
153}
154
155/// Accent colors available for UI elements
156#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
157#[serde(rename_all = "lowercase")]
158pub enum AccentColor {
159    Coral,
160    Teal,
161    Blue,
162    Green,
163    Purple,
164    Orange,
165    Yellow,
166    Red,
167}
168
169impl AccentColor {
170    pub fn as_str(&self) -> &'static str {
171        match self {
172            AccentColor::Coral => "coral",
173            AccentColor::Teal => "teal",
174            AccentColor::Blue => "blue",
175            AccentColor::Green => "green",
176            AccentColor::Purple => "purple",
177            AccentColor::Orange => "orange",
178            AccentColor::Yellow => "yellow",
179            AccentColor::Red => "red",
180        }
181    }
182}