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.

803 lines
25KB

  1. #include "global_pre.hpp"
  2. #include "window.hpp"
  3. #include "app.hpp"
  4. #include "asset.hpp"
  5. #include "settings.hpp"
  6. #include "gamepad.hpp"
  7. #include "keyboard.hpp"
  8. #include "util/color.hpp"
  9. #include <map>
  10. #include <queue>
  11. #include <thread>
  12. #include "osdialog.h"
  13. #define NANOVG_GL2_IMPLEMENTATION 1
  14. // #define NANOVG_GL3_IMPLEMENTATION 1
  15. // #define NANOVG_GLES2_IMPLEMENTATION 1
  16. // #define NANOVG_GLES3_IMPLEMENTATION 1
  17. #include "nanovg_gl.h"
  18. // Hack to get framebuffer objects working on OpenGL 2 (we blindly assume the extension is supported)
  19. #define NANOVG_FBO_VALID 1
  20. #include "nanovg_gl_utils.h"
  21. #define BLENDISH_IMPLEMENTATION
  22. #include "blendish.h"
  23. #define NANOSVG_IMPLEMENTATION
  24. #define NANOSVG_ALL_COLOR_KEYWORDS
  25. #include "nanosvg.h"
  26. #ifdef ARCH_MAC
  27. // For CGAssociateMouseAndMouseCursorPosition
  28. #include <ApplicationServices/ApplicationServices.h>
  29. #endif
  30. #include "global.hpp"
  31. #include "global_ui.hpp"
  32. #ifndef RACK_PLUGIN_SHARED_LIB_BUILD
  33. extern void vst2_set_globals (void *_wrapper);
  34. extern "C" { extern void lglw_timer_cbk (lglw_t _lglw); } // implemented in vst2_main.cpp
  35. extern "C" { extern void lglw_redraw_cbk (lglw_t _lglw); } // implemented in vst2_main.cpp
  36. #else
  37. void vst2_set_globals(void *) { }
  38. void vst2_window_size_set(int, int) { }
  39. void vst2_refresh_rate_set(float) { }
  40. void lglw_timer_cbk(lglw_t) { }
  41. void lglw_redraw_cbk(lglw_t) { }
  42. #endif // RACK_PLUGIN_SHARED_LIB_BUILD
  43. namespace rack {
  44. extern "C" {
  45. static void lglw_mouse_cbk(lglw_t _lglw, int32_t _x, int32_t _y, uint32_t _buttonState, uint32_t _changedButtonState) {
  46. // printf("xxx lglw_mouse_cbk: lglw=%p wrapper=%p p=(%d; %d) bt=0x%08x changedBt=0x%08x\n", _lglw, lglw_userdata_get(_lglw), _x, _y, _buttonState, _changedButtonState);
  47. vst2_set_globals(lglw_userdata_get(_lglw));
  48. // printf("xxx lglw_mouse_cbk: &global=%p global=%p\n", &rack::global, rack::global);
  49. // (note) assumes that GL context is never touched during regular mouse move
  50. // (note) mouse clicks may cause new SVGs to be loaded, which in turn may cause new GL textures to be created
  51. // if(0u != _changedButtonState)
  52. lglw_glcontext_push(global_ui->window.lglw);
  53. if(LGLW_MOUSE_WHEELUP == _buttonState)
  54. {
  55. // onScroll
  56. EventScroll e;
  57. e.pos = global_ui->window.gMousePos;
  58. Vec scrollRel = Vec(0, 1);
  59. e.scrollRel = scrollRel.mult(50.0);
  60. global_ui->ui.gScene->onScroll(e);
  61. }
  62. else if(LGLW_MOUSE_WHEELDOWN == _buttonState)
  63. {
  64. // onScroll
  65. EventScroll e;
  66. e.pos = global_ui->window.gMousePos;
  67. Vec scrollRel = Vec(0, -1);
  68. e.scrollRel = scrollRel.mult(50.0);
  69. global_ui->ui.gScene->onScroll(e);
  70. }
  71. else if(0u == _changedButtonState)
  72. {
  73. // onMouseMotion
  74. Vec mousePos = Vec(_x, _y);//.div(global_ui->window.gPixelRatio / global_ui->window.gWindowRatio).round();
  75. Vec mouseRel = mousePos.minus(global_ui->window.gMousePos);
  76. // #ifdef ARCH_MAC
  77. // // Workaround for Mac. We can't use GLFW_CURSOR_DISABLED because it's buggy, so implement it on our own.
  78. // // This is not an ideal implementation. For example, if the user drags off the screen, the new mouse position will be clamped.
  79. // if (cursorMode == GLFW_CURSOR_HIDDEN) {
  80. // // CGSetLocalEventsSuppressionInterval(0.0);
  81. // glfwSetCursorPos(global_ui->window.gWindow, global_ui->window.gMousePos.x, global_ui->window.gMousePos.y);
  82. // CGAssociateMouseAndMouseCursorPosition(true);
  83. // mousePos = global_ui->window.gMousePos;
  84. // }
  85. // // Because sometimes the cursor turns into an arrow when its position is on the boundary of the window
  86. // glfwSetCursor(global_ui->window.gWindow, NULL);
  87. // #endif
  88. global_ui->window.gMousePos = mousePos;
  89. global_ui->widgets.gTempWidget = NULL;
  90. // onMouseMove
  91. {
  92. EventMouseMove e;
  93. e.pos = mousePos;
  94. e.mouseRel = mouseRel;
  95. global_ui->ui.gScene->onMouseMove(e);
  96. global_ui->widgets.gTempWidget = e.target;
  97. }
  98. if (global_ui->widgets.gDraggedWidget) {
  99. // onDragMove
  100. EventDragMove e;
  101. e.mouseRel = mouseRel;
  102. global_ui->widgets.gDraggedWidget->onDragMove(e);
  103. if (global_ui->widgets.gTempWidget != global_ui->widgets.gDragHoveredWidget) {
  104. if (global_ui->widgets.gDragHoveredWidget) {
  105. EventDragEnter e;
  106. e.origin = global_ui->widgets.gDraggedWidget;
  107. global_ui->widgets.gDragHoveredWidget->onDragLeave(e);
  108. }
  109. global_ui->widgets.gDragHoveredWidget = global_ui->widgets.gTempWidget;
  110. if (global_ui->widgets.gDragHoveredWidget) {
  111. EventDragEnter e;
  112. e.origin = global_ui->widgets.gDraggedWidget;
  113. global_ui->widgets.gDragHoveredWidget->onDragEnter(e);
  114. }
  115. }
  116. }
  117. else {
  118. if (global_ui->widgets.gTempWidget != global_ui->widgets.gHoveredWidget) {
  119. if (global_ui->widgets.gHoveredWidget) {
  120. // onMouseLeave
  121. EventMouseLeave e;
  122. global_ui->widgets.gHoveredWidget->onMouseLeave(e);
  123. }
  124. global_ui->widgets.gHoveredWidget = global_ui->widgets.gTempWidget;
  125. if (global_ui->widgets.gHoveredWidget) {
  126. // onMouseEnter
  127. EventMouseEnter e;
  128. global_ui->widgets.gHoveredWidget->onMouseEnter(e);
  129. }
  130. }
  131. }
  132. global_ui->widgets.gTempWidget = NULL;
  133. if(0u != (_buttonState & LGLW_MOUSE_MBUTTON)) {
  134. // TODO
  135. // Define a new global called gScrollWidget, which remembers the widget where middle-click was first pressed
  136. EventScroll e;
  137. e.pos = mousePos;
  138. e.scrollRel = mouseRel;
  139. global_ui->ui.gScene->onScroll(e);
  140. }
  141. }
  142. else
  143. {
  144. // Mouse button state changed
  145. // #ifdef ARCH_MAC
  146. // // Ctrl-left click --> right click
  147. // if (button == GLFW_MOUSE_BUTTON_LEFT) {
  148. // if (glfwGetKey(global_ui->window.gWindow, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(global_ui->window.gWindow, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {
  149. // button = GLFW_MOUSE_BUTTON_RIGHT;
  150. // }
  151. // }
  152. // #endif
  153. int button =
  154. (0u != (_changedButtonState & LGLW_MOUSE_LBUTTON)) ? RACK_MOUSE_BUTTON_LEFT/*0*/ :
  155. (0u != (_changedButtonState & LGLW_MOUSE_RBUTTON)) ? RACK_MOUSE_BUTTON_RIGHT/*1*/ :
  156. (0u != (_changedButtonState & LGLW_MOUSE_MBUTTON)) ? RACK_MOUSE_BUTTON_MIDDLE/*2*/ :
  157. -1;
  158. bool bPressed = (0u != (_changedButtonState & _buttonState));
  159. if (bPressed) {
  160. global_ui->widgets.gTempWidget = NULL;
  161. // onMouseDown
  162. {
  163. EventMouseDown e;
  164. e.pos = global_ui->window.gMousePos;
  165. e.button = button;
  166. global_ui->ui.gScene->onMouseDown(e);
  167. global_ui->widgets.gTempWidget = e.target;
  168. }
  169. if (RACK_MOUSE_BUTTON_LEFT/*0*/ == button) {
  170. if (global_ui->widgets.gTempWidget) {
  171. // onDragStart
  172. EventDragStart e;
  173. global_ui->widgets.gTempWidget->onDragStart(e);
  174. }
  175. global_ui->widgets.gDraggedWidget = global_ui->widgets.gTempWidget;
  176. if (global_ui->widgets.gTempWidget != global_ui->widgets.gFocusedWidget) {
  177. if (global_ui->widgets.gFocusedWidget) {
  178. // onDefocus
  179. EventDefocus e;
  180. global_ui->widgets.gFocusedWidget->onDefocus(e);
  181. }
  182. global_ui->widgets.gFocusedWidget = NULL;
  183. if (global_ui->widgets.gTempWidget) {
  184. // onFocus
  185. EventFocus e;
  186. global_ui->widgets.gTempWidget->onFocus(e);
  187. if (e.consumed) {
  188. global_ui->widgets.gFocusedWidget = global_ui->widgets.gTempWidget;
  189. }
  190. }
  191. }
  192. }
  193. global_ui->widgets.gTempWidget = NULL;
  194. }
  195. else {
  196. // onMouseUp
  197. global_ui->widgets.gTempWidget = NULL;
  198. {
  199. EventMouseUp e;
  200. e.pos = global_ui->window.gMousePos;
  201. e.button = button;
  202. global_ui->ui.gScene->onMouseUp(e);
  203. global_ui->widgets.gTempWidget = e.target;
  204. }
  205. if (RACK_MOUSE_BUTTON_LEFT/*0*/ == button) {
  206. if (global_ui->widgets.gDraggedWidget) {
  207. // onDragDrop
  208. EventDragDrop e;
  209. e.origin = global_ui->widgets.gDraggedWidget;
  210. global_ui->widgets.gTempWidget->onDragDrop(e);
  211. }
  212. // gDraggedWidget might have been set to null in the last event, recheck here
  213. if (global_ui->widgets.gDraggedWidget) {
  214. // onDragEnd
  215. EventDragEnd e;
  216. global_ui->widgets.gDraggedWidget->onDragEnd(e);
  217. }
  218. global_ui->widgets.gDraggedWidget = NULL;
  219. global_ui->widgets.gDragHoveredWidget = NULL;
  220. }
  221. global_ui->widgets.gTempWidget = NULL;
  222. }
  223. }
  224. // if(0u != _changedButtonState)
  225. lglw_glcontext_pop(global_ui->window.lglw);
  226. // printf("xxx lglw_mouse_cbk: LEAVE global=%p\n", rack::global);
  227. }
  228. static void lglw_focus_cbk(lglw_t _lglw, uint32_t _focusState, uint32_t _changedFocusState) {
  229. // printf("xxx lglw_focus_cbk: lglw=%p focusState=0x%08x changedFocusState=0x%08x\n", _lglw, _focusState, _changedFocusState);
  230. vst2_set_globals(lglw_userdata_get(_lglw));
  231. if(0u != (_changedFocusState & LGLW_FOCUS_MOUSE))
  232. {
  233. if(0u != (_focusState & LGLW_FOCUS_MOUSE))
  234. {
  235. // onMouseEnter
  236. }
  237. else
  238. {
  239. if (global_ui->widgets.gHoveredWidget) {
  240. // onMouseLeave
  241. EventMouseLeave e;
  242. global_ui->widgets.gHoveredWidget->onMouseLeave(e);
  243. }
  244. global_ui->widgets.gHoveredWidget = NULL;
  245. }
  246. }
  247. }
  248. static lglw_bool_t lglw_keyboard_cbk(lglw_t _lglw, uint32_t _vkey, uint32_t _kmod, lglw_bool_t _bPressed) {
  249. // printf("xxx lglw_keyboard_cbk: lglw=%p vkey=0x%08x (\'%c\') kmod=0x%08x bPressed=%d\n", _lglw, _vkey, (char)_vkey, _kmod, _bPressed);
  250. lglw_bool_t bHandled = LGLW_FALSE;
  251. vst2_set_globals(lglw_userdata_get(_lglw));
  252. if( (0u == (_vkey & LGLW_VKEY_EXT)) && (0u == (_kmod & (LGLW_KMOD_LCTRL | LGLW_KMOD_RCTRL))) )
  253. {
  254. // Unicode or ASCII character
  255. if(_bPressed)
  256. {
  257. if (global_ui->widgets.gFocusedWidget) {
  258. // onText
  259. EventText e;
  260. e.codepoint = _vkey;
  261. global_ui->widgets.gFocusedWidget->onText(e);
  262. if(e.consumed)
  263. return LGLW_TRUE;
  264. }
  265. }
  266. }
  267. if(_bPressed)
  268. {
  269. if (global_ui->widgets.gFocusedWidget) {
  270. // onKey
  271. EventKey e;
  272. e.key = _vkey;
  273. global_ui->widgets.gFocusedWidget->onKey(e);
  274. if (e.consumed)
  275. return LGLW_TRUE;
  276. }
  277. // onHoverKey
  278. EventHoverKey e;
  279. e.pos = global_ui->window.gMousePos;
  280. e.key = _vkey;
  281. global_ui->ui.gScene->onHoverKey(e);
  282. }
  283. return bHandled;
  284. }
  285. int vst2_handle_effeditkeydown(unsigned int _vkey) {
  286. // (note) only used for touch keyboard input
  287. lglw_bool_t bHandled = lglw_keyboard_cbk(rack::global_ui->window.lglw, _vkey, 0u/*kmod*/, LGLW_TRUE/*bPressed*/);
  288. lglw_keyboard_cbk(rack::global_ui->window.lglw, _vkey, 0u/*kmod*/, LGLW_FALSE/*bPressed*/);
  289. return bHandled;
  290. }
  291. void lglw_dropfiles_cbk(lglw_t _lglw, int32_t _x, int32_t _y, uint32_t _numFiles, const char **_pathNames) {
  292. // onPathDrop
  293. vst2_set_globals(lglw_userdata_get(_lglw));
  294. lglw_glcontext_push(global_ui->window.lglw);
  295. EventPathDrop e;
  296. e.pos = Vec(_x, _y);
  297. for(uint32_t i = 0u; i < _numFiles; i++) {
  298. e.paths.push_back(_pathNames[i]);
  299. }
  300. global_ui->ui.gScene->onPathDrop(e);
  301. lglw_glcontext_pop(global_ui->window.lglw);
  302. }
  303. } // extern C
  304. void renderGui() {
  305. int width, height;
  306. // printf("xxx renderGui: ENTER\n");
  307. lglw_window_size_get(global_ui->window.lglw, &width, &height);
  308. // printf("xxx renderGui: 1 lglw=%p size=(%d; %d)\n", global_ui->window.lglw, width, height);
  309. // Update and render
  310. nvgBeginFrame(global_ui->window.gVg, width, height, global_ui->window.gPixelRatio);
  311. // printf("xxx renderGui: 2\n");
  312. nvgReset(global_ui->window.gVg);
  313. // printf("xxx renderGui: 3\n");
  314. nvgScale(global_ui->window.gVg, global_ui->window.gPixelRatio, global_ui->window.gPixelRatio);
  315. // printf("xxx renderGui: gScene->draw() BEGIN\n");
  316. // printf("xxx renderGui: 4\n");
  317. global_ui->ui.gScene->draw(global_ui->window.gVg);
  318. // printf("xxx renderGui: gScene->draw() END\n");
  319. // printf("xxx renderGui: 5\n");
  320. glViewport(0, 0, width, height);
  321. // printf("xxx renderGui: 6\n");
  322. glClearColor(0.0, 0.0, 0.0, 1.0);
  323. // printf("xxx renderGui: 7\n");
  324. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  325. // printf("xxx renderGui: 8\n");
  326. nvgEndFrame(global_ui->window.gVg);
  327. // printf("xxx renderGui: LEAVE\n");
  328. }
  329. void windowInit() {
  330. int err;
  331. printf("xxx vstrack_plugin:windowInit: ENTER\n");
  332. // (note) the hidden LGLW context window must have the same size as the real window created later on
  333. settingsLoad(assetLocal("settings.json"), true/*bWindowSizeOnly*/);
  334. printf("xxx vstrack_plugin:windowInit: 2\n");
  335. global_ui->window.lglw = lglw_init(global_ui->window.windowWidth, global_ui->window.windowHeight);
  336. printf("xxx vstrack_plugin:windowInit: 3\n");
  337. lglw_userdata_set(global_ui->window.lglw, global->vst2.wrapper);
  338. printf("xxx vstrack_plugin:windowInit: 4\n");
  339. global_ui->window.lastWindowTitle = "";
  340. lglw_glcontext_push(global_ui->window.lglw);
  341. printf("xxx vstrack_plugin:windowInit: 5\n");
  342. global_ui->pending_swap_interval = 1;
  343. printf("xxx vstrack_plugin:windowInit: 6\n");
  344. lglw_mouse_callback_set (global_ui->window.lglw, &lglw_mouse_cbk);
  345. lglw_focus_callback_set (global_ui->window.lglw, &lglw_focus_cbk);
  346. lglw_keyboard_callback_set (global_ui->window.lglw, &lglw_keyboard_cbk);
  347. lglw_timer_callback_set (global_ui->window.lglw, &lglw_timer_cbk);
  348. lglw_dropfiles_callback_set (global_ui->window.lglw, &lglw_dropfiles_cbk);
  349. lglw_redraw_callback_set (global_ui->window.lglw, &lglw_redraw_cbk);
  350. printf("xxx vstrack_plugin:windowInit: 7\n");
  351. // Set up GLEW
  352. glewExperimental = GL_TRUE;
  353. err = glewInit();
  354. if (err != GLEW_OK) {
  355. osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Could not initialize GLEW. Does your graphics card support OpenGL 2.0 or greater? If so, make sure you have the latest graphics drivers installed.");
  356. lglw_glcontext_pop(global_ui->window.lglw);
  357. exit(1);
  358. }
  359. printf("xxx vstrack_plugin:windowInit: 8\n");
  360. // GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here.
  361. glGetError();
  362. printf("xxx vstrack_plugin:windowInit: 9\n");
  363. // Set up NanoVG
  364. int nvgFlags = NVG_ANTIALIAS;
  365. #if defined NANOVG_GL2
  366. global_ui->window.gVg = nvgCreateGL2(nvgFlags);
  367. #elif defined NANOVG_GL3
  368. global_ui->window.gVg = nvgCreateGL3(nvgFlags);
  369. #elif defined NANOVG_GLES2
  370. global_ui->window.gVg = nvgCreateGLES2(nvgFlags);
  371. #endif
  372. printf("xxx vstrack_plugin:windowInit: 10\n");
  373. assert(global_ui->window.gVg);
  374. #if defined NANOVG_GL2
  375. global_ui->window.gFramebufferVg = nvgCreateGL2(nvgFlags);
  376. #elif defined NANOVG_GL3
  377. global_ui->window.gFramebufferVg = nvgCreateGL3(nvgFlags);
  378. #elif defined NANOVG_GLES2
  379. global_ui->window.gFramebufferVg = nvgCreateGLES2(nvgFlags);
  380. #endif
  381. printf("xxx vstrack_plugin:windowInit: 11\n");
  382. assert(global_ui->window.gFramebufferVg);
  383. // Set up Blendish
  384. printf("xxx vstrack_plugin:windowInit: 12\n");
  385. global_ui->window.gGuiFont = Font::load(assetGlobal("res/fonts/DejaVuSans.ttf"));
  386. printf("xxx vstrack_plugin:windowInit: 13\n");
  387. bndSetFont(global_ui->window.gGuiFont->handle);
  388. printf("xxx vstrack_plugin:windowInit: 14\n");
  389. windowSetTheme(nvgRGB(0x33, 0x33, 0x33), nvgRGB(0xf0, 0xf0, 0xf0));
  390. printf("xxx vstrack_plugin:windowInit: 15\n");
  391. lglw_glcontext_pop(global_ui->window.lglw);
  392. printf("xxx vstrack_plugin:windowInit: LEAVE\n");
  393. }
  394. void windowDestroy() {
  395. printf("xxx vstrack_plugin: windowDestroy()\n");
  396. lglw_glcontext_push(global_ui->window.lglw);
  397. global_ui->window.gGuiFont.reset();
  398. #if defined NANOVG_GL2
  399. nvgDeleteGL2(global_ui->window.gVg);
  400. #elif defined NANOVG_GL3
  401. nvgDeleteGL3(global_ui->window.gVg);
  402. #elif defined NANOVG_GLES2
  403. nvgDeleteGLES2(global_ui->window.gVg);
  404. #endif
  405. #if defined NANOVG_GL2
  406. nvgDeleteGL2(global_ui->window.gFramebufferVg);
  407. #elif defined NANOVG_GL3
  408. nvgDeleteGL3(global_ui->window.gFramebufferVg);
  409. #elif defined NANOVG_GLES2
  410. nvgDeleteGLES2(global_ui->window.gFramebufferVg);
  411. #endif
  412. lglw_glcontext_pop(global_ui->window.lglw);
  413. lglw_exit(global_ui->window.lglw);
  414. global_ui->window.lglw = NULL;
  415. }
  416. void vst2_editor_redraw(void) {
  417. // (note) the GL context is set by the caller
  418. // printf("xxx vst2_editor_redraw: ENTER\n");
  419. if(-1 != global_ui->pending_swap_interval)
  420. {
  421. lglw_swap_interval_set(global_ui->window.lglw, global_ui->pending_swap_interval); // can be overridden via settings.json:"vsync" property
  422. global_ui->pending_swap_interval = -1;
  423. }
  424. global_ui->window.gGuiFrame++;
  425. // Find/validate hover param
  426. // printf("xxx vst2_editor_redraw: 2 global_ui->param_info.last_param_widget=%p\n", global_ui->param_info.last_param_widget);
  427. if(NULL != global_ui->param_info.last_param_widget)
  428. {
  429. int uniqueParamId;
  430. ParamWidget *paramWidget =
  431. global_ui->app.gRackWidget->findParamWidgetAndUniqueParamIdByWidgetRef(global_ui->param_info.last_param_widget,
  432. &uniqueParamId
  433. );
  434. if(NULL != paramWidget)
  435. {
  436. global_ui->param_info.last_param_gid = uniqueParamId;
  437. global_ui->param_info.last_param_value = paramWidget->value;
  438. #if 0
  439. printf("xxx vst2_editor_redraw: param_info: uniqueParamId=%d value=%f clipboardValue=%f\n",
  440. global_ui->param_info.last_param_gid,
  441. global_ui->param_info.last_param_value,
  442. global_ui->param_info.value_clipboard
  443. );
  444. #endif
  445. char buf[64];
  446. sprintf(buf, "%d", global_ui->param_info.last_param_gid);
  447. global_ui->param_info.tf_id->setTextQuiet(buf);
  448. sprintf(buf, "%f", global_ui->param_info.last_param_value);
  449. // Delete trailing zeros
  450. {
  451. char *d = buf;
  452. while(0 != *d)
  453. d++;
  454. d--;
  455. if(d > buf)
  456. {
  457. while('0' == *d)
  458. {
  459. if(((d-1) > buf) && ('.' != d[-1]))
  460. *d-- = 0;
  461. else
  462. break;
  463. }
  464. }
  465. }
  466. global_ui->param_info.tf_value->setTextQuiet(buf);
  467. }
  468. global_ui->param_info.last_param_widget = NULL;
  469. global_ui->param_info.placeholder_framecount = 1;
  470. }
  471. else if(0 != global_ui->param_info.placeholder_framecount)
  472. {
  473. if(++global_ui->param_info.placeholder_framecount > (30*30))
  474. {
  475. global_ui->param_info.tf_id->setTextQuiet("");
  476. global_ui->param_info.tf_value->setTextQuiet("");
  477. global_ui->param_info.placeholder_framecount = 0;
  478. }
  479. }
  480. // printf("xxx vst2_editor_redraw: 3\n");
  481. #if 0
  482. // Set window title
  483. // (note) the VST plugin editor window title is set by the VST host
  484. std::string windowTitle;
  485. windowTitle = global_ui->app.gApplicationName;
  486. windowTitle += " ";
  487. windowTitle += global_ui->app.gApplicationVersion;
  488. if (!global_ui->app.gRackWidget->lastPath.empty()) {
  489. windowTitle += " - ";
  490. windowTitle += stringFilename(global_ui->app.gRackWidget->lastPath);
  491. }
  492. if (windowTitle != global_ui->window.lastWindowTitle) {
  493. // // glfwSetWindowTitle(global_ui->window.gWindow, windowTitle.c_str());
  494. global_ui->window.lastWindowTitle = windowTitle;
  495. }
  496. #endif
  497. // Get framebuffer/window ratio
  498. int width, height;
  499. lglw_window_size_get(global_ui->window.lglw, &width, &height);
  500. global_ui->window.gWindowRatio = 1.0f;
  501. global_ui->ui.gScene->box.size = Vec(width, height);
  502. // printf("xxx vst2_editor_redraw: 4\n");
  503. // Step scene
  504. global_ui->ui.gScene->step();
  505. // printf("xxx vst2_editor_redraw: 5\n");
  506. // Render
  507. renderGui();
  508. // printf("xxx vst2_editor_redraw: 6\n");
  509. // Present
  510. glFlush();
  511. // printf("xxx vst2_editor_redraw: 7\n");
  512. lglw_swap_buffers(global_ui->window.lglw);
  513. // printf("xxx vst2_editor_redraw: LEAVE\n");
  514. }
  515. void windowCursorLock() {
  516. if (global_ui->window.gAllowCursorLock) {
  517. lglw_mouse_grab(global_ui->window.lglw, LGLW_MOUSE_GRAB_WARP);
  518. }
  519. }
  520. void windowCursorUnlock() {
  521. if (global_ui->window.gAllowCursorLock) {
  522. lglw_mouse_ungrab(global_ui->window.lglw);
  523. }
  524. }
  525. bool windowIsModPressed() {
  526. return (0u != (lglw_keyboard_get_modifiers(global_ui->window.lglw) & (LGLW_KMOD_LCTRL | LGLW_KMOD_RCTRL)));
  527. }
  528. bool windowIsShiftPressed() {
  529. return (0u != (lglw_keyboard_get_modifiers(global_ui->window.lglw) & (LGLW_KMOD_LSHIFT | LGLW_KMOD_RSHIFT)));
  530. }
  531. Vec windowGetWindowSize() {
  532. int width, height;
  533. lglw_window_size_get(global_ui->window.lglw, &width, &height);
  534. return Vec(width, height);
  535. }
  536. void windowSetWindowSize(Vec size) {
  537. (void)size;
  538. // (note) not supported
  539. }
  540. Vec windowGetWindowPos() {
  541. int x, y;
  542. x = 0;
  543. y = 0;
  544. return Vec(x, y);
  545. }
  546. void windowSetWindowPos(Vec pos) {
  547. int x = pos.x;
  548. int y = pos.y;
  549. // (note) not supported
  550. (void)x;
  551. (void)y;
  552. }
  553. bool windowIsMaximized() {
  554. return true;
  555. }
  556. void windowSetTheme(NVGcolor bg, NVGcolor fg) {
  557. // Assume dark background and light foreground
  558. BNDwidgetTheme w;
  559. w.outlineColor = bg;
  560. w.itemColor = fg;
  561. w.innerColor = bg;
  562. w.innerSelectedColor = colorPlus(bg, nvgRGB(0x30, 0x30, 0x30));
  563. w.textColor = fg;
  564. w.textSelectedColor = fg;
  565. w.shadeTop = 0;
  566. w.shadeDown = 0;
  567. BNDtheme t;
  568. t.backgroundColor = colorPlus(bg, nvgRGB(0x30, 0x30, 0x30));
  569. t.regularTheme = w;
  570. t.toolTheme = w;
  571. t.radioTheme = w;
  572. t.textFieldTheme = w;
  573. t.optionTheme = w;
  574. t.choiceTheme = w;
  575. t.numberFieldTheme = w;
  576. t.sliderTheme = w;
  577. t.scrollBarTheme = w;
  578. t.tooltipTheme = w;
  579. t.menuTheme = w;
  580. t.menuItemTheme = w;
  581. t.sliderTheme.itemColor = bg;
  582. t.sliderTheme.innerColor = colorPlus(bg, nvgRGB(0x50, 0x50, 0x50));
  583. t.sliderTheme.innerSelectedColor = colorPlus(bg, nvgRGB(0x60, 0x60, 0x60));
  584. t.textFieldTheme = t.sliderTheme;
  585. t.textFieldTheme.textColor = colorMinus(bg, nvgRGB(0x20, 0x20, 0x20));
  586. t.textFieldTheme.textSelectedColor = t.textFieldTheme.textColor;
  587. t.scrollBarTheme.itemColor = colorPlus(bg, nvgRGB(0x50, 0x50, 0x50));
  588. t.scrollBarTheme.innerColor = bg;
  589. t.menuTheme.innerColor = colorMinus(bg, nvgRGB(0x10, 0x10, 0x10));
  590. t.menuTheme.textColor = colorMinus(fg, nvgRGB(0x50, 0x50, 0x50));
  591. t.menuTheme.textSelectedColor = t.menuTheme.textColor;
  592. bndSetTheme(t);
  593. }
  594. void windowSetFullScreen(bool fullScreen) {
  595. (void)fullScreen;
  596. // (note) not supported
  597. }
  598. bool windowGetFullScreen() {
  599. return false;
  600. }
  601. void windowClose(void) {
  602. // (note) not supported
  603. }
  604. ////////////////////
  605. // resources
  606. ////////////////////
  607. Font::Font(const std::string &filename) {
  608. printf("xxx vstrack_plugin: Font::Font\n");
  609. handle = nvgCreateFont(global_ui->window.gVg, filename.c_str(), filename.c_str());
  610. if (handle >= 0) {
  611. info("Loaded font %s", filename.c_str());
  612. }
  613. else {
  614. warn("Failed to load font %s", filename.c_str());
  615. }
  616. }
  617. Font::~Font() {
  618. // There is no NanoVG deleteFont() function yet, so do nothing
  619. }
  620. std::shared_ptr<Font> Font::load(const std::string &filename) {
  621. auto sp = global_ui->window.font_cache[filename].lock();
  622. if (!sp)
  623. global_ui->window.font_cache[filename] = sp = std::make_shared<Font>(filename);
  624. return sp;
  625. }
  626. ////////////////////
  627. // Image
  628. ////////////////////
  629. Image::Image(const std::string &filename) {
  630. printf("xxx vstrack_plugin: Image::Image\n");
  631. handle = nvgCreateImage(global_ui->window.gVg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
  632. if (handle > 0) {
  633. info("Loaded image %s", filename.c_str());
  634. }
  635. else {
  636. warn("Failed to load image %s", filename.c_str());
  637. }
  638. }
  639. Image::~Image() {
  640. // TODO What if handle is invalid?
  641. nvgDeleteImage(global_ui->window.gVg, handle);
  642. }
  643. std::shared_ptr<Image> Image::load(const std::string &filename) {
  644. auto sp = global_ui->window.image_cache[filename].lock();
  645. if (!sp)
  646. global_ui->window.image_cache[filename] = sp = std::make_shared<Image>(filename);
  647. return sp;
  648. }
  649. ////////////////////
  650. // SVG
  651. ////////////////////
  652. SVG::SVG(const std::string &filename) {
  653. // printf("xxx vstrack: SVG::SVG\n");
  654. // printf("xxx SVG::SVG: ENTER\n");
  655. handle = nsvgParseFromFile(filename.c_str(), "px", SVG_DPI);
  656. // printf("xxx SVG::SVG: handle=%p\n");
  657. if (handle) {
  658. info("Loaded SVG %s", filename.c_str());
  659. }
  660. else {
  661. warn("Failed to load SVG %s", filename.c_str());
  662. }
  663. // printf("xxx SVG::SVG: LEAVE\n");
  664. }
  665. SVG::~SVG() {
  666. nsvgDelete(handle);
  667. }
  668. std::shared_ptr<SVG> SVG::load(const std::string &filename) {
  669. // printf("xxx SVG::load: ENTER\n");
  670. auto sp = global_ui->window.svg_cache[filename].lock();
  671. if (!sp)
  672. global_ui->window.svg_cache[filename] = sp = std::make_shared<SVG>(filename);
  673. // printf("xxx SVG::load: RETURN\n");
  674. return sp;
  675. }
  676. } // namespace rack