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