- commit
- 864914d7aa02b1ac360dfc58fa39fc9c0eacf39c
- parent
- 13b37062afeec5a888192cdae8601c0d58210644
- Author
- Tobias Bengfort <tobias.bengfort@posteo.de>
- Date
- 2024-07-05 18:27
boon UI
Diffstat
| M | sheet/__main__.py | 126 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
| M | sheet/term.py | 36 | ------------------------------------ |
2 files changed, 122 insertions, 40 deletions
diff --git a/sheet/__main__.py b/sheet/__main__.py
@@ -1,9 +1,127 @@ 1 1 import sys 2 2 -1 3 import boon -1 4 3 5 from .csv import load_csv4 -1 from .term import render-1 6 from .expression import x2col -1 7 from .term import align_center -1 8 from .term import align_left -1 9 from .term import align_right -1 10 from .term import red -1 11 from .term import invert -1 12 -1 13 -1 14 def to_cell(value: float|int|str|None|Exception, width: int) -> str: -1 15 if isinstance(value, float): -1 16 return align_right(str(value), width) -1 17 elif isinstance(value, int): -1 18 return align_right(str(value), width) -1 19 elif isinstance(value, str): -1 20 return align_left(value, width) -1 21 elif value is None: -1 22 return ' ' * width -1 23 elif isinstance(value, Exception): -1 24 return red(align_left(repr(value), width)) -1 25 -1 26 -1 27 class App(boon.App): -1 28 def __init__(self): -1 29 super().__init__() -1 30 with open(sys.argv[1]) as fh: -1 31 self.sheet = load_csv(fh) -1 32 self.x0 = 0 -1 33 self.y0 = 0 -1 34 self.cursor_x = 0 -1 35 self.cursor_y = 0 -1 36 self.widths = {} -1 37 -1 38 def scroll_into_view(self, rows, cols): -1 39 if self.cursor_y < self.y0: -1 40 self.y0 = self.cursor_y -1 41 elif self.cursor_y > self.y0 + rows - 3: -1 42 self.y0 = self.cursor_y - rows + 3 -1 43 -1 44 if self.cursor_x < self.x0: -1 45 self.x0 = self.cursor_x -1 46 else: -1 47 widths = [self.get_width(x) for x in range(self.x0, self.cursor_x + 1)] -1 48 offset = 0 -1 49 while sum(widths[offset:]) > cols: -1 50 offset += 1 -1 51 self.x0 += offset -1 52 -1 53 def render(self, rows, cols): -1 54 self.scroll_into_view(rows, cols) -1 55 -1 56 lines = [] -1 57 -1 58 lines.append(' ' * 4) -1 59 x = self.x0 -1 60 while len(lines[-1]) < cols: -1 61 row_head = align_center(x2col(x), self.get_width(x)) -1 62 if x == self.cursor_x: -1 63 row_head = invert(row_head) -1 64 lines[-1] += row_head -1 65 x += 1 -1 66 -1 67 for dy in range(rows - 2): -1 68 y = self.y0 + dy -1 69 # FIXME: col_head vanishes -1 70 col_head = align_right(str(y + 1), 4) -1 71 if y == self.cursor_y: -1 72 col_head = invert(col_head) -1 73 lines.append(col_head) -1 74 -1 75 x = self.x0 -1 76 # FIXME: do not count ANSI codes for length -1 77 # FIXME; lines are longer than they should be (we stop once we are >=) -1 78 while len(lines[-1]) < cols: -1 79 value = self.sheet.get_value((x, y)) -1 80 cell = to_cell(value, self.get_width(x)) -1 81 if x == self.cursor_x and y == self.cursor_y: -1 82 cell = invert(cell) -1 83 lines[-1] += cell -1 84 x += 1 -1 85 -1 86 lines.append(self.sheet.get_raw((self.cursor_x, self.cursor_y))) -1 87 -1 88 return lines -1 89 -1 90 def get_width(self, x): -1 91 return self.widths.get(x, 10) -1 92 -1 93 def set_width(self, x, value): -1 94 self.widths[x] = max(value, 3) -1 95 -1 96 def change_width(self, x, d): -1 97 old = self.get_width(x) -1 98 self.set_width(x, old + d) -1 99 -1 100 def on_key(self, key): -1 101 if key == 'q': -1 102 self.running = False -1 103 elif key == boon.KEY_DOWN: -1 104 self.cursor_y += 1 -1 105 elif key == boon.KEY_UP: -1 106 self.cursor_y = max(self.cursor_y - 1, 0) -1 107 elif key == boon.KEY_NPAGE: -1 108 self.cursor_y += 20 # TODO: relativ to rows -1 109 elif key == boon.KEY_PPAGE: -1 110 self.cursor_y = max(self.cursor_y - 20, 0) -1 111 elif key == boon.KEY_RIGHT: -1 112 self.cursor_x += 1 -1 113 elif key == boon.KEY_LEFT: -1 114 self.cursor_x = max(self.cursor_x - 1, 0) -1 115 elif key == '>': -1 116 self.change_width(self.cursor_x, 1) -1 117 elif key == '<': -1 118 self.change_width(self.cursor_x, -1) -1 119 elif key == '=': -1 120 pass -1 121 # self.set_width(self.cursor_x, max() # TODO auto width -1 122 elif key == '\n': -1 123 pass # TODO: edit 5 1246 -1 with open(sys.argv[1]) as fh:7 -1 sheet = load_csv(fh)8 1259 -1 print(render(sheet, 80, 40, (0, 0), 10))-1 126 app = App() -1 127 app.run()
diff --git a/sheet/term.py b/sheet/term.py
@@ -1,6 +1,3 @@1 -1 from .expression import x2col2 -13 -14 1 def align_right(s, width): 5 2 if len(s) > width: 6 3 s = '###' @@ -26,36 +23,3 @@ def red(s): 26 23 27 24 def invert(s): 28 25 return f'\033[7m{s}\033[0m'29 -130 -131 -1 def to_cell(value: float|int|str|None|Exception, width: int) -> str:32 -1 if isinstance(value, float):33 -1 return align_right(str(value), width)34 -1 elif isinstance(value, int):35 -1 return align_right(str(value), width)36 -1 elif isinstance(value, str):37 -1 return align_left(value, width)38 -1 elif value is None:39 -1 return ' ' * width40 -1 elif isinstance(value, Exception):41 -1 return red(align_left(repr(value), width))42 -143 -144 -1 def render(sheet, width, height, cell_offset, cell_width):45 -1 x0, y0 = cell_offset46 -1 rows = []47 -1 w = width // cell_width48 -1 rows.append([49 -1 ' ' * cell_width,50 -1 ] + [51 -1 align_center(x2col(x0 + dx), cell_width)52 -1 for dx in range(w - 1)53 -1 ])54 -1 for dy in range(height - 1):55 -1 rows.append([56 -1 align_right(str(y0 + dy + 1), cell_width),57 -1 ] + [58 -1 to_cell(sheet.get_value((x0 + dx, y0 + dy)), cell_width)59 -1 for dx in range(w - 1)60 -1 ])61 -1 return '\n'.join([''.join(row) for row in rows])