1use crate::{
22 border::BorderBuilder,
23 brush::Brush,
24 core::{
25 algebra::SVector, color::Color, num_traits, pool::Handle, reflect::prelude::*,
26 type_traits::prelude::*, visitor::prelude::*,
27 },
28 define_constructor,
29 grid::{Column, GridBuilder, Row},
30 message::{MessageDirection, UiMessage},
31 numeric::{NumericType, NumericUpDownBuilder, NumericUpDownMessage},
32 widget::WidgetBuilder,
33 BuildContext, Control, Thickness, UiNode, UserInterface, Widget,
34};
35use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor};
36use std::ops::{Deref, DerefMut};
37
38fn make_numeric_input<T: NumericType>(
39 ctx: &mut BuildContext,
40 column: usize,
41 value: T,
42 min: T,
43 max: T,
44 step: T,
45 editable: bool,
46 precision: usize,
47) -> Handle<UiNode> {
48 NumericUpDownBuilder::new(
49 WidgetBuilder::new()
50 .on_row(0)
51 .on_column(column)
52 .with_margin(Thickness {
53 left: 1.0,
54 top: 0.0,
55 right: 1.0,
56 bottom: 0.0,
57 }),
58 )
59 .with_precision(precision)
60 .with_value(value)
61 .with_min_value(min)
62 .with_max_value(max)
63 .with_step(step)
64 .with_editable(editable)
65 .build(ctx)
66}
67
68pub fn make_mark(ctx: &mut BuildContext, column: usize, color: Color) -> Handle<UiNode> {
69 BorderBuilder::new(
70 WidgetBuilder::new()
71 .on_row(0)
72 .on_column(column)
73 .with_background(Brush::Solid(color).into())
74 .with_foreground(Brush::Solid(Color::TRANSPARENT).into())
75 .with_width(4.0),
76 )
77 .with_corner_radius(2.0f32.into())
78 .with_pad_by_corner_radius(false)
79 .build(ctx)
80}
81
82#[derive(Debug, Clone, PartialEq)]
83pub enum VecEditorMessage<T, const D: usize>
84where
85 T: NumericType,
86{
87 Value(SVector<T, D>),
88}
89
90impl<T, const D: usize> VecEditorMessage<T, D>
91where
92 T: NumericType,
93{
94 define_constructor!(VecEditorMessage:Value => fn value(SVector<T, D>), layout: false);
95}
96
97#[derive(Clone, Visit, Reflect, Debug, ComponentProvider)]
98pub struct VecEditor<T, const D: usize>
99where
100 T: NumericType,
101{
102 pub widget: Widget,
103 pub fields: Vec<Handle<UiNode>>,
104 #[reflect(hidden)]
105 #[visit(skip)]
106 pub value: SVector<T, D>,
107 #[reflect(hidden)]
108 #[visit(skip)]
109 pub min: SVector<T, D>,
110 #[reflect(hidden)]
111 #[visit(skip)]
112 pub max: SVector<T, D>,
113 #[reflect(hidden)]
114 #[visit(skip)]
115 pub step: SVector<T, D>,
116}
117
118impl<T: NumericType, const D: usize> ConstructorProvider<UiNode, UserInterface>
119 for VecEditor<T, D>
120{
121 fn constructor() -> GraphNodeConstructor<UiNode, UserInterface> {
122 GraphNodeConstructor::new::<Self>()
123 .with_variant(
124 format!("Vec Editor<{}, {}>", std::any::type_name::<T>(), D),
125 |ui| {
126 VecEditorBuilder::<T, D>::new(WidgetBuilder::new().with_name("Vec Editor"))
127 .build(&mut ui.build_ctx())
128 .into()
129 },
130 )
131 .with_group("Vector")
132 }
133}
134
135impl<T, const D: usize> Default for VecEditor<T, D>
136where
137 T: NumericType,
138{
139 fn default() -> Self {
140 Self {
141 widget: Default::default(),
142 fields: Default::default(),
143 value: SVector::from([T::default(); D]),
144 min: SVector::from([T::default(); D]),
145 max: SVector::from([T::default(); D]),
146 step: SVector::from([T::default(); D]),
147 }
148 }
149}
150
151impl<T, const D: usize> Deref for VecEditor<T, D>
152where
153 T: NumericType,
154{
155 type Target = Widget;
156
157 fn deref(&self) -> &Self::Target {
158 &self.widget
159 }
160}
161
162impl<T, const D: usize> DerefMut for VecEditor<T, D>
163where
164 T: NumericType,
165{
166 fn deref_mut(&mut self) -> &mut Self::Target {
167 &mut self.widget
168 }
169}
170
171const DIM_UUIDS: [Uuid; 16] = [
173 uuid!("11ec6ec2-9780-4dbe-827a-935cb9ec5bb0"),
174 uuid!("af532488-8833-443a-8ece-d8380e5ad148"),
175 uuid!("6738154a-9663-4628-bb9d-f61d453eafcd"),
176 uuid!("448dab8c-b4e6-478e-a704-ea0b0db628aa"),
177 uuid!("67246977-8802-4e72-a19f-6e4f60b6eced"),
178 uuid!("f711a9f8-288a-4a28-b30e-e7bcfdf26ab0"),
179 uuid!("c92ac3ad-5dc5-41dd-abbd-7fb9aacb9a5f"),
180 uuid!("88d9a035-4424-40d2-af62-f701025bd767"),
181 uuid!("dda09036-18d8-40bc-ae9d-1a69f45e2ba0"),
182 uuid!("b6fe9585-6ebc-4b4d-be66-484b4d7b3d5b"),
183 uuid!("03c41033-e8fe-420d-b246-e7c9dcd7c01b"),
184 uuid!("14ea7e95-0f94-4b15-a53c-97d7d2e58d4e"),
185 uuid!("0149f666-33cf-4e39-b4bd-58502994b162"),
186 uuid!("abb9f691-0958-464b-a37d-a3336b4d33f9"),
187 uuid!("6f37cfd5-9bec-40ec-9dbc-e532d43b81b7"),
188 uuid!("fa786077-95b9-4e7c-9268-7d0314c005ba"),
189];
190
191impl<T: NumericType, const D: usize> TypeUuidProvider for VecEditor<T, D> {
192 fn type_uuid() -> Uuid {
193 combine_uuids(
194 combine_uuids(
195 uuid!("0332144f-c70e-456a-812b-f9b89980d2ba"),
196 T::type_uuid(),
197 ),
198 DIM_UUIDS[D],
199 )
200 }
201}
202
203impl<T, const D: usize> Control for VecEditor<T, D>
204where
205 T: NumericType,
206{
207 fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
208 self.widget.handle_routed_message(ui, message);
209
210 if let Some(&NumericUpDownMessage::Value(value)) = message.data::<NumericUpDownMessage<T>>()
211 {
212 if message.direction() == MessageDirection::FromWidget {
213 for (i, field) in self.fields.iter().enumerate() {
214 if message.destination() == *field {
215 let mut new_value = self.value;
216 new_value[i] = value;
217 ui.send_message(VecEditorMessage::value(
218 self.handle(),
219 MessageDirection::ToWidget,
220 new_value,
221 ));
222 }
223 }
224 }
225 } else if let Some(&VecEditorMessage::Value(new_value)) =
226 message.data::<VecEditorMessage<T, D>>()
227 {
228 if message.direction() == MessageDirection::ToWidget {
229 let mut changed = false;
230
231 for i in 0..D {
232 let editor = self.fields[i];
233 let current = &mut self.value[i];
234 let min = self.min[i];
235 let max = self.max[i];
236 let new = num_traits::clamp(new_value[i], min, max);
237
238 if *current != new {
239 *current = new;
240 ui.send_message(NumericUpDownMessage::value(
241 editor,
242 MessageDirection::ToWidget,
243 new,
244 ));
245 changed = true;
246 }
247 }
248
249 if changed {
250 ui.send_message(message.reverse());
251 }
252 }
253 }
254 }
255}
256
257pub struct VecEditorBuilder<T, const D: usize>
258where
259 T: NumericType,
260{
261 widget_builder: WidgetBuilder,
262 value: SVector<T, D>,
263 editable: bool,
264 min: SVector<T, D>,
265 max: SVector<T, D>,
266 step: SVector<T, D>,
267 precision: usize,
268}
269
270impl<T, const D: usize> VecEditorBuilder<T, D>
271where
272 T: NumericType,
273{
274 pub fn new(widget_builder: WidgetBuilder) -> Self {
275 Self {
276 widget_builder,
277 value: SVector::repeat(Default::default()),
278 editable: true,
279 min: SVector::repeat(T::min_value()),
280 max: SVector::repeat(T::max_value()),
281 step: SVector::repeat(T::one()),
282 precision: 3,
283 }
284 }
285
286 pub fn with_value(mut self, value: SVector<T, D>) -> Self {
287 self.value = value;
288 self
289 }
290
291 pub fn with_editable(mut self, editable: bool) -> Self {
292 self.editable = editable;
293 self
294 }
295
296 pub fn with_min(mut self, min: SVector<T, D>) -> Self {
297 self.min = min;
298 self
299 }
300
301 pub fn with_max(mut self, max: SVector<T, D>) -> Self {
302 self.max = max;
303 self
304 }
305
306 pub fn with_step(mut self, step: SVector<T, D>) -> Self {
307 self.step = step;
308 self
309 }
310
311 pub fn with_precision(mut self, precision: usize) -> Self {
312 self.precision = precision;
313 self
314 }
315
316 pub fn build(self, ctx: &mut BuildContext) -> Handle<UiNode> {
317 let mut fields = Vec::new();
318 let mut children = Vec::new();
319 let mut columns = Vec::new();
320
321 let colors = [
322 Color::opaque(120, 0, 0),
323 Color::opaque(0, 120, 0),
324 Color::opaque(0, 0, 120),
325 Color::opaque(120, 0, 120),
326 Color::opaque(0, 120, 120),
327 Color::opaque(120, 120, 0),
328 ];
329
330 for i in 0..D {
331 children.push(make_mark(
332 ctx,
333 i * 2,
334 colors.get(i).cloned().unwrap_or(Color::ORANGE),
335 ));
336
337 let field = make_numeric_input(
338 ctx,
339 i * 2 + 1,
340 self.value[i],
341 self.min[i],
342 self.max[i],
343 self.step[i],
344 self.editable,
345 self.precision,
346 );
347 children.push(field);
348 fields.push(field);
349
350 columns.push(Column::auto());
351 columns.push(Column::stretch());
352 }
353
354 let grid = GridBuilder::new(WidgetBuilder::new().with_children(children))
355 .add_row(Row::stretch())
356 .add_columns(columns)
357 .build(ctx);
358
359 let node = VecEditor {
360 widget: self.widget_builder.with_child(grid).build(ctx),
361 fields,
362 value: self.value,
363 min: self.min,
364 max: self.max,
365 step: self.step,
366 };
367
368 ctx.add_node(UiNode::new(node))
369 }
370}
371
372pub type Vec2Editor<T> = VecEditor<T, 2>;
373pub type Vec3Editor<T> = VecEditor<T, 3>;
374pub type Vec4Editor<T> = VecEditor<T, 4>;
375pub type Vec5Editor<T> = VecEditor<T, 5>;
376pub type Vec6Editor<T> = VecEditor<T, 6>;
377
378pub type Vec2EditorMessage<T> = VecEditorMessage<T, 2>;
379pub type Vec3EditorMessage<T> = VecEditorMessage<T, 3>;
380pub type Vec4EditorMessage<T> = VecEditorMessage<T, 4>;
381pub type Vec5EditorMessage<T> = VecEditorMessage<T, 5>;
382pub type Vec6EditorMessage<T> = VecEditorMessage<T, 6>;
383
384pub type Vec2EditorBuilder<T> = VecEditorBuilder<T, 2>;
385pub type Vec3EditorBuilder<T> = VecEditorBuilder<T, 3>;
386pub type Vec4EditorBuilder<T> = VecEditorBuilder<T, 4>;
387pub type Vec5EditorBuilder<T> = VecEditorBuilder<T, 5>;
388pub type Vec6EditorBuilder<T> = VecEditorBuilder<T, 6>;
389
390#[cfg(test)]
391mod test {
392 use crate::vec::Vec2EditorBuilder;
393 use crate::{test::test_widget_deletion, widget::WidgetBuilder};
394
395 #[test]
396 fn test_deletion() {
397 test_widget_deletion(|ctx| Vec2EditorBuilder::<f32>::new(WidgetBuilder::new()).build(ctx));
398 }
399}