summaryrefslogtreecommitdiff
path: root/engine/src/ui/view/world.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2026-08-04 19:59:28 +0200
committerHampusM <hampus@hampusmat.com>2026-08-04 19:59:28 +0200
commitcb43fefd72f97e4ee639968042fdba4bcb8c154c (patch)
treec5f938fb765def030898bd2dd213a70a018b424a /engine/src/ui/view/world.rs
parent4bb88a1a15bf79b9510c12fa729a680a52c75a54 (diff)
feat(engine): make pairs in entities viewable in world ui viewHEADmaster
Diffstat (limited to 'engine/src/ui/view/world.rs')
-rw-r--r--engine/src/ui/view/world.rs210
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,