#[derive(Copy, Clone, Debug)]
pub enum RunMode {
Once,
Loop {
wait: Duration,
},
}
#[derive(Copy, Clone, Default, Resource)]
pub struct TuiScheduleRunnerSettings {
pub run_mode: RunMode,
}
impl TuiScheduleRunnerSettings {
#[must_use]
pub fn run_loop(wait: Duration) -> Self {
Self {
run_mode: RunMode::Loop { wait },
}
}
#[must_use]
pub fn run_once() -> Self {
Self {
run_mode: RunMode::Once,
}
}
}
pub struct TuiPlugins;
impl PluginGroup for TuiPlugins {
fn build(self) -> PluginGroupBuilder {
PluginGroupBuilder::start::<Self>()
.add(CorePlugin::default())
.add(TimePlugin::default())
.add(TuiScheduleRunnerPlugin::default())
}
}
#[derive(Default)]
pub struct TuiScheduleRunnerPlugin;
impl Plugin for TuiScheduleRunnerPlugin {
fn build(&self, app: &mut App) {
let settings = app
.world
.get_resource_or_insert_with(TuiScheduleRunnerSettings::default)
.to_owned();
app.set_runner(move |mut app: App| {
let mut app_exit_event_reader = ManualEventReader::<AppExit>::default();
match settings.run_mode {
RunMode::Once => {
app.update();
}
RunMode::Loop { wait } => {
let mut tick = move |app: &mut App,
wait: Duration|
-> Result<Option<Duration>, AppExit> {
let start_time = Instant::now();
process_all_events(app);
if let Some(app_exit_events) =
app.world.get_resource_mut::<BevyEvents<AppExit>>()
{
if let Some(exit) = app_exit_event_reader.iter(&app_exit_events).last()
{
println!("found app exit event 1");
return Err(exit.clone());
} else {
println!("no app exit event 1");
}
} else {
println!("no exit event reader 1");
}
app.update();
if let Some(app_exit_events) =
app.world.get_resource_mut::<BevyEvents<AppExit>>()
{
if let Some(exit) = app_exit_event_reader.iter(&app_exit_events).last()
{
println!("found app exit event 1");
return Err(exit.clone());
} else {
println!("no app exit event 1");
}
} else {
println!("no exit event reader 1");
}
let end_time = Instant::now();
let exe_time = end_time - start_time;
if exe_time < wait {
return Ok(Some(wait - exe_time));
}
Ok(None)
};
{
while let Ok(delay) = tick(&mut app, wait) {
if let Some(delay) = delay {
std::thread::sleep(delay);
}
}
}
}
}
});
}
}
fn process_event(app: &mut App, event: TerminalEvent) {
match event {
TerminalEvent::Key(key) => match key.code {
TerminalKeyCode::Char('q') => {
println!("detected exit command");
app.world.send_event(AppExit);
}
TerminalKeyCode::Esc => {
crossterm::terminal::disable_raw_mode().expect("disabling raw mode");
if let Some(mut terminal) = app.world.get_resource_mut::<BevyTerminal<ratatui::backend::CrosstermBackend<std::io::Stdout>>>() {
{
let term_stdout = terminal.0.backend_mut();
term_stdout.queue(crossterm::terminal::LeaveAlternateScreen).expect("returning to normal screen");
term_stdout.queue(crossterm::event::DisableMouseCapture).expect("release mouse capture");
term_stdout.flush().expect("flush terminal commands");
}
terminal.0.show_cursor().expect("restoring cursor");
}
std::process::exit(23);
}
_ => {
println!("received unbound terminal key: {key:?}");
}
},
_ => {
println!("received unknown terminal event: {event:?}");
}
}
}