mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Move LayoutProperty into styles, add some comments
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
/* CSS file for basic.py */
|
||||
|
||||
App > View {
|
||||
layout: dock;
|
||||
docks: side=left/1;
|
||||
text: on #20639b;
|
||||
}
|
||||
|
||||
@@ -510,7 +510,7 @@ class App(DOMNode):
|
||||
# Handle input events that haven't been forwarded
|
||||
# If the event has been forwarded it may have bubbled up back to the App
|
||||
if isinstance(event, events.Mount):
|
||||
view = View()
|
||||
view = View(id="_root")
|
||||
self.register(self, view)
|
||||
await self.push_view(view)
|
||||
await super().on_event(event)
|
||||
|
||||
@@ -28,6 +28,7 @@ from .constants import NULL_SPACING
|
||||
from .errors import StyleTypeError, StyleValueError
|
||||
from .transition import Transition
|
||||
from ._error_tools import friendly_list
|
||||
from ..layouts.factory import get_layout
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .styles import Styles
|
||||
@@ -290,6 +291,22 @@ class DockProperty:
|
||||
return spacing
|
||||
|
||||
|
||||
class LayoutProperty:
|
||||
def __set_name__(self, owner: Styles, name: str) -> None:
|
||||
self._internal_name = f"_rule_{name}"
|
||||
|
||||
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> str:
|
||||
return getattr(obj, self._internal_name) or ""
|
||||
|
||||
def __set__(self, obj: Styles, layout: str | Styles):
|
||||
obj.refresh(True)
|
||||
if isinstance(layout, str):
|
||||
new_layout = get_layout(layout)
|
||||
else:
|
||||
new_layout = layout
|
||||
self._layout = new_layout
|
||||
|
||||
|
||||
class OffsetProperty:
|
||||
def __set_name__(self, owner: Styles, name: str) -> None:
|
||||
self._internal_name = f"_rule_{name}"
|
||||
|
||||
@@ -42,6 +42,7 @@ from ._style_properties import (
|
||||
StyleProperty,
|
||||
StyleFlagsProperty,
|
||||
TransitionsProperty,
|
||||
LayoutProperty,
|
||||
)
|
||||
from .types import Display, Edge, Visibility
|
||||
|
||||
@@ -110,7 +111,7 @@ class Styles:
|
||||
|
||||
display = StringProperty(VALID_DISPLAY, "block")
|
||||
visibility = StringProperty(VALID_VISIBILITY, "visible")
|
||||
layout = StringProperty(VALID_LAYOUT, "dock")
|
||||
layout = LayoutProperty()
|
||||
|
||||
text = StyleProperty()
|
||||
text_color = ColorProperty()
|
||||
@@ -279,6 +280,10 @@ class Styles:
|
||||
)
|
||||
else:
|
||||
setattr(styles, f"_rule_{key}", value)
|
||||
|
||||
if self.node.id == "_root":
|
||||
log("_root.styles.layout =", self.node.styles.layout)
|
||||
|
||||
if self.node is not None:
|
||||
self.node.on_style_change()
|
||||
|
||||
|
||||
@@ -108,18 +108,24 @@ class Stylesheet:
|
||||
yield selector_set.specificity
|
||||
|
||||
def apply(self, node: DOMNode) -> None:
|
||||
# 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.
|
||||
# We can use this to determine, for a given rule, whether we should apply it
|
||||
# or not by examining the specificity. If we have two rules for the
|
||||
# same attribute, then we can choose the most specific rule and use that.
|
||||
rule_attributes: dict[str, list[tuple[Specificity4, object]]]
|
||||
rule_attributes = defaultdict(list)
|
||||
|
||||
_check_rule = self._check_rule
|
||||
|
||||
# TODO: The line below breaks inline styles and animations
|
||||
node.styles.reset()
|
||||
|
||||
# Get the default node CSS rules
|
||||
# Collect default node CSS rules
|
||||
for key, default_specificity, value in node._default_rules:
|
||||
rule_attributes[key].append((default_specificity, value))
|
||||
|
||||
# Apply styles on top of the default node CSS rules
|
||||
# Collect the rules defined in the stylesheet
|
||||
for rule in self.rules:
|
||||
for specificity in _check_rule(rule, node):
|
||||
for key, rule_specificity, value in rule.styles.extract_rules(
|
||||
@@ -127,12 +133,14 @@ class Stylesheet:
|
||||
):
|
||||
rule_attributes[key].append((rule_specificity, value))
|
||||
|
||||
# For each rule declared for this node, keep only the most specific one
|
||||
get_first_item = itemgetter(0)
|
||||
node_rules = [
|
||||
(name, max(specificity_rules, key=get_first_item)[1])
|
||||
for name, specificity_rules in rule_attributes.items()
|
||||
]
|
||||
|
||||
log(node.id, node_rules)
|
||||
node.styles.apply_rules(node_rules)
|
||||
|
||||
def update(self, root: DOMNode) -> None:
|
||||
|
||||
@@ -16,26 +16,13 @@ from .layouts.factory import get_layout
|
||||
from .geometry import Size, Offset, Region
|
||||
from .reactive import Reactive, watch
|
||||
|
||||
from .widget import Widget, Widget
|
||||
from .widget import Widget
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .app import App
|
||||
|
||||
|
||||
class LayoutProperty:
|
||||
def __get__(self, obj: View, objtype: type[View] | None = None) -> str:
|
||||
return obj._layout.name
|
||||
|
||||
def __set__(self, obj: View, layout: str | Layout) -> str:
|
||||
if isinstance(layout, str):
|
||||
new_layout = get_layout(layout)
|
||||
else:
|
||||
new_layout = layout
|
||||
self._layout = new_layout
|
||||
return self._layout.name
|
||||
|
||||
|
||||
@rich.repr.auto
|
||||
class View(Widget):
|
||||
|
||||
@@ -45,7 +32,7 @@ class View(Widget):
|
||||
"""
|
||||
|
||||
def __init__(self, name: str | None = None, id: str | None = None) -> None:
|
||||
|
||||
# TODO: Get rid of this, replace usages with layout from Styles object
|
||||
from .layouts.dock import DockLayout
|
||||
|
||||
self._layout: Layout = DockLayout()
|
||||
@@ -69,8 +56,6 @@ class View(Widget):
|
||||
cls.layout_factory = layout
|
||||
super().__init_subclass__(**kwargs)
|
||||
|
||||
layout = LayoutProperty()
|
||||
|
||||
background: Reactive[str] = Reactive("")
|
||||
scroll_x: Reactive[int] = Reactive(0)
|
||||
scroll_y: Reactive[int] = Reactive(0)
|
||||
|
||||
Reference in New Issue
Block a user