using System;
using System.Collections.Generic;
namespace Editor;
///
/// Base class for dropdown control widgets with multi-select support.
///
public abstract class DropdownControlWidget : ControlWidget
{
public override bool IsControlActive => base.IsControlActive || _menu.IsValid();
public override bool IsControlButton => true;
public override bool IsControlHovered => base.IsControlHovered || _menu.IsValid();
protected PopupWidget _menu;
protected bool IsMultiSelect { get; set; }
public DropdownControlWidget( SerializedProperty property ) : base( property )
{
Cursor = CursorShape.Finger;
Layout = Layout.Row();
Layout.Spacing = 2;
}
protected override void PaintControl()
{
var color = IsControlHovered ? Theme.Blue : Theme.TextControl;
if ( IsControlDisabled ) color = color.WithAlpha( 0.5f );
var rect = LocalRect.Shrink( 8, 0 );
if ( SerializedProperty.IsMultipleDifferentValues )
{
Paint.SetPen( Theme.MultipleValues );
Paint.DrawText( rect, "Multiple Values", TextFlag.LeftCenter );
}
else
{
PaintDisplayText( rect, color );
}
Paint.SetPen( color );
Paint.DrawIcon( rect, "Arrow_Drop_Down", 17, TextFlag.RightCenter );
}
///
/// Override to paint the display text in the control
///
protected abstract void PaintDisplayText( Rect rect, Color color );
public override void StartEditing()
{
if ( IsControlDisabled ) return;
if ( !_menu.IsValid )
{
OpenMenu();
}
}
protected override void OnMouseClick( MouseEvent e )
{
if ( IsControlDisabled ) return;
if ( e.LeftMouseButton && !_menu.IsValid() )
{
OpenMenu();
}
}
protected override void OnDoubleClick( MouseEvent e )
{
// nothing
}
void OpenMenu()
{
PropertyStartEdit();
_menu = new PopupWidget( null );
_menu.Layout = Layout.Column();
_menu.MinimumWidth = ScreenRect.Width;
_menu.MaximumWidth = ScreenRect.Width;
_menu.OnLostFocus += PropertyFinishEdit;
var scroller = _menu.Layout.Add( new ScrollArea( this ), 1 );
scroller.Canvas = new Widget( scroller )
{
Layout = Layout.Column(),
VerticalSizeMode = SizeMode.CanGrow | SizeMode.Expand,
MaximumWidth = ScreenRect.Width
};
PopulateMenu( scroller.Canvas );
_menu.Position = ScreenRect.BottomLeft;
_menu.Visible = true;
_menu.AdjustSize();
_menu.ConstrainToScreen();
_menu.OnPaintOverride = PaintMenuBackground;
if ( scroller.VerticalScrollbar.Minimum != scroller.VerticalScrollbar.Maximum )
{
scroller.Canvas.MaximumWidth -= 8;
}
}
///
/// Override to populate the menu with options
///
protected abstract void PopulateMenu( Widget canvas );
///
/// Helper to add a menu option
///
protected Widget AddMenuOption( Widget canvas, string displayName, string icon, Func isSelected, Action onSelect )
{
var option = canvas.Layout.Add( new DropdownMenuOption( displayName, icon, isSelected ) );
option.MouseLeftPress = () =>
{
onSelect();
_menu.Update();
if ( !IsMultiSelect )
{
_menu.Close();
}
};
return option;
}
bool PaintMenuBackground()
{
Paint.SetBrushAndPen( Theme.ControlBackground );
Paint.DrawRect( Paint.LocalRect, 0 );
return true;
}
}
file class DropdownMenuOption : Widget
{
string displayName;
string icon;
Func isSelectedFunc;
public DropdownMenuOption( string displayName, string icon, Func isSelectedFunc ) : base( null )
{
this.displayName = displayName;
this.icon = icon;
this.isSelectedFunc = isSelectedFunc;
Layout = Layout.Row();
Layout.Margin = 8;
VerticalSizeMode = SizeMode.CanGrow;
if ( !string.IsNullOrWhiteSpace( icon ) )
{
Layout.Add( new IconButton( icon ) { Background = Color.Transparent, TransparentForMouseEvents = true, IconSize = 18 } );
Layout.AddSpacingCell( 8 );
}
Layout.Add( new Label( displayName ) );
}
protected override void OnPaint()
{
var isSelected = isSelectedFunc?.Invoke() ?? false;
if ( Paint.HasMouseOver || isSelected )
{
Paint.SetBrushAndPen( Theme.Blue.WithAlpha( isSelected ? 0.3f : 0.1f ) );
Paint.DrawRect( LocalRect.Shrink( 2 ), 2 );
}
}
}