Przeglądaj źródła

added key and focus events
added h2d.comp.Input

ncannasse 12 lat temu
rodzic
commit
bcca55a743
10 zmienionych plików z 326 dodań i 39 usunięć
  1. 6 0
      h2d/Event.hx
  2. 82 26
      h2d/Interactive.hx
  3. 36 0
      h2d/Key.hx
  4. 52 8
      h2d/Scene.hx
  5. 9 5
      h2d/Text.hx
  6. 116 0
      h2d/comp/Input.hx
  7. 9 0
      h2d/comp/Parser.hx
  8. 13 0
      h2d/css/default.css
  9. 3 0
      samples/comps/components.html
  10. BIN
      samples/comps/comps.swf

+ 6 - 0
h2d/Event.hx

@@ -7,6 +7,10 @@ enum EventKind {
 	EOver;
 	EOut;
 	EWheel;
+	EFocus;
+	EFocusLost;
+	EKeyDown;
+	EKeyUp;
 }
 
 class Event {
@@ -17,6 +21,8 @@ class Event {
 	public var propagate : Bool;
 	public var cancel : Bool;
 	public var touchId : Int;
+	public var keyCode : Int;
+	public var charCode : Int;
 	public var wheelDelta : Float;
 	
 	public function new(k,x=0.,y=0.) {

+ 82 - 26
h2d/Interactive.hx

@@ -29,14 +29,26 @@ class Interactive extends Sprite {
 	}
 	
 	override function onDelete() {
-		if( scene != null )
+		if( scene != null ) {
 			scene.removeEventTarget(this);
+			if( scene.currentOver == this ) {
+				scene.currentOver = null;
+				h3d.System.setCursor(Default);
+			}
+		}
 		super.onDelete();
 	}
 
+	function checkBounds( e : Event ) {
+		return switch( e.kind ) {
+		case EOut, ERelease, EFocus, EFocusLost: false;
+		default: true;
+		}
+	}
+	
 	@:allow(h2d.Scene)
 	function handleEvent( e : Event ) {
-		if( isEllipse && (e.kind != EOut && e.kind != ERelease) ) {
+		if( isEllipse && checkBounds(e) ) {
 			var cx = width * 0.5, cy = height * 0.5;
 			var dx = (e.relX - cx) / cx;
 			var dy = (e.relY - cy) / cy;
@@ -62,6 +74,16 @@ class Interactive extends Sprite {
 			onOut(e);
 		case EWheel:
 			onWheel(e);
+		case EFocusLost:
+			onFocusLost(e);
+			if( !e.cancel && scene != null && scene.currentFocus == this ) scene.currentFocus = null;
+		case EFocus:
+			onFocus(e);
+			if( !e.cancel && scene != null ) scene.currentFocus = this;
+		case EKeyUp:
+			onKeyUp(e);
+		case EKeyDown:
+			onKeyDown(e);
 		}
 	}
 	
@@ -72,34 +94,37 @@ class Interactive extends Sprite {
 		return c;
 	}
 	
+	function globalToLocal( e : Event ) {
+		// convert global event to our local space
+		var x = e.relX, y = e.relY;
+		var rx = x * scene.matA + y * scene.matB + scene.absX;
+		var ry = x * scene.matC + y * scene.matD + scene.absY;
+		var r = scene.height / scene.width;
+		
+		var i = this;
+		
+		var dx = rx - i.absX;
+		var dy = ry - i.absY;
+		
+		var w1 = i.width * i.matA * r;
+		var h1 = i.width * i.matC;
+		var ky = h1 * dx - w1 * dy;
+		
+		var w2 = i.height * i.matB * r;
+		var h2 = i.height * i.matD;
+		var kx = w2 * dy - h2 * dx;
+		
+		var max = h1 * w2 - w1 * h2;
+		
+		e.relX = (kx * r / max) * i.width;
+		e.relY = (ky / max) * i.height;
+	}
+	
 	public function startDrag(callb) {
 		scene.startDrag(function(event) {
-			// convert global event to our local space
 			var x = event.relX, y = event.relY;
-			var rx = x * scene.matA + y * scene.matB + scene.absX;
-			var ry = x * scene.matC + y * scene.matD + scene.absY;
-			var r = scene.height / scene.width;
-			
-			var i = this;
-			
-			var dx = rx - i.absX;
-			var dy = ry - i.absY;
-			
-			var w1 = i.width * i.matA * r;
-			var h1 = i.width * i.matC;
-			var ky = h1 * dx - w1 * dy;
-			
-			var w2 = i.height * i.matB * r;
-			var h2 = i.height * i.matD;
-			var kx = w2 * dy - h2 * dx;
-			
-			var max = h1 * w2 - w1 * h2;
-			
-			event.relX = (kx * r / max) * i.width;
-			event.relY = (ky / max) * i.height;
-			
+			globalToLocal(event);
 			callb(event);
-			
 			event.relX = x;
 			event.relY = y;
 		});
@@ -109,6 +134,25 @@ class Interactive extends Sprite {
 		scene.stopDrag();
 	}
 	
+	public function focus() {
+		if( scene == null )
+			return;
+		var ev = new h2d.Event(null);
+		if( scene.currentFocus != null ) {
+			if( scene.currentFocus == this )
+				return;
+			ev.kind = EFocusLost;
+			scene.currentFocus.handleEvent(ev);
+			if( ev.cancel ) return;
+		}
+		ev.kind = EFocus;
+		handleEvent(ev);
+	}
+	
+	public function hasFocus() {
+		return scene != null && scene.currentFocus == this;
+	}
+	
 	public dynamic function onOver( e : Event ) {
 	}
 
@@ -126,5 +170,17 @@ class Interactive extends Sprite {
 
 	public dynamic function onWheel( e : Event ) {
 	}
+
+	public dynamic function onFocus( e : Event ) {
+	}
+	
+	public dynamic function onFocusLost( e : Event ) {
+	}
+
+	public dynamic function onKeyUp( e : Event ) {
+	}
+
+	public dynamic function onKeyDown( e : Event ) {
+	}
 	
 }

+ 36 - 0
h2d/Key.hx

@@ -0,0 +1,36 @@
+package h2d;
+
+class Key {
+	public static inline var BACK 		= 8;
+	public static inline var TAB		= 9;
+	public static inline var ENTER		= 13;
+	public static inline var SHIFT		= 16;
+	public static inline var CTRL		= 17;
+	public static inline var ALT		= 18;
+	public static inline var ESCAPE		= 27;
+	public static inline var SPACE		= 32;
+	public static inline var PGUP		= 33;
+	public static inline var PGDOWN		= 34;
+	public static inline var END		= 35;
+	public static inline var HOME		= 36;
+	public static inline var LEFT		= 37;
+	public static inline var UP			= 38;
+	public static inline var RIGHT		= 39;
+	public static inline var DOWN		= 40;
+	public static inline var INSERT		= 45;
+	public static inline var DELETE		= 46;
+	
+	public static inline var NUMBER_0	= 48;
+	public static inline var NUMPAD_0	= 96;
+	public static inline var A			= 65;
+	public static inline var F1			= 112;
+	
+	public static inline var NUMPAD_MULT = 106;
+	public static inline var NUMPAD_ADD	= 107;
+	public static inline var NUMPAD_ENTER = 108;
+	public static inline var NUMPAD_SUB = 109;
+	public static inline var NUMPAD_DOT = 110;
+	public static inline var NUMPAD_DIV = 111;
+	
+}
+

+ 52 - 8
h2d/Scene.hx

@@ -16,6 +16,9 @@ class Scene extends Layers implements h3d.IDrawable {
 	
 	@:allow(h2d.Interactive)
 	var currentOver : Interactive;
+	@:allow(h2d.Interactive)
+	var currentFocus : Interactive;
+		
 	var pushList : Array<Interactive>;
 	var currentDrag : { f : Event -> Void, ref : Null<Int> };
 	
@@ -48,7 +51,10 @@ class Scene extends Layers implements h3d.IDrawable {
 			stage.removeEventListener(flash.events.MouseEvent.MOUSE_MOVE, onMouseMove);
 			stage.removeEventListener(flash.events.MouseEvent.MOUSE_UP, onMouseUp);
 			stage.removeEventListener(flash.events.MouseEvent.MOUSE_WHEEL, onMouseWheel);
-			flash.ui.Mouse.cursor = flash.ui.MouseCursor.AUTO;
+			stage.removeEventListener(flash.events.MouseEvent.MOUSE_UP, onMouseUp);
+			stage.removeEventListener(flash.events.KeyboardEvent.KEY_DOWN, onKeyDown);
+			stage.removeEventListener(flash.events.KeyboardEvent.KEY_UP, onKeyUp);
+			h3d.System.setCursor(Default);
 		}
 		super.onDelete();
 	}
@@ -64,6 +70,8 @@ class Scene extends Layers implements h3d.IDrawable {
 			stage.addEventListener(flash.events.MouseEvent.MOUSE_MOVE, onMouseMove);
 			stage.addEventListener(flash.events.MouseEvent.MOUSE_UP, onMouseUp);
 			stage.addEventListener(flash.events.MouseEvent.MOUSE_WHEEL, onMouseWheel);
+			stage.addEventListener(flash.events.KeyboardEvent.KEY_DOWN, onKeyDown);
+			stage.addEventListener(flash.events.KeyboardEvent.KEY_UP, onKeyUp);
 		}
 		super.onAlloc();
 	}
@@ -107,6 +115,24 @@ class Scene extends Layers implements h3d.IDrawable {
 		}
 	}
 	
+	function onKeyUp(e:flash.events.KeyboardEvent) {
+		if( pendingEvents != null ) {
+			var ev = new Event(EKeyUp);
+			ev.keyCode = e.keyCode;
+			ev.charCode = e.charCode;
+			pendingEvents.push(ev);
+		}
+	}
+
+	function onKeyDown(e:flash.events.KeyboardEvent) {
+		if( pendingEvents != null ) {
+			var ev = new Event(EKeyDown);
+			ev.keyCode = e.keyCode;
+			ev.charCode = e.charCode;
+			pendingEvents.push(ev);
+		}
+	}
+	
 	function onTouchDown(e:flash.events.TouchEvent) {
 		if( pendingEvents != null ) {
 			var ev = new Event(EPush, screenXToLocal(e.localX), screenYToLocal(e.localY));
@@ -136,13 +162,20 @@ class Scene extends Layers implements h3d.IDrawable {
 		var rx = x * matA + y * matB + absX;
 		var ry = x * matC + y * matD + absY;
 		var r = height / width;
-		var checkOver = false, checkPush = false;
+		var checkOver = false, checkPush = false, cancelFocus = false;
 		switch( event.kind ) {
 		case EMove: checkOver = true;
-		case EPush, ERelease: checkPush = true;
+		case EPush: cancelFocus = true; checkPush = true;
+		case ERelease: checkPush = true;
+		case EKeyUp, EKeyDown:
+			if( currentFocus != null )
+				currentFocus.handleEvent(event);
+			return;
 		default:
 		}
 		for( i in interactive ) {
+			
+
 			// TODO : we are not sure that the positions are correctly updated !
 			
 			// this is a bit tricky since we are not in the not-euclide viewport space
@@ -175,6 +208,7 @@ class Scene extends Layers implements h3d.IDrawable {
 			event.relY = (ky / max) * i.height;
 			
 			i.handleEvent(event);
+			
 			if( event.cancel )
 				event.cancel = false;
 			else if( checkOver ) {
@@ -199,19 +233,29 @@ class Scene extends Layers implements h3d.IDrawable {
 					event.propagate = old;
 				} else
 					checkOver = false;
-			} else if( checkPush ) {
-				if( event.kind == EPush )
-					pushList.push(i);
-				else
-					pushList.remove(i);
+			} else {
+				if( checkPush ) {
+					if( event.kind == EPush )
+						pushList.push(i);
+					else
+						pushList.remove(i);
+				}
+				if( cancelFocus && i == currentFocus )
+					cancelFocus = false;
 			}
 				
 			if( event.propagate ) {
 				event.propagate = false;
 				continue;
 			}
+			
 			break;
 		}
+		if( cancelFocus && currentFocus != null ) {
+			event.kind = EFocusLost;
+			currentFocus.handleEvent(event);
+			event.kind = EPush;
+		}
 		if( checkOver && currentOver != null ) {
 			event.kind = EOut;
 			currentOver.handleEvent(event);

+ 9 - 5
h2d/Text.hx

@@ -31,7 +31,7 @@ class Text extends Drawable {
 	
 	override function onAlloc() {
 		super.onAlloc();
-		if( text != null && font != null ) initGlyphs();
+		if( text != null && font != null ) initGlyphs(text);
 	}
 	
 	override function draw(ctx:RenderContext) {
@@ -53,11 +53,15 @@ class Text extends Drawable {
 	
 	function set_text(t) {
 		this.text = t == null ? "null" : t;
-		if( allocated ) initGlyphs();
+		if( allocated ) initGlyphs(text);
 		return t;
 	}
 	
-	function initGlyphs( rebuild = true ) {
+	public function calcTextWidth( text : String ) {
+		return initGlyphs(text,false).width;
+	}
+	
+	function initGlyphs( text : String, rebuild = true ) {
 		if( rebuild ) glyphs.reset();
 		var letters = font.glyphs;
 		var x = 0, y = 0, xMax = 0;
@@ -94,11 +98,11 @@ class Text extends Drawable {
 	}
 	
 	function get_textHeight() {
-		return initGlyphs(false).height;
+		return initGlyphs(text,false).height;
 	}
 	
 	function get_textWidth() {
-		return initGlyphs(false).width;
+		return initGlyphs(text,false).width;
 	}
 	
 	function set_maxWidth(w) {

+ 116 - 0
h2d/comp/Input.hx

@@ -0,0 +1,116 @@
+package h2d.comp;
+
+@:access(h2d.comp.Input.scene)
+class Input extends Component {
+	
+	var input : h2d.Interactive;
+	var tf : h2d.Text;
+	var cursor : h2d.Bitmap;
+	var cursorPos(default,set) : Int;
+	
+	public var value(default, set) : String;
+	
+	public function new(?parent) {
+		super("input",parent);
+		tf = new h2d.Text(null, this);
+		input = new h2d.Interactive(0, 0, bg);
+		input.cursor = TextInput;
+		cursor = new h2d.Bitmap(null, bg);
+		cursor.visible = false;
+		var active = false;
+		input.onPush = function(_) {
+			focus();
+		};
+		input.onOver = function(_) {
+			addClass(":hover");
+		};
+		input.onOut = function(_) {
+			active = false;
+			removeClass(":hover");
+		};
+		input.onFocus = function(_) {
+			addClass(":focus");
+			cursor.visible = true;
+		};
+		input.onFocusLost = function(_) {
+			removeClass(":focus");
+			cursor.visible = false;
+		};
+		input.onKeyDown = function(e:Event) {
+			if( input.hasFocus() ) {
+				// BACK
+				switch( e.keyCode ) {
+				case Key.LEFT:
+					if( cursorPos > 0 )
+						cursorPos--;
+				case Key.RIGHT:
+					if( cursorPos < value.length )
+						cursorPos++;
+				case Key.HOME:
+					cursorPos = 0;
+				case Key.END:
+					cursorPos = value.length;
+				case Key.DELETE:
+					value = value.substr(0, cursorPos) + value.substr(cursorPos + 1);
+					onChange(value);
+					return;
+				case Key.BACK:
+					value = value.substr(0, cursorPos - 1) + value.substr(cursorPos);
+					cursorPos--;
+					onChange(value);
+					return;
+				}
+				if( e.charCode != 0 ) {
+					value = value.substr(0, cursorPos) + String.fromCharCode(e.charCode) + value.substr(cursorPos);
+					cursorPos++;
+					onChange(value);
+				}
+			}
+		};
+		this.value = "";
+	}
+	
+	function set_cursorPos(v:Int) {
+		cursor.x = tf.calcTextWidth(value.substr(0, v)) + extLeft();
+		return cursorPos = v;
+	}
+
+	public function focus() {
+		input.focus();
+		cursorPos = value.length;
+	}
+	
+	function get_value() {
+		return tf.text;
+	}
+	
+	function set_value(t) {
+		needRebuild = true;
+		return value = t;
+	}
+	
+	override function resize( ctx : Context ) {
+		if( ctx.measure ) {
+			tf.font = getFont();
+			tf.textColor = style.color;
+			tf.text = value;
+			tf.filter = true;
+			contentWidth = tf.textWidth;
+			contentHeight = tf.textHeight;
+			if( cursorPos < 0 ) cursorPos = 0;
+			if( cursorPos > value.length ) cursorPos = value.length;
+			cursorPos = cursorPos;
+		}
+		super.resize(ctx);
+		if( !ctx.measure ) {
+			input.width = width - (style.marginLeft + style.marginRight);
+			input.height = height - (style.marginTop + style.marginBottom);
+			cursor.y = extTop() - 1;
+			cursor.tile = h2d.Tile.fromColor(style.cursorColor | 0xFF000000, 1, Std.int(height - extTop() - extBottom() + 2));
+		}
+	}
+	
+	public dynamic function onChange( value : String ) {
+	}
+	
+}

+ 9 - 0
h2d/comp/Parser.hx

@@ -43,6 +43,8 @@ class Parser {
 			c = new Checkbox(parent);
 		case "itemlist":
 			c = new ItemList(parent);
+		case "input":
+			c = new Input(parent);
 		case n:
 			var make = comps.get(n);
 			if( make != null )
@@ -65,6 +67,9 @@ class Parser {
 				case "slider":
 					var c : Slider = cast c;
 					c.value = Std.parseFloat(v);
+				case "input":
+					var c : Input = cast c;
+					c.value = v;
 				default:
 				}
 			case "onclick":
@@ -88,6 +93,10 @@ class Parser {
 					var c : ItemList = cast c;
 					var s = makeScript(c,v);
 					c.onChange = function(_) s();
+				case "input":
+					var c : Input = cast c;
+					var s = makeScript(c,v);
+					c.onChange = function(_) s();
 				default:
 				}
 			case "style":

+ 13 - 0
h2d/css/default.css

@@ -81,3 +81,16 @@ itemlist {
 	border : 1px solid gradient(#A0A0A0,#909090,#707070,#606060);
 	background-color : gradient(#303030,#252525,#252525,#252525);
 }
+
+input {
+	width : 80px;
+	height : 16px;
+	padding : 3px;
+	border : 1px solid gradient(#A0A0A0,#909090,#707070,#606060);
+	background-color : gradient(#303030,#252525,#252525,#252525);
+}
+
+input:focus {
+	border : 1px solid white;
+	cursor-color : white;
+}

+ 3 - 0
samples/comps/components.html

@@ -67,6 +67,9 @@
 				</div>
 			</itemlist>
 			
+			<input value="bla"/>
+			<input/>
+			
 			<div class="dock">
 				<div class="panel border" style="dock:top; height:60px"/>
 				<div class="panel border" style="dock:left; width:30px"/>

BIN
samples/comps/comps.swf