aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar Silas Bartha <silas@exvacuum.dev>2024-11-21 12:33:58 -0500
committerLibravatar Silas Bartha <silas@exvacuum.dev>2024-11-21 12:33:58 -0500
commitc2d89772336c52cce0b629f6ffc506eb1f221867 (patch)
tree96f30f3d94b7821fb769b0f2c86b17248f36a6d9
parente1eb0d99f17e6604e79496db68b191202cb95d60 (diff)
Thu Nov 21 12:33:58 PM EST 2024
-rw-r--r--Cargo.toml10
-rw-r--r--src/display/systems.rs1
-rw-r--r--src/input/components.rs4
-rw-r--r--src/input/mod.rs3
-rw-r--r--src/input/resources.rs96
-rw-r--r--src/input/systems.rs306
-rw-r--r--src/lib.rs17
-rw-r--r--src/widgets/mod.rs3
-rw-r--r--src/widgets/systems.rs6
9 files changed, 372 insertions, 74 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 1c434b1..7134c75 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "bevy_terminal_display"
-version = "0.4.3"
+version = "0.4.4"
edition = "2021"
license = "0BSD OR MIT OR Apache-2.0"
description = "A plugin for the Bevy game engine which enables rendering to a terminal using unicode braille characters."
@@ -8,15 +8,21 @@ repository = "https://github.com/exvacuum/bevy_terminal_display"
[dependencies]
crossbeam-channel = "0.5"
-crossterm = "0.28"
downcast-rs = "1.2"
once_cell = "1.19"
bevy_headless_render = "0.1"
bevy_dither_post_process = "0.2"
ratatui = "0.28"
color-eyre = "0.6"
+leafwing-input-manager = "0.15"
+serde = "1.0"
+smol_str = "0.2"
[dependencies.bevy]
version = "0.14"
default-features = false
features = ["bevy_render"]
+
+[dependencies.crossterm]
+version = "0.28"
+features = ["serde"]
diff --git a/src/display/systems.rs b/src/display/systems.rs
index 120272b..706d296 100644
--- a/src/display/systems.rs
+++ b/src/display/systems.rs
@@ -72,7 +72,6 @@ pub fn print_to_terminal(
frame.render_widget(
Paragraph::new(string)
.white()
- .bold()
.wrap(Wrap { trim: true }),
frame.area(),
);
diff --git a/src/input/components.rs b/src/input/components.rs
new file mode 100644
index 0000000..b386457
--- /dev/null
+++ b/src/input/components.rs
@@ -0,0 +1,4 @@
+use bevy::prelude::*;
+
+#[derive(Debug, Component)]
+pub struct DummyWindow;
diff --git a/src/input/mod.rs b/src/input/mod.rs
index 80c36bc..e582555 100644
--- a/src/input/mod.rs
+++ b/src/input/mod.rs
@@ -6,3 +6,6 @@ pub mod resources;
/// Systems for this module
pub(crate) mod systems;
+
+/// Components for this module
+pub(crate) mod components;
diff --git a/src/input/resources.rs b/src/input/resources.rs
index a733984..0324593 100644
--- a/src/input/resources.rs
+++ b/src/input/resources.rs
@@ -2,54 +2,54 @@ use bevy::{prelude::*, utils::HashSet};
use crossterm::event::{Event, KeyCode};
use std::sync::{Arc, Mutex};
-/// Resource containing currently pressed and released keys
-#[derive(Resource, Default)]
-pub struct TerminalInput {
- pressed_keys: HashSet<KeyCode>,
- just_pressed_keys: HashSet<KeyCode>,
- just_released_keys: HashSet<KeyCode>,
-}
-
-impl TerminalInput {
- /// Gets whether the given key is pressed
- pub fn is_pressed(&self, code: KeyCode) -> bool {
- self.pressed_keys.contains(&code)
- }
-
- /// Gets whether the given key was just pressed
- pub fn just_pressed(&self, code: KeyCode) -> bool {
- self.just_pressed_keys.contains(&code)
- }
-
- /// Gets whether the given key was just released
- pub fn just_released(&self, code: KeyCode) -> bool {
- self.just_released_keys.contains(&code)
- }
-
- /// Sets given key to pressed
- pub(super) fn press(&mut self, code: KeyCode) {
- if !self.pressed_keys.contains(&code) {
- self.pressed_keys.insert(code);
- self.just_pressed_keys.insert(code);
- }
- }
-
- /// Sets given key to released and removes pressed state
- pub(super) fn release(&mut self, code: KeyCode) {
- self.pressed_keys.remove(&code);
- self.just_released_keys.insert(code);
- }
-
- /// Clears all just released keys
- pub(super) fn clear_just_released(&mut self) {
- self.just_released_keys.clear();
- }
-
- /// Clears all just pressed keys
- pub(super) fn clear_just_pressed(&mut self) {
- self.just_pressed_keys.clear();
- }
-}
+// /// Resource containing currently pressed and released keys
+// #[derive(Resource, Default)]
+// pub struct TerminalInput {
+// pressed_keys: HashSet<KeyCode>,
+// just_pressed_keys: HashSet<KeyCode>,
+// just_released_keys: HashSet<KeyCode>,
+// }
+//
+// impl TerminalInput {
+// /// Gets whether the given key is pressed
+// pub fn is_pressed(&self, code: KeyCode) -> bool {
+// self.pressed_keys.contains(&code)
+// }
+//
+// /// Gets whether the given key was just pressed
+// pub fn just_pressed(&self, code: KeyCode) -> bool {
+// self.just_pressed_keys.contains(&code)
+// }
+//
+// /// Gets whether the given key was just released
+// pub fn just_released(&self, code: KeyCode) -> bool {
+// self.just_released_keys.contains(&code)
+// }
+//
+// /// Sets given key to pressed
+// pub(super) fn press(&mut self, code: KeyCode) {
+// if !self.pressed_keys.contains(&code) {
+// self.pressed_keys.insert(code);
+// self.just_pressed_keys.insert(code);
+// }
+// }
+//
+// /// Sets given key to released and removes pressed state
+// pub(super) fn release(&mut self, code: KeyCode) {
+// self.pressed_keys.remove(&code);
+// self.just_released_keys.insert(code);
+// }
+//
+// /// Clears all just released keys
+// pub(super) fn clear_just_released(&mut self) {
+// self.just_released_keys.clear();
+// }
+//
+// /// Clears all just pressed keys
+// pub(super) fn clear_just_pressed(&mut self) {
+// self.just_pressed_keys.clear();
+// }
+// }
/// Event queue for crossterm input event thread
#[derive(Resource, Default)]
diff --git a/src/input/systems.rs b/src/input/systems.rs
index 9be9f25..e851977 100644
--- a/src/input/systems.rs
+++ b/src/input/systems.rs
@@ -1,12 +1,21 @@
use std::cmp::Ordering;
-use bevy::prelude::*;
-use crossterm::event::{read, Event, KeyEvent, KeyEventKind};
+use bevy::{
+ input::{keyboard::KeyboardInput, ButtonState},
+ prelude::*,
+};
+use crossterm::event::{read, Event, KeyEvent, KeyEventKind, MediaKeyCode, ModifierKeyCode};
+use smol_str::SmolStr;
-use super::{events::TerminalInputEvent, resources::{EventQueue, TerminalInput}};
+use super::{
+ components::DummyWindow,
+ events::TerminalInputEvent,
+ resources::EventQueue,
+};
/// Initializes event queue and thread
-pub fn setup_input(event_queue: Res<EventQueue>) {
+pub fn setup_input(mut commands: Commands, event_queue: Res<EventQueue>) {
+ commands.spawn(DummyWindow);
let event_queue = event_queue.0.clone();
std::thread::spawn(move || {
loop {
@@ -26,30 +35,295 @@ pub fn setup_input(event_queue: Res<EventQueue>) {
/// Reads events from queue and broadcasts corresponding `TerminalInputEvent`s
pub fn input_handling(
event_queue: Res<EventQueue>,
- mut input: ResMut<TerminalInput>,
- mut event_writer: EventWriter<TerminalInputEvent>,
+ dummy_window_query: Query<Entity, With<DummyWindow>>,
+ mut terminal_event_writer: EventWriter<TerminalInputEvent>,
+ mut key_event_writer: EventWriter<KeyboardInput>,
) {
- input.clear_just_released();
- input.clear_just_pressed();
let mut event_queue = event_queue.0.lock().unwrap();
let mut key_events = Vec::<KeyEvent>::new();
while let Some(event) = event_queue.pop() {
if let Event::Key(event) = event {
key_events.push(event);
}
- event_writer.send(TerminalInputEvent(event));
+ terminal_event_writer.send(TerminalInputEvent(event));
}
key_events.sort_by(|&a, &b| a.kind.partial_cmp(&b.kind).unwrap_or(Ordering::Equal));
+ let window = dummy_window_query.single();
for event in key_events {
- match event.kind {
- KeyEventKind::Press => {
- input.press(event.code);
- }
- KeyEventKind::Release => {
- input.release(event.code);
+ if let Some(key_code) = crossterm_keycode_to_bevy_keycode(event.code) {
+ if let Some(logical_key) = crossterm_keycode_to_bevy_key(event.code) {
+ match event.kind {
+ KeyEventKind::Press | KeyEventKind::Repeat => {
+ // input.press(event.code);
+ key_event_writer.send(KeyboardInput {
+ key_code,
+ logical_key,
+ state: ButtonState::Pressed,
+ window,
+ });
+ }
+ KeyEventKind::Release => {
+ key_event_writer.send(KeyboardInput {
+ key_code,
+ logical_key,
+ state: ButtonState::Released,
+ window,
+ });
+ }
+ }
}
- _ => (),
}
}
}
+
+fn crossterm_keycode_to_bevy_keycode(
+ crossterm_keycode: crossterm::event::KeyCode,
+) -> Option<bevy::input::keyboard::KeyCode> {
+ use bevy::input::keyboard::KeyCode as BKey;
+ use crossterm::event::KeyCode as CKey;
+ match crossterm_keycode {
+ CKey::Backspace => Some(BKey::Backspace),
+ CKey::Enter => Some(BKey::Enter),
+ CKey::Left => Some(BKey::ArrowLeft),
+ CKey::Right => Some(BKey::ArrowRight),
+ CKey::Up => Some(BKey::ArrowUp),
+ CKey::Down => Some(BKey::ArrowDown),
+ CKey::Home => Some(BKey::Home),
+ CKey::End => Some(BKey::End),
+ CKey::PageUp => Some(BKey::PageUp),
+ CKey::PageDown => Some(BKey::PageDown),
+ CKey::Tab | CKey::BackTab => Some(BKey::Tab),
+ CKey::Delete => Some(BKey::Delete),
+ CKey::Insert => Some(BKey::Insert),
+ CKey::F(num) => match num {
+ 1 => Some(BKey::F1),
+ 2 => Some(BKey::F2),
+ 3 => Some(BKey::F3),
+ 4 => Some(BKey::F4),
+ 5 => Some(BKey::F5),
+ 6 => Some(BKey::F6),
+ 7 => Some(BKey::F7),
+ 8 => Some(BKey::F8),
+ 9 => Some(BKey::F9),
+ 10 => Some(BKey::F10),
+ 11 => Some(BKey::F11),
+ 12 => Some(BKey::F12),
+ 13 => Some(BKey::F13),
+ 14 => Some(BKey::F14),
+ 15 => Some(BKey::F15),
+ 16 => Some(BKey::F16),
+ 17 => Some(BKey::F17),
+ 18 => Some(BKey::F18),
+ 19 => Some(BKey::F19),
+ 20 => Some(BKey::F20),
+ 21 => Some(BKey::F21),
+ 22 => Some(BKey::F22),
+ 23 => Some(BKey::F23),
+ 24 => Some(BKey::F24),
+ 25 => Some(BKey::F25),
+ 26 => Some(BKey::F26),
+ 27 => Some(BKey::F27),
+ 28 => Some(BKey::F28),
+ 29 => Some(BKey::F29),
+ 30 => Some(BKey::F30),
+ 31 => Some(BKey::F31),
+ 32 => Some(BKey::F32),
+ 33 => Some(BKey::F33),
+ 34 => Some(BKey::F34),
+ 35 => Some(BKey::F35),
+ _ => None,
+ },
+ CKey::Char(c) => match c {
+ '1' | '!' => Some(BKey::Digit1),
+ '2' | '@' => Some(BKey::Digit2),
+ '3' | '#' => Some(BKey::Digit3),
+ '4' | '$' => Some(BKey::Digit4),
+ '5' | '%' => Some(BKey::Digit5),
+ '6' | '^' => Some(BKey::Digit5),
+ '7' | '&' => Some(BKey::Digit7),
+ '8' | '*' => Some(BKey::Digit8),
+ '9' | '(' => Some(BKey::Digit9),
+ '0' | ')' => Some(BKey::Digit0),
+ '-' | '_' => Some(BKey::Minus),
+ '=' | '+' => Some(BKey::Equal),
+ '`' | '~' => Some(BKey::Backquote),
+ 'q' | 'Q' => Some(BKey::KeyQ),
+ 'w' | 'W' => Some(BKey::KeyW),
+ 'e' | 'E' => Some(BKey::KeyE),
+ 'r' | 'R' => Some(BKey::KeyR),
+ 't' | 'T' => Some(BKey::KeyT),
+ 'y' | 'Y' => Some(BKey::KeyY),
+ 'u' | 'U' => Some(BKey::KeyU),
+ 'i' | 'I' => Some(BKey::KeyI),
+ 'o' | 'O' => Some(BKey::KeyO),
+ 'p' | 'P' => Some(BKey::KeyP),
+ '[' | '{' => Some(BKey::BracketLeft),
+ ']' | '}' => Some(BKey::BracketRight),
+ 'a' | 'A' => Some(BKey::KeyA),
+ 's' | 'S' => Some(BKey::KeyS),
+ 'd' | 'D' => Some(BKey::KeyD),
+ 'f' | 'F' => Some(BKey::KeyF),
+ 'g' | 'G' => Some(BKey::KeyG),
+ 'h' | 'H' => Some(BKey::KeyH),
+ 'j' | 'J' => Some(BKey::KeyJ),
+ 'k' | 'K' => Some(BKey::KeyK),
+ 'l' | 'L' => Some(BKey::KeyL),
+ ';' | ':' => Some(BKey::Semicolon),
+ '\'' | '"' => Some(BKey::Slash),
+ 'z' | 'Z' => Some(BKey::KeyZ),
+ 'x' | 'X' => Some(BKey::KeyX),
+ 'c' | 'C' => Some(BKey::KeyC),
+ 'v' | 'V' => Some(BKey::KeyV),
+ 'b' | 'B' => Some(BKey::KeyB),
+ 'n' | 'N' => Some(BKey::KeyN),
+ 'm' | 'M' => Some(BKey::KeyM),
+ ',' | '<' => Some(BKey::Comma),
+ '.' | '>' => Some(BKey::Period),
+ '/' | '?' => Some(BKey::Slash),
+ ' ' => Some(BKey::Space),
+ _ => None,
+ },
+ CKey::Null => None,
+ CKey::Esc => Some(BKey::Escape),
+ CKey::CapsLock => Some(BKey::CapsLock),
+ CKey::ScrollLock => Some(BKey::ScrollLock),
+ CKey::NumLock => Some(BKey::NumLock),
+ CKey::PrintScreen => Some(BKey::PrintScreen),
+ CKey::Pause => Some(BKey::Pause),
+ CKey::Menu => Some(BKey::ContextMenu),
+ CKey::KeypadBegin => None,
+ CKey::Media(media) => match media {
+ MediaKeyCode::Play => Some(BKey::MediaPlayPause),
+ MediaKeyCode::Pause => Some(BKey::Pause),
+ MediaKeyCode::PlayPause => Some(BKey::MediaPlayPause),
+ MediaKeyCode::Reverse => None,
+ MediaKeyCode::Stop => Some(BKey::MediaStop),
+ MediaKeyCode::FastForward => Some(BKey::MediaTrackNext),
+ MediaKeyCode::Rewind => Some(BKey::MediaTrackPrevious),
+ MediaKeyCode::TrackNext => Some(BKey::MediaTrackNext),
+ MediaKeyCode::TrackPrevious => Some(BKey::MediaTrackPrevious),
+ MediaKeyCode::Record => None,
+ MediaKeyCode::LowerVolume => Some(BKey::AudioVolumeDown),
+ MediaKeyCode::RaiseVolume => Some(BKey::AudioVolumeUp),
+ MediaKeyCode::MuteVolume => Some(BKey::AudioVolumeMute),
+ },
+ CKey::Modifier(modifier) => match modifier {
+ ModifierKeyCode::LeftShift => Some(BKey::ShiftLeft),
+ ModifierKeyCode::LeftControl => Some(BKey::ControlLeft),
+ ModifierKeyCode::LeftAlt => Some(BKey::AltLeft),
+ ModifierKeyCode::LeftSuper => Some(BKey::SuperLeft),
+ ModifierKeyCode::LeftHyper => Some(BKey::Hyper),
+ ModifierKeyCode::LeftMeta => Some(BKey::Meta),
+ ModifierKeyCode::RightShift => Some(BKey::ShiftRight),
+ ModifierKeyCode::RightControl => Some(BKey::ControlRight),
+ ModifierKeyCode::RightAlt => Some(BKey::AltLeft),
+ ModifierKeyCode::RightSuper => Some(BKey::SuperRight),
+ ModifierKeyCode::RightHyper => Some(BKey::Hyper),
+ ModifierKeyCode::RightMeta => Some(BKey::Meta),
+ ModifierKeyCode::IsoLevel3Shift => None,
+ ModifierKeyCode::IsoLevel5Shift => None,
+ },
+ }
+}
+
+fn crossterm_keycode_to_bevy_key(
+ crossterm_keycode: crossterm::event::KeyCode,
+) -> Option<bevy::input::keyboard::Key> {
+ use bevy::input::keyboard::Key as BKey;
+ use crossterm::event::KeyCode as CKey;
+ match crossterm_keycode {
+ CKey::Backspace => Some(BKey::Backspace),
+ CKey::Enter => Some(BKey::Enter),
+ CKey::Left => Some(BKey::ArrowLeft),
+ CKey::Right => Some(BKey::ArrowRight),
+ CKey::Up => Some(BKey::ArrowUp),
+ CKey::Down => Some(BKey::ArrowDown),
+ CKey::Home => Some(BKey::Home),
+ CKey::End => Some(BKey::End),
+ CKey::PageUp => Some(BKey::PageUp),
+ CKey::PageDown => Some(BKey::PageDown),
+ CKey::Tab | CKey::BackTab => Some(BKey::Tab),
+ CKey::Delete => Some(BKey::Delete),
+ CKey::Insert => Some(BKey::Insert),
+ CKey::F(num) => match num {
+ 1 => Some(BKey::F1),
+ 2 => Some(BKey::F2),
+ 3 => Some(BKey::F3),
+ 4 => Some(BKey::F4),
+ 5 => Some(BKey::F5),
+ 6 => Some(BKey::F6),
+ 7 => Some(BKey::F7),
+ 8 => Some(BKey::F8),
+ 9 => Some(BKey::F9),
+ 10 => Some(BKey::F10),
+ 11 => Some(BKey::F11),
+ 12 => Some(BKey::F12),
+ 13 => Some(BKey::F13),
+ 14 => Some(BKey::F14),
+ 15 => Some(BKey::F15),
+ 16 => Some(BKey::F16),
+ 17 => Some(BKey::F17),
+ 18 => Some(BKey::F18),
+ 19 => Some(BKey::F19),
+ 20 => Some(BKey::F20),
+ 21 => Some(BKey::F21),
+ 22 => Some(BKey::F22),
+ 23 => Some(BKey::F23),
+ 24 => Some(BKey::F24),
+ 25 => Some(BKey::F25),
+ 26 => Some(BKey::F26),
+ 27 => Some(BKey::F27),
+ 28 => Some(BKey::F28),
+ 29 => Some(BKey::F29),
+ 30 => Some(BKey::F30),
+ 31 => Some(BKey::F31),
+ 32 => Some(BKey::F32),
+ 33 => Some(BKey::F33),
+ 34 => Some(BKey::F34),
+ 35 => Some(BKey::F35),
+ _ => None,
+ },
+ CKey::Char(c) => Some(BKey::Character(SmolStr::from(c.encode_utf8(&mut [0;4])))),
+ CKey::Null => None,
+ CKey::Esc => Some(BKey::Escape),
+ CKey::CapsLock => Some(BKey::CapsLock),
+ CKey::ScrollLock => Some(BKey::ScrollLock),
+ CKey::NumLock => Some(BKey::NumLock),
+ CKey::PrintScreen => Some(BKey::PrintScreen),
+ CKey::Pause => Some(BKey::Pause),
+ CKey::Menu => Some(BKey::ContextMenu),
+ CKey::KeypadBegin => None,
+ CKey::Media(media) => match media {
+ MediaKeyCode::Play => Some(BKey::MediaPlayPause),
+ MediaKeyCode::Pause => Some(BKey::Pause),
+ MediaKeyCode::PlayPause => Some(BKey::MediaPlayPause),
+ MediaKeyCode::Reverse => None,
+ MediaKeyCode::Stop => Some(BKey::MediaStop),
+ MediaKeyCode::FastForward => Some(BKey::MediaTrackNext),
+ MediaKeyCode::Rewind => Some(BKey::MediaTrackPrevious),
+ MediaKeyCode::TrackNext => Some(BKey::MediaTrackNext),
+ MediaKeyCode::TrackPrevious => Some(BKey::MediaTrackPrevious),
+ MediaKeyCode::Record => None,
+ MediaKeyCode::LowerVolume => Some(BKey::AudioVolumeDown),
+ MediaKeyCode::RaiseVolume => Some(BKey::AudioVolumeUp),
+ MediaKeyCode::MuteVolume => Some(BKey::AudioVolumeMute),
+ },
+ CKey::Modifier(modifier) => match modifier {
+ ModifierKeyCode::LeftShift => Some(BKey::Shift),
+ ModifierKeyCode::LeftControl => Some(BKey::Control),
+ ModifierKeyCode::LeftAlt => Some(BKey::Alt),
+ ModifierKeyCode::LeftSuper => Some(BKey::Super),
+ ModifierKeyCode::LeftHyper => Some(BKey::Hyper),
+ ModifierKeyCode::LeftMeta => Some(BKey::Meta),
+ ModifierKeyCode::RightShift => Some(BKey::Shift),
+ ModifierKeyCode::RightControl => Some(BKey::Control),
+ ModifierKeyCode::RightAlt => Some(BKey::Alt),
+ ModifierKeyCode::RightSuper => Some(BKey::Super),
+ ModifierKeyCode::RightHyper => Some(BKey::Hyper),
+ ModifierKeyCode::RightMeta => Some(BKey::Meta),
+ ModifierKeyCode::IsoLevel3Shift => Some(BKey::AltGraph),
+ ModifierKeyCode::IsoLevel5Shift => None,
+ },
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 09134f9..e17f271 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,7 +3,7 @@
//! Bevy plugin which allows a camera to render to a terminal window.
use std::{
- fs::OpenOptions, io::stdout, path::PathBuf, sync::{Arc, Mutex}
+ fs::OpenOptions, io::{stdout, Write}, path::PathBuf, sync::{Arc, Mutex}
};
use bevy::{
@@ -79,6 +79,7 @@ impl Plugin for TerminalDisplayPlugin {
std::panic::set_hook(Box::new(move |info| {
let _ = restore_terminal();
+ error!("{info}");
panic(info);
}));
@@ -94,19 +95,21 @@ impl Plugin for TerminalDisplayPlugin {
display::systems::resize_handling,
display::systems::print_to_terminal,
widgets::systems::widget_input_handling,
+ widgets::systems::update_widgets,
),
)
.insert_resource(display::resources::Terminal::default())
.insert_resource(input::resources::EventQueue::default())
- .insert_resource(input::resources::TerminalInput::default())
.add_event::<input::events::TerminalInputEvent>();
}
}
-fn restore_terminal() {
+fn restore_terminal() -> Result<(), Box<dyn std::error::Error>>{
+ disable_raw_mode()?;
let mut stdout = stdout();
- let _ = stdout.execute(PopKeyboardEnhancementFlags);
- let _ = stdout.execute(DisableMouseCapture);
- let _ = stdout.execute(LeaveAlternateScreen);
- let _ = disable_raw_mode();
+ stdout.execute(PopKeyboardEnhancementFlags)?
+ .execute(DisableMouseCapture)?
+ .execute(LeaveAlternateScreen)?
+ .flush()?;
+ Ok(())
}
diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs
index 46bfa20..7751b2d 100644
--- a/src/widgets/mod.rs
+++ b/src/widgets/mod.rs
@@ -17,5 +17,8 @@ pub trait TerminalWidget: DowncastSync {
/// Called when a terminal input event is invoked to update any state accordingly
fn handle_events(&mut self, _event: &TerminalInputEvent, _commands: &mut Commands) {}
+
+ /// Called every frame during the Update schedule
+ fn update(&mut self, _time: &Time, _commands: &mut Commands) {}
}
impl_downcast!(sync TerminalWidget);
diff --git a/src/widgets/systems.rs b/src/widgets/systems.rs
index 2626ec6..0638b01 100644
--- a/src/widgets/systems.rs
+++ b/src/widgets/systems.rs
@@ -16,3 +16,9 @@ pub fn widget_input_handling(
}
}
}
+
+pub fn update_widgets(mut widgets: Query<&mut Widget>, time: Res<Time>, mut commands: Commands) {
+ for mut widget in widgets.iter_mut() {
+ widget.widget.update(&time, &mut commands);
+ }
+}