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.
Files changed (44) hide show
  1. urwid/__init__.py +2 -0
  2. urwid/canvas.py +34 -22
  3. urwid/command_map.py +6 -4
  4. urwid/display/_posix_raw_display.py +15 -4
  5. urwid/display/_raw_display_base.py +37 -37
  6. urwid/display/_win32_raw_display.py +15 -4
  7. urwid/display/curses.py +2 -4
  8. urwid/display/html_fragment.py +2 -4
  9. urwid/display/web.py +2 -4
  10. urwid/listbox.py +111 -26
  11. urwid/monitored_list.py +2 -4
  12. urwid/str_util.pyd +0 -0
  13. urwid/util.py +1 -2
  14. urwid/version.py +2 -2
  15. urwid/vterm.py +3 -3
  16. urwid/widget/__init__.py +4 -0
  17. urwid/widget/attr_map.py +5 -3
  18. urwid/widget/bar_graph.py +9 -9
  19. urwid/widget/box_adapter.py +6 -7
  20. urwid/widget/columns.py +17 -10
  21. urwid/widget/constants.py +169 -63
  22. urwid/widget/divider.py +27 -3
  23. urwid/widget/edit.py +1 -1
  24. urwid/widget/filler.py +9 -8
  25. urwid/widget/frame.py +9 -1
  26. urwid/widget/grid_flow.py +4 -6
  27. urwid/widget/line_box.py +64 -19
  28. urwid/widget/overlay.py +1 -1
  29. urwid/widget/padding.py +11 -8
  30. urwid/widget/pile.py +10 -7
  31. urwid/widget/popup.py +16 -6
  32. urwid/widget/progress_bar.py +13 -6
  33. urwid/widget/scrollable.py +599 -0
  34. urwid/widget/solid_fill.py +3 -1
  35. urwid/widget/text.py +1 -1
  36. urwid/widget/widget.py +51 -113
  37. urwid/widget/widget_decoration.py +21 -12
  38. urwid/widget/wimp.py +12 -20
  39. {urwid-2.4.6.dist-info → urwid-2.5.1.dist-info}/METADATA +7 -2
  40. urwid-2.5.1.dist-info/RECORD +76 -0
  41. urwid-2.4.6.dist-info/RECORD +0 -75
  42. {urwid-2.4.6.dist-info → urwid-2.5.1.dist-info}/COPYING +0 -0
  43. {urwid-2.4.6.dist-info → urwid-2.5.1.dist-info}/WHEEL +0 -0
  44. {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 .widget import Widget, WidgetWrap
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: 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(("flow", top))
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(("flow", bottom))
123
- pile = Pile(pile_widgets, focus_item=focus_pos)
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
- WidgetDecoration.__init__(self, original_widget)
126
- WidgetWrap.__init__(self, pile)
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
@@ -801,7 +801,7 @@ class Overlay(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
801
801
  def mouse_event(
802
802
  self,
803
803
  size: tuple[()] | tuple[int] | tuple[int, int],
804
- event,
804
+ event: str,
805
805
  button: int,
806
806
  col: int,
807
807
  row: int,
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
- from .widget import Widget
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: Widget,
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: Literal["clip", "pack", WHSettings.CLIP, WHSettings.PACK]
241
- | int
242
- | tuple[Literal["relative", WHSettings.RELATIVE], int],
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
- Unhandled 'up' and 'down' keys may cause a focus change."""
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 {"cursor up", "cursor down"}:
866
+ if self._command_map[key] not in {Command.UP, Command.DOWN}:
864
867
  return key
865
868
 
866
- if self._command_map[key] == "cursor up":
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] == "cursor up":
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
- Pass the event to the contained widget.
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
- class PopUpLauncher(delegate_to_widget_mixin("_original_widget"), WidgetDecoration):
39
- def __init__(self, original_widget: Widget) -> None:
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: Widget) -> None:
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(self, size: tuple[int, int], event, button: int, x: int, y: int, focus: bool) -> bool | None:
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
 
@@ -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. If satt
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: