replace rules

This commit is contained in:
Will McGugan
2022-02-17 14:18:57 +00:00
parent ccb891887b
commit 0b131c0b0f
4 changed files with 42 additions and 93 deletions

View File

@@ -11,9 +11,9 @@ class BasicApp(App):
"""Build layout here."""
self.mount(
header=Widget(),
# content=Placeholder(),
# footer=Widget(),
# sidebar=Widget(),
content=Placeholder(),
footer=Widget(),
sidebar=Widget(),
)
async def on_key(self, event: events.Key) -> None:

View File

@@ -683,17 +683,12 @@ class App(DOMNode):
async def action_add_class_(self, selector: str, class_name: str) -> None:
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:
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:
self.view.query(selector).toggle_class(class_name)
self.view.refresh(layout=True)
async def handle_styles_updated(self, message: messages.StylesUpdated) -> None:
self.reset_styles()
self.stylesheet.update(self)
self.view.refresh(layout=True)

View File

@@ -180,11 +180,13 @@ class Stylesheet:
},
)
self.apply_rules(node, node_rules, animate=animate)
self.replace_rules(node, node_rules, animate=animate)
@classmethod
def apply_rules(cls, node: DOMNode, rules: RulesMap, animate: bool = False) -> None:
"""Apply style rules to a node, animating as required.
def replace_rules(
cls, node: DOMNode, rules: RulesMap, animate: bool = False
) -> None:
"""Replace style rules to a node, animating as required.
Args:
node (DOMNode): A DOM node.
@@ -192,114 +194,67 @@ class Stylesheet:
animate (bool, optional): Enable animation. Defaults to False.
"""
# Alias styles and base styles
styles = node.styles
base_styles = styles.base
# Styles currently used an new rules
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()
# Calculate replacement rules (defaults + new rules)
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()
base_styles.reset()
base_styles.merge(new_stylea)
node.refresh()
return
# Some aliases
is_animatable = styles.is_animatable
get_current_render_rule = current_render_rules.get
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:
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
for key, value in rules.items():
current = current_rules.get(key)
if current == value:
continue
if is_animatable(key):
transition = styles.get_transition(key)
if transition is None:
set_rule(key, value)
else:
# Check if this can / should be animated
if is_animatable(key) and new_render_value != old_render_value:
transition = new_styles.get_transition(key)
if transition is not None:
duration, easing, delay = transition
node.app.animator.animate(
node.styles.base,
key,
value,
new_render_value,
final_value=new_value,
duration=duration,
easing=easing,
)
else:
set_rule(key, value)
continue
# Default is to set value (if new_value is None, rule will be removed)
setattr(base_styles, key, new_value)
else:
for key, value in rules.items():
current = current_rules.get(key)
if current == value:
continue
set_rule(key, value)
# styles.base.merge_rules(rules)
# styles.refresh()
# Not animated, so we apply the rules directly
for key in modified_rule_keys:
setattr(base_styles, key, rules.get(key))
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:
"""Update a node and its children."""
apply = self.apply
for node in root.walk_children():
apply(node, animate=animate)
# if hasattr(node, "clear_render_cache"):
# # TODO: Not ideal
# node.clear_render_cache()
if __name__ == "__main__":

View File

@@ -344,7 +344,6 @@ class DOMNode(MessagePump):
"""
self._classes.symmetric_difference_update(class_names)
self.app.stylesheet.update(self.app, animate=True)
self.app.refresh()
def has_pseudo_class(self, *class_names: str) -> bool:
"""Check for pseudo class (such as hover, focus etc)"""