1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use super::*;

#[derive(Debug)]
pub struct Video {
    name: String,
    signal: u8,
    hsync: bool,
    vsync: bool,
    frame_buffer: String,
    disabled: bool,
    initialized: bool,
}

impl Video {
    pub fn new(name: String) -> Video {
        Video {
            name,
            signal: 0,
            hsync: false,
            vsync: false,
            frame_buffer: String::new(),
            disabled: false,
            initialized: false,
        }
    }

    pub fn disable(&mut self) {
        self.disabled = true;
    }
}

impl Ext for Video {
    fn name(&self) -> String { self.name.clone() }
    fn instantiate(&mut self, _path: Path) {}
    fn incoming_ports(&self) -> Vec<PortName> { vec!["signal".to_string(), "hsync".to_string(), "vsync".to_string()] }

    fn update(&mut self, _path: Path, portname: &PortName, value: Value) -> Vec<(PortName, Value)> {
        if value.is_x() {
            return vec![];
        }
        if portname == "signal" {
            self.signal = value.try_into().unwrap();
        } else if portname == "hsync" {
            self.hsync = value.try_into().unwrap();
        } else if portname == "vsync" {
            self.vsync = value.try_into().unwrap();
        }
        vec![]
    }

    fn clock(&mut self, _path: Path) -> Vec<(PortName, Value)> {
        if !self.disabled {
            use std::fmt::Write;
            let c: char = " ░▒▓".chars().collect::<Vec<char>>()[self.signal as usize];

            write!(self.frame_buffer, "{c}{c}").unwrap();
            if self.hsync {
                writeln!(self.frame_buffer).unwrap();
            }

            if self.vsync {
                std::thread::sleep(std::time::Duration::from_millis(30));

                // clear screen
                print!("\x1B[2J");

                // move cursor to the upper left corner
                print!("\x1B[H");

                println!("{}", self.frame_buffer);
                self.frame_buffer.clear();
            }
        }
        vec![]
    }

    fn reset(&mut self, _path: Path) -> Vec<(PortName, Value)>{
        if !self.disabled {
            if !self.initialized {
                ctrlc::set_handler(move || {
                    // show the cursor
                    println!("\x1B[?25h");
                    std::process::exit(0);
                }).unwrap();
            }

            // hide the cursor
            print!("\x1B[?25l");

            // clear the screen
            print!("\x1B[2J");
        }

        self.initialized = true;

        vec![]
    }
}