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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
use std::any::Any;

use bevy_math::{prelude::*, DMat2, DMat3, DMat4, DVec2, DVec3, DVec4, Mat3A, Vec3A};
use bevy_reflect::Reflect;

use crate::egui_reflect_inspector::InspectorUi;

macro_rules! vec_ui_many {
    ($name_many:ident $ty:ty>$elem_ty:ty: $count:literal $($component:ident)*) => {
        pub fn $name_many<'a>(
            ui: &mut egui::Ui,
            _: &dyn Any,
            _env: InspectorUi<'_, '_>,
            values: &mut [&mut dyn Reflect],
            projector: &dyn Fn(&mut dyn Reflect) -> &mut dyn Reflect,
        ) -> bool {
            let mut changed = false;
            ui.scope(|ui| {
                ui.style_mut().spacing.item_spacing = egui::Vec2::new(4.0, 0.);

                ui.columns($count, |ui| match ui {
                    [$($component),*] => {
                        $(

                            let same = super::iter_all_eq(values.iter_mut().map(|value| {
                                projector(*value).downcast_ref::<$ty>().unwrap().$component
                            }));

                            let id = egui::Id::new(stringify!($component));
                            changed |= crate::inspector_egui_impls::change_slider($component, id, same, |change, overwrite| {
                                for value in values.iter_mut() {
                                    let value = projector(*value);
                                    let value = value.downcast_mut::<$ty>().unwrap();

                                    if false { value.$component = change };
                                    if overwrite {
                                        value.$component = change;
                                    } else {
                                        value.$component += change;
                                    }

                                }
                            });
                        )*
                    }
                    _ => unreachable!(),
                });
            });
            changed
        }
    };
}

macro_rules! vec_ui {
    ($name:ident $name_readonly:ident $ty:ty: $count:literal $($component:ident)*) => {
        pub fn $name(
            value: &mut dyn Any,
            ui: &mut egui::Ui,
            _: &dyn Any,
            mut env: InspectorUi<'_, '_>,
        ) -> bool {
            let value = value.downcast_mut::<$ty>().unwrap();

            let mut changed = false;
            ui.scope(|ui| {
                ui.style_mut().spacing.item_spacing = egui::Vec2::new(4.0, 0.);

                ui.columns($count, |ui| match ui {
                    [$($component),*] => {
                        $(changed |= env.ui_for_reflect(&mut value.$component, $component);)*
                    }
                    _ => unreachable!(),
                });
            });
            changed
        }

        pub fn $name_readonly(
            value: &dyn Any,
            ui: &mut egui::Ui,
            _: &dyn Any,
            mut env: InspectorUi<'_, '_>,
        ) {
            let value = value.downcast_ref::<$ty>().unwrap();

            ui.scope(|ui| {
                ui.style_mut().spacing.item_spacing = egui::Vec2::new(4.0, 0.);

                ui.columns($count, |ui| match ui {
                    [$($component),*] => {
                        $(env.ui_for_reflect_readonly(&value.$component, $component);)*
                    }
                    _ => unreachable!(),
                });
            });
        }
    };
}

macro_rules! mat_ui {
    ($name:ident $name_readonly:ident $ty:ty: $($component:ident)*) => {
        pub fn $name(
            value: &mut dyn Any,
            ui: &mut egui::Ui,
            _: &dyn Any,
            mut env: InspectorUi<'_, '_>,
        ) -> bool {

            let value = value.downcast_mut::<$ty>().unwrap();

            let mut changed = false;
            ui.vertical(|ui| {
                $(changed |= env.ui_for_reflect(&mut value.$component, ui);)*
            });
            changed
        }

        pub fn $name_readonly(
            value: &dyn Any,
            ui: &mut egui::Ui,
            _: &dyn Any,
            mut env: InspectorUi<'_, '_>,
        ) {
            let value = value.downcast_ref::<$ty>().unwrap();

            ui.vertical(|ui| {
                $(env.ui_for_reflect_readonly(&value.$component, ui);)*
            });
        }
    };
}

