mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-11 07:48:36 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
160 lines
3.8 KiB
C#
160 lines
3.8 KiB
C#
namespace Sandbox.UI;
|
|
|
|
internal class WorldInputInternal : PanelInput
|
|
{
|
|
internal static List<WeakReference<WorldInputInternal>> WorldInputs = new();
|
|
|
|
internal bool Enabled { get; set; } = true;
|
|
internal Ray Ray { get; set; }
|
|
internal bool MouseLeftPressed;
|
|
internal bool MouseRightPressed;
|
|
internal Vector2 MouseWheel;
|
|
internal bool UseMouseInput;
|
|
|
|
public WorldInputInternal()
|
|
{
|
|
WorldInputs.Add( new WeakReference<WorldInputInternal>( this, false ) );
|
|
}
|
|
|
|
internal static void Clear()
|
|
{
|
|
WorldInputs.Clear();
|
|
}
|
|
|
|
internal static void TickAll( IEnumerable<RootPanel> panels )
|
|
{
|
|
for ( int i = WorldInputs.Count - 1; i >= 0; i-- )
|
|
{
|
|
// Remove any dead references
|
|
if ( !WorldInputs[i].TryGetTarget( out var input ) )
|
|
{
|
|
WorldInputs.RemoveAt( i );
|
|
continue;
|
|
}
|
|
|
|
input.Tick( panels, true );
|
|
}
|
|
}
|
|
|
|
internal override void Tick( IEnumerable<RootPanel> panels, bool mouseIsActive )
|
|
{
|
|
if ( !Enabled )
|
|
{
|
|
SetHovered( null );
|
|
return;
|
|
}
|
|
|
|
bool hoveredAny = false;
|
|
var inputData = GetInputData();
|
|
|
|
List<RootPanel> worldPanels = new();
|
|
foreach ( var panel in panels.Where( p => p.ChildrenWantMouseInput ) )
|
|
{
|
|
if ( panel.RayToLocalPosition( Ray, out panel.WorldCursor, out panel.WorldDistance ) )
|
|
worldPanels.Add( panel );
|
|
}
|
|
|
|
// In order of distance, update our mouse on them
|
|
foreach ( var panel in worldPanels.OrderBy( x => x.WorldDistance ) )
|
|
{
|
|
inputData.MousePos = panel.WorldCursor;
|
|
if ( UpdateMouse( panel, inputData ) )
|
|
{
|
|
hoveredAny = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !hoveredAny )
|
|
{
|
|
SetHovered( null );
|
|
}
|
|
|
|
SimulateEvents();
|
|
}
|
|
|
|
internal override InputData GetInputData()
|
|
{
|
|
if ( UseMouseInput )
|
|
{
|
|
return base.GetInputData();
|
|
}
|
|
|
|
return new InputData
|
|
{
|
|
Mouse0 = MouseLeftPressed,
|
|
Mouse2 = MouseRightPressed,
|
|
MouseWheel = MouseWheel,
|
|
};
|
|
}
|
|
|
|
//
|
|
// Simulate some events, these are a bit different from how InputRouter
|
|
// handles it, so it's a bit shit that this is repeated but required for now.
|
|
//
|
|
|
|
//
|
|
// We only want to count as a double click if it was clicked within
|
|
// a small amount of pixels & on the same root panel.
|
|
// It's not a double click if you click, move the mouse, and then click again.
|
|
//
|
|
internal Panel LastClickRoot;
|
|
internal Vector2 LastClickPos;
|
|
internal RealTimeSince LastClickTimeSince;
|
|
|
|
// Bit more forgiving then normal panels ( shaky VR hands )
|
|
internal const float MaxAltClickDelta = 50.0f;
|
|
|
|
internal Queue<string> DoubleClicks = new();
|
|
internal Vector2 MouseMovement;
|
|
internal Vector2 LastMousePosition;
|
|
|
|
internal override bool UpdateMouse( RootPanel root, InputData data )
|
|
{
|
|
MouseMovement += LastMousePosition - data.MousePos;
|
|
LastMousePosition = data.MousePos;
|
|
|
|
var leftMousePressed = !MouseStates[0].Pressed && data.Mouse0;
|
|
if ( leftMousePressed )
|
|
{
|
|
// Are we a double clicker ( 250ms matches engine )
|
|
if ( LastClickTimeSince < 0.25f && LastClickRoot == root )
|
|
{
|
|
// let's be a lot more forgiving with the delta then on normal panels
|
|
// people can have shaky vr hands
|
|
var AltClickDelta = LastClickPos - data.MousePos;
|
|
if ( AltClickDelta.Length < MaxAltClickDelta / root.Scale )
|
|
{
|
|
DoubleClicks.Enqueue( "mouseleft" );
|
|
}
|
|
}
|
|
|
|
LastClickRoot = root;
|
|
LastClickPos = data.MousePos;
|
|
LastClickTimeSince = 0;
|
|
}
|
|
|
|
return base.UpdateMouse( root, data );
|
|
}
|
|
|
|
internal void SimulateEvents()
|
|
{
|
|
var listSize = DoubleClicks.Count;
|
|
for ( int i = 0; i < listSize; i++ )
|
|
if ( DoubleClicks.TryDequeue( out var e ) )
|
|
{
|
|
Hovered?.CreateEvent( new MousePanelEvent( "ondoubleclick", Hovered, e ) );
|
|
}
|
|
|
|
if ( MouseMovement != 0 )
|
|
{
|
|
// If we're pressing down on a panel we send all the mouse move events to that
|
|
var moveRecv = Hovered;
|
|
if ( Active != null ) moveRecv = Active;
|
|
|
|
moveRecv?.CreateEvent( new MousePanelEvent( "onmousemove", moveRecv, "none" ) );
|
|
MouseMovement = 0;
|
|
}
|
|
}
|
|
}
|