rg3d_ui/inspector/editors/
numeric.rs

1use crate::{
2    core::num_traits::NumCast,
3    inspector::{
4        editors::{
5            PropertyEditorBuildContext, PropertyEditorDefinition, PropertyEditorInstance,
6            PropertyEditorMessageContext,
7        },
8        FieldKind, InspectorError, PropertyChanged,
9    },
10    message::{MessageDirection, UiMessage},
11    numeric::{NumericType, NumericUpDownBuilder, NumericUpDownMessage},
12    widget::WidgetBuilder,
13    Thickness,
14};
15use std::{any::TypeId, marker::PhantomData};
16
17#[derive(Debug)]
18pub struct NumericPropertyEditorDefinition<T>
19where
20    T: NumericType,
21{
22    phantom: PhantomData<T>,
23}
24
25impl<T> Default for NumericPropertyEditorDefinition<T>
26where
27    T: NumericType,
28{
29    fn default() -> Self {
30        Self {
31            phantom: PhantomData,
32        }
33    }
34}
35
36impl<T> PropertyEditorDefinition for NumericPropertyEditorDefinition<T>
37where
38    T: NumericType,
39{
40    fn value_type_id(&self) -> TypeId {
41        TypeId::of::<T>()
42    }
43
44    fn create_instance(
45        &self,
46        ctx: PropertyEditorBuildContext,
47    ) -> Result<PropertyEditorInstance, InspectorError> {
48        let value = ctx.property_info.cast_value::<T>()?;
49        Ok(PropertyEditorInstance::Simple {
50            editor: NumericUpDownBuilder::new(
51                WidgetBuilder::new().with_margin(Thickness::uniform(1.0)),
52            )
53            .with_min_value(
54                ctx.property_info
55                    .min_value
56                    .and_then(NumCast::from)
57                    .unwrap_or_else(T::min_value),
58            )
59            .with_max_value(
60                ctx.property_info
61                    .max_value
62                    .and_then(NumCast::from)
63                    .unwrap_or_else(T::max_value),
64            )
65            .with_step(
66                ctx.property_info
67                    .step
68                    .and_then(NumCast::from)
69                    .unwrap_or_else(T::one),
70            )
71            .with_precision(ctx.property_info.precision.unwrap_or(3))
72            .with_value(*value)
73            .build(ctx.build_context),
74        })
75    }
76
77    fn create_message(
78        &self,
79        ctx: PropertyEditorMessageContext,
80    ) -> Result<Option<UiMessage>, InspectorError> {
81        let value = ctx.property_info.cast_value::<T>()?;
82        Ok(Some(NumericUpDownMessage::value(
83            ctx.instance,
84            MessageDirection::ToWidget,
85            *value,
86        )))
87    }
88
89    fn translate_message(
90        &self,
91        name: &str,
92        owner_type_id: TypeId,
93        message: &UiMessage,
94    ) -> Option<PropertyChanged> {
95        if message.direction() == MessageDirection::FromWidget {
96            if let Some(NumericUpDownMessage::Value(value)) =
97                message.data::<NumericUpDownMessage<T>>()
98            {
99                return Some(PropertyChanged {
100                    name: name.to_string(),
101                    owner_type_id,
102                    value: FieldKind::object(*value),
103                });
104            }
105        }
106
107        None
108    }
109}