pocketlang/tests/examples/tui/_init.pk
2022-05-27 18:59:52 +05:30

322 lines
5.9 KiB
Plaintext

import term, io
from time import clock, sleep
from types import ByteBuffer
def write(msg)
io.write(io.stdout, msg)
end
## The configuration that should be used to create tui context
## and run.
class Config
def _init()
self.title = null
self.fps = 60
self.hide_cursor = false
self.capture_events = false
self.new_buffer = false
self.init_fn = null
self.event_fn = null
self.frame_fn = null
self.cleanup_fn = null
end
end
## Interlan context contains draw buffer and other data.
class _Context
def _init()
self.buff = ByteBuffer()
self.clear()
end
## Called to reset all the internal for reusing the context.
def clear()
self.buff.clear()
self.done = false ## If true the main loop ends.
end
end
## Internal global context.
_ctx = _Context()
## -------------------------------------------------------------------------
## FUNCTIONS
## -------------------------------------------------------------------------
## Flush all the buffered bytes in the context's buffer.
def flush()
write(_ctx.buff.string())
io.flush()
_ctx.buff.clear()
end
## Stops the main loop and return from run().
def stop()
_ctx.done = true
end
def set_title(title)
write("\x1b]0;$title\x07")
end
def hide_cursor()
write("\x1b[?25l")
end
def show_cursor()
write("\x1b[?25h")
end
## It'll write escape sequence to move the cursor but not actually move.
## for this to make effect, one should flush the buffer.
def set_position(x, y)
_ctx.buff.write("\x1b[${y + 1};${x + 1}H")
end
def get_size()
return term.getsize()
end
##
## Hex ASCII DEC-Line-Drawing
## ------------------------------
## 0x6a j ┘
## 0x6b k ┐
## 0x6c l ┌
## 0x6d m └
## 0x6e n ┼
## 0x71 q ─
## 0x74 t ├
## 0x75 u ┤
## 0x76 v ┴
## 0x77 w ┬
## 0x78 x │
##
def box_char(c)
_ctx.buff.write("\x1b(0$c\x1b(B")
end
## FIXME: Implement str * int multiplicatin to support
##
## "\x1b(0${ c * n }\x1b(B"
##
## and define box_char_len() or refactor the above to take argument n.
## Write a string to the context buffer.
def string(s)
_ctx.buff.write(str(s))
end
## Clear the screen and move cursor to (0, 0).
def clear()
_ctx.buff.write("\x1b[H\x1b[J")
end
## Clear everythin from cursor to EOL.
def clear_eol()
_ctx.buff.write("\x1b[K")
end
## Clear everythin from cursor to EOF.
def clear_eof()
_ctx.buff.write("\x1b[J")
end
## Reset all the stylings.
def reset()
_ctx.buff.write("\x1b[0m")
end
def _is_valid_color(r, g, b)
return r is Number and g is Number and b is Number
return r.isbyte() and g.isbyte() and b.isbyte()
end
## Set the forground color.
def start_color(r, g, b)
assert(_is_valid_color(r, g, b))
_ctx.buff.write("\x1b[38;2;$r;$g;${b}m")
end
## End the forground color.
def end_color()
_ctx.buff.write("\x1b[39m")
end
## Start the background color.
def start_bg(r, g, b)
assert(_is_valid_color(r, g, b))
_ctx.buff.write("\x1b[48;2;$r;$g;${b}m")
end
## End the background color.
def end_bg()
_ctx.buff.write("\x1b[49m")
end
def start_bold()
_ctx.buff.write("\x1b[1m")
end
def end_bold()
_ctx.buff.write("\x1b[22m")
end
def start_dim()
_ctx.buff.write("\x1b[2m")
end
def end_dim()
_ctx.buff.write("\x1b[22m")
end
def start_italic()
_ctx.buff.write("\x1b[3m")
end
def end_italic()
_ctx.buff.write("\x1b[23m")
end
def start_underline()
_ctx.buff.write("\x1b[4m")
end
def end_underline()
_ctx.buff.write("\x1b[24m")
end
def start_hidden()
_ctx.buff.write("\x1b[8m")
end
def end_hidden()
_ctx.buff.write("\x1b[28m")
end
def start_strikethrough()
_ctx.buff.write("\x1b[9m")
end
def end_strikethrough()
_ctx.buff.write("\x1b[29m")
end
def start_color_black()
_ctx.buff.write("\x1b[30m")
end
def end_color_black()
_ctx.buff.write("\x1b[40m")
end
def start_color_red()
_ctx.buff.write("\x1b[31m")
end
def end_color_red()
_ctx.buff.write("\x1b[41m")
end
def start_color_green()
_ctx.buff.write("\x1b[32m")
end
def end_color_green()
_ctx.buff.write("\x1b[42m")
end
def start_color_yellow()
_ctx.buff.write("\x1b[33m")
end
def end_color_yellow()
_ctx.buff.write("\x1b[43m")
end
def start_color_blue()
_ctx.buff.write("\x1b[34m")
end
def end_color_blue()
_ctx.buff.write("\x1b[44m")
end
def start_color_magenta()
_ctx.buff.write("\x1b[35m")
end
def end_color_magenta()
_ctx.buff.write("\x1b[45m")
end
def start_color_cyan()
_ctx.buff.write("\x1b[36m")
end
def end_color_cyan()
_ctx.buff.write("\x1b[46m")
end
def start_color_white()
_ctx.buff.write("\x1b[37m")
end
def end_color_white()
_ctx.buff.write("\x1b[47m")
end
def start_color_default()
_ctx.buff.write("\x1b[39m")
end
def end_color_default()
_ctx.buff.write("\x1b[49m")
end
## -------------------------------------------------------------------------
## TUI MAIN LOOP
## -------------------------------------------------------------------------
def run(config)
term.init(config.capture_events)
if config.new_buffer then term.new_screen_buffer() end
if config.hide_cursor then hide_cursor() end
if config.init_fn then config.init_fn() end
event = term.Event()
## The main loop.
while not _ctx.done
start = clock()
## Dispatch events.
while term.read_event(event)
if config.event_fn then config.event_fn(event) end
if _ctx.done then break end
end
## Run frame function
if config.frame_fn then config.frame_fn() end
## Sleep to sync FPS.
et = clock() - start ## Elapsed time.
ft = 1 / config.fps ## Frame time.
## TODO: set title to print fps if said in config.
if ft > et then sleep((ft - et) * 1000) end
end
## Cleanup.
if config.cleanup_fn then config.cleanup_fn() end
if config.hide_cursor then show_cursor() end
if config.new_buffer then term.restore_screen_buffer() end
term.cleanup()
_ctx.clear()
end