Procházet zdrojové kódy

started cell edition with undo (partial)

Nicolas Cannasse před 7 roky
rodič
revize
ad6e2c444f

+ 25 - 0
bin/cdb.css

@@ -36,6 +36,31 @@
   padding: 2px 4px;
   padding: 2px 4px;
   overflow: hidden;
   overflow: hidden;
 }
 }
+.cdb .cdb-sheet td.edit {
+  padding: 2px;
+  padding-right: 6px;
+}
+.cdb .cdb-sheet td.edit > input,
+.cdb .cdb-sheet td.edit textarea {
+  width: 100%;
+  padding: 0px 2px;
+  border: none;
+}
+.cdb .cdb-sheet td.edit > textarea {
+  overflow: hidden;
+}
+.cdb .cdb-sheet td.edit > div.error {
+  margin-top: 5px;
+  position: absolute;
+  color: red;
+  background-color: #633;
+  border: 1px solid #833;
+  max-width: 200px;
+  padding: 2px;
+}
+.cdb .cdb-sheet td.edit_long {
+  padding-bottom: 0px;
+}
 .cdb .cdb-sheet td.cursor {
 .cdb .cdb-sheet td.cursor {
   outline: 1px solid #ccc;
   outline: 1px solid #ccc;
 }
 }

+ 25 - 0
bin/cdb.less

@@ -43,6 +43,31 @@
 			overflow : hidden;
 			overflow : hidden;
 		}
 		}
 
 
+		td.edit {
+			padding : 2px;
+			padding-right : 6px;
+			&> input, textarea {
+				width : 100%;
+				padding : 0px 2px;
+				border : none;
+			}
+			&> textarea {
+				overflow: hidden;
+			}
+			&> div.error {
+				margin-top : 5px;
+				position : absolute;
+				color : red;
+				background-color : #633;
+				border : 1px solid #833;
+				max-width : 200px;
+				padding : 2px;
+			}
+		}
+		td.edit_long {
+			padding-bottom : 0px;
+		}
+
 		td.cursor {
 		td.cursor {
 			outline : 1px solid #ccc;
 			outline : 1px solid #ccc;
 		}
 		}

+ 2 - 1
bin/defaultProps.json

@@ -17,13 +17,14 @@
 	"key.paste" : "Ctrl-V",
 	"key.paste" : "Ctrl-V",
 
 
 	"key.search" : "Ctrl-F",
 	"key.search" : "Ctrl-F",
+	"key.rename" : "F2",
 
 
 	// cdb keys
 	// cdb keys
 
 
 	"key.cdb.showReferences" : "F3",
 	"key.cdb.showReferences" : "F3",
 	"key.cdb.gotoReference" : "F4",
 	"key.cdb.gotoReference" : "F4",
-	"key.cdb.toggleList" : "Enter",
 	"key.cdb.closeList" : "Escape",
 	"key.cdb.closeList" : "Escape",
+	"key.cdb.editCell" : "Enter",
 
 
 	// cdb config
 	// cdb config
 
 

+ 10 - 5
bin/style.css

@@ -19,12 +19,14 @@ li,
 p,
 p,
 a,
 a,
 input,
 input,
-select {
+select,
+textarea {
   font-family: Verdana, serif;
   font-family: Verdana, serif;
   font-size: 9pt;
   font-size: 9pt;
   color: #aaa;
   color: #aaa;
 }
 }
-input {
+input,
+textarea {
   padding-left: 4px;
   padding-left: 4px;
 }
 }
 select:focus {
 select:focus {
@@ -34,16 +36,19 @@ select:focus:hover {
   border-color: #444;
   border-color: #444;
 }
 }
 select,
 select,
-input {
+input,
+textarea {
   background-color: #222222;
   background-color: #222222;
   border: 1px solid #444;
   border: 1px solid #444;
 }
 }
 select:focus,
 select:focus,
-input:focus {
+input:focus,
+textarea:focus {
   background-color: #141414;
   background-color: #141414;
 }
 }
 select:hover,
 select:hover,
-input:hover {
+input:hover,
+textarea:hover {
   border-color: #888;
   border-color: #888;
 }
 }
 input.file {
 input.file {

+ 3 - 3
bin/style.less

@@ -15,13 +15,13 @@ ul, li {
 	list-style : none;
 	list-style : none;
 }
 }
 
 
-body, td, th, li, p, a, input, select {
+body, td, th, li, p, a, input, select, textarea {
 	font-family : Verdana, serif;
 	font-family : Verdana, serif;
 	font-size : 9pt;
 	font-size : 9pt;
 	color: #aaa;
 	color: #aaa;
 }
 }
 
 
-input {
+input, textarea {
 	padding-left : 4px;
 	padding-left : 4px;
 }
 }
 
 
@@ -34,7 +34,7 @@ select {
 	}
 	}
 }
 }
 
 
