Editor widget that inspects and edits a TilesetResource asset. It builds UI controls for tileset properties, global tags, rect ordering, provides buttons to generate/clear tiles, add/delete rects, respond to hotloads, and save changes back to the asset.
using Editor;
using Editor.Assets;
using Saandy.Tilemapper;
using Sandbox;
using static Editor.Inspectors.AssetInspector;
namespace Saandy.Editor.Tilemapper;
[CanEdit( "asset:tileset" )]
public sealed class TilesetResourceEditor : Widget, IAssetInspector
{
private Asset _asset;
private TilesetResource _tileset;
private ControlSheet _sheet;
private TilesetGlobalTagsWidget _globalTagsWidget;
private TilesetRectOrderWidget _rectWidget;
public TilesetResourceEditor( Widget parent ) : base( parent )
{
Layout = Layout.Column();
Layout.Margin = 8;
Layout.Spacing = 8;
MinimumHeight = 1000;
MinimumWidth = 600;
VerticalSizeMode = SizeMode.CanGrow;
HorizontalSizeMode = SizeMode.Flexible;
}
public void SetAssetPreview( AssetPreview preview )
{
}
public void SetAsset( Asset asset )
{
_asset = asset;
_tileset = asset?.LoadResource<TilesetResource>();
Rebuild();
}
[EditorEvent.Hotload]
private void OnHotload()
{
if ( _asset != null )
_tileset = _asset.LoadResource<TilesetResource>();
Rebuild();
}
private void Rebuild()
{
if ( Layout == null )
return;
Layout.Clear( true );
if ( _tileset == null )
{
Layout.Add( new Label( "No TilesetResource loaded.", this ) );
return;
}
var title = new Label( "Tileset Editor", this );
title.SetStyles( "font-size: 22px; font-weight: 700; margin-bottom: 8px;" );
Layout.Add( title );
var brushTemplate = TileBrushEditorTemplates.Get( _tileset.BrushType );
var brushInfo = new Label(
brushTemplate != null
? $"{brushTemplate.Title}: {brushTemplate.Description}"
: "No brush template selected.",
this
);
brushInfo.WordWrap = true;
brushInfo.SetStyles( "color: #ddd; margin-bottom: 6px;" );
Layout.Add( brushInfo );
var serializedObject = _tileset.GetSerialized();
_sheet = new ControlSheet();
_sheet.AddObject( serializedObject, prop =>
{
if ( prop.HasAttribute<HideAttribute>() )
return false;
if ( prop.Name == nameof( TilesetResource.Tiles ) )
return false;
if ( prop.Name == nameof( TilesetResource.GlobalTags ) )
return false;
return prop.HasAttribute<PropertyAttribute>();
} );
serializedObject.OnPropertyChanged += prop =>
{
if ( prop != null && prop.Name == nameof( TilesetResource.FilePath ) )
{
_tileset.ClearTextureCache();
_rectWidget?.Refresh();
MarkChanged();
return;
}
if ( prop != null && prop.Name == nameof( TilesetResource.BrushType ) )
{
MarkChanged();
Rebuild();
return;
}
MarkChanged();
};
Layout.Add( _sheet );
_globalTagsWidget = new TilesetGlobalTagsWidget( this, _tileset, MarkChanged )
{
MinimumWidth = 560
};
Layout.Add( _globalTagsWidget );
_rectWidget = new TilesetRectOrderWidget( _tileset, brushTemplate, MarkChanged )
{
MinimumWidth = 560
};
var buttonRow = Layout.Add( Layout.Row() );
buttonRow.Spacing = 6;
var generateButton = new Button( "Generate Grid Rects", "grid_on", this );
generateButton.Clicked = () =>
{
_tileset.GenerateTilesFromGrid();
MarkChanged();
_rectWidget?.Refresh();
_rectWidget?.LoadTemplateFromCurrentOrder();
};
buttonRow.Add( generateButton );
var clearButton = new Button( "Clear Tiles", "delete", this );
clearButton.Clicked = () =>
{
_tileset.ClearTiles();
MarkChanged();
_rectWidget?.Refresh();
_rectWidget?.ClearTemplate();
};
buttonRow.Add( clearButton );
var rectActionRow = Layout.Add( Layout.Row() );
rectActionRow.Spacing = 6;
var addRectButton = new Button( "Add Rect", "add", this );
addRectButton.Clicked = () => _rectWidget?.AddPendingRect();
rectActionRow.Add( addRectButton );
var deleteTileButton = new Button( "Delete Selected Rect", "delete", this );
deleteTileButton.Clicked = () => _rectWidget?.DeleteSelectedTile();
rectActionRow.Add( deleteTileButton );
if ( _rectWidget.HasTemplate )
{
var loadOrderButton = new Button( "Load Current Order", "refresh", this );
loadOrderButton.Clicked = () => _rectWidget?.LoadTemplateFromCurrentOrder();
rectActionRow.Add( loadOrderButton );
var applyOrderButton = new Button( "Apply Template Order", "done", this );
applyOrderButton.Clicked = () => _rectWidget?.ApplyTemplateOrder();
rectActionRow.Add( applyOrderButton );
}
Layout.Add( _rectWidget );
Layout.AddStretchCell();
}
private void MarkChanged()
{
if ( _tileset == null )
return;
_tileset.InternalUpdateTiles();
_tileset.StateHasChanged();
SaveAsset();
Update();
}
private void SaveAsset()
{
if ( _asset == null || _tileset == null )
return;
_asset.SaveToDisk( _tileset );
}
}