浏览代码

Implement multiple Overs for Interactives (#537)

Pavel Alexandrov 6 年之前
父节点
当前提交
1be675f3d8
共有 3 个文件被更改,包括 86 次插入47 次删除
  1. 3 8
      h2d/Interactive.hx
  2. 3 8
      h3d/scene/Interactive.hx
  3. 80 31
      hxd/SceneEvents.hx

+ 3 - 8
h2d/Interactive.hx

@@ -174,13 +174,8 @@ class Interactive extends Drawable implements hxd.SceneEvents.Interactive {
 			mouseDownButton = -1;
 		case EOver:
 			onOver(e);
-			if( !e.cancel && cursor != null )
-				hxd.System.setCursor(cursor);
 		case EOut:
-			mouseDownButton = -1;
 			onOut(e);
-			if( !e.cancel )
-				hxd.System.setCursor(Default);
 		case EWheel:
 			onWheel(e);
 		case EFocusLost:
@@ -206,8 +201,8 @@ class Interactive extends Drawable implements hxd.SceneEvents.Interactive {
 
 	function set_cursor(c) {
 		this.cursor = c;
-		if( isOver() && cursor != null )
-			hxd.System.setCursor(cursor);
+		if ( scene != null && scene.events != null )
+			scene.events.updateCursor(this);
 		return c;
 	}
 
@@ -247,7 +242,7 @@ class Interactive extends Drawable implements hxd.SceneEvents.Interactive {
 	}
 
 	public function isOver() {
-		return scene != null && scene.events != null && @:privateAccess scene.events.currentOver == this;
+		return scene != null && scene.events != null && @:privateAccess scene.events.overList.indexOf(this) != -1;
 	}
 
 	public function hasFocus() {

+ 3 - 8
h3d/scene/Interactive.hx

@@ -94,13 +94,8 @@ class Interactive extends Object implements hxd.SceneEvents.Interactive {
 			mouseDownButton = -1;
 		case EOver:
 			onOver(e);
-			if( !e.cancel && cursor != null )
-				hxd.System.setCursor(cursor);
 		case EOut:
-			mouseDownButton = -1;
 			onOut(e);
-			if( !e.cancel )
-				hxd.System.setCursor(Default);
 		case EWheel:
 			onWheel(e);
 		case EFocusLost:
@@ -120,8 +115,8 @@ class Interactive extends Object implements hxd.SceneEvents.Interactive {
 
 	function set_cursor(c) {
 		this.cursor = c;
-		if( isOver() && cursor != null )
-			hxd.System.setCursor(cursor);
+		if ( scene != null && scene.events != null )
+			scene.events.updateCursor(this);
 		return c;
 	}
 
@@ -136,7 +131,7 @@ class Interactive extends Object implements hxd.SceneEvents.Interactive {
 	}
 
 	public function isOver() {
-		return scene != null && scene.events != null && @:privateAccess scene.events.currentOver == this;
+		return scene != null && scene.events != null && @:privateAccess scene.events.overList.indexOf(this) != -1;
 	}
 
 	public function hasFocus() {

+ 80 - 31
hxd/SceneEvents.hx

@@ -9,6 +9,8 @@ interface InteractiveScene {
 }
 
 interface Interactive {
+	public var propagateEvents : Bool;
+	public var cursor(default, set) : hxd.Cursor;
 	public function handleEvent( e : Event ) : Void;
 	public function getInteractiveScene() : InteractiveScene;
 }
@@ -18,7 +20,7 @@ class SceneEvents {
 	var window : hxd.Window;
 	var scenes : Array<InteractiveScene>;
 
-	var currentOver : Interactive;
+	var overList : Array<Interactive>;
 	var currentFocus : Interactive;
 
 	var pendingEvents : Array<hxd.Event>;
@@ -47,6 +49,7 @@ class SceneEvents {
 		scenes = [];
 		pendingEvents = [];
 		pushList = [];
+		overList = [];
 		if( window == null ) window = hxd.Window.getInstance();
 		this.window = window;
 		window.addEventTarget(onEvent);
@@ -60,10 +63,8 @@ class SceneEvents {
 	function onRemove(i) {
 		if( i == currentFocus )
 			currentFocus = null;
-		if( i == currentOver ) {
-			currentOver = null;
-			hxd.System.setCursor(Default);
-		}
+		if ( overList.remove(i) )
+			selectCursor();
 		pushList.remove(i);
 	}
 
@@ -120,9 +121,12 @@ class SceneEvents {
 	function emitEvent( event : hxd.Event ) {
 		var oldX = event.relX, oldY = event.relY;
 		var handled = false;
-		var checkOver = false, checkPush = false, cancelFocus = false;
+		var checkOver = false, fillOver = false, checkPush = false, cancelFocus = false, updateCursor = false;
+		var overIndex : Int = 0;
 		switch( event.kind ) {
-		case EMove, ECheck: checkOver = true;
+		case EMove, ECheck:
+			checkOver = true;
+			fillOver = true;
 		case EPush: cancelFocus = true; checkPush = true;
 		case ERelease: checkPush = true;
 		case EKeyUp, EKeyDown, ETextInput, EWheel:
@@ -149,28 +153,44 @@ class SceneEvents {
 				}
 
 				if( checkOver ) {
-					if( currentOver != i ) {
-						onOut.cancel = false;
-						if( currentOver != null )
-							currentOver.handleEvent(onOut);
-						if( !onOut.cancel ) {
-							var old = event.propagate;
+					if ( fillOver ) {
+						var idx = overList.indexOf(i);
+						if ( idx == -1 ) {
+							var oldPropagate = event.propagate;
 							var oldKind = event.kind;
 							event.kind = EOver;
 							event.cancel = false;
 							i.handleEvent(event);
-							if( event.cancel )
-								currentOver = null;
-							else {
-								currentOver = i;
-								checkOver = false;
+							if ( !event.cancel ) {
+								overList.insert(overIndex, i);
+								overIndex++;
+								fillOver = event.propagate;
+								updateCursor = true;
 							}
 							event.kind = oldKind;
+							event.propagate = oldPropagate;
 							event.cancel = false;
-							event.propagate = old;
+						} else {
+							var o = overList[idx];
+							if ( idx < overIndex ) {
+								do {
+									overList[idx] = overList[idx + 1];
+									idx++;
+								} while ( idx < overIndex );
+								overList[overIndex] = o;
+								updateCursor = true;
+							} else if ( idx > overIndex ) {
+								do {
+									overList[idx] = overList[idx - 1];
+									idx--;
+								} while ( idx > overIndex );
+								overList[overIndex] = o;
+								updateCursor = true;
+							}
+							fillOver = i.propagateEvents;
+							overIndex++;
 						}
-					} else
-						checkOver = false;
+					}
 				} else {
 					if( checkPush ) {
 						if( event.kind == EPush )
@@ -200,12 +220,20 @@ class SceneEvents {
 		if( cancelFocus && currentFocus != null )
 			blur();
 
-		if( checkOver && currentOver != null ) {
-			onOut.cancel = false;
-			currentOver.handleEvent(onOut);
-			if( !onOut.cancel )
-				currentOver = null;
+		if( checkOver && overIndex < overList.length ) {
+			var idx = overList.length - 1;
+			do {
+				onOut.cancel = false;
+				overList[idx].handleEvent(onOut);
+				if ( !onOut.cancel ) {
+					overList.remove(overList[idx]);
+					continue;
+				}
+			} while ( --idx >= overIndex );
+			updateCursor = true;
 		}
+		if ( updateCursor )
+			selectCursor();
 
 		if( !handled && event != checkPos ) {
 			if( event.kind == EPush )
@@ -264,15 +292,21 @@ class SceneEvents {
 					}
 				case EOver:
 					isOut = false;
+					selectCursor();
 					continue;
 				case EOut:
 					// leave window
 					isOut = true;
-					if( currentOver != null ) {
-						onOut.cancel = false;
-						currentOver.handleEvent(onOut);
-						if( !onOut.cancel )
-							currentOver = null;
+					if ( overList.length > 0 ) {
+						var i = overList.length - 1;
+						while ( i >= 0 ) {
+							onOut.cancel = false;
+							overList[i].handleEvent(onOut);
+							if ( !onOut.cancel )
+								overList.remove(overList[i]);
+							i--;
+						}
+						selectCursor();
 					}
 					continue;
 				default:
@@ -324,6 +358,21 @@ class SceneEvents {
 		return currentFocus;
 	}
 
+	public function updateCursor( i : Interactive ) {
+		if ( overList.indexOf(i) != -1 ) selectCursor();
+	}
+
+	function selectCursor() {
+		var cur : hxd.Cursor = Default;
+		for ( o in overList ) {
+			if ( o.cursor != null ) {
+				cur = o.cursor;
+				break;
+			}
+		}
+		hxd.System.setCursor(cur);
+	}
+
 	function onEvent( e : hxd.Event ) {
 		if( !enablePhysicalMouse && e.kind == EMove ) return;
 		pendingEvents.push(e);