use cursive::theme::{Color, PaletteColor};
use cursive::{Cursive, CursiveRunnable, CursiveRunner};
use super::Effects;
pub fn with_siv<T, F: FnOnce(Effects, CursiveRunner<CursiveRunnable>) -> eyre::Result<T>>(
effects: &Effects,
f: F,
) -> eyre::Result<T> {
let mut siv = cursive::crossterm();
siv.update_theme(|theme| {
theme.shadow = false;
theme.palette.extend(vec![
(PaletteColor::Background, Color::TerminalDefault),
(PaletteColor::View, Color::TerminalDefault),
(PaletteColor::Primary, Color::TerminalDefault),
]);
});
let effects = effects.enable_tui_mode();
f(effects, siv.into_runner())
}
pub trait SingletonView<V> {
fn find(siv: &mut Cursive) -> cursive::views::ViewRef<V>;
}
#[macro_export]
macro_rules! declare_views {
{ $( $k:ident => $v:ty ),* $(,)? } => {
$(
struct $k {
view: cursive::views::NamedView<$v>,
}
impl $crate::tui::SingletonView<$v> for $k {
fn find(siv: &mut Cursive) -> cursive::views::ViewRef<$v> {
siv.find_name::<$v>(stringify!($k)).unwrap()
}
}
impl cursive::view::IntoBoxedView for $k {
fn into_boxed_view(self) -> Box<dyn cursive::view::View> {
Box::new(self.view)
}
}
impl From<$v> for $k {
fn from(view: $v) -> Self {
use cursive::view::Nameable;
let view = view.with_name(stringify!($k));
$k { view }
}
}
)*
};
}
pub mod testing {
use std::borrow::Borrow;
use std::cell::RefCell;
use std::rc::Rc;
use cursive::backend::Backend;
use cursive::theme::Color;
pub type Screen = Vec<Vec<char>>;
#[derive(Clone, Debug)]
pub enum CursiveTestingEvent {
Event(cursive::event::Event),
TakeScreenshot(Rc<RefCell<Screen>>),
}
#[derive(Debug)]
pub struct CursiveTestingBackend {
events: Vec<CursiveTestingEvent>,
event_index: usize,
just_emitted_event: bool,
screen: RefCell<Screen>,
screenshots: Vec<Screen>,
}
impl<'screenshot> CursiveTestingBackend {
pub fn init(events: Vec<CursiveTestingEvent>) -> Box<dyn Backend> {
Box::new(CursiveTestingBackend {
events,
event_index: 0,
just_emitted_event: false,
screen: RefCell::new(vec![vec![' '; 120]; 24]),
screenshots: Vec::new(),
})
}
}
impl Backend for CursiveTestingBackend {
fn poll_event(&mut self) -> Option<cursive::event::Event> {
if self.just_emitted_event {
self.just_emitted_event = false;
return None;
}
let event_index = self.event_index;
self.event_index += 1;
match self.events.get(event_index)?.to_owned() {
CursiveTestingEvent::TakeScreenshot(screen_target) => {
let mut screen_target = (*screen_target).borrow_mut();
*screen_target = self.screen.borrow().clone();
self.poll_event()
}
CursiveTestingEvent::Event(event) => {
self.just_emitted_event = true;
Some(event)
}
}
}
fn refresh(&mut self) {}
fn has_colors(&self) -> bool {
false
}
fn screen_size(&self) -> cursive::Vec2 {
let screen = self.screen.borrow();
(screen[0].len(), screen.len()).into()
}
fn print_at(&self, pos: cursive::Vec2, text: &str) {
for (i, c) in text.char_indices() {
let mut screen = self.screen.borrow_mut();
let screen_width = screen[0].len();
if pos.x + i < screen_width {
screen[pos.y][pos.x + i] = c;
} else {
screen[pos.y][screen_width - 1] = '$';
}
}
}
fn clear(&self, _color: Color) {
let mut screen = self.screen.borrow_mut();
for i in 0..screen.len() {
for j in 0..screen[i].len() {
screen[i][j] = ' ';
}
}
}
fn set_color(&self, colors: cursive::theme::ColorPair) -> cursive::theme::ColorPair {
colors
}
fn set_effect(&self, _effect: cursive::theme::Effect) {}
fn unset_effect(&self, _effect: cursive::theme::Effect) {}
}
pub fn screen_to_string(screen: &Rc<RefCell<Screen>>) -> String {
let screen = Rc::borrow(screen);
let screen = RefCell::borrow(screen);
screen
.iter()
.map(|row| {
let line: String = row.iter().collect();
line.trim().to_owned() + "\n"
})
.collect::<String>()
.trim()
.to_owned()
}
}