mittens_engine/engine/ecs/component/
layout.rs1use crate::engine::ecs::ComponentId;
2use crate::engine::ecs::component::Component;
3use crate::engine::ecs::component::style::SizeDimension;
4
5#[derive(Debug, Clone)]
19pub struct LayoutComponent {
20 pub available_width: f32,
22
23 pub authored_available_width: SizeDimension,
25
26 pub available_height: Option<f32>,
28
29 pub authored_available_height: Option<SizeDimension>,
31
32 pub dirty: bool,
34
35 pub unit_scale: f32,
45
46 pub inspect: bool,
53
54 pub computed_size_wu: Option<(f32, f32)>,
57
58 component: Option<ComponentId>,
59}
60
61impl LayoutComponent {
62 pub fn new(available_width: f32) -> Self {
63 Self {
64 available_width,
65 authored_available_width: SizeDimension::GlyphUnits(available_width),
66 available_height: None,
67 authored_available_height: None,
68 dirty: true,
69 unit_scale: 1.0,
70 inspect: false,
71 computed_size_wu: None,
72 component: None,
73 }
74 }
75
76 fn resolve_layout_length_gu(length: SizeDimension, unit_scale: f32) -> f32 {
77 match length {
78 SizeDimension::GlyphUnits(v) => v,
79 SizeDimension::WorldUnits(v) => {
80 if unit_scale.abs() > f32::EPSILON {
81 v / unit_scale
82 } else {
83 v
84 }
85 }
86 SizeDimension::Auto | SizeDimension::Percent(_) => {
87 debug_assert!(false, "LayoutRoot sizes only support gu or wu units");
88 0.0
89 }
90 }
91 }
92
93 fn refresh_available_bounds(&mut self) {
94 self.available_width =
95 Self::resolve_layout_length_gu(self.authored_available_width, self.unit_scale);
96 self.available_height = self
97 .authored_available_height
98 .map(|height| Self::resolve_layout_length_gu(height, self.unit_scale));
99 }
100
101 pub fn with_height(mut self, h: f32) -> Self {
102 self.set_available_height(h);
103 self
104 }
105
106 pub fn with_unit_scale(mut self, scale: f32) -> Self {
107 self.set_unit_scale(scale);
108 self
109 }
110
111 pub fn mark_dirty(&mut self) {
113 self.dirty = true;
114 }
115
116 pub fn set_available_width(&mut self, w: f32) {
118 self.set_available_width_dimension(SizeDimension::GlyphUnits(w));
119 }
120
121 pub fn set_available_width_dimension(&mut self, width: SizeDimension) {
122 self.authored_available_width = width;
123 self.refresh_available_bounds();
124 self.dirty = true;
125 }
126
127 pub fn set_available_height(&mut self, h: f32) {
128 self.set_available_height_dimension(SizeDimension::GlyphUnits(h));
129 }
130
131 pub fn set_available_height_dimension(&mut self, height: SizeDimension) {
132 self.authored_available_height = Some(height);
133 self.refresh_available_bounds();
134 self.dirty = true;
135 }
136
137 pub fn set_unit_scale(&mut self, scale: f32) {
138 self.unit_scale = scale;
139 self.refresh_available_bounds();
140 self.dirty = true;
141 }
142}
143
144impl Component for LayoutComponent {
145 fn name(&self) -> &'static str {
146 "layout"
147 }
148
149 fn set_id(&mut self, id: ComponentId) {
150 self.component = Some(id);
151 }
152
153 fn as_any(&self) -> &dyn std::any::Any {
154 self
155 }
156 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
157 self
158 }
159
160 fn to_mms_ast(
161 &self,
162 _world: &crate::engine::ecs::World,
163 ) -> crate::scripting::ast::ComponentExpression {
164 use crate::engine::ecs::component::ce_helpers::*;
165 use crate::scripting::ast::Expression;
166 use crate::scripting::token::Unit;
167
168 fn layout_dim_expr(sd: SizeDimension) -> Expression {
169 match sd {
170 SizeDimension::GlyphUnits(v) => Expression::Dimension(v as f64, Unit::GlyphUnits),
171 SizeDimension::WorldUnits(v) => Expression::Dimension(v as f64, Unit::WorldUnits),
172 SizeDimension::Percent(v) => Expression::Dimension(v as f64, Unit::Percent),
173 SizeDimension::Auto => num(0.0),
174 }
175 }
176
177 let mut ce = ce_call(
178 "LayoutRoot",
179 "width",
180 vec![layout_dim_expr(self.authored_available_width)],
181 );
182 if let Some(h) = self.authored_available_height {
183 ce = ce.with_call("height", vec![layout_dim_expr(h)]);
184 }
185 if (self.unit_scale - 1.0).abs() > f32::EPSILON {
186 ce = ce.with_call("unit_scale", nums([self.unit_scale as f64]));
187 }
188 ce
189 }
190}