From 44ad6f0ea0c4fc0a3b896b4700eb0fa9196e6fdf Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 14 Nov 2023 11:30:08 +0100 Subject: [PATCH 001/120] validateNow if no style yet --- haxe/ui/backend/ScreenImpl.hx | 83 ++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index b4e3bf9..26d443f 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -20,29 +20,29 @@ import openfl.Lib; @:access(haxe.ui.backend.ComponentImpl) class ScreenImpl extends ScreenBase { private var _mapping:MapVoid>; - + #if (flixel < "4.9.0") // subStateOpened / subStateClosed added in 4.9.0 private static var _inputManager:haxe.ui.backend.flixel.InputManager = null; #end - + public function new() { _mapping = new MapVoid>(); #if (flixel < "4.9.0") // subStateOpened / subStateClosed added in 4.9.0 - + if (_inputManager == null) { _inputManager = new haxe.ui.backend.flixel.InputManager(); _inputManager.onResetCb = onReset; FlxG.inputs.add(_inputManager); } - + #end - + FlxG.signals.postGameStart.add(onPostGameStart); FlxG.signals.postStateSwitch.add(onPostStateSwitch); FlxG.signals.preStateCreate.add(onPreStateCreate); onPostStateSwitch(); - + addResizeHandler(); } @@ -51,9 +51,9 @@ class ScreenImpl extends ScreenBase { checkMembers(state); state.memberRemoved.add(onMemberRemoved); } - + #if (flixel < "4.9.0") // subStateOpened / subStateClosed added in 4.9.0 - + private function onReset() { if (FlxG.state != null && FlxG.state.subState != null) { var cachedSubStateOpenedCallback = FlxG.state.subState.openCallback; @@ -65,26 +65,26 @@ class ScreenImpl extends ScreenBase { } } } - + #end - + private function onPostGameStart() { onPostStateSwitch(); } - + private function onPostStateSwitch() { if (FlxG.game == null) { return; } rootComponents = []; - + #if (flixel >= "4.9.0") // subStateOpened / subStateClosed added in 4.9.0 FlxG.state.subStateOpened.add(onMemberAdded); #end - + FlxG.state.memberAdded.add(onMemberAdded); checkMembers(FlxG.state); - + FlxG.state.memberRemoved.add(onMemberRemoved); #if (!FLX_NO_MOUSE && !haxeui_no_mouse_reset) @@ -155,36 +155,36 @@ class ScreenImpl extends ScreenBase { } return found; } - + private override function get_width():Float { return FlxG.width / Toolkit.scaleX; } - + private override function get_height() { return FlxG.height / Toolkit.scaleY; } - + private override function get_actualWidth():Float { return FlxG.width; } - + private override function get_actualHeight():Float { return FlxG.height; } - + private override function get_dpi():Float { return System.getDisplay(0).dpi; } - + private override function get_title():String { return Lib.current.stage.window.title; } - + private override function set_title(s:String):String { Lib.current.stage.window.title = s; return s; } - + private var _cursor:String = null; public function setCursor(cursor:String, offsetX:Null = null, offsetY:Null = null) { #if haxeui_flixel_no_custom_cursors @@ -217,7 +217,7 @@ class ScreenImpl extends ScreenBase { component.cameras = cameras; } } - + if (StateHelper.currentState.exists == true) { StateHelper.currentState.add(component); if (rootComponents.indexOf(component) == -1) { @@ -230,7 +230,7 @@ class ScreenImpl extends ScreenBase { } return component; } - + public override function removeComponent(component:Component, dispose:Bool = true):Component { if (rootComponents.indexOf(component) == -1) { return component; @@ -253,7 +253,7 @@ class ScreenImpl extends ScreenBase { onContainerResize(); return component; } - + private var _resizeHandlerAdded:Bool = false; private function addResizeHandler() { if (_resizeHandlerAdded == true) { @@ -262,11 +262,11 @@ class ScreenImpl extends ScreenBase { _resizeHandlerAdded = true; FlxG.signals.gameResized.add(onGameResized); } - + private function onGameResized(width:Int, height:Int) { onContainerResize(); } - + private function onContainerResize() { for (c in rootComponents) { if (c.percentWidth > 0) { @@ -277,17 +277,17 @@ class ScreenImpl extends ScreenBase { } } } - + private override function handleSetComponentIndex(child:Component, index:Int) { var offset = 0; StateHelper.currentState.forEach((item) -> { offset++; }); - + StateHelper.currentState.remove(child); StateHelper.currentState.insert(index + offset, child); } - + private override function supportsEvent(type:String):Bool { if (type == MouseEvent.MOUSE_MOVE || type == MouseEvent.MOUSE_DOWN @@ -302,7 +302,7 @@ class ScreenImpl extends ScreenBase { } return false; } - + private var _mouseDownButton:Int = 0; private override function mapEvent(type:String, listener:UIEvent->Void) { switch (type) { @@ -311,25 +311,25 @@ class ScreenImpl extends ScreenBase { _mapping.set(type, listener); MouseHelper.notify(MouseEvent.MOUSE_MOVE, __onMouseMove, 10); } - + case MouseEvent.MOUSE_DOWN | MouseEvent.RIGHT_MOUSE_DOWN: if (_mapping.exists(type) == false) { _mapping.set(type, listener); MouseHelper.notify(MouseEvent.MOUSE_DOWN, __onMouseDown, 10); } - + case MouseEvent.MOUSE_UP | MouseEvent.RIGHT_MOUSE_UP: if (_mapping.exists(type) == false) { _mapping.set(type, listener); MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp, 10); } - + case KeyboardEvent.KEY_DOWN: if (_mapping.exists(type) == false) { _mapping.set(type, listener); FlxG.stage.addEventListener(openfl.events.KeyboardEvent.KEY_DOWN, __onKeyEvent); } - + case KeyboardEvent.KEY_UP: if (_mapping.exists(type) == false) { _mapping.set(type, listener); @@ -337,7 +337,7 @@ class ScreenImpl extends ScreenBase { } } } - + private function __onMouseMove(event:MouseEvent) { var fn = _mapping.get(MouseEvent.MOUSE_MOVE); if (fn != null) { @@ -352,7 +352,7 @@ class ScreenImpl extends ScreenBase { event.canceled = mouseEvent.canceled; } } - + private function __onMouseDown(event:MouseEvent) { var state = FlxG.state; if (state.subState != null) { @@ -380,7 +380,7 @@ class ScreenImpl extends ScreenBase { event.canceled = mouseEvent.canceled; } } - + private function __onMouseUp(event:MouseEvent) { var fn = _mapping.get(MouseEvent.MOUSE_UP); if (fn != null) { @@ -397,7 +397,7 @@ class ScreenImpl extends ScreenBase { event.canceled = mouseEvent.canceled; } } - + private function __onKeyEvent(event:openfl.events.KeyboardEvent) { var type:String = null; if (event.type == openfl.events.KeyboardEvent.KEY_DOWN) { @@ -482,6 +482,9 @@ class ScreenImpl extends ScreenBase { var desiredCursorOffsetX:Null = null; var desiredCursorOffsetY:Null = null; for (c in components) { + if (c.style == null) { + c.validateNow(); + } if (c.style.cursor != null) { desiredCursor = c.style.cursor; desiredCursorOffsetX = c.style.cursorOffsetX; @@ -492,4 +495,4 @@ class ScreenImpl extends ScreenBase { setCursor(desiredCursor, desiredCursorOffsetX, desiredCursorOffsetY); } -} \ No newline at end of file +} From 0d8774f233edba052810b1a130da90aa7fdb26be Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 14 Nov 2023 11:31:13 +0100 Subject: [PATCH 002/120] throw exception if can load ui asset --- haxe/ui/backend/flixel/UIRuntimeState.hx | 3 +++ haxe/ui/backend/flixel/UIRuntimeSubState.hx | 3 +++ 2 files changed, 6 insertions(+) diff --git a/haxe/ui/backend/flixel/UIRuntimeState.hx b/haxe/ui/backend/flixel/UIRuntimeState.hx index 69260d1..f987584 100644 --- a/haxe/ui/backend/flixel/UIRuntimeState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeState.hx @@ -90,6 +90,9 @@ class UIRuntimeState extends UIStateBase { // uses rtti to "build" a class with assetId = assetId.replace("\"", ""); assetId = assetId.replace("'", ""); this.root = RuntimeComponentBuilder.fromAsset(assetId); + if (this.root == null) { + throw "could not loading runtime ui from asset (" + assetId + ")"; + } } m = getMetaRTTI(rtti.meta, "xml"); if (m != null) { // comes back as an escaped CDATA section diff --git a/haxe/ui/backend/flixel/UIRuntimeSubState.hx b/haxe/ui/backend/flixel/UIRuntimeSubState.hx index 762e626..55d2b52 100644 --- a/haxe/ui/backend/flixel/UIRuntimeSubState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeSubState.hx @@ -90,6 +90,9 @@ class UIRuntimeSubState extends UISubStateBase { // uses rtti to "build" a class assetId = assetId.replace("\"", ""); assetId = assetId.replace("'", ""); this.root = RuntimeComponentBuilder.fromAsset(assetId); + if (this.root == null) { + throw "could not loading runtime ui from asset (" + assetId + ")"; + } } m = getMetaRTTI(rtti.meta, "xml"); if (m != null) { // comes back as an escaped CDATA section From a35258c6151d364f88508ab2aa07c5bdb2dd2b1d Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 14 Nov 2023 12:55:21 +0100 Subject: [PATCH 003/120] UIFragments --- haxe/ui/backend/flixel/UIFragment.hx | 5 + haxe/ui/backend/flixel/UIFragmentBase.hx | 3 + haxe/ui/backend/flixel/UIRuntimeFragment.hx | 200 ++++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 haxe/ui/backend/flixel/UIFragment.hx create mode 100644 haxe/ui/backend/flixel/UIFragmentBase.hx create mode 100644 haxe/ui/backend/flixel/UIRuntimeFragment.hx diff --git a/haxe/ui/backend/flixel/UIFragment.hx b/haxe/ui/backend/flixel/UIFragment.hx new file mode 100644 index 0000000..1dd63b7 --- /dev/null +++ b/haxe/ui/backend/flixel/UIFragment.hx @@ -0,0 +1,5 @@ +package haxe.ui.backend.flixel; + +class UIFragment extends UIFragmentBase { + +} \ No newline at end of file diff --git a/haxe/ui/backend/flixel/UIFragmentBase.hx b/haxe/ui/backend/flixel/UIFragmentBase.hx new file mode 100644 index 0000000..0350066 --- /dev/null +++ b/haxe/ui/backend/flixel/UIFragmentBase.hx @@ -0,0 +1,3 @@ +package haxe.ui.backend.flixel; + +typedef UIFragmentBase = flixel.group.FlxSpriteGroup; \ No newline at end of file diff --git a/haxe/ui/backend/flixel/UIRuntimeFragment.hx b/haxe/ui/backend/flixel/UIRuntimeFragment.hx new file mode 100644 index 0000000..56a98ff --- /dev/null +++ b/haxe/ui/backend/flixel/UIRuntimeFragment.hx @@ -0,0 +1,200 @@ +package haxe.ui.backend.flixel; + +import haxe.rtti.CType; +import haxe.ui.RuntimeComponentBuilder; +import haxe.ui.core.Component; +import haxe.ui.core.ComponentClassMap; +import haxe.ui.core.Screen; + +using StringTools; + +@:rtti +class UIRuntimeFragment extends UIFragmentBase implements IComponentDelegate { // uses rtti to "build" a class with a similar experience to using macros + public var root:Component; + + public var assetId:String; + + public function new(assetId:String = null) { + super(); + this.assetId = assetId; + + buildViaRTTI(); + linkViaRTTI(); + if (root != null) { + add(root); + } + } + + public var component(get, null):Component; + private function get_component():Component { + return root; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////// + // util functions + ///////////////////////////////////////////////////////////////////////////////////////////////// + public function addComponent(child:Component):Component { + if (root == null) { + throw "no root component"; + } + + return root.addComponent(child); + } + + public function removeComponent(child:Component):Component { + if (root == null) { + throw "no root component"; + } + + return root.removeComponent(child); + } + + public function findComponent(criteria:String = null, type:Class = null, recursive:Null = null, searchType:String = "id"):Null { + if (root == null) { + throw "no root component"; + } + + return root.findComponent(criteria, type, recursive, searchType); + } + + public function findComponents(styleName:String = null, type:Class = null, maxDepth:Int = 5):Array { + if (root == null) { + throw "no root component"; + } + + return root.findComponents(styleName, type, maxDepth); + } + + public function findAncestor(criteria:String = null, type:Class = null, searchType:String = "id"):Null { + if (root == null) { + throw "no root component"; + } + + return root.findAncestor(criteria, type, searchType); + } + + public function findComponentsUnderPoint(screenX:Float, screenY:Float, type:Class = null):Array { + if (root == null) { + throw "no root component"; + } + + return root.findComponentsUnderPoint(screenX, screenY, type); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////// + // rtti functions + ///////////////////////////////////////////////////////////////////////////////////////////////// + private function buildViaRTTI() { + var rtti = haxe.rtti.Rtti.getRtti(Type.getClass(this)); + var m = getMetaWithValueRTTI(rtti.meta, "build", "haxe.ui.RuntimeComponentBuilder.build"); + if (m != null) { + assetId = m.params[0].replace("haxe.ui.RuntimeComponentBuilder.build(", "").replace(")", ""); + assetId = assetId.replace("\"", ""); + assetId = assetId.replace("'", ""); + this.root = RuntimeComponentBuilder.fromAsset(assetId); + if (this.root == null) { + throw "could not loading runtime ui from asset (" + assetId + ")"; + } + } + m = getMetaRTTI(rtti.meta, "xml"); + if (m != null) { // comes back as an escaped CDATA section + var xmlString = m.params[0].trim(); + if (xmlString.startsWith("")) { + xmlString = xmlString.substring(0, xmlString.length - "]]>".length); + } + if (xmlString.startsWith("\"")) { + xmlString = xmlString.substring(1); + } + if (xmlString.endsWith("\"")) { + xmlString = xmlString.substring(0, xmlString.length - 1); + } + xmlString = xmlString.replace("\\r", "\r"); + xmlString = xmlString.replace("\\n", "\n"); + xmlString = xmlString.replace("\\\"", "\""); + xmlString = xmlString.trim(); + try { + this.root = RuntimeComponentBuilder.fromString(xmlString); + } catch (e:Dynamic) { + trace("ERROR", e); + } + } + } + + private function linkViaRTTI(force:Bool = false) { + if (root == null) { + return; + } + var rtti = haxe.rtti.Rtti.getRtti(Type.getClass(this)); + for (f in rtti.fields) { + switch (f.type) { + case CClass(name, params): + if (ComponentClassMap.instance.hasClassName(name)) { + var candidate = root.findComponent(f.name); + if (force) { + Reflect.setField(this, f.name, null); + } + if (candidate != null && Reflect.field(this, f.name) == null) { + Reflect.setField(this, f.name, candidate); + } + } + case CFunction(args, ret): + var m = getMetaRTTI(f.meta, "bind"); + if (m != null) { + var candidate:Component = root.findComponent(m.params[0]); + if (candidate != null) { + var parts = m.params[1].split("."); + var candidateEvent = "haxe.ui.events." + parts[0]; + var c = Type.resolveClass(candidateEvent); + if (c != null) { + var eventString = Reflect.field(c, parts[1]); + var fn = Reflect.field(this, f.name); + candidate.registerEvent(eventString, fn); + } + + } + } + case _: + } + } + } + + private function getMetaRTTI(metadata:MetaData, name:String):{name:String, params:Array} { + for (m in metadata) { + if (m.name == name || m.name == ":" + name) { + return m; + } + } + return null; + } + + private function getMetasRTTI(metadata:MetaData, name:String):Array<{name:String, params:Array}> { + var metas = []; + for (m in metadata) { + if (m.name == name || m.name == ":" + name) { + metas.push(m); + } + } + return metas; + } + + private function getMetaWithValueRTTI(metadata:MetaData, name:String, value:String, paramIndex:Int = 0):{name:String, params:Array} { + for (m in metadata) { + if (m.name == name || m.name == ":" + name) { + if (m.params[paramIndex].startsWith(value)) { + return m; + } + } + } + return null; + } + + public override function destroy() { + if (root != null) { + remove(root); + } + root = null; + } +} \ No newline at end of file From 9e219ef99ef22a26240f5715ddf7e98e8bb55e92 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 14 Nov 2023 19:04:17 +0100 Subject: [PATCH 004/120] dispatch call --- haxe/ui/backend/flixel/UIRuntimeFragment.hx | 9 +++++++++ haxe/ui/backend/flixel/UIRuntimeState.hx | 9 +++++++++ haxe/ui/backend/flixel/UIRuntimeSubState.hx | 9 +++++++++ 3 files changed, 27 insertions(+) diff --git a/haxe/ui/backend/flixel/UIRuntimeFragment.hx b/haxe/ui/backend/flixel/UIRuntimeFragment.hx index 56a98ff..b77ed41 100644 --- a/haxe/ui/backend/flixel/UIRuntimeFragment.hx +++ b/haxe/ui/backend/flixel/UIRuntimeFragment.hx @@ -5,6 +5,7 @@ import haxe.ui.RuntimeComponentBuilder; import haxe.ui.core.Component; import haxe.ui.core.ComponentClassMap; import haxe.ui.core.Screen; +import haxe.ui.events.UIEvent; using StringTools; @@ -81,6 +82,14 @@ class UIRuntimeFragment extends UIFragmentBase implements IComponentDelegate { / return root.findComponentsUnderPoint(screenX, screenY, type); } + public function dispatch(event:T) { + if (root == null) { + throw "no root component"; + } + + root.dispatch(event); + } + ///////////////////////////////////////////////////////////////////////////////////////////////// // rtti functions ///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/haxe/ui/backend/flixel/UIRuntimeState.hx b/haxe/ui/backend/flixel/UIRuntimeState.hx index f987584..b26d153 100644 --- a/haxe/ui/backend/flixel/UIRuntimeState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeState.hx @@ -5,6 +5,7 @@ import haxe.ui.RuntimeComponentBuilder; import haxe.ui.core.Component; import haxe.ui.core.ComponentClassMap; import haxe.ui.core.Screen; +import haxe.ui.events.UIEvent; using StringTools; @@ -79,6 +80,14 @@ class UIRuntimeState extends UIStateBase { // uses rtti to "build" a class with return root.findComponentsUnderPoint(screenX, screenY, type); } + public function dispatch(event:T) { + if (root == null) { + throw "no root component"; + } + + root.dispatch(event); + } + ///////////////////////////////////////////////////////////////////////////////////////////////// // rtti functions ///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/haxe/ui/backend/flixel/UIRuntimeSubState.hx b/haxe/ui/backend/flixel/UIRuntimeSubState.hx index 55d2b52..cb97f71 100644 --- a/haxe/ui/backend/flixel/UIRuntimeSubState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeSubState.hx @@ -5,6 +5,7 @@ import haxe.ui.RuntimeComponentBuilder; import haxe.ui.core.Component; import haxe.ui.core.ComponentClassMap; import haxe.ui.core.Screen; +import haxe.ui.events.UIEvent; using StringTools; @@ -79,6 +80,14 @@ class UIRuntimeSubState extends UISubStateBase { // uses rtti to "build" a class return root.findComponentsUnderPoint(screenX, screenY, type); } + public function dispatch(event:T) { + if (root == null) { + throw "no root component"; + } + + root.dispatch(event); + } + ///////////////////////////////////////////////////////////////////////////////////////////////// // rtti functions ///////////////////////////////////////////////////////////////////////////////////////////////// From 1cff484dd1ce49556c33c6102dbce50a61a0a483 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 14 Nov 2023 21:08:09 +0100 Subject: [PATCH 005/120] refactor rtti classes --- haxe/ui/backend/flixel/UIRTTITools.hx | 124 +++++++++++++++++ haxe/ui/backend/flixel/UIRuntimeFragment.hx | 140 +++----------------- haxe/ui/backend/flixel/UIRuntimeState.hx | 126 +----------------- haxe/ui/backend/flixel/UIRuntimeSubState.hx | 126 +----------------- 4 files changed, 153 insertions(+), 363 deletions(-) create mode 100644 haxe/ui/backend/flixel/UIRTTITools.hx diff --git a/haxe/ui/backend/flixel/UIRTTITools.hx b/haxe/ui/backend/flixel/UIRTTITools.hx new file mode 100644 index 0000000..b9d04d8 --- /dev/null +++ b/haxe/ui/backend/flixel/UIRTTITools.hx @@ -0,0 +1,124 @@ +package haxe.ui.backend.flixel; + +import haxe.ui.RuntimeComponentBuilder; +import haxe.ui.core.Component; +import haxe.rtti.CType; +import haxe.ui.core.ComponentClassMap; + +using StringTools; + +class UIRTTITools { + public static function buildViaRTTI(rtti:Classdef):Component { + var root:Component = null; + var m = getMetaWithValueRTTI(rtti.meta, "build", "haxe.ui.RuntimeComponentBuilder.build"); + if (m != null) { + var assetId = m.params[0].replace("haxe.ui.RuntimeComponentBuilder.build(", "").replace(")", ""); + assetId = assetId.replace("\"", ""); + assetId = assetId.replace("'", ""); + root = RuntimeComponentBuilder.fromAsset(assetId); + if (root == null) { + throw "could not loading runtime ui from asset (" + assetId + ")"; + } + } + m = getMetaRTTI(rtti.meta, "xml"); + if (m != null) { // comes back as an escaped CDATA section + var xmlString = m.params[0].trim(); + if (xmlString.startsWith("")) { + xmlString = xmlString.substring(0, xmlString.length - "]]>".length); + } + if (xmlString.startsWith("\"")) { + xmlString = xmlString.substring(1); + } + if (xmlString.endsWith("\"")) { + xmlString = xmlString.substring(0, xmlString.length - 1); + } + xmlString = xmlString.replace("\\r", "\r"); + xmlString = xmlString.replace("\\n", "\n"); + xmlString = xmlString.replace("\\\"", "\""); + xmlString = xmlString.trim(); + try { + root = RuntimeComponentBuilder.fromString(xmlString); + } catch (e:Dynamic) { + trace("ERROR", e); + } + } + return root; + } + + public static function linkViaRTTI(rtti:Classdef, target:Dynamic, root:Component, force:Bool = false) { + if (root == null) { + return; + } + for (f in rtti.fields) { + switch (f.type) { + case CClass(name, params): + if (ComponentClassMap.instance.hasClassName(name)) { + var candidate = root.findComponent(f.name); + if (force) { + Reflect.setField(target, f.name, null); + } + if (candidate != null && Reflect.field(target, f.name) == null) { + var temp = Type.createEmptyInstance(Type.resolveClass(name)); + if ((temp is IComponentDelegate)) { + var componentDelegate:IComponentDelegate = Type.createInstance(Type.resolveClass(name), [false]); + componentDelegate.component = candidate; + Reflect.setField(target, f.name, componentDelegate); + } else { + Reflect.setField(target, f.name, candidate); + } + } + } + case CFunction(args, ret): + var m = getMetaRTTI(f.meta, "bind"); + if (m != null) { + var candidate:Component = root.findComponent(m.params[0]); + if (candidate != null) { + var parts = m.params[1].split("."); + var candidateEvent = "haxe.ui.events." + parts[0]; + var c = Type.resolveClass(candidateEvent); + if (c != null) { + var eventString = Reflect.field(c, parts[1]); + var fn = Reflect.field(target, f.name); + candidate.registerEvent(eventString, fn); + } + + } + } + case _: + } + } + } + + private static function getMetaRTTI(metadata:MetaData, name:String):{name:String, params:Array} { + for (m in metadata) { + if (m.name == name || m.name == ":" + name) { + return m; + } + } + return null; + } + + private static function getMetasRTTI(metadata:MetaData, name:String):Array<{name:String, params:Array}> { + var metas = []; + for (m in metadata) { + if (m.name == name || m.name == ":" + name) { + metas.push(m); + } + } + return metas; + } + + private static function getMetaWithValueRTTI(metadata:MetaData, name:String, value:String, paramIndex:Int = 0):{name:String, params:Array} { + for (m in metadata) { + if (m.name == name || m.name == ":" + name) { + if (m.params[paramIndex].startsWith(value)) { + return m; + } + } + } + return null; + } +} \ No newline at end of file diff --git a/haxe/ui/backend/flixel/UIRuntimeFragment.hx b/haxe/ui/backend/flixel/UIRuntimeFragment.hx index b77ed41..165fd8c 100644 --- a/haxe/ui/backend/flixel/UIRuntimeFragment.hx +++ b/haxe/ui/backend/flixel/UIRuntimeFragment.hx @@ -1,11 +1,9 @@ package haxe.ui.backend.flixel; -import haxe.rtti.CType; import haxe.ui.RuntimeComponentBuilder; import haxe.ui.core.Component; -import haxe.ui.core.ComponentClassMap; -import haxe.ui.core.Screen; import haxe.ui.events.UIEvent; +import haxe.ui.backend.flixel.UIRTTITools.*; using StringTools; @@ -13,23 +11,29 @@ using StringTools; class UIRuntimeFragment extends UIFragmentBase implements IComponentDelegate { // uses rtti to "build" a class with a similar experience to using macros public var root:Component; - public var assetId:String; - - public function new(assetId:String = null) { + public function new(buildFragment:Bool = true) { super(); - this.assetId = assetId; - buildViaRTTI(); - linkViaRTTI(); - if (root != null) { - add(root); - } + if (buildFragment) { + var rtti = haxe.rtti.Rtti.getRtti(Type.getClass(this)); + root = buildViaRTTI(rtti); + linkViaRTTI(rtti, this, root); + if (root != null) { + add(root); + } + } } - public var component(get, null):Component; + public var component(get, set):Component; private function get_component():Component { return root; } + private function set_component(value:Component):Component { + root = value; + var rtti = haxe.rtti.Rtti.getRtti(Type.getClass(this)); + linkViaRTTI(rtti, this, root); + return value; + } ///////////////////////////////////////////////////////////////////////////////////////////////// // util functions @@ -90,116 +94,6 @@ class UIRuntimeFragment extends UIFragmentBase implements IComponentDelegate { / root.dispatch(event); } - ///////////////////////////////////////////////////////////////////////////////////////////////// - // rtti functions - ///////////////////////////////////////////////////////////////////////////////////////////////// - private function buildViaRTTI() { - var rtti = haxe.rtti.Rtti.getRtti(Type.getClass(this)); - var m = getMetaWithValueRTTI(rtti.meta, "build", "haxe.ui.RuntimeComponentBuilder.build"); - if (m != null) { - assetId = m.params[0].replace("haxe.ui.RuntimeComponentBuilder.build(", "").replace(")", ""); - assetId = assetId.replace("\"", ""); - assetId = assetId.replace("'", ""); - this.root = RuntimeComponentBuilder.fromAsset(assetId); - if (this.root == null) { - throw "could not loading runtime ui from asset (" + assetId + ")"; - } - } - m = getMetaRTTI(rtti.meta, "xml"); - if (m != null) { // comes back as an escaped CDATA section - var xmlString = m.params[0].trim(); - if (xmlString.startsWith("")) { - xmlString = xmlString.substring(0, xmlString.length - "]]>".length); - } - if (xmlString.startsWith("\"")) { - xmlString = xmlString.substring(1); - } - if (xmlString.endsWith("\"")) { - xmlString = xmlString.substring(0, xmlString.length - 1); - } - xmlString = xmlString.replace("\\r", "\r"); - xmlString = xmlString.replace("\\n", "\n"); - xmlString = xmlString.replace("\\\"", "\""); - xmlString = xmlString.trim(); - try { - this.root = RuntimeComponentBuilder.fromString(xmlString); - } catch (e:Dynamic) { - trace("ERROR", e); - } - } - } - - private function linkViaRTTI(force:Bool = false) { - if (root == null) { - return; - } - var rtti = haxe.rtti.Rtti.getRtti(Type.getClass(this)); - for (f in rtti.fields) { - switch (f.type) { - case CClass(name, params): - if (ComponentClassMap.instance.hasClassName(name)) { - var candidate = root.findComponent(f.name); - if (force) { - Reflect.setField(this, f.name, null); - } - if (candidate != null && Reflect.field(this, f.name) == null) { - Reflect.setField(this, f.name, candidate); - } - } - case CFunction(args, ret): - var m = getMetaRTTI(f.meta, "bind"); - if (m != null) { - var candidate:Component = root.findComponent(m.params[0]); - if (candidate != null) { - var parts = m.params[1].split("."); - var candidateEvent = "haxe.ui.events." + parts[0]; - var c = Type.resolveClass(candidateEvent); - if (c != null) { - var eventString = Reflect.field(c, parts[1]); - var fn = Reflect.field(this, f.name); - candidate.registerEvent(eventString, fn); - } - - } - } - case _: - } - } - } - - private function getMetaRTTI(metadata:MetaData, name:String):{name:String, params:Array} { - for (m in metadata) { - if (m.name == name || m.name == ":" + name) { - return m; - } - } - return null; - } - - private function getMetasRTTI(metadata:MetaData, name:String):Array<{name:String, params:Array}> { - var metas = []; - for (m in metadata) { - if (m.name == name || m.name == ":" + name) { - metas.push(m); - } - } - return metas; - } - - private function getMetaWithValueRTTI(metadata:MetaData, name:String, value:String, paramIndex:Int = 0):{name:String, params:Array} { - for (m in metadata) { - if (m.name == name || m.name == ":" + name) { - if (m.params[paramIndex].startsWith(value)) { - return m; - } - } - } - return null; - } - public override function destroy() { if (root != null) { remove(root); diff --git a/haxe/ui/backend/flixel/UIRuntimeState.hx b/haxe/ui/backend/flixel/UIRuntimeState.hx index b26d153..e171faa 100644 --- a/haxe/ui/backend/flixel/UIRuntimeState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeState.hx @@ -1,11 +1,9 @@ package haxe.ui.backend.flixel; -import haxe.rtti.CType; -import haxe.ui.RuntimeComponentBuilder; import haxe.ui.core.Component; -import haxe.ui.core.ComponentClassMap; import haxe.ui.core.Screen; import haxe.ui.events.UIEvent; +import haxe.ui.backend.flixel.UIRTTITools.*; using StringTools; @@ -13,16 +11,14 @@ using StringTools; class UIRuntimeState extends UIStateBase { // uses rtti to "build" a class with a similar experience to using macros public var root:Component; - public var assetId:String; - - public function new(assetId:String = null) { + public function new() { super(); - this.assetId = assetId; } public override function create() { - buildViaRTTI(); - linkViaRTTI(); + var rtti = haxe.rtti.Rtti.getRtti(Type.getClass(this)); + root = buildViaRTTI(rtti); + linkViaRTTI(rtti, this, root); if (root != null) { Screen.instance.addComponent(root); } @@ -88,119 +84,9 @@ class UIRuntimeState extends UIStateBase { // uses rtti to "build" a class with root.dispatch(event); } - ///////////////////////////////////////////////////////////////////////////////////////////////// - // rtti functions - ///////////////////////////////////////////////////////////////////////////////////////////////// - private function buildViaRTTI() { - var rtti = haxe.rtti.Rtti.getRtti(Type.getClass(this)); - var m = getMetaWithValueRTTI(rtti.meta, "build", "haxe.ui.RuntimeComponentBuilder.build"); - if (m != null) { - assetId = m.params[0].replace("haxe.ui.RuntimeComponentBuilder.build(", "").replace(")", ""); - assetId = assetId.replace("\"", ""); - assetId = assetId.replace("'", ""); - this.root = RuntimeComponentBuilder.fromAsset(assetId); - if (this.root == null) { - throw "could not loading runtime ui from asset (" + assetId + ")"; - } - } - m = getMetaRTTI(rtti.meta, "xml"); - if (m != null) { // comes back as an escaped CDATA section - var xmlString = m.params[0].trim(); - if (xmlString.startsWith("")) { - xmlString = xmlString.substring(0, xmlString.length - "]]>".length); - } - if (xmlString.startsWith("\"")) { - xmlString = xmlString.substring(1); - } - if (xmlString.endsWith("\"")) { - xmlString = xmlString.substring(0, xmlString.length - 1); - } - xmlString = xmlString.replace("\\r", "\r"); - xmlString = xmlString.replace("\\n", "\n"); - xmlString = xmlString.replace("\\\"", "\""); - xmlString = xmlString.trim(); - try { - this.root = RuntimeComponentBuilder.fromString(xmlString); - } catch (e:Dynamic) { - trace("ERROR", e); - } - } - } - - private function linkViaRTTI(force:Bool = false) { - if (root == null) { - return; - } - var rtti = haxe.rtti.Rtti.getRtti(Type.getClass(this)); - for (f in rtti.fields) { - switch (f.type) { - case CClass(name, params): - if (ComponentClassMap.instance.hasClassName(name)) { - var candidate = root.findComponent(f.name); - if (force) { - Reflect.setField(this, f.name, null); - } - if (candidate != null && Reflect.field(this, f.name) == null) { - Reflect.setField(this, f.name, candidate); - } - } - case CFunction(args, ret): - var m = getMetaRTTI(f.meta, "bind"); - if (m != null) { - var candidate:Component = root.findComponent(m.params[0]); - if (candidate != null) { - var parts = m.params[1].split("."); - var candidateEvent = "haxe.ui.events." + parts[0]; - var c = Type.resolveClass(candidateEvent); - if (c != null) { - var eventString = Reflect.field(c, parts[1]); - var fn = Reflect.field(this, f.name); - candidate.registerEvent(eventString, fn); - } - - } - } - case _: - } - } - } - - private function getMetaRTTI(metadata:MetaData, name:String):{name:String, params:Array} { - for (m in metadata) { - if (m.name == name || m.name == ":" + name) { - return m; - } - } - return null; - } - - private function getMetasRTTI(metadata:MetaData, name:String):Array<{name:String, params:Array}> { - var metas = []; - for (m in metadata) { - if (m.name == name || m.name == ":" + name) { - metas.push(m); - } - } - return metas; - } - - private function getMetaWithValueRTTI(metadata:MetaData, name:String, value:String, paramIndex:Int = 0):{name:String, params:Array} { - for (m in metadata) { - if (m.name == name || m.name == ":" + name) { - if (m.params[paramIndex].startsWith(value)) { - return m; - } - } - } - return null; - } - public override function destroy() { if (root != null) { - remove(root); + Screen.instance.removeComponent(root); } root = null; } diff --git a/haxe/ui/backend/flixel/UIRuntimeSubState.hx b/haxe/ui/backend/flixel/UIRuntimeSubState.hx index cb97f71..91a5dc4 100644 --- a/haxe/ui/backend/flixel/UIRuntimeSubState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeSubState.hx @@ -1,11 +1,9 @@ package haxe.ui.backend.flixel; -import haxe.rtti.CType; -import haxe.ui.RuntimeComponentBuilder; import haxe.ui.core.Component; -import haxe.ui.core.ComponentClassMap; import haxe.ui.core.Screen; import haxe.ui.events.UIEvent; +import haxe.ui.backend.flixel.UIRTTITools.*; using StringTools; @@ -13,16 +11,14 @@ using StringTools; class UIRuntimeSubState extends UISubStateBase { // uses rtti to "build" a class with a similar experience to using macros public var root:Component; - public var assetId:String; - - public function new(assetId:String = null) { + public function new() { super(); - this.assetId = assetId; } public override function create() { - buildViaRTTI(); - linkViaRTTI(); + var rtti = haxe.rtti.Rtti.getRtti(Type.getClass(this)); + root = buildViaRTTI(rtti); + linkViaRTTI(rtti, this, root); if (root != null) { Screen.instance.addComponent(root); } @@ -88,119 +84,9 @@ class UIRuntimeSubState extends UISubStateBase { // uses rtti to "build" a class root.dispatch(event); } - ///////////////////////////////////////////////////////////////////////////////////////////////// - // rtti functions - ///////////////////////////////////////////////////////////////////////////////////////////////// - private function buildViaRTTI() { - var rtti = haxe.rtti.Rtti.getRtti(Type.getClass(this)); - var m = getMetaWithValueRTTI(rtti.meta, "build", "haxe.ui.RuntimeComponentBuilder.build"); - if (m != null) { - assetId = m.params[0].replace("haxe.ui.RuntimeComponentBuilder.build(", "").replace(")", ""); - assetId = assetId.replace("\"", ""); - assetId = assetId.replace("'", ""); - this.root = RuntimeComponentBuilder.fromAsset(assetId); - if (this.root == null) { - throw "could not loading runtime ui from asset (" + assetId + ")"; - } - } - m = getMetaRTTI(rtti.meta, "xml"); - if (m != null) { // comes back as an escaped CDATA section - var xmlString = m.params[0].trim(); - if (xmlString.startsWith("")) { - xmlString = xmlString.substring(0, xmlString.length - "]]>".length); - } - if (xmlString.startsWith("\"")) { - xmlString = xmlString.substring(1); - } - if (xmlString.endsWith("\"")) { - xmlString = xmlString.substring(0, xmlString.length - 1); - } - xmlString = xmlString.replace("\\r", "\r"); - xmlString = xmlString.replace("\\n", "\n"); - xmlString = xmlString.replace("\\\"", "\""); - xmlString = xmlString.trim(); - try { - this.root = RuntimeComponentBuilder.fromString(xmlString); - } catch (e:Dynamic) { - trace("ERROR", e); - } - } - } - - private function linkViaRTTI(force:Bool = false) { - if (root == null) { - return; - } - var rtti = haxe.rtti.Rtti.getRtti(Type.getClass(this)); - for (f in rtti.fields) { - switch (f.type) { - case CClass(name, params): - if (ComponentClassMap.instance.hasClassName(name)) { - var candidate = root.findComponent(f.name); - if (force) { - Reflect.setField(this, f.name, null); - } - if (candidate != null && Reflect.field(this, f.name) == null) { - Reflect.setField(this, f.name, candidate); - } - } - case CFunction(args, ret): - var m = getMetaRTTI(f.meta, "bind"); - if (m != null) { - var candidate:Component = root.findComponent(m.params[0]); - if (candidate != null) { - var parts = m.params[1].split("."); - var candidateEvent = "haxe.ui.events." + parts[0]; - var c = Type.resolveClass(candidateEvent); - if (c != null) { - var eventString = Reflect.field(c, parts[1]); - var fn = Reflect.field(this, f.name); - candidate.registerEvent(eventString, fn); - } - - } - } - case _: - } - } - } - - private function getMetaRTTI(metadata:MetaData, name:String):{name:String, params:Array} { - for (m in metadata) { - if (m.name == name || m.name == ":" + name) { - return m; - } - } - return null; - } - - private function getMetasRTTI(metadata:MetaData, name:String):Array<{name:String, params:Array}> { - var metas = []; - for (m in metadata) { - if (m.name == name || m.name == ":" + name) { - metas.push(m); - } - } - return metas; - } - - private function getMetaWithValueRTTI(metadata:MetaData, name:String, value:String, paramIndex:Int = 0):{name:String, params:Array} { - for (m in metadata) { - if (m.name == name || m.name == ":" + name) { - if (m.params[paramIndex].startsWith(value)) { - return m; - } - } - } - return null; - } - public override function destroy() { if (root != null) { - remove(root); + Screen.instance.removeComponent(root); } root = null; } From d3cc7dd2188ff970f994fd979bd0ff2f3c2d0306 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 14 Nov 2023 21:43:06 +0100 Subject: [PATCH 006/120] dont call constructor --- haxe/ui/backend/flixel/UIRTTITools.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haxe/ui/backend/flixel/UIRTTITools.hx b/haxe/ui/backend/flixel/UIRTTITools.hx index b9d04d8..56bf4ab 100644 --- a/haxe/ui/backend/flixel/UIRTTITools.hx +++ b/haxe/ui/backend/flixel/UIRTTITools.hx @@ -63,7 +63,7 @@ class UIRTTITools { if (candidate != null && Reflect.field(target, f.name) == null) { var temp = Type.createEmptyInstance(Type.resolveClass(name)); if ((temp is IComponentDelegate)) { - var componentDelegate:IComponentDelegate = Type.createInstance(Type.resolveClass(name), [false]); + var componentDelegate:IComponentDelegate = Type.createEmptyInstance(Type.resolveClass(name)); componentDelegate.component = candidate; Reflect.setField(target, f.name, componentDelegate); } else { From b062f513b35656639135fe7dbf27c42f93f92079 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 14 Nov 2023 21:43:25 +0100 Subject: [PATCH 007/120] registerEvent call proxy --- haxe/ui/backend/flixel/UIRuntimeFragment.hx | 23 ++++++++++++++------- haxe/ui/backend/flixel/UIRuntimeState.hx | 9 ++++++++ haxe/ui/backend/flixel/UIRuntimeSubState.hx | 9 ++++++++ 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/haxe/ui/backend/flixel/UIRuntimeFragment.hx b/haxe/ui/backend/flixel/UIRuntimeFragment.hx index 165fd8c..5bb15a6 100644 --- a/haxe/ui/backend/flixel/UIRuntimeFragment.hx +++ b/haxe/ui/backend/flixel/UIRuntimeFragment.hx @@ -3,6 +3,7 @@ package haxe.ui.backend.flixel; import haxe.ui.RuntimeComponentBuilder; import haxe.ui.core.Component; import haxe.ui.events.UIEvent; +import haxe.ui.events.EventType; import haxe.ui.backend.flixel.UIRTTITools.*; using StringTools; @@ -11,16 +12,14 @@ using StringTools; class UIRuntimeFragment extends UIFragmentBase implements IComponentDelegate { // uses rtti to "build" a class with a similar experience to using macros public var root:Component; - public function new(buildFragment:Bool = true) { + public function new() { super(); - if (buildFragment) { - var rtti = haxe.rtti.Rtti.getRtti(Type.getClass(this)); - root = buildViaRTTI(rtti); - linkViaRTTI(rtti, this, root); - if (root != null) { - add(root); - } + var rtti = haxe.rtti.Rtti.getRtti(Type.getClass(this)); + root = buildViaRTTI(rtti); + linkViaRTTI(rtti, this, root); + if (root != null) { + add(root); } } @@ -94,6 +93,14 @@ class UIRuntimeFragment extends UIFragmentBase implements IComponentDelegate { / root.dispatch(event); } + public function registerEvent(type:EventType, listener:T->Void, priority:Int = 0) { + if (root == null) { + throw "no root component"; + } + + root.registerEvent(type, listener, priority); + } + public override function destroy() { if (root != null) { remove(root); diff --git a/haxe/ui/backend/flixel/UIRuntimeState.hx b/haxe/ui/backend/flixel/UIRuntimeState.hx index e171faa..9bb975d 100644 --- a/haxe/ui/backend/flixel/UIRuntimeState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeState.hx @@ -3,6 +3,7 @@ package haxe.ui.backend.flixel; import haxe.ui.core.Component; import haxe.ui.core.Screen; import haxe.ui.events.UIEvent; +import haxe.ui.events.EventType; import haxe.ui.backend.flixel.UIRTTITools.*; using StringTools; @@ -84,6 +85,14 @@ class UIRuntimeState extends UIStateBase { // uses rtti to "build" a class with root.dispatch(event); } + public function registerEvent(type:EventType, listener:T->Void, priority:Int = 0) { + if (root == null) { + throw "no root component"; + } + + root.registerEvent(type, listener, priority); + } + public override function destroy() { if (root != null) { Screen.instance.removeComponent(root); diff --git a/haxe/ui/backend/flixel/UIRuntimeSubState.hx b/haxe/ui/backend/flixel/UIRuntimeSubState.hx index 91a5dc4..a27ee76 100644 --- a/haxe/ui/backend/flixel/UIRuntimeSubState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeSubState.hx @@ -3,6 +3,7 @@ package haxe.ui.backend.flixel; import haxe.ui.core.Component; import haxe.ui.core.Screen; import haxe.ui.events.UIEvent; +import haxe.ui.events.EventType; import haxe.ui.backend.flixel.UIRTTITools.*; using StringTools; @@ -84,6 +85,14 @@ class UIRuntimeSubState extends UISubStateBase { // uses rtti to "build" a class root.dispatch(event); } + public function registerEvent(type:EventType, listener:T->Void, priority:Int = 0) { + if (root == null) { + throw "no root component"; + } + + root.registerEvent(type, listener, priority); + } + public override function destroy() { if (root != null) { Screen.instance.removeComponent(root); From a6758c4e4d4eb6168d334d737195d7d59029d85d Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 14 Nov 2023 22:01:14 +0100 Subject: [PATCH 008/120] allow @:bind(this, ...) to work --- haxe/ui/backend/flixel/UIRTTITools.hx | 43 +++++++++++++++++++-------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/haxe/ui/backend/flixel/UIRTTITools.hx b/haxe/ui/backend/flixel/UIRTTITools.hx index 56bf4ab..df4755e 100644 --- a/haxe/ui/backend/flixel/UIRTTITools.hx +++ b/haxe/ui/backend/flixel/UIRTTITools.hx @@ -74,24 +74,43 @@ class UIRTTITools { case CFunction(args, ret): var m = getMetaRTTI(f.meta, "bind"); if (m != null) { - var candidate:Component = root.findComponent(m.params[0]); - if (candidate != null) { - var parts = m.params[1].split("."); - var candidateEvent = "haxe.ui.events." + parts[0]; - var c = Type.resolveClass(candidateEvent); - if (c != null) { - var eventString = Reflect.field(c, parts[1]); - var fn = Reflect.field(target, f.name); - candidate.registerEvent(eventString, fn); - } - - } + if (m.params[0] == "this") { + if ((target is IComponentDelegate)) { + var componentDelegate:IComponentDelegate = cast target; + bindEvent(componentDelegate.component, f.name, target, m.params[1]); + } else { + bindEvent(root, f.name, target, m.params[1]); + } + } else { + var candidate:Component = root.findComponent(m.params[0]); + bindEvent(candidate, f.name, target, m.params[1]); + } } case _: } } } + private static function bindEvent(candidate:Component, fieldName:String, target:Dynamic, eventClass:String) { + if (candidate == null) { + return; + } + var parts = eventClass.split("."); + var c = resolveEventClass(eventClass); + if (c != null) { + var eventString = Reflect.field(c, parts[1]); + var fn = Reflect.field(target, fieldName); + candidate.registerEvent(eventString, fn); + } + } + + private static function resolveEventClass(eventClass:String) { + var parts = eventClass.split("."); + var candidateEvent = "haxe.ui.events." + parts[0]; + var c = Type.resolveClass(candidateEvent); + return c; + } + private static function getMetaRTTI(metadata:MetaData, name:String):{name:String, params:Array} { for (m in metadata) { if (m.name == name || m.name == ":" + name) { From 7a95c832af5e41d7daeeeea64520eebd80475286 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 14 Nov 2023 22:46:36 +0100 Subject: [PATCH 009/120] allow @:bind to work with any event type --- haxe/ui/backend/flixel/UIRTTITools.hx | 60 ++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/haxe/ui/backend/flixel/UIRTTITools.hx b/haxe/ui/backend/flixel/UIRTTITools.hx index df4755e..2e190c3 100644 --- a/haxe/ui/backend/flixel/UIRTTITools.hx +++ b/haxe/ui/backend/flixel/UIRTTITools.hx @@ -77,13 +77,13 @@ class UIRTTITools { if (m.params[0] == "this") { if ((target is IComponentDelegate)) { var componentDelegate:IComponentDelegate = cast target; - bindEvent(componentDelegate.component, f.name, target, m.params[1]); + bindEvent(rtti, componentDelegate.component, f.name, target, m.params[1]); } else { - bindEvent(root, f.name, target, m.params[1]); + bindEvent(rtti, root, f.name, target, m.params[1]); } } else { var candidate:Component = root.findComponent(m.params[0]); - bindEvent(candidate, f.name, target, m.params[1]); + bindEvent(rtti, candidate, f.name, target, m.params[1]); } } case _: @@ -91,24 +91,62 @@ class UIRTTITools { } } - private static function bindEvent(candidate:Component, fieldName:String, target:Dynamic, eventClass:String) { + private static function bindEvent(rtti:Classdef, candidate:Component, fieldName:String, target:Dynamic, eventClass:String) { if (candidate == null) { return; } var parts = eventClass.split("."); - var c = resolveEventClass(eventClass); + var eventName = parts.pop(); + eventClass = parts.join("."); + var c = resolveEventClass(rtti, eventClass); if (c != null) { - var eventString = Reflect.field(c, parts[1]); + var eventString = Reflect.field(c, eventName); var fn = Reflect.field(target, fieldName); candidate.registerEvent(eventString, fn); + } else { + throw "could not resolve event class '" + eventClass + "' (you may need to use fully qualified class names)"; } } - private static function resolveEventClass(eventClass:String) { - var parts = eventClass.split("."); - var candidateEvent = "haxe.ui.events." + parts[0]; - var c = Type.resolveClass(candidateEvent); - return c; + private static function resolveEventClass(rtti:Classdef, eventClass:String) { + var candidateEvent = "haxe.ui.events." + eventClass; + var event = Type.resolveClass(candidateEvent); + if (event != null) { + return event; + } + + var event = Type.resolveClass(eventClass); + if (event != null) { + return event; + } + + // this is pretty brute force method, were going to see if we can find any functions + // with @:bind meta, these are presumably the event handlers, if we can find one + // where the the last part of the arg type (which would be the event type) matches + // the event we are looking for, we'll consider that match, and can use that as a + // fully qualified event class + for (f in rtti.fields) { + switch (f.type) { + case CFunction(args, ret): + if (getMetaRTTI(f.meta, "bind") != null) { + for (arg in args) { + switch (arg.t) { + case CClass(name, params): + if (name.endsWith(eventClass)) { + var event = Type.resolveClass(name); + if (event != null) { + return event; + } + } + case _: + } + } + } + case _: + } + } + + return null; } private static function getMetaRTTI(metadata:MetaData, name:String):{name:String, params:Array} { From 54190121468b0cb008acbc0e28928f9e9a5e1447 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 14 Nov 2023 22:55:17 +0100 Subject: [PATCH 010/120] stop double binding in component delegates --- haxe/ui/backend/flixel/UIRTTITools.hx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/haxe/ui/backend/flixel/UIRTTITools.hx b/haxe/ui/backend/flixel/UIRTTITools.hx index 2e190c3..e04e9f6 100644 --- a/haxe/ui/backend/flixel/UIRTTITools.hx +++ b/haxe/ui/backend/flixel/UIRTTITools.hx @@ -77,7 +77,7 @@ class UIRTTITools { if (m.params[0] == "this") { if ((target is IComponentDelegate)) { var componentDelegate:IComponentDelegate = cast target; - bindEvent(rtti, componentDelegate.component, f.name, target, m.params[1]); + bindEvent(rtti, componentDelegate.component, f.name, target, m.params[1], true); } else { bindEvent(rtti, root, f.name, target, m.params[1]); } @@ -91,7 +91,7 @@ class UIRTTITools { } } - private static function bindEvent(rtti:Classdef, candidate:Component, fieldName:String, target:Dynamic, eventClass:String) { + private static function bindEvent(rtti:Classdef, candidate:Component, fieldName:String, target:Dynamic, eventClass:String, isComponentDelegate:Bool = false) { if (candidate == null) { return; } @@ -102,6 +102,14 @@ class UIRTTITools { if (c != null) { var eventString = Reflect.field(c, eventName); var fn = Reflect.field(target, fieldName); + // this may be ill-concieved, but if we are talking about a component delegate (ie, a fragment) + // it means we are going to attach a component to an "empty" class which means this code has + // already run once, meaning there are two event listeners, this way we remove them first + // in practice its probably _exactly_ what we want, but this could also clear up binding + // two functions to the same event (which isnt common at all) + if (isComponentDelegate) { + candidate.unregisterEvents(eventString); + } candidate.registerEvent(eventString, fn); } else { throw "could not resolve event class '" + eventClass + "' (you may need to use fully qualified class names)"; From 1a4893e3f700d9410bad64b11398fd8c61548aa9 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 14 Nov 2023 23:32:35 +0100 Subject: [PATCH 011/120] onReady proxy --- haxe/ui/backend/flixel/UIRuntimeFragment.hx | 6 ++++++ haxe/ui/backend/flixel/UIRuntimeState.hx | 6 ++++++ haxe/ui/backend/flixel/UIRuntimeSubState.hx | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/haxe/ui/backend/flixel/UIRuntimeFragment.hx b/haxe/ui/backend/flixel/UIRuntimeFragment.hx index 5bb15a6..3ab0575 100644 --- a/haxe/ui/backend/flixel/UIRuntimeFragment.hx +++ b/haxe/ui/backend/flixel/UIRuntimeFragment.hx @@ -19,10 +19,16 @@ class UIRuntimeFragment extends UIFragmentBase implements IComponentDelegate { / root = buildViaRTTI(rtti); linkViaRTTI(rtti, this, root); if (root != null) { + root.registerEvent(UIEvent.READY, (_) -> { + onReady(); + }); add(root); } } + private function onReady() { + } + public var component(get, set):Component; private function get_component():Component { return root; diff --git a/haxe/ui/backend/flixel/UIRuntimeState.hx b/haxe/ui/backend/flixel/UIRuntimeState.hx index 9bb975d..31ea1dd 100644 --- a/haxe/ui/backend/flixel/UIRuntimeState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeState.hx @@ -21,11 +21,17 @@ class UIRuntimeState extends UIStateBase { // uses rtti to "build" a class with root = buildViaRTTI(rtti); linkViaRTTI(rtti, this, root); if (root != null) { + root.registerEvent(UIEvent.READY, (_) -> { + onReady(); + }); Screen.instance.addComponent(root); } super.create(); } + private function onReady() { + } + ///////////////////////////////////////////////////////////////////////////////////////////////// // util functions ///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/haxe/ui/backend/flixel/UIRuntimeSubState.hx b/haxe/ui/backend/flixel/UIRuntimeSubState.hx index a27ee76..6d0dba2 100644 --- a/haxe/ui/backend/flixel/UIRuntimeSubState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeSubState.hx @@ -21,11 +21,17 @@ class UIRuntimeSubState extends UISubStateBase { // uses rtti to "build" a class root = buildViaRTTI(rtti); linkViaRTTI(rtti, this, root); if (root != null) { + root.registerEvent(UIEvent.READY, (_) -> { + onReady(); + }); Screen.instance.addComponent(root); } super.create(); } + private function onReady() { + } + ///////////////////////////////////////////////////////////////////////////////////////////////// // util functions ///////////////////////////////////////////////////////////////////////////////////////////////// From 93f66f9793c2de88987f2f0f6df7fb63904b8cad Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Wed, 15 Nov 2023 09:13:39 +0100 Subject: [PATCH 012/120] ability to bind to static fields --- haxe/ui/backend/flixel/UIRTTITools.hx | 46 ++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/haxe/ui/backend/flixel/UIRTTITools.hx b/haxe/ui/backend/flixel/UIRTTITools.hx index e04e9f6..76bb555 100644 --- a/haxe/ui/backend/flixel/UIRTTITools.hx +++ b/haxe/ui/backend/flixel/UIRTTITools.hx @@ -83,7 +83,51 @@ class UIRTTITools { } } else { var candidate:Component = root.findComponent(m.params[0]); - bindEvent(rtti, candidate, f.name, target, m.params[1]); + if (candidate != null) { + bindEvent(rtti, candidate, f.name, target, m.params[1]); + } else { + // another perfectly valid contruct, albeit less common (though still useful), is the ability to use + // @:bind to bind to variables on static fields, eg: + // @:bind(MyClass.instance, SomeEvent.EventType) + // this code facilitates that by attempting to resolve the item and binding the event to it + var parts = m.params[0].split("."); + var className = parts.shift(); + var c = Type.resolveClass(className); + if (c != null) { + var ref:Dynamic = c; + var found = (parts.length > 0); + for (part in parts) { + if (!Reflect.hasField(ref, part)) { + found = false; + break; + } + ref = Reflect.field(ref, part); + } + if (found) { + if (ref != null) { + if ((ref is UIRuntimeState)) { + var state:UIRuntimeState = cast ref; + bindEvent(rtti, state.root, f.name, target, m.params[1]); + } else if ((ref is UIRuntimeSubState)) { + var subState:UIRuntimeSubState = cast ref; + bindEvent(rtti, subState.root, f.name, target, m.params[1]); + } else if ((ref is IComponentDelegate)) { + var componentDelegate:IComponentDelegate = cast ref; + bindEvent(rtti, componentDelegate.component, f.name, target, m.params[1]); + } else if ((ref is Component)) { + var component:Component = cast ref; + bindEvent(rtti, component, f.name, target, m.params[1]); + } + } else { + throw "could not resolve bind param '" + m.params[0] + "'"; + } + } else { + throw "could not resolve bind param '" + m.params[0] + "'"; + } + } else { + throw "could not resolve bind param '" + m.params[0] + "'"; + } + } } } case _: From 4803ea445c322470cd4b5f2994dcb6806604b4ea Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Wed, 15 Nov 2023 09:23:18 +0100 Subject: [PATCH 013/120] better errors --- haxe/ui/backend/flixel/UIRTTITools.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/haxe/ui/backend/flixel/UIRTTITools.hx b/haxe/ui/backend/flixel/UIRTTITools.hx index 76bb555..b83b213 100644 --- a/haxe/ui/backend/flixel/UIRTTITools.hx +++ b/haxe/ui/backend/flixel/UIRTTITools.hx @@ -119,13 +119,13 @@ class UIRTTITools { bindEvent(rtti, component, f.name, target, m.params[1]); } } else { - throw "could not resolve bind param '" + m.params[0] + "'"; + throw "bind param resolved, but was null '" + m.params[0] + "'"; } } else { throw "could not resolve bind param '" + m.params[0] + "'"; } } else { - throw "could not resolve bind param '" + m.params[0] + "'"; + throw "could not resolve class '" + className + "'"; } } } From dc895ed1fd714f372a66bf67cc60d8c6b6b2a1a4 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Wed, 15 Nov 2023 09:36:16 +0100 Subject: [PATCH 014/120] allow for full qualified class names --- haxe/ui/backend/flixel/UIRTTITools.hx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/haxe/ui/backend/flixel/UIRTTITools.hx b/haxe/ui/backend/flixel/UIRTTITools.hx index b83b213..d425dfd 100644 --- a/haxe/ui/backend/flixel/UIRTTITools.hx +++ b/haxe/ui/backend/flixel/UIRTTITools.hx @@ -93,6 +93,24 @@ class UIRTTITools { var parts = m.params[0].split("."); var className = parts.shift(); var c = Type.resolveClass(className); + + if (c == null) { + // this allows full qualified class names: + // @:bind(some.pkg.MyClass.instance, SomeEvent.EventType) + // by looping over each part looking for a valid class + // its not fast (or pretty), but it will only happen once (per @:bind) + var candidateClass = className; + while (parts.length > 0) { + var part = parts.shift(); + candidateClass += "." + part; + var temp = Type.resolveClass(candidateClass); + if (temp != null) { + c = temp; + break; + } + } + } + if (c != null) { var ref:Dynamic = c; var found = (parts.length > 0); From 206ab70c5abbad0c1c33d6eb8a4d5fc6ac0c8467 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 16 Nov 2023 08:54:07 +0100 Subject: [PATCH 015/120] ensure textinput is always at very top --- haxe/ui/backend/ComponentImpl.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 8ce079e..7514edb 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -1037,7 +1037,7 @@ class ComponentImpl extends ComponentBase { super.createTextInput(text); _textInput.attach(); _textInput.tf.visible = false; - FlxG.addChildBelowMouse(_textInput.tf); + FlxG.addChildBelowMouse(_textInput.tf, 0xffffff); /* Toolkit.callLater(function() { // lets show it a frame later so its had a chance to reposition if (_textInput != null) { From dd0660e5b054f8e68aad7d254eb533072cade5b6 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 16 Nov 2023 08:54:22 +0100 Subject: [PATCH 016/120] remove overlap code (textfields need a rework) --- haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx b/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx index 8c894ec..0d19c0b 100644 --- a/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx @@ -89,11 +89,13 @@ class OpenFLTextInput extends TextBase { } } + /* if (overlaps == true && tf.visible == true) { tf.visible = false; } else if (overlaps == false && tf.visible == false) { tf.visible = true; } + */ } public function destroy() { From 94244d9a4be65a8002aa94a3fab0243bd2618d1b Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 16 Nov 2023 18:47:06 +0100 Subject: [PATCH 017/120] show / hide proxy functions --- haxe/ui/backend/flixel/UIRuntimeFragment.hx | 14 ++++++++++++++ haxe/ui/backend/flixel/UIRuntimeState.hx | 14 ++++++++++++++ haxe/ui/backend/flixel/UIRuntimeSubState.hx | 14 ++++++++++++++ haxe/ui/backend/flixel/UIState.hx | 8 ++++++++ haxe/ui/backend/flixel/UISubState.hx | 9 +++++++++ 5 files changed, 59 insertions(+) diff --git a/haxe/ui/backend/flixel/UIRuntimeFragment.hx b/haxe/ui/backend/flixel/UIRuntimeFragment.hx index 3ab0575..2dd22bf 100644 --- a/haxe/ui/backend/flixel/UIRuntimeFragment.hx +++ b/haxe/ui/backend/flixel/UIRuntimeFragment.hx @@ -107,6 +107,20 @@ class UIRuntimeFragment extends UIFragmentBase implements IComponentDelegate { / root.registerEvent(type, listener, priority); } + public function show() { + if (root != null) { + remove(root); + } + root.show(); + } + + public function hide() { + if (root != null) { + remove(root); + } + root.hide(); + } + public override function destroy() { if (root != null) { remove(root); diff --git a/haxe/ui/backend/flixel/UIRuntimeState.hx b/haxe/ui/backend/flixel/UIRuntimeState.hx index 31ea1dd..09cf0b1 100644 --- a/haxe/ui/backend/flixel/UIRuntimeState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeState.hx @@ -99,6 +99,20 @@ class UIRuntimeState extends UIStateBase { // uses rtti to "build" a class with root.registerEvent(type, listener, priority); } + public function show() { + if (root != null) { + remove(root); + } + root.show(); + } + + public function hide() { + if (root != null) { + remove(root); + } + root.hide(); + } + public override function destroy() { if (root != null) { Screen.instance.removeComponent(root); diff --git a/haxe/ui/backend/flixel/UIRuntimeSubState.hx b/haxe/ui/backend/flixel/UIRuntimeSubState.hx index 6d0dba2..61563da 100644 --- a/haxe/ui/backend/flixel/UIRuntimeSubState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeSubState.hx @@ -99,6 +99,20 @@ class UIRuntimeSubState extends UISubStateBase { // uses rtti to "build" a class root.registerEvent(type, listener, priority); } + public function show() { + if (root != null) { + remove(root); + } + root.show(); + } + + public function hide() { + if (root != null) { + remove(root); + } + root.hide(); + } + public override function destroy() { if (root != null) { Screen.instance.removeComponent(root); diff --git a/haxe/ui/backend/flixel/UIState.hx b/haxe/ui/backend/flixel/UIState.hx index 04034a1..b82c9e0 100644 --- a/haxe/ui/backend/flixel/UIState.hx +++ b/haxe/ui/backend/flixel/UIState.hx @@ -87,4 +87,12 @@ class UIState extends UIStateBase { // must use -D haxeui_dont_impose_base_class root.styleString = value; return value; } + + public function show() { + root.show(); + } + + public function hide() { + root.hide(); + } } \ No newline at end of file diff --git a/haxe/ui/backend/flixel/UISubState.hx b/haxe/ui/backend/flixel/UISubState.hx index 7c304a0..a2b3b3a 100644 --- a/haxe/ui/backend/flixel/UISubState.hx +++ b/haxe/ui/backend/flixel/UISubState.hx @@ -87,4 +87,13 @@ class UISubState extends UISubStateBase { // must use -D haxeui_dont_impose_base root.styleString = value; return value; } + + public function show() { + root.show(); + } + + public function hide() { + root.hide(); + } + } \ No newline at end of file From a7acc90b8097118879bbe48422e2bfeb518bda8f Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 16 Nov 2023 18:50:00 +0100 Subject: [PATCH 018/120] copy paste mistake --- haxe/ui/backend/flixel/UIRuntimeFragment.hx | 4 ++-- haxe/ui/backend/flixel/UIRuntimeState.hx | 4 ++-- haxe/ui/backend/flixel/UIRuntimeSubState.hx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/haxe/ui/backend/flixel/UIRuntimeFragment.hx b/haxe/ui/backend/flixel/UIRuntimeFragment.hx index 2dd22bf..725aeea 100644 --- a/haxe/ui/backend/flixel/UIRuntimeFragment.hx +++ b/haxe/ui/backend/flixel/UIRuntimeFragment.hx @@ -109,14 +109,14 @@ class UIRuntimeFragment extends UIFragmentBase implements IComponentDelegate { / public function show() { if (root != null) { - remove(root); + throw "no root component"; } root.show(); } public function hide() { if (root != null) { - remove(root); + throw "no root component"; } root.hide(); } diff --git a/haxe/ui/backend/flixel/UIRuntimeState.hx b/haxe/ui/backend/flixel/UIRuntimeState.hx index 09cf0b1..65ea853 100644 --- a/haxe/ui/backend/flixel/UIRuntimeState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeState.hx @@ -101,14 +101,14 @@ class UIRuntimeState extends UIStateBase { // uses rtti to "build" a class with public function show() { if (root != null) { - remove(root); + throw "no root component"; } root.show(); } public function hide() { if (root != null) { - remove(root); + throw "no root component"; } root.hide(); } diff --git a/haxe/ui/backend/flixel/UIRuntimeSubState.hx b/haxe/ui/backend/flixel/UIRuntimeSubState.hx index 61563da..658bb97 100644 --- a/haxe/ui/backend/flixel/UIRuntimeSubState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeSubState.hx @@ -101,14 +101,14 @@ class UIRuntimeSubState extends UISubStateBase { // uses rtti to "build" a class public function show() { if (root != null) { - remove(root); + throw "no root component"; } root.show(); } public function hide() { if (root != null) { - remove(root); + throw "no root component"; } root.hide(); } From 455d261e80c409cf4ab10f7c38fd3de4203c6fd8 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 16 Nov 2023 18:52:23 +0100 Subject: [PATCH 019/120] incorrect null check --- haxe/ui/backend/flixel/UIRuntimeFragment.hx | 4 ++-- haxe/ui/backend/flixel/UIRuntimeState.hx | 4 ++-- haxe/ui/backend/flixel/UIRuntimeSubState.hx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/haxe/ui/backend/flixel/UIRuntimeFragment.hx b/haxe/ui/backend/flixel/UIRuntimeFragment.hx index 725aeea..21dbef2 100644 --- a/haxe/ui/backend/flixel/UIRuntimeFragment.hx +++ b/haxe/ui/backend/flixel/UIRuntimeFragment.hx @@ -108,14 +108,14 @@ class UIRuntimeFragment extends UIFragmentBase implements IComponentDelegate { / } public function show() { - if (root != null) { + if (root == null) { throw "no root component"; } root.show(); } public function hide() { - if (root != null) { + if (root == null) { throw "no root component"; } root.hide(); diff --git a/haxe/ui/backend/flixel/UIRuntimeState.hx b/haxe/ui/backend/flixel/UIRuntimeState.hx index 65ea853..f1cac83 100644 --- a/haxe/ui/backend/flixel/UIRuntimeState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeState.hx @@ -100,14 +100,14 @@ class UIRuntimeState extends UIStateBase { // uses rtti to "build" a class with } public function show() { - if (root != null) { + if (root == null) { throw "no root component"; } root.show(); } public function hide() { - if (root != null) { + if (root == null) { throw "no root component"; } root.hide(); diff --git a/haxe/ui/backend/flixel/UIRuntimeSubState.hx b/haxe/ui/backend/flixel/UIRuntimeSubState.hx index 658bb97..01fe737 100644 --- a/haxe/ui/backend/flixel/UIRuntimeSubState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeSubState.hx @@ -100,14 +100,14 @@ class UIRuntimeSubState extends UISubStateBase { // uses rtti to "build" a class } public function show() { - if (root != null) { + if (root == null) { throw "no root component"; } root.show(); } public function hide() { - if (root != null) { + if (root == null) { throw "no root component"; } root.hide(); From 89a4cf621e5c204922f7a12fbde5d1d84f8b47f5 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Fri, 17 Nov 2023 11:23:45 +0100 Subject: [PATCH 020/120] dont use weak ref or priority --- haxe/ui/backend/TimerImpl.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haxe/ui/backend/TimerImpl.hx b/haxe/ui/backend/TimerImpl.hx index d69c1b2..27f0165 100644 --- a/haxe/ui/backend/TimerImpl.hx +++ b/haxe/ui/backend/TimerImpl.hx @@ -42,7 +42,7 @@ class TimerImpl { _start = Timer.stamp() + (delay / 1000); __timers.push(this); if (__timers.length == 1) { - Lib.current.stage.addEventListener(Event.ENTER_FRAME, update, false, 10000, true); + Lib.current.stage.addEventListener(Event.ENTER_FRAME, update); } } From 602d1bbc2b7b0c6e7c5fcf83e15cc1e425272f07 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 7 Dec 2023 18:41:29 +0100 Subject: [PATCH 021/120] remove mouse reset stuff (not sure why is there) --- haxe/ui/backend/ScreenImpl.hx | 9 --------- haxe/ui/backend/flixel/MouseHelper.hx | 8 -------- 2 files changed, 17 deletions(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 26d443f..be8cc74 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -86,15 +86,6 @@ class ScreenImpl extends ScreenBase { checkMembers(FlxG.state); FlxG.state.memberRemoved.add(onMemberRemoved); - - #if (!FLX_NO_MOUSE && !haxeui_no_mouse_reset) - var screen = cast(this, haxe.ui.core.Screen); - screen.registerEvent(MouseEvent.MOUSE_DOWN, function(e:MouseEvent) { - if (screen.hasSolidComponentUnderPoint(e.screenX, e.screenY)) { - FlxG.mouse.reset(); - } - }); - #end } private function onMemberAdded(m:FlxBasic) { diff --git a/haxe/ui/backend/flixel/MouseHelper.hx b/haxe/ui/backend/flixel/MouseHelper.hx index 84c0e56..ea5e50e 100644 --- a/haxe/ui/backend/flixel/MouseHelper.hx +++ b/haxe/ui/backend/flixel/MouseHelper.hx @@ -19,8 +19,6 @@ class MouseHelper { private static var _callbacks:Map> = new Map>(); - private static var _inputManager:InputManager = null; - public static function notify(event:String, callback:MouseEvent->Void, priority:Int = 5) { switch (event) { case MouseEvent.MOUSE_DOWN: @@ -71,12 +69,6 @@ class MouseHelper { return a.priority - b.priority; }); } - - if (_inputManager == null) { - _inputManager = new InputManager(); - _inputManager.onResetCb = onPreStateSwitched; - FlxG.inputs.add(_inputManager); - } } public static function remove(event:String, callback:MouseEvent->Void) { From 197bf5e077b4dd36dc29cbe339f68b0137d2535b Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 7 Dec 2023 18:42:39 +0100 Subject: [PATCH 022/120] use @Starmapo's flixel input text (incubating) --- haxe/ui/backend/ComponentImpl.hx | 71 ++-- haxe/ui/backend/TextInputImpl.hx | 13 +- .../backend/flixel/textinputs/FlxTextInput.hx | 343 ++++++++++++++++++ .../flixel/textinputs/OpenFLTextInput.hx | 170 ++++++++- 4 files changed, 560 insertions(+), 37 deletions(-) create mode 100644 haxe/ui/backend/flixel/textinputs/FlxTextInput.hx diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 7514edb..3f79e71 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -1,5 +1,6 @@ package haxe.ui.backend; +import haxe.ui.backend.TextInputImpl.TextInputEvent; import flixel.FlxG; import flixel.FlxSprite; import flixel.math.FlxRect; @@ -284,11 +285,17 @@ class ComponentImpl extends ComponentBase { _unsolicitedMembers = []; } if (findUnsolictedEntryFromSprite(sprite) == null) { - _unsolicitedMembers.push({ - sprite: sprite, - originalX: sprite.x, - originalY: sprite.y - }); + var use = true; + if (_textInput != null && _textInput.equals(sprite)) { + use = false; + } + if (use) { + _unsolicitedMembers.push({ + sprite: sprite, + originalX: sprite.x, + originalY: sprite.y + }); + } } } super.preAdd(sprite); @@ -350,7 +357,7 @@ class ComponentImpl extends ComponentBase { _textDisplay.tf.visible = show; } if (hasTextInput()) { - _textInput.tf.visible = show; + _textInput.visible = show; } for (c in this.childComponents) { @@ -387,7 +394,7 @@ class ComponentImpl extends ComponentBase { getTextDisplay().tf.alpha = value; } if (hasTextInput()) { - getTextInput().tf.alpha = value; + getTextInput().alpha = value; } for (c in childComponents) { c.applyAlpha(value); @@ -400,7 +407,7 @@ class ComponentImpl extends ComponentBase { getTextDisplay().tf.alpha = value; } if (hasTextInput()) { - getTextInput().tf.alpha = alpha; + getTextInput().alpha = alpha; } return super.set_alpha(alpha); } @@ -474,7 +481,7 @@ class ComponentImpl extends ComponentBase { notifyMouseMove(true); _eventMap.set(MouseEvent.MOUSE_DOWN, listener); if (hasTextInput()) { - getTextInput().tf.addEventListener(openfl.events.MouseEvent.MOUSE_DOWN, __onTextInputMouseEvent); + getTextInput().onMouseDown = __onTextInputMouseEvent; } } @@ -485,7 +492,7 @@ class ComponentImpl extends ComponentBase { notifyMouseMove(true); _eventMap.set(MouseEvent.MOUSE_UP, listener); if (hasTextInput()) { - getTextInput().tf.addEventListener(openfl.events.MouseEvent.MOUSE_UP, __onTextInputMouseEvent); + getTextInput().onMouseUp = __onTextInputMouseEvent; } } @@ -503,7 +510,7 @@ class ComponentImpl extends ComponentBase { notifyMouseMove(true); _eventMap.set(MouseEvent.CLICK, listener); if (hasTextInput()) { - getTextInput().tf.addEventListener(openfl.events.MouseEvent.CLICK, __onTextInputMouseEvent); + getTextInput().onClick = __onTextInputMouseEvent; } } @@ -543,7 +550,7 @@ class ComponentImpl extends ComponentBase { if (_eventMap.exists(UIEvent.CHANGE) == false) { if (hasTextInput() == true) { _eventMap.set(UIEvent.CHANGE, listener); - getTextInput().tf.addEventListener(Event.CHANGE, __onTextInputChange); + getTextInput().onChange = __onTextInputChange; } } } @@ -569,7 +576,7 @@ class ComponentImpl extends ComponentBase { notifyMouseUp(false); notifyMouseMove(false); if (hasTextInput()) { - getTextInput().tf.removeEventListener(openfl.events.MouseEvent.MOUSE_DOWN, __onTextInputMouseEvent); + getTextInput().onMouseDown = null; } @@ -579,7 +586,7 @@ class ComponentImpl extends ComponentBase { notifyMouseUp(false); notifyMouseMove(false); if (hasTextInput()) { - getTextInput().tf.removeEventListener(openfl.events.MouseEvent.MOUSE_UP, __onTextInputMouseEvent); + getTextInput().onMouseUp = null; } case MouseEvent.MOUSE_WHEEL: @@ -593,7 +600,7 @@ class ComponentImpl extends ComponentBase { notifyMouseUp(false); notifyMouseMove(false); if (hasTextInput()) { - getTextInput().tf.removeEventListener(openfl.events.MouseEvent.CLICK, __onTextInputMouseEvent); + getTextInput().onClick = null; } case MouseEvent.DBL_CLICK: @@ -623,7 +630,7 @@ class ComponentImpl extends ComponentBase { case UIEvent.CHANGE: _eventMap.remove(type); if (hasTextInput() == true) { - getTextInput().tf.removeEventListener(Event.CHANGE, __onTextInputChange); + getTextInput().onChange = null; } } } @@ -693,16 +700,14 @@ class ComponentImpl extends ComponentBase { } } - private function __onTextInputChange(event:Event) { + private function __onTextInputChange(event:TextInputEvent) { var fn:UIEvent->Void = _eventMap.get(UIEvent.CHANGE); if (fn != null) { fn(new UIEvent(UIEvent.CHANGE)); } } - // since we use openfl's text input for text input we need to handle its events differently - // to how we do in the rest of haxeui-flixel - private function __onTextInputMouseEvent(event:openfl.events.MouseEvent) { + private function __onTextInputMouseEvent(event:TextInputEvent) { var type = null; switch (event.type) { case openfl.events.MouseEvent.MOUSE_DOWN: @@ -1036,8 +1041,8 @@ class ComponentImpl extends ComponentBase { if (_textInput == null) { super.createTextInput(text); _textInput.attach(); - _textInput.tf.visible = false; - FlxG.addChildBelowMouse(_textInput.tf, 0xffffff); + _textInput.visible = false; + _textInput.addToComponent(cast this); /* Toolkit.callLater(function() { // lets show it a frame later so its had a chance to reposition if (_textInput != null) { @@ -1079,10 +1084,10 @@ class ComponentImpl extends ComponentBase { var offsetY = 2 / Toolkit.scaleY; #end - _textInput.tf.x = (_surface.x + _textInput.left - offsetX) * FlxG.scaleMode.scale.x; - _textInput.tf.y = (_surface.y + _textInput.top - offsetY) * FlxG.scaleMode.scale.y; - _textInput.tf.scaleX = FlxG.scaleMode.scale.x; - _textInput.tf.scaleY = FlxG.scaleMode.scale.y; + _textInput.x = (_surface.x + _textInput.left - offsetX) * FlxG.scaleMode.scale.x; + _textInput.y = (_surface.y + _textInput.top - offsetY) * FlxG.scaleMode.scale.y; + _textInput.scaleX = FlxG.scaleMode.scale.x; + _textInput.scaleY = FlxG.scaleMode.scale.y; _textInput.update(); } @@ -1225,8 +1230,12 @@ class ComponentImpl extends ComponentBase { // application, this means that when things are removed from the screen (and not destroyed) it can leave them // behind private function applyAddInternal() { + if (!TextInputImpl.USE_ON_ADDED) { + return; + } + if (hasTextInput() && asComponent.hidden == false) { - getTextInput().tf.visible = true; + getTextInput().visible = true; } for (c in childComponents) { c.applyAddInternal(); @@ -1234,8 +1243,12 @@ class ComponentImpl extends ComponentBase { } private function applyRemoveInternal() { + if (!TextInputImpl.USE_ON_REMOVED) { + return; + } + if (hasTextInput()) { - getTextInput().tf.visible = false; + getTextInput().visible = false; } for (c in childComponents) { c.applyRemoveInternal(); @@ -1258,7 +1271,7 @@ class ComponentImpl extends ComponentBase { } if (_textInput != null) { - _textInput.destroy(); + _textInput.destroy(cast this); _textInput = null; } diff --git a/haxe/ui/backend/TextInputImpl.hx b/haxe/ui/backend/TextInputImpl.hx index 061bf09..5eba182 100644 --- a/haxe/ui/backend/TextInputImpl.hx +++ b/haxe/ui/backend/TextInputImpl.hx @@ -1,6 +1,13 @@ package haxe.ui.backend; -import haxe.ui.backend.flixel.textinputs.OpenFLTextInput; +typedef TextInputEvent = {type:String, stageX:Float, stageY:Float}; -class TextInputImpl extends OpenFLTextInput { -} +#if flixel_text_input + +typedef TextInputImpl = haxe.ui.backend.flixel.textinputs.FlxTextInput; + +#else + +typedef TextInputImpl = haxe.ui.backend.flixel.textinputs.OpenFLTextInput; + +#end diff --git a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx new file mode 100644 index 0000000..e4a69f7 --- /dev/null +++ b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx @@ -0,0 +1,343 @@ +package haxe.ui.backend.flixel.textinputs; + +import flixel.FlxSprite; +import haxe.ui.backend.TextInputImpl.TextInputEvent; +import haxe.ui.core.Component; +import openfl.events.Event; + +class FlxTextInput extends TextBase { + public static var USE_ON_ADDED:Bool = false; + public static var USE_ON_REMOVED:Bool = false; + + private var PADDING_X:Int = 4; + private var PADDING_Y:Int = 0; + + private var tf:flixel.addons.text.FlxTextInput; + + public function new() { + super(); + tf = new flixel.addons.text.FlxTextInput(); + tf.onChange.add(onInternalChange); + tf.onScroll.add(onScroll); + tf.moves = false; + } + + public override function focus() { + tf.focus = true; + } + + public override function blur() { + tf.focus = false; + } + + public function attach() { + } + + public var visible(get, set):Bool; + private function get_visible():Bool { + return tf.visible; + } + private function set_visible(value:Bool):Bool { + tf.visible = value; + return value; + } + + public var x(get, set):Float; + private function get_x():Float { + return tf.x; + } + private function set_x(value:Float):Float { + tf.x = value; + return value; + } + + public var y(get, set):Float; + private function get_y():Float { + return tf.y; + } + private function set_y(value:Float):Float { + tf.y = value; + return value; + } + + public var scaleX(get, set):Float; + private function get_scaleX():Float { + return tf.scale.x; + } + private function set_scaleX(value:Float):Float { + tf.scale.x = value; + return value; + } + + public var scaleY(get, set):Float; + private function get_scaleY():Float { + return tf.scale.y; + } + private function set_scaleY(value:Float):Float { + tf.scale.y = value; + return value; + } + + public var alpha(get, set):Float; + private function get_alpha():Float { + return tf.alpha; + } + private function set_alpha(value:Float):Float { + tf.alpha = value; + return value; + } + + private override function validateData() { + if (_text != null) { + if (_dataSource == null) { + tf.text = normalizeText(_text); + } + } + + var hscrollValue = Std.int(_inputData.hscrollPos); + if (tf.scrollH != hscrollValue) { + tf.scrollH = hscrollValue; + } + + var vscrollValue = Std.int(_inputData.vscrollPos); + if (tf.scrollV != vscrollValue) { + tf.scrollV = vscrollValue; + } + } + + private function normalizeText(text:String):String { + text = StringTools.replace(text, "\\n", "\n"); + return text; + } + + private override function measureText() { + //tf.width = _width * Toolkit.scaleX; + _textHeight = tf.textField.textHeight; + if (_textHeight == 0) { + var tmpText:String = tf.text; + tf.text = "|"; + _textHeight = tf.textField.textHeight; + tf.text = tmpText; + } + + _textWidth = Math.round(_textWidth) / Toolkit.scaleX; + _textHeight = Math.round(_textHeight) / Toolkit.scaleY; + + ////////////////////////////////////////////////////////////////////////////// + + _inputData.hscrollMax = tf.maxScrollH; + // see below + _inputData.hscrollPageSize = (_width * _inputData.hscrollMax) / _textWidth; + + _inputData.vscrollMax = tf.maxScrollV; + _inputData.vscrollPageSize = (_height * _inputData.vscrollMax) / _textHeight; + } + + private override function validateStyle():Bool { + var measureTextRequired:Bool = false; + + if (_textStyle != null) { + if (tf.alignment != _textStyle.textAlign) { + tf.alignment = _textStyle.textAlign; + } + + var fontSizeValue = Std.int(_textStyle.fontSize); + if (tf.size != fontSizeValue) { + tf.size = Std.int(fontSizeValue * Toolkit.scale); + + measureTextRequired = true; + } + + if (_fontInfo != null && tf.font != _fontInfo.data) { + tf.font = _fontInfo.data; + measureTextRequired = true; + } + + if (tf.color != _textStyle.color) { + tf.color = _textStyle.color; + } + + if (tf.bold != _textStyle.fontBold) { + tf.bold = _textStyle.fontBold; + measureTextRequired = true; + } + + if (tf.italic != _textStyle.fontItalic) { + tf.italic = _textStyle.fontItalic; + measureTextRequired = true; + } + } + + if (tf.wordWrap != _displayData.wordWrap) { + tf.wordWrap = _displayData.wordWrap; + measureTextRequired = true; + } + + if (tf.multiline != _displayData.multiline) { + tf.multiline = _displayData.multiline; + measureTextRequired = true; + } + + if (tf.displayAsPassword != _inputData.password) { + tf.displayAsPassword = _inputData.password; + } + + return measureTextRequired; + } + + private override function validatePosition() { + _left = Math.round(_left * Toolkit.scaleX); + _top = Math.round(_top * Toolkit.scaleY); + } + + private override function validateDisplay() { + if (_width <= 0 || _height <= 0) { + return; + } + + if (tf.width != _width * Toolkit.scaleX) { + tf.width = _width * Toolkit.scaleX; + tf.fieldWidth = tf.width; + } + + if (tf.height != _height * Toolkit.scaleY) { + tf.height = _height * Toolkit.scaleY; + tf.fieldHeight = tf.height; + } + } + + private var _onMouseDown:TextInputEvent->Void = null; + public var onMouseDown(null, set):TextInputEvent->Void; + private function set_onMouseDown(value:TextInputEvent->Void):TextInputEvent->Void { + if (_onMouseDown != null) { + //tf.removeEventListener(openfl.events.MouseEvent.MOUSE_DOWN, __onTextInputMouseDownEvent); + } + _onMouseDown = value; + if (_onMouseDown != null) { + //tf.addEventListener(openfl.events.MouseEvent.MOUSE_DOWN, __onTextInputMouseDownEvent); + } + return value; + } + + /* + private function __onTextInputMouseDownEvent(event:openfl.events.MouseEvent) { + if (_onMouseDown != null) { + _onMouseDown({ + type: event.type, + stageX: event.stageX, + stageY: event.stageY + }); + } + } + */ + + private var _onMouseUp:TextInputEvent->Void = null; + public var onMouseUp(null, set):TextInputEvent->Void; + private function set_onMouseUp(value:TextInputEvent->Void):TextInputEvent->Void { + if (_onMouseUp != null) { + //tf.removeEventListener(openfl.events.MouseEvent.MOUSE_UP, __onTextInputMouseUpEvent); + } + _onMouseUp = value; + if (_onMouseUp != null) { + //tf.addEventListener(openfl.events.MouseEvent.MOUSE_UP, __onTextInputMouseUpEvent); + } + return value; + } + + /* + private function __onTextInputMouseUpEvent(event:openfl.events.MouseEvent) { + if (_onMouseUp != null) { + _onMouseUp({ + type: event.type, + stageX: event.stageX, + stageY: event.stageY + }); + } + } + */ + + public function equals(sprite:FlxSprite):Bool { + return sprite == tf; + } + + private var _onClick:TextInputEvent->Void = null; + public var onClick(null, set):TextInputEvent->Void; + private function set_onClick(value:TextInputEvent->Void):TextInputEvent->Void { + if (_onClick != null) { + //tf.removeEventListener(openfl.events.MouseEvent.CLICK, __onTextInputClickEvent); + } + _onClick = value; + if (_onClick != null) { + //tf.addEventListener(openfl.events.MouseEvent.CLICK, __onTextInputClickEvent); + } + return value; + } + + /* + private function __onTextInputClickEvent(event:openfl.events.MouseEvent) { + if (_onClick != null) { + _onClick({ + type: event.type, + stageX: event.stageX, + stageY: event.stageY + }); + } + } + */ + + private var _onChange:TextInputEvent->Void = null; + public var onChange(null, set):TextInputEvent->Void; + private function set_onChange(value:TextInputEvent->Void):TextInputEvent->Void { + if (_onChange != null) { + tf.onChange.remove(__onTextInputChangeEvent); + } + _onChange = value; + if (_onChange != null) { + tf.onChange.add(__onTextInputChangeEvent); + } + return value; + } + + private function __onTextInputChangeEvent() { + if (_onChange != null) { + _onChange({ + type: "change", + stageX: 0, + stageY: 0 + }); + } + } + + private function onInternalChange() { + _text = tf.text; + + measureText(); + + if (_inputData.onChangedCallback != null) { + _inputData.onChangedCallback(); + } + } + + private function onScroll() { + _inputData.hscrollPos = tf.scrollH; + _inputData.vscrollPos = tf.scrollV; + + if (_inputData.onScrollCallback != null) { + _inputData.onScrollCallback(); + } + } + + public function update() { + } + + public function addToComponent(component:Component) { + //StateHelper.currentState.add(tf); + component.add(tf); + } + + public function destroy(component:Component) { + tf.visible = false; + component.remove(tf); + tf = null; + } +} \ No newline at end of file diff --git a/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx b/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx index 0d19c0b..db55676 100644 --- a/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx @@ -1,5 +1,6 @@ package haxe.ui.backend.flixel.textinputs; +import flixel.FlxSprite; import flixel.FlxG; import haxe.ui.Toolkit; import haxe.ui.core.Component; @@ -11,8 +12,12 @@ import openfl.text.TextField; import openfl.text.TextFieldAutoSize; import openfl.text.TextFieldType; import openfl.text.TextFormat; +import haxe.ui.backend.TextInputImpl.TextInputEvent; class OpenFLTextInput extends TextBase { + public static var USE_ON_ADDED:Bool = true; + public static var USE_ON_REMOVED:Bool = true; + private var PADDING_X:Int = 4; private var PADDING_Y:Int = 0; @@ -29,24 +34,179 @@ class OpenFLTextInput extends TextBase { tf.wordWrap = true; tf.tabEnabled = false; //tf.stage.focus = null; - tf.addEventListener(Event.CHANGE, onChange); + tf.addEventListener(Event.CHANGE, onInternalChange); } public override function focus() { if (tf.stage != null) { - tf.stage.focus = tf; + //tf.stage.focus = tf; } } public override function blur() { if (tf.stage != null) { - tf.stage.focus = null; + //tf.stage.focus = null; } } public function attach() { } + public var visible(get, set):Bool; + private function get_visible():Bool { + return tf.visible; + } + private function set_visible(value:Bool):Bool { + tf.visible = value; + return value; + } + + public var x(get, set):Float; + private function get_x():Float { + return tf.x; + } + private function set_x(value:Float):Float { + tf.x = value; + return value; + } + + public var y(get, set):Float; + private function get_y():Float { + return tf.y; + } + private function set_y(value:Float):Float { + tf.y = value; + return value; + } + + public var scaleX(get, set):Float; + private function get_scaleX():Float { + return tf.scaleX; + } + private function set_scaleX(value:Float):Float { + tf.scaleX = value; + return value; + } + + public var scaleY(get, set):Float; + private function get_scaleY():Float { + return tf.scaleY; + } + private function set_scaleY(value:Float):Float { + tf.scaleY = value; + return value; + } + + public var alpha(get, set):Float; + private function get_alpha():Float { + return tf.alpha; + } + private function set_alpha(value:Float):Float { + tf.alpha = value; + return value; + } + + + private var _onMouseDown:TextInputEvent->Void = null; + public var onMouseDown(null, set):TextInputEvent->Void; + private function set_onMouseDown(value:TextInputEvent->Void):TextInputEvent->Void { + if (_onMouseDown != null) { + tf.removeEventListener(openfl.events.MouseEvent.MOUSE_DOWN, __onTextInputMouseDownEvent); + } + _onMouseDown = value; + if (_onMouseDown != null) { + tf.addEventListener(openfl.events.MouseEvent.MOUSE_DOWN, __onTextInputMouseDownEvent); + } + return value; + } + + private function __onTextInputMouseDownEvent(event:openfl.events.MouseEvent) { + if (_onMouseDown != null) { + _onMouseDown({ + type: event.type, + stageX: event.stageX, + stageY: event.stageY + }); + } + } + + private var _onMouseUp:TextInputEvent->Void = null; + public var onMouseUp(null, set):TextInputEvent->Void; + private function set_onMouseUp(value:TextInputEvent->Void):TextInputEvent->Void { + if (_onMouseUp != null) { + tf.removeEventListener(openfl.events.MouseEvent.MOUSE_UP, __onTextInputMouseUpEvent); + } + _onMouseUp = value; + if (_onMouseUp != null) { + tf.addEventListener(openfl.events.MouseEvent.MOUSE_UP, __onTextInputMouseUpEvent); + } + return value; + } + + private function __onTextInputMouseUpEvent(event:openfl.events.MouseEvent) { + if (_onMouseUp != null) { + _onMouseUp({ + type: event.type, + stageX: event.stageX, + stageY: event.stageY + }); + } + } + + private var _onClick:TextInputEvent->Void = null; + public var onClick(null, set):TextInputEvent->Void; + private function set_onClick(value:TextInputEvent->Void):TextInputEvent->Void { + if (_onClick != null) { + tf.removeEventListener(openfl.events.MouseEvent.CLICK, __onTextInputClickEvent); + } + _onClick = value; + if (_onClick != null) { + tf.addEventListener(openfl.events.MouseEvent.CLICK, __onTextInputClickEvent); + } + return value; + } + + private function __onTextInputClickEvent(event:openfl.events.MouseEvent) { + if (_onClick != null) { + _onClick({ + type: event.type, + stageX: event.stageX, + stageY: event.stageY + }); + } + } + + private var _onChange:TextInputEvent->Void = null; + public var onChange(null, set):TextInputEvent->Void; + private function set_onChange(value:TextInputEvent->Void):TextInputEvent->Void { + if (_onChange != null) { + tf.removeEventListener(Event.CHANGE, __onTextInputChangeEvent); + } + _onChange = value; + if (_onChange != null) { + tf.addEventListener(Event.CHANGE, __onTextInputChangeEvent); + } + return value; + } + + private function __onTextInputChangeEvent(event:Event) { + if (_onChange != null) { + _onChange({ + type: event.type, + stageX: 0, + stageY: 0 + }); + } + } + + public function addToComponent(component:Component) { + FlxG.addChildBelowMouse(tf, 0xffffff); + } + + public function equals(sprite:FlxSprite):Bool { + return false; + } + private var _parentHidden:Bool = false; public function update() { var ref = parentComponent; @@ -98,7 +258,7 @@ class OpenFLTextInput extends TextBase { */ } - public function destroy() { + public function destroy(component:Component) { _parentHidden = true; tf.visible = false; FlxG.removeChild(tf); @@ -219,7 +379,7 @@ class OpenFLTextInput extends TextBase { return measureTextRequired; } - private function onChange(e) { + private function onInternalChange(e:Event) { _text = tf.text; measureText(); From cbe677796491dea9321eb80a3074c17bc1f21869 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 7 Dec 2023 18:46:44 +0100 Subject: [PATCH 023/120] guard against lib not being installed and all classes included --- haxe/ui/backend/flixel/textinputs/FlxTextInput.hx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx index e4a69f7..e552882 100644 --- a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx @@ -5,6 +5,8 @@ import haxe.ui.backend.TextInputImpl.TextInputEvent; import haxe.ui.core.Component; import openfl.events.Event; +#if flixel_text_input + class FlxTextInput extends TextBase { public static var USE_ON_ADDED:Bool = false; public static var USE_ON_REMOVED:Bool = false; @@ -340,4 +342,6 @@ class FlxTextInput extends TextBase { component.remove(tf); tf = null; } -} \ No newline at end of file +} + +#end \ No newline at end of file From c10e2e21a03f3bf34b806e1c20e61af3695a81b6 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Sat, 9 Dec 2023 09:42:13 +0100 Subject: [PATCH 024/120] should be "alpha" not "value" --- haxe/ui/backend/ComponentImpl.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 3f79e71..68a2839 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -404,7 +404,7 @@ class ComponentImpl extends ComponentBase { public override function set_alpha(alpha:Float):Float { _surface.alpha = alpha; if (hasTextDisplay()) { - getTextDisplay().tf.alpha = value; + getTextDisplay().tf.alpha = alpha; } if (hasTextInput()) { getTextInput().alpha = alpha; From 4c5e45a5d0b69fa43ce6bfe50a5c8f32f1220b8c Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Wed, 13 Dec 2023 21:28:11 +0100 Subject: [PATCH 025/120] use timer for calllaterimpl --- haxe/ui/backend/CallLaterImpl.hx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/haxe/ui/backend/CallLaterImpl.hx b/haxe/ui/backend/CallLaterImpl.hx index 9bdb662..61ba381 100644 --- a/haxe/ui/backend/CallLaterImpl.hx +++ b/haxe/ui/backend/CallLaterImpl.hx @@ -1,5 +1,12 @@ package haxe.ui.backend; +class CallLaterImpl { + public function new(fn:Void->Void) { + haxe.ui.util.Timer.delay(fn, 0); + } +} + +/* this version seems to hold the main loop up - unsure why, but animations simply dont work - even though the props seem to be get set correctly import flixel.FlxG; class CallLaterImpl { @@ -18,4 +25,5 @@ class CallLaterImpl { fns.pop()(); } } -} \ No newline at end of file +} +*/ \ No newline at end of file From d1964c69f185b5ecfbb338ef389eb10495ab0f85 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Wed, 13 Dec 2023 21:38:18 +0100 Subject: [PATCH 026/120] apply alpha to imagedisplay --- haxe/ui/backend/ComponentImpl.hx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 68a2839..896be17 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -396,6 +396,9 @@ class ComponentImpl extends ComponentBase { if (hasTextInput()) { getTextInput().alpha = value; } + if (hasImageDisplay()) { + getImageDisplay().alpha = value; + } for (c in childComponents) { c.applyAlpha(value); } From 989698a1b8f76b18775730688b1783e8d46305e5 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Wed, 13 Dec 2023 21:39:08 +0100 Subject: [PATCH 027/120] apply alpha to imagedisplay --- haxe/ui/backend/ComponentImpl.hx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 896be17..7f6db69 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -412,6 +412,9 @@ class ComponentImpl extends ComponentBase { if (hasTextInput()) { getTextInput().alpha = alpha; } + if (hasImageDisplay()) { + getImageDisplay().alpha = alpha; + } return super.set_alpha(alpha); } From 7f146b57e7cb6588d7e6c22891ad4eef779b0e0c Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Wed, 13 Dec 2023 21:40:56 +0100 Subject: [PATCH 028/120] imagedisplay could have been destroyed between frames --- haxe/ui/backend/ComponentImpl.hx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 7f6db69..4f8defe 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -442,7 +442,9 @@ class ComponentImpl extends ComponentBase { _imageDisplay.visible = false; add(_imageDisplay); Toolkit.callLater(function() { // lets show it a frame later so its had a chance to reposition - _imageDisplay.visible = true; + if (_imaageDisplay != null) { + _imageDisplay.visible = true; + } }); } From d90758b229d05206400df867d333c79d9fdbd478 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Wed, 13 Dec 2023 21:41:28 +0100 Subject: [PATCH 029/120] typo --- haxe/ui/backend/ComponentImpl.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 4f8defe..09c48a4 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -442,7 +442,7 @@ class ComponentImpl extends ComponentBase { _imageDisplay.visible = false; add(_imageDisplay); Toolkit.callLater(function() { // lets show it a frame later so its had a chance to reposition - if (_imaageDisplay != null) { + if (_imageDisplay != null) { _imageDisplay.visible = true; } }); From b3cc6f1b08f4d7b1e39e7c31dea330ae8ef3a8af Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 14 Dec 2023 09:15:27 +0100 Subject: [PATCH 030/120] remove 4.9 code (min version >= 4.9) --- haxe/ui/backend/ScreenImpl.hx | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index be8cc74..ec01e4f 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -21,23 +21,9 @@ import openfl.Lib; class ScreenImpl extends ScreenBase { private var _mapping:MapVoid>; - #if (flixel < "4.9.0") // subStateOpened / subStateClosed added in 4.9.0 - private static var _inputManager:haxe.ui.backend.flixel.InputManager = null; - #end - public function new() { _mapping = new MapVoid>(); - #if (flixel < "4.9.0") // subStateOpened / subStateClosed added in 4.9.0 - - if (_inputManager == null) { - _inputManager = new haxe.ui.backend.flixel.InputManager(); - _inputManager.onResetCb = onReset; - FlxG.inputs.add(_inputManager); - } - - #end - FlxG.signals.postGameStart.add(onPostGameStart); FlxG.signals.postStateSwitch.add(onPostStateSwitch); FlxG.signals.preStateCreate.add(onPreStateCreate); @@ -52,22 +38,6 @@ class ScreenImpl extends ScreenBase { state.memberRemoved.add(onMemberRemoved); } - #if (flixel < "4.9.0") // subStateOpened / subStateClosed added in 4.9.0 - - private function onReset() { - if (FlxG.state != null && FlxG.state.subState != null) { - var cachedSubStateOpenedCallback = FlxG.state.subState.openCallback; - FlxG.state.subState.openCallback = function() { - onMemberAdded(FlxG.state.subState); - if (cachedSubStateOpenedCallback != null) { - cachedSubStateOpenedCallback(); - } - } - } - } - - #end - private function onPostGameStart() { onPostStateSwitch(); } @@ -78,10 +48,7 @@ class ScreenImpl extends ScreenBase { } rootComponents = []; - #if (flixel >= "4.9.0") // subStateOpened / subStateClosed added in 4.9.0 FlxG.state.subStateOpened.add(onMemberAdded); - #end - FlxG.state.memberAdded.add(onMemberAdded); checkMembers(FlxG.state); From f85d9e97c513fff5f28e1b708a0b23c939a742c4 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 14 Dec 2023 10:29:03 +0100 Subject: [PATCH 031/120] ensure events are only added once --- haxe/ui/backend/ScreenImpl.hx | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index ec01e4f..bf2aab0 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -33,9 +33,13 @@ class ScreenImpl extends ScreenBase { } private function onPreStateCreate(state:flixel.FlxState) { - state.memberAdded.add(onMemberAdded); + if (!state.memberAdded.has(onMemberAdded)) { + state.memberAdded.add(onMemberAdded); + } checkMembers(state); - state.memberRemoved.add(onMemberRemoved); + if (!state.memberRemoved.has(onMemberRemoved)) { + state.memberRemoved.add(onMemberRemoved); + } } private function onPostGameStart() { @@ -48,11 +52,17 @@ class ScreenImpl extends ScreenBase { } rootComponents = []; - FlxG.state.subStateOpened.add(onMemberAdded); - FlxG.state.memberAdded.add(onMemberAdded); + if (!FlxG.state.subStateOpened.has(onMemberAdded)) { + FlxG.state.subStateOpened.add(onMemberAdded); + } + if (!FlxG.state.memberAdded.has(onMemberAdded)) { + FlxG.state.memberAdded.add(onMemberAdded); + } checkMembers(FlxG.state); - FlxG.state.memberRemoved.add(onMemberRemoved); + if (!FlxG.state.memberRemoved.has(onMemberRemoved)) { + FlxG.state.memberRemoved.add(onMemberRemoved); + } } private function onMemberAdded(m:FlxBasic) { From 3cf7dd8382abfdfd0ecf3dc80dcf35fc53450dc4 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 14 Dec 2023 10:37:31 +0100 Subject: [PATCH 032/120] better way to detect the state a component is in --- haxe/ui/backend/ComponentImpl.hx | 25 ++++++++++++++++++------- haxe/ui/backend/ScreenImpl.hx | 2 ++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 09c48a4..35d2788 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -1,5 +1,6 @@ package haxe.ui.backend; +import flixel.FlxState; import haxe.ui.backend.TextInputImpl.TextInputEvent; import flixel.FlxG; import flixel.FlxSprite; @@ -72,6 +73,17 @@ class ComponentImpl extends ComponentBase { } } + private var _state:FlxState; + public var state(get, set):FlxState; + private function get_state():FlxState { + return findRootComponent()._state; + } + private function set_state(value:FlxState):FlxState { + findRootComponent()._state = value; + return value; + } + + // lets cache certain items so we dont have to loop multiple times per frame private var _cachedScreenX:Null = null; private var _cachedScreenY:Null = null; @@ -745,7 +757,7 @@ class ComponentImpl extends ComponentBase { lastMouseX = x; lastMouseY = y; - var hasMember = StateHelper.hasMember(_surface); + var hasMember = (this.state == StateHelper.currentState); if (Platform.instance.isMobile == false) { if (_mouseOverFlag == true) { @@ -841,11 +853,10 @@ class ComponentImpl extends ComponentBase { } } - - if (StateHelper.hasMember(_surface) == false) { + if (this.state != StateHelper.currentState) { return; } - + var button:Int = event.data; var x = event.screenX; var y = event.screenY; @@ -884,7 +895,7 @@ class ComponentImpl extends ComponentBase { } } - if (StateHelper.hasMember(_surface) == false) { + if (this.state != StateHelper.currentState) { return; } @@ -949,7 +960,7 @@ class ComponentImpl extends ComponentBase { #end private function __onDoubleClick(event:MouseEvent) { - if (StateHelper.hasMember(_surface) == false) { + if (this.state != StateHelper.currentState) { return; } @@ -988,7 +999,7 @@ class ComponentImpl extends ComponentBase { } private function __onMouseWheel(event:MouseEvent) { - if (StateHelper.hasMember(_surface) == false) { + if (this.state != StateHelper.currentState) { return; } diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index bf2aab0..66ac9cd 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -74,6 +74,7 @@ class ScreenImpl extends ScreenBase { if (c.percentHeight > 0) { c.height = (this.height * c.percentHeight) / 100; } + c.state = StateHelper.currentState; rootComponents.push(c); c.recursiveReady(); c.syncComponentValidation(); @@ -101,6 +102,7 @@ class ScreenImpl extends ScreenBase { if (c.percentHeight > 0) { c.height = (this.height * c.percentHeight) / 100; } + c.state = StateHelper.currentState; rootComponents.push(c); c.recursiveReady(); c.syncComponentValidation(); From 27bdb4e164ea683b229583cf0096f650280e8b8d Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 14 Dec 2023 10:59:11 +0100 Subject: [PATCH 033/120] unset .state (so no refs are kept) --- haxe/ui/backend/ScreenImpl.hx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 66ac9cd..f9fe7d6 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -63,6 +63,9 @@ class ScreenImpl extends ScreenBase { if (!FlxG.state.memberRemoved.has(onMemberRemoved)) { FlxG.state.memberRemoved.add(onMemberRemoved); } + if (!FlxG.state.subStateClosed.has(onMemberRemoved)) { + FlxG.state.subStateClosed.add(onMemberRemoved); + } } private function onMemberAdded(m:FlxBasic) { @@ -219,6 +222,7 @@ class ScreenImpl extends ScreenBase { if (StateHelper.currentState.exists == true) { StateHelper.currentState.remove(component, true); } + component.state = null; checkResetCursor(); onContainerResize(); return component; From 26b6bb132c92dfa9b77b4a61eaeda8f9a9efda98 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 14 Dec 2023 18:26:32 +0100 Subject: [PATCH 034/120] better calllaterimpl (now behaves somewhat like requestAnimationFrame) --- haxe/ui/backend/CallLaterImpl.hx | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/haxe/ui/backend/CallLaterImpl.hx b/haxe/ui/backend/CallLaterImpl.hx index 61ba381..fbe8a20 100644 --- a/haxe/ui/backend/CallLaterImpl.hx +++ b/haxe/ui/backend/CallLaterImpl.hx @@ -1,29 +1,33 @@ package haxe.ui.backend; -class CallLaterImpl { - public function new(fn:Void->Void) { - haxe.ui.util.Timer.delay(fn, 0); - } -} - -/* this version seems to hold the main loop up - unsure why, but animations simply dont work - even though the props seem to be get set correctly import flixel.FlxG; +// we'll flip between two list references between updates meaning there is breathing space +// between calls rather that just filling a list and blocking class CallLaterImpl { + private static var added:Bool = false; - private static var fns:ArrayVoid> = []; + private static var current:ArrayVoid>; + private static var list1:ArrayVoid> = []; + private static var list2:ArrayVoid> = []; public function new(fn:Void->Void) { if (!added) { - FlxG.signals.preUpdate.add(onUpdate); added = true; + current = list1; + FlxG.signals.postUpdate.add(onUpdate); } - fns.insert(0, fn); + current.insert(0, fn); } private static function onUpdate() { - while (fns.length > 0) { - fns.pop()(); + var ref = current; + if (current == list1) { + current = list2; + } else { + current = list1; + } + while (ref.length > 0) { + ref.pop()(); } } } -*/ \ No newline at end of file From 10544fa45e19e7c4c925ea7590d1e68bf3f629b1 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Fri, 15 Dec 2023 09:49:01 +0100 Subject: [PATCH 035/120] different offsets for html5 dont seem to be needed anymore --- haxe/ui/backend/ComponentImpl.hx | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 35d2788..72b78c6 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -1,12 +1,12 @@ package haxe.ui.backend; -import flixel.FlxState; -import haxe.ui.backend.TextInputImpl.TextInputEvent; import flixel.FlxG; import flixel.FlxSprite; +import flixel.FlxState; import flixel.math.FlxRect; import flixel.text.FlxText.FlxTextBorderStyle; import haxe.ui.Toolkit; +import haxe.ui.backend.TextInputImpl.TextInputEvent; import haxe.ui.backend.flixel.FlxStyleHelper; import haxe.ui.backend.flixel.MouseHelper; import haxe.ui.backend.flixel.StateHelper; @@ -1083,26 +1083,15 @@ class ComponentImpl extends ComponentBase { } if (_textDisplay != null) { - #if html5 - var offsetX = 1 / Toolkit.scaleX; - var offsetY = 1 / Toolkit.scaleY; - #else var offsetX = 2 / Toolkit.scaleX; var offsetY = 2 / Toolkit.scaleY; - #end _textDisplay.tf.x = _surface.x + _textDisplay.left - offsetX; _textDisplay.tf.y = _surface.y + _textDisplay.top - offsetY; } if (_textInput != null) { - #if html5 - var offsetX = 1 / Toolkit.scaleX; - var offsetY = 1 / Toolkit.scaleY; - #else var offsetX = 2 / Toolkit.scaleX; var offsetY = 2 / Toolkit.scaleY; - #end - _textInput.x = (_surface.x + _textInput.left - offsetX) * FlxG.scaleMode.scale.x; _textInput.y = (_surface.y + _textInput.top - offsetY) * FlxG.scaleMode.scale.y; _textInput.scaleX = FlxG.scaleMode.scale.x; From e700d85777538b0620b85b7676936054d5c07f8d Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Fri, 15 Dec 2023 10:30:56 +0100 Subject: [PATCH 036/120] small tweaks --- haxe/ui/backend/CallLaterImpl.hx | 2 +- haxe/ui/backend/ComponentImpl.hx | 16 ++++------------ .../backend/flixel/components/SparrowPlayer.hx | 15 ++++++--------- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/haxe/ui/backend/CallLaterImpl.hx b/haxe/ui/backend/CallLaterImpl.hx index fbe8a20..06e694d 100644 --- a/haxe/ui/backend/CallLaterImpl.hx +++ b/haxe/ui/backend/CallLaterImpl.hx @@ -14,7 +14,7 @@ class CallLaterImpl { if (!added) { added = true; current = list1; - FlxG.signals.postUpdate.add(onUpdate); + FlxG.signals.preUpdate.add(onUpdate); } current.insert(0, fn); } diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 72b78c6..fef411a 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -261,18 +261,10 @@ class ComponentImpl extends ComponentBase { return child; } - // TODO: really need revision on if this is still needed, or what purpose it was originally supposed - // to serve, maybe its no longer needed in flixel 5.0? - private var _overrideSkipTransformChildren:Bool = true; private function superVisible(value:Bool) { - if (_overrideSkipTransformChildren) { - _skipTransformChildren = true; - } + _skipTransformChildren = true; super.set_visible(value); _skipTransformChildren = false; - if (_overrideSkipTransformChildren) { - _skipTransformChildren = false; - } } private override function handleAddComponentAt(child:Component, index:Int):Component { @@ -1185,7 +1177,7 @@ class ComponentImpl extends ComponentBase { // Flixel overrides //*********************************************************************************************************** - private var _updates:Int = 0; + private var _updates:Float = 0; public override function update(elapsed:Float) { if (_destroyed) { super.update(elapsed); @@ -1198,11 +1190,11 @@ class ComponentImpl extends ComponentBase { } clearCaches(); - applyClipRect(); repositionChildren(); + applyClipRect(); _updates++; - if (_updates == 2) { + if (_updates == 1) { if (asComponent.hidden == false) { applyVisibility(true); } else { diff --git a/haxe/ui/backend/flixel/components/SparrowPlayer.hx b/haxe/ui/backend/flixel/components/SparrowPlayer.hx index 00c374d..451f19c 100644 --- a/haxe/ui/backend/flixel/components/SparrowPlayer.hx +++ b/haxe/ui/backend/flixel/components/SparrowPlayer.hx @@ -1,15 +1,15 @@ package haxe.ui.backend.flixel.components; -import haxe.ui.data.DataSource; -import haxe.ui.core.IDataComponent; -import haxe.ui.events.AnimationEvent; -import haxe.ui.core.Component; -import haxe.ui.geom.Size; -import haxe.ui.layouts.DefaultLayout; import flixel.FlxSprite; import flixel.graphics.frames.FlxAtlasFrames; import flixel.graphics.frames.FlxFramesCollection; import haxe.ui.containers.Box; +import haxe.ui.core.Component; +import haxe.ui.core.IDataComponent; +import haxe.ui.data.DataSource; +import haxe.ui.events.AnimationEvent; +import haxe.ui.geom.Size; +import haxe.ui.layouts.DefaultLayout; import openfl.Assets; private typedef AnimationInfo = { @@ -38,7 +38,6 @@ class SparrowPlayer extends Box implements IDataComponent { public function new() { super(); - _overrideSkipTransformChildren = false; sprite = new FlxSprite(1, 1); add(sprite); } @@ -138,8 +137,6 @@ class SparrowPlayer extends Box implements IDataComponent { _redispatchStart = false; dispatch(new AnimationEvent(AnimationEvent.START)); } - - parentComponent._overrideSkipTransformChildren = false; } private var _cachedAnimationPrefixes:Array = []; // component might not have an animation yet, so we'll cache it if thats the case From 7144193b2e0bc184904e750ee87ff2a0fa9cdf36 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Fri, 15 Dec 2023 10:46:33 +0100 Subject: [PATCH 037/120] apply clip rect first --- haxe/ui/backend/ComponentImpl.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index fef411a..fd485ed 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -1190,8 +1190,8 @@ class ComponentImpl extends ComponentBase { } clearCaches(); - repositionChildren(); applyClipRect(); + repositionChildren(); _updates++; if (_updates == 1) { From b8ef3b5a3e8e8ed11448f7d76c559311fb078594 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Sun, 17 Dec 2023 09:26:00 +0100 Subject: [PATCH 038/120] better mouse handling --- haxe/ui/backend/ComponentImpl.hx | 205 +++++++++++-------------------- 1 file changed, 69 insertions(+), 136 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index fd485ed..860f35c 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -744,46 +744,23 @@ class ComponentImpl extends ComponentBase { private var _mouseOverFlag:Bool = false; private var _cursorSet:Bool = false; private function __onMouseMove(event:MouseEvent) { + if (Platform.instance.isMobile) { + return; + } + var x = event.screenX; var y = event.screenY; lastMouseX = x; lastMouseY = y; - var hasMember = (this.state == StateHelper.currentState); + var inCurrentState = (this.state == StateHelper.currentState); - if (Platform.instance.isMobile == false) { + if (inCurrentState == false) { if (_mouseOverFlag == true) { - if (hasMember == false) { - _mouseOverFlag = false; - var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_OUT); - if (fn != null) { - var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OUT); - mouseEvent.screenX = x / Toolkit.scaleX; - mouseEvent.screenY = y / Toolkit.scaleY; - #if mobile - mouseEvent.touchEvent = true; - #end - fn(mouseEvent); - event.canceled = mouseEvent.canceled; - } - return; - } - } - - if (hasMember == false) { - return; - } - - var i = inBounds(x, y); - if (i == true) { - if (this.style != null && this.style.cursor != null) { - Screen.instance.setCursor(this.style.cursor, this.style.cursorOffsetX, this.style.cursorOffsetY); - _cursorSet = true; - } - - var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_MOVE); + _mouseOverFlag = false; + var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_OUT); if (fn != null) { - var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_MOVE); + var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OUT); mouseEvent.screenX = x / Toolkit.scaleX; mouseEvent.screenY = y / Toolkit.scaleY; #if mobile @@ -793,45 +770,53 @@ class ComponentImpl extends ComponentBase { event.canceled = mouseEvent.canceled; } } - - if (i == true && _mouseOverFlag == false) { - if (isEventRelevant(getComponentsAtPoint(x, y, true), MouseEvent.MOUSE_OVER)) { - if (this.style != null && this.style.cursor != null) { - Screen.instance.setCursor(this.style.cursor, this.style.cursorOffsetX, this.style.cursorOffsetY); - _cursorSet = true; - } - - _mouseOverFlag = true; - var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_OVER); - if (fn != null) { - var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OVER); - mouseEvent.screenX = x / Toolkit.scaleX; - mouseEvent.screenY = y / Toolkit.scaleY; - #if mobile - mouseEvent.touchEvent = true; - #end - fn(mouseEvent); - event.canceled = mouseEvent.canceled; - } - } - } else if (i == false && _mouseOverFlag == true) { - if (_cursorSet) { - Screen.instance.setCursor("default"); - _cursorSet = false; - } + return; + } - _mouseOverFlag = false; + var i = inBounds(x, y); + if (i == true) { + if (hasComponentOver(cast this, x, y) == true) { var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_OUT); if (fn != null) { var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OUT); mouseEvent.screenX = x / Toolkit.scaleX; mouseEvent.screenY = y / Toolkit.scaleY; - #if mobile - mouseEvent.touchEvent = true; - #end fn(mouseEvent); - event.canceled = mouseEvent.canceled; } + return; + } + if (this.style != null && this.style.cursor != null) { + Screen.instance.setCursor(this.style.cursor, this.style.cursorOffsetX, this.style.cursorOffsetY); + } + var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_MOVE); + if (fn != null) { + var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_MOVE); + mouseEvent.screenX = x / Toolkit.scaleX; + mouseEvent.screenY = y / Toolkit.scaleY; + fn(mouseEvent); + } + } + if (i == true && _mouseOverFlag == false) { + if (hasComponentOver(cast this, x, y) == true) { + return; + } + _mouseOverFlag = true; + var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_OVER); + if (fn != null) { + var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OVER); + mouseEvent.screenX = x / Toolkit.scaleX; + mouseEvent.screenY = y / Toolkit.scaleY; + fn(mouseEvent); + } + } else if (i == false && _mouseOverFlag == true) { + _mouseOverFlag = false; + Screen.instance.setCursor("default"); + var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_OUT); + if (fn != null) { + var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OUT); + mouseEvent.screenX = x / Toolkit.scaleX; + mouseEvent.screenY = y / Toolkit.scaleY; + fn(mouseEvent); } } } @@ -839,12 +824,6 @@ class ComponentImpl extends ComponentBase { private var _mouseDownFlag:Bool = false; private var _mouseDownButton:Int = -1; private function __onMouseDown(event:MouseEvent) { - if (Platform.instance.isMobile == false) { - if (_mouseOverFlag == false) { - return; - } - } - if (this.state != StateHelper.currentState) { return; } @@ -852,59 +831,45 @@ class ComponentImpl extends ComponentBase { var button:Int = event.data; var x = event.screenX; var y = event.screenY; + lastMouseX = x; lastMouseY = y; var i = inBounds(x, y); if (i == true && _mouseDownFlag == false) { - /* if (hasComponentOver(cast this, x, y) == true) { return; } - */ - if (isEventRelevant(getComponentsAtPoint(x, y, true), MouseEvent.MOUSE_DOWN)) { - _mouseDownFlag = true; - _mouseDownButton = button; - var type = button == 0 ? haxe.ui.events.MouseEvent.MOUSE_DOWN: haxe.ui.events.MouseEvent.RIGHT_MOUSE_DOWN; - var fn:UIEvent->Void = _eventMap.get(type); - if (fn != null) { - var mouseEvent = new haxe.ui.events.MouseEvent(type); - mouseEvent.screenX = x / Toolkit.scaleX; - mouseEvent.screenY = y / Toolkit.scaleY; - if (Platform.instance.isMobile) { - mouseEvent.touchEvent = true; - } - fn(mouseEvent); - event.canceled = mouseEvent.canceled; - } + _mouseDownFlag = true; + + var type = button == 0 ? haxe.ui.events.MouseEvent.MOUSE_DOWN: haxe.ui.events.MouseEvent.RIGHT_MOUSE_DOWN; + var fn:UIEvent->Void = _eventMap.get(type); + if (fn != null) { + var mouseEvent = new haxe.ui.events.MouseEvent(type); + mouseEvent.screenX = x / Toolkit.scaleX; + mouseEvent.screenY = y / Toolkit.scaleY; + fn(mouseEvent); } } } private function __onMouseUp(event:MouseEvent) { - if (Platform.instance.isMobile == false) { - if (_mouseOverFlag == false) { - //return; - } - } - if (this.state != StateHelper.currentState) { return; } - - var button:Int = _mouseDownButton; + + var button:Int = event.data; var x = event.screenX; var y = event.screenY; - + lastMouseX = x; lastMouseY = y; + var i = inBounds(x, y); if (i == true) { - /* if (hasComponentOver(cast this, x, y) == true) { return; } - */ - + if (_mouseDownFlag == true) { var type = button == 0 ? haxe.ui.events.MouseEvent.CLICK: haxe.ui.events.MouseEvent.RIGHT_CLICK; var fn:UIEvent->Void = _eventMap.get(type); @@ -912,13 +877,9 @@ class ComponentImpl extends ComponentBase { var mouseEvent = new haxe.ui.events.MouseEvent(type); mouseEvent.screenX = x / Toolkit.scaleX; mouseEvent.screenY = y / Toolkit.scaleY; - if (Platform.instance.isMobile) { - mouseEvent.touchEvent = true; - } fn(mouseEvent); - event.canceled = mouseEvent.canceled; } - + if (type == haxe.ui.events.MouseEvent.CLICK) { _lastClickTimeDiff = Timer.stamp() - _lastClickTime; _lastClickTime = Timer.stamp(); @@ -936,14 +897,10 @@ class ComponentImpl extends ComponentBase { var mouseEvent = new haxe.ui.events.MouseEvent(type); mouseEvent.screenX = x / Toolkit.scaleX; mouseEvent.screenY = y / Toolkit.scaleY; - if (Platform.instance.isMobile) { - mouseEvent.touchEvent = true; - } fn(mouseEvent); - event.canceled = mouseEvent.canceled; } } - _mouseDownFlag = false; + _mouseDownFlag = false; } #if haxeui_dont_impose_base_class @@ -952,24 +909,18 @@ class ComponentImpl extends ComponentBase { #end private function __onDoubleClick(event:MouseEvent) { - if (this.state != StateHelper.currentState) { - return; - } - - var button:Int = _mouseDownButton; + var button:Int = event.data; var x = event.screenX; var y = event.screenY; - + lastMouseX = x; lastMouseY = y; var i = inBounds(x, y); if (i == true && button == 0) { - /* if (hasComponentOver(cast this, x, y) == true) { return; } - */ - + _mouseDownFlag = false; var mouseDelta:Float = MathUtil.distance(x, y, _lastClickX, _lastClickY); if (_lastClickTimeDiff < 0.5 && mouseDelta < 5) { // 0.5 seconds @@ -979,11 +930,7 @@ class ComponentImpl extends ComponentBase { var mouseEvent = new haxe.ui.events.MouseEvent(type); mouseEvent.screenX = x / Toolkit.scaleX; mouseEvent.screenY = y / Toolkit.scaleY; - if (Platform.instance.isMobile) { - mouseEvent.touchEvent = true; - } fn(mouseEvent); - event.canceled = mouseEvent.canceled; } } } @@ -1017,20 +964,6 @@ class ComponentImpl extends ComponentBase { event.canceled = mouseEvent.canceled; } - private function isEventRelevant(children:Array, eventType:String):Bool { - var relevant = false; - for (c in children) { - if (c == this) { - relevant = true; - } - if (c.parentComponent == null) { - break; - } - } - - return relevant; - } - //*********************************************************************************************************** // Text related //*********************************************************************************************************** @@ -1194,7 +1127,7 @@ class ComponentImpl extends ComponentBase { repositionChildren(); _updates++; - if (_updates == 1) { + if (_updates == 2) { if (asComponent.hidden == false) { applyVisibility(true); } else { From 8209c4d25029da56c88a1bd9412cd637801d4100 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 19 Dec 2023 08:49:36 +0100 Subject: [PATCH 039/120] .state ref should only be nulled if component is being disposed --- haxe/ui/backend/ScreenImpl.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index f9fe7d6..9cdc515 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -213,6 +213,7 @@ class ScreenImpl extends ScreenBase { throw "component wasnt actually removed from array, or there is a duplicate in the array"; } if (dispose) { + component.state = null; component.destroyInternal(); component.destroy(); component.destroyComponent(); @@ -222,7 +223,6 @@ class ScreenImpl extends ScreenBase { if (StateHelper.currentState.exists == true) { StateHelper.currentState.remove(component, true); } - component.state = null; checkResetCursor(); onContainerResize(); return component; From 9a1abf4b450118e5222d7456024db31cc3b9f8d1 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 19 Dec 2023 09:13:17 +0100 Subject: [PATCH 040/120] dont check for overlapping components if component is already "down" --- haxe/ui/backend/ComponentImpl.hx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 860f35c..9232a4b 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -866,10 +866,11 @@ class ComponentImpl extends ComponentBase { var i = inBounds(x, y); if (i == true) { + /* if (hasComponentOver(cast this, x, y) == true) { return; } - + */ if (_mouseDownFlag == true) { var type = button == 0 ? haxe.ui.events.MouseEvent.CLICK: haxe.ui.events.MouseEvent.RIGHT_CLICK; var fn:UIEvent->Void = _eventMap.get(type); From d70232e7486104589b66977c776e5a55ef851a57 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 21 Dec 2023 11:19:01 +0100 Subject: [PATCH 041/120] dont reset button down on stage down (use event prop directly) --- haxe/ui/backend/ComponentImpl.hx | 1 - haxe/ui/backend/flixel/MouseHelper.hx | 69 ++++++--------------------- 2 files changed, 15 insertions(+), 55 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 9232a4b..c6f93a7 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -590,7 +590,6 @@ class ComponentImpl extends ComponentBase { if (hasTextInput()) { getTextInput().onMouseDown = null; } - case MouseEvent.MOUSE_UP: _eventMap.remove(type); diff --git a/haxe/ui/backend/flixel/MouseHelper.hx b/haxe/ui/backend/flixel/MouseHelper.hx index ea5e50e..bea313b 100644 --- a/haxe/ui/backend/flixel/MouseHelper.hx +++ b/haxe/ui/backend/flixel/MouseHelper.hx @@ -25,19 +25,12 @@ class MouseHelper { if (_hasOnMouseDown == false) { FlxG.stage.addEventListener(openfl.events.MouseEvent.MOUSE_DOWN, onMouseDown); FlxG.stage.addEventListener(openfl.events.MouseEvent.RIGHT_MOUSE_DOWN, onMouseDown); - - - FlxG.stage.addEventListener(openfl.events.MouseEvent.MOUSE_DOWN, onStageDown); - FlxG.stage.addEventListener(openfl.events.MouseEvent.RIGHT_MOUSE_DOWN, onStageRightDown); _hasOnMouseDown = true; } case MouseEvent.MOUSE_UP: if (_hasOnMouseUp == false) { FlxG.stage.addEventListener(openfl.events.MouseEvent.MOUSE_UP, onMouseUp); FlxG.stage.addEventListener(openfl.events.MouseEvent.RIGHT_MOUSE_UP, onMouseUp); - - FlxG.stage.addEventListener(openfl.events.MouseEvent.MOUSE_UP, onStageUp); - FlxG.stage.addEventListener(openfl.events.MouseEvent.RIGHT_MOUSE_UP, onStageRightUp); _hasOnMouseUp = true; FlxG.signals.preStateSwitch.add(onPreStateSwitched); } @@ -64,7 +57,7 @@ class MouseHelper { fn: callback, priority: priority }); - + list.sort(function(a, b) { return a.priority - b.priority; }); @@ -83,18 +76,12 @@ class MouseHelper { if (_hasOnMouseDown == true) { FlxG.stage.removeEventListener(openfl.events.MouseEvent.MOUSE_DOWN, onMouseDown); FlxG.stage.removeEventListener(openfl.events.MouseEvent.RIGHT_MOUSE_DOWN, onMouseDown); - - FlxG.stage.removeEventListener(openfl.events.MouseEvent.MOUSE_DOWN, onStageDown); - FlxG.stage.removeEventListener(openfl.events.MouseEvent.RIGHT_MOUSE_DOWN, onStageRightDown); _hasOnMouseDown = false; } case MouseEvent.MOUSE_UP: if (_hasOnMouseUp == true) { FlxG.stage.removeEventListener(openfl.events.MouseEvent.MOUSE_UP, onMouseUp); FlxG.stage.removeEventListener(openfl.events.MouseEvent.RIGHT_MOUSE_UP, onMouseUp); - - FlxG.stage.removeEventListener(openfl.events.MouseEvent.MOUSE_UP, onStageUp); - FlxG.stage.removeEventListener(openfl.events.MouseEvent.RIGHT_MOUSE_UP, onStageRightUp); _hasOnMouseUp = false; FlxG.signals.preStateSwitch.remove(onPreStateSwitched); } @@ -139,7 +126,13 @@ class MouseHelper { event.screenX = (currentMouseX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom()); event.screenY = (currentMouseY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); } - event.data = buttonPressed; + + #if FLX_NO_MOUSE + event.data = -1; + #else + event.data = (e.buttonDown ? 0 : 1); + #end + for (l in list) { l.fn(event); if (event.canceled == true) { @@ -169,7 +162,13 @@ class MouseHelper { event.screenX = (currentMouseX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom()); event.screenY = (currentMouseY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); } - event.data = buttonPressed; + + #if FLX_NO_MOUSE + event.data = -1; + #else + event.data = (e.buttonDown ? 0 : 1); + #end + for (l in list) { l.fn(event); if (event.canceled == true) { @@ -225,44 +224,6 @@ class MouseHelper { } } - private static function onStageDown(_) { - _buttonPressed = 0; - } - - private static function onStageUp(_) { - _buttonPressed = -1; - } - - private static function onStageRightDown(_) { - _buttonPressed = 1; - } - - private static function onStageRightUp(_) { - _buttonPressed = -1; - } - - private static var _buttonPressed:Int = -1; - private static var buttonPressed(get, null):Int; - private static function get_buttonPressed():Int { - var n = _buttonPressed; - - #if FLX_NO_MOUSE - - n = 0; - - #else - - if (FlxG.mouse.pressed == true) { - n = 0; - } else if (FlxG.mouse.pressedRight == true) { - n = 1; - } - - #end - - return n; - } - private static inline function initialZoom():Float { #if (flixel <= "4.11.0") // FlxG.initialZoom removed in later versions of flixel From 69dc988dd7f4cf99f7d9bfa53fdb1c5113a4e936 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 21 Dec 2023 13:08:45 +0100 Subject: [PATCH 042/120] simulate mouse events when states switch to mop up any visual styles --- haxe/ui/backend/flixel/MouseHelper.hx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/haxe/ui/backend/flixel/MouseHelper.hx b/haxe/ui/backend/flixel/MouseHelper.hx index bea313b..05c9173 100644 --- a/haxe/ui/backend/flixel/MouseHelper.hx +++ b/haxe/ui/backend/flixel/MouseHelper.hx @@ -101,8 +101,18 @@ class MouseHelper { } private static function onPreStateSwitched() { - onMouseUp(null); - onMouseMove(null); + // simulate mouse events when states switch to mop up any visual styles + var e = new openfl.events.MouseEvent(openfl.events.MouseEvent.MOUSE_DOWN); + e.stageX = currentMouseX; + e.stageY = currentMouseY; + e.buttonDown = false; + onMouseUp(e); + + var e = new openfl.events.MouseEvent(openfl.events.MouseEvent.MOUSE_MOVE); + e.stageX = currentMouseX; + e.stageY = currentMouseY; + e.buttonDown = false; + onMouseMove(e); } private static function onMouseDown(e:openfl.events.MouseEvent) { From 583c26e0be58da1dfc9ee17480561ffa7d36a5ce Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 21 Dec 2023 13:25:24 +0100 Subject: [PATCH 043/120] dont apply scale to flx-text-input when positioning --- haxe/ui/backend/ComponentImpl.hx | 4 ++-- haxe/ui/backend/flixel/textinputs/FlxTextInput.hx | 4 ++-- haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index c6f93a7..9235cc1 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -1017,8 +1017,8 @@ class ComponentImpl extends ComponentBase { if (_textInput != null) { var offsetX = 2 / Toolkit.scaleX; var offsetY = 2 / Toolkit.scaleY; - _textInput.x = (_surface.x + _textInput.left - offsetX) * FlxG.scaleMode.scale.x; - _textInput.y = (_surface.y + _textInput.top - offsetY) * FlxG.scaleMode.scale.y; + _textInput.x = (_surface.x + _textInput.left - offsetX); + _textInput.y = (_surface.y + _textInput.top - offsetY); _textInput.scaleX = FlxG.scaleMode.scale.x; _textInput.scaleY = FlxG.scaleMode.scale.y; _textInput.update(); diff --git a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx index e552882..2af8d65 100644 --- a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx @@ -67,7 +67,7 @@ class FlxTextInput extends TextBase { return tf.scale.x; } private function set_scaleX(value:Float):Float { - tf.scale.x = value; + // do nothing return value; } @@ -76,7 +76,7 @@ class FlxTextInput extends TextBase { return tf.scale.y; } private function set_scaleY(value:Float):Float { - tf.scale.y = value; + // do nothing return value; } diff --git a/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx b/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx index db55676..6f40b09 100644 --- a/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx @@ -1,8 +1,9 @@ package haxe.ui.backend.flixel.textinputs; -import flixel.FlxSprite; import flixel.FlxG; +import flixel.FlxSprite; import haxe.ui.Toolkit; +import haxe.ui.backend.TextInputImpl.TextInputEvent; import haxe.ui.core.Component; import haxe.ui.core.Screen; import haxe.ui.events.UIEvent; @@ -12,7 +13,6 @@ import openfl.text.TextField; import openfl.text.TextFieldAutoSize; import openfl.text.TextFieldType; import openfl.text.TextFormat; -import haxe.ui.backend.TextInputImpl.TextInputEvent; class OpenFLTextInput extends TextBase { public static var USE_ON_ADDED:Bool = true; @@ -66,7 +66,7 @@ class OpenFLTextInput extends TextBase { return tf.x; } private function set_x(value:Float):Float { - tf.x = value; + tf.x = value * FlxG.scaleMode.scale.x; return value; } @@ -75,7 +75,7 @@ class OpenFLTextInput extends TextBase { return tf.y; } private function set_y(value:Float):Float { - tf.y = value; + tf.y = value * FlxG.scaleMode.scale.y; return value; } From 1bc0401b9e705619b65b65c1f35bb9b661988079 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Sat, 23 Dec 2023 11:05:50 +0100 Subject: [PATCH 044/120] handle mouse buttons better / properly --- haxe/ui/backend/flixel/MouseHelper.hx | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/haxe/ui/backend/flixel/MouseHelper.hx b/haxe/ui/backend/flixel/MouseHelper.hx index 05c9173..6edbacf 100644 --- a/haxe/ui/backend/flixel/MouseHelper.hx +++ b/haxe/ui/backend/flixel/MouseHelper.hx @@ -137,11 +137,12 @@ class MouseHelper { event.screenY = (currentMouseY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); } - #if FLX_NO_MOUSE - event.data = -1; - #else - event.data = (e.buttonDown ? 0 : 1); - #end + event.data = -1; + if (e.type == openfl.events.MouseEvent.MOUSE_DOWN) { + event.data = 0; + } else if (e.type == openfl.events.MouseEvent.RIGHT_MOUSE_DOWN) { + event.data = 1; + } for (l in list) { l.fn(event); @@ -173,11 +174,12 @@ class MouseHelper { event.screenY = (currentMouseY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); } - #if FLX_NO_MOUSE - event.data = -1; - #else - event.data = (e.buttonDown ? 0 : 1); - #end + event.data = -1; + if (e.type == openfl.events.MouseEvent.MOUSE_UP) { + event.data = 0; + } else if (e.type == openfl.events.MouseEvent.RIGHT_MOUSE_UP) { + event.data = 1; + } for (l in list) { l.fn(event); From a81c55e806e4a4d2e115097d4ead7e5836dd6425 Mon Sep 17 00:00:00 2001 From: Sword352 <99792114+Sword352@users.noreply.github.com> Date: Sat, 23 Dec 2023 14:45:43 +0100 Subject: [PATCH 045/120] Add a `mouseLoadFunction` callback --- haxe/ui/backend/flixel/CursorHelper.hx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/haxe/ui/backend/flixel/CursorHelper.hx b/haxe/ui/backend/flixel/CursorHelper.hx index c98a026..f1a5c35 100644 --- a/haxe/ui/backend/flixel/CursorHelper.hx +++ b/haxe/ui/backend/flixel/CursorHelper.hx @@ -4,6 +4,14 @@ class CursorHelper { public static var useCustomCursors:Bool = true; public static var registeredCursors:Map = new Map(); + public static var mouseLoadFunction(default, set):String->BitmapData = (bmd) -> openfl.Assets.getBitmapData(bmd); + static function set_mouseLoadFunction(v:String->BitmapData):String->BitmapData { + if (v == null) + return mouseLoadFunction; + + return mouseLoadFunction = v; + } + public static function registerCursor(name:String, graphic:String, scale:Float = 1, offsetX:Int = 0, offsetY:Int = 0) { registeredCursors.set(name, { name: name, @@ -46,4 +54,4 @@ private typedef CursorInfo = { var scale:Float; var offsetX:Int; var offsetY:Int; -} \ No newline at end of file +} From e62c73594edabd77d006bf191d56ca00c80a4049 Mon Sep 17 00:00:00 2001 From: Sword352 <99792114+Sword352@users.noreply.github.com> Date: Sat, 23 Dec 2023 14:48:56 +0100 Subject: [PATCH 046/120] Smarter way to load mouse graphics --- haxe/ui/backend/ScreenImpl.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 9cdc515..226d2cc 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -175,9 +175,9 @@ class ScreenImpl extends ScreenBase { _cursor = cursor; if (CursorHelper.hasCursor(_cursor)) { var cursorInfo = CursorHelper.registeredCursors.get(_cursor); - FlxG.mouse.load(new FlxSprite().loadGraphic(cursorInfo.graphic).pixels, cursorInfo.scale, cursorInfo.offsetX, cursorInfo.offsetY); + FlxG.mouse.load(CursorHelper.mouseLoadFunction(cursorInfo.graphic), cursorInfo.scale, cursorInfo.offsetX, cursorInfo.offsetY); } else if (openfl.Assets.exists(_cursor)) { - FlxG.mouse.load(new FlxSprite().loadGraphic(_cursor).pixels, 1, offsetX, offsetY); + FlxG.mouse.load(CursorHelper.mouseLoadFunction(_cursor), 1, offsetX, offsetY); } else { FlxG.mouse.load(null); } From cb504c6e214fcdaff39f269aab53bc5b7d6dcb7a Mon Sep 17 00:00:00 2001 From: Sword352 <99792114+Sword352@users.noreply.github.com> Date: Sat, 23 Dec 2023 14:59:56 +0100 Subject: [PATCH 047/120] Update CursorHelper.hx --- haxe/ui/backend/flixel/CursorHelper.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/haxe/ui/backend/flixel/CursorHelper.hx b/haxe/ui/backend/flixel/CursorHelper.hx index f1a5c35..177dc10 100644 --- a/haxe/ui/backend/flixel/CursorHelper.hx +++ b/haxe/ui/backend/flixel/CursorHelper.hx @@ -1,5 +1,7 @@ package haxe.ui.backend.flixel; +import openfl.display.BitmapData; + class CursorHelper { public static var useCustomCursors:Bool = true; public static var registeredCursors:Map = new Map(); From 210a6a27d5ec9698b5fbfa501094382b16d4853d Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sat, 23 Dec 2023 21:29:11 -0400 Subject: [PATCH 048/120] Implement keyboard events for components --- haxe/ui/backend/ComponentImpl.hx | 76 +++++++++++ haxe/ui/backend/ScreenImpl.hx | 32 ++--- haxe/ui/backend/flixel/KeyboardHelper.hx | 125 ++++++++++++++++++ haxe/ui/backend/flixel/MouseHelper.hx | 12 +- .../backend/flixel/textinputs/FlxTextInput.hx | 37 ++++++ .../flixel/textinputs/OpenFLTextInput.hx | 37 ++++++ 6 files changed, 294 insertions(+), 25 deletions(-) create mode 100644 haxe/ui/backend/flixel/KeyboardHelper.hx diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 9235cc1..3751bae 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -8,6 +8,7 @@ import flixel.text.FlxText.FlxTextBorderStyle; import haxe.ui.Toolkit; import haxe.ui.backend.TextInputImpl.TextInputEvent; import haxe.ui.backend.flixel.FlxStyleHelper; +import haxe.ui.backend.flixel.KeyboardHelper; import haxe.ui.backend.flixel.MouseHelper; import haxe.ui.backend.flixel.StateHelper; import haxe.ui.core.Component; @@ -16,6 +17,7 @@ import haxe.ui.core.Platform; import haxe.ui.core.Screen; import haxe.ui.core.TextDisplay; import haxe.ui.core.TextInput; +import haxe.ui.events.KeyboardEvent; import haxe.ui.events.MouseEvent; import haxe.ui.events.UIEvent; import haxe.ui.filters.DropShadow; @@ -557,6 +559,24 @@ class ComponentImpl extends ComponentBase { notifyMouseMove(true); _eventMap.set(MouseEvent.RIGHT_CLICK, listener); } + + case KeyboardEvent.KEY_DOWN: + if (_eventMap.exists(KeyboardEvent.KEY_DOWN) == false) { + KeyboardHelper.notify(KeyboardEvent.KEY_DOWN, __onKeyboardEvent); + _eventMap.set(KeyboardEvent.KEY_DOWN, listener); + if (hasTextInput()) { + getTextInput().onKeyDown = __onTextInputKeyboardEvent; + } + } + + case KeyboardEvent.KEY_UP: + if (_eventMap.exists(KeyboardEvent.KEY_UP) == false) { + KeyboardHelper.notify(KeyboardEvent.KEY_UP, __onKeyboardEvent); + _eventMap.set(KeyboardEvent.KEY_UP, listener); + if (hasTextInput()) { + getTextInput().onKeyUp = __onTextInputKeyboardEvent; + } + } case UIEvent.CHANGE: if (_eventMap.exists(UIEvent.CHANGE) == false) { @@ -637,6 +657,20 @@ class ComponentImpl extends ComponentBase { notifyMouseDown(false); notifyMouseUp(false); notifyMouseMove(false); + + case KeyboardEvent.KEY_DOWN: + _eventMap.remove(type); + KeyboardHelper.remove(KeyboardEvent.KEY_DOWN, __onKeyboardEvent); + if (hasTextInput()) { + getTextInput().onKeyDown = null; + } + + case KeyboardEvent.KEY_UP: + _eventMap.remove(type); + KeyboardHelper.remove(KeyboardEvent.KEY_UP, __onKeyboardEvent); + if (hasTextInput()) { + getTextInput().onKeyUp = null; + } case UIEvent.CHANGE: _eventMap.remove(type); @@ -963,6 +997,48 @@ class ComponentImpl extends ComponentBase { fn(mouseEvent); event.canceled = mouseEvent.canceled; } + + private function __onKeyboardEvent(event:KeyboardEvent) { + if (this.state != StateHelper.currentState) { + return; + } + + var fn = _eventMap.get(event.type); + if (fn == null) { + return; + } + + var keyboardEvent = new KeyboardEvent(event.type); + keyboardEvent.keyCode = event.keyCode; + keyboardEvent.altKey = event.altKey; + keyboardEvent.ctrlKey = event.ctrlKey; + keyboardEvent.shiftKey = event.shiftKey; + fn(keyboardEvent); + event.canceled = keyboardEvent.canceled; + } + + private function __onTextInputKeyboardEvent(event:openfl.events.KeyboardEvent) { + var type = switch (event.type) { + case openfl.events.KeyboardEvent.KEY_DOWN: + KeyboardEvent.KEY_DOWN; + case openfl.events.KeyboardEvent.KEY_UP: + KeyboardEvent.KEY_UP; + default: + null; + } + + var fn = _eventMap.get(type); + if (fn == null) { + return; + } + + var keyboardEvent = new KeyboardEvent(type); + keyboardEvent.keyCode = event.keyCode; + keyboardEvent.altKey = event.altKey; + keyboardEvent.ctrlKey = event.ctrlKey; + keyboardEvent.shiftKey = event.shiftKey; + fn(keyboardEvent); + } //*********************************************************************************************************** // Text related diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 226d2cc..392569f 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -7,6 +7,7 @@ import flixel.group.FlxGroup.FlxTypedGroup; import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup; import haxe.ui.Toolkit; import haxe.ui.backend.flixel.CursorHelper; +import haxe.ui.backend.flixel.KeyboardHelper; import haxe.ui.backend.flixel.MouseHelper; import haxe.ui.backend.flixel.StateHelper; import haxe.ui.core.Component; @@ -301,13 +302,13 @@ class ScreenImpl extends ScreenBase { case KeyboardEvent.KEY_DOWN: if (_mapping.exists(type) == false) { _mapping.set(type, listener); - FlxG.stage.addEventListener(openfl.events.KeyboardEvent.KEY_DOWN, __onKeyEvent); + KeyboardHelper.notify(KeyboardEvent.KEY_DOWN, __onKeyEvent, 10); } case KeyboardEvent.KEY_UP: if (_mapping.exists(type) == false) { _mapping.set(type, listener); - FlxG.stage.addEventListener(openfl.events.KeyboardEvent.KEY_UP, __onKeyEvent); + KeyboardHelper.notify(KeyboardEvent.KEY_UP, __onKeyEvent, 10); } } } @@ -372,23 +373,16 @@ class ScreenImpl extends ScreenBase { } } - private function __onKeyEvent(event:openfl.events.KeyboardEvent) { - var type:String = null; - if (event.type == openfl.events.KeyboardEvent.KEY_DOWN) { - type = KeyboardEvent.KEY_DOWN; - } else if (event.type == openfl.events.KeyboardEvent.KEY_UP) { - type = KeyboardEvent.KEY_UP; - } - - if (type != null) { - var fn = _mapping.get(type); - if (fn != null) { - var keyboardEvent = new KeyboardEvent(type); - keyboardEvent.keyCode = event.keyCode; - keyboardEvent.ctrlKey = event.ctrlKey; - keyboardEvent.shiftKey = event.shiftKey; - fn(keyboardEvent); - } + private function __onKeyEvent(event:KeyboardEvent) { + var fn = _mapping.get(event.type); + if (fn != null) { + var keyboardEvent = new KeyboardEvent(event.type); + keyboardEvent.keyCode = event.keyCode; + keyboardEvent.altKey = event.altKey; + keyboardEvent.ctrlKey = event.ctrlKey; + keyboardEvent.shiftKey = event.shiftKey; + fn(keyboardEvent); + event.canceled = keyboardEvent.canceled; } } diff --git a/haxe/ui/backend/flixel/KeyboardHelper.hx b/haxe/ui/backend/flixel/KeyboardHelper.hx new file mode 100644 index 0000000..8047bcc --- /dev/null +++ b/haxe/ui/backend/flixel/KeyboardHelper.hx @@ -0,0 +1,125 @@ +package haxe.ui.backend.flixel; + +import flixel.FlxG; +import haxe.ui.events.KeyboardEvent; + +typedef KeyboardCallback = { + var fn:KeyboardEvent->Void; + var priority:Int; +} + +class KeyboardHelper { + private static var _hasOnKeyDown:Bool = false; + private static var _hasOnKeyUp:Bool = false; + + private static var _callbacks:Map> = new Map>(); + + public static function notify(event:String, callback:KeyboardEvent->Void, priority:Int = 5) { + switch (event) { + case KeyboardEvent.KEY_DOWN: + if (_hasOnKeyDown == false) { + FlxG.stage.addEventListener(openfl.events.KeyboardEvent.KEY_DOWN, onKeyDown); + _hasOnKeyDown = true; + } + case KeyboardEvent.KEY_UP: + if (_hasOnKeyUp == false) { + FlxG.stage.addEventListener(openfl.events.KeyboardEvent.KEY_UP, onKeyUp); + _hasOnKeyUp = true; + } + } + + var list = _callbacks.get(event); + if (list == null) { + list = new Array(); + _callbacks.set(event, list); + } + + if (!hasCallback(list, callback)) { + list.insert(0, { + fn: callback, + priority: priority + }); + + list.sort(function(a, b) { + return a.priority - b.priority; + }); + } + } + + public static function remove(event:String, callback:KeyboardEvent->Void) { + var list = _callbacks.get(event); + if (list != null) { + removeCallback(list, callback); + if (list.length == 0) { + _callbacks.remove(event); + + switch (event) { + case KeyboardEvent.KEY_DOWN: + if (_hasOnKeyDown == true) { + FlxG.stage.removeEventListener(openfl.events.KeyboardEvent.KEY_DOWN, onKeyDown); + _hasOnKeyDown = false; + } + case KeyboardEvent.KEY_UP: + if (_hasOnKeyUp == true) { + FlxG.stage.removeEventListener(openfl.events.KeyboardEvent.KEY_UP, onKeyUp); + _hasOnKeyUp = false; + } + } + } + } + } + + private static function onKeyDown(e:openfl.events.KeyboardEvent) { + dispatchEvent(KeyboardEvent.KEY_DOWN, e); + } + + private static function onKeyUp(e:openfl.events.KeyboardEvent) { + dispatchEvent(KeyboardEvent.KEY_UP, e); + } + + private static function dispatchEvent(type:String, e:openfl.events.KeyboardEvent) { + var list = _callbacks.get(type); + if (list == null || list.length == 0) { + return; + } + + list = list.copy(); + + var event = new KeyboardEvent(type); + event.keyCode = e.keyCode; + event.altKey = e.altKey; + event.ctrlKey = e.ctrlKey; + event.shiftKey = e.shiftKey; + + for (l in list) { + l.fn(event); + if (event.canceled == true) { + break; + } + } + } + + private static function hasCallback(list:Array, fn:KeyboardEvent->Void):Bool { + var has = false; + for (item in list) { + if (item.fn == fn) { + has = true; + break; + } + } + return has; + } + + private static function removeCallback(list:Array, fn:KeyboardEvent->Void) { + var itemToRemove:KeyboardCallback = null; + for (item in list) { + if (item.fn == fn) { + itemToRemove = item; + break; + } + } + if (itemToRemove != null) { + list.remove(itemToRemove); + } + } +} \ No newline at end of file diff --git a/haxe/ui/backend/flixel/MouseHelper.hx b/haxe/ui/backend/flixel/MouseHelper.hx index 6edbacf..b402112 100644 --- a/haxe/ui/backend/flixel/MouseHelper.hx +++ b/haxe/ui/backend/flixel/MouseHelper.hx @@ -3,7 +3,7 @@ package haxe.ui.backend.flixel; import flixel.FlxG; import haxe.ui.events.MouseEvent; -typedef Callback = { +typedef MouseCallback = { var fn:MouseEvent->Void; var priority:Int; } @@ -17,7 +17,7 @@ class MouseHelper { private static var _hasOnMouseMove:Bool = false; private static var _hasOnMouseWheel:Bool = false; - private static var _callbacks:Map> = new Map>(); + private static var _callbacks:Map> = new Map>(); public static function notify(event:String, callback:MouseEvent->Void, priority:Int = 5) { switch (event) { @@ -48,7 +48,7 @@ class MouseHelper { var list = _callbacks.get(event); if (list == null) { - list = new Array(); + list = new Array(); _callbacks.set(event, list); } @@ -248,7 +248,7 @@ class MouseHelper { #end } - private static function hasCallback(list:Array, fn:MouseEvent->Void):Bool { + private static function hasCallback(list:Array, fn:MouseEvent->Void):Bool { var has = false; for (item in list) { if (item.fn == fn) { @@ -259,8 +259,8 @@ class MouseHelper { return has; } - private static function removeCallback(list:Array, fn:MouseEvent->Void) { - var itemToRemove:Callback = null; + private static function removeCallback(list:Array, fn:MouseEvent->Void) { + var itemToRemove:MouseCallback = null; for (item in list) { if (item.fn == fn) { itemToRemove = item; diff --git a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx index 2af8d65..d5a06f8 100644 --- a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx @@ -4,6 +4,7 @@ import flixel.FlxSprite; import haxe.ui.backend.TextInputImpl.TextInputEvent; import haxe.ui.core.Component; import openfl.events.Event; +import openfl.events.KeyboardEvent; #if flixel_text_input @@ -310,6 +311,42 @@ class FlxTextInput extends TextBase { } } + private var _onKeyDown:KeyboardEvent->Void = null; + public var onKeyDown(null, set):KeyboardEvent->Void; + private function set_onKeyDown(value:KeyboardEvent->Void):KeyboardEvent->Void { + if (_onKeyDown != null) { + tf.textField.removeEventListener(KeyboardEvent.KEY_DOWN, __onTextInputKeyDown); + } + _onKeyDown = value; + if (_onKeyDown != null) { + tf.textField.addEventListener(KeyboardEvent.KEY_DOWN, __onTextInputKeyDown); + } + return value; + } + + private function __onTextInputKeyDown(e:KeyboardEvent) { + if (_onKeyDown != null) + _onKeyDown(e); + } + + private var _onKeyUp:KeyboardEvent->Void = null; + public var onKeyUp(null, set):KeyboardEvent->Void; + private function set_onKeyUp(value:KeyboardEvent->Void):KeyboardEvent->Void { + if (_onKeyUp != null) { + tf.textField.removeEventListener(KeyboardEvent.KEY_UP, __onTextInputKeyUp); + } + _onKeyUp = value; + if (_onKeyUp != null) { + tf.textField.addEventListener(KeyboardEvent.KEY_UP, __onTextInputKeyUp); + } + return value; + } + + private function __onTextInputKeyUp(e:KeyboardEvent) { + if (_onKeyUp != null) + _onKeyUp(e); + } + private function onInternalChange() { _text = tf.text; diff --git a/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx b/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx index 6f40b09..25ddfbc 100644 --- a/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx @@ -9,6 +9,7 @@ import haxe.ui.core.Screen; import haxe.ui.events.UIEvent; import haxe.ui.geom.Rectangle; import openfl.events.Event; +import openfl.events.KeyboardEvent; import openfl.text.TextField; import openfl.text.TextFieldAutoSize; import openfl.text.TextFieldType; @@ -199,6 +200,42 @@ class OpenFLTextInput extends TextBase { } } + private var _onKeyDown:KeyboardEvent->Void = null; + public var onKeyDown(null, set):KeyboardEvent->Void; + private function set_onKeyDown(value:KeyboardEvent->Void):KeyboardEvent->Void { + if (_onKeyDown != null) { + tf.removeEventListener(KeyboardEvent.KEY_DOWN, __onTextInputKeyDown); + } + _onKeyDown = value; + if (_onKeyDown != null) { + tf.addEventListener(KeyboardEvent.KEY_DOWN, __onTextInputKeyDown); + } + return value; + } + + private function __onTextInputKeyDown(e:KeyboardEvent) { + if (_onKeyDown != null) + _onKeyDown(e); + } + + private var _onKeyUp:KeyboardEvent->Void = null; + public var onKeyUp(null, set):KeyboardEvent->Void; + private function set_onKeyUp(value:KeyboardEvent->Void):KeyboardEvent->Void { + if (_onKeyUp != null) { + tf.removeEventListener(KeyboardEvent.KEY_UP, __onTextInputKeyUp); + } + _onKeyUp = value; + if (_onKeyUp != null) { + tf.addEventListener(KeyboardEvent.KEY_UP, __onTextInputKeyUp); + } + return value; + } + + private function __onTextInputKeyUp(e:KeyboardEvent) { + if (_onKeyUp != null) + _onKeyUp(e); + } + public function addToComponent(component:Component) { FlxG.addChildBelowMouse(tf, 0xffffff); } From 39d9754c02d8fcc76cb4a358db19c90b617c9473 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sun, 24 Dec 2023 17:13:51 -0400 Subject: [PATCH 049/120] Make text input uneditable if its component is disabled --- haxe/ui/backend/flixel/textinputs/FlxTextInput.hx | 2 ++ haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx index d5a06f8..b37fd5e 100644 --- a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx @@ -185,6 +185,8 @@ class FlxTextInput extends TextBase { tf.displayAsPassword = _inputData.password; } + tf.type = (parentComponent.disabled ? DYNAMIC : INPUT); + return measureTextRequired; } diff --git a/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx b/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx index 25ddfbc..45c048c 100644 --- a/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx @@ -412,6 +412,8 @@ class OpenFLTextInput extends TextBase { if (tf.displayAsPassword != _inputData.password) { tf.displayAsPassword = _inputData.password; } + + tf.type = (parentComponent.disabled ? DYNAMIC : INPUT); return measureTextRequired; } From 6ce81d5525c97bf879574c1b4f1fb95b857ff9e8 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sun, 24 Dec 2023 18:50:56 -0400 Subject: [PATCH 050/120] Set `vscrollPageStep` and `vscrollNativeWheel` for text inputs --- haxe/ui/backend/flixel/textinputs/FlxTextInput.hx | 2 ++ haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx index b37fd5e..c6f75c6 100644 --- a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx @@ -23,6 +23,8 @@ class FlxTextInput extends TextBase { tf.onChange.add(onInternalChange); tf.onScroll.add(onScroll); tf.moves = false; + _inputData.vscrollPageStep = 1; + _inputData.vscrollNativeWheel = true; } public override function focus() { diff --git a/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx b/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx index 45c048c..dad47bf 100644 --- a/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx @@ -36,6 +36,8 @@ class OpenFLTextInput extends TextBase { tf.tabEnabled = false; //tf.stage.focus = null; tf.addEventListener(Event.CHANGE, onInternalChange); + _inputData.vscrollPageStep = 1; + _inputData.vscrollNativeWheel = true; } public override function focus() { From 19d26df63789ef7c4a3b3041973eb73a560131a0 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sun, 24 Dec 2023 20:55:29 -0400 Subject: [PATCH 051/120] Fix text field values being set to `null` where it isn't accepted --- haxe/ui/backend/flixel/textinputs/FlxTextInput.hx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx index c6f75c6..0c334e9 100644 --- a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx @@ -142,8 +142,9 @@ class FlxTextInput extends TextBase { var measureTextRequired:Bool = false; if (_textStyle != null) { - if (tf.alignment != _textStyle.textAlign) { - tf.alignment = _textStyle.textAlign; + var textAlign = (_textStyle.textAlign != null ? _textStyle.textAlign : "left"); + if (tf.alignment != textAlign) { + tf.alignment = textAlign; } var fontSizeValue = Std.int(_textStyle.fontSize); @@ -162,13 +163,15 @@ class FlxTextInput extends TextBase { tf.color = _textStyle.color; } - if (tf.bold != _textStyle.fontBold) { - tf.bold = _textStyle.fontBold; + var fontBold = (_textStyle.fontBold != null ? _textStyle.fontBold : false); + if (tf.bold != fontBold) { + tf.bold = fontBold; measureTextRequired = true; } - if (tf.italic != _textStyle.fontItalic) { - tf.italic = _textStyle.fontItalic; + var fontItalic = (_textStyle.fontItalic != null ? _textStyle.fontItalic : false); + if (tf.italic != fontItalic) { + tf.italic = fontItalic; measureTextRequired = true; } } From b6c9805db1320a13921041eeed320a7afb7dc3c2 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Mon, 25 Dec 2023 09:58:34 -0400 Subject: [PATCH 052/120] Comment out keyboard event listeners for FlxTextInput as it's no longer needed --- haxe/ui/backend/flixel/textinputs/FlxTextInput.hx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx index 0c334e9..e09be35 100644 --- a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx @@ -322,37 +322,41 @@ class FlxTextInput extends TextBase { public var onKeyDown(null, set):KeyboardEvent->Void; private function set_onKeyDown(value:KeyboardEvent->Void):KeyboardEvent->Void { if (_onKeyDown != null) { - tf.textField.removeEventListener(KeyboardEvent.KEY_DOWN, __onTextInputKeyDown); + //tf.textField.removeEventListener(KeyboardEvent.KEY_DOWN, __onTextInputKeyDown); } _onKeyDown = value; if (_onKeyDown != null) { - tf.textField.addEventListener(KeyboardEvent.KEY_DOWN, __onTextInputKeyDown); + //tf.textField.addEventListener(KeyboardEvent.KEY_DOWN, __onTextInputKeyDown); } return value; } + /* private function __onTextInputKeyDown(e:KeyboardEvent) { if (_onKeyDown != null) _onKeyDown(e); } + */ private var _onKeyUp:KeyboardEvent->Void = null; public var onKeyUp(null, set):KeyboardEvent->Void; private function set_onKeyUp(value:KeyboardEvent->Void):KeyboardEvent->Void { if (_onKeyUp != null) { - tf.textField.removeEventListener(KeyboardEvent.KEY_UP, __onTextInputKeyUp); + //tf.textField.removeEventListener(KeyboardEvent.KEY_UP, __onTextInputKeyUp); } _onKeyUp = value; if (_onKeyUp != null) { - tf.textField.addEventListener(KeyboardEvent.KEY_UP, __onTextInputKeyUp); + //tf.textField.addEventListener(KeyboardEvent.KEY_UP, __onTextInputKeyUp); } return value; } + /* private function __onTextInputKeyUp(e:KeyboardEvent) { if (_onKeyUp != null) _onKeyUp(e); } + */ private function onInternalChange() { _text = tf.text; From b696360671b725102aec433f193b67ba42892a27 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Mon, 25 Dec 2023 19:33:31 -0400 Subject: [PATCH 053/120] Fixed text area scrollbar not starting from the very top --- haxe/ui/backend/flixel/textinputs/FlxTextInput.hx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx index e09be35..f6dd83b 100644 --- a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx @@ -104,7 +104,7 @@ class FlxTextInput extends TextBase { tf.scrollH = hscrollValue; } - var vscrollValue = Std.int(_inputData.vscrollPos); + var vscrollValue = Std.int(_inputData.vscrollPos) + 1; if (tf.scrollV != vscrollValue) { tf.scrollV = vscrollValue; } @@ -134,7 +134,7 @@ class FlxTextInput extends TextBase { // see below _inputData.hscrollPageSize = (_width * _inputData.hscrollMax) / _textWidth; - _inputData.vscrollMax = tf.maxScrollV; + _inputData.vscrollMax = tf.maxScrollV - 1; _inputData.vscrollPageSize = (_height * _inputData.vscrollMax) / _textHeight; } @@ -370,7 +370,7 @@ class FlxTextInput extends TextBase { private function onScroll() { _inputData.hscrollPos = tf.scrollH; - _inputData.vscrollPos = tf.scrollV; + _inputData.vscrollPos = tf.scrollV - 1; if (_inputData.onScrollCallback != null) { _inputData.onScrollCallback(); From 126a22ce626f157225583dc61d53500cde759920 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Mon, 25 Dec 2023 19:38:05 -0400 Subject: [PATCH 054/120] Fix max vscroll for OpenFL text input --- haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx b/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx index dad47bf..086876b 100644 --- a/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/OpenFLTextInput.hx @@ -348,7 +348,7 @@ class OpenFLTextInput extends TextBase { // see below _inputData.hscrollPageSize = (_width * _inputData.hscrollMax) / _textWidth; - _inputData.vscrollMax = tf.maxScrollV; + _inputData.vscrollMax = tf.maxScrollV - 1; // cant have page size yet as there seems to be an openfl issue with bottomScrollV // https://github.com/openfl/openfl/issues/2220 _inputData.vscrollPageSize = (_height * _inputData.vscrollMax) / _textHeight; From 061d24321f05325e0c916f650518c584acc101f3 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Mon, 25 Dec 2023 22:50:39 -0400 Subject: [PATCH 055/120] Enable `pixelPerfectRender` for text objects --- haxe/ui/backend/TextDisplayImpl.hx | 2 +- haxe/ui/backend/flixel/textinputs/FlxTextInput.hx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/haxe/ui/backend/TextDisplayImpl.hx b/haxe/ui/backend/TextDisplayImpl.hx index 958a310..df4d101 100644 --- a/haxe/ui/backend/TextDisplayImpl.hx +++ b/haxe/ui/backend/TextDisplayImpl.hx @@ -12,7 +12,7 @@ class TextDisplayImpl extends TextBase { public function new() { super(); tf = new FlxText(); - tf.pixelPerfectPosition = true; + tf.pixelPerfectRender = true; tf.autoSize = true; } diff --git a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx index f6dd83b..0fb95e4 100644 --- a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx @@ -22,6 +22,7 @@ class FlxTextInput extends TextBase { tf = new flixel.addons.text.FlxTextInput(); tf.onChange.add(onInternalChange); tf.onScroll.add(onScroll); + tf.pixelPerfectRender = true; tf.moves = false; _inputData.vscrollPageStep = 1; _inputData.vscrollNativeWheel = true; From 075ad80cacbc339dbb81303cf779f9af6d4db08e Mon Sep 17 00:00:00 2001 From: Starmapo Date: Thu, 4 Jan 2024 19:50:38 -0400 Subject: [PATCH 056/120] Reuse event objects when possible instead of creating new ones - All events can now be canceled - All mouse events now have `touchEvent` set - Only dispatch mouse out events if the component was moused over beforehand - Mouse wheel events now have `screenX` and `screenY` set --- haxe/ui/backend/ComponentImpl.hx | 99 ++++++++++++++------------- haxe/ui/backend/flixel/MouseHelper.hx | 17 ++++- 2 files changed, 66 insertions(+), 50 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 3751bae..5afe61a 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -796,9 +796,7 @@ class ComponentImpl extends ComponentBase { var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OUT); mouseEvent.screenX = x / Toolkit.scaleX; mouseEvent.screenY = y / Toolkit.scaleY; - #if mobile - mouseEvent.touchEvent = true; - #end + mouseEvent.touchEvent = event.touchEvent; fn(mouseEvent); event.canceled = mouseEvent.canceled; } @@ -809,12 +807,17 @@ class ComponentImpl extends ComponentBase { var i = inBounds(x, y); if (i == true) { if (hasComponentOver(cast this, x, y) == true) { - var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_OUT); - if (fn != null) { - var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OUT); - mouseEvent.screenX = x / Toolkit.scaleX; - mouseEvent.screenY = y / Toolkit.scaleY; - fn(mouseEvent); + if (_mouseOverFlag == true) { + _mouseOverFlag = false; + var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_OUT); + if (fn != null) { + var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OUT); + mouseEvent.screenX = x / Toolkit.scaleX; + mouseEvent.screenY = y / Toolkit.scaleY; + mouseEvent.touchEvent = event.touchEvent; + fn(mouseEvent); + event.canceled = mouseEvent.canceled; + } } return; } @@ -823,10 +826,11 @@ class ComponentImpl extends ComponentBase { } var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_MOVE); if (fn != null) { - var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_MOVE); - mouseEvent.screenX = x / Toolkit.scaleX; - mouseEvent.screenY = y / Toolkit.scaleY; - fn(mouseEvent); + event.screenX = x / Toolkit.scaleX; + event.screenY = y / Toolkit.scaleY; + fn(event); + event.screenX = x; + event.screenY = y; } } if (i == true && _mouseOverFlag == false) { @@ -839,7 +843,9 @@ class ComponentImpl extends ComponentBase { var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OVER); mouseEvent.screenX = x / Toolkit.scaleX; mouseEvent.screenY = y / Toolkit.scaleY; + mouseEvent.touchEvent = event.touchEvent; fn(mouseEvent); + event.canceled = mouseEvent.canceled; } } else if (i == false && _mouseOverFlag == true) { _mouseOverFlag = false; @@ -849,7 +855,9 @@ class ComponentImpl extends ComponentBase { var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OUT); mouseEvent.screenX = x / Toolkit.scaleX; mouseEvent.screenY = y / Toolkit.scaleY; + mouseEvent.touchEvent = event.touchEvent; fn(mouseEvent); + event.canceled = mouseEvent.canceled; } } } @@ -861,7 +869,6 @@ class ComponentImpl extends ComponentBase { return; } - var button:Int = event.data; var x = event.screenX; var y = event.screenY; @@ -874,13 +881,13 @@ class ComponentImpl extends ComponentBase { } _mouseDownFlag = true; - var type = button == 0 ? haxe.ui.events.MouseEvent.MOUSE_DOWN: haxe.ui.events.MouseEvent.RIGHT_MOUSE_DOWN; - var fn:UIEvent->Void = _eventMap.get(type); + var fn:UIEvent->Void = _eventMap.get(event.type); if (fn != null) { - var mouseEvent = new haxe.ui.events.MouseEvent(type); - mouseEvent.screenX = x / Toolkit.scaleX; - mouseEvent.screenY = y / Toolkit.scaleY; - fn(mouseEvent); + event.screenX = x / Toolkit.scaleX; + event.screenY = y / Toolkit.scaleY; + fn(event); + event.screenX = x; + event.screenY = y; } } } @@ -911,7 +918,9 @@ class ComponentImpl extends ComponentBase { var mouseEvent = new haxe.ui.events.MouseEvent(type); mouseEvent.screenX = x / Toolkit.scaleX; mouseEvent.screenY = y / Toolkit.scaleY; + mouseEvent.touchEvent = event.touchEvent; fn(mouseEvent); + event.canceled = mouseEvent.canceled; } if (type == haxe.ui.events.MouseEvent.CLICK) { @@ -925,13 +934,13 @@ class ComponentImpl extends ComponentBase { } _mouseDownFlag = false; - var type = button == 0 ? haxe.ui.events.MouseEvent.MOUSE_UP: haxe.ui.events.MouseEvent.RIGHT_MOUSE_UP; - var fn:UIEvent->Void = _eventMap.get(type); + var fn:UIEvent->Void = _eventMap.get(event.type); if (fn != null) { - var mouseEvent = new haxe.ui.events.MouseEvent(type); - mouseEvent.screenX = x / Toolkit.scaleX; - mouseEvent.screenY = y / Toolkit.scaleY; - fn(mouseEvent); + event.screenX = x / Toolkit.scaleX; + event.screenY = y / Toolkit.scaleY; + fn(event); + event.screenX = x; + event.screenY = y; } } _mouseDownFlag = false; @@ -958,13 +967,13 @@ class ComponentImpl extends ComponentBase { _mouseDownFlag = false; var mouseDelta:Float = MathUtil.distance(x, y, _lastClickX, _lastClickY); if (_lastClickTimeDiff < 0.5 && mouseDelta < 5) { // 0.5 seconds - var type = haxe.ui.events.MouseEvent.DBL_CLICK; - var fn:UIEvent->Void = _eventMap.get(type); + var fn:UIEvent->Void = _eventMap.get(event.type); if (fn != null) { - var mouseEvent = new haxe.ui.events.MouseEvent(type); - mouseEvent.screenX = x / Toolkit.scaleX; - mouseEvent.screenY = y / Toolkit.scaleY; - fn(mouseEvent); + event.screenX = x / Toolkit.scaleX; + event.screenY = y / Toolkit.scaleY; + fn(event); + event.screenX = x; + event.screenY = y; } } } @@ -977,25 +986,23 @@ class ComponentImpl extends ComponentBase { } var delta = event.delta; + var x = event.screenX; + var y = event.screenY; var fn = _eventMap.get(MouseEvent.MOUSE_WHEEL); if (fn == null) { return; } - if (!inBounds(lastMouseX, lastMouseY)) { + if (!inBounds(x, y)) { return; } - var mouseEvent = new MouseEvent(MouseEvent.MOUSE_WHEEL); - mouseEvent.screenX = lastMouseX / Toolkit.scaleX; - mouseEvent.screenY = lastMouseY / Toolkit.scaleY; - mouseEvent.delta = Math.max(-1, Math.min(1, -delta)); - if (Platform.instance.isMobile) { - mouseEvent.touchEvent = true; - } - fn(mouseEvent); - event.canceled = mouseEvent.canceled; + event.screenX = x / Toolkit.scaleX; + event.screenY = y / Toolkit.scaleY; + fn(event); + event.screenX = x; + event.screenY = y; } private function __onKeyboardEvent(event:KeyboardEvent) { @@ -1008,13 +1015,7 @@ class ComponentImpl extends ComponentBase { return; } - var keyboardEvent = new KeyboardEvent(event.type); - keyboardEvent.keyCode = event.keyCode; - keyboardEvent.altKey = event.altKey; - keyboardEvent.ctrlKey = event.ctrlKey; - keyboardEvent.shiftKey = event.shiftKey; - fn(keyboardEvent); - event.canceled = keyboardEvent.canceled; + fn(event); } private function __onTextInputKeyboardEvent(event:openfl.events.KeyboardEvent) { diff --git a/haxe/ui/backend/flixel/MouseHelper.hx b/haxe/ui/backend/flixel/MouseHelper.hx index b402112..ef48bd8 100644 --- a/haxe/ui/backend/flixel/MouseHelper.hx +++ b/haxe/ui/backend/flixel/MouseHelper.hx @@ -1,6 +1,7 @@ package haxe.ui.backend.flixel; import flixel.FlxG; +import haxe.ui.core.Platform; import haxe.ui.events.MouseEvent; typedef MouseCallback = { @@ -136,6 +137,9 @@ class MouseHelper { event.screenX = (currentMouseX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom()); event.screenY = (currentMouseY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); } + if (Platform.instance.isMobile) { + event.touchEvent = true; + } event.data = -1; if (e.type == openfl.events.MouseEvent.MOUSE_DOWN) { @@ -173,6 +177,9 @@ class MouseHelper { event.screenX = (currentMouseX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom()); event.screenY = (currentMouseY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); } + if (Platform.instance.isMobile) { + event.touchEvent = true; + } event.data = -1; if (e.type == openfl.events.MouseEvent.MOUSE_UP) { @@ -209,6 +216,9 @@ class MouseHelper { event.screenX = (currentMouseX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom()); event.screenY = (currentMouseY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); } + if (Platform.instance.isMobile) { + event.touchEvent = true; + } for (l in list) { l.fn(event); @@ -227,7 +237,12 @@ class MouseHelper { list = list.copy(); var event = new MouseEvent(MouseEvent.MOUSE_WHEEL); - event.delta = -e.delta; + event.screenX = (e.stageX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom()); + event.screenY = (e.stageY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); + event.delta = Math.max(-1, Math.min(1, e.delta)); + if (Platform.instance.isMobile) { + event.touchEvent = true; + } for (l in list) { l.fn(event); if (event.canceled == true) { From b3d78e2a35ca1e34ac22ea786d67c4866efb3add Mon Sep 17 00:00:00 2001 From: Starmapo Date: Thu, 4 Jan 2024 20:14:08 -0400 Subject: [PATCH 057/120] Fixed pre-state switch mouse up event having a MOUSE_DOWN type --- haxe/ui/backend/flixel/MouseHelper.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haxe/ui/backend/flixel/MouseHelper.hx b/haxe/ui/backend/flixel/MouseHelper.hx index ef48bd8..d0b0791 100644 --- a/haxe/ui/backend/flixel/MouseHelper.hx +++ b/haxe/ui/backend/flixel/MouseHelper.hx @@ -103,7 +103,7 @@ class MouseHelper { private static function onPreStateSwitched() { // simulate mouse events when states switch to mop up any visual styles - var e = new openfl.events.MouseEvent(openfl.events.MouseEvent.MOUSE_DOWN); + var e = new openfl.events.MouseEvent(openfl.events.MouseEvent.MOUSE_UP); e.stageX = currentMouseX; e.stageY = currentMouseY; e.buttonDown = false; From 762130877b5b94e2a2d7b9145b061a537b4ffb88 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sat, 6 Jan 2024 11:51:24 -0400 Subject: [PATCH 058/120] Reworked mouse events - All mouse events are now supported by the screen and components - All mouse events now have `buttonDown`, `touchEvent`, `ctrlKey` and `shiftKey` set correctly - Reuse screen event objects when possible instead of creating new ones - Removed now-unused variables and functions --- haxe/ui/backend/ComponentImpl.hx | 430 +------------------------- haxe/ui/backend/ScreenImpl.hx | 105 ++----- haxe/ui/backend/flixel/MouseHelper.hx | 339 ++++++++++---------- 3 files changed, 201 insertions(+), 673 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 5afe61a..4112fe3 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -32,15 +32,6 @@ class ComponentImpl extends ComponentBase { private var _surface:FlxSprite; - private var lastMouseX:Float = -1; - private var lastMouseY:Float = -1; - - // For doubleclick detection - private var _lastClickTime:Float = 0; - private var _lastClickTimeDiff:Float = MathUtil.MAX_INT; - private var _lastClickX:Float = -1; - private var _lastClickY:Float = -1; - private var asComponent:Component; public function new() { @@ -470,95 +461,29 @@ class ComponentImpl extends ComponentBase { //*********************************************************************************************************** private override function mapEvent(type:String, listener:UIEvent->Void) { switch (type) { - case MouseEvent.MOUSE_MOVE: - if (_eventMap.exists(MouseEvent.MOUSE_MOVE) == false) { - notifyMouseMove(true); - _eventMap.set(MouseEvent.MOUSE_MOVE, listener); - } - - case MouseEvent.MOUSE_OVER: - if (_eventMap.exists(MouseEvent.MOUSE_OVER) == false) { - notifyMouseMove(true); - _eventMap.set(MouseEvent.MOUSE_OVER, listener); - } - - case MouseEvent.MOUSE_OUT: - if (_eventMap.exists(MouseEvent.MOUSE_OUT) == false) { - notifyMouseMove(true); - _eventMap.set(MouseEvent.MOUSE_OUT, listener); - } - case MouseEvent.MOUSE_DOWN: if (_eventMap.exists(MouseEvent.MOUSE_DOWN) == false) { - notifyMouseDown(true); - notifyMouseUp(true); - notifyMouseMove(true); - _eventMap.set(MouseEvent.MOUSE_DOWN, listener); if (hasTextInput()) { + _eventMap.set(MouseEvent.MOUSE_DOWN, listener); getTextInput().onMouseDown = __onTextInputMouseEvent; } } case MouseEvent.MOUSE_UP: if (_eventMap.exists(MouseEvent.MOUSE_UP) == false) { - notifyMouseDown(true); - notifyMouseUp(true); - notifyMouseMove(true); - _eventMap.set(MouseEvent.MOUSE_UP, listener); if (hasTextInput()) { + _eventMap.set(MouseEvent.MOUSE_UP, listener); getTextInput().onMouseUp = __onTextInputMouseEvent; } } - case MouseEvent.MOUSE_WHEEL: - if (_eventMap.exists(MouseEvent.MOUSE_WHEEL) == false) { - notifyMouseMove(true); - notifyMouseWheel(true); - _eventMap.set(MouseEvent.MOUSE_WHEEL, listener); - } - case MouseEvent.CLICK: if (_eventMap.exists(MouseEvent.CLICK) == false) { - notifyMouseDown(true); - notifyMouseUp(true); - notifyMouseMove(true); - _eventMap.set(MouseEvent.CLICK, listener); if (hasTextInput()) { + _eventMap.set(MouseEvent.CLICK, listener); getTextInput().onClick = __onTextInputMouseEvent; } } - - case MouseEvent.DBL_CLICK: - if (_eventMap.exists(MouseEvent.DBL_CLICK) == false) { - notifyMouseDown(true); - notifyMouseUp(true); - notifyMouseMove(true); - _eventMap.set(MouseEvent.DBL_CLICK, listener); - } - - case MouseEvent.RIGHT_MOUSE_DOWN: - if (_eventMap.exists(MouseEvent.RIGHT_MOUSE_DOWN) == false) { - notifyMouseDown(true); - notifyMouseUp(true); - notifyMouseMove(true); - _eventMap.set(MouseEvent.RIGHT_MOUSE_DOWN, listener); - } - - case MouseEvent.RIGHT_MOUSE_UP: - if (_eventMap.exists(MouseEvent.RIGHT_MOUSE_UP) == false) { - notifyMouseDown(true); - notifyMouseUp(true); - notifyMouseMove(true); - _eventMap.set(MouseEvent.RIGHT_MOUSE_UP, listener); - } - - case MouseEvent.RIGHT_CLICK: - if (_eventMap.exists(MouseEvent.RIGHT_CLICK) == false) { - notifyMouseDown(true); - notifyMouseUp(true); - notifyMouseMove(true); - _eventMap.set(MouseEvent.RIGHT_CLICK, listener); - } case KeyboardEvent.KEY_DOWN: if (_eventMap.exists(KeyboardEvent.KEY_DOWN) == false) { @@ -590,73 +515,23 @@ class ComponentImpl extends ComponentBase { private override function unmapEvent(type:String, listener:UIEvent->Void) { switch (type) { - case MouseEvent.MOUSE_MOVE: - _eventMap.remove(type); - notifyMouseMove(false); - - case MouseEvent.MOUSE_OVER: - _eventMap.remove(type); - notifyMouseMove(false); - - case MouseEvent.MOUSE_OUT: - _eventMap.remove(type); - notifyMouseMove(false); - case MouseEvent.MOUSE_DOWN: - _eventMap.remove(type); - notifyMouseDown(false); - notifyMouseUp(false); - notifyMouseMove(false); if (hasTextInput()) { + _eventMap.remove(type); getTextInput().onMouseDown = null; } case MouseEvent.MOUSE_UP: - _eventMap.remove(type); - notifyMouseDown(false); - notifyMouseUp(false); - notifyMouseMove(false); if (hasTextInput()) { + _eventMap.remove(type); getTextInput().onMouseUp = null; } - case MouseEvent.MOUSE_WHEEL: - _eventMap.remove(type); - notifyMouseMove(false); - notifyMouseWheel(false); - case MouseEvent.CLICK: - _eventMap.remove(type); - notifyMouseDown(false); - notifyMouseUp(false); - notifyMouseMove(false); if (hasTextInput()) { + _eventMap.remove(type); getTextInput().onClick = null; } - - case MouseEvent.DBL_CLICK: - _eventMap.remove(type); - notifyMouseDown(false); - notifyMouseUp(false); - notifyMouseMove(false); - - case MouseEvent.RIGHT_MOUSE_DOWN: - _eventMap.remove(type); - notifyMouseDown(false); - notifyMouseUp(false); - notifyMouseMove(false); - - case MouseEvent.RIGHT_MOUSE_UP: - _eventMap.remove(type); - notifyMouseDown(false); - notifyMouseUp(false); - notifyMouseMove(false); - - case MouseEvent.RIGHT_CLICK: - _eventMap.remove(type); - notifyMouseDown(false); - notifyMouseUp(false); - notifyMouseMove(false); case KeyboardEvent.KEY_DOWN: _eventMap.remove(type); @@ -673,77 +548,12 @@ class ComponentImpl extends ComponentBase { } case UIEvent.CHANGE: - _eventMap.remove(type); if (hasTextInput() == true) { + _eventMap.remove(type); getTextInput().onChange = null; } } } - - private var _counterNotifyMouseDown:Int = 0; - private function notifyMouseDown(notify:Bool) { - if (notify == true) { - _counterNotifyMouseDown++; - } else { - _counterNotifyMouseDown--; - if (_counterNotifyMouseDown < 0) { - _counterNotifyMouseDown = 0; - } - } - if (notify == true && _counterNotifyMouseDown == 1) { - MouseHelper.notify(MouseEvent.MOUSE_DOWN, __onMouseDown); - } else if (notify == false && _counterNotifyMouseDown == 0) { - MouseHelper.remove(MouseEvent.MOUSE_DOWN, __onMouseDown); - } - } - - private var _counterNotifyMouseUp:Int = 0; - private function notifyMouseUp(notify:Bool) { - if (notify == true) { - _counterNotifyMouseUp++; - } else { - _counterNotifyMouseUp--; - if (_counterNotifyMouseUp < 0) { - _counterNotifyMouseUp = 0; - } - } - if (notify == true && _counterNotifyMouseUp == 1) { - MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp); - } else if (notify == false && _counterNotifyMouseUp == 0) { - MouseHelper.remove(MouseEvent.MOUSE_UP, __onMouseUp); - } - } - - private var _counterNotifyMouseMove:Int = 0; - private function notifyMouseMove(notify:Bool) { - if (notify == true) { - _counterNotifyMouseMove++; - } else { - _counterNotifyMouseMove--; - if (_counterNotifyMouseMove < 0) { - _counterNotifyMouseMove = 0; - } - } - if (notify == true && _counterNotifyMouseMove == 1) { - MouseHelper.notify(MouseEvent.MOUSE_MOVE, __onMouseMove); - } else if (notify == false && _counterNotifyMouseMove == 0) { - MouseHelper.remove(MouseEvent.MOUSE_MOVE, __onMouseMove); - } - } - - private var _counterNotifyMouseWheel:Int = 0; - private function notifyMouseWheel(notify:Bool) { - if (notify == true) { - _counterNotifyMouseWheel++; - } else { - _counterNotifyMouseWheel--; - } - if (notify == true && _counterNotifyMouseWheel == 1) { - MouseHelper.notify(MouseEvent.MOUSE_WHEEL, __onMouseWheel); - } else if (notify == false && _counterNotifyMouseWheel == 0) { - MouseHelper.remove(MouseEvent.MOUSE_WHEEL, __onMouseWheel); - } - } private function __onTextInputChange(event:TextInputEvent) { var fn:UIEvent->Void = _eventMap.get(UIEvent.CHANGE); @@ -774,236 +584,22 @@ class ComponentImpl extends ComponentBase { } } + /* private var _mouseOverFlag:Bool = false; private var _cursorSet:Bool = false; - private function __onMouseMove(event:MouseEvent) { - if (Platform.instance.isMobile) { - return; - } - - var x = event.screenX; - var y = event.screenY; - lastMouseX = x; - lastMouseY = y; - - var inCurrentState = (this.state == StateHelper.currentState); - - if (inCurrentState == false) { - if (_mouseOverFlag == true) { - _mouseOverFlag = false; - var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_OUT); - if (fn != null) { - var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OUT); - mouseEvent.screenX = x / Toolkit.scaleX; - mouseEvent.screenY = y / Toolkit.scaleY; - mouseEvent.touchEvent = event.touchEvent; - fn(mouseEvent); - event.canceled = mouseEvent.canceled; - } - } - return; - } - - var i = inBounds(x, y); - if (i == true) { - if (hasComponentOver(cast this, x, y) == true) { - if (_mouseOverFlag == true) { - _mouseOverFlag = false; - var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_OUT); - if (fn != null) { - var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OUT); - mouseEvent.screenX = x / Toolkit.scaleX; - mouseEvent.screenY = y / Toolkit.scaleY; - mouseEvent.touchEvent = event.touchEvent; - fn(mouseEvent); - event.canceled = mouseEvent.canceled; - } - } - return; - } - if (this.style != null && this.style.cursor != null) { - Screen.instance.setCursor(this.style.cursor, this.style.cursorOffsetX, this.style.cursorOffsetY); - } - var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_MOVE); - if (fn != null) { - event.screenX = x / Toolkit.scaleX; - event.screenY = y / Toolkit.scaleY; - fn(event); - event.screenX = x; - event.screenY = y; - } - } - if (i == true && _mouseOverFlag == false) { - if (hasComponentOver(cast this, x, y) == true) { - return; - } - _mouseOverFlag = true; - var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_OVER); - if (fn != null) { - var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OVER); - mouseEvent.screenX = x / Toolkit.scaleX; - mouseEvent.screenY = y / Toolkit.scaleY; - mouseEvent.touchEvent = event.touchEvent; - fn(mouseEvent); - event.canceled = mouseEvent.canceled; - } - } else if (i == false && _mouseOverFlag == true) { - _mouseOverFlag = false; - Screen.instance.setCursor("default"); - var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_OUT); - if (fn != null) { - var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OUT); - mouseEvent.screenX = x / Toolkit.scaleX; - mouseEvent.screenY = y / Toolkit.scaleY; - mouseEvent.touchEvent = event.touchEvent; - fn(mouseEvent); - event.canceled = mouseEvent.canceled; - } - } + private function __onMouseOver(event:MouseEvent) { + _mouseOverFlag = true; } - private var _mouseDownFlag:Bool = false; - private var _mouseDownButton:Int = -1; - private function __onMouseDown(event:MouseEvent) { - if (this.state != StateHelper.currentState) { - return; - } - - var x = event.screenX; - var y = event.screenY; - - lastMouseX = x; - lastMouseY = y; - var i = inBounds(x, y); - if (i == true && _mouseDownFlag == false) { - if (hasComponentOver(cast this, x, y) == true) { - return; - } - _mouseDownFlag = true; - - var fn:UIEvent->Void = _eventMap.get(event.type); - if (fn != null) { - event.screenX = x / Toolkit.scaleX; - event.screenY = y / Toolkit.scaleY; - fn(event); - event.screenX = x; - event.screenY = y; - } - } - } - - private function __onMouseUp(event:MouseEvent) { - if (this.state != StateHelper.currentState) { - return; - } - - var button:Int = event.data; - var x = event.screenX; - var y = event.screenY; - - lastMouseX = x; - lastMouseY = y; - - var i = inBounds(x, y); - if (i == true) { - /* - if (hasComponentOver(cast this, x, y) == true) { - return; - } - */ - if (_mouseDownFlag == true) { - var type = button == 0 ? haxe.ui.events.MouseEvent.CLICK: haxe.ui.events.MouseEvent.RIGHT_CLICK; - var fn:UIEvent->Void = _eventMap.get(type); - if (fn != null) { - var mouseEvent = new haxe.ui.events.MouseEvent(type); - mouseEvent.screenX = x / Toolkit.scaleX; - mouseEvent.screenY = y / Toolkit.scaleY; - mouseEvent.touchEvent = event.touchEvent; - fn(mouseEvent); - event.canceled = mouseEvent.canceled; - } - - if (type == haxe.ui.events.MouseEvent.CLICK) { - _lastClickTimeDiff = Timer.stamp() - _lastClickTime; - _lastClickTime = Timer.stamp(); - if (_lastClickTimeDiff >= 0.5) { // 0.5 seconds - _lastClickX = x; - _lastClickY = y; - } - } - } - - _mouseDownFlag = false; - var fn:UIEvent->Void = _eventMap.get(event.type); - if (fn != null) { - event.screenX = x / Toolkit.scaleX; - event.screenY = y / Toolkit.scaleY; - fn(event); - event.screenX = x; - event.screenY = y; - } - } - _mouseDownFlag = false; + private function __onMouseOut(event:MouseEvent) { + _mouseOverFlag = false; } + */ #if haxeui_dont_impose_base_class private function applyRootLayout(l:String) { } #end - - private function __onDoubleClick(event:MouseEvent) { - var button:Int = event.data; - var x = event.screenX; - var y = event.screenY; - - lastMouseX = x; - lastMouseY = y; - var i = inBounds(x, y); - if (i == true && button == 0) { - if (hasComponentOver(cast this, x, y) == true) { - return; - } - - _mouseDownFlag = false; - var mouseDelta:Float = MathUtil.distance(x, y, _lastClickX, _lastClickY); - if (_lastClickTimeDiff < 0.5 && mouseDelta < 5) { // 0.5 seconds - var fn:UIEvent->Void = _eventMap.get(event.type); - if (fn != null) { - event.screenX = x / Toolkit.scaleX; - event.screenY = y / Toolkit.scaleY; - fn(event); - event.screenX = x; - event.screenY = y; - } - } - } - _mouseDownFlag = false; - } - - private function __onMouseWheel(event:MouseEvent) { - if (this.state != StateHelper.currentState) { - return; - } - - var delta = event.delta; - var x = event.screenX; - var y = event.screenY; - var fn = _eventMap.get(MouseEvent.MOUSE_WHEEL); - - if (fn == null) { - return; - } - - if (!inBounds(x, y)) { - return; - } - - event.screenX = x / Toolkit.scaleX; - event.screenY = y / Toolkit.scaleY; - fn(event); - event.screenX = x; - event.screenY = y; - } private function __onKeyboardEvent(event:KeyboardEvent) { if (this.state != StateHelper.currentState) { diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 392569f..bbf03d4 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -25,6 +25,8 @@ class ScreenImpl extends ScreenBase { public function new() { _mapping = new MapVoid>(); + MouseHelper.init(); + FlxG.signals.postGameStart.add(onPostGameStart); FlxG.signals.postStateSwitch.add(onPostStateSwitch); FlxG.signals.preStateCreate.add(onPreStateCreate); @@ -265,10 +267,19 @@ class ScreenImpl extends ScreenBase { private override function supportsEvent(type:String):Bool { if (type == MouseEvent.MOUSE_MOVE + || type == MouseEvent.MOUSE_OVER + || type == MouseEvent.MOUSE_OUT || type == MouseEvent.MOUSE_DOWN || type == MouseEvent.MOUSE_UP + || type == MouseEvent.MOUSE_WHEEL + || type == MouseEvent.CLICK + || type == MouseEvent.DBL_CLICK + || type == MouseEvent.RIGHT_CLICK || type == MouseEvent.RIGHT_MOUSE_DOWN || type == MouseEvent.RIGHT_MOUSE_UP + || type == MouseEvent.MIDDLE_CLICK + || type == MouseEvent.MIDDLE_MOUSE_DOWN + || type == MouseEvent.MIDDLE_MOUSE_UP || type == UIEvent.RESIZE || type == KeyboardEvent.KEY_DOWN || type == KeyboardEvent.KEY_UP @@ -278,111 +289,33 @@ class ScreenImpl extends ScreenBase { return false; } - private var _mouseDownButton:Int = 0; private override function mapEvent(type:String, listener:UIEvent->Void) { switch (type) { - case MouseEvent.MOUSE_MOVE: - if (_mapping.exists(type) == false) { - _mapping.set(type, listener); - MouseHelper.notify(MouseEvent.MOUSE_MOVE, __onMouseMove, 10); - } - - case MouseEvent.MOUSE_DOWN | MouseEvent.RIGHT_MOUSE_DOWN: - if (_mapping.exists(type) == false) { - _mapping.set(type, listener); - MouseHelper.notify(MouseEvent.MOUSE_DOWN, __onMouseDown, 10); - } - - case MouseEvent.MOUSE_UP | MouseEvent.RIGHT_MOUSE_UP: - if (_mapping.exists(type) == false) { - _mapping.set(type, listener); - MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp, 10); - } - - case KeyboardEvent.KEY_DOWN: + case MouseEvent.MOUSE_MOVE | MouseEvent.MOUSE_OVER | MouseEvent.MOUSE_OUT | MouseEvent.MOUSE_DOWN | MouseEvent.MOUSE_UP | MouseEvent.MOUSE_WHEEL | MouseEvent.CLICK | MouseEvent.DBL_CLICK | MouseEvent.RIGHT_CLICK | MouseEvent.RIGHT_MOUSE_DOWN | MouseEvent.RIGHT_MOUSE_UP | MouseEvent.MIDDLE_CLICK | MouseEvent.MIDDLE_MOUSE_DOWN | MouseEvent.MIDDLE_MOUSE_UP: if (_mapping.exists(type) == false) { _mapping.set(type, listener); - KeyboardHelper.notify(KeyboardEvent.KEY_DOWN, __onKeyEvent, 10); + MouseHelper.notify(type, __onMouseEvent, 10); } - case KeyboardEvent.KEY_UP: + case KeyboardEvent.KEY_DOWN | KeyboardEvent.KEY_UP: if (_mapping.exists(type) == false) { _mapping.set(type, listener); - KeyboardHelper.notify(KeyboardEvent.KEY_UP, __onKeyEvent, 10); + KeyboardHelper.notify(type, __onKeyEvent, 10); } } } - private function __onMouseMove(event:MouseEvent) { - var fn = _mapping.get(MouseEvent.MOUSE_MOVE); - if (fn != null) { - var mouseEvent = new MouseEvent(MouseEvent.MOUSE_MOVE); - mouseEvent.screenX = event.screenX / Toolkit.scaleX; - mouseEvent.screenY = event.screenY / Toolkit.scaleY; - mouseEvent.buttonDown = event.data; - #if mobile - mouseEvent.touchEvent = true; - #end - fn(mouseEvent); - event.canceled = mouseEvent.canceled; - } - } - - private function __onMouseDown(event:MouseEvent) { - var state = FlxG.state; - if (state.subState != null) { - state = state.subState; - } - /* - var contains = containsUnsolicitedMemberAt(event.screenX, event.screenY, state); - if (contains) { // lets attempt not in intercept unsolicated member events - return; - } - */ - - var fn = _mapping.get(MouseEvent.MOUSE_DOWN); - if (fn != null) { - var button:Int = event.data; - var type = button == 0 ? MouseEvent.MOUSE_DOWN: MouseEvent.RIGHT_MOUSE_DOWN; - var mouseEvent = new MouseEvent(type); - mouseEvent.screenX = event.screenX / Toolkit.scaleX; - mouseEvent.screenY = event.screenY / Toolkit.scaleY; - mouseEvent.buttonDown = event.data; - #if mobile - mouseEvent.touchEvent = true; - #end - fn(mouseEvent); - event.canceled = mouseEvent.canceled; - } - } - - private function __onMouseUp(event:MouseEvent) { - var fn = _mapping.get(MouseEvent.MOUSE_UP); + private function __onMouseEvent(event:MouseEvent) { + var fn = _mapping.get(event.type); if (fn != null) { - var button:Int = event.data; - var type = button == 0 ? MouseEvent.MOUSE_UP: MouseEvent.RIGHT_MOUSE_UP; - var mouseEvent = new MouseEvent(type); - mouseEvent.screenX = event.screenX / Toolkit.scaleX; - mouseEvent.screenY = event.screenY / Toolkit.scaleY; - mouseEvent.buttonDown = event.data; - #if mobile - mouseEvent.touchEvent = true; - #end - fn(mouseEvent); - event.canceled = mouseEvent.canceled; + fn(event); } } private function __onKeyEvent(event:KeyboardEvent) { var fn = _mapping.get(event.type); if (fn != null) { - var keyboardEvent = new KeyboardEvent(event.type); - keyboardEvent.keyCode = event.keyCode; - keyboardEvent.altKey = event.altKey; - keyboardEvent.ctrlKey = event.ctrlKey; - keyboardEvent.shiftKey = event.shiftKey; - fn(keyboardEvent); - event.canceled = keyboardEvent.canceled; + fn(event); } } diff --git a/haxe/ui/backend/flixel/MouseHelper.hx b/haxe/ui/backend/flixel/MouseHelper.hx index d0b0791..b878f65 100644 --- a/haxe/ui/backend/flixel/MouseHelper.hx +++ b/haxe/ui/backend/flixel/MouseHelper.hx @@ -1,7 +1,9 @@ package haxe.ui.backend.flixel; import flixel.FlxG; +import haxe.ui.core.Component; import haxe.ui.core.Platform; +import haxe.ui.core.Screen; import haxe.ui.events.MouseEvent; typedef MouseCallback = { @@ -12,41 +14,42 @@ typedef MouseCallback = { class MouseHelper { public static var currentMouseX:Float = 0; public static var currentMouseY:Float = 0; + public static var currentWorldX:Float = 0; + public static var currentWorldY:Float = 0; - private static var _hasOnMouseDown:Bool = false; - private static var _hasOnMouseUp:Bool = false; - private static var _hasOnMouseMove:Bool = false; - private static var _hasOnMouseWheel:Bool = false; - + private static var _initialized = false; private static var _callbacks:Map> = new Map>(); - - public static function notify(event:String, callback:MouseEvent->Void, priority:Int = 5) { - switch (event) { - case MouseEvent.MOUSE_DOWN: - if (_hasOnMouseDown == false) { - FlxG.stage.addEventListener(openfl.events.MouseEvent.MOUSE_DOWN, onMouseDown); - FlxG.stage.addEventListener(openfl.events.MouseEvent.RIGHT_MOUSE_DOWN, onMouseDown); - _hasOnMouseDown = true; - } - case MouseEvent.MOUSE_UP: - if (_hasOnMouseUp == false) { - FlxG.stage.addEventListener(openfl.events.MouseEvent.MOUSE_UP, onMouseUp); - FlxG.stage.addEventListener(openfl.events.MouseEvent.RIGHT_MOUSE_UP, onMouseUp); - _hasOnMouseUp = true; - FlxG.signals.preStateSwitch.add(onPreStateSwitched); - } - case MouseEvent.MOUSE_MOVE: - if (_hasOnMouseMove == false) { - FlxG.stage.addEventListener(openfl.events.MouseEvent.MOUSE_MOVE, onMouseMove); - _hasOnMouseMove = true; - } - case MouseEvent.MOUSE_WHEEL: - if (_hasOnMouseWheel == false) { - FlxG.stage.addEventListener(openfl.events.MouseEvent.MOUSE_WHEEL, onMouseWheel); - _hasOnMouseWheel = true; - } + + private static var _mouseDownLeft:Dynamic; + private static var _mouseDownMiddle:Dynamic; + private static var _mouseDownRight:Dynamic; + private static var _lastClickTarget:Dynamic; + private static var _lastClickTime:Float; + private static var _mouseOverTarget:Dynamic; + + public static function init() { + if (_initialized == true) { + return; } + _initialized = true; + + FlxG.stage.addEventListener(openfl.events.MouseEvent.MOUSE_DOWN, onMouseDown); + FlxG.stage.addEventListener(openfl.events.MouseEvent.RIGHT_MOUSE_DOWN, onMouseDown); + FlxG.stage.addEventListener(openfl.events.MouseEvent.MIDDLE_MOUSE_DOWN, onMouseDown); + + FlxG.stage.addEventListener(openfl.events.MouseEvent.MOUSE_UP, onMouseUp); + FlxG.stage.addEventListener(openfl.events.MouseEvent.RIGHT_MOUSE_UP, onMouseUp); + FlxG.stage.addEventListener(openfl.events.MouseEvent.MIDDLE_MOUSE_UP, onMouseUp); + + FlxG.stage.addEventListener(openfl.events.MouseEvent.MOUSE_MOVE, onMouseMove); + + FlxG.stage.addEventListener(openfl.events.MouseEvent.MOUSE_WHEEL, onMouseWheel); + + FlxG.signals.preStateSwitch.add(onPreStateSwitched); + } + + public static function notify(event:String, callback:MouseEvent->Void, priority:Int = 5) { var list = _callbacks.get(event); if (list == null) { list = new Array(); @@ -71,154 +74,152 @@ class MouseHelper { removeCallback(list, callback); if (list.length == 0) { _callbacks.remove(event); - - switch (event) { - case MouseEvent.MOUSE_DOWN: - if (_hasOnMouseDown == true) { - FlxG.stage.removeEventListener(openfl.events.MouseEvent.MOUSE_DOWN, onMouseDown); - FlxG.stage.removeEventListener(openfl.events.MouseEvent.RIGHT_MOUSE_DOWN, onMouseDown); - _hasOnMouseDown = false; - } - case MouseEvent.MOUSE_UP: - if (_hasOnMouseUp == true) { - FlxG.stage.removeEventListener(openfl.events.MouseEvent.MOUSE_UP, onMouseUp); - FlxG.stage.removeEventListener(openfl.events.MouseEvent.RIGHT_MOUSE_UP, onMouseUp); - _hasOnMouseUp = false; - FlxG.signals.preStateSwitch.remove(onPreStateSwitched); - } - case MouseEvent.MOUSE_MOVE: - if (_hasOnMouseMove == true) { - FlxG.stage.removeEventListener(openfl.events.MouseEvent.MOUSE_MOVE, onMouseMove); - _hasOnMouseMove = false; - } - case MouseEvent.MOUSE_WHEEL: - if (_hasOnMouseWheel == true) { - FlxG.stage.removeEventListener(openfl.events.MouseEvent.MOUSE_WHEEL, onMouseWheel); - _hasOnMouseWheel = false; - } - } } } } private static function onPreStateSwitched() { // simulate mouse events when states switch to mop up any visual styles - var e = new openfl.events.MouseEvent(openfl.events.MouseEvent.MOUSE_UP); - e.stageX = currentMouseX; - e.stageY = currentMouseY; - e.buttonDown = false; - onMouseUp(e); - - var e = new openfl.events.MouseEvent(openfl.events.MouseEvent.MOUSE_MOVE); - e.stageX = currentMouseX; - e.stageY = currentMouseY; - e.buttonDown = false; - onMouseMove(e); + onMouse(MouseEvent.MOUSE_UP, currentMouseX, currentMouseY); + onMouse(MouseEvent.MOUSE_MOVE, currentMouseX, currentMouseY); } private static function onMouseDown(e:openfl.events.MouseEvent) { - if (e != null) { - currentMouseX = e.stageX; - currentMouseY = e.stageY; - } - - var list = _callbacks.get(MouseEvent.MOUSE_DOWN); - if (list == null || list.length == 0) { - return; - } - - list = list.copy(); - - var event = new MouseEvent(MouseEvent.MOUSE_DOWN); - if (e != null) { - event.screenX = (e.stageX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom()); - event.screenY = (e.stageY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); - } else { - event.screenX = (currentMouseX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom()); - event.screenY = (currentMouseY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); - } - if (Platform.instance.isMobile) { - event.touchEvent = true; - } - - event.data = -1; - if (e.type == openfl.events.MouseEvent.MOUSE_DOWN) { - event.data = 0; - } else if (e.type == openfl.events.MouseEvent.RIGHT_MOUSE_DOWN) { - event.data = 1; - } - - for (l in list) { - l.fn(event); - if (event.canceled == true) { - break; - } + var type = switch (e.type) { + case openfl.events.MouseEvent.MIDDLE_MOUSE_DOWN: MouseEvent.MIDDLE_MOUSE_DOWN; + case openfl.events.MouseEvent.RIGHT_MOUSE_DOWN: MouseEvent.RIGHT_MOUSE_DOWN; + default: MouseEvent.MOUSE_DOWN; } + onMouse(type, e.stageX, e.stageY, e.buttonDown, e.ctrlKey, e.shiftKey); } private static function onMouseUp(e:openfl.events.MouseEvent) { - if (e != null) { - currentMouseX = e.stageX; - currentMouseY = e.stageY; + var type = switch (e.type) { + case openfl.events.MouseEvent.MIDDLE_MOUSE_UP: MouseEvent.MIDDLE_MOUSE_UP; + case openfl.events.MouseEvent.RIGHT_MOUSE_UP: MouseEvent.RIGHT_MOUSE_UP; + default: MouseEvent.MOUSE_UP; } - - var list = _callbacks.get(MouseEvent.MOUSE_UP); - if (list == null || list.length == 0) { - return; + onMouse(type, e.stageX, e.stageY, e.buttonDown, e.ctrlKey, e.shiftKey); + } + + private static function onMouseMove(e:openfl.events.MouseEvent) { + onMouse(MouseEvent.MOUSE_MOVE, e.stageX, e.stageY, e.buttonDown, e.ctrlKey, e.shiftKey); + } + + private static function onMouseWheel(e:openfl.events.MouseEvent) { + var event = createEvent(MouseEvent.MOUSE_WHEEL, e.buttonDown, e.ctrlKey, e.shiftKey); + event.delta = Math.max(-1, Math.min(1, e.delta)); + + var target:Dynamic = getTarget(currentWorldX, currentWorldY); + + dispatchEvent(event, target); + } + + private static function onMouse(type:String, x:Float, y:Float, buttonDown:Bool = false, ctrlKey:Bool = false, shiftKey:Bool = false) { + if (currentMouseX != x) { + currentMouseX = x; + currentWorldX = (currentMouseX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom()); } - - list = list.copy(); - - var event = new MouseEvent(MouseEvent.MOUSE_UP); - if (e != null) { - event.screenX = (e.stageX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom()); - event.screenY = (e.stageY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); - } else { - event.screenX = (currentMouseX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom()); - event.screenY = (currentMouseY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); + if (currentMouseY != y) { + currentMouseY = y; + currentWorldY = (currentMouseY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); } - if (Platform.instance.isMobile) { - event.touchEvent = true; + + var target:Dynamic = getTarget(currentWorldX, currentWorldY); + + var clickType:String = null; + switch (type) { + case MouseEvent.MOUSE_DOWN: + _mouseDownLeft = target; + + case MouseEvent.MIDDLE_MOUSE_DOWN: + _mouseDownMiddle = target; + + case MouseEvent.RIGHT_MOUSE_DOWN: + _mouseDownRight = target; + + case MouseEvent.MOUSE_UP: + if (_mouseDownLeft == target) { + clickType = MouseEvent.CLICK; + } + _mouseDownLeft = null; + + case MouseEvent.MIDDLE_MOUSE_UP: + if (_mouseDownMiddle == target) { + clickType = MouseEvent.MIDDLE_CLICK; + } + _mouseDownMiddle = null; + + case MouseEvent.RIGHT_MOUSE_UP: + if (_mouseDownRight == target) { + clickType = MouseEvent.RIGHT_CLICK; + } + _mouseDownRight = null; } - event.data = -1; - if (e.type == openfl.events.MouseEvent.MOUSE_UP) { - event.data = 0; - } else if (e.type == openfl.events.MouseEvent.RIGHT_MOUSE_UP) { - event.data = 1; + dispatchEventType(type, buttonDown, ctrlKey, shiftKey, target); + + if (clickType != null) { + dispatchEventType(clickType, buttonDown, ctrlKey, shiftKey, target); + + if (type == MouseEvent.MOUSE_UP) { + var currentTime = Timer.stamp(); + if (currentTime - _lastClickTime < 0.5 && target == _lastClickTarget) { + dispatchEventType(MouseEvent.DBL_CLICK, buttonDown, ctrlKey, shiftKey, target); + _lastClickTime = 0; + _lastClickTarget = null; + } else { + _lastClickTarget = target; + _lastClickTime = currentTime; + } + } } - for (l in list) { - l.fn(event); - if (event.canceled == true) { - break; + if (target != _mouseOverTarget) { + if (_mouseOverTarget != null) { + if ((_mouseOverTarget is Component)) { + Screen.instance.setCursor("default"); + } + dispatchEventType(MouseEvent.MOUSE_OUT, buttonDown, ctrlKey, shiftKey, _mouseOverTarget); } + if ((target is Component)) { + var c:Component = target; + if (c.style != null && c.style.cursor != null) { + Screen.instance.setCursor(c.style.cursor, c.style.cursorOffsetX, c.style.cursorOffsetY); + } + } + dispatchEventType(MouseEvent.MOUSE_OVER, buttonDown, ctrlKey, shiftKey, target); + _mouseOverTarget = target; } } - - private static function onMouseMove(e:openfl.events.MouseEvent) { - if (e != null) { - currentMouseX = e.stageX; - currentMouseY = e.stageY; + + private static function dispatchEventType(type:String, buttonDown:Bool, ctrlKey:Bool, shiftKey:Bool, target:Dynamic) { + var event = createEvent(type, buttonDown, ctrlKey, shiftKey); + dispatchEvent(event, target); + } + + private static function dispatchEvent(event:MouseEvent, target:Dynamic) { + if ((target is Component)) { + var c:Component = cast target; + // recreate a bubbling effect, so components will pass events onto their parents + // can't use the `bubble` property as it causes a crash when `target` isn't the expected result, for example, on ListView.onRendererClick + while (c != null) { + if (c.hasEvent(event.type)) { + c.dispatch(event); + if (event.canceled == true) { + return; + } + } + c = c.parentComponent; + } } - var list = _callbacks.get(MouseEvent.MOUSE_MOVE); + var list = _callbacks.get(event.type); if (list == null || list.length == 0) { return; } list = list.copy(); - var event = new MouseEvent(MouseEvent.MOUSE_MOVE); - if (e != null) { - event.screenX = (e.stageX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom()); - event.screenY = (e.stageY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); - } else { - event.screenX = (currentMouseX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom()); - event.screenY = (currentMouseY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); - } - if (Platform.instance.isMobile) { - event.touchEvent = true; - } for (l in list) { l.fn(event); @@ -227,28 +228,26 @@ class MouseHelper { } } } - - private static function onMouseWheel(e:openfl.events.MouseEvent) { - var list = _callbacks.get(MouseEvent.MOUSE_WHEEL); - if (list == null || list.length == 0) { - return; - } - - list = list.copy(); - - var event = new MouseEvent(MouseEvent.MOUSE_WHEEL); - event.screenX = (e.stageX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom()); - event.screenY = (e.stageY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); - event.delta = Math.max(-1, Math.min(1, e.delta)); - if (Platform.instance.isMobile) { - event.touchEvent = true; - } - for (l in list) { - l.fn(event); - if (event.canceled == true) { - break; - } + + private static function createEvent(type:String, buttonDown:Bool, ctrlKey:Bool, shiftKey:Bool):MouseEvent { + var event = new MouseEvent(type); + event.screenX = currentWorldX / Toolkit.scaleX; + event.screenY = currentWorldY / Toolkit.scaleY; + event.buttonDown = buttonDown; + event.touchEvent = Platform.instance.isMobile; + event.ctrlKey = ctrlKey; + event.shiftKey = shiftKey; + return event; + } + + private static function getTarget(x:Float, y:Float):Dynamic { + var target:Dynamic = null; + var components = Screen.instance.findComponentsUnderPoint(x, y); + if (components.length > 0 && components[components.length - 1].state == StateHelper.currentState) { + target = components[components.length - 1]; } + if (target == null) target = Screen.instance; + return target; } private static inline function initialZoom():Float { From 55f02ac66771cf5761abbcc59a7119b36adebce0 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sat, 6 Jan 2024 17:33:13 -0400 Subject: [PATCH 059/120] Reworked keyboard events - Removed KeyboardEvent.KEY_PRESS from the supported events list --- haxe/ui/backend/ComponentImpl.hx | 32 ++-------- haxe/ui/backend/ScreenImpl.hx | 4 +- haxe/ui/backend/flixel/KeyboardHelper.hx | 76 +++++++++++++----------- 3 files changed, 48 insertions(+), 64 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 4112fe3..da2c860 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -8,9 +8,6 @@ import flixel.text.FlxText.FlxTextBorderStyle; import haxe.ui.Toolkit; import haxe.ui.backend.TextInputImpl.TextInputEvent; import haxe.ui.backend.flixel.FlxStyleHelper; -import haxe.ui.backend.flixel.KeyboardHelper; -import haxe.ui.backend.flixel.MouseHelper; -import haxe.ui.backend.flixel.StateHelper; import haxe.ui.core.Component; import haxe.ui.core.ImageDisplay; import haxe.ui.core.Platform; @@ -24,8 +21,6 @@ import haxe.ui.filters.DropShadow; import haxe.ui.filters.Outline; import haxe.ui.geom.Rectangle; import haxe.ui.styles.Style; -import haxe.ui.util.MathUtil; -import openfl.events.Event; class ComponentImpl extends ComponentBase { private var _eventMap:MapVoid>; @@ -487,18 +482,16 @@ class ComponentImpl extends ComponentBase { case KeyboardEvent.KEY_DOWN: if (_eventMap.exists(KeyboardEvent.KEY_DOWN) == false) { - KeyboardHelper.notify(KeyboardEvent.KEY_DOWN, __onKeyboardEvent); - _eventMap.set(KeyboardEvent.KEY_DOWN, listener); if (hasTextInput()) { + _eventMap.set(KeyboardEvent.KEY_DOWN, listener); getTextInput().onKeyDown = __onTextInputKeyboardEvent; } } case KeyboardEvent.KEY_UP: if (_eventMap.exists(KeyboardEvent.KEY_UP) == false) { - KeyboardHelper.notify(KeyboardEvent.KEY_UP, __onKeyboardEvent); - _eventMap.set(KeyboardEvent.KEY_UP, listener); if (hasTextInput()) { + _eventMap.set(KeyboardEvent.KEY_UP, listener); getTextInput().onKeyUp = __onTextInputKeyboardEvent; } } @@ -534,21 +527,19 @@ class ComponentImpl extends ComponentBase { } case KeyboardEvent.KEY_DOWN: - _eventMap.remove(type); - KeyboardHelper.remove(KeyboardEvent.KEY_DOWN, __onKeyboardEvent); if (hasTextInput()) { + _eventMap.remove(type); getTextInput().onKeyDown = null; } case KeyboardEvent.KEY_UP: - _eventMap.remove(type); - KeyboardHelper.remove(KeyboardEvent.KEY_UP, __onKeyboardEvent); if (hasTextInput()) { + _eventMap.remove(type); getTextInput().onKeyUp = null; } case UIEvent.CHANGE: - if (hasTextInput() == true) { + if (hasTextInput()) { _eventMap.remove(type); getTextInput().onChange = null; } @@ -601,19 +592,6 @@ class ComponentImpl extends ComponentBase { } #end - private function __onKeyboardEvent(event:KeyboardEvent) { - if (this.state != StateHelper.currentState) { - return; - } - - var fn = _eventMap.get(event.type); - if (fn == null) { - return; - } - - fn(event); - } - private function __onTextInputKeyboardEvent(event:openfl.events.KeyboardEvent) { var type = switch (event.type) { case openfl.events.KeyboardEvent.KEY_DOWN: diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index bbf03d4..2220748 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -26,6 +26,7 @@ class ScreenImpl extends ScreenBase { _mapping = new MapVoid>(); MouseHelper.init(); + KeyboardHelper.init(); FlxG.signals.postGameStart.add(onPostGameStart); FlxG.signals.postStateSwitch.add(onPostStateSwitch); @@ -282,8 +283,7 @@ class ScreenImpl extends ScreenBase { || type == MouseEvent.MIDDLE_MOUSE_UP || type == UIEvent.RESIZE || type == KeyboardEvent.KEY_DOWN - || type == KeyboardEvent.KEY_UP - || type == KeyboardEvent.KEY_PRESS) { + || type == KeyboardEvent.KEY_UP) { return true; } return false; diff --git a/haxe/ui/backend/flixel/KeyboardHelper.hx b/haxe/ui/backend/flixel/KeyboardHelper.hx index 8047bcc..4c3c42e 100644 --- a/haxe/ui/backend/flixel/KeyboardHelper.hx +++ b/haxe/ui/backend/flixel/KeyboardHelper.hx @@ -1,7 +1,9 @@ package haxe.ui.backend.flixel; import flixel.FlxG; +import haxe.ui.core.Component; import haxe.ui.events.KeyboardEvent; +import haxe.ui.focus.FocusManager; typedef KeyboardCallback = { var fn:KeyboardEvent->Void; @@ -9,25 +11,21 @@ typedef KeyboardCallback = { } class KeyboardHelper { - private static var _hasOnKeyDown:Bool = false; - private static var _hasOnKeyUp:Bool = false; - + private static var _initialized = false; private static var _callbacks:Map> = new Map>(); - - public static function notify(event:String, callback:KeyboardEvent->Void, priority:Int = 5) { - switch (event) { - case KeyboardEvent.KEY_DOWN: - if (_hasOnKeyDown == false) { - FlxG.stage.addEventListener(openfl.events.KeyboardEvent.KEY_DOWN, onKeyDown); - _hasOnKeyDown = true; - } - case KeyboardEvent.KEY_UP: - if (_hasOnKeyUp == false) { - FlxG.stage.addEventListener(openfl.events.KeyboardEvent.KEY_UP, onKeyUp); - _hasOnKeyUp = true; - } + + public static function init() { + if (_initialized == true) { + return; } + + _initialized = true; + FlxG.stage.addEventListener(openfl.events.KeyboardEvent.KEY_DOWN, onKeyDown); + FlxG.stage.addEventListener(openfl.events.KeyboardEvent.KEY_UP, onKeyUp); + } + + public static function notify(event:String, callback:KeyboardEvent->Void, priority:Int = 5) { var list = _callbacks.get(event); if (list == null) { list = new Array(); @@ -52,19 +50,6 @@ class KeyboardHelper { removeCallback(list, callback); if (list.length == 0) { _callbacks.remove(event); - - switch (event) { - case KeyboardEvent.KEY_DOWN: - if (_hasOnKeyDown == true) { - FlxG.stage.removeEventListener(openfl.events.KeyboardEvent.KEY_DOWN, onKeyDown); - _hasOnKeyDown = false; - } - case KeyboardEvent.KEY_UP: - if (_hasOnKeyUp == true) { - FlxG.stage.removeEventListener(openfl.events.KeyboardEvent.KEY_UP, onKeyUp); - _hasOnKeyUp = false; - } - } } } } @@ -78,6 +63,25 @@ class KeyboardHelper { } private static function dispatchEvent(type:String, e:openfl.events.KeyboardEvent) { + var event = new KeyboardEvent(type); + event.keyCode = e.keyCode; + event.altKey = e.altKey; + event.ctrlKey = e.ctrlKey; + event.shiftKey = e.shiftKey; + + var target = getTarget(); + // recreate a bubbling effect, so components will pass events onto their parents + // can't use the `bubble` property as it causes a crash when `target` isn't the expected result, for example, on ListView.onRendererClick + while (target != null) { + if (target.hasEvent(event.type)) { + target.dispatch(event); + if (event.canceled == true) { + return; + } + } + target = target.parentComponent; + } + var list = _callbacks.get(type); if (list == null || list.length == 0) { return; @@ -85,12 +89,6 @@ class KeyboardHelper { list = list.copy(); - var event = new KeyboardEvent(type); - event.keyCode = e.keyCode; - event.altKey = e.altKey; - event.ctrlKey = e.ctrlKey; - event.shiftKey = e.shiftKey; - for (l in list) { l.fn(event); if (event.canceled == true) { @@ -99,6 +97,14 @@ class KeyboardHelper { } } + private static function getTarget():Component { + var target:Component = cast FocusManager.instance.focus; + if (target != null && target.state == StateHelper.currentState) { + return target; + } + return null; + } + private static function hasCallback(list:Array, fn:KeyboardEvent->Void):Bool { var has = false; for (item in list) { From 9c8ab039524086f5a8c8f35b9fb14538b5bfba5d Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 11 Jan 2024 15:16:40 +0100 Subject: [PATCH 060/120] handle component destruction better (esp on state switches) --- haxe/ui/backend/ScreenImpl.hx | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 2220748..d4a3f9a 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -15,6 +15,7 @@ import haxe.ui.core.Screen; import haxe.ui.events.KeyboardEvent; import haxe.ui.events.MouseEvent; import haxe.ui.events.UIEvent; +import haxe.ui.tooltips.ToolTipManager; import lime.system.System; import openfl.Lib; @@ -29,6 +30,7 @@ class ScreenImpl extends ScreenBase { KeyboardHelper.init(); FlxG.signals.postGameStart.add(onPostGameStart); + FlxG.signals.preStateSwitch.add(onPreStateSwitch); FlxG.signals.postStateSwitch.add(onPostStateSwitch); FlxG.signals.preStateCreate.add(onPreStateCreate); onPostStateSwitch(); @@ -50,11 +52,24 @@ class ScreenImpl extends ScreenBase { onPostStateSwitch(); } - private function onPostStateSwitch() { + private function onPreStateSwitch() { if (FlxG.game == null) { return; } + ToolTipManager.instance.reset(); + if (rootComponents != null) { + while (rootComponents.length > 0) { + var root = rootComponents[rootComponents.length - 1]; + removeComponent(root); + } + } rootComponents = []; + } + + private function onPostStateSwitch() { + if (FlxG.game == null) { + return; + } if (!FlxG.state.subStateOpened.has(onMemberAdded)) { FlxG.state.subStateOpened.add(onMemberAdded); @@ -94,7 +109,7 @@ class ScreenImpl extends ScreenBase { private function onMemberRemoved(m:FlxBasic) { if ((m is Component) && rootComponents.indexOf(cast(m, Component)) != -1) { @:privateAccess var isDisposed = cast(m, Component)._isDisposed; - removeComponent(cast m, isDisposed); + removeComponent(cast m, !isDisposed); } } @@ -220,7 +235,7 @@ class ScreenImpl extends ScreenBase { component.state = null; component.destroyInternal(); component.destroy(); - component.destroyComponent(); + component.disposeComponent(); } else { component.applyRemoveInternal(); } From 9b7827fcb818ff7911d976076e7bf74a71f7ad5d Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Sun, 14 Jan 2024 11:33:50 +0100 Subject: [PATCH 061/120] use isDisposed correctly, no reason to have inverted it in prev change --- haxe/ui/backend/ScreenImpl.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index d4a3f9a..665192e 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -109,7 +109,7 @@ class ScreenImpl extends ScreenBase { private function onMemberRemoved(m:FlxBasic) { if ((m is Component) && rootComponents.indexOf(cast(m, Component)) != -1) { @:privateAccess var isDisposed = cast(m, Component)._isDisposed; - removeComponent(cast m, !isDisposed); + removeComponent(cast m, isDisposed); } } From 1ec470c297afd7758a90dc9399aa1e3a4ea6ca0b Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Sun, 14 Jan 2024 21:25:24 +0100 Subject: [PATCH 062/120] better component destruction handling --- haxe/ui/backend/ComponentImpl.hx | 13 +++++-------- haxe/ui/backend/ScreenImpl.hx | 6 +++--- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index da2c860..47390b3 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -240,6 +240,10 @@ class ComponentImpl extends ComponentBase { // Display tree //*********************************************************************************************************** + private override function handleDestroy() { + destroyInternal(); + } + private override function handleSetComponentIndex(child:Component, index:Int) { handleAddComponentAt(child, index); } @@ -841,9 +845,6 @@ class ComponentImpl extends ComponentBase { private var _destroyed:Bool = false; private function destroyInternal() { - if (!_allowDestroy) { - return; - } if (_surface != null) { _surface.destroy(); _surface = null; @@ -868,17 +869,13 @@ class ComponentImpl extends ComponentBase { _unsolicitedMembers = null; } + this.state = null; _destroy = false; _destroyed = true; super.destroy(); } - private var _allowDestroy:Bool = true; public override function destroy():Void { - if (!_allowDestroy) { - return; - } - if (parentComponent != null) { if (parentComponent.getComponentIndex(cast this) != -1) { parentComponent.removeComponent(cast this); diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 665192e..abcfc4f 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -225,6 +225,9 @@ class ScreenImpl extends ScreenBase { public override function removeComponent(component:Component, dispose:Bool = true):Component { if (rootComponents.indexOf(component) == -1) { + if (dispose) { + component.disposeComponent(); + } return component; } rootComponents.remove(component); @@ -232,9 +235,6 @@ class ScreenImpl extends ScreenBase { throw "component wasnt actually removed from array, or there is a duplicate in the array"; } if (dispose) { - component.state = null; - component.destroyInternal(); - component.destroy(); component.disposeComponent(); } else { component.applyRemoveInternal(); From e9f880522e27134b29df4067f82df7d7e5237b70 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Wed, 24 Jan 2024 22:01:43 +0100 Subject: [PATCH 063/120] SpriteWrapper component --- .../flixel/components/SpriteWrapper.hx | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 haxe/ui/backend/flixel/components/SpriteWrapper.hx diff --git a/haxe/ui/backend/flixel/components/SpriteWrapper.hx b/haxe/ui/backend/flixel/components/SpriteWrapper.hx new file mode 100644 index 0000000..ef51c86 --- /dev/null +++ b/haxe/ui/backend/flixel/components/SpriteWrapper.hx @@ -0,0 +1,65 @@ +package haxe.ui.backend.flixel.components; + +import flixel.FlxSprite; +import flixel.math.FlxRect; +import haxe.ui.containers.Box; +import haxe.ui.core.Component; +import haxe.ui.geom.Size; +import haxe.ui.layouts.DefaultLayout; + +@:composite(Layout) +class SpriteWrapper extends Box { + public var spriteOffsetX:Float = 0; + public var spriteOffsetY:Float = 0; + + private var _sprite:FlxSprite = null; + public var sprite(get, set):FlxSprite; + private function get_sprite():FlxSprite { + return _sprite; + } + private function set_sprite(value:FlxSprite):FlxSprite { + if (_sprite != null) { + remove(_sprite); + } + _sprite = value; + add(_sprite); + invalidateComponentLayout(); + return value; + } + + private override function repositionChildren() { + super.repositionChildren(); + if (sprite != null) { + sprite.x = spriteOffsetX + this.screenX; + sprite.y = spriteOffsetY + this.screenY; + } + } +} + +@:access(haxe.ui.backend.flixel.components.SpriteWrapper) +private class Layout extends DefaultLayout { + public override function resizeChildren() { + super.resizeChildren(); + + var wrapper = cast(_component, SpriteWrapper); + var sprite = wrapper.sprite; + if (sprite == null) { + return super.resizeChildren(); + } + + sprite.origin.set(0, 0); + sprite.setGraphicSize(Std.int(innerWidth), Std.int(innerHeight)); + } + + public override function calcAutoSize(exclusions:Array = null):Size { + var wrapper = cast(_component, SpriteWrapper); + var sprite = wrapper.sprite; + if (sprite == null) { + return super.calcAutoSize(exclusions); + } + var size = new Size(); + size.width = sprite.width + paddingLeft + paddingRight; + size.height = sprite.height + paddingTop + paddingBottom; + return size; + } +} \ No newline at end of file From 63a906a6148958dbfde8c7b48d90b0693767fd95 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 6 Feb 2024 09:12:50 +0100 Subject: [PATCH 064/120] grab fullPath from openfls internal var __path (not ideal) --- haxe/ui/backend/OpenFileDialogImpl.hx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/haxe/ui/backend/OpenFileDialogImpl.hx b/haxe/ui/backend/OpenFileDialogImpl.hx index 0db9bdb..57b22cb 100644 --- a/haxe/ui/backend/OpenFileDialogImpl.hx +++ b/haxe/ui/backend/OpenFileDialogImpl.hx @@ -86,9 +86,16 @@ class OpenFileDialogImpl extends OpenFileDialogBase { destroyFileRef(); var infos:Array = []; for (fileRef in fileList) { + + var fullPath:String = null; + #if sys + fullPath = @:privateAccess fileRef.__path; + #end + var info:SelectedFileInfo = { isBinary: false, - name: fileRef.name + name: fileRef.name, + fullPath: fullPath } if (options.readContents == true) { _refToInfo.set(fileRef, info); From 62dcf12f892b2daed4d6d2315a541219baf033ef Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Sun, 18 Feb 2024 15:41:46 +0100 Subject: [PATCH 065/120] additional params in screen.removeComponent --- haxe/ui/backend/ScreenImpl.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index abcfc4f..50b69af 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -223,7 +223,7 @@ class ScreenImpl extends ScreenBase { return component; } - public override function removeComponent(component:Component, dispose:Bool = true):Component { + public override function removeComponent(component:Component, dispose:Bool = true, invalidate:Bool = true):Component { if (rootComponents.indexOf(component) == -1) { if (dispose) { component.disposeComponent(); From 6f425189c35dbaa3c219b36e5e2beeb74fba8435 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Wed, 28 Feb 2024 19:38:55 -0400 Subject: [PATCH 066/120] Fixed crash from text input not being destroyed --- haxe/ui/backend/flixel/textinputs/FlxTextInput.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx index 0fb95e4..c420969 100644 --- a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx @@ -389,6 +389,7 @@ class FlxTextInput extends TextBase { public function destroy(component:Component) { tf.visible = false; component.remove(tf); + tf.destroy(); tf = null; } } From 6e52afa038672193bff0467663038814e5fbf8cc Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 7 Mar 2024 08:55:53 +0100 Subject: [PATCH 067/120] use .exists as state could have been destroyed --- haxe/ui/backend/ScreenImpl.hx | 6 +++++- haxe/ui/backend/flixel/StateHelper.hx | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 50b69af..391e83f 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -114,6 +114,10 @@ class ScreenImpl extends ScreenBase { } private function checkMembers(state:FlxTypedGroup) { + if (state == null || !state.exists) { + return false; + } + var found = false; // we only want top level components for (m in state.members) { if ((m is Component) && rootComponents.indexOf(cast(m, Component)) == -1) { @@ -335,7 +339,7 @@ class ScreenImpl extends ScreenBase { } private function containsUnsolicitedMemberAt(x:Float, y:Float, state:FlxTypedGroup):Bool { - if (state == null) { + if (state == null || !state.exists) { return false; } diff --git a/haxe/ui/backend/flixel/StateHelper.hx b/haxe/ui/backend/flixel/StateHelper.hx index b0c43f3..a38ad52 100644 --- a/haxe/ui/backend/flixel/StateHelper.hx +++ b/haxe/ui/backend/flixel/StateHelper.hx @@ -32,7 +32,7 @@ class StateHelper { group = currentState; } - if (group == null || group.members == null) { + if (group == null || !group.exists) { return false; } @@ -60,7 +60,7 @@ class StateHelper { } private static function groupHasMember(member:FlxBasic, group:FlxSpriteGroup) { - if (group == null || group.group == null || group.members == null) { + if (group == null || !group.exists) { return false; } @@ -92,7 +92,7 @@ class StateHelper { group = currentState; } - if (group == null || group.members == null) { + if (group == null || !group.exists) { return null; } From b642122146e972e3ed076fbaa2feb438f862f763 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 12 Mar 2024 09:07:39 +0100 Subject: [PATCH 068/120] box now contains a dataSource property, use override --- haxe/ui/backend/flixel/components/SparrowPlayer.hx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/haxe/ui/backend/flixel/components/SparrowPlayer.hx b/haxe/ui/backend/flixel/components/SparrowPlayer.hx index 451f19c..d31704e 100644 --- a/haxe/ui/backend/flixel/components/SparrowPlayer.hx +++ b/haxe/ui/backend/flixel/components/SparrowPlayer.hx @@ -65,11 +65,10 @@ class SparrowPlayer extends Box implements IDataComponent { } private var _dataSource:DataSource = null; - public var dataSource(get, set):DataSource; - private function get_dataSource():DataSource { + private override function get_dataSource():DataSource { return _dataSource; } - private function set_dataSource(value:DataSource):DataSource { + private override function set_dataSource(value:DataSource):DataSource { _dataSource = value; for (i in 0..._dataSource.size) { var item:Dynamic = _dataSource.get(i); From 4406a44d857cf77c266ff9b8bda3e92ce6c89736 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Wed, 13 Mar 2024 20:37:41 -0400 Subject: [PATCH 069/120] Fix child components being added to `Screen.instance.rootComponents` --- haxe/ui/backend/ScreenImpl.hx | 50 +++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 391e83f..81369e9 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -88,18 +88,20 @@ class ScreenImpl extends ScreenBase { } private function onMemberAdded(m:FlxBasic) { - if ((m is Component) && rootComponents.indexOf(cast(m, Component)) == -1) { - var c = cast(m, Component); - if (c.percentWidth > 0) { - c.width = (this.width * c.percentWidth) / 100; - } - if (c.percentHeight > 0) { - c.height = (this.height * c.percentHeight) / 100; + if ((m is Component)) { + if (rootComponents.indexOf(cast(m, Component)) == -1) { + var c = cast(m, Component); + if (c.percentWidth > 0) { + c.width = (this.width * c.percentWidth) / 100; + } + if (c.percentHeight > 0) { + c.height = (this.height * c.percentHeight) / 100; + } + c.state = StateHelper.currentState; + rootComponents.push(c); + c.recursiveReady(); + c.syncComponentValidation(); } - c.state = StateHelper.currentState; - rootComponents.push(c); - c.recursiveReady(); - c.syncComponentValidation(); } else if ((m is FlxTypedGroup)) { var group:FlxTypedGroup = cast m; checkMembers(group); @@ -120,19 +122,21 @@ class ScreenImpl extends ScreenBase { var found = false; // we only want top level components for (m in state.members) { - if ((m is Component) && rootComponents.indexOf(cast(m, Component)) == -1) { - var c = cast(m, Component); - if (c.percentWidth > 0) { - c.width = (this.width * c.percentWidth) / 100; - } - if (c.percentHeight > 0) { - c.height = (this.height * c.percentHeight) / 100; + if ((m is Component)) { + if (rootComponents.indexOf(cast(m, Component)) == -1) { + var c = cast(m, Component); + if (c.percentWidth > 0) { + c.width = (this.width * c.percentWidth) / 100; + } + if (c.percentHeight > 0) { + c.height = (this.height * c.percentHeight) / 100; + } + c.state = StateHelper.currentState; + rootComponents.push(c); + c.recursiveReady(); + c.syncComponentValidation(); + found = true; } - c.state = StateHelper.currentState; - rootComponents.push(c); - c.recursiveReady(); - c.syncComponentValidation(); - found = true; } else if ((m is FlxTypedGroup)) { var group:FlxTypedGroup = cast m; group.memberAdded.addOnce(onMemberAdded); From 0e7faae41ed889111d9701be3a0c589b318e9b57 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sat, 30 Mar 2024 15:59:43 -0400 Subject: [PATCH 070/120] `onMemberAdded` and `checkMembers` now use `addComponent` - `addComponent` now set the component's state and call `syncComponentValidation` for consistency --- haxe/ui/backend/ScreenImpl.hx | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 81369e9..0b07c04 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -89,18 +89,9 @@ class ScreenImpl extends ScreenBase { private function onMemberAdded(m:FlxBasic) { if ((m is Component)) { - if (rootComponents.indexOf(cast(m, Component)) == -1) { - var c = cast(m, Component); - if (c.percentWidth > 0) { - c.width = (this.width * c.percentWidth) / 100; - } - if (c.percentHeight > 0) { - c.height = (this.height * c.percentHeight) / 100; - } - c.state = StateHelper.currentState; - rootComponents.push(c); - c.recursiveReady(); - c.syncComponentValidation(); + var c = cast(m, Component); + if (rootComponents.indexOf(c) == -1) { + addComponent(c); } } else if ((m is FlxTypedGroup)) { var group:FlxTypedGroup = cast m; @@ -123,18 +114,9 @@ class ScreenImpl extends ScreenBase { var found = false; // we only want top level components for (m in state.members) { if ((m is Component)) { - if (rootComponents.indexOf(cast(m, Component)) == -1) { - var c = cast(m, Component); - if (c.percentWidth > 0) { - c.width = (this.width * c.percentWidth) / 100; - } - if (c.percentHeight > 0) { - c.height = (this.height * c.percentHeight) / 100; - } - c.state = StateHelper.currentState; - rootComponents.push(c); - c.recursiveReady(); - c.syncComponentValidation(); + var c = cast(m, Component); + if (rootComponents.indexOf(c) == -1) { + addComponent(c); found = true; } } else if ((m is FlxTypedGroup)) { @@ -220,10 +202,12 @@ class ScreenImpl extends ScreenBase { if (StateHelper.currentState.exists == true) { StateHelper.currentState.add(component); + component.state = StateHelper.currentState; if (rootComponents.indexOf(component) == -1) { rootComponents.push(component); } component.recursiveReady(); + component.syncComponentValidation(); onContainerResize(); component.applyAddInternal(); checkResetCursor(); From 60c6fd05653d1682a319f35c0da092fd99b4c7ff Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sat, 30 Mar 2024 16:24:04 -0400 Subject: [PATCH 071/120] Resize component before calling `recursiveReady` --- haxe/ui/backend/ScreenImpl.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 0b07c04..7bcfd0c 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -206,9 +206,9 @@ class ScreenImpl extends ScreenBase { if (rootComponents.indexOf(component) == -1) { rootComponents.push(component); } + onContainerResize(); component.recursiveReady(); component.syncComponentValidation(); - onContainerResize(); component.applyAddInternal(); checkResetCursor(); } From 627a260542f0257c37c355f616e2fbefb81f16dd Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Sat, 6 Apr 2024 13:15:05 +0200 Subject: [PATCH 072/120] uses structInit classes rather than typedefs --- haxe/ui/backend/flixel/KeyboardHelper.hx | 7 ++++--- haxe/ui/backend/flixel/MouseHelper.hx | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/haxe/ui/backend/flixel/KeyboardHelper.hx b/haxe/ui/backend/flixel/KeyboardHelper.hx index 4c3c42e..889b220 100644 --- a/haxe/ui/backend/flixel/KeyboardHelper.hx +++ b/haxe/ui/backend/flixel/KeyboardHelper.hx @@ -5,9 +5,10 @@ import haxe.ui.core.Component; import haxe.ui.events.KeyboardEvent; import haxe.ui.focus.FocusManager; -typedef KeyboardCallback = { - var fn:KeyboardEvent->Void; - var priority:Int; +@:structInit +class KeyboardCallback { + public var fn:KeyboardEvent->Void; + public var priority:Int; } class KeyboardHelper { diff --git a/haxe/ui/backend/flixel/MouseHelper.hx b/haxe/ui/backend/flixel/MouseHelper.hx index b878f65..14e158e 100644 --- a/haxe/ui/backend/flixel/MouseHelper.hx +++ b/haxe/ui/backend/flixel/MouseHelper.hx @@ -6,9 +6,10 @@ import haxe.ui.core.Platform; import haxe.ui.core.Screen; import haxe.ui.events.MouseEvent; -typedef MouseCallback = { - var fn:MouseEvent->Void; - var priority:Int; +@:structInit +class MouseCallback { + public var fn:MouseEvent->Void; + public var priority:Int; } class MouseHelper { From 06b7cb7d745be97760f1a24b09a2e78e635fcdd1 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Sat, 6 Apr 2024 13:15:19 +0200 Subject: [PATCH 073/120] UIFragments should scroll by default --- haxe/ui/backend/flixel/UIRuntimeFragment.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/haxe/ui/backend/flixel/UIRuntimeFragment.hx b/haxe/ui/backend/flixel/UIRuntimeFragment.hx index 21dbef2..50e62b8 100644 --- a/haxe/ui/backend/flixel/UIRuntimeFragment.hx +++ b/haxe/ui/backend/flixel/UIRuntimeFragment.hx @@ -15,6 +15,8 @@ class UIRuntimeFragment extends UIFragmentBase implements IComponentDelegate { / public function new() { super(); + scrollFactor.set(0, 0); // ui doesn't scroll by default + var rtti = haxe.rtti.Rtti.getRtti(Type.getClass(this)); root = buildViaRTTI(rtti); linkViaRTTI(rtti, this, root); From 328b382a003eabfd6cda215210a0def4df0315f2 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Sun, 7 Apr 2024 19:30:28 +0200 Subject: [PATCH 074/120] haxelib --- haxelib.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/haxelib.json b/haxelib.json index d3d1f90..b7fc9d9 100644 --- a/haxelib.json +++ b/haxelib.json @@ -1,21 +1,21 @@ { + "version": "1.7.0", "contributors": [ "haxeui", "MSGhero", "ianharrigan" ], - "version": "1.6.0", - "releasenote": "1.6.0 release", + "dependencies": { + "haxeui-core": "", + "flixel": "" + }, + "license": "MIT", "tags": [ "ui", "gui", "flixel" ], - "license": "MIT", - "dependencies": { - "flixel": "", - "haxeui-core": "" - }, + "releasenote": "1.7.0 release", "name": "haxeui-flixel", "description": "The Flixel backend of the HaxeUI framework", "url": "https://github.com/haxeui/haxeui-flixel" From 479dbb1416329e922a0b68b9b631e722120435dc Mon Sep 17 00:00:00 2001 From: Sword <99792114+Sword352@users.noreply.github.com> Date: Mon, 8 Apr 2024 12:46:36 +0200 Subject: [PATCH 075/120] Destroy `UIRuntimeFragment` entirely --- haxe/ui/backend/flixel/UIRuntimeFragment.hx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/haxe/ui/backend/flixel/UIRuntimeFragment.hx b/haxe/ui/backend/flixel/UIRuntimeFragment.hx index 50e62b8..6e23892 100644 --- a/haxe/ui/backend/flixel/UIRuntimeFragment.hx +++ b/haxe/ui/backend/flixel/UIRuntimeFragment.hx @@ -124,9 +124,7 @@ class UIRuntimeFragment extends UIFragmentBase implements IComponentDelegate { / } public override function destroy() { - if (root != null) { - remove(root); - } + super.destroy(); root = null; } -} \ No newline at end of file +} From f3397d45872a15f32632f4805faa0cf7c6d55697 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Fri, 12 Apr 2024 20:22:37 -0400 Subject: [PATCH 076/120] `currentWorldX` and `currentWorldY` are now adjusted with `Toolkit.scale` by default --- haxe/ui/backend/flixel/MouseHelper.hx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/haxe/ui/backend/flixel/MouseHelper.hx b/haxe/ui/backend/flixel/MouseHelper.hx index 14e158e..b9882af 100644 --- a/haxe/ui/backend/flixel/MouseHelper.hx +++ b/haxe/ui/backend/flixel/MouseHelper.hx @@ -119,11 +119,11 @@ class MouseHelper { private static function onMouse(type:String, x:Float, y:Float, buttonDown:Bool = false, ctrlKey:Bool = false, shiftKey:Bool = false) { if (currentMouseX != x) { currentMouseX = x; - currentWorldX = (currentMouseX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom()); + currentWorldX = ((currentMouseX - FlxG.scaleMode.offset.x) / (FlxG.scaleMode.scale.x * initialZoom())) / Toolkit.scaleX; } if (currentMouseY != y) { currentMouseY = y; - currentWorldY = (currentMouseY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom()); + currentWorldY = ((currentMouseY - FlxG.scaleMode.offset.y) / (FlxG.scaleMode.scale.y * initialZoom())) / Toolkit.scaleY; } var target:Dynamic = getTarget(currentWorldX, currentWorldY); @@ -232,8 +232,8 @@ class MouseHelper { private static function createEvent(type:String, buttonDown:Bool, ctrlKey:Bool, shiftKey:Bool):MouseEvent { var event = new MouseEvent(type); - event.screenX = currentWorldX / Toolkit.scaleX; - event.screenY = currentWorldY / Toolkit.scaleY; + event.screenX = currentWorldX; + event.screenY = currentWorldY; event.buttonDown = buttonDown; event.touchEvent = Platform.instance.isMobile; event.ctrlKey = ctrlKey; From cdf4a4d14d999c6efb978b1b1efe19263aeb7747 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Fri, 12 Apr 2024 20:48:16 -0400 Subject: [PATCH 077/120] Mouse out/over events are now dispatched before mouse move (consistent with haxeui-html5) --- haxe/ui/backend/flixel/MouseHelper.hx | 34 +++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/haxe/ui/backend/flixel/MouseHelper.hx b/haxe/ui/backend/flixel/MouseHelper.hx index b9882af..300901e 100644 --- a/haxe/ui/backend/flixel/MouseHelper.hx +++ b/haxe/ui/backend/flixel/MouseHelper.hx @@ -128,6 +128,23 @@ class MouseHelper { var target:Dynamic = getTarget(currentWorldX, currentWorldY); + if (target != _mouseOverTarget) { + if (_mouseOverTarget != null) { + if ((_mouseOverTarget is Component)) { + Screen.instance.setCursor("default"); + } + dispatchEventType(MouseEvent.MOUSE_OUT, buttonDown, ctrlKey, shiftKey, _mouseOverTarget); + } + if ((target is Component)) { + var c:Component = target; + if (c.style != null && c.style.cursor != null) { + Screen.instance.setCursor(c.style.cursor, c.style.cursorOffsetX, c.style.cursorOffsetY); + } + } + dispatchEventType(MouseEvent.MOUSE_OVER, buttonDown, ctrlKey, shiftKey, target); + _mouseOverTarget = target; + } + var clickType:String = null; switch (type) { case MouseEvent.MOUSE_DOWN: @@ -175,23 +192,6 @@ class MouseHelper { } } } - - if (target != _mouseOverTarget) { - if (_mouseOverTarget != null) { - if ((_mouseOverTarget is Component)) { - Screen.instance.setCursor("default"); - } - dispatchEventType(MouseEvent.MOUSE_OUT, buttonDown, ctrlKey, shiftKey, _mouseOverTarget); - } - if ((target is Component)) { - var c:Component = target; - if (c.style != null && c.style.cursor != null) { - Screen.instance.setCursor(c.style.cursor, c.style.cursorOffsetX, c.style.cursorOffsetY); - } - } - dispatchEventType(MouseEvent.MOUSE_OVER, buttonDown, ctrlKey, shiftKey, target); - _mouseOverTarget = target; - } } private static function dispatchEventType(type:String, buttonDown:Bool, ctrlKey:Bool, shiftKey:Bool, target:Dynamic) { From 32cac68d992f1e74643188d0cb96b8ba41643469 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sat, 13 Apr 2024 00:13:35 -0400 Subject: [PATCH 078/120] Rewrote `getTarget()` to hopefully be more efficient --- haxe/ui/backend/flixel/MouseHelper.hx | 40 +++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/haxe/ui/backend/flixel/MouseHelper.hx b/haxe/ui/backend/flixel/MouseHelper.hx index 300901e..0426a38 100644 --- a/haxe/ui/backend/flixel/MouseHelper.hx +++ b/haxe/ui/backend/flixel/MouseHelper.hx @@ -242,13 +242,41 @@ class MouseHelper { } private static function getTarget(x:Float, y:Float):Dynamic { - var target:Dynamic = null; - var components = Screen.instance.findComponentsUnderPoint(x, y); - if (components.length > 0 && components[components.length - 1].state == StateHelper.currentState) { - target = components[components.length - 1]; + if (Screen.instance.rootComponents.length == 0) { + return Screen.instance; } - if (target == null) target = Screen.instance; - return target; + + var i = Screen.instance.rootComponents.length - 1; + while (i >= 0) { + var c = findDeepestComponentUnderPoint(Screen.instance.rootComponents[i], x, y); + if (c != null) { + return c; + } + --i; + } + + return Screen.instance; + } + + private static function findDeepestComponentUnderPoint(c:Component, x:Float, y:Float):Null + { + if (c.state != StateHelper.currentState) { + return null; + } + + var hit = c.hitTest(x, y); + if (c.childComponents.length > 0 && hit) { + var i = c.childComponents.length - 1; + while (i >= 0) { + var ret = findDeepestComponentUnderPoint(c.childComponents[i], x, y); + if (ret != null) { + return ret; + } + --i; + } + } + + return hit ? c : null; } private static inline function initialZoom():Float { From 1851cbc30779e7f5da7ebda9dde90f03cef9108c Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sat, 13 Apr 2024 11:24:09 -0400 Subject: [PATCH 079/120] Fixed cursor changing to default when hovering over a child of a component with a custom cursor - `ScreenImpl.checkResetCursor` now iterates backwards through the components (so deeper ones will get checked first) --- haxe/ui/backend/ScreenImpl.hx | 2 ++ haxe/ui/backend/flixel/MouseHelper.hx | 10 +--------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 7bcfd0c..ca6e8dc 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -378,6 +378,7 @@ class ScreenImpl extends ScreenBase { return false; } + @:allow(haxe.ui.backend.flixel.MouseHelper) private function checkResetCursor(x:Null = null, y:Null = null) { if (x == null) { x = MouseHelper.currentMouseX; @@ -386,6 +387,7 @@ class ScreenImpl extends ScreenBase { y = MouseHelper.currentMouseY; } var components = Screen.instance.findComponentsUnderPoint(x, y); + components.reverse(); var desiredCursor = "default"; var desiredCursorOffsetX:Null = null; var desiredCursorOffsetY:Null = null; diff --git a/haxe/ui/backend/flixel/MouseHelper.hx b/haxe/ui/backend/flixel/MouseHelper.hx index 0426a38..1f45ef5 100644 --- a/haxe/ui/backend/flixel/MouseHelper.hx +++ b/haxe/ui/backend/flixel/MouseHelper.hx @@ -129,18 +129,10 @@ class MouseHelper { var target:Dynamic = getTarget(currentWorldX, currentWorldY); if (target != _mouseOverTarget) { + Screen.instance.checkResetCursor(); if (_mouseOverTarget != null) { - if ((_mouseOverTarget is Component)) { - Screen.instance.setCursor("default"); - } dispatchEventType(MouseEvent.MOUSE_OUT, buttonDown, ctrlKey, shiftKey, _mouseOverTarget); } - if ((target is Component)) { - var c:Component = target; - if (c.style != null && c.style.cursor != null) { - Screen.instance.setCursor(c.style.cursor, c.style.cursorOffsetX, c.style.cursorOffsetY); - } - } dispatchEventType(MouseEvent.MOUSE_OVER, buttonDown, ctrlKey, shiftKey, target); _mouseOverTarget = target; } From daf2e3abbe9839289e90ba2310d15fdcc281599b Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sat, 13 Apr 2024 11:29:47 -0400 Subject: [PATCH 080/120] Fix `checkResetCursor()` not working properly with modified `Toolkit.scale` --- haxe/ui/backend/ScreenImpl.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index ca6e8dc..32c25bd 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -381,10 +381,10 @@ class ScreenImpl extends ScreenBase { @:allow(haxe.ui.backend.flixel.MouseHelper) private function checkResetCursor(x:Null = null, y:Null = null) { if (x == null) { - x = MouseHelper.currentMouseX; + x = MouseHelper.currentWorldX; } if (y == null) { - y = MouseHelper.currentMouseY; + y = MouseHelper.currentWorldY; } var components = Screen.instance.findComponentsUnderPoint(x, y); components.reverse(); From 88a82afc77a981222304e4573189e3c01c28b487 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sat, 13 Apr 2024 11:51:47 -0400 Subject: [PATCH 081/120] Revert `getTarget()` rewrite, but still clean it up a bit, and allow it to return another component if the top one is in a different state --- haxe/ui/backend/flixel/MouseHelper.hx | 35 +++------------------------ 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/haxe/ui/backend/flixel/MouseHelper.hx b/haxe/ui/backend/flixel/MouseHelper.hx index 1f45ef5..ea17f1d 100644 --- a/haxe/ui/backend/flixel/MouseHelper.hx +++ b/haxe/ui/backend/flixel/MouseHelper.hx @@ -234,42 +234,15 @@ class MouseHelper { } private static function getTarget(x:Float, y:Float):Dynamic { - if (Screen.instance.rootComponents.length == 0) { - return Screen.instance; - } - - var i = Screen.instance.rootComponents.length - 1; - while (i >= 0) { - var c = findDeepestComponentUnderPoint(Screen.instance.rootComponents[i], x, y); - if (c != null) { + var components = Screen.instance.findComponentsUnderPoint(x, y); + components.reverse(); + for (c in components) { + if (c.state == StateHelper.currentState) { return c; } - --i; } - return Screen.instance; } - - private static function findDeepestComponentUnderPoint(c:Component, x:Float, y:Float):Null - { - if (c.state != StateHelper.currentState) { - return null; - } - - var hit = c.hitTest(x, y); - if (c.childComponents.length > 0 && hit) { - var i = c.childComponents.length - 1; - while (i >= 0) { - var ret = findDeepestComponentUnderPoint(c.childComponents[i], x, y); - if (ret != null) { - return ret; - } - --i; - } - } - - return hit ? c : null; - } private static inline function initialZoom():Float { #if (flixel <= "4.11.0") // FlxG.initialZoom removed in later versions of flixel From 57391a34308c35309a61ec1c6ff99ddcf81c7ae5 Mon Sep 17 00:00:00 2001 From: Sword <99792114+Sword352@users.noreply.github.com> Date: Wed, 24 Apr 2024 12:45:02 +0200 Subject: [PATCH 082/120] Fix `onReady` callback in `UISubState` --- haxe/ui/backend/flixel/UISubState.hx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/haxe/ui/backend/flixel/UISubState.hx b/haxe/ui/backend/flixel/UISubState.hx index a2b3b3a..38e76d4 100644 --- a/haxe/ui/backend/flixel/UISubState.hx +++ b/haxe/ui/backend/flixel/UISubState.hx @@ -3,6 +3,7 @@ package haxe.ui.backend.flixel; import haxe.ui.layouts.LayoutFactory; import haxe.ui.containers.Box; import haxe.ui.core.Component; +import haxe.ui.events.UIEvent; @:autoBuild(haxe.ui.macros.Macros.buildBehaviours()) @:autoBuild(haxe.ui.macros.Macros.build()) @@ -25,7 +26,7 @@ class UISubState extends UISubStateBase { // must use -D haxeui_dont_impose_base public override function create() { super.create(); - + root.registerEvent(UIEvent.READY, (_) -> onReady()); add(root); } @@ -96,4 +97,4 @@ class UISubState extends UISubStateBase { // must use -D haxeui_dont_impose_base root.hide(); } -} \ No newline at end of file +} From 4cd9fbe6ad0d2bf8d47c119720f7b15cdfe17bb3 Mon Sep 17 00:00:00 2001 From: Sword <99792114+Sword352@users.noreply.github.com> Date: Wed, 24 Apr 2024 12:45:52 +0200 Subject: [PATCH 083/120] Fix `onReady` in `UIState` (untested) --- haxe/ui/backend/flixel/UIState.hx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/haxe/ui/backend/flixel/UIState.hx b/haxe/ui/backend/flixel/UIState.hx index b82c9e0..1ac7596 100644 --- a/haxe/ui/backend/flixel/UIState.hx +++ b/haxe/ui/backend/flixel/UIState.hx @@ -3,6 +3,7 @@ package haxe.ui.backend.flixel; import haxe.ui.layouts.LayoutFactory; import haxe.ui.containers.Box; import haxe.ui.core.Component; +import haxe.ui.events.UIEvent; @:autoBuild(haxe.ui.macros.Macros.buildBehaviours()) @:autoBuild(haxe.ui.macros.Macros.build()) @@ -25,7 +26,7 @@ class UIState extends UIStateBase { // must use -D haxeui_dont_impose_base_class public override function create() { super.create(); - + root.registerEvent(UIEvent.READY, (_) -> onReady()); add(root); } @@ -95,4 +96,4 @@ class UIState extends UIStateBase { // must use -D haxeui_dont_impose_base_class public function hide() { root.hide(); } -} \ No newline at end of file +} From 47c3fc905739ac2002f158cb1284dca5965294c0 Mon Sep 17 00:00:00 2001 From: Sword <99792114+Sword352@users.noreply.github.com> Date: Thu, 25 Apr 2024 07:28:41 +0200 Subject: [PATCH 084/120] Remove lambda in `UIState` --- haxe/ui/backend/flixel/UIState.hx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/haxe/ui/backend/flixel/UIState.hx b/haxe/ui/backend/flixel/UIState.hx index 1ac7596..bdc9a73 100644 --- a/haxe/ui/backend/flixel/UIState.hx +++ b/haxe/ui/backend/flixel/UIState.hx @@ -26,7 +26,9 @@ class UIState extends UIStateBase { // must use -D haxeui_dont_impose_base_class public override function create() { super.create(); - root.registerEvent(UIEvent.READY, (_) -> onReady()); + root.registerEvent(UIEvent.READY, (_) -> { + onReady(); + }); add(root); } From 89dafd2b166b4c363b6d772fe50b6c48265d5396 Mon Sep 17 00:00:00 2001 From: Sword <99792114+Sword352@users.noreply.github.com> Date: Thu, 25 Apr 2024 07:29:47 +0200 Subject: [PATCH 085/120] Remove lambda in `UISubState` --- haxe/ui/backend/flixel/UISubState.hx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/haxe/ui/backend/flixel/UISubState.hx b/haxe/ui/backend/flixel/UISubState.hx index 38e76d4..e61a245 100644 --- a/haxe/ui/backend/flixel/UISubState.hx +++ b/haxe/ui/backend/flixel/UISubState.hx @@ -26,7 +26,9 @@ class UISubState extends UISubStateBase { // must use -D haxeui_dont_impose_base public override function create() { super.create(); - root.registerEvent(UIEvent.READY, (_) -> onReady()); + root.registerEvent(UIEvent.READY, (_) -> { + onReady(); + }); add(root); } From 5845351b0427e9134a2d5f579dff6471aa4ba6e0 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sun, 28 Apr 2024 18:47:13 -0400 Subject: [PATCH 086/120] Minor fixes - Fixed crash when a canvas gets resized to be smaller - Components now set their own `_state` to null instead of their parents' when destroyed - Components passing their opacity onto their children will take the child's opacity into account - `ComponentImpl.set_x()` and `set_y()` will no longer change `left` or `top` if the component isn't ready yet - Fixed `ScreenImpl.handleSetComponentIndex()` using a wrong offset - Fixed `ScreenImpl.handleSetComponentIndex()` not removing the object entirely before inserting it again - Prevent `Screen.addComponent()` from being called twice when using it directly, due to the `FlxG.state.memberAdded` listener - Fixed incorrect frame size warning when resizing a text field to 0 --- haxe/ui/backend/ComponentGraphicsImpl.hx | 5 +++++ haxe/ui/backend/ComponentImpl.hx | 12 ++++++++---- haxe/ui/backend/ScreenImpl.hx | 19 +++++++++++++------ haxe/ui/backend/TextDisplayImpl.hx | 6 ++++-- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/haxe/ui/backend/ComponentGraphicsImpl.hx b/haxe/ui/backend/ComponentGraphicsImpl.hx index 3a96566..ad62857 100644 --- a/haxe/ui/backend/ComponentGraphicsImpl.hx +++ b/haxe/ui/backend/ComponentGraphicsImpl.hx @@ -20,6 +20,11 @@ class ComponentGraphicsImpl extends ComponentGraphicsBase { var w = Std.int(_component.width); var h = Std.int(_component.height); + if (bitmapData != null && (bitmapData.width != w || bitmapData.height != h)) { + bitmapData.dispose(); + bitmapData = null; + } + if (bitmapData == null) { bitmapData = new BitmapData(w, h, true, 0x00000000); } diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 47390b3..adda721 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -396,7 +396,11 @@ class ComponentImpl extends ComponentBase { getImageDisplay().alpha = value; } for (c in childComponents) { - c.applyAlpha(value); + if (c.style != null && c.style.opacity != null) { + c.applyAlpha(c.style.opacity * value); + } else { + c.applyAlpha(value); + } } } @@ -869,7 +873,7 @@ class ComponentImpl extends ComponentBase { _unsolicitedMembers = null; } - this.state = null; + _state = null; _destroy = false; _destroyed = true; super.destroy(); @@ -890,7 +894,7 @@ class ComponentImpl extends ComponentBase { private override function set_x(value:Float):Float { var r = super.set_x(value); - if (this.parentComponent == null) { + if (this.parentComponent == null && this.isReady) { this.left = value; } return r; @@ -898,7 +902,7 @@ class ComponentImpl extends ComponentBase { private override function set_y(value:Float):Float { var r = super.set_y(value); - if (this.parentComponent == null) { + if (this.parentComponent == null && this.isReady) { this.top = value; } return r; diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 32c25bd..8ddbb87 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -193,6 +193,10 @@ class ScreenImpl extends ScreenBase { } public override function addComponent(component:Component):Component { + if (rootComponents.contains(component) && StateHelper.currentState.members.contains(component)) { + return component; + } + if (rootComponents.length > 0) { var cameras = StateHelper.findCameras(rootComponents[0]); if (cameras != null) { @@ -201,11 +205,11 @@ class ScreenImpl extends ScreenBase { } if (StateHelper.currentState.exists == true) { - StateHelper.currentState.add(component); - component.state = StateHelper.currentState; if (rootComponents.indexOf(component) == -1) { rootComponents.push(component); } + StateHelper.currentState.add(component); + component.state = StateHelper.currentState; onContainerResize(); component.recursiveReady(); component.syncComponentValidation(); @@ -265,11 +269,14 @@ class ScreenImpl extends ScreenBase { private override function handleSetComponentIndex(child:Component, index:Int) { var offset = 0; - StateHelper.currentState.forEach((item) -> { - offset++; - }); + for (i in 0...StateHelper.currentState.length) { + if ((StateHelper.currentState.members[i] is Component)) { + offset = i; + break; + } + } - StateHelper.currentState.remove(child); + StateHelper.currentState.remove(child, true); StateHelper.currentState.insert(index + offset, child); } diff --git a/haxe/ui/backend/TextDisplayImpl.hx b/haxe/ui/backend/TextDisplayImpl.hx index df4d101..badcf12 100644 --- a/haxe/ui/backend/TextDisplayImpl.hx +++ b/haxe/ui/backend/TextDisplayImpl.hx @@ -82,10 +82,12 @@ class TextDisplayImpl extends TextBase { private override function validateDisplay() { if (tf.textField.width != _width) { - tf.textField.width = _width * Toolkit.scaleX; + var width = _width * Toolkit.scaleX; + tf.textField.width = (width >= 1 ? width : 1); } if (tf.textField.height != _height) { - tf.textField.height = _height * Toolkit.scaleY; + var height = _height * Toolkit.scaleY; + tf.textField.height = (height >= 1 ? height : 1); } } From 255e0f8a220aa7ff99a9da235b697b3cf3c3aae5 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Fri, 3 May 2024 09:11:07 +0200 Subject: [PATCH 087/120] use macos-13 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d7bfc55..3a36432 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest, macos-13, windows-latest] haxe-version: [4.2.5, 4.3.0, 4.3.1] target: [html5, linux, windows, mac] exclude: From 03d5440ca332274a1d85bf902ac9630cc72a00ef Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Fri, 3 May 2024 09:20:54 +0200 Subject: [PATCH 088/120] use mac os 13 --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3a36432..c6e10df 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,9 +20,9 @@ jobs: target: linux - os: windows-latest target: mac - - os: macos-latest + - os: macos-13 target: linux - - os: macos-latest + - os: macos-13 target: windows From c60f7177658bf801021741d1b4723ecf1dd40356 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sat, 4 May 2024 17:28:09 -0400 Subject: [PATCH 089/120] Reduce update & draw calls - All sprites except text inputs are now always inactive, skipping their update calls - `ComponentImpl._surface` will be invisible if the style doesn't have anything to display, skipping a draw call - `ComponentGraphicsImpl.sprite` will be invisible if the width or height are 0 - `FlxTextInput.visible` now also changes the `active` property to prevent unnecessary update calls - `ComponentImpl.applyVisibility()` is now called properly to prevent unnecessary text input update calls --- haxe/ui/backend/ComponentGraphicsImpl.hx | 6 ++- haxe/ui/backend/ComponentImpl.hx | 10 ++-- haxe/ui/backend/ImageDisplayImpl.hx | 1 + haxe/ui/backend/TextDisplayImpl.hx | 1 + haxe/ui/backend/flixel/FlxStyleHelper.hx | 46 +++++++++++++++++-- haxe/ui/backend/flixel/OpenFLStyleHelper.hx | 16 ++++++- .../backend/flixel/textinputs/FlxTextInput.hx | 2 +- 7 files changed, 67 insertions(+), 15 deletions(-) diff --git a/haxe/ui/backend/ComponentGraphicsImpl.hx b/haxe/ui/backend/ComponentGraphicsImpl.hx index ad62857..a5ba3d2 100644 --- a/haxe/ui/backend/ComponentGraphicsImpl.hx +++ b/haxe/ui/backend/ComponentGraphicsImpl.hx @@ -48,15 +48,17 @@ class ComponentGraphicsImpl extends ComponentGraphicsBase { var byteArray = ByteArray.fromBytes(newPixels); bitmapData.setPixels(new Rectangle(0, 0, bitmapData.width, bitmapData.height), byteArray); - if (this.sprite == null) { + if (sprite == null) { sprite = new FlxSprite(0, 0); + sprite.active = false; _component.add(sprite); } sprite.width = w; sprite.height = h; - this.sprite.pixels = bitmapData; + sprite.pixels = bitmapData; + sprite.visible = (w > 0 && h > 0); } public override function resize(width:Null, height:Null) { diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index adda721..f98f393 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -48,7 +48,8 @@ class ComponentImpl extends ComponentBase { _surface = new FlxSprite(); _surface.makeGraphic(1, 1, 0x0, true); _surface.pixelPerfectRender = true; - _surface.moves = false; + _surface.active = false; + _surface.visible = false; add(_surface); //recursiveReady(); @@ -228,6 +229,7 @@ class ComponentImpl extends ComponentBase { if (w <= 0 || h <= 0) { _surface.graphic.destroy(); _surface.makeGraphic(1, 1, 0x0, true); + _surface.visible = false; } else { _surface.graphic.destroy(); _surface.makeGraphic(w, h, 0x0, true); @@ -357,9 +359,7 @@ class ComponentImpl extends ComponentBase { } for (c in this.childComponents) { - if (!c.hidden) { - c.applyVisibility(show); - } + c.applyVisibility(show && !c.hidden); } } @@ -380,7 +380,7 @@ class ComponentImpl extends ComponentBase { } */ - FlxStyleHelper.applyStyle(_surface, style); + _surface.visible = FlxStyleHelper.applyStyle(_surface, style); applyFilters(style); } diff --git a/haxe/ui/backend/ImageDisplayImpl.hx b/haxe/ui/backend/ImageDisplayImpl.hx index 5fbc096..5092a3e 100644 --- a/haxe/ui/backend/ImageDisplayImpl.hx +++ b/haxe/ui/backend/ImageDisplayImpl.hx @@ -7,6 +7,7 @@ class ImageDisplayImpl extends ImageBase { public function new() { super(); this.pixelPerfectRender = true; + this.active = false; } private override function validateData():Void { diff --git a/haxe/ui/backend/TextDisplayImpl.hx b/haxe/ui/backend/TextDisplayImpl.hx index badcf12..6e7e700 100644 --- a/haxe/ui/backend/TextDisplayImpl.hx +++ b/haxe/ui/backend/TextDisplayImpl.hx @@ -14,6 +14,7 @@ class TextDisplayImpl extends TextBase { tf = new FlxText(); tf.pixelPerfectRender = true; tf.autoSize = true; + tf.active = false; } private override function validateData() { diff --git a/haxe/ui/backend/flixel/FlxStyleHelper.hx b/haxe/ui/backend/flixel/FlxStyleHelper.hx index 07b329d..cd7dcf9 100644 --- a/haxe/ui/backend/flixel/FlxStyleHelper.hx +++ b/haxe/ui/backend/flixel/FlxStyleHelper.hx @@ -15,9 +15,9 @@ import openfl.geom.Point; import openfl.geom.Rectangle; class FlxStyleHelper { - public static function applyStyle(sprite:FlxSprite, style:Style) { + public static function applyStyle(sprite:FlxSprite, style:Style):Bool { if (sprite == null || sprite.pixels == null) { - return; + return false; } var pixels:BitmapData = sprite.pixels; @@ -28,7 +28,7 @@ class FlxStyleHelper { var height:Float = sprite.frameHeight; if (width <= 0 || height <= 0) { - return; + return false; } var rc:Rectangle = new Rectangle(top, left, width, height); @@ -49,12 +49,14 @@ class FlxStyleHelper { if (useOpenFLDrawing) { var g = FlxSpriteUtil.flashGfx; - OpenFLStyleHelper.paintStyleSection(g, style, width, height, left, top); + var painted = OpenFLStyleHelper.paintStyleSection(g, style, width, height, left, top); FlxSpriteUtil.updateSpriteGraphic(sprite); - return; + return painted; } #end + var painted = false; + if (style.borderLeftSize != null && style.borderLeftSize != 0 && style.borderLeftSize == style.borderRightSize && style.borderLeftSize == style.borderBottomSize @@ -73,6 +75,8 @@ class FlxStyleHelper { pixels.fillRect(new Rectangle(rc.left, rc.height - borderSize, rc.width, borderSize), color); // bottom pixels.fillRect(new Rectangle(rc.left, rc.top + borderSize, borderSize, rc.height - (borderSize * 2)), color); // left rc.inflate(-borderSize, -borderSize); + + painted = true; } else { // compound border var org = rc.clone(); @@ -95,6 +99,10 @@ class FlxStyleHelper { var color:FlxColor = Std.int(opacity * 0xFF) << 24 | style.borderTopColor; pixels.fillRect(new Rectangle(rc.left + borderLeftSize, rc.top, org.width - (borderLeftSize + borderRightSize), borderSize), color); // top rc.top += borderSize; + + if (opacity > 0) { + painted = true; + } } if (style.borderBottomSize != null && style.borderBottomSize > 0) { @@ -103,6 +111,10 @@ class FlxStyleHelper { var color:FlxColor = Std.int(opacity * 0xFF) << 24 | style.borderBottomColor; pixels.fillRect(new Rectangle(rc.left, org.height - borderSize, rc.width, borderSize), color); // bottom rc.bottom -= borderSize; + + if (opacity > 0) { + painted = true; + } } if (style.borderLeftSize != null && style.borderLeftSize > 0) { @@ -111,6 +123,10 @@ class FlxStyleHelper { var color:FlxColor = Std.int(opacity * 0xFF) << 24 | style.borderLeftColor; pixels.fillRect(new Rectangle(rc.left, rc.top - borderTopSize, borderSize, org.height - rc.top + borderTopSize), color); // left rc.left += borderSize; + + if (opacity > 0) { + painted = true; + } } if (style.borderRightSize != null && style.borderRightSize > 0) { @@ -119,6 +135,10 @@ class FlxStyleHelper { var color:FlxColor = Std.int(opacity * 0xFF) << 24 | style.borderRightColor; pixels.fillRect(new Rectangle(org.width - borderSize, rc.top - borderTopSize, borderSize, org.height + borderTopSize), color); // right rc.right -= borderSize; + + if (opacity > 0) { + painted = true; + } } } @@ -141,6 +161,10 @@ class FlxStyleHelper { pixels.fillRect(rcLine, Std.int(opacity * 0xFF) << 24 | c); n++; } + + if (opacity > 0 && n > 0) { + painted = true; + } } else if (gradientType == "horizontal") { arr = ColorUtil.buildColorArray(style.backgroundColor, style.backgroundColorEnd, Std.int(rc.width)); for (c in arr) { @@ -148,10 +172,18 @@ class FlxStyleHelper { pixels.fillRect(rcLine, Std.int(opacity * 0xFF) << 24 | c); n++; } + + if (opacity > 0 && n > 0) { + painted = true; + } } } else { var color:FlxColor = Std.int(opacity * 0xFF) << 24 | style.backgroundColor; pixels.fillRect(rc, color); + + if (opacity > 0) { + painted = true; + } } } @@ -159,9 +191,13 @@ class FlxStyleHelper { Toolkit.assets.getImage(style.backgroundImage, function(info:ImageInfo) { if (info != null && info.data != null) { paintBackroundImage(sprite, info.data, style); + + painted = true; } }); } + + return painted; } private static function paintBackroundImage(sprite:FlxSprite, data:ImageData, style:Style) { diff --git a/haxe/ui/backend/flixel/OpenFLStyleHelper.hx b/haxe/ui/backend/flixel/OpenFLStyleHelper.hx index fcb3665..338dea8 100644 --- a/haxe/ui/backend/flixel/OpenFLStyleHelper.hx +++ b/haxe/ui/backend/flixel/OpenFLStyleHelper.hx @@ -12,13 +12,13 @@ class OpenFLStyleHelper { public function new() { } - public static function paintStyleSection(graphics:Graphics, style:Style, width:Float, height:Float, left:Float = 0, top:Float = 0, clear:Bool = true) { + public static function paintStyleSection(graphics:Graphics, style:Style, width:Float, height:Float, left:Float = 0, top:Float = 0, clear:Bool = true):Bool { if (clear == true) { graphics.clear(); } if (width <= 0 || height <= 0) { - return; + return false; } /* @@ -45,6 +45,8 @@ class OpenFLStyleHelper { borderRadius = style.borderRadius * Toolkit.scale; } + var painted = false; + if (style.borderLeftSize != null && style.borderLeftSize != 0 && style.borderLeftSize == style.borderRightSize && style.borderLeftSize == style.borderBottomSize @@ -61,6 +63,8 @@ class OpenFLStyleHelper { rc.bottom -= (style.borderLeftSize * Toolkit.scale) / 2; rc.right -= (style.borderLeftSize * Toolkit.scale) / 2; //rc.inflate( -(style.borderLeftSize / 2), -(style.borderLeftSize / 2)); + + painted = true; } else { // compound border if ((style.borderTopSize != null && style.borderTopSize > 0) || (style.borderBottomSize != null && style.borderBottomSize > 0) @@ -100,6 +104,8 @@ class OpenFLStyleHelper { rc.right -= (style.borderRightSize * Toolkit.scale); } + + painted = true; } } @@ -147,6 +153,10 @@ class OpenFLStyleHelper { } else { graphics.beginFill(backgroundColor, backgroundOpacity); } + + if (backgroundOpacity > 0) { + painted = true; + } } if (borderRadius == 0) { @@ -165,5 +175,7 @@ class OpenFLStyleHelper { } graphics.endFill(); + + return painted; } } \ No newline at end of file diff --git a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx index c420969..677a710 100644 --- a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx @@ -44,7 +44,7 @@ class FlxTextInput extends TextBase { return tf.visible; } private function set_visible(value:Bool):Bool { - tf.visible = value; + tf.active = tf.visible = value; // text input shouldn't be active if it's hidden return value; } From b9c66194665eeb7e98267479da35411b5d7e29e4 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Mon, 6 May 2024 17:12:10 -0400 Subject: [PATCH 090/120] Fix resized images not being clipped correctly - `width` and `height` are now set properly for resized image displays - Prevent unnecessary `origin` resets (only needed when the frames change) --- haxe/ui/backend/ImageDisplayImpl.hx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/haxe/ui/backend/ImageDisplayImpl.hx b/haxe/ui/backend/ImageDisplayImpl.hx index 5092a3e..c31ecec 100644 --- a/haxe/ui/backend/ImageDisplayImpl.hx +++ b/haxe/ui/backend/ImageDisplayImpl.hx @@ -1,6 +1,7 @@ package haxe.ui.backend; import flixel.graphics.frames.FlxImageFrame; +import flixel.math.FlxRect; import haxe.ui.Toolkit; class ImageDisplayImpl extends ImageBase { @@ -15,16 +16,25 @@ class ImageDisplayImpl extends ImageBase { frames = FlxImageFrame.fromFrame(_imageInfo.data); aspectRatio = _imageInfo.width / _imageInfo.height; - - width = frameWidth = Std.int(_imageInfo.width * Toolkit.scaleX); - height = frameHeight = Std.int(_imageInfo.height * Toolkit.scaleY); + + origin.set(0, 0); } } private override function validateDisplay() { var scaleX:Float = _imageWidth / (_imageInfo.width / Toolkit.scaleX); var scaleY:Float = _imageHeight / (_imageInfo.height / Toolkit.scaleY); - origin.set(0, 0); scale.set(scaleX, scaleY); + + width = Math.abs(scaleX) * frameWidth; + height = Math.abs(scaleY) * frameHeight; + } + + override function set_clipRect(rect:FlxRect):FlxRect { + if (rect != null) { + return super.set_clipRect(FlxRect.get(rect.x / scale.x, rect.y / scale.y, rect.width / scale.x, rect.height / scale.y)); + } else { + return super.set_clipRect(null); + } } } From 8505e2089c6657f84b484dac728fdd6767bfffed Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sat, 25 May 2024 21:39:16 -0400 Subject: [PATCH 091/120] Clipped components inside another clipped component will now display correctly - Root components with clipping will now display correctly --- haxe/ui/backend/ComponentImpl.hx | 61 ++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index f98f393..ee72b0d 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -782,7 +782,6 @@ class ComponentImpl extends ComponentBase { } clearCaches(); - applyClipRect(); repositionChildren(); _updates++; @@ -795,25 +794,57 @@ class ComponentImpl extends ComponentBase { } super.update(elapsed); + + // only the root component will start the applyClipRect() chain + if (parentComponent == null) { + // this needs to be called after super.update() so the children's positions + // get updated before clipping them + applyClipRect(); + } } private function applyClipRect() { - if (this.componentClipRect != null) { - var value = this.componentClipRect; - value.top = Std.int(value.top); - value.left = Std.int(value.left); - if (parentComponent != null) { - var rect = FlxRect.get((value.left * Toolkit.scaleX) + _surface.x - parentComponent.x, - (value.top * Toolkit.scaleY) + _surface.y - parentComponent.y, - (value.width * Toolkit.scaleX), (value.height * Toolkit.scaleY)); - clipRect = rect; - rect.put(); - } else { // top-level (root) components can also clip (Absolute auto clips via a css style), but this means they wont have a parentComponent set, lets handle them differently - var rect = FlxRect.get(_surface.x, _surface.y, value.width, value.height); - clipRect = rect; - rect.put(); + if (componentClipRect != null) { + clipRect = getFlixelClipRect(clipRect); + } + + for (c in childComponents) { + c.applyClipRect(); + } + } + + private function getFlixelClipRect(?rect:FlxRect):FlxRect { + var value = componentClipRect; + if (value == null) { + return null; + } + + value.top = Std.int(value.top); + value.left = Std.int(value.left); + + if (rect == null) { + rect = FlxRect.get(); + } + rect.set((value.left * Toolkit.scaleX) + _surface.x - x, + (value.top * Toolkit.scaleY) + _surface.y - y, + (value.width * Toolkit.scaleX), (value.height * Toolkit.scaleY)); + + // find the nearest parent with a clip rect so we can intersect it with + // the one from this component + var p = parentComponent; + while (p != null) { + if (p.componentClipRect != null) { + var pRect = p.getFlixelClipRect(); + var oldRect = rect; + rect = rect.intersection(pRect); + pRect.put(); + oldRect.put(); + break; } + p = p.parentComponent; } + + return rect; } // these functions (applyAddInternal / applyRemoveInternal) are called when a component is added / removed From b4c4a1aec0821179b2e739c6130351aaff7556f3 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Wed, 5 Jun 2024 23:42:19 +0200 Subject: [PATCH 092/120] component shouldnt have to be ready to set its .x/.y --- haxe/ui/backend/ComponentImpl.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index ee72b0d..07bccc5 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -925,7 +925,7 @@ class ComponentImpl extends ComponentBase { private override function set_x(value:Float):Float { var r = super.set_x(value); - if (this.parentComponent == null && this.isReady) { + if (this.parentComponent == null) { this.left = value; } return r; @@ -933,7 +933,7 @@ class ComponentImpl extends ComponentBase { private override function set_y(value:Float):Float { var r = super.set_y(value); - if (this.parentComponent == null && this.isReady) { + if (this.parentComponent == null) { this.top = value; } return r; From 57c1604d6b5174839d7e0e012a4dd5dcbfc129da Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 11 Jun 2024 08:17:14 +0200 Subject: [PATCH 093/120] only allow left / top to be set after constructor has run --- haxe/ui/backend/ComponentImpl.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 07bccc5..d56050a 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -925,7 +925,7 @@ class ComponentImpl extends ComponentBase { private override function set_x(value:Float):Float { var r = super.set_x(value); - if (this.parentComponent == null) { + if (this.parentComponent == null && _surface != null) { this.left = value; } return r; @@ -933,7 +933,7 @@ class ComponentImpl extends ComponentBase { private override function set_y(value:Float):Float { var r = super.set_y(value); - if (this.parentComponent == null) { + if (this.parentComponent == null && _surface != null) { this.top = value; } return r; From e87bd06c8f50a69768af30d159518379c5af8fa4 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Thu, 27 Jun 2024 09:26:17 +0200 Subject: [PATCH 094/120] _allowDispose flag --- haxe/ui/backend/ScreenImpl.hx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 8ddbb87..49e578b 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -220,6 +220,9 @@ class ScreenImpl extends ScreenBase { } public override function removeComponent(component:Component, dispose:Bool = true, invalidate:Bool = true):Component { + if (@:privateAccess !component._allowDispose) { + dispose = false; + } if (rootComponents.indexOf(component) == -1) { if (dispose) { component.disposeComponent(); From 226021daea0ae87cb697bef771281ddc377a7745 Mon Sep 17 00:00:00 2001 From: Sword352 Date: Sun, 7 Jul 2024 08:14:40 +0200 Subject: [PATCH 095/120] error macro for ui states --- haxe/ui/backend/flixel/UIState.hx | 1 + haxe/ui/backend/flixel/UISubState.hx | 1 + haxe/ui/backend/flixel/macros/UIStateMacro.hx | 42 +++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 haxe/ui/backend/flixel/macros/UIStateMacro.hx diff --git a/haxe/ui/backend/flixel/UIState.hx b/haxe/ui/backend/flixel/UIState.hx index bdc9a73..c1362eb 100644 --- a/haxe/ui/backend/flixel/UIState.hx +++ b/haxe/ui/backend/flixel/UIState.hx @@ -7,6 +7,7 @@ import haxe.ui.events.UIEvent; @:autoBuild(haxe.ui.macros.Macros.buildBehaviours()) @:autoBuild(haxe.ui.macros.Macros.build()) +@:autoBuild(haxe.ui.backend.flixel.macros.UIStateMacro.checkDefine()) class UIState extends UIStateBase { // must use -D haxeui_dont_impose_base_class public var bindingRoot:Bool = false; diff --git a/haxe/ui/backend/flixel/UISubState.hx b/haxe/ui/backend/flixel/UISubState.hx index e61a245..0bf236c 100644 --- a/haxe/ui/backend/flixel/UISubState.hx +++ b/haxe/ui/backend/flixel/UISubState.hx @@ -7,6 +7,7 @@ import haxe.ui.events.UIEvent; @:autoBuild(haxe.ui.macros.Macros.buildBehaviours()) @:autoBuild(haxe.ui.macros.Macros.build()) +@:autoBuild(haxe.ui.backend.flixel.macros.UIStateMacro.checkDefine()) class UISubState extends UISubStateBase { // must use -D haxeui_dont_impose_base_class public var bindingRoot:Bool = false; diff --git a/haxe/ui/backend/flixel/macros/UIStateMacro.hx b/haxe/ui/backend/flixel/macros/UIStateMacro.hx new file mode 100644 index 0000000..cf20fc4 --- /dev/null +++ b/haxe/ui/backend/flixel/macros/UIStateMacro.hx @@ -0,0 +1,42 @@ +package haxe.ui.backend.flixel.macros; + +#if macro +import haxe.macro.Expr.Field; +import haxe.macro.Context; + +/** + * Macro which makes an error at compile time if the user attemps to use `UIState` or `UISubState` without having `haxeui_dont_impose_base_class` defined. + */ +class UIStateMacro { + public static function checkDefine():Array { + var localClass:String = Context.getLocalClass().get().name; + + if (!Context.defined("haxeui_dont_impose_base_class")) + Context.error("You must define haxeui_dont_impose_base_class in order to use " + findUIClass() + " (for class " + localClass + ")", Context.currentPos()); + + return Context.getBuildFields(); + } + + static function findUIClass():String { + var cls = Context.getLocalClass().get(); + + while (!isUIState(cls.name)) { + if (cls.superClass == null) + break; + + cls = cls.superClass.t.get(); + } + + if (!isUIState(cls.name)) { + // shouldn't happen, but just in case + return "UI states"; + } + + return cls.name; + } + + static function isUIState(name:String):Bool { + return name == "UIState" || name == "UISubState"; + } +} +#end From 39a78e8a7c053fc90bf0367060756ed7564f2bb4 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Thu, 11 Jul 2024 09:01:43 -0400 Subject: [PATCH 096/120] Implement `App.icon` and `Platform.getSystemLocale()` --- haxe/ui/backend/AppImpl.hx | 17 +++++++++++++++++ haxe/ui/backend/PlatformImpl.hx | 5 +++++ 2 files changed, 22 insertions(+) diff --git a/haxe/ui/backend/AppImpl.hx b/haxe/ui/backend/AppImpl.hx index 40b2d23..1d83eeb 100644 --- a/haxe/ui/backend/AppImpl.hx +++ b/haxe/ui/backend/AppImpl.hx @@ -2,6 +2,7 @@ package haxe.ui.backend; import flixel.FlxGame; import haxe.ui.backend.flixel.FlxHaxeUIAppState; +import lime.graphics.Image; import openfl.Lib; class AppImpl extends AppBase { @@ -23,4 +24,20 @@ class AppImpl extends AppBase { Lib.current.stage.addChild(new openfl.display.FPS(x, y, c)); } } + + private override function set_icon(value:String):String { + if (_icon == value) { + return value; + } + _icon = value; + + ToolkitAssets.instance.getImage(_icon, function(imageInfo) { + if (imageInfo != null) { + var iconImage = Image.fromBitmapData(imageInfo.data.parent.bitmap); + Lib.current.stage.window.setIcon(iconImage); + } + }); + + return value; + } } diff --git a/haxe/ui/backend/PlatformImpl.hx b/haxe/ui/backend/PlatformImpl.hx index 32ce443..7f77666 100644 --- a/haxe/ui/backend/PlatformImpl.hx +++ b/haxe/ui/backend/PlatformImpl.hx @@ -1,4 +1,9 @@ package haxe.ui.backend; +import openfl.system.Capabilities; + class PlatformImpl extends PlatformBase { + public override function getSystemLocale():String { + return Capabilities.language; + } } \ No newline at end of file From 576ee63faee77bc4f55d8200ca93e5447f49e2a6 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Thu, 11 Jul 2024 13:31:56 -0400 Subject: [PATCH 097/120] Implement missing functions for ComponentGraphicsImpl - Draw commands can now be replayed --- haxe/ui/backend/ComponentGraphicsImpl.hx | 256 ++++++++++++++++++++++- 1 file changed, 248 insertions(+), 8 deletions(-) diff --git a/haxe/ui/backend/ComponentGraphicsImpl.hx b/haxe/ui/backend/ComponentGraphicsImpl.hx index a5ba3d2..fb931fd 100644 --- a/haxe/ui/backend/ComponentGraphicsImpl.hx +++ b/haxe/ui/backend/ComponentGraphicsImpl.hx @@ -3,18 +3,70 @@ package haxe.ui.backend; import flixel.FlxSprite; import haxe.io.Bytes; import haxe.ui.core.Component; +import haxe.ui.loaders.image.ImageLoader; +import haxe.ui.util.Color; +import haxe.ui.util.Variant; import openfl.display.BitmapData; +import openfl.display.GraphicsPath; +import openfl.display.GraphicsPathCommand; +import openfl.display.Sprite; +import openfl.geom.Matrix; import openfl.geom.Rectangle; import openfl.utils.ByteArray; +@:allow(haxe.ui.backend.ComponentGraphicsSprite) class ComponentGraphicsImpl extends ComponentGraphicsBase { private var _hasSize:Bool = false; private var bitmapData:BitmapData = null; - private var sprite:FlxSprite; + private var sprite:ComponentGraphicsSprite; + + private var flashGfxSprite:Sprite = new Sprite(); + + private var _currentFillColor:Null = null; + private var _currentFillAlpha:Null = null; + private var _globalFillColor:Null = null; + private var _globalFillAlpha:Null = null; + + private var _globalLineThickness:Null = null; + private var _globalLineColor:Null = null; + private var _globalLineAlpha:Null = null; + + private var currentPath:GraphicsPath; + + public function new(component:Component) { + super(component); + sprite = new ComponentGraphicsSprite(this); + sprite.active = false; + sprite.visible = false; + _component.add(sprite); + } + + public override function clear() { + super.clear(); + if (_hasSize == false) { + return; + } + flashGfxSprite.graphics.clear(); + + sprite.pixels.fillRect(sprite.pixels.rect, 0x00000000); + sprite._needsDraw = true; + } + + public override function setPixel(x:Float, y:Float, color:Color) { + super.setPixel(x, y, color); + if (_hasSize == false) { + return; + } + flashGfxSprite.graphics.beginFill(color); + flashGfxSprite.graphics.drawRect(x, y, 1, 1); + flashGfxSprite.graphics.endFill(); + sprite._needsDraw = true; + } public override function setPixels(pixels:Bytes) { + super.setPixels(pixels); if (_hasSize == false) { - return super.setPixels(pixels); + return; } var w = Std.int(_component.width); @@ -48,12 +100,6 @@ class ComponentGraphicsImpl extends ComponentGraphicsBase { var byteArray = ByteArray.fromBytes(newPixels); bitmapData.setPixels(new Rectangle(0, 0, bitmapData.width, bitmapData.height), byteArray); - if (sprite == null) { - sprite = new FlxSprite(0, 0); - sprite.active = false; - _component.add(sprite); - } - sprite.width = w; sprite.height = h; @@ -61,12 +107,206 @@ class ComponentGraphicsImpl extends ComponentGraphicsBase { sprite.visible = (w > 0 && h > 0); } + public override function moveTo(x:Float, y:Float) { + super.moveTo(x, y); + if (_hasSize == false) { + return; + } + if (currentPath != null) { + currentPath.moveTo(x, y); + } else { + flashGfxSprite.graphics.moveTo(x, y); + sprite._needsDraw = true; + } + } + + public override function lineTo(x:Float, y:Float) { + super.lineTo(x, y); + if (_hasSize == false) { + return; + } + if (currentPath != null) { + currentPath.lineTo(x, y); + } else { + flashGfxSprite.graphics.lineTo(x, y); + sprite._needsDraw = true; + } + } + + public override function strokeStyle(color:Null, thickness:Null = 1, alpha:Null = 1) { + super.strokeStyle(color, thickness, alpha); + if (_hasSize == false) { + return; + } + if (currentPath == null) { + _globalLineThickness = thickness; + _globalLineColor = color; + _globalLineAlpha = alpha; + } + + flashGfxSprite.graphics.lineStyle(thickness, color, alpha); + } + + public override function circle(x:Float, y:Float, radius:Float) { + super.circle(x, y, radius); + if (_hasSize == false) { + return; + } + if (_currentFillColor != null) { + flashGfxSprite.graphics.beginFill(_currentFillColor, _currentFillAlpha); + } + flashGfxSprite.graphics.drawCircle(x, y, radius); + if (_currentFillColor != null) { + flashGfxSprite.graphics.endFill(); + } + sprite._needsDraw = true; + } + + public override function fillStyle(color:Null, alpha:Null = 1) { + super.fillStyle(color, alpha); + if (_hasSize == false) { + return; + } + if (currentPath == null) { + _globalFillColor = color; + _globalFillAlpha = alpha; + } + _currentFillColor = color; + _currentFillAlpha = alpha; + } + + public override function curveTo(controlX:Float, controlY:Float, anchorX:Float, anchorY:Float) { + super.curveTo(controlX, controlY, anchorX, anchorY); + if (_hasSize == false) { + return; + } + + if (currentPath != null) { + currentPath.curveTo(controlX, controlY, anchorX, anchorY); + } else { + flashGfxSprite.graphics.curveTo(controlX, controlY, anchorX, anchorY); + sprite._needsDraw = true; + } + } + + public override function cubicCurveTo(controlX1:Float, controlY1:Float, controlX2:Float, controlY2:Float, anchorX:Float, anchorY:Float) { + super.cubicCurveTo(controlX1, controlY1, controlX2, controlY2, anchorX, anchorY); + if (_hasSize == false) { + return; + } + if (currentPath != null) { + currentPath.cubicCurveTo(controlX1, controlY1, controlX2, controlY2, anchorX, anchorY); + } else { + flashGfxSprite.graphics.cubicCurveTo(controlX1, controlY1, controlX2, controlY2, anchorX, anchorY); + sprite._needsDraw = true; + } + } + + public override function rectangle(x:Float, y:Float, width:Float, height:Float) { + super.rectangle(x, y, width, height); + if (_hasSize == false) { + return; + } + if (_currentFillColor != null) { + flashGfxSprite.graphics.beginFill(_currentFillColor, _currentFillAlpha); + } + flashGfxSprite.graphics.drawRect(x, y, width, height); + if (_currentFillColor != null) { + flashGfxSprite.graphics.endFill(); + } + sprite._needsDraw = true; + } + + public override function image(resource:Variant, x:Null = null, y:Null = null, width:Null = null, height:Null = null) { + super.image(resource, x, y, width, height); + if (_hasSize == false) { + return; + } + ImageLoader.instance.load(resource, function(imageInfo) { + if (imageInfo != null) { + if (x == null) x = 0; + if (y == null) y = 0; + if (width == null) width = imageInfo.width; + if (height == null) height = imageInfo.height; + + var mat:Matrix = new Matrix(); + mat.scale(width / imageInfo.width, height / imageInfo.width); + mat.translate(x, y); + + flashGfxSprite.graphics.beginBitmapFill(imageInfo.data.parent.bitmap, mat); + flashGfxSprite.graphics.drawRect(x, y, width, height); + flashGfxSprite.graphics.endFill(); + sprite._needsDraw = true; + } else { + trace("could not load: " + resource); + } + }); + } + + public override function beginPath() { + super.beginPath(); + if (_hasSize == false) { + return; + } + currentPath = new GraphicsPath(); + } + + public override function closePath() { + super.closePath(); + if (_hasSize == false) { + return; + } + if (currentPath != null && currentPath.commands != null && currentPath.commands.length > 0) { + if (_currentFillColor != null) { + flashGfxSprite.graphics.beginFill(_currentFillColor, _currentFillAlpha); + } + if (currentPath.commands[0] != GraphicsPathCommand.MOVE_TO) { + currentPath.commands.insertAt(0, GraphicsPathCommand.MOVE_TO); + @:privateAccess currentPath.data.insertAt(0, flashGfxSprite.graphics.__positionX); + @:privateAccess currentPath.data.insertAt(0, flashGfxSprite.graphics.__positionY); + } + flashGfxSprite.graphics.drawPath(currentPath.commands, currentPath.data); + if (_currentFillColor != null) { + flashGfxSprite.graphics.endFill(); + } + sprite._needsDraw = true; + } + currentPath = null; + _currentFillColor = _globalFillColor; + _currentFillAlpha = _globalFillAlpha; + + // it seems openfl forgets about lineStyle after drawing a shape; + flashGfxSprite.graphics.lineStyle(_globalLineThickness, _globalLineColor, _globalLineAlpha); + } + public override function resize(width:Null, height:Null) { if (width > 0 && height > 0) { if (_hasSize == false) { _hasSize = true; + sprite.makeGraphic(Std.int(width), Std.int(height), 0x00000000, true); + sprite.visible = true; replayDrawCommands(); } } } +} + +@:allow(haxe.ui.backend.ComponentGraphicsImpl) +class ComponentGraphicsSprite extends FlxSprite { + private var componentGraphics:ComponentGraphicsImpl; + + private var _needsDraw:Bool = false; + + public function new(componentGraphics:ComponentGraphicsImpl) { + super(); + this.componentGraphics = componentGraphics; + } + + public override function draw() { + if (pixels != null && _needsDraw) { + pixels.draw(componentGraphics.flashGfxSprite); + _needsDraw = false; + } + super.draw(); + } } \ No newline at end of file From b5c5787629bde2a5997559837a41b08839789f13 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Thu, 5 Sep 2024 15:42:02 -0400 Subject: [PATCH 098/120] Implement new text input from core Flixel --- haxe/ui/backend/TextInputImpl.hx | 6 +-- .../backend/flixel/textinputs/FlxTextInput.hx | 43 ++++++++++--------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/haxe/ui/backend/TextInputImpl.hx b/haxe/ui/backend/TextInputImpl.hx index 5eba182..29432db 100644 --- a/haxe/ui/backend/TextInputImpl.hx +++ b/haxe/ui/backend/TextInputImpl.hx @@ -2,12 +2,8 @@ package haxe.ui.backend; typedef TextInputEvent = {type:String, stageX:Float, stageY:Float}; -#if flixel_text_input - +#if (flixel >= "5.9.0") typedef TextInputImpl = haxe.ui.backend.flixel.textinputs.FlxTextInput; - #else - typedef TextInputImpl = haxe.ui.backend.flixel.textinputs.OpenFLTextInput; - #end diff --git a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx index 677a710..4c915cb 100644 --- a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx @@ -1,13 +1,14 @@ package haxe.ui.backend.flixel.textinputs; import flixel.FlxSprite; +import flixel.text.FlxInputText; +import flixel.util.FlxColor; import haxe.ui.backend.TextInputImpl.TextInputEvent; import haxe.ui.core.Component; import openfl.events.Event; import openfl.events.KeyboardEvent; -#if flixel_text_input - +#if (flixel >= "5.9.0") class FlxTextInput extends TextBase { public static var USE_ON_ADDED:Bool = false; public static var USE_ON_REMOVED:Bool = false; @@ -15,25 +16,24 @@ class FlxTextInput extends TextBase { private var PADDING_X:Int = 4; private var PADDING_Y:Int = 0; - private var tf:flixel.addons.text.FlxTextInput; + private var tf:FlxInputText; public function new() { super(); - tf = new flixel.addons.text.FlxTextInput(); - tf.onChange.add(onInternalChange); - tf.onScroll.add(onScroll); + tf = new FlxInputText(0, 0, 0, null, 8, FlxColor.BLACK, FlxColor.TRANSPARENT); + tf.onTextChange.add(onInternalChange); + tf.onScrollChange.add(onScroll); tf.pixelPerfectRender = true; - tf.moves = false; _inputData.vscrollPageStep = 1; _inputData.vscrollNativeWheel = true; } public override function focus() { - tf.focus = true; + tf.startFocus(); } public override function blur() { - tf.focus = false; + tf.endFocus(); } public function attach() { @@ -184,14 +184,16 @@ class FlxTextInput extends TextBase { if (tf.multiline != _displayData.multiline) { tf.multiline = _displayData.multiline; - measureTextRequired = true; + // `multiline` only decides whether the user can add new lines, + // so measuring the text is not required. } - if (tf.displayAsPassword != _inputData.password) { - tf.displayAsPassword = _inputData.password; + if (tf.passwordMode != _inputData.password) { + tf.passwordMode = _inputData.password; + measureTextRequired = true; } - tf.type = (parentComponent.disabled ? DYNAMIC : INPUT); + tf.editable = !parentComponent.disabled; return measureTextRequired; } @@ -300,16 +302,16 @@ class FlxTextInput extends TextBase { public var onChange(null, set):TextInputEvent->Void; private function set_onChange(value:TextInputEvent->Void):TextInputEvent->Void { if (_onChange != null) { - tf.onChange.remove(__onTextInputChangeEvent); + tf.onTextChange.remove(__onTextInputChangeEvent); } _onChange = value; if (_onChange != null) { - tf.onChange.add(__onTextInputChangeEvent); + tf.onTextChange.add(__onTextInputChangeEvent); } return value; } - private function __onTextInputChangeEvent() { + private function __onTextInputChangeEvent(text:String, action:FlxInputTextChange) { if (_onChange != null) { _onChange({ type: "change", @@ -359,7 +361,7 @@ class FlxTextInput extends TextBase { } */ - private function onInternalChange() { + private function onInternalChange(text:String, action:FlxInputTextChange) { _text = tf.text; measureText(); @@ -368,8 +370,8 @@ class FlxTextInput extends TextBase { _inputData.onChangedCallback(); } } - - private function onScroll() { + + private function onScroll(scrollH:Int, scrollV:Int) { _inputData.hscrollPos = tf.scrollH; _inputData.vscrollPos = tf.scrollV - 1; @@ -388,10 +390,9 @@ class FlxTextInput extends TextBase { public function destroy(component:Component) { tf.visible = false; - component.remove(tf); + component.remove(tf, true); tf.destroy(); tf = null; } } - #end \ No newline at end of file From e70cbffa4882f0f83e638d67b2ffe412fb549195 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Thu, 5 Sep 2024 16:06:04 -0400 Subject: [PATCH 099/120] Fix components not being spliced from the state when removed --- haxe/ui/backend/ScreenImpl.hx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 49e578b..4d51fe2 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -233,14 +233,17 @@ class ScreenImpl extends ScreenBase { if (rootComponents.indexOf(component) != -1) { throw "component wasnt actually removed from array, or there is a duplicate in the array"; } + if (StateHelper.currentState.exists == true) { + StateHelper.currentState.remove(component, true); + } + // Destroying a sprite makes it get removed from its container (in this case, the state) without + // being spliced, causing issues later with `addComponent()` not actually adding components on top + // of everything else, so this has to go after the component has been properly removed. if (dispose) { component.disposeComponent(); } else { component.applyRemoveInternal(); } - if (StateHelper.currentState.exists == true) { - StateHelper.currentState.remove(component, true); - } checkResetCursor(); onContainerResize(); return component; From a01ff89ad55fba489a3f1a8fd26915b94b3d2fa5 Mon Sep 17 00:00:00 2001 From: TechnikTil <89487150+TechnikTil@users.noreply.github.com> Date: Wed, 18 Sep 2024 00:36:07 -0600 Subject: [PATCH 100/120] Use Frame Resolution instead of parent --- haxe/ui/backend/AssetsImpl.hx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/haxe/ui/backend/AssetsImpl.hx b/haxe/ui/backend/AssetsImpl.hx index 9fe7b90..df0792a 100644 --- a/haxe/ui/backend/AssetsImpl.hx +++ b/haxe/ui/backend/AssetsImpl.hx @@ -93,12 +93,12 @@ class AssetsImpl extends AssetsBase { public override function imageInfoFromImageData(imageData:ImageData):ImageInfo { return { data: imageData, - width: imageData.parent.width, - height: imageData.parent.height + width: imageData.frame.width, + height: imageData.frame.height } } private static inline function isEmbeddedFont(fontName:String):Bool { return fontName != "_sans" && fontName != "_serif" && fontName != "_typewriter"; } -} \ No newline at end of file +} From 0ebd3a5c2d3823363c32994a2340095ea45326b2 Mon Sep 17 00:00:00 2001 From: Sword352 Date: Sun, 22 Sep 2024 15:07:35 +0200 Subject: [PATCH 101/120] floor frame resolution --- haxe/ui/backend/AssetsImpl.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/haxe/ui/backend/AssetsImpl.hx b/haxe/ui/backend/AssetsImpl.hx index df0792a..ca44e40 100644 --- a/haxe/ui/backend/AssetsImpl.hx +++ b/haxe/ui/backend/AssetsImpl.hx @@ -93,8 +93,8 @@ class AssetsImpl extends AssetsBase { public override function imageInfoFromImageData(imageData:ImageData):ImageInfo { return { data: imageData, - width: imageData.frame.width, - height: imageData.frame.height + width: Std.int(imageData.frame.width), + height: Std.int(imageData.frame.height) } } From da27e833947f32ef007ed11f523aa5524f5a5d54 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Mon, 30 Sep 2024 12:11:42 +0200 Subject: [PATCH 102/120] dont destroy graphic, deincrementUseCount to ensure its uncached --- haxe/ui/backend/ComponentImpl.hx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index d56050a..70082cb 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -227,11 +227,11 @@ class ComponentImpl extends ComponentBase { var h:Int = Std.int(height * Toolkit.scaleY); if (_surface.width != w || _surface.height != h) { if (w <= 0 || h <= 0) { - _surface.graphic.destroy(); + _surface.graphic.decrementUseCount(); _surface.makeGraphic(1, 1, 0x0, true); _surface.visible = false; } else { - _surface.graphic.destroy(); + _surface.graphic.decrementUseCount(); _surface.makeGraphic(w, h, 0x0, true); applyStyle(style); } @@ -881,6 +881,7 @@ class ComponentImpl extends ComponentBase { private var _destroyed:Bool = false; private function destroyInternal() { if (_surface != null) { + _surface.graphic.decrementUseCount(); _surface.destroy(); _surface = null; } From eb6ec2f6fa28ecc5b316651f1a6b5a2d9f61fc7b Mon Sep 17 00:00:00 2001 From: Sword352 Date: Wed, 2 Oct 2024 16:46:35 +0200 Subject: [PATCH 103/120] fix runtime states not being fully destroyed --- haxe/ui/backend/flixel/UIRuntimeState.hx | 1 + haxe/ui/backend/flixel/UIRuntimeSubState.hx | 1 + 2 files changed, 2 insertions(+) diff --git a/haxe/ui/backend/flixel/UIRuntimeState.hx b/haxe/ui/backend/flixel/UIRuntimeState.hx index f1cac83..80cfdfb 100644 --- a/haxe/ui/backend/flixel/UIRuntimeState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeState.hx @@ -117,6 +117,7 @@ class UIRuntimeState extends UIStateBase { // uses rtti to "build" a class with if (root != null) { Screen.instance.removeComponent(root); } + super.destroy(); root = null; } } \ No newline at end of file diff --git a/haxe/ui/backend/flixel/UIRuntimeSubState.hx b/haxe/ui/backend/flixel/UIRuntimeSubState.hx index 01fe737..d9346c0 100644 --- a/haxe/ui/backend/flixel/UIRuntimeSubState.hx +++ b/haxe/ui/backend/flixel/UIRuntimeSubState.hx @@ -117,6 +117,7 @@ class UIRuntimeSubState extends UISubStateBase { // uses rtti to "build" a class if (root != null) { Screen.instance.removeComponent(root); } + super.destroy(); root = null; } } \ No newline at end of file From f148895376cd554fb8b2678bf78145de961b331a Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Wed, 2 Oct 2024 20:22:00 +0200 Subject: [PATCH 104/120] clear caches for good measure on destruction --- haxe/ui/backend/ComponentImpl.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 70082cb..cbb9995 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -776,6 +776,7 @@ class ComponentImpl extends ComponentBase { return; } if (_destroy == true) { + clearCaches(); destroyInternal(); super.update(elapsed); return; From ecc624bf050644fe33691b6da5a0d1077214f680 Mon Sep 17 00:00:00 2001 From: Sword352 Date: Thu, 3 Oct 2024 09:16:03 +0200 Subject: [PATCH 105/120] fix some more graphic leaks --- haxe/ui/backend/ComponentImpl.hx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 70082cb..aebe59e 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -46,7 +46,6 @@ class ComponentImpl extends ComponentBase { scrollFactor.set(0, 0); // ui doesn't scroll by default _surface = new FlxSprite(); - _surface.makeGraphic(1, 1, 0x0, true); _surface.pixelPerfectRender = true; _surface.active = false; _surface.visible = false; @@ -227,11 +226,9 @@ class ComponentImpl extends ComponentBase { var h:Int = Std.int(height * Toolkit.scaleY); if (_surface.width != w || _surface.height != h) { if (w <= 0 || h <= 0) { - _surface.graphic.decrementUseCount(); _surface.makeGraphic(1, 1, 0x0, true); _surface.visible = false; } else { - _surface.graphic.decrementUseCount(); _surface.makeGraphic(w, h, 0x0, true); applyStyle(style); } @@ -776,6 +773,7 @@ class ComponentImpl extends ComponentBase { return; } if (_destroy == true) { + clearCaches(); destroyInternal(); super.update(elapsed); return; @@ -881,7 +879,6 @@ class ComponentImpl extends ComponentBase { private var _destroyed:Bool = false; private function destroyInternal() { if (_surface != null) { - _surface.graphic.decrementUseCount(); _surface.destroy(); _surface = null; } From 3da709ce9bbf0ab68a49215b32ee3067e95c751e Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Mon, 7 Oct 2024 10:09:56 +0200 Subject: [PATCH 106/120] use screenLeft / screenTop from core --- haxe/ui/backend/ComponentImpl.hx | 67 ++++++++++++++------------------ 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index aebe59e..3cce20b 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -91,32 +91,19 @@ class ComponentImpl extends ComponentBase { if (_cachedScreenX != null && _cachedScreenY != null) { return; } - - var c:Component = asComponent; - var xpos:Float = 0; - var ypos:Float = 0; - while (c != null) { - xpos += c.left; - ypos += c.top; - if (c.componentClipRect != null) { - xpos -= c.componentClipRect.left; - ypos -= c.componentClipRect.top; - } - c = c.parentComponent; - } - - _cachedScreenX = xpos * Toolkit.scaleX; - _cachedScreenY = ypos * Toolkit.scaleY; + var screenBounds = asComponent.screenBounds; + _cachedScreenX = screenBounds.left; + _cachedScreenY = screenBounds.top; } - private var screenX(get, null):Float; - private function get_screenX():Float { + private var cachedScreenX(get, null):Float; + private function get_cachedScreenX():Float { cacheScreenPos(); return _cachedScreenX; } - private var screenY(get, null):Float; - private function get_screenY():Float { + private var cachedScreenY(get, null):Float; + private function get_cachedScreenY():Float { cacheScreenPos(); return _cachedScreenY; } @@ -172,8 +159,8 @@ class ComponentImpl extends ComponentBase { } var b:Bool = false; - var sx = screenX; - var sy = screenY; + var sx = cachedScreenX; + var sy = cachedScreenY; var cx = asComponent.componentWidth * Toolkit.scaleX; var cy = asComponent.componentHeight * Toolkit.scaleY; @@ -186,8 +173,8 @@ class ComponentImpl extends ComponentBase { var clip:Component = findClipComponent(); if (clip != null) { b = false; - var sx = (clip.screenX + (clip.componentClipRect.left * Toolkit.scaleX)); - var sy = (clip.screenY + (clip.componentClipRect.top * Toolkit.scaleY)); + var sx = (clip.cachedScreenX + (clip.componentClipRect.left * Toolkit.scaleX)); + var sy = (clip.cachedScreenY + (clip.componentClipRect.top * Toolkit.scaleY)); var cx = clip.componentClipRect.width * Toolkit.scaleX; var cy = clip.componentClipRect.height * Toolkit.scaleY; if (x >= sx && y >= sy && x <= sx + cx && y < sy + cy) { @@ -205,10 +192,10 @@ class ComponentImpl extends ComponentBase { if (parentComponent == null) { if (left != null) { - this.x = left; + //this.x = left; } if (top != null) { - this.y = top; + //this.y = top; } } } @@ -658,23 +645,25 @@ class ComponentImpl extends ComponentBase { // Util //*********************************************************************************************************** private function repositionChildren() { + var xpos = this.cachedScreenX; + var ypos = this.cachedScreenY; if (_surface != null) { - _surface.x = this.screenX; - _surface.y = this.screenY; + _surface.x = xpos; + _surface.y = ypos; } if (_textDisplay != null) { var offsetX = 2 / Toolkit.scaleX; var offsetY = 2 / Toolkit.scaleY; - _textDisplay.tf.x = _surface.x + _textDisplay.left - offsetX; - _textDisplay.tf.y = _surface.y + _textDisplay.top - offsetY; + _textDisplay.tf.x = xpos + _textDisplay.left - offsetX; + _textDisplay.tf.y = ypos + _textDisplay.top - offsetY; } if (_textInput != null) { var offsetX = 2 / Toolkit.scaleX; var offsetY = 2 / Toolkit.scaleY; - _textInput.x = (_surface.x + _textInput.left - offsetX); - _textInput.y = (_surface.y + _textInput.top - offsetY); + _textInput.x = (xpos + _textInput.left - offsetX); + _textInput.y = (ypos + _textInput.top - offsetY); _textInput.scaleX = FlxG.scaleMode.scale.x; _textInput.scaleY = FlxG.scaleMode.scale.y; _textInput.update(); @@ -683,14 +672,14 @@ class ComponentImpl extends ComponentBase { if (_imageDisplay != null) { var offsetX = 0; var offsetY = 0; - _imageDisplay.x = _surface.x + _imageDisplay.left - offsetX; - _imageDisplay.y = _surface.y + _imageDisplay.top - offsetY; + _imageDisplay.x = xpos + _imageDisplay.left - offsetX; + _imageDisplay.y = ypos + _imageDisplay.top - offsetY; } if (_unsolicitedMembers != null) { for (m in _unsolicitedMembers) { - m.sprite.x = m.originalX + this.screenX; - m.sprite.y = m.originalY + this.screenY; + m.sprite.x = m.originalX + this.cachedScreenX; + m.sprite.y = m.originalY + this.cachedScreenY; } } } @@ -921,10 +910,11 @@ class ComponentImpl extends ComponentBase { _destroy = true; } + /* private override function set_x(value:Float):Float { var r = super.set_x(value); if (this.parentComponent == null && _surface != null) { - this.left = value; + //this.left = value; } return r; } @@ -932,8 +922,9 @@ class ComponentImpl extends ComponentBase { private override function set_y(value:Float):Float { var r = super.set_y(value); if (this.parentComponent == null && _surface != null) { - this.top = value; + //this.top = value; } return r; } + */ } \ No newline at end of file From 6986d410302ba8939d8771041d8ae86d4b8e83c6 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Mon, 7 Oct 2024 12:59:26 +0200 Subject: [PATCH 107/120] use padding in text input --- haxe/ui/backend/flixel/textinputs/FlxTextInput.hx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx index 677a710..70009dc 100644 --- a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx @@ -12,8 +12,8 @@ class FlxTextInput extends TextBase { public static var USE_ON_ADDED:Bool = false; public static var USE_ON_REMOVED:Bool = false; - private var PADDING_X:Int = 4; - private var PADDING_Y:Int = 0; + private static inline var PADDING_X:Int = 4; + private static inline var PADDING_Y:Int = 2; private var tf:flixel.addons.text.FlxTextInput; @@ -198,7 +198,7 @@ class FlxTextInput extends TextBase { private override function validatePosition() { _left = Math.round(_left * Toolkit.scaleX); - _top = Math.round(_top * Toolkit.scaleY); + _top = Math.round(_top * Toolkit.scaleY) + (PADDING_Y / 2); } private override function validateDisplay() { @@ -211,8 +211,8 @@ class FlxTextInput extends TextBase { tf.fieldWidth = tf.width; } - if (tf.height != _height * Toolkit.scaleY) { - tf.height = _height * Toolkit.scaleY; + if (tf.height != (_height + PADDING_Y) * Toolkit.scaleY) { + tf.height = (_height + PADDING_Y) * Toolkit.scaleY; tf.fieldHeight = tf.height; } } From 46ebd5c4f78a21d393209099db0bee3cee8ab992 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Tue, 8 Oct 2024 23:10:48 +0200 Subject: [PATCH 108/120] screenX/Y => cachedScreenX/Y --- haxe/ui/backend/flixel/components/SparrowPlayer.hx | 4 ++-- haxe/ui/backend/flixel/components/SpriteWrapper.hx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/haxe/ui/backend/flixel/components/SparrowPlayer.hx b/haxe/ui/backend/flixel/components/SparrowPlayer.hx index d31704e..c162c1c 100644 --- a/haxe/ui/backend/flixel/components/SparrowPlayer.hx +++ b/haxe/ui/backend/flixel/components/SparrowPlayer.hx @@ -249,8 +249,8 @@ class SparrowPlayer extends Box implements IDataComponent { private override function repositionChildren() { super.repositionChildren(); - sprite.x = this.screenX; - sprite.y = this.screenY; + sprite.x = this.cachedScreenX; + sprite.y = this.cachedScreenY; } } diff --git a/haxe/ui/backend/flixel/components/SpriteWrapper.hx b/haxe/ui/backend/flixel/components/SpriteWrapper.hx index ef51c86..cd1e843 100644 --- a/haxe/ui/backend/flixel/components/SpriteWrapper.hx +++ b/haxe/ui/backend/flixel/components/SpriteWrapper.hx @@ -30,8 +30,8 @@ class SpriteWrapper extends Box { private override function repositionChildren() { super.repositionChildren(); if (sprite != null) { - sprite.x = spriteOffsetX + this.screenX; - sprite.y = spriteOffsetY + this.screenY; + sprite.x = spriteOffsetX + this.cachedScreenX; + sprite.y = spriteOffsetY + this.cachedScreenY; } } } From 0d968bac711e658bd791e362ba959d1505f5c2bb Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Fri, 11 Oct 2024 09:29:59 +0200 Subject: [PATCH 109/120] tabs -> spaces --- haxe/ui/backend/flixel/UIState.hx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/haxe/ui/backend/flixel/UIState.hx b/haxe/ui/backend/flixel/UIState.hx index c1362eb..20ca40a 100644 --- a/haxe/ui/backend/flixel/UIState.hx +++ b/haxe/ui/backend/flixel/UIState.hx @@ -1,9 +1,9 @@ package haxe.ui.backend.flixel; -import haxe.ui.layouts.LayoutFactory; import haxe.ui.containers.Box; import haxe.ui.core.Component; import haxe.ui.events.UIEvent; +import haxe.ui.layouts.LayoutFactory; @:autoBuild(haxe.ui.macros.Macros.buildBehaviours()) @:autoBuild(haxe.ui.macros.Macros.build()) @@ -27,9 +27,9 @@ class UIState extends UIStateBase { // must use -D haxeui_dont_impose_base_class public override function create() { super.create(); - root.registerEvent(UIEvent.READY, (_) -> { + root.registerEvent(UIEvent.READY, (_) -> { onReady(); - }); + }); add(root); } @@ -92,11 +92,11 @@ class UIState extends UIStateBase { // must use -D haxeui_dont_impose_base_class return value; } - public function show() { - root.show(); - } + public function show() { + root.show(); + } - public function hide() { - root.hide(); - } + public function hide() { + root.hide(); + } } From 7d9b1af2061df47a9659e8c7445e468e61e81cf1 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Mon, 28 Oct 2024 09:28:32 +0100 Subject: [PATCH 110/120] #if !flash --- haxe/ui/backend/ComponentGraphicsImpl.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/haxe/ui/backend/ComponentGraphicsImpl.hx b/haxe/ui/backend/ComponentGraphicsImpl.hx index fb931fd..681a06e 100644 --- a/haxe/ui/backend/ComponentGraphicsImpl.hx +++ b/haxe/ui/backend/ComponentGraphicsImpl.hx @@ -262,8 +262,10 @@ class ComponentGraphicsImpl extends ComponentGraphicsBase { } if (currentPath.commands[0] != GraphicsPathCommand.MOVE_TO) { currentPath.commands.insertAt(0, GraphicsPathCommand.MOVE_TO); + #if !flash @:privateAccess currentPath.data.insertAt(0, flashGfxSprite.graphics.__positionX); @:privateAccess currentPath.data.insertAt(0, flashGfxSprite.graphics.__positionY); + #end } flashGfxSprite.graphics.drawPath(currentPath.commands, currentPath.data); if (_currentFillColor != null) { From bd7ebd956f0fd97bda0ab0095f2a5b61165b2e5f Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Mon, 18 Nov 2024 08:45:55 +0100 Subject: [PATCH 111/120] re-add commented out x/y overrides --- haxe/ui/backend/ComponentImpl.hx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/haxe/ui/backend/ComponentImpl.hx b/haxe/ui/backend/ComponentImpl.hx index 3cce20b..8c181e1 100644 --- a/haxe/ui/backend/ComponentImpl.hx +++ b/haxe/ui/backend/ComponentImpl.hx @@ -910,11 +910,10 @@ class ComponentImpl extends ComponentBase { _destroy = true; } - /* private override function set_x(value:Float):Float { var r = super.set_x(value); if (this.parentComponent == null && _surface != null) { - //this.left = value; + this.left = value; } return r; } @@ -922,9 +921,8 @@ class ComponentImpl extends ComponentBase { private override function set_y(value:Float):Float { var r = super.set_y(value); if (this.parentComponent == null && _surface != null) { - //this.top = value; + this.top = value; } return r; } - */ } \ No newline at end of file From 884e7cbfba59154c62890e15adc729526b2a8a75 Mon Sep 17 00:00:00 2001 From: Starmapo Date: Sat, 21 Dec 2024 15:05:50 -0400 Subject: [PATCH 112/120] Padding is no longer needed --- haxe/ui/backend/flixel/textinputs/FlxTextInput.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx index d954754..e3bda74 100644 --- a/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx +++ b/haxe/ui/backend/flixel/textinputs/FlxTextInput.hx @@ -200,7 +200,7 @@ class FlxTextInput extends TextBase { private override function validatePosition() { _left = Math.round(_left * Toolkit.scaleX); - _top = Math.round(_top * Toolkit.scaleY) + (PADDING_Y / 2); + _top = Math.round(_top * Toolkit.scaleY); } private override function validateDisplay() { From 97f142bde8fab1e3f8c8dac888dd073c0cc24e36 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Wed, 8 Jan 2025 08:54:50 +0100 Subject: [PATCH 113/120] better exceptions --- haxe/ui/backend/flixel/UIRTTITools.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/haxe/ui/backend/flixel/UIRTTITools.hx b/haxe/ui/backend/flixel/UIRTTITools.hx index d425dfd..f8fc6c8 100644 --- a/haxe/ui/backend/flixel/UIRTTITools.hx +++ b/haxe/ui/backend/flixel/UIRTTITools.hx @@ -43,6 +43,7 @@ class UIRTTITools { root = RuntimeComponentBuilder.fromString(xmlString); } catch (e:Dynamic) { trace("ERROR", e); + trace(haxe.CallStack.toString(haxe.CallStack.exceptionStack(true))); } } return root; From 34fe148e45292439a9c3caf00890c93bcc6f9453 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Sun, 12 Jan 2025 17:49:16 +0100 Subject: [PATCH 114/120] set painted=true sooner --- haxe/ui/backend/flixel/FlxStyleHelper.hx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/haxe/ui/backend/flixel/FlxStyleHelper.hx b/haxe/ui/backend/flixel/FlxStyleHelper.hx index cd7dcf9..45020e3 100644 --- a/haxe/ui/backend/flixel/FlxStyleHelper.hx +++ b/haxe/ui/backend/flixel/FlxStyleHelper.hx @@ -188,11 +188,10 @@ class FlxStyleHelper { } if (style.backgroundImage != null) { + painted = true; Toolkit.assets.getImage(style.backgroundImage, function(info:ImageInfo) { if (info != null && info.data != null) { paintBackroundImage(sprite, info.data, style); - - painted = true; } }); } From 3c4ec999f7f971401cce4fb1de78f7ce5ce28392 Mon Sep 17 00:00:00 2001 From: George Kurelic Date: Thu, 6 Feb 2025 13:51:19 -0600 Subject: [PATCH 115/120] Replace FlxGroups with FlxContainers --- haxe/ui/backend/ComponentSurface.hx | 2 +- haxe/ui/backend/ScreenImpl.hx | 26 ++++++++++++------------ haxe/ui/backend/flixel/UIFragmentBase.hx | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/haxe/ui/backend/ComponentSurface.hx b/haxe/ui/backend/ComponentSurface.hx index 934a1b2..c15ef02 100644 --- a/haxe/ui/backend/ComponentSurface.hx +++ b/haxe/ui/backend/ComponentSurface.hx @@ -1,3 +1,3 @@ package haxe.ui.backend; -typedef ComponentSurface = flixel.group.FlxSpriteGroup; \ No newline at end of file +typedef ComponentSurface = flixel.group.FlxSpriteContainer; \ No newline at end of file diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 4d51fe2..a3b17cf 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -3,8 +3,8 @@ package haxe.ui.backend; import flixel.FlxBasic; import flixel.FlxG; import flixel.FlxSprite; -import flixel.group.FlxGroup.FlxTypedGroup; -import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup; +import flixel.group.FlxContainer; +import flixel.group.FlxSpriteContainer; import haxe.ui.Toolkit; import haxe.ui.backend.flixel.CursorHelper; import haxe.ui.backend.flixel.KeyboardHelper; @@ -93,8 +93,8 @@ class ScreenImpl extends ScreenBase { if (rootComponents.indexOf(c) == -1) { addComponent(c); } - } else if ((m is FlxTypedGroup)) { - var group:FlxTypedGroup = cast m; + } else if ((m is FlxTypedContainer)) { + var group:FlxTypedContainer = cast m; checkMembers(group); } } @@ -106,7 +106,7 @@ class ScreenImpl extends ScreenBase { } } - private function checkMembers(state:FlxTypedGroup) { + private function checkMembers(state:FlxTypedContainer) { if (state == null || !state.exists) { return false; } @@ -119,15 +119,15 @@ class ScreenImpl extends ScreenBase { addComponent(c); found = true; } - } else if ((m is FlxTypedGroup)) { - var group:FlxTypedGroup = cast m; + } else if ((m is FlxTypedContainer)) { + var group:FlxTypedContainer = cast m; group.memberAdded.addOnce(onMemberAdded); if (checkMembers(group) == true) { found = true; break; } - } else if ((m is FlxTypedSpriteGroup)) { - var spriteGroup:FlxTypedSpriteGroup = cast m; + } else if ((m is FlxTypedSpriteContainer)) { + var spriteGroup:FlxTypedSpriteContainer = cast m; spriteGroup.group.memberAdded.addOnce(onMemberAdded); if (checkMembers(cast spriteGroup.group) == true) { found = true; @@ -339,7 +339,7 @@ class ScreenImpl extends ScreenBase { } } - private function containsUnsolicitedMemberAt(x:Float, y:Float, state:FlxTypedGroup):Bool { + private function containsUnsolicitedMemberAt(x:Float, y:Float, state:FlxTypedContainer):Bool { if (state == null || !state.exists) { return false; } @@ -364,12 +364,12 @@ class ScreenImpl extends ScreenBase { } } } - var spriteGroup:FlxTypedSpriteGroup = cast m; + var spriteGroup:FlxTypedSpriteContainer = cast m; if (containsUnsolicitedMemberAt(x, y, cast spriteGroup.group) == true) { return true; } - } else if ((m is FlxTypedSpriteGroup)) { - var spriteGroup:FlxTypedSpriteGroup = cast m; + } else if ((m is FlxTypedSpriteContainer)) { + var spriteGroup:FlxTypedSpriteContainer = cast m; if (!spriteGroup.visible) { continue; } diff --git a/haxe/ui/backend/flixel/UIFragmentBase.hx b/haxe/ui/backend/flixel/UIFragmentBase.hx index 0350066..0e6aed4 100644 --- a/haxe/ui/backend/flixel/UIFragmentBase.hx +++ b/haxe/ui/backend/flixel/UIFragmentBase.hx @@ -1,3 +1,3 @@ package haxe.ui.backend.flixel; -typedef UIFragmentBase = flixel.group.FlxSpriteGroup; \ No newline at end of file +typedef UIFragmentBase = flixel.group.FlxSpriteContainer; \ No newline at end of file From 97eee6bd410778bb12312b91de3f56d233ad7c42 Mon Sep 17 00:00:00 2001 From: GeoKureli-BlackbookPro Date: Fri, 7 Feb 2025 10:20:06 -0600 Subject: [PATCH 116/120] revert FlxContianers to FlxGroups --- haxe/ui/backend/ScreenImpl.hx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index a3b17cf..1f46dae 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -3,7 +3,7 @@ package haxe.ui.backend; import flixel.FlxBasic; import flixel.FlxG; import flixel.FlxSprite; -import flixel.group.FlxContainer; +import flixel.group.FlxGroup; import flixel.group.FlxSpriteContainer; import haxe.ui.Toolkit; import haxe.ui.backend.flixel.CursorHelper; @@ -93,8 +93,8 @@ class ScreenImpl extends ScreenBase { if (rootComponents.indexOf(c) == -1) { addComponent(c); } - } else if ((m is FlxTypedContainer)) { - var group:FlxTypedContainer = cast m; + } else if ((m is FlxTypedGroup)) { + var group:FlxTypedGroup = cast m; checkMembers(group); } } @@ -106,7 +106,7 @@ class ScreenImpl extends ScreenBase { } } - private function checkMembers(state:FlxTypedContainer) { + private function checkMembers(state:FlxTypedGroup) { if (state == null || !state.exists) { return false; } @@ -119,8 +119,8 @@ class ScreenImpl extends ScreenBase { addComponent(c); found = true; } - } else if ((m is FlxTypedContainer)) { - var group:FlxTypedContainer = cast m; + } else if ((m is FlxTypedGroup)) { + var group:FlxTypedGroup = cast m; group.memberAdded.addOnce(onMemberAdded); if (checkMembers(group) == true) { found = true; @@ -339,7 +339,7 @@ class ScreenImpl extends ScreenBase { } } - private function containsUnsolicitedMemberAt(x:Float, y:Float, state:FlxTypedContainer):Bool { + private function containsUnsolicitedMemberAt(x:Float, y:Float, state:FlxTypedGroup):Bool { if (state == null || !state.exists) { return false; } From 275c939a8eb05a0994044629f9b040b64e80ce17 Mon Sep 17 00:00:00 2001 From: GeoKureli-BlackbookPro Date: Fri, 7 Feb 2025 10:22:44 -0600 Subject: [PATCH 117/120] sprite containers too --- haxe/ui/backend/ScreenImpl.hx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 1f46dae..7f4f0cd 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -4,7 +4,7 @@ import flixel.FlxBasic; import flixel.FlxG; import flixel.FlxSprite; import flixel.group.FlxGroup; -import flixel.group.FlxSpriteContainer; +import flixel.group.FlxSpriteGroup; import haxe.ui.Toolkit; import haxe.ui.backend.flixel.CursorHelper; import haxe.ui.backend.flixel.KeyboardHelper; @@ -126,8 +126,8 @@ class ScreenImpl extends ScreenBase { found = true; break; } - } else if ((m is FlxTypedSpriteContainer)) { - var spriteGroup:FlxTypedSpriteContainer = cast m; + } else if ((m is FlxTypedSpriteGroup)) { + var spriteGroup:FlxTypedSpriteGroup = cast m; spriteGroup.group.memberAdded.addOnce(onMemberAdded); if (checkMembers(cast spriteGroup.group) == true) { found = true; @@ -364,12 +364,12 @@ class ScreenImpl extends ScreenBase { } } } - var spriteGroup:FlxTypedSpriteContainer = cast m; + var spriteGroup:FlxTypedSpriteGroup = cast m; if (containsUnsolicitedMemberAt(x, y, cast spriteGroup.group) == true) { return true; } - } else if ((m is FlxTypedSpriteContainer)) { - var spriteGroup:FlxTypedSpriteContainer = cast m; + } else if ((m is FlxTypedSpriteGroup)) { + var spriteGroup:FlxTypedSpriteGroup = cast m; if (!spriteGroup.visible) { continue; } From 61313123fc02cb608546ab0c45a4c4c0090b4c21 Mon Sep 17 00:00:00 2001 From: Ian Harrigan Date: Mon, 17 Feb 2025 09:33:20 +0100 Subject: [PATCH 118/120] fix for https://github.com/haxeui/haxeui-flixel/issues/61 --- haxe/ui/backend/ScreenImpl.hx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index 4d51fe2..530c4bc 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -275,12 +275,17 @@ class ScreenImpl extends ScreenBase { private override function handleSetComponentIndex(child:Component, index:Int) { var offset = 0; + StateHelper.currentState.forEach((item) -> { + offset++; + }); + /* see: https://github.com/haxeui/haxeui-flixel/issues/61 for (i in 0...StateHelper.currentState.length) { if ((StateHelper.currentState.members[i] is Component)) { offset = i; break; } } + */ StateHelper.currentState.remove(child, true); StateHelper.currentState.insert(index + offset, child); From 96ac633dd8aacb0142f2a7700fa0b6647e156935 Mon Sep 17 00:00:00 2001 From: UncertainProd <83609901+UncertainProd@users.noreply.github.com> Date: Thu, 10 Apr 2025 04:32:32 +0545 Subject: [PATCH 119/120] exclude code using FlxG.mouse from compilation if FLX_NO_MOUSE is defined --- haxe/ui/backend/ScreenImpl.hx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/haxe/ui/backend/ScreenImpl.hx b/haxe/ui/backend/ScreenImpl.hx index dc22049..7596740 100644 --- a/haxe/ui/backend/ScreenImpl.hx +++ b/haxe/ui/backend/ScreenImpl.hx @@ -169,9 +169,9 @@ class ScreenImpl extends ScreenBase { private var _cursor:String = null; public function setCursor(cursor:String, offsetX:Null = null, offsetY:Null = null) { - #if haxeui_flixel_no_custom_cursors + #if (haxeui_flixel_no_custom_cursors || FLX_NO_MOUSE) return; - #end + #else if (!CursorHelper.useCustomCursors) { return; @@ -190,6 +190,7 @@ class ScreenImpl extends ScreenBase { } else { FlxG.mouse.load(null); } + #end } public override function addComponent(component:Component):Component { From 2ba18130789cd72298598eaf78ce11232d907ee3 Mon Sep 17 00:00:00 2001 From: MAJigsaw77 <77043862+MAJigsaw77@users.noreply.github.com> Date: Thu, 26 Jun 2025 10:02:33 +0300 Subject: [PATCH 120/120] Fix `finishCallback` and `callback` warnings on flixel `5.9.0+`. --- haxe/ui/backend/flixel/components/SparrowPlayer.hx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/haxe/ui/backend/flixel/components/SparrowPlayer.hx b/haxe/ui/backend/flixel/components/SparrowPlayer.hx index c162c1c..c2c0176 100644 --- a/haxe/ui/backend/flixel/components/SparrowPlayer.hx +++ b/haxe/ui/backend/flixel/components/SparrowPlayer.hx @@ -169,12 +169,21 @@ class SparrowPlayer extends Box implements IDataComponent { var frames:FlxFramesCollection = FlxAtlasFrames.fromSparrow(png, Assets.getText(xml)); sprite.frames = frames; + #if (flixel >= "5.9.0") + if (!sprite.animation.onFrameChange.has(onFrame)) { + sprite.animation.onFrameChange.add(onFrame); + } + if (!sprite.animation.onFinish.has(onFinish)) { + sprite.animation.onFinish.add(onFinish); + } + #else if (sprite.animation.callback == null) { sprite.animation.callback = onFrame; } if (sprite.animation.finishCallback == null) { sprite.animation.finishCallback = onFinish; } + #end invalidateComponentLayout(); _animationLoaded = true;