UI/SpawnMenu/ToolsTab.razor

Razor UI panel for the spawn menu Tools tab. It lists available ToolMode types from the TypeLibrary, allows switching the active tool mode, and shows property controls either for the selected postprocess components or the currently active tool mode.

Reflection
@using Sandbox;
@using Sandbox.UI;
@inherits Panel
@namespace Sandbox
@implements IUtilityTab
@attribute [Icon( "🔧" )]
@attribute [Title( "#spawnmenu.tab.tools" )]
@attribute [Order( -100 )]

<root class="tab">
	<div class="left">
        <VerticalMenu Value="@(CurrentMode?.GetType())"  class="menuinner">
            <Options>
                @foreach (var group in Game.TypeLibrary.GetTypes<ToolMode>().GroupBy(x => x.Group).OrderBy( x => x.Key ) )
                {
                    @if ( !string.IsNullOrWhiteSpace( group.Key ) )
                    {
                        <h2>@group.Key</h2>
                    }

                    @foreach (var type in group.OrderBy(x => x.Title))
                    {
                        if (type.IsAbstract) continue;

                        <MenuOption Text="@type.Title" Icon="@type.Icon" @onclick="@(() => SwitchMode(type))" Value="@type.TargetType"></MenuOption>
                    }
                }
            </Options>
        </VerticalMenu>
	</div>

    <div class="body menuinner">
        @if ( PostProcessManager?.GetSelectedComponents().Count > 0 )
        {
            @foreach ( var component in PostProcessManager.GetSelectedComponents() )
            {
                <h2>@(Game.TypeLibrary.GetType( component.GetType() )?.Title ?? component.GetType().Name)</h2>
                <ControlSheet Target="@component" PropertyFilter="@FilterProperties"></ControlSheet>
            }
        }
        else
        {
            <ControlSheet PropertyFilter="@FilterProperties" Target="@GetCurrentMode()"></ControlSheet>
        }
	</div>

</root>

@code
{
    ToolMode CurrentMode => Player.FindLocalPlayer()?.GetWeapon<Toolgun>()?.GetCurrentMode();
    PostProcessManager PostProcessManager => Game.ActiveScene.GetSystem<PostProcessManager>();

    protected override int BuildHash() => HashCode.Combine(CurrentMode, PostProcessManager?.SelectedPath, PostProcessManager?.GetSelectedComponents().Count);

	bool IsActiveMode( TypeDescription t )
	{
		var localPlayer = Player.FindLocalPlayer();
		var toolgun = localPlayer?.GetWeapon<Toolgun>();
		if (!toolgun.IsValid()) return false;

		return toolgun.GetCurrentMode()?.GetType() == t.TargetType;
	}

	void SwitchMode(TypeDescription t)
	{
		var localPlayer = Player.FindLocalPlayer();
		if ( localPlayer == null ) return;

		PostProcessManager?.Deselect();

		var inventory = localPlayer.GetComponent<PlayerInventory>();
		if ( !inventory.IsValid() ) return;

		inventory.SetToolMode( t.ClassName );
	}

	protected override void OnVisibilityChanged()
	{
		if ( !IsVisible )
		{
			GetCurrentMode()?.SaveCookies();
		}
	}

	ToolMode GetCurrentMode()
	{
		var localPlayer = Player.FindLocalPlayer();
		var toolgun = localPlayer?.GetWeapon<Toolgun>();
		return toolgun?.GetCurrentMode();
	}

	static bool FilterProperties(SerializedProperty o)
	{
		if (o.PropertyType is null) return false;
		if (o.PropertyType.IsAssignableTo(typeof(Delegate))) return false;

		if (o.IsMethod) return true;
		if (!o.HasAttribute<PropertyAttribute>()) return false;

		return true;
	}
}