diff --git a/src/main.rs b/src/main.rs index aa4e2ee..ac09af3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,8 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; mod gui; mod tui; +mod tuiplugin; + #[derive(Parser)] struct Args { #[command(subcommand)] @@ -41,7 +43,8 @@ fn main() { tui_logger::init_logger(tui_logger::LevelFilter::Trace).unwrap(); tui_logger::set_env_filter_from_string(FILTERSTRING); - app.add_plugins(tui::RiichiTui) + // app.add_plugins(tui::RiichiTui) + app.add_plugins(tuiplugin::TuiPlugin) } }; diff --git a/src/tui/render/mod.rs b/src/tui/render/mod.rs index 6ae950b..4d58592 100644 --- a/src/tui/render/mod.rs +++ b/src/tui/render/mod.rs @@ -39,3 +39,4 @@ pub(crate) fn draw_system( })?; Ok(()) } + diff --git a/src/tui/states.rs b/src/tui/states.rs index d351f57..91c1515 100644 --- a/src/tui/states.rs +++ b/src/tui/states.rs @@ -7,20 +7,6 @@ pub(crate) enum TuiState { InGame, } -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub(crate) struct InGame; - -impl ComputedStates for InGame { - type SourceStates = TuiState; - - fn compute(sources: Self::SourceStates) -> Option { - match sources { - TuiState::InGame => Some(Self), - _ => None, - } - } -} - #[derive(SubStates, Default, Clone, Copy, PartialEq, Eq, Hash, Debug)] #[source(TuiState = TuiState::MainMenu)] pub(crate) enum ZenState { @@ -36,6 +22,20 @@ pub(crate) enum ConsoleState { Open, } +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub(crate) struct InGame; + +impl ComputedStates for InGame { + type SourceStates = TuiState; + + fn compute(sources: Self::SourceStates) -> Option { + match sources { + TuiState::InGame => Some(Self), + _ => None, + } + } +} + impl std::ops::Not for ConsoleState { type Output = Self; diff --git a/src/tuiplugin.rs b/src/tuiplugin.rs new file mode 100644 index 0000000..410f5b1 --- /dev/null +++ b/src/tuiplugin.rs @@ -0,0 +1,164 @@ +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(()) + } +}