From 44c4bf9e797bedd988e7235c64a3ac5e1d7c5e1c Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Thu, 7 Apr 2022 23:50:58 -0400 Subject: [PATCH] More enums, changed btui.open_btui() to btui.open() --- Python/bed.py | 14 +-- Python/btui.py | 238 ++++++++++++++++++++++++++----------------------- Python/test.py | 4 +- README.md | 6 +- btui.h | 12 +-- 5 files changed, 142 insertions(+), 132 deletions(-) diff --git a/Python/bed.py b/Python/bed.py index 85c0a1c..696e974 100755 --- a/Python/bed.py +++ b/Python/bed.py @@ -10,7 +10,7 @@ # Save with Ctrl-S, Quit with Ctrl-Q or Ctrl-C # import sys -from btui import open_btui +import btui from collections import namedtuple Vec2 = namedtuple('Vec2', 'x y') @@ -141,7 +141,7 @@ class BedFile: x = self.pos.x self.bt.move(x, y) if lineno >= len(self.lines): - self.bt.clear('line') + self.bt.clear(btui.ClearType.LINE) self.drawn.add(lineno) continue with self.bt.attributes("faint"): @@ -149,7 +149,7 @@ class BedFile: x += self.numlen + 1 self.bt.move(x, y) self.bt.write_bytes(bytes(self.lines[lineno])) - self.bt.clear('right') + self.bt.clear(btui.ClearType.RIGHT) self.drawn.add(lineno) class BED: @@ -165,7 +165,7 @@ class BED: self.renders = 0 def edit(self): - self.bt.set_cursor('blinking bar') + self.bt.set_cursor(btui.CursorType.BLINKING_BAR) self.render() key, mx, my = self.bt.getkey() while True: @@ -212,7 +212,7 @@ class BED: if self.file.unsaved: with self.bt.attributes("dim"): self.bt.write(" (modified)") - self.bt.clear('right') + self.bt.clear(btui.ClearType.RIGHT) self.drawn.add(k) self.file.render() @@ -221,7 +221,7 @@ class BED: with self.bt.attributes("bold"): self.bt.move(0, self.bt.height-1) self.bt.write("Ctrl-Q to quit, Ctrl-S to save") - self.bt.clear('right') + self.bt.clear(btui.ClearType.RIGHT) with self.bt.attributes("faint"): s = f"Line {self.file.cursor.y}, Col {self.file.cursor.x}, {self.renders} redraws" self.bt.move(self.bt.width-len(s), self.bt.height-1) @@ -243,6 +243,6 @@ if __name__ == '__main__': sys.exit(1) filename = args[0] - with open_btui(debug=debug) as bt: + with btui.open(debug=debug) as bt: bed = BED(bt, filename) bed.edit() diff --git a/Python/btui.py b/Python/btui.py index 77b7067..11cfe46 100644 --- a/Python/btui.py +++ b/Python/btui.py @@ -1,9 +1,10 @@ import ctypes -import time +import enum import functools +import time from contextlib import contextmanager -__all__ = ['open_btui'] +__all__ = ['open', 'TextAttr', 'ClearType', 'CursorType', 'BTUIMode'] # Load the shared library into c types. libbtui = ctypes.CDLL("./libbtui.so") @@ -22,99 +23,112 @@ class BTUI_struct(ctypes.Structure): libbtui.btui_create.restype = ctypes.POINTER(BTUI_struct) -BTUI_MODE_UNINITIALIZED, BTUI_MODE_NORMAL, BTUI_MODE_TUI = 0, 1, 2 - -attr = lambda name: ctypes.c_longlong.in_dll(libbtui, name) +attr = lambda name: ctypes.c_longlong.in_dll(libbtui, name).value attr_t = ctypes.c_longlong -BTUI_ATTRS = { - "normal": attr('BTUI_NORMAL'), - "bold": attr('BTUI_BOLD'), - "faint": attr('BTUI_FAINT'), - "dim": attr('BTUI_FAINT'), - "italic": attr('BTUI_ITALIC'), - "underline": attr('BTUI_UNDERLINE'), - "blink_slow": attr('BTUI_BLINK_SLOW'), - "blink_fast": attr('BTUI_BLINK_FAST'), - "reverse": attr('BTUI_REVERSE'), - "conceal": attr('BTUI_CONCEAL'), - "strikethrough": attr('BTUI_STRIKETHROUGH'), - "fraktur": attr('BTUI_FRAKTUR'), - "double_underline": attr('BTUI_DOUBLE_UNDERLINE'), - "no_bold_or_faint": attr('BTUI_NO_BOLD_OR_FAINT'), - "no_italic_or_fraktur": attr('BTUI_NO_ITALIC_OR_FRAKTUR'), - "no_underline": attr('BTUI_NO_UNDERLINE'), - "no_blink": attr('BTUI_NO_BLINK'), - "no_reverse": attr('BTUI_NO_REVERSE'), - "no_conceal": attr('BTUI_NO_CONCEAL'), - "no_strikethrough": attr('BTUI_NO_STRIKETHROUGH'), - "fg_black": attr('BTUI_FG_BLACK'), - "fg_red": attr('BTUI_FG_RED'), - "fg_green": attr('BTUI_FG_GREEN'), - "fg_yellow": attr('BTUI_FG_YELLOW'), - "fg_blue": attr('BTUI_FG_BLUE'), - "fg_magenta": attr('BTUI_FG_MAGENTA'), - "fg_cyan": attr('BTUI_FG_CYAN'), - "fg_white": attr('BTUI_FG_WHITE'), - "fg_normal": attr('BTUI_FG_NORMAL'), - "bg_black": attr('BTUI_BG_BLACK'), - "bg_red": attr('BTUI_BG_RED'), - "bg_green": attr('BTUI_BG_GREEN'), - "bg_yellow": attr('BTUI_BG_YELLOW'), - "bg_blue": attr('BTUI_BG_BLUE'), - "bg_magenta": attr('BTUI_BG_MAGENTA'), - "bg_cyan": attr('BTUI_BG_CYAN'), - "bg_white": attr('BTUI_BG_WHITE'), - "bg_normal": attr('BTUI_BG_NORMAL'), - "framed": attr('BTUI_FRAMED'), - "encircled": attr('BTUI_ENCIRCLED'), - "overlined": attr('BTUI_OVERLINED'), -} + +class TextAttr(enum.IntEnum): + NORMAL = attr('BTUI_NORMAL') + BOLD = attr('BTUI_BOLD') + FAINT = attr('BTUI_FAINT') + DIM = attr('BTUI_FAINT') + ITALIC = attr('BTUI_ITALIC') + UNDERLINE = attr('BTUI_UNDERLINE') + BLINK_SLOW = attr('BTUI_BLINK_SLOW') + BLINK_FAST = attr('BTUI_BLINK_FAST') + REVERSE = attr('BTUI_REVERSE') + CONCEAL = attr('BTUI_CONCEAL') + STRIKETHROUGH = attr('BTUI_STRIKETHROUGH') + FRAKTUR = attr('BTUI_FRAKTUR') + DOUBLE_UNDERLINE = attr('BTUI_DOUBLE_UNDERLINE') + NO_BOLD_OR_FAINT = attr('BTUI_NO_BOLD_OR_FAINT') + NO_ITALIC_OR_FRAKTUR = attr('BTUI_NO_ITALIC_OR_FRAKTUR') + NO_UNDERLINE = attr('BTUI_NO_UNDERLINE') + NO_BLINK = attr('BTUI_NO_BLINK') + NO_REVERSE = attr('BTUI_NO_REVERSE') + NO_CONCEAL = attr('BTUI_NO_CONCEAL') + NO_STRIKETHROUGH = attr('BTUI_NO_STRIKETHROUGH') + FG_BLACK = attr('BTUI_FG_BLACK') + FG_RED = attr('BTUI_FG_RED') + FG_GREEN = attr('BTUI_FG_GREEN') + FG_YELLOW = attr('BTUI_FG_YELLOW') + FG_BLUE = attr('BTUI_FG_BLUE') + FG_MAGENTA = attr('BTUI_FG_MAGENTA') + FG_CYAN = attr('BTUI_FG_CYAN') + FG_WHITE = attr('BTUI_FG_WHITE') + FG_NORMAL = attr('BTUI_FG_NORMAL') + BG_BLACK = attr('BTUI_BG_BLACK') + BG_RED = attr('BTUI_BG_RED') + BG_GREEN = attr('BTUI_BG_GREEN') + BG_YELLOW = attr('BTUI_BG_YELLOW') + BG_BLUE = attr('BTUI_BG_BLUE') + BG_MAGENTA = attr('BTUI_BG_MAGENTA') + BG_CYAN = attr('BTUI_BG_CYAN') + BG_WHITE = attr('BTUI_BG_WHITE') + BG_NORMAL = attr('BTUI_BG_NORMAL') + FRAMED = attr('BTUI_FRAMED') + ENCIRCLED = attr('BTUI_ENCIRCLED') + OVERLINED = attr('BTUI_OVERLINED') + NO_FRAMED_OR_ENCIRCLED = attr('BTUI_NO_FRAMED_OR_ENCIRCLED') + NO_OVERLINED = attr('BTUI_NO_OVERLINED') BTUI_INVERSE_ATTRS = { - "normal": attr('BTUI_NORMAL'), - "bold": attr('BTUI_NO_BOLD_OR_FAINT'), - "faint": attr('BTUI_NO_BOLD_OR_FAINT'), - "dim": attr('BTUI_NO_BOLD_OR_FAINT'), - "italic": attr('BTUI_NO_ITALIC_OR_FRAKTUR'), - "underline": attr('BTUI_NO_UNDERLINE'), - "blink_slow": attr('BTUI_NO_BLINK'), - "blink_fast": attr('BTUI_NO_BLINK'), - "reverse": attr('BTUI_NO_REVERSE'), - "conceal": attr('BTUI_NO_CONCEAL'), - "strikethrough": attr('BTUI_NO_STRIKETHROUGH'), - "fraktur": attr('BTUI_NO_ITALIC_OR_FRAKTUR'), - "double_underline": attr('BTUI_NO_UNDERLINE'), - "fg_black": attr('BTUI_FG_NORMAL'), - "fg_red": attr('BTUI_FG_NORMAL'), - "fg_green": attr('BTUI_FG_NORMAL'), - "fg_yellow": attr('BTUI_FG_NORMAL'), - "fg_blue": attr('BTUI_FG_NORMAL'), - "fg_magenta": attr('BTUI_FG_NORMAL'), - "fg_cyan": attr('BTUI_FG_NORMAL'), - "fg_white": attr('BTUI_FG_NORMAL'), - "fg_normal": attr('BTUI_FG_NORMAL'), - "bg_black": attr('BTUI_BG_NORMAL'), - "bg_red": attr('BTUI_BG_NORMAL'), - "bg_green": attr('BTUI_BG_NORMAL'), - "bg_yellow": attr('BTUI_BG_NORMAL'), - "bg_blue": attr('BTUI_BG_NORMAL'), - "bg_magenta": attr('BTUI_BG_NORMAL'), - "bg_cyan": attr('BTUI_BG_NORMAL'), - "bg_white": attr('BTUI_BG_NORMAL'), - "bg_normal": attr('BTUI_BG_NORMAL'), - "framed": attr('BTUI_NO_FRAMED_OR_ENCIRCLED'), - "encircled": attr('BTUI_NO_FRAMED_OR_ENCIRCLED'), - "overlined": attr('BTUI_NO_OVERLINED'), + TextAttr.NORMAL : TextAttr.NORMAL, + TextAttr.BOLD : TextAttr.NO_BOLD_OR_FAINT, + TextAttr.FAINT : TextAttr.NO_BOLD_OR_FAINT, + TextAttr.DIM : TextAttr.NO_BOLD_OR_FAINT, + TextAttr.ITALIC : TextAttr.NO_ITALIC_OR_FRAKTUR, + TextAttr.UNDERLINE : TextAttr.NO_UNDERLINE, + TextAttr.BLINK_SLOW : TextAttr.NO_BLINK, + TextAttr.BLINK_FAST : TextAttr.NO_BLINK, + TextAttr.REVERSE : TextAttr.NO_REVERSE, + TextAttr.CONCEAL : TextAttr.NO_CONCEAL, + TextAttr.STRIKETHROUGH : TextAttr.NO_STRIKETHROUGH, + TextAttr.FRAKTUR : TextAttr.NO_ITALIC_OR_FRAKTUR, + TextAttr.DOUBLE_UNDERLINE: TextAttr.NO_UNDERLINE, + TextAttr.FG_BLACK : TextAttr.FG_NORMAL, + TextAttr.FG_RED : TextAttr.FG_NORMAL, + TextAttr.FG_GREEN : TextAttr.FG_NORMAL, + TextAttr.FG_YELLOW : TextAttr.FG_NORMAL, + TextAttr.FG_BLUE : TextAttr.FG_NORMAL, + TextAttr.FG_MAGENTA : TextAttr.FG_NORMAL, + TextAttr.FG_CYAN : TextAttr.FG_NORMAL, + TextAttr.FG_WHITE : TextAttr.FG_NORMAL, + TextAttr.FG_NORMAL : TextAttr.FG_NORMAL, + TextAttr.BG_BLACK : TextAttr.BG_NORMAL, + TextAttr.BG_RED : TextAttr.BG_NORMAL, + TextAttr.BG_GREEN : TextAttr.BG_NORMAL, + TextAttr.BG_YELLOW : TextAttr.BG_NORMAL, + TextAttr.BG_BLUE : TextAttr.BG_NORMAL, + TextAttr.BG_MAGENTA : TextAttr.BG_NORMAL, + TextAttr.BG_CYAN : TextAttr.BG_NORMAL, + TextAttr.BG_WHITE : TextAttr.BG_NORMAL, + TextAttr.BG_NORMAL : TextAttr.BG_NORMAL, + TextAttr.FRAMED : TextAttr.NO_FRAMED_OR_ENCIRCLED, + TextAttr.ENCIRCLED : TextAttr.NO_FRAMED_OR_ENCIRCLED, + TextAttr.OVERLINED : TextAttr.NO_OVERLINED, } -BTUI_CLEAR_VALUES = { - "screen": 0, - "above": 1, - "below": 2, - "line": 3, - "left": 4, - "right": 5, -} +class BTUIMode(enum.IntEnum): + UNINITIALIZED = 0 + NORMAL = 1 + TUI = 2 + +class CursorType(enum.IntEnum): + DEFAULT = 0 + BLINKING_BLOCK = 1 + BLOCK = 2 + BLINKING_UNDERLINE = 3 + UNDERLINE = 4 + BLINKING_BAR = 5 + BAR = 6 + +class ClearType(enum.IntEnum): + SCREEN = 0 + ABOVE = 1 + BELOW = 2 + LINE = 3 + LEFT = 4 + RIGHT = 5 class BTUI: @contextmanager @@ -129,11 +143,11 @@ class BTUI: try: yield finally: self.set_attributes("bg_normal") - def clear(self, mode='screen'): + def clear(self, clear_type=ClearType.SCREEN): assert self._btui - if mode not in BTUI_CLEAR_VALUES: - raise ArgumentError("Not a supported clear type: "+repr(mode)) - libbtui.btui_clear(self._btui, BTUI_CLEAR_VALUES[mode]) + if isinstance(clear_type, str): + clear_type = ClearType[clear_type.upper()] + libbtui.btui_clear(self._btui, clear_type) libbtui.btui_flush(self._btui) def disable(self): @@ -150,20 +164,14 @@ class BTUI: libbtui.btui_draw_shadow(self._btui, int(x), int(y), int(w), int(h)) libbtui.btui_flush(self._btui) - def enable(self, mode='TUI'): - if mode == 'TUI': - mode = BTUI_MODE_TUI - elif mode == 'normal': - mode = BTUI_MODE_NORMAL - else: raise ArgumentError("Invalid mode: "+str(mode)) + def enable(self, mode=BTUIMode.TUI): + if isinstance(mode, str): + mode = BTUIMode[mode.upper()] self._btui = libbtui.btui_create(mode) def set_mode(self, mode): - if mode == 'TUI': - mode = BTUI_MODE_TUI - elif mode == 'normal': - mode = BTUI_MODE_NORMAL - else: raise ArgumentError("Invalid mode: "+str(mode)) + if isinstance(mode, str): + mode = BTUIMode[mode.upper()] self._btui = libbtui.set_mode(self._btui, mode) @contextmanager @@ -204,13 +212,11 @@ class BTUI: libbtui.btui_move_cursor(self._btui, int(x), int(y)) libbtui.btui_flush(self._btui) - def set_cursor(self, cursor_type="default"): + def set_cursor(self, cursor_type=CursorType.DEFAULT): assert self._btui - if cursor_type in ('default', 'blinking block', 'blinking underline', 'blinking bar'): - c = ctypes.c_uint.in_dll(libbtui, 'CURSOR_' + cursor_type.replace(' ', '_').upper()) - elif cursor_type in ('block', 'underline', 'bar'): - c = ctypes.c_uint.in_dll(libbtui, 'CURSOR_STEADY_' + cursor_type.upper()) - libbtui.btui_set_cursor(self._btui, c) + if isinstance(cursor_type, str): + cursor_type = CursorType[cursor_type.upper()] + libbtui.btui_set_cursor(self._btui, cursor_type) libbtui.btui_flush(self._btui) def hide_cursor(self): @@ -240,7 +246,9 @@ class BTUI: assert self._btui attr_long = ctypes.c_longlong(0) for a in attrs: - attr_long.value |= BTUI_ATTRS[a].value + if isinstance(a, str): + a = TextAttr[a.upper()] + attr_long.value |= a libbtui.btui_set_attributes(self._btui, attr_long) def set_bg(self, r, g, b): @@ -259,7 +267,9 @@ class BTUI: assert self._btui attr_long = ctypes.c_longlong(0) for a in attrs: - attr_long.value |= BTUI_INVERSE_ATTRS[a].value + if isinstance(a, str): + a = TextAttr[a.upper()] + attr_long.value |= BTUI_INVERSE_ATTRS[a] libbtui.btui_set_attributes(self._btui, attr_long) @property @@ -296,7 +306,7 @@ for fn_name in ('clear', 'draw_shadow', 'fill_box', 'move', 'set_cursor', 'hide_ _btui = None @contextmanager -def open_btui(*, debug=False, delay=0.05, mode='TUI'): +def open(*, debug=False, delay=0.05, mode=BTUIMode.TUI): global _btui if not _btui: if debug: diff --git a/Python/test.py b/Python/test.py index 1c4274d..1ae0572 100644 --- a/Python/test.py +++ b/Python/test.py @@ -3,9 +3,9 @@ # This file contains a simple test program for demonstrating some basic Python # BTUI usage. # -from btui import open_btui +import btui -with open_btui() as bt: +with btui.open() as bt: key = None x, y = 1, 1 while key != 'q' and key != 'Ctrl-c': diff --git a/README.md b/README.md index f78fb3a..6b72470 100644 --- a/README.md +++ b/README.md @@ -163,13 +163,13 @@ Lua library, and `make testlua` to run the Lua BTUI demo. ### Python API -The Python library has only one value: `open_btui()`. This is a context manager, -which can be used to safely wrap TUI applications. +The Python library has one main function: `btui.open()`. This is a context +manager, which can be used to safely wrap TUI applications. ```python import btui -with btui.open_btui() as bt: +with btui.open() as bt: # Your code here... ``` diff --git a/btui.h b/btui.h index 096d1df..90126b6 100644 --- a/btui.h +++ b/btui.h @@ -101,12 +101,12 @@ const btui_key_t KEY_CTRL_SLASH = KEY_CTRL_UNDERSCORE; const btui_key_t KEY_CTRL_8 = KEY_BACKSPACE2; typedef enum { - BTUI_CLEAR_SCREEN, - BTUI_CLEAR_ABOVE, - BTUI_CLEAR_BELOW, - BTUI_CLEAR_LINE, - BTUI_CLEAR_LEFT, - BTUI_CLEAR_RIGHT, + BTUI_CLEAR_SCREEN = 0, + BTUI_CLEAR_ABOVE = 1, + BTUI_CLEAR_BELOW = 2, + BTUI_CLEAR_LINE = 3, + BTUI_CLEAR_LEFT = 4, + BTUI_CLEAR_RIGHT = 5, } btui_clear_t; // Text attributes: