mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
replace rules
This commit is contained in:
@@ -11,9 +11,9 @@ class BasicApp(App):
|
|||||||
"""Build layout here."""
|
"""Build layout here."""
|
||||||
self.mount(
|
self.mount(
|
||||||
header=Widget(),
|
header=Widget(),
|
||||||
# content=Placeholder(),
|
content=Placeholder(),
|
||||||
# footer=Widget(),
|
footer=Widget(),
|
||||||
# sidebar=Widget(),
|
sidebar=Widget(),
|
||||||
)
|
)
|
||||||
|
|
||||||
async def on_key(self, event: events.Key) -> None:
|
async def on_key(self, event: events.Key) -> None:
|
||||||
|
|||||||
@@ -683,17 +683,12 @@ class App(DOMNode):
|
|||||||
|
|
||||||
async def action_add_class_(self, selector: str, class_name: str) -> None:
|
async def action_add_class_(self, selector: str, class_name: str) -> None:
|
||||||
self.view.query(selector).add_class(class_name)
|
self.view.query(selector).add_class(class_name)
|
||||||
self.view.refresh(layout=True)
|
|
||||||
|
|
||||||
async def action_remove_class_(self, selector: str, class_name: str) -> None:
|
async def action_remove_class_(self, selector: str, class_name: str) -> None:
|
||||||
self.view.query(selector).remove_class(class_name)
|
self.view.query(selector).remove_class(class_name)
|
||||||
self.view.refresh(layout=True)
|
|
||||||
|
|
||||||
async def action_toggle_class(self, selector: str, class_name: str) -> None:
|
async def action_toggle_class(self, selector: str, class_name: str) -> None:
|
||||||
self.view.query(selector).toggle_class(class_name)
|
self.view.query(selector).toggle_class(class_name)
|
||||||
self.view.refresh(layout=True)
|
|
||||||
|
|
||||||
async def handle_styles_updated(self, message: messages.StylesUpdated) -> None:
|
async def handle_styles_updated(self, message: messages.StylesUpdated) -> None:
|
||||||
self.reset_styles()
|
|
||||||
self.stylesheet.update(self)
|
self.stylesheet.update(self)
|
||||||
self.view.refresh(layout=True)
|
|
||||||
|
|||||||
@@ -180,11 +180,13 @@ class Stylesheet:
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
self.apply_rules(node, node_rules, animate=animate)
|
self.replace_rules(node, node_rules, animate=animate)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def apply_rules(cls, node: DOMNode, rules: RulesMap, animate: bool = False) -> None:
|
def replace_rules(
|
||||||
"""Apply style rules to a node, animating as required.
|
cls, node: DOMNode, rules: RulesMap, animate: bool = False
|
||||||
|
) -> None:
|
||||||
|
"""Replace style rules to a node, animating as required.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
node (DOMNode): A DOM node.
|
node (DOMNode): A DOM node.
|
||||||
@@ -192,114 +194,67 @@ class Stylesheet:
|
|||||||
animate (bool, optional): Enable animation. Defaults to False.
|
animate (bool, optional): Enable animation. Defaults to False.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Alias styles and base styles
|
||||||
styles = node.styles
|
styles = node.styles
|
||||||
base_styles = styles.base
|
base_styles = styles.base
|
||||||
|
|
||||||
|
# Styles currently used an new rules
|
||||||
modified_rule_keys = {*base_styles.get_rules().keys(), *rules.keys()}
|
modified_rule_keys = {*base_styles.get_rules().keys(), *rules.keys()}
|
||||||
|
# Current render rules (missing rules are filled with default)
|
||||||
current_render_rules = styles.get_render_rules()
|
current_render_rules = styles.get_render_rules()
|
||||||
|
|
||||||
|
# Calculate replacement rules (defaults + new rules)
|
||||||
new_styles = node._default_styles.copy()
|
new_styles = node._default_styles.copy()
|
||||||
new_styles.merge(rules)
|
new_styles.merge_rules(rules)
|
||||||
|
|
||||||
|
# New render rules
|
||||||
new_render_rules = new_styles.get_render_rules()
|
new_render_rules = new_styles.get_render_rules()
|
||||||
|
|
||||||
base_styles.reset()
|
# Some aliases
|
||||||
base_styles.merge(new_stylea)
|
is_animatable = styles.is_animatable
|
||||||
node.refresh()
|
get_current_render_rule = current_render_rules.get
|
||||||
return
|
get_new_render_rule = new_render_rules.get
|
||||||
|
|
||||||
base_rules = list(base_styles.get_rules().keys())
|
|
||||||
old_rules = {key: None for key in base_rules}
|
|
||||||
rule_updates = {**old_rules, **rules}
|
|
||||||
|
|
||||||
set_rule = base_styles.set_rule
|
|
||||||
base_styles.reset()
|
|
||||||
base_styles.merge(node._default_styles)
|
|
||||||
# base_styles.merge_rules(rules)
|
|
||||||
|
|
||||||
log("*", rule_updates)
|
|
||||||
|
|
||||||
for key, value in rule_updates.items():
|
|
||||||
setattr(base_styles, key, value)
|
|
||||||
|
|
||||||
repaint, layout = styles.check_refresh()
|
|
||||||
if repaint or layout:
|
|
||||||
node.refresh(repaint=repaint, layout=layout)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
# repaint = False
|
|
||||||
# layout = False
|
|
||||||
|
|
||||||
# for (rule_name, rule1), (_, rule2) in zip(start_rules.items(), new_rules.items()):
|
|
||||||
# if rule1 != rule2:
|
|
||||||
|
|
||||||
# return
|
|
||||||
|
|
||||||
styles = node.styles.base
|
|
||||||
styles = Styles()
|
|
||||||
current_styles = styles.get_render_rules()
|
|
||||||
styles.reset()
|
|
||||||
styles.merge_rules(rules)
|
|
||||||
new_styles = styles.get_render_rules()
|
|
||||||
|
|
||||||
for (key, value1), (_, value2) in zip(
|
|
||||||
current_styles.items(), new_styles.items()
|
|
||||||
):
|
|
||||||
if value1 != value2:
|
|
||||||
setattr(styles, key, value1)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
current_styles = styles.get_render_rules()
|
|
||||||
|
|
||||||
styles = node._default_styles.copy()
|
|
||||||
|
|
||||||
styles = node.styles
|
|
||||||
set_rule = styles.base.set_rule
|
|
||||||
current_rules = styles.get_rules()
|
|
||||||
styles.reset()
|
|
||||||
if animate:
|
if animate:
|
||||||
|
for key in modified_rule_keys:
|
||||||
|
# Get old and new render rules
|
||||||
|
old_render_value = get_current_render_rule(key)
|
||||||
|
new_render_value = get_new_render_rule(key)
|
||||||
|
# Get new rule value (may be None)
|
||||||
|
new_value = rules.get(key)
|
||||||
|
|
||||||
is_animatable = styles.is_animatable
|
# Check if this can / should be animated
|
||||||
|
if is_animatable(key) and new_render_value != old_render_value:
|
||||||
for key, value in rules.items():
|
transition = new_styles.get_transition(key)
|
||||||
current = current_rules.get(key)
|
if transition is not None:
|
||||||
if current == value:
|
|
||||||
continue
|
|
||||||
if is_animatable(key):
|
|
||||||
transition = styles.get_transition(key)
|
|
||||||
if transition is None:
|
|
||||||
set_rule(key, value)
|
|
||||||
else:
|
|
||||||
duration, easing, delay = transition
|
duration, easing, delay = transition
|
||||||
node.app.animator.animate(
|
node.app.animator.animate(
|
||||||
node.styles.base,
|
node.styles.base,
|
||||||
key,
|
key,
|
||||||
value,
|
new_render_value,
|
||||||
|
final_value=new_value,
|
||||||
duration=duration,
|
duration=duration,
|
||||||
easing=easing,
|
easing=easing,
|
||||||
)
|
)
|
||||||
else:
|
continue
|
||||||
set_rule(key, value)
|
# Default is to set value (if new_value is None, rule will be removed)
|
||||||
|
setattr(base_styles, key, new_value)
|
||||||
else:
|
else:
|
||||||
for key, value in rules.items():
|
# Not animated, so we apply the rules directly
|
||||||
current = current_rules.get(key)
|
for key in modified_rule_keys:
|
||||||
if current == value:
|
setattr(base_styles, key, rules.get(key))
|
||||||
continue
|
|
||||||
set_rule(key, value)
|
|
||||||
# styles.base.merge_rules(rules)
|
|
||||||
# styles.refresh()
|
|
||||||
|
|
||||||
node.on_style_change()
|
# The styles object may have requested a refresh / layout
|
||||||
|
# It's the style properties that set these flags
|
||||||
|
repaint, layout = styles.check_refresh()
|
||||||
|
if repaint:
|
||||||
|
node.refresh(layout=layout)
|
||||||
|
|
||||||
def update(self, root: DOMNode, animate: bool = False) -> None:
|
def update(self, root: DOMNode, animate: bool = False) -> None:
|
||||||
"""Update a node and its children."""
|
"""Update a node and its children."""
|
||||||
apply = self.apply
|
apply = self.apply
|
||||||
for node in root.walk_children():
|
for node in root.walk_children():
|
||||||
apply(node, animate=animate)
|
apply(node, animate=animate)
|
||||||
# if hasattr(node, "clear_render_cache"):
|
|
||||||
# # TODO: Not ideal
|
|
||||||
# node.clear_render_cache()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -344,7 +344,6 @@ class DOMNode(MessagePump):
|
|||||||
"""
|
"""
|
||||||
self._classes.symmetric_difference_update(class_names)
|
self._classes.symmetric_difference_update(class_names)
|
||||||
self.app.stylesheet.update(self.app, animate=True)
|
self.app.stylesheet.update(self.app, animate=True)
|
||||||
self.app.refresh()
|
|
||||||
|
|
||||||
def has_pseudo_class(self, *class_names: str) -> bool:
|
def has_pseudo_class(self, *class_names: str) -> bool:
|
||||||
"""Check for pseudo class (such as hover, focus etc)"""
|
"""Check for pseudo class (such as hover, focus etc)"""
|
||||||
|
|||||||
Reference in New Issue
Block a user