using Godot; using System; using System.Collections.Generic; using System.Text.Json.Serialization; namespace Rokojori { public class UIDragging { public class MappedEvent { public MouseButton mouseButton; public EditableUIDraggingEvent uiEvent; } public class ButtonState { public MouseButton mouseButton; public bool dragging; } public class UIDraggingCallbacks: ICustomDisposer { public UI ui; public Control control; public bool wasDisposed = false; public bool notValid => wasDisposed || onMouseClick == null || onDragging == null || onProcess == null || mouseEvents == null || mouseEvents.FilterNulls().Count == 0 || mouseEventsDragging == null || mouseEventsDragging.FilterNulls().Count == 0; public Action onMouseClick; public Callable callable; public Action onDragging; public Action onProcess; // public Dictionary mouseEvents = new Dictionary(); public List mouseEvents = new List(); public List mouseEventsDragging = new List(); // public Dictionary mouseEventsDragging = new Dictionary(); public string uid = IDGenerator.GenerateID(); public string GetUID(){ return uid; } string info = ""; public string GetInfo(){ return info;} public void Set( Control c, Func callback ) { var callbacks = this; callbacks.control = c; callbacks.ui = c.FindParentThatIs(); callbacks.ui.AddForDisposing( callbacks ); info = HierarchyName.Of( c ); callbacks.onProcess = (float delta )=> { callbacks.mouseEvents.ForEach( ( m )=> { callback( m.uiEvent ); } ); // foreach ( var m in callbacks.mouseEvents ) // { // callback( callbacks.mouseEvents[ m.Key ] ); // } }; callbacks.onDragging = ( InputEvent ie ) => { if ( ie is InputEventMouseButton mb && ! mb.Pressed ) { var mdIndex = callbacks.mouseEventsDragging.FindIndex( me => me.mouseButton == mb.ButtonIndex ); var meIndex = callbacks.mouseEvents.FindIndex( md => md.mouseButton == mb.ButtonIndex ); callbacks.mouseEventsDragging[ mdIndex ].dragging = false; callbacks.mouseEvents[ meIndex ].uiEvent.UpdatePosition( mb.GlobalPosition, true ); callback( callbacks.mouseEvents[ meIndex ].uiEvent ); if ( ! callbacks.hasAnyMouseDragging ) { callbacks.ui.onInputEvent.RemoveAction( callbacks.onDragging ); callbacks.ui.onProcess.RemoveAction( callbacks.onProcess ); callbacks.hasDraggingCallback = false; if ( c is UIStylePropertyContainer sc ) { sc.GetUISelectorFlags().Remove( UISelectorFlag.Dragging ); } } } if ( ie is InputEventMouseMotion mo ) { var globalPosition = mo.GlobalPosition; // foreach ( var m in callbacks.mouseEvents ) // { // callbacks.mouseEvents[ m.Key ].UpdatePosition( globalPosition ); // // callback( callbacks.mouseEvents[ m.Key ] ); // } callbacks.mouseEvents.ForEach( ( m )=> { m.uiEvent.UpdatePosition( globalPosition ); } ); } }; callbacks.onMouseClick = ( InputEvent ie )=> { if ( ! ( ie is InputEventMouseButton b && b.Pressed ) ) { return; } var mb = ie as InputEventMouseButton; var button = mb.ButtonIndex; var draggingEvent = callbacks.GetMouseEvent( button ); draggingEvent.SetStart( mb.GlobalPosition ); var result = callback( draggingEvent ); if ( ! result ) { return; } if ( c is UIStylePropertyContainer sc ) { sc.GetUISelectorFlags().AddIfNotPresent( UISelectorFlag.Dragging ); } var buttonIndex = callbacks.mouseEventsDragging.FindIndex( bs => bs.mouseButton == button ); if ( buttonIndex == -1 ) { var bs = new ButtonState(); bs.mouseButton = button; callbacks.mouseEventsDragging.Add( bs ); buttonIndex = callbacks.mouseEventsDragging.Count - 1; } callbacks.mouseEventsDragging[ buttonIndex ].dragging = true; if ( ! callbacks.hasDraggingCallback ) { callbacks.ui.onInputEvent.AddAction( callbacks.onDragging ); callbacks.ui.onProcess.AddAction( callbacks.onProcess ); } }; callbacks.Connect(); wasDisposed = false; } public void Dispose() { wasDisposed = true; if ( control != null && Node.IsInstanceValid( control ) ) { control.Disconnect( "gui_input", callable ); } // ui = null; // control = null; onMouseClick = null; onDragging = null; onProcess = null; mouseEvents.Clear(); mouseEventsDragging.Clear(); // mouseEvents = null; // mouseEventsDragging = null; } public bool hasAnyMouseDragging { get { foreach ( var mb in mouseEventsDragging ) { if ( mb.dragging ) { return true; } } return false; } } public bool hasDraggingCallback = false; public EditableUIDraggingEvent GetMouseEvent( MouseButton mb ) { var index = mouseEvents.FindIndex( m => m.mouseButton == mb ); if ( index == -1) { var mappedEvent = new MappedEvent(); mappedEvent.mouseButton = mb; mappedEvent.uiEvent = new EditableUIDraggingEvent( mb ); mouseEvents.Add( mappedEvent ); index = mouseEvents.Count - 1; } mouseEvents[ index ].uiEvent.SetUI( ui ); return mouseEvents[ index ].uiEvent; } public void Clear() { control.Disconnect( "gui_input", callable ); } public void Connect() { callable = Callable.From( onMouseClick ); control.Connect( "gui_input", callable ); } } public class UIDraggingEvent { public enum Phase { Start, Dragging, End } protected Phase _phase = Phase.Start; public bool isStart => Phase.Start == _phase; public bool isDragging => Phase.Dragging == _phase; public bool isEnd => Phase.End == _phase; protected UI _ui; public UI ui => _ui; protected MouseButton _mouseButton; public MouseButton mouseButton => _mouseButton; public bool isLeftMouseButton => MouseButton.Left == _mouseButton; public bool isMiddleMouseButton => MouseButton.Middle == _mouseButton; public bool isRightMouseButton => MouseButton.Right == _mouseButton; public Vector2 customOffset; protected int _touchID = -1; protected Vector2 _startPosition; protected Vector2 _position; protected Vector2 _lastPosition; protected Vector2 _furthestPointFromStart; protected float _biggestDistance; public Vector2 startPosition => _startPosition; public Vector2 position => _position; public Vector2 lastPosition => _lastPosition; public Vector2 movementSinceLastFrame => _position - lastPosition; public Vector2 distanceToStart => _position - _startPosition; public Vector2 furthestPointToStart => _furthestPointFromStart; public float maximumMovement => _biggestDistance; public UIDraggingEvent( MouseButton mb ) { _mouseButton = mb; } public UIDraggingEvent( int touchID ) { this._touchID = touchID; } } public class EditableUIDraggingEvent:UIDraggingEvent { public EditableUIDraggingEvent( MouseButton mb ):base( mb ){} public EditableUIDraggingEvent( int touchID ):base( touchID ){} public void SetUI( UI ui ) { _ui = ui; } public void SetStart( Vector2 startPosition ) { _startPosition = startPosition; _position = startPosition; _lastPosition = startPosition; _furthestPointFromStart = Vector2.Zero; _phase = Phase.Start; } public void UpdatePosition( Vector2 position, bool isEnd = false ) { _lastPosition = _position; _position = position; var d = position.DistanceTo( _startPosition ); if ( d > _biggestDistance ) { _biggestDistance = d; _furthestPointFromStart = position; } _phase = isEnd ? Phase.End : Phase.Dragging; } } public static UIDraggingCallbacks OnLeftMouseButton( Control c, Action callback ) { return OnOneMouseButton( c, MouseButton.Left, callback ); } public static UIDraggingCallbacks OnMiddleMouseButton( Control c, Action callback ) { return OnOneMouseButton( c, MouseButton.Middle, callback ); } public static UIDraggingCallbacks OnRightMouseButton( Control c, Action callback ) { return OnOneMouseButton( c, MouseButton.Right, callback ); } public static UIDraggingCallbacks OnOneMouseButton( Control c, MouseButton mouseButton, Action callback ) { var oneButtonCallback = ( UIDraggingEvent ev ) => { if ( ev.mouseButton != mouseButton ) { return false; } callback( ev ); return true; }; return OnAnyMouseButton( c, oneButtonCallback ); } public static UIDraggingCallbacks OnAnyMouseButton( Control c, Func callback ) { var callbacks = new UIDraggingCallbacks(); callbacks.Set( c, callback ); // callbacks.control = c; // callbacks.ui = c.FindParentThatIs(); // callbacks.ui.AddForDisposing( callbacks ); // callbacks.onProcess = (float delta )=> // { // foreach ( var m in callbacks.mouseEvents ) // { // callback( callbacks.mouseEvents[ m.Key ] ); // } // }; // callbacks.onDragging = ( InputEvent ie ) => // { // if ( ie is InputEventMouseButton mb && ! mb.Pressed ) // { // callbacks.mouseEventsDragging[ mb.ButtonIndex ] = false; // callbacks.mouseEvents[ mb.ButtonIndex ].UpdatePosition( mb.GlobalPosition, true ); // callback( callbacks.mouseEvents[ mb.ButtonIndex ] ); // if ( ! callbacks.hasAnyMouseDragging ) // { // callbacks.ui.onInputEvent.RemoveAction( callbacks.onDragging ); // callbacks.ui.onProcess.RemoveAction( callbacks.onProcess ); // callbacks.hasDraggingCallback = false; // } // } // if ( ie is InputEventMouseMotion mo ) // { // var globalPosition = mo.GlobalPosition; // foreach ( var m in callbacks.mouseEvents ) // { // callbacks.mouseEvents[ m.Key ].UpdatePosition( globalPosition ); // // callback( callbacks.mouseEvents[ m.Key ] ); // } // } // }; // callbacks.onMouseClick = ( InputEvent ie )=> // { // if ( ! ( ie is InputEventMouseButton b && b.Pressed ) ) // { // return; // } // var mb = ie as InputEventMouseButton; // var button = mb.ButtonIndex; // var draggingEvent = callbacks.GetMouseEvent( button ); // draggingEvent.SetStart( mb.GlobalPosition ); // var result = callback( draggingEvent ); // if ( ! result ) // { // return; // } // callbacks.mouseEventsDragging[ button ] = true; // if ( ! callbacks.hasDraggingCallback ) // { // callbacks.ui.onInputEvent.AddAction( callbacks.onDragging ); // callbacks.ui.onProcess.AddAction( callbacks.onProcess ); // } // }; // callbacks.Connect(); // c.Connect( "gui_input", Callable.From( callbacks.onMouseClick ) ); // c.GuiInput += callbacks.onMouseClick; return callbacks; } } }