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.

315 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. static int mouseButtonToImGui(int button);
  38. ImGuiUI* fSelf = nullptr;
  39. ImGuiContext* fContext = nullptr;
  40. Color fBackgroundColor{0.25f, 0.25f, 0.25f};
  41. int fRepaintIntervalMs = 15;
  42. using Clock = std::chrono::steady_clock;
  43. Clock::time_point fLastRepainted;
  44. bool fWasEverPainted = false;
  45. };
  46. ImGuiUI::ImGuiUI(Window& windowToMapTo)
  47. : TopLevelWidget(windowToMapTo),
  48. fImpl(new ImGuiUI::Impl(this))
  49. {
  50. getApp().addIdleCallback(this);
  51. }
  52. ImGuiUI::~ImGuiUI()
  53. {
  54. delete fImpl;
  55. }
  56. void ImGuiUI::setBackgroundColor(Color color)
  57. {
  58. fImpl->fBackgroundColor = color;
  59. }
  60. void ImGuiUI::setRepaintInterval(int intervalMs)
  61. {
  62. fImpl->fRepaintIntervalMs = intervalMs;
  63. }
  64. void ImGuiUI::onDisplay()
  65. {
  66. ImGui::SetCurrentContext(fImpl->fContext);
  67. #if defined(IMGUI_GL2)
  68. ImGui_ImplOpenGL2_NewFrame();
  69. #elif defined(IMGUI_GL3)
  70. ImGui_ImplOpenGL3_NewFrame();
  71. #endif
  72. ImGui::NewFrame();
  73. onImGuiDisplay();
  74. ImGui::Render();
  75. ImGuiIO &io = ImGui::GetIO();
  76. glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
  77. Color backgroundColor = fImpl->fBackgroundColor;
  78. glClearColor(
  79. backgroundColor.red, backgroundColor.green,
  80. backgroundColor.blue, backgroundColor.alpha);
  81. glClear(GL_COLOR_BUFFER_BIT);
  82. glLoadIdentity();
  83. #if defined(IMGUI_GL2)
  84. ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
  85. #elif defined(IMGUI_GL3)
  86. ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
  87. #endif
  88. fImpl->fLastRepainted = Impl::Clock::now();
  89. fImpl->fWasEverPainted = true;
  90. }
  91. bool ImGuiUI::onKeyboard(const KeyboardEvent& event)
  92. {
  93. ImGui::SetCurrentContext(fImpl->fContext);
  94. ImGuiIO &io = ImGui::GetIO();
  95. if (event.press)
  96. io.AddInputCharacter(event.key);
  97. int imGuiKey = event.key;
  98. if (imGuiKey >= 0 && imGuiKey < 128)
  99. {
  100. if (imGuiKey >= 'a' && imGuiKey <= 'z')
  101. imGuiKey = imGuiKey - 'a' + 'A';
  102. io.KeysDown[imGuiKey] = event.press;
  103. }
  104. return io.WantCaptureKeyboard;
  105. }
  106. bool ImGuiUI::onSpecial(const SpecialEvent& event)
  107. {
  108. ImGui::SetCurrentContext(fImpl->fContext);
  109. ImGuiIO &io = ImGui::GetIO();
  110. int imGuiKey = IM_ARRAYSIZE(io.KeysDown) - event.key;
  111. io.KeysDown[imGuiKey] = event.press;
  112. switch (event.key)
  113. {
  114. case kKeyShift:
  115. io.KeyShift = event.press;
  116. break;
  117. case kKeyControl:
  118. io.KeyCtrl = event.press;
  119. break;
  120. case kKeyAlt:
  121. io.KeyAlt = event.press;
  122. break;
  123. case kKeySuper:
  124. io.KeySuper = event.press;
  125. break;
  126. default:
  127. break;
  128. }
  129. return io.WantCaptureKeyboard;
  130. }
  131. bool ImGuiUI::onMouse(const MouseEvent& event)
  132. {
  133. ImGui::SetCurrentContext(fImpl->fContext);
  134. ImGuiIO &io = ImGui::GetIO();
  135. int imGuiButton = Impl::mouseButtonToImGui(event.button);
  136. if (imGuiButton != -1)
  137. io.MouseDown[imGuiButton] = event.press;
  138. return io.WantCaptureMouse;
  139. }
  140. bool ImGuiUI::onMotion(const MotionEvent& event)
  141. {
  142. ImGui::SetCurrentContext(fImpl->fContext);
  143. ImGuiIO &io = ImGui::GetIO();
  144. // FIXME
  145. const double scaleFactor = 1; // getScaleFactor();
  146. io.MousePos.x = std::round(scaleFactor * event.pos.getX());
  147. io.MousePos.y = std::round(scaleFactor * event.pos.getY());
  148. return false;
  149. }
  150. bool ImGuiUI::onScroll(const ScrollEvent& event)
  151. {
  152. ImGui::SetCurrentContext(fImpl->fContext);
  153. ImGuiIO &io = ImGui::GetIO();
  154. io.MouseWheel += event.delta.getY();
  155. io.MouseWheelH += event.delta.getX();
  156. return io.WantCaptureMouse;
  157. }
  158. void ImGuiUI::onResize(const ResizeEvent& event)
  159. {
  160. TopLevelWidget::onResize(event);
  161. const uint width = event.size.getWidth();
  162. const uint height = event.size.getHeight();
  163. ImGui::SetCurrentContext(fImpl->fContext);
  164. ImGuiIO &io = ImGui::GetIO();
  165. const double scaleFactor = getScaleFactor();
  166. io.DisplaySize.x = std::round(scaleFactor * width);
  167. io.DisplaySize.y = std::round(scaleFactor * height);
  168. }
  169. void ImGuiUI::idleCallback()
  170. {
  171. bool shouldRepaint;
  172. if (fImpl->fWasEverPainted)
  173. {
  174. Impl::Clock::duration elapsed =
  175. Impl::Clock::now() - fImpl->fLastRepainted;
  176. std::chrono::milliseconds elapsedMs =
  177. std::chrono::duration_cast<std::chrono::milliseconds>(elapsed);
  178. shouldRepaint = elapsedMs.count() > fImpl->fRepaintIntervalMs;
  179. }
  180. else
  181. {
  182. shouldRepaint = true;
  183. }
  184. if (shouldRepaint)
  185. repaint();
  186. }
  187. ImGuiUI::Impl::Impl(ImGuiUI* self)
  188. : fSelf(self)
  189. {
  190. setupGL();
  191. }
  192. ImGuiUI::Impl::~Impl()
  193. {
  194. cleanupGL();
  195. }
  196. void ImGuiUI::Impl::setupGL()
  197. {
  198. DISTRHO_SAFE_ASSERT_RETURN(glewInit() == 0,);
  199. IMGUI_CHECKVERSION();
  200. fContext = ImGui::CreateContext();
  201. ImGui::SetCurrentContext(fContext);
  202. ImGuiIO &io = ImGui::GetIO();
  203. const double scaleFactor = fSelf->getScaleFactor();
  204. io.DisplaySize.x = std::round(scaleFactor * fSelf->getWidth());
  205. io.DisplaySize.y = std::round(scaleFactor * fSelf->getHeight());
  206. io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
  207. io.IniFilename = nullptr;
  208. io.KeyMap[ImGuiKey_Tab] = '\t';
  209. io.KeyMap[ImGuiKey_LeftArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyLeft;
  210. io.KeyMap[ImGuiKey_RightArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyRight;
  211. io.KeyMap[ImGuiKey_UpArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyUp;
  212. io.KeyMap[ImGuiKey_DownArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyDown;
  213. io.KeyMap[ImGuiKey_PageUp] = IM_ARRAYSIZE(io.KeysDown) - kKeyPageUp;
  214. io.KeyMap[ImGuiKey_PageDown] = IM_ARRAYSIZE(io.KeysDown) - kKeyPageDown;
  215. io.KeyMap[ImGuiKey_Home] = IM_ARRAYSIZE(io.KeysDown) - kKeyHome;
  216. io.KeyMap[ImGuiKey_End] = IM_ARRAYSIZE(io.KeysDown) - kKeyEnd;
  217. io.KeyMap[ImGuiKey_Insert] = IM_ARRAYSIZE(io.KeysDown) - kKeyInsert;
  218. io.KeyMap[ImGuiKey_Delete] = 127;
  219. io.KeyMap[ImGuiKey_Backspace] = '\b';
  220. io.KeyMap[ImGuiKey_Space] = ' ';
  221. io.KeyMap[ImGuiKey_Enter] = '\r';
  222. io.KeyMap[ImGuiKey_Escape] = 27;
  223. io.KeyMap[ImGuiKey_A] = 'A';
  224. io.KeyMap[ImGuiKey_C] = 'C';
  225. io.KeyMap[ImGuiKey_V] = 'V';
  226. io.KeyMap[ImGuiKey_X] = 'X';
  227. io.KeyMap[ImGuiKey_Y] = 'Y';
  228. io.KeyMap[ImGuiKey_Z] = 'Z';
  229. #if defined(IMGUI_GL2)
  230. ImGui_ImplOpenGL2_Init();
  231. #elif defined(IMGUI_GL3)
  232. ImGui_ImplOpenGL3_Init();
  233. #endif
  234. }
  235. void ImGuiUI::Impl::cleanupGL()
  236. {
  237. ImGui::SetCurrentContext(fContext);
  238. #if defined(IMGUI_GL2)
  239. ImGui_ImplOpenGL2_Shutdown();
  240. #elif defined(IMGUI_GL3)
  241. ImGui_ImplOpenGL3_Shutdown();
  242. #endif
  243. ImGui::DestroyContext(fContext);
  244. }
  245. int ImGuiUI::Impl::mouseButtonToImGui(int button)
  246. {
  247. switch (button)
  248. {
  249. default:
  250. return -1;
  251. case 1:
  252. return 0;
  253. case 2:
  254. return 2;
  255. case 3:
  256. return 1;
  257. }
  258. }
  259. END_NAMESPACE_DGL