/* * DISTRHO Plugin Framework (DPF) * Copyright (C) 2021 Jean Pierre Cimalando * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this * permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "Application.hpp" #include #include "ImGuiUI.hpp" #include #if !defined(IMGUI_GL2) && !defined(IMGUI_GL3) # define IMGUI_GL2 1 #endif #if defined(IMGUI_GL2) # include #elif defined(IMGUI_GL3) # include #endif #include #include START_NAMESPACE_DGL struct ImGuiUI::Impl { explicit Impl(ImGuiUI* self); ~Impl(); void setupGL(); void cleanupGL(); static int mouseButtonToImGui(int button); ImGuiUI* fSelf = nullptr; ImGuiContext* fContext = nullptr; Color fBackgroundColor{0.25f, 0.25f, 0.25f}; int fRepaintIntervalMs = 15; using Clock = std::chrono::steady_clock; Clock::time_point fLastRepainted; bool fWasEverPainted = false; }; ImGuiUI::ImGuiUI(Window& windowToMapTo) : TopLevelWidget(windowToMapTo), fImpl(new ImGuiUI::Impl(this)) { getApp().addIdleCallback(this); } ImGuiUI::~ImGuiUI() { delete fImpl; } void ImGuiUI::setBackgroundColor(Color color) { fImpl->fBackgroundColor = color; } void ImGuiUI::setRepaintInterval(int intervalMs) { fImpl->fRepaintIntervalMs = intervalMs; } void ImGuiUI::onDisplay() { ImGui::SetCurrentContext(fImpl->fContext); #if defined(IMGUI_GL2) ImGui_ImplOpenGL2_NewFrame(); #elif defined(IMGUI_GL3) ImGui_ImplOpenGL3_NewFrame(); #endif ImGui::NewFrame(); onImGuiDisplay(); ImGui::Render(); ImGuiIO &io = ImGui::GetIO(); glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); Color backgroundColor = fImpl->fBackgroundColor; glClearColor( backgroundColor.red, backgroundColor.green, backgroundColor.blue, backgroundColor.alpha); glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); #if defined(IMGUI_GL2) ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); #elif defined(IMGUI_GL3) ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); #endif fImpl->fLastRepainted = Impl::Clock::now(); fImpl->fWasEverPainted = true; } bool ImGuiUI::onKeyboard(const KeyboardEvent& event) { ImGui::SetCurrentContext(fImpl->fContext); ImGuiIO &io = ImGui::GetIO(); if (event.press) io.AddInputCharacter(event.key); int imGuiKey = event.key; if (imGuiKey >= 0 && imGuiKey < 128) { if (imGuiKey >= 'a' && imGuiKey <= 'z') imGuiKey = imGuiKey - 'a' + 'A'; io.KeysDown[imGuiKey] = event.press; } return io.WantCaptureKeyboard; } bool ImGuiUI::onSpecial(const SpecialEvent& event) { ImGui::SetCurrentContext(fImpl->fContext); ImGuiIO &io = ImGui::GetIO(); int imGuiKey = IM_ARRAYSIZE(io.KeysDown) - event.key; io.KeysDown[imGuiKey] = event.press; switch (event.key) { case kKeyShift: io.KeyShift = event.press; break; case kKeyControl: io.KeyCtrl = event.press; break; case kKeyAlt: io.KeyAlt = event.press; break; case kKeySuper: io.KeySuper = event.press; break; default: break; } return io.WantCaptureKeyboard; } bool ImGuiUI::onMouse(const MouseEvent& event) { ImGui::SetCurrentContext(fImpl->fContext); ImGuiIO &io = ImGui::GetIO(); int imGuiButton = Impl::mouseButtonToImGui(event.button); if (imGuiButton != -1) io.MouseDown[imGuiButton] = event.press; return io.WantCaptureMouse; } bool ImGuiUI::onMotion(const MotionEvent& event) { ImGui::SetCurrentContext(fImpl->fContext); ImGuiIO &io = ImGui::GetIO(); // FIXME const double scaleFactor = 1; // getScaleFactor(); io.MousePos.x = std::round(scaleFactor * event.pos.getX()); io.MousePos.y = std::round(scaleFactor * event.pos.getY()); return false; } bool ImGuiUI::onScroll(const ScrollEvent& event) { ImGui::SetCurrentContext(fImpl->fContext); ImGuiIO &io = ImGui::GetIO(); io.MouseWheel += event.delta.getY(); io.MouseWheelH += event.delta.getX(); return io.WantCaptureMouse; } void ImGuiUI::onResize(const ResizeEvent& event) { TopLevelWidget::onResize(event); const uint width = event.size.getWidth(); const uint height = event.size.getHeight(); ImGui::SetCurrentContext(fImpl->fContext); ImGuiIO &io = ImGui::GetIO(); const double scaleFactor = getScaleFactor(); io.DisplaySize.x = std::round(scaleFactor * width); io.DisplaySize.y = std::round(scaleFactor * height); } void ImGuiUI::idleCallback() { bool shouldRepaint; if (fImpl->fWasEverPainted) { Impl::Clock::duration elapsed = Impl::Clock::now() - fImpl->fLastRepainted; std::chrono::milliseconds elapsedMs = std::chrono::duration_cast(elapsed); shouldRepaint = elapsedMs.count() > fImpl->fRepaintIntervalMs; } else { shouldRepaint = true; } if (shouldRepaint) repaint(); } ImGuiUI::Impl::Impl(ImGuiUI* self) : fSelf(self) { setupGL(); } ImGuiUI::Impl::~Impl() { cleanupGL(); } void ImGuiUI::Impl::setupGL() { DISTRHO_SAFE_ASSERT_RETURN(glewInit() == 0,); IMGUI_CHECKVERSION(); fContext = ImGui::CreateContext(); ImGui::SetCurrentContext(fContext); ImGuiIO &io = ImGui::GetIO(); const double scaleFactor = fSelf->getScaleFactor(); io.DisplaySize.x = std::round(scaleFactor * fSelf->getWidth()); io.DisplaySize.y = std::round(scaleFactor * fSelf->getHeight()); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; io.IniFilename = nullptr; io.KeyMap[ImGuiKey_Tab] = '\t'; io.KeyMap[ImGuiKey_LeftArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyLeft; io.KeyMap[ImGuiKey_RightArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyRight; io.KeyMap[ImGuiKey_UpArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyUp; io.KeyMap[ImGuiKey_DownArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyDown; io.KeyMap[ImGuiKey_PageUp] = IM_ARRAYSIZE(io.KeysDown) - kKeyPageUp; io.KeyMap[ImGuiKey_PageDown] = IM_ARRAYSIZE(io.KeysDown) - kKeyPageDown; io.KeyMap[ImGuiKey_Home] = IM_ARRAYSIZE(io.KeysDown) - kKeyHome; io.KeyMap[ImGuiKey_End] = IM_ARRAYSIZE(io.KeysDown) - kKeyEnd; io.KeyMap[ImGuiKey_Insert] = IM_ARRAYSIZE(io.KeysDown) - kKeyInsert; io.KeyMap[ImGuiKey_Delete] = 127; io.KeyMap[ImGuiKey_Backspace] = '\b'; io.KeyMap[ImGuiKey_Space] = ' '; io.KeyMap[ImGuiKey_Enter] = '\r'; io.KeyMap[ImGuiKey_Escape] = 27; io.KeyMap[ImGuiKey_A] = 'A'; io.KeyMap[ImGuiKey_C] = 'C'; io.KeyMap[ImGuiKey_V] = 'V'; io.KeyMap[ImGuiKey_X] = 'X'; io.KeyMap[ImGuiKey_Y] = 'Y'; io.KeyMap[ImGuiKey_Z] = 'Z'; #if defined(IMGUI_GL2) ImGui_ImplOpenGL2_Init(); #elif defined(IMGUI_GL3) ImGui_ImplOpenGL3_Init(); #endif } void ImGuiUI::Impl::cleanupGL() { ImGui::SetCurrentContext(fContext); #if defined(IMGUI_GL2) ImGui_ImplOpenGL2_Shutdown(); #elif defined(IMGUI_GL3) ImGui_ImplOpenGL3_Shutdown(); #endif ImGui::DestroyContext(fContext); } int ImGuiUI::Impl::mouseButtonToImGui(int button) { switch (button) { default: return -1; case 1: return 0; case 2: return 2; case 3: return 1; } } END_NAMESPACE_DGL