diff --git a/src/tui/input.rs b/src/tui/input/keyboard.rs similarity index 87% rename from src/tui/input.rs rename to src/tui/input/keyboard.rs index 44947c3..ee77c1a 100644 --- a/src/tui/input.rs +++ b/src/tui/input/keyboard.rs @@ -1,13 +1,17 @@ use bevy::prelude::*; -use bevy_ratatui::event::{KeyMessage, MouseMessage}; +use bevy_ratatui::crossterm::event::KeyCode; +use bevy_ratatui::event::KeyMessage; use jong::game::GameState; use crate::tui::{TuiState, console::ConsoleState}; +// TODO change this to handle console open request, esc for menu, etc, then +// route other messages to other systems + #[allow(clippy::too_many_arguments)] -pub(crate) fn kb_input_system( - mut kb_messages: MessageReader, +pub(crate) fn input_system( + mut messages: MessageReader, curr_tuistate: Res>, curr_consolestate: Res>, @@ -19,15 +23,13 @@ pub(crate) fn kb_input_system( mut exit: MessageWriter, ) { - use bevy_ratatui::crossterm::event::KeyCode; - let (ts, cs, gs) = ( curr_tuistate.get(), curr_consolestate.get(), curr_gamestate.get(), ); - for message in kb_messages.read() { + for message in messages.read() { if let KeyCode::Char('`') = message.code { next_consolestate.set(!*curr_consolestate.get()); continue; diff --git a/src/tui/input/mod.rs b/src/tui/input/mod.rs new file mode 100644 index 0000000..d7eb1ae --- /dev/null +++ b/src/tui/input/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod keyboard; +pub(crate) mod mouse; diff --git a/src/tui/input/mouse.rs b/src/tui/input/mouse.rs new file mode 100644 index 0000000..5926222 --- /dev/null +++ b/src/tui/input/mouse.rs @@ -0,0 +1,65 @@ +use bevy::prelude::*; +use bevy_ratatui::{RatatuiContext, event::MouseMessage}; +use ratatui::{crossterm::event::MouseEvent, layout::Position}; + +use crate::tui::render::Hovered; + +#[derive(Component)] +pub(crate) struct PickRegion { + pub(crate) area: ratatui::prelude::Rect, +} + +// enum PickEvent { +// Click { col: u16, row: u16 }, +// Hover { col: u16, row: u16 }, +// } + +pub(crate) fn input_system( + mut commands: Commands, + mut messages: MessageReader, + context: Res, + entities: Query<(Entity, &PickRegion)>, + hovered: Query<(Entity, &PickRegion), With>, +) -> Result { + for message in messages.read() { + let event = message.0; + // let term_size = context.size().unwrap(); + let position = Position::new(event.column, event.row); + match event.kind { + ratatui::crossterm::event::MouseEventKind::Down(mouse_button) => match mouse_button { + ratatui::crossterm::event::MouseButton::Left => { + for (entity, region) in &entities {} + } + // ratatui::crossterm::event::MouseButton::Right => todo!(), + // ratatui::crossterm::event::MouseButton::Middle => todo!(), + _ => {} + }, + // ratatui::crossterm::event::MouseEventKind::Up(mouse_button) => todo!(), + // ratatui::crossterm::event::MouseEventKind::Drag(mouse_button) => todo!(), + ratatui::crossterm::event::MouseEventKind::Moved => { + for (entity, region) in &hovered { + if !region.area.contains(position) { + commands.get_entity(entity)?.remove::(); + } + } + for (entity, region) in &entities { + // debug!( + // "{:?}, {position:?}", + // region.area.positions().collect::>() + // ); + if region.area.contains(position) { + commands.get_entity(entity)?.insert(Hovered); + // trace!("{entity:?} hovered!") + } + } + } + // ratatui::crossterm::event::MouseEventKind::ScrollDown => todo!(), + // ratatui::crossterm::event::MouseEventKind::ScrollUp => todo!(), + // ratatui::crossterm::event::MouseEventKind::ScrollLeft => todo!(), + // ratatui::crossterm::event::MouseEventKind::ScrollRight => todo!(), + _ => {} + } + } + + Ok(()) +} diff --git a/src/tui/mod.rs b/src/tui/mod.rs index 33ac500..05311b0 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -59,15 +59,16 @@ impl Plugin for RiichiTui { // general setup .init_state::() .add_computed_state::() - .add_systems(PreUpdate, input::kb_input_system) + .add_systems(PreUpdate, input::keyboard::input_system) + .add_systems(PreUpdate, input::mouse::input_system.chain()) // main menu - .add_systems(PostUpdate, menu::draw_mainmenu.run_if(in_state(TuiState::MainMenu))) + .add_systems(Update, menu::draw_mainmenu.run_if(in_state(TuiState::MainMenu))) // gaming .init_resource::() - .add_systems(PostUpdate, render::hand::render_hands.run_if(in_state(InGame).and(in_state(GameState::Play)))) - .add_systems(PostUpdate, render::ingame::draw_ingame.run_if(in_state(InGame))) + .add_systems(Update, render::hand::render_hands.run_if(in_state(InGame).and(in_state(GameState::Play)))) + .add_systems(Update, render::ingame::draw_ingame.run_if(in_state(InGame))) // semicolon stopper ; diff --git a/src/tui/render/ingame.rs b/src/tui/render/ingame.rs index e0a4b0e..1c2a1aa 100644 --- a/src/tui/render/ingame.rs +++ b/src/tui/render/ingame.rs @@ -1,14 +1,22 @@ use bevy::prelude::*; use bevy_ratatui::RatatuiContext; use jong::game::player::{MainPlayer, Player}; +use rand::rand_core::block::BlockRngCore; +use ratatui::style::Styled; +use ratatui::widgets::{Block, Borders, Widget}; -use crate::tui::render::{hand, tile::RenderedTile}; +use crate::tui::{ + input::mouse::PickRegion, + render::{Hovered, hand, tile::RenderedTile}, +}; pub(crate) fn draw_ingame( - rendered_hand: Res, - rendered_tiles: Populated<&RenderedTile>, - main_player: Single, With)>, + mut commands: Commands, mut tui_ctx: ResMut, + main_player: Single, With)>, + hovered_entity: Query>, + rendered_tiles: Populated<&RenderedTile>, + rendered_hand: Res, ) -> Result { use ratatui::layout::Flex; use ratatui::prelude::*; @@ -16,14 +24,74 @@ pub(crate) fn draw_ingame( tui_ctx.draw(|frame| { // debug!("{}", frame.area()); + let term_area = frame.area(); + + // TODO this is gross + let constraints = [Constraint::Fill(3), Constraint::Fill(18)]; + let horizontal_slicer_right = Layout::horizontal(constraints); + let vertical_slicer_bottom = Layout::vertical(constraints); + let horizontal_slicer_left = Layout::horizontal(constraints.iter().rev()); + let vertical_slicer_top = Layout::vertical(constraints.iter().rev()); + let [left_hand, this_hand] = horizontal_slicer_right.areas::<2>(term_area); + let [_, mut left_hand] = vertical_slicer_bottom.areas::<2>(left_hand); + let [_, mut this_hand] = vertical_slicer_top.areas::<2>(this_hand); + let [cross_hand, right_hand] = horizontal_slicer_left.areas::<2>(term_area); + let [mut right_hand, _] = vertical_slicer_top.areas::<2>(right_hand); + let [mut cross_hand, _] = vertical_slicer_bottom.areas::<2>(cross_hand); + + let margin = Margin::new( + (left_hand.width + right_hand.width) / 2, + (cross_hand.height + this_hand.height) / 2, + ); + let pond_area = term_area.inner(margin); + let all_pond = Layout::horizontal([Constraint::Fill(1); 3]); + let cross_pond = Layout::vertical([Constraint::Fill(1), Constraint::Max(1),Constraint::Fill(1)]); + let [mut left_pond, center, mut right_pond] = all_pond.areas::<3>(pond_area); + let [cross_pond, compass, this_pond] = cross_pond.areas::<3>(center); + // let shift = left_pond.height - cross_pond.height; + left_pond.height = cross_pond.height; + left_pond.y += cross_pond.height / 2; + right_pond.height = cross_pond.height; + right_pond.y+= cross_pond.height / 2; + + let debug_block = Block::new().borders(Borders::ALL); + frame.render_widget(debug_block.clone(), this_hand); + frame.render_widget(debug_block.clone(), left_hand); + frame.render_widget(debug_block.clone(), cross_hand); + frame.render_widget(debug_block.clone(), right_hand); + frame.render_widget(debug_block.clone(), this_pond); + frame.render_widget(debug_block.clone(), left_pond); + frame.render_widget(debug_block.clone(), cross_pond); + frame.render_widget(debug_block.clone(), right_pond); + + // TODO attempt to merge blocks on smol term? let layout = Layout::horizontal(vec![Constraint::Max(5); 13]).flex(Flex::Start); - let mut area = frame.area(); - area.height = 4; - let areas = layout.areas::<13>(area); - // if let Some(hand) = rendered_hand.0.get(&*main_player) { + let this_clamped = this_hand.height.abs_diff(5); + if let Some(val) = this_hand.height.checked_sub(this_clamped) { + this_hand.height = val + } else { + // FIXME show error + panic!("terminal too small!"); + } + this_hand.y += this_clamped + 1; + let areas = layout.areas::<13>(this_hand); if let Some(hand) = rendered_hand.0.get(&*main_player) { - for (tile, area) in hand.iter().zip(areas.iter()) { - frame.render_widget(&rendered_tiles.get(*tile).unwrap().0, *area); + for (tile, mut tile_area) in hand.iter().zip(areas.into_iter()) { + tile_area.height = 4; + let mut widget = rendered_tiles.get(*tile).unwrap().0.clone(); + if hovered_entity.contains(*tile) { + widget = widget.add_modifier(Modifier::BOLD); + if let Some(val) = tile_area.y.checked_sub(1) { + tile_area.y = val + } else { + // FIXME show error + panic!("terminal too small!"); + } + } + commands + .entity(*tile) + .insert(PickRegion { area: tile_area }); + frame.render_widget(widget, tile_area); } } })?; diff --git a/src/tui/render/mod.rs b/src/tui/render/mod.rs index 0e3cc55..a8aef30 100644 --- a/src/tui/render/mod.rs +++ b/src/tui/render/mod.rs @@ -1,3 +1,8 @@ +use bevy::prelude::*; + pub(crate) mod hand; pub(crate) mod ingame; pub(crate) mod tile; + +#[derive(Component)] +pub(crate) struct Hovered;