#include "UI.hpp"

#include <imgui.h>
#include "../state.hpp"
#include "../Window.hpp"
#include "../../core/world/materials.hpp"
#include <filesystem>

using namespace render;

UI *UI::sInstance = nullptr;

constexpr auto UI_MARGIN = 5;

UI::UI() {
    // Setup Dear ImGui context
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    {
        ImGui::StyleColorsDark();
        ImGuiStyle &style = ImGui::GetStyle();
        style.TabRounding = 1;
        style.WindowRounding = 2;
        style.GrabRounding = 2;
        style.FrameRounding = 4;
        style.ScrollbarRounding = 4;
        style.WindowMenuButtonPosition = ImGuiDir_Right;

        // Purple dark theme
        /*ImVec4* colors = style.Colors;
        colors[ImGuiCol_Text]                   = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
        colors[ImGuiCol_TextDisabled]           = ImVec4(0.56f, 0.56f, 0.56f, 1.00f);
        colors[ImGuiCol_WindowBg]               = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
        colors[ImGuiCol_ChildBg]                = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
        colors[ImGuiCol_PopupBg]                = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
        colors[ImGuiCol_Border]                 = ImVec4(0.53f, 0.46f, 0.54f, 0.50f);
        colors[ImGuiCol_BorderShadow]           = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
        colors[ImGuiCol_FrameBg]                = ImVec4(0.38f, 0.34f, 0.40f, 0.54f);
        colors[ImGuiCol_FrameBgHovered]         = ImVec4(0.83f, 0.26f, 0.98f, 0.40f);
        colors[ImGuiCol_FrameBgActive]          = ImVec4(0.73f, 0.26f, 0.98f, 0.67f);
        colors[ImGuiCol_TitleBg]                = ImVec4(0.14f, 0.00f, 0.21f, 1.00f);
        colors[ImGuiCol_TitleBgActive]          = ImVec4(0.39f, 0.16f, 0.48f, 1.00f);
        colors[ImGuiCol_TitleBgCollapsed]       = ImVec4(0.13f, 0.00f, 0.21f, 0.51f);
        colors[ImGuiCol_MenuBarBg]              = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
        colors[ImGuiCol_ScrollbarBg]            = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
        colors[ImGuiCol_ScrollbarGrab]          = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
        colors[ImGuiCol_ScrollbarGrabHovered]   = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
        colors[ImGuiCol_ScrollbarGrabActive]    = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
        colors[ImGuiCol_CheckMark]              = ImVec4(0.74f, 0.27f, 0.83f, 1.00f);
        colors[ImGuiCol_SliderGrab]             = ImVec4(0.55f, 0.21f, 0.80f, 1.00f);
        colors[ImGuiCol_SliderGrabActive]       = ImVec4(0.75f, 0.27f, 0.83f, 1.00f);
        colors[ImGuiCol_Button]                 = ImVec4(0.85f, 0.26f, 0.98f, 0.40f);
        colors[ImGuiCol_ButtonHovered]          = ImVec4(0.76f, 0.26f, 0.98f, 1.00f);
        colors[ImGuiCol_ButtonActive]           = ImVec4(0.63f, 0.06f, 0.98f, 1.00f);
        colors[ImGuiCol_Header]                 = ImVec4(0.81f, 0.26f, 0.98f, 0.31f);
        colors[ImGuiCol_HeaderHovered]          = ImVec4(0.84f, 0.26f, 0.98f, 0.80f);
        colors[ImGuiCol_HeaderActive]           = ImVec4(0.79f, 0.26f, 0.98f, 1.00f);
        colors[ImGuiCol_Separator]              = ImVec4(0.38f, 0.35f, 0.40f, 0.54f);
        colors[ImGuiCol_SeparatorHovered]       = ImVec4(0.64f, 0.10f, 0.75f, 0.78f);
        colors[ImGuiCol_SeparatorActive]        = ImVec4(0.53f, 0.10f, 0.75f, 1.00f);
        colors[ImGuiCol_ResizeGrip]             = ImVec4(0.77f, 0.26f, 0.98f, 0.25f);
        colors[ImGuiCol_ResizeGripHovered]      = ImVec4(0.83f, 0.26f, 0.98f, 0.67f);
        colors[ImGuiCol_ResizeGripActive]       = ImVec4(0.76f, 0.26f, 0.98f, 0.95f);
        colors[ImGuiCol_Tab]                    = ImVec4(0.48f, 0.18f, 0.58f, 0.86f);
        colors[ImGuiCol_TabHovered]             = ImVec4(0.79f, 0.26f, 0.98f, 0.80f);
        colors[ImGuiCol_TabActive]              = ImVec4(0.54f, 0.20f, 0.68f, 1.00f);
        colors[ImGuiCol_TabUnfocused]           = ImVec4(0.10f, 0.07f, 0.15f, 0.97f);
        colors[ImGuiCol_TabUnfocusedActive]     = ImVec4(0.22f, 0.14f, 0.42f, 1.00f);
        colors[ImGuiCol_PlotLines]              = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
        colors[ImGuiCol_PlotLinesHovered]       = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
        colors[ImGuiCol_PlotHistogram]          = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
        colors[ImGuiCol_PlotHistogramHovered]   = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
        colors[ImGuiCol_TextSelectedBg]         = ImVec4(0.55f, 0.26f, 0.98f, 0.35f);
        colors[ImGuiCol_DragDropTarget]         = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
        colors[ImGuiCol_NavHighlight]           = ImVec4(0.55f, 0.26f, 0.98f, 1.00f);
        colors[ImGuiCol_NavWindowingHighlight]  = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
        colors[ImGuiCol_NavWindowingDimBg]      = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
        colors[ImGuiCol_ModalWindowDimBg]       = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);*/
    }

    for(auto file: std::filesystem::directory_iterator("content/textures/")) {
        if(file.is_directory() && file.path().filename() != "ui")
            texturePacks.push_back(file.path().filename().string());
    }
}
UI::~UI() {
    ImGui::DestroyContext();
}

