1use crate::common::*;
2use crate::{Dropdown, DropdownEvent, Textbox, TextboxEvent};
3use crate::AnimationState;
4
5#[derive(Debug, Clone, PartialEq)]
6pub enum VectorEditEvent<T> {
7 ValueChanged(T, T, T, T),
8 Dim1(T),
9 Dim2(T, T),
10 Dim3(T, T, T),
11 Dim4(T, T, T, T),
12}
13
14pub struct Dimension {
15 text: String,
16 pressed: bool,
17}
18
19impl Dimension {
20 pub fn new(text: &str) -> Self {
21 Dimension {
22 text: text.to_string(),
23 pressed: false,
24 }
25 }
26}
27
28impl Widget for Dimension {
29 type Ret = Entity;
30 type Data = ();
31 fn on_build(&mut self, state: &mut State, entity: Entity) -> Self::Ret {
32 entity
33 .set_text(state, &self.text)
34 .set_child_space(state, Stretch(1.0))
35 }
36
37 fn on_event(&mut self, state: &mut State, entity: Entity, event: &mut Event) {
38 if let Some(window_event) = event.message.downcast::<WindowEvent>() {
39 match window_event {
40 WindowEvent::MouseDown(button) => {
41 if *button == MouseButton::Left {
42 if entity == event.target {
43 self.pressed = true;
44 }
51 }
52 }
53
54 WindowEvent::MouseUp(button) => {
55 if *button == MouseButton::Left {
56 if self.pressed {
57 self.pressed = false;
58 state.insert_event(
61 Event::new(DropdownEvent::SetText(self.text.clone()))
62 .target(entity)
63 .propagate(Propagation::Up),
64 );
65 }
66 }
67 }
68
69 _ => {}
70 }
71 }
72 }
73}
74
75pub struct VectorEdit<T> {
76 textbox_x: Entity,
78 textbox_y: Entity,
79 textbox_z: Entity,
80 textbox_w: Entity,
81 dims: Entity,
82
83 reveal: Animation,
85 hide: Animation,
86 grow: Animation,
87 shrink: Animation,
88
89 pub x: T,
91 pub y: T,
92 pub z: T,
93 pub w: T,
94 pub num_of_dims: u8,
95
96 on_change: Option<Box<dyn Fn(&mut Self, &mut State, Entity)>>,
98}
99
100impl<T> VectorEdit<T>
101where
102 T: 'static
103 + Default
104 + std::fmt::Debug
105 + std::fmt::Display
106 + Copy
107 + PartialEq
108 + std::str::FromStr,
109{
110 pub fn new() -> Self {
111 VectorEdit {
112 textbox_x: Entity::null(),
113 textbox_y: Entity::null(),
114 textbox_z: Entity::null(),
115 textbox_w: Entity::null(),
116 dims: Entity::null(),
117
118 reveal: Animation::default(),
119 hide: Animation::default(),
120 grow: Animation::default(),
121 shrink: Animation::default(),
122
123 x: T::default(),
124 y: T::default(),
125 z: T::default(),
126 w: T::default(),
127 num_of_dims: 4,
128
129 on_change: None,
130 }
131 }
132
133 pub fn with_x(mut self, val: T) -> Self {
134 self.x = val;
135
136 self
137 }
138
139 pub fn with_y(mut self, val: T) -> Self {
140 self.y = val;
141
142 self
143 }
144
145 pub fn with_z(mut self, val: T) -> Self {
146 self.z = val;
147
148 self
149 }
150
151 pub fn with_w(mut self, val: T) -> Self {
152 self.w = val;
153
154 self
155 }
156
157 pub fn on_change<F>(mut self, message: F) -> Self
158 where
159 F: 'static + Fn(&mut Self, &mut State, Entity),
160 {
161 self.on_change = Some(Box::new(message));
162
163 self
164 }
165}
166
167impl<T> Widget for VectorEdit<T>
168where
169 T: 'static
170 + Default
171 + std::fmt::Debug
172 + std::fmt::Display
173 + Copy
174 + PartialEq
175 + std::str::FromStr,
176{
177 type Ret = Entity;
178 type Data = ();
179 fn on_build(&mut self, state: &mut State, entity: Entity) -> Self::Ret {
180 entity.set_layout_type(state, LayoutType::Row);
183
184 self.textbox_x = Textbox::new(&self.x.to_string())
185 .build(state, entity, |builder|
186 builder.set_right(Pixels(5.0))
187 );
188 self.textbox_y = Textbox::new(&self.y.to_string()).build(state, entity, |builder| {
189 builder.set_right(Pixels(5.0))
190 });
191 self.textbox_z = Textbox::new(&self.z.to_string()).build(state, entity, |builder| {
192 builder.set_right(Pixels(5.0))
193 });
194 self.textbox_w = Textbox::new(&self.w.to_string()).build(state, entity, |builder| {
195 builder.set_right(Pixels(5.0))
196 });
197
198 self.dims = Dropdown::<()>::new("4")
199 .build(state, entity, |builder| {
200 builder
201 .set_width(Pixels(30.0))
202 .class("dim")
204 });
205
206 Dimension::new("1").build(state, self.dims, |builder| builder.class("item"));
207 Dimension::new("2").build(state, self.dims, |builder| builder.class("item"));
208 Dimension::new("3").build(state, self.dims, |builder| builder.class("item"));
209 Dimension::new("4").build(state, self.dims, |builder| builder.class("item"));
210
211 self.reveal = state.style.width.insert_animation(
212 AnimationState::new()
213 .with_duration(std::time::Duration::from_millis(100))
214 .with_keyframe((0.0, Stretch(0.0)))
215 .with_keyframe((1.0, Stretch(1.0))),
216 );
217
218 self.grow = state.style.right.insert_animation(
219 AnimationState::new()
220 .with_duration(std::time::Duration::from_millis(100))
221 .with_keyframe((0.0, Units::Pixels(0.0)))
222 .with_keyframe((1.0, Units::Pixels(5.0))),
223 );
224
225 self.shrink = state.style.right.insert_animation(
226 AnimationState::new()
227 .with_duration(std::time::Duration::from_millis(100))
228 .with_keyframe((0.0, Units::Pixels(5.0)))
229 .with_keyframe((1.0, Units::Pixels(0.0))),
230 );
231
232 self.hide = state.style.width.insert_animation(
233 AnimationState::new()
234 .with_duration(std::time::Duration::from_millis(100))
235 .with_keyframe((0.0, Stretch(1.0)))
236 .with_keyframe((1.0, Stretch(0.0))),
237 );
238
239 if let Some(callback) = self.on_change.take() {
240 (callback)(self, state, entity);
241 self.on_change = Some(callback);
242 }
243
244 entity.set_element(state, "vector_edit");
245
246 entity
247 }
248
249 fn on_event(&mut self, state: &mut State, entity: Entity, event: &mut Event) {
250 let target = event.target;
251
252 if let Some(dropdown_event) = event.message.downcast::<DropdownEvent>() {
253 match dropdown_event {
254 DropdownEvent::SetText(text) => match text.as_ref() {
255 "1" => {
256 if state.data.get_width(self.textbox_x) == 0.0 {
257 state.style.width.play_animation(self.textbox_x, self.reveal);
258 state.style.right.play_animation(self.textbox_x, self.grow);
259 }
260
261 if state.data.get_width(self.textbox_y) != 0.0 {
262 state.style.width.play_animation(self.textbox_y, self.hide);
263 state.style.right.play_animation(self.textbox_y, self.shrink);
264 }
265
266 if state.data.get_width(self.textbox_z) != 0.0 {
267 state.style.width.play_animation(self.textbox_z, self.hide);
268 state.style.right.play_animation(self.textbox_z, self.shrink);
269 }
270
271 if state.data.get_width(self.textbox_w) != 0.0 {
272 state.style.width.play_animation(self.textbox_w, self.hide);
273 state.style.right.play_animation(self.textbox_w, self.shrink);
274 }
275
276 self.textbox_x.set_width(state, Stretch(1.0));
277 self.textbox_y.set_width(state, Stretch(0.0));
278 self.textbox_z.set_width(state, Stretch(0.0));
279 self.textbox_w.set_width(state, Stretch(0.0));
280
281 self.textbox_x.set_right(state, Pixels(5.0));
282 self.textbox_y.set_right(state, Pixels(0.0));
283 self.textbox_z.set_right(state, Pixels(0.0));
284 self.textbox_w.set_right(state, Pixels(0.0));
285
286 self.num_of_dims = 1;
287
288 state.insert_event(
289 Event::new(VectorEditEvent::Dim1(self.x)).target(entity),
290 );
291 }
292
293 "2" => {
294 if state.data.get_width(self.textbox_x) == 0.0 {
295 state.style.width.play_animation(self.textbox_x, self.reveal);
296 state.style.right.play_animation(self.textbox_x, self.grow);
297 }
298
299 if state.data.get_width(self.textbox_y) == 0.0 {
300 state.style.width.play_animation(self.textbox_y, self.reveal);
301 state.style.right.play_animation(self.textbox_y, self.grow);
302 }
303
304 if state.data.get_width(self.textbox_z) != 0.0 {
305 state.style.width.play_animation(self.textbox_z, self.hide);
306 state.style.right.play_animation(self.textbox_z, self.shrink);
307 }
308
309 if state.data.get_width(self.textbox_w) != 0.0 {
310 state.style.width.play_animation(self.textbox_w, self.hide);
311 state.style.right.play_animation(self.textbox_w, self.shrink);
312 }
313
314 self.textbox_x.set_width(state, Stretch(1.0));
315 self.textbox_y.set_width(state, Stretch(1.0));
316 self.textbox_z.set_width(state, Stretch(0.0));
317 self.textbox_w.set_width(state, Stretch(0.0));
318
319 self.textbox_x.set_right(state, Units::Pixels(5.0));
320 self.textbox_y.set_right(state, Units::Pixels(5.0));
321 self.textbox_z.set_right(state, Units::Pixels(0.0));
322 self.textbox_w.set_right(state, Units::Pixels(0.0));
323
324 self.num_of_dims = 2;
325
326 state.insert_event(
327 Event::new(VectorEditEvent::Dim2(self.x, self.y)).target(entity),
328 );
329 }
330
331 "3" => {
332 if state.data.get_width(self.textbox_x) == 0.0 {
333 state.style.width.play_animation(self.textbox_x, self.reveal);
334 state.style.right.play_animation(self.textbox_x, self.grow);
335 }
336
337 if state.data.get_width(self.textbox_y) == 0.0 {
338 state.style.width.play_animation(self.textbox_y, self.reveal);
339 state.style.right.play_animation(self.textbox_y, self.grow);
340 }
341
342 if state.data.get_width(self.textbox_z) == 0.0 {
343 state.style.width.play_animation(self.textbox_z, self.reveal);
344 state.style.right.play_animation(self.textbox_z, self.grow);
345 }
346
347 if state.data.get_width(self.textbox_w) != 0.0 {
348 state.style.width.play_animation(self.textbox_w, self.hide);
349 state.style.right.play_animation(self.textbox_w, self.shrink);
350 }
351
352 self.textbox_x.set_width(state, Stretch(1.0));
353 self.textbox_y.set_width(state, Stretch(1.0));
354 self.textbox_z.set_width(state, Stretch(1.0));
355 self.textbox_w.set_width(state, Stretch(0.0));
356
357 self.textbox_x.set_right(state, Units::Pixels(5.0));
358 self.textbox_y.set_right(state, Units::Pixels(5.0));
359 self.textbox_z.set_right(state, Units::Pixels(5.0));
360 self.textbox_w.set_right(state, Units::Pixels(0.0));
361
362 self.num_of_dims = 3;
363
364 state.insert_event(
365 Event::new(VectorEditEvent::Dim3(self.x, self.y, self.z))
366 .target(entity),
367 );
368 }
369
370 "4" => {
371 if state.data.get_width(self.textbox_x) == 0.0 {
372 state.style.width.play_animation(self.textbox_x, self.reveal);
373 state.style.right.play_animation(self.textbox_x, self.grow);
374 }
375
376 if state.data.get_width(self.textbox_y) == 0.0 {
377 state.style.width.play_animation(self.textbox_y, self.reveal);
378 state.style.right.play_animation(self.textbox_y, self.grow);
379 }
380
381 if state.data.get_width(self.textbox_z) == 0.0 {
382 state.style.width.play_animation(self.textbox_z, self.reveal);
383 state.style.right.play_animation(self.textbox_z, self.grow);
384 }
385
386 if state.data.get_width(self.textbox_w) == 0.0 {
387 state.style.width.play_animation(self.textbox_w, self.reveal);
388 state.style.right.play_animation(self.textbox_w, self.grow);
389 }
390
391 self.textbox_x.set_width(state, Stretch(1.0));
392 self.textbox_y.set_width(state, Stretch(1.0));
393 self.textbox_z.set_width(state, Stretch(1.0));
394 self.textbox_w.set_width(state, Stretch(1.0));
395
396 self.textbox_x.set_right(state, Units::Pixels(5.0));
397 self.textbox_y.set_right(state, Units::Pixels(5.0));
398 self.textbox_z.set_right(state, Units::Pixels(5.0));
399 self.textbox_w.set_right(state, Units::Pixels(5.0));
400
401 self.num_of_dims = 4;
402
403 state.insert_event(
404 Event::new(VectorEditEvent::Dim4(
405 self.x, self.y, self.z, self.w,
406 ))
407 .target(entity),
408 );
409 }
410
411 _ => {}
412 },
413 }
414 }
415
416 if let Some(textbox_event) = event.message.downcast::<TextboxEvent>() {
417 match textbox_event {
418 TextboxEvent::ValueChanged(text) => {
419 if let Ok(val) = text.clone().parse::<T>() {
420 if target == self.textbox_x {
421 self.x = val;
422 }
423
424 if target == self.textbox_y {
425 self.y = val;
426 }
427
428 if target == self.textbox_z {
429 self.z = val;
430 }
431
432 if target == self.textbox_w {
433 self.w = val;
434 }
435
436 match self.num_of_dims {
437 1 => state.insert_event(
438 Event::new(VectorEditEvent::Dim1(self.x)).target(entity),
439 ),
440 2 => state.insert_event(
441 Event::new(VectorEditEvent::Dim2(self.x, self.y))
442 .target(entity),
443 ),
444 3 => state.insert_event(
445 Event::new(VectorEditEvent::Dim3(self.x, self.y, self.z))
446 .target(entity),
447 ),
448 4 => state.insert_event(
449 Event::new(VectorEditEvent::Dim4(
450 self.x, self.y, self.z, self.w,
451 ))
452 .target(entity),
453 ),
454 _ => {}
455 }
456
457 if let Some(callback) = self.on_change.take() {
458 (callback)(self, state, entity);
459 self.on_change = Some(callback);
460 }
461
462 }
464 }
465
466 _ => {}
467 }
468 }
469 }
470}