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.

694 lines
22KB

  1. /*
  2. * DISTRHO Cardinal Plugin
  3. * Copyright (C) 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 General Public License as
  7. * published by the Free Software Foundation; either version 3 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the LICENSE file.
  16. */
  17. #include <app/Scene.hpp>
  18. #include <context.hpp>
  19. #include <helpers.hpp>
  20. #include <patch.hpp>
  21. #include <settings.hpp>
  22. #include <string.hpp>
  23. #include <system.hpp>
  24. #include <ui/Button.hpp>
  25. #include <ui/MenuItem.hpp>
  26. #include <ui/MenuSeparator.hpp>
  27. #include <window/Window.hpp>
  28. #ifdef NDEBUG
  29. # undef DEBUG
  30. #endif
  31. #include <Application.hpp>
  32. #include "AsyncDialog.hpp"
  33. #include "PluginContext.hpp"
  34. #include "WindowParameters.hpp"
  35. #include "ResizeHandle.hpp"
  36. GLFWAPI const char* glfwGetClipboardString(GLFWwindow*) { return nullptr; }
  37. GLFWAPI void glfwSetClipboardString(GLFWwindow*, const char*) {}
  38. GLFWAPI int glfwGetKeyScancode(int) { return 0; }
  39. GLFWAPI double glfwGetTime(void)
  40. {
  41. CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP);
  42. DISTRHO_SAFE_ASSERT_RETURN(context != nullptr, 0.0);
  43. DISTRHO_SAFE_ASSERT_RETURN(context->ui != nullptr, 0.0);
  44. return context->ui->getApp().getTime();
  45. }
  46. GLFWAPI const char* glfwGetKeyName(const int key, int)
  47. {
  48. switch (key)
  49. {
  50. case '\"': return "\"";
  51. case '\'': return "\'";
  52. case '\\': return "\\";
  53. case ' ': return " ";
  54. case '!': return "!";
  55. case '#': return "#";
  56. case '$': return "$";
  57. case '%': return "%";
  58. case '&': return "&";
  59. case '(': return "(";
  60. case ')': return ")";
  61. case '*': return "*";
  62. case '+': return "+";
  63. case ',': return ",";
  64. case '-': return "-";
  65. case '.': return ".";
  66. case '/': return "/";
  67. case '0': return "0";
  68. case '1': return "1";
  69. case '2': return "2";
  70. case '3': return "3";
  71. case '4': return "4";
  72. case '5': return "5";
  73. case '6': return "6";
  74. case '7': return "7";
  75. case '8': return "8";
  76. case '9': return "9";
  77. case ':': return ":";
  78. case ';': return ";";
  79. case '<': return "<";
  80. case '=': return "=";
  81. case '>': return ">";
  82. case '?': return "?";
  83. case '@': return "@";
  84. case 'A': return "A";
  85. case 'B': return "B";
  86. case 'C': return "C";
  87. case 'D': return "D";
  88. case 'E': return "E";
  89. case 'F': return "F";
  90. case 'G': return "G";
  91. case 'H': return "H";
  92. case 'I': return "I";
  93. case 'J': return "J";
  94. case 'K': return "K";
  95. case 'L': return "L";
  96. case 'M': return "M";
  97. case 'N': return "N";
  98. case 'O': return "O";
  99. case 'P': return "P";
  100. case 'Q': return "Q";
  101. case 'R': return "R";
  102. case 'S': return "S";
  103. case 'T': return "T";
  104. case 'U': return "U";
  105. case 'V': return "V";
  106. case 'W': return "W";
  107. case 'X': return "X";
  108. case 'Y': return "Y";
  109. case 'Z': return "Z";
  110. case '[': return "[";
  111. case ']': return "]";
  112. case '^': return "^";
  113. case '_': return "_";
  114. case '`': return "`";
  115. case 'a': return "a";
  116. case 'b': return "b";
  117. case 'c': return "c";
  118. case 'd': return "d";
  119. case 'e': return "e";
  120. case 'f': return "f";
  121. case 'g': return "g";
  122. case 'h': return "h";
  123. case 'i': return "i";
  124. case 'j': return "j";
  125. case 'k': return "k";
  126. case 'l': return "l";
  127. case 'm': return "m";
  128. case 'n': return "n";
  129. case 'o': return "o";
  130. case 'p': return "p";
  131. case 'q': return "q";
  132. case 'r': return "r";
  133. case 's': return "s";
  134. case 't': return "t";
  135. case 'u': return "u";
  136. case 'v': return "v";
  137. case 'w': return "w";
  138. case 'x': return "x";
  139. case 'y': return "y";
  140. case 'z': return "z";
  141. default: return nullptr;
  142. }
  143. }
  144. namespace rack {
  145. namespace app {
  146. widget::Widget* createMenuBar(CardinalBaseUI* const ui, bool isStandalone);
  147. }
  148. namespace window {
  149. void WindowSetPluginUI(Window* window, DISTRHO_NAMESPACE::UI* ui);
  150. void WindowSetMods(Window* window, int mods);
  151. }
  152. }
  153. START_NAMESPACE_DISTRHO
  154. // -----------------------------------------------------------------------------------------------------------
  155. bool CardinalPluginContext::addIdleCallback(IdleCallback* const cb)
  156. {
  157. if (ui == nullptr)
  158. return false;
  159. ui->addIdleCallback(cb);
  160. return true;
  161. }
  162. void CardinalPluginContext::removeIdleCallback(IdleCallback* const cb)
  163. {
  164. if (ui == nullptr)
  165. return;
  166. ui->removeIdleCallback(cb);
  167. }
  168. // -----------------------------------------------------------------------------------------------------------
  169. class CardinalUI : public CardinalBaseUI,
  170. public WindowParametersCallback
  171. {
  172. rack::math::Vec fLastMousePos;
  173. ResizeHandle fResizeHandle;
  174. WindowParameters fWindowParameters;
  175. struct ScopedContext {
  176. CardinalPluginContext* const context;
  177. ScopedContext(CardinalUI* const ui)
  178. : context(ui->context)
  179. {
  180. rack::contextSet(context);
  181. WindowParametersRestore(context->window);
  182. }
  183. ScopedContext(CardinalUI* const ui, const int mods)
  184. : context(ui->context)
  185. {
  186. rack::contextSet(context);
  187. rack::window::WindowSetMods(context->window, mods);
  188. WindowParametersRestore(context->window);
  189. }
  190. ~ScopedContext()
  191. {
  192. if (context->window != nullptr)
  193. WindowParametersSave(context->window);
  194. rack::contextSet(nullptr);
  195. }
  196. };
  197. public:
  198. CardinalUI()
  199. : CardinalBaseUI(1228, 666),
  200. fResizeHandle(this)
  201. {
  202. Window& window(getWindow());
  203. window.setIgnoringKeyRepeat(true);
  204. context->nativeWindowId = window.getNativeWindowHandle();
  205. if (isResizable())
  206. fResizeHandle.hide();
  207. const double scaleFactor = getScaleFactor();
  208. if (scaleFactor != 1)
  209. setSize(1228 * scaleFactor, 666 * scaleFactor);
  210. rack::contextSet(context);
  211. rack::window::WindowSetPluginUI(context->window, this);
  212. if (context->scene->menuBar != nullptr)
  213. context->scene->removeChild(context->scene->menuBar);
  214. context->scene->menuBar = rack::app::createMenuBar(this, getApp().isStandalone());
  215. context->scene->addChildBelow(context->scene->menuBar, context->scene->rackScroll);
  216. // hide "Browse VCV Library" button
  217. rack::widget::Widget* const browser = context->scene->browser->children.back();
  218. rack::widget::Widget* const headerLayout = browser->children.front();
  219. rack::widget::Widget* const libraryButton = headerLayout->children.back();
  220. libraryButton->hide();
  221. context->window->step();
  222. rack::contextSet(nullptr);
  223. WindowParametersSetCallback(context->window, this);
  224. }
  225. ~CardinalUI() override
  226. {
  227. rack::contextSet(context);
  228. context->nativeWindowId = 0;
  229. rack::widget::Widget* const menuBar = context->scene->menuBar;
  230. context->scene->menuBar = nullptr;
  231. context->scene->removeChild(menuBar);
  232. rack::window::WindowSetPluginUI(context->window, nullptr);
  233. rack::contextSet(nullptr);
  234. }
  235. void onNanoDisplay() override
  236. {
  237. const ScopedContext sc(this);
  238. context->window->step();
  239. }
  240. void uiIdle() override
  241. {
  242. repaint();
  243. }
  244. void WindowParametersChanged(const WindowParameterList param, float value) override
  245. {
  246. float mult = 1.0f;
  247. switch (param)
  248. {
  249. case kWindowParameterShowTooltips:
  250. fWindowParameters.tooltips = value > 0.5f;
  251. break;
  252. case kWindowParameterCableOpacity:
  253. mult = 100.0f;
  254. fWindowParameters.cableOpacity = value;
  255. break;
  256. case kWindowParameterCableTension:
  257. mult = 100.0f;
  258. fWindowParameters.cableTension = value;
  259. break;
  260. case kWindowParameterRackBrightness:
  261. mult = 100.0f;
  262. fWindowParameters.rackBrightness = value;
  263. break;
  264. case kWindowParameterHaloBrightness:
  265. mult = 100.0f;
  266. fWindowParameters.haloBrightness = value;
  267. break;
  268. case kWindowParameterKnobMode:
  269. switch (static_cast<int>(value + 0.5f))
  270. {
  271. case rack::settings::KNOB_MODE_LINEAR:
  272. value = 0;
  273. fWindowParameters.knobMode = rack::settings::KNOB_MODE_LINEAR;
  274. break;
  275. case rack::settings::KNOB_MODE_ROTARY_ABSOLUTE:
  276. value = 1;
  277. fWindowParameters.knobMode = rack::settings::KNOB_MODE_ROTARY_ABSOLUTE;
  278. break;
  279. case rack::settings::KNOB_MODE_ROTARY_RELATIVE:
  280. value = 2;
  281. fWindowParameters.knobMode = rack::settings::KNOB_MODE_ROTARY_RELATIVE;
  282. break;
  283. }
  284. break;
  285. case kWindowParameterWheelKnobControl:
  286. fWindowParameters.knobScroll = value > 0.5f;
  287. break;
  288. case kWindowParameterWheelSensitivity:
  289. mult = 1000.0f;
  290. fWindowParameters.knobScrollSensitivity = value;
  291. break;
  292. case kWindowParameterLockModulePositions:
  293. fWindowParameters.lockModules = value > 0.5f;
  294. break;
  295. default:
  296. return;
  297. }
  298. setParameterValue(kModuleParameters + param, value * mult);
  299. }
  300. protected:
  301. /* --------------------------------------------------------------------------------------------------------
  302. * DSP/Plugin Callbacks */
  303. /**
  304. A parameter has changed on the plugin side.
  305. This is called by the host to inform the UI about parameter changes.
  306. */
  307. void parameterChanged(const uint32_t index, const float value) override
  308. {
  309. if (index < kModuleParameters)
  310. return;
  311. switch (index - kModuleParameters)
  312. {
  313. case kWindowParameterShowTooltips:
  314. fWindowParameters.tooltips = value > 0.5f;
  315. break;
  316. case kWindowParameterCableOpacity:
  317. fWindowParameters.cableOpacity = value / 100.0f;
  318. break;
  319. case kWindowParameterCableTension:
  320. fWindowParameters.cableTension = value / 100.0f;
  321. break;
  322. case kWindowParameterRackBrightness:
  323. fWindowParameters.rackBrightness = value / 100.0f;
  324. break;
  325. case kWindowParameterHaloBrightness:
  326. fWindowParameters.haloBrightness = value / 100.0f;
  327. break;
  328. case kWindowParameterKnobMode:
  329. switch (static_cast<int>(value + 0.5f))
  330. {
  331. case 0:
  332. fWindowParameters.knobMode = rack::settings::KNOB_MODE_LINEAR;
  333. break;
  334. case 1:
  335. fWindowParameters.knobMode = rack::settings::KNOB_MODE_ROTARY_ABSOLUTE;
  336. break;
  337. case 2:
  338. fWindowParameters.knobMode = rack::settings::KNOB_MODE_ROTARY_RELATIVE;
  339. break;
  340. }
  341. break;
  342. case kWindowParameterWheelKnobControl:
  343. fWindowParameters.knobScroll = value > 0.5f;
  344. break;
  345. case kWindowParameterWheelSensitivity:
  346. fWindowParameters.knobScrollSensitivity = value / 1000.0f;
  347. break;
  348. case kWindowParameterLockModulePositions:
  349. fWindowParameters.lockModules = value > 0.5f;
  350. break;
  351. default:
  352. return;
  353. }
  354. WindowParametersSetValues(context->window, fWindowParameters);
  355. }
  356. void stateChanged(const char* key, const char* value) override
  357. {
  358. if (std::strcmp(key, "windowSize") != 0)
  359. return;
  360. int width = 0;
  361. int height = 0;
  362. std::sscanf(value, "%i:%i", &width, &height);
  363. if (width > 0 && height > 0)
  364. {
  365. const double scaleFactor = getScaleFactor();
  366. setSize(width * scaleFactor, height * scaleFactor);
  367. }
  368. }
  369. // -------------------------------------------------------------------------------------------------------
  370. static int glfwMods(const uint mod) noexcept
  371. {
  372. int mods = 0;
  373. if (mod & kModifierControl)
  374. mods |= GLFW_MOD_CONTROL;
  375. if (mod & kModifierShift)
  376. mods |= GLFW_MOD_SHIFT;
  377. if (mod & kModifierAlt)
  378. mods |= GLFW_MOD_ALT;
  379. if (mod & kModifierSuper)
  380. mods |= GLFW_MOD_SUPER;
  381. /*
  382. if (glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS)
  383. mods |= GLFW_MOD_SHIFT;
  384. if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS)
  385. mods |= GLFW_MOD_CONTROL;
  386. if (glfwGetKey(win, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS)
  387. mods |= GLFW_MOD_ALT;
  388. if (glfwGetKey(win, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS)
  389. mods |= GLFW_MOD_SUPER;
  390. */
  391. return mods;
  392. }
  393. bool onMouse(const MouseEvent& ev) override
  394. {
  395. const int action = ev.press ? GLFW_PRESS : GLFW_RELEASE;
  396. const int mods = glfwMods(ev.mod);
  397. int button;
  398. switch (ev.button)
  399. {
  400. case 1: button = GLFW_MOUSE_BUTTON_LEFT; break;
  401. #ifdef DISTRHO_OS_MAC
  402. case 2: button = GLFW_MOUSE_BUTTON_RIGHT; break;
  403. case 3: button = GLFW_MOUSE_BUTTON_MIDDLE; break;
  404. #else
  405. case 2: button = GLFW_MOUSE_BUTTON_MIDDLE; break;
  406. case 3: button = GLFW_MOUSE_BUTTON_RIGHT; break;
  407. #endif
  408. default:
  409. button = ev.button;
  410. break;
  411. }
  412. /*
  413. #if defined ARCH_MAC
  414. // Remap Ctrl-left click to right click on Mac
  415. if (button == GLFW_MOUSE_BUTTON_LEFT && (mods & RACK_MOD_MASK) == GLFW_MOD_CONTROL) {
  416. button = GLFW_MOUSE_BUTTON_RIGHT;
  417. mods &= ~GLFW_MOD_CONTROL;
  418. }
  419. // Remap Ctrl-shift-left click to middle click on Mac
  420. if (button == GLFW_MOUSE_BUTTON_LEFT && (mods & RACK_MOD_MASK) == (GLFW_MOD_CONTROL | GLFW_MOD_SHIFT)) {
  421. button = GLFW_MOUSE_BUTTON_MIDDLE;
  422. mods &= ~(GLFW_MOD_CONTROL | GLFW_MOD_SHIFT);
  423. }
  424. #endif
  425. */
  426. const ScopedContext sc(this, mods);
  427. return context->event->handleButton(fLastMousePos, button, action, mods);
  428. }
  429. bool onMotion(const MotionEvent& ev) override
  430. {
  431. const rack::math::Vec mousePos = rack::math::Vec(ev.pos.getX(), ev.pos.getY()).div(getScaleFactor()).round();
  432. const rack::math::Vec mouseDelta = mousePos.minus(fLastMousePos);
  433. fLastMousePos = mousePos;
  434. const ScopedContext sc(this, glfwMods(ev.mod));
  435. return context->event->handleHover(mousePos, mouseDelta);
  436. }
  437. bool onScroll(const ScrollEvent& ev) override
  438. {
  439. rack::math::Vec scrollDelta = rack::math::Vec(ev.delta.getX(), ev.delta.getY());
  440. #ifdef DISTRHO_OS_MAC
  441. scrollDelta = scrollDelta.mult(10.0);
  442. #else
  443. scrollDelta = scrollDelta.mult(50.0);
  444. #endif
  445. const int mods = glfwMods(ev.mod);
  446. const ScopedContext sc(this, mods);
  447. return context->event->handleScroll(fLastMousePos, scrollDelta);
  448. }
  449. bool onCharacterInput(const CharacterInputEvent& ev) override
  450. {
  451. if (ev.character <= ' ' || ev.character >= kKeyDelete)
  452. return false;
  453. const int mods = glfwMods(ev.mod);
  454. const ScopedContext sc(this, mods);
  455. return context->event->handleText(fLastMousePos, ev.character);
  456. }
  457. bool onKeyboard(const KeyboardEvent& ev) override
  458. {
  459. const int action = ev.press ? GLFW_PRESS : GLFW_RELEASE;
  460. const int mods = glfwMods(ev.mod);
  461. /* These are unsupported in pugl right now
  462. #define GLFW_KEY_KP_0 320
  463. #define GLFW_KEY_KP_1 321
  464. #define GLFW_KEY_KP_2 322
  465. #define GLFW_KEY_KP_3 323
  466. #define GLFW_KEY_KP_4 324
  467. #define GLFW_KEY_KP_5 325
  468. #define GLFW_KEY_KP_6 326
  469. #define GLFW_KEY_KP_7 327
  470. #define GLFW_KEY_KP_8 328
  471. #define GLFW_KEY_KP_9 329
  472. #define GLFW_KEY_KP_DECIMAL 330
  473. #define GLFW_KEY_KP_DIVIDE 331
  474. #define GLFW_KEY_KP_MULTIPLY 332
  475. #define GLFW_KEY_KP_SUBTRACT 333
  476. #define GLFW_KEY_KP_ADD 334
  477. #define GLFW_KEY_KP_ENTER 335
  478. #define GLFW_KEY_KP_EQUAL 336
  479. */
  480. int key;
  481. switch (ev.key)
  482. {
  483. case '\r': key = GLFW_KEY_ENTER; break;
  484. case '\t': key = GLFW_KEY_TAB; break;
  485. case kKeyBackspace: key = GLFW_KEY_BACKSPACE; break;
  486. case kKeyEscape: key = GLFW_KEY_ESCAPE; break;
  487. case kKeyDelete: key = GLFW_KEY_DELETE; break;
  488. case kKeyF1: key = GLFW_KEY_F1; break;
  489. case kKeyF2: key = GLFW_KEY_F2; break;
  490. case kKeyF3: key = GLFW_KEY_F3; break;
  491. case kKeyF4: key = GLFW_KEY_F4; break;
  492. case kKeyF5: key = GLFW_KEY_F5; break;
  493. case kKeyF6: key = GLFW_KEY_F6; break;
  494. case kKeyF7: key = GLFW_KEY_F7; break;
  495. case kKeyF8: key = GLFW_KEY_F8; break;
  496. case kKeyF9: key = GLFW_KEY_F9; break;
  497. case kKeyF10: key = GLFW_KEY_F10; break;
  498. case kKeyF11: key = GLFW_KEY_F11; break;
  499. case kKeyF12: key = GLFW_KEY_F12; break;
  500. case kKeyLeft: key = GLFW_KEY_LEFT; break;
  501. case kKeyUp: key = GLFW_KEY_UP; break;
  502. case kKeyRight: key = GLFW_KEY_RIGHT; break;
  503. case kKeyDown: key = GLFW_KEY_DOWN; break;
  504. case kKeyPageUp: key = GLFW_KEY_PAGE_UP; break;
  505. case kKeyPageDown: key = GLFW_KEY_PAGE_DOWN; break;
  506. case kKeyHome: key = GLFW_KEY_HOME; break;
  507. case kKeyEnd: key = GLFW_KEY_END; break;
  508. case kKeyInsert: key = GLFW_KEY_INSERT; break;
  509. case kKeyShiftL: key = GLFW_KEY_LEFT_SHIFT; break;
  510. case kKeyShiftR: key = GLFW_KEY_RIGHT_SHIFT; break;
  511. case kKeyControlL: key = GLFW_KEY_LEFT_CONTROL; break;
  512. case kKeyControlR: key = GLFW_KEY_RIGHT_CONTROL; break;
  513. case kKeyAltL: key = GLFW_KEY_LEFT_ALT; break;
  514. case kKeyAltR: key = GLFW_KEY_RIGHT_ALT; break;
  515. case kKeySuperL: key = GLFW_KEY_LEFT_SUPER; break;
  516. case kKeySuperR: key = GLFW_KEY_RIGHT_SUPER; break;
  517. case kKeyMenu: key = GLFW_KEY_MENU; break;
  518. case kKeyCapsLock: key = GLFW_KEY_CAPS_LOCK; break;
  519. case kKeyScrollLock: key = GLFW_KEY_SCROLL_LOCK; break;
  520. case kKeyNumLock: key = GLFW_KEY_NUM_LOCK; break;
  521. case kKeyPrintScreen: key = GLFW_KEY_PRINT_SCREEN; break;
  522. case kKeyPause: key = GLFW_KEY_PAUSE; break;
  523. default: key = ev.key; break;
  524. }
  525. const ScopedContext sc(this, mods);
  526. return context->event->handleKey(fLastMousePos, key, ev.keycode, action, mods);
  527. }
  528. void onResize(const ResizeEvent& ev) override
  529. {
  530. UI::onResize(ev);
  531. if (context->window != nullptr)
  532. context->window->setSize(rack::math::Vec(ev.size.getWidth(), ev.size.getHeight()));
  533. const double scaleFactor = getScaleFactor();
  534. char sizeString[64];
  535. std::snprintf(sizeString, sizeof(sizeString), "%d:%d",
  536. (int)(ev.size.getWidth() / scaleFactor), (int)(ev.size.getHeight() / scaleFactor));
  537. setState("windowSize", sizeString);
  538. }
  539. void uiFocus(const bool focus, CrossingMode) override
  540. {
  541. if (focus)
  542. return;
  543. const ScopedContext sc(this, 0);
  544. context->event->handleLeave();
  545. }
  546. void uiFileBrowserSelected(const char* const filename) override
  547. {
  548. if (filename == nullptr)
  549. return;
  550. rack::contextSet(context);
  551. WindowParametersRestore(context->window);
  552. std::string sfilename = filename;
  553. if (saving)
  554. {
  555. if (rack::system::getExtension(sfilename) != ".vcv")
  556. sfilename += ".vcv";
  557. try {
  558. context->patch->save(sfilename);
  559. }
  560. catch (rack::Exception& e) {
  561. std::string message = rack::string::f("Could not save patch: %s", e.what());
  562. asyncDialog::create(message.c_str());
  563. return;
  564. }
  565. }
  566. else
  567. {
  568. try {
  569. context->patch->load(sfilename);
  570. } catch (rack::Exception& e) {
  571. std::string message = rack::string::f("Could not load patch: %s", e.what());
  572. asyncDialog::create(message.c_str());
  573. return;
  574. }
  575. }
  576. context->patch->path = sfilename;
  577. context->history->setSaved();
  578. }
  579. #if 0
  580. void uiReshape(const uint width, const uint height) override
  581. {
  582. glEnable(GL_BLEND);
  583. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  584. glMatrixMode(GL_PROJECTION);
  585. glLoadIdentity();
  586. glOrtho(0.0, width, 0.0, height, -1.0, 1.0);
  587. glViewport(0, 0, width, height);
  588. glMatrixMode(GL_MODELVIEW);
  589. glLoadIdentity();
  590. }
  591. #endif
  592. private:
  593. /**
  594. Set our UI class as non-copyable and add a leak detector just in case.
  595. */
  596. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CardinalUI)
  597. };
  598. /* ------------------------------------------------------------------------------------------------------------
  599. * UI entry point, called by DPF to create a new UI instance. */
  600. UI* createUI()
  601. {
  602. return new CardinalUI();
  603. }
  604. // -----------------------------------------------------------------------------------------------------------
  605. END_NAMESPACE_DISTRHO