// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using FlaxEditor.CustomEditors.Elements;
using FlaxEditor.CustomEditors.GUI;
using FlaxEditor.GUI;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Json;
namespace FlaxEditor.CustomEditors.Editors
{
///
/// Default implementation of the inspector used to edit key-value dictionaries.
///
public class DictionaryEditor : CustomEditor
{
///
/// The custom implementation of the dictionary items labels that can be used to remove items or edit keys.
///
///
private class DictionaryItemLabel : PropertyNameLabel
{
private DictionaryEditor _editor;
private object _key;
///
/// Initializes a new instance of the class.
///
/// The editor.
/// The key.
public DictionaryItemLabel(DictionaryEditor editor, object key)
: base(key?.ToString() ?? "")
{
_editor = editor;
_key = key;
SetupContextMenu += OnSetupContextMenu;
}
private void OnSetupContextMenu(PropertyNameLabel label, ContextMenu menu, CustomEditor linkedEditor)
{
menu.AddSeparator();
menu.AddButton("Remove", OnRemoveClicked).Enabled = !_editor._readOnly;
menu.AddButton("Edit", OnEditClicked).Enabled = _editor._canEditKeys;
}
private void OnRemoveClicked(ContextMenuButton button)
{
_editor.Remove(_key);
}
private void OnEditClicked(ContextMenuButton button)
{
var keyType = _editor.Values.Type.GetGenericArguments()[0];
if (keyType == typeof(string) || keyType.IsPrimitive)
{
var popup = RenamePopup.Show(Parent, Rectangle.Margin(Bounds, Margin), Text, false);
popup.Validate += (renamePopup, value) =>
{
object newKey;
if (keyType.IsPrimitive)
newKey = JsonSerializer.Deserialize(value, keyType);
else
newKey = value;
return !((IDictionary)_editor.Values[0]).Contains(newKey);
};
popup.Renamed += renamePopup =>
{
object newKey;
if (keyType.IsPrimitive)
newKey = JsonSerializer.Deserialize(renamePopup.Text, keyType);
else
newKey = renamePopup.Text;
_editor.ChangeKey(_key, newKey);
_key = newKey;
Text = _key.ToString();
};
}
else if (keyType.IsEnum)
{
var popup = RenamePopup.Show(Parent, Rectangle.Margin(Bounds, Margin), Text, false);
var picker = new EnumComboBox(keyType)
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = Margin.Zero,
Parent = popup,
EnumTypeValue = _key,
};
picker.ValueChanged += () =>
{
popup.Hide();
object newKey = picker.EnumTypeValue;
if (!((IDictionary)_editor.Values[0]).Contains(newKey))
{
_editor.ChangeKey(_key, newKey);
_key = newKey;
Text = _key.ToString();
}
};
}
else
{
throw new NotImplementedException("Missing editing for dictionary key type " + keyType);
}
}
///
public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
{
if (button == MouseButton.Left)
{
OnEditClicked(null);
return true;
}
return base.OnMouseDoubleClick(location, button);
}
///
public override void OnDestroy()
{
_editor = null;
_key = null;
base.OnDestroy();
}
}
private IntegerValueElement _size;
private Color _background;
private int _elementsCount;
private bool _readOnly;
private bool _notNullItems;
private bool _canEditKeys;
private bool _keyEdited;
///
/// Gets the length of the collection.
///
public int Count => (Values[0] as IDictionary)?.Count ?? 0;
///
public override void Initialize(LayoutElementsContainer layout)
{
// No support for different collections for now
if (HasDifferentValues || HasDifferentTypes)
return;
var type = Values.Type;
var size = Count;
var argTypes = type.GetGenericArguments();
var keyType = argTypes[0];
var valueType = argTypes[1];
_canEditKeys = keyType == typeof(string) || keyType.IsPrimitive || keyType.IsEnum;
_background = FlaxEngine.GUI.Style.Current.CollectionBackgroundColor;
_readOnly = false;
_notNullItems = false;
// Try get CollectionAttribute for collection editor meta
var attributes = Values.GetAttributes();
Type overrideEditorType = null;
float spacing = 0.0f;
var collection = (CollectionAttribute)attributes?.FirstOrDefault(x => x is CollectionAttribute);
if (collection != null)
{
_readOnly = collection.ReadOnly;
_notNullItems = collection.NotNullItems;
if (collection.BackgroundColor.HasValue)
_background = collection.BackgroundColor.Value;
overrideEditorType = TypeUtils.GetType(collection.OverrideEditorTypeName).Type;
spacing = collection.Spacing;
}
// Size
if (_readOnly || !_canEditKeys)
{
layout.Label("Size", size.ToString());
}
else
{
_size = layout.IntegerValue("Size");
_size.IntValue.MinValue = 0;
_size.IntValue.MaxValue = _notNullItems ? size : ushort.MaxValue;
_size.IntValue.Value = size;
_size.IntValue.EditEnd += OnSizeChanged;
}
// Elements
if (size > 0)
{
var panel = layout.VerticalPanel();
panel.Panel.BackgroundColor = _background;
var keysEnumerable = ((IDictionary)Values[0]).Keys.OfType