Render Signal

App now has a renderer object that can be retrieved to send a render
signal from outside the application.

This is useful for rendering based on operations taking place in other
threads.
This commit is contained in:
Joe Bellus 2023-12-01 13:20:21 -05:00
parent ba7703e4c2
commit 82e044a34a
6 changed files with 62 additions and 32 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "arkham"
version = "0.1.0"
version = "0.3.0"
edition = "2021"
[[example]]
@ -37,6 +37,6 @@ path = "examples/paragraph.rs"
[dependencies]
anyhow = "1.0.71"
crossterm = "0.26.1"
crossterm = "0.27"
ctrlc = "3.3.1"
textwrap = "0.16.0"

View File

@ -1,4 +1,12 @@
use std::{any::Any, cell::RefCell, io::Write, marker::PhantomData, rc::Rc};
use std::{
any::Any,
cell::RefCell,
io::Write,
marker::PhantomData,
rc::Rc,
sync::mpsc::{channel, Receiver, Sender},
time::Duration,
};
use crossterm::{
cursor,
@ -14,6 +22,17 @@ use crate::{
use super::input::Keyboard;
/// A renderer that can signal a render needs to take place.
pub struct Renderer {
tx: Sender<()>,
}
impl Renderer {
pub fn render(&self) {
let _ = self.tx.send(());
}
}
/// The app is the core container for the application logic, resources,
/// state, and run loop.
pub struct App<F, Args>
@ -23,6 +42,8 @@ where
{
container: Rc<RefCell<Container>>,
main_view: View,
render_signal: Receiver<()>,
render_tx: Sender<()>,
root: F,
args: PhantomData<Args>,
}
@ -39,14 +60,25 @@ where
let container = Rc::new(RefCell::new(Container::default()));
let size = terminal::size().unwrap();
let main_view = View::new(size);
let (render_tx, render_signal) = channel();
App {
container,
root,
main_view,
render_tx,
render_signal,
args: PhantomData,
}
}
/// Returns a renderer that can signal the application to rerender. This
/// renderer can be cloned and passed between threads.
pub fn get_renderer(&self) -> Renderer {
Renderer {
tx: self.render_tx.clone(),
}
}
/// Insert a resource which can be injected into component functions.
///
/// This resource can only be accessed immutably by reference.
@ -146,24 +178,29 @@ where
.unwrap()
.reset();
if let Ok(event) = crossterm::event::read() {
match event {
Event::FocusGained => todo!(),
Event::FocusLost => todo!(),
Event::Key(key_event) if key_event.code == KeyCode::Char('q') => {
break;
if crossterm::event::poll(Duration::from_millis(100)).unwrap_or(false) {
if let Ok(event) = crossterm::event::read() {
match event {
Event::FocusGained => self.render()?,
Event::FocusLost => {}
Event::Key(key_event) if key_event.code == KeyCode::Char('q') => {
break;
}
Event::Key(key_event) if key_event.kind == KeyEventKind::Press => {
let container = self.container.borrow();
let kb = container.get::<Res<Keyboard>>().unwrap();
kb.set_key(key_event.code);
}
Event::Mouse(_) => todo!(),
Event::Paste(_) => todo!(),
Event::Resize(_, _) => self.render()?,
_ => {}
}
Event::Key(key_event) if key_event.kind == KeyEventKind::Press => {
let container = self.container.borrow();
let kb = container.get::<Res<Keyboard>>().unwrap();
kb.set_key(key_event.code);
}
Event::Mouse(_) => todo!(),
Event::Paste(_) => todo!(),
Event::Resize(_, _) => todo!(),
_ => {}
}
}
if self.render_signal.try_recv().is_ok() {
self.render()?;
}
}
self.teardown();

View File

@ -1,9 +1,7 @@
use std::ops::Deref;
use crossterm::style::Color;
use crate::prelude::{Callable, ToRuneExt};
use crossterm::style::Color;
use std::ops::Deref;
#[allow(dead_code)]
#[derive(Debug)]
pub struct Paragraph {
content: String,
@ -29,7 +27,7 @@ impl Callable<()> for Paragraph {
let lines = textwrap::wrap(&self.content, view.width());
let mut stack = view.vertical_stack(view.size());
for line in lines.iter() {
let l = line.deref().to_runes();
let _ = line.deref().to_runes();
stack.insert(line);
}

View File

@ -13,7 +13,7 @@ mod view;
pub mod prelude {
pub use super::{
app::{App, Terminal},
app::{App, Renderer, Terminal},
container::{Callable, FromContainer, Res, State},
context::ViewContext,
geometry::{Pos, Rect, Size},

View File

@ -1 +1,2 @@
#[allow(dead_code)]
pub struct KeybindPlugin;

View File

@ -1,6 +1,5 @@
#![allow(dead_code)]
#[cfg(any(not(windows), all(windows)))]
mod universal {
pub const TICK: char = '✔';
pub const CROSS: char = '✖';
@ -61,11 +60,9 @@ mod universal {
pub const SEVEN_EIGHTHS: char = '⅞';
}
#[cfg(any(not(windows), all(windows)))]
pub use universal::*;
#[cfg(all(windows))]
mod win {
pub mod win {
pub const TICK: char = '√';
pub const CROSS: char = '×';
pub const STAR: char = '*';
@ -89,6 +86,3 @@ mod win {
pub const QUESTION_MARK_PREFIX: char = '';
pub const ONE_HALF: char = ' ';
}
#[cfg(all(windows))]
pub use win::*;