Skip to content

File ImguiManager.cpp

File List > src > UI > ImguiManager.cpp

Go to the documentation of this file

#include "ImGui/backends/imgui_impl_glfw.h"
#include "ImGui/backends/imgui_impl_opengl3.h"

#include "ImguiManager.h"
#include "ImguiTheme.h"
#include "Input.h"
#include "layer/ShaderEditor.h"
#include "Guizmo/ImGuizmo.h"

#include "events/KeyMouseEvents.h"

#include "../app/Window.h"

bool ImguiManager::is_prefW_open = false;

ImguiManager::ImguiManager(EventPool& evt, Window& w)
{
    // Create the ImGui context; must happen before any ImGui::GetIO() / GetStyle() calls.
    // Moved here from Application so ImguiManager fully owns its context lifetime.
    ImGui::CreateContext();

    io = &ImGui::GetIO();
    m_style = &ImGui::GetStyle();

    DefultViewports();
    RegistarMenuEvents(evt);
    RegisterLayerEvents(evt);

    ImGui_ImplOpenGL3_Init();
    ImGui_ImplGlfw_InitForOpenGL(w.Get(), true);
    ImGui::StyleColorsDark();

    ImGui::GetStyle().Colors[ImGuiCol_Header] = ImVec4(1, 1, 1, 0);
    ImGui::GetStyle().Colors[ImGuiCol_HeaderActive] = ImVec4(1, 1, 1, 0.4f);
    ImGui::GetStyle().Colors[ImGuiCol_HeaderHovered] = ImVec4(1, 1, 1, 0.2f);
    ImGui::GetStyle().Colors[ImGuiCol_Text] = ImVec4(1, 1, 1, 1);
    ImGui::GetStyle().Colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.07f, 1);
    ImGui::GetStyle().Colors[ImGuiCol_FrameBg] = ImVec4(0, 0.21f, 0.51f, 0.51f);
    ImGui::GetStyle().Colors[ImGuiCol_ButtonActive] = ImVec4(0.71f, 0.84f, 0.96f, 1);
    ImGui::GetStyle().Colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.1f, 0.1f, 0.1f, 1);

    ImGui::GetStyle().WindowRounding = 0.0f;// <- Set this on init or use ImGui::PushStyleVar()
    ImGui::GetStyle().ChildRounding = 5.0f;
    ImGui::GetStyle().FrameRounding = 3.0f;
    ImGui::GetStyle().GrabRounding = 100.0f;
    ImGui::GetStyle().PopupRounding = 10.0f;
    ImGui::GetStyle().ScrollbarRounding = 5.0f;
    ImGui::GetStyle().TabRounding = 7;

    ImGui::GetStyle().FrameBorderSize = 1;
    ImGui::GetStyle().FramePadding = ImVec2(10, 4);
    ImGui::GetStyle().ItemSpacing = ImVec2(5, 4);
    ImGui::GetStyle().ScrollbarSize = 11;
    ImGui::GetStyle().GrabMinSize = 7;

    ImFontConfig config;
    //config.MergeMode = true;
    //config.GlyphMinAdvanceX = 13.0f;// Use if you want to make the icon monospaced
    static const ImWchar icon_ranges[] = { ICON_MIN,ICON_MAX,0 };
    ImguiTheme::th_data.font_data.push_back(ImGui::GetIO().Fonts->AddFontFromFileTTF("res/icon/OpenFontIcons.ttf", 13.0f, &config, icon_ranges));
}

ImguiManager::~ImguiManager()
{
    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImGui::DestroyContext();
}

void ImguiManager::_debug() const
{
    for (auto& [name, id] : layer_name_buffer) {
        std::cout << name << " " << id << "\n";
    }
}

void ImguiManager::RegistarMenuEvents(EventPool& evt)
{
    for (auto& menu : menu_list)
        for (auto& submenu : menu->subm_list) {
            if (submenu->mitem_shortcut.empty()) continue;

            Input::KeyState key_state = Input::ParseKeyState(submenu->mitem_shortcut);
            evt.subscribe<KeyClickEvent>([submenu, key_state](KeyClickEvent e) {
                if (e.key == key_state) submenu->mitem_func(true);
                });
        }
}



void ImguiManager::RegisterLayerEvents(EventPool& evt)
{
    for (auto& layer : layer_list) {
        layer->RegisterEvents(evt);
    }
}

void ImguiManager::NewFrame() const
{
    ImGui_ImplOpenGL3_NewFrame();
    ImGui_ImplGlfw_NewFrame();
    ImGui::NewFrame();
    ImGuizmo::BeginFrame();
}

#include "menu/ImguiMSwitch.h"
void ImguiManager::PushImguiLayer(std::shared_ptr<ImguiLayer> layer)
{
    assert(layer_name_buffer.find(layer->uly_name) == layer_name_buffer.end());

    layer->uly_ID = (int)layer_list.size(); //start with 0
    layer_list.push_back(layer);
    layer_name_buffer[layer->uly_name] = layer->uly_ID;

    auto window = std::make_shared<UI::ImguiMSwitch>(layer->uly_name);
    window->BindSwitch(&layer->uly_is_rendered);
    FindImguiMenu("Window")->PushSubMenu(window);
}

ImguiLayer* ImguiManager::FindImguiLayer(const std::string& name) const
{
    if (layer_name_buffer.find(name) != layer_name_buffer.end())
        return layer_list[layer_name_buffer[name]].get();
    DEBUG("[ no layer named " + name + " ]");
    return nullptr;
}

