diff options
Diffstat (limited to 'demo/hjkl/hjkl.ha')
| -rw-r--r-- | demo/hjkl/hjkl.ha | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/demo/hjkl/hjkl.ha b/demo/hjkl/hjkl.ha new file mode 100644 index 0000000..487ebd3 --- /dev/null +++ b/demo/hjkl/hjkl.ha | |||
| @@ -0,0 +1,190 @@ | |||
| 1 | use fmt; | ||
| 2 | use tb = termbox2; | ||
| 3 | |||
| 4 | def bg = tb::COLOR.DEFAULT; | ||
| 5 | def fg = tb::COLOR.DEFAULT | tb::ATTRIBUTE.BOLD; | ||
| 6 | def exit_help: str = "Use :q to exit (colon, q, enter). Sad to see you go :("; | ||
| 7 | |||
| 8 | let wpos: (int, int) = (-1, -1); | ||
| 9 | let msg: str = "Use HJKL to move the widget around"; | ||
| 10 | let colon_mode: bool = false; | ||
| 11 | let exit_attempts: size = 0; | ||
| 12 | |||
| 13 | type cmd = enum { | ||
| 14 | UP, | ||
| 15 | DOWN, | ||
| 16 | LEFT, | ||
| 17 | RIGHT, | ||
| 18 | COLON, | ||
| 19 | ARROW, | ||
| 20 | Q, | ||
| 21 | ENTER, | ||
| 22 | EXIT_ATTEMPT, | ||
| 23 | NONE, | ||
| 24 | }; | ||
| 25 | |||
| 26 | fn draw_small_widget_thing(w: size, h: size) void = { | ||
| 27 | if (wpos.0 < 4) wpos.0 += 1 | ||
| 28 | else if (wpos.0 > w: int - 5) wpos.0 -= 1 | ||
| 29 | else if (wpos.1 < 2) wpos.1 += 1 | ||
| 30 | else if (wpos.1 > h: int - 3) wpos.1 -= 1; | ||
| 31 | |||
| 32 | tb::print(wpos.0, wpos.1 - 1, fg, bg, "K")!; | ||
| 33 | tb::print(wpos.0, wpos.1 + 1, fg, bg, "J")!; | ||
| 34 | tb::print(wpos.0 - 2, wpos.1, fg, bg, "H + L")!; | ||
| 35 | }; | ||
| 36 | |||
| 37 | fn paint(x: int, y: int, c: tb::uattr) void = | ||
| 38 | tb::set_cell(x, y, ' ', tb::COLOR.DEFAULT, c)!; | ||
| 39 | |||
| 40 | fn paint_col3(x: int, y: int, c: tb::uattr) void = { | ||
| 41 | paint(x, y-1, c); | ||
| 42 | paint(x, y, c); | ||
| 43 | paint(x, y+1, c); | ||
| 44 | }; | ||
| 45 | |||
| 46 | fn paint_row5(x: int, y: int, c: tb::uattr) void = { | ||
| 47 | paint(x-2, y, c); | ||
| 48 | paint(x-1, y, c); | ||
| 49 | paint(x, y, c); | ||
| 50 | paint(x+1, y, c); | ||
| 51 | paint(x+2, y, c); | ||
| 52 | }; | ||
| 53 | |||
| 54 | fn paint_cell(x: int, y: int, c: tb::uattr, s: str) void = { | ||
| 55 | paint_col3(x-2, y, c); | ||
| 56 | paint_row5(x, y-1, c); | ||
| 57 | tb::print(x, y, fg, bg, s)!; | ||
| 58 | paint_row5(x, y+1, c); | ||
| 59 | paint_col3(x+2, y, c); | ||
| 60 | }; | ||
| 61 | |||
| 62 | fn draw_large_widget_thing(w: size, h: size) void = { | ||
| 63 | if (wpos.0 < 10) wpos.0 += 1 | ||
| 64 | else if (wpos.0 > w: int - 11) wpos.0 -= 1 | ||
| 65 | else if (wpos.1 < 7) wpos.1 += 1 | ||
| 66 | else if (wpos.1 > h: int - 8) wpos.1 -= 1; | ||
| 67 | |||
| 68 | let c = tb::COLOR.BLUE; | ||
| 69 | paint_cell(wpos.0-6, wpos.1, c, "H"); | ||
| 70 | paint_cell(wpos.0+6, wpos.1, c, "L"); | ||
| 71 | paint_cell(wpos.0, wpos.1-4, c, "K"); | ||
| 72 | paint_cell(wpos.0, wpos.1+4, c, "J"); | ||
| 73 | paint_col3(wpos.0, wpos.1, c); | ||
| 74 | paint_row5(wpos.0, wpos.1, c); | ||
| 75 | }; | ||
| 76 | |||
| 77 | fn draw_widget_thing(w: size, h: size) void = { | ||
| 78 | if (w < 30 || h < 15) | ||
| 79 | draw_small_widget_thing(w, h) | ||
| 80 | else | ||
| 81 | draw_large_widget_thing(w, h); | ||
| 82 | }; | ||
| 83 | |||
| 84 | fn draw_bottom_bar(w: size, h: size) void = { | ||
| 85 | tb::print(0, h: int - 1, fg, bg, msg)!; | ||
| 86 | }; | ||
| 87 | |||
| 88 | fn handle_events_and_exit() bool = { | ||
| 89 | let e = tb::poll_event(); | ||
| 90 | if (e is tb::err) | ||
| 91 | return false; | ||
| 92 | |||
| 93 | return match (e as tb::event) { | ||
| 94 | case tb::resize_event => yield false; | ||
| 95 | case tb::mouse_event => yield { | ||
| 96 | msg = "A mouse? Are you serious?"; | ||
| 97 | yield false; | ||
| 98 | }; | ||
| 99 | case let ke: tb::key_event => yield handle_key_event_and_exit(ke); | ||
| 100 | }; | ||
| 101 | }; | ||
| 102 | |||
| 103 | fn is_arrow(k: tb::key) bool = | ||
| 104 | k == tb::KEY.ARROW_UP || k == tb::KEY.ARROW_DOWN || | ||
| 105 | k == tb::KEY.ARROW_LEFT || k == tb::KEY.ARROW_RIGHT; | ||
| 106 | |||
| 107 | fn is_exit_attempt(k: tb::key) bool = | ||
| 108 | k == tb::KEY.CTRL_Q || k == tb::KEY.CTRL_C || k == tb::KEY.CTRL_X || | ||
| 109 | k == tb::KEY.CTRL_Z || k == tb::KEY.CTRL_D || | ||
| 110 | k == tb::KEY.DELETE || k == tb::KEY.BACKSPACE || k == tb::KEY.ESC; | ||
| 111 | |||
| 112 | fn get_cmd(ke: tb::key_event) cmd = match (ke.key_or_ch) { | ||
| 113 | case let r: rune => yield | ||
| 114 | if (r == 'h') cmd::LEFT | ||
| 115 | else if (r == 'j') cmd::DOWN | ||
| 116 | else if (r == 'k') cmd::UP | ||
| 117 | else if (r == 'l') cmd::RIGHT | ||
| 118 | else if (r == ':') cmd::COLON | ||
| 119 | else if (r == 'q') cmd::Q | ||
| 120 | else if (r == 'Q') cmd::EXIT_ATTEMPT | ||
| 121 | else cmd::NONE; | ||
| 122 | case let k: tb::key => yield | ||
| 123 | if (k == tb::KEY.ENTER) cmd::ENTER | ||
| 124 | else if (is_arrow(k)) cmd::ARROW | ||
| 125 | else if (is_exit_attempt(k)) cmd::EXIT_ATTEMPT | ||
| 126 | else cmd::NONE; | ||
| 127 | }; | ||
| 128 | |||
| 129 | fn exit_attempt() void = { | ||
| 130 | exit_attempts += 1; | ||
| 131 | msg = if (exit_attempts < 3) "Trying to get out? :3" | ||
| 132 | else if (exit_attempts < 6) "It's just like Vim!" | ||
| 133 | else if (exit_attempts < 8) "Uhm no, that won't work" | ||
| 134 | else if (exit_attempts < 10) "Ok, I'll tell you..." | ||
| 135 | else exit_help; | ||
| 136 | }; | ||
| 137 | |||
| 138 | fn handle_key_event_and_exit(ke: tb::key_event) bool = { | ||
| 139 | let c = get_cmd(ke); | ||
| 140 | |||
| 141 | if (c == cmd::COLON) | ||
| 142 | colon_mode = true; | ||
| 143 | |||
| 144 | if (colon_mode) { | ||
| 145 | if (msg == ":q" && c == cmd::ENTER) | ||
| 146 | return true; | ||
| 147 | |||
| 148 | msg = if (msg == ":") { | ||
| 149 | yield if (c == cmd::Q) ":q" else exit_help; | ||
| 150 | } else if (c == cmd::COLON) ":" else exit_help; | ||
| 151 | |||
| 152 | return false; | ||
| 153 | }; | ||
| 154 | |||
| 155 | switch (c) { | ||
| 156 | case cmd::UP => wpos.1 -= 1; | ||
| 157 | case cmd::DOWN => wpos.1 += 1; | ||
| 158 | case cmd::LEFT => wpos.0 -= 1; | ||
| 159 | case cmd::RIGHT => wpos.0 += 1; | ||
| 160 | case cmd::ARROW => msg = "No arrows allowed!"; | ||
| 161 | case cmd::COLON => colon_mode = true; | ||
| 162 | case cmd::EXIT_ATTEMPT => exit_attempt(); | ||
| 163 | case cmd::Q => exit_attempt(); | ||
| 164 | case => yield; | ||
| 165 | }; | ||
| 166 | |||
| 167 | return false; | ||
| 168 | }; | ||
| 169 | |||
| 170 | export fn main() void = { | ||
| 171 | let e = tb::init(); | ||
| 172 | if (e is tb::err) | ||
| 173 | fmt::fatalf(tb::strerror(e as tb::err)); | ||
| 174 | defer tb::shutdown()!; | ||
| 175 | |||
| 176 | wpos = (tb::width()!: int / 2, tb::height()!: int / 2); | ||
| 177 | for (true) { | ||
| 178 | tb::clear()!; | ||
| 179 | |||
| 180 | let w = tb::width()!; | ||
| 181 | let h = tb::height()!; | ||
| 182 | |||
| 183 | draw_widget_thing(w, h); | ||
| 184 | draw_bottom_bar(w, h); | ||
| 185 | tb::present()!; | ||
| 186 | |||
| 187 | if (handle_events_and_exit()) break; | ||
| 188 | }; | ||
| 189 | return; | ||
| 190 | }; | ||
