namespace Editor; [CustomEditor( typeof( Dictionary<,> ) )] [CustomEditor( typeof( NetDictionary<,> ) )] public class DictionaryControlWidget : ControlWidget { public override bool SupportsMultiEdit => false; SerializedCollection Collection; readonly Layout Content; protected override int ValueHash => Collection is null ? base.ValueHash : HashCode.Combine( base.ValueHash, Collection.Count() ); int? buildHash; object buildValue; public DictionaryControlWidget( SerializedProperty property ) : base( property ) { Layout = Layout.Column(); Layout.Spacing = 2; if ( !property.TryGetAsObject( out var so ) || so is not SerializedCollection sc ) return; Collection = sc; Collection.OnEntryAdded = Rebuild; Collection.OnEntryRemoved = Rebuild; buildValue = SerializedProperty?.GetValue(); Content = Layout.Column(); Layout.Add( Content ); Rebuild(); } private void RefreshCollection() { var value = SerializedProperty?.GetValue(); if ( buildValue == value ) return; buildValue = value; if ( !SerializedProperty.TryGetAsObject( out var so ) || so is not SerializedCollection sc ) return; Collection = sc; Collection.OnEntryAdded = Rebuild; Collection.OnEntryRemoved = Rebuild; } protected override void OnValueChanged() { RefreshCollection(); Rebuild(); } public void Rebuild() { if ( Collection is not null ) { var hash = ValueHash; if ( buildHash.HasValue && hash == buildHash.Value ) return; buildHash = hash; } using var _ = SuspendUpdates.For( this ); Content.Clear( true ); Content.Margin = 0; var grid = Layout.Grid(); grid.VerticalSpacing = 2; grid.HorizontalSpacing = 2; grid.SetMinimumColumnWidth( 1, 10 ); grid.SetMinimumColumnWidth( 3, 150 ); grid.SetColumnStretch( 0, 1, 0, 100, 0 ); int y = 0; foreach ( var entry in Collection ) { var key = entry.GetKey(); var keyControl = ControlSheetRow.CreateEditor( key ); var valControl = ControlSheetRow.CreateEditor( entry ); keyControl.ReadOnly = ReadOnly; keyControl.Enabled = Enabled; valControl.ReadOnly = ReadOnly; valControl.Enabled = Enabled; var index = y; //grid.AddCell( 0, y, new IconButton( "drag_handle" ) { IconSize = 13, Foreground = Theme.ControlBackground, Background = Color.Transparent, FixedWidth = Theme.RowHeight, FixedHeight = Theme.RowHeight } ); grid.AddCell( 1, y, keyControl, 1, 1, keyControl.CellAlignment ); grid.AddCell( 2, y, new IconButton( ":" ) { IconSize = 13, Foreground = Theme.TextControl, Background = Color.Transparent, FixedWidth = Theme.RowHeight, FixedHeight = Theme.RowHeight } ); grid.AddCell( 3, y, valControl, 1, 1, valControl.CellAlignment ); if ( !IsControlDisabled ) { grid.AddCell( 4, y, new IconButton( "clear", () => RemoveEntry( key.GetValue() ) ) { Background = Theme.ControlBackground, FixedWidth = Theme.RowHeight, FixedHeight = Theme.RowHeight } ); } y++; } // Add entry if ( !IsControlDisabled ) { var newKeyProperty = Collection.NewKeyProperty(); var keyControl = ControlSheetRow.CreateEditor( newKeyProperty ); var addButton = new IconButton( "add" ) { Background = Theme.ControlBackground, ToolTip = "Add Entry", FixedWidth = Theme.RowHeight, FixedHeight = Theme.RowHeight }; addButton.MouseClick = () => { var value = newKeyProperty.GetValue() ?? newKeyProperty.GetDefault(); value ??= newKeyProperty.PropertyType == typeof( string ) ? string.Empty : null; if ( value is not null ) { AddEntry( value ); } }; grid.AddCell( 1, y, keyControl, 1, 1, keyControl.CellAlignment ); grid.AddCell( 2, y, addButton, 3 ); } Content.Add( grid ); // Content.Margin = y > 0 ? 3 : 0; } void AddEntry( object key ) { if ( Collection.Add( key, null ) ) { Rebuild(); } } void RemoveEntry( object key ) { if ( Collection.RemoveAt( key ) ) { Rebuild(); } } protected override void OnPaint() { Paint.Antialiasing = true; // Paint.ClearPen(); //Paint.SetBrush( Theme.TextControl.Darken( 0.6f ) ); if ( Collection is not null && Collection.Count() > 0 ) { //Paint.DrawRect( Content.OuterRect, 2.0f ); // Paint.DrawRect( new Rect( addButton.Position, addButton.Size ).Grow( 0, 8, 0, 0 ), 2.0f ); } else { // Paint.DrawRect( new Rect( addButton.Position, addButton.Size ).Grow( 0, 0, 0, 0 ), 2.0f ); } } }