Advertisement
Guest User

Untitled

a guest
Nov 28th, 2018
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Haxe 7.35 KB | None | 0 0
  1. package haxe.ui.binding;
  2.  
  3. import haxe.ui.core.Component;
  4. import haxe.ui.scripting.ScriptInterp;
  5. import hscript.Expr;
  6. import hscript.Interp;
  7. import hscript.Parser;
  8.  
  9. class PropertyInfo {
  10.     public var name:String;
  11.     public var script:String;
  12.    
  13.     public var objects:Map<String, Array<String>> = new Map<String, Array<String>>();
  14.    
  15.     public function new() {
  16.     }
  17.    
  18.     public function addObject(objectId:String, objectProp:String) {
  19.         var array:Array<String> = objects.get(objectId);
  20.         if (array == null) {
  21.             array = [];
  22.             objects.set(objectId, array);
  23.         }
  24.         if (array.indexOf(objectProp) == -1) {
  25.             array.push(objectProp);
  26.         }
  27.     }
  28. }
  29.  
  30. class TargetInfo {
  31.     public var props:Map<String, Map<Component, Array<PropertyInfo>>> = new Map<String, Map<Component, Array<PropertyInfo>>>();
  32.    
  33.     public function new() {
  34.     }
  35.    
  36.     public function addBinding(sourceProp:String, target:Component, targetProp:PropertyInfo) {
  37.         var map:Map<Component, Array<PropertyInfo>> = props.get(sourceProp);
  38.         if (map == null) {
  39.             map = new Map<Component, Array<PropertyInfo>>();
  40.             props.set(sourceProp, map);
  41.         }
  42.        
  43.         var array = map.get(target);
  44.         if (array == null) {
  45.             array = new Array<PropertyInfo>();
  46.             map.set(target, array);
  47.         }
  48.  
  49.         array.push(targetProp);
  50.     }
  51. }
  52.  
  53. class BindingInfo {
  54.     public var props:Map<String, PropertyInfo> = new Map<String, PropertyInfo>();
  55.    
  56.     public function new() {
  57.     }
  58.    
  59.     public function addProp(name:String, script:String):PropertyInfo {
  60.         var p = props.get(name);
  61.         if (p == null) {
  62.             p = new PropertyInfo();
  63.             p.name = name;
  64.             p.script = script;
  65.             props.set(name, p);
  66.         }
  67.         return p;
  68.     }
  69. }
  70.  
  71. class BindingManager {
  72.     private static var _instance:BindingManager = null;
  73.     public static var instance(get, null):BindingManager;
  74.     private static function get_instance():BindingManager {
  75.         if (_instance == null) {
  76.             _instance = new BindingManager();
  77.         }
  78.         return _instance;
  79.     }
  80.    
  81.     //****************************************************************************************************
  82.     // Instance
  83.     //****************************************************************************************************
  84.     private static var bindingInfo:Map<Component, BindingInfo> = new Map<Component, BindingInfo>();
  85.     private static var targets:Map<String, TargetInfo> = new Map<String, TargetInfo>();
  86.    
  87.     private function new() {
  88.     }
  89.    
  90.     public function add(c:Component, prop:String, script:String) {
  91.         var n1:Int = script.indexOf("${");
  92.         while (n1 != -1) {
  93.             var n2:Int = script.indexOf("}", n1);
  94.             var scriptPart:String = script.substr(n1 + 2, n2 - n1 - 2);
  95.        
  96.             var parser:Parser = new Parser();
  97.             var expr:Expr = parser.parseString(scriptPart);
  98.            
  99.             var info = bindingInfo.get(c);
  100.             if (info == null) {
  101.                 info = new BindingInfo();
  102.                 bindingInfo.set(c, info);
  103.             }
  104.  
  105.             var propInfo:PropertyInfo = info.addProp(prop, script);
  106.             extractFields(expr, propInfo);
  107.             for (objectId in propInfo.objects.keys()) {
  108.                 for (fieldId in propInfo.objects.get(objectId)) {
  109.                     var targetInfo = targets.get(objectId);
  110.                     if (targetInfo == null) {
  111.                         targetInfo = new TargetInfo();
  112.                         targets.set(objectId, targetInfo);
  113.                     }
  114.                     targetInfo.addBinding(fieldId, c, propInfo);
  115.                 }
  116.             }
  117.             handleProp(c, propInfo);
  118.            
  119.             n1 = script.indexOf("${", n2);
  120.         }
  121.     }
  122.    
  123.     public function componentPropChanged(c:Component, prop:String) {
  124.         if (c == null || c.id == null) {
  125.             return;
  126.         }
  127.        
  128.         var targetInfo = targets.get(c.id);
  129.         if (targetInfo == null) {
  130.             return;
  131.         }
  132.        
  133.         var map:Map<Component, Array<PropertyInfo>> = targetInfo.props.get(prop);
  134.         if (map == null) {
  135.             return;
  136.         }
  137.  
  138.         for (t in map.keys()) {
  139.             var array:Array<PropertyInfo> = map.get(t);
  140.             for (prop in array) {
  141.                 handleProp(t, prop);
  142.             }
  143.         }
  144.     }
  145.    
  146.     private function handleProp(t:Component, prop:PropertyInfo) {
  147.         var result:Dynamic = interpolate(prop.script, prop, t);
  148.         var currentType = Type.typeof(Reflect.getProperty(t, prop.name));
  149.         if (currentType == TFloat) {
  150.             result = Std.parseFloat(Std.string(result));
  151.         } else if (currentType == TInt) {
  152.             result = Std.parseInt(Std.string(result));
  153.         } else if (currentType == TBool) {
  154.             result = (Std.string(result) == "true");
  155.         }
  156.        
  157.         Reflect.setProperty(t, prop.name, result);
  158.     }
  159.    
  160.     private function interpolate(s:String, prop:PropertyInfo, t:Component):String {
  161.         var copy:String = s;
  162.         var n1:Int = copy.indexOf("${");
  163.         while (n1 != -1) {
  164.             var n2:Int = copy.indexOf("}", n1);
  165.             var before:String = copy.substr(0, n1);
  166.             var after:String = copy.substr(n2 + 1, copy.length);
  167.             var script:String = copy.substr(n1 + 2, n2 - n1 - 2);
  168.            
  169.             var result = exec(script, prop, t);
  170.             copy = before + result + after;
  171.             n1 = copy.indexOf("${");
  172.         }
  173.         return copy;
  174.     }
  175.  
  176.     private var interp = new ScriptInterp();
  177.     private function exec(script:String, prop:PropertyInfo, t:Component) {
  178.         var parser = new Parser();
  179.         var expr = parser.parseString(script);
  180.        
  181.         interp.variables = new Map<String,Dynamic>();
  182.         var root = findRoot(t);
  183.         for (objectId in prop.objects.keys()) {
  184.             interp.variables.set(objectId, root.findComponent(objectId));
  185.         }
  186.         interp.variables.set("this", t);
  187.        
  188.         var result:Dynamic = interp.expr(expr);
  189.         return result;
  190.     }
  191.    
  192.     private function findRoot(c:Component):Component {
  193.         var root = c;
  194.        
  195.         var ref = c;
  196.         while (ref != null) {
  197.             root = ref;
  198.             if (root.bindingRoot) {
  199.                 break;
  200.             }
  201.             ref = ref.parentComponent;
  202.         }
  203.        
  204.         return root;
  205.     }
  206.    
  207.     private function extractFields(expr:Expr, propInfo:PropertyInfo) {
  208.         switch (expr) {
  209.             case ECall(e, params):
  210.                 for (p in params) {
  211.                     extractFields(p, propInfo);
  212.                 }
  213.             case EField(EIdent(objectId), fieldId):
  214.                 propInfo.addObject(objectId, fieldId);
  215.             case EIdent(objectId):
  216.                 propInfo.addObject(objectId, "value");
  217.             case EBinop(op, e1, e2):    
  218.                     extractFields(e1, propInfo);
  219.                     extractFields(e2, propInfo);
  220.             case EUnop(op, prefix, e):    
  221.                     extractFields(e, propInfo);
  222.             case EConst(_):        
  223.             case _:
  224.                 trace(expr);
  225.         }
  226.     }
  227. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement