Files
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

137 lines
3.2 KiB
C#

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
namespace Sandbox.UI;
public partial class Panel
{
/// <summary>
/// true when the tree should be re-rendered next frame.
/// </summary>
bool razorTreeDirty = true;
string razorLastTreeChecksum = null;
[Parameter] public RenderFragment ChildContent { get; set; }
/// <summary>
/// For razor panels, call when the state of the render tree has changed such that
/// it would be a good idea to re-render the tree. You would usually not need to call
/// this manually.
/// </summary>
public void StateHasChanged()
{
ThreadSafe.AssertIsMainThread();
razorTreeDirty = true;
}
/// <summary>
/// Overridden/implemented by Razor templating, contains render tree checksum to determine when the render tree content has changed.
/// </summary>
protected virtual string GetRenderTreeChecksum() => ChildContent == null ? null : "1";
internal bool HasRenderTree => GetRenderTreeChecksum() is not null;
PanelRenderTreeBuilder renderTree;
/// <summary>
/// Overridden/implemented by Razor templating to build a render tree.
/// </summary>
protected virtual void BuildRenderTree( RenderTreeBuilder tree )
{
ChildContent?.Invoke( tree );
}
int previousHash;
/// <summary>
/// By overriding this you can return a hash of variables used by the Razor layout, which
/// will cause a rebuild when changed. This is useful when your layout uses a global variable
/// because by adding it to a HashCode.Combine here you can easily trigger a build when it changes.
/// </summary>
protected virtual int BuildHash()
{
return 0;
}
/// <summary>
/// A RenderFragment has been set on us, so our tree has potential changes now.
/// Lets update and see.
/// </summary>
public void OnRenderFragmentChanged( Panel upTo )
{
if ( upTo == this )
return;
razorTreeDirty = true;
Parent?.OnRenderFragmentChanged( upTo );
}
internal void InternalTreeBinds()
{
if ( renderTree == null )
return;
try
{
var hash = BuildHash();
if ( previousHash != hash )
{
previousHash = hash;
razorTreeDirty = true;
}
}
catch ( System.Exception e )
{
Log.Warning( e, $"Error calculating hash on {GetType()} - {e.Message}" );
}
if ( renderTree.UpdateBinds() )
{
razorTreeDirty = true;
}
}
/// <summary>
/// Allows building render tree from outside of the class.
/// </summary>
internal RenderTreeBuilder InternalRenderTree()
{
if ( !HasRenderTree )
return null;
razorTreeDirty = false;
renderTree ??= new PanelRenderTreeBuilder( this );
razorLastTreeChecksum = GetRenderTreeChecksum();
renderTree.Start();
try
{
BuildRenderTree( renderTree );
}
catch ( System.Exception e )
{
Log.Warning( e, $"Error when building render tree on {GetType()} - {e.Message}" );
}
renderTree.Finish();
return renderTree;
}
/// <summary>
/// Called after the razor tree has been created/rendered.
/// </summary>
protected virtual void OnAfterTreeRender( bool firstTime )
{
}
/// <summary>
/// Delete all children generated by the Razor render tree.
/// </summary>
internal void ClearRenderTree()
{
renderTree?.Clear();
renderTree = null;
}
}