diff options
Diffstat (limited to 'engine/src/ui/view/world.rs')
| -rw-r--r-- | engine/src/ui/view/world.rs | 210 |
1 files changed, 192 insertions, 18 deletions
diff --git a/engine/src/ui/view/world.rs b/engine/src/ui/view/world.rs index 8191d89..ccdbfb3 100644 --- a/engine/src/ui/view/world.rs +++ b/engine/src/ui/view/world.rs @@ -4,7 +4,11 @@ use std::io::Cursor; use crate::ecs::actions::Actions; use crate::ecs::component::local::Local; -use crate::ecs::component::{Info as ComponentInfo, Parts as ComponentParts}; +use crate::ecs::component::{ + Handle as ComponentHandle, + Info as ComponentInfo, + Parts as ComponentParts, +}; use crate::ecs::entity::{Handle as EntityHandle, Name as EntityName}; use crate::ecs::sole::Single; use crate::ecs::uid::Uid; @@ -32,6 +36,7 @@ pub struct State spawning_entity: Option<Uid>, add_component_popup_state: Option<AddComponentPopupState>, despawn_icon_tex: Option<dear_imgui_bindings::OwnedTextureData>, + warning_icon_tex: Option<dear_imgui_bindings::OwnedTextureData>, } impl Default for State @@ -42,6 +47,7 @@ impl Default for State spawning_entity: None, add_component_popup_state: None, despawn_icon_tex: None, + warning_icon_tex: None, } } } @@ -72,10 +78,30 @@ pub fn show( spawning_entity, add_component_popup_state, despawn_icon_tex, + warning_icon_tex, } = &mut *state; - let despawn_icon_tex = despawn_icon_tex - .get_or_insert_with(|| create_despawn_icon_texture(dear_imgui_context)); + let despawn_icon_tex = despawn_icon_tex.get_or_insert_with(|| { + create_texture( + dear_imgui_context, + Image::from_reader( + Cursor::new(include_bytes!("../../../res/ui/delete.png")), + ImageFormat::Png, + ) + .unwrap(), + ) + }); + + let warning_icon_tex = warning_icon_tex.get_or_insert_with(|| { + create_texture( + dear_imgui_context, + Image::from_reader( + Cursor::new(include_bytes!("../../../res/ui/warning.png")), + ImageFormat::Png, + ) + .unwrap(), + ) + }); let Some(frame) = dear_imgui_context.frame() else { return Ok(()); @@ -101,6 +127,7 @@ pub fn show( frame, add_component_popup_state, despawn_icon_tex, + warning_icon_tex, &ent_handle, world, &mut actions, @@ -117,32 +144,28 @@ pub fn show( Ok(()) } -fn create_despawn_icon_texture( +fn create_texture( dear_imgui_context: &mut DearImguiContext, + image: Image, ) -> dear_imgui_bindings::OwnedTextureData { - let despawn_icon_image = Image::from_reader( - Cursor::new(include_bytes!("../../../res/ui/delete.png")), - ImageFormat::Png, - ) - .unwrap() - .into_rgba8(); + let image = image.into_rgba8(); - let mut despawn_icon_tex = dear_imgui_bindings::OwnedTextureData::new(); + let mut texture_data = dear_imgui_bindings::OwnedTextureData::new(); - despawn_icon_tex.create( + texture_data.create( dear_imgui_bindings::TextureFormat::RGBA32, - despawn_icon_image.dimensions().width, - despawn_icon_image.dimensions().height, + image.dimensions().width, + image.dimensions().height, ); - despawn_icon_tex.set_data(despawn_icon_image.as_bytes()); + texture_data.set_data(image.as_bytes()); - despawn_icon_tex.set_status(dear_imgui_bindings::TextureStatus::WantCreate); + texture_data.set_status(dear_imgui_bindings::TextureStatus::WantCreate); - dear_imgui_context.register_texture(&mut despawn_icon_tex); + dear_imgui_context.register_texture(&mut texture_data); - despawn_icon_tex + texture_data } fn create_spawn_button_widgets( @@ -181,6 +204,7 @@ fn create_entity_widgets( frame: &dear_imgui_bindings::Ui, add_component_popup_state: &mut Option<AddComponentPopupState>, despawn_icon_tex: &mut dear_imgui_bindings::OwnedTextureData, + warning_icon_tex: &mut dear_imgui_bindings::OwnedTextureData, ent_handle: &EntityHandle, world: &World, actions: &mut Actions, @@ -237,6 +261,21 @@ fn create_entity_widgets( if is_open { for component_id in ent_handle.component_ids() { + if component_id.is_pair() { + create_pair_component_widgets( + frame, + warning_icon_tex, + ent_handle, + component_id, + world, + actions, + ); + + frame.spacing(); + + continue; + } + create_component_widgets(frame, ent_handle, component_id, world, actions); } } @@ -319,6 +358,141 @@ fn create_component_widgets( } } +fn create_pair_component_widgets( + frame: &dear_imgui_bindings::Ui, + warning_icon_tex: &mut dear_imgui_bindings::OwnedTextureData, + ent_handle: &EntityHandle, + pair_id: Uid, + world: &World, + actions: &mut Actions, +) +{ + { + let _color_token = frame.push_style_color( + dear_imgui_bindings::StyleColor::Button, + BUTTON_RED_NORMAL.map(|num| num / 255.0), + ); + + let _color_token_b = frame.push_style_color( + dear_imgui_bindings::StyleColor::ButtonHovered, + BUTTON_RED_HOVERED.map(|num| num / 255.0), + ); + + let _color_token_c = frame.push_style_color( + dear_imgui_bindings::StyleColor::ButtonActive, + BUTTON_RED_ACTIVE.map(|num| num / 255.0), + ); + + if frame.small_button(format!( + "X##world_view_entity_{}_remove_component_button_{}", + ent_handle.uid(), + pair_id + )) { + actions.remove_components(ent_handle.uid(), [pair_id]); + } + } + + frame.same_line(); + + let relation_comp_info_or_ent_name = + get_comp_info_or_ent_name(world, pair_id.relation()); + + let relation_name: Cow<'_, str> = match &relation_comp_info_or_ent_name { + Some(Either::A(comp_info)) => comp_info.name.into(), + Some(Either::B(ent_name)) => format!("🌐 {}", ent_name.name).into(), + None => format!("<unnamed> {}", pair_id.relation()).into(), + }; + + let target_comp_info_or_ent_name = get_comp_info_or_ent_name(world, pair_id.target()); + + let target_name: Cow<'_, str> = match &target_comp_info_or_ent_name { + Some(Either::A(comp_info)) => comp_info.name.into(), + Some(Either::B(ent_name)) => format!("🌐 {}", ent_name.name).into(), + None => format!("<unnamed> {}", pair_id.target()).into(), + }; + + // TODO: Make relation & target ids editable + + frame.text(format!("({relation_name}, {target_name})")); + + let Some(mut pair_data) = ent_handle.get_any_by_id_mut(pair_id) else { + unreachable!(); + }; + + let pair_data_ty_id = (*pair_data).type_id(); + + let Some(pair_data_comp_info) = [ + &relation_comp_info_or_ent_name, + &target_comp_info_or_ent_name, + ] + .map(Option::as_ref) + .map(|item| item.and_then(Either::as_a)) + .into_iter() + .flatten() + .find(|comp_info| comp_info.ty_id == pair_data_ty_id) else { + return; + }; + + let Some(pair_data_ty) = pair_data_comp_info.type_reflection else { + frame.same_line(); + + frame.image(&mut **warning_icon_tex, [16.0, 16.0]); + + if frame.is_item_hovered() { + frame.tooltip_text(format!( + "Pair data type {} does not have reflection", + pair_data_comp_info.name + )); + } + + return; + }; + + frame.indent(); + + let mut component_changed = false; + + add_item_to_frame( + frame, + ItemRef::Mutable(&mut *pair_data), + &mut component_changed, + ItemInfo { + item_title: pair_data_comp_info.name, + item_tag: &format!( + "world_view_entity_{}_pair_component_{pair_id}", + ent_handle.uid(), + ), + item_type_name: None, + item_type: ItemType::Reflected(pair_data_ty), + item_is_read_only: false, + }, + &[], + ); + + frame.unindent(); + + // The pair component is not set as changed here since events do not support + // pairs as event targets +} + +fn get_comp_info_or_ent_name( + world: &World, + id: Uid, +) -> Option<Either<ComponentHandle<'_, ComponentInfo>, ComponentHandle<'_, EntityName>>> +{ + let ent = world.get_entity(id)?; + + if let Some(component_info) = ent.get::<ComponentInfo>() { + return Some(Either::A(component_info)); + } + + if let Some(entity_name) = ent.get::<EntityName>() { + return Some(Either::B(entity_name)); + } + + None +} + fn create_add_component_button_widget( frame: &dear_imgui_bindings::Ui, ent_handle: &EntityHandle, |
