urwid 3.0.3__py3-none-any.whl → 3.0.5__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.
- urwid/__init__.py +29 -16
- urwid/display/__init__.py +53 -48
- urwid/display/_raw_display_base.py +2 -2
- urwid/display/common.py +17 -17
- urwid/display/curses.py +1 -3
- urwid/display/web.py +1 -1
- urwid/event_loop/asyncio_loop.py +3 -1
- urwid/event_loop/main_loop.py +5 -5
- urwid/font.py +6 -4
- urwid/numedit.py +65 -65
- urwid/signals.py +17 -26
- urwid/split_repr.py +9 -3
- urwid/str_util.py +90 -42
- urwid/text_layout.py +8 -6
- urwid/util.py +1 -1
- urwid/version.py +2 -2
- urwid/vterm.py +2 -2
- urwid/widget/attr_map.py +10 -10
- urwid/widget/attr_wrap.py +3 -3
- urwid/widget/big_text.py +0 -3
- urwid/widget/box_adapter.py +2 -2
- urwid/widget/divider.py +6 -6
- urwid/widget/edit.py +42 -42
- urwid/widget/filler.py +8 -8
- urwid/widget/frame.py +3 -3
- urwid/widget/line_box.py +19 -19
- urwid/widget/listbox.py +1 -1
- urwid/widget/monitored_list.py +69 -45
- urwid/widget/padding.py +20 -20
- urwid/widget/progress_bar.py +7 -7
- urwid/widget/solid_fill.py +3 -3
- urwid/widget/text.py +44 -30
- urwid/widget/widget.py +6 -6
- urwid/widget/widget_decoration.py +2 -2
- urwid/widget/wimp.py +61 -61
- {urwid-3.0.3.dist-info → urwid-3.0.5.dist-info}/METADATA +6 -5
- urwid-3.0.5.dist-info/RECORD +74 -0
- {urwid-3.0.3.dist-info → urwid-3.0.5.dist-info}/WHEEL +1 -1
- urwid-3.0.3.dist-info/RECORD +0 -74
- {urwid-3.0.3.dist-info → urwid-3.0.5.dist-info}/licenses/COPYING +0 -0
- {urwid-3.0.3.dist-info → urwid-3.0.5.dist-info}/top_level.txt +0 -0
urwid/widget/progress_bar.py
CHANGED
|
@@ -38,7 +38,7 @@ class ProgressBar(Widget):
|
|
|
38
38
|
If satt is ``None`` then no smoothing will be done.
|
|
39
39
|
|
|
40
40
|
>>> from urwid import LineBox
|
|
41
|
-
>>> pb = ProgressBar(
|
|
41
|
+
>>> pb = ProgressBar("a", "b")
|
|
42
42
|
>>> pb
|
|
43
43
|
<ProgressBar flow widget>
|
|
44
44
|
>>> print(pb.get_text())
|
|
@@ -48,18 +48,18 @@ class ProgressBar(Widget):
|
|
|
48
48
|
34 %
|
|
49
49
|
>>> class CustomProgressBar(ProgressBar):
|
|
50
50
|
... def get_text(self):
|
|
51
|
-
... return
|
|
52
|
-
>>> cpb = CustomProgressBar(
|
|
51
|
+
... return "Foobar"
|
|
52
|
+
>>> cpb = CustomProgressBar("a", "b")
|
|
53
53
|
>>> print(cpb.get_text())
|
|
54
54
|
Foobar
|
|
55
55
|
>>> for x in range(101):
|
|
56
56
|
... cpb.set_completion(x)
|
|
57
|
-
... s = cpb.render((10,
|
|
58
|
-
>>> cpb2 = CustomProgressBar(
|
|
57
|
+
... s = cpb.render((10,))
|
|
58
|
+
>>> cpb2 = CustomProgressBar("a", "b", satt="c")
|
|
59
59
|
>>> for x in range(101):
|
|
60
60
|
... cpb2.set_completion(x)
|
|
61
|
-
... s = cpb2.render((10,
|
|
62
|
-
>>> pb = ProgressBar(
|
|
61
|
+
... s = cpb2.render((10,))
|
|
62
|
+
>>> pb = ProgressBar("a", "b", satt="c")
|
|
63
63
|
>>> pb.set_completion(34.56)
|
|
64
64
|
>>> print(LineBox(pb).render((20,)))
|
|
65
65
|
┌──────────────────┐
|
urwid/widget/solid_fill.py
CHANGED
|
@@ -22,7 +22,7 @@ class SolidFill(Widget):
|
|
|
22
22
|
:param fill_char: character to fill area with
|
|
23
23
|
:type fill_char: bytes or unicode
|
|
24
24
|
|
|
25
|
-
>>> SolidFill(
|
|
25
|
+
>>> SolidFill("8")
|
|
26
26
|
<SolidFill box widget '8'>
|
|
27
27
|
"""
|
|
28
28
|
super().__init__()
|
|
@@ -39,9 +39,9 @@ class SolidFill(Widget):
|
|
|
39
39
|
"""
|
|
40
40
|
Render the Fill as a canvas and return it.
|
|
41
41
|
|
|
42
|
-
>>> SolidFill().render((4,2)).text
|
|
42
|
+
>>> SolidFill().render((4, 2)).text # ... = b in Python 3
|
|
43
43
|
[...' ', ...' ']
|
|
44
|
-
>>> SolidFill(
|
|
44
|
+
>>> SolidFill("#").render((5, 3)).text
|
|
45
45
|
[...'#####', ...'#####', ...'#####']
|
|
46
46
|
"""
|
|
47
47
|
maxcol, maxrow = size
|
urwid/widget/text.py
CHANGED
|
@@ -61,9 +61,9 @@ class Text(Widget):
|
|
|
61
61
|
:param layout: defaults to a shared :class:`StandardTextLayout` instance
|
|
62
62
|
:type layout: text layout instance
|
|
63
63
|
|
|
64
|
-
>>> Text(
|
|
64
|
+
>>> Text("Hello")
|
|
65
65
|
<Text fixed/flow widget 'Hello'>
|
|
66
|
-
>>> t = Text((
|
|
66
|
+
>>> t = Text(("bold", "stuff"), "right", "any")
|
|
67
67
|
>>> t
|
|
68
68
|
<Text fixed/flow widget 'stuff' align='right' wrap='any'>
|
|
69
69
|
>>> print(t.text)
|
|
@@ -73,6 +73,7 @@ class Text(Widget):
|
|
|
73
73
|
"""
|
|
74
74
|
super().__init__()
|
|
75
75
|
self._cache_maxcol: int | None = None
|
|
76
|
+
self._layout: text_layout.TextLayout = layout or text_layout.default_layout
|
|
76
77
|
self.set_text(markup)
|
|
77
78
|
self.set_layout(align, wrap, layout)
|
|
78
79
|
|
|
@@ -108,13 +109,13 @@ class Text(Widget):
|
|
|
108
109
|
:param markup: see :class:`Text` for description.
|
|
109
110
|
:type markup: text markup
|
|
110
111
|
|
|
111
|
-
>>> t = Text(
|
|
112
|
+
>>> t = Text("foo")
|
|
112
113
|
>>> print(t.text)
|
|
113
114
|
foo
|
|
114
|
-
>>> t.set_text(
|
|
115
|
+
>>> t.set_text("bar")
|
|
115
116
|
>>> print(t.text)
|
|
116
117
|
bar
|
|
117
|
-
>>> t.text =
|
|
118
|
+
>>> t.text = "baz" # not supported because text stores text but set_text() takes markup
|
|
118
119
|
Traceback (most recent call last):
|
|
119
120
|
AttributeError: can't set attribute
|
|
120
121
|
"""
|
|
@@ -132,11 +133,11 @@ class Text(Widget):
|
|
|
132
133
|
run length encoded display attributes for *text*, eg.
|
|
133
134
|
``[('attr1', 10), ('attr2', 5)]``
|
|
134
135
|
|
|
135
|
-
>>> Text(
|
|
136
|
+
>>> Text("Hello").get_text() # ... = u in Python 2
|
|
136
137
|
(...'Hello', [])
|
|
137
|
-
>>> Text((
|
|
138
|
+
>>> Text(("bright", "Headline")).get_text()
|
|
138
139
|
(...'Headline', [('bright', 8)])
|
|
139
|
-
>>> Text([(
|
|
140
|
+
>>> Text([("a", "one"), "two", ("b", "three")]).get_text()
|
|
140
141
|
(...'onetwothree', [('a', 3), (None, 3), ('b', 5)])
|
|
141
142
|
"""
|
|
142
143
|
return self._text, self._attrib
|
|
@@ -165,16 +166,16 @@ class Text(Widget):
|
|
|
165
166
|
:param mode: typically ``'left'``, ``'center'`` or ``'right'``
|
|
166
167
|
:type mode: text alignment mode
|
|
167
168
|
|
|
168
|
-
>>> t = Text(
|
|
169
|
-
>>> t.set_align_mode(
|
|
169
|
+
>>> t = Text("word")
|
|
170
|
+
>>> t.set_align_mode("right")
|
|
170
171
|
>>> t.align
|
|
171
172
|
'right'
|
|
172
|
-
>>> t.render((10,)).text
|
|
173
|
+
>>> t.render((10,)).text # ... = b in Python 3
|
|
173
174
|
[...' word']
|
|
174
|
-
>>> t.align =
|
|
175
|
+
>>> t.align = "center"
|
|
175
176
|
>>> t.render((10,)).text
|
|
176
177
|
[...' word ']
|
|
177
|
-
>>> t.align =
|
|
178
|
+
>>> t.align = "somewhere"
|
|
178
179
|
Traceback (most recent call last):
|
|
179
180
|
TextError: Alignment mode 'somewhere' not supported.
|
|
180
181
|
"""
|
|
@@ -191,18 +192,18 @@ class Text(Widget):
|
|
|
191
192
|
:param mode: typically ``'space'``, ``'any'``, ``'clip'`` or ``'ellipsis'``
|
|
192
193
|
:type mode: text wrapping mode
|
|
193
194
|
|
|
194
|
-
>>> t = Text(
|
|
195
|
-
>>> t.render((6,)).text
|
|
195
|
+
>>> t = Text("some words")
|
|
196
|
+
>>> t.render((6,)).text # ... = b in Python 3
|
|
196
197
|
[...'some ', ...'words ']
|
|
197
|
-
>>> t.set_wrap_mode(
|
|
198
|
+
>>> t.set_wrap_mode("clip")
|
|
198
199
|
>>> t.wrap
|
|
199
200
|
'clip'
|
|
200
201
|
>>> t.render((6,)).text
|
|
201
202
|
[...'some w']
|
|
202
|
-
>>> t.wrap =
|
|
203
|
+
>>> t.wrap = "any" # Urwid 0.9.9 or later
|
|
203
204
|
>>> t.render((6,)).text
|
|
204
205
|
[...'some w', ...'ords ']
|
|
205
|
-
>>> t.wrap =
|
|
206
|
+
>>> t.wrap = "somehow"
|
|
206
207
|
Traceback (most recent call last):
|
|
207
208
|
TextError: Wrap mode 'somehow' not supported.
|
|
208
209
|
"""
|
|
@@ -227,8 +228,8 @@ class Text(Widget):
|
|
|
227
228
|
:param layout: defaults to a shared :class:`StandardTextLayout` instance
|
|
228
229
|
:type layout: text layout instance
|
|
229
230
|
|
|
230
|
-
>>> t = Text(
|
|
231
|
-
>>> t.set_layout(
|
|
231
|
+
>>> t = Text("hi")
|
|
232
|
+
>>> t.set_layout("right", "clip")
|
|
232
233
|
>>> t
|
|
233
234
|
<Text fixed/flow widget 'hi' align='right' wrap='clip'>
|
|
234
235
|
"""
|
|
@@ -255,9 +256,9 @@ class Text(Widget):
|
|
|
255
256
|
|
|
256
257
|
See :meth:`Widget.render` for parameter details.
|
|
257
258
|
|
|
258
|
-
>>> Text(
|
|
259
|
+
>>> Text("important things").render((18,)).text
|
|
259
260
|
[b'important things ']
|
|
260
|
-
>>> Text(
|
|
261
|
+
>>> Text("important things").render((11,)).text
|
|
261
262
|
[b'important ', b'things ']
|
|
262
263
|
>>> Text("demo text").render(()).text
|
|
263
264
|
[b'demo text']
|
|
@@ -277,9 +278,9 @@ class Text(Widget):
|
|
|
277
278
|
|
|
278
279
|
See :meth:`Widget.rows` for parameter details.
|
|
279
280
|
|
|
280
|
-
>>> Text(
|
|
281
|
+
>>> Text("important things").rows((18,))
|
|
281
282
|
1
|
|
282
|
-
>>> Text(
|
|
283
|
+
>>> Text("important things").rows((11,))
|
|
283
284
|
2
|
|
284
285
|
"""
|
|
285
286
|
(maxcol,) = size
|
|
@@ -332,14 +333,25 @@ class Text(Widget):
|
|
|
332
333
|
:param focus: widget is focused on
|
|
333
334
|
:type focus: bool
|
|
334
335
|
|
|
335
|
-
>>> Text(
|
|
336
|
+
>>> Text("important things").pack()
|
|
336
337
|
(16, 1)
|
|
337
|
-
>>> Text(
|
|
338
|
+
>>> Text("important things").pack((15,))
|
|
338
339
|
(9, 2)
|
|
339
|
-
>>> Text(
|
|
340
|
+
>>> Text("important things").pack((8,))
|
|
340
341
|
(8, 2)
|
|
341
|
-
>>> Text(
|
|
342
|
+
>>> Text("important things").pack(())
|
|
342
343
|
(16, 1)
|
|
344
|
+
>>> not_common_separated_text = "Line feed\\nLine Separator\\u2028Paragraph Separator\\u2029"
|
|
345
|
+
>>> # \u2028 (Line Separator) and \u2029 (Paragraph Separator) are not splitted by StandardTextLayout
|
|
346
|
+
>>> not_common_separated = Text(not_common_separated_text)
|
|
347
|
+
|
|
348
|
+
>>> not_common_separated.pack()
|
|
349
|
+
(33, 2)
|
|
350
|
+
>>> not_common_separated_canv = not_common_separated.render(())
|
|
351
|
+
>>> not_common_separated_canv.cols()
|
|
352
|
+
33
|
|
353
|
+
>>> not_common_separated_canv.rows()
|
|
354
|
+
2
|
|
343
355
|
"""
|
|
344
356
|
text, attr = self.get_text()
|
|
345
357
|
|
|
@@ -356,8 +368,10 @@ class Text(Widget):
|
|
|
356
368
|
if isinstance(text, bytes):
|
|
357
369
|
text = text.decode(get_encoding())
|
|
358
370
|
|
|
371
|
+
split_text = text.split("\n")
|
|
372
|
+
|
|
359
373
|
return (
|
|
360
|
-
max(calc_width(line, 0, len(line)) for line in
|
|
361
|
-
|
|
374
|
+
max(calc_width(line, 0, len(line)) for line in split_text),
|
|
375
|
+
len(split_text),
|
|
362
376
|
)
|
|
363
377
|
return 0, 1
|
urwid/widget/widget.py
CHANGED
|
@@ -678,12 +678,12 @@ class WidgetWrap(delegate_to_widget_mixin("_wrapped_widget"), typing.Generic[Wra
|
|
|
678
678
|
only by subclasses.
|
|
679
679
|
|
|
680
680
|
>>> size = (10,)
|
|
681
|
-
>>> ww = WidgetWrap(Edit("hello? ","hi"))
|
|
682
|
-
>>> ww.render(size).text
|
|
681
|
+
>>> ww = WidgetWrap(Edit("hello? ", "hi"))
|
|
682
|
+
>>> ww.render(size).text # ... = b in Python 3
|
|
683
683
|
[...'hello? hi ']
|
|
684
684
|
>>> ww.selectable()
|
|
685
685
|
True
|
|
686
|
-
>>> ww._w = Text("goodbye")
|
|
686
|
+
>>> ww._w = Text("goodbye") # calls _set_w()
|
|
687
687
|
>>> ww.render(size).text
|
|
688
688
|
[...'goodbye ']
|
|
689
689
|
>>> ww.selectable()
|
|
@@ -698,12 +698,12 @@ class WidgetWrap(delegate_to_widget_mixin("_wrapped_widget"), typing.Generic[Wra
|
|
|
698
698
|
only by subclasses.
|
|
699
699
|
>>> from urwid import Edit, Text
|
|
700
700
|
>>> size = (10,)
|
|
701
|
-
>>> ww = WidgetWrap(Edit("hello? ","hi"))
|
|
702
|
-
>>> ww.render(size).text
|
|
701
|
+
>>> ww = WidgetWrap(Edit("hello? ", "hi"))
|
|
702
|
+
>>> ww.render(size).text # ... = b in Python 3
|
|
703
703
|
[...'hello? hi ']
|
|
704
704
|
>>> ww.selectable()
|
|
705
705
|
True
|
|
706
|
-
>>> ww._w = Text("goodbye")
|
|
706
|
+
>>> ww._w = Text("goodbye") # calls _set_w()
|
|
707
707
|
>>> ww.render(size).text
|
|
708
708
|
[...'goodbye ']
|
|
709
709
|
>>> ww.selectable()
|
|
@@ -37,7 +37,7 @@ class WidgetDecoration(Widget, typing.Generic[WrappedWidget]): # pylint: disabl
|
|
|
37
37
|
Don't actually do this -- use a WidgetDecoration subclass instead, these are not real widgets:
|
|
38
38
|
|
|
39
39
|
>>> from urwid import Text
|
|
40
|
-
>>> WidgetDecoration(Text(
|
|
40
|
+
>>> WidgetDecoration(Text("hi"))
|
|
41
41
|
<WidgetDecoration fixed/flow widget <Text fixed/flow widget 'hi'>>
|
|
42
42
|
|
|
43
43
|
.. Warning:
|
|
@@ -79,7 +79,7 @@ class WidgetDecoration(Widget, typing.Generic[WrappedWidget]): # pylint: disabl
|
|
|
79
79
|
If there is only one Decoration, then this is the same as original_widget.
|
|
80
80
|
|
|
81
81
|
>>> from urwid import Text
|
|
82
|
-
>>> t = Text(
|
|
82
|
+
>>> t = Text("hello")
|
|
83
83
|
>>> wd1 = WidgetDecoration(t)
|
|
84
84
|
>>> wd2 = WidgetDecoration(wd1)
|
|
85
85
|
>>> wd3 = WidgetDecoration(wd2)
|
urwid/widget/wimp.py
CHANGED
|
@@ -84,7 +84,7 @@ class SelectableIcon(Text):
|
|
|
84
84
|
Render the text content of this widget with a cursor when
|
|
85
85
|
in focus.
|
|
86
86
|
|
|
87
|
-
>>> si = SelectableIcon(
|
|
87
|
+
>>> si = SelectableIcon("[!]")
|
|
88
88
|
>>> si
|
|
89
89
|
<SelectableIcon selectable fixed/flow widget '[!]'>
|
|
90
90
|
>>> si.render((4,), focus=True).cursor
|
|
@@ -170,10 +170,10 @@ class CheckBox(WidgetWrap[Columns]):
|
|
|
170
170
|
def __init__(
|
|
171
171
|
self,
|
|
172
172
|
label: str | tuple[Hashable, str] | list[str | tuple[Hashable, str]],
|
|
173
|
-
state: bool = False,
|
|
174
|
-
has_mixed: typing.Literal[
|
|
175
|
-
on_state_change: Callable[[Self, bool], typing.Any] | None = None,
|
|
176
|
-
user_data:
|
|
173
|
+
state: typing.Literal["mixed"] | bool = False,
|
|
174
|
+
has_mixed: typing.Literal[True] = True,
|
|
175
|
+
on_state_change: Callable[[Self, bool | typing.Literal["mixed"], _T], typing.Any] | None = None,
|
|
176
|
+
user_data: _T = ...,
|
|
177
177
|
checked_symbol: str | None = ...,
|
|
178
178
|
) -> None: ...
|
|
179
179
|
|
|
@@ -181,10 +181,10 @@ class CheckBox(WidgetWrap[Columns]):
|
|
|
181
181
|
def __init__(
|
|
182
182
|
self,
|
|
183
183
|
label: str | tuple[Hashable, str] | list[str | tuple[Hashable, str]],
|
|
184
|
-
state:
|
|
185
|
-
has_mixed: typing.Literal[
|
|
186
|
-
on_state_change: Callable[[Self, bool
|
|
187
|
-
user_data:
|
|
184
|
+
state: bool = False,
|
|
185
|
+
has_mixed: typing.Literal[False] = False,
|
|
186
|
+
on_state_change: Callable[[Self, bool], typing.Any] | None = None,
|
|
187
|
+
user_data: None = None,
|
|
188
188
|
checked_symbol: str | None = ...,
|
|
189
189
|
) -> None: ...
|
|
190
190
|
|
|
@@ -206,8 +206,8 @@ class CheckBox(WidgetWrap[Columns]):
|
|
|
206
206
|
has_mixed: typing.Literal[False, True] = False, # MyPy issue: Literal[True, False] is not equal `bool`
|
|
207
207
|
on_state_change: (
|
|
208
208
|
Callable[[Self, bool, _T], typing.Any]
|
|
209
|
-
| Callable[[Self, bool], typing.Any]
|
|
210
209
|
| Callable[[Self, bool | typing.Literal["mixed"], _T], typing.Any]
|
|
210
|
+
| Callable[[Self, bool], typing.Any]
|
|
211
211
|
| Callable[[Self, bool | typing.Literal["mixed"]], typing.Any]
|
|
212
212
|
| None
|
|
213
213
|
) = None,
|
|
@@ -228,12 +228,12 @@ class CheckBox(WidgetWrap[Columns]):
|
|
|
228
228
|
|
|
229
229
|
Register signal handler with::
|
|
230
230
|
|
|
231
|
-
urwid.connect_signal(check_box,
|
|
231
|
+
urwid.connect_signal(check_box, "change", callback, user_data)
|
|
232
232
|
|
|
233
233
|
where callback is callback(check_box, new_state [,user_data])
|
|
234
234
|
Unregister signal handlers with::
|
|
235
235
|
|
|
236
|
-
urwid.disconnect_signal(check_box,
|
|
236
|
+
urwid.disconnect_signal(check_box, "change", callback, user_data)
|
|
237
237
|
|
|
238
238
|
>>> CheckBox("Confirm")
|
|
239
239
|
<CheckBox selectable fixed/flow widget 'Confirm' state=False>
|
|
@@ -303,10 +303,10 @@ class CheckBox(WidgetWrap[Columns]):
|
|
|
303
303
|
label -- markup for label. See Text widget for description
|
|
304
304
|
of text markup.
|
|
305
305
|
|
|
306
|
-
>>> cb = CheckBox(
|
|
306
|
+
>>> cb = CheckBox("foo")
|
|
307
307
|
>>> cb
|
|
308
308
|
<CheckBox selectable fixed/flow widget 'foo' state=False>
|
|
309
|
-
>>> cb.set_label((
|
|
309
|
+
>>> cb.set_label(("bright_attr", "bar"))
|
|
310
310
|
>>> cb
|
|
311
311
|
<CheckBox selectable fixed/flow widget 'bar' state=False>
|
|
312
312
|
"""
|
|
@@ -318,12 +318,12 @@ class CheckBox(WidgetWrap[Columns]):
|
|
|
318
318
|
"""
|
|
319
319
|
Return label text.
|
|
320
320
|
|
|
321
|
-
>>> cb = CheckBox(
|
|
321
|
+
>>> cb = CheckBox("Seriously")
|
|
322
322
|
>>> print(cb.get_label())
|
|
323
323
|
Seriously
|
|
324
324
|
>>> print(cb.label)
|
|
325
325
|
Seriously
|
|
326
|
-
>>> cb.set_label([(
|
|
326
|
+
>>> cb.set_label([("bright_attr", "flashy"), " normal"])
|
|
327
327
|
>>> print(cb.label) # only text is returned
|
|
328
328
|
flashy normal
|
|
329
329
|
"""
|
|
@@ -348,20 +348,20 @@ class CheckBox(WidgetWrap[Columns]):
|
|
|
348
348
|
... changes.append("A %r %r" % (state, user_data))
|
|
349
349
|
>>> def callback_b(cb, state):
|
|
350
350
|
... changes.append("B %r" % state)
|
|
351
|
-
>>> cb = CheckBox(
|
|
352
|
-
>>> key1 = connect_signal(cb,
|
|
353
|
-
>>> key2 = connect_signal(cb,
|
|
354
|
-
>>> cb.set_state(True)
|
|
351
|
+
>>> cb = CheckBox("test", False, False)
|
|
352
|
+
>>> key1 = connect_signal(cb, "change", callback_a, user_args=("user_a",))
|
|
353
|
+
>>> key2 = connect_signal(cb, "change", callback_b)
|
|
354
|
+
>>> cb.set_state(True) # both callbacks will be triggered
|
|
355
355
|
>>> cb.state
|
|
356
356
|
True
|
|
357
|
-
>>> disconnect_signal(cb,
|
|
357
|
+
>>> disconnect_signal(cb, "change", callback_a, user_args=("user_a",))
|
|
358
358
|
>>> cb.state = False
|
|
359
359
|
>>> cb.state
|
|
360
360
|
False
|
|
361
361
|
>>> cb.set_state(True)
|
|
362
362
|
>>> cb.state
|
|
363
363
|
True
|
|
364
|
-
>>> cb.set_state(False, False)
|
|
364
|
+
>>> cb.set_state(False, False) # don't send signal
|
|
365
365
|
>>> changes
|
|
366
366
|
["A True 'user_a'", 'B True', 'B False', 'B True']
|
|
367
367
|
"""
|
|
@@ -392,16 +392,16 @@ class CheckBox(WidgetWrap[Columns]):
|
|
|
392
392
|
"""
|
|
393
393
|
Toggle state on 'activate' command.
|
|
394
394
|
|
|
395
|
-
>>> assert CheckBox._command_map[
|
|
396
|
-
>>> assert CheckBox._command_map[
|
|
395
|
+
>>> assert CheckBox._command_map[" "] == "activate"
|
|
396
|
+
>>> assert CheckBox._command_map["enter"] == "activate"
|
|
397
397
|
>>> size = (10,)
|
|
398
|
-
>>> cb = CheckBox(
|
|
398
|
+
>>> cb = CheckBox("press me")
|
|
399
399
|
>>> cb.state
|
|
400
400
|
False
|
|
401
|
-
>>> cb.keypress(size,
|
|
401
|
+
>>> cb.keypress(size, " ")
|
|
402
402
|
>>> cb.state
|
|
403
403
|
True
|
|
404
|
-
>>> cb.keypress(size,
|
|
404
|
+
>>> cb.keypress(size, " ")
|
|
405
405
|
>>> cb.state
|
|
406
406
|
False
|
|
407
407
|
"""
|
|
@@ -446,7 +446,7 @@ class CheckBox(WidgetWrap[Columns]):
|
|
|
446
446
|
>>> cb = CheckBox("clickme")
|
|
447
447
|
>>> cb.state
|
|
448
448
|
False
|
|
449
|
-
>>> cb.mouse_event(size,
|
|
449
|
+
>>> cb.mouse_event(size, "mouse press", 1, 2, 0, True)
|
|
450
450
|
True
|
|
451
451
|
>>> cb.state
|
|
452
452
|
True
|
|
@@ -510,23 +510,23 @@ class RadioButton(CheckBox):
|
|
|
510
510
|
|
|
511
511
|
Register signal handler with::
|
|
512
512
|
|
|
513
|
-
urwid.connect_signal(radio_button,
|
|
513
|
+
urwid.connect_signal(radio_button, "change", callback, user_data)
|
|
514
514
|
|
|
515
515
|
where callback is callback(radio_button, new_state [,user_data])
|
|
516
516
|
Unregister signal handlers with::
|
|
517
517
|
|
|
518
|
-
urwid.disconnect_signal(radio_button,
|
|
518
|
+
urwid.disconnect_signal(radio_button, "change", callback, user_data)
|
|
519
519
|
|
|
520
|
-
>>> bgroup = []
|
|
521
|
-
>>> b1 = RadioButton(bgroup,
|
|
522
|
-
>>> b2 = RadioButton(bgroup,
|
|
520
|
+
>>> bgroup = [] # button group
|
|
521
|
+
>>> b1 = RadioButton(bgroup, "Agree")
|
|
522
|
+
>>> b2 = RadioButton(bgroup, "Disagree")
|
|
523
523
|
>>> len(bgroup)
|
|
524
524
|
2
|
|
525
525
|
>>> b1
|
|
526
526
|
<RadioButton selectable fixed/flow widget 'Agree' state=True>
|
|
527
527
|
>>> b2
|
|
528
528
|
<RadioButton selectable fixed/flow widget 'Disagree' state=False>
|
|
529
|
-
>>> b2.render((15,), focus=True).text
|
|
529
|
+
>>> b2.render((15,), focus=True).text # ... = b in Python 3
|
|
530
530
|
[...'( ) Disagree ']
|
|
531
531
|
"""
|
|
532
532
|
if state == "first True":
|
|
@@ -547,21 +547,21 @@ class RadioButton(CheckBox):
|
|
|
547
547
|
If state is True all other radio buttons in the same button
|
|
548
548
|
group will be set to False.
|
|
549
549
|
|
|
550
|
-
>>> bgroup = []
|
|
551
|
-
>>> b1 = RadioButton(bgroup,
|
|
552
|
-
>>> b2 = RadioButton(bgroup,
|
|
553
|
-
>>> b3 = RadioButton(bgroup,
|
|
550
|
+
>>> bgroup = [] # button group
|
|
551
|
+
>>> b1 = RadioButton(bgroup, "Agree")
|
|
552
|
+
>>> b2 = RadioButton(bgroup, "Disagree")
|
|
553
|
+
>>> b3 = RadioButton(bgroup, "Unsure")
|
|
554
554
|
>>> b1.state, b2.state, b3.state
|
|
555
555
|
(True, False, False)
|
|
556
556
|
>>> b2.set_state(True)
|
|
557
557
|
>>> b1.state, b2.state, b3.state
|
|
558
558
|
(False, True, False)
|
|
559
559
|
>>> def relabel_button(radio_button, new_state):
|
|
560
|
-
... radio_button.set_label(
|
|
561
|
-
>>> key = connect_signal(b3,
|
|
560
|
+
... radio_button.set_label("Think Harder!")
|
|
561
|
+
>>> key = connect_signal(b3, "change", relabel_button)
|
|
562
562
|
>>> b3
|
|
563
563
|
<RadioButton selectable fixed/flow widget 'Unsure' state=False>
|
|
564
|
-
>>> b3.set_state(True)
|
|
564
|
+
>>> b3.set_state(True) # this will trigger the callback
|
|
565
565
|
>>> b3
|
|
566
566
|
<RadioButton selectable fixed/flow widget 'Think Harder!' state=True>
|
|
567
567
|
"""
|
|
@@ -586,7 +586,7 @@ class RadioButton(CheckBox):
|
|
|
586
586
|
"""
|
|
587
587
|
Set state to True.
|
|
588
588
|
|
|
589
|
-
>>> bgroup = []
|
|
589
|
+
>>> bgroup = [] # button group
|
|
590
590
|
>>> b1 = RadioButton(bgroup, "Agree")
|
|
591
591
|
>>> b2 = RadioButton(bgroup, "Disagree")
|
|
592
592
|
>>> b1.state, b2.state
|
|
@@ -659,25 +659,25 @@ class Button(WidgetWrap[Columns]):
|
|
|
659
659
|
|
|
660
660
|
Register signal handler with::
|
|
661
661
|
|
|
662
|
-
urwid.connect_signal(button,
|
|
662
|
+
urwid.connect_signal(button, "click", callback, user_data)
|
|
663
663
|
|
|
664
664
|
where callback is callback(button [,user_data])
|
|
665
665
|
Unregister signal handlers with::
|
|
666
666
|
|
|
667
|
-
urwid.disconnect_signal(button,
|
|
667
|
+
urwid.disconnect_signal(button, "click", callback, user_data)
|
|
668
668
|
|
|
669
669
|
>>> from urwid.util import set_temporary_encoding
|
|
670
|
-
>>> Button(
|
|
670
|
+
>>> Button("Ok")
|
|
671
671
|
<Button selectable fixed/flow widget 'Ok'>
|
|
672
672
|
>>> b = Button("Cancel")
|
|
673
|
-
>>> b.render((15,), focus=True).text
|
|
673
|
+
>>> b.render((15,), focus=True).text # ... = b in Python 3
|
|
674
674
|
[b'< Cancel >']
|
|
675
675
|
>>> aligned_button = Button("Test", align=Align.CENTER)
|
|
676
676
|
>>> aligned_button.render((10,), focus=True).text
|
|
677
677
|
[b'< Test >']
|
|
678
678
|
>>> wrapped_button = Button("Long label", wrap=WrapMode.ELLIPSIS)
|
|
679
679
|
>>> with set_temporary_encoding("utf-8"):
|
|
680
|
-
... wrapped_button.render((7,), focus=False).text[0].decode(
|
|
680
|
+
... wrapped_button.render((7,), focus=False).text[0].decode("utf-8")
|
|
681
681
|
'< Lo… >'
|
|
682
682
|
"""
|
|
683
683
|
self._label = SelectableIcon(label, 0, align=align, wrap=wrap, layout=layout)
|
|
@@ -719,7 +719,7 @@ class Button(WidgetWrap[Columns]):
|
|
|
719
719
|
label -- markup for button label
|
|
720
720
|
|
|
721
721
|
>>> b = Button("Ok")
|
|
722
|
-
>>> b.set_label(
|
|
722
|
+
>>> b.set_label("Yup yup")
|
|
723
723
|
>>> b
|
|
724
724
|
<Button selectable fixed/flow widget 'Yup yup'>
|
|
725
725
|
"""
|
|
@@ -729,7 +729,7 @@ class Button(WidgetWrap[Columns]):
|
|
|
729
729
|
"""
|
|
730
730
|
Return label text.
|
|
731
731
|
|
|
732
|
-
>>> b = Button(
|
|
732
|
+
>>> b = Button("Ok")
|
|
733
733
|
>>> print(b.get_label())
|
|
734
734
|
Ok
|
|
735
735
|
>>> print(b.label)
|
|
@@ -743,17 +743,17 @@ class Button(WidgetWrap[Columns]):
|
|
|
743
743
|
"""
|
|
744
744
|
Send 'click' signal on 'activate' command.
|
|
745
745
|
|
|
746
|
-
>>> assert Button._command_map[
|
|
747
|
-
>>> assert Button._command_map[
|
|
746
|
+
>>> assert Button._command_map[" "] == "activate"
|
|
747
|
+
>>> assert Button._command_map["enter"] == "activate"
|
|
748
748
|
>>> size = (15,)
|
|
749
|
-
>>> b = Button(
|
|
749
|
+
>>> b = Button("Cancel")
|
|
750
750
|
>>> clicked_buttons = []
|
|
751
751
|
>>> def handle_click(button):
|
|
752
752
|
... clicked_buttons.append(button.label)
|
|
753
|
-
>>> key = connect_signal(b,
|
|
754
|
-
>>> b.keypress(size,
|
|
755
|
-
>>> b.keypress(size,
|
|
756
|
-
>>> clicked_buttons
|
|
753
|
+
>>> key = connect_signal(b, "click", handle_click)
|
|
754
|
+
>>> b.keypress(size, "enter")
|
|
755
|
+
>>> b.keypress(size, " ")
|
|
756
|
+
>>> clicked_buttons # ... = u in Python 2
|
|
757
757
|
[...'Cancel', ...'Cancel']
|
|
758
758
|
"""
|
|
759
759
|
if self._command_map[key] != Command.ACTIVATE:
|
|
@@ -767,16 +767,16 @@ class Button(WidgetWrap[Columns]):
|
|
|
767
767
|
Send 'click' signal on button 1 press.
|
|
768
768
|
|
|
769
769
|
>>> size = (15,)
|
|
770
|
-
>>> b = Button(
|
|
770
|
+
>>> b = Button("Ok")
|
|
771
771
|
>>> clicked_buttons = []
|
|
772
772
|
>>> def handle_click(button):
|
|
773
773
|
... clicked_buttons.append(button.label)
|
|
774
|
-
>>> key = connect_signal(b,
|
|
775
|
-
>>> b.mouse_event(size,
|
|
774
|
+
>>> key = connect_signal(b, "click", handle_click)
|
|
775
|
+
>>> b.mouse_event(size, "mouse press", 1, 4, 0, True)
|
|
776
776
|
True
|
|
777
|
-
>>> b.mouse_event(size,
|
|
777
|
+
>>> b.mouse_event(size, "mouse press", 2, 4, 0, True) # ignored
|
|
778
778
|
False
|
|
779
|
-
>>> clicked_buttons
|
|
779
|
+
>>> clicked_buttons # ... = u in Python 2
|
|
780
780
|
[...'Ok']
|
|
781
781
|
"""
|
|
782
782
|
if button != 1 or not is_mouse_press(event):
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: urwid
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.5
|
|
4
4
|
Summary: A full-featured console (xterm et al.) user interface library
|
|
5
5
|
Author-email: Ian Ward <ian@excess.org>
|
|
6
|
-
License: LGPL-2.1-only
|
|
6
|
+
License-Expression: LGPL-2.1-only
|
|
7
7
|
Project-URL: Homepage, https://urwid.org/
|
|
8
8
|
Project-URL: Documentation, https://urwid.org/manual/index.html
|
|
9
9
|
Project-URL: Repository, https://github.com/urwid/urwid
|
|
@@ -14,7 +14,6 @@ Classifier: Development Status :: 5 - Production/Stable
|
|
|
14
14
|
Classifier: Environment :: Console
|
|
15
15
|
Classifier: Environment :: Console :: Curses
|
|
16
16
|
Classifier: Intended Audience :: Developers
|
|
17
|
-
Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
|
|
18
17
|
Classifier: Operating System :: POSIX
|
|
19
18
|
Classifier: Operating System :: Unix
|
|
20
19
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
@@ -27,13 +26,14 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
27
26
|
Classifier: Programming Language :: Python :: 3.11
|
|
28
27
|
Classifier: Programming Language :: Python :: 3.12
|
|
29
28
|
Classifier: Programming Language :: Python :: 3.13
|
|
29
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
30
30
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
31
31
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
32
32
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
33
33
|
Requires-Python: >=3.9.0
|
|
34
34
|
Description-Content-Type: text/x-rst
|
|
35
35
|
License-File: COPYING
|
|
36
|
-
Requires-Dist: wcwidth
|
|
36
|
+
Requires-Dist: wcwidth>=0.4
|
|
37
37
|
Provides-Extra: curses
|
|
38
38
|
Requires-Dist: windows-curses; sys_platform == "win32" and extra == "curses"
|
|
39
39
|
Provides-Extra: glib
|
|
@@ -74,7 +74,7 @@ It includes many features useful for text console application developers includi
|
|
|
74
74
|
- Display modules include raw, curses, and experimental LCD and web displays
|
|
75
75
|
- Support for UTF-8, simple 8-bit and CJK encodings
|
|
76
76
|
- 24-bit (true color), 256 color, and 88 color mode support
|
|
77
|
-
- Compatible with Python 3.
|
|
77
|
+
- Compatible with Python 3.9+ and PyPy
|
|
78
78
|
|
|
79
79
|
Home Page:
|
|
80
80
|
http://urwid.org/
|
|
@@ -147,6 +147,7 @@ Supported Python versions
|
|
|
147
147
|
- 3.11
|
|
148
148
|
- 3.12
|
|
149
149
|
- 3.13
|
|
150
|
+
- 3.14
|
|
150
151
|
- pypy3
|
|
151
152
|
|
|
152
153
|
Authors
|