use crate::{
hlayout,
views::{LoadingAnimation, Spacer}
};
use std::fmt::Display;
use cursive_core::{
Cursive, With,
view::Nameable,
event::{Event, Key},
views::{
EditView,
Dialog,
OnEventView,
NamedView,
Checkbox,
LinearLayout,
TextView,
DummyView,
ResizedView
},
utils::markup::StyledString,
theme::{
PaletteColor,
Color,
BaseColor,
ColorType,
ColorStyle,
BorderStyle,
Theme
}
};
#[cfg(feature = "buffered_backend")]
use cursive::CursiveRunnable;
#[cfg(feature = "buffered_backend")]
use std::convert::Infallible;
pub fn better_theme() -> Theme {
let mut theme_def = Theme {
shadow: false,
.. Theme::default()
};
theme_def.palette[PaletteColor::Background] = Color::TerminalDefault;
theme_def.palette[PaletteColor::Primary] = Color::Light(BaseColor::White);
theme_def.palette[PaletteColor::View] = Color::TerminalDefault;
theme_def.palette[PaletteColor::Highlight] = Color::Light(BaseColor::Blue);
theme_def.palette[PaletteColor::HighlightText] = Color::Dark(BaseColor::White);
theme_def.palette[PaletteColor::Secondary] = Color::Dark(BaseColor::Blue);
theme_def.palette[PaletteColor::TitlePrimary] = Color::Light(BaseColor::Blue);
theme_def.palette[PaletteColor::TitleSecondary] = Color::Dark(BaseColor::Blue);
theme_def.borders = BorderStyle::Outset;
theme_def
}
pub fn confirm_dialog<C, T, U>(title: T, text: U, cb: C) -> OnEventView<Dialog>
where
C: Fn(&mut Cursive) + 'static,
T: Display,
U: Into<StyledString>
{
Dialog::text(text)
.dismiss_button("No")
.button("Yes", cb)
.title(title.to_string())
.wrap_with(OnEventView::new)
.on_event(Event::Key(Key::Esc), |r| {
if r.screen().len() <= 1 { r.quit(); }
else { r.pop_layer(); }
})
}
pub fn info_dialog<T: Display, U: Into<StyledString>>(title: T, text: U) -> OnEventView<Dialog> {
Dialog::text(text)
.dismiss_button("Back")
.title(title.to_string())
.wrap_with(OnEventView::new)
.on_event(Event::Key(Key::Esc), |r| {
if r.screen().len() <= 1 { r.quit(); }
else { r.pop_layer(); }
})
}
pub fn styled_editview<C: Display>(content: C, view_name: &str, password: bool) -> NamedView<EditView> {
styled_editview_color(content, view_name, password, PaletteColor::TitlePrimary)
}
pub fn styled_editview_color<T: Display, C: Into<ColorType>>(content: T, view_name: &str, password: bool, color: C) -> NamedView<EditView> {
let input_style = ColorStyle::new(
color,
Color::Light(BaseColor::White),
);
let view = EditView::new().content(content.to_string()).style(input_style).filler(" ");
if password { view.secret() }
else { view }
.with_name(view_name)
}
pub fn get_checkbox_option(root: &mut Cursive, name: &str) -> bool {
if let Some(cbox) = root.find_name::<Checkbox>(name) {
cbox.is_checked()
}
else { false }
}
pub fn labeled_checkbox(text: &str, name: &str, checked: bool) -> LinearLayout {
labeled_checkbox_cb(text, name, checked, |_, _| { })
}
pub fn labeled_checkbox_cb<C: Fn(&mut Cursive, bool) + 'static>(text: &str, name: &str, checked: bool, callback: C) -> LinearLayout {
hlayout!(
Checkbox::new()
.with_checked(checked)
.on_change(callback)
.with_name(name),
TextView::new(format!(" {text}"))
)
}
pub fn load_resource<T, R, F, D, M>(root: &mut Cursive, title: D, msg: M, task: R, finish_task: F)
where
D: Display,
T: Send + Sync + 'static,
R: FnOnce() -> T + Send + Sync + 'static,
M: Into<StyledString>,
F: FnOnce(&mut Cursive, T) + Send + Sync + 'static
{
let loader = LoadingAnimation::new(msg, move || (task(), finish_task));
if root.fps().is_none() { root.set_fps(30); }
root.add_layer(
Dialog::around(loader.with_name("load")).title(title.to_string())
.wrap_with(OnEventView::new)
.on_event(Event::Refresh, |root: &mut Cursive| {
let mut loader = root.find_name::<LoadingAnimation<(T, F)>>("load").unwrap();
if loader.is_done() {
root.pop_layer();
let (val, finish_func) = loader.finish().unwrap();
finish_func(root, val);
}
})
);
}
pub fn fixed_hspacer(width: usize) -> Spacer { ResizedView::with_fixed_width(width, DummyView) }
pub fn filled_hspacer() -> Spacer { ResizedView::with_full_width(DummyView) }
pub fn fixed_vspacer(height: usize) -> Spacer { ResizedView::with_fixed_height(height, DummyView) }
pub fn filled_vspacer() -> Spacer { ResizedView::with_full_height(DummyView) }
#[cfg(feature = "buffered_backend")]
pub fn buffered_backend_root() -> CursiveRunnable {
use cursive_core::backend::Backend;
use cursive_buffered_backend::BufferedBackend;
use cursive::backends::termion::Backend as TermionBackend;
CursiveRunnable::new(|| -> Result<Box<dyn Backend>, Infallible> {
let backend = TermionBackend::init().expect("Why is the backend not starting?");
let buffered_backend = BufferedBackend::new(backend);
Ok(Box::new(buffered_backend))
})
}