kopia lustrzana https://github.com/micropython/micropython-lib
ucurses: Implementation of curses subset.
This implements only curses windows, with unbuffered output directly to terminal. Curses pads (offscreen windows) are thus not supported. Only subset of APIs are implemented, too.pull/26/head
rodzic
631ebfd8ba
commit
6984f17acc
|
@ -0,0 +1,303 @@
|
|||
import os
|
||||
import tty, termios
|
||||
|
||||
COLOR_BLACK = 0
|
||||
COLOR_RED = 1
|
||||
COLOR_GREEN = 2
|
||||
COLOR_YELLOW = 3
|
||||
COLOR_BLUE = 4
|
||||
COLOR_MAGENTA = 5
|
||||
COLOR_CYAN = 6
|
||||
COLOR_WHITE = 7
|
||||
|
||||
A_NORMAL = 0
|
||||
A_BOLD = 1
|
||||
A_UNDERLINE = 2
|
||||
A_REVERSE = 4
|
||||
A_STANDOUT = A_REVERSE
|
||||
|
||||
ATTRMAP = {
|
||||
A_NORMAL: b"\x1b[0m",
|
||||
A_BOLD: b"\x1b[1m", # Some terminal emulators don't render bold by default, then use 4m for underline
|
||||
A_REVERSE: b"\x1b[7m",
|
||||
}
|
||||
|
||||
# Use http://www.utf8-chartable.de/unicode-utf8-table.pl
|
||||
# for utf-8 pseudographic reference
|
||||
# "─"
|
||||
ACS_HLINE = b"\xe2\x94\x80"
|
||||
# "│"
|
||||
ACS_VLINE = b"\xe2\x94\x82"
|
||||
# "┌"
|
||||
ACS_ULCORNER = b"\xe2\x94\x8c"
|
||||
# "┐"
|
||||
ACS_URCORNER = b"\xe2\x94\x90"
|
||||
# "└"
|
||||
ACS_LLCORNER = b"\xe2\x94\x94"
|
||||
# "┘"
|
||||
ACS_LRCORNER = b"\xe2\x94\x98"
|
||||
|
||||
KEY_F1 = 1031
|
||||
KEY_RESIZE = 1100
|
||||
KEY_MOUSE = 1101
|
||||
KEY_BTAB = 1090
|
||||
|
||||
KEY_UP = 1001
|
||||
KEY_DOWN = 1002
|
||||
KEY_LEFT = 1003
|
||||
KEY_RIGHT = 1004
|
||||
KEY_HOME = 1005
|
||||
KEY_END = 1006
|
||||
KEY_PGUP = 1007
|
||||
KEY_PGDN = 1008
|
||||
KEY_QUIT = 1009
|
||||
KEY_ENTER = 1010
|
||||
KEY_BACKSPACE = 1011
|
||||
KEY_DELETE = 1012
|
||||
KEY_ESC = 1020
|
||||
|
||||
KEY_DC = KEY_DELETE
|
||||
KEY_PPAGE = KEY_PGUP
|
||||
KEY_NPAGE = KEY_PGDN
|
||||
|
||||
KEYMAP = {
|
||||
b"\x1b[A": KEY_UP,
|
||||
b"\x1b[B": KEY_DOWN,
|
||||
b"\x1b[D": KEY_LEFT,
|
||||
b"\x1b[C": KEY_RIGHT,
|
||||
b"\x1bOH": KEY_HOME,
|
||||
b"\x1bOF": KEY_END,
|
||||
b"\x1b[1~": KEY_HOME,
|
||||
b"\x1b[4~": KEY_END,
|
||||
b"\x1b[5~": KEY_PGUP,
|
||||
b"\x1b[6~": KEY_PGDN,
|
||||
b"\x03": KEY_QUIT,
|
||||
b"\r": KEY_ENTER,
|
||||
b"\x7f": KEY_BACKSPACE,
|
||||
b"\x1b[3~": KEY_DELETE,
|
||||
|
||||
b"\x1bOA": KEY_UP,
|
||||
b"\x1bOB": KEY_DOWN,
|
||||
b"\x1bOD": KEY_LEFT,
|
||||
b"\x1bOC": KEY_RIGHT,
|
||||
b"\x1bOP": KEY_F1,
|
||||
b"\x1b": KEY_ESC,
|
||||
|
||||
b"\x1b[Z": KEY_BTAB,
|
||||
}
|
||||
|
||||
ALL_MOUSE_EVENTS = 0xff
|
||||
|
||||
|
||||
def _wr(s):
|
||||
# TODO: When Python is 3.5, update this to use only bytes
|
||||
if isinstance(s, str):
|
||||
s = bytes(s, "utf-8")
|
||||
os.write(1, s)
|
||||
|
||||
def _move(row, col):
|
||||
# TODO: When Python is 3.5, update this to use bytes
|
||||
_wr("\x1b[%d;%dH" % (row + 1, col + 1))
|
||||
|
||||
# Clear specified number of positions
|
||||
def _clear_num_pos(num):
|
||||
if num > 0:
|
||||
_wr("\x1b[%dX" % num)
|
||||
|
||||
def _draw_box(left, top, width, height):
|
||||
bottom = top + height - 1
|
||||
_move(top, left)
|
||||
_wr(ACS_ULCORNER)
|
||||
hor = ACS_HLINE * (width - 2)
|
||||
_wr(hor)
|
||||
_wr(ACS_URCORNER)
|
||||
|
||||
_move(bottom, left)
|
||||
_wr(ACS_LLCORNER)
|
||||
_wr(hor)
|
||||
_wr(ACS_LRCORNER)
|
||||
|
||||
top += 1
|
||||
while top < bottom:
|
||||
_move(top, left)
|
||||
_wr(ACS_VLINE)
|
||||
_move(top, left + width - 1)
|
||||
_wr(ACS_VLINE)
|
||||
top += 1
|
||||
|
||||
|
||||
class error(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Window:
|
||||
|
||||
def __init__(self, lines, cols, y, x):
|
||||
self.lines = lines
|
||||
self.cols = cols
|
||||
self.y = y
|
||||
self.x = x
|
||||
self.bkgattr = A_NORMAL
|
||||
self.keybuf = None
|
||||
self.keyi = 0
|
||||
|
||||
def _goto(self, row, col):
|
||||
_move(self.y + row, self.x + col)
|
||||
|
||||
def move(self, y, x):
|
||||
# Maybe need to cache coords?
|
||||
self._goto(y, x)
|
||||
|
||||
def getmaxyx(self):
|
||||
return (self.lines, self.cols)
|
||||
|
||||
def addstr(self, y, x, str, attr=A_NORMAL):
|
||||
self._goto(y, x)
|
||||
# TODO: Should be "ORed"
|
||||
if attr == A_NORMAL:
|
||||
attr = self.bkgattr
|
||||
if attr != A_NORMAL:
|
||||
_wr(ATTRMAP[attr])
|
||||
_wr(str)
|
||||
_wr(ATTRMAP[A_NORMAL])
|
||||
else:
|
||||
_wr(str)
|
||||
|
||||
def addnstr(self, y, x, str, n, attr=A_NORMAL):
|
||||
self.addstr(y, x, str[:n], attr)
|
||||
|
||||
def addch(self, y, x, ch, attr=A_NORMAL):
|
||||
if isinstance(ch, int):
|
||||
ch = chr(ch)
|
||||
self.addstr(y, x, ch, attr)
|
||||
|
||||
def attron(self, attr):
|
||||
pass
|
||||
|
||||
def attroff(self, attr):
|
||||
pass
|
||||
|
||||
def attrset(self, attr):
|
||||
pass
|
||||
|
||||
def bkgdset(self, ch, attr=A_NORMAL):
|
||||
self.bkgattr = attr
|
||||
|
||||
def erase(self):
|
||||
for i in range(self.lines):
|
||||
self._goto(i, 0)
|
||||
_clear_num_pos(self.cols)
|
||||
|
||||
def border(self):
|
||||
_draw_box(self.x, self.y, self.cols, self.lines)
|
||||
|
||||
def hline(self, y, x, ch, n):
|
||||
self.move(y, x)
|
||||
_wr(ch * n)
|
||||
|
||||
def vline(self, y, x, ch, n):
|
||||
for i in range(n):
|
||||
self.move(y + i, x)
|
||||
_wr(ch)
|
||||
|
||||
def refresh(self):
|
||||
pass
|
||||
|
||||
def redrawwin(self):
|
||||
pass
|
||||
|
||||
def keypad(self, yes):
|
||||
pass
|
||||
|
||||
def timeout(self, delay):
|
||||
assert delay < 0
|
||||
|
||||
def getch(self):
|
||||
if self.keybuf and self.keyi < len(self.keybuf):
|
||||
c = self.keybuf[self.keyi]
|
||||
self.keyi += 1
|
||||
return c
|
||||
|
||||
key = os.read(0, 32)
|
||||
if key[0] != 0x1b:
|
||||
self.keybuf = key
|
||||
self.keyi = 1
|
||||
key = key[0]
|
||||
|
||||
else:
|
||||
if key in KEYMAP:
|
||||
key = KEYMAP[key]
|
||||
else:
|
||||
assert False, repr(key)
|
||||
return key
|
||||
|
||||
|
||||
SCREEN = Window(24, 80, 0, 0)
|
||||
org_termios = None
|
||||
|
||||
|
||||
def wrapper(func):
|
||||
global org_termios
|
||||
org_termios = termios.tcgetattr(0)
|
||||
res = func()
|
||||
endwin()
|
||||
return res
|
||||
|
||||
def initscr():
|
||||
global org_termios
|
||||
org_termios = termios.tcgetattr(0)
|
||||
return SCREEN
|
||||
|
||||
def doupdate():
|
||||
pass
|
||||
|
||||
def endwin():
|
||||
global org_termios
|
||||
_wr(b"\r")
|
||||
termios.tcsetattr(0, termios.TCSANOW, org_termios)
|
||||
|
||||
def raw():
|
||||
tty.setraw(0)
|
||||
|
||||
def cbreak():
|
||||
#TODO
|
||||
pass
|
||||
|
||||
def nocbreak():
|
||||
#TODO
|
||||
pass
|
||||
|
||||
def echo():
|
||||
#TODO
|
||||
pass
|
||||
|
||||
def noecho():
|
||||
#TODO
|
||||
pass
|
||||
|
||||
def meta(yes):
|
||||
#TODO
|
||||
pass
|
||||
|
||||
def mousemask(mask):
|
||||
# Mouse reporting - X10 compatbility mode
|
||||
_wr(b"\x1b[?9h")
|
||||
|
||||
def has_colors():
|
||||
return False
|
||||
|
||||
def can_change_color():
|
||||
return False
|
||||
|
||||
def curs_set(visibility):
|
||||
if visibility > 0:
|
||||
_wr(b"\x1b[?25h")
|
||||
else:
|
||||
_wr(b"\x1b[?25l")
|
||||
|
||||
def beep():
|
||||
_wr(b"\x07")
|
||||
|
||||
def newwin(lines, cols, y, x):
|
||||
#print("newwin(%d, %d, %d, %d)" % (lines, cols, y, x))
|
||||
return Window(lines, cols, y, x)
|
Ładowanie…
Reference in New Issue