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.

390 lines
11KB

  1. /*
  2. * DISTRHO ProM Plugin
  3. * Copyright (C) 2015-2026 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(),
  30. fPM(nullptr),
  31. fResizeHandle(this)
  32. {
  33. const double scaleFactor = getScaleFactor();
  34. setGeometryConstraints(256 * scaleFactor, 256 * scaleFactor, true);
  35. // no need to show resize handle if window is user-resizable
  36. // if (isResizable())
  37. // fResizeHandle.hide();
  38. }
  39. DistrhoUIProM::~DistrhoUIProM()
  40. {
  41. if (fPM == nullptr)
  42. return;
  43. if (DistrhoPluginProM* const dspPtr = (DistrhoPluginProM*)getPluginInstancePointer())
  44. {
  45. const MutexLocker csm(dspPtr->fMutex);
  46. dspPtr->fPM = nullptr;
  47. }
  48. }
  49. // -----------------------------------------------------------------------
  50. // DSP Callbacks
  51. void DistrhoUIProM::parameterChanged(uint32_t, float)
  52. {
  53. }
  54. // -----------------------------------------------------------------------
  55. // UI Callbacks
  56. void DistrhoUIProM::uiIdle()
  57. {
  58. if (fPM == nullptr)
  59. return;
  60. repaint();
  61. if (DistrhoPluginProM* const dspPtr = (DistrhoPluginProM*)getPluginInstancePointer())
  62. {
  63. if (dspPtr->fPM != nullptr)
  64. return;
  65. const MutexLocker csm(dspPtr->fMutex);
  66. dspPtr->fPM = fPM;
  67. }
  68. }
  69. // -----------------------------------------------------------------------
  70. // Widget Callbacks
  71. void DistrhoUIProM::onDisplay()
  72. {
  73. if (fResized)
  74. {
  75. if (fPM == nullptr)
  76. {
  77. #ifdef PROJECTM_DATA_DIR
  78. fPM = new projectM(PROJECTM_DATA_DIR "/config.inp");
  79. #else
  80. if (const char* const bundlePath = getBundlePath())
  81. {
  82. const String datadir(getResourcePath(bundlePath));
  83. d_stdout("ProM datadir: '%s'", datadir.buffer());
  84. projectM::Settings settings;
  85. settings.presetURL = datadir + DISTRHO_OS_SEP_STR "presets";
  86. settings.titleFontURL = datadir + DISTRHO_OS_SEP_STR "fonts" DISTRHO_OS_SEP_STR "Vera.ttf";
  87. settings.menuFontURL = datadir + DISTRHO_OS_SEP_STR "fonts" DISTRHO_OS_SEP_STR "VeraMono.ttf";
  88. settings.datadir = datadir;
  89. fPM = new projectM(settings);
  90. }
  91. else
  92. {
  93. d_stderr2("ProM: failed to find bundle path, UI will be empty");
  94. }
  95. #endif
  96. }
  97. if (fPM != nullptr)
  98. fPM->projectM_resetGL(getWidth(), getHeight());
  99. fResized = false;
  100. }
  101. if (fPM == nullptr)
  102. return;
  103. fPM->renderFrame();
  104. // some projectM versions do not turn off the last set GL program
  105. glUseProgram(0);
  106. }
  107. static projectMKeycode dgl2pmkey(const DGL_NAMESPACE::Key key) noexcept
  108. {
  109. switch (key)
  110. {
  111. case DGL_NAMESPACE::kKeyF1:
  112. return PROJECTM_K_F1;
  113. case DGL_NAMESPACE::kKeyF2:
  114. return PROJECTM_K_F2;
  115. case DGL_NAMESPACE::kKeyF3:
  116. return PROJECTM_K_F3;
  117. case DGL_NAMESPACE::kKeyF4:
  118. return PROJECTM_K_F4;
  119. case DGL_NAMESPACE::kKeyF5:
  120. return PROJECTM_K_F5;
  121. case DGL_NAMESPACE::kKeyF6:
  122. return PROJECTM_K_F6;
  123. case DGL_NAMESPACE::kKeyF7:
  124. return PROJECTM_K_F7;
  125. case DGL_NAMESPACE::kKeyF8:
  126. return PROJECTM_K_F8;
  127. case DGL_NAMESPACE::kKeyF9:
  128. return PROJECTM_K_F9;
  129. case DGL_NAMESPACE::kKeyF10:
  130. return PROJECTM_K_F10;
  131. case DGL_NAMESPACE::kKeyF11:
  132. return PROJECTM_K_F11;
  133. case DGL_NAMESPACE::kKeyF12:
  134. return PROJECTM_K_F12;
  135. case DGL_NAMESPACE::kKeyPageUp:
  136. return PROJECTM_K_PAGEUP;
  137. case DGL_NAMESPACE::kKeyPageDown:
  138. return PROJECTM_K_PAGEDOWN;
  139. case DGL_NAMESPACE::kKeyEnd:
  140. return PROJECTM_K_END;
  141. case DGL_NAMESPACE::kKeyHome:
  142. return PROJECTM_K_HOME;
  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::kKeyInsert:
  152. return PROJECTM_K_INSERT;
  153. case DGL_NAMESPACE::kKeyShiftL:
  154. return PROJECTM_K_LSHIFT;
  155. case DGL_NAMESPACE::kKeyShiftR:
  156. return PROJECTM_K_RSHIFT;
  157. case DGL_NAMESPACE::kKeyControlL:
  158. return PROJECTM_K_LCTRL;
  159. case DGL_NAMESPACE::kKeyPad0:
  160. return PROJECTM_K_0;
  161. case DGL_NAMESPACE::kKeyPad1:
  162. return PROJECTM_K_1;
  163. case DGL_NAMESPACE::kKeyPad2:
  164. return PROJECTM_K_2;
  165. case DGL_NAMESPACE::kKeyPad3:
  166. return PROJECTM_K_3;
  167. case DGL_NAMESPACE::kKeyPad4:
  168. return PROJECTM_K_4;
  169. case DGL_NAMESPACE::kKeyPad5:
  170. return PROJECTM_K_5;
  171. case DGL_NAMESPACE::kKeyPad6:
  172. return PROJECTM_K_6;
  173. case DGL_NAMESPACE::kKeyPad7:
  174. return PROJECTM_K_7;
  175. case DGL_NAMESPACE::kKeyPad8:
  176. return PROJECTM_K_8;
  177. case DGL_NAMESPACE::kKeyPad9:
  178. return PROJECTM_K_9;
  179. case DGL_NAMESPACE::kKeyPadEnter:
  180. return PROJECTM_K_RETURN;
  181. case DGL_NAMESPACE::kKeyPadPageUp:
  182. return PROJECTM_K_PAGEUP;
  183. case DGL_NAMESPACE::kKeyPadPageDown:
  184. return PROJECTM_K_PAGEDOWN;
  185. case DGL_NAMESPACE::kKeyPadEnd:
  186. return PROJECTM_K_END;
  187. case DGL_NAMESPACE::kKeyPadHome:
  188. return PROJECTM_K_HOME;
  189. case DGL_NAMESPACE::kKeyPadLeft:
  190. return PROJECTM_K_LEFT;
  191. case DGL_NAMESPACE::kKeyPadUp:
  192. return PROJECTM_K_UP;
  193. case DGL_NAMESPACE::kKeyPadRight:
  194. return PROJECTM_K_RIGHT;
  195. case DGL_NAMESPACE::kKeyPadDown:
  196. return PROJECTM_K_DOWN;
  197. case DGL_NAMESPACE::kKeyPadInsert:
  198. return PROJECTM_K_INSERT;
  199. case DGL_NAMESPACE::kKeyPadDelete:
  200. return PROJECTM_K_DELETE;
  201. case DGL_NAMESPACE::kKeyPadEqual:
  202. return PROJECTM_K_EQUALS;
  203. case DGL_NAMESPACE::kKeyPadAdd:
  204. return PROJECTM_K_PLUS;
  205. case DGL_NAMESPACE::kKeyPadSubtract:
  206. return PROJECTM_K_MINUS;
  207. case DGL_NAMESPACE::kKeyBackspace:
  208. return PROJECTM_K_BACKSPACE;
  209. case DGL_NAMESPACE::kKeyTab:
  210. // TODO
  211. case DGL_NAMESPACE::kKeyEnter:
  212. return PROJECTM_K_RETURN;
  213. case DGL_NAMESPACE::kKeyEscape:
  214. return PROJECTM_K_ESCAPE;
  215. case DGL_NAMESPACE::kKeyDelete:
  216. return PROJECTM_K_DELETE;
  217. case DGL_NAMESPACE::kKeySpace:
  218. break;
  219. case DGL_NAMESPACE::kKeyPrintScreen:
  220. case DGL_NAMESPACE::kKeyPause:
  221. case DGL_NAMESPACE::kKeyMenu:
  222. case DGL_NAMESPACE::kKeyNumLock:
  223. case DGL_NAMESPACE::kKeyScrollLock:
  224. case DGL_NAMESPACE::kKeyCapsLock:
  225. case DGL_NAMESPACE::kKeyControlR:
  226. case DGL_NAMESPACE::kKeyAltL:
  227. case DGL_NAMESPACE::kKeyAltR:
  228. case DGL_NAMESPACE::kKeySuperL:
  229. case DGL_NAMESPACE::kKeySuperR:
  230. case DGL_NAMESPACE::kKeyPadClear:
  231. case DGL_NAMESPACE::kKeyPadMultiply:
  232. case DGL_NAMESPACE::kKeyPadSeparator:
  233. case DGL_NAMESPACE::kKeyPadDecimal:
  234. case DGL_NAMESPACE::kKeyPadDivide:
  235. break;
  236. }
  237. return PROJECTM_K_NONE;
  238. }
  239. bool DistrhoUIProM::onKeyboard(const KeyboardEvent& ev)
  240. {
  241. if (fPM == nullptr)
  242. return false;
  243. #ifdef HAVE_PROJECTM_TEXT_FUNCTIONS
  244. // special handling for text
  245. if (fPM->isTextInputActive(true) && !ev.press)
  246. {
  247. if (ev.key >= ' ' && ev.key <= 'z')
  248. {
  249. std::string key;
  250. key += static_cast<char>(ev.key);
  251. fPM->setSearchText(key);
  252. return true;
  253. }
  254. else if (ev.key == DGL_NAMESPACE::kKeyBackspace)
  255. {
  256. fPM->deleteSearchText();
  257. return true;
  258. }
  259. }
  260. #endif
  261. projectMKeycode pmKey = PROJECTM_K_NONE;
  262. if (ev.key >= kKeyF1)
  263. {
  264. pmKey = dgl2pmkey(static_cast<DGL_NAMESPACE::Key>(ev.key));
  265. }
  266. else if ((ev.key >= PROJECTM_K_0 && ev.key <= PROJECTM_K_9) ||
  267. (ev.key >= PROJECTM_K_A && ev.key <= PROJECTM_K_Z) ||
  268. (ev.key >= PROJECTM_K_a && ev.key <= PROJECTM_K_z))
  269. {
  270. pmKey = static_cast<projectMKeycode>(ev.key);
  271. if (ev.key >= PROJECTM_K_A && ev.key <= PROJECTM_K_Z && (ev.mod & DGL_NAMESPACE::kModifierShift))
  272. pmKey = static_cast<projectMKeycode>(pmKey + (PROJECTM_K_a - PROJECTM_K_A));
  273. }
  274. else
  275. {
  276. /* missing:
  277. * PROJECTM_K_TAB
  278. * PROJECTM_K_SPACE
  279. */
  280. switch (ev.key)
  281. {
  282. case DGL_NAMESPACE::kKeyBackspace:
  283. pmKey = PROJECTM_K_BACKSPACE;
  284. break;
  285. case DGL_NAMESPACE::kKeyTab:
  286. break;
  287. case DGL_NAMESPACE::kKeyEnter:
  288. pmKey = PROJECTM_K_RETURN;
  289. break;
  290. case DGL_NAMESPACE::kKeyEscape:
  291. pmKey = PROJECTM_K_ESCAPE;
  292. break;
  293. case DGL_NAMESPACE::kKeyDelete:
  294. pmKey = PROJECTM_K_DELETE;
  295. break;
  296. case DGL_NAMESPACE::kKeySpace:
  297. break;
  298. case '\n':
  299. pmKey = PROJECTM_K_RETURN;
  300. break;
  301. #ifdef HAVE_PROJECTM_TEXT_FUNCTIONS
  302. case '/':
  303. pmKey = PROJECTM_K_SLASH;
  304. break;
  305. case '\\':
  306. pmKey = PROJECTM_K_BACKSLASH;
  307. break;
  308. #endif
  309. case '+':
  310. pmKey = PROJECTM_K_PLUS;
  311. break;
  312. case '-':
  313. pmKey = PROJECTM_K_MINUS;
  314. break;
  315. case '=':
  316. pmKey = PROJECTM_K_EQUALS;
  317. break;
  318. default:
  319. // d_stdout("Unhandled key %u %u %c", ev.keycode, ev.key, ev.key);
  320. break;
  321. }
  322. }
  323. if (pmKey == PROJECTM_K_NONE)
  324. return false;
  325. fPM->default_key_handler(ev.press ? PROJECTM_KEYUP : PROJECTM_KEYDOWN, pmKey);
  326. return true;
  327. }
  328. bool DistrhoUIProM::onMouse(const MouseEvent& ev)
  329. {
  330. if (ev.press)
  331. getWindow().focus();
  332. return false;
  333. }
  334. void DistrhoUIProM::onResize(const ResizeEvent& ev)
  335. {
  336. fResized = true;
  337. UI::onResize(ev);
  338. }
  339. // -----------------------------------------------------------------------
  340. UI* createUI()
  341. {
  342. return new DistrhoUIProM();
  343. }
  344. // -----------------------------------------------------------------------
  345. END_NAMESPACE_DISTRHO