diff --git a/src/features/input/mod.rs b/src/features/input/mod.rs index 449c7f0..15a377e 100644 --- a/src/features/input/mod.rs +++ b/src/features/input/mod.rs @@ -19,6 +19,7 @@ impl Plugin for InputPlugin { app.add_systems(Update, move_click.run_if(in_state(AppState::GameScreen))); app.add_message::(); + app.add_message::(); app.add_systems( Update, interact_click.run_if(in_state(AppState::GameScreen)), @@ -65,7 +66,7 @@ fn move_click( } fn interact_click( - mut interact_messages: MessageWriter, + mut tile_click_messages: MessageWriter, mouse_btn: Res>, keys: Res>, window: Single<&Window, With>, @@ -88,7 +89,7 @@ fn interact_click( }; println!("Interact Click: ({}, {})", x, y); - interact_messages.write(InteractStartMessage { x, y }); + tile_click_messages.write(TileClickMessage { x, y }); } } diff --git a/src/features/pom/messages.rs b/src/features/pom/messages.rs index b823c29..60aa82c 100644 --- a/src/features/pom/messages.rs +++ b/src/features/pom/messages.rs @@ -16,3 +16,9 @@ pub struct InteractStartMessage { pub x: u32, pub y: u32, } + +#[derive(Message)] +pub struct TileClickMessage { + pub x: u32, + pub y: u32, +} diff --git a/src/features/pom/mod.rs b/src/features/pom/mod.rs index aaa1e74..447278c 100644 --- a/src/features/pom/mod.rs +++ b/src/features/pom/mod.rs @@ -7,12 +7,14 @@ use utils::manhattan_distance; pub mod components; pub mod messages; +pub mod ui; pub mod utils; pub struct PomPlugin; impl Plugin for PomPlugin { fn build(&self, app: &mut App) { + app.add_plugins(ui::PomUiPlugin); app.add_systems(OnEnter(AppState::GameScreen), setup); app.add_systems(OnExit(AppState::GameScreen), cleanup); diff --git a/src/features/pom/ui/context_menu.rs b/src/features/pom/ui/context_menu.rs new file mode 100644 index 0000000..3139cca --- /dev/null +++ b/src/features/pom/ui/context_menu.rs @@ -0,0 +1,122 @@ +use crate::features::ui::utils::ui_blocks; +use crate::prelude::*; +use bevy::window::PrimaryWindow; + +#[derive(Component)] +pub enum RootMarker { + ContextMenu, +} + +#[derive(Component)] +pub enum ButtonType { + Interact { x: u32, y: u32 }, + Cancel, +} + +pub fn spawn_context_menu( + mut commands: Commands, + mut tile_click_messages: MessageReader, + root_query: Query>, + camera_query: Single<(&Camera, &GlobalTransform), With>, + config: Res, +) { + for message in tile_click_messages.read() { + // Despawn existing menu + for entity in root_query.iter() { + commands.entity(entity).try_despawn(); + } + + let world_pos = grid_to_world_coords( + message.x, + message.y, + Some(0.0), + config.grid_width, + config.grid_height, + ); + + let (camera, camera_transform) = *camera_query; + + if let Ok(screen_pos) = camera.world_to_viewport(camera_transform, world_pos) { + commands + .spawn(( + Node { + position_type: PositionType::Absolute, + left: px(screen_pos.x), + top: px(screen_pos.y), + padding: UiRect::all(px(5.0)), + ..Node::vstack(px(5.0)) + }, + ZIndex(100), + BackgroundColor(Color::srgb(0.1, 0.1, 0.1)), + BorderRadius::all(px(5)), + RootMarker::ContextMenu, + )) + .with_children(|parent| { + parent.spawn(button( + ButtonType::Interact { + x: message.x, + y: message.y, + }, + ButtonVariant::Primary, + Node { + padding: UiRect::all(px(5)), + ..default() + }, + |c| text("", 20.0, c), + )); + + parent.spawn(button( + ButtonType::Cancel, + ButtonVariant::Destructive, + Node { + padding: UiRect::all(px(5)), + ..default() + }, + |c| text("Abbrechen", 20.0, c), + )); + }); + } + } +} + +pub fn click_outside_context_menu( + mut commands: Commands, + mouse_btn: Res>, + window: Single<&Window, With>, + ui_query: Query<(&ComputedNode, &GlobalTransform), With>, + root_query: Query>, +) { + if mouse_btn.just_pressed(MouseButton::Left) { + let Some(cursor_pos) = window.cursor_position() else { + return; + }; + + if !ui_blocks(window, cursor_pos, ui_query) { + for entity in root_query.iter() { + commands.entity(entity).try_despawn(); + } + } + } +} + +pub fn buttons( + mut commands: Commands, + mut button_query: Query<(&Interaction, &ButtonType), (Changed, With