Move LayoutProperty into styles, add some comments

This commit is contained in:
Darren Burns
2022-01-21 12:33:35 +00:00
parent 185788b760
commit 5773e39845
6 changed files with 37 additions and 21 deletions

View File

@@ -1,6 +1,7 @@
/* CSS file for basic.py */
App > View {
layout: dock;
docks: side=left/1;
text: on #20639b;
}

View File

@@ -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)

View File

@@ -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}"

View File

@@ -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()

View File

@@ -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:

View File

@@ -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)