Skip to content

Commit

Permalink
Fix regression: Overlay not accepted relative positioning
Browse files Browse the repository at this point in the history
  • Loading branch information
Aleksei Stepanov committed Mar 4, 2024
1 parent 3da112e commit b2c1d1e
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 10 deletions.
29 changes: 29 additions & 0 deletions tests/test_overlay.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,35 @@ def test_sizing_box_fixed_relative(self):
[line.decode("utf-8") for line in canvas.text],
)

def test_relative(self):
ovl = urwid.Overlay(
urwid.Text("aaa"),
urwid.SolidFill(urwid.SolidFill.Symbols.LITE_SHADE),
width=urwid.PACK,
height=urwid.PACK,
align=(urwid.RELATIVE, 30),
valign=(urwid.RELATIVE, 70),
)
self.assertEqual(
ovl.contents[1][1],
(urwid.RELATIVE, 30, urwid.PACK, None, None, 0, 0, urwid.RELATIVE, 70, urwid.PACK, None, None, 0, 0),
)
self.assertEqual(
(
"░░░░░░░░░░░░░░░░░░░░",
"░░░░░░░░░░░░░░░░░░░░",
"░░░░░░░░░░░░░░░░░░░░",
"░░░░░░░░░░░░░░░░░░░░",
"░░░░░░░░░░░░░░░░░░░░",
"░░░░░░░░░░░░░░░░░░░░",
"░░░░░aaa░░░░░░░░░░░░",
"░░░░░░░░░░░░░░░░░░░░",
"░░░░░░░░░░░░░░░░░░░░",
"░░░░░░░░░░░░░░░░░░░░",
),
ovl.render((20, 10)).decoded_text,
)

def test_old_params(self):
o1 = urwid.Overlay(
urwid.SolidFill("X"),
Expand Down
47 changes: 37 additions & 10 deletions urwid/widget/overlay.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from .widget import Widget, WidgetError, WidgetWarning

if typing.TYPE_CHECKING:
from collections.abc import Iterator
from collections.abc import Collection, Iterator, MutableSequence

from typing_extensions import Literal

Expand Down Expand Up @@ -56,14 +56,14 @@ def _check_widget_subclass(widget: Widget) -> None:


class OverlayOptions(typing.NamedTuple):
align: Align
align: Align | Literal[WHSettings.RELATIVE]
align_amount: int | None
width_type: WHSettings
width_amount: int | None
min_width: int | None
left: int
right: int
valign_type: VAlign
valign_type: VAlign | Literal[WHSettings.RELATIVE]
valign_amount: int | None
height_type: WHSettings
height_amount: int | None
Expand Down Expand Up @@ -395,11 +395,11 @@ def height(

@staticmethod
def options(
align_type: Literal["left", "center", "right", "relative"] | Align,
align_type: Literal["left", "center", "right", "relative", WHSettings.RELATIVE] | Align,
align_amount: int | None,
width_type: Literal["clip", "pack", "relative", "given"] | WHSettings,
width_amount: int | None,
valign_type: Literal["top", "middle", "bottom", "relative"] | VAlign,
valign_type: Literal["top", "middle", "bottom", "relative", WHSettings.RELATIVE] | VAlign,
valign_amount: int | None,
height_type: Literal["flow", "pack", "relative", "given"] | WHSettings,
height_amount: int | None,
Expand All @@ -418,16 +418,29 @@ def options(
but is not necessarily the easiest way to change the overlay parameters.
See also :meth:`.set_overlay_parameters`
"""
if align_type in {Align.LEFT, Align.CENTER, Align.RIGHT}:
align = Align(align_type)
elif align_type == WHSettings.RELATIVE:
align = WHSettings.RELATIVE
else:
raise ValueError(f"Unknown alignment type {align_type!r}")

if valign_type in {VAlign.TOP, VAlign.MIDDLE, VAlign.BOTTOM}:
valign = VAlign(valign_type)
elif valign_type == WHSettings.RELATIVE:
valign = WHSettings.RELATIVE
else:
raise ValueError(f"Unknown vertical alignment type {valign_type!r}")

return OverlayOptions(
Align(align_type),
align,
align_amount,
WHSettings(width_type),
width_amount,
min_width,
left,
right,
VAlign(valign_type),
valign,
valign_amount,
WHSettings(height_type),
height_amount,
Expand Down Expand Up @@ -618,7 +631,7 @@ def _set_focus_position(self, position: int) -> None:
raise IndexError(f"Overlay widget focus_position currently must always be set to 1, not {position}")

@property
def contents(self):
def contents(self) -> MutableSequence[tuple[TopWidget | BottomWidget, OverlayOptions]]:
"""
a list-like object similar to::
Expand All @@ -642,14 +655,28 @@ def contents(self):
"""

# noinspection PyMethodParameters
class OverlayContents(typing.Sequence[typing.Tuple[typing.Union[TopWidget, BottomWidget], OverlayOptions]]):
class OverlayContents(
typing.MutableSequence[
typing.Tuple[
typing.Union[TopWidget, BottomWidget],
OverlayOptions,
]
]
):

# pylint: disable=no-self-argument
def __len__(inner_self) -> int:
return 2

__getitem__ = self._contents__getitem__
__setitem__ = self._contents__setitem__

def __delitem__(self, index: int | slice) -> typing.NoReturn:
raise TypeError("OverlayContents is fixed-sized sequence")

def insert(self, index: int | slice, value: typing.Any) -> typing.NoReturn:
raise TypeError("OverlayContents is fixed-sized sequence")

def __repr__(inner_self) -> str:
return repr(f"<{inner_self.__class__.__name__}({[inner_self[0], inner_self[1]]})> for {self}")

Expand All @@ -664,7 +691,7 @@ def __iter__(inner_self) -> Iterator[tuple[Widget, OverlayOptions]]:
return OverlayContents()

@contents.setter
def contents(self, new_contents):
def contents(self, new_contents: Collection[tuple[width, OverlayOptions]]):
if len(new_contents) != 2:
raise ValueError("Contents length for overlay should be only 2")
self.contents[0] = new_contents[0]
Expand Down

0 comments on commit b2c1d1e

Please sign in to comment.