fyrox_ui/node/
container.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! A wrapper for node pool record that allows to define custom visit method to have full
22//! control over instantiation process at deserialization.
23
24use crate::{
25    constructor::WidgetConstructorContainer,
26    core::{
27        pool::PayloadContainer,
28        reflect::prelude::*,
29        uuid::Uuid,
30        visitor::{Visit, VisitError, VisitResult, Visitor},
31    },
32    UiNode,
33};
34
35/// A wrapper for widget pool record that allows to define custom visit method to have full
36/// control over instantiation process at deserialization.
37#[derive(Debug, Default, Reflect)]
38pub struct WidgetContainer(Option<UiNode>);
39
40fn read_widget(name: &str, visitor: &mut Visitor) -> Result<UiNode, VisitError> {
41    let mut region = visitor.enter_region(name)?;
42
43    let mut id = Uuid::default();
44    id.visit("TypeUuid", &mut region)?;
45
46    let serialization_context = region
47        .blackboard
48        .get::<WidgetConstructorContainer>()
49        .expect("Visitor environment must contain serialization context!");
50
51    let mut widget = serialization_context
52        .try_create(&id)
53        .ok_or_else(|| panic!("Unknown widget type uuid {id}!"))
54        .unwrap();
55
56    widget.visit("WidgetData", &mut region)?;
57
58    Ok(widget)
59}
60
61fn write_widget(name: &str, widget: &mut UiNode, visitor: &mut Visitor) -> VisitResult {
62    let mut region = visitor.enter_region(name)?;
63
64    let mut id = widget.id();
65    id.visit("TypeUuid", &mut region)?;
66
67    widget.visit("WidgetData", &mut region)?;
68
69    Ok(())
70}
71
72impl Visit for WidgetContainer {
73    fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
74        let mut region = visitor.enter_region(name)?;
75
76        let mut is_some = u8::from(self.is_some());
77        is_some.visit("IsSome", &mut region)?;
78
79        if is_some != 0 {
80            if region.is_reading() {
81                *self = WidgetContainer(Some(read_widget("Data", &mut region)?));
82            } else {
83                write_widget("Data", self.0.as_mut().unwrap(), &mut region)?;
84            }
85        }
86
87        Ok(())
88    }
89}
90
91impl PayloadContainer for WidgetContainer {
92    type Element = UiNode;
93
94    fn new_empty() -> Self {
95        Self(None)
96    }
97
98    fn new(element: Self::Element) -> Self {
99        Self(Some(element))
100    }
101
102    fn is_some(&self) -> bool {
103        self.0.is_some()
104    }
105
106    fn as_ref(&self) -> Option<&Self::Element> {
107        self.0.as_ref()
108    }
109
110    fn as_mut(&mut self) -> Option<&mut Self::Element> {
111        self.0.as_mut()
112    }
113
114    fn replace(&mut self, element: Self::Element) -> Option<Self::Element> {
115        self.0.replace(element)
116    }
117
118    fn take(&mut self) -> Option<Self::Element> {
119        self.0.take()
120    }
121}