use bevy::prelude::*; use bevy_ratatui::{ event::{KeyEvent, MouseEvent}, terminal::RatatuiContext, }; use crossterm::event::{KeyCode, KeyEventKind, MouseButton, MouseEventKind}; use ratatui::layout::Size; use crate::{camera::DaylightEvent, pellets::PelletEvent, Flags}; const DRAGS_PER_EVENT: u32 = 2; pub(super) fn plugin(app: &mut App) { app.add_systems(PreUpdate, (handle_keyboard_system, handle_mouse_system)) .init_resource::(); } #[derive(Resource, Default, Deref, DerefMut)] pub struct DragThreshold(u32); fn handle_keyboard_system( mut ratatui_events: EventReader, mut exit: EventWriter, mut flags: ResMut, mut daylight_event: EventWriter, ) { for key_event in ratatui_events.read() { match key_event.kind { KeyEventKind::Press | KeyEventKind::Repeat => match key_event.code { KeyCode::Char('q') => { exit.send_default(); } KeyCode::Char('d') => { flags.debug = !flags.debug; } KeyCode::Char('m') => { flags.muted = !flags.muted; } KeyCode::Char(' ') => { daylight_event.send_default(); } _ => {} }, _ => {} } } } fn handle_mouse_system( ratatui: Res, mut events: EventReader, mut pellet_event: EventWriter, mut drag_threshold: ResMut, camera: Query<&Transform, With>, ) { for event in events.read() { let crossterm::event::MouseEvent { kind, column, row, .. } = event.0; match kind { MouseEventKind::Drag(MouseButton::Left) | MouseEventKind::Down(MouseButton::Left) => { if **drag_threshold == 0 || kind == MouseEventKind::Down(MouseButton::Left) { let size = ratatui.size().unwrap(); let camera_transform = camera.single(); if let Some(transform) = terminal_coords_to_world_transform(column, row, size, camera_transform) { pellet_event.send(PelletEvent(transform)); } **drag_threshold = DRAGS_PER_EVENT; } else { **drag_threshold -= 1; } } _ => {} } } } fn terminal_coords_to_world_transform( column: u16, row: u16, terminal_size: Size, camera: &Transform, ) -> Option { let block_width = terminal_size.width; let block_height = terminal_size.height * 2; let render_column = column as f32 - block_width.saturating_sub(block_height) as f32 / 2.; let render_row = (row as f32 - block_height.saturating_sub(block_width) as f32 / 4.) * 2.; let x = render_column / block_width.min(block_height) as f32 * 2. - 1.; let y = render_row / block_height.min(block_width) as f32 * 2. - 1.; if x.abs() > 0.9 || y > 0.9 { return None; } let mut world_coords = *camera * Vec3::new(x * 2.05, -y * 2. + 0.02, 0.); world_coords.z = 0.; Some(Transform::from_translation(world_coords)) }