Browse Source

more work on formulas: allow referenced objects access, allow ignore export, added hidden column support

Nicolas Cannasse 4 years ago
parent
commit
3cdfcf749f
4 changed files with 113 additions and 21 deletions
  1. 28 14
      hide/comp/cdb/DataFiles.hx
  2. 2 0
      hide/comp/cdb/Editor.hx
  3. 63 2
      hide/comp/cdb/Formulas.hx
  4. 20 5
      hide/comp/cdb/ModalColumnForm.hx

+ 28 - 14
hide/comp/cdb/DataFiles.hx

@@ -142,7 +142,21 @@ class DataFiles {
 		var temp = [];
 		var titles = [];
 		var prefabs = new Map();
-		for( s in base.sheets )
+		for( s in base.sheets ) {
+			for( c in s.columns ) {
+				var p : Editor.EditorColumnProps = c.editor;
+				if( p != null && p.ignoreExport ) {
+					var prev = [for( o in s.lines ) Reflect.field(o, c.name)];
+					for( o in s.lines ) Reflect.deleteField(o, c.name);
+					temp.push(function() {
+						for( i in 0...prev.length ) {
+							var v = prev[i];
+							if( v == null ) continue;
+							Reflect.setField(s.lines[i], c.name, v);
+						}
+					});
+				}
+			}
 			if( s.props.dataFiles != null ) {
 				var sheet = @:privateAccess s.sheet;
 				var sheetName = getTypeName(s);
@@ -166,29 +180,29 @@ class DataFiles {
 							inst.props = o;
 					}
 				}
-				temp.push(Reflect.copy(sheet));
-				titles.push(sheet.props.separatorTitles);
+				var old = Reflect.copy(sheet);
+				var oldTitles = sheet.props.separatorTitles;
+				temp.push(function() {
+					sheet.lines = old.lines;
+					sheet.linesData = old.linesData;
+					sheet.separators = old.separators;
+					sheet.props.separatorTitles = oldTitles;
+				});
 				Reflect.deleteField(sheet,"lines");
 				Reflect.deleteField(sheet,"linesData");
-				Reflect.deleteField(sheet.props,"separatorTitles");
 				sheet.separators = [];
+				Reflect.deleteField(sheet.props,"separatorTitles");
 			}
+		}
 		for( file => pf in prefabs ) {
 			skip++;
 			sys.io.File.saveContent(ide.getPath(file), ide.toJSON(pf.saveData()));
 		}
 		if( onSaveBase != null )
 			onSaveBase();
-		for( s in base.sheets ) {
-			if( s.props.dataFiles != null ) {
-				var d = temp.shift();
-				var sheet = @:privateAccess s.sheet;
-				sheet.lines = d.lines;
-				sheet.linesData = d.linesData;
-				sheet.separators = d.separators;
-				sheet.props.separatorTitles = titles.shift();
-			}
-		}
+		temp.reverse();
+		for( t in temp )
+			t();
 	}
 
 	// ---- TYPES Instances API -----

+ 2 - 0
hide/comp/cdb/Editor.hx

@@ -21,6 +21,7 @@ typedef EditorApi = {
 
 typedef EditorColumnProps = {
 	var ?formula : String;
+	var ?ignoreExport : Bool;
 }
 
 @:allow(hide.comp.cdb)
@@ -589,6 +590,7 @@ class Editor extends Component {
 		});
 
 		formulas = new Formulas(this);
+		formulas.evaluateAll(currentSheet.realSheet);
 
 		var content = new Element("<table>");
 		tables = [];

+ 63 - 2
hide/comp/cdb/Formulas.hx

