urwid 2.4.6__cp37-cp37m-win32.whl → 2.5.1__cp37-cp37m-win32.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.
- urwid/__init__.py +2 -0
- urwid/canvas.py +34 -22
- urwid/command_map.py +6 -4
- urwid/display/_posix_raw_display.py +15 -4
- urwid/display/_raw_display_base.py +37 -37
- urwid/display/_win32_raw_display.py +15 -4
- urwid/display/curses.py +2 -4
- urwid/display/html_fragment.py +2 -4
- urwid/display/web.py +2 -4
- urwid/listbox.py +111 -26
- urwid/monitored_list.py +2 -4
- urwid/str_util.pyd +0 -0
- urwid/util.py +1 -2
- urwid/version.py +2 -2
- urwid/vterm.py +3 -3
- urwid/widget/__init__.py +4 -0
- urwid/widget/attr_map.py +5 -3
- urwid/widget/bar_graph.py +9 -9
- urwid/widget/box_adapter.py +6 -7
- urwid/widget/columns.py +17 -10
- urwid/widget/constants.py +169 -63
- urwid/widget/divider.py +27 -3
- urwid/widget/edit.py +1 -1
- urwid/widget/filler.py +9 -8
- urwid/widget/frame.py +9 -1
- urwid/widget/grid_flow.py +4 -6
- urwid/widget/line_box.py +64 -19
- urwid/widget/overlay.py +1 -1
- urwid/widget/padding.py +11 -8
- urwid/widget/pile.py +10 -7
- urwid/widget/popup.py +16 -6
- urwid/widget/progress_bar.py +13 -6
- urwid/widget/scrollable.py +599 -0
- urwid/widget/solid_fill.py +3 -1
- urwid/widget/text.py +1 -1
- urwid/widget/widget.py +51 -113
- urwid/widget/widget_decoration.py +21 -12
- urwid/widget/wimp.py +12 -20
- {urwid-2.4.6.dist-info → urwid-2.5.1.dist-info}/METADATA +7 -2
- urwid-2.5.1.dist-info/RECORD +76 -0
- urwid-2.4.6.dist-info/RECORD +0 -75
- {urwid-2.4.6.dist-info → urwid-2.5.1.dist-info}/COPYING +0 -0
- {urwid-2.4.6.dist-info → urwid-2.5.1.dist-info}/WHEEL +0 -0
- {urwid-2.4.6.dist-info → urwid-2.5.1.dist-info}/top_level.txt +0 -0
urwid/listbox.py
CHANGED
|
@@ -25,6 +25,8 @@ import warnings
|
|
|
25
25
|
from collections.abc import Iterable, Sized
|
|
26
26
|
from contextlib import suppress
|
|
27
27
|
|
|
28
|
+
from typing_extensions import Protocol, runtime_checkable
|
|
29
|
+
|
|
28
30
|
from urwid import signals
|
|
29
31
|
from urwid.canvas import CanvasCombine, SolidCanvas
|
|
30
32
|
from urwid.command_map import Command
|
|
@@ -50,12 +52,30 @@ if typing.TYPE_CHECKING:
|
|
|
50
52
|
from urwid.canvas import CompositeCanvas
|
|
51
53
|
|
|
52
54
|
_T = typing.TypeVar("_T")
|
|
55
|
+
_K = typing.TypeVar("_K")
|
|
53
56
|
|
|
54
57
|
|
|
55
58
|
class ListWalkerError(Exception):
|
|
56
59
|
pass
|
|
57
60
|
|
|
58
61
|
|
|
62
|
+
@runtime_checkable
|
|
63
|
+
class ScrollSupportingBody(Sized, Protocol):
|
|
64
|
+
"""Protocol for ListWalkers that support Scrolling."""
|
|
65
|
+
|
|
66
|
+
def get_focus(self) -> tuple[Widget, _K]: ...
|
|
67
|
+
|
|
68
|
+
def set_focus(self, position: _K) -> None: ...
|
|
69
|
+
|
|
70
|
+
def __getitem__(self, index: _K) -> _T: ...
|
|
71
|
+
|
|
72
|
+
def positions(self, reverse: bool = False) -> Iterable[_K]: ...
|
|
73
|
+
|
|
74
|
+
def get_next(self, position: _K) -> tuple[Widget, _K] | tuple[None, None]: ...
|
|
75
|
+
|
|
76
|
+
def get_prev(self, position: _K) -> tuple[Widget, _K] | tuple[None, None]: ...
|
|
77
|
+
|
|
78
|
+
|
|
59
79
|
class ListWalker(metaclass=signals.MetaSignals):
|
|
60
80
|
signals: typing.ClassVar[list[str]] = ["modified"]
|
|
61
81
|
|
|
@@ -262,6 +282,8 @@ class ListBoxError(Exception):
|
|
|
262
282
|
|
|
263
283
|
|
|
264
284
|
class _Middle(typing.NamedTuple):
|
|
285
|
+
"""Named tuple for ListBox internals."""
|
|
286
|
+
|
|
265
287
|
offset: int
|
|
266
288
|
focus_widget: Widget
|
|
267
289
|
focus_pos: Hashable
|
|
@@ -269,20 +291,30 @@ class _Middle(typing.NamedTuple):
|
|
|
269
291
|
cursor: tuple[int, int] | tuple[int] | None
|
|
270
292
|
|
|
271
293
|
|
|
294
|
+
class _FillItem(typing.NamedTuple):
|
|
295
|
+
"""Named tuple for ListBox internals."""
|
|
296
|
+
|
|
297
|
+
widget: Widget
|
|
298
|
+
position: Hashable
|
|
299
|
+
rows: int
|
|
300
|
+
|
|
301
|
+
|
|
272
302
|
class _TopBottom(typing.NamedTuple):
|
|
303
|
+
"""Named tuple for ListBox internals."""
|
|
304
|
+
|
|
273
305
|
trim: int
|
|
274
|
-
fill: list[
|
|
306
|
+
fill: list[_FillItem]
|
|
275
307
|
|
|
276
308
|
|
|
277
309
|
class ListBox(Widget, WidgetContainerMixin):
|
|
278
310
|
"""
|
|
279
|
-
|
|
311
|
+
Vertically stacked list of widgets
|
|
280
312
|
"""
|
|
281
313
|
|
|
282
314
|
_selectable = True
|
|
283
315
|
_sizing = frozenset([Sizing.BOX])
|
|
284
316
|
|
|
285
|
-
def __init__(self, body: ListWalker) -> None:
|
|
317
|
+
def __init__(self, body: ListWalker | Iterable[Widget]) -> None:
|
|
286
318
|
"""
|
|
287
319
|
:param body: a ListWalker subclass such as :class:`SimpleFocusListWalker`
|
|
288
320
|
that contains widgets to be displayed inside the list box
|
|
@@ -314,6 +346,10 @@ class ListBox(Widget, WidgetContainerMixin):
|
|
|
314
346
|
# variable for delayed valign change used by set_focus_valign
|
|
315
347
|
self.set_focus_valign_pending = None
|
|
316
348
|
|
|
349
|
+
# used for scrollable protocol
|
|
350
|
+
self._rows_max_cached = 0
|
|
351
|
+
self._rendered_size = 0, 0
|
|
352
|
+
|
|
317
353
|
@property
|
|
318
354
|
def body(self) -> ListWalker:
|
|
319
355
|
"""
|
|
@@ -323,7 +359,7 @@ class ListBox(Widget, WidgetContainerMixin):
|
|
|
323
359
|
return self._body
|
|
324
360
|
|
|
325
361
|
@body.setter
|
|
326
|
-
def body(self, body):
|
|
362
|
+
def body(self, body: Iterable[Widget] | ListWalker) -> None:
|
|
327
363
|
with suppress(AttributeError):
|
|
328
364
|
disconnect_signal(self._body, "modified", self._invalidate)
|
|
329
365
|
# _body may be not yet assigned
|
|
@@ -383,12 +419,10 @@ class ListBox(Widget, WidgetContainerMixin):
|
|
|
383
419
|
*cursor coords* or ``None``)
|
|
384
420
|
*top*
|
|
385
421
|
(*# lines to trim off top*,
|
|
386
|
-
list of (*widget*, *position*, *rows*) tuples above focus
|
|
387
|
-
in order from bottom to top)
|
|
422
|
+
list of (*widget*, *position*, *rows*) tuples above focus in order from bottom to top)
|
|
388
423
|
*bottom*
|
|
389
424
|
(*# lines to trim off bottom*,
|
|
390
|
-
list of (*widget*, *position*, *rows*) tuples below focus
|
|
391
|
-
in order from top to bottom)
|
|
425
|
+
list of (*widget*, *position*, *rows*) tuples below focus in order from top to bottom)
|
|
392
426
|
"""
|
|
393
427
|
(maxcol, maxrow) = size
|
|
394
428
|
|
|
@@ -441,7 +475,7 @@ class ListBox(Widget, WidgetContainerMixin):
|
|
|
441
475
|
|
|
442
476
|
p_rows = prev.rows((maxcol,))
|
|
443
477
|
if p_rows: # filter out 0-height widgets
|
|
444
|
-
fill_above.append((prev, pos, p_rows))
|
|
478
|
+
fill_above.append(_FillItem(prev, pos, p_rows))
|
|
445
479
|
if p_rows > fill_lines: # crosses top edge?
|
|
446
480
|
trim_top = p_rows - fill_lines
|
|
447
481
|
break
|
|
@@ -462,7 +496,7 @@ class ListBox(Widget, WidgetContainerMixin):
|
|
|
462
496
|
|
|
463
497
|
n_rows = next_pos.rows((maxcol,))
|
|
464
498
|
if n_rows: # filter out 0-height widgets
|
|
465
|
-
fill_below.append((next_pos, pos, n_rows))
|
|
499
|
+
fill_below.append(_FillItem(next_pos, pos, n_rows))
|
|
466
500
|
if n_rows > fill_lines: # crosses bottom edge?
|
|
467
501
|
trim_bottom = n_rows - fill_lines
|
|
468
502
|
fill_lines -= n_rows
|
|
@@ -488,7 +522,7 @@ class ListBox(Widget, WidgetContainerMixin):
|
|
|
488
522
|
break
|
|
489
523
|
|
|
490
524
|
p_rows = prev.rows((maxcol,))
|
|
491
|
-
fill_above.append((prev, pos, p_rows))
|
|
525
|
+
fill_above.append(_FillItem(prev, pos, p_rows))
|
|
492
526
|
if p_rows > fill_lines: # more than required
|
|
493
527
|
trim_top = p_rows - fill_lines
|
|
494
528
|
offset_rows += fill_lines
|
|
@@ -503,6 +537,54 @@ class ListBox(Widget, WidgetContainerMixin):
|
|
|
503
537
|
_TopBottom(trim_bottom, fill_below),
|
|
504
538
|
)
|
|
505
539
|
|
|
540
|
+
def get_scrollpos(self, size: tuple[int, int] | None = None, focus: bool = False) -> int:
|
|
541
|
+
"""Current scrolling position."""
|
|
542
|
+
if not isinstance(self._body, ScrollSupportingBody):
|
|
543
|
+
raise ListBoxError(f"{self} body do not implement methods required for scrolling protocol")
|
|
544
|
+
|
|
545
|
+
if not self._body:
|
|
546
|
+
return 0
|
|
547
|
+
|
|
548
|
+
if size is not None:
|
|
549
|
+
self._rendered_size = size
|
|
550
|
+
|
|
551
|
+
_, focus_pos = self._body.get_focus()
|
|
552
|
+
|
|
553
|
+
mid, top, bottom = self.calculate_visible(self._rendered_size, focus)
|
|
554
|
+
|
|
555
|
+
start_row = top.trim
|
|
556
|
+
maxcol = self._rendered_size[0]
|
|
557
|
+
|
|
558
|
+
if top.fill:
|
|
559
|
+
pos = top.fill[-1].position
|
|
560
|
+
else:
|
|
561
|
+
pos = mid.focus_pos
|
|
562
|
+
|
|
563
|
+
prev, pos = self._body.get_prev(pos)
|
|
564
|
+
while prev is not None:
|
|
565
|
+
start_row += prev.rows((maxcol,))
|
|
566
|
+
prev, pos = self._body.get_prev(pos)
|
|
567
|
+
|
|
568
|
+
return start_row
|
|
569
|
+
|
|
570
|
+
def rows_max(self, size: tuple[int, int] | None = None, focus: bool = False) -> int:
|
|
571
|
+
"""Scrollable protocol for sized iterable and not wrapped around contents."""
|
|
572
|
+
if not isinstance(self._body, ScrollSupportingBody):
|
|
573
|
+
raise ListBoxError(f"{self} body do not implement methods required for scrolling protocol")
|
|
574
|
+
|
|
575
|
+
if getattr(self._body, "wrap_around", False):
|
|
576
|
+
raise ListBoxError("Body is wrapped around")
|
|
577
|
+
|
|
578
|
+
if size is not None:
|
|
579
|
+
self._rendered_size = size
|
|
580
|
+
|
|
581
|
+
if size or not self._rows_max_cached:
|
|
582
|
+
self._rows_max_cached = sum(
|
|
583
|
+
self._body[position].rows((self._rendered_size[0],), focus) for position in self._body.positions()
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
return self._rows_max_cached
|
|
587
|
+
|
|
506
588
|
def render(self, size: tuple[int, int], focus: bool = False) -> CompositeCanvas | SolidCanvas:
|
|
507
589
|
"""
|
|
508
590
|
Render ListBox and return canvas.
|
|
@@ -511,6 +593,8 @@ class ListBox(Widget, WidgetContainerMixin):
|
|
|
511
593
|
"""
|
|
512
594
|
(maxcol, maxrow) = size
|
|
513
595
|
|
|
596
|
+
self._rendered_size = size
|
|
597
|
+
|
|
514
598
|
middle, top, bottom = self.calculate_visible((maxcol, maxrow), focus=focus)
|
|
515
599
|
if middle is None:
|
|
516
600
|
return SolidCanvas(" ", maxcol, maxrow)
|
|
@@ -615,9 +699,7 @@ class ListBox(Widget, WidgetContainerMixin):
|
|
|
615
699
|
):
|
|
616
700
|
"""Set the focus widget's display offset and inset.
|
|
617
701
|
|
|
618
|
-
:param valign: one of:
|
|
619
|
-
'top', 'middle', 'bottom'
|
|
620
|
-
('relative', percentage 0=top 100=bottom)
|
|
702
|
+
:param valign: one of: 'top', 'middle', 'bottom' ('relative', percentage 0=top 100=bottom)
|
|
621
703
|
"""
|
|
622
704
|
vt, va = normalize_valign(valign, ListBoxError)
|
|
623
705
|
self.set_focus_valign_pending = vt, va
|
|
@@ -756,10 +838,7 @@ class ListBox(Widget, WidgetContainerMixin):
|
|
|
756
838
|
"""
|
|
757
839
|
|
|
758
840
|
def _set_focus_valign_complete(self, size: tuple[int, int], focus: bool) -> None:
|
|
759
|
-
"""
|
|
760
|
-
Finish setting the offset and inset now that we have have a
|
|
761
|
-
maxcol & maxrow.
|
|
762
|
-
"""
|
|
841
|
+
"""Finish setting the offset and inset now that we have have a maxcol & maxrow."""
|
|
763
842
|
(maxcol, maxrow) = size
|
|
764
843
|
vt, va = self.set_focus_valign_pending
|
|
765
844
|
self.set_focus_valign_pending = None
|
|
@@ -784,10 +863,7 @@ class ListBox(Widget, WidgetContainerMixin):
|
|
|
784
863
|
self.shift_focus((maxcol, maxrow), rtop)
|
|
785
864
|
|
|
786
865
|
def _set_focus_first_selectable(self, size: tuple[int, int], focus: bool) -> None:
|
|
787
|
-
"""
|
|
788
|
-
Choose the first visible, selectable widget below the
|
|
789
|
-
current focus as the focus widget.
|
|
790
|
-
"""
|
|
866
|
+
"""Choose the first visible, selectable widget below the current focus as the focus widget."""
|
|
791
867
|
(maxcol, maxrow) = size
|
|
792
868
|
self.set_focus_valign_pending = None
|
|
793
869
|
self.set_focus_pending = None
|
|
@@ -813,9 +889,7 @@ class ListBox(Widget, WidgetContainerMixin):
|
|
|
813
889
|
new_row_offset += rows
|
|
814
890
|
|
|
815
891
|
def _set_focus_complete(self, size: tuple[int, int], focus: bool) -> None:
|
|
816
|
-
"""
|
|
817
|
-
Finish setting the position now that we have maxcol & maxrow.
|
|
818
|
-
"""
|
|
892
|
+
"""Finish setting the position now that we have maxcol & maxrow."""
|
|
819
893
|
(maxcol, maxrow) = size
|
|
820
894
|
self._invalidate()
|
|
821
895
|
if self.set_focus_pending == "first selectable":
|
|
@@ -1716,7 +1790,18 @@ class ListBox(Widget, WidgetContainerMixin):
|
|
|
1716
1790
|
)
|
|
1717
1791
|
return False
|
|
1718
1792
|
|
|
1719
|
-
|
|
1793
|
+
handled = w.mouse_event((maxcol,), event, button, col, row - wrow, focus)
|
|
1794
|
+
if handled:
|
|
1795
|
+
return True
|
|
1796
|
+
|
|
1797
|
+
if is_mouse_press(event):
|
|
1798
|
+
if button == 4:
|
|
1799
|
+
return not self._keypress_up((maxcol, maxrow))
|
|
1800
|
+
|
|
1801
|
+
if button == 5:
|
|
1802
|
+
return not self._keypress_down((maxcol, maxrow))
|
|
1803
|
+
|
|
1804
|
+
return False
|
|
1720
1805
|
|
|
1721
1806
|
def ends_visible(self, size: tuple[int, int], focus: bool = False) -> list[Literal["top", "bottom"]]:
|
|
1722
1807
|
"""
|
urwid/monitored_list.py
CHANGED
|
@@ -337,12 +337,10 @@ class MonitoredFocusList(MonitoredList[_T], typing.Generic[_T]):
|
|
|
337
337
|
self.focus = focus
|
|
338
338
|
|
|
339
339
|
@typing.overload
|
|
340
|
-
def __setitem__(self, i: int, y: _T) -> None:
|
|
341
|
-
...
|
|
340
|
+
def __setitem__(self, i: int, y: _T) -> None: ...
|
|
342
341
|
|
|
343
342
|
@typing.overload
|
|
344
|
-
def __setitem__(self, i: slice, y: Collection[_T]) -> None:
|
|
345
|
-
...
|
|
343
|
+
def __setitem__(self, i: slice, y: Collection[_T]) -> None: ...
|
|
346
344
|
|
|
347
345
|
def __setitem__(self, i: int | slice, y: _T | Collection[_T]) -> None:
|
|
348
346
|
"""
|
urwid/str_util.pyd
CHANGED
|
Binary file
|
urwid/util.py
CHANGED
urwid/version.py
CHANGED
urwid/vterm.py
CHANGED
|
@@ -1437,11 +1437,11 @@ class TermCanvas(Canvas):
|
|
|
1437
1437
|
def content(
|
|
1438
1438
|
self,
|
|
1439
1439
|
trim_left: int = 0,
|
|
1440
|
-
|
|
1440
|
+
trim_top: int = 0,
|
|
1441
1441
|
cols: int | None = None,
|
|
1442
1442
|
rows: int | None = None,
|
|
1443
1443
|
attr=None,
|
|
1444
|
-
):
|
|
1444
|
+
) -> Iterable[list[tuple[object, object, bytes]]]:
|
|
1445
1445
|
if self.scrolling_up == 0:
|
|
1446
1446
|
yield from self.term
|
|
1447
1447
|
else:
|
|
@@ -1669,7 +1669,7 @@ class Terminal(Widget):
|
|
|
1669
1669
|
elif hasattr(self, "old_tios"):
|
|
1670
1670
|
RealTerminal().tty_signal_keys(*self.old_tios)
|
|
1671
1671
|
|
|
1672
|
-
def render(self, size: tuple[int, int], focus: bool = False):
|
|
1672
|
+
def render(self, size: tuple[int, int], focus: bool = False) -> TermCanvas:
|
|
1673
1673
|
if not self.terminated:
|
|
1674
1674
|
self.change_focus(focus)
|
|
1675
1675
|
|
urwid/widget/__init__.py
CHANGED
|
@@ -34,6 +34,7 @@ from .padding import Padding, PaddingError, PaddingWarning, calculate_left_right
|
|
|
34
34
|
from .pile import Pile, PileError, PileWarning
|
|
35
35
|
from .popup import PopUpLauncher, PopUpTarget
|
|
36
36
|
from .progress_bar import ProgressBar
|
|
37
|
+
from .scrollable import Scrollable, ScrollableError, ScrollBar
|
|
37
38
|
from .solid_fill import SolidFill
|
|
38
39
|
from .text import Text, TextError
|
|
39
40
|
from .widget import (
|
|
@@ -151,6 +152,9 @@ __all__ = (
|
|
|
151
152
|
"ProgressBar",
|
|
152
153
|
"WidgetContainerListContentsMixin",
|
|
153
154
|
"WidgetWarning",
|
|
155
|
+
"Scrollable",
|
|
156
|
+
"ScrollableError",
|
|
157
|
+
"ScrollBar",
|
|
154
158
|
)
|
|
155
159
|
|
|
156
160
|
# Backward compatibility
|
urwid/widget/attr_map.py
CHANGED
|
@@ -5,22 +5,24 @@ from collections.abc import Hashable, Mapping
|
|
|
5
5
|
|
|
6
6
|
from urwid.canvas import CompositeCanvas
|
|
7
7
|
|
|
8
|
-
from .widget import
|
|
8
|
+
from .widget import WidgetError, delegate_to_widget_mixin
|
|
9
9
|
from .widget_decoration import WidgetDecoration
|
|
10
10
|
|
|
11
|
+
WrappedWidget = typing.TypeVar("WrappedWidget")
|
|
12
|
+
|
|
11
13
|
|
|
12
14
|
class AttrMapError(WidgetError):
|
|
13
15
|
pass
|
|
14
16
|
|
|
15
17
|
|
|
16
|
-
class AttrMap(delegate_to_widget_mixin("_original_widget"), WidgetDecoration):
|
|
18
|
+
class AttrMap(delegate_to_widget_mixin("_original_widget"), WidgetDecoration[WrappedWidget]):
|
|
17
19
|
"""
|
|
18
20
|
AttrMap is a decoration that maps one set of attributes to another.
|
|
19
21
|
This object will pass all function calls and variable references to the
|
|
20
22
|
wrapped widget.
|
|
21
23
|
"""
|
|
22
24
|
|
|
23
|
-
def __init__(self, w:
|
|
25
|
+
def __init__(self, w: WrappedWidget, attr_map, focus_map=None) -> None:
|
|
24
26
|
"""
|
|
25
27
|
:param w: widget to wrap (stored as self.original_widget)
|
|
26
28
|
:type w: widget
|
urwid/widget/bar_graph.py
CHANGED
|
@@ -5,7 +5,7 @@ import typing
|
|
|
5
5
|
from urwid.canvas import CanvasCombine, CompositeCanvas, SolidCanvas
|
|
6
6
|
from urwid.util import get_encoding_mode
|
|
7
7
|
|
|
8
|
-
from .constants import Sizing
|
|
8
|
+
from .constants import BAR_SYMBOLS, Sizing
|
|
9
9
|
from .text import Text
|
|
10
10
|
from .widget import Widget, WidgetError, WidgetMeta, nocache_widget_render, nocache_widget_render_instance
|
|
11
11
|
|
|
@@ -49,10 +49,10 @@ class BarGraph(Widget, metaclass=BarGraphMeta):
|
|
|
49
49
|
|
|
50
50
|
ignore_focus = True
|
|
51
51
|
|
|
52
|
-
eighths =
|
|
52
|
+
eighths = BAR_SYMBOLS.VERTICAL[:8] # Full height is done by style
|
|
53
53
|
hlines = "_⎺⎻─⎼⎽"
|
|
54
54
|
|
|
55
|
-
def __init__(self, attlist, hatt=None, satt=None):
|
|
55
|
+
def __init__(self, attlist, hatt=None, satt=None) -> None:
|
|
56
56
|
"""
|
|
57
57
|
Create a bar graph with the passed display characteristics.
|
|
58
58
|
see set_segment_attributes for a description of the parameters.
|
|
@@ -134,7 +134,7 @@ class BarGraph(Widget, metaclass=BarGraphMeta):
|
|
|
134
134
|
raise BarGraphError(f"fg ({fg}) not > bg ({bg})")
|
|
135
135
|
self.satt = satt
|
|
136
136
|
|
|
137
|
-
def set_data(self, bardata, top, hlines=None):
|
|
137
|
+
def set_data(self, bardata, top: float, hlines=None) -> None:
|
|
138
138
|
"""
|
|
139
139
|
Store bar data, bargraph top and horizontal line positions.
|
|
140
140
|
|
|
@@ -428,7 +428,7 @@ class BarGraph(Widget, metaclass=BarGraphMeta):
|
|
|
428
428
|
return canv
|
|
429
429
|
|
|
430
430
|
|
|
431
|
-
def calculate_bargraph_display(bardata, top, bar_widths, maxrow: int):
|
|
431
|
+
def calculate_bargraph_display(bardata, top: float, bar_widths: list[int], maxrow: int):
|
|
432
432
|
"""
|
|
433
433
|
Calculate a rendering of the bar graph described by data, bar_widths
|
|
434
434
|
and height.
|
|
@@ -574,7 +574,7 @@ def calculate_bargraph_display(bardata, top, bar_widths, maxrow: int):
|
|
|
574
574
|
class GraphVScale(Widget):
|
|
575
575
|
_sizing = frozenset([Sizing.BOX])
|
|
576
576
|
|
|
577
|
-
def __init__(self, labels, top):
|
|
577
|
+
def __init__(self, labels, top: float) -> None:
|
|
578
578
|
"""
|
|
579
579
|
GraphVScale( [(label1 position, label1 markup),...], top )
|
|
580
580
|
label position -- 0 < position < top for the y position
|
|
@@ -587,7 +587,7 @@ class GraphVScale(Widget):
|
|
|
587
587
|
super().__init__()
|
|
588
588
|
self.set_scale(labels, top)
|
|
589
589
|
|
|
590
|
-
def set_scale(self, labels, top):
|
|
590
|
+
def set_scale(self, labels, top: float) -> None:
|
|
591
591
|
"""
|
|
592
592
|
set_scale( [(label1 position, label1 markup),...], top )
|
|
593
593
|
label position -- 0 < position < top for the y position
|
|
@@ -610,7 +610,7 @@ class GraphVScale(Widget):
|
|
|
610
610
|
"""
|
|
611
611
|
return False
|
|
612
612
|
|
|
613
|
-
def render(self, size: tuple[int, int], focus: bool = False):
|
|
613
|
+
def render(self, size: tuple[int, int], focus: bool = False) -> SolidCanvas | CompositeCanvas:
|
|
614
614
|
"""
|
|
615
615
|
Render GraphVScale.
|
|
616
616
|
"""
|
|
@@ -641,7 +641,7 @@ class GraphVScale(Widget):
|
|
|
641
641
|
return c
|
|
642
642
|
|
|
643
643
|
|
|
644
|
-
def scale_bar_values(bar, top, maxrow: int):
|
|
644
|
+
def scale_bar_values(bar, top: float, maxrow: int) -> list[int]:
|
|
645
645
|
"""
|
|
646
646
|
Return a list of bar values aliased to integer values of maxrow.
|
|
647
647
|
"""
|
urwid/widget/box_adapter.py
CHANGED
|
@@ -8,22 +8,21 @@ from urwid.canvas import CompositeCanvas
|
|
|
8
8
|
from .constants import Sizing
|
|
9
9
|
from .widget_decoration import WidgetDecoration, WidgetError
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
from .widget import Widget
|
|
11
|
+
WrappedWidget = typing.TypeVar("WrappedWidget")
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class BoxAdapterError(WidgetError):
|
|
16
15
|
pass
|
|
17
16
|
|
|
18
17
|
|
|
19
|
-
class BoxAdapter(WidgetDecoration):
|
|
18
|
+
class BoxAdapter(WidgetDecoration[WrappedWidget]):
|
|
20
19
|
"""
|
|
21
20
|
Adapter for using a box widget where a flow widget would usually go
|
|
22
21
|
"""
|
|
23
22
|
|
|
24
23
|
no_cache: typing.ClassVar[list[str]] = ["rows"]
|
|
25
24
|
|
|
26
|
-
def __init__(self, box_widget, height):
|
|
25
|
+
def __init__(self, box_widget: WrappedWidget, height: int) -> None:
|
|
27
26
|
"""
|
|
28
27
|
Create a flow widget that contains a box widget
|
|
29
28
|
|
|
@@ -47,7 +46,7 @@ class BoxAdapter(WidgetDecoration):
|
|
|
47
46
|
|
|
48
47
|
# originally stored as box_widget, keep for compatibility
|
|
49
48
|
@property
|
|
50
|
-
def box_widget(self) ->
|
|
49
|
+
def box_widget(self) -> WrappedWidget:
|
|
51
50
|
warnings.warn(
|
|
52
51
|
"original stored as original_widget, keep for compatibility",
|
|
53
52
|
PendingDeprecationWarning,
|
|
@@ -56,7 +55,7 @@ class BoxAdapter(WidgetDecoration):
|
|
|
56
55
|
return self.original_widget
|
|
57
56
|
|
|
58
57
|
@box_widget.setter
|
|
59
|
-
def box_widget(self, widget:
|
|
58
|
+
def box_widget(self, widget: WrappedWidget) -> None:
|
|
60
59
|
warnings.warn(
|
|
61
60
|
"original stored as original_widget, keep for compatibility",
|
|
62
61
|
PendingDeprecationWarning,
|
|
@@ -104,7 +103,7 @@ class BoxAdapter(WidgetDecoration):
|
|
|
104
103
|
def mouse_event(
|
|
105
104
|
self,
|
|
106
105
|
size: tuple[int],
|
|
107
|
-
event,
|
|
106
|
+
event: str,
|
|
108
107
|
button: int,
|
|
109
108
|
col: int,
|
|
110
109
|
row: int,
|
urwid/widget/columns.py
CHANGED
|
@@ -6,6 +6,7 @@ from itertools import chain, repeat
|
|
|
6
6
|
|
|
7
7
|
import urwid
|
|
8
8
|
from urwid.canvas import Canvas, CanvasJoin, CompositeCanvas, SolidCanvas
|
|
9
|
+
from urwid.command_map import Command
|
|
9
10
|
from urwid.monitored_list import MonitoredFocusList, MonitoredList
|
|
10
11
|
from urwid.util import is_mouse_press
|
|
11
12
|
|
|
@@ -455,9 +456,9 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
|
|
|
455
456
|
|
|
456
457
|
@staticmethod
|
|
457
458
|
def options(
|
|
458
|
-
width_type:
|
|
459
|
-
|
|
460
|
-
|
|
459
|
+
width_type: Literal[
|
|
460
|
+
"pack", "given", "weight", WHSettings.PACK, WHSettings.GIVEN, WHSettings.WEIGHT
|
|
461
|
+
] = WHSettings.WEIGHT,
|
|
461
462
|
width_amount: int | None = 1,
|
|
462
463
|
box_widget: bool = False,
|
|
463
464
|
) -> tuple[Literal[WHSettings.PACK], None, bool] | tuple[Literal[WHSettings.GIVEN, WHSettings.WEIGHT], int, bool]:
|
|
@@ -795,13 +796,16 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
|
|
|
795
796
|
else:
|
|
796
797
|
w_h_args[i] = (0,)
|
|
797
798
|
|
|
798
|
-
elif Sizing.
|
|
799
|
-
|
|
799
|
+
elif Sizing.FLOW in w_sizing or is_box:
|
|
800
|
+
if Sizing.FIXED in w_sizing:
|
|
801
|
+
width, height = widget.pack((), focused)
|
|
802
|
+
else:
|
|
803
|
+
width = self.min_width
|
|
804
|
+
|
|
800
805
|
weighted.setdefault(size_weight, []).append((widget, i, is_box, focused))
|
|
801
806
|
weights.append(size_weight)
|
|
802
807
|
weight_max_sizes.setdefault(size_weight, width)
|
|
803
808
|
weight_max_sizes[size_weight] = max(weight_max_sizes[size_weight], width)
|
|
804
|
-
|
|
805
809
|
else:
|
|
806
810
|
raise ColumnsError(f"Unsupported combination of {size_kind} box={is_box!r} for {widget}")
|
|
807
811
|
|
|
@@ -819,6 +823,9 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
|
|
|
819
823
|
else:
|
|
820
824
|
box.append(i)
|
|
821
825
|
|
|
826
|
+
if not heights:
|
|
827
|
+
raise ColumnsError(f"No height information for pack {self!r} as FIXED")
|
|
828
|
+
|
|
822
829
|
max_height = max(heights.values())
|
|
823
830
|
for idx in box:
|
|
824
831
|
heights[idx] = max_height
|
|
@@ -1019,7 +1026,7 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
|
|
|
1019
1026
|
def mouse_event(
|
|
1020
1027
|
self,
|
|
1021
1028
|
size: tuple[()] | tuple[int] | tuple[int, int],
|
|
1022
|
-
event,
|
|
1029
|
+
event: str,
|
|
1023
1030
|
button: int,
|
|
1024
1031
|
col: int,
|
|
1025
1032
|
row: int,
|
|
@@ -1115,15 +1122,15 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
|
|
|
1115
1122
|
|
|
1116
1123
|
i = self.focus_position
|
|
1117
1124
|
w, _ = self.contents[i]
|
|
1118
|
-
if self._command_map[key] not in {
|
|
1125
|
+
if self._command_map[key] not in {Command.UP, Command.DOWN, Command.PAGE_UP, Command.PAGE_DOWN}:
|
|
1119
1126
|
self.pref_col = None
|
|
1120
1127
|
if w.selectable():
|
|
1121
1128
|
key = w.keypress(size_args[i], key)
|
|
1122
1129
|
|
|
1123
|
-
if self._command_map[key] not in {
|
|
1130
|
+
if self._command_map[key] not in {Command.LEFT, Command.RIGHT}:
|
|
1124
1131
|
return key
|
|
1125
1132
|
|
|
1126
|
-
if self._command_map[key] ==
|
|
1133
|
+
if self._command_map[key] == Command.LEFT:
|
|
1127
1134
|
candidates = list(range(i - 1, -1, -1)) # count backwards to 0
|
|
1128
1135
|
else: # key == 'right'
|
|
1129
1136
|
candidates = list(range(i + 1, len(self.contents)))
|