DISTRHO Plugin Framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

317 lines
7.9KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "Application.hpp"
  17. #include <GL/glew.h>
  18. #include "ImGuiUI.hpp"
  19. #include <imgui.h>
  20. #if !defined(IMGUI_GL2) && !defined(IMGUI_GL3)
  21. # define IMGUI_GL2 1
  22. #endif
  23. #if defined(IMGUI_GL2)
  24. # include <imgui_impl_opengl2.h>
  25. #elif defined(IMGUI_GL3)
  26. # include <imgui_impl_opengl3.h>
  27. #endif
  28. #include <chrono>
  29. #include <cmath>
  30. START_NAMESPACE_DGL
  31. struct ImGuiUI::Impl
  32. {
  33. explicit Impl(ImGuiUI* self);
  34. ~Impl();
  35. void setupGL();
  36. void cleanupGL();
  37. // perhaps DPF will implement this in the future
  38. float getScaleFactor() const { return 1.0f; }
  39. static int mouseButtonToImGui(int button);
  40. ImGuiUI* fSelf = nullptr;
  41. ImGuiContext* fContext = nullptr;
  42. Color fBackgroundColor{0.25f, 0.25f, 0.25f};
  43. int fRepaintIntervalMs = 15;
  44. using Clock = std::chrono::steady_clock;
  45. Clock::time_point fLastRepainted;
  46. bool fWasEverPainted = false;
  47. };
  48. ImGuiUI::ImGuiUI(Window& windowToMapTo)
  49. : TopLevelWidget(windowToMapTo),
  50. fImpl(new ImGuiUI::Impl(this))
  51. {
  52. getApp().addIdleCallback(this);
  53. }
  54. ImGuiUI::~ImGuiUI()
  55. {
  56. delete fImpl;
  57. }
  58. void ImGuiUI::setBackgroundColor(Color color)
  59. {
  60. fImpl->fBackgroundColor = color;
  61. }
  62. void ImGuiUI::setRepaintInterval(int intervalMs)
  63. {
  64. fImpl->fRepaintIntervalMs = intervalMs;
  65. }
  66. void ImGuiUI::onDisplay()
  67. {
  68. ImGui::SetCurrentContext(fImpl->fContext);
  69. #if defined(IMGUI_GL2)
  70. ImGui_ImplOpenGL2_NewFrame();
  71. #elif defined(IMGUI_GL3)
  72. ImGui_ImplOpenGL3_NewFrame();
  73. #endif
  74. ImGui::NewFrame();
  75. onImGuiDisplay();
  76. ImGui::Render();
  77. ImGuiIO &io = ImGui::GetIO();
  78. glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
  79. Color backgroundColor = fImpl->fBackgroundColor;
  80. glClearColor(
  81. backgroundColor.red, backgroundColor.green,
  82. backgroundColor.blue, backgroundColor.alpha);
  83. glClear(GL_COLOR_BUFFER_BIT);
  84. glLoadIdentity();
  85. #if defined(IMGUI_GL2)
  86. ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
  87. #elif defined(IMGUI_GL3)
  88. ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
  89. #endif
  90. fImpl->fLastRepainted = Impl::Clock::now();
  91. fImpl->fWasEverPainted = true;
  92. }
  93. bool ImGuiUI::onKeyboard(const KeyboardEvent& event)
  94. {
  95. ImGui::SetCurrentContext(fImpl->fContext);
  96. ImGuiIO &io = ImGui::GetIO();
  97. if (event.press)
  98. io.AddInputCharacter(event.key);
  99. int imGuiKey = event.key;
  100. if (imGuiKey >= 0 && imGuiKey < 128)
  101. {
  102. if (imGuiKey >= 'a' && imGuiKey <= 'z')
  103. imGuiKey = imGuiKey - 'a' + 'A';
  104. io.KeysDown[imGuiKey] = event.press;
  105. }
  106. return io.WantCaptureKeyboard;
  107. }
  108. bool ImGuiUI::onSpecial(const SpecialEvent& event)
  109. {
  110. ImGui::SetCurrentContext(fImpl->fContext);
  111. ImGuiIO &io = ImGui::GetIO();
  112. int imGuiKey = IM_ARRAYSIZE(io.KeysDown) - event.key;
  113. io.KeysDown[imGuiKey] = event.press;
  114. switch (event.key)
  115. {
  116. case kKeyShift:
  117. io.KeyShift = event.press;
  118. break;
  119. case kKeyControl:
  120. io.KeyCtrl = event.press;
  121. break;
  122. case kKeyAlt:
  123. io.KeyAlt = event.press;
  124. break;
  125. case kKeySuper:
  126. io.KeySuper = event.press;
  127. break;
  128. default:
  129. break;
  130. }
  131. return io.WantCaptureKeyboard;
  132. }
  133. bool ImGuiUI::onMouse(const MouseEvent& event)
  134. {
  135. ImGui::SetCurrentContext(fImpl->fContext);
  136. ImGuiIO &io = ImGui::GetIO();
  137. int imGuiButton = Impl::mouseButtonToImGui(event.button);
  138. if (imGuiButton != -1)
  139. io.MouseDown[imGuiButton] = event.press;
  140. return io.WantCaptureMouse;
  141. }
  142. bool ImGuiUI::onMotion(const MotionEvent& event)
  143. {
  144. ImGui::SetCurrentContext(fImpl->fContext);
  145. ImGuiIO &io = ImGui::GetIO();
  146. const float scaleFactor = fImpl->getScaleFactor();
  147. io.MousePos.x = std::round(scaleFactor * event.pos.getX());
  148. io.MousePos.y = std::round(scaleFactor * event.pos.getY());
  149. return false;
  150. }
  151. bool ImGuiUI::onScroll(const ScrollEvent& event)
  152. {
  153. ImGui::SetCurrentContext(fImpl->fContext);
  154. ImGuiIO &io = ImGui::GetIO();
  155. io.MouseWheel += event.delta.getY();
  156. io.MouseWheelH += event.delta.getX();
  157. return io.WantCaptureMouse;
  158. }
  159. void ImGuiUI::onResize(const ResizeEvent& event)
  160. {
  161. TopLevelWidget::onResize(event);
  162. const uint width = event.size.getWidth();
  163. const uint height = event.size.getHeight();
  164. ImGui::SetCurrentContext(fImpl->fContext);
  165. ImGuiIO &io = ImGui::GetIO();
  166. const float scaleFactor = fImpl->getScaleFactor();
  167. io.DisplaySize.x = std::round(scaleFactor * width);
  168. io.DisplaySize.y = std::round(scaleFactor * height);
  169. }
  170. void ImGuiUI::idleCallback()
  171. {
  172. bool shouldRepaint;
  173. if (fImpl->fWasEverPainted)
  174. {
  175. Impl::Clock::duration elapsed =
  176. Impl::Clock::now() - fImpl->fLastRepainted;
  177. std::chrono::milliseconds elapsedMs =
  178. std::chrono::duration_cast<std::chrono::milliseconds>(elapsed);
  179. shouldRepaint = elapsedMs.count() > fImpl->fRepaintIntervalMs;
  180. }
  181. else
  182. {
  183. shouldRepaint = true;
  184. }
  185. if (shouldRepaint)
  186. repaint();
  187. }
  188. ImGuiUI::Impl::Impl(ImGuiUI* self)
  189. : fSelf(self)
  190. {
  191. setupGL();
  192. }
  193. ImGuiUI::Impl::~Impl()
  194. {
  195. cleanupGL();
  196. }
  197. void ImGuiUI::Impl::setupGL()
  198. {
  199. DISTRHO_SAFE_ASSERT_RETURN(glewInit() == 0,);
  200. IMGUI_CHECKVERSION();
  201. fContext = ImGui::CreateContext();
  202. ImGui::SetCurrentContext(fContext);
  203. ImGuiIO &io = ImGui::GetIO();
  204. const float scaleFactor = getScaleFactor();
  205. io.DisplaySize.x = std::round(scaleFactor * fSelf->getWidth());
  206. io.DisplaySize.y = std::round(scaleFactor * fSelf->getHeight());
  207. io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
  208. io.IniFilename = nullptr;
  209. io.KeyMap[ImGuiKey_Tab] = '\t';
  210. io.KeyMap[ImGuiKey_LeftArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyLeft;
  211. io.KeyMap[ImGuiKey_RightArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyRight;
  212. io.KeyMap[ImGuiKey_UpArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyUp;
  213. io.KeyMap[ImGuiKey_DownArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyDown;
  214. io.KeyMap[ImGuiKey_PageUp] = IM_ARRAYSIZE(io.KeysDown) - kKeyPageUp;
  215. io.KeyMap[ImGuiKey_PageDown] = IM_ARRAYSIZE(io.KeysDown) - kKeyPageDown;
  216. io.KeyMap[ImGuiKey_Home] = IM_ARRAYSIZE(io.KeysDown) - kKeyHome;
  217. io.KeyMap[ImGuiKey_End] = IM_ARRAYSIZE(io.KeysDown) - kKeyEnd;
  218. io.KeyMap[ImGuiKey_Insert] = IM_ARRAYSIZE(io.KeysDown) - kKeyInsert;
  219. io.KeyMap[ImGuiKey_Delete] = 127;
  220. io.KeyMap[ImGuiKey_Backspace] = '\b';
  221. io.KeyMap[ImGuiKey_Space] = ' ';
  222. io.KeyMap[ImGuiKey_Enter] = '\r';
  223. io.KeyMap[ImGuiKey_Escape] = 27;
  224. io.KeyMap[ImGuiKey_A] = 'A';
  225. io.KeyMap[ImGuiKey_C] = 'C';
  226. io.KeyMap[ImGuiKey_V] = 'V';
  227. io.KeyMap[ImGuiKey_X] = 'X';
  228. io.KeyMap[ImGuiKey_Y] = 'Y';
  229. io.KeyMap[ImGuiKey_Z] = 'Z';
  230. #if defined(IMGUI_GL2)
  231. ImGui_ImplOpenGL2_Init();
  232. #elif defined(IMGUI_GL3)
  233. ImGui_ImplOpenGL3_Init();
  234. #endif
  235. }
  236. void ImGuiUI::Impl::cleanupGL()
  237. {
  238. ImGui::SetCurrentContext(fContext);
  239. #if defined(IMGUI_GL2)
  240. ImGui_ImplOpenGL2_Shutdown();
  241. #elif defined(IMGUI_GL3)
  242. ImGui_ImplOpenGL3_Shutdown();
  243. #endif
  244. ImGui::DestroyContext(fContext);
  245. }
  246. int ImGuiUI::Impl::mouseButtonToImGui(int button)
  247. {
  248. switch (button)
  249. {
  250. default:
  251. return -1;
  252. case 1:
  253. return 0;
  254. case 2:
  255. return 2;
  256. case 3:
  257. return 1;
  258. }
  259. }
  260. END_NAMESPACE_DGL