@@ -28,6 +28,7 @@ class Formulas {
 	}
 
 	public function evaluateAll( ?sheet : cdb.Sheet ) {
+		var maps = new Map();
 		for( s in editor.base.sheets ) {
 			if( sheet != null && sheet != s ) continue;
 			var forms = fmap.get(s.name);
@@ -39,11 +40,14 @@ class Formulas {
 					columns.push({ name : c.name, def : def, opt : c.opt });
 				}
 			for( o in s.getLines() ) {
+				var omapped : Dynamic = null;
 				for( c in columns ) {
 					var fname : String = Reflect.field(o,c.name+"__f");
 					if( fname == null ) fname = c.def;
 					if( fname == null ) continue;
-					var v = try forms.get(fname).call(o) catch( e : Dynamic ) Math.NaN;
+					if( omapped == null )
+						omapped = remap(o, s, maps);
+					var v = try forms.get(fname).call(omapped) catch( e : Dynamic ) Math.NaN;
 					if( v == null && c.opt )
 						Reflect.deleteField(o, c.name);
 					else {
@@ -55,6 +59,37 @@ class Formulas {
 		}
 	}
 
+	function remap( o : Dynamic, s : cdb.Sheet, maps : Map<String,Dynamic> ) : Dynamic {
+		var id = s.idCol != null ? Reflect.field(o, s.idCol.name) : null;
+		var m = if( id != null ) maps.get(s.name+":"+id) else null;
+		if( m != null )
+			return m;
+		m = {};
+		if( id != null )
+			maps.set(s.name+":"+id, m);
+		for( c in s.columns ) {
+			var v : Dynamic = Reflect.field(o, c.name);
+			if( v == null ) continue;
+			switch( c.type ) {
+			case TRef(other):
+				var sother = editor.base.getSheet(other);
+				var o2 = sother.index.get(v);
+				if( o2 == null ) continue;
+				v = remap(o2.obj, sother, maps);
+			case TProperties:
+				v = remap(v, s.getSub(c), maps);
+			case TList:
+				var sub = s.getSub(c);
+				v = [for( o in (v:Array<Dynamic>) ) remap(o, sub, maps)];
+			//case TEnum(values) -- TODO later (remap String?)
+			//case TFlags(values) -- TODO later
+			default:
+			}
+			Reflect.setField(m, c.name, v);
+		}
+		return m;
+	}
+
 	function load() {
 		var code = try sys.io.File.getContent(ide.getPath(formulasFile)) catch( e : Dynamic ) return;
 		var parser = new hscript.Parser();
@@ -78,6 +113,7 @@ class Formulas {
 		formulas = [];
 		fmap = new Map();
 		var interp = new hscript.Interp();
+		interp.variables.set("Math", Math);
 		try interp.execute(expr) catch( e : hscript.Expr.Error ) {
 			ide.error(formulasFile+": "+e.toString());
 			return;
@@ -203,6 +239,31 @@ class FormulasView extends hide.view.Script {
 			if( s.idCol != null )
 				skind.set(s.name, check.addCDBEnum(s.name.split("@").join(".")));
 		}
+
+		var mfields = new Map<String,CField>();
+		inline function field(name,t,r,?r2) {
+			mfields.set(name, {
+				name : name,
+				t : r2 == null ? TFun([{ name : "v", t : t, opt : false }], r) : TFun([{ name : "v1", t: t, opt : false },{ name : "v2", t : r, opt : false }],r2),
+				isPublic : true,
+				complete : true,
+				canWrite : false,
+				params : [],
+			});
+		}
+		field("ceil",TFloat,TInt);
+		field("floor",TFloat,TInt);
+		field("round",TFloat,TInt);
+		field("sqrt",TFloat,TInt);
+		field("abs",TFloat,TFloat);
+		field("pow",TFloat,TFloat,TFloat);
+		@:privateAccess check.checker.setGlobal("Math", TInst({
+			name : "Math",
+			fields : mfields,
+			statics : [],
+			params : [],
+		},[]));
+
 		var tstring = check.checker.types.resolve("String");
 		var cdefs = new Map();
 		for( s in ide.database.sheets ) {
@@ -223,7 +284,7 @@ class FormulasView extends hide.view.Script {
 				case TFloat: TFloat;
 				case TBool: TBool;
 				case TDynamic: TDynamic;
-				case TRef(other): skind.get(other);
+				case TRef(other): TInst(cdefs.get(other),[]);
 				case TCustom(_), TImage, TLayer(_), TTileLayer, TTilePos: null;
 				case TList, TProperties:
 					var t = TInst(cdefs.get(s.name+"@"+c.name),[]);

+ 20 - 5
hide/comp/cdb/ModalColumnForm.hx

@@ -107,9 +107,15 @@ class ModalColumnForm extends Modal {
 						<select name="formula">
 						<option value="">None</option>
 						</select>
+						<label><input type="checkbox" name="export" style="float:none;display:inline-block" checked/>&nbsp;Export</label>
 					</td>
 				</tr>
 
+				<tr class="doc hide">
+					<td>&nbsp;
+					<td><label><input type="checkbox" name="hidden"/>&nbsp;Hidden</label>
+				</tr>
+
 				<tr class="doc hide">
 					<td>Documentation
 					<td><textarea name="doc"></textarea>
@@ -180,10 +186,11 @@ class ModalColumnForm extends Modal {
 		for( f in editor.formulas.getList(sheet) )
 			new Element("<option>").attr("value", f.name).text(f.name).appendTo(cforms);
 
-		form.find(".hide").addClass("can-hide");
-		form.find(".doctog").click(function(_) {
+		function toggleHide() {
 			form.find(".can-hide").toggleClass("hide");
-		});
+		}
+		form.find(".hide").addClass("can-hide");
+		form.find(".doctog").click(function(_) toggleHide());
 
 		if (editForm) {
 			form.addClass("edit");
@@ -193,6 +200,7 @@ class ModalColumnForm extends Modal {
 			form.find("[name=display]").val(column.display == null ? "0" : Std.string(column.display));
 			form.find("[name=kind]").val(column.kind == null ? "" : ""+column.kind);
 			form.find("[name=scope]").val(column.scope == null ? "" : ""+column.scope);
+			form.find("[name=hidden]").prop("checked", column.kind == Hidden);
 			if( column.documentation != null ) {
 				form.find("[name=doc]").val(column.documentation);
 				form.find(".doc").removeClass("hide");
@@ -206,8 +214,9 @@ class ModalColumnForm extends Modal {
 			case TCustom(name):
 				form.find("[name=ctype]").val(name);
 			case TInt, TFloat:
-				var f = editor.getColumnProps(column).formula;
-				form.find("[name=formula]").val( f == null ? "" : f );
+				var p = editor.getColumnProps(column);
+				form.find("[name=formula]").val( p.formula == null ? "" : p.formula );
+				form.find("[name=export]").prop( "checked", !p.ignoreExport );
 			default:
 			}
 		} else {
@@ -225,6 +234,8 @@ class ModalColumnForm extends Modal {
 		contentModal.click( function(e) e.stopPropagation());
 
 		form.find("#cancelBtn").click(function(e) closeModal());
+		if( column != null && editor.getColumnProps(column).formula != null )
+			toggleHide();
 	}
 
 	public function setCallback(callback : (Void -> Void)) {
@@ -311,15 +322,19 @@ class ModalColumnForm extends Modal {
 		};
 		if( v.req != "on" ) c.opt = true;
 		if( v.display != "0" ) c.display = cast Std.parseInt(v.display);
+		c.kind = null;
 		switch( v.kind ) {
 		case "localizable": c.kind = Localizable;
 		case "script": c.kind = Script;
 		}
+		if( form.find("[name=hidden]").is(":checked") ) c.kind = Hidden;
+
 		var props = editor.getColumnProps(c);
 		switch( t ) {
 		case TFloat, TInt:
 			props.formula = form.find("[name=formula]").val();
 			if( props.formula == "" ) props.formula = null;
+			props.ignoreExport = props.formula != null && !form.find("[name=export]").is(":checked") ? true : null;
 		default:
 		}
 		if( t == TId && v.scope != "" ) c.scope = Std.parseInt(v.scope);