|
- /*
- * DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
- *
- * 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 <GL/glew.h>
-
- #include "ImGuiUI.hpp"
- #include <imgui.h>
- #if !defined(IMGUI_GL2) && !defined(IMGUI_GL3)
- # define IMGUI_GL2 1
- #endif
- #if defined(IMGUI_GL2)
- # include <imgui_impl_opengl2.h>
- #elif defined(IMGUI_GL3)
- # include <imgui_impl_opengl3.h>
- #endif
- #include <chrono>
- #include <cmath>
-
- 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<std::chrono::milliseconds>(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
|