UI::Actions UI::draw(config::client::options &options, state::state &state, const state::reports &reports, intptr_t aim) {
    auto actions = Actions::None;
    ImGui::NewFrame();

    const ImGuiIO &io = ImGui::GetIO();

    if(state.capture_mouse) {
        ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x / 2, io.DisplaySize.y / 2), ImGuiCond_Always, ImVec2(.5f, .5f));
        ImGui::Begin("Aim", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoInputs);
        ImGui::Image((void *)aim, ImVec2(32, 32));
        ImGui::End();
    }

    if (options.debugMenu.bar) {
        ImGui::BeginMainMenuBar();
        if (ImGui::BeginMenu("Debug")) {
            ImGui::Checkbox("Render", &options.debugMenu.render);
            ImGui::Checkbox("World", &options.debugMenu.world);
            ImGui::Checkbox("Contouring", &options.debugMenu.contouring);
            ImGui::Checkbox("Controls", &options.debugMenu.controls);
            ImGui::EndMenu();
        }
        ImGui::Checkbox("Editor", &options.editor.visible);
        ImGui::Checkbox("Console", &options.console.visible);

        if(ImGui::MenuItem("Close"))
            options.debugMenu.bar = false;
        ImGui::EndMainMenuBar();
    }

    if (options.debugMenu.render) {
        ImGui::Begin("Debug: Render", &options.debugMenu.render, ImGuiWindowFlags_AlwaysAutoResize);
        ImGui::Checkbox("Overlay", &options.overlay.visible);
        {
            ImGui::Combo("Driver", (int*)&options.preferVulkan, "OpenGL\0Vulkan\0");
            if (ImGui::IsItemHovered())
                ImGui::SetTooltip("Prefer Vulkan over OpenGL if available (requires restart)");
            auto samples = std::to_string(options.window.getSamples()) + "x";
            ImGui::SliderInt("MSAA", &options.window.sampling, -1, 7, options.window.sampling > 0 ? samples.c_str() :
                (options.window.sampling < 0 ? "System default" : "Minimun"));
            if (ImGui::IsItemHovered())
                ImGui::SetTooltip("Anti-aliasing (requires restart).\nActual value may be smaller than requested");

            ImGui::Separator();
        }

        if (ImGui::SliderInt("FPS", &options.window.targetFPS, Window::MIN_FPS-1, Window::MAX_FPS+1, options.window.targetFPS > Window::MIN_FPS ? (options.window.targetFPS < Window::MAX_FPS ? "%d" : "UNLIMITED") : "VSYNC")){
            actions |= Actions::FPS;
        }
#ifdef _WINDOWS
        if (ImGui::IsItemHovered())
            ImGui::SetTooltip("Due to windows clock inaccuracy prefer vsync or unlimited.");
#endif

        if (ImGui::Checkbox("Fullscreen", &options.window.fullscreen)){
            actions |= Actions::FullScreen;
        }

        {
            bool changeRenderer = false;
            {
                int planarIdx = static_cast<int>(options.renderer.voxel.planar) - 1;
                changeRenderer |= ImGui::Combo("Mapping", &planarIdx, "Cheap\0Biplanar\0Triplanar\0");
                options.renderer.voxel.planar = static_cast<render::Planar>(planarIdx + 1);
            }
            changeRenderer |= ImGui::Checkbox("PBR", &options.renderer.voxel.pbr);
            ImGui::SameLine();
            changeRenderer |= ImGui::Checkbox("Stochastic", &options.renderer.voxel.stochastic);
            if (ImGui::IsItemHovered())
                ImGui::SetTooltip("Hide textures tiling\nMay cause visible inconsistances on chunk borders");

            changeRenderer |= ImGui::Checkbox("Geometry", &options.renderer.voxel.geometry);
            ImGui::SameLine();
            if(options.renderer.voxel.geometry) {
                changeRenderer |= ImGui::Checkbox("Blend", &options.renderer.voxel.blend);
            } else {
                ImGui::TextDisabled("Blend");
            }

            changeRenderer |= ImGui::Checkbox("Curvature", &options.renderer.voxel.curvature);
            ImGui::SameLine();
            if(options.renderer.voxel.curvature) {
                changeRenderer |= ImGui::Checkbox("Depth", &options.renderer.voxel.curv_depth);
                if(ImGui::IsItemHovered())
                    ImGui::SetTooltip("Planets may look way bigger than expected without it");
            } else {
                ImGui::TextDisabled("Depth");
            }

            changeRenderer |= ImGui::Checkbox("Transparency", &options.renderer.voxel.transparency);

            changeRenderer |= ImGui::Checkbox("Fog", &options.renderer.voxel.fog);
            ImGui::SameLine();
            ImGui::Checkbox("Skybox", &options.renderer.skybox);
            if (changeRenderer) {
                actions |= Actions::RendererSharders;
            }
        }
        if (ImGui::ColorEdit3("Fog color", &options.renderer.clear_color[0])) {
            actions |= Actions::ClearColor;
        }
        if (ImGui::Checkbox("Wireframe", &options.renderer.wireframe)) {
            actions |= Actions::FillMode;
        }
        if (ImGui::BeginCombo("Textures", options.renderer.textures.c_str())) {
            for (auto& pack: texturePacks) {
                const bool is_selected = (pack == options.renderer.textures);
                if (ImGui::Selectable(pack.c_str(), is_selected)) {
                    options.renderer.textures = pack;
                    actions |= Actions::RendererTextures;
                }
                if (is_selected)
                    ImGui::SetItemDefaultFocus();
            }
            ImGui::EndCombo();
        }
        std::string anisotropy = std::to_string(options.renderer.getAnisotropy()) + "x";
        if (ImGui::SliderInt("Quality", &options.renderer.textureQuality, 0, 200, "%d%%") |
            ImGui::SliderInt("Sharpness", &options.renderer.textureSharpness, 0, 8, anisotropy.c_str())) {
            actions |= Actions::RendererTextures;
        }
        if(ImGui::IsItemHovered())
            ImGui::SetTooltip("Better texture quality especially at low angles");
        ImGui::End();
    }

    if (options.debugMenu.world) {
        ImGui::Begin("Debug: World", &options.debugMenu.world, ImGuiWindowFlags_AlwaysAutoResize);
        int load = options.world.loadDistance;
        int keep = options.world.keepDistance;
        if (ImGui::SliderInt("Load distance", &load, 1, options.world.keepDistance) |
            ImGui::SliderInt("Keep distance", &keep, options.world.loadDistance + 1, 21)) {
            options.world.loadDistance = load;
            options.world.keepDistance = keep;
            actions |= Actions::World;
        }
        if(ImGui::SliderInt("Voxel density", &options.voxel_density, 1, CHUNK_LENGTH * REGION_LENGTH)) {
            options.voxel_density = pow(2, ceil(log(options.voxel_density) / log(2)));
        }
        ImGui::End();
    }

    if (options.debugMenu.contouring) {
        ImGui::Begin("Debug: Contouring", &options.debugMenu.contouring, ImGuiWindowFlags_AlwaysAutoResize);
        ImGui::SliderInt("Culling", &options.culling, -1, 10, options.culling > 0 ? "Occlusion %d" : (options.culling < 0 ? "None" : "Frustum"));
        state.contouring->onGui();
        ImGui::End();
    }

    {
        const auto farRange = state.contouring->getFarRange();
        if (options.debugMenu.controls) {
            ImGui::Begin("Debug: Controls", &options.debugMenu.controls, ImGuiWindowFlags_AlwaysAutoResize);
            const auto p = state.position.as_voxel(options.voxel_density);
            ImGui::Text("Position: (%lld, %lld, %lld)", p.x, p.y, p.z);
            ImGui::Separator();
            {
                if (ImGui::SliderFloat("Move speed", &options.control.speed, 0.1, 50) |
                    ImGui::SliderInt("Sensibility", &options.control.sensibility, 1, 100, "%d%%")) {
                    actions |= Actions::Control;
                }
                ImGui::Checkbox("Collide", &options.control.collide);
            }
            ImGui::Separator();
            {
                bool changePerspective = false;
                changePerspective |= ImGui::SliderAngle("FoV", &options.camera.fov, 30, 110);
                changePerspective |= ImGui::SliderFloat("Near", &options.camera.near_dist, 0.01, 10);
                changePerspective |= ImGui::SliderFloat("Far", &options.camera.far_dist, farRange.first / options.voxel_density, farRange.second / options.voxel_density);
                if(changePerspective) {
                    actions |= Actions::Camera;
                }
            }
            ImGui::End();
        }
        const auto far_dist = std::clamp(options.camera.far_dist, farRange.first / options.voxel_density, farRange.second / options.voxel_density);
        if(far_dist != options.camera.far_dist) {
            options.camera.far_dist = far_dist;
            actions |= Actions::Camera;
        }
    }

    if (options.editor.visible) {
        ImGui::Begin("Editor", &options.editor.visible, ImGuiWindowFlags_AlwaysAutoResize);
        if (state.look_at.has_value()) {
            const auto &look = state.look_at.value();
            ImGui::Text("Look at: (%ld: %lld, %lld, %lld) (%s, %.1f)", look.pos.first.index, look.pos.second.x, look.pos.second.y, look.pos.second.z,
                world::materials::names[look.value.material()].c_str(), look.value.density_ratio());
            const auto w_pos = look.pos.second + look.offset;
            ImGui::Text("(%.3f, %.3f, %.3f)", w_pos.x * 1. / options.voxel_density, w_pos.y * 1. / options.voxel_density, w_pos.z * 1. / options.voxel_density);
        } else {
            ImGui::Text("Look at: none");
        }
        ImGui::Separator();
        if (ImGui::BeginCombo("Material", world::materials::names[options.editor.tool.material].c_str())) {
            for (size_t i = 0; i < world::materials::names.size(); i++) {
                if (!world::materials::invisibility[i]) {
                    const bool is_selected = (options.editor.tool.material == i);
                    if (ImGui::Selectable(world::materials::names[i].c_str(), is_selected))
                        options.editor.tool.material = i;
                    if (is_selected)
                        ImGui::SetItemDefaultFocus();
                }
            }
            ImGui::EndCombo();
        }
        ImGui::SliderInt("Radius", &options.editor.tool.radius, 1, 15);
        const auto shapeId = (size_t)options.editor.tool.shape;
        if (ImGui::BeginCombo("Shape", world::action::SHAPES[shapeId].c_str())) {
            for (size_t i = 0; i < world::action::SHAPES.size(); i++) {
                const bool is_selected = (shapeId == i);
                if (ImGui::Selectable(world::action::SHAPES[i].c_str(), is_selected))
                    options.editor.tool.shape = (world::action::Shape)i;
                if (is_selected)
                    ImGui::SetItemDefaultFocus();
                if (i == (size_t)world::action::Shape::SmoothSphere && ImGui::IsItemHovered())
                    ImGui::SetTooltip("Asymmetrical with small radius");
            }
            ImGui::EndCombo();
        }
        ImGui::Checkbox("Empty air", &options.editor.tool.emptyAir);
        if (ImGui::IsItemHovered())
            ImGui::SetTooltip("Is cleaned area breathable");
        ImGui::End();
    }

    if (options.console.visible) {
        {
            const auto SIZE = ImVec2(300, 200);
            ImGui::SetNextWindowSize(SIZE, ImGuiCond_FirstUseEver);
            ImGui::SetNextWindowPos(ImVec2(UI_MARGIN, io.DisplaySize.y - SIZE.y - UI_MARGIN), ImGuiCond_FirstUseEver);
        }
        ImGui::PushStyleVar(ImGuiStyleVar_Alpha, options.console.opacity);
        ImGui::Begin("Console", &options.console.visible, ImGuiWindowFlags_MenuBar);
        ImGui::BeginMenuBar();
        if(ImGui::BeginMenu("Options")) {
            ImGui::Checkbox("Auto-scrool", &options.console.scroll);
            ImGui::SliderFloat("Opacity", &options.console.opacity, 0.1, 1);
            ImGui::EndMenu();
        }
        if (ImGui::Button("Clear"))
            state.console.lines.clear();
        const bool copy_to_clipboard = ImGui::Button("Copy");
        ImGui::EndMenuBar();

        // Reserve enough left-over height for 1 separator + 1 input text
        const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
        ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar);
        /*if (ImGui::BeginPopupContextWindow()) {
            if (ImGui::Selectable("Clear")) ClearLog();
            ImGui::EndPopup();
        }*/

        // Display every line as a separate entry so we can change their color or add custom widgets.
        // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
        // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping
        // to only process visible items. The clipper will automatically measure the height of your first item and then
        // "seek" to display only items in the visible area.
        // To use the clipper we can replace your standard loop:
        //      for (int i = 0; i < Items.Size; i++)
        //   With:
        //      ImGuiListClipper clipper(Items.Size);
        //      while (clipper.Step())
        //         for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
        // - That your items are evenly spaced (same height)
        // - That you have cheap random access to your elements (you can access them given their index,
        //   without processing all the ones before)
        // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property.
        // We would need random-access on the post-filtered list.
        // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices
        // or offsets of items that passed the filtering test, recomputing this array when user changes the filter,
        // and appending newly elements as they are inserted. This is left as a task to the user until we can manage
        // to improve this example code!
        // If your items are of variable height:
        // - Split them into same height items would be simpler and facilitate random-seeking into your list.
        // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items.
        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
        if (copy_to_clipboard)
            ImGui::LogToClipboard();
        for (const auto& item: state.console.lines) {
            /*if (!Filter.PassFilter(item))
                continue;*/

            if (item.color.has_value())
                ImGui::PushStyleColor(ImGuiCol_Text, item.color.value());
            ImGui::TextUnformatted(item.text.c_str());
            if (item.color.has_value())
                ImGui::PopStyleColor();
        }
        if (copy_to_clipboard)
            ImGui::LogFinish();

        if (options.console.scroll || ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
            ImGui::SetScrollHereY(1.0f);

        ImGui::PopStyleVar();
        ImGui::EndChild();
        ImGui::Separator();

        // Command-line
        const auto flags = ImGuiInputTextFlags_EnterReturnsTrue;
        // | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
        ImGui::GetColumnWidth();
        if (ImGui::InputText("", state.console.buffer.data(), state.console.buffer.size(), flags /*TODO: completion (, callback, context)*/) && strlen(state.console.buffer.data()) > 0)
            actions |= Actions::Message;

        // Auto-focus on window apparition
        ImGui::SetItemDefaultFocus();
        if (actions && Actions::Message)
            ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget

        ImGui::End();
        ImGui::PopStyleVar();
    }

    if (options.overlay.visible) {
        if (options.overlay.corner != -1) {
            ImVec2 window_pos = ImVec2((options.overlay.corner & 1) ? io.DisplaySize.x - UI_MARGIN : UI_MARGIN, (options.overlay.corner & 2) ? io.DisplaySize.y - UI_MARGIN : UI_MARGIN);
            ImVec2 window_pos_pivot = ImVec2((options.overlay.corner & 1) ? 1.0f : 0.0f, (options.overlay.corner & 2) ? 1.0f : 0.0f);
            ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
        }
        ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
        ImGui::Begin("Overlay", &options.overlay.visible, (options.overlay.corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav);
        ImGui::Text("%.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
        ImGui::Text("%ld tris(%ld models)", reports.tris_count, reports.models_count);
        if (ImGui::BeginPopupContextWindow()) {
            if (ImGui::MenuItem("Custom", NULL, options.overlay.corner == -1))
                options.overlay.corner = -1;
            if (ImGui::MenuItem("Top-left", NULL, options.overlay.corner == 0))
                options.overlay.corner = 0;
            if (ImGui::MenuItem("Top-right", NULL, options.overlay.corner == 1))
                options.overlay.corner = 1;
            if (ImGui::MenuItem("Bottom-left", NULL, options.overlay.corner == 2))
                options.overlay.corner = 2;
            if (ImGui::MenuItem("Bottom-right", NULL, options.overlay.corner == 3))
                options.overlay.corner = 3;
            if (options.overlay.visible && ImGui::MenuItem("Close"))
                options.overlay.visible = false;
            ImGui::EndPopup();
        }
        ImGui::End();
    }
    ImGui::Render();
    return actions;
}

bool UI::IsFocus() {
    return ImGui::IsAnyItemActive();
}

void UI::Unload() {
    delete sInstance;
    sInstance = nullptr;
}