summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2026-09-01 16:11:00 +0200
committerHampusM <hampus@hampusmat.com>2026-09-01 16:11:00 +0200
commit632a7188ea267c93b5317ceffd18f1dab0e97cbe (patch)
treee8443268eae230d1daba89c31cca77971e15fe93
parentbc3d97cdf57431e33ea012858cc3d59f458e5283 (diff)
feat(engine): add entity renaming buttons to world ui view
-rw-r--r--engine/res/ui/edit.pngbin0 -> 581 bytes
-rw-r--r--engine/src/ui/view/world.rs343
2 files changed, 247 insertions, 96 deletions
diff --git a/engine/res/ui/edit.png b/engine/res/ui/edit.png
new file mode 100644
index 0000000..2431e79
--- /dev/null
+++ b/engine/res/ui/edit.png
Binary files differ
diff --git a/engine/src/ui/view/world.rs b/engine/src/ui/view/world.rs
index 143ff84..81c2377 100644
--- a/engine/src/ui/view/world.rs
+++ b/engine/src/ui/view/world.rs
@@ -35,38 +35,12 @@ const BUTTON_RED_NORMAL: [f32; 4] = [124.0, 52.0, 39.0, 255.0];
const BUTTON_RED_HOVERED: [f32; 4] = [181.0, 76.0, 57.0, 255.0];
const BUTTON_RED_ACTIVE: [f32; 4] = [162.0, 68.0, 51.0, 255.0];
-#[derive(Component)]
+#[derive(Default, Component)]
pub struct State
{
spawning_entity: Option<Uid>,
- add_component_popup_state: Option<AddComponentPopupState>,
- despawn_icon_tex_id: Option<dear_imgui_bindings::ManagedTextureId>,
- warning_icon_tex_id: Option<dear_imgui_bindings::ManagedTextureId>,
-}
-
-impl Default for State
-{
- fn default() -> Self
- {
- Self {
- spawning_entity: None,
- add_component_popup_state: None,
- despawn_icon_tex_id: None,
- warning_icon_tex_id: None,
- }
- }
-}
-
-#[derive(Debug)]
-pub struct AddComponentPopupState
-{
- popup_name: String,
- target_entity_id: Uid,
- search_text: String,
- searched_components: Vec<(Uid, ComponentInfo, ComponentUserCreatable)>,
- searchable_components: Vec<(Uid, ComponentInfo, ComponentUserCreatable)>,
- selected_search_result: i32,
- new_component: Option<(Box<dyn Any>, ComponentInfo, Uid)>,
+ popup_state: Option<PopupState>,
+ textures: Option<Textures>,
}
pub fn show(
@@ -81,32 +55,11 @@ pub fn show(
let State {
spawning_entity,
- add_component_popup_state,
- despawn_icon_tex_id,
- warning_icon_tex_id,
+ popup_state,
+ textures,
} = &mut *state;
- let despawn_icon_tex_id = *despawn_icon_tex_id.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_id = *warning_icon_tex_id.get_or_insert_with(|| {
- create_texture(
- dear_imgui_context,
- Image::from_reader(
- Cursor::new(include_bytes!("../../../res/ui/warning.png")),
- ImageFormat::Png,
- )
- .unwrap(),
- )
- });
+ let textures = textures.get_or_insert_with(|| Textures::new(dear_imgui_context));
let Some(frame) = dear_imgui_context.frame() else {
return Ok(());
@@ -119,7 +72,7 @@ pub fn show(
create_spawn_button_widgets(
frame,
spawning_entity,
- add_component_popup_state,
+ popup_state,
world,
&mut actions,
);
@@ -130,19 +83,26 @@ pub fn show(
for ent_handle in &query.into_flexible_query() {
create_entity_widgets(
frame,
- add_component_popup_state,
- despawn_icon_tex_id,
- warning_icon_tex_id,
+ popup_state,
+ textures,
&ent_handle,
world,
&mut actions,
);
}
- if let Some(popup_state) = add_component_popup_state {
- if show_add_component_popup(frame, popup_state, &mut actions) {
- *add_component_popup_state = None;
+ let popup_closed = match popup_state {
+ Some(PopupState::AddComponent(popup_state)) => {
+ show_add_component_popup(frame, popup_state, &mut actions)
+ }
+ Some(PopupState::RenameEntity(popup_state)) => {
+ show_rename_entity_popup(frame, popup_state, &mut actions, world)
}
+ _ => false,
+ };
+
+ if popup_closed {
+ *popup_state = None;
}
});
@@ -172,7 +132,7 @@ fn create_texture(
fn create_spawn_button_widgets(
frame: &dear_imgui_bindings::Ui,
spawning_entity: &mut Option<Uid>,
- add_component_popup_state: &mut Option<AddComponentPopupState>,
+ popup_state: &mut Option<PopupState>,
world: &World,
actions: &mut Actions,
)
@@ -187,25 +147,24 @@ fn create_spawn_button_widgets(
if let Some(spawning_ent) = &spawning_entity {
if let Some(spawned_ent) = world.get_entity(*spawning_ent) {
- *spawning_entity = None;
-
let spawned_ent_title = create_entity_title(&spawned_ent);
- enter_add_component_popup_state(
- add_component_popup_state,
+ if enter_add_component_popup_state(
+ popup_state,
&spawned_ent,
&spawned_ent_title,
world,
- );
+ ) {
+ *spawning_entity = None;
+ }
}
}
}
fn create_entity_widgets(
frame: &dear_imgui_bindings::Ui,
- add_component_popup_state: &mut Option<AddComponentPopupState>,
- despawn_icon_tex: dear_imgui_bindings::ManagedTextureId,
- warning_icon_tex: dear_imgui_bindings::ManagedTextureId,
+ popup_state: &mut Option<PopupState>,
+ textures: &Textures,
ent_handle: &EntityHandle,
world: &World,
actions: &mut Actions,
@@ -236,6 +195,7 @@ fn create_entity_widgets(
.fixed_width(frame.content_region_avail_width() * 0.8),
dear_imgui_bindings::TableColumnSetup::new("b"),
dear_imgui_bindings::TableColumnSetup::new("c"),
+ dear_imgui_bindings::TableColumnSetup::new("d"),
])
.build(|frame| {
frame.table_next_row();
@@ -251,13 +211,23 @@ fn create_entity_widgets(
frame,
&ent_handle,
&ent_title,
- add_component_popup_state,
+ popup_state,
world,
);
frame.table_next_column();
- create_despawn_button_widget(frame, despawn_icon_tex, ent_handle, actions);
+ create_despawn_button_widget(frame, textures, ent_handle, actions);
+
+ frame.table_next_column();
+
+ create_rename_entity_button_widget(
+ frame,
+ textures,
+ ent_handle,
+ &ent_title,
+ popup_state,
+ );
});
if is_open {
@@ -265,7 +235,7 @@ fn create_entity_widgets(
if component_id.is_pair() {
create_pair_component_widgets(
frame,
- warning_icon_tex,
+ textures,
ent_handle,
component_id,
world,
@@ -372,7 +342,7 @@ fn create_component_widgets(
fn create_pair_component_widgets(
frame: &dear_imgui_bindings::Ui,
- warning_icon_tex_id: dear_imgui_bindings::ManagedTextureId,
+ textures: &Textures,
ent_handle: &EntityHandle,
pair_id: Uid,
world: &World,
@@ -448,7 +418,7 @@ fn create_pair_component_widgets(
let Some(pair_data_ty) = pair_data_comp_info.type_reflection else {
frame.same_line();
- frame.image(warning_icon_tex_id, [16.0, 16.0]);
+ frame.image(textures.warning_icon_tex_id, [16.0, 16.0]);
if frame.is_item_hovered() {
frame.tooltip_text(format!(
@@ -518,7 +488,7 @@ fn create_add_component_button_widget(
frame: &dear_imgui_bindings::Ui,
ent_handle: &EntityHandle,
ent_title: &str,
- add_component_popup_state: &mut Option<AddComponentPopupState>,
+ popup_state: &mut Option<PopupState>,
world: &World,
)
{
@@ -542,28 +512,14 @@ fn create_add_component_button_widget(
ent_handle.uid()
));
- if add_component_popup_state
- .as_ref()
- .is_some_and(|add_component_popup_state| {
- add_component_popup_state.target_entity_id != ent_handle.uid()
- })
- {
- return;
- }
-
if is_button_clicked {
- enter_add_component_popup_state(
- add_component_popup_state,
- ent_handle,
- ent_title,
- world,
- );
+ enter_add_component_popup_state(popup_state, ent_handle, ent_title, world);
}
}
fn create_despawn_button_widget(
frame: &dear_imgui_bindings::Ui,
- despawn_icon_tex: dear_imgui_bindings::ManagedTextureId,
+ textures: &Textures,
ent_handle: &EntityHandle,
actions: &mut Actions,
)
@@ -586,7 +542,7 @@ fn create_despawn_button_widget(
if frame
.image_button_config(
&format!("ent_{}_despawn_button", ent_handle.uid()),
- despawn_icon_tex,
+ textures.despawn_icon_tex_id,
[14.0, 14.0],
)
.build()
@@ -595,13 +551,133 @@ fn create_despawn_button_widget(
}
}
+fn create_rename_entity_button_widget(
+ frame: &dear_imgui_bindings::Ui,
+ textures: &Textures,
+ ent_handle: &EntityHandle,
+ ent_title: &str,
+ popup_state: &mut Option<PopupState>,
+)
+{
+ if frame
+ .image_button_config(
+ &format!("ent_{}_rename_button", ent_handle.uid()),
+ textures.edit_icon_tex_id,
+ [16.0, 16.0],
+ )
+ .build()
+ {
+ enter_rename_entity_popup_state(popup_state, ent_handle, ent_title);
+ }
+}
+
+fn enter_rename_entity_popup_state(
+ popup_state: &mut Option<PopupState>,
+ ent_handle: &EntityHandle,
+ ent_title: &str,
+) -> bool
+{
+ if popup_state.is_some() {
+ return false;
+ }
+
+ *popup_state = Some(PopupState::RenameEntity(RenameEntityPopupState {
+ popup_name: format!("Rename entity {ent_title}"),
+ target_entity_id: ent_handle.uid(),
+ new_entity_name: String::with_capacity(32),
+ }));
+
+ true
+}
+
+fn show_rename_entity_popup(
+ frame: &dear_imgui_bindings::Ui,
+ popup_state: &mut RenameEntityPopupState,
+ actions: &mut Actions,
+ world: &World,
+) -> bool
+{
+ frame.open_popup(&popup_state.popup_name);
+
+ let mut is_opened = true;
+
+ let should_close =
+ frame.modal_popup_with_opened(&popup_state.popup_name, &mut is_opened, || {
+ frame.set_window_size([
+ frame.calc_text_size(&popup_state.popup_name)[0] + 32.0,
+ 120.0,
+ ]);
+
+ frame.spacing();
+ frame.spacing();
+
+ frame.text("Name:");
+ frame.same_line();
+
+ frame
+ .input_text(
+ "##rename_entity_popup_new_name_input",
+ &mut popup_state.new_entity_name,
+ )
+ .build();
+
+ frame.spacing();
+ frame.spacing();
+
+ let rename_text_size = frame.calc_text_size("Rename");
+
+ if frame.button_with_size(
+ "Rename##rename_entity_popup_rename_button",
+ [rename_text_size[0] * 2.0, rename_text_size[1] * 2.0],
+ ) {
+ let Some(target_ent) = world.get_entity(popup_state.target_entity_id)
+ else {
+ tracing::error!(
+ entity = ?popup_state.target_entity_id,
+ "Cannot rename entity: entity no longer exists"
+ );
+ return true;
+ };
+
+ if let Some(mut target_ent_name) = target_ent.get_mut::<EntityName>() {
+ target_ent_name.name = popup_state.new_entity_name.clone().into();
+ } else {
+ actions.add_components(
+ popup_state.target_entity_id,
+ (EntityName {
+ name: popup_state.new_entity_name.clone().into(),
+ },),
+ );
+ }
+
+ return true;
+ }
+
+ false
+ });
+
+ if let Some(true) = should_close {
+ return true;
+ }
+
+ if !is_opened {
+ return true;
+ }
+
+ false
+}
+
fn enter_add_component_popup_state(
- add_component_popup_state: &mut Option<AddComponentPopupState>,
+ popup_state: &mut Option<PopupState>,
ent_handle: &EntityHandle,
ent_title: &str,
world: &World,
-)
+) -> bool
{
+ if popup_state.is_some() {
+ return false;
+ }
+
let popup_name = format!("Add component to {ent_title}");
let mut searchable_components = world
@@ -634,7 +710,7 @@ fn enter_add_component_popup_state(
searchable_components.sort_by_key(|(_, _, user_creatable)| *user_creatable);
- *add_component_popup_state = Some(AddComponentPopupState {
+ *popup_state = Some(PopupState::AddComponent(AddComponentPopupState {
popup_name: popup_name.clone(),
target_entity_id: ent_handle.uid(),
search_text: String::with_capacity(20),
@@ -642,7 +718,9 @@ fn enter_add_component_popup_state(
searchable_components,
selected_search_result: -1,
new_component: None,
- });
+ }));
+
+ true
}
fn show_add_component_popup(
@@ -2161,3 +2239,76 @@ fn create_entity_title(ent_handle: &EntityHandle) -> String
ent_handle.uid()
)
}
+
+struct Textures
+{
+ despawn_icon_tex_id: dear_imgui_bindings::ManagedTextureId,
+ warning_icon_tex_id: dear_imgui_bindings::ManagedTextureId,
+ edit_icon_tex_id: dear_imgui_bindings::ManagedTextureId,
+}
+
+impl Textures
+{
+ fn new(dear_imgui_context: &mut DearImguiContext) -> Self
+ {
+ let despawn_icon_tex_id = create_texture(
+ dear_imgui_context,
+ Image::from_reader(
+ Cursor::new(include_bytes!("../../../res/ui/delete.png")),
+ ImageFormat::Png,
+ )
+ .unwrap(),
+ );
+
+ let warning_icon_tex_id = create_texture(
+ dear_imgui_context,
+ Image::from_reader(
+ Cursor::new(include_bytes!("../../../res/ui/warning.png")),
+ ImageFormat::Png,
+ )
+ .unwrap(),
+ );
+
+ let edit_icon_tex_id = create_texture(
+ dear_imgui_context,
+ Image::from_reader(
+ Cursor::new(include_bytes!("../../../res/ui/edit.png")),
+ ImageFormat::Png,
+ )
+ .unwrap(),
+ );
+
+ Self {
+ despawn_icon_tex_id,
+ warning_icon_tex_id,
+ edit_icon_tex_id,
+ }
+ }
+}
+
+#[derive(Debug)]
+struct AddComponentPopupState
+{
+ popup_name: String,
+ target_entity_id: Uid,
+ search_text: String,
+ searched_components: Vec<(Uid, ComponentInfo, ComponentUserCreatable)>,
+ searchable_components: Vec<(Uid, ComponentInfo, ComponentUserCreatable)>,
+ selected_search_result: i32,
+ new_component: Option<(Box<dyn Any>, ComponentInfo, Uid)>,
+}
+
+#[derive(Debug)]
+struct RenameEntityPopupState
+{
+ popup_name: String,
+ target_entity_id: Uid,
+ new_entity_name: String,
+}
+
+#[derive(Debug)]
+enum PopupState
+{
+ AddComponent(AddComponentPopupState),
+ RenameEntity(RenameEntityPopupState),
+}