Editor/EffigyEditor/EffigyVariablesPanel.cs
using Editor;
using Effigy;
using Sandbox;
using System;
using System.Linq;
namespace Marionette.EditorTools;
/// <summary>
/// The document's named values: name, expression, evaluated result.
///
/// A dock with a list and three columns is enough. No dependency graph. Changing a value dirties
/// the whole tree because any feature might refer to it.
/// </summary>
internal sealed class EffigyVariablesPanel : Widget
{
private PartStudio _studio;
private readonly Widget _list;
public Action Changing { get; set; }
public Action Changed { get; set; }
public EffigyVariablesPanel( Widget parent, PartStudio studio ) : base( parent )
{
_studio = studio;
Layout = Layout.Column();
Layout.Margin = 8;
Layout.Spacing = 6;
var header = Layout.AddRow();
header.Add( new Editor.Label( "Variables" ) { Color = Theme.TextControl } );
header.AddStretchCell();
var add = new Button( "Add", this );
add.Clicked = AddVariable;
header.Add( add );
_list = new Widget( this );
_list.Layout = Layout.Column();
_list.Layout.Spacing = 4;
Layout.Add( _list, 1 );
Rebuild();
}
public void Bind( PartStudio studio )
{
_studio = studio;
Rebuild();
}
public void Rebuild()
{
if ( _list is null || !_list.IsValid() )
return;
_list.Layout.Clear( true );
if ( _studio is null || _studio.Variables.Count == 0 )
{
_list.Layout.Add( new Editor.Label( "No variables. Add one, then type #name in a dimension." )
{
Color = Theme.TextControl.WithAlpha( 0.55f ),
} );
return;
}
VariableResolver.EvaluateAll( _studio.Variables );
foreach ( var variable in _studio.Variables.ToList() )
{
var row = _list.Layout.AddRow();
row.Spacing = 6;
var name = new LineEdit( variable.Name ?? "", _list );
name.ToolTip = "The name you type after # in a dimension.";
name.TextEdited += text => Rename( variable, text );
row.Add( name, 1 );
var expr = new LineEdit( variable.Expr ?? "", _list );
expr.ToolTip = "A number or an expression. Other variables are #name.";
expr.TextEdited += text => SetExpr( variable, text );
row.Add( expr, 2 );
row.Add( new Editor.Label( $"= {Expression.Format( variable.Value )}" )
{
Color = Theme.TextControl.WithAlpha( 0.55f ),
} );
var remove = new Button( "×", _list );
remove.Clicked = () => Remove( variable );
row.Add( remove );
}
}
private void AddVariable()
{
if ( _studio is null )
return;
Changing?.Invoke();
var n = 1;
var name = "thickness";
while ( _studio.Variables.Any( v => string.Equals( v.Name, name, StringComparison.OrdinalIgnoreCase ) ) )
name = $"var{n++}";
_studio.SetVariable( name, "1" );
Changed?.Invoke();
Rebuild();
}
private void Rename( StudioVariable variable, string text )
{
if ( _studio is null || variable is null )
return;
if ( !VariableResolver.IsLegalName( text ) )
return;
Changing?.Invoke();
variable.Name = text;
_studio.MarkAllDirty();
Changed?.Invoke();
}
private void SetExpr( StudioVariable variable, string text )
{
if ( _studio is null || variable is null )
return;
Changing?.Invoke();
variable.Expr = text ?? "";
_studio.MarkAllDirty();
Changed?.Invoke();
}
private void Remove( StudioVariable variable )
{
if ( _studio is null || variable is null )
return;
Changing?.Invoke();
_studio.RemoveVariable( variable.Name );
Changed?.Invoke();
Rebuild();
}
}