use async_channel::Sender;
use endbasic_core::exec::Signal;
use endbasic_std::console::{Console, ConsoleSpec, Resolution};
use std::cell::RefCell;
use std::fs::File;
use std::io::{self, Write};
use std::num::NonZeroU32;
use std::path::PathBuf;
use std::rc::Rc;
use tempfile::TempDir;
mod console;
mod font;
mod host;
const DEFAULT_RESOLUTION_PIXELS: (u32, u32) = (800, 600);
const DEFAULT_FONT_BYTES: &[u8] = include_bytes!("IBMPlexMono-Regular-6.0.0.ttf");
const DEFAULT_FONT_SIZE: u16 = 16;
fn string_error_to_io_error(e: String) -> io::Error {
io::Error::other(e)
}
pub(crate) struct TempFont {
dir: TempDir,
}
impl TempFont {
pub(crate) fn default_font() -> io::Result<Self> {
let dir = tempfile::tempdir()?;
let mut file = File::create(dir.path().join("font.ttf"))?;
file.write_all(DEFAULT_FONT_BYTES)?;
Ok(Self { dir })
}
pub(crate) fn path(&self) -> PathBuf {
self.dir.path().join("font.ttf")
}
}
pub fn setup(
spec: &mut ConsoleSpec,
signals_tx: Sender<Signal>,
) -> io::Result<Rc<RefCell<dyn Console>>> {
let resolution: Resolution = spec.take_keyed_flag("resolution")?.unwrap_or_else(|| {
let width = NonZeroU32::new(DEFAULT_RESOLUTION_PIXELS.0).unwrap();
let height = NonZeroU32::new(DEFAULT_RESOLUTION_PIXELS.1).unwrap();
Resolution::Windowed((width, height))
});
let default_fg_color = spec.take_keyed_flag::<u8>("fg_color")?;
let default_bg_color = spec.take_keyed_flag::<u8>("bg_color")?;
let font_path = spec.take_keyed_flag::<PathBuf>("font_path")?;
let font_size = spec.take_keyed_flag("font_size")?.unwrap_or(DEFAULT_FONT_SIZE);
let console = match font_path {
None => {
let default_font = TempFont::default_font()?;
console::SdlConsole::new(
resolution,
default_fg_color,
default_bg_color,
default_font.path(),
font_size,
signals_tx,
)?
}
Some(font_path) => console::SdlConsole::new(
resolution,
default_fg_color,
default_bg_color,
font_path.to_owned(),
font_size,
signals_tx,
)?,
};
Ok(Rc::from(RefCell::from(console)))
}