Mercurial > MadButterfly
changeset 1362:bb76f9d57363
Generate CSS3 transition rules
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Fri, 18 Feb 2011 09:00:02 +0800 |
parents | cf5ed0b8f45d |
children | a05ea7fa43ec |
files | pyink/html5css3.py |
diffstat | 1 files changed, 190 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/pyink/html5css3.py Thu Feb 17 10:58:40 2011 +0800 +++ b/pyink/html5css3.py Fri Feb 18 09:00:02 2011 +0800 @@ -1,6 +1,6 @@ import pybExtension from domview import component_manager, layers_parser, scenes_parser -from trait import composite +from trait import composite, trait, require def _scene_node_range(node): @@ -16,18 +16,20 @@ scene_type = 'normal' pass - return int(start), int(stop), scene_type + return int(start), int(end), scene_type @composite class dom_parser(object): use_traits = (component_manager, layers_parser, scenes_parser) + provide_traits = {layers_parser.get_scene: '_scenes_get_scene'} method_map_traits = { scenes_parser._find_maxframe: '_find_maxframe', scenes_parser._collect_all_scenes: '_collect_all_scenes', scenes_parser._collect_node_ids: '_collect_node_ids', component_manager._start_component_manager: - '_start_component_manager' + '_start_component_manager', + scenes_parser.get_scene: '_scenes_get_scene' } def __init__(self): @@ -178,17 +180,201 @@ _print_node_close(node, lvl, out) pass + +## \brief CSS3 animation code generator. +# +# This trait parses and generate transition code, in CSS3, for two +# nodes. +# +@trait +class css3_ani_gen(object): + _parse_ani_attrs = require + + _passing = lambda name, value: (name, str(value)) + _trans_transform = lambda name, value: \ + (name, 'matrix(' + ','.join([str(e) for e in value]) + ')') + + _translators = {'x': _passing, 'y': _passing, + 'width': _passing, 'height': _passing, + 'opacity': _passing, 'transform': _trans_transform + } + + del _trans_transform + del _passing + + @staticmethod + def _ani_attr_to_css3(attrname, attrvalue, css): + translator = css3_ani_gen._translators[attrname] + cssname, cssvalue = translator(attrname, attrvalue) + css[cssname] = cssvalue + pass + + def _make_css3_transition(self, node1, node2, duration): + from tween import _normalize_attrs + + ani_attrs1 = self._parse_ani_attrs(node1) + ani_attrs2 = self._parse_ani_attrs(node2) + + _normalize_attrs(node1, ani_attrs1, node2, ani_attrs2) + + css = {} + + attrnames = set(ani_attrs1.keys() + ani_attrs2.keys()) + for attrname in attrnames: + attrvalue = ani_attrs2[attrname] + self._ani_attr_to_css3(attrname, attrvalue, css) + pass + + properties = css.keys() + css['transition-property'] = ', '.join(properties) + css['transition-duration'] = '%gs' % (duration) + + return css + + def _write_css(self, selector, css_props, out): + print >> out, '%s {' % (selector) + for prop_name, prop_value in css_props.items(): + print >> out, ' %s: %s' % (prop_name, prop_value) + pass + print >> out, '}' + pass + pass + + +@composite class html5css3_ext(pybExtension.PYBindExtImp): + use_traits = (css3_ani_gen,) + method_map_traits = {css3_ani_gen._make_css3_transition: + '_make_css3_transition', + css3_ani_gen._write_css: '_write_css' + } + + _frame_rate = 12 + + def __init__(self): + self._stylesheet = {} + pass + + @staticmethod + def _parse_ani_attrs(node): + from tween import _parse_attr_ani, _parse_style_ani + attrs = {} + _parse_attr_ani(node, attrs) + _parse_style_ani(node, attrs) + return attrs + def save(self, module, doc, filename): import sys parser = dom_parser() + self._parser = parser parser.start_handle(doc.rdoc) print parser._maxframe print doc.rdoc.root().allAttributes() print parser.all_comp_names() - print parser._layers print 'save to ' + filename + + self._handle_transition_layers() + print self._stylesheet.keys() + pass + + ## \brief Find all animation pairs. + # + # An animation pair is two nodes, one from start scene group and + # another from stop scene group. The node from start scene group + # will transite to the state of the node from stop scene group. + # This method is responsible for finding all pairs. + # + @staticmethod + def _find_transition_pairs(start_scene_group, stop_scene_group): + # Collect all nodes in stop scene + stop_nodes = {} + node = stop_scene_group.firstChild() + while node: + try: + node_label = node.getAttribute("ns0:duplicate-src") + stop_nodes[node_label] = node + except: + pass + node = node.next() + pass + + # Collect all nodes in start scene + start_nodes = {} + node = start_scene_group.firstChild() + while node: + try: + node_label = node.getAttribute("id") + start_nodes[node_label] = node + except: + pass + node = node.next() + pass + + pairs = [] + for start_node in start_scene_group.childList(): + start_node_id = start_node.getAttribute('id') + try: + stop_node = stop_nodes[start_node_id] + except: + stop_node = start_node + pass + pairs.append((start_node, stop_node)) + pass + + return pairs + + def _handle_transition_layer(self, layer_idx): + parser = self._parser + maxframe = parser.get_maxframe() + stylesheet = self._stylesheet + + frame_idx = 0 + while frame_idx < maxframe: + scene = parser.get_scene(frame_idx, layer_idx) + if not scene: + frame_idx = frame_idx + 1 + continue + + start, end, tween_type = scene + if start == end: + frame_idx = frame_idx + 1 + continue + + next_start = end + 1 + scene = parser.get_scene(next_start, layer_idx) + if not scene: + frame_idx = next_start + 1 + continue + + scene_group = parser.get_scene_group(start, layer_idx) + next_scene_group = parser.get_scene_group(next_start, layer_idx) + + duration = float(next_start - start) / self._frame_rate + + # + # Generate style for every transition pair + # + transition_pairs = \ + self._find_transition_pairs(scene_group, next_scene_group) + for start_node, stop_node in transition_pairs: + css_props = self._make_css3_transition(start_node, + stop_node, + duration) + node_id = start_node.getAttribute('id') + selector = '.transition%d #%s' % (start, node_id) + stylesheet[selector] = css_props + pass + + frame_idx = next_start + pass + pass + + def _handle_transition_layers(self): + num_layers = self._parser.get_layer_num() + for layer_idx in range(num_layers): + self._handle_transition_layer(layer_idx) + pass pass pass