urwid 2.6.0.post0__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.

Potentially problematic release.


This version of urwid might be problematic. Click here for more details.

Files changed (75) hide show
  1. urwid/__init__.py +333 -0
  2. urwid/canvas.py +1413 -0
  3. urwid/command_map.py +137 -0
  4. urwid/container.py +59 -0
  5. urwid/decoration.py +65 -0
  6. urwid/display/__init__.py +97 -0
  7. urwid/display/_posix_raw_display.py +413 -0
  8. urwid/display/_raw_display_base.py +914 -0
  9. urwid/display/_web.css +12 -0
  10. urwid/display/_web.js +462 -0
  11. urwid/display/_win32.py +171 -0
  12. urwid/display/_win32_raw_display.py +269 -0
  13. urwid/display/common.py +1219 -0
  14. urwid/display/curses.py +690 -0
  15. urwid/display/escape.py +624 -0
  16. urwid/display/html_fragment.py +251 -0
  17. urwid/display/lcd.py +518 -0
  18. urwid/display/raw.py +37 -0
  19. urwid/display/web.py +636 -0
  20. urwid/event_loop/__init__.py +55 -0
  21. urwid/event_loop/abstract_loop.py +175 -0
  22. urwid/event_loop/asyncio_loop.py +231 -0
  23. urwid/event_loop/glib_loop.py +294 -0
  24. urwid/event_loop/main_loop.py +721 -0
  25. urwid/event_loop/select_loop.py +230 -0
  26. urwid/event_loop/tornado_loop.py +206 -0
  27. urwid/event_loop/trio_loop.py +302 -0
  28. urwid/event_loop/twisted_loop.py +269 -0
  29. urwid/event_loop/zmq_loop.py +275 -0
  30. urwid/font.py +695 -0
  31. urwid/graphics.py +96 -0
  32. urwid/highlight.css +19 -0
  33. urwid/listbox.py +1899 -0
  34. urwid/monitored_list.py +522 -0
  35. urwid/numedit.py +376 -0
  36. urwid/signals.py +330 -0
  37. urwid/split_repr.py +130 -0
  38. urwid/str_util.py +358 -0
  39. urwid/text_layout.py +632 -0
  40. urwid/treetools.py +515 -0
  41. urwid/util.py +557 -0
  42. urwid/version.py +16 -0
  43. urwid/vterm.py +1806 -0
  44. urwid/widget/__init__.py +181 -0
  45. urwid/widget/attr_map.py +161 -0
  46. urwid/widget/attr_wrap.py +140 -0
  47. urwid/widget/bar_graph.py +649 -0
  48. urwid/widget/big_text.py +77 -0
  49. urwid/widget/box_adapter.py +126 -0
  50. urwid/widget/columns.py +1145 -0
  51. urwid/widget/constants.py +574 -0
  52. urwid/widget/container.py +227 -0
  53. urwid/widget/divider.py +110 -0
  54. urwid/widget/edit.py +718 -0
  55. urwid/widget/filler.py +403 -0
  56. urwid/widget/frame.py +539 -0
  57. urwid/widget/grid_flow.py +539 -0
  58. urwid/widget/line_box.py +194 -0
  59. urwid/widget/overlay.py +829 -0
  60. urwid/widget/padding.py +597 -0
  61. urwid/widget/pile.py +971 -0
  62. urwid/widget/popup.py +170 -0
  63. urwid/widget/progress_bar.py +141 -0
  64. urwid/widget/scrollable.py +597 -0
  65. urwid/widget/solid_fill.py +44 -0
  66. urwid/widget/text.py +354 -0
  67. urwid/widget/widget.py +852 -0
  68. urwid/widget/widget_decoration.py +166 -0
  69. urwid/widget/wimp.py +792 -0
  70. urwid/wimp.py +23 -0
  71. urwid-2.6.0.post0.dist-info/COPYING +504 -0
  72. urwid-2.6.0.post0.dist-info/METADATA +332 -0
  73. urwid-2.6.0.post0.dist-info/RECORD +75 -0
  74. urwid-2.6.0.post0.dist-info/WHEEL +5 -0
  75. urwid-2.6.0.post0.dist-info/top_level.txt +1 -0