vec_ui!(vec2_ui vec2_ui_readonly Vec2: 2 x y);
vec_ui!(vec3_ui vec3_ui_readonly Vec3: 3 x y z);
vec_ui!(vec3a_ui vec3a_ui_readonly Vec3A: 3 x y z);
vec_ui!(vec4_ui vec4_ui_readonly Vec4: 4 x y z w);
vec_ui!(uvec2_ui uvec2_ui_readonly UVec2: 2 x y);
vec_ui!(uvec3_ui uvec3_ui_readonly UVec3: 3 x y z);
vec_ui!(uvec4_ui uvec4_ui_readonly UVec4: 4 x y z w);
vec_ui!(ivec2_ui ivec2_ui_readonly IVec2: 2 x y);
vec_ui!(ivec3_ui ivec3_ui_readonly IVec3: 3 x y z);
vec_ui!(ivec4_ui ivec4_ui_readonly IVec4: 4 x y z w);
vec_ui!(dvec2_ui dvec2_ui_readonly DVec2: 2 x y);
vec_ui!(dvec3_ui dvec3_ui_readonly DVec3: 3 x y z);
vec_ui!(dvec4_ui dvec4_ui_readonly DVec4: 4 x y z w);
vec_ui!(bvec2_ui bvec2_ui_readonly BVec2: 2 x y);
vec_ui!(bvec3_ui bvec3_ui_readonly BVec3: 3 x y z);
vec_ui!(bvec4_ui bvec4_ui_readonly BVec4: 4 x y z w);
vec_ui_many!(vec2_ui_many Vec2>f32: 2 x y);
vec_ui_many!(vec3_ui_many Vec3>f32: 3 x y z);
vec_ui_many!(vec3a_ui_many Vec3A>f32: 3 x y z);
vec_ui_many!(vec4_ui_many Vec4>f32: 4 x y z w);
vec_ui_many!(uvec2_ui_many UVec2>u32: 2 x y);
vec_ui_many!(uvec3_ui_many UVec3>u32: 3 x y z);
vec_ui_many!(uvec4_ui_many UVec4>u32: 4 x y z w);
vec_ui_many!(ivec2_ui_many IVec2>i32: 2 x y);
vec_ui_many!(ivec3_ui_many IVec3>i32: 3 x y z);
vec_ui_many!(ivec4_ui_many IVec4>i32: 4 x y z w);
vec_ui_many!(dvec2_ui_many DVec2>f64: 2 x y);
vec_ui_many!(dvec3_ui_many DVec3>f64: 3 x y z);
vec_ui_many!(dvec4_ui_many DVec4>f64: 4 x y z w);

mat_ui!(mat2_ui mat2_ui_readonly Mat2: x_axis y_axis);
mat_ui!(mat3_ui mat3_ui_readonly Mat3: x_axis y_axis z_axis);
mat_ui!(mat3a_ui mat3a_ui_readonly Mat3A: x_axis y_axis z_axis);
mat_ui!(mat4_ui mat4_ui_readonly Mat4: x_axis y_axis z_axis w_axis);
mat_ui!(dmat2_ui dmat2_ui_readonly DMat2: x_axis y_axis);
mat_ui!(dmat3_ui dmat3_ui_readonly DMat3: x_axis y_axis z_axis);
mat_ui!(dmat4_ui dmat4_ui_readonly DMat4: x_axis y_axis z_axis w_axis);

pub mod quat {
    use std::any::Any;

    use bevy_egui::egui;
    use bevy_math::{prelude::*, EulerRot};

    use crate::{
        egui_reflect_inspector::InspectorUi,
        inspector_options::std_options::{QuatDisplay, QuatOptions},
        many_ui,
    };

    #[derive(Clone, Copy)]
    struct Euler(Vec3);
    #[derive(Clone, Copy)]
    struct YawPitchRoll((f32, f32, f32));
    #[derive(Clone, Copy)]
    struct AxisAngle((Vec3, f32));

    trait RotationEdit {
        fn from_quat(quat: Quat) -> Self;
        fn to_quat(self) -> Quat;

        fn ui(&mut self, ui: &mut egui::Ui, env: InspectorUi<'_, '_>) -> bool;
    }

    impl RotationEdit for Euler {
        fn from_quat(quat: Quat) -> Self {
            Euler(quat.to_euler(EulerRot::XYZ).into())
        }

        fn to_quat(self) -> Quat {
            Quat::from_euler(EulerRot::XYZ, self.0.x, self.0.y, self.0.z)
        }

        fn ui(&mut self, ui: &mut egui::Ui, mut env: InspectorUi<'_, '_>) -> bool {
            env.ui_for_reflect(&mut self.0, ui)
        }
    }

