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.""" """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:

View File

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

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

View File

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