diff options
| author | HampusM <hampus@hampusmat.com> | 2026-08-07 18:18:07 +0200 |
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2026-08-07 18:18:07 +0200 |
| commit | 8520817a39d6554246485ce0f8775a7cd8e9c3a7 (patch) | |
| tree | 1045dc2f55702bf34723931a386ab8a6aa081dbd | |
| parent | 5d4921cc41af2f1cac790661fc0e55389ba1eaee (diff) | |
| -rw-r--r-- | engine/src/ui/view/world.rs | 397 |
1 files changed, 321 insertions, 76 deletions
diff --git a/engine/src/ui/view/world.rs b/engine/src/ui/view/world.rs index ccdbfb3..2bf3ca5 100644 --- a/engine/src/ui/view/world.rs +++ b/engine/src/ui/view/world.rs @@ -17,7 +17,10 @@ use crate::ecs::{Component, Query, World}; use crate::image::{Format as ImageFormat, Image}; use crate::reflection::{ Enum as EnumReflection, + EnumVariant as EnumVariantReflection, + GetError as ReflectionGetError, LiteralType, + Struct as StructReflection, Type as TypeReflection, Visibility, }; @@ -333,6 +336,13 @@ fn create_component_widgets( let mut component_changed = false; + create_item_title_widget( + frame, + component_info.name, + &ItemType::Reflected(component_type), + None, + ); + add_item_to_frame( frame, ItemRef::Mutable(&mut *component), @@ -452,6 +462,13 @@ fn create_pair_component_widgets( let mut component_changed = false; + create_item_title_widget( + frame, + pair_data_comp_info.name, + &ItemType::Reflected(pair_data_ty), + None, + ); + add_item_to_frame( frame, ItemRef::Mutable(&mut *pair_data), @@ -727,6 +744,13 @@ fn show_add_component_popup( unreachable!(); }; + create_item_title_widget( + frame, + new_component_info.name, + &ItemType::Reflected(new_component_type), + None, + ); + add_item_to_frame( frame, ItemRef::Mutable(&mut **new_component), @@ -820,6 +844,27 @@ enum ItemType CowStr, } +impl ItemType +{ + fn spans_multiple_rows(&self) -> bool + { + match self { + Self::Reflected( + TypeReflection::Struct(_) + | TypeReflection::Array(_) + | TypeReflection::Slice(_), + ) => true, + Self::Reflected(TypeReflection::Enum(enum_ty)) if !enum_ty.is_unit_only => { + true + } + Self::Reflected(TypeReflection::Reference(ref_ty)) => { + ItemType::Reflected(ref_ty.ty).spans_multiple_rows() + } + _ => false, + } + } +} + fn get_item_type(ty: Option<&'static TypeReflection>, type_id: TypeId) -> Option<ItemType> { @@ -840,6 +885,41 @@ enum ItemRef<'item> Immutable(&'item dyn Any), } +impl ItemRef<'_> +{ + fn get_struct_field( + &mut self, + ty: &StructReflection, + field_index: usize, + ) -> Result<ItemRef<'_>, ReflectionGetError> + { + match self { + ItemRef::Mutable(item) => { + (ty.try_get_field_mut)(*item, field_index).map(ItemRef::Mutable) + } + ItemRef::Immutable(item) => { + (ty.try_get_field)(*item, field_index).map(ItemRef::Immutable) + } + } + } + + fn get_enum_variant_field( + &mut self, + variant: &EnumVariantReflection, + field_index: usize, + ) -> Result<ItemRef<'_>, ReflectionGetError> + { + match self { + ItemRef::Mutable(item) => { + (variant.try_get_field_mut)(*item, field_index).map(ItemRef::Mutable) + } + ItemRef::Immutable(item) => { + (variant.try_get_field)(*item, field_index).map(ItemRef::Immutable) + } + } + } +} + impl AsRef<dyn Any> for ItemRef<'_> { fn as_ref(&self) -> &dyn Any @@ -851,6 +931,24 @@ impl AsRef<dyn Any> for ItemRef<'_> } } +fn create_item_title_widget( + frame: &dear_imgui_bindings::Ui, + item_title: &str, + item_type: &ItemType, + item_type_name: Option<&str>, +) +{ + if !matches!(item_type, ItemType::Reflected(TypeReflection::Reference(_))) { + frame.text(&item_title); + + if let Some(item_type_name) = item_type_name { + if frame.is_item_hovered() { + frame.tooltip_text(item_type_name); + } + } + } +} + fn add_item_to_frame<'a>( frame: &dear_imgui_bindings::Ui, mut item: ItemRef<'_>, @@ -865,16 +963,6 @@ fn add_item_to_frame<'a>( prev_item_tags: &[&'a str], ) { - if !matches!(item_type, ItemType::Reflected(TypeReflection::Reference(_))) { - frame.text(&item_title); - - if let Some(item_type_name) = item_type_name { - if frame.is_item_hovered() { - frame.tooltip_text(item_type_name); - } - } - } - let _disabled = frame.begin_disabled_with_cond( !matches!( item_type, @@ -888,56 +976,18 @@ fn add_item_to_frame<'a>( ); match item_type { - ItemType::Reflected(TypeReflection::Struct(struct_reflection)) => { + ItemType::Reflected(TypeReflection::Struct(struct_ty)) => { frame.indent(); - let mut prev_item_tags = prev_item_tags.to_vec(); - - prev_item_tags.push(item_tag.as_ref()); - - for (field_index, field) in struct_reflection.fields.iter().enumerate() { - let field_name = field - .name - .map(Cow::Borrowed) - .unwrap_or_else(|| field_index.to_string().into()); - - let Some(field_item_type) = - get_item_type(field.type_reflection(), field.type_id) - else { - continue; - }; - - let Ok(field_item) = (match &mut item { - ItemRef::Mutable(item) => { - (struct_reflection.try_get_field_mut)(*item, field_index) - .map(ItemRef::Mutable) - } - ItemRef::Immutable(item) => { - (struct_reflection.try_get_field)(*item, field_index) - .map(ItemRef::Immutable) - } - }) else { - unreachable!(); - }; - - add_item_to_frame( - frame, - field_item, - data_changed, - ItemInfo { - item_title: field_name.as_ref(), - item_tag: field_name.as_ref(), - item_type_name: Some(field.type_name()), - item_type: field_item_type, - item_is_read_only: item_is_read_only - || matches!( - field.visibility, - Visibility::Private | Visibility::PubScoped(_) - ), - }, - &prev_item_tags, - ); - } + create_struct_widgets( + frame, + &mut item, + data_changed, + item_tag, + item_is_read_only, + struct_ty, + prev_item_tags, + ); frame.unindent(); } @@ -1163,6 +1213,13 @@ fn add_item_to_frame<'a>( unreachable!(); }; + create_item_title_widget( + frame, + &array_item_name, + &ItemType::Reflected(array_type.item_type), + Some(array_type.item_type_name()), + ); + add_item_to_frame( frame, item_item, @@ -1201,6 +1258,13 @@ fn add_item_to_frame<'a>( let mut slice_item_changed = false; + create_item_title_widget( + frame, + &item_name, + &ItemType::Reflected(slice_type.item_type), + Some(slice_type.item_type_name()), + ); + add_item_to_frame( frame, ItemRef::Immutable(item_item), @@ -1227,6 +1291,13 @@ fn add_item_to_frame<'a>( unreachable!(); }; + create_item_title_widget( + frame, + item_title, + &ItemType::Reflected(ref_type.ty), + item_type_name, + ); + add_item_to_frame( frame, ItemRef::Immutable(derefed_item), @@ -1344,6 +1415,132 @@ fn create_scalar_item_input<Scalar>( } } +fn item_layout_table<'frame>( + frame: &'frame dear_imgui_bindings::Ui, + prev_item_tags: &[&str], +) -> dear_imgui_bindings::TableBuilder<'frame> +{ + frame + .table(create_item_label("item_layout", "table", &prev_item_tags)) + .headers(false) + .sizing_policy(dear_imgui_bindings::TableSizingPolicy::StretchSame) + .columns([ + dear_imgui_bindings::TableColumnSetup::new("a"), + dear_imgui_bindings::TableColumnSetup::new("b").stretch_weight(2.0), + ]) +} + +fn create_struct_widgets( + frame: &dear_imgui_bindings::Ui, + item: &mut ItemRef<'_>, + data_changed: &mut bool, + item_tag: &str, + item_is_read_only: bool, + struct_ty: &StructReflection, + prev_item_tags: &[&str], +) +{ + let mut prev_item_tags = prev_item_tags.to_vec(); + + prev_item_tags.push(item_tag.as_ref()); + + let struct_fields = + struct_ty + .fields + .iter() + .enumerate() + .filter_map(|(field_index, field)| { + let field_item_type = + get_item_type(field.type_reflection(), field.type_id)?; + + Some((field_index, field, field_item_type)) + }); + + item_layout_table(frame, &prev_item_tags).build(|frame| { + for (field_index, field, field_item_type) in struct_fields + .clone() + .filter(|(.., field_item_type)| !field_item_type.spans_multiple_rows()) + { + frame.table_next_row(); + frame.table_next_column(); + + let field_name = field + .name + .map(Cow::Borrowed) + .unwrap_or_else(|| field_index.to_string().into()); + + let Ok(field_item) = item.get_struct_field(struct_ty, field_index) else { + unreachable!(); + }; + + create_item_title_widget( + frame, + &field_name, + &field_item_type, + Some(field.type_name()), + ); + + frame.table_next_column(); + + add_item_to_frame( + frame, + field_item, + data_changed, + ItemInfo { + item_title: field_name.as_ref(), + item_tag: field_name.as_ref(), + item_type_name: Some(field.type_name()), + item_type: field_item_type, + item_is_read_only: item_is_read_only + || matches!( + field.visibility, + Visibility::Private | Visibility::PubScoped(_) + ), + }, + &prev_item_tags, + ); + } + }); + + for (field_index, field, field_item_type) in struct_fields + .filter(|(.., field_item_type)| field_item_type.spans_multiple_rows()) + { + let field_name = field + .name + .map(Cow::Borrowed) + .unwrap_or_else(|| field_index.to_string().into()); + + let Ok(field_item) = item.get_struct_field(struct_ty, field_index) else { + unreachable!(); + }; + + create_item_title_widget( + frame, + &field_name, + &field_item_type, + Some(field.type_name()), + ); + + add_item_to_frame( + frame, + field_item, + data_changed, + ItemInfo { + item_title: field_name.as_ref(), + item_tag: field_name.as_ref(), + item_type_name: Some(field.type_name()), + item_type: field_item_type, + item_is_read_only: item_is_read_only + || matches!( + field.visibility, + Visibility::Private | Visibility::PubScoped(_) + ), + }, + &prev_item_tags, + ); + } +} + fn create_enum_widgets( frame: &dear_imgui_bindings::Ui, item: &mut ItemRef<'_>, @@ -1438,32 +1635,45 @@ fn create_enum_widgets( let curr_variant = &enum_type.variants[curr_variant_index]; - if let Some(curr_variant_fields) = &curr_variant.fields { - for (field_index, field) in curr_variant_fields.fields().iter().enumerate() { - let Some(field_item_type) = - get_item_type(field.type_reflection(), field.type_id) - else { - continue; - }; + let Some(curr_variant_fields) = &curr_variant.fields else { + return; + }; + + let variant_fields = curr_variant_fields.fields().iter().enumerate().filter_map( + |(field_index, field)| { + let field_item_type = get_item_type(field.type_reflection(), field.type_id)?; + + Some((field_index, field, field_item_type)) + }, + ); + + item_layout_table(frame, &prev_item_tags).build(|_| { + for (field_index, field, field_item_type) in variant_fields + .clone() + .filter(|(.., field_item_type)| !field_item_type.spans_multiple_rows()) + { + frame.table_next_row(); + frame.table_next_column(); let field_name: Cow<str> = match field.name { Some(field_name) => field_name.into(), None => field_index.to_string().into(), }; - let Ok(field_item) = (match item { - ItemRef::Mutable(item) => { - (curr_variant.try_get_field_mut)(*item, field_index) - .map(ItemRef::Mutable) - } - ItemRef::Immutable(item) => { - (curr_variant.try_get_field)(*item, field_index) - .map(ItemRef::Immutable) - } - }) else { + let Ok(field_item) = item.get_enum_variant_field(curr_variant, field_index) + else { unreachable!(); }; + create_item_title_widget( + frame, + &field_name, + &field_item_type, + Some(field.type_name()), + ); + + frame.table_next_column(); + add_item_to_frame( frame, field_item, @@ -1478,7 +1688,42 @@ fn create_enum_widgets( &prev_item_tags, ); } - }; + }); + + for (field_index, field, field_item_type) in variant_fields + .filter(|(.., field_item_type)| field_item_type.spans_multiple_rows()) + { + let field_name: Cow<str> = match field.name { + Some(field_name) => field_name.into(), + None => field_index.to_string().into(), + }; + + let Ok(field_item) = item.get_enum_variant_field(curr_variant, field_index) + else { + unreachable!(); + }; + + create_item_title_widget( + frame, + &field_name, + &field_item_type, + Some(field.type_name()), + ); + + add_item_to_frame( + frame, + field_item, + data_changed, + ItemInfo { + item_title: field_name.as_ref(), + item_tag: field_name.as_ref(), + item_type_name: Some(field.type_name()), + item_type: field_item_type, + item_is_read_only: item_is_read_only, + }, + &prev_item_tags, + ); + } } fn create_item_label(item_tag: &str, value_name: &str, prev_item_tags: &[&str]) |
