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