mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
fix basic
This commit is contained in:
@@ -13,10 +13,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
App > Screen {
|
App > Screen {
|
||||||
layout: dock;
|
|
||||||
docks: side=left/1;
|
|
||||||
background: $surface;
|
background: $surface;
|
||||||
color: $text-surface;
|
color: $text-surface;
|
||||||
|
layers: sidebar;
|
||||||
|
|
||||||
|
color: $text-background;
|
||||||
|
background: $background;
|
||||||
|
layout: vertical;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DataTable {
|
DataTable {
|
||||||
@@ -31,11 +36,12 @@ DataTable {
|
|||||||
#sidebar {
|
#sidebar {
|
||||||
color: $text-panel;
|
color: $text-panel;
|
||||||
background: $panel;
|
background: $panel;
|
||||||
dock: side;
|
dock: left;
|
||||||
width: 30;
|
width: 30;
|
||||||
offset-x: -100%;
|
offset-x: -100%;
|
||||||
layout: dock;
|
|
||||||
transition: offset 500ms in_out_cubic;
|
transition: offset 500ms in_out_cubic;
|
||||||
|
layer: sidebar;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sidebar.-active {
|
#sidebar.-active {
|
||||||
@@ -71,14 +77,7 @@ DataTable {
|
|||||||
height: 1;
|
height: 1;
|
||||||
content-align: center middle;
|
content-align: center middle;
|
||||||
|
|
||||||
|
dock: top;
|
||||||
}
|
|
||||||
|
|
||||||
#content {
|
|
||||||
color: $text-background;
|
|
||||||
background: $background;
|
|
||||||
layout: vertical;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -168,6 +167,7 @@ Tweet.scroll-horizontal TweetBody {
|
|||||||
height: 1;
|
height: 1;
|
||||||
|
|
||||||
content-align: center middle;
|
content-align: center middle;
|
||||||
|
dock:bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from rich.console import RenderableType
|
from rich.console import RenderableType
|
||||||
from rich.style import Style
|
|
||||||
from rich.syntax import Syntax
|
from rich.syntax import Syntax
|
||||||
from rich.text import Text
|
from rich.text import Text
|
||||||
|
|
||||||
from textual.app import App
|
from textual.app import App, ComposeResult
|
||||||
from textual.reactive import Reactive
|
from textual.reactive import Reactive
|
||||||
from textual.widget import Widget
|
from textual.widget import Widget
|
||||||
from textual.widgets import Static, DataTable
|
from textual.widgets import Static, DataTable
|
||||||
@@ -98,45 +98,45 @@ class BasicApp(App, css_path="basic.css"):
|
|||||||
"""Bind keys here."""
|
"""Bind keys here."""
|
||||||
self.bind("s", "toggle_class('#sidebar', '-active')")
|
self.bind("s", "toggle_class('#sidebar', '-active')")
|
||||||
|
|
||||||
def on_mount(self):
|
def compose(self) -> ComposeResult:
|
||||||
"""Build layout here."""
|
|
||||||
|
|
||||||
table = DataTable()
|
table = DataTable()
|
||||||
self.scroll_to_target = Tweet(TweetBody())
|
self.scroll_to_target = Tweet(TweetBody())
|
||||||
self.mount(
|
|
||||||
header=Static(
|
yield Static(
|
||||||
Text.from_markup(
|
Text.from_markup(
|
||||||
"[b]This is a [u]Textual[/u] app, running in the terminal"
|
"[b]This is a [u]Textual[/u] app, running in the terminal"
|
||||||
),
|
|
||||||
),
|
|
||||||
content=Widget(
|
|
||||||
Tweet(TweetBody()),
|
|
||||||
Widget(
|
|
||||||
Static(Syntax(CODE, "python"), classes="code"),
|
|
||||||
classes="scrollable",
|
|
||||||
),
|
|
||||||
table,
|
|
||||||
Error(),
|
|
||||||
Tweet(TweetBody(), classes="scrollbar-size-custom"),
|
|
||||||
Warning(),
|
|
||||||
Tweet(TweetBody(), classes="scroll-horizontal"),
|
|
||||||
Success(),
|
|
||||||
Tweet(TweetBody(), classes="scroll-horizontal"),
|
|
||||||
Tweet(TweetBody(), classes="scroll-horizontal"),
|
|
||||||
Tweet(TweetBody(), classes="scroll-horizontal"),
|
|
||||||
Tweet(TweetBody(), classes="scroll-horizontal"),
|
|
||||||
Tweet(TweetBody(), classes="scroll-horizontal"),
|
|
||||||
),
|
|
||||||
footer=Widget(),
|
|
||||||
sidebar=Widget(
|
|
||||||
Widget(classes="title"),
|
|
||||||
Widget(classes="user"),
|
|
||||||
OptionItem(),
|
|
||||||
OptionItem(),
|
|
||||||
OptionItem(),
|
|
||||||
Widget(classes="content"),
|
|
||||||
),
|
),
|
||||||
|
id="header",
|
||||||
)
|
)
|
||||||
|
yield from (
|
||||||
|
Tweet(TweetBody()),
|
||||||
|
Widget(
|
||||||
|
Static(Syntax(CODE, "python"), classes="code"),
|
||||||
|
classes="scrollable",
|
||||||
|
),
|
||||||
|
table,
|
||||||
|
Error(),
|
||||||
|
Tweet(TweetBody(), classes="scrollbar-size-custom"),
|
||||||
|
Warning(),
|
||||||
|
Tweet(TweetBody(), classes="scroll-horizontal"),
|
||||||
|
Success(),
|
||||||
|
Tweet(TweetBody(), classes="scroll-horizontal"),
|
||||||
|
Tweet(TweetBody(), classes="scroll-horizontal"),
|
||||||
|
Tweet(TweetBody(), classes="scroll-horizontal"),
|
||||||
|
Tweet(TweetBody(), classes="scroll-horizontal"),
|
||||||
|
Tweet(TweetBody(), classes="scroll-horizontal"),
|
||||||
|
)
|
||||||
|
yield Widget(id="footer")
|
||||||
|
yield Widget(
|
||||||
|
Widget(classes="title"),
|
||||||
|
Widget(classes="user"),
|
||||||
|
OptionItem(),
|
||||||
|
OptionItem(),
|
||||||
|
OptionItem(),
|
||||||
|
Widget(classes="content"),
|
||||||
|
id="sidebar",
|
||||||
|
)
|
||||||
|
|
||||||
table.add_column("Foo", width=20)
|
table.add_column("Foo", width=20)
|
||||||
table.add_column("Bar", width=20)
|
table.add_column("Bar", width=20)
|
||||||
table.add_column("Baz", width=20)
|
table.add_column("Baz", width=20)
|
||||||
|
|||||||
@@ -41,8 +41,9 @@ class DockApp(App):
|
|||||||
|
|
||||||
for n, color in zip(range(5), ["red", "green", "blue", "yellow", "magenta"]):
|
for n, color in zip(range(5), ["red", "green", "blue", "yellow", "magenta"]):
|
||||||
thing = Static(f"Thing {n}", id=f"#thing{n}")
|
thing = Static(f"Thing {n}", id=f"#thing{n}")
|
||||||
|
thing.styles.border = ("heavy", "rgba(0,0,0,0.2)")
|
||||||
thing.styles.background = f"{color} 20%"
|
thing.styles.background = f"{color} 20%"
|
||||||
thing.styles.height = 5
|
thing.styles.height = 15
|
||||||
yield thing
|
yield thing
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,16 +5,25 @@ from fractions import Fraction
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from .geometry import Region, Size, Spacing
|
from .geometry import Region, Size, Spacing
|
||||||
from ._layout import ArrangeResult, WidgetPlacement
|
from ._layout import DockArrangeResult, WidgetPlacement
|
||||||
from ._partition import partition
|
from ._partition import partition
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ._layout import ArrangeResult
|
|
||||||
from .widget import Widget
|
from .widget import Widget
|
||||||
|
|
||||||
|
|
||||||
def arrange(widget: Widget, size: Size, viewport: Size) -> ArrangeResult:
|
def arrange(widget: Widget, size: Size, viewport: Size) -> DockArrangeResult:
|
||||||
|
"""Arrange widgets by applying docks and calling layouts
|
||||||
|
|
||||||
|
Args:
|
||||||
|
widget (Widget): The parent (container) widget.
|
||||||
|
size (Size): The size of the available area.
|
||||||
|
viewport (Size): The size of the viewport (terminal).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple[list[WidgetPlacement], set[Widget], Spacing]: Widget arrangement information.
|
||||||
|
"""
|
||||||
display_children = [child for child in widget.children if child.display]
|
display_children = [child for child in widget.children if child.display]
|
||||||
|
|
||||||
arrange_widgets: set[Widget] = set()
|
arrange_widgets: set[Widget] = set()
|
||||||
@@ -31,7 +40,8 @@ def arrange(widget: Widget, size: Size, viewport: Size) -> ArrangeResult:
|
|||||||
|
|
||||||
_WidgetPlacement = WidgetPlacement
|
_WidgetPlacement = WidgetPlacement
|
||||||
|
|
||||||
top_z = 2**32 - 1
|
# TODO: This is a bit of a fudge, need to ensure it is impossible for layouts to generate this value
|
||||||
|
top_z = 2**31 - 1
|
||||||
|
|
||||||
scroll_spacing = Spacing()
|
scroll_spacing = Spacing()
|
||||||
|
|
||||||
@@ -47,23 +57,15 @@ def arrange(widget: Widget, size: Size, viewport: Size) -> ArrangeResult:
|
|||||||
for dock_widget in dock_widgets:
|
for dock_widget in dock_widgets:
|
||||||
edge = dock_widget.styles.dock
|
edge = dock_widget.styles.dock
|
||||||
|
|
||||||
(
|
fraction_unit = Fraction(
|
||||||
widget_width_fraction,
|
size.height if edge in ("top", "bottom") else size.width
|
||||||
widget_height_fraction,
|
|
||||||
margin,
|
|
||||||
) = dock_widget.get_box_model(
|
|
||||||
size,
|
|
||||||
viewport,
|
|
||||||
Fraction(size.height if edge in ("top", "bottom") else size.width),
|
|
||||||
)
|
)
|
||||||
|
box_model = dock_widget.get_box_model(size, viewport, fraction_unit)
|
||||||
|
widget_width_fraction, widget_height_fraction, margin = box_model
|
||||||
|
|
||||||
widget_width = int(widget_width_fraction) + margin.width
|
widget_width = int(widget_width_fraction) + margin.width
|
||||||
widget_height = int(widget_height_fraction) + margin.height
|
widget_height = int(widget_height_fraction) + margin.height
|
||||||
|
|
||||||
align_offset = dock_widget.styles.align_size(
|
|
||||||
(widget_width, widget_height), size
|
|
||||||
)
|
|
||||||
|
|
||||||
if edge == "bottom":
|
if edge == "bottom":
|
||||||
dock_region = Region(
|
dock_region = Region(
|
||||||
0, height - widget_height, widget_width, widget_height
|
0, height - widget_height, widget_width, widget_height
|
||||||
@@ -80,13 +82,18 @@ def arrange(widget: Widget, size: Size, viewport: Size) -> ArrangeResult:
|
|||||||
width - widget_width, 0, widget_width, widget_height
|
width - widget_width, 0, widget_width, widget_height
|
||||||
)
|
)
|
||||||
right = max(right, dock_region.width)
|
right = max(right, dock_region.width)
|
||||||
|
else:
|
||||||
|
raise AssertionError("invalid value for edge")
|
||||||
|
|
||||||
|
align_offset = dock_widget.styles.align_size(
|
||||||
|
(widget_width, widget_height), size
|
||||||
|
)
|
||||||
dock_region = dock_region.shrink(margin).translate(align_offset)
|
dock_region = dock_region.shrink(margin).translate(align_offset)
|
||||||
add_placement(_WidgetPlacement(dock_region, dock_widget, top_z, True))
|
add_placement(_WidgetPlacement(dock_region, dock_widget, top_z, True))
|
||||||
|
|
||||||
dock_spacing = Spacing(top, right, bottom, left)
|
dock_spacing = Spacing(top, right, bottom, left)
|
||||||
region = size.region.shrink(dock_spacing)
|
region = size.region.shrink(dock_spacing)
|
||||||
layout_placements, _layout_widgets, spacing = widget.layout.arrange(
|
layout_placements, _layout_widgets = widget.layout.arrange(
|
||||||
widget, layout_widgets, region.size
|
widget, layout_widgets, region.size
|
||||||
)
|
)
|
||||||
if _layout_widgets:
|
if _layout_widgets:
|
||||||
@@ -101,26 +108,4 @@ def arrange(widget: Widget, size: Size, viewport: Size) -> ArrangeResult:
|
|||||||
|
|
||||||
placements.extend(layout_placements)
|
placements.extend(layout_placements)
|
||||||
|
|
||||||
result = ArrangeResult(placements, arrange_widgets, scroll_spacing)
|
return placements, arrange_widgets, scroll_spacing
|
||||||
return result
|
|
||||||
|
|
||||||
# dock_spacing = Spacing(top, right, bottom, left)
|
|
||||||
# region = region.shrink(dock_spacing)
|
|
||||||
|
|
||||||
# placements, placement_widgets, spacing = widget.layout.arrange(
|
|
||||||
# widget, layout_widgets, region.size
|
|
||||||
# )
|
|
||||||
# dock_spacing += spacing
|
|
||||||
|
|
||||||
# placement_offset = region.offset
|
|
||||||
# if placement_offset:
|
|
||||||
# placements = [
|
|
||||||
# _WidgetPlacement(_region + placement_offset, widget, order, fixed)
|
|
||||||
# for _region, widget, order, fixed in placements
|
|
||||||
# ]
|
|
||||||
|
|
||||||
# return ArrangeResult(
|
|
||||||
# (dock_placements + placements),
|
|
||||||
# placement_widgets.union(layout_widgets),
|
|
||||||
# dock_spacing,
|
|
||||||
# )
|
|
||||||
|
|||||||
@@ -17,12 +17,8 @@ if TYPE_CHECKING:
|
|||||||
from .widget import Widget
|
from .widget import Widget
|
||||||
|
|
||||||
|
|
||||||
class ArrangeResult(NamedTuple):
|
ArrangeResult: TypeAlias = "tuple[list[WidgetPlacement], set[Widget]]"
|
||||||
"""The result of an arrange operation."""
|
DockArrangeResult: TypeAlias = "tuple[list[WidgetPlacement], set[Widget], Spacing]"
|
||||||
|
|
||||||
placements: list[WidgetPlacement]
|
|
||||||
widgets: set[Widget]
|
|
||||||
spacing: Spacing = Spacing()
|
|
||||||
|
|
||||||
|
|
||||||
class WidgetPlacement(NamedTuple):
|
class WidgetPlacement(NamedTuple):
|
||||||
@@ -93,6 +89,6 @@ class Layout(ABC):
|
|||||||
if not widget.displayed_children:
|
if not widget.displayed_children:
|
||||||
height = container.height
|
height = container.height
|
||||||
else:
|
else:
|
||||||
placements, widgets = widget._arrange(Size(width, container.height))
|
placements, *_ = widget._arrange(Size(width, container.height))
|
||||||
height = max(placement.region.bottom for placement in placements)
|
height = max(placement.region.bottom for placement in placements)
|
||||||
return height
|
return height
|
||||||
|
|||||||
@@ -246,7 +246,9 @@ class StylesCache:
|
|||||||
line: Iterable[Segment]
|
line: Iterable[Segment]
|
||||||
# Draw top or bottom borders (A)
|
# Draw top or bottom borders (A)
|
||||||
if (border_top and y == 0) or (border_bottom and y == height - 1):
|
if (border_top and y == 0) or (border_bottom and y == height - 1):
|
||||||
border_color = border_top_color if y == 0 else border_bottom_color
|
border_color = background + (
|
||||||
|
border_top_color if y == 0 else border_bottom_color
|
||||||
|
)
|
||||||
box_segments = get_box(
|
box_segments = get_box(
|
||||||
border_top if y == 0 else border_bottom,
|
border_top if y == 0 else border_bottom,
|
||||||
inner,
|
inner,
|
||||||
@@ -290,9 +292,9 @@ class StylesCache:
|
|||||||
|
|
||||||
if border_left or border_right:
|
if border_left or border_right:
|
||||||
# Add left / right border
|
# Add left / right border
|
||||||
left_style = from_color(border_left_color.rich_color)
|
left_style = from_color((background + border_left_color).rich_color)
|
||||||
left = get_box(border_left, inner, outer, left_style)[1][0]
|
left = get_box(border_left, inner, outer, left_style)[1][0]
|
||||||
right_style = from_color(border_right_color.rich_color)
|
right_style = from_color((background + border_right_color).rich_color)
|
||||||
right = get_box(border_right, inner, outer, right_style)[1][2]
|
right = get_box(border_right, inner, outer, right_style)[1][2]
|
||||||
|
|
||||||
if border_left and border_right:
|
if border_left and border_right:
|
||||||
@@ -321,9 +323,9 @@ class StylesCache:
|
|||||||
|
|
||||||
elif outline_left or outline_right:
|
elif outline_left or outline_right:
|
||||||
# Lines in side outline
|
# Lines in side outline
|
||||||
left_style = from_color(outline_left_color.rich_color)
|
left_style = from_color((background + outline_left_color).rich_color)
|
||||||
left = get_box(outline_left, inner, outer, left_style)[1][0]
|
left = get_box(outline_left, inner, outer, left_style)[1][0]
|
||||||
right_style = from_color(outline_right_color.rich_color)
|
right_style = from_color((background + outline_right_color).rich_color)
|
||||||
right = get_box(outline_right, inner, outer, right_style)[1][2]
|
right = get_box(outline_right, inner, outer, right_style)[1][2]
|
||||||
line = line_trim(list(line), outline_left != "", outline_right != "")
|
line = line_trim(list(line), outline_left != "", outline_right != "")
|
||||||
if outline_left and outline_right:
|
if outline_left and outline_right:
|
||||||
|
|||||||
@@ -802,8 +802,9 @@ class NameListProperty:
|
|||||||
class ColorProperty:
|
class ColorProperty:
|
||||||
"""Descriptor for getting and setting color properties."""
|
"""Descriptor for getting and setting color properties."""
|
||||||
|
|
||||||
def __init__(self, default_color: Color | str) -> None:
|
def __init__(self, default_color: Color | str, background: bool = False) -> None:
|
||||||
self._default_color = Color.parse(default_color)
|
self._default_color = Color.parse(default_color)
|
||||||
|
self._is_background = background
|
||||||
|
|
||||||
def __set_name__(self, owner: StylesBase, name: str) -> None:
|
def __set_name__(self, owner: StylesBase, name: str) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
@@ -837,10 +838,10 @@ class ColorProperty:
|
|||||||
_rich_traceback_omit = True
|
_rich_traceback_omit = True
|
||||||
if color is None:
|
if color is None:
|
||||||
if obj.clear_rule(self.name):
|
if obj.clear_rule(self.name):
|
||||||
obj.refresh(children=True)
|
obj.refresh(children=self._is_background)
|
||||||
elif isinstance(color, Color):
|
elif isinstance(color, Color):
|
||||||
if obj.set_rule(self.name, color):
|
if obj.set_rule(self.name, color):
|
||||||
obj.refresh(children=True)
|
obj.refresh(children=self._is_background)
|
||||||
elif isinstance(color, str):
|
elif isinstance(color, str):
|
||||||
alpha = 1.0
|
alpha = 1.0
|
||||||
parsed_color = Color(255, 255, 255)
|
parsed_color = Color(255, 255, 255)
|
||||||
@@ -862,7 +863,7 @@ class ColorProperty:
|
|||||||
)
|
)
|
||||||
parsed_color = parsed_color.with_alpha(alpha)
|
parsed_color = parsed_color.with_alpha(alpha)
|
||||||
if obj.set_rule(self.name, parsed_color):
|
if obj.set_rule(self.name, parsed_color):
|
||||||
obj.refresh(children=True)
|
obj.refresh(children=self._is_background)
|
||||||
else:
|
else:
|
||||||
raise StyleValueError(f"Invalid color value {color}")
|
raise StyleValueError(f"Invalid color value {color}")
|
||||||
|
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ class StylesBase(ABC):
|
|||||||
layout = LayoutProperty()
|
layout = LayoutProperty()
|
||||||
|
|
||||||
color = ColorProperty(Color(255, 255, 255))
|
color = ColorProperty(Color(255, 255, 255))
|
||||||
background = ColorProperty(Color(0, 0, 0, 0))
|
background = ColorProperty(Color(0, 0, 0, 0), background=True)
|
||||||
text_style = StyleFlagsProperty()
|
text_style = StyleFlagsProperty()
|
||||||
|
|
||||||
opacity = FractionalProperty()
|
opacity = FractionalProperty()
|
||||||
@@ -437,6 +437,15 @@ class StylesBase(ABC):
|
|||||||
return offset_y
|
return offset_y
|
||||||
|
|
||||||
def align_size(self, child: tuple[int, int], parent: tuple[int, int]) -> Offset:
|
def align_size(self, child: tuple[int, int], parent: tuple[int, int]) -> Offset:
|
||||||
|
"""Align a size according to alignment rules.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
child (tuple[int, int]): The size of the child (width, height)
|
||||||
|
parent (tuple[int, int]): The size of the parent (width, height)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Offset: Offset required to align the child.
|
||||||
|
"""
|
||||||
width, height = child
|
width, height = child
|
||||||
parent_width, parent_height = parent
|
parent_width, parent_height = parent
|
||||||
return Offset(
|
return Offset(
|
||||||
|
|||||||
@@ -304,6 +304,8 @@ class Stylesheet:
|
|||||||
animate (bool, optional): Animate changed rules. Defaults to ``False``.
|
animate (bool, optional): Animate changed rules. Defaults to ``False``.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
print(node)
|
||||||
|
|
||||||
# Dictionary of rule attribute names e.g. "text_background" to list of tuples.
|
# Dictionary of rule attribute names e.g. "text_background" to list of tuples.
|
||||||
# The tuples contain the rule specificity, and the value for that rule.
|
# The tuples contain the rule specificity, and the value for that rule.
|
||||||
# We can use this to determine, for a given rule, whether we should apply it
|
# We can use this to determine, for a given rule, whether we should apply it
|
||||||
@@ -405,7 +407,12 @@ class Stylesheet:
|
|||||||
else:
|
else:
|
||||||
# Not animated, so we apply the rules directly
|
# Not animated, so we apply the rules directly
|
||||||
get_rule = rules.get
|
get_rule = rules.get
|
||||||
|
from ..screen import Screen
|
||||||
|
|
||||||
for key in modified_rule_keys:
|
for key in modified_rule_keys:
|
||||||
|
if isinstance(node, Screen):
|
||||||
|
|
||||||
|
print(node, key, get_rule(key))
|
||||||
setattr(base_styles, key, get_rule(key))
|
setattr(base_styles, key, get_rule(key))
|
||||||
|
|
||||||
node.post_message_no_wait(messages.StylesUpdated(sender=node))
|
node.post_message_no_wait(messages.StylesUpdated(sender=node))
|
||||||
|
|||||||
@@ -60,4 +60,4 @@ class VerticalLayout(Layout):
|
|||||||
total_region = Region(0, 0, size.width, int(y))
|
total_region = Region(0, 0, size.width, int(y))
|
||||||
add_placement(WidgetPlacement(total_region, None, 0))
|
add_placement(WidgetPlacement(total_region, None, 0))
|
||||||
|
|
||||||
return ArrangeResult(placements, set(children))
|
return placements, set(children)
|
||||||
|
|||||||
@@ -117,7 +117,11 @@ class Screen(Widget):
|
|||||||
self._refresh_layout()
|
self._refresh_layout()
|
||||||
self._layout_required = False
|
self._layout_required = False
|
||||||
self._dirty_widgets.clear()
|
self._dirty_widgets.clear()
|
||||||
elif self._dirty_widgets:
|
if self._repaint_required:
|
||||||
|
self._dirty_widgets.add(self)
|
||||||
|
self._repaint_required = False
|
||||||
|
|
||||||
|
if self._dirty_widgets:
|
||||||
self.update_timer.resume()
|
self.update_timer.resume()
|
||||||
|
|
||||||
def _on_update(self) -> None:
|
def _on_update(self) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user