using Godot; using System; using System.Collections.Generic; using System.Text.Json.Serialization; namespace Rokojori { public class UIDragging { public class UIDraggingCallbacks: ICustomDisposer { public UI ui; public Control control; public bool wasDisposed = false; public Action onMouseClick; public Callable callable; public Action onDragging; public Action onProcess; public Dictionary mouseEvents = new Dictionary(); 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 )=> { 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 ( 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.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 ); } callbacks.mouseEventsDragging[ button ] = 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.Value ) { return true; } } return false; } } public bool hasDraggingCallback = false; public EditableUIDraggingEvent GetMouseEvent( MouseButton mb ) { if ( ! mouseEvents.ContainsKey( mb ) ) { mouseEvents[ mb ] = new EditableUIDraggingEvent( mb ); } mouseEvents[ mb ].SetUI( ui ); return mouseEvents[ mb ]; } 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; } } }