pub enum StatefulProtocol {
Halfblocks(StatefulHalfblocks),
Sixel(StatefulSixel),
Kitty(StatefulKitty),
ITerm2(StatefulIterm2),
}Expand description
A stateful resizing image protocol for the crate::StatefulImage widget.
The [create::thread::ThreadImage] widget also uses this, and is the reason why resizing is split from rendering.
Variants§
Implementations§
Source§impl StatefulProtocol
impl StatefulProtocol
Sourcepub fn background_color(&self) -> Rgba<u8>
pub fn background_color(&self) -> Rgba<u8>
Examples found in repository?
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
fn main() -> Result<(), Box<dyn std::error::Error>> {
// setup terminal
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen,)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let mut picker = Picker::from_query_stdio()?;
let dyn_img = image::io::Reader::open("./assets/Ada.png")?.decode()?;
// Send a [ResizeProtocol] to resize and encode it in a separate thread.
let (tx_worker, rec_worker) = mpsc::channel::<(StatefulProtocol, Resize, Rect)>();
// Send UI-events and the [ResizeProtocol] result back to main thread.
let (tx_main, rec_main) = mpsc::channel();
// Resize and encode in background thread.
let tx_main_render = tx_main.clone();
thread::spawn(move || loop {
if let Ok((mut protocol, resize, area)) = rec_worker.recv() {
protocol.resize_encode(&resize, protocol.background_color(), area);
tx_main_render.send(AppEvent::Redraw(protocol)).unwrap();
}
});
// Poll events in background thread to demonstrate polling terminal events and redraw events
// concurrently. It's not required to do it this way - the "redraw event" from the channel
// could be read after polling the terminal events (as long as it's done with a timout). But
// then the rendering of the image will always be somewhat delayed.
let tx_main_events = tx_main.clone();
thread::spawn(move || -> Result<(), std::io::Error> {
loop {
if ratatui::crossterm::event::poll(Duration::from_millis(1000))? {
if let Event::Key(key) = event::read()? {
tx_main_events.send(AppEvent::KeyEvent(key)).unwrap();
}
}
}
});
let mut app = App {
async_state: ThreadProtocol::new(tx_worker, picker.new_resize_protocol(dyn_img)),
};
loop {
terminal.draw(|f| ui(f, &mut app))?;
if let Ok(ev) = rec_main.try_recv() {
match ev {
AppEvent::KeyEvent(key) => {
if key.kind == KeyEventKind::Press {
if key.code == KeyCode::Esc {
break;
}
}
}
AppEvent::Redraw(protocol) => {
app.async_state.set_protocol(protocol);
}
}
}
}
// restore terminal
disable_raw_mode()?;
execute!(terminal.backend_mut(), LeaveAlternateScreen,)?;
terminal.show_cursor()?;
Ok(())
}Sourcepub fn resize_encode_render(
&mut self,
resize: &Resize,
background_color: Rgba<u8>,
area: Rect,
buf: &mut Buffer,
)
pub fn resize_encode_render( &mut self, resize: &Resize, background_color: Rgba<u8>, area: Rect, buf: &mut Buffer, )
Resize and encode if necessary, and render immediately.
This blocks the UI thread but requires neither threads nor async.
Sourcepub fn needs_resize(&mut self, resize: &Resize, area: Rect) -> Option<Rect>
pub fn needs_resize(&mut self, resize: &Resize, area: Rect) -> Option<Rect>
Check if the current image state would need resizing (grow or shrink) for the given area.
This can be called by the UI thread to check if this StatefulProtocol should be sent off to some background thread/task to do the resizing and encoding, instead of rendering. The thread should then return the StatefulProtocol so that it can be rendered.protoco
Sourcepub fn resize_encode(
&mut self,
resize: &Resize,
background_color: Rgba<u8>,
area: Rect,
)
pub fn resize_encode( &mut self, resize: &Resize, background_color: Rgba<u8>, area: Rect, )
Resize the image and encode it for rendering. The result should be stored statefully so that next call for the given area does not need to redo the work.
This can be done in a background thread, and the result is stored in this StatefulProtocol.
Examples found in repository?
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
fn main() -> Result<(), Box<dyn std::error::Error>> {
// setup terminal
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen,)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let mut picker = Picker::from_query_stdio()?;
let dyn_img = image::io::Reader::open("./assets/Ada.png")?.decode()?;
// Send a [ResizeProtocol] to resize and encode it in a separate thread.
let (tx_worker, rec_worker) = mpsc::channel::<(StatefulProtocol, Resize, Rect)>();
// Send UI-events and the [ResizeProtocol] result back to main thread.
let (tx_main, rec_main) = mpsc::channel();
// Resize and encode in background thread.
let tx_main_render = tx_main.clone();
thread::spawn(move || loop {
if let Ok((mut protocol, resize, area)) = rec_worker.recv() {
protocol.resize_encode(&resize, protocol.background_color(), area);
tx_main_render.send(AppEvent::Redraw(protocol)).unwrap();
}
});
// Poll events in background thread to demonstrate polling terminal events and redraw events
// concurrently. It's not required to do it this way - the "redraw event" from the channel
// could be read after polling the terminal events (as long as it's done with a timout). But
// then the rendering of the image will always be somewhat delayed.
let tx_main_events = tx_main.clone();
thread::spawn(move || -> Result<(), std::io::Error> {
loop {
if ratatui::crossterm::event::poll(Duration::from_millis(1000))? {
if let Event::Key(key) = event::read()? {
tx_main_events.send(AppEvent::KeyEvent(key)).unwrap();
}
}
}
});
let mut app = App {
async_state: ThreadProtocol::new(tx_worker, picker.new_resize_protocol(dyn_img)),
};
loop {
terminal.draw(|f| ui(f, &mut app))?;
if let Ok(ev) = rec_main.try_recv() {
match ev {
AppEvent::KeyEvent(key) => {
if key.kind == KeyEventKind::Press {
if key.code == KeyCode::Esc {
break;
}
}
}
AppEvent::Redraw(protocol) => {
app.async_state.set_protocol(protocol);
}
}
}
}
// restore terminal
disable_raw_mode()?;
execute!(terminal.backend_mut(), LeaveAlternateScreen,)?;
terminal.show_cursor()?;
Ok(())
}Trait Implementations§
Source§impl Clone for StatefulProtocol
impl Clone for StatefulProtocol
Source§fn clone(&self) -> StatefulProtocol
fn clone(&self) -> StatefulProtocol
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more