Collection of DPF-based plugins for packaging
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.

318 lines
8.5KB

  1. /*
  2. * DISTRHO ProM Plugin
  3. * Copyright (C) 2015-2022 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU Lesser General Public License for more details.
  13. *
  14. * For a full copy of the license see the LICENSE file.
  15. */
  16. /* s/private/public/ as workaround old projectM versions */
  17. #define private public
  18. #include "libprojectM/projectM.hpp"
  19. #undef private
  20. #ifndef PROJECTM_DATA_DIR
  21. #include "libprojectM/projectM-opengl.h"
  22. #endif
  23. #include "DistrhoPluginProM.hpp"
  24. #include "DistrhoUIProM.hpp"
  25. #include "DistrhoPluginUtils.hpp"
  26. START_NAMESPACE_DISTRHO
  27. // -----------------------------------------------------------------------
  28. DistrhoUIProM::DistrhoUIProM()
  29. : UI(512, 512),
  30. fPM(nullptr),
  31. fResizeHandle(this)
  32. {
  33. const double scaleFactor = getScaleFactor();
  34. if (d_isNotZero(scaleFactor))
  35. setSize(512*scaleFactor, 512*scaleFactor);
  36. setGeometryConstraints(256*scaleFactor, 256*scaleFactor, true);
  37. // no need to show resize handle if window is user-resizable
  38. // if (isResizable())
  39. // fResizeHandle.hide();
  40. }
  41. DistrhoUIProM::~DistrhoUIProM()
  42. {
  43. if (fPM == nullptr)
  44. return;
  45. if (DistrhoPluginProM* const dspPtr = (DistrhoPluginProM*)getPluginInstancePointer())
  46. {
  47. const MutexLocker csm(dspPtr->fMutex);
  48. dspPtr->fPM = nullptr;
  49. }
  50. }
  51. // -----------------------------------------------------------------------
  52. // DSP Callbacks
  53. void DistrhoUIProM::parameterChanged(uint32_t, float)
  54. {
  55. }
  56. // -----------------------------------------------------------------------
  57. // UI Callbacks
  58. void DistrhoUIProM::uiIdle()
  59. {
  60. if (fPM == nullptr)
  61. return;
  62. repaint();
  63. if (DistrhoPluginProM* const dspPtr = (DistrhoPluginProM*)getPluginInstancePointer())
  64. {
  65. if (dspPtr->fPM != nullptr)
  66. return;
  67. const MutexLocker csm(dspPtr->fMutex);
  68. dspPtr->fPM = fPM;
  69. }
  70. }
  71. void DistrhoUIProM::uiReshape(const uint width, const uint height)
  72. {
  73. UI::uiReshape(width, height);
  74. if (fPM == nullptr)
  75. {
  76. #ifdef PROJECTM_DATA_DIR
  77. fPM = new projectM(PROJECTM_DATA_DIR "/config.inp");
  78. #else
  79. if (const char* const bundlePath = getBundlePath())
  80. {
  81. const String datadir(getResourcePath(bundlePath));
  82. d_stdout("ProM datadir: '%s'", datadir.buffer());
  83. projectM::Settings settings;
  84. settings.presetURL = datadir + DISTRHO_OS_SEP_STR "presets";
  85. settings.titleFontURL = datadir + DISTRHO_OS_SEP_STR "fonts" DISTRHO_OS_SEP_STR "Vera.ttf";
  86. settings.menuFontURL = datadir + DISTRHO_OS_SEP_STR "fonts" DISTRHO_OS_SEP_STR "VeraMono.ttf";
  87. settings.datadir = datadir;
  88. fPM = new projectM(settings);
  89. }
  90. else
  91. {
  92. d_stderr2("ProM: failed to find bundle path, UI will be empty");
  93. }
  94. #endif
  95. }
  96. if (fPM != nullptr)
  97. fPM->projectM_resetGL(width, height);
  98. }
  99. // -----------------------------------------------------------------------
  100. // Widget Callbacks
  101. void DistrhoUIProM::onDisplay()
  102. {
  103. if (fPM == nullptr)
  104. return;
  105. fPM->renderFrame();
  106. // some projectM versions do not turn off the last set GL program
  107. glUseProgram(0);
  108. }
  109. static projectMKeycode dgl2pmkey(const DGL_NAMESPACE::Key key) noexcept
  110. {
  111. switch (key)
  112. {
  113. case DGL_NAMESPACE::kKeyBackspace:
  114. return PROJECTM_K_BACKSPACE;
  115. case DGL_NAMESPACE::kKeyEscape:
  116. return PROJECTM_K_ESCAPE;
  117. case DGL_NAMESPACE::kKeyDelete:
  118. return PROJECTM_K_DELETE;
  119. case DGL_NAMESPACE::kKeyF1:
  120. return PROJECTM_K_F1;
  121. case DGL_NAMESPACE::kKeyF2:
  122. return PROJECTM_K_F2;
  123. case DGL_NAMESPACE::kKeyF3:
  124. return PROJECTM_K_F3;
  125. case DGL_NAMESPACE::kKeyF4:
  126. return PROJECTM_K_F4;
  127. case DGL_NAMESPACE::kKeyF5:
  128. return PROJECTM_K_F5;
  129. case DGL_NAMESPACE::kKeyF6:
  130. return PROJECTM_K_F6;
  131. case DGL_NAMESPACE::kKeyF7:
  132. return PROJECTM_K_F7;
  133. case DGL_NAMESPACE::kKeyF8:
  134. return PROJECTM_K_F8;
  135. case DGL_NAMESPACE::kKeyF9:
  136. return PROJECTM_K_F9;
  137. case DGL_NAMESPACE::kKeyF10:
  138. return PROJECTM_K_F10;
  139. case DGL_NAMESPACE::kKeyF11:
  140. return PROJECTM_K_F11;
  141. case DGL_NAMESPACE::kKeyF12:
  142. return PROJECTM_K_F12;
  143. case DGL_NAMESPACE::kKeyLeft:
  144. return PROJECTM_K_LEFT;
  145. case DGL_NAMESPACE::kKeyUp:
  146. return PROJECTM_K_UP;
  147. case DGL_NAMESPACE::kKeyRight:
  148. return PROJECTM_K_RIGHT;
  149. case DGL_NAMESPACE::kKeyDown:
  150. return PROJECTM_K_DOWN;
  151. case DGL_NAMESPACE::kKeyPageUp:
  152. return PROJECTM_K_PAGEUP;
  153. case DGL_NAMESPACE::kKeyPageDown:
  154. return PROJECTM_K_PAGEDOWN;
  155. case DGL_NAMESPACE::kKeyHome:
  156. return PROJECTM_K_HOME;
  157. case DGL_NAMESPACE::kKeyEnd:
  158. return PROJECTM_K_END;
  159. case DGL_NAMESPACE::kKeyInsert:
  160. return PROJECTM_K_INSERT;
  161. case DGL_NAMESPACE::kKeyShiftL:
  162. return PROJECTM_K_LSHIFT;
  163. case DGL_NAMESPACE::kKeyShiftR:
  164. return PROJECTM_K_RSHIFT;
  165. case DGL_NAMESPACE::kKeyControlL:
  166. return PROJECTM_K_LCTRL;
  167. case DGL_NAMESPACE::kKeyControlR:
  168. case DGL_NAMESPACE::kKeyAltL:
  169. case DGL_NAMESPACE::kKeyAltR:
  170. case DGL_NAMESPACE::kKeySuperL:
  171. case DGL_NAMESPACE::kKeySuperR:
  172. case DGL_NAMESPACE::kKeyMenu:
  173. case DGL_NAMESPACE::kKeyCapsLock:
  174. case DGL_NAMESPACE::kKeyScrollLock:
  175. case DGL_NAMESPACE::kKeyNumLock:
  176. case DGL_NAMESPACE::kKeyPrintScreen:
  177. case DGL_NAMESPACE::kKeyPause:
  178. break;
  179. }
  180. return PROJECTM_K_NONE;
  181. }
  182. bool DistrhoUIProM::onKeyboard(const KeyboardEvent& ev)
  183. {
  184. if (fPM == nullptr)
  185. return false;
  186. #ifdef HAVE_PROJECTM_TEXT_FUNCTIONS
  187. // special handling for text
  188. if (fPM->isTextInputActive(true) && !ev.press)
  189. {
  190. if (ev.key >= ' ' && ev.key <= 'z')
  191. {
  192. std::string key;
  193. key += static_cast<char>(ev.key);
  194. fPM->setSearchText(key);
  195. return true;
  196. }
  197. else if (ev.key == DGL_NAMESPACE::kKeyBackspace)
  198. {
  199. fPM->deleteSearchText();
  200. return true;
  201. }
  202. }
  203. #endif
  204. projectMKeycode pmKey = PROJECTM_K_NONE;
  205. if (ev.key >= kKeyF1)
  206. {
  207. pmKey = dgl2pmkey(static_cast<DGL_NAMESPACE::Key>(ev.key));
  208. }
  209. else if ((ev.key >= PROJECTM_K_0 && ev.key <= PROJECTM_K_9) ||
  210. (ev.key >= PROJECTM_K_A && ev.key <= PROJECTM_K_Z) ||
  211. (ev.key >= PROJECTM_K_a && ev.key <= PROJECTM_K_z))
  212. {
  213. pmKey = static_cast<projectMKeycode>(ev.key);
  214. if (ev.key >= PROJECTM_K_A && ev.key <= PROJECTM_K_Z && (ev.mod & DGL_NAMESPACE::kModifierShift))
  215. pmKey = static_cast<projectMKeycode>(pmKey + (PROJECTM_K_a - PROJECTM_K_A));
  216. }
  217. else
  218. {
  219. /* missing:
  220. * PROJECTM_K_CAPSLOCK
  221. */
  222. switch (ev.key)
  223. {
  224. case DGL_NAMESPACE::kKeyBackspace:
  225. pmKey = PROJECTM_K_BACKSPACE;
  226. break;
  227. case DGL_NAMESPACE::kKeyEscape:
  228. pmKey = PROJECTM_K_ESCAPE;
  229. break;
  230. case DGL_NAMESPACE::kKeyDelete:
  231. pmKey = PROJECTM_K_DELETE;
  232. break;
  233. case '\r':
  234. pmKey = PROJECTM_K_RETURN;
  235. break;
  236. #ifdef HAVE_PROJECTM_TEXT_FUNCTIONS
  237. case '/':
  238. pmKey = PROJECTM_K_SLASH;
  239. break;
  240. case '\\':
  241. pmKey = PROJECTM_K_BACKSLASH;
  242. break;
  243. #endif
  244. case '+':
  245. pmKey = PROJECTM_K_PLUS;
  246. break;
  247. case '-':
  248. pmKey = PROJECTM_K_MINUS;
  249. break;
  250. case '=':
  251. pmKey = PROJECTM_K_EQUALS;
  252. break;
  253. default:
  254. // d_stdout("Unhandled key %u %u %c", ev.keycode, ev.key, ev.key);
  255. break;
  256. }
  257. }
  258. if (pmKey == PROJECTM_K_NONE)
  259. return false;
  260. fPM->default_key_handler(ev.press ? PROJECTM_KEYUP : PROJECTM_KEYDOWN, pmKey);
  261. return true;
  262. }
  263. bool DistrhoUIProM::onMouse(const MouseEvent& ev)
  264. {
  265. if (ev.press)
  266. getWindow().focus();
  267. return false;
  268. }
  269. // -----------------------------------------------------------------------
  270. UI* createUI()
  271. {
  272. return new DistrhoUIProM();
  273. }
  274. // -----------------------------------------------------------------------
  275. END_NAMESPACE_DISTRHO