Files
glitchy-engine-beef/ScriptCore/Editor/DictionaryEditor.cs
T

171 lines
5.8 KiB
C#

using GlitchyEngine.Extensions;
using ImGuiNET;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace GlitchyEngine.Editor;
[CustomEditor(typeof(Dictionary<,>))]
public class DictionaryEditor
{
private static object? _dictionaryForNewValue = null;
private static DictionaryEntry _newDictionaryValue = new();
private static object? _keyLastCreated = null;
public static object? ShowEditor(object? reference, Type fieldType, string fieldName)
{
object newDictionary = EntityEditor.DidNotChange;
IDictionary? dictionary = reference as IDictionary;
Type keyType = fieldType.GetGenericArguments()[0];
Type valueType = fieldType.GetGenericArguments()[1];
// The buttons should always be visible -> save whether the node is open
// If we have no instance, the user shouldn't be able to open the list
bool listOpen = ImGui.TreeNodeEx(fieldName, ImGuiTreeNodeFlags.AllowOverlap | ImGuiTreeNodeFlags.SpanFullWidth |
(dictionary == null ? ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.NoTreePushOnOpen : ImGuiTreeNodeFlags.Framed));
if (dictionary == null)
listOpen = false;
var addButtonWidth = ImGui.CalcTextSize("+").X + 2 * ImGui.GetStyle().FramePadding.X;
var removeButtonWidth = ImGui.CalcTextSize("-").X + 2 * ImGui.GetStyle().FramePadding.X;
ImGui.SameLine(ImGui.GetWindowContentRegionMax().X - addButtonWidth - ImGui.GetStyle().FramePadding.X);
if (ImGui.SmallButton("+"))
{
if (dictionary == null)
{
newDictionary = Activator.CreateInstance(fieldType);
dictionary = newDictionary as IDictionary;
Debug.Assert(dictionary != null);
}
_dictionaryForNewValue = dictionary;
_newDictionaryValue = new DictionaryEntry();
}
ImGuiExtension.AttachTooltip("Add a new Entry to the dictionary.");
if (listOpen)
{
Debug.Assert(dictionary != null, "Opened tree node even though it should have been a leaf!");
int id = 0;
List<DictionaryEntry> newEntries = new();
List<object> keysToDelete = new();
foreach (DictionaryEntry entry in dictionary!)
{
id++;
ImGui.PushID(id);
if (entry.Key == _keyLastCreated)
{
// The current key is the one that was last created. Open the tree node.
ImGui.SetNextItemOpen(true);
_keyLastCreated = null;
}
bool isEntryOpen = ImGui.TreeNode("");
ImGui.SameLine(ImGui.GetWindowContentRegionMax().X - removeButtonWidth);
if (ImGui.SmallButton("-"))
{
keysToDelete.Add(entry.Key!);
}
ImGuiExtension.AttachTooltip("Remove the last Element from the list.");
if (isEntryOpen)
{
object? newKey = EntityEditor.ShowFieldEditor(entry.Key, entry.Key?.GetType() ?? keyType, "Key");
if (newKey != EntityEditor.DidNotChange && newKey != null)
{
keysToDelete.Add(entry.Key!);
newEntries.Add(new DictionaryEntry(newKey, entry.Value));
}
object? newValue = EntityEditor.ShowFieldEditor(entry.Value, entry.Value?.GetType() ?? valueType, "Value");
if (newValue != EntityEditor.DidNotChange)
{
keysToDelete.Add(entry.Key!);
newEntries.Add(new DictionaryEntry(entry.Key!, newValue));
}
ImGui.TreePop();
}
ImGui.PopID();
}
if (ReferenceEquals(_dictionaryForNewValue, dictionary))
{
ImGui.PushID("NewEntry");
ImGui.SetNextItemOpen(true);
bool isEntryOpen = ImGui.TreeNode("");
ImGui.SameLine(ImGui.GetWindowContentRegionMax().X - removeButtonWidth);
if (ImGui.SmallButton("-"))
{
_dictionaryForNewValue = null;
_newDictionaryValue = new();
}
ImGuiExtension.AttachTooltip("Remove the Entry from the dictionary");
if (isEntryOpen)
{
object? newKey = EntityEditor.ShowFieldEditor(_newDictionaryValue.Key, keyType, "Key");
if (newKey != EntityEditor.DidNotChange && newKey != null)
{
newEntries.Add(new DictionaryEntry(newKey, _newDictionaryValue.Value));
_dictionaryForNewValue = null;
_newDictionaryValue = new();
_keyLastCreated = newKey;
}
object? newValue = EntityEditor.ShowFieldEditor(_newDictionaryValue.Value, _newDictionaryValue.Value?.GetType() ?? valueType, "Value");
if (newValue != EntityEditor.DidNotChange)
{
_newDictionaryValue.Value = newValue;
}
ImGui.TreePop();
}
ImGui.PopID();
}
foreach (object key in keysToDelete)
{
dictionary.Remove(key);
}
foreach (DictionaryEntry newEntry in newEntries)
{
dictionary.Add(newEntry.Key, newEntry.Value);
}
ImGui.TreePop();
}
return newDictionary;
}
}