v / examples / vmatrix.v
116 lines · 104 sloc · 2.79 KB · ca07347430c6f67adf38547e3bd5a64d94ef1ae9
Raw
1import os
2import rand
3import term
4import term.termios
5import time
6
7const snooze = time.millisecond * 70
8const symbols = '0123456789!@#$%^&*()-=+[]{}|;:<>?~bdjpqtvz'
9
10struct RainColumn {
11mut:
12 col int
13 len int // length of the rain column
14 head int = 1 // y position of the head of rain column
15}
16
17fn main() {
18 init_terminal()!
19 rain() // ctrl-c to exit
20}
21
22fn rain() {
23 mut rain_columns := []RainColumn{}
24 mut width := 0
25 mut height := 0
26
27 for {
28 // clear screen and all rain columns if terminal resized
29 w, h := term.get_terminal_size()
30 if w != width || h != height {
31 width = w
32 height = h
33 term.clear()
34 rain_columns.clear()
35 }
36 // gradually add more rain columns
37 if rain_columns.len < (width / 4 * 3) {
38 rain_columns << random_rain_column(width, height)
39 }
40 // update and print all rain columns
41 for mut rc in rain_columns {
42 update_rain_column(mut rc, width, height)
43 print_rain_column(rc, height)
44 }
45 // snooze controls update speed
46 time.sleep(snooze)
47 }
48}
49
50fn update_rain_column(mut rc RainColumn, width int, height int) {
51 rc.head += 1
52 if rc.head > height + rc.len {
53 rc = random_rain_column(width, height)
54 }
55}
56
57fn random_rain_column(max_col int, max_height int) RainColumn {
58 return RainColumn{
59 // console positions are 1 based, not zero
60 col: rand.int_in_range(1, max_col + 1) or { 1 }
61 len: rand.int_in_range(4, max_height / 4 * 3) or { 4 }
62 }
63}
64
65fn print_rain_column(rc RainColumn, height int) {
66 // print head in gray
67 if rc.head <= height {
68 print_at(term.gray(random_symbol()), rc.col, rc.head)
69 }
70 // print the char above the head in green to remove
71 // gray color of the previous head. Dim chars
72 // randomly to add more interest to the effect
73 if (rc.head - 1) <= height {
74 symbol := random_dim(term.green(random_symbol()))
75 print_at(symbol, rc.col, rc.head - 1)
76 }
77 // remove tail by printing a space
78 tail := rc.head - rc.len + 1
79 if tail > 0 && tail <= height {
80 print_at(' ', rc.col, tail)
81 }
82}
83
84fn print_at(s string, x int, y int) {
85 term.set_cursor_position(term.Coord{ x: x, y: y })
86 print(s)
87}
88
89fn random_symbol() string {
90 idx := rand.int_in_range(0, symbols.len) or { 0 }
91 return symbols[idx].ascii_str()
92}
93
94fn random_dim(s string) string {
95 i := rand.int_in_range(0, 10) or { 0 }
96 return if i == 1 { term.dim(s) } else { s }
97}
98
99fn init_terminal() ! {
100 mut old_state := termios.Termios{}
101 termios.tcgetattr(0, mut old_state)
102 // restore terminal state on exit
103 at_exit(fn [mut old_state] () {
104 termios.set_state(0, old_state)
105 println('\e[?1049l\e[?25h') // cursor on, alternate buffer mode off
106 })!
107 // exit on Ctrl+C
108 os.signal_opt(os.Signal.int, fn (sig os.Signal) {
109 exit(0)
110 })!
111 // exit/restore setup, ok to init terminal
112 mut new_state := old_state
113 new_state.disable_echo()
114 termios.set_state(0, new_state)
115 print('\e[?1049h\e[?25l') // cursor off, alternate buffer mode on
116}
117