1use async_channel::Sender;
19use endbasic_core::exec::Signal;
20use endbasic_std::console::{Console, ConsoleSpec, Resolution};
21use std::cell::RefCell;
22use std::fs::File;
23use std::io::{self, Write};
24use std::num::NonZeroU32;
25use std::path::PathBuf;
26use std::rc::Rc;
27use tempfile::TempDir;
28
29mod console;
30mod font;
31mod host;
32
33const DEFAULT_RESOLUTION_PIXELS: (u32, u32) = (800, 600);
35
36const DEFAULT_FONT_BYTES: &[u8] = include_bytes!("IBMPlexMono-Regular-6.0.0.ttf");
38
39const DEFAULT_FONT_SIZE: u16 = 16;
41
42fn string_error_to_io_error(e: String) -> io::Error {
44 io::Error::other(e)
45}
46
47pub(crate) struct TempFont {
49 dir: TempDir,
50}
51
52impl TempFont {
53 pub(crate) fn default_font() -> io::Result<Self> {
55 let dir = tempfile::tempdir()?;
56 let mut file = File::create(dir.path().join("font.ttf"))?;
57 file.write_all(DEFAULT_FONT_BYTES)?;
58 Ok(Self { dir })
59 }
60
61 pub(crate) fn path(&self) -> PathBuf {
63 self.dir.path().join("font.ttf")
64 }
65}
66
67pub fn setup(
69 spec: &mut ConsoleSpec,
70 signals_tx: Sender<Signal>,
71) -> io::Result<Rc<RefCell<dyn Console>>> {
72 let resolution: Resolution = spec.take_keyed_flag("resolution")?.unwrap_or_else(|| {
73 let width = NonZeroU32::new(DEFAULT_RESOLUTION_PIXELS.0).unwrap();
74 let height = NonZeroU32::new(DEFAULT_RESOLUTION_PIXELS.1).unwrap();
75 Resolution::Windowed((width, height))
76 });
77
78 let default_fg_color = spec.take_keyed_flag::<u8>("fg_color")?;
79 let default_bg_color = spec.take_keyed_flag::<u8>("bg_color")?;
80
81 let font_path = spec.take_keyed_flag::<PathBuf>("font_path")?;
82
83 let font_size = spec.take_keyed_flag("font_size")?.unwrap_or(DEFAULT_FONT_SIZE);
84
85 let console = match font_path {
86 None => {
87 let default_font = TempFont::default_font()?;
88 console::SdlConsole::new(
89 resolution,
90 default_fg_color,
91 default_bg_color,
92 default_font.path(),
93 font_size,
94 signals_tx,
95 )?
96 }
99 Some(font_path) => console::SdlConsole::new(
100 resolution,
101 default_fg_color,
102 default_bg_color,
103 font_path.to_owned(),
104 font_size,
105 signals_tx,
106 )?,
107 };
108 Ok(Rc::from(RefCell::from(console)))
109}