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