1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! Way of associating options to fields using [`struct@InspectorOptions`]

use std::{any::Any, collections::HashMap};

use bevy_reflect::{FromType, TypeData};

pub(crate) mod default_options;

/// Options for dealing with common types such as numbers or quaternions
pub mod std_options;

/// Descriptor of a path into a struct/enum. Either a `Field` (`.foo`) or a `VariantField` (`RGBA.r`)
#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)]
#[non_exhaustive]
pub enum Target {
    Field(usize),
    VariantField {
        variant_index: usize,
        field_index: usize,
    },
}

pub use bevy_inspector_egui_derive::InspectorOptions;

/// Map of [`Target`]s to arbitrary [`TypeData`] used to control how the value is displayed, e.g. [`NumberOptions`](crate::inspector_options::std_options::NumberOptions).
///
/// Comes with a [derive macro](derive@InspectorOptions), which generates a `FromType<T> for InspectorOptions` impl:
/// ```rust
/// use bevy_inspector_egui::prelude::*;
/// use bevy_reflect::Reflect;
///
/// #[derive(Reflect, Default, InspectorOptions)]
/// #[reflect(InspectorOptions)]
/// struct Config {
///     #[inspector(min = 10.0, max = 70.0)]
///     font_size: f32,
///     option: Option<f32>,
/// }
/// ```
/// will expand roughly to
/// ```rust
/// # use bevy_inspector_egui::inspector_options::{InspectorOptions, Target, std_options::NumberOptions};
/// let mut options = InspectorOptions::default();
/// let mut field_options = NumberOptions { min: 10.0.into(), max: 70.0.into(), ..Default::default() };
/// options.insert(Target::Field(0usize), field_options);
/// ```
#[derive(Default)]
pub struct InspectorOptions {
    options: HashMap<Target, Box<dyn TypeData>>,
}

impl std::fmt::Debug for InspectorOptions {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut options = f.debug_struct("InspectorOptions");
        for entry in self.options.keys() {
            options.field(&format!("{entry:?}"), &"..");
        }
        options.finish()
    }
}

impl Clone for InspectorOptions {
    fn clone(&self) -> Self {
        Self {
            options: self
                .options
                .iter()
                .map(|(target, data)| (*target, TypeData::clone_type_data(&**data)))
                .collect(),
        }
    }
}
impl InspectorOptions {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn insert<T: TypeData>(&mut self, target: Target, options: T) {
        self.options.insert(target, Box::new(options));
    }
    pub fn insert_boxed(&mut self, target: Target, options: Box<dyn TypeData>) {
        self.options.insert(target, options);
    }
    pub fn get(&self, target: Target) -> Option<&dyn Any> {
        self.options.get(&target).map(|value| value.as_any())
    }

    pub fn iter(&self) -> impl Iterator<Item = (Target, &dyn TypeData)> + '_ {
        self.options.iter().map(|(target, data)| (*target, &**data))
    }
}

/// Wrapper of [`struct@InspectorOptions`] to be stored in the [`TypeRegistry`](bevy_reflect::TypeRegistry)
#[derive(Clone)]
pub struct ReflectInspectorOptions(pub InspectorOptions);

impl<T> FromType<T> for ReflectInspectorOptions
where
    InspectorOptions: FromType<T>,
{
    fn from_type() -> Self {
        ReflectInspectorOptions(InspectorOptions::from_type())
    }
}

/// Helper trait for the [`derive@InspectorOptions`] macro.
///
/// ```skip
///     #[inspector(min = 0.0, max = 1.0)]
///     field: f32
/// ```
/// will expand to this:
/// ```rust
/// # use std::convert::Into;
/// # use bevy_inspector_egui::inspector_options::{InspectorOptions, InspectorOptionsType, Target};
/// let mut options = InspectorOptions::default();
/// let mut field_options =  <f32 as InspectorOptionsType>::DeriveOptions::default();
/// field_options.min = Into::into(2.0);
/// field_options.max = Into::into(3.0);
/// options.insert(
///     Target::Field(0usize),
///     <f32 as InspectorOptionsType>::options_from_derive(field_options),
/// );
pub trait InspectorOptionsType {
    type DeriveOptions: Default;
    /// Can be arbitrary types which will be passed to [`InspectorEguiImpl`](crate::inspector_egui_impls::InspectorEguiImpl) like [`NumberOptions`](crate::inspector_options::std_options::NumberOptions),
    /// or nested [`struct@InspectorOptions`] which will be passed to children (see [`impl InspectorOptionsType for Option`](trait.InspectorOptionsType.html#impl-InspectorOptionsType-for-Option<T>)).
    type Options: TypeData;

    fn options_from_derive(options: Self::DeriveOptions) -> Self::Options;
}