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.

345 lines
8.9KB

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