ImguiLayer* ImguiManager::FindImguiLayer(int id) const
{
    if (id > layer_list.size())
        return nullptr;

    return layer_list[id].get();
}

ImguiItem* ImguiManager::FindImguiItem(const std::string& layer, const std::string& name) const
{
    ImguiLayer* layer_ptr = FindImguiLayer(layer);
    if (layer_ptr == nullptr)
        return nullptr;

    return layer_ptr->FindImguiItem(name);
}

ImguiItem* ImguiManager::FindImguiItem(int id, const std::string& name) const
{
    ImguiLayer* layer_ptr = FindImguiLayer(id);
    if (layer_ptr == nullptr)
        return nullptr;

    return layer_ptr->FindImguiItem(name);
}

ImguiItem* ImguiManager::FindImguiItem(int id, int item_id) const
{
    ImguiLayer* layer_ptr = FindImguiLayer(id);
    if (layer_ptr == nullptr)
        return nullptr;

    return layer_ptr->FindImguiItem(item_id);
}

void ImguiManager::PushImguiMenu(std::shared_ptr<ImguiMenu> _menu)
{
    _menu->menu_id = (int)menu_list.size();
    menu_list.push_back(_menu);
    menu_name_buffer[_menu->menu_name] = _menu->menu_id;
}

ImguiMenu* ImguiManager::FindImguiMenu(const std::string& name) const
{
    if (menu_name_buffer.find(name) != menu_name_buffer.end())
        return menu_list[menu_name_buffer[name]].get();
    DEBUG("[ no menu named " + name + " ]");
    return nullptr;
}

ImguiMenuItem* ImguiManager::FindImguiMenuItem(const std::string& menu, const std::string& submenu) const
{
    ImguiMenu* menu_ptr = FindImguiMenu(menu);
    if (menu_ptr == nullptr)
        return nullptr;

    return menu_ptr->FindMenuItem(submenu);
}

std::shared_ptr<ImguiMenu> ImguiManager::CreateImguiMenu(std::string name)
{
    std::shared_ptr<ImguiMenu> menu = std::make_shared<ImguiMenu>(name);
    PushImguiMenu(menu);

    return menu;
}

void ImguiManager::ActivateLayer(const std::string& name)
{
    auto it = layer_name_buffer.find(name);
    if (it == layer_name_buffer.end())
        return;

    int idx = it->second;

    if (idx == layer_list.size() - 1)
        return; // already active

    auto layer = layer_list[idx];
    layer_list.erase(layer_list.begin() + idx);

    // update name mapping
    for (auto& [n, i] : layer_name_buffer)
        if (i > idx)
            --i;

    layer_list.push_back(layer);
    layer_name_buffer[name] = layer_list.size() - 1;
}

void ImguiManager::SetButtonFunc(const std::string& ly_name, const std::string& it_name, const std::function<void(void)>& func)
{
    if (FindImguiItem(ly_name, it_name)) {
        DEBUG(ly_name + " " + it_name);
        FindImguiItem(ly_name, it_name)->ButtonFunc = func;
    }
    else {
        DEBUG("button not found");
    }

}

Parameters* ImguiManager::GetParaValue(const std::string& ly_name, const std::string& it_name)
{
    ImguiItem* item = FindImguiItem(ly_name, it_name);
    if (item == nullptr)
        return nullptr;

    return item->GetPara();
}

void RenderLayer(ImguiLayer* layer, const Context& ctx, EventPool& evt)
{
    if (layer->uly_is_rendered) {
        if (ImGui::Begin(layer->uly_name.c_str(), &layer->uly_is_rendered)) {
            const ImVec2 layer_size = layer->GetLayerSize();
            const ImVec2 layer_pos = layer->GetLayerPos();
            const ImVec2 mouse_pos = ImVec2(Input::GetMousePosX(), Input::GetMousePosY());
            layer->is_mouse_hovered = Item::is_inside(layer_size, mouse_pos);

            layer->RenderLayer(ctx, evt);

            layer->is_size_changed_b = layer->is_size_changed;
        }
        else {
            layer->is_mouse_hovered = false;
        }
        ImGui::End();
    }
    else {
        layer->is_mouse_hovered = false;
    }
}

void ImguiManager::RenderUI(const Context& ctx, EventPool& evt, bool rend)
{
    if (rend) {

        if (ParaUpdate)
            ParaUpdate();

    ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport());
        ImGui::BeginMainMenuBar();
        /*          ImGui::BeginMenuBar();*/
        for (const auto& menu : menu_list) {
            menu->RenderMenu(ctx);
        }
        /*          ImGui::EndMenuBar();*/
        ImGui::EndMainMenuBar();

        for (const auto& layer : layer_list) {
            ::RenderLayer(layer.get(), ctx, evt);
        }
    }
    else {
        io->ConfigFlags = !ImGuiConfigFlags_DockingEnable;
    }

    if (is_prefW_open)
        ImGui::ShowStyleEditor();

    ImGui::Render();
    ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
    if (io->ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
    {
        ImGui::UpdatePlatformWindows();
        ImGui::RenderPlatformWindowsDefault();
        glfwSetErrorCallback([](int code, const char* desc) {
            fprintf(stderr, "GLFW Error %d: %s\n", code, desc);
            });
        //glfwMakeContextCurrent(window);
    }
}