boacon 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- boacon/__init__.py +360 -0
- boacon/c_BCChar.py +140 -0
- boacon/c_BCCoord.py +185 -0
- boacon/c_BCCursesAttrFunc.py +14 -0
- boacon/c_BCError.py +7 -0
- boacon/c_BCPane.py +93 -0
- boacon/c_BCPostDrawArgs.py +50 -0
- boacon/c_BCSetChrFunc.py +19 -0
- boacon/c_BCSignal.py +39 -0
- boacon/c_BCSignalEmitter.py +47 -0
- boacon/c_BCState.py +14 -0
- boacon/c_BCStr.py +307 -0
- boacon/g_attr.py +42 -0
- boacon/g_key.py +731 -0
- boacon/p_BCConsolePane.py +175 -0
- boacon-0.0.1.dist-info/METADATA +145 -0
- boacon-0.0.1.dist-info/RECORD +19 -0
- boacon-0.0.1.dist-info/WHEEL +4 -0
- boacon-0.0.1.dist-info/licenses/LICENSE +21 -0
boacon/__init__.py
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
from .c_BCChar import *
|
|
2
|
+
from .c_BCCoord import *
|
|
3
|
+
from .c_BCError import *
|
|
4
|
+
from .c_BCPane import *
|
|
5
|
+
from .c_BCPostDrawArgs import *
|
|
6
|
+
from .c_BCSetChrFunc import *
|
|
7
|
+
from .c_BCSignal import *
|
|
8
|
+
from .c_BCSignalEmitter import *
|
|
9
|
+
from .c_BCState import *
|
|
10
|
+
from .c_BCStr import *
|
|
11
|
+
from .g_attr import *
|
|
12
|
+
from .g_key import *
|
|
13
|
+
from .p_BCConsolePane import *
|
|
14
|
+
|
|
15
|
+
import curses as _curses
|
|
16
|
+
import numpy as _np
|
|
17
|
+
import numpy.typing as _npt
|
|
18
|
+
|
|
19
|
+
#region const
|
|
20
|
+
|
|
21
|
+
_C_BORDERCHARS = [\
|
|
22
|
+
0xFF, 0x50, 0x50, 0x50, 0x51, 0x54, 0x5A, 0x50, 0x51, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,\
|
|
23
|
+
0x5D, 0x50, 0x69, 0x50, 0x51, 0x54, 0x5A, 0x50, 0x63, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,\
|
|
24
|
+
0x5A, 0x50, 0x69, 0x50, 0x60, 0x54, 0x5A, 0x50, 0x51, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,\
|
|
25
|
+
0x69, 0x50, 0x69, 0x50, 0x60, 0x54, 0x5A, 0x50, 0x63, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,\
|
|
26
|
+
0x57, 0x66, 0x50, 0x50, 0x51, 0x54, 0x5A, 0x50, 0x63, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,\
|
|
27
|
+
0x63, 0x66, 0x69, 0x50, 0x51, 0x54, 0x5A, 0x50, 0x63, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,\
|
|
28
|
+
0x6C, 0x66, 0x69, 0x50, 0x60, 0x54, 0x5A, 0x50, 0x63, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,\
|
|
29
|
+
0x6C, 0x66, 0x69, 0x50, 0x60, 0x54, 0x5A, 0x50, 0x63, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,\
|
|
30
|
+
0x54, 0x66, 0x50, 0x50, 0x60, 0x54, 0x5A, 0x50, 0x51, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,\
|
|
31
|
+
0x6C, 0x66, 0x69, 0x50, 0x60, 0x54, 0x5A, 0x50, 0x63, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,\
|
|
32
|
+
0x60, 0x66, 0x69, 0x50, 0x60, 0x54, 0x5A, 0x50, 0x51, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,\
|
|
33
|
+
0x6C, 0x66, 0x69, 0x50, 0x60, 0x54, 0x5A, 0x50, 0x63, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,\
|
|
34
|
+
0x66, 0x66, 0x50, 0x50, 0x60, 0x54, 0x5A, 0x50, 0x63, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,\
|
|
35
|
+
0x6C, 0x66, 0x69, 0x50, 0x60, 0x54, 0x5A, 0x50, 0x63, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,\
|
|
36
|
+
0x6C, 0x66, 0x69, 0x50, 0x60, 0x54, 0x5A, 0x50, 0x63, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,\
|
|
37
|
+
0x6C, 0x66, 0x69, 0x50, 0x60, 0x54, 0x5A, 0x50, 0x63, 0x57, 0x5D, 0x50, 0x51, 0x51, 0x51, 0xA1,]
|
|
38
|
+
|
|
39
|
+
#endregion
|
|
40
|
+
|
|
41
|
+
#region variables
|
|
42
|
+
|
|
43
|
+
_f_state = BCState.NORUN
|
|
44
|
+
_f_win:None|_curses.window = None
|
|
45
|
+
_f_win_ok = False
|
|
46
|
+
_f_win_w = 0
|
|
47
|
+
_f_win_h = 0
|
|
48
|
+
_f_color = False
|
|
49
|
+
_f_panes:None|list[BCPane] = None
|
|
50
|
+
_f_bgbuffer:None|_npt.NDArray[_np.bool_] = None
|
|
51
|
+
|
|
52
|
+
_f_border = False
|
|
53
|
+
|
|
54
|
+
_s_on_init_emitter = BCSignalEmitter[()]()
|
|
55
|
+
_s_on_init = BCSignal(_s_on_init_emitter)
|
|
56
|
+
_s_on_final_emitter = BCSignalEmitter[()]()
|
|
57
|
+
_s_on_final = BCSignal(_s_on_final_emitter)
|
|
58
|
+
|
|
59
|
+
_s_postdraw_emitter:None|BCSignalEmitter[BCPostDrawArgs] = None
|
|
60
|
+
_s_postdraw:None|BCSignal[BCPostDrawArgs] = None
|
|
61
|
+
|
|
62
|
+
#endregion
|
|
63
|
+
|
|
64
|
+
#region helper
|
|
65
|
+
|
|
66
|
+
def _m_verify_run():
|
|
67
|
+
global _f_state
|
|
68
|
+
if _f_state == BCState.RUN: return
|
|
69
|
+
raise BCError("boacon system is not currently running.")
|
|
70
|
+
|
|
71
|
+
def _m_setcursor(visible:bool):
|
|
72
|
+
global _f_win, _f_win_ok
|
|
73
|
+
assert _f_win is not None
|
|
74
|
+
# Try to hide normally
|
|
75
|
+
if not _f_win_ok:
|
|
76
|
+
try: _curses.curs_set(1 if visible else 0)
|
|
77
|
+
except _curses.error: _f_win_ok = True
|
|
78
|
+
# Try to hide alternatively
|
|
79
|
+
if _f_win_ok: # Do NOT change to else or elif
|
|
80
|
+
try: _f_win.leaveok(not visible)
|
|
81
|
+
except _curses.error: pass
|
|
82
|
+
|
|
83
|
+
def _m_cursesattr_color(attr:int):
|
|
84
|
+
cattr = _curses.A_STANDOUT if attr_emp(attr) else _curses.A_NORMAL
|
|
85
|
+
return cattr | _curses.color_pair(0b111 ^ attr_color(attr))
|
|
86
|
+
|
|
87
|
+
def _m_cursesattr_nocolor(attr:int):
|
|
88
|
+
return _curses.A_STANDOUT if attr_emp(attr) else _curses.A_NORMAL
|
|
89
|
+
|
|
90
|
+
def _m_setchr_color(x:int, y:int, char:BCChar):
|
|
91
|
+
global _f_win, _f_bgbuffer, _f_win_w
|
|
92
|
+
assert _f_win is not None
|
|
93
|
+
assert _f_bgbuffer is not None
|
|
94
|
+
attr = _m_cursesattr_color(char.attr)
|
|
95
|
+
try:
|
|
96
|
+
_f_win.addch(y, x, chr(char.ord), attr)
|
|
97
|
+
_f_bgbuffer[y * _f_win_w + x] = True
|
|
98
|
+
except: pass
|
|
99
|
+
|
|
100
|
+
def _m_setchr_nocolor(x:int, y:int, char:BCChar):
|
|
101
|
+
global _f_win, _f_bgbuffer, _f_win_w
|
|
102
|
+
assert _f_win is not None
|
|
103
|
+
assert _f_bgbuffer is not None
|
|
104
|
+
attr = _m_cursesattr_nocolor(char.attr)
|
|
105
|
+
try:
|
|
106
|
+
_f_win.addch(y, x, chr(char.ord), attr)
|
|
107
|
+
_f_bgbuffer[y * _f_win_w + x] = True
|
|
108
|
+
except: pass
|
|
109
|
+
|
|
110
|
+
def _m_borderchar(x:int, y:int):
|
|
111
|
+
global _f_win_w, _f_win_h, _f_bgbuffer
|
|
112
|
+
assert _f_bgbuffer is not None
|
|
113
|
+
# Examine neighbors
|
|
114
|
+
index = y * _f_win_w + x
|
|
115
|
+
index_t = index - _f_win_w
|
|
116
|
+
index_b = index + _f_win_w
|
|
117
|
+
notedge_t = y > 0
|
|
118
|
+
notedge_b = (y + 1) < _f_win_h
|
|
119
|
+
notedge_l = x > 0
|
|
120
|
+
notedge_r = (x + 1) < _f_win_w
|
|
121
|
+
if notedge_t:
|
|
122
|
+
neighbor_t = _f_bgbuffer[index_t]
|
|
123
|
+
neighbor_tl = notedge_l and _f_bgbuffer[index_t - 1]
|
|
124
|
+
neighbor_tr = notedge_r and _f_bgbuffer[index_t + 1]
|
|
125
|
+
else:
|
|
126
|
+
neighbor_t = False
|
|
127
|
+
neighbor_tl = False
|
|
128
|
+
neighbor_tr = False
|
|
129
|
+
if notedge_b:
|
|
130
|
+
neighbor_b = _f_bgbuffer[index_b]
|
|
131
|
+
neighbor_bl = notedge_l and _f_bgbuffer[index_b - 1]
|
|
132
|
+
neighbor_br = notedge_r and _f_bgbuffer[index_b + 1]
|
|
133
|
+
else:
|
|
134
|
+
neighbor_b = False
|
|
135
|
+
neighbor_bl = False
|
|
136
|
+
neighbor_br = False
|
|
137
|
+
neighbor_l = notedge_l and _f_bgbuffer[index - 1]
|
|
138
|
+
neighbor_r = notedge_r and _f_bgbuffer[index + 1]
|
|
139
|
+
# Determine character
|
|
140
|
+
index = 0
|
|
141
|
+
if neighbor_t: index |= 0b00000001
|
|
142
|
+
if neighbor_b: index |= 0b00000010
|
|
143
|
+
if neighbor_l: index |= 0b00000100
|
|
144
|
+
if neighbor_r: index |= 0b00001000
|
|
145
|
+
if neighbor_tl: index |= 0b00010000
|
|
146
|
+
if neighbor_tr: index |= 0b00100000
|
|
147
|
+
if neighbor_bl: index |= 0b01000000
|
|
148
|
+
if neighbor_br: index |= 0b10000000
|
|
149
|
+
raw = _C_BORDERCHARS[index]
|
|
150
|
+
return ' ' if (raw == 0xFF) else chr(0x2500 | raw)
|
|
151
|
+
|
|
152
|
+
#endregion
|
|
153
|
+
|
|
154
|
+
#region init/final
|
|
155
|
+
|
|
156
|
+
def init():
|
|
157
|
+
global _f_state
|
|
158
|
+
if _f_state != BCState.NORUN: return
|
|
159
|
+
_f_state = BCState.INIT
|
|
160
|
+
# Global vars
|
|
161
|
+
global _f_win, _f_win_w, _f_win_h, _f_color, _f_panes
|
|
162
|
+
global _f_border
|
|
163
|
+
# Initialize window
|
|
164
|
+
_f_win = _curses.initscr()
|
|
165
|
+
_f_win.keypad(True)
|
|
166
|
+
_f_win.nodelay(True)
|
|
167
|
+
_f_win_w = 0
|
|
168
|
+
_f_win_h = 0
|
|
169
|
+
# Initialize curses
|
|
170
|
+
_curses.noecho()
|
|
171
|
+
_curses.cbreak()
|
|
172
|
+
_m_setcursor(False)
|
|
173
|
+
# Initialize color
|
|
174
|
+
_curses.start_color()
|
|
175
|
+
if _curses.has_colors() and _curses.COLOR_PAIRS >= 8:
|
|
176
|
+
_curses.use_default_colors()
|
|
177
|
+
_curses.init_pair(0b001, _curses.COLOR_CYAN, -1)
|
|
178
|
+
_curses.init_pair(0b010, _curses.COLOR_MAGENTA, -1)
|
|
179
|
+
_curses.init_pair(0b011, _curses.COLOR_BLUE, -1)
|
|
180
|
+
_curses.init_pair(0b100, _curses.COLOR_YELLOW, -1)
|
|
181
|
+
_curses.init_pair(0b101, _curses.COLOR_GREEN, -1)
|
|
182
|
+
_curses.init_pair(0b110, _curses.COLOR_RED, -1)
|
|
183
|
+
_curses.init_pair(0b111, _curses.COLOR_BLACK, -1)
|
|
184
|
+
_f_color = True
|
|
185
|
+
else:
|
|
186
|
+
_f_color = False
|
|
187
|
+
# Initialize panes
|
|
188
|
+
_f_panes = []
|
|
189
|
+
# Initialize border
|
|
190
|
+
_f_border = True
|
|
191
|
+
# Initialize signals
|
|
192
|
+
global _s_postdraw, _s_postdraw_emitter
|
|
193
|
+
_s_postdraw_emitter = BCSignalEmitter[BCPostDrawArgs]()
|
|
194
|
+
_s_postdraw = BCSignal[BCPostDrawArgs](_s_postdraw_emitter)
|
|
195
|
+
# Success!!!
|
|
196
|
+
_f_state = BCState.RUN
|
|
197
|
+
_s_on_init_emitter.emit(())
|
|
198
|
+
|
|
199
|
+
def final():
|
|
200
|
+
global _f_state
|
|
201
|
+
if _f_state != BCState.RUN: return
|
|
202
|
+
_s_on_final_emitter.emit(())
|
|
203
|
+
_f_state = BCState.FINAL
|
|
204
|
+
# Global vars
|
|
205
|
+
global _f_win, _panes
|
|
206
|
+
assert _f_win is not None
|
|
207
|
+
# Finalize curses
|
|
208
|
+
_curses.nocbreak()
|
|
209
|
+
_curses.echo()
|
|
210
|
+
_curses.endwin()
|
|
211
|
+
# Finalize window
|
|
212
|
+
_m_setcursor(True)
|
|
213
|
+
_f_win.nodelay(False)
|
|
214
|
+
_f_win.keypad(False)
|
|
215
|
+
# Success!!!
|
|
216
|
+
_f_state = BCState.NORUN
|
|
217
|
+
|
|
218
|
+
#endregion
|
|
219
|
+
|
|
220
|
+
#region "properties"
|
|
221
|
+
|
|
222
|
+
def state():
|
|
223
|
+
"""
|
|
224
|
+
State of the boacon system
|
|
225
|
+
"""
|
|
226
|
+
global _f_state
|
|
227
|
+
return _f_state
|
|
228
|
+
|
|
229
|
+
def panes():
|
|
230
|
+
"""
|
|
231
|
+
Panes that are being displayed
|
|
232
|
+
|
|
233
|
+
:raise BCError:
|
|
234
|
+
boacon system is not currently running
|
|
235
|
+
"""
|
|
236
|
+
_m_verify_run()
|
|
237
|
+
global _f_panes
|
|
238
|
+
assert _f_panes is not None
|
|
239
|
+
return _f_panes
|
|
240
|
+
|
|
241
|
+
def on_init():
|
|
242
|
+
"""
|
|
243
|
+
Emitted after the boacon system is initialized
|
|
244
|
+
"""
|
|
245
|
+
global _s_on_init
|
|
246
|
+
return _s_on_init
|
|
247
|
+
|
|
248
|
+
def on_final():
|
|
249
|
+
"""
|
|
250
|
+
Emitted before the boacon system is finalized
|
|
251
|
+
"""
|
|
252
|
+
global _s_on_final
|
|
253
|
+
return _s_on_final
|
|
254
|
+
|
|
255
|
+
def postdraw():
|
|
256
|
+
"""
|
|
257
|
+
Emitted after drawing the panes and right before the screen is refreshed
|
|
258
|
+
|
|
259
|
+
:raise BCError:
|
|
260
|
+
boacon system is not currently running
|
|
261
|
+
"""
|
|
262
|
+
_m_verify_run()
|
|
263
|
+
global _s_postdraw
|
|
264
|
+
assert _s_postdraw is not None
|
|
265
|
+
return _s_postdraw
|
|
266
|
+
|
|
267
|
+
#endregion
|
|
268
|
+
|
|
269
|
+
#region functions
|
|
270
|
+
|
|
271
|
+
def refresh():
|
|
272
|
+
"""
|
|
273
|
+
Refreshes the screen
|
|
274
|
+
|
|
275
|
+
:raise BCError:
|
|
276
|
+
boacon system is not currently running
|
|
277
|
+
"""
|
|
278
|
+
_m_verify_run()
|
|
279
|
+
global _f_win, _f_win_w, _f_win_h, _f_color, _f_panes, _f_bgbuffer
|
|
280
|
+
global _f_border
|
|
281
|
+
assert _f_win is not None
|
|
282
|
+
assert _f_panes is not None
|
|
283
|
+
global _s_postdraw_emitter
|
|
284
|
+
assert _s_postdraw_emitter is not None
|
|
285
|
+
# Determine functions
|
|
286
|
+
_func_cursesattr = _m_cursesattr_color if _f_color else _m_cursesattr_nocolor
|
|
287
|
+
_func_setchr = _m_setchr_color if _f_color else _m_setchr_nocolor
|
|
288
|
+
# Update size
|
|
289
|
+
_new_h, _new_w = _f_win.getmaxyx()
|
|
290
|
+
if _f_win_w != _new_w or _f_win_h != _new_h:
|
|
291
|
+
_f_win_w = _new_w
|
|
292
|
+
_f_win_h = _new_h
|
|
293
|
+
_f_bgbuffer = _np.zeros(_f_win_w * _f_win_h, dtype = bool)
|
|
294
|
+
resized = True
|
|
295
|
+
else:
|
|
296
|
+
assert _f_bgbuffer is not None
|
|
297
|
+
resized = False
|
|
298
|
+
# Resolve pane dimensions
|
|
299
|
+
redrawbg = resized
|
|
300
|
+
for _pane in _f_panes:
|
|
301
|
+
if _pane._m_resolve(resized, _f_win_w, _f_win_h):
|
|
302
|
+
redrawbg = True
|
|
303
|
+
if redrawbg:
|
|
304
|
+
_f_bgbuffer.fill(False)
|
|
305
|
+
# Update panes
|
|
306
|
+
for _pane in _f_panes:
|
|
307
|
+
_pane._m_refresh(redrawbg, _func_setchr)
|
|
308
|
+
# Draw background
|
|
309
|
+
if redrawbg:
|
|
310
|
+
for _y in range(_f_win_h):
|
|
311
|
+
for _x in range(_f_win_w):
|
|
312
|
+
_i = _y * _f_win_w + _x
|
|
313
|
+
if _f_bgbuffer[_i]: continue
|
|
314
|
+
# Determine character
|
|
315
|
+
_chr = _m_borderchar(_x, _y) if _f_border else ' '
|
|
316
|
+
# Set character
|
|
317
|
+
try: _f_win.addch(_y, _x, _chr)
|
|
318
|
+
except: pass
|
|
319
|
+
# Post draw
|
|
320
|
+
_s_postdraw_emitter.emit((BCPostDrawArgs(_f_win, _func_cursesattr, _func_setchr),))
|
|
321
|
+
# Success!!!
|
|
322
|
+
_f_win.refresh()
|
|
323
|
+
|
|
324
|
+
def getch():
|
|
325
|
+
"""
|
|
326
|
+
Gets a character code from the keyboard
|
|
327
|
+
|
|
328
|
+
:return:
|
|
329
|
+
Character code (or -1 if no character is pressed)
|
|
330
|
+
:raise BCError:
|
|
331
|
+
boacon system is not currently running
|
|
332
|
+
"""
|
|
333
|
+
_m_verify_run()
|
|
334
|
+
global _f_win
|
|
335
|
+
assert _f_win is not None
|
|
336
|
+
return _f_win.getch()
|
|
337
|
+
|
|
338
|
+
def get_border():
|
|
339
|
+
"""
|
|
340
|
+
Gets whether or not pane borders are enabled
|
|
341
|
+
|
|
342
|
+
:raise BCError:
|
|
343
|
+
boacon system is not currently running
|
|
344
|
+
"""
|
|
345
|
+
_m_verify_run()
|
|
346
|
+
global _f_border
|
|
347
|
+
return _f_border
|
|
348
|
+
|
|
349
|
+
def set_border(value:bool):
|
|
350
|
+
"""
|
|
351
|
+
Sets whether or not pane borders are enabled
|
|
352
|
+
|
|
353
|
+
:raise BCError:
|
|
354
|
+
boacon system is not currently running
|
|
355
|
+
"""
|
|
356
|
+
_m_verify_run()
|
|
357
|
+
global _f_border
|
|
358
|
+
_f_border = value
|
|
359
|
+
|
|
360
|
+
#endregion
|
boacon/c_BCChar.py
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
all = ['BCChar']
|
|
2
|
+
|
|
3
|
+
from .g_attr import\
|
|
4
|
+
ATTR_NORMAL as _ATTR_NORMAL
|
|
5
|
+
|
|
6
|
+
class BCChar:
|
|
7
|
+
"""
|
|
8
|
+
Represents a text character
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
#region init
|
|
12
|
+
|
|
13
|
+
def __init__(self, ord:int, attr:int = _ATTR_NORMAL):
|
|
14
|
+
"""
|
|
15
|
+
Initializer for BBChar
|
|
16
|
+
|
|
17
|
+
:param ord:
|
|
18
|
+
Ordinal code
|
|
19
|
+
:param attr:
|
|
20
|
+
Text attribute
|
|
21
|
+
"""
|
|
22
|
+
self.__ord = ord
|
|
23
|
+
self.__attr = attr
|
|
24
|
+
|
|
25
|
+
#endregion
|
|
26
|
+
|
|
27
|
+
#region operators
|
|
28
|
+
|
|
29
|
+
def __repr__(self):
|
|
30
|
+
return f"BCChar({self.__ord}, attr = {self.__attr})"
|
|
31
|
+
|
|
32
|
+
def __str__(self):
|
|
33
|
+
return chr(self.__ord)
|
|
34
|
+
|
|
35
|
+
def __eq__(self, other:object):
|
|
36
|
+
equ = self.__equ(other)
|
|
37
|
+
if equ is None: return NotImplemented
|
|
38
|
+
return equ
|
|
39
|
+
|
|
40
|
+
def __ne__(self, other:object):
|
|
41
|
+
equ = self.__equ(other)
|
|
42
|
+
if equ is None: return NotImplemented
|
|
43
|
+
return not equ
|
|
44
|
+
|
|
45
|
+
def __lt__(self, other:object):
|
|
46
|
+
cmp = self.__cmp(other)
|
|
47
|
+
if cmp is None: return NotImplemented
|
|
48
|
+
return cmp < 0
|
|
49
|
+
|
|
50
|
+
def __le__(self, other:object):
|
|
51
|
+
cmp = self.__cmp(other)
|
|
52
|
+
if cmp is None: return NotImplemented
|
|
53
|
+
return cmp <= 0
|
|
54
|
+
|
|
55
|
+
def __gt__(self, other:object):
|
|
56
|
+
cmp = self.__cmp(other)
|
|
57
|
+
if cmp is None: return NotImplemented
|
|
58
|
+
return cmp > 0
|
|
59
|
+
|
|
60
|
+
def __ge__(self, other:object):
|
|
61
|
+
cmp = self.__cmp(other)
|
|
62
|
+
if cmp is None: return NotImplemented
|
|
63
|
+
return cmp >= 0
|
|
64
|
+
|
|
65
|
+
def __hash__(self):
|
|
66
|
+
return self.__ord
|
|
67
|
+
|
|
68
|
+
#endregion
|
|
69
|
+
|
|
70
|
+
#region properties
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def ord(self):
|
|
74
|
+
"""
|
|
75
|
+
Ordinal code
|
|
76
|
+
"""
|
|
77
|
+
return self.__ord
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def attr(self):
|
|
81
|
+
"""
|
|
82
|
+
Text attribute
|
|
83
|
+
"""
|
|
84
|
+
return self.__attr
|
|
85
|
+
|
|
86
|
+
#endregion
|
|
87
|
+
|
|
88
|
+
#region helper methods
|
|
89
|
+
|
|
90
|
+
def __equ(self, other: object):
|
|
91
|
+
if isinstance(other, BCChar):
|
|
92
|
+
return self.__ord == other.__ord and self.__attr == other.__attr
|
|
93
|
+
if isinstance(other, str):
|
|
94
|
+
return len(other) == 1 and self.__ord == ord(other)
|
|
95
|
+
return None
|
|
96
|
+
|
|
97
|
+
def __cmp(self, other: object) -> None|int:
|
|
98
|
+
if isinstance(other, BCChar):
|
|
99
|
+
if self.__ord != other.__ord: return self.__ord - other.__ord
|
|
100
|
+
return self.__attr - other.__attr
|
|
101
|
+
if isinstance(other, str):
|
|
102
|
+
if len(other) != 1: return None
|
|
103
|
+
return self.__ord - ord(other)
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
#endregion
|
|
107
|
+
|
|
108
|
+
#region methods
|
|
109
|
+
|
|
110
|
+
def equ(self, other:object):
|
|
111
|
+
"""
|
|
112
|
+
Checks if the character is equal to another character
|
|
113
|
+
|
|
114
|
+
:param other:
|
|
115
|
+
Other character
|
|
116
|
+
:return:
|
|
117
|
+
Whether or not the two characters are equal
|
|
118
|
+
"""
|
|
119
|
+
equ = self.__equ(other)
|
|
120
|
+
if equ is None: return False
|
|
121
|
+
return equ
|
|
122
|
+
|
|
123
|
+
def cmp(self, other:object):
|
|
124
|
+
"""
|
|
125
|
+
Compares the character to another character
|
|
126
|
+
|
|
127
|
+
:param other:
|
|
128
|
+
Other character
|
|
129
|
+
:return:
|
|
130
|
+
lt 0: Current character precedes other character\n
|
|
131
|
+
eq 0: Current character is equal to the other character\n
|
|
132
|
+
gt 0: Current character follows other character
|
|
133
|
+
:raise TypeError:
|
|
134
|
+
Cannot compare with other type
|
|
135
|
+
"""
|
|
136
|
+
cmp = self.__cmp(other)
|
|
137
|
+
if cmp is None: raise TypeError(f"Cannot compare BCChar with {type(other)}.")
|
|
138
|
+
return cmp
|
|
139
|
+
|
|
140
|
+
#endregion
|
boacon/c_BCCoord.py
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
all = ['BCCoord']
|
|
2
|
+
|
|
3
|
+
class BCCoord:
|
|
4
|
+
"""
|
|
5
|
+
Represents coordinates for a single axis
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
#region init
|
|
9
|
+
|
|
10
|
+
def __init__(self, dis0:None|int = None, dis1:None|int = None, len:None|int = None):
|
|
11
|
+
"""
|
|
12
|
+
Initializer for BCCoord
|
|
13
|
+
|
|
14
|
+
:param dis0:
|
|
15
|
+
For X-axis: Distance from the left edge of console to left edge of pane\n
|
|
16
|
+
For Y-axis: Distance from the top edge of console to top edge of pane
|
|
17
|
+
:param dis1:
|
|
18
|
+
For X-axis: Distance from the right edge of console to right edge of pane\n
|
|
19
|
+
For Y-axis: Distance from the bottom edge of console to bottom edge of pane
|
|
20
|
+
:param len:
|
|
21
|
+
For X-axis: Width of pane\n
|
|
22
|
+
For Y-axis: Height of pane
|
|
23
|
+
"""
|
|
24
|
+
self.__dis0 = dis0
|
|
25
|
+
self.__dis1 = dis1
|
|
26
|
+
self.__len = len
|
|
27
|
+
self.__first = True
|
|
28
|
+
self.__prev_dis0:None|int = None
|
|
29
|
+
self.__prev_dis1:None|int = None
|
|
30
|
+
self.__prev_len:None|int = None
|
|
31
|
+
self.__pnt0:int = 0
|
|
32
|
+
self.__pnt1:int = 0
|
|
33
|
+
self.__pntlen:int = 0
|
|
34
|
+
self.__clip0:int = 0
|
|
35
|
+
self.__clip1:int = 0
|
|
36
|
+
self.__cliplen:int = 0
|
|
37
|
+
self.__clipoff:int = 0
|
|
38
|
+
|
|
39
|
+
#endregion
|
|
40
|
+
|
|
41
|
+
#region properties
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def dis0(self):
|
|
45
|
+
"""
|
|
46
|
+
For X-axis: Distance from the left edge of console to left edge of pane\n
|
|
47
|
+
For Y-axis: Distance from the top edge of console to top edge of pane
|
|
48
|
+
"""
|
|
49
|
+
return self.__dis0
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def dis1(self):
|
|
53
|
+
"""
|
|
54
|
+
For X-axis: Distance from the right edge of console to right edge of pane\n
|
|
55
|
+
For Y-axis: Distance from the bottom edge of console to bottom edge of pane
|
|
56
|
+
"""
|
|
57
|
+
return self.__dis1
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def len(self):
|
|
61
|
+
"""
|
|
62
|
+
For X-axis: Width of pane\n
|
|
63
|
+
For Y-axis: Height of pane
|
|
64
|
+
"""
|
|
65
|
+
return self.__len
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def pnt0(self):
|
|
69
|
+
"""
|
|
70
|
+
For X-axis: X-coordinate of left edge\n
|
|
71
|
+
For Y-axis: Y-coordinate of top edge
|
|
72
|
+
"""
|
|
73
|
+
return self.__pnt0
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def pnt1(self):
|
|
77
|
+
"""
|
|
78
|
+
For X-axis: X-coordinate of right edge\n
|
|
79
|
+
For Y-axis: Y-coordinate of bottom edge
|
|
80
|
+
"""
|
|
81
|
+
return self.__pnt1
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def pntlen(self):
|
|
85
|
+
"""
|
|
86
|
+
Distance between pnt0 and pnt1\n
|
|
87
|
+
For X-axis: Resolved width\n
|
|
88
|
+
For Y-axis: Resolved height
|
|
89
|
+
"""
|
|
90
|
+
return self.__pntlen
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def clip0(self):
|
|
94
|
+
"""
|
|
95
|
+
For X-axis: X-coordinate of left clip\n
|
|
96
|
+
For Y-axis: Y-coordinate of top clip
|
|
97
|
+
"""
|
|
98
|
+
return self.__clip0
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def clip1(self):
|
|
102
|
+
"""
|
|
103
|
+
For X-axis: X-coordinate of right clip\n
|
|
104
|
+
For Y-axis: Y-coordinate of bottom clip
|
|
105
|
+
"""
|
|
106
|
+
return self.__clip1
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def cliplen(self):
|
|
110
|
+
"""
|
|
111
|
+
Distance between clip0 and clip1\n
|
|
112
|
+
For X-axis: Clip width\n
|
|
113
|
+
For Y-axis: Clip height
|
|
114
|
+
"""
|
|
115
|
+
return self.__cliplen
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def clipoff(self):
|
|
119
|
+
"""
|
|
120
|
+
This is the offset from pnt0 to clip0
|
|
121
|
+
"""
|
|
122
|
+
return self.__clipoff
|
|
123
|
+
|
|
124
|
+
@dis0.setter
|
|
125
|
+
def dis0(self, value:None|int): self.__dis0 = value
|
|
126
|
+
|
|
127
|
+
@dis1.setter
|
|
128
|
+
def dis1(self, value:None|int): self.__dis1 = value
|
|
129
|
+
|
|
130
|
+
@len.setter
|
|
131
|
+
def len(self, value:None|int): self.__len = value
|
|
132
|
+
|
|
133
|
+
#endregion
|
|
134
|
+
|
|
135
|
+
#region helper methods
|
|
136
|
+
|
|
137
|
+
def _m_resolve(self, force:bool, containlen:int):
|
|
138
|
+
"""
|
|
139
|
+
Also accessed by TPPane
|
|
140
|
+
"""
|
|
141
|
+
if not (force or self.__first or\
|
|
142
|
+
self.__prev_dis0 != self.__dis0 or\
|
|
143
|
+
self.__prev_dis1 != self.__dis1 or\
|
|
144
|
+
self.__prev_len != self.__len):
|
|
145
|
+
return False
|
|
146
|
+
# Update previous
|
|
147
|
+
self.__first = False
|
|
148
|
+
self.__prev_dis0 = self.__dis0
|
|
149
|
+
self.__prev_dis1 = self.__dis1
|
|
150
|
+
self.__prev_len = self.__len
|
|
151
|
+
# Resolve
|
|
152
|
+
pnt0 = self.dis0
|
|
153
|
+
pnt1 = None if (self.dis1 is None) else (containlen - self.dis1)
|
|
154
|
+
pntlen = self.len
|
|
155
|
+
if pnt0 is not None:
|
|
156
|
+
if pnt1 is not None:
|
|
157
|
+
pntlen = pnt1 - pnt0
|
|
158
|
+
elif pntlen is not None:
|
|
159
|
+
pnt1 = pnt0 + pntlen
|
|
160
|
+
else:
|
|
161
|
+
pnt1 = pnt0
|
|
162
|
+
pntlen = 0
|
|
163
|
+
elif pnt1 is not None:
|
|
164
|
+
if pntlen is not None:
|
|
165
|
+
pnt0 = pnt1 - pntlen
|
|
166
|
+
else:
|
|
167
|
+
pnt0 = pnt1
|
|
168
|
+
pntlen = 0
|
|
169
|
+
elif pntlen is not None:
|
|
170
|
+
pnt0 = 0
|
|
171
|
+
pnt1 = pntlen
|
|
172
|
+
else:
|
|
173
|
+
pnt0 = 0
|
|
174
|
+
pnt1 = 0
|
|
175
|
+
pntlen = 0
|
|
176
|
+
self.__pnt0 = pnt0
|
|
177
|
+
self.__pnt1 = pnt1
|
|
178
|
+
self.__pntlen = pntlen
|
|
179
|
+
self.__clip0 = max(0, min(containlen, self.__pnt0))
|
|
180
|
+
self.__clip1 = max(0, min(containlen, self.__pnt1))
|
|
181
|
+
self.__cliplen = self.__clip1 - self.__clip0
|
|
182
|
+
self.__clipoff = self.__clip0 - self.pnt0
|
|
183
|
+
return True
|
|
184
|
+
|
|
185
|
+
#endregion
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
all = ['BCCursesAttrFunc']
|
|
2
|
+
|
|
3
|
+
from typing import\
|
|
4
|
+
Callable as _Callable
|
|
5
|
+
|
|
6
|
+
type BCCursesAttrFunc = _Callable[[int], int]
|
|
7
|
+
"""
|
|
8
|
+
Function for computing a curses character attribute
|
|
9
|
+
|
|
10
|
+
:param 0:
|
|
11
|
+
boacon character attribute
|
|
12
|
+
:return:
|
|
13
|
+
curses character attribute
|
|
14
|
+
"""
|