Skip to content

Commit

Permalink
Fix regression: Columns render incorrect BOX/FLOW widgets height
Browse files Browse the repository at this point in the history
* Fix and re-sort calculation
* Add tests to cover regression
* Add helper property `decoded_text` to `the` Canvas
  to stop a copy-paste decoded lines collection for tests

Fix urwid#753
  • Loading branch information
penguinolog committed Jan 18, 2024
1 parent 9301924 commit 8006260
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 19 deletions.
36 changes: 36 additions & 0 deletions tests/test_columns.py
Original file line number Diff line number Diff line change
Expand Up @@ -708,3 +708,39 @@ def test_deprecated(self):
self.assertEqual(c.column_types, [("flow", None), ("weight", 1), ("weight", 1)])
c.column_types[:] = [("weight", 2)]
self.assertEqual(len(c.contents), 1)

def test_regression_columns_different_height(self):
size = (20, 5)
box_w = urwid.SolidFill("#")
f_f_widget = urwid.Text("Fixed/Flow")
box_flow = urwid.LineBox(urwid.Filler(f_f_widget, valign=urwid.TOP))
self.assertIn(urwid.BOX, box_w.sizing())
self.assertEqual(frozenset((urwid.BOX, urwid.FLOW)), box_flow.sizing())

with self.subTest("BoxFlow weight"):
widget = urwid.Columns(((1, box_w), box_flow))

self.assertEqual(
(
"#┌─────────────────┐",
"#│Fixed/Flow │",
"#│ │",
"#│ │",
"#└─────────────────┘",
),
widget.render(size, False).decoded_text,
)

with self.subTest("BoxFlow GIVEN"):
widget = urwid.Columns((box_w, (12, box_flow)))

self.assertEqual(
(
"########┌──────────┐",
"########│Fixed/Flow│",
"########│ │",
"########│ │",
"########└──────────┘",
),
widget.render(size, False).decoded_text,
)
11 changes: 8 additions & 3 deletions urwid/canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,11 +268,16 @@ def _get_widget_info(self):
@property
def text(self) -> list[bytes]:
"""
Return the text content of the canvas as a list of strings,
one for each row.
Return the text content of the canvas as a list of strings, one for each row.
"""
return [b"".join([text for (attr, cs, text) in row]) for row in self.content()]

@property
def decoded_text(self) -> Sequence[str]:
"""Decoded text content of the canvas as a sequence of strings, one for each row."""
encoding = get_encoding()
return tuple(line.decode(encoding) for line in self.text)

def _text_content(self):
warnings.warn(
f"Method `{self.__class__.__name__}._text_content` is deprecated, "
Expand Down Expand Up @@ -371,7 +376,7 @@ def __repr__(self) -> str:

def __str__(self) -> str:
with contextlib.suppress(BaseException):
return b"\n".join(self.text).decode(get_encoding())
return "\n".join(self.decoded_text)

return repr(self)

Expand Down
23 changes: 7 additions & 16 deletions urwid/widget/columns.py
Original file line number Diff line number Diff line change
Expand Up @@ -821,22 +821,9 @@ def get_column_sizes(
for i, (width, (widget, (size_kind, _size_weight, is_box))) in enumerate(zip(widths, self.contents)):
w_sizing = widget.sizing()

if size_kind == WHSettings.GIVEN:
if is_box:
box.append(i)
elif Sizing.FLOW in w_sizing and not is_box:
heights[i] = widget.rows((width,), focus and i == self.focus_position)
w_h_args[i] = (width,)
else:
box_need_height.append(i)

elif size_kind == WHSettings.PACK:
if Sizing.FLOW in w_sizing:
heights[i] = widget.rows((width,), focus and i == self.focus_position)
w_h_args[i] = (width,)
else:
heights[i] = widget.pack((), focus and i == self.focus_position)[1]
w_h_args[i] = ()
if len(size) == 2 and Sizing.BOX in w_sizing:
heights[i] = size[1]
w_h_args[i] = (width, size[1])

elif is_box:
box.append(i)
Expand All @@ -845,6 +832,10 @@ def get_column_sizes(
heights[i] = widget.rows((width,), focus and i == self.focus_position)
w_h_args[i] = (width,)

elif size_kind == WHSettings.PACK:
heights[i] = widget.pack((), focus and i == self.focus_position)[1]
w_h_args[i] = ()

else:
box_need_height.append(i)

Expand Down

0 comments on commit 8006260

Please sign in to comment.