freya_core/states/
viewport.rs

1use freya_native_core::{
2    attributes::AttributeName,
3    exports::shipyard::Component,
4    node_ref::NodeView,
5    prelude::{
6        AttributeMaskBuilder,
7        Dependancy,
8        NodeMaskBuilder,
9        State,
10    },
11    NodeId,
12    SendAnyMap,
13};
14use freya_native_core_macro::partial_derive_state;
15
16use crate::{
17    custom_attributes::CustomAttributeValues,
18    parsing::{
19        Parse,
20        ParseAttribute,
21        ParseError,
22    },
23    values::OverflowMode,
24};
25
26#[derive(Default, PartialEq, Clone, Debug, Component)]
27pub struct ViewportState {
28    pub viewports: Vec<NodeId>,
29    pub node_id: NodeId,
30    pub overflow: OverflowMode,
31}
32
33impl ParseAttribute for ViewportState {
34    fn parse_attribute(
35        &mut self,
36        attr: freya_native_core::prelude::OwnedAttributeView<CustomAttributeValues>,
37    ) -> Result<(), ParseError> {
38        #[allow(clippy::single_match)]
39        match attr.attribute {
40            AttributeName::Overflow => {
41                if let Some(value) = attr.value.as_text() {
42                    self.overflow = OverflowMode::parse(value).map_err(|_| ParseError)?;
43                }
44            }
45            _ => {}
46        }
47
48        Ok(())
49    }
50}
51
52#[partial_derive_state]
53impl State<CustomAttributeValues> for ViewportState {
54    type ParentDependencies = (Self,);
55
56    type ChildDependencies = ();
57
58    type NodeDependencies = ();
59
60    const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new()
61        .with_attrs(AttributeMaskBuilder::Some(&[AttributeName::Overflow]))
62        .with_tag();
63
64    fn update<'a>(
65        &mut self,
66        node_view: NodeView<CustomAttributeValues>,
67        _node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
68        parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
69        _children: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
70        _context: &SendAnyMap,
71    ) -> bool {
72        if !node_view.node_type().is_visible_element() {
73            return false;
74        }
75
76        let mut viewports_state = ViewportState {
77            node_id: node_view.node_id(),
78            ..Default::default()
79        };
80
81        if let Some(attributes) = node_view.attributes() {
82            for attr in attributes {
83                viewports_state.parse_safe(attr)
84            }
85        }
86
87        if let Some((parent,)) = parent {
88            viewports_state.viewports.extend(parent.viewports.clone());
89            if parent.overflow == OverflowMode::Clip {
90                viewports_state.viewports.push(parent.node_id);
91            }
92        }
93
94        let changed = &viewports_state != self;
95        *self = viewports_state;
96        changed
97    }
98}