Files
sbox-public/game/editor/MovieMaker/Code/Editor/IconComboBox.cs
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

196 lines
4.0 KiB
C#

using System.Linq;
namespace Editor.MovieMaker;
#nullable enable
public abstract class IconComboBox<T> : IconButton
{
private T _value = default!;
public T Value
{
get => _value;
set
{
if ( Equals( _value, value ) ) return;
_value = value;
Update();
}
}
private float? _iconAspect;
public float? IconAspect
{
get => _iconAspect;
set
{
_iconAspect = value;
if ( value is { } aspect )
{
var margin = (FixedHeight - IconSize) * 0.5f;
// Add 0.5 for the dropdown arrow
FixedWidth = IconSize * (aspect + 0.5f) + margin * 2.5f;
}
else
{
MinimumSize = IconSize;
MaximumSize = 65536f;
}
}
}
public IconComboBox() : base( "" )
{
IconSize = 10f;
IconAspect = 1f;
}
protected abstract IEnumerable<T> OnGetOptions();
protected abstract string OnGetOptionTitle( T option );
protected abstract void OnPaintOptionIcon( T option, Rect rect );
protected override void OnMousePress( MouseEvent e )
{
e.Accepted = true;
IsActive = true;
var menu = new Menu( this );
OnCreateMenu( menu );
menu.AboutToHide += () =>
{
IsActive = false;
};
menu.OpenAt( ScreenRect.BottomLeft );
}
protected virtual void OnCreateMenu( Menu menu )
{
foreach ( var value in OnGetOptions() )
{
var option = menu.AddOption( OnGetOptionTitle( value ), action: () => Value = value );
option.Checkable = true;
option.Checked = Equals( Value, value );
}
}
protected override void OnPaint()
{
Paint.Antialiasing = true;
Paint.ClearBrush();
Paint.ClearPen();
bool active = Enabled && IsActive;
var bg = active ? BackgroundActive : Background;
var fg = active ? ForegroundActive : Foreground;
Paint.SetBrush( bg.WithAlphaMultiplied( Enabled ? 1f : 0.25f ) );
Paint.DrawRect( LocalRect, 2.0f );
Paint.ClearBrush();
Paint.ClearPen();
fg = Enabled
? fg.WithAlphaMultiplied( Paint.HasMouseOver ? 1.0f : 0.7f )
: fg.WithAlphaMultiplied( 0.25f );
var iconSize = IconAspect is { } aspect
? new Vector2( IconSize * aspect, IconSize )
: new Vector2( Width - IconSize * 0.5f, IconSize );
var iconRect = LocalRect.Shrink( 0f, 0f, 0.5f * FixedHeight, 0f ).Contain( iconSize );
var arrowRect = LocalRect.Contain( FixedHeight * 0.625f, TextFlag.RightCenter ).Contain( IconSize );
Paint.SetPen( fg );
OnPaintOptionIcon( Value, iconRect );
Paint.SetPen( fg );
Paint.DrawIcon( arrowRect, "expand_more", IconSize );
}
}
public class EnumIconComboBox<T> : IconComboBox<T>
where T : struct, Enum
{
protected override IEnumerable<T> OnGetOptions() => Enum.GetValues<T>().Where( x => Convert.ToInt64( x ) >= 0 );
private static EnumDescription.Entry GetEntry( T option )
{
var typeDesc = EditorTypeLibrary.GetEnumDescription( typeof( T ) );
return typeDesc.GetEntry( option );
}
protected override string OnGetOptionTitle( T option )
{
var entry = GetEntry( option );
return entry.Title ?? entry.Name.ToTitleCase();
}
protected override void OnPaintOptionIcon( T option, Rect rect )
{
var entry = GetEntry( option );
Paint.DrawIcon( rect, entry.Icon, IconSize );
}
}
public class FunctionSelector<T> : EnumIconComboBox<T>
where T : struct, Enum
{
private readonly Func<T, Func<float, float>?> _getFunc;
public FunctionSelector( string title, Func<T, Func<float, float>?> getFunc )
{
ToolTip = title;
_getFunc = getFunc;
}
protected override void OnPaintOptionIcon( T option, Rect rect )
{
if ( _getFunc( option ) is { } func )
{
Paint.SetPen( Paint.Pen, size: 2f );
Paint.DrawLine( BuildIconPath( func, rect ) );
}
else
{
Paint.DrawIcon( rect, "question_mark", IconSize );
}
}
private static IEnumerable<Vector2> BuildIconPath( Func<float, float> func, Rect rect )
{
const int steps = 16;
yield return rect.BottomLeft;
for ( var i = 1; i <= steps; ++i )
{
var t = (float)i / steps;
var x = rect.Left + t * rect.Width;
var y = rect.Bottom - func( t ) * rect.Height;
yield return new Vector2( x, y );
}
yield return rect.TopRight;
}
}