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, GlobalTransform::default(), )) .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