147 lines
4.5 KiB
Rust
147 lines
4.5 KiB
Rust
use crate::features::pom::actions::InteractionAction;
|
|
use crate::features::ui::messages::ClosePopupMessage;
|
|
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,
|
|
action: InteractionAction,
|
|
},
|
|
Cancel,
|
|
}
|
|
|
|
pub fn open_context_menu(
|
|
mut commands: Commands,
|
|
mut tile_click_messages: MessageReader<TileClickMessage>,
|
|
root_query: Query<Entity, With<RootMarker>>,
|
|
camera_query: Single<(&Camera, &GlobalTransform), With<Camera2d>>,
|
|
config: Res<GameConfig>,
|
|
grid: Res<Grid>,
|
|
tile_query: Query<&TileState>,
|
|
inventory: Res<Inventory>,
|
|
item_query: Query<&ItemStack>,
|
|
game_config: Res<GameConfig>,
|
|
) {
|
|
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) {
|
|
let Ok(tile_entity) = grid.get_tile((message.x, message.y)) else {
|
|
return;
|
|
};
|
|
let Ok(tile_state) = tile_query.get(tile_entity) else {
|
|
return;
|
|
};
|
|
let options =
|
|
InteractionAction::list_options(tile_state, &inventory, item_query, &game_config);
|
|
|
|
spawn_context_menu(
|
|
&mut commands,
|
|
RootMarker::ContextMenu,
|
|
screen_pos,
|
|
|parent| {
|
|
for option in options {
|
|
parent.spawn(button(
|
|
ButtonType::Interact {
|
|
x: message.x,
|
|
y: message.y,
|
|
action: option.clone(),
|
|
},
|
|
ButtonVariant::Primary,
|
|
Node::from_padding(UiRect::all(px(5))),
|
|
|c| text(option.clone().get_name(&game_config), 20.0, c), // TODO: add sprite
|
|
));
|
|
}
|
|
|
|
parent.spawn(button(
|
|
ButtonType::Cancel,
|
|
ButtonVariant::Destructive,
|
|
Node::from_padding(UiRect::all(px(5))),
|
|
|c| text("Abbrechen", 20.0, c),
|
|
));
|
|
},
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn click_outside_context_menu(
|
|
mut commands: Commands,
|
|
mouse_btn: Res<ButtonInput<MouseButton>>,
|
|
window: Single<&Window, With<PrimaryWindow>>,
|
|
ui_query: Query<(&ComputedNode, &GlobalTransform), With<Node>>,
|
|
root_query: Query<Entity, With<RootMarker>>,
|
|
) {
|
|
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<Interaction>, With<Button>)>,
|
|
mut interact_messages: MessageWriter<InteractStartMessage>,
|
|
root_query: Query<Entity, With<RootMarker>>,
|
|
) {
|
|
for (interaction, button_type) in button_query.iter_mut() {
|
|
if *interaction == Interaction::Pressed {
|
|
match button_type {
|
|
ButtonType::Interact { x, y, action } => {
|
|
interact_messages.write(InteractStartMessage {
|
|
x: *x,
|
|
y: *y,
|
|
action: action.clone(),
|
|
});
|
|
}
|
|
ButtonType::Cancel => (),
|
|
}
|
|
|
|
for entity in root_query.iter() {
|
|
commands.entity(entity).despawn();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn close_context_menu(
|
|
mut commands: Commands,
|
|
mut close_popup_reader: MessageReader<ClosePopupMessage>,
|
|
root_query: Query<Entity, With<RootMarker>>,
|
|
) {
|
|
for _ in close_popup_reader.read() {
|
|
for entity in root_query.iter() {
|
|
commands.entity(entity).despawn();
|
|
}
|
|
}
|
|
}
|