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