diff options
| -rw-r--r-- | engine/res/ui/edit.png | bin | 0 -> 581 bytes | |||
| -rw-r--r-- | engine/src/ui/view/world.rs | 343 |
2 files changed, 247 insertions, 96 deletions
diff --git a/engine/res/ui/edit.png b/engine/res/ui/edit.png Binary files differnew file mode 100644 index 0000000..2431e79 --- /dev/null +++ b/engine/res/ui/edit.png 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), +} |
