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