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/widget/popup.py ADDED
@@ -0,0 +1,170 @@
1
+ # Urwid Window-Icon-Menu-Pointer-style widget classes
2
+ # Copyright (C) 2004-2011 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
+
25
+ from urwid.canvas import CompositeCanvas
26
+
27
+ from .constants import Sizing
28
+ from .overlay import Overlay
29
+ from .widget import delegate_to_widget_mixin
30
+ from .widget_decoration import WidgetDecoration
31
+
32
+ if typing.TYPE_CHECKING:
33
+ from typing_extensions import TypedDict
34
+
35
+ from urwid.canvas import Canvas
36
+
37
+ from .widget import Widget
38
+
39
+ class PopUpParametersModel(TypedDict):
40
+ left: int
41
+ top: int
42
+ overlay_width: int
43
+ overlay_height: int
44
+
45
+
46
+ WrappedWidget = typing.TypeVar("WrappedWidget")
47
+
48
+
49
+ class PopUpLauncher(delegate_to_widget_mixin("_original_widget"), WidgetDecoration[WrappedWidget]):
50
+ def __init__(self, original_widget: [WrappedWidget]) -> None:
51
+ super().__init__(original_widget)
52
+ self._pop_up_widget = None
53
+
54
+ def create_pop_up(self) -> Widget:
55
+ """
56
+ Subclass must override this method and return a widget
57
+ to be used for the pop-up. This method is called once each time
58
+ the pop-up is opened.
59
+ """
60
+ raise NotImplementedError("Subclass must override this method")
61
+
62
+ def get_pop_up_parameters(self) -> PopUpParametersModel:
63
+ """
64
+ Subclass must override this method and have it return a dict, eg:
65
+
66
+ {'left':0, 'top':1, 'overlay_width':30, 'overlay_height':4}
67
+
68
+ This method is called each time this widget is rendered.
69
+ """
70
+ raise NotImplementedError("Subclass must override this method")
71
+
72
+ def open_pop_up(self) -> None:
73
+ self._pop_up_widget = self.create_pop_up()
74
+ self._invalidate()
75
+
76
+ def close_pop_up(self) -> None:
77
+ self._pop_up_widget = None
78
+ self._invalidate()
79
+
80
+ def render(self, size, focus: bool = False) -> CompositeCanvas | Canvas:
81
+ canv = super().render(size, focus)
82
+ if self._pop_up_widget:
83
+ canv = CompositeCanvas(canv)
84
+ canv.set_pop_up(self._pop_up_widget, **self.get_pop_up_parameters())
85
+ return canv
86
+
87
+
88
+ class PopUpTarget(WidgetDecoration[WrappedWidget]):
89
+ # FIXME: this whole class is a terrible hack and must be fixed
90
+ # when layout and rendering are separated
91
+ _sizing = frozenset((Sizing.BOX,))
92
+ _selectable = True
93
+
94
+ def __init__(self, original_widget: WrappedWidget) -> None:
95
+ super().__init__(original_widget)
96
+ self._pop_up = None
97
+ self._current_widget = self._original_widget
98
+
99
+ def _update_overlay(self, size: tuple[int, int], focus: bool) -> None:
100
+ canv = self._original_widget.render(size, focus=focus)
101
+ self._cache_original_canvas = canv # imperfect performance hack
102
+ pop_up = canv.get_pop_up()
103
+ if pop_up:
104
+ left, top, (w, overlay_width, overlay_height) = pop_up
105
+ if self._pop_up != w:
106
+ self._pop_up = w
107
+ self._current_widget = Overlay(
108
+ w,
109
+ self._original_widget,
110
+ ("fixed left", left),
111
+ overlay_width,
112
+ ("fixed top", top),
113
+ overlay_height,
114
+ )
115
+ else:
116
+ self._current_widget.set_overlay_parameters(
117
+ ("fixed left", left),
118
+ overlay_width,
119
+ ("fixed top", top),
120
+ overlay_height,
121
+ )
122
+ else:
123
+ self._pop_up = None
124
+ self._current_widget = self._original_widget
125
+
126
+ def render(self, size: tuple[int, int], focus: bool = False) -> Canvas:
127
+ self._update_overlay(size, focus)
128
+ return self._current_widget.render(size, focus=focus)
129
+
130
+ def get_cursor_coords(self, size: tuple[int, int]) -> tuple[int, int] | None:
131
+ self._update_overlay(size, True)
132
+ return self._current_widget.get_cursor_coords(size)
133
+
134
+ def get_pref_col(self, size: tuple[int, int]) -> int:
135
+ self._update_overlay(size, True)
136
+ return self._current_widget.get_pref_col(size)
137
+
138
+ def keypress(self, size: tuple[int, int], key: str) -> str | None:
139
+ self._update_overlay(size, True)
140
+ return self._current_widget.keypress(size, key)
141
+
142
+ def move_cursor_to_coords(self, size: tuple[int, int], x: int, y: int):
143
+ self._update_overlay(size, True)
144
+ return self._current_widget.move_cursor_to_coords(size, x, y)
145
+
146
+ def mouse_event(
147
+ self,
148
+ size: tuple[int, int],
149
+ event: str,
150
+ button: int,
151
+ col: int,
152
+ row: int,
153
+ focus: bool,
154
+ ) -> bool | None:
155
+ self._update_overlay(size, focus)
156
+ return self._current_widget.mouse_event(size, event, button, col, row, focus)
157
+
158
+ def pack(self, size: tuple[int, int] | None = None, focus: bool = False) -> tuple[int, int]:
159
+ self._update_overlay(size, focus)
160
+ return self._current_widget.pack(size)
161
+
162
+
163
+ def _test():
164
+ import doctest
165
+
166
+ doctest.testmod()
167
+
168
+
169
+ if __name__ == "__main__":
170
+ _test()
@@ -0,0 +1,141 @@
1
+ from __future__ import annotations
2
+
3
+ import typing
4
+ import warnings
5
+
6
+ from .constants import BAR_SYMBOLS, Align, Sizing, WrapMode
7
+ from .text import Text
8
+ from .widget import Widget
9
+
10
+ if typing.TYPE_CHECKING:
11
+ from urwid.canvas import TextCanvas
12
+
13
+
14
+ class ProgressBar(Widget):
15
+ _sizing = frozenset([Sizing.FLOW])
16
+
17
+ eighths = BAR_SYMBOLS.HORISONTAL[:8] # Full width line is made by style
18
+
19
+ text_align = Align.CENTER
20
+
21
+ def __init__(self, normal, complete, current: int = 0, done: int = 100, satt=None):
22
+ """
23
+ :param normal: display attribute for incomplete part of progress bar
24
+ :param complete: display attribute for complete part of progress bar
25
+ :param current: current progress
26
+ :param done: progress amount at 100%
27
+ :param satt: display attribute for smoothed part of bar where the
28
+ foreground of satt corresponds to the normal part and the
29
+ background corresponds to the complete part.
30
+ If satt is ``None`` then no smoothing will be done.
31
+
32
+ >>> from urwid import LineBox
33
+ >>> pb = ProgressBar('a', 'b')
34
+ >>> pb
35
+ <ProgressBar flow widget>
36
+ >>> print(pb.get_text())
37
+ 0 %
38
+ >>> pb.set_completion(34.42)
39
+ >>> print(pb.get_text())
40
+ 34 %
41
+ >>> class CustomProgressBar(ProgressBar):
42
+ ... def get_text(self):
43
+ ... return u'Foobar'
44
+ >>> cpb = CustomProgressBar('a', 'b')
45
+ >>> print(cpb.get_text())
46
+ Foobar
47
+ >>> for x in range(101):
48
+ ... cpb.set_completion(x)
49
+ ... s = cpb.render((10, ))
50
+ >>> cpb2 = CustomProgressBar('a', 'b', satt='c')
51
+ >>> for x in range(101):
52
+ ... cpb2.set_completion(x)
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
+ └──────────────────┘
60
+ """
61
+ super().__init__()
62
+ self.normal = normal
63
+ self.complete = complete
64
+ self._current = current
65
+ self._done = done
66
+ self.satt = satt
67
+
68
+ def set_completion(self, current: int) -> None:
69
+ """
70
+ current -- current progress
71
+ """
72
+ self._current = current
73
+ self._invalidate()
74
+
75
+ current = property(lambda self: self._current, set_completion)
76
+
77
+ @property
78
+ def done(self):
79
+ return self._done
80
+
81
+ @done.setter
82
+ def done(self, done):
83
+ """
84
+ done -- progress amount at 100%
85
+ """
86
+ self._done = done
87
+ self._invalidate()
88
+
89
+ def _set_done(self, done):
90
+ warnings.warn(
91
+ f"Method `{self.__class__.__name__}._set_done` is deprecated, "
92
+ f"please use property `{self.__class__.__name__}.done`",
93
+ DeprecationWarning,
94
+ stacklevel=2,
95
+ )
96
+ self.done = done
97
+
98
+ def rows(self, size: tuple[int], focus: bool = False) -> int:
99
+ return 1
100
+
101
+ def get_text(self) -> str:
102
+ """
103
+ Return the progress bar percentage text.
104
+ You can override this method to display custom text.
105
+ """
106
+ percent = min(100, max(0, int(self.current * 100 / self.done)))
107
+ return f"{percent!s} %"
108
+
109
+ def render(self, size: tuple[int], focus: bool = False) -> TextCanvas:
110
+ """
111
+ Render the progress bar.
112
+ """
113
+ # pylint: disable=protected-access
114
+ (maxcol,) = size
115
+ c = Text(self.get_text(), self.text_align, WrapMode.CLIP).render((maxcol,))
116
+
117
+ cf = float(self.current) * maxcol / self.done
118
+ ccol_dirty = int(cf)
119
+ ccol = len(c._text[0][:ccol_dirty].decode("utf-8", "ignore").encode("utf-8"))
120
+ cs = 0
121
+ if self.satt is not None:
122
+ cs = int((cf - ccol) * 8)
123
+ if ccol < 0 or (ccol == cs == 0):
124
+ c._attr = [[(self.normal, maxcol)]]
125
+ elif ccol >= maxcol:
126
+ c._attr = [[(self.complete, maxcol)]]
127
+ elif cs and c._text[0][ccol] == 32:
128
+ t = c._text[0]
129
+ cenc = self.eighths[cs].encode("utf-8")
130
+ c._text[0] = t[:ccol] + cenc + t[ccol + 1 :]
131
+ a = []
132
+ if ccol > 0:
133
+ a.append((self.complete, ccol))
134
+ a.append((self.satt, len(cenc)))
135
+ if maxcol - ccol - 1 > 0:
136
+ a.append((self.normal, maxcol - ccol - 1))
137
+ c._attr = [a]
138
+ c._cs = [[(None, len(c._text[0]))]]
139
+ else:
140
+ c._attr = [[(self.complete, ccol), (self.normal, maxcol - ccol)]]
141
+ return c