urwid/font.py ADDED
@@ -0,0 +1,695 @@
1
+ # Urwid BigText fonts
2
+ # Copyright (C) 2004-2006 Ian Ward
3
+ #
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License as published by the Free Software Foundation; either
7
+ # version 2.1 of the License, or (at your option) any later version.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ #
18
+ # Urwid web site: https://urwid.org/
19
+
20
+
21
+ from __future__ import annotations
22
+
23
+ import typing
24
+ import warnings
25
+ from pprint import pformat
26
+
27
+ from urwid.canvas import CanvasError, TextCanvas
28
+ from urwid.display.escape import SAFE_ASCII_DEC_SPECIAL_RE
29
+ from urwid.util import apply_target_encoding, str_util
30
+
31
+ if typing.TYPE_CHECKING:
32
+ from collections.abc import Iterable, Iterator, Sequence
33
+
34
+ from typing_extensions import Literal
35
+
36
+
37
+ def separate_glyphs(gdata: str, height: int) -> tuple[dict[str, tuple[int, list[str]]], bool]:
38
+ """return (dictionary of glyphs, utf8 required)"""
39
+ gl: list[str] = gdata.split("\n")[1:-1]
40
+
41
+ if any("\t" in elem for elem in gl):
42
+ raise ValueError(f"Incorrect glyphs data:\n{gdata!r}")
43
+
44
+ if len(gl) != height + 1:
45
+ raise ValueError(f"Incorrect glyphs height (expected: {height}):\n{gdata}")
46
+
47
+ key_line: str = gl[0]
48
+
49
+ character: str | None = None # current character
50
+ key_index = 0 # index into character key line
51
+ end_col = 0 # column position at end of glyph
52
+ start_col = 0 # column position at start of glyph
53
+ jl: list[int] = [0] * height # indexes into lines of gdata (gl)
54
+ result: dict[str, tuple[int, list[str]]] = {}
55
+ utf8_required = False
56
+ while True:
57
+ if character is None:
58
+ if key_index >= len(key_line):
59
+ break
60
+ character = key_line[key_index]
61
+
62
+ if key_index < len(key_line) and key_line[key_index] == character:
63
+ end_col += str_util.get_char_width(character)
64
+ key_index += 1
65
+ continue
66
+
67
+ out: list[str] = []
68
+ y = 0
69
+ fill = 0
70
+
71
+ for k, line in enumerate(gl[1:]):
72
+ j: int = jl[k]
73
+ y = 0
74
+ fill = 0
75
+ while y < end_col - start_col:
76
+ if j >= len(line):
77
+ fill = end_col - start_col - y
78
+ break
79
+ y += str_util.get_char_width(line[j])
80
+ j += 1
81
+ if y + fill != end_col - start_col:
82
+ raise ValueError(repr((y, fill, end_col)))
83
+
84
+ segment = line[jl[k] : j]
85
+ if not SAFE_ASCII_DEC_SPECIAL_RE.match(segment):
86
+ utf8_required = True
87
+
88
+ out.append(segment + " " * fill)
89
+ jl[k] = j
90
+
91
+ start_col = end_col
92
+ result[character] = (y + fill, out)
93
+ character = None
94
+ return result, utf8_required
95
+
96
+
97
+ def add_font(name: str, cls: FontRegistry) -> None:
98
+ warnings.warn(
99
+ "`add_font` is deprecated, please set 'name' attribute to the font class,"
100
+ " use metaclass keyword argument 'font_name'"
101
+ " or use `Font.register(<name>)`",
102
+ DeprecationWarning,
103
+ stacklevel=2,
104
+ )
105
+ cls.register(name)
106
+
107
+
108
+ class FontRegistryWarning(UserWarning):
109
+ """FontRegistry warning."""
110
+
111
+
112
+ class FontRegistry(type):
113
+ """Font registry.
114
+
115
+ Store all registered fonts, register during class creation if possible.
116
+ """
117
+
118
+ __slots__ = ()
119
+
120
+ __registered: typing.ClassVar[dict[str, FontRegistry]] = {}
121
+
122
+ def __iter__(cls) -> Iterator[str]:
123
+ """Iterate over registered font names."""
124
+ return iter(cls.__registered)
125
+
126
+ def __getitem__(cls, item: str) -> FontRegistry | None:
127
+ """Get font by name if registered."""
128
+ return cls.__registered.get(item)
129
+
130
+ def __class_getitem__(mcs, item: str) -> FontRegistry | None:
131
+ """Get font by name if registered.
132
+
133
+ This method is needed to get access to font from registry class.
134
+ >>> from urwid.util import set_temporary_encoding
135
+ >>> repr(FontRegistry["a"])
136
+ 'None'
137
+ >>> font = FontRegistry["Thin 3x3"]()
138
+ >>> font.height
139
+ 3
140
+ >>> with set_temporary_encoding("utf-8"):
141
+ ... canvas: TextCanvas = font.render("+")
142
+ >>> b'\\n'.join(canvas.text).decode('utf-8')
143
+ ' \\n ┼\\n '
144
+ """
145
+ return mcs.__registered.get(item)
146
+
147
+ @property
148
+ def registered(cls) -> Sequence[str]:
149
+ """Registered font names in alphabetical order."""
150
+ return tuple(sorted(cls.__registered))
151
+
152
+ @classmethod
153
+ def as_list(mcs) -> list[tuple[str, FontRegistry]]:
154
+ """List of (font name, font class) tuples."""
155
+ return list(mcs.__registered.items())
156
+
157
+ def __new__(
158
+ mcs: type[FontRegistry],
159
+ name: str,
160
+ bases: tuple[type, ...],
161
+ namespace: dict[str, typing.Any],
162
+ **kwds: typing.Any,
163
+ ) -> FontRegistry:
164
+ font_name: str = namespace.setdefault("name", kwds.get("font_name", ""))
165
+ font_class = super().__new__(mcs, name, bases, namespace)
166
+ if font_name:
167
+ if font_name not in mcs.__registered:
168
+ mcs.__registered[font_name] = font_class
169
+ if mcs.__registered[font_name] != font_class:
170
+ warnings.warn(
171
+ f"{font_name!r} is already registered, please override explicit if required or change name",
172
+ FontRegistryWarning,
173
+ stacklevel=2,
174
+ )
175
+ return font_class
176
+
177
+ def register(cls, font_name: str) -> None:
178
+ """Register font explicit.
179
+
180
+ :param font_name: Font name to use in registration.
181
+ """
182
+ if not font_name:
183
+ raise ValueError('"font_name" is not set.')
184
+ cls.__registered[font_name] = cls
185
+
186
+
187
+ get_all_fonts = FontRegistry.as_list
188
+
189
+
190
+ class Font(metaclass=FontRegistry):
191
+ """Font base class."""
192
+
193
+ __slots__ = ("canvas", "char", "utf8_required")
194
+
195
+ height: int
196
+ data: Sequence[str]
197
+ name: str
198
+
199
+ def __init__(self) -> None:
200
+ if not self.height:
201
+ raise ValueError(f'"height" is invalid: {self.height!r}')
202
+ if not self.data:
203
+ raise ValueError(f'"data" is empty: {self.data!r}')
204
+
205
+ self.char: dict[str, tuple[int, list[str]]] = {}
206
+ self.canvas: dict[str, TextCanvas] = {}
207
+ self.utf8_required = False
208
+ if isinstance(self.data, str):
209
+ self.add_glyphs(self._to_text(self.data))
210
+
211
+ else:
212
+ data: Iterable[str] = (self._to_text(block) for block in self.data)
213
+
214
+ for gdata in data:
215
+ self.add_glyphs(gdata)
216
+
217
+ def __repr__(self) -> str:
218
+ return f"{self.__class__.__name__}()"
219
+
220
+ def __str__(self) -> str:
221
+ """Font description."""
222
+ return f"{self.__class__.__name__}():\n {self.height!r}\n {pformat(self.data, indent=4)}"
223
+
224
+ @staticmethod
225
+ def _to_text(
226
+ obj: str | bytes,
227
+ encoding: str = "utf-8",
228
+ errors: Literal["strict", "ignore", "replace"] = "strict",
229
+ ) -> str:
230
+ if isinstance(obj, str):
231
+ return obj
232
+
233
+ if isinstance(obj, bytes):
234
+ warnings.warn(
235
+ "Bytes based fonts are deprecated, please switch to the text one",
236
+ DeprecationWarning,
237
+ stacklevel=3,
238
+ )
239
+ return obj.decode(encoding, errors)
240
+
241
+ raise TypeError(f"{obj!r} is not str|bytes")
242
+
243
+ def add_glyphs(self, gdata: str) -> None:
244
+ d, utf8_required = separate_glyphs(gdata, self.height)
245
+ self.char.update(d)
246
+ self.utf8_required |= utf8_required
247
+
248
+ def characters(self) -> str:
249
+ return "".join(sorted(self.char))
250
+
251
+ def char_width(self, character: str) -> int:
252
+ if character in self.char:
253
+ return self.char[character][0]
254
+ return 0
255
+
256
+ def char_data(self, character: str) -> list[str]:
257
+ return self.char[character][1]
258
+
259
+ def render(self, character: str) -> TextCanvas:
260
+ if character in self.canvas:
261
+ return self.canvas[character]
262
+ width, line = self.char[character]
263
+ byte_lines = []
264
+ character_set_lines = []
265
+ for d in line:
266
+ t, cs = apply_target_encoding(d)
267
+ byte_lines.append(t)
268
+ character_set_lines.append(cs)
269
+
270
+ try:
271
+ canv = TextCanvas(byte_lines, None, character_set_lines, maxcol=width, check_width=False)
272
+ except CanvasError as exc:
273
+ raise CanvasError(f"Failed render of {character!r} from line {line!r}:\n{self}\n:{exc}").with_traceback(
274
+ exc.__traceback__
275
+ ) from exc
276
+
277
+ self.canvas[character] = canv
278
+ return canv
279
+
280
+
281
+ # safe_palette = u"┘┐┌└┼─├┤┴┬│"
282
+ # more_palette = u"═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬○"
283
+ # block_palette = u"▄#█#▀#▌#▐#▖#▗#▘#▙#▚#▛#▜#▝#▞#▟"
284
+
285
+
286
+ class Thin3x3Font(Font):
287
+ name = "Thin 3x3"
288
+ height = 3
289
+ data = (
290
+ """
291
+ 000111222333444555666777888999 !
292
+ ┌─┐ ┐ ┌─┐┌─┐ ┐┌─ ┌─ ┌─┐┌─┐┌─┐ │
293
+ │ │ │ ┌─┘ ─┤└─┼└─┐├─┐ ┼├─┤└─┤ │
294
+ └─┘ ┴ └─ └─┘ ┴ ─┘└─┘ ┴└─┘ ─┘ .
295
+ """,
296
+ r"""
297
+ "###$$$%%%'*++,--.///:;==???[[\\\]]^__`
298
+ " ┼┼┌┼┐O /' /.. _┌─┐┌ \ ┐^ `
299
+ ┼┼└┼┐ / * ┼ ─ / ., _ ┌┘│ \ │
300
+ └┼┘/ O , ./ . └ \ ┘ ──
301
+ """,
302
+ )
303
+
304
+
305
+ class Thin4x3Font(Font):
306
+ name = "Thin 4x3"
307
+ height = 3
308
+ data = (
309
+ *Thin3x3Font.data,
310
+ """
311
+ 0000111122223333444455556666777788889999 ####$$$$
312
+ ┌──┐ ┐ ┌──┐┌──┐ ┐┌── ┌── ┌──┐┌──┐┌──┐ ┼─┼┌┼┼┐
313
+ │ │ │ ┌──┘ ─┤└──┼└──┐├──┐ ┼├──┤└──┤ ┼─┼└┼┼┐
314
+ └──┘ ┴ └── └──┘ ┴ ──┘└──┘ ┴└──┘ ──┘ └┼┼┘
315
+ """,
316
+ )
317
+
318
+
319
+ class Sextant3x3Font(Font):
320
+ name = "Sextant 3x3"
321
+ height = 3
322
+ data = (
323
+ """
324
+ !!!###$$$%%%&&&'''((()))***+++,,,---...///
325
+ ▐ 🬞🬲🬲🬞🬍🬋🬉🬄🬖🬦🬧 🬉 🬞🬅 🬁🬢 🬞🬦🬞 🬦 🬖
326
+ 🬉 🬇🬛🬛🬞🬰🬗🬞🬅🬭🬦🬈🬖 🬉🬏 🬘 🬇🬨🬈🬁🬨🬂 🬭 🬁🬂🬂 🬭 🬞🬅
327
+ 🬁 🬀🬀 🬁 🬂 🬂🬁 🬁 🬁 🬅 🬂
328
+ """,
329
+ """
330
+ 000111222333444555666777888999
331
+ 🬦🬂🬧🬞🬫 🬇🬂🬧🬁🬂🬧 🬞🬫▐🬂🬂🬞🬅🬀🬁🬂🬙🬦🬂🬧🬦🬂🬧
332
+ ▐🬁▐ ▐ 🬞🬅🬀 🬂🬧🬇🬌🬫🬁🬂🬧▐🬂🬧 🬔 🬦🬂🬧 🬂🬙
333
+ 🬂🬀 🬁 🬁🬂🬂🬁🬂🬀 🬁🬁🬂🬀 🬂🬀 🬀 🬂🬀 🬂
334
+ """,
335
+ """
336
+ \"\"\"
337
+ 🬄🬄
338
+
339
+
340
+ """,
341
+ """
342
+ :::;;;<<<===>>>???@@@
343
+ 🬭 🬭 🬖🬀 🬁🬢 🬇🬂🬧🬦🬂🬧
344
+ 🬰 🬰 🬁🬢 🬠🬰🬰 🬖🬀 🬇🬀▐🬉🬅
345
+ 🬂 🬅 🬀 🬁 🬁 🬂🬀
346
+ """,
347
+ """
348
+ AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQ
349
+ 🬞🬅🬢▐🬂🬧🬦🬂🬈▐🬂🬧▐🬂🬂▐🬂🬂🬦🬂🬈▐ ▐ 🬨🬀 ▐▐🬞🬅▐ ▐🬢🬫▐🬢▐🬦🬂🬧▐🬂🬧🬦🬂🬧
350
+ ▐🬋🬫▐🬂🬧▐ 🬞▐ ▐▐🬂 ▐🬂 ▐ 🬨▐🬂🬨 ▐ 🬞 ▐▐🬈🬏▐ ▐🬁▐▐ 🬨▐ ▐▐🬂🬀▐🬇🬘
351
+ 🬁 🬁🬁🬂🬀 🬂🬀🬁🬂🬀🬁🬂🬂🬁 🬂🬂🬁 🬁 🬂🬀 🬂🬀🬁 🬁🬁🬂🬂🬁 🬁🬁 🬁 🬂🬀🬁 🬂🬁
352
+ """,
353
+ """
354
+ RRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[]]]^^^___```
355
+ ▐🬂🬧🬦🬂🬈🬁🬨🬂▐ ▐▐ ▐▐ ▐🬉🬏🬘▐ ▐🬁🬂🬙 🬕🬀 🬂▌🬞🬅🬢 🬈🬏
356
+ ▐🬊🬐🬞🬂🬧 ▐ ▐ ▐🬉🬏🬘▐🬖🬷🬞🬅🬢 🬧🬀🬞🬅 ▌ ▌
357
+ 🬁 🬁 🬂🬀 🬁 🬂🬀 🬁 🬁 🬁🬁 🬁 🬁 🬁🬂🬂 🬂🬀 🬂🬀 🬂🬂🬂
358
+ """,
359
+ """
360
+ \\\\\\
361
+ 🬇🬏
362
+ 🬁🬢
363
+
364
+ """,
365
+ )
366
+
367
+
368
+ class Sextant2x2Font(Font):
369
+ name = "Sextant 2x2"
370
+ height = 2
371
+ data = """
372
+ ..,,%%00112233445566778899
373
+ 🬁🬖▐🬨🬇▌🬁🬗🬠🬸🬦▐▐🬒▐🬭🬁🬙▐🬸▐🬸
374
+ 🬇 🬇🬀🬁🬇🬉🬍 🬄🬉🬋🬇🬍🬁🬊🬇🬅🬉🬍 🬄🬉🬍 🬉
375
+ """
376
+
377
+
378
+ class HalfBlock5x4Font(Font):
379
+ name = "Half Block 5x4"
380
+ height = 4
381
+ data = (
382
+ """
383
+ 00000111112222233333444445555566666777778888899999 !!
384
+ ▄▀▀▄ ▄█ ▄▀▀▄ ▄▀▀▄ ▄ █ █▀▀▀ ▄▀▀ ▀▀▀█ ▄▀▀▄ ▄▀▀▄ █
385
+ █ █ █ ▄▀ ▄▀ █▄▄█ █▄▄ █▄▄ ▐▌ ▀▄▄▀ ▀▄▄█ █
386
+ █ █ █ ▄▀ ▄ █ █ █ █ █ █ █ █ █ ▀
387
+ ▀▀ ▀▀▀ ▀▀▀▀ ▀▀ ▀ ▀▀▀ ▀▀ ▀ ▀▀ ▀▀ ▀
388
+ """,
389
+ '''
390
+ """######$$$$$$%%%%%&&&&&((()))******++++++,,,-----..////::;;;
391
+ █▐▌ █ █ ▄▀█▀▄ ▐▌▐▌ ▄▀▄ █ █ ▄ ▄ ▄ ▐▌
392
+ ▀█▀█▀ ▀▄█▄ █ ▀▄▀ ▐▌ ▐▌ ▄▄█▄▄ ▄▄█▄▄ ▄▄▄▄ █ ▀ ▀
393
+ ▀█▀█▀ ▄ █ █ ▐▌▄ █ ▀▄▌▐▌ ▐▌ ▄▀▄ █ ▐▌ ▀ ▄▀
394
+ ▀ ▀ ▀▀▀ ▀ ▀ ▀▀ ▀ ▀ ▄▀ ▀ ▀
395
+ ''',
396
+ r"""
397
+ <<<<<=====>>>>>?????@@@@@@[[[[\\\\]]]]^^^^____```{{{{||}}}}~~~~''```
398
+ ▄▀ ▀▄ ▄▀▀▄ ▄▀▀▀▄ █▀▀ ▐▌ ▀▀█ ▄▀▄ ▀▄ ▄▀ █ ▀▄ ▄ █ ▄▀
399
+ ▄▀ ▀▀▀▀ ▀▄ ▄▀ █ █▀█ █ █ █ ▄▀ █ ▀▄ ▐▐▌▌
400
+ ▀▄ ▀▀▀▀ ▄▀ ▀ █ ▀▀▀ █ ▐▌ █ █ █ █ ▀
401
+ ▀ ▀ ▀ ▀▀▀ ▀▀▀ ▀ ▀▀▀ ▀▀▀▀ ▀ ▀ ▀
402
+ """,
403
+ """
404
+ AAAAABBBBBCCCCCDDDDDEEEEEFFFFFGGGGGHHHHHIIJJJJJKKKKK
405
+ ▄▀▀▄ █▀▀▄ ▄▀▀▄ █▀▀▄ █▀▀▀ █▀▀▀ ▄▀▀▄ █ █ █ █ █ █
406
+ █▄▄█ █▄▄▀ █ █ █ █▄▄ █▄▄ █ █▄▄█ █ █ █▄▀
407
+ █ █ █ █ █ ▄ █ █ █ █ █ ▀█ █ █ █ ▄ █ █ ▀▄
408
+ ▀ ▀ ▀▀▀ ▀▀ ▀▀▀ ▀▀▀▀ ▀ ▀▀ ▀ ▀ ▀ ▀▀ ▀ ▀
409
+ """,
410
+ """
411
+ LLLLLMMMMMMNNNNNOOOOOPPPPPQQQQQRRRRRSSSSSTTTTT
412
+ █ █▄ ▄█ ██ █ ▄▀▀▄ █▀▀▄ ▄▀▀▄ █▀▀▄ ▄▀▀▄ ▀▀█▀▀
413
+ █ █ ▀ █ █▐▌█ █ █ █▄▄▀ █ █ █▄▄▀ ▀▄▄ █
414
+ █ █ █ █ ██ █ █ █ █ ▌█ █ █ ▄ █ █
415
+ ▀▀▀▀ ▀ ▀ ▀ ▀ ▀▀ ▀ ▀▀▌ ▀ ▀ ▀▀ ▀
416
+ """,
417
+ """
418
+ UUUUUVVVVVVWWWWWWXXXXXXYYYYYYZZZZZ
419
+ █ █ █ █ █ █ █ █ █ █ ▀▀▀█
420
+ █ █ ▐▌ ▐▌ █ ▄ █ ▀▄▀ ▀▄▀ ▄▀
421
+ █ █ █ █ ▐▌█▐▌ ▄▀ ▀▄ █ █
422
+ ▀▀ ▀ ▀ ▀ ▀ ▀ ▀ ▀▀▀▀
423
+ """,
424
+ """
425
+ aaaaabbbbbcccccdddddeeeeeffffggggghhhhhiijjjjkkkkk
426
+ █ █ ▄▀▀ █ ▄ ▄ █
427
+ ▀▀▄ █▀▀▄ ▄▀▀▄ ▄▀▀█ ▄▀▀▄ ▀█▀ ▄▀▀▄ █▀▀▄ ▄ ▄ █ ▄▀
428
+ ▄▀▀█ █ █ █ ▄ █ █ █▀▀ █ ▀▄▄█ █ █ █ █ █▀▄
429
+ ▀▀▀ ▀▀▀ ▀▀ ▀▀▀ ▀▀ ▀ ▄▄▀ ▀ ▀ ▀ ▄▄▀ ▀ ▀
430
+ """,
431
+ """
432
+ llmmmmmmnnnnnooooopppppqqqqqrrrrssssstttt
433
+ █ █
434
+ █ █▀▄▀▄ █▀▀▄ ▄▀▀▄ █▀▀▄ ▄▀▀█ █▀▀ ▄▀▀▀ ▀█▀
435
+ █ █ █ █ █ █ █ █ █ █ █ █ █ ▀▀▄ █
436
+ ▀ ▀ ▀ ▀ ▀ ▀▀ █▀▀ ▀▀█ ▀ ▀▀▀ ▀
437
+ """,
438
+ """
439
+ uuuuuvvvvvwwwwwwxxxxxxyyyyyzzzzz
440
+
441
+ █ █ █ █ █ ▄ █ ▀▄ ▄▀ █ █ ▀▀█▀
442
+ █ █ ▐▌▐▌ ▐▌█▐▌ ▄▀▄ ▀▄▄█ ▄▀
443
+ ▀▀ ▀▀ ▀ ▀ ▀ ▀ ▄▄▀ ▀▀▀▀
444
+ """,
445
+ )
446
+
447
+
448
+ class HalfBlock6x5Font(Font):
449
+ name = "Half Block 6x5"
450
+ height = 5
451
+ data = """
452
+ 000000111111222222333333444444555555666666777777888888999999 ..::////
453
+ ▄▀▀▀▄ ▄█ ▄▀▀▀▄ ▄▀▀▀▄ ▄ █ █▀▀▀▀ ▄▀▀▀ ▀▀▀▀█ ▄▀▀▀▄ ▄▀▀▀▄ █
454
+ █ █ █ █ █ █ █ █ █ ▐▌ █ █ █ █ ▀ ▐▌
455
+ █ █ █ ▄▀ ▀▀▄ ▀▀▀█▀ ▀▀▀▀▄ █▀▀▀▄ █ ▄▀▀▀▄ ▀▀▀█ ▄ █
456
+ █ █ █ ▄▀ ▄ █ █ █ █ █ ▐▌ █ █ █ ▐▌
457
+ ▀▀▀ ▀▀▀ ▀▀▀▀▀ ▀▀▀ ▀ ▀▀▀▀ ▀▀▀ ▀ ▀▀▀ ▀▀▀ ▀ ▀
458
+ """
459
+
460
+
461
+ class HalfBlockHeavy6x5Font(Font):
462
+ name = "Half Block Heavy 6x5"
463
+ height = 5
464
+ data = """
465
+ 000000111111222222333333444444555555666666777777888888999999 ..::////
466
+ ▄███▄ ▐█▌ ▄███▄ ▄███▄ █▌ █████ ▄███▄ █████ ▄███▄ ▄███▄ █▌
467
+ █▌ ▐█ ▀█▌ ▀ ▐█ ▀ ▐█ █▌ █▌ █▌ █▌ █▌ █▌ ▐█ █▌ ▐█ █▌ ▐█
468
+ █▌ ▐█ █▌ ▄█▀ ██▌ █████ ████▄ ████▄ ▐█ ▐███▌ ▀████ █▌
469
+ █▌ ▐█ █▌ ▄█▀ ▄ ▐█ █▌ ▐█ █▌ ▐█ █▌ █▌ ▐█ ▐█ █▌▐█
470
+ ▀███▀ ███▌ █████ ▀███▀ █▌ ████▀ ▀███▀ ▐█ ▀███▀ ▀███▀ █▌ █▌
471
+ """
472
+
473
+
474
+ class Thin6x6Font(Font):
475
+ name = "Thin 6x6"
476
+ height = 6
477
+ data = (
478
+ """
479
+ 000000111111222222333333444444555555666666777777888888999999''
480
+ ┌───┐ ┐ ┌───┐ ┌───┐ ┐ ┌─── ┌─── ┌───┐ ┌───┐ ┌───┐ │
481
+ │ │ │ │ │ ┌ │ │ │ │ │ │ │ │
482
+ │ / │ │ ┌───┘ ─┤ └──┼─ └───┐ ├───┐ ┼ ├───┤ └───┤
483
+ │ │ │ │ │ │ │ │ │ │ │ │ │
484
+ └───┘ ┴ └─── └───┘ ┴ ───┘ └───┘ ┴ └───┘ ───┘
485
+
486
+ """,
487
+ r'''
488
+ !! """######$$$$$$%%%%%%&&&&&&((()))******++++++
489
+ │ ││ ┌ ┌ ┌─┼─┐ ┌┐ / ┌─┐ / \
490
+ │ ─┼─┼─ │ │ └┘ / │ │ │ │ \ / │
491
+ │ │ │ └─┼─┐ / ┌─\┘ │ │ ──X── ──┼──
492
+ │ ─┼─┼─ │ │ / ┌┐ │ \, │ │ / \ │
493
+ . ┘ ┘ └─┼─┘ / └┘ └───\ \ /
494
+
495
+ ''',
496
+ r"""
497
+ ,,-----..//////::;;<<<<=====>>>>??????@@@@@@
498
+ / ┌───┐ ┌───┐
499
+ / . . / ──── \ │ │┌──┤
500
+ ──── / / \ ┌─┘ ││ │
501
+ / . , \ ──── / │ │└──┘
502
+ , . / \ / . └───┘
503
+
504
+ """,
505
+ r"""
506
+ [[\\\\\\]]^^^____``{{||}}~~~~~~
507
+ ┌ \ ┐ /\ \ ┌ │ ┐
508
+ │ \ │ │ │ │ ┌─┐
509
+ │ \ │ ┤ │ ├ └─┘
510
+ │ \ │ │ │ │
511
+ └ \ ┘ ──── └ │ ┘
512
+
513
+ """,
514
+ """
515
+ AAAAAABBBBBBCCCCCCDDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIIJJJJJJ
516
+ ┌───┐ ┬───┐ ┌───┐ ┬───┐ ┬───┐ ┬───┐ ┌───┐ ┬ ┬ ┬ ┬
517
+ │ │ │ │ │ │ │ │ │ │ │ │ │ │
518
+ ├───┤ ├───┤ │ │ │ ├── ├── │ ──┬ ├───┤ │ │
519
+ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┬ │
520
+ ┴ ┴ ┴───┘ └───┘ ┴───┘ ┴───┘ ┴ └───┘ ┴ ┴ ┴ └───┘
521
+
522
+ """,
523
+ """
524
+ KKKKKKLLLLLLMMMMMMNNNNNNOOOOOOPPPPPPQQQQQQRRRRRRSSSSSS
525
+ ┬ ┬ ┬ ┌─┬─┐ ┬─┐ ┬ ┌───┐ ┬───┐ ┌───┐ ┬───┐ ┌───┐
526
+ │ ┌─┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
527
+ ├─┴┐ │ │ │ │ │ │ │ │ │ ├───┘ │ │ ├─┬─┘ └───┐
528
+ │ └┐ │ │ │ │ │ │ │ │ │ │ ┐│ │ └─┐ │
529
+ ┴ ┴ ┴───┘ ┴ ┴ ┴ └─┴ └───┘ ┴ └──┼┘ ┴ ┴ └───┘
530
+
531
+ """,
532
+ """
533
+ TTTTTTUUUUUUVVVVVVWWWWWWXXXXXXYYYYYYZZZZZZ
534
+ ┌─┬─┐ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┌───┐
535
+ │ │ │ │ │ │ │ └┐ ┌┘ │ │ ┌─┘
536
+ │ │ │ │ │ │ │ │ ├─┤ └─┬─┘ ┌┘
537
+ │ │ │ └┐ ┌┘ │ │ │ ┌┘ └┐ │ ┌┘
538
+ ┴ └───┘ └─┘ └─┴─┘ ┴ ┴ ┴ └───┘
539
+
540
+ """,
541
+ """
542
+ aaaaaabbbbbbccccccddddddeeeeeefffgggggghhhhhhiijjj
543
+ ┌─┐
544
+ │ │ │ │ . .
545
+ ┌───┐ ├───┐ ┌───┐ ┌───┤ ┌───┐ ┼ ┌───┐ ├───┐ ┐ ┐
546
+ ┌───┤ │ │ │ │ │ ├───┘ │ │ │ │ │ │ │
547
+ └───┴ └───┘ └───┘ └───┘ └───┘ ┴ └───┤ ┴ ┴ ┴ │
548
+ └───┘ ─┘
549
+ """,
550
+ """
551
+ kkkkkkllmmmmmmnnnnnnooooooppppppqqqqqqrrrrrssssss
552
+
553
+ │ │
554
+ │ ┌─ │ ┬─┬─┐ ┬───┐ ┌───┐ ┌───┐ ┌───┐ ┬──┐ ┌───┐
555
+ ├─┴┐ │ │ │ │ │ │ │ │ │ │ │ │ │ └───┐
556
+ ┴ └─ └ ┴ ┴ ┴ ┴ └───┘ ├───┘ └───┤ ┴ └───┘
557
+ │ │
558
+ """,
559
+ """
560
+ ttttuuuuuuvvvvvvwwwwwwxxxxxxyyyyyyzzzzzz
561
+
562
+
563
+ ─┼─ ┬ ┬ ┬ ┬ ┬ ┬ ─┐ ┌─ ┬ ┬ ────┬
564
+ │ │ │ └┐ ┌┘ │ │ │ ├─┤ │ │ ┌───┘
565
+ └─ └───┴ └─┘ └─┴─┘ ─┘ └─ └───┤ ┴────
566
+ └───┘
567
+ """,
568
+ )
569
+
570
+
571
+ class HalfBlock7x7Font(Font):
572
+ name = "Half Block 7x7"
573
+ height = 7
574
+ data = (
575
+ """
576
+ 0000000111111122222223333333444444455555556666666777777788888889999999'''
577
+ ▄███▄ ▐█▌ ▄███▄ ▄███▄ █▌ ▐█████▌ ▄███▄ ▐█████▌ ▄███▄ ▄███▄ ▐█
578
+ ▐█ █▌ ▀█▌ ▐█ █▌▐█ █▌▐█ █▌ ▐█ ▐█ ▐█ ▐█ █▌▐█ █▌▐█
579
+ ▐█ ▐ █▌ █▌ █▌ ▐██ ▐█████▌▐████▄ ▐████▄ █▌ █████ ▀████▌
580
+ ▐█ ▌ █▌ █▌ ▄█▀ █▌ █▌ █▌▐█ █▌ ▐█ ▐█ █▌ █▌
581
+ ▐█ █▌ █▌ ▄█▀ ▐█ █▌ █▌ █▌▐█ █▌ █▌ ▐█ █▌ █▌
582
+ ▀███▀ ███▌ ▐█████▌ ▀███▀ █▌ ▐████▀ ▀███▀ ▐█ ▀███▀ ▀███▀
583
+
584
+ """,
585
+ '''
586
+ !!! """""#######$$$$$$$%%%%%%%&&&&&&&(((())))*******++++++
587
+ ▐█ ▐█ █▌ ▐█ █▌ █ ▄ █▌ ▄█▄ █▌▐█ ▄▄ ▄▄
588
+ ▐█ ▐█ █▌▐█████▌ ▄███▄ ▐█▌▐█ ▐█ █▌ ▐█ █▌ ▀█▄█▀ ▐█
589
+ ▐█ ▐█ █▌ ▐█▄█▄▄ ▀ █▌ ███ █▌ ▐█ ▐█████▌ ████▌
590
+ ▐█ ▐█████▌ ▀▀█▀█▌ ▐█ ▄ ███▌▄ █▌ ▐█ ▄█▀█▄ ▐█
591
+ ▐█ █▌ ▀███▀ █▌▐█▌▐█ █▌ ▐█ █▌ ▀▀ ▀▀
592
+ ▐█ █ ▐█ ▀ ▀██▀█▌ █▌▐█
593
+
594
+ ''',
595
+ """
596
+ ,,,------.../////:::;;;<<<<<<<======>>>>>>>???????@@@@@@@
597
+ █▌ ▄█▌ ▐█▄ ▄███▄ ▄███▄
598
+ ▐█ ▐█ ▐█ ▄█▀ ▐████▌ ▀█▄ ▐█ █▌▐█ ▄▄█▌
599
+ ▐████▌ █▌ ▐██ ██▌ █▌ ▐█▐█▀█▌
600
+ ▐█ ▐█ ▐█ ▀█▄ ▐████▌ ▄█▀ █▌ ▐█▐█▄█▌
601
+ █▌ ▀ ▀█▌ ▐█▀ ▐█ ▀▀▀
602
+ ▐█ ▐█ ▐█ █▌ ▀███▀
603
+
604
+ """,
605
+ r"""
606
+ [[[[\\\\\]]]]^^^^^^^_____```{{{{{|||}}}}}~~~~~~~```
607
+ ▐██▌▐█ ▐██▌ ▐█▌ ▐█ █▌▐█ ▐█ █▌
608
+ ▐█ █▌ █▌ ▐█ █▌ █▌ █▌ ▐█ ▐█ ▄▄ ▐█
609
+ ▐█ ▐█ █▌▐█ █▌ ▄█▌ ▐█ ▐█▄ ▐▀▀█▄▄▌
610
+ ▐█ █▌ █▌ ▀█▌ ▐█ ▐█▀ ▀▀
611
+ ▐█ ▐█ █▌ █▌ ▐█ ▐█
612
+ ▐██▌ █▌▐██▌ █████ █▌▐█ ▐█
613
+
614
+ """,
615
+ """
616
+ AAAAAAABBBBBBBCCCCCCCDDDDDDDEEEEEEEFFFFFFFGGGGGGGHHHHHHHIIIIJJJJJJJ
617
+ ▄███▄ ▐████▄ ▄███▄ ▐████▄ ▐█████▌▐█████▌ ▄███▄ ▐█ █▌ ██▌ █▌
618
+ ▐█ █▌▐█ █▌▐█ ▐█ █▌▐█ ▐█ ▐█ ▐█ █▌ ▐█ █▌
619
+ ▐█████▌▐█████ ▐█ ▐█ █▌▐████ ▐████ ▐█ ▐█████▌ ▐█ █▌
620
+ ▐█ █▌▐█ █▌▐█ ▐█ █▌▐█ ▐█ ▐█ ██▌▐█ █▌ ▐█ █▌
621
+ ▐█ █▌▐█ █▌▐█ ▐█ █▌▐█ ▐█ ▐█ █▌▐█ █▌ ▐█ ▐█ █▌
622
+ ▐█ █▌▐████▀ ▀███▀ ▐████▀ ▐█████▌▐█ ▀███▀ ▐█ █▌ ██▌ ▀███▀
623
+
624
+ """,
625
+ """
626
+ KKKKKKKLLLLLLLMMMMMMMMNNNNNNNOOOOOOOPPPPPPPQQQQQQQRRRRRRRSSSSSSS
627
+ ▐█ █▌▐█ ▄█▌▐█▄ ▐██ █▌ ▄███▄ ▐████▄ ▄███▄ ▐████▄ ▄███▄
628
+ ▐█ █▌ ▐█ ▐█ ▐▌ █▌▐██▌ █▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌▐█
629
+ ▐█▄█▌ ▐█ ▐█ ▐▌ █▌▐█▐█ █▌▐█ █▌▐████▀ ▐█ █▌▐█████ ▀███▄
630
+ ▐█▀█▌ ▐█ ▐█ █▌▐█ █▌█▌▐█ █▌▐█ ▐█ █▌▐█ █▌ █▌
631
+ ▐█ █▌ ▐█ ▐█ █▌▐█ ▐██▌▐█ █▌▐█ ▐█ █▌█▌▐█ █▌ █▌
632
+ ▐█ █▌▐█████▌▐█ █▌▐█ ██▌ ▀███▀ ▐█ ▀███▀ ▐█ █▌ ▀███▀
633
+ ▀▀
634
+ """,
635
+ """
636
+ TTTTTTTUUUUUUUVVVVVVVWWWWWWWWXXXXXXXYYYYYYYZZZZZZZ
637
+ █████▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌ █▌ █▌▐█████▌
638
+ █▌ ▐█ █▌ █▌ ▐█ ▐█ █▌ ▐█ █▌ ▐█ ▐█ █▌
639
+ █▌ ▐█ █▌ ▐█ █▌ ▐█ █▌ ▐█▌ ▐██ █▌
640
+ █▌ ▐█ █▌ ███ ▐█ ▐▌ █▌ ███ █▌ █▌
641
+ █▌ ▐█ █▌ ▐█▌ ▐█ ▐▌ █▌ █▌ ▐█ █▌ █▌
642
+ █▌ ▀███▀ █ ▀█▌▐█▀ ▐█ █▌ █▌ ▐█████▌
643
+
644
+ """,
645
+ """
646
+ aaaaaaabbbbbbbcccccccdddddddeeeeeeefffffggggggghhhhhhhiiijjjj
647
+ ▐█ █▌ ▄█▌ ▐█ █▌ █▌
648
+ ▐█ █▌ ▐█ ▐█
649
+ ▄███▄ ▐████▄ ▄███▄ ▄████▌ ▄███▄ ▐███ ▄███▄ ▐████▄ ▐█▌ ▐█▌
650
+ ▄▄▄█▌▐█ █▌▐█ ▐█ █▌▐█▄▄▄█▌ ▐█ ▐█ █▌▐█ █▌ █▌ █▌
651
+ ▐█▀▀▀█▌▐█ █▌▐█ ▐█ █▌▐█▀▀▀ ▐█ ▐█▄▄▄█▌▐█ █▌ █▌ █▌
652
+ ▀████▌▐████▀ ▀███▀ ▀████▌ ▀███▀ ▐█ ▀▀▀█▌▐█ █▌ █▌ █▌
653
+ ▀███▀ ▐██
654
+ """,
655
+ """
656
+ kkkkkkkllllmmmmmmmmnnnnnnnooooooopppppppqqqqqqqrrrrrrsssssss
657
+ ▐█ ██
658
+ ▐█ ▐█
659
+ ▐█ ▄█▌ ▐█ ▄█▌▐█▄ ▐████▄ ▄███▄ ▐████▄ ▄████▌ ▄███▌ ▄███▄
660
+ ▐█▄█▀ ▐█ ▐█ ▐▌ █▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌▐█ ▐█▄▄▄
661
+ ▐█▀▀█▄ ▐█ ▐█ ▐▌ █▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌▐█ ▀▀▀█▌
662
+ ▐█ █▌ ▐█▌▐█ █▌▐█ █▌ ▀███▀ ▐████▀ ▀████▌▐█ ▀███▀
663
+ ▐█ █▌
664
+ """,
665
+ """
666
+ tttttuuuuuuuvvvvvvvwwwwwwwwxxxxxxxyyyyyyyzzzzzzz
667
+ █▌
668
+ █▌
669
+ ███▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌▐█████▌
670
+ █▌ ▐█ █▌ █▌ ▐█ ▐█ █▌ ▀█▄█▀ ▐█ █▌ ▄█▀
671
+ █▌ ▐█ █▌ ███ ▐█ ▐▌ █▌ ▄█▀█▄ ▐█▄▄▄█▌ ▄█▀
672
+ █▌ ▀███▀ ▐█▌ ▀█▌▐█▀ ▐█ █▌ ▀▀▀█▌▐█████▌
673
+ ▀███▀
674
+ """,
675
+ )
676
+
677
+
678
+ if __name__ == "__main__":
679
+ all_ascii = frozenset(chr(x) for x in range(32, 127))
680
+ print("Available Fonts: (U) = UTF-8 required")
681
+ print("----------------")
682
+ for n, font_cls in get_all_fonts():
683
+ f = font_cls()
684
+ u = ""
685
+ if f.utf8_required:
686
+ u = "(U)"
687
+ print(f"{n:<20} {u:>3} ", end=" ")
688
+ chars = f.characters()
689
+ font_chars = frozenset(chars)
690
+ if font_chars == all_ascii:
691
+ print("Full ASCII")
692
+ elif font_chars & all_ascii == all_ascii:
693
+ print(f"Full ASCII + {''.join(font_chars ^ all_ascii)!r}")
694
+ else:
695
+ print(f"Characters: {chars!r}")