Editor/TagsPicker.cs
using System;
using System.Buffers.Text;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Editor;
using Sandbox;
namespace DesignerBrowser.Editor;
public class TagsPicker : Widget
{
public Action Updated;
private ScrollArea Scroller;
public Func<AssetTagSystem.TagDefinition, bool> Filter;
public TagsPicker( Widget parent = null ) : base( parent )
{
Layout = Layout.Column();
Scroller = new ScrollArea( this );
Scroller.VerticalScrollbarMode = ScrollbarMode.Off;
Scroller.HorizontalScrollbarMode = ScrollbarMode.Off;
Scroller.Canvas = new Widget( Scroller );
Scroller.Canvas.Layout = Layout.Row();
Scroller.Canvas.Layout.Alignment = TextFlag.Left;
Scroller.Canvas.Layout.Spacing = 4;
Scroller.Canvas.Layout.Margin = new Sandbox.UI.Margin( 4, 0 );
Layout.Add( Scroller, 1 );
var addButton = new IconButton("add");
addButton.OnClick = () =>
{
var selector = new PopupWidget(addButton);
selector.IsPopup = true;
var grid = Layout.Grid();
grid.Spacing = 4f;
grid.Margin = 8f;
grid.SetColumnStretch(1, 1, 1, 1, 1);
//grid.SetColumnStretch(0);
selector.Layout = grid;
var gridColumns = 4;
var count = 0;
foreach (var tag in AssetTagSystem.All
.Where(x => !x.AutoTag)
.Where(x =>
{
return Filter is null || Filter(x);
}))
{
var column = count % gridColumns;
var row = (count / gridColumns);
var button = grid.AddCell(column, row, new TagButton()
{
Text = tag.Title,
Icon = tag.IconPixmap,
InternalName = tag.Tag,
Value = Scroller.Canvas.Children.OfType<TagButton>().Any(x => x.InternalName == tag.Tag)
} );
button.Clicked = () =>
{
ToggleOption(tag, button);
button.Value = Scroller.Canvas.Children.OfType<TagButton>().Any(x => x.InternalName == tag.Tag);
};
count++;
}
var newColumn = count % gridColumns;
var newRow = (count / gridColumns);
var tagAdd = grid.AddCell(newColumn, newRow, new LineEdit());
tagAdd.PlaceholderText = "Add New Tag..";
tagAdd.MinimumHeight = 32 - 8;
tagAdd.ReturnPressed += () =>
{
var tagList = tagAdd.Text.Split( new[] { ',', ' ' } );
foreach ( var tag in tagList )
{
var method = typeof(AssetTagSystem).GetMethod("EnsureRegistered", BindingFlags.Static | BindingFlags.NonPublic);
method?.Invoke(null, new object[]{tag});
//AssetTagSystem.EnsureRegistered(tag);
AddOption(FindTag(tag));
selector.Close();
}
};
selector.FixedWidth = 360;
selector.Show();
selector.Position = addButton.ScreenRect.BottomRight;
selector.ConstrainToScreen();
};
Scroller.Canvas.Layout.Add(addButton);
}
public string Serialize()
{
var str = "";
foreach (var tagButton in Scroller.Canvas.Children.OfType<TagButton>())
{
str += tagButton.InternalName + '/';
}
return str.Base64Encode();
}
public void Deserialize(string data)
{
if (string.IsNullOrWhiteSpace(data) || !Base64.IsValid(data))
return;
var tags = data.Base64Decode().Split('/', StringSplitOptions.RemoveEmptyEntries);
foreach (var tag in tags)
{
AddOption(FindTag(tag));
}
}
private void AddOption( AssetTagSystem.TagDefinition option )
{
if (Scroller.Canvas.Children.OfType<TagButton>().Any(x => x.InternalName == option.Tag))
return;
Scroller.FixedHeight = 24;
var button = Scroller.Canvas.Layout.Add( new TagButton()
{
Text = option.Title,
Icon = option.IconPixmap,
InternalName = option.Tag
} );
button.Clicked = () =>
{
button.Destroy();
Updated?.Invoke();
};
Updated?.Invoke();
}
private void ToggleOption(AssetTagSystem.TagDefinition option, TagButton tagButton)
{
var activeButton = Scroller.Canvas.Children.OfType<TagButton>()
.FirstOrDefault(x => x.InternalName == option.Tag);
if (activeButton is not null)
{
activeButton.Destroy();
Updated?.Invoke();
return;
}
AddOption(option);
}
private void AddOption(AssetTagSystem.TagDefinition? option)
{
if (option is null)
return;
AddOption(option.Value);
}
public static AssetTagSystem.TagDefinition? FindTag( string tagName )
{
if (tagName is null)
return null;
foreach ( var tag in AssetTagSystem.All )
{
if ( tag.Tag.Equals( tagName ) )
{
return tag;
}
}
Log.Warning($"Didn't fing a tag for {tagName}");
return null;
}
}
public class TagButton : Button
{
public string InternalName { get; set; }
public bool Value { get; set; }
public new Pixmap Icon { get; set; }
private const float FontSize = 8.0f;
protected override Vector2 SizeHint()
{
Paint.SetDefaultFont( FontSize );
var textSize = Paint.MeasureText( $"{Text}" );
var iconSize = new Vector2( 0, 0 );
if ( Icon != null )
iconSize = new Vector2( 16, 16 );
var padding = new Vector2( 8, 4 ) * 2.0f;
var totalWidth = textSize.x + iconSize.x;
var totalSize = new Vector2( totalWidth, textSize.y ) + padding;
return totalSize;
}
protected override void OnPaint()
{
var rect = LocalRect;
Paint.ClearPen();
Paint.ClearBrush();
var color = (IsPressed || Value) ? Theme.Primary : Theme.ControlBackground;
if ( Paint.HasMouseOver )
color = color.Lighten( 0.5f );
Paint.SetBrush( color );
Paint.DrawRect( rect, rect.Height / 2f );
Paint.ClearPen();
Paint.ClearBrush();
Paint.SetPen( Theme.ControlText );
Paint.SetDefaultFont( FontSize );
if ( Icon != null )
{
var iconRect = rect.Shrink( 8, 6 );
iconRect.Width = iconRect.Height;
Paint.Draw( iconRect, Icon );
rect.Left += 16.0f;
}
Paint.DrawText( rect, $"{Text}" );
}
}