mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
layers and z
This commit is contained in:
@@ -10,11 +10,13 @@ class BasicApp(App):
|
||||
App > DockView {
|
||||
layout: dock;
|
||||
docks: sidebar=left widgets=top;
|
||||
layers: base panels;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
dock-group: sidebar;
|
||||
width: 40;
|
||||
layer: panels;
|
||||
}
|
||||
|
||||
#widget1 {
|
||||
|
||||
@@ -312,7 +312,7 @@ class NameProperty:
|
||||
self._internal_name = f"_rule_{name}"
|
||||
|
||||
def __get__(self, obj: Styles, objtype: type[Styles] | None) -> str:
|
||||
return getattr(obj, self._internal_name, None) or ""
|
||||
return getattr(obj, self._internal_name) or ""
|
||||
|
||||
def __set__(self, obj: Styles, name: str | None) -> str | None:
|
||||
if not isinstance(name, str):
|
||||
|
||||
@@ -320,3 +320,16 @@ class StylesBuilder:
|
||||
self.styles.dock_edge = tokens[0].value if tokens else ""
|
||||
except StyleValueError as error:
|
||||
self.error(name, tokens[0], str(error))
|
||||
|
||||
def process_layer(self, name: str, tokens: list[Token]) -> None:
|
||||
if len(tokens) > 1:
|
||||
self.error(name, tokens[1], f"unexpected tokens in dock-edge declaration")
|
||||
self.styles._rule_layer = tokens[0].value
|
||||
|
||||
def process_layers(self, name: str, tokens: list[Token]) -> None:
|
||||
layers: list[str] = []
|
||||
for token in tokens:
|
||||
if token.name != "token":
|
||||
self.error(name, token, "{token.name} not expected here")
|
||||
layers.append(token.value)
|
||||
self.styles._rule_layers = tuple(layers)
|
||||
|
||||
@@ -8,11 +8,10 @@ if TYPE_CHECKING:
|
||||
from ..dom import DOMNode
|
||||
|
||||
|
||||
def match(selector_sets: Iterable[SelectorSet], node: DOMNode):
|
||||
for selector_set in selector_sets:
|
||||
if _check_selectors(selector_set.selectors, node):
|
||||
return True
|
||||
return False
|
||||
def match(selector_sets: Iterable[SelectorSet], node: DOMNode) -> bool:
|
||||
return any(
|
||||
_check_selectors(selector_set.selectors, node) for selector_set in selector_sets
|
||||
)
|
||||
|
||||
|
||||
def _check_selectors(selectors: list[Selector], node: DOMNode) -> bool:
|
||||
|
||||
@@ -32,10 +32,6 @@ class Location:
|
||||
column: tuple[int, int]
|
||||
|
||||
|
||||
def _default_check(node: DOMNode) -> bool | None:
|
||||
return True
|
||||
|
||||
|
||||
@dataclass
|
||||
class Selector:
|
||||
name: str
|
||||
@@ -67,27 +63,27 @@ class Selector:
|
||||
SelectorType.ID: self._check_id,
|
||||
}
|
||||
|
||||
def check(self, node: DOMNode) -> bool | None:
|
||||
def check(self, node: DOMNode) -> bool:
|
||||
return self._checks[self.type](node)
|
||||
|
||||
def _check_universal(self, node: DOMNode) -> bool | None:
|
||||
def _check_universal(self, node: DOMNode) -> bool:
|
||||
return True
|
||||
|
||||
def _check_type(self, node: DOMNode) -> bool | None:
|
||||
def _check_type(self, node: DOMNode) -> bool:
|
||||
if node.css_type != self._name_lower:
|
||||
return False
|
||||
if self.pseudo_classes and not node.has_psuedo_class(*self.pseudo_classes):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _check_class(self, node: DOMNode) -> bool | None:
|
||||
def _check_class(self, node: DOMNode) -> bool:
|
||||
if not node.has_class(self._name_lower):
|
||||
return False
|
||||
if self.pseudo_classes and not node.has_psuedo_class(*self.pseudo_classes):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _check_id(self, node: DOMNode) -> bool | None:
|
||||
def _check_id(self, node: DOMNode) -> bool:
|
||||
if not node.id == self._name_lower:
|
||||
return False
|
||||
if self.pseudo_classes and not node.has_psuedo_class(*self.pseudo_classes):
|
||||
@@ -110,9 +106,8 @@ class SelectorSet:
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
SAME = CombinatorType.SAME
|
||||
# self.selectors[-1].advance = 1
|
||||
for selector, next_selector in zip(self.selectors, self.selectors[1:]):
|
||||
selector.advance = 0 if next_selector.combinator == SAME else 1
|
||||
selector.advance = int(next_selector.combinator != SAME)
|
||||
|
||||
def __rich_repr__(self) -> rich.repr.Result:
|
||||
selectors = RuleSet._selector_to_css(self.selectors)
|
||||
@@ -157,6 +152,11 @@ class RuleSet:
|
||||
|
||||
@property
|
||||
def css(self) -> str:
|
||||
"""Generate the CSS this RuleSet
|
||||
|
||||
Returns:
|
||||
str: A string containing CSS code.
|
||||
"""
|
||||
declarations = "\n".join(f" {line}" for line in self.styles.css_lines)
|
||||
css = f"{self.selectors} {{\n{declarations}\n}}"
|
||||
return css
|
||||
|
||||
@@ -74,8 +74,8 @@ class Styles:
|
||||
_rule_dock_edge: str | None = None
|
||||
_rule_docks: tuple[tuple[str, str], ...] | None = None
|
||||
|
||||
_rule_layers: str | None = None
|
||||
_rule_layer: tuple[str, ...] | None = None
|
||||
_rule_layers: tuple[str, ...] | None = None
|
||||
_rule_layer: str | None = None
|
||||
|
||||
important: set[str] = field(default_factory=set)
|
||||
|
||||
|
||||
@@ -17,6 +17,10 @@ if TYPE_CHECKING:
|
||||
from .widget import Widget
|
||||
|
||||
|
||||
class NoParent(Exception):
|
||||
pass
|
||||
|
||||
|
||||
@rich.repr.auto
|
||||
class DOMNode(MessagePump):
|
||||
"""A node in a hierarchy of things forming the UI.
|
||||
@@ -39,6 +43,13 @@ class DOMNode(MessagePump):
|
||||
if self._classes:
|
||||
yield "classes", self._classes
|
||||
|
||||
@property
|
||||
def parent(self) -> DOMNode:
|
||||
if self._parent is None:
|
||||
raise NoParent(f"{self._parent} has no parent")
|
||||
assert isinstance(self._parent, DOMNode)
|
||||
return self._parent
|
||||
|
||||
@property
|
||||
def id(self) -> str | None:
|
||||
return self._id
|
||||
@@ -84,6 +95,27 @@ class DOMNode(MessagePump):
|
||||
def visible(self) -> bool:
|
||||
return self.styles.display != "none"
|
||||
|
||||
@property
|
||||
def z(self) -> tuple[int, ...]:
|
||||
"""Get the z index tuple for this node.
|
||||
|
||||
Returns:
|
||||
tuple[int, ...]: A tuple of ints to sort layers by.
|
||||
"""
|
||||
indexes: list[int] = []
|
||||
append = indexes.append
|
||||
node = self
|
||||
while node._parent:
|
||||
styles = node.styles
|
||||
parent_styles = node.parent.styles
|
||||
append(
|
||||
parent_styles.layers.index(styles.layer)
|
||||
if styles.layer in parent_styles.layers
|
||||
else 0
|
||||
)
|
||||
node = node.parent
|
||||
return tuple(reversed(indexes))
|
||||
|
||||
@property
|
||||
def tree(self) -> Tree:
|
||||
highlighter = ReprHighlighter()
|
||||
|
||||
@@ -48,10 +48,8 @@ class MessagePump:
|
||||
return self._task
|
||||
|
||||
@property
|
||||
def parent(self) -> MessagePump:
|
||||
if self._parent is None:
|
||||
raise NoParent(f"{self._parent} has no parent")
|
||||
return self._parent
|
||||
def has_parent(self) -> bool:
|
||||
return self._parent is not None
|
||||
|
||||
@property
|
||||
def app(self) -> "App":
|
||||
|
||||
Reference in New Issue
Block a user