mirror of
https://github.com/Facepunch/sbox-public.git
synced 2025-12-23 22:48:07 -05:00
354 lines
9.1 KiB
C#
354 lines
9.1 KiB
C#
using System.Reflection;
|
|
|
|
namespace Sandbox.UI;
|
|
|
|
public partial class Panel
|
|
{
|
|
internal struct EventCallback
|
|
{
|
|
public string EventName;
|
|
public Action BaseAction;
|
|
public Action<PanelEvent> Action;
|
|
public bool Automatic;
|
|
|
|
public Action<EventCallback, PanelEvent> Event;
|
|
public Panel Panel;
|
|
public Panel Context;
|
|
}
|
|
|
|
internal List<EventCallback> EventListeners { get; set; }
|
|
|
|
/// <summary>
|
|
/// Called on creation and hotload to delete and re-initialize event listeners.
|
|
/// </summary>
|
|
protected virtual void InitializeEvents()
|
|
{
|
|
EventListeners?.RemoveAll( x => x.Automatic );
|
|
|
|
if ( Game.TypeLibrary == null || !Game.TypeLibrary.TryGetType( GetType(), out var typeDescription ) )
|
|
return;
|
|
|
|
|
|
foreach ( var methodDesc in typeDescription.Members.OfType<MethodDescription>() )
|
|
{
|
|
if ( methodDesc.IsStatic ) continue;
|
|
|
|
var pea = methodDesc.Attributes.OfType<PanelEventAttribute>().FirstOrDefault();
|
|
if ( pea == null ) continue;
|
|
|
|
var method = methodDesc.MemberInfo as MethodInfo;
|
|
var event_name = methodDesc.Name.ToLower();
|
|
|
|
var args = method.GetParameters(); // todo cache
|
|
var ret = method.ReturnParameter;
|
|
|
|
if ( event_name.EndsWith( "event" ) ) event_name = event_name[..^5];
|
|
if ( pea != null && pea.Name != null ) event_name = pea.Name.ToLower();
|
|
|
|
if ( args.Length == 1 )
|
|
{
|
|
var argType = args[0].ParameterType;
|
|
var argcache = new object[1];
|
|
|
|
if ( argType == typeof( PanelEvent ) )
|
|
{
|
|
AddAutomaticEventListener( event_name, ( x ) => { argcache[0] = x; method.Invoke( this, argcache ); } );
|
|
}
|
|
else
|
|
{
|
|
AddAutomaticEventListener( event_name, ( x ) =>
|
|
{
|
|
argcache[0] = Convert.ChangeType( x.Value, argType );
|
|
var response = method.Invoke( this, argcache );
|
|
|
|
// If the response is a bool, and false, stop propogation
|
|
if ( response != null && response is bool bReturnedValue )
|
|
{
|
|
x.Propagate = x.Propagate && bReturnedValue;
|
|
}
|
|
|
|
} );
|
|
|
|
}
|
|
}
|
|
else if ( args.Length == 0 )
|
|
{
|
|
AddAutomaticEventListener( event_name, ( x ) =>
|
|
{
|
|
var response = method.Invoke( this, null );
|
|
|
|
// If the response is a bool, and false, stop propogation
|
|
if ( response != null && response is bool bReturnedValue )
|
|
{
|
|
x.Propagate = x.Propagate && bReturnedValue;
|
|
}
|
|
|
|
} );
|
|
}
|
|
else
|
|
{
|
|
Log.Warning( $"PanelEvent {method} - couldn't set up (too many arguments)" );
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void AddAutomaticEventListener( string name, Action<PanelEvent> e )
|
|
{
|
|
EventListeners ??= new List<EventCallback>();
|
|
|
|
var ev = new EventCallback
|
|
{
|
|
EventName = name,
|
|
Action = e,
|
|
Automatic = true
|
|
};
|
|
|
|
EventListeners.Add( ev );
|
|
}
|
|
|
|
internal void RemoveEventListener( string name )
|
|
{
|
|
EventListeners?.RemoveAll( x => x.EventName == name );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Runs given callback when the given event is triggered.
|
|
/// </summary>
|
|
public void AddEventListener( string eventName, Action<PanelEvent> e )
|
|
{
|
|
AddEventListener( new EventCallback
|
|
{
|
|
EventName = eventName,
|
|
Action = e
|
|
} );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Runs given callback when the given event is triggered, without access to the <see cref="PanelEvent"/>.
|
|
/// </summary>
|
|
public void AddEventListener( string eventName, Action action )
|
|
{
|
|
AddEventListener( new EventCallback
|
|
{
|
|
EventName = eventName,
|
|
BaseAction = action
|
|
} );
|
|
}
|
|
|
|
internal void AddEventListener( EventCallback eventCallback )
|
|
{
|
|
EventListeners ??= new List<EventCallback>();
|
|
EventListeners.Add( eventCallback );
|
|
}
|
|
|
|
List<PanelEvent> PendingEvents;
|
|
|
|
internal void RunPendingEvents()
|
|
{
|
|
if ( PendingEvents is null || PendingEvents.Count == 0 ) return;
|
|
|
|
for ( int i = 0; i < PendingEvents.Count; i++ )
|
|
{
|
|
var e = PendingEvents[i];
|
|
if ( e.Time > TimeNow ) continue;
|
|
|
|
PendingEvents.RemoveAt( i );
|
|
i--;
|
|
|
|
try
|
|
{
|
|
OnEvent( e );
|
|
}
|
|
catch ( System.Exception ex )
|
|
{
|
|
Log.Error( ex, $"\"{ex.Message}\" when running panel event \"{e.Name}\" from \"{e.Target}\"" );
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a new event and pass it to the panels event queue.
|
|
/// </summary>
|
|
/// <param name="name">Event name.</param>
|
|
/// <param name="value">Event value.</param>
|
|
/// <param name="debounce">Time, in seconds, to wait before firing the event.<br/>
|
|
/// All subsequent calls to <see cref="CreateEvent(string, object, float?)"/> with the same event
|
|
/// name will update the original event instead of creating a new event, until it finally triggers.</param>
|
|
public virtual void CreateEvent( string name, object value = null, float? debounce = null )
|
|
{
|
|
var e = PendingEvents?.FirstOrDefault( x => x.Name == name );
|
|
if ( e == null )
|
|
{
|
|
e = new PanelEvent( name, this );
|
|
CreateEvent( e );
|
|
}
|
|
|
|
e.Value = value;
|
|
|
|
if ( debounce.HasValue )
|
|
{
|
|
e.Time = (float)(TimeNow + debounce.Value);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Pass given event to the event queue.
|
|
/// </summary>
|
|
public virtual void CreateEvent( PanelEvent evnt )
|
|
{
|
|
PendingEvents ??= new List<PanelEvent>();
|
|
PendingEvents.Add( evnt );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when various <see cref="PanelEvent"/>s happen. Handles event listeners and many standard events by default.
|
|
/// </summary>
|
|
protected virtual void OnEvent( PanelEvent e )
|
|
{
|
|
e.This = this;
|
|
|
|
if ( e is CopyEvent || e is CutEvent )
|
|
{
|
|
var text = GetClipboardValue( e is CutEvent );
|
|
if ( text != null )
|
|
{
|
|
NativeEngine.EngineGlobal.Plat_SetClipboardText( text );
|
|
}
|
|
}
|
|
|
|
if ( e is PasteEvent paste )
|
|
{
|
|
OnPaste( paste.ClipboardValue );
|
|
}
|
|
|
|
if ( e is MousePanelEvent mpe )
|
|
{
|
|
if ( e.Is( "onclick" ) ) OnClick( mpe );
|
|
if ( e.Is( "onmiddleclick" ) ) OnMiddleClick( mpe );
|
|
if ( e.Is( "onrightclick" ) ) OnRightClick( mpe );
|
|
if ( e.Is( "onmousedown" ) ) OnMouseDown( mpe );
|
|
if ( e.Is( "onmouseup" ) ) OnMouseUp( mpe );
|
|
if ( e.Is( "ondoubleclick" ) ) OnDoubleClick( mpe );
|
|
if ( e.Is( "onmousemove" ) ) OnMouseMove( mpe );
|
|
if ( e.Is( "onmouseover" ) ) OnMouseOver( mpe );
|
|
if ( e.Is( "onmouseout" ) ) OnMouseOut( mpe );
|
|
|
|
if ( !e.Is( "onmousemove" ) )
|
|
{
|
|
razorTreeDirty = true;
|
|
}
|
|
}
|
|
|
|
if ( e is DragEvent de )
|
|
{
|
|
InternalDragEvent( de );
|
|
}
|
|
|
|
if ( e.Is( "onfocus" ) ) OnFocus( e );
|
|
if ( e.Is( "onblur" ) ) OnBlur( e );
|
|
if ( e.Is( "onback" ) ) OnBack( e );
|
|
if ( e.Is( "onforward" ) ) OnForward( e );
|
|
if ( e.Is( "onescape" ) ) OnEscape( e );
|
|
|
|
if ( e is SelectionEvent se )
|
|
{
|
|
if ( e.Is( "ondragselect" ) ) OnDragSelect( se );
|
|
}
|
|
|
|
if ( !e.Propagate )
|
|
return;
|
|
|
|
if ( EventListeners != null )
|
|
{
|
|
foreach ( var listener in EventListeners )
|
|
{
|
|
if ( !e.Is( listener.EventName ) ) continue;
|
|
|
|
listener.Event?.Invoke( listener, e );
|
|
listener.Action?.Invoke( e );
|
|
listener.BaseAction?.Invoke();
|
|
}
|
|
}
|
|
|
|
if ( !e.Propagate ) return;
|
|
|
|
Parent?.OnEvent( e );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when the player releases their left mouse button (Mouse 1) while hovering this panel.
|
|
/// </summary>
|
|
protected virtual void OnClick( MousePanelEvent e ) { }
|
|
|
|
/// <summary>
|
|
/// Called when the player releases their middle mouse button (Mouse 3) while hovering this panel.
|
|
/// </summary>
|
|
protected virtual void OnMiddleClick( MousePanelEvent e ) { }
|
|
|
|
/// <summary>
|
|
/// Called when the player releases their right mouse button (Mouse 2) while hovering this panel.
|
|
/// </summary>
|
|
protected virtual void OnRightClick( MousePanelEvent e ) { }
|
|
|
|
/// <summary>
|
|
/// Called when the player presses down the left or right mouse buttons while hovering this panel.
|
|
/// </summary>
|
|
protected virtual void OnMouseDown( MousePanelEvent e ) { }
|
|
|
|
/// <summary>
|
|
/// Called when the player releases left or right mouse button.
|
|
/// </summary>
|
|
protected virtual void OnMouseUp( MousePanelEvent e ) { }
|
|
|
|
/// <summary>
|
|
/// Called when the player double clicks the panel with the left mouse button.
|
|
/// </summary>
|
|
protected virtual void OnDoubleClick( MousePanelEvent e ) { }
|
|
|
|
/// <summary>
|
|
/// Called when the cursor moves while hovering this panel.
|
|
/// </summary>
|
|
protected virtual void OnMouseMove( MousePanelEvent e ) { }
|
|
|
|
/// <summary>
|
|
/// Called when the cursor enters this panel.
|
|
/// </summary>
|
|
protected virtual void OnMouseOver( MousePanelEvent e ) { }
|
|
|
|
/// <summary>
|
|
/// Called when the cursor leaves this panel.
|
|
/// </summary>
|
|
protected virtual void OnMouseOut( MousePanelEvent e ) { }
|
|
|
|
/// <summary>
|
|
/// Called when the player presses the "Back" button while hovering this panel, which is typically "mouse 5", aka one of the mouse buttons on its side.
|
|
/// </summary>
|
|
protected virtual void OnBack( PanelEvent e ) { }
|
|
|
|
|
|
/// <summary>
|
|
/// Called when the player presses the "Forward" button while hovering this panel, which is typically "mouse 4", aka one of the mouse buttons on its side.
|
|
/// </summary>
|
|
protected virtual void OnForward( PanelEvent e ) { }
|
|
|
|
/// <summary>
|
|
/// Called when the escape key is pressed
|
|
/// </summary>
|
|
protected virtual void OnEscape( PanelEvent e )
|
|
{
|
|
if ( HasFocus )
|
|
Blur();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when this panel receives input focus.
|
|
/// </summary>
|
|
protected virtual void OnFocus( PanelEvent e ) { }
|
|
|
|
/// <summary>
|
|
/// Called when this panel loses input focus.
|
|
/// </summary>
|
|
protected virtual void OnBlur( PanelEvent e ) { }
|
|
}
|