-select, input {
+select, input, textarea {
 	background-color: rgb(34,34,34);
 	background-color: rgb(34,34,34);
 	border : 1px solid #444;
 	border : 1px solid #444;
 	&:focus {
 	&:focus {

+ 113 - 16
hide/comp/cdb/Cell.hx

@@ -1,4 +1,5 @@
 package hide.comp.cdb;
 package hide.comp.cdb;
+import hxd.Key in K;
 
 
 class Cell extends Component {
 class Cell extends Component {
 
 
@@ -10,7 +11,7 @@ class Cell extends Component {
 	public var line(default,null) : Line;
 	public var line(default,null) : Line;
 	public var column(default, null) : cdb.Data.Column;
 	public var column(default, null) : cdb.Data.Column;
 	public var columnIndex(get, never) : Int;
 	public var columnIndex(get, never) : Int;
-	public var value(get, set) : Dynamic;
+	public var value(get, never) : Dynamic;
 	public var table(get, never) : Table;
 	public var table(get, never) : Table;
 
 
 	public function new( root : Element, line : Line, column : cdb.Data.Column ) {
 	public function new( root : Element, line : Line, column : cdb.Data.Column ) {
@@ -25,21 +26,6 @@ class Cell extends Component {
 
 
 	function get_table() return line.table;
 	function get_table() return line.table;
 	function get_columnIndex() return table.sheet.columns.indexOf(column);
 	function get_columnIndex() return table.sheet.columns.indexOf(column);
-
-	function set_value( v : Dynamic ) {
-		var old = currentValue;
-		currentValue = v;
-		if( v != currentValue ) {
-			if( v == null )
-				Reflect.deleteField(line.obj, column.name);
-			else
-				Reflect.setField(line.obj, column.name, v);
-			// TODO : history
-		}
-		refresh();
-		return v;
-	}
-
 	inline function get_value() return currentValue;
 	inline function get_value() return currentValue;
 
 
 	public function refresh() {
 	public function refresh() {
@@ -50,6 +36,8 @@ class Cell extends Component {
 	}
 	}
 
 
 	function updateClasses() {
 	function updateClasses() {
+		root.removeClass("edit");
+		root.removeClass("edit_long");
 		switch( column.type ) {
 		switch( column.type ) {
 		case TBool :
 		case TBool :
 			root.removeClass("true false").addClass( value==true ? "true" : "false" );
 			root.removeClass("true false").addClass( value==true ? "true" : "false" );
@@ -203,4 +191,113 @@ class Cell extends Component {
 		return html;
 		return html;
 	}
 	}
 
 
+	public function edit() {
+		switch( column.type ) {
+		case TInt, TFloat, TString, TId, TCustom(_), TDynamic:
+			var str = value == null ? "" : editor.base.valToString(column.type, value);
+			var textHeight = root.wrapInner("<span>").find("span").height();
+			var longText = textHeight > 25;
+			root.empty();
+			root.addClass("edit");
+			var i = new Element(longText ? "<textarea>" : "<input>").appendTo(root);
+			if( longText ) {
+				root.addClass("edit_long");
+				i.css({ height : Math.ceil(textHeight - 1) + "px" });
+			}
+			i.val(str);
+			i.keydown(function(e) {
+				switch( e.keyCode ) {
+				case K.ESCAPE:
+					refresh();
+				case K.ENTER:
+					closeEdit();
+					e.preventDefault();
+				case K.UP, K.DOWN if( !longText ):
+					closeEdit();
+					return;
+				case K.TAB:
+					closeEdit();
+					e.preventDefault();
+					editor.cursor.move(e.shiftKey ? -1 : 1, 0, false, false);
+					var c = editor.cursor.getCell();
+					if( c != this ) c.edit();
+				}
+				e.stopPropagation();
+			});
+			i.keyup(function(_) try {
+				editor.base.parseValue(column.type, i.val());
+				setErrorMessage(null);
+			} catch( e : Dynamic ) {
+				setErrorMessage(StringTools.htmlUnescape(""+e));
+			});
+			i.keyup(null);
+			i.blur(function(_) closeEdit());
+			i.focus();
+			i.select();
+			if( longText ) i.scrollTop(0);
+		case TProperties, TList:
+			@:privateAccess table.toggleList(this);
+		default:
+			throw "TODO "+column.type;
+		}
+	}
+
+	public function setErrorMessage( msg : String ) {
+		root.find("div.error").remove();
+		if( msg == null )  return;
+		new Element("<div>").addClass("error").html(msg).appendTo(root);
+	}
+
+	function setRawValue( str : String ) {
+		var newValue : Dynamic = try editor.base.parseValue(column.type, str, false) catch( e : Dynamic ) return;
+		if( newValue == null || newValue == currentValue )
+			return;
+
+		switch( column.type ) {
+		case TId:
+			var obj = line.obj;
+			var prevValue = value;
+			// most likely our obj, unless there was a #DUP
+			var prevObj = value != null ? table.sheet.index.get(value) : null;
+			// have we already an obj mapped to the same id ?
+			var prevTarget = table.sheet.index.get(newValue);
+			var undo = null;
+			if( prevObj == null || prevObj.obj == obj ) {
+				// remap
+				var m = new Map();
+				m.set(value, newValue);
+				undo = editor.base.updateRefs(table.sheet, m);
+			}
+			setValue(newValue, undo);
+			// creates or remove a #DUP : need to refresh the whole table
+			if( prevTarget != null || (prevObj != null && (prevObj.obj != obj || table.sheet.index.get(prevValue) != null)) )
+				table.refresh();
+		default:
+			setValue(newValue);
+		}
+	}
+
+	function setValue( value : Dynamic, ?undo : cdb.Database.Changes ) {
+		if( undo == null )
+			undo = [];
+		currentValue = value;
+		var mainLine = line;
+		while( true ) {
+			var sub = Std.instance(mainLine.table, SubTable);
+			if( sub == null ) break;
+			mainLine = sub.cell.line;
+		}
+		var prev = Reflect.field(line.obj, column.name);
+		undo.push({ ref : { mainSheet : mainLine.table.sheet, mainObj : mainLine.obj, obj : line.obj, sheet : line.table.sheet }, v : SetField(line.obj, column.name, prev) });
+		Reflect.setField(line.obj, column.name, value);
+		table.sheet.updateValue(column, line.index, prev);
+		editor.addChanges(undo);
+	}
+
+	public function closeEdit() {
+		var str = root.find("input,textarea").val();
+		if( str != null ) setRawValue(str);
+		refresh();
+	}
+
 }
 }

+ 12 - 8
hide/comp/cdb/Editor.hx

@@ -32,14 +32,11 @@ class Editor extends Component {
 		keys.register("cdb.showReferences", showReferences);
 		keys.register("cdb.showReferences", showReferences);
 		keys.register("undo", function() if( undo.undo() ) { refresh(); save(); });
 		keys.register("undo", function() if( undo.undo() ) { refresh(); save(); });
 		keys.register("redo", function() if( undo.redo() ) { refresh(); save(); });
 		keys.register("redo", function() if( undo.redo() ) { refresh(); save(); });
-		keys.register("cdb.toggleList", function() {
-			var c = cursor.getCell();
-			if( c != null )
-				switch( c.column.type ) {
-				case TProperties, TList: c.root.click(); // toggle
-				default:
-				}
-		});
+		for( k in ["cdb.editCell","rename"] )
+			keys.register(k, function() {
+				var c = cursor.getCell();
+				if( c != null ) c.edit();
+			});
 		keys.register("cdb.closeList", function() {
 		keys.register("cdb.closeList", function() {
 			var c = cursor.getCell();
 			var c = cursor.getCell();
 			if( c != null ) {
 			if( c != null ) {
@@ -218,6 +215,13 @@ class Editor extends Component {
 	public function popupColumn( table : Table, col : cdb.Data.Column ) {
 	public function popupColumn( table : Table, col : cdb.Data.Column ) {
 	}
 	}
 
 
+	public function addChanges( changes : cdb.Database.Changes ) {
+		undo.change(Custom(function(undo) {
+			changes = base.applyChanges(changes);
+			refresh();
+		}));
+	}
+
 	function moveLine( line : Line, delta : Int ) {
 	function moveLine( line : Line, delta : Int ) {
 		/*
 		/*
 		// remove opened list
 		// remove opened list

+ 4 - 0
hide/comp/cdb/SubTable.hx

@@ -138,8 +138,12 @@ class SubTable extends Table {
 					return;
 					return;
 				}
 				}
 			});
 			});
+
+			cell.root.dblclick(function(_) cell.edit());
 		}
 		}
 
 
+		// add/edit properties
+
 		/*
 		/*
 		var end = J("<tr>").appendTo(content);
 		var end = J("<tr>").appendTo(content);
 		end = J("<td>").attr("colspan", "2").appendTo(end);
 		end = J("<td>").attr("colspan", "2").appendTo(end);

+ 1 - 1
hide/comp/cdb/Table.hx

@@ -81,12 +81,12 @@ class Table extends Component {
 
 
 				switch( c.type ) {
 				switch( c.type ) {
 				case TList, TProperties:
 				case TList, TProperties:
-					var key = sheet.getPath() + "@" + c.name + ":" + index;
 					cell.root.click(function(e) {
 					cell.root.click(function(e) {
 						e.stopPropagation();
 						e.stopPropagation();
 						toggleList(cell);
 						toggleList(cell);
 					});
 					});
 				default:
 				default:
+					cell.root.dblclick(function(_) cell.edit());
 				}
 				}
 			}
 			}
 		}
 		}