Merge pull request #436 from Textualize/bugfix-display-none-is-being-ignored-in-vertical-and-horizontal-layouts

[layout][bugfix] Horizontal & Vertical layouts shouldn't display children that have `display: none`
This commit is contained in:
Olivier Philippon
2022-04-28 15:01:20 +01:00
committed by GitHub
7 changed files with 47 additions and 8 deletions

View File

@@ -521,6 +521,7 @@ class App(DOMNode):
mount_event = events.Mount(sender=self) mount_event = events.Mount(sender=self)
await self.dispatch_message(mount_event) await self.dispatch_message(mount_event)
# TODO: don't override `self.console` here
self.console = Console(file=sys.__stdout__) self.console = Console(file=sys.__stdout__)
self.title = self._title self.title = self._title
self.refresh() self.refresh()

View File

@@ -70,7 +70,7 @@ if TYPE_CHECKING:
class RulesMap(TypedDict, total=False): class RulesMap(TypedDict, total=False):
"""A typed dict for CSS rules. """A typed dict for CSS rules.
Any key may be absent, indiciating that rule has not been set. Any key may be absent, indicating that rule has not been set.
Does not define composite rules, that is a rule that is made of a combination of other rules. Does not define composite rules, that is a rule that is made of a combination of other rules.

View File

@@ -278,6 +278,10 @@ class DOMNode(MessagePump):
add_children(tree, self) add_children(tree, self)
return tree return tree
@property
def displayed_children(self) -> list[DOMNode]:
return [child for child in self.children if child.display]
def get_pseudo_classes(self) -> Iterable[str]: def get_pseudo_classes(self) -> Iterable[str]:
"""Get any pseudo classes applicable to this Node, e.g. hover, focus. """Get any pseudo classes applicable to this Node, e.g. hover, focus.

View File

@@ -50,10 +50,9 @@ class DockLayout(Layout):
def get_docks(self, parent: Widget) -> list[Dock]: def get_docks(self, parent: Widget) -> list[Dock]:
groups: dict[str, list[Widget]] = defaultdict(list) groups: dict[str, list[Widget]] = defaultdict(list)
for child in parent.children: for child in parent.displayed_children:
assert isinstance(child, Widget) assert isinstance(child, Widget)
if child.display: groups[child.styles.dock].append(child)
groups[child.styles.dock].append(child)
docks: list[Dock] = [] docks: list[Dock] = []
append_dock = docks.append append_dock = docks.append
for name, edge, z in parent.styles.docks: for name, edge, z in parent.styles.docks:

View File

@@ -39,7 +39,9 @@ class HorizontalLayout(Layout):
x = box_models[0].margin.left if box_models else 0 x = box_models[0].margin.left if box_models else 0
for widget, box_model, margin in zip(parent.children, box_models, margins): displayed_children = parent.displayed_children
for widget, box_model, margin in zip(displayed_children, box_models, margins):
content_width, content_height = box_model.size content_width, content_height = box_model.size
offset_y = widget.styles.align_height(content_height, parent_size.height) offset_y = widget.styles.align_height(content_height, parent_size.height)
region = Region(x, offset_y, content_width, content_height) region = Region(x, offset_y, content_width, content_height)
@@ -53,4 +55,4 @@ class HorizontalLayout(Layout):
total_region = Region(0, 0, max_width, max_height) total_region = Region(0, 0, max_width, max_height)
add_placement(WidgetPlacement(total_region, None, 0)) add_placement(WidgetPlacement(total_region, None, 0))
return placements, set(parent.children) return placements, set(displayed_children)

View File

@@ -40,10 +40,13 @@ class VerticalLayout(Layout):
y = box_models[0].margin.top if box_models else 0 y = box_models[0].margin.top if box_models else 0
for widget, box_model, margin in zip(parent.children, box_models, margins): displayed_children = parent.displayed_children
for widget, box_model, margin in zip(displayed_children, box_models, margins):
content_width, content_height = box_model.size content_width, content_height = box_model.size
offset_x = widget.styles.align_width(content_width, parent_size.width) offset_x = widget.styles.align_width(content_width, parent_size.width)
region = Region(offset_x, y, content_width, content_height) region = Region(offset_x, y, content_width, content_height)
# TODO: it seems that `max_height` is not used?
max_height = max(max_height, content_height) max_height = max(max_height, content_height)
add_placement(WidgetPlacement(region, widget, 0)) add_placement(WidgetPlacement(region, widget, 0))
y += region.height + margin y += region.height + margin
@@ -54,4 +57,4 @@ class VerticalLayout(Layout):
total_region = Region(0, 0, max_width, max_height) total_region = Region(0, 0, max_width, max_height)
add_placement(WidgetPlacement(total_region, None, 0)) add_placement(WidgetPlacement(total_region, None, 0))
return placements, set(parent.children) return placements, set(displayed_children)

View File

@@ -0,0 +1,30 @@
import pytest
from textual.screen import Screen
from textual.widget import Widget
@pytest.mark.parametrize(
"layout,display,expected_in_displayed_children",
[
("dock", "block", True),
("horizontal", "block", True),
("vertical", "block", True),
("dock", "none", False),
("horizontal", "none", False),
("vertical", "none", False),
],
)
def test_nodes_take_display_property_into_account_when_they_display_their_children(
layout: str, display: str, expected_in_displayed_children: bool
):
widget = Widget(name="widget that might not be visible 🥷 ")
widget.styles.display = display
screen = Screen()
screen.styles.layout = layout
screen.add_child(widget)
displayed_children = screen.displayed_children
assert isinstance(displayed_children, list)
assert (widget in screen.displayed_children) is expected_in_displayed_children