fyrox_ui/inspector/editors/
inspectable.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 general-purpose property editor definition that creates
22//! a nested inspector within an [Expander](crate::expander::Expander) widget.
23use crate::{
24    core::reflect::prelude::*,
25    inspector::{
26        editors::{
27            PropertyEditorBuildContext, PropertyEditorDefinition, PropertyEditorInstance,
28            PropertyEditorMessageContext, PropertyEditorTranslationContext,
29        },
30        make_expander_container, FieldKind, Inspector, InspectorBuilder, InspectorContext,
31        InspectorError, InspectorMessage, PropertyChanged,
32    },
33    message::{MessageDirection, UiMessage},
34    widget::WidgetBuilder,
35};
36use fyrox_core::pool::Handle;
37use fyrox_core::PhantomDataSendSync;
38use fyrox_graph::BaseSceneGraph;
39use std::{
40    any::TypeId,
41    fmt::{Debug, Formatter},
42};
43
44/// A general-purpose property editor definition that creates
45/// a nested inspector within an [Expander](crate::expander::Expander) widget to allow the user
46/// to edited properties of type T.
47/// The expander is labeled with [FieldInfo::display_name].
48/// The layer_index for the inner inspector is increased by 1.
49pub struct InspectablePropertyEditorDefinition<T>
50where
51    T: Reflect + 'static,
52{
53    #[allow(dead_code)]
54    phantom: PhantomDataSendSync<T>,
55}
56
57impl<T> InspectablePropertyEditorDefinition<T>
58where
59    T: Reflect + 'static,
60{
61    pub fn new() -> Self {
62        Self {
63            phantom: Default::default(),
64        }
65    }
66}
67
68impl<T> Debug for InspectablePropertyEditorDefinition<T>
69where
70    T: Reflect + 'static,
71{
72    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
73        writeln!(f, "InspectablePropertyEditorDefinition")
74    }
75}
76
77impl<T> PropertyEditorDefinition for InspectablePropertyEditorDefinition<T>
78where
79    T: Reflect + 'static,
80{
81    fn value_type_id(&self) -> TypeId {
82        TypeId::of::<T>()
83    }
84
85    fn create_instance(
86        &self,
87        ctx: PropertyEditorBuildContext,
88    ) -> Result<PropertyEditorInstance, InspectorError> {
89        let value = ctx.property_info.cast_value::<T>()?;
90
91        let inspector_context = InspectorContext::from_object(
92            value,
93            ctx.build_context,
94            ctx.definition_container.clone(),
95            ctx.environment.clone(),
96            ctx.sync_flag,
97            ctx.layer_index + 1,
98            ctx.generate_property_string_values,
99            ctx.filter,
100            ctx.name_column_width,
101        );
102
103        let editor;
104        let container = make_expander_container(
105            ctx.layer_index,
106            ctx.property_info.display_name,
107            ctx.property_info.description,
108            Handle::NONE,
109            {
110                editor = InspectorBuilder::new(WidgetBuilder::new())
111                    .with_context(inspector_context)
112                    .build(ctx.build_context);
113                editor
114            },
115            ctx.name_column_width,
116            ctx.build_context,
117        );
118
119        Ok(PropertyEditorInstance::Custom { container, editor })
120    }
121
122    /// Instead of creating a message to update its widget,
123    /// call [InspectorContext::sync] to directly send whatever messages are necessary
124    /// and return None.
125    fn create_message(
126        &self,
127        ctx: PropertyEditorMessageContext,
128    ) -> Result<Option<UiMessage>, InspectorError> {
129        let value = ctx.property_info.cast_value::<T>()?;
130
131        let mut error_group = Vec::new();
132
133        let inspector_context = ctx
134            .ui
135            .node(ctx.instance)
136            .cast::<Inspector>()
137            .expect("Must be Inspector!")
138            .context()
139            .clone();
140        if let Err(e) = inspector_context.sync(
141            value,
142            ctx.ui,
143            ctx.layer_index + 1,
144            ctx.generate_property_string_values,
145            ctx.filter,
146        ) {
147            error_group.extend(e)
148        }
149
150        if error_group.is_empty() {
151            Ok(None)
152        } else {
153            Err(InspectorError::Group(error_group))
154        }
155    }
156
157    fn translate_message(&self, ctx: PropertyEditorTranslationContext) -> Option<PropertyChanged> {
158        if let Some(InspectorMessage::PropertyChanged(msg)) = ctx.message.data::<InspectorMessage>()
159        {
160            if ctx.message.direction() == MessageDirection::FromWidget {
161                return Some(PropertyChanged {
162                    name: ctx.name.to_owned(),
163                    owner_type_id: ctx.owner_type_id,
164                    value: FieldKind::Inspectable(Box::new(msg.clone())),
165                });
166            }
167        }
168
169        None
170    }
171}