I want to add properties window with auto properties based on struct fields. I'am downcasting every field, but for Vec<> and Option<> I have to duplicate all code, how can I automatically check is that any Option or Vec.
Downcaster:
pub fn downcast_property(ui: &mut Ui, title: &str, value_mut: &mut (dyn Any + 'static), interactable: bool) {
if let Some(string_v) = value_mut.downcast_mut::<String>() {
string_property(ui, title, string_v, interactable);
} else if let Some(int_v) = value_mut.downcast_mut::<i32>() {
i_property(ui, title, int_v, interactable);
} else if let Some(float_v) = value_mut.downcast_mut::<f32>() {
f_property(ui, title, float_v, interactable);
} else if let Some(usize_v) = value_mut.downcast_mut::<usize>() {
i_property(ui, title, usize_v, interactable);
} else if let Some(bool_v) = value_mut.downcast_mut::<bool>() {
bool_property(ui, title, bool_v, interactable);
} else if downcast_all_enum_properties(value_mut, ui, title, interactable, true) {
// Automaticall enum downcaster
} else if let Some(named_type_value) = value_mut.downcast_mut::<NamedTypeValue>() {
namedvalue_property(ui, title, named_type_value, interactable);
} else if let Some(argument_named_value) = value_mut.downcast_mut::<ArgumentNamedValue>() {
argnamedvalue_property(ui, title, argument_named_value, interactable);
} else if let Some(v) = value_mut.downcast_mut::<Vec<String>>() {
list_property(ui, title, v, interactable);
} else if let Some(v) = value_mut.downcast_mut::<Vec<i32>>() {
list_property(ui, title, v, interactable);
} else if let Some(v) = value_mut.downcast_mut::<Vec<f32>>() {
list_property(ui, title, v, interactable);
} else if let Some(v) = value_mut.downcast_mut::<Vec<bool>>() {
list_property(ui, title, v, interactable);
} else if let Some(v) = value_mut.downcast_mut::<Vec<DataType>>() {
list_property(ui, title, v, interactable);
} else if let Some(v) = value_mut.downcast_mut::<Vec<ValueType>>() {
list_property(ui, title, v, interactable);
} else if let Some(v) = value_mut.downcast_mut::<Vec<NamedTypeValue>>() {
list_property(ui, title, v, interactable);
} else if let Some(v) = value_mut.downcast_mut::<Vec<ArgumentNamedValue>>() {
list_property(ui, title, v, interactable);
} else if let Some(o) = value_mut.downcast_mut::<Option<DataType>>() {
option_propery(ui, title, o, interactable);
} else if let Some(o) = value_mut.downcast_mut::<Option<String>>() {
option_propery(ui, title, o, interactable);
} else if let Some(o) = value_mut.downcast_mut::<Option<usize>>() {
option_propery(ui, title, o, interactable);
} else {
ui.label(RichText::new(format!("Field {}: unknown type", title)).color(Color32::LIGHT_RED));
}
}
list_property and option_property functions:
pub fn list_property<T>(ui: &mut Ui, title: &str, value_mut: &mut Vec<T>, interactable: bool)
where T: Default + 'static {
egui::CollapsingHeader::new(title)
.default_open(true)
.enabled(interactable)
.show(ui, |ui| {
ui.horizontal_top(|ui| {
if ui.button("➕ Add").clicked() {
value_mut.push(T::default());
}
});
let mut i = 0;
while i < value_mut.len() {
ui.horizontal(|ui| {
downcast_property(ui, "", &mut value_mut[i], interactable);
if ui.button("❌").on_hover_text("Remove").clicked() {
value_mut.remove(i);
} else {
i += 1;
}
});
}
});
}
pub fn option_propery<T>(ui: &mut Ui, title: &str, value_mut: &mut Option<T>, interactable: bool)
where T: Default + 'static {
let mut is_option_none = value_mut.is_none();
ui.horizontal(|ui| {
ui.label(title);
ui.add_space(PROPERTY_LABEL_PADDING);
bool_property(ui, "None", &mut is_option_none, interactable);
ui.add_space(2.0);
if is_option_none {
*value_mut = None;
} else {
if let Some(inner) = value_mut.as_mut() {
downcast_property(ui, "", inner, interactable);
} else {
*value_mut = Some(T::default());
}
}
});
}
TypeId's, it's impossible to downcastAnyintoOption<T>orVec<T>without statically knowing what theTis. If you must useAny, consider a macro to reduce code duplication.