fyrox_ui/inspector/editors/
inherit.rs1use crate::{
25 button::{ButtonBuilder, ButtonMessage},
26 core::{
27 pool::Handle, reflect::prelude::*, reflect::FieldValue, type_traits::prelude::*,
28 uuid_provider, variable::InheritableVariable, visitor::prelude::*, PhantomDataSendSync,
29 },
30 define_constructor,
31 grid::{Column, GridBuilder, Row},
32 inspector::{
33 editors::{
34 PropertyEditorBuildContext, PropertyEditorDefinition, PropertyEditorInstance,
35 PropertyEditorMessageContext, PropertyEditorTranslationContext,
36 },
37 InspectorError, PropertyChanged,
38 },
39 inspector::{FieldKind, InheritableAction},
40 message::UiMessage,
41 utils::make_simple_tooltip,
42 widget::WidgetBuilder,
43 BuildContext, Control, MessageDirection, Thickness, UiNode, UserInterface, VerticalAlignment,
44 Widget, WidgetMessage,
45};
46use fyrox_graph::BaseSceneGraph;
47use std::{
48 any::TypeId,
49 fmt::{Debug, Formatter},
50 ops::{Deref, DerefMut},
51};
52
53#[derive(Debug, Clone, PartialEq, Eq)]
54pub enum InheritablePropertyEditorMessage {
55 Revert,
56 Modified(bool),
57}
58
59impl InheritablePropertyEditorMessage {
60 define_constructor!(InheritablePropertyEditorMessage:Revert => fn revert(), layout: false);
61 define_constructor!(InheritablePropertyEditorMessage:Modified => fn modified(bool), layout: false);
62}
63
64#[derive(Debug, Clone, Visit, Reflect, ComponentProvider)]
65pub struct InheritablePropertyEditor {
66 widget: Widget,
67 revert: Handle<UiNode>,
68 inner_editor: Handle<UiNode>,
69}
70
71impl Deref for InheritablePropertyEditor {
72 type Target = Widget;
73
74 fn deref(&self) -> &Self::Target {
75 &self.widget
76 }
77}
78
79impl DerefMut for InheritablePropertyEditor {
80 fn deref_mut(&mut self) -> &mut Self::Target {
81 &mut self.widget
82 }
83}
84
85uuid_provider!(InheritablePropertyEditor = "d5dce72c-a54b-4754-96a3-2e923eaa802f");
86
87impl Control for InheritablePropertyEditor {
88 fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
89 self.widget.handle_routed_message(ui, message);
90
91 if let Some(ButtonMessage::Click) = message.data() {
92 if message.destination() == self.revert {
93 ui.send_message(InheritablePropertyEditorMessage::revert(
94 self.handle,
95 MessageDirection::FromWidget,
96 ));
97 }
98 } else if let Some(InheritablePropertyEditorMessage::Modified(modified)) = message.data() {
99 if message.destination() == self.handle {
100 ui.send_message(WidgetMessage::visibility(
101 self.revert,
102 MessageDirection::ToWidget,
103 *modified,
104 ));
105 }
106 }
107
108 if message.destination() == self.inner_editor
114 && message.direction == MessageDirection::FromWidget
115 {
116 let mut clone = message.clone();
117 clone.destination = self.handle;
118 ui.send_message(clone);
119 }
120 }
121}
122
123struct InheritablePropertyEditorBuilder {
124 widget_builder: WidgetBuilder,
125 inner_editor: Handle<UiNode>,
126 container: Handle<UiNode>,
127 modified: bool,
128}
129
130impl InheritablePropertyEditorBuilder {
131 pub fn new(widget_builder: WidgetBuilder) -> Self {
132 Self {
133 widget_builder,
134 inner_editor: Handle::NONE,
135 container: Handle::NONE,
136 modified: false,
137 }
138 }
139
140 pub fn with_inner_editor(mut self, inner_editor: Handle<UiNode>) -> Self {
141 self.inner_editor = inner_editor;
142 self
143 }
144
145 pub fn with_container(mut self, container: Handle<UiNode>) -> Self {
146 self.container = container;
147 self
148 }
149
150 pub fn with_modified(mut self, modified: bool) -> Self {
151 self.modified = modified;
152 self
153 }
154
155 pub fn build(self, ctx: &mut BuildContext) -> Handle<UiNode> {
156 let revert;
157 let grid = GridBuilder::new(WidgetBuilder::new().with_child(self.container).with_child({
158 revert = ButtonBuilder::new(
159 WidgetBuilder::new()
160 .with_visibility(self.modified)
161 .with_width(16.0)
162 .with_height(16.0)
163 .with_vertical_alignment(VerticalAlignment::Top)
164 .with_tooltip(make_simple_tooltip(ctx, "Revert To Parent"))
165 .with_margin(Thickness::uniform(1.0))
166 .on_column(1),
167 )
168 .with_text("<")
169 .build(ctx);
170 revert
171 }))
172 .add_row(Row::auto())
173 .add_column(Column::stretch())
174 .add_column(Column::auto())
175 .build(ctx);
176
177 ctx.add_node(UiNode::new(InheritablePropertyEditor {
178 widget: self.widget_builder.with_child(grid).build(ctx),
179 revert,
180 inner_editor: self.inner_editor,
181 }))
182 }
183}
184
185pub struct InheritablePropertyEditorDefinition<T>
186where
187 T: FieldValue,
188{
189 #[allow(dead_code)]
190 phantom: PhantomDataSendSync<T>,
191}
192
193impl<T> InheritablePropertyEditorDefinition<T>
194where
195 T: FieldValue,
196{
197 pub fn new() -> Self {
198 Self {
199 phantom: Default::default(),
200 }
201 }
202}
203
204impl<T> Debug for InheritablePropertyEditorDefinition<T>
205where
206 T: Reflect + FieldValue,
207{
208 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
209 writeln!(f, "InheritablePropertyEditorDefinition")
210 }
211}
212
213fn make_proxy<'a, 'b, 'c, T>(
214 property_info: &'b FieldInfo<'a, 'c>,
215) -> Result<FieldInfo<'a, 'c>, InspectorError>
216where
217 T: Reflect + FieldValue,
218 'b: 'a,
219{
220 let value = property_info.cast_value::<InheritableVariable<T>>()?;
221
222 Ok(FieldInfo {
223 owner_type_id: TypeId::of::<T>(),
224 name: property_info.name,
225 display_name: property_info.display_name,
226 value: &**value,
227 reflect_value: &**value,
228 read_only: property_info.read_only,
229 immutable_collection: property_info.immutable_collection,
230 min_value: property_info.min_value,
231 max_value: property_info.max_value,
232 step: property_info.step,
233 precision: property_info.precision,
234 description: property_info.description,
235 tag: property_info.tag,
236 type_name: property_info.type_name,
237 doc: property_info.doc,
238 })
239}
240
241impl<T> PropertyEditorDefinition for InheritablePropertyEditorDefinition<T>
242where
243 T: Reflect + FieldValue,
244{
245 fn value_type_id(&self) -> TypeId {
246 TypeId::of::<InheritableVariable<T>>()
247 }
248
249 fn create_instance(
250 &self,
251 ctx: PropertyEditorBuildContext,
252 ) -> Result<PropertyEditorInstance, InspectorError> {
253 if let Some(definition) = ctx
254 .definition_container
255 .definitions()
256 .get(&TypeId::of::<T>())
257 {
258 let instance =
259 definition
260 .property_editor
261 .create_instance(PropertyEditorBuildContext {
262 build_context: ctx.build_context,
263 property_info: &make_proxy::<T>(ctx.property_info)?,
264 environment: ctx.environment.clone(),
265 definition_container: ctx.definition_container.clone(),
266 sync_flag: ctx.sync_flag,
267 layer_index: ctx.layer_index,
268 generate_property_string_values: ctx.generate_property_string_values,
269 filter: ctx.filter,
270 name_column_width: ctx.name_column_width,
271 })?;
272
273 let wrapper = InheritablePropertyEditorBuilder::new(WidgetBuilder::new())
274 .with_container(match instance {
275 PropertyEditorInstance::Simple { editor } => editor,
276 PropertyEditorInstance::Custom { container, .. } => container,
277 })
278 .with_inner_editor(match instance {
279 PropertyEditorInstance::Simple { editor } => editor,
280 PropertyEditorInstance::Custom { editor, .. } => editor,
281 })
282 .with_modified(
283 ctx.property_info
284 .cast_value::<InheritableVariable<T>>()?
285 .is_modified(),
286 )
287 .build(ctx.build_context);
288
289 Ok(match instance {
290 PropertyEditorInstance::Simple { .. } => {
291 PropertyEditorInstance::Simple { editor: wrapper }
292 }
293 PropertyEditorInstance::Custom { .. } => PropertyEditorInstance::Custom {
294 container: wrapper,
295 editor: wrapper,
296 },
297 })
298 } else {
299 Err(InspectorError::Custom("No editor!".to_string()))
300 }
301 }
302
303 fn create_message(
304 &self,
305 ctx: PropertyEditorMessageContext,
306 ) -> Result<Option<UiMessage>, InspectorError> {
307 if let Some(definition) = ctx
308 .definition_container
309 .definitions()
310 .get(&TypeId::of::<T>())
311 {
312 let instance = ctx
313 .ui
314 .node(ctx.instance)
315 .cast::<InheritablePropertyEditor>()
316 .unwrap();
317
318 ctx.ui
319 .send_message(InheritablePropertyEditorMessage::modified(
320 instance.handle,
321 MessageDirection::ToWidget,
322 ctx.property_info
323 .cast_value::<InheritableVariable<T>>()?
324 .is_modified(),
325 ));
326
327 return definition
328 .property_editor
329 .create_message(PropertyEditorMessageContext {
330 property_info: &make_proxy::<T>(ctx.property_info)?,
331 environment: ctx.environment.clone(),
332 definition_container: ctx.definition_container.clone(),
333 sync_flag: ctx.sync_flag,
334 instance: instance.inner_editor,
335 layer_index: ctx.layer_index,
336 ui: ctx.ui,
337 generate_property_string_values: ctx.generate_property_string_values,
338 filter: ctx.filter,
339 name_column_width: ctx.name_column_width,
340 });
341 }
342
343 Err(InspectorError::Custom("No editor!".to_string()))
344 }
345
346 fn translate_message(&self, ctx: PropertyEditorTranslationContext) -> Option<PropertyChanged> {
347 if let Some(InheritablePropertyEditorMessage::Revert) = ctx.message.data() {
348 return Some(PropertyChanged {
349 name: ctx.name.to_string(),
350 owner_type_id: ctx.owner_type_id,
351 value: FieldKind::Inheritable(InheritableAction::Revert),
352 });
353 }
354
355 if let Some(definition) = ctx
357 .definition_container
358 .definitions()
359 .get(&TypeId::of::<T>())
360 {
361 return definition.property_editor.translate_message(
362 PropertyEditorTranslationContext {
363 environment: ctx.environment.clone(),
364 name: ctx.name,
365 owner_type_id: ctx.owner_type_id,
366 message: ctx.message,
367 definition_container: ctx.definition_container.clone(),
368 },
369 );
370 }
371
372 None
373 }
374}