    impl RotationEdit for YawPitchRoll {
        fn from_quat(quat: Quat) -> Self {
            YawPitchRoll(quat.to_euler(EulerRot::YXZ))
        }

        fn to_quat(self) -> Quat {
            let (y, p, r) = self.0;
            Quat::from_euler(EulerRot::YXZ, y, p, r)
        }

        fn ui(&mut self, ui: &mut egui::Ui, _env: InspectorUi<'_, '_>) -> bool {
            let (yaw, pitch, roll) = &mut self.0;

            let mut changed = false;
            ui.vertical(|ui| {
                egui::Grid::new("ypr grid").show(ui, |ui| {
                    ui.label("Yaw");
                    changed |= ui.drag_angle(yaw).changed();
                    ui.end_row();
                    ui.label("Pitch").changed();
                    changed |= ui.drag_angle(pitch).changed();
                    ui.end_row();
                    ui.label("Roll");
                    changed |= ui.drag_angle(roll).changed();
                    ui.end_row();
                });
            });
            changed
        }
    }

    impl RotationEdit for AxisAngle {
        fn from_quat(quat: Quat) -> Self {
            AxisAngle(quat.to_axis_angle())
        }

        fn to_quat(self) -> Quat {
            let (axis, angle) = self.0;
            let axis = axis.normalize();
            if axis.is_nan() {
                Quat::IDENTITY
            } else {
                Quat::from_axis_angle(axis.normalize(), angle)
            }
        }

        fn ui(&mut self, ui: &mut egui::Ui, mut env: InspectorUi<'_, '_>) -> bool {
            let (axis, angle) = &mut self.0;

            let mut changed = false;
            ui.vertical(|ui| {
                egui::Grid::new("axis-angle quat").show(ui, |ui| {
                    ui.label("Axis");
                    changed |= env.ui_for_reflect(axis, ui);
                    ui.end_row();
                    ui.label("Angle");
                    changed |= ui.drag_angle(angle).changed();
                    ui.end_row();
                });
            });
            changed
        }
    }

    fn quat_ui_kind<T: Send + Sync + 'static + Copy + RotationEdit>(
        val: &mut Quat,
        ui: &mut egui::Ui,
        env: InspectorUi<'_, '_>,
    ) -> bool {
        let id = ui.id();
        let mut intermediate = *ui
            .memory()
            .data
            .get_temp_mut_or_insert_with(id, || T::from_quat(*val));

        let externally_changed = !intermediate.to_quat().abs_diff_eq(*val, std::f32::EPSILON);
        if externally_changed {
            intermediate = T::from_quat(*val);
        }

        let changed = intermediate.ui(ui, env);

        if changed || externally_changed {
            *val = intermediate.to_quat();
            ui.memory().data.insert_temp(id, intermediate);
        }

        changed
    }

    pub fn quat_ui(
        value: &mut dyn Any,
        ui: &mut egui::Ui,
        options: &dyn Any,
        mut env: InspectorUi<'_, '_>,
    ) -> bool {
        let value = value.downcast_mut::<Quat>().unwrap();

        let options = options
            .downcast_ref::<QuatOptions>()
            .cloned()
            .unwrap_or_default();

        ui.vertical(|ui| match options.display {
            QuatDisplay::Raw => {
                let mut vec4 = Vec4::from(*value);
                let changed = env.ui_for_reflect(&mut vec4, ui);
                if changed {
                    *value = Quat::from_vec4(vec4).normalize();
                }
                changed
            }
            QuatDisplay::Euler => quat_ui_kind::<Euler>(value, ui, env),
            QuatDisplay::YawPitchRoll => quat_ui_kind::<YawPitchRoll>(value, ui, env),
            QuatDisplay::AxisAngle => quat_ui_kind::<AxisAngle>(value, ui, env),
        })
        .inner
    }

    pub fn quat_ui_readonly(
        value: &dyn Any,
        ui: &mut egui::Ui,
        options: &dyn Any,
        env: InspectorUi<'_, '_>,
    ) {
        let mut value = *value.downcast_ref::<Quat>().unwrap();
        ui.add_enabled_ui(false, |ui| quat_ui(&mut value, ui, options, env));
    }

    many_ui!(quat_ui_many quat_ui Quat);
}