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.

381 lines
10KB

  1. /*
  2. * DISTRHO ProM Plugin
  3. * Copyright (C) 2015-2021 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. #include "libprojectM/projectM-opengl.h"
  17. #include "libprojectM/projectM.hpp"
  18. #include "DistrhoPluginProM.hpp"
  19. #include "DistrhoUIProM.hpp"
  20. #ifndef DISTRHO_OS_WINDOWS
  21. # include <dlfcn.h>
  22. #endif
  23. #ifdef DISTRHO_OS_WINDOWS
  24. static HINSTANCE hInstance = nullptr;
  25. DISTRHO_PLUGIN_EXPORT
  26. BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason, LPVOID)
  27. {
  28. if (reason == DLL_PROCESS_ATTACH)
  29. hInstance = hInst;
  30. return 1;
  31. }
  32. #endif
  33. START_NAMESPACE_DISTRHO
  34. // -----------------------------------------------------------------------
  35. static String getCurrentExecutableDataDir()
  36. {
  37. static String datadir;
  38. if (datadir.isNotEmpty())
  39. return datadir;
  40. #ifdef DISTRHO_OS_WINDOWS
  41. CHAR filename[MAX_PATH + 256];
  42. filename[0] = '\0';
  43. GetModuleFileName(hInstance, filename, sizeof(filename));
  44. datadir = String(filename);
  45. datadir.truncate(datadir.rfind('\\'));
  46. #else
  47. Dl_info info;
  48. dladdr((void*)getCurrentExecutableDataDir, &info);
  49. datadir = String(info.dli_fname);
  50. datadir.truncate(datadir.rfind('/'));
  51. # ifdef DISTRHO_OS_MAC
  52. if (datadir.endsWith("/MacOS"))
  53. {
  54. datadir.truncate(datadir.rfind('/'));
  55. datadir += "/Resources";
  56. }
  57. else
  58. # endif
  59. #endif
  60. {
  61. datadir += "/resources";
  62. }
  63. return datadir;
  64. }
  65. // -----------------------------------------------------------------------
  66. DistrhoUIProM::DistrhoUIProM()
  67. : UI(512, 512),
  68. fPM(nullptr),
  69. fResizeHandle(this)
  70. {
  71. // const double scaleFactor = getScaleFactor();
  72. // if (d_isNotZero(scaleFactor))
  73. // setSize(512*scaleFactor, 512*scaleFactor)
  74. setGeometryConstraints(256, 256, true);
  75. // no need to show resize handle if window is user-resizable
  76. // if (isResizable())
  77. // fResizeHandle.hide();
  78. }
  79. DistrhoUIProM::~DistrhoUIProM()
  80. {
  81. if (DistrhoPluginProM* const dspPtr = (DistrhoPluginProM*)getPluginInstancePointer())
  82. {
  83. const MutexLocker csm(dspPtr->fMutex);
  84. dspPtr->fPM = nullptr;
  85. }
  86. }
  87. // -----------------------------------------------------------------------
  88. // DSP Callbacks
  89. void DistrhoUIProM::parameterChanged(uint32_t, float)
  90. {
  91. }
  92. // -----------------------------------------------------------------------
  93. // UI Callbacks
  94. void DistrhoUIProM::uiIdle()
  95. {
  96. if (fPM == nullptr)
  97. return;
  98. repaint();
  99. if (DistrhoPluginProM* const dspPtr = (DistrhoPluginProM*)getPluginInstancePointer())
  100. {
  101. if (dspPtr->fPM != nullptr)
  102. return;
  103. const MutexLocker csm(dspPtr->fMutex);
  104. dspPtr->fPM = fPM;
  105. }
  106. }
  107. void DistrhoUIProM::uiReshape(uint width, uint height)
  108. {
  109. UI::uiReshape(width, height);
  110. if (fPM == nullptr)
  111. {
  112. #ifdef PROJECTM_DATA_DIR
  113. fPM = new projectM(PROJECTM_DATA_DIR "/config.inp");
  114. #else
  115. const String datadir(getCurrentExecutableDataDir());
  116. d_stdout("ProM datadir: '%s'", datadir.buffer());
  117. projectM::Settings settings;
  118. settings.presetURL = datadir + DISTRHO_OS_SEP_STR "presets";
  119. settings.titleFontURL = datadir + DISTRHO_OS_SEP_STR "fonts" DISTRHO_OS_SEP_STR "Vera.ttf";
  120. settings.menuFontURL = datadir + DISTRHO_OS_SEP_STR "fonts" DISTRHO_OS_SEP_STR "VeraMono.ttf";
  121. settings.datadir = datadir;
  122. fPM = new projectM(settings);
  123. #endif
  124. }
  125. fPM->projectM_resetGL(width, height);
  126. }
  127. // -----------------------------------------------------------------------
  128. // Widget Callbacks
  129. void DistrhoUIProM::onDisplay()
  130. {
  131. if (fPM == nullptr)
  132. return;
  133. fPM->renderFrame();
  134. // turn off shaders at the end of the drawing cycle, so other things can draw properly
  135. glUseProgram(0);
  136. }
  137. static projectMKeycode dgl2pmkey(const DGL_NAMESPACE::Key key) noexcept
  138. {
  139. switch (key)
  140. {
  141. case DGL_NAMESPACE::kKeyBackspace:
  142. return PROJECTM_K_BACKSPACE;
  143. case DGL_NAMESPACE::kKeyEscape:
  144. return PROJECTM_K_ESCAPE;
  145. case DGL_NAMESPACE::kKeyDelete:
  146. return PROJECTM_K_DELETE;
  147. case DGL_NAMESPACE::kKeyF1:
  148. return PROJECTM_K_F1;
  149. case DGL_NAMESPACE::kKeyF2:
  150. return PROJECTM_K_F2;
  151. case DGL_NAMESPACE::kKeyF3:
  152. return PROJECTM_K_F3;
  153. case DGL_NAMESPACE::kKeyF4:
  154. return PROJECTM_K_F4;
  155. case DGL_NAMESPACE::kKeyF5:
  156. return PROJECTM_K_F5;
  157. case DGL_NAMESPACE::kKeyF6:
  158. return PROJECTM_K_F6;
  159. case DGL_NAMESPACE::kKeyF7:
  160. return PROJECTM_K_F7;
  161. case DGL_NAMESPACE::kKeyF8:
  162. return PROJECTM_K_F8;
  163. case DGL_NAMESPACE::kKeyF9:
  164. return PROJECTM_K_F9;
  165. case DGL_NAMESPACE::kKeyF10:
  166. return PROJECTM_K_F10;
  167. case DGL_NAMESPACE::kKeyF11:
  168. return PROJECTM_K_F11;
  169. case DGL_NAMESPACE::kKeyF12:
  170. return PROJECTM_K_F12;
  171. case DGL_NAMESPACE::kKeyLeft:
  172. return PROJECTM_K_LEFT;
  173. case DGL_NAMESPACE::kKeyUp:
  174. return PROJECTM_K_UP;
  175. case DGL_NAMESPACE::kKeyRight:
  176. return PROJECTM_K_RIGHT;
  177. case DGL_NAMESPACE::kKeyDown:
  178. return PROJECTM_K_DOWN;
  179. case DGL_NAMESPACE::kKeyPageUp:
  180. return PROJECTM_K_PAGEUP;
  181. case DGL_NAMESPACE::kKeyPageDown:
  182. return PROJECTM_K_PAGEDOWN;
  183. case DGL_NAMESPACE::kKeyHome:
  184. return PROJECTM_K_HOME;
  185. case DGL_NAMESPACE::kKeyEnd:
  186. return PROJECTM_K_END;
  187. case DGL_NAMESPACE::kKeyInsert:
  188. return PROJECTM_K_INSERT;
  189. case DGL_NAMESPACE::kKeyShiftL:
  190. return PROJECTM_K_LSHIFT;
  191. case DGL_NAMESPACE::kKeyShiftR:
  192. return PROJECTM_K_RSHIFT;
  193. case DGL_NAMESPACE::kKeyControlL:
  194. return PROJECTM_K_LCTRL;
  195. case DGL_NAMESPACE::kKeyControlR:
  196. case DGL_NAMESPACE::kKeyAltL:
  197. case DGL_NAMESPACE::kKeyAltR:
  198. case DGL_NAMESPACE::kKeySuperL:
  199. case DGL_NAMESPACE::kKeySuperR:
  200. case DGL_NAMESPACE::kKeyMenu:
  201. case DGL_NAMESPACE::kKeyCapsLock:
  202. case DGL_NAMESPACE::kKeyScrollLock:
  203. case DGL_NAMESPACE::kKeyNumLock:
  204. case DGL_NAMESPACE::kKeyPrintScreen:
  205. case DGL_NAMESPACE::kKeyPause:
  206. break;
  207. }
  208. return PROJECTM_K_NONE;
  209. }
  210. bool DistrhoUIProM::onKeyboard(const KeyboardEvent& ev)
  211. {
  212. if (fPM == nullptr)
  213. return false;
  214. #if 0
  215. if (ev.press && (ev.key == '1' || ev.key == '+' || ev.key == '-'))
  216. {
  217. if (ev.key == '1')
  218. {
  219. if (getWidth() != 512 || getHeight() != 512)
  220. setSize(512, 512);
  221. }
  222. else if (ev.key == '+')
  223. {
  224. /**/ if (getWidth() < 1100 && getHeight() < 1100)
  225. setSize(getWidth()+100, getHeight()+100);
  226. else if (getWidth() != 1100 || getHeight() != 1100)
  227. setSize(1100, 1100);
  228. }
  229. else if (ev.key == '-')
  230. {
  231. /**/ if (getWidth() >= 200 && getHeight() >= 200)
  232. setSize(getWidth()-100, getHeight()-100);
  233. else if (getWidth() != 100 || getHeight() != 100)
  234. setSize(100, 100);
  235. }
  236. return true;
  237. }
  238. #endif
  239. // special handling for text
  240. if (fPM->isTextInputActive(true) && !ev.press)
  241. {
  242. if (ev.key >= ' ' && ev.key <= 'z')
  243. {
  244. std::string key;
  245. key += static_cast<char>(ev.key);
  246. fPM->setSearchText(key);
  247. return true;
  248. }
  249. else if (ev.key == DGL_NAMESPACE::kKeyBackspace)
  250. {
  251. fPM->deleteSearchText();
  252. return true;
  253. }
  254. }
  255. projectMKeycode pmKey = PROJECTM_K_NONE;
  256. if (ev.key >= kKeyF1)
  257. {
  258. pmKey = dgl2pmkey(static_cast<DGL_NAMESPACE::Key>(ev.key));
  259. }
  260. else if ((ev.key >= PROJECTM_K_0 && ev.key <= PROJECTM_K_9) ||
  261. (ev.key >= PROJECTM_K_A && ev.key <= PROJECTM_K_Z) ||
  262. (ev.key >= PROJECTM_K_a && ev.key <= PROJECTM_K_z))
  263. {
  264. pmKey = static_cast<projectMKeycode>(ev.key);
  265. if (ev.key >= PROJECTM_K_A && ev.key <= PROJECTM_K_Z && (ev.mod & DGL_NAMESPACE::kModifierShift))
  266. pmKey = static_cast<projectMKeycode>(pmKey + (PROJECTM_K_a - PROJECTM_K_A));
  267. }
  268. else
  269. {
  270. /* missing:
  271. * PROJECTM_K_CAPSLOCK
  272. */
  273. switch (ev.key)
  274. {
  275. case DGL_NAMESPACE::kKeyBackspace:
  276. pmKey = PROJECTM_K_BACKSPACE;
  277. break;
  278. case DGL_NAMESPACE::kKeyEscape:
  279. pmKey = PROJECTM_K_ESCAPE;
  280. break;
  281. case DGL_NAMESPACE::kKeyDelete:
  282. pmKey = PROJECTM_K_DELETE;
  283. break;
  284. case '\r':
  285. pmKey = PROJECTM_K_RETURN;
  286. break;
  287. case '/':
  288. pmKey = PROJECTM_K_SLASH;
  289. break;
  290. case '\\':
  291. pmKey = PROJECTM_K_BACKSLASH;
  292. break;
  293. case '+':
  294. pmKey = PROJECTM_K_PLUS;
  295. break;
  296. case '-':
  297. pmKey = PROJECTM_K_MINUS;
  298. break;
  299. case '=':
  300. pmKey = PROJECTM_K_EQUALS;
  301. break;
  302. default:
  303. // d_stdout("Unhandled key %u %u %c", ev.keycode, ev.key, ev.key);
  304. break;
  305. }
  306. }
  307. if (pmKey == PROJECTM_K_NONE)
  308. return false;
  309. fPM->default_key_handler(ev.press ? PROJECTM_KEYUP : PROJECTM_KEYDOWN, pmKey);
  310. return true;
  311. }
  312. bool DistrhoUIProM::onSpecial(const SpecialEvent& ev)
  313. {
  314. if (fPM == nullptr)
  315. return false;
  316. const projectMKeycode pmKey = dgl2pmkey(ev.key);
  317. if (pmKey == PROJECTM_K_NONE)
  318. return false;
  319. fPM->default_key_handler(ev.press ? PROJECTM_KEYUP : PROJECTM_KEYDOWN, pmKey);
  320. return true;
  321. }
  322. // -----------------------------------------------------------------------
  323. UI* createUI()
  324. {
  325. return new DistrhoUIProM();
  326. }
  327. // -----------------------------------------------------------------------
  328. END_NAMESPACE_DISTRHO