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/widget/line_box.py
CHANGED
|
@@ -3,33 +3,38 @@ from __future__ import annotations
|
|
|
3
3
|
import typing
|
|
4
4
|
|
|
5
5
|
from .columns import Columns
|
|
6
|
-
from .constants import Align, WHSettings
|
|
6
|
+
from .constants import BOX_SYMBOLS, Align, WHSettings
|
|
7
7
|
from .divider import Divider
|
|
8
8
|
from .pile import Pile
|
|
9
9
|
from .solid_fill import SolidFill
|
|
10
10
|
from .text import Text
|
|
11
|
-
from .
|
|
12
|
-
from .widget_decoration import WidgetDecoration
|
|
11
|
+
from .widget_decoration import WidgetDecoration, delegate_to_widget_mixin
|
|
13
12
|
|
|
14
13
|
if typing.TYPE_CHECKING:
|
|
15
14
|
from typing_extensions import Literal
|
|
16
15
|
|
|
16
|
+
from .widget import Widget
|
|
17
|
+
|
|
18
|
+
WrappedWidget = typing.TypeVar("WrappedWidget")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class LineBox(WidgetDecoration[WrappedWidget], delegate_to_widget_mixin("_wrapped_widget")):
|
|
22
|
+
Symbols = BOX_SYMBOLS
|
|
17
23
|
|
|
18
|
-
class LineBox(WidgetDecoration, WidgetWrap):
|
|
19
24
|
def __init__(
|
|
20
25
|
self,
|
|
21
|
-
original_widget:
|
|
26
|
+
original_widget: WrappedWidget,
|
|
22
27
|
title: str = "",
|
|
23
28
|
title_align: Literal["left", "center", "right"] | Align = Align.CENTER,
|
|
24
29
|
title_attr=None,
|
|
25
|
-
tlcorner: str =
|
|
26
|
-
tline: str =
|
|
27
|
-
lline: str =
|
|
28
|
-
trcorner: str =
|
|
29
|
-
blcorner: str =
|
|
30
|
-
rline: str =
|
|
31
|
-
bline: str =
|
|
32
|
-
brcorner: str =
|
|
30
|
+
tlcorner: str = BOX_SYMBOLS.LIGHT.TOP_LEFT,
|
|
31
|
+
tline: str = BOX_SYMBOLS.LIGHT.HORIZONTAL,
|
|
32
|
+
lline: str = BOX_SYMBOLS.LIGHT.VERTICAL,
|
|
33
|
+
trcorner: str = BOX_SYMBOLS.LIGHT.TOP_RIGHT,
|
|
34
|
+
blcorner: str = BOX_SYMBOLS.LIGHT.BOTTOM_LEFT,
|
|
35
|
+
rline: str = BOX_SYMBOLS.LIGHT.VERTICAL,
|
|
36
|
+
bline: str = BOX_SYMBOLS.LIGHT.HORIZONTAL,
|
|
37
|
+
brcorner: str = BOX_SYMBOLS.LIGHT.BOTTOM_RIGHT,
|
|
33
38
|
) -> None:
|
|
34
39
|
"""
|
|
35
40
|
Draw a line around original_widget.
|
|
@@ -55,6 +60,44 @@ class LineBox(WidgetDecoration, WidgetWrap):
|
|
|
55
60
|
If empty string is specified for one of the lines/corners, then no character will be output there.
|
|
56
61
|
If no top/bottom/left/right lines - whole lines will be omitted.
|
|
57
62
|
This allows for seamless use of adjoining LineBoxes.
|
|
63
|
+
|
|
64
|
+
Class attribute `Symbols` can be used as source for standard lines:
|
|
65
|
+
|
|
66
|
+
>>> print(LineBox(Text("Some text")).render(()))
|
|
67
|
+
┌─────────┐
|
|
68
|
+
│Some text│
|
|
69
|
+
└─────────┘
|
|
70
|
+
>>> print(
|
|
71
|
+
... LineBox(
|
|
72
|
+
... Text("Some text"),
|
|
73
|
+
... tlcorner=LineBox.Symbols.LIGHT.TOP_LEFT_ROUNDED,
|
|
74
|
+
... trcorner=LineBox.Symbols.LIGHT.TOP_RIGHT_ROUNDED,
|
|
75
|
+
... blcorner=LineBox.Symbols.LIGHT.BOTTOM_LEFT_ROUNDED,
|
|
76
|
+
... brcorner=LineBox.Symbols.LIGHT.BOTTOM_RIGHT_ROUNDED,
|
|
77
|
+
... ).render(())
|
|
78
|
+
... )
|
|
79
|
+
╭─────────╮
|
|
80
|
+
│Some text│
|
|
81
|
+
╰─────────╯
|
|
82
|
+
>>> print(
|
|
83
|
+
... LineBox(
|
|
84
|
+
... Text("Some text"),
|
|
85
|
+
... tline=LineBox.Symbols.HEAVY.HORIZONTAL,
|
|
86
|
+
... bline=LineBox.Symbols.HEAVY.HORIZONTAL,
|
|
87
|
+
... lline=LineBox.Symbols.HEAVY.VERTICAL,
|
|
88
|
+
... rline=LineBox.Symbols.HEAVY.VERTICAL,
|
|
89
|
+
... tlcorner=LineBox.Symbols.HEAVY.TOP_LEFT,
|
|
90
|
+
... trcorner=LineBox.Symbols.HEAVY.TOP_RIGHT,
|
|
91
|
+
... blcorner=LineBox.Symbols.HEAVY.BOTTOM_LEFT,
|
|
92
|
+
... brcorner=LineBox.Symbols.HEAVY.BOTTOM_RIGHT,
|
|
93
|
+
... ).render(())
|
|
94
|
+
... )
|
|
95
|
+
┏━━━━━━━━━┓
|
|
96
|
+
┃Some text┃
|
|
97
|
+
┗━━━━━━━━━┛
|
|
98
|
+
|
|
99
|
+
To make Table constructions, some lineboxes need to be drawn without sides
|
|
100
|
+
and T or CROSS symbols used for corners of cells.
|
|
58
101
|
"""
|
|
59
102
|
|
|
60
103
|
w_lline = SolidFill(lline)
|
|
@@ -115,15 +158,17 @@ class LineBox(WidgetDecoration, WidgetWrap):
|
|
|
115
158
|
|
|
116
159
|
pile_widgets = []
|
|
117
160
|
if top:
|
|
118
|
-
pile_widgets.append((
|
|
161
|
+
pile_widgets.append((WHSettings.PACK, top))
|
|
119
162
|
pile_widgets.append(middle)
|
|
120
|
-
focus_pos = len(pile_widgets) - 1
|
|
121
163
|
if bottom:
|
|
122
|
-
pile_widgets.append((
|
|
123
|
-
|
|
164
|
+
pile_widgets.append((WHSettings.PACK, bottom))
|
|
165
|
+
|
|
166
|
+
self._wrapped_widget = Pile(pile_widgets, focus_item=middle)
|
|
167
|
+
|
|
168
|
+
super().__init__(original_widget)
|
|
124
169
|
|
|
125
|
-
|
|
126
|
-
|
|
170
|
+
def _w(self) -> Pile:
|
|
171
|
+
return self._wrapped_widget
|
|
127
172
|
|
|
128
173
|
def format_title(self, text: str) -> str:
|
|
129
174
|
if text:
|
urwid/widget/overlay.py
CHANGED
urwid/widget/padding.py
CHANGED
|
@@ -22,7 +22,8 @@ from .widget_decoration import WidgetDecoration, WidgetError, WidgetWarning
|
|
|
22
22
|
if typing.TYPE_CHECKING:
|
|
23
23
|
from typing_extensions import Literal
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
|
|
26
|
+
WrappedWidget = typing.TypeVar("WrappedWidget")
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
class PaddingError(WidgetError):
|
|
@@ -33,10 +34,10 @@ class PaddingWarning(WidgetWarning):
|
|
|
33
34
|
"""Padding related warnings."""
|
|
34
35
|
|
|
35
36
|
|
|
36
|
-
class Padding(WidgetDecoration):
|
|
37
|
+
class Padding(WidgetDecoration[WrappedWidget]):
|
|
37
38
|
def __init__(
|
|
38
39
|
self,
|
|
39
|
-
w:
|
|
40
|
+
w: WrappedWidget,
|
|
40
41
|
align: (
|
|
41
42
|
Literal["left", "center", "right"] | Align | tuple[Literal["relative", WHSettings.RELATIVE], int]
|
|
42
43
|
) = Align.LEFT,
|
|
@@ -48,7 +49,7 @@ class Padding(WidgetDecoration):
|
|
|
48
49
|
min_width: int | None = None,
|
|
49
50
|
left: int = 0,
|
|
50
51
|
right: int = 0,
|
|
51
|
-
):
|
|
52
|
+
) -> None:
|
|
52
53
|
"""
|
|
53
54
|
:param w: a box, flow or fixed widget to pad on the left and/or right
|
|
54
55
|
this widget is stored as self.original_widget
|
|
@@ -237,9 +238,11 @@ class Padding(WidgetDecoration):
|
|
|
237
238
|
@width.setter
|
|
238
239
|
def width(
|
|
239
240
|
self,
|
|
240
|
-
width:
|
|
241
|
-
|
|
242
|
-
|
|
241
|
+
width: (
|
|
242
|
+
Literal["clip", "pack", WHSettings.CLIP, WHSettings.PACK]
|
|
243
|
+
| int
|
|
244
|
+
| tuple[Literal["relative", WHSettings.RELATIVE], int]
|
|
245
|
+
),
|
|
243
246
|
) -> None:
|
|
244
247
|
"""
|
|
245
248
|
Set the padding width.
|
|
@@ -471,7 +474,7 @@ class Padding(WidgetDecoration):
|
|
|
471
474
|
def mouse_event(
|
|
472
475
|
self,
|
|
473
476
|
size: tuple[()] | tuple[int] | tuple[int, int],
|
|
474
|
-
event,
|
|
477
|
+
event: str,
|
|
475
478
|
button: int,
|
|
476
479
|
x: int,
|
|
477
480
|
y: int,
|
urwid/widget/pile.py
CHANGED
|
@@ -5,6 +5,7 @@ import warnings
|
|
|
5
5
|
from itertools import chain, repeat
|
|
6
6
|
|
|
7
7
|
from urwid.canvas import CanvasCombine, CompositeCanvas, SolidCanvas
|
|
8
|
+
from urwid.command_map import Command
|
|
8
9
|
from urwid.monitored_list import MonitoredFocusList, MonitoredList
|
|
9
10
|
from urwid.util import is_mouse_press
|
|
10
11
|
|
|
@@ -852,7 +853,9 @@ class Pile(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
|
|
|
852
853
|
|
|
853
854
|
def keypress(self, size: tuple[()] | tuple[int] | tuple[int, int], key: str) -> str | None:
|
|
854
855
|
"""Pass the keypress to the widget in focus.
|
|
855
|
-
|
|
856
|
+
|
|
857
|
+
Unhandled 'up' and 'down' keys may cause a focus change.
|
|
858
|
+
"""
|
|
856
859
|
if not self.contents:
|
|
857
860
|
return key
|
|
858
861
|
|
|
@@ -860,10 +863,10 @@ class Pile(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
|
|
|
860
863
|
_widths, heights, size_args = self.get_rows_sizes(size, focus=self.selectable())
|
|
861
864
|
if self.selectable():
|
|
862
865
|
key = self.focus.keypress(size_args[i], key)
|
|
863
|
-
if self._command_map[key] not in {
|
|
866
|
+
if self._command_map[key] not in {Command.UP, Command.DOWN}:
|
|
864
867
|
return key
|
|
865
868
|
|
|
866
|
-
if self._command_map[key] ==
|
|
869
|
+
if self._command_map[key] == Command.UP:
|
|
867
870
|
candidates = tuple(range(i - 1, -1, -1)) # count backwards to 0
|
|
868
871
|
else: # self._command_map[key] == 'cursor down'
|
|
869
872
|
candidates = tuple(range(i + 1, len(self.contents)))
|
|
@@ -878,7 +881,7 @@ class Pile(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
|
|
|
878
881
|
return None
|
|
879
882
|
|
|
880
883
|
rows = heights[j]
|
|
881
|
-
if self._command_map[key] ==
|
|
884
|
+
if self._command_map[key] == Command.UP:
|
|
882
885
|
rowlist = tuple(range(rows - 1, -1, -1))
|
|
883
886
|
else: # self._command_map[key] == 'cursor down'
|
|
884
887
|
rowlist = tuple(range(rows))
|
|
@@ -934,14 +937,14 @@ class Pile(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
|
|
|
934
937
|
def mouse_event(
|
|
935
938
|
self,
|
|
936
939
|
size: tuple[()] | tuple[int] | tuple[int, int],
|
|
937
|
-
event,
|
|
940
|
+
event: str,
|
|
938
941
|
button: int,
|
|
939
942
|
col: int,
|
|
940
943
|
row: int,
|
|
941
944
|
focus: bool,
|
|
942
945
|
) -> bool | None:
|
|
943
|
-
"""
|
|
944
|
-
|
|
946
|
+
"""Pass the event to the contained widget.
|
|
947
|
+
|
|
945
948
|
May change focus on button 1 press.
|
|
946
949
|
"""
|
|
947
950
|
wrow = 0
|
urwid/widget/popup.py
CHANGED
|
@@ -34,13 +34,15 @@ if typing.TYPE_CHECKING:
|
|
|
34
34
|
|
|
35
35
|
from .widget import Widget
|
|
36
36
|
|
|
37
|
+
WrappedWidget = typing.TypeVar("WrappedWidget")
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
|
|
40
|
+
class PopUpLauncher(delegate_to_widget_mixin("_original_widget"), WidgetDecoration[WrappedWidget]):
|
|
41
|
+
def __init__(self, original_widget: [WrappedWidget]) -> None:
|
|
40
42
|
super().__init__(original_widget)
|
|
41
43
|
self._pop_up_widget = None
|
|
42
44
|
|
|
43
|
-
def create_pop_up(self):
|
|
45
|
+
def create_pop_up(self) -> Widget:
|
|
44
46
|
"""
|
|
45
47
|
Subclass must override this method and return a widget
|
|
46
48
|
to be used for the pop-up. This method is called once each time
|
|
@@ -74,13 +76,13 @@ class PopUpLauncher(delegate_to_widget_mixin("_original_widget"), WidgetDecorati
|
|
|
74
76
|
return canv
|
|
75
77
|
|
|
76
78
|
|
|
77
|
-
class PopUpTarget(WidgetDecoration):
|
|
79
|
+
class PopUpTarget(WidgetDecoration[WrappedWidget]):
|
|
78
80
|
# FIXME: this whole class is a terrible hack and must be fixed
|
|
79
81
|
# when layout and rendering are separated
|
|
80
82
|
_sizing = frozenset((Sizing.BOX,))
|
|
81
83
|
_selectable = True
|
|
82
84
|
|
|
83
|
-
def __init__(self, original_widget:
|
|
85
|
+
def __init__(self, original_widget: WrappedWidget) -> None:
|
|
84
86
|
super().__init__(original_widget)
|
|
85
87
|
self._pop_up = None
|
|
86
88
|
self._current_widget = self._original_widget
|
|
@@ -132,7 +134,15 @@ class PopUpTarget(WidgetDecoration):
|
|
|
132
134
|
self._update_overlay(size, True)
|
|
133
135
|
return self._current_widget.move_cursor_to_coords(size, x, y)
|
|
134
136
|
|
|
135
|
-
def mouse_event(
|
|
137
|
+
def mouse_event(
|
|
138
|
+
self,
|
|
139
|
+
size: tuple[int, int],
|
|
140
|
+
event: str,
|
|
141
|
+
button: int,
|
|
142
|
+
x: int,
|
|
143
|
+
y: int,
|
|
144
|
+
focus: bool,
|
|
145
|
+
) -> bool | None:
|
|
136
146
|
self._update_overlay(size, focus)
|
|
137
147
|
return self._current_widget.mouse_event(size, event, button, x, y, focus)
|
|
138
148
|
|
urwid/widget/progress_bar.py
CHANGED
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import typing
|
|
4
4
|
import warnings
|
|
5
5
|
|
|
6
|
-
from .constants import Align, Sizing, WrapMode
|
|
6
|
+
from .constants import BAR_SYMBOLS, Align, Sizing, WrapMode
|
|
7
7
|
from .text import Text
|
|
8
8
|
from .widget import Widget
|
|
9
9
|
|
|
@@ -14,7 +14,7 @@ if typing.TYPE_CHECKING:
|
|
|
14
14
|
class ProgressBar(Widget):
|
|
15
15
|
_sizing = frozenset([Sizing.FLOW])
|
|
16
16
|
|
|
17
|
-
eighths =
|
|
17
|
+
eighths = BAR_SYMBOLS.HORISONTAL[:8] # Full width line is made by style
|
|
18
18
|
|
|
19
19
|
text_align = Align.CENTER
|
|
20
20
|
|
|
@@ -26,9 +26,10 @@ class ProgressBar(Widget):
|
|
|
26
26
|
:param done: progress amount at 100%
|
|
27
27
|
:param satt: display attribute for smoothed part of bar where the
|
|
28
28
|
foreground of satt corresponds to the normal part and the
|
|
29
|
-
background corresponds to the complete part.
|
|
30
|
-
is ``None`` then no smoothing will be done.
|
|
29
|
+
background corresponds to the complete part.
|
|
30
|
+
If satt is ``None`` then no smoothing will be done.
|
|
31
31
|
|
|
32
|
+
>>> from urwid import LineBox
|
|
32
33
|
>>> pb = ProgressBar('a', 'b')
|
|
33
34
|
>>> pb
|
|
34
35
|
<ProgressBar flow widget>
|
|
@@ -50,6 +51,12 @@ class ProgressBar(Widget):
|
|
|
50
51
|
>>> for x in range(101):
|
|
51
52
|
... cpb2.set_completion(x)
|
|
52
53
|
... s = cpb2.render((10, ))
|
|
54
|
+
>>> pb = ProgressBar('a', 'b', satt='c')
|
|
55
|
+
>>> pb.set_completion(34.56)
|
|
56
|
+
>>> print(LineBox(pb).render((20,)))
|
|
57
|
+
┌──────────────────┐
|
|
58
|
+
│ ▏34 % │
|
|
59
|
+
└──────────────────┘
|
|
53
60
|
"""
|
|
54
61
|
super().__init__()
|
|
55
62
|
self.normal = normal
|
|
@@ -58,7 +65,7 @@ class ProgressBar(Widget):
|
|
|
58
65
|
self._done = done
|
|
59
66
|
self.satt = satt
|
|
60
67
|
|
|
61
|
-
def set_completion(self, current):
|
|
68
|
+
def set_completion(self, current: int) -> None:
|
|
62
69
|
"""
|
|
63
70
|
current -- current progress
|
|
64
71
|
"""
|
|
@@ -88,7 +95,7 @@ class ProgressBar(Widget):
|
|
|
88
95
|
)
|
|
89
96
|
self.done = done
|
|
90
97
|
|
|
91
|
-
def rows(self, size, focus: bool = False) -> int:
|
|
98
|
+
def rows(self, size: tuple[int], focus: bool = False) -> int:
|
|
92
99
|
return 1
|
|
93
100
|
|
|
94
101
|
def get_text(self) -> str:
|