فهرست منبع

start cdb integration

Nicolas Cannasse 8 سال پیش
والد
کامیت
3c113cc64a
8فایلهای تغییر یافته به همراه539 افزوده شده و 2 حذف شده
  1. 4 0
      bin/app.html
  2. 7 0
      bin/style.css
  3. 14 0
      bin/style.less
  4. 2 0
      hide.hxml
  5. 1 1
      hide.hxproj
  6. 450 0
      hide/comp/SheetEditor.hx
  7. 29 1
      hide/ui/Ide.hx
  8. 32 0
      hide/view/CdbTable.hx

+ 4 - 0
bin/app.html

@@ -57,6 +57,10 @@
 		<menu label="About" component="hide.view.About"></menu>
 		<menu label="Debug" class="debug"></menu>
 	</menu>
+	<menu label="Database" class="database">
+		<menu label="View" class="dbview"></menu>
+		<menu label="New Sheet"></menu>
+	</menu>
 	<menu label="Layout" class="layout">
 		<div class="content">
 		</div>

+ 7 - 0
bin/style.css

@@ -335,6 +335,13 @@ input[type=checkbox]:checked:after {
 .hide-properties .group > .content {
   margin-bottom: 5px;
 }
+/* CDB */
+.hide-sheet table {
+  width: 100%;
+  table-layout: fixed;
+  border-collapse: collapse;
+  border-spacing: 0;
+}
 /* Golden Layout Fixes */
 .lm_header .lm_tabs {
   z-index: 1;

+ 14 - 0
bin/style.less

@@ -369,6 +369,20 @@ input[type=checkbox] {
 
 }
 
+/* CDB */
+
+.hide-sheet {
+
+	table {
+		width : 100%;
+		table-layout:fixed;
+		border-collapse : collapse;
+		border-spacing : 0;
+	}
+
+}
+
+
 /* Golden Layout Fixes */
 
 .lm_header .lm_tabs {

+ 2 - 0
hide.hxml

@@ -5,8 +5,10 @@
 -lib heaps
 -lib hxbit
 -lib hscript
+-lib castle
 -D hscriptPos
 -dce no
+-D old-error-format
 --macro include('hide.view')
 --macro include('h3d.prim')
 --macro include('h3d.scene')

+ 1 - 1
hide.hxproj

@@ -24,7 +24,7 @@
     <option noInlineOnDebug="False" />
     <option mainClass="hide.ui.Ide" />
     <option enabledebug="False" />
-    <option additional="-lib hxnodejs&#xA;-lib heaps&#xA;-lib hxbit&#xA;-lib hscript&#xA;-D hscriptPos&#xA;-dce no&#xA;&#xA;--macro include('hide.view')&#xA;--macro include('h3d.prim')&#xA;--macro include('h3d.scene')" />
+    <option additional="-lib hxnodejs&#xA;-lib heaps&#xA;-lib hxbit&#xA;-lib hscript&#xA;-lib castle&#xA;-D hscriptPos&#xA;-dce no&#xA;-D old-error-format&#xA;&#xA;--macro include('hide.view')&#xA;--macro include('h3d.prim')&#xA;--macro include('h3d.scene')" />
   </build>
   <!-- haxelib libraries -->
   <haxelib>

+ 450 - 0
hide/comp/SheetEditor.hx

@@ -0,0 +1,450 @@
+package hide.comp;
+import js.jquery.Helper.*;
+
+private typedef Cursor = {
+	s : cdb.Sheet,
+	x : Int,
+	y : Int,
+	?select : { x : Int, y : Int },
+	?onchange : Void -> Void,
+}
+
+class SheetEditor extends Component {
+
+	static var UID = 0;
+
+	var base : cdb.Database;
+	var sheet : cdb.Sheet;
+	var cursor : Cursor;
+	var existsCache : Map<String,{ t : Float, r : Bool }> = new Map();
+
+	public function new(root, sheet) {
+		super(root);
+		this.sheet = sheet;
+		base = sheet.base;
+		cursor = {
+			s : null,
+			x : 0,
+			y : 0,
+		};
+		refresh();
+	}
+
+	function refresh() {
+
+		root.html('');
+		root.addClass('hide-sheet');
+
+		if( sheet.columns.length == 0 ) {
+			J("<a>Add a column</a>").appendTo(root).click(function(_) {
+				newColumn(sheet);
+			});
+			return;
+		}
+
+		var content = J("<table>");
+		fillTable(content, sheet);
+		content.appendTo(root);
+	}
+
+	function fillTable( content : Element, sheet : cdb.Sheet ) {
+
+		content.attr("sheet", sheet.getPath());
+
+		var cols = J("<tr>").addClass("head");
+		J("<th>").addClass("start").appendTo(cols);
+		var lines = [for( i in 0...sheet.lines.length ) {
+			var l = J("<tr>");
+			l.data("index", i);
+			var head = J("<td>").addClass("start").text("" + i);
+			l.mousedown(function(e) {
+				if( e.which == 3 ) {
+					head.click();
+					//haxe.Timer.delay(popupLine.bind(sheet,i),1);
+					e.preventDefault();
+					return;
+				}
+			}).click(function(e) {
+				if( e.shiftKey && cursor.s == sheet && cursor.x < 0 ) {
+					cursor.select = { x : -1, y : i };
+					updateCursor();
+				} else
+					setCursor(sheet, -1, i);
+			});
+			head.appendTo(l);
+			l;
+		}];
+
+
+		var colCount = sheet.columns.length;
+		var todo = [];
+		var inTodo = false;
+		var types = [for( t in Type.getEnumConstructs(cdb.Data.ColumnType) ) t.substr(1).toLowerCase()];
+		for( cindex in 0...sheet.columns.length ) {
+			var c = sheet.columns[cindex];
+			var col = J("<th>");
+			col.text(c.name);
+			col.addClass( "t_"+c.type.getName().substr(1).toLowerCase() );
+			if( sheet.props.displayColumn == c.name )
+				col.addClass("display");
+			col.mousedown(function(e) {
+				if( e.which == 3 ) {
+					//haxe.Timer.delay(popupColumn.bind(sheet,c),1);
+					e.preventDefault();
+					return;
+				}
+			});
+			col.dblclick(function(_) {
+				newColumn(sheet, c);
+			});
+			cols.append(col);
+
+			var ctype = "t_" + types[Type.enumIndex(c.type)];
+			for( index in 0...sheet.lines.length ) {
+				var obj = sheet.lines[index];
+				var val : Dynamic = Reflect.field(obj,c.name);
+				var v = J("<td>").addClass(ctype).addClass("c");
+				var l = lines[index];
+				v.appendTo(l);
+
+				updateClasses(v, c, val);
+
+				var html = valueHtml(c, val, sheet, obj);
+				if( html == "&nbsp;" ) v.text(" ") else if( html.indexOf('<') < 0 && html.indexOf('&') < 0 ) v.text(html) else v.html(html);
+				v.data("index", cindex);
+				v.click(function(e) {
+					if( inTodo ) {
+						// nothing
+					} else if( e.shiftKey && cursor.s == sheet ) {
+						cursor.select = { x : cindex, y : index };
+						updateCursor();
+						e.stopImmediatePropagation();
+					} else
+						setCursor(sheet, cindex, index);
+					e.stopPropagation();
+				});
+
+				function set(val2:Dynamic) {
+					var old = val;
+					val = val2;
+					if( val == null )
+						Reflect.deleteField(obj, c.name);
+					else
+						Reflect.setField(obj, c.name, val);
+					html = valueHtml(c, val, sheet, obj);
+					v.html(html);
+					updateClasses(v, c, val);
+					//this.changed(sheet, c, index, old);
+					trace("CHANGED");
+				}
+
+				/* TODO */
+			}
+		}
+
+		if( sheet.lines.length == 0 ) {
+			var l = J('<tr><td colspan="${sheet.columns.length + 1}"><a href="javascript:_.insertLine()">Insert Line</a></td></tr>');
+			l.find("a").click(function(_) setCursor(sheet));
+			lines.push(l);
+		}
+
+		content.empty();
+		content.append(cols);
+
+		var snext = 0;
+		for( i in 0...lines.length ) {
+			while( sheet.separators[snext] == i ) {
+				var sep = J("<tr>").addClass("separator").append('<td colspan="${colCount+1}">').appendTo(content);
+				var content = sep.find("td");
+				var title = if( sheet.props.separatorTitles != null ) sheet.props.separatorTitles[snext] else null;
+				if( title != null ) content.text(title);
+				var pos = snext;
+				sep.dblclick(function(e) {
+					content.empty();
+					J("<input>").appendTo(content).focus().val(title == null ? "" : title).blur(function(_) {
+						/*title = JTHIS.val();
+						JTHIS.remove();
+						content.text(title);
+						var titles = sheet.props.separatorTitles;
+						if( titles == null ) titles = [];
+						while( titles.length < pos )
+							titles.push(null);
+						titles[pos] = title == "" ? null : title;
+						while( titles[titles.length - 1] == null && titles.length > 0 )
+							titles.pop();
+						if( titles.length == 0 ) titles = null;
+						sheet.props.separatorTitles = titles;
+						save();*/
+					}).keypress(function(e) {
+						e.stopPropagation();
+					}).keydown(function(e) {
+						if( e.keyCode == 13 ) { JTHIS.blur(); e.preventDefault(); } else if( e.keyCode == 27 ) content.text(title);
+						e.stopPropagation();
+					});
+				});
+				snext++;
+			}
+			content.append(lines[i]);
+		}
+
+		inTodo = true;
+		for( t in todo ) t();
+		inTodo = false;
+	}
+
+
+
+	function setCursor( ?s, ?x=0, ?y=0, ?sel, update = true ) {
+		cursor.s = s;
+		cursor.x = x;
+		cursor.y = y;
+		cursor.select = sel;
+		var ch = cursor.onchange;
+		if( ch != null ) {
+			cursor.onchange = null;
+			ch();
+		}
+		if( update ) updateCursor();
+	}
+
+	function getLine( sheet : cdb.Sheet, index : Int ) {
+		return J("table[sheet='"+sheet.getPath()+"'] > tbody > tr").not(".head,.separator,.list").eq(index);
+	}
+
+	function updateCursor() {
+		J(".selected").removeClass("selected");
+		J(".cursor").removeClass("cursor");
+		J(".cursorLine").removeClass("cursorLine");
+		if( cursor.s == null )
+			return;
+		if( cursor.y < 0 ) {
+			cursor.y = 0;
+			cursor.select = null;
+		}
+		if( cursor.y >= cursor.s.lines.length ) {
+			cursor.y = cursor.s.lines.length - 1;
+			cursor.select = null;
+		}
+		var max = cursor.s.props.isProps ? 1 : cursor.s.columns.length;
+		if( cursor.x >= max ) {
+			cursor.x = max - 1;
+			cursor.select = null;
+		}
+		var l = getLine(cursor.s, cursor.y);
+		if( cursor.x < 0 ) {
+			l.addClass("selected");
+			if( cursor.select != null ) {
+				var y = cursor.y;
+				while( cursor.select.y != y ) {
+					if( cursor.select.y > y ) y++ else y--;
+					getLine(cursor.s, y).addClass("selected");
+				}
+			}
+		} else {
+			l.find("td.c").eq(cursor.x).addClass("cursor").closest("tr").addClass("cursorLine");
+			if( cursor.select != null ) {
+				var s = getSelection();
+				for( y in s.y1...s.y2 + 1 )
+					getLine(cursor.s, y).find("td.c").slice(s.x1, s.x2+1).addClass("selected");
+			}
+		}
+		var e = l[0];
+		if( e != null ) untyped e.scrollIntoViewIfNeeded();
+	}
+
+	public function valueHtml( c : cdb.Data.Column, v : Dynamic, sheet : cdb.Sheet, obj : Dynamic ) : String {
+		if( v == null ) {
+			if( c.opt )
+				return "&nbsp;";
+			return '<span class="error">#NULL</span>';
+		}
+		return switch( c.type ) {
+		case TInt, TFloat:
+			switch( c.display ) {
+			case Percent:
+				(Math.round(v * 10000)/100) + "%";
+			default:
+				v + "";
+			}
+		case TId:
+			v == "" ? '<span class="error">#MISSING</span>' : (base.getSheet(sheet.name).index.get(v).obj == obj ? v : '<span class="error">#DUP($v)</span>');
+		case TString, TLayer(_):
+			v == "" ? "&nbsp;" : StringTools.htmlEscape(v);
+		case TRef(sname):
+			if( v == "" )
+				'<span class="error">#MISSING</span>';
+			else {
+				var s = base.getSheet(sname);
+				var i = s.index.get(v);
+				i == null ? '<span class="error">#REF($v)</span>' : (i.ico == null ? "" : tileHtml(i.ico,true)+" ") + StringTools.htmlEscape(i.disp);
+			}
+		case TBool:
+			v?"Y":"N";
+		case TEnum(values):
+			values[v];
+		case TImage:
+			""; // deprecated
+		case TList:
+			var a : Array<Dynamic> = v;
+			var ps = sheet.getSub(c);
+			var out : Array<String> = [];
+			var size = 0;
+			for( v in a ) {
+				var vals = [];
+				for( c in ps.columns )
+					switch( c.type ) {
+					case TList, TProperties:
+						continue;
+					default:
+						vals.push(valueHtml(c, Reflect.field(v, c.name), ps, v));
+					}
+				var v = vals.length == 1 ? vals[0] : ""+vals;
+				if( size > 200 ) {
+					out.push("...");
+					break;
+				}
+				var vstr = v;
+				if( v.indexOf("<") >= 0 ) {
+					vstr = ~/<img src="[^"]+" style="display:none"[^>]+>/g.replace(vstr, "");
+					vstr = ~/<img src="[^"]+"\/>/g.replace(vstr, "[I]");
+					vstr = ~/<div id="[^>]+><\/div>/g.replace(vstr, "[D]");
+				}
+				size += vstr.length;
+				out.push(v);
+			}
+			if( out.length == 0 )
+				return "[]";
+			return out.join(", ");
+		case TProperties:
+			var ps = sheet.getSub(c);
+			var out = [];
+			for( c in ps.columns ) {
+				var pval = Reflect.field(v, c.name);
+				if( pval == null && c.opt ) continue;
+				out.push(c.name+" : "+valueHtml(c, pval, ps, v));
+			}
+			return out.join("<br/>");
+		case TCustom(name):
+			var t = base.getCustomType(name);
+			var a : Array<Dynamic> = v;
+			var cas = t.cases[a[0]];
+			var str = cas.name;
+			if( cas.args.length > 0 ) {
+				str += "(";
+				var out = [];
+				var pos = 1;
+				for( i in 1...a.length )
+					out.push(valueHtml(cas.args[i-1], a[i], sheet, this));
+				str += out.join(",");
+				str += ")";
+			}
+			str;
+		case TFlags(values):
+			var v : Int = v;
+			var flags = [];
+			for( i in 0...values.length )
+				if( v & (1 << i) != 0 )
+					flags.push(StringTools.htmlEscape(values[i]));
+			flags.length == 0 ? String.fromCharCode(0x2205) : flags.join("|<wbr>");
+		case TColor:
+			'<div class="color" style="background-color:#${StringTools.hex(v,6)}"></div>';
+		case TFile:
+			var path = ide.getPath(v);
+			var url = "file://" + path;
+			var ext = v.split(".").pop().toLowerCase();
+			var html = v == "" ? '<span class="error">#MISSING</span>' : StringTools.htmlEscape(v);
+			if( v != "" && !quickExists(path) )
+				html = '<span class="error">' + html + '</span>';
+			else if( ext == "png" || ext == "jpg" || ext == "jpeg" || ext == "gif" )
+				html = '<span class="preview">$html<div class="previewContent"><div class="label"></div><img src="$url" onload="$(this).parent().find(\'.label\').text(this.width+\'x\'+this.height)"/></div></span>';
+			if( v != "" )
+				html += ' <input type="submit" value="open" onclick="_.openFile(\'$path\')"/>';
+			html;
+		case TTilePos:
+			return tileHtml(v);
+		case TTileLayer:
+			var v : cdb.Types.TileLayer = v;
+			var path = ide.getPath(v.file);
+			if( !quickExists(path) )
+				'<span class="error">' + v.file + '</span>';
+			else
+				'#DATA';
+		case TDynamic:
+			var str = Std.string(v).split("\n").join(" ").split("\t").join("");
+			if( str.length > 50 ) str = str.substr(0, 47) + "...";
+			str;
+		}
+	}
+
+	function tileHtml( v : cdb.Types.TilePos, ?isInline ) {
+		var path = ide.getPath(v.file);
+		if( !quickExists(path) ) {
+			if( isInline ) return "";
+			return '<span class="error">' + v.file + '</span>';
+		}
+		var id = UID++;
+		var width = v.size * (v.width == null?1:v.width);
+		var height = v.size * (v.height == null?1:v.height);
+		var max = width > height ? width : height;
+		var zoom = max <= 32 ? 2 : 64 / max;
+		var inl = isInline ? 'display:inline-block;' : '';
+		var url = "file://" + path;
+		var html = '<div class="tile" id="_c${id}" style="width : ${Std.int(width * zoom)}px; height : ${Std.int(height * zoom)}px; background : url(\'$url\') -${Std.int(v.size*v.x*zoom)}px -${Std.int(v.size*v.y*zoom)}px; opacity:0; $inl"></div>';
+		html += '<img src="$url" style="display:none" onload="$(\'#_c$id\').css({opacity:1, backgroundSize : ((this.width*$zoom)|0)+\'px \' + ((this.height*$zoom)|0)+\'px\' '+(zoom > 1 ? ", imageRendering : 'pixelated'" : "") +'}); if( this.parentNode != null ) this.parentNode.removeChild(this)"/>';
+		return html;
+	}
+
+	function getSelection() {
+		if( cursor.s == null )
+			return null;
+		var x1 = if( cursor.x < 0 ) 0 else cursor.x;
+		var x2 = if( cursor.x < 0 ) cursor.s.columns.length-1 else if( cursor.select != null ) cursor.select.x else x1;
+		var y1 = cursor.y;
+		var y2 = if( cursor.select != null ) cursor.select.y else y1;
+		if( x2 < x1 ) {
+			var tmp = x2;
+			x2 = x1;
+			x1 = tmp;
+		}
+		if( y2 < y1 ) {
+			var tmp = y2;
+			y2 = y1;
+			y1 = tmp;
+		}
+		return { x1 : x1, x2 : x2, y1 : y1, y2 : y2 };
+	}
+
+
+	function quickExists(path) {
+		var c = existsCache.get(path);
+		if( c == null ) {
+			c = { t : -1e9, r : false };
+			existsCache.set(path, c);
+		}
+		var t = haxe.Timer.stamp();
+		if( c.t < t - 10 ) { // cache result for 10s
+			c.r = sys.FileSystem.exists(path);
+			c.t = t;
+		}
+		return c.r;
+	}
+
+	function updateClasses(v:Element, c:cdb.Data.Column, val:Dynamic) {
+		switch( c.type ) {
+		case TBool :
+			v.removeClass("true, false").addClass( val==true ? "true" : "false" );
+		case TInt, TFloat :
+			v.removeClass("zero");
+			if( val==0 )
+				v.addClass("zero");
+		default:
+		}
+	}
+
+	function newColumn( sheet : cdb.Sheet, ?after ) {
+	}
+
+	public dynamic function save() {
+	}
+
+}

+ 29 - 1
hide/ui/Ide.hx

@@ -12,6 +12,9 @@ class Ide {
 
 	public var isWindows(get, never) : Bool;
 
+	public var database : cdb.Database;
+	var databaseFile : String;
+
 	var props : {
 		global : Props,
 		project : Props,
@@ -251,6 +254,17 @@ class Ide {
 			r.onError = function(msg) error(msg);
 		}
 
+		var db = getPath("data.cdb");
+		databaseFile = db;
+		database = new cdb.Database();
+		if( sys.FileSystem.exists(db) ) {
+			try {
+				database.load(sys.io.File.getContent(db));
+			} catch( e : Dynamic ) {
+				error(e);
+			}
+		}
+
 		var render = renderers[0];
 		for( r in renderers )
 			if( r.name == props.current.current.hide.renderer ) {
@@ -371,6 +385,15 @@ class Ide {
 			});
 		}
 
+		// database
+		var db = menu.find(".database");
+		for( s in database.sheets ) {
+			if( s.props.hide ) continue;
+			new Element("<menu>").attr("label", s.name).appendTo(db.find(".dbview")).click(function(_) {
+				open("hide.view.CdbTable", { path : s.name });
+			});
+		}
+
 		// layout
 		var layouts = menu.find(".layout .content");
 		layouts.html("");
@@ -415,7 +438,12 @@ class Ide {
 	}
 
 	public function open( component : String, state : Dynamic, ?onCreate : View<Dynamic> -> Void ) {
-		var options = View.viewClasses.get(component).options;
+		var c = View.viewClasses.get(component);
+
+		if( c == null )
+			throw "Unknown component " + component;
+
+		var options = c.options;
 
 		var bestTarget : golden.Container = null;
 		for( v in views )

+ 32 - 0
hide/view/CdbTable.hx

@@ -0,0 +1,32 @@
+package hide.view;
+
+class CdbTable extends hide.ui.View<{ path : String }> {
+
+	var sheet : cdb.Sheet;
+	var editor : hide.comp.SheetEditor;
+
+	public function new(state) {
+		super(state);
+		for( s in ide.database.sheets )
+			if( s.name == state.path ) {
+				sheet = s;
+				break;
+			}
+	}
+
+	override function onDisplay() {
+		if( sheet == null ) {
+			root.text("Sheet not found '" + state.path + "'");
+			return;
+		}
+		root.addClass("hide-scroll");
+		editor = new hide.comp.SheetEditor(root, sheet);
+	}
+
+	override function getTitle() {
+		return state.path.charAt(0).toUpperCase() + state.path.substr(1);
+	}
+
+	static var _ = hide.ui.View.register(CdbTable);
+
+}