1use std::collections::HashMap;
2use std::path::PathBuf;
3use std::str::FromStr;
4use serde::{Deserialize, Serialize};
5use crate::thread::rendering::{Color, RendererComponent};
6
7#[derive(Serialize, Deserialize, Clone, Debug)]
9pub struct ComponentDefinition {
10 pub display_name: String,
12
13 pub description: String,
15
16 pub default_looks: RendererComponent
18}
19
20#[derive(Serialize, Deserialize, Clone, Debug)]
22pub struct UIField {
23 pub name: String,
25
26 pub display_name: String,
28
29 pub description: String,
31
32 pub ty: UIFieldType,
34
35 pub default_value: UIFieldValue<UIValue>
37}
38
39#[derive(Serialize, Deserialize, Clone, Debug)]
41pub struct UIValue {
42 pub name: String,
44
45 pub display_name: String,
47
48 pub description: String,
50
51 pub ty: UIFieldType,
53
54 pub value: UIFieldValue<UIValue>,
56}
57
58#[derive(Serialize, Deserialize, Clone, Debug)]
60pub struct UIPathValue {
61 pub name: String,
63
64 pub path: String,
66
67 pub display_name: String,
69
70 pub description: String,
72
73 pub ty: UIFieldType,
75
76 pub value: UIFieldValue<UIPathValue>,
78}
79
80#[derive(Serialize, Deserialize, Clone, Debug)]
82pub enum UIFieldType {
83 Header,
85
86 Label,
88
89 InputFieldFloat,
91 InputFieldInteger,
93 InputFieldString,
95
96 InputFieldFloat2,
98
99 InputFieldInteger2,
101
102 InputFieldUnsignedInteger,
104
105 ValueSliderFloat(UIScalar<f32>),
109 ValueSliderInteger(UIScalar<i32>),
111
112 Collapsable,
114
115 Array(Vec<UIField>),
117
118 Choice(Vec<String>),
120
121 Checkbox {
123 disabled: bool
127 },
128
129 Color,
131
132 ImageData,
134
135 ExistingImage,
137
138 Font,
140
141 Button {
143 disabled: bool
145 },
146
147 ImagePreview,
149}
150
151#[derive(Serialize, Deserialize, Clone, Debug)]
153pub enum UIFieldValue<V> {
154 Header,
156
157 Label(String),
159
160 InputFieldFloat(f32),
162 InputFieldInteger(i32),
164 InputFieldString(String),
166
167 InputFieldFloat2(f32, f32),
169
170 InputFieldInteger2(i32, i32),
172
173 InputFieldUnsignedInteger(u32),
175
176 ValueSliderFloat(f32),
178 ValueSliderInteger(i32),
180
181 Collapsable(Vec<V>),
183
184 Array(Vec<Vec<V>>),
186
187 Choice(String),
189
190 Checkbox(bool),
192
193 Color(u8, u8, u8, u8),
195
196 ImageData(String),
198
199 ExistingImage(String),
201
202 Font(String),
204
205 Button,
207
208 ImagePreview(String)
210}
211
212impl<V> UIFieldValue<V> {
213 pub fn try_into_bool(&self) -> Result<bool, String> {
215 TryInto::<bool>::try_into(self)
216 }
217
218 pub fn try_into_f32(&self) -> Result<f32, String> {
220 TryInto::<f32>::try_into(self)
221 }
222
223 pub fn try_into_i32(&self) -> Result<i32, String> {
225 TryInto::<i32>::try_into(self)
226 }
227
228 pub fn try_into_u32(&self) -> Result<u32, String> {
230 TryInto::<u32>::try_into(self)
231 }
232
233 pub fn try_into_f32_f32(&self) -> Result<(f32, f32), String> {
235 TryInto::<(f32, f32)>::try_into(self)
236 }
237
238 pub fn try_into_i32_i32(&self) -> Result<(i32, i32), String> {
240 TryInto::<(i32, i32)>::try_into(self)
241 }
242
243 pub fn try_into_color(&self) -> Result<Color, String> {
245 TryInto::<Color>::try_into(self)
246 }
247
248 pub fn try_into_string(&self) -> Result<String, String> {
250 TryInto::<String>::try_into(self)
251 }
252}
253
254impl<V> Into<UIFieldValue<V>> for Color {
256 fn into(self) -> UIFieldValue<V> {
257 UIFieldValue::Color(self.0, self.1, self.2, self.3)
258 }
259}
260
261impl<V> Into<UIFieldValue<V>> for &Color {
262 fn into(self) -> UIFieldValue<V> {
263 UIFieldValue::Color(self.0, self.1, self.2, self.3)
264 }
265}
266
267impl<V> TryInto<bool> for UIFieldValue<V> {
269 type Error = String;
270
271 fn try_into(self) -> Result<bool, Self::Error> {
272 if let UIFieldValue::Checkbox(b) = self {
273 Ok(b)
274 } else {
275 Err("Incorrect value".to_string())
276 }
277 }
278}
279
280impl<V> TryInto<bool> for &UIFieldValue<V> {
281 type Error = String;
282
283 fn try_into(self) -> Result<bool, Self::Error> {
284 if let UIFieldValue::Checkbox(b) = self {
285 Ok(*b)
286 } else {
287 Err("Incorrect value".to_string())
288 }
289 }
290}
291
292impl<V> TryInto<f32> for UIFieldValue<V> {
293 type Error = String;
294
295 fn try_into(self) -> Result<f32, Self::Error> {
296 if let UIFieldValue::InputFieldFloat(f) | UIFieldValue::ValueSliderFloat(f) = self {
297 Ok(f)
298 } else {
299 Err("Incorrect value".to_string())
300 }
301 }
302}
303
304impl<V> TryInto<f32> for &UIFieldValue<V> {
305 type Error = String;
306
307 fn try_into(self) -> Result<f32, Self::Error> {
308 if let UIFieldValue::InputFieldFloat(f) | UIFieldValue::ValueSliderFloat(f) = self {
309 Ok(*f)
310 } else {
311 Err("Incorrect value".to_string())
312 }
313 }
314}
315
316impl<V> TryInto<i32> for UIFieldValue<V> {
317 type Error = String;
318
319 fn try_into(self) -> Result<i32, Self::Error> {
320 if let UIFieldValue::InputFieldInteger(i) | UIFieldValue::ValueSliderInteger(i) = self {
321 Ok(i)
322 } else {
323 Err("Incorrect value".to_string())
324 }
325 }
326}
327
328impl<V> TryInto<i32> for &UIFieldValue<V> {
329 type Error = String;
330
331 fn try_into(self) -> Result<i32, Self::Error> {
332 if let UIFieldValue::InputFieldInteger(i) | UIFieldValue::ValueSliderInteger(i) = self {
333 Ok(*i)
334 } else {
335 Err("Incorrect value".to_string())
336 }
337 }
338}
339
340impl<V> TryInto<u32> for UIFieldValue<V> {
341 type Error = String;
342
343 fn try_into(self) -> Result<u32, Self::Error> {
344 if let UIFieldValue::InputFieldUnsignedInteger(u) = self {
345 Ok(u)
346 } else {
347 Err("Incorrect value".to_string())
348 }
349 }
350}
351
352impl<V> TryInto<u32> for &UIFieldValue<V> {
353 type Error = String;
354
355 fn try_into(self) -> Result<u32, Self::Error> {
356 if let UIFieldValue::InputFieldUnsignedInteger(u) = self {
357 Ok(*u)
358 } else {
359 Err("Incorrect value".to_string())
360 }
361 }
362}
363
364impl<V> TryInto<(f32, f32)> for UIFieldValue<V> {
365 type Error = String;
366
367 fn try_into(self) -> Result<(f32, f32), Self::Error> {
368 if let UIFieldValue::InputFieldFloat2(f1, f2) = self {
369 Ok((f1, f2))
370 } else {
371 Err("Incorrect value".to_string())
372 }
373 }
374}
375
376impl<V> TryInto<(f32, f32)> for &UIFieldValue<V> {
377 type Error = String;
378
379 fn try_into(self) -> Result<(f32, f32), Self::Error> {
380 if let UIFieldValue::InputFieldFloat2(f1, f2) = self {
381 Ok((*f1, *f2))
382 } else {
383 Err("Incorrect value".to_string())
384 }
385 }
386}
387
388impl<V> TryInto<(i32, i32)> for UIFieldValue<V> {
389 type Error = String;
390
391 fn try_into(self) -> Result<(i32, i32), Self::Error> {
392 if let UIFieldValue::InputFieldInteger2(i1, i2) = self {
393 Ok((i1, i2))
394 } else {
395 Err("Incorrect value".to_string())
396 }
397 }
398}
399
400impl<V> TryInto<(i32, i32)> for &UIFieldValue<V> {
401 type Error = String;
402
403 fn try_into(self) -> Result<(i32, i32), Self::Error> {
404 if let UIFieldValue::InputFieldInteger2(i1, i2) = self {
405 Ok((*i1, *i2))
406 } else {
407 Err("Incorrect value".to_string())
408 }
409 }
410}
411
412impl<V> TryInto<Color> for UIFieldValue<V> {
413 type Error = String;
414
415 fn try_into(self) -> Result<Color, Self::Error> {
416 if let UIFieldValue::Color(c1, c2, c3, c4) = self {
417 Ok((c1, c2, c3, c4))
418 } else {
419 Err("Incorrect value".to_string())
420 }
421 }
422}
423
424impl<V> TryInto<Color> for &UIFieldValue<V> {
425 type Error = String;
426
427 fn try_into(self) -> Result<Color, Self::Error> {
428 if let UIFieldValue::Color(c1, c2, c3, c4) = self {
429 Ok((*c1, *c2, *c3, *c4))
430 } else {
431 Err("Incorrect value".to_string())
432 }
433 }
434}
435
436impl<V> TryInto<String> for UIFieldValue<V> {
437 type Error = String;
438
439 fn try_into(self) -> Result<String, Self::Error> {
440 if let UIFieldValue::InputFieldString(str) |
441 UIFieldValue::Choice(str) |
442 UIFieldValue::ImageData(str) |
443 UIFieldValue::ExistingImage(str) |
444 UIFieldValue::Font(str) |
445 UIFieldValue::Label(str) |
446 UIFieldValue::ImagePreview(str) = self {
447 Ok(str)
448 } else {
449 Err("Incorrect value".to_string())
450 }
451 }
452}
453
454impl<V> TryInto<String> for &UIFieldValue<V> {
455 type Error = String;
456
457 fn try_into(self) -> Result<String, Self::Error> {
458 if let UIFieldValue::InputFieldString(str) |
459 UIFieldValue::Choice(str) |
460 UIFieldValue::ImageData(str) |
461 UIFieldValue::ExistingImage(str) |
462 UIFieldValue::Font(str) |
463 UIFieldValue::Label(str) |
464 UIFieldValue::ImagePreview(str) = self {
465 Ok(str.clone())
466 } else {
467 Err("Incorrect value".to_string())
468 }
469 }
470}
471
472impl<V> TryInto<PathBuf> for UIFieldValue<V> {
473 type Error = String;
474
475 fn try_into(self) -> Result<PathBuf, Self::Error> {
476 if let UIFieldValue::InputFieldString(str) | UIFieldValue::Choice(str) = self {
477 if let Ok(path) = PathBuf::from_str(&str) {
478 Ok(path)
479 } else {
480 Err("Failed to parse path".to_string())
481 }
482 } else {
483 Err("Incorrect enum value".to_string())
484 }
485 }
486}
487
488impl<V> TryInto<PathBuf> for &UIFieldValue<V> {
489 type Error = String;
490
491 fn try_into(self) -> Result<PathBuf, Self::Error> {
492 if let UIFieldValue::InputFieldString(str) | UIFieldValue::Choice(str) = self {
493 if let Ok(path) = PathBuf::from_str(str) {
494 Ok(path)
495 } else {
496 Err("Failed to parse path".to_string())
497 }
498 } else {
499 Err("Incorrect value".to_string())
500 }
501 }
502}
503
504impl From<UIFieldValue<UIValue>> for UIFieldValue<UIPathValue> {
505 fn from(val: UIFieldValue<UIValue>) -> Self {
506 match val {
507 UIFieldValue::Header => UIFieldValue::Header,
508 UIFieldValue::Label(s) => UIFieldValue::Label(s),
509 UIFieldValue::InputFieldFloat(f) => UIFieldValue::InputFieldFloat(f),
510 UIFieldValue::InputFieldInteger(i) => UIFieldValue::InputFieldInteger(i),
511 UIFieldValue::InputFieldString(s) => UIFieldValue::InputFieldString(s),
512 UIFieldValue::InputFieldFloat2(f1, f2) => UIFieldValue::InputFieldFloat2(f1, f2),
513 UIFieldValue::InputFieldInteger2(i1, i2) => UIFieldValue::InputFieldInteger2(i1, i2),
514 UIFieldValue::InputFieldUnsignedInteger(u) => UIFieldValue::InputFieldUnsignedInteger(u),
515 UIFieldValue::ValueSliderFloat(f) => UIFieldValue::ValueSliderFloat(f),
516 UIFieldValue::ValueSliderInteger(i) => UIFieldValue::ValueSliderInteger(i),
517
518 UIFieldValue::Collapsable(_) => {
519 panic!("Please use convert_value_to_path")
520 }
521
522 UIFieldValue::Array(_) => {
523 panic!("Please use convert_value_to_path")
524 }
525
526 UIFieldValue::Choice(c) => UIFieldValue::Choice(c),
527 UIFieldValue::Checkbox(b) => UIFieldValue::Checkbox(b),
528 UIFieldValue::Color(c1, c2, c3, c4) => UIFieldValue::Color(c1, c2, c3, c4),
529 UIFieldValue::ImageData(d) => UIFieldValue::ImageData(d),
530 UIFieldValue::ExistingImage(i) => UIFieldValue::ExistingImage(i),
531 UIFieldValue::Font(f) => UIFieldValue::Font(f),
532 UIFieldValue::Button => UIFieldValue::Button,
533 UIFieldValue::ImagePreview(d) => UIFieldValue::ImagePreview(d)
534 }
535 }
536}
537
538impl From<UIFieldValue<UIPathValue>> for UIFieldValue<UIValue> {
539 fn from(val: UIFieldValue<UIPathValue>) -> Self {
540 match val {
541 UIFieldValue::Header => UIFieldValue::Header,
542 UIFieldValue::Label(s) => UIFieldValue::Label(s),
543 UIFieldValue::InputFieldFloat(f) => UIFieldValue::InputFieldFloat(f),
544 UIFieldValue::InputFieldInteger(i) => UIFieldValue::InputFieldInteger(i),
545 UIFieldValue::InputFieldString(s) => UIFieldValue::InputFieldString(s),
546 UIFieldValue::InputFieldFloat2(f1, f2) => UIFieldValue::InputFieldFloat2(f1, f2),
547 UIFieldValue::InputFieldInteger2(i1, i2) => UIFieldValue::InputFieldInteger2(i1, i2),
548 UIFieldValue::InputFieldUnsignedInteger(u) => UIFieldValue::InputFieldUnsignedInteger(u),
549 UIFieldValue::ValueSliderFloat(f) => UIFieldValue::ValueSliderFloat(f),
550 UIFieldValue::ValueSliderInteger(i) => UIFieldValue::ValueSliderInteger(i),
551
552 UIFieldValue::Collapsable(m) => {
553 UIFieldValue::Collapsable(m.into_iter()
554 .map(|x| UIValue {
555 name: x.name,
556 display_name: x.display_name,
557 description: x.description,
558 ty: x.ty,
559 value: x.value.into()
560 })
561 .collect())
562 }
563
564 UIFieldValue::Array(a) => {
565 UIFieldValue::Array(a.into_iter()
566 .map(|x| x.into_iter()
567 .map(|x| UIValue {
568 name: x.name,
569 display_name: x.display_name,
570 description: x.description,
571 ty: x.ty,
572 value: x.value.into()
573 })
574 .collect())
575 .collect())
576 }
577
578 UIFieldValue::Choice(c) => UIFieldValue::Choice(c),
579 UIFieldValue::Checkbox(b) => UIFieldValue::Checkbox(b),
580 UIFieldValue::Color(c1, c2, c3, c4) => UIFieldValue::Color(c1, c2, c3, c4),
581 UIFieldValue::ImageData(d) => UIFieldValue::ImageData(d),
582 UIFieldValue::ExistingImage(i) => UIFieldValue::ExistingImage(i),
583 UIFieldValue::Font(f) => UIFieldValue::Font(f),
584 UIFieldValue::Button => UIFieldValue::Button,
585 UIFieldValue::ImagePreview(d) => UIFieldValue::ImagePreview(d)
586 }
587 }
588}
589
590impl From<UIPathValue> for UIValue {
591 fn from(value: UIPathValue) -> Self {
592 UIValue {
593 name: value.name,
594 display_name: value.display_name,
595 description: value.description,
596 ty: value.ty,
597 value: value.value.into()
598 }
599 }
600}
601
602#[derive(Serialize, Deserialize, Clone, Debug)]
604pub struct UIScalar<T: PartialEq> {
605 pub max_value: T,
607 pub min_value: T,
609 pub step: T,
611 pub allow_out_of_bounds: bool
613}
614
615pub fn map_ui_values(values: Vec<UIValue>) -> HashMap<String, UIValue> {
617 values.into_iter()
618 .map(|x| (x.name.clone(), x))
619 .collect()
620}
621
622pub fn map_ui_values_ref(values: &Vec<UIValue>) -> HashMap<String, UIValue> {
624 values.into_iter()
625 .map(|x| (x.name.clone(), x.clone()))
626 .collect()
627}
628
629pub fn map_ui_path_values(values: &Vec<UIPathValue>) -> HashMap<String, UIPathValue> {
631 let mut map = HashMap::new();
632
633 fn add_values_to_map(values: &Vec<UIPathValue>, map: &mut HashMap<String, UIPathValue>) {
634 values.into_iter()
635 .for_each(|x| {
636 match &x.value {
637 UIFieldValue::Collapsable(m) => {
638 add_values_to_map(m, map);
639 }
640
641 UIFieldValue::Array(a) => {
642 a.into_iter()
643 .for_each(|x| add_values_to_map(x, map))
644 }
645
646 _ => {
647 map.insert(x.path.to_string(), x.clone());
648 }
649 }
650 })
651 }
652
653 add_values_to_map(values, &mut map);
654
655 return map;
656}