khora_editor/widgets/inspector/
renderers.rs1use khora_sdk::editor_ui::{UiBuilder, UiTheme};
18use serde_json::Value;
19
20pub fn is_vec3(map: &serde_json::Map<String, Value>) -> bool {
23 map.len() == 3
24 && map.get("x").is_some_and(|v| v.is_number())
25 && map.get("y").is_some_and(|v| v.is_number())
26 && map.get("z").is_some_and(|v| v.is_number())
27}
28
29pub fn is_quat(map: &serde_json::Map<String, Value>) -> bool {
30 map.len() == 4
31 && map.get("x").is_some_and(|v| v.is_number())
32 && map.get("y").is_some_and(|v| v.is_number())
33 && map.get("z").is_some_and(|v| v.is_number())
34 && map.get("w").is_some_and(|v| v.is_number())
35}
36
37pub fn is_color(map: &serde_json::Map<String, Value>) -> bool {
38 map.len() == 4
39 && map.get("r").is_some_and(|v| v.is_number())
40 && map.get("g").is_some_and(|v| v.is_number())
41 && map.get("b").is_some_and(|v| v.is_number())
42 && map.get("a").is_some_and(|v| v.is_number())
43}
44
45pub fn render_vec3(
48 ui: &mut dyn UiBuilder,
49 map: &mut serde_json::Map<String, Value>,
50 _theme: &UiTheme,
51) -> bool {
52 let mut v = [
53 json_to_f32(map.get("x")),
54 json_to_f32(map.get("y")),
55 json_to_f32(map.get("z")),
56 ];
57 let changed = ui.vec3_editor("", &mut v, 0.05);
58 if changed {
59 map.insert("x".into(), f32_to_json(v[0]));
60 map.insert("y".into(), f32_to_json(v[1]));
61 map.insert("z".into(), f32_to_json(v[2]));
62 }
63 changed
64}
65
66pub fn render_quat(ui: &mut dyn UiBuilder, map: &mut serde_json::Map<String, Value>) -> bool {
67 let mut changed = false;
68 for axis in ["x", "y", "z", "w"] {
69 let mut local = json_to_f32(map.get(axis));
70 if ui.drag_value_f32(axis, &mut local, 0.01) {
71 map.insert(axis.into(), f32_to_json(local));
72 changed = true;
73 }
74 }
75 changed
76}
77
78pub fn render_color(
79 ui: &mut dyn UiBuilder,
80 map: &mut serde_json::Map<String, Value>,
81 _theme: &UiTheme,
82) -> bool {
83 let mut rgba = [
84 json_to_f32(map.get("r")),
85 json_to_f32(map.get("g")),
86 json_to_f32(map.get("b")),
87 json_to_f32(map.get("a")),
88 ];
89 let changed = ui.color_edit("", &mut rgba);
90 if changed {
91 map.insert("r".into(), f32_to_json(rgba[0]));
92 map.insert("g".into(), f32_to_json(rgba[1]));
93 map.insert("b".into(), f32_to_json(rgba[2]));
94 map.insert("a".into(), f32_to_json(rgba[3]));
95 }
96 changed
97}
98
99pub fn render_number_row(ui: &mut dyn UiBuilder, label: &str, value: &mut Value) -> bool {
100 let mut local = json_to_f32(Some(&*value));
101 let changed = ui.drag_value_f32(label, &mut local, 0.05);
102 if changed {
103 *value = f32_to_json(local);
104 }
105 changed
106}
107
108pub fn render_numeric_triple(ui: &mut dyn UiBuilder, label: &str, arr: &mut [Value]) -> bool {
109 let mut v = [
110 json_to_f32(Some(&arr[0])),
111 json_to_f32(Some(&arr[1])),
112 json_to_f32(Some(&arr[2])),
113 ];
114 let changed = ui.vec3_editor(label, &mut v, 0.05);
115 if changed {
116 arr[0] = f32_to_json(v[0]);
117 arr[1] = f32_to_json(v[1]);
118 arr[2] = f32_to_json(v[2]);
119 }
120 changed
121}
122
123pub fn render_numeric_quad(
124 ui: &mut dyn UiBuilder,
125 label: &str,
126 arr: &mut [Value],
127 _theme: &UiTheme,
128) -> bool {
129 let all_unit = arr.iter().all(|v| {
131 let n = v.as_f64().unwrap_or(f64::NAN);
132 (0.0..=1.0).contains(&n)
133 });
134 if all_unit {
135 let mut rgba = [
136 json_to_f32(Some(&arr[0])),
137 json_to_f32(Some(&arr[1])),
138 json_to_f32(Some(&arr[2])),
139 json_to_f32(Some(&arr[3])),
140 ];
141 let changed = ui.color_edit(label, &mut rgba);
142 if changed {
143 for (i, v) in rgba.iter().enumerate() {
144 arr[i] = f32_to_json(*v);
145 }
146 }
147 return changed;
148 }
149 let mut changed = false;
151 ui.horizontal(&mut |row| {
152 row.label(label);
153 for v in arr.iter_mut() {
154 let mut local = json_to_f32(Some(&*v));
155 if row.drag_value_f32("", &mut local, 0.05) {
156 *v = f32_to_json(local);
157 changed = true;
158 }
159 }
160 });
161 changed
162}
163
164pub fn json_to_f32(v: Option<&Value>) -> f32 {
167 v.and_then(|v| v.as_f64()).map(|f| f as f32).unwrap_or(0.0)
168}
169
170pub fn f32_to_json(f: f32) -> Value {
171 serde_json::Number::from_f64(f as f64)
172 .map(Value::Number)
173 .unwrap_or(Value::Null)
174}
175
176pub fn humanise(field: &str) -> String {
179 let mut out = String::with_capacity(field.len());
180 let mut up = true;
181 for c in field.chars() {
182 if c == '_' {
183 out.push(' ');
184 up = true;
185 } else if up {
186 out.extend(c.to_uppercase());
187 up = false;
188 } else {
189 out.push(c);
190 }
191 }
192 out
193}