Files
sbox-public/game/editor/ActionGraph/Code/InputActionControlWidget.cs
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

127 lines
3.0 KiB
C#

using Editor.NodeEditor;
using Sandbox;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Editor.ActionGraphs;
[CustomEditor( typeof( string ), WithAllAttributes = new[] { typeof( InputActionAttribute ) } )]
internal class InputActionControlWidget : ControlWidget
{
public override bool IsControlButton => true;
public override bool IsControlHovered => base.IsControlHovered || _menu.IsValid();
Menu _menu;
public InputActionControlWidget( SerializedProperty property ) : base( property )
{
Cursor = CursorShape.Finger;
Layout = Layout.Row();
Layout.Spacing = 2;
}
protected override void PaintControl()
{
var value = SerializedProperty.GetValue<string>();
var color = IsControlHovered ? Theme.Blue : Theme.TextControl;
var rect = LocalRect;
rect = rect.Shrink( 8, 0 );
var inputName = value?.ToLower() ?? "None";
Paint.SetPen( color );
Paint.DrawText( rect, string.IsNullOrWhiteSpace( inputName ) ? "None" : inputName, TextFlag.LeftCenter );
Paint.SetPen( color );
Paint.DrawIcon( rect, "Arrow_Drop_Down", 17, TextFlag.RightCenter );
}
public override void StartEditing()
{
if ( !_menu.IsValid() )
{
OpenMenu();
}
}
protected override void OnMousePress( MouseEvent e )
{
base.OnMousePress( e );
if ( e.LeftMouseButton && !_menu.IsValid() )
{
OpenMenu();
}
}
void OpenMenu()
{
var actions = Sandbox.Input.ActionNames
.ToArray();
_menu = new ContextMenu( this );
_menu.DeleteOnClose = true;
_menu.AddLineEdit( "Filter", placeholder: "Filter Actions..",
autoFocus: true,
onChange: s => PopulateInputActionMenu( _menu, actions, s ) );
_menu.AboutToShow += () => PopulateInputActionMenu( _menu, actions );
_menu.OpenAtCursor( true );
_menu.MinimumWidth = ScreenRect.Width;
}
private void PopulateInputActionMenu( Menu menu, IEnumerable<string> actions, string filter = null )
{
menu.RemoveMenus();
menu.RemoveOptions();
const int maxFiltered = 10;
var useFilter = !string.IsNullOrEmpty( filter );
var truncated = 0;
_menu.AddOption( "Set to None", "clear_all", () => SerializedProperty.SetValue<string>( "" ) );
if ( useFilter )
{
var filtered = actions.Where( x => x.Contains( filter, StringComparison.OrdinalIgnoreCase ) ).ToArray();
if ( filtered.Length > maxFiltered + 1 )
{
truncated = filtered.Length - maxFiltered;
actions = filtered.Take( maxFiltered );
}
else
{
actions = filtered;
}
}
actions = actions
.OrderBy( x => Sandbox.Input.GetGroupName( x ) ?? "Other", StringComparer.OrdinalIgnoreCase )
.ThenBy( x => x, StringComparer.OrdinalIgnoreCase );
foreach ( var action in actions )
{
var group = Sandbox.Input.GetGroupName( action ) ?? "Other";
var groupMenu = string.IsNullOrEmpty( filter ) ? menu.FindOrCreateMenu( group ) : menu;
var option = groupMenu.AddOption( action?.ToLower(), "gamepad" );
option.Triggered += () => SerializedProperty.SetValue( action );
}
if ( truncated > 0 )
{
menu.AddOption( $"...and {truncated} more" );
}
menu.AdjustSize();
menu.Update();
}
}