private void DrawUiActions()
        {
            var toolbarSize = NVector2.UnitY * (ImGui.GetTextLineHeightWithSpacing() + ImGui.GetStyle().ItemSpacing.Y * 2);

            ImGui.Text($"{ImGuiEx.IcoMoon.HammerIcon} Actions");
            ImGui.BeginChildFrame(1, toolbarSize);
            {
                if (ImGuiEx.DelegateButton("New project", $"{ImGuiEx.IcoMoon.HammerIcon}", "New project"))
                {
                    _state = new State();
                    ResetEditor(_state);
                }
                ImGui.SameLine();

                if (ImGuiEx.DelegateButton("Save project", $"{ImGuiEx.IcoMoon.FloppyDiskIcon}", "Save project"))
                {
                    _openFdDefinition = ImGuiEx.CreateFilePickerDefinition(Assembly.GetExecutingAssembly()
                                                                           .Location, "Save", ".json");
                    ImGui.OpenPopup("Save project");
                }
                DoPopup("Save project", ref _openFdDefinition, () =>
                {
                    var json = JsonSerializer.Serialize(_state, CreateJsonSerializerOptions(_state.PropertyDefinitions));
                    File.WriteAllText(_openFdDefinition.SelectedRelativePath, json);
                });

                ImGui.SameLine();
                if (ImGuiEx.DelegateButton("Open project", $"{ImGuiEx.IcoMoon.FolderOpenIcon}", "Open project"))
                {
                    _openFdDefinition = ImGuiEx.CreateFilePickerDefinition(Assembly.GetExecutingAssembly()
                                                                           .Location, "Open", ".json");
                    ImGui.OpenPopup("Open project");
                }
                DoPopup("Open project", ref _openFdDefinition, () =>
                {
                    // load json
                    var json = File.ReadAllText(_openFdDefinition.SelectedRelativePath);

                    using var jsonDocument = JsonDocument.Parse(json);
                    var propJson           = jsonDocument.RootElement.GetProperty(nameof(_state.PropertyDefinitions)).ToString();
                    var properties         = JsonSerializer.Deserialize <Dictionary <string, Property> >(propJson, CreateJsonSerializerOptions());
                    var newState           = JsonSerializer.Deserialize <State>(json, CreateJsonSerializerOptions(properties));

                    // clean animator and sprites/textures
                    ResetEditor(newState, false);
                    _state = newState;
                });


                ImGui.SameLine();
            }
            ImGui.EndChildFrame();
        }
        private void DrawUiHierarchyFrame()
        {
            var size        = ImGui.GetContentRegionAvail();
            var itemSpacing = ImGui.GetStyle().ItemSpacing + NVector2.UnitY * 4;

            ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, itemSpacing);

            ImGui.Text($"{ImGuiEx.IcoMoon.ListIcon} Hierarchy");
            ImGui.BeginChildFrame(2, size - NVector2.UnitY * 256);
            {
                // create sprite
                bool itemHovered = false;
                ImGui.Text($"{ImGuiEx.IcoMoon.ImagesIcon} Entities");
                ImGui.SameLine();

                if (_state.Textures.Count > 0)
                {
                    if (ImGui.SmallButton($"{ImGuiEx.IcoMoon.PlusIcon}##1"))
                    {
                        ImGui.OpenPopup("Create entity");
                        ImGuiEx.DoEntityCreatorReset();
                    }
                }
                else
                {
                    ImGuiEx.DisabledButton($"{ImGuiEx.IcoMoon.PlusIcon}");
                }

                ImGuiEx.DoEntityCreatorModal(_state.Textures.Keys.ToArray(), (name, selectedTexture) =>
                {
                    Entity entity = new Entity(name, selectedTexture);

                    var propDef = _state.PropertyDefinitions[POSITION_PROPERTY];
                    entity.SetCurrentPropertyValue(propDef, propDef.CreateInstance());
                    _state.Animator.CreateTrack(propDef.Type, name, POSITION_PROPERTY);

                    var fiPropDef = _state.PropertyDefinitions[FRAMEINDEX_PROPERTY];
                    entity.SetCurrentPropertyValue(fiPropDef, fiPropDef.CreateInstance());
                    _state.Animator.CreateTrack(fiPropDef.Type, name, FRAMEINDEX_PROPERTY);

                    _state.Entities[entity.Id] = entity;
                });

                // show all created entities
                ImGui.Indent();
                foreach (var entity in _state.Entities.Values)
                {
                    bool selected = selectedEntityId == entity.Id;
                    ImGui.Selectable(entity.Id, ref selected);

                    if (selected)
                    {
                        selectedTextureId = string.Empty;
                        selectedEntityId  = entity.Id;
                    }

                    if (ImGui.IsItemHovered())
                    {
                        itemHovered     = true;
                        hoveredentityId = entity.Id;
                    }
                }
                ImGui.Unindent();

                if (!itemHovered)
                {
                    hoveredentityId = string.Empty;
                }

                // Add textures
                ImGui.Text($"{ImGuiEx.IcoMoon.TextureIcon} Textures");
                ImGui.SameLine();

                if (ImGui.SmallButton($"{ImGuiEx.IcoMoon.PlusIcon}##2"))
                {
                    _openFdDefinition = ImGuiEx.CreateFilePickerDefinition(Assembly.GetExecutingAssembly()
                                                                           .Location, "Open", ".png");
                    ImGui.OpenPopup("Load texture");
                }

                DoPopup("Load texture", ref _openFdDefinition, () =>
                {
                    var key = Path.GetFileNameWithoutExtension(_openFdDefinition.SelectedFileName);
                    if (!_state.Textures.ContainsKey(key))
                    {
                        var path             = _openFdDefinition.SelectedRelativePath;
                        var texture          = Texture2D.FromFile(GraphicsDevice, path);
                        _state.Textures[key] = new TextureFrame(texture, path,
                                                                new NVector2(32, 32),
                                                                new NVector2(16, 16));
                    }
                });

                // show all loaded textures
                ImGui.Indent();
                foreach (var texture in _state.Textures.Keys)
                {
                    bool selected = selectedTextureId == texture;
                    ImGui.Selectable(texture, ref selected);

                    if (selected)
                    {
                        selectedEntityId  = string.Empty;
                        selectedTextureId = texture;
                    }
                }
                ImGui.Unindent();

                ImGui.TreePop();
            }
            ImGui.EndChildFrame();
            ImGui.PopStyleVar();
        }