use std::{
any::{Any, TypeId},
mem,
sync::Arc,
thread,
time::Duration,
};
use crate::{
canvas::Canvas,
core::interactor::{Dispatcher, GeneralListener, Interactor},
node::HasListener,
style::GeneralStyle,
utils::Lazy,
};
use crossterm::terminal;
use downcast_trait::{downcast_trait_impl_convert_to, DowncastTrait};
use parking_lot::{Mutex, RwLock};
use crate::{
core::{
looper::Looper,
renderer::{FrameBuffer, Renderable, Renderer},
ICmdWindow,
},
measure::Fixed,
node::{LayoutAttribute, Node, StyleAttribute},
};
#[derive(Debug)]
pub struct Console {
pub name: String,
pub children: RwLock<Vec<Arc<dyn Node>>>,
renderer: Renderer,
looper: Looper,
interactor: Interactor,
dispatcher: Dispatcher,
context: ConsoleContext,
listeners: RwLock<Vec<GeneralListener>>,
layout_attributes: RwLock<LayoutAttribute>,
visibility: RwLock<bool>,
}
impl Console {
pub fn new(name: &'static str) -> Arc<Self> {
let window = Arc::new(RwLock::new(ICmdWindow::new_with_name(name)));
let window_read = window.read();
let (console_width, console_height) = window_read.get_size();
let background = window_read.bg_color.clone();
let fps = window_read.fps;
drop(window_read);
Arc::new(Console {
name: name.to_string(),
children: RwLock::new(vec![]),
renderer: Renderer::new(window.clone()),
looper: Looper::new(window.clone(), fps),
interactor: Interactor::new(window.clone()),
dispatcher: Dispatcher::new(window.clone()),
context: ConsoleContext {
console_width,
console_height,
background,
fps,
},
listeners: RwLock::new(vec![]),
layout_attributes: RwLock::new(LayoutAttribute {
l: Fixed(0).into(),
t: Fixed(0).into(),
r: Lazy::new(|| {
let (width, _) = terminal::size().unwrap();
width as i32
}),
b: Lazy::new(|| {
let (_, height) = terminal::size().unwrap();
height as i32
}),
}),
visibility: RwLock::new(true),
})
}
pub fn context(&self) -> ConsoleContext {
self.context.clone()
}
pub fn print(self: &Arc<Self>) {
self.renderer.render(self.clone());
}
pub fn start(self: Arc<Self>) {
thread::sleep(Duration::from_millis(200));
let arc = self.clone();
thread::spawn(move || {
arc.renderer.launch(arc.clone());
});
let arc = self.clone();
thread::spawn(move || {
arc.looper.launch();
});
let arc = self.clone();
thread::spawn(move || {
arc.dispatcher.launch(arc.clone());
});
self.interactor.launch();
}
}
#[derive(Debug, Clone)]
pub struct ConsoleContext {
pub console_width: u16,
pub console_height: u16,
pub background: String,
pub fps: u16,
}
impl Renderable for Console {
fn render(&self) -> FrameBuffer {
let style = &self.context.background;
Canvas::new(self)
.fill(' ', GeneralStyle::new(style.clone()))
.finish()
}
fn get_style_attributes(&self) -> Option<&Mutex<StyleAttribute>> {
None
}
fn get_layout_attributes(&self) -> &RwLock<LayoutAttribute> {
&self.layout_attributes
}
fn children(&self) -> &RwLock<Vec<Arc<dyn Node>>> {
&self.children
}
fn parent(&self) -> Option<&Arc<dyn Node>> {
None
}
fn get_visibility(&self) -> &RwLock<bool> {
&self.visibility
}
}
impl Node for Console {}
impl HasListener for Console {
fn get_listeners(&self) -> &RwLock<Vec<GeneralListener>> {
&self.listeners
}
}
impl DowncastTrait for Console {
downcast_trait_impl_convert_to!(dyn HasListener);
}