Skip to main content

morph_ir/
style.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Default, Serialize, Deserialize)]
4pub struct IRStyle {
5    pub bg_color: [f32; 4],
6    pub color: [f32; 4],
7    pub width: Option<f32>,
8    pub min_width: Option<f32>,
9    pub max_width: Option<f32>,
10    pub height: Option<f32>,
11    pub min_height: Option<f32>,
12    pub max_height: Option<f32>,
13    pub margin: [f32; 4],
14    pub margin_auto: [bool; 4],
15    pub padding: [f32; 4],
16    pub border_radius: f32,
17    pub font_size: f32,
18    pub font_weight: String,
19    pub text_align: String,
20    pub display: String,
21    pub flex_dir: String,
22    pub flex_grow: f32,
23    pub flex_shrink: f32,
24    pub flex_basis: String,
25    pub gap: f32,
26    pub position: String,
27    pub left: Option<f32>,
28    pub right: Option<f32>,
29    pub top: Option<f32>,
30    pub bottom: Option<f32>,
31    pub justify_content: String,
32    pub align_items: String,
33    pub flex_wrap: String,
34    pub cursor: String,
35    pub overflow: String,
36    pub border_width: f32,
37    pub border_color: [f32; 4],
38    pub border_style: String,
39    pub box_sizing: String,
40    pub z_index: Option<i32>,
41    pub opacity: f32,
42    // ── Scrollbar (feature: scrollbar) ───────────────────────────────
43    pub scrollbar_width: f32,
44    pub scrollbar_track_color: [f32; 4],
45    pub scrollbar_thumb_color: [f32; 4],
46    pub scrollbar_border_radius: f32,
47    // ── Transform (feature: transform) ───────────────────────────────
48    pub transform_ops: Option<Vec<crate::transforms::TransformOp>>,
49    pub transform_matrix: Option<[f32; 16]>,
50    pub transform_origin: Option<((f32, bool), (f32, bool))>,
51    pub transform_origin_resolved: Option<(f32, f32)>,
52}
53
54impl IRStyle {
55    pub fn new() -> Self {
56        Self {
57            bg_color: [0.0, 0.0, 0.0, 0.0],
58            color: [0.0, 0.0, 0.0, 1.0],
59            border_color: [0.0, 0.0, 0.0, 1.0],
60            width: None,
61            height: None,
62            font_size: 16.0,
63            display: "block".to_string(),
64            position: "static".to_string(),
65            flex_dir: "row".to_string(),
66            justify_content: "flex-start".to_string(),
67            align_items: "stretch".to_string(),
68            overflow: "visible".to_string(),
69            opacity: 1.0,
70            border_style: "none".to_string(),
71            box_sizing: "content-box".to_string(),
72            cursor: "default".to_string(),
73            flex_shrink: 1.0,
74            font_weight: "normal".to_string(),
75            text_align: "left".to_string(),
76            flex_basis: "auto".to_string(),
77            flex_wrap: "nowrap".to_string(),
78            scrollbar_width: 8.0,
79            scrollbar_track_color: [0.85, 0.85, 0.85, 0.4],
80            scrollbar_thumb_color: [0.5, 0.5, 0.5, 0.6],
81            scrollbar_border_radius: 4.0,
82            ..Default::default()
83        }
84    }
85
86    /// True when no meaningful style delta has been applied for a pseudo
87    /// (hover/active) bucket, i.e. every field is still at its default.
88    pub fn is_empty_style(&self) -> bool {
89        self.bg_color == [0.0, 0.0, 0.0, 0.0]
90            && self.color == [0.0, 0.0, 0.0, 1.0]
91            && self.border_color == [0.0, 0.0, 0.0, 1.0]
92            && self.border_width == 0.0
93            && self.border_style == "none"
94            && self.width.is_none()
95            && self.height.is_none()
96            && self.min_width.is_none()
97            && self.max_width.is_none()
98            && self.min_height.is_none()
99            && self.max_height.is_none()
100            && self.padding == [0.0, 0.0, 0.0, 0.0]
101            && self.margin == [0.0, 0.0, 0.0, 0.0]
102            && self.border_radius == 0.0
103            && self.font_size == 16.0
104            && self.font_weight == "normal"
105            && self.text_align == "left"
106            && self.display == "block"
107            && self.flex_dir == "row"
108            && self.gap == 0.0
109            && self.position == "static"
110            && self.justify_content == "flex-start"
111            && self.align_items == "stretch"
112            && self.flex_wrap == "nowrap"
113            && self.cursor == "default"
114            && self.overflow == "visible"
115            && self.box_sizing == "content-box"
116            && self.opacity == 1.0
117            && self.z_index.is_none()
118            && self.left.is_none()
119            && self.right.is_none()
120            && self.top.is_none()
121            && self.bottom.is_none()
122            && self.transform_matrix.is_none()
123            && self.transform_origin.is_none()
124    }
125}