1use std::{
2 borrow::Cow,
3 hash::Hash,
4 ops::{
5 Deref,
6 DerefMut,
7 },
8 rc::Rc,
9};
10
11use torin::{
12 prelude::Area,
13 torin::Torin,
14};
15
16use crate::{
17 accessibility::{
18 dirty_nodes::AccessibilityDirtyNodes,
19 focusable::Focusable,
20 groups::AccessibilityGroups,
21 id::{
22 AccessibilityGenerator,
23 AccessibilityId,
24 },
25 tree::ACCESSIBILITY_ROOT_ID,
26 },
27 element::ElementExt,
28 layers::{
29 Layer,
30 Layers,
31 },
32 node_id::NodeId,
33 prelude::AccessibilityFocusStrategy,
34 style::{
35 border::Border,
36 color::Color,
37 corner_radius::CornerRadius,
38 fill::Fill,
39 font_size::FontSize,
40 font_slant::FontSlant,
41 font_weight::FontWeight,
42 font_width::FontWidth,
43 scale::Scale,
44 shadow::Shadow,
45 text_align::TextAlign,
46 text_height::TextHeightBehavior,
47 text_overflow::TextOverflow,
48 text_shadow::TextShadow,
49 },
50};
51
52#[derive(Debug, Default, Clone, PartialEq)]
53pub struct LayoutData {
54 pub layout: torin::node::Node,
55}
56
57impl From<torin::node::Node> for LayoutData {
58 fn from(layout: torin::node::Node) -> Self {
59 LayoutData { layout }
60 }
61}
62
63impl Deref for LayoutData {
64 type Target = torin::node::Node;
65
66 fn deref(&self) -> &Self::Target {
67 &self.layout
68 }
69}
70
71impl DerefMut for LayoutData {
72 fn deref_mut(&mut self) -> &mut Self::Target {
73 &mut self.layout
74 }
75}
76
77#[derive(Debug, Default, Clone, PartialEq)]
78pub struct EffectData {
79 pub overflow: Overflow,
80 pub rotation: Option<f32>,
81 pub scale: Option<Scale>,
82 pub opacity: Option<f32>,
83 pub scrollable: bool,
84 pub interactive: Interactive,
85}
86
87#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
88#[derive(Debug, Default, Clone, PartialEq)]
89pub struct StyleState {
90 pub background: Fill,
91 pub corner_radius: CornerRadius,
92 pub borders: Vec<Border>,
93 pub shadows: Vec<Shadow>,
94}
95
96#[derive(Debug, Clone, PartialEq)]
97pub struct CursorStyleData {
98 pub color: Color,
99 pub highlight_color: Color,
100}
101
102impl Default for CursorStyleData {
103 fn default() -> Self {
104 Self {
105 color: Color::BLACK,
106 highlight_color: Color::from_rgb(87, 108, 188),
107 }
108 }
109}
110
111#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
112#[derive(Debug, Clone, PartialEq, Hash)]
113pub struct TextStyleState {
114 pub font_size: FontSize,
115 pub color: Color,
116 pub text_align: TextAlign,
117 pub font_families: Vec<Cow<'static, str>>,
118 pub text_height: TextHeightBehavior,
119 pub text_overflow: TextOverflow,
120 pub text_shadows: Vec<TextShadow>,
121 pub font_slant: FontSlant,
122 pub font_weight: FontWeight,
123 pub font_width: FontWidth,
124}
125
126impl Default for TextStyleState {
127 fn default() -> Self {
128 Self {
129 font_size: FontSize::default(),
130 color: Color::BLACK,
131 text_align: TextAlign::default(),
132 font_families: Vec::new(),
133 text_height: TextHeightBehavior::default(),
134 text_overflow: TextOverflow::default(),
135 text_shadows: Vec::new(),
136 font_slant: FontSlant::default(),
137 font_weight: FontWeight::default(),
138 font_width: FontWidth::default(),
139 }
140 }
141}
142
143impl TextStyleState {
144 pub fn from_data(parent: &TextStyleState, data: &TextStyleData) -> Self {
145 let color = data.color.unwrap_or(parent.color);
146
147 let text_align = data.text_align.unwrap_or_default();
148 let text_height = data.text_height.unwrap_or_default();
149 let text_overflow = data.text_overflow.clone().unwrap_or_default();
150 let text_shadows = data.text_shadows.clone();
151
152 let font_size = data.font_size.unwrap_or(parent.font_size);
154 let font_slant = data.font_slant.unwrap_or(parent.font_slant);
155 let font_weight = data.font_weight.unwrap_or(parent.font_weight);
156 let font_width = data.font_width.unwrap_or(parent.font_width);
157 let mut font_families = data.font_families.clone();
158 font_families.extend_from_slice(&parent.font_families);
159
160 Self {
161 color,
162 text_align,
163 text_height,
164 text_overflow,
165 text_shadows,
166 font_size,
167 font_slant,
168 font_weight,
169 font_width,
170 font_families,
171 }
172 }
173
174 pub fn update(
175 &mut self,
176 node_id: NodeId,
177 parent_text_style: &Self,
178 element: &Rc<dyn ElementExt>,
179 layout: &mut Torin<NodeId>,
180 ) {
181 let text_style_data = element.text_style();
182
183 let text_style = Self::from_data(parent_text_style, &text_style_data);
184 let is_equal = *self == text_style;
185
186 *self = text_style;
187
188 if !is_equal {
189 layout.invalidate(node_id);
191 }
192 }
193}
194
195#[derive(Debug, Clone, PartialEq, Default, Hash)]
196pub struct TextStyleData {
197 pub color: Option<Color>,
198 pub font_size: Option<FontSize>,
199 pub font_families: Vec<Cow<'static, str>>,
200 pub text_align: Option<TextAlign>,
201 pub text_height: Option<TextHeightBehavior>,
202 pub text_overflow: Option<TextOverflow>,
203 pub text_shadows: Vec<TextShadow>,
204 pub font_slant: Option<FontSlant>,
205 pub font_weight: Option<FontWeight>,
206 pub font_width: Option<FontWidth>,
207}
208
209#[derive(Debug, Default)]
210pub struct LayerState {
211 pub layer: i16,
212}
213
214impl LayerState {
215 pub fn create_for_root(node_id: NodeId, layers: &mut Layers) -> Self {
216 let layer = 0;
217
218 layers.insert_node_in_layer(node_id, layer);
219
220 Self { layer }
221 }
222
223 pub fn remove(self, node_id: NodeId, layers: &mut Layers) {
224 layers.remove_node_from_layer(&node_id, self.layer);
225 }
226
227 pub fn update(
228 &mut self,
229 parent_layer: &Self,
230 node_id: NodeId,
231 element: &Rc<dyn ElementExt>,
232 layers: &mut Layers,
233 ) {
234 let relative_layer = element.layer();
235
236 layers.remove_node_from_layer(&node_id, self.layer);
238
239 self.layer = match relative_layer {
241 Layer::Relative(relative_layer) => parent_layer.layer + relative_layer + 1,
242 Layer::Overlay => i16::MAX / 2,
243 };
244 layers.insert_node_in_layer(node_id, self.layer);
245 }
246}
247
248#[derive(Clone, Debug, PartialEq, Eq, Default, Copy)]
249pub enum Overflow {
250 #[default]
251 None,
252 Clip,
253}
254
255#[derive(Clone, Debug, PartialEq, Eq, Default, Copy)]
256pub enum Interactive {
257 #[default]
258 Yes,
259 No,
260}
261
262impl From<bool> for Interactive {
263 fn from(value: bool) -> Self {
264 match value {
265 true => Interactive::Yes,
266 false => Interactive::No,
267 }
268 }
269}
270
271#[derive(PartialEq, Default, Debug, Clone)]
272pub struct EffectState {
273 pub overflow: Overflow,
274 pub clips: Rc<[NodeId]>,
275
276 pub rotations: Rc<[NodeId]>,
277 pub rotation: Option<f32>,
278
279 pub scales: Rc<[NodeId]>,
280 pub scale: Option<Scale>,
281
282 pub opacities: Rc<[f32]>,
283
284 pub scrollables: Rc<[NodeId]>,
285
286 pub interactive: Interactive,
287}
288
289impl EffectState {
290 pub fn update(
291 &mut self,
292 parent_node_id: NodeId,
293 parent_effect_state: &Self,
294 node_id: NodeId,
295 effect_data: Option<Cow<'_, EffectData>>,
296 ) {
297 *self = Self {
298 overflow: Overflow::default(),
299 ..parent_effect_state.clone()
300 };
301
302 if parent_effect_state.overflow == Overflow::Clip {
303 let mut clips = parent_effect_state.clips.to_vec();
304 clips.push(parent_node_id);
305 if self.clips.as_ref() != clips {
306 self.clips = Rc::from(clips);
307 }
308 }
309
310 if let Some(effect_data) = effect_data {
311 self.overflow = effect_data.overflow;
312
313 if let Some(rotation) = effect_data.rotation {
314 let mut rotations = parent_effect_state.rotations.to_vec();
315 rotations.push(node_id);
316 self.rotation = Some(rotation);
317 if self.rotations.as_ref() != rotations {
318 self.rotations = Rc::from(rotations);
319 }
320 }
321
322 if let Some(scale) = effect_data.scale {
323 let mut scales = parent_effect_state.scales.to_vec();
324 scales.push(node_id);
325 self.scale = Some(scale);
326 if self.scales.as_ref() != scales {
327 self.scales = Rc::from(scales);
328 }
329 }
330
331 if let Some(opacity) = effect_data.opacity {
332 let mut opacities = parent_effect_state.opacities.to_vec();
333 opacities.push(opacity);
334 if self.opacities.as_ref() != opacities {
335 self.opacities = Rc::from(opacities);
336 }
337 }
338
339 if effect_data.scrollable {
340 let mut scrolls = parent_effect_state.scrollables.to_vec();
341 scrolls.push(node_id);
342 if self.scrollables.as_ref() != scrolls {
343 self.scrollables = Rc::from(scrolls);
344 }
345 }
346
347 self.interactive = effect_data.interactive;
348 }
349 }
350
351 pub fn is_visible(&self, layout: &Torin<NodeId>, area: &Area) -> bool {
352 for viewport_id in self.clips.iter() {
354 let viewport = layout.get(viewport_id).unwrap().visible_area();
355 if !viewport.intersects(area) {
356 return false;
357 }
358 }
359 true
360 }
361}
362
363#[derive(PartialEq, Clone)]
364pub struct AccessibilityState {
365 pub a11y_id: AccessibilityId,
366 pub a11y_focusable: Focusable,
367 pub a11y_member_of: Option<AccessibilityId>,
368}
369
370impl AccessibilityState {
371 pub fn create(
372 node_id: NodeId,
373 element: &Rc<dyn ElementExt>,
374 accessibility_diff: &mut AccessibilityDirtyNodes,
375 accessibility_generator: &AccessibilityGenerator,
376 accessibility_groups: &mut AccessibilityGroups,
377 ) -> Self {
378 let data = element.accessibility();
379
380 let a11y_id = if node_id == NodeId::ROOT {
381 ACCESSIBILITY_ROOT_ID
382 } else {
383 data.a11y_id
384 .unwrap_or_else(|| AccessibilityId(accessibility_generator.new_id()))
385 };
386
387 accessibility_diff.add_or_update(node_id);
388
389 if let Some(member_of) = data.builder.member_of() {
390 let group = accessibility_groups.entry(member_of).or_default();
391 group.push(a11y_id);
395 }
396
397 if data.a11y_auto_focus {
398 accessibility_diff.request_focus(AccessibilityFocusStrategy::Node(a11y_id));
399 }
400
401 Self {
402 a11y_id,
403 a11y_focusable: data.a11y_focusable.clone(),
404 a11y_member_of: data.builder.member_of(),
405 }
406 }
407
408 pub fn remove(
409 self,
410 node_id: NodeId,
411 parent_id: NodeId,
412 accessibility_diff: &mut AccessibilityDirtyNodes,
413 accessibility_groups: &mut AccessibilityGroups,
414 ) {
415 accessibility_diff.remove(node_id, parent_id);
416
417 if let Some(member_of) = self.a11y_member_of {
418 let group = accessibility_groups.get_mut(&member_of).unwrap();
419 group.retain(|id| *id != self.a11y_id);
420 }
421 }
422
423 pub fn update(
424 &mut self,
425 node_id: NodeId,
426 element: &Rc<dyn ElementExt>,
427 accessibility_diff: &mut AccessibilityDirtyNodes,
428 accessibility_groups: &mut AccessibilityGroups,
429 ) {
430 let data = element.accessibility();
431
432 if let Some(member_of) = self.a11y_member_of
433 && self.a11y_member_of != data.builder.member_of()
434 {
435 let group = accessibility_groups.get_mut(&member_of).unwrap();
436 group.retain(|id| *id != self.a11y_id);
437 }
438
439 if let Some(a11y_id) = data.a11y_id
440 && self.a11y_id != a11y_id
441 {
442 accessibility_diff.add_or_update(node_id);
443 self.a11y_id = a11y_id;
444 }
445
446 if let Some(member_of) = data.builder.member_of() {
447 let group = accessibility_groups.entry(member_of).or_default();
448 group.push(self.a11y_id);
452
453 self.a11y_member_of = Some(member_of);
454 }
455
456 self.a11y_focusable = data.a11y_focusable.clone();
457 }
458}
459
460#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
461#[derive(Debug, Default, Clone, PartialEq)]
462pub struct AccessibilityData {
463 pub a11y_id: Option<AccessibilityId>,
464 pub a11y_auto_focus: bool,
465 pub a11y_focusable: Focusable,
466 pub builder: accesskit::Node,
467}