diff --git a/src/game/hand.rs b/src/game/hand.rs index fd5a97b..be67921 100644 --- a/src/game/hand.rs +++ b/src/game/hand.rs @@ -46,6 +46,7 @@ pub(crate) fn shuffle_deal( // commands.get_entity(*wall_ent)?.replace_children(&walltiles); for player_ent in players { + debug!("deal to player_ent {player_ent:?}"); let handtiles = walltiles.split_off(walltiles.len() - 13); // commands.get_entity(*wall_ent)?.remove_children(&handtiles); @@ -56,7 +57,6 @@ pub(crate) fn shuffle_deal( .get_entity(player_ent)? .replace_children(&[hand_ent]); - debug!("dealt to player_ent {player_ent:?}"); } commands.get_entity(*wall_ent)?.replace_children(&walltiles); diff --git a/src/game/round.rs b/src/game/round.rs index 9cf95df..ff9f522 100644 --- a/src/game/round.rs +++ b/src/game/round.rs @@ -45,7 +45,7 @@ impl Default for MatchSettings { } } -#[derive(Component, Clone, Copy, FromRepr, EnumCount)] +#[derive(Component, Clone, Copy, FromRepr, EnumCount, PartialEq)] pub enum Wind { Ton, Nan, @@ -53,6 +53,12 @@ pub enum Wind { Pei, } +pub enum WindRelation { + Shimocha, + Toimen, + Kamicha, +} + impl EnumNextCycle for Wind { fn next(&self) -> Self { if (*self as usize + 1) >= Self::COUNT { @@ -63,6 +69,18 @@ impl EnumNextCycle for Wind { } } +impl Wind { + pub fn relate(&self, other: &Self) -> WindRelation { + if self.next() == *other { + WindRelation::Shimocha + } else if other.next() == *self { + WindRelation::Kamicha + } else { + WindRelation::Toimen + } + } +} + #[derive(Resource)] pub(crate) struct CurrentPlayer(pub Entity); @@ -97,7 +115,7 @@ pub(crate) fn tsumo( curr_turnstate: Res>, mut next_turnstate: ResMut>, ) { - trace!("tsumo for: {:?}", curr_player.0); + debug!("tsumo for: {:?}", curr_player.0); let drawn = walltiles.last().unwrap(); commands.entity(*wall_ent).remove_child(*drawn); diff --git a/src/main.rs b/src/main.rs index ac09af3..784bd0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,8 +6,6 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; mod gui; mod tui; -mod tuiplugin; - #[derive(Parser)] struct Args { #[command(subcommand)] @@ -44,7 +42,7 @@ fn main() { tui_logger::set_env_filter_from_string(FILTERSTRING); // app.add_plugins(tui::RiichiTui) - app.add_plugins(tuiplugin::TuiPlugin) + app.add_plugins(tui::TuiPlugin) } }; diff --git a/src/tui.rs b/src/tui.rs new file mode 100644 index 0000000..f577ca4 --- /dev/null +++ b/src/tui.rs @@ -0,0 +1,89 @@ +use std::time::Duration; + +use bevy::{app::ScheduleRunnerPlugin, prelude::*, state::app::StatesPlugin}; +use bevy_ratatui::RatatuiPlugins; +use jong::game::GameState; +use tui_logger::TuiWidgetState; + +use crate::tui::states::ConsoleWidget; + +mod input; +mod layout; +mod render; + +#[derive(Default)] +pub struct TuiPlugin; + +#[derive(Clone, Debug, Eq, Hash, PartialEq, SystemSet)] +pub enum TuiSet { + Input, + Layout, + Render, +} + +impl Plugin for TuiPlugin { + fn build(&self, app: &mut App) { + app.add_plugins(( + MinimalPlugins.set(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f32( + 1. / 60., + ))), + RatatuiPlugins { + // enable_kitty_protocol: todo!(), + enable_mouse_capture: true, + enable_input_forwarding: true, + ..Default::default() + }, + )) + .add_plugins(StatesPlugin) + .init_resource::() + .insert_resource(ConsoleWidget { + state: TuiWidgetState::new(), + open: true, + }) + .init_state::() + .configure_sets( + Update, + (TuiSet::Input, TuiSet::Layout, TuiSet::Render).chain(), + ) + .add_systems( + Update, + (input::keyboard, input::mouse).in_set(TuiSet::Input), + ) + .add_systems(Update, layout::layout.in_set(TuiSet::Layout)) + .add_systems( + Update, + ( + render::render_hands.run_if(in_state(GameState::Play)), + render::render, + ) + .chain() + .in_set(TuiSet::Render), + ); + } +} + +mod states { + use bevy::prelude::*; + use tui_logger::TuiWidgetState; + + #[derive(Resource)] + pub(crate) struct ConsoleWidget { + pub(crate) state: TuiWidgetState, + pub(crate) open: bool, + } + + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, States, Default)] + pub(crate) enum TuiState { + #[default] + MainMenu, + InGame, + } + + // #[derive(SubStates, Default, Clone, Copy, PartialEq, Eq, Hash, Debug)] + // #[source(TuiState = TuiState::MainMenu)] + // pub(crate) enum ZenState { + // #[default] + // Menu, + // Zen, + // } +} diff --git a/src/tui/input.rs b/src/tui/input.rs new file mode 100644 index 0000000..915c3bb --- /dev/null +++ b/src/tui/input.rs @@ -0,0 +1,149 @@ +pub(crate) use keyboard::keyboard; +pub(crate) use mouse::mouse; + +pub(crate) mod keyboard { + use bevy::prelude::*; + use bevy_ratatui::event::KeyMessage; + use ratatui::crossterm::event::KeyCode; + use tui_logger::TuiWidgetEvent; + + use jong::game::GameState; + + use crate::tui::layout::Overlays; + use crate::tui::states::ConsoleWidget; + use crate::tui::states::TuiState; + + pub(crate) fn keyboard( + mut messages: MessageReader, + mut overlays: ResMut, + mut consolewidget: ResMut, + mut exit: MessageWriter, + + curr_gamestate: Res>, + curr_tuistate: Res>, + + mut next_gamestate: ResMut>, + mut next_tuistate: ResMut>, + ) { + 'message: for message in messages.read() { + let key = message.code; + if consolewidget.handle_keyboard(key) { + continue 'message; + } + for overlay in overlays.stack.iter().rev() { + let consumed = match overlay { + _ => false, + }; + if consumed { + continue 'message; + } + } + + match curr_tuistate.get() { + TuiState::MainMenu => match key { + KeyCode::Char('p') => { + next_tuistate.set(TuiState::InGame); + next_gamestate.set(GameState::Setup); + } + KeyCode::Char('z') => { + // if let Some(ref curr_zenstate) = curr_zenstate { + // match curr_zenstate.get() { + // ZenState::Menu => next_zenstate.set(ZenState::Zen), + // ZenState::Zen => next_zenstate.set(ZenState::Menu), + // } + // } + } + KeyCode::Char('q') => { + exit.write_default(); + } + _ => {} + }, + TuiState::InGame => todo!(), + } + } + } + + impl ConsoleWidget { + pub(crate) fn handle_keyboard(&mut self, key: KeyCode) -> bool { + if key == KeyCode::Char('`') { + self.open = !self.open; + return true; + } + if self.open { + match key { + KeyCode::Up => self.state.transition(TuiWidgetEvent::UpKey), + KeyCode::Down => self.state.transition(TuiWidgetEvent::DownKey), + // KeyCode::Home => self.state.transition(TuiWidgetEvent::), + // KeyCode::End => self.state.transition(TuiWidgetEvent::), + KeyCode::PageUp => self.state.transition(TuiWidgetEvent::PrevPageKey), + KeyCode::PageDown => self.state.transition(TuiWidgetEvent::NextPageKey), + KeyCode::Esc => { + self.open = false; + return true; + } + _ => return false, + } + } + self.open + } + } +} + +pub(crate) mod mouse { + use bevy::prelude::*; + use bevy_ratatui::event::MouseMessage; + use ratatui::layout::Position; + + use crate::tui::render::{Hovered, PickRegion}; + + pub(crate) fn mouse( + mut commands: Commands, + mut messages: MessageReader, + 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::>() + // region.area + // ); + 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/layout.rs b/src/tui/layout.rs new file mode 100644 index 0000000..827c6ea --- /dev/null +++ b/src/tui/layout.rs @@ -0,0 +1,82 @@ +use bevy::prelude::*; +use bevy_ratatui::RatatuiContext; +use ratatui::{ + layout::{Constraint, Layout, Margin}, + prelude::Rect, +}; + +#[derive(Resource, Default)] +pub(crate) struct Overlays { + pub(crate) stack: Vec, +} + +pub(crate) enum Overlay {} + +#[derive(Resource, Clone, Copy)] +pub(crate) struct HandLayouts { + pub(crate) left_pond: Rect, + pub(crate) cross_pond: Rect, + pub(crate) right_pond: Rect, + pub(crate) this_pond: Rect, + pub(crate) left_hand: Rect, + pub(crate) cross_hand: Rect, + pub(crate) right_hand: Rect, + pub(crate) this_hand: Rect, +} + +pub(crate) enum LayoutError { + TerminalTooSmall, +} + +pub(crate) fn layout(mut commands: Commands, mut tui: ResMut) -> Result { + tui.autoresize()?; + let frame = tui.get_frame(); + let term_area = frame.area(); + + let tiles = tiles_areas(term_area); + commands.insert_resource(tiles); + + Ok(()) +} + +// TODO make fallible to warn area too small +fn tiles_areas(term_area: Rect) -> HandLayouts { + 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 [_, left_hand] = vertical_slicer_bottom.areas::<2>(left_hand); + let [_, this_hand] = vertical_slicer_top.areas::<2>(this_hand); + let [cross_hand, right_hand] = horizontal_slicer_left.areas::<2>(term_area); + let [right_hand, _] = vertical_slicer_top.areas::<2>(right_hand); + let [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; + + HandLayouts { + left_pond, + cross_pond, + right_pond, + this_pond, + left_hand, + cross_hand, + right_hand, + this_hand, + } +} diff --git a/src/tui/render.rs b/src/tui/render.rs new file mode 100644 index 0000000..ed61c4e --- /dev/null +++ b/src/tui/render.rs @@ -0,0 +1,205 @@ +use std::io::Write as _; +use std::ops::Sub; + +use bevy::platform::collections::HashSet; +use bevy::prelude::*; +use bevy_ratatui::RatatuiContext; +use ratatui::layout::{Constraint, Flex, Layout, Offset, Rect, Size}; +use ratatui::style::{Modifier, Style, Stylize}; +use ratatui::widgets::{Block, Borders, Clear, Paragraph}; + +use jong::game::hand::{DrawnTile, Hand}; +use jong::game::player::{MainPlayer, Player}; +use jong::game::round::Wind; +use jong::tile::Tile; + +use crate::tui::layout::*; +use crate::tui::states::ConsoleWidget; + +#[derive(Component)] +pub(crate) struct Hovered; + +#[derive(Component)] +pub(crate) struct PickRegion { + pub(crate) area: Rect, +} + +fn render_tile(tile: &Tile, hovered: bool) -> (Paragraph<'_>) { + let block = ratatui::widgets::Block::bordered(); + let mut widget = Paragraph::new(match &tile.suit { + jong::tile::Suit::Pin(rank) => format!("{}\np", rank.0), + jong::tile::Suit::Sou(rank) => format!("{}\ns", rank.0), + jong::tile::Suit::Man(rank) => format!("{}\nm", rank.0), + jong::tile::Suit::Wind(wind) => (match wind { + jong::tile::Wind::Ton => "e\nw", + jong::tile::Wind::Nan => "s\nw", + jong::tile::Wind::Shaa => "w\nw", + jong::tile::Wind::Pei => "n\nw", + }) + .into(), + jong::tile::Suit::Dragon(dragon) => (match dragon { + jong::tile::Dragon::Haku => "w\nd", + jong::tile::Dragon::Hatsu => "g\nd", + jong::tile::Dragon::Chun => "r\nd", + }) + .into(), + }) + .block(block) + .centered(); + + if hovered { + widget = widget.add_modifier(Modifier::BOLD); + } + + widget +} + +fn debug_blocks(layouts: HandLayouts, frame: &mut ratatui::Frame<'_>) { + let debug_block = Block::new().borders(Borders::ALL); + frame.render_widget(debug_block.clone(), layouts.this_hand); + frame.render_widget(debug_block.clone(), layouts.left_hand); + frame.render_widget(debug_block.clone(), layouts.cross_hand); + frame.render_widget(debug_block.clone(), layouts.right_hand); + frame.render_widget(debug_block.clone(), layouts.this_pond); + frame.render_widget(debug_block.clone(), layouts.left_pond); + frame.render_widget(debug_block.clone(), layouts.cross_pond); + frame.render_widget(debug_block.clone(), layouts.right_pond); +} + +pub(crate) fn render( + mut tui: ResMut, + layouts: Res, + overlays: Res, + consolewidget: Res, +) -> Result { + let mut frame = tui.get_frame(); + + for overlay in overlays.stack.iter() { + match overlay { + _ => {} + } + } + + if consolewidget.open { + let block = Block::bordered().title("console [press esc to close]"); + frame.render_widget(Clear, frame.area()); + frame.render_widget( + tui_logger::TuiLoggerWidget::default() + .block(block) + .state(&consolewidget.state), + frame.area(), /* .inner(Margin { horizontal: 8, vertical: 8 }) */ + ); + } + + tui.hide_cursor()?; + tui.flush()?; + tui.swap_buffers(); + tui.backend_mut().flush()?; + Ok(()) +} + +pub(crate) fn render_hands( + mut commands: Commands, + mut tui: ResMut, + hovered: Query>, + layouts: Res, + mainplayer: Single<(&Player, &Wind), With>, + players: Populated<(&Player, /* &Wind, */ &Children)>, + hands: Populated<&Children, (With, Without)>, + tiles: Populated<&Tile>, + drawn_tile: Option>, +) -> Result { + let mut frame = tui.get_frame(); + debug_blocks(*layouts, &mut frame); + + for (player, /* wind, */ hand_ent) in players { + let hand = hand_ent.iter().next().unwrap(); + let hand: Vec<_> = hands + .get(hand)? + .iter() + .map(|entity| -> Result<_> { + let tile = tiles.get(entity)?; + // let paragraph = render_tile(tile,); + let hovered = hovered.contains(entity); + let widget = render_tile(tile, hovered); + Ok((entity, widget, hovered)) + }) + .collect::>()?; + + if player == mainplayer.0 { + // split main box into thirds + let mut this_hand = layouts.this_hand; + let this_drawer = drawn_tile.as_ref().is_some_and(|dt| dt.0 == player); + let tile_drawn = if this_drawer { 7 } else { 0 }; + let hand_draw_meld = Layout::horizontal([ + Constraint::Max(hand.len() as u16 * 5), + Constraint::Max(tile_drawn), + Constraint::Fill(1), + ]) + .flex(Flex::SpaceBetween); + this_hand = this_hand.offset(Offset { + x: 0, + y: this_hand.height.abs_diff(5) as i32 + 1, + }); + this_hand = this_hand.resize(Size { + width: this_hand.width, + height: 4, + }); + let [hand_area, drawn_area, meld_area] = hand_draw_meld.areas::<3>(this_hand); + + // split hand area into tile areas + let mut constraints = vec![Constraint::Max(5); hand.len()]; + constraints.push(Constraint::Fill(1)); + let layout = Layout::horizontal(constraints).flex(Flex::Start); + let tile_areas = layout.split(hand_area); + + for ((entity, widget, hovered), mut area) in + hand.into_iter().zip(tile_areas.iter().copied()) + { + if hovered { + area = area.offset(Offset { x: 0, y: -1 }); + let mut hitbox = area.as_size(); + hitbox.height += 1; + commands.entity(entity).insert(PickRegion { + area: area.resize(hitbox), + }); + } else { + commands.entity(entity).insert(PickRegion { area }); + } + frame.render_widget(widget, area); + } + + // tsumo tile + if this_drawer { + let (_, tile, entity) = **drawn_tile.as_ref().unwrap(); + let mut area = drawn_area.resize(Size { + width: 5, + height: 4, + }); + area = area.offset(Offset { x: 2, y: 0 }); + let hovered = hovered.contains(entity); + let widget = render_tile(tiles.get(tile.0)?, hovered); + if hovered { + area = area.offset(Offset { x: 0, y: -1 }); + let mut hitbox = area.as_size(); + hitbox.height += 1; + commands.entity(entity).insert(PickRegion { + area: area.resize(hitbox), + }); + } else { + commands.entity(entity).insert(PickRegion { area }); + } + frame.render_widget(widget, area); + } + // TODO draw melds + } else { + // match mainplayer.1.relate(wind) { + // jong::game::round::WindRelation::Shimocha => todo!(), + // jong::game::round::WindRelation::Toimen => todo!(), + // jong::game::round::WindRelation::Kamicha => todo!(), + // } + } + } + + Ok(()) +} diff --git a/src/tui/input/keyboard.rs b/src/tuiold/input/keyboard.rs similarity index 100% rename from src/tui/input/keyboard.rs rename to src/tuiold/input/keyboard.rs diff --git a/src/tui/input/mod.rs b/src/tuiold/input/mod.rs similarity index 100% rename from src/tui/input/mod.rs rename to src/tuiold/input/mod.rs diff --git a/src/tui/input/mouse.rs b/src/tuiold/input/mouse.rs similarity index 98% rename from src/tui/input/mouse.rs rename to src/tuiold/input/mouse.rs index acc9fa0..8994d41 100644 --- a/src/tui/input/mouse.rs +++ b/src/tuiold/input/mouse.rs @@ -17,7 +17,6 @@ pub(crate) struct PickRegion { pub(crate) fn input_system( mut commands: Commands, mut messages: MessageReader, - _context: Res, entities: Query<(Entity, &PickRegion)>, hovered: Query<(Entity, &PickRegion), With>, ) -> Result { diff --git a/src/tui/mod.rs b/src/tuiold/mod.rs similarity index 100% rename from src/tui/mod.rs rename to src/tuiold/mod.rs diff --git a/src/tui/render/hand.rs b/src/tuiold/render/hand.rs similarity index 100% rename from src/tui/render/hand.rs rename to src/tuiold/render/hand.rs diff --git a/src/tui/render/ingame.rs b/src/tuiold/render/ingame.rs similarity index 100% rename from src/tui/render/ingame.rs rename to src/tuiold/render/ingame.rs diff --git a/src/tui/render/menu.rs b/src/tuiold/render/menu.rs similarity index 100% rename from src/tui/render/menu.rs rename to src/tuiold/render/menu.rs diff --git a/src/tui/render/mod.rs b/src/tuiold/render/mod.rs similarity index 100% rename from src/tui/render/mod.rs rename to src/tuiold/render/mod.rs diff --git a/src/tui/render/tile.rs b/src/tuiold/render/tile.rs similarity index 99% rename from src/tui/render/tile.rs rename to src/tuiold/render/tile.rs index 95bf282..dcf0306 100644 --- a/src/tui/render/tile.rs +++ b/src/tuiold/render/tile.rs @@ -7,8 +7,6 @@ use jong::tile::Tile; pub(crate) struct RenderedTile(pub(crate) Paragraph<'static>); pub(crate) fn draw_tile(tile: &Tile) -> Paragraph<'static> { - - let block = ratatui::widgets::Block::bordered(); Paragraph::new(match &tile.suit { diff --git a/src/tui/states.rs b/src/tuiold/states.rs similarity index 100% rename from src/tui/states.rs rename to src/tuiold/states.rs diff --git a/src/tuiplugin.rs b/src/tuiplugin.rs deleted file mode 100644 index 410f5b1..0000000 --- a/src/tuiplugin.rs +++ /dev/null @@ -1,164 +0,0 @@ -use std::time::Duration; - -use bevy::{app::ScheduleRunnerPlugin, prelude::*, state::app::StatesPlugin}; -use bevy_ratatui::{RatatuiContext, RatatuiPlugins}; -use ratatui::{prelude::Backend, widgets::Widget}; -use tui_logger::TuiWidgetState; - -use crate::tuiplugin::layout::Overlays; - -#[derive(Default)] -pub struct TuiPlugin; - -#[derive(Clone, Debug, Eq, Hash, PartialEq, SystemSet)] -pub enum TuiSet { - Input, - Layout, - Render, -} - -impl Plugin for TuiPlugin { - fn build(&self, app: &mut App) { - app.add_plugins(( - MinimalPlugins.set(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f32( - 1. / 60., - ))), - RatatuiPlugins { - // enable_kitty_protocol: todo!(), - enable_mouse_capture: true, - enable_input_forwarding: true, - ..Default::default() - }, - )) - .add_plugins(StatesPlugin) - .init_resource::() - .init_resource::() - .configure_sets( - Update, - (TuiSet::Input, TuiSet::Layout, TuiSet::Render).chain(), - ) - .add_systems( - Update, - (input::keyboard, input::mouse).in_set(TuiSet::Input), - ) - .add_systems(Update, layout::layout.in_set(TuiSet::Layout)) - .add_systems(PostUpdate, render::render.in_set(TuiSet::Render)); - } -} - -#[derive(Resource, Default)] -struct ConsoleWidget { - state: TuiWidgetState, - open: bool, -} - -mod input { - use bevy::prelude::*; - use bevy_ratatui::event::KeyMessage; - use ratatui::crossterm::event::KeyCode; - use tui_logger::TuiWidgetEvent; - - use crate::tuiplugin::{ConsoleWidget, layout::Overlays}; - - pub(crate) fn keyboard( - mut messages: MessageReader, - mut overlays: ResMut, - mut consolewidget: ResMut, - ) { - 'message: for message in messages.read() { - let key = message.code; - if consolewidget.handle_input(key) { - continue 'message; - } - for overlay in overlays.stack.iter().rev() { - let consumed = match overlay { - _ => false, - }; - if consumed { - continue 'message; - } - } - match key { - _ => todo!(), - } - } - } - - impl ConsoleWidget { - fn handle_input(&mut self, key: KeyCode) -> bool { - if key == KeyCode::Char('`') { - self.open = !self.open; - return true; - } - if self.open { - match key { - KeyCode::Up => self.state.transition(TuiWidgetEvent::UpKey), - KeyCode::Down => self.state.transition(TuiWidgetEvent::DownKey), - // KeyCode::Home => self.state.transition(TuiWidgetEvent::), - // KeyCode::End => self.state.transition(TuiWidgetEvent::), - KeyCode::PageUp => self.state.transition(TuiWidgetEvent::PrevPageKey), - KeyCode::PageDown => self.state.transition(TuiWidgetEvent::NextPageKey), - KeyCode::Esc => self.open = false, - _ => {} - } - } - self.open - } - } - - pub(crate) fn mouse() {} -} - -mod layout { - use bevy::prelude::*; - use bevy_ratatui::RatatuiContext; - - #[derive(Resource, Default)] - pub(crate) struct Overlays { - pub(crate) stack: Vec, - } - - pub(crate) enum Overlay {} - - pub(crate) fn layout(mut tui: ResMut) -> Result { - tui.draw(|frame| { - let size = frame.area(); - })?; - - Ok(()) - } -} - -mod render { - use bevy::prelude::*; - use bevy_ratatui::RatatuiContext; - use ratatui::widgets::Block; - use ratatui::widgets::Clear; - use tui_logger::TuiLoggerWidget; - - use crate::tuiplugin::ConsoleWidget; - use crate::tuiplugin::layout; - - pub(crate) fn render( - mut tui: ResMut, - overlays: Res, - consolewidget: Res, - ) -> Result { - tui.draw(|frame| { - for overlay in overlays.stack.iter() { - match overlay { - _ => {} - } - } - if consolewidget.open { - let block = Block::bordered().title("console"); - frame.render_widget(Clear, frame.area()); - frame.render_widget( - TuiLoggerWidget::default().block(block), - frame.area(), /* .inner(Margin { horizontal: 8, vertical: 8 }) */ - ); - } - })?; - Ok(()) - } -}