use crate::command_processor::*; use crate::settings::Settings; use crossbeam_channel::Sender; use cursive::align::*; use cursive::event::*; use cursive::theme::*; use cursive::traits::*; use cursive::utils::markup::StyledString; use cursive::views::*; use cursive::Cursive; use cursive::CursiveRunnable; use cursive_flexi_logger_view::{CursiveLogWriter, FlexiLoggerView}; use log::*; use std::cell::RefCell; use std::collections::{HashMap, VecDeque}; use std::rc::Rc; use veilid_core::*; ////////////////////////////////////////////////////////////// /// struct Dirty { pub value: T, dirty: bool, } impl Dirty { pub fn new(value: T) -> Self { Self { value, dirty: true } } pub fn set(&mut self, value: T) { self.value = value; self.dirty = true; } pub fn get(&self) -> &T { &self.value } // pub fn get_mut(&mut self) -> &mut T { // &mut self.value // } pub fn take_dirty(&mut self) -> bool { let is_dirty = self.dirty; self.dirty = false; is_dirty } } pub type UICallback = Box; struct UIState { attachment_state: Dirty, network_started: Dirty, network_down_up: Dirty<(f32, f32)>, connection_state: Dirty, } impl UIState { pub fn new() -> Self { Self { attachment_state: Dirty::new(AttachmentState::Detached), network_started: Dirty::new(false), network_down_up: Dirty::new((0.0, 0.0)), connection_state: Dirty::new(ConnectionState::Disconnected), } } } //#[derive(Error, Debug)] //#[error("???")] //struct UIError; pub struct UIInner { ui_state: UIState, log_colors: HashMap, cmdproc: Option, cb_sink: Sender>, cmd_history: VecDeque, cmd_history_position: usize, cmd_history_max_size: usize, connection_dialog_state: Option, } type Handle = Rc>; #[derive(Clone)] pub struct UI { siv: Handle, inner: Handle, } impl UI { ///////////////////////////////////////////////////////////////////////////////////// // Private functions fn command_processor(s: &mut Cursive) -> CommandProcessor { let inner = Self::inner(s); inner.cmdproc.as_ref().unwrap().clone() } fn inner(s: &mut Cursive) -> std::cell::Ref<'_, UIInner> { s.user_data::>().unwrap().borrow() } fn inner_mut(s: &mut Cursive) -> std::cell::RefMut<'_, UIInner> { s.user_data::>().unwrap().borrow_mut() } fn setup_colors(siv: &mut CursiveRunnable, inner: &mut UIInner, settings: &Settings) { // Make colors let mut theme = cursive::theme::load_default(); theme.shadow = settings.interface.theme.shadow; theme.borders = BorderStyle::from(&settings.interface.theme.borders); theme.palette.set_color( "background", Color::parse(settings.interface.theme.colors.background.as_str()).unwrap(), ); theme.palette.set_color( "shadow", Color::parse(settings.interface.theme.colors.shadow.as_str()).unwrap(), ); theme.palette.set_color( "view", Color::parse(settings.interface.theme.colors.view.as_str()).unwrap(), ); theme.palette.set_color( "primary", Color::parse(settings.interface.theme.colors.primary.as_str()).unwrap(), ); theme.palette.set_color( "secondary", Color::parse(settings.interface.theme.colors.secondary.as_str()).unwrap(), ); theme.palette.set_color( "tertiary", Color::parse(settings.interface.theme.colors.tertiary.as_str()).unwrap(), ); theme.palette.set_color( "title_primary", Color::parse(settings.interface.theme.colors.title_primary.as_str()).unwrap(), ); theme.palette.set_color( "title_secondary", Color::parse(settings.interface.theme.colors.title_secondary.as_str()).unwrap(), ); theme.palette.set_color( "highlight", Color::parse(settings.interface.theme.colors.highlight.as_str()).unwrap(), ); theme.palette.set_color( "highlight_inactive", Color::parse(settings.interface.theme.colors.highlight_inactive.as_str()).unwrap(), ); theme.palette.set_color( "highlight_text", Color::parse(settings.interface.theme.colors.highlight_text.as_str()).unwrap(), ); siv.set_theme(theme); // Make log colors let mut colors = HashMap::::new(); colors.insert( Level::Trace, Color::parse(settings.interface.theme.log_colors.trace.as_str()).unwrap(), ); colors.insert( Level::Debug, Color::parse(settings.interface.theme.log_colors.debug.as_str()).unwrap(), ); colors.insert( Level::Info, Color::parse(settings.interface.theme.log_colors.info.as_str()).unwrap(), ); colors.insert( Level::Warn, Color::parse(settings.interface.theme.log_colors.warn.as_str()).unwrap(), ); colors.insert( Level::Error, Color::parse(settings.interface.theme.log_colors.error.as_str()).unwrap(), ); inner.log_colors = colors; } fn setup_quit_handler(siv: &mut Cursive) { siv.clear_global_callbacks(cursive::event::Event::CtrlChar('c')); siv.set_on_pre_event(cursive::event::Event::CtrlChar('c'), UI::quit_handler); siv.set_global_callback(cursive::event::Event::Key(Key::Esc), UI::quit_handler); } fn quit_handler(siv: &mut Cursive) { siv.add_layer( Dialog::text("Do you want to exit?") .button("Yes", |s| s.quit()) .button("No", |s| { s.pop_layer(); UI::setup_quit_handler(s); }), ); siv.set_on_pre_event(cursive::event::Event::CtrlChar('c'), |s| { s.quit(); }); siv.set_global_callback(cursive::event::Event::Key(Key::Esc), |s| { s.pop_layer(); UI::setup_quit_handler(s); }); } fn command_line(s: &mut Cursive) -> ViewRef { s.find_name("command-line").unwrap() } fn button_attach(s: &mut Cursive) -> ViewRef