DISTRHO Plugin Framework
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.

804 lines
27KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "DistrhoUIInternal.hpp"
  17. #include <atomic>
  18. // TESTING awful idea dont reuse
  19. #include "../extra/Thread.hpp"
  20. #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI
  21. # undef DISTRHO_PLUGIN_HAS_UI
  22. # define DISTRHO_PLUGIN_HAS_UI 0
  23. #endif
  24. #if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  25. # undef DISTRHO_PLUGIN_HAS_UI
  26. # define DISTRHO_PLUGIN_HAS_UI 0
  27. #endif
  28. // #undef DISTRHO_PLUGIN_HAS_UI
  29. // #define DISTRHO_PLUGIN_HAS_UI 1
  30. // #if DISTRHO_PLUGIN_HAS_UI
  31. # include "DistrhoUIInternal.hpp"
  32. // #endif
  33. #include "travesty/edit_controller.h"
  34. #include "travesty/message.h"
  35. #include "travesty/view.h"
  36. /* TODO items:
  37. * - disable UI if non-embed UI build
  38. * - parameter change listener
  39. * - parameter change sender
  40. * - program change listener
  41. * - program change sender
  42. * - state change listener
  43. * - state change sender
  44. * - sample rate change listener
  45. * - call component handler restart with params-changed flag when setting program?
  46. */
  47. START_NAMESPACE_DISTRHO
  48. // --------------------------------------------------------------------------------------------------------------------
  49. #if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT
  50. static constexpr const sendNoteFunc sendNoteCallback = nullptr;
  51. #endif
  52. #if ! DISTRHO_PLUGIN_WANT_STATE
  53. static constexpr const setStateFunc setStateCallback = nullptr;
  54. #endif
  55. // --------------------------------------------------------------------------------------------------------------------
  56. // Utility functions (defined on plugin side)
  57. const char* tuid2str(const v3_tuid iid);
  58. // --------------------------------------------------------------------------------------------------------------------
  59. // dpf_message (needed by the UI class, implementation comes later)
  60. struct v3_message_cpp : v3_funknown {
  61. v3_message msg;
  62. };
  63. // NOTE value type must be POD
  64. template<typename T>
  65. struct dpf_message : v3_message_cpp {
  66. dpf_message(ScopedPointer<dpf_message>* self, const char* id, T value);
  67. struct PrivateData;
  68. PrivateData* const pData;
  69. };
  70. // --------------------------------------------------------------------------------------------------------------------
  71. /**
  72. * VST3 UI class.
  73. *
  74. * All the dynamic things from VST3 get implemented here, free of complex low-level VST3 pointer things.
  75. * The UI is created during the "attach" view event, and destroyed during "removed".
  76. *
  77. * Note that DPF VST3 implementation works over the connection point interface,
  78. * rather than using edit controller directly.
  79. * This allows the UI to be running remotely from the DSP.
  80. *
  81. * The low-level VST3 stuff comes after.
  82. */
  83. class UIVst3 : public Thread
  84. {
  85. public:
  86. UIVst3(v3_plugin_view** const view,
  87. v3_connection_point** const connection,
  88. const intptr_t winId,
  89. const float scaleFactor,
  90. const double sampleRate,
  91. void* const instancePointer)
  92. : fUI(this, winId, sampleRate,
  93. editParameterCallback,
  94. setParameterCallback,
  95. setStateCallback,
  96. sendNoteCallback,
  97. setSizeCallback,
  98. nullptr, // TODO file request
  99. nullptr,
  100. instancePointer,
  101. scaleFactor),
  102. fView(view),
  103. fConnection(connection),
  104. fFrame(nullptr),
  105. fScaleFactor(scaleFactor)
  106. {
  107. // TESTING awful idea dont reuse
  108. startThread();
  109. }
  110. ~UIVst3() override
  111. {
  112. stopThread(5000);
  113. }
  114. // TESTING awful idea dont reuse
  115. void run() override
  116. {
  117. while (! shouldThreadExit())
  118. {
  119. fUI.plugin_idle();
  120. d_msleep(50);
  121. }
  122. }
  123. // ----------------------------------------------------------------------------------------------------------------
  124. // v3_plugin_view interface calls
  125. v3_result onWheel(float /*distance*/)
  126. {
  127. // TODO
  128. return V3_NOT_IMPLEMENTED;
  129. };
  130. v3_result onKeyDown(int16_t /*key_char*/, int16_t /*key_code*/, int16_t /*modifiers*/)
  131. {
  132. // TODO
  133. return V3_NOT_IMPLEMENTED;
  134. };
  135. v3_result onKeyUp(int16_t /*key_char*/, int16_t /*key_code*/, int16_t /*modifiers*/)
  136. {
  137. // TODO
  138. return V3_NOT_IMPLEMENTED;
  139. };
  140. v3_result getSize(v3_view_rect* const rect) const noexcept
  141. {
  142. std::memset(rect, 0, sizeof(v3_view_rect));
  143. rect->right = fUI.getWidth();
  144. rect->bottom = fUI.getHeight();
  145. #ifdef DISTRHO_OS_MAC
  146. const double scaleFactor = fUI.getScaleFactor();
  147. rect->right /= scaleFactor;
  148. rect->bottom /= scaleFactor;
  149. #endif
  150. return V3_OK;
  151. }
  152. v3_result onSize(v3_view_rect* const /*rect*/)
  153. {
  154. // TODO
  155. return V3_NOT_IMPLEMENTED;
  156. }
  157. v3_result onFocus(const bool state)
  158. {
  159. #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  160. fUI.notifyFocusChanged(state);
  161. return V3_OK;
  162. #else
  163. return V3_NOT_IMPLEMENTED;
  164. // unused
  165. (void)state;
  166. #endif
  167. }
  168. v3_result setFrame(v3_plugin_frame** const frame) noexcept
  169. {
  170. fFrame = frame;
  171. return V3_OK;
  172. }
  173. v3_result checkSizeConstraint(v3_view_rect* const /*rect*/)
  174. {
  175. // TODO
  176. return V3_NOT_IMPLEMENTED;
  177. }
  178. // ----------------------------------------------------------------------------------------------------------------
  179. // v3_plugin_view_content_scale_steinberg interface calls
  180. v3_result setContentScaleFactor(const float factor)
  181. {
  182. if (d_isEqual(fScaleFactor, factor))
  183. return V3_OK;
  184. fScaleFactor = factor;
  185. fUI.notifyScaleFactorChanged(factor);
  186. return V3_OK;
  187. }
  188. // ----------------------------------------------------------------------------------------------------------------
  189. private:
  190. // Plugin UI
  191. UIExporter fUI;
  192. // VST3 stuff
  193. v3_plugin_view** const fView;
  194. v3_connection_point** const fConnection;
  195. v3_plugin_frame** fFrame;
  196. // Temporary data
  197. float fScaleFactor;
  198. // ----------------------------------------------------------------------------------------------------------------
  199. // DPF callbacks
  200. void editParameter(const uint32_t /*rindex*/, const bool /*started*/) const
  201. {
  202. // DISTRHO_SAFE_ASSERT_RETURN(fHandler != nullptr,);
  203. // if (started)
  204. // v3_cpp_obj(fHandler)->begin_edit(fHandler, rindex);
  205. // else
  206. // v3_cpp_obj(fHandler)->end_edit(fHandler, rindex);
  207. }
  208. static void editParameterCallback(void* ptr, uint32_t rindex, bool started)
  209. {
  210. ((UIVst3*)ptr)->editParameter(rindex, started);
  211. }
  212. void setParameterValue(const uint32_t rindex, const float realValue)
  213. {
  214. DISTRHO_SAFE_ASSERT_RETURN(fConnection != nullptr,);
  215. d_stdout("setParameterValue %p %u %f", this, rindex, realValue);
  216. struct IndexAndValue {
  217. uint32_t index;
  218. float value;
  219. };
  220. ScopedPointer<dpf_message<IndexAndValue>>* const messageptr = new ScopedPointer<dpf_message<IndexAndValue>>;
  221. *messageptr = new dpf_message<IndexAndValue>(messageptr, "parameter-value-set", { rindex, realValue });
  222. v3_cpp_obj(fConnection)->notify(fConnection, (v3_message**)messageptr);
  223. }
  224. static void setParameterCallback(void* ptr, uint32_t rindex, float value)
  225. {
  226. ((UIVst3*)ptr)->setParameterValue(rindex, value);
  227. }
  228. void setSize(uint width, uint height)
  229. {
  230. DISTRHO_SAFE_ASSERT_RETURN(fView != nullptr,);
  231. DISTRHO_SAFE_ASSERT_RETURN(fFrame != nullptr,);
  232. d_stdout("from UI setSize %u %u | %p %p", width, height, fView, fFrame);
  233. // #ifdef DISTRHO_OS_MAC
  234. // const double scaleFactor = fUI.getScaleFactor();
  235. // width /= scaleFactor;
  236. // height /= scaleFactor;
  237. // #endif
  238. //
  239. // v3_view_rect rect;
  240. // std::memset(&rect, 0, sizeof(rect));
  241. // rect.right = width;
  242. // rect.bottom = height;
  243. // v3_cpp_obj(fFrame)->resize_view(fFrame, fView, &rect);
  244. }
  245. static void setSizeCallback(void* ptr, uint width, uint height)
  246. {
  247. ((UIVst3*)ptr)->setSize(width, height);
  248. }
  249. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  250. void sendNote(const uint8_t /*channel*/, const uint8_t /*note*/, const uint8_t /*velocity*/)
  251. {
  252. // uint8_t midiData[3];
  253. // midiData[0] = (velocity != 0 ? 0x90 : 0x80) | channel;
  254. // midiData[1] = note;
  255. // midiData[2] = velocity;
  256. // fNotesRingBuffer.writeCustomData(midiData, 3);
  257. // fNotesRingBuffer.commitWrite();
  258. }
  259. static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
  260. {
  261. ((UIVst3*)ptr)->sendNote(channel, note, velocity);
  262. }
  263. #endif
  264. #if DISTRHO_PLUGIN_WANT_STATE
  265. void setState(const char* const /*key*/, const char* const /*value*/)
  266. {
  267. // fUiHelper->setStateFromUI(key, value);
  268. }
  269. static void setStateCallback(void* ptr, const char* key, const char* value)
  270. {
  271. ((UIVst3*)ptr)->setState(key, value);
  272. }
  273. #endif
  274. };
  275. // --------------------------------------------------------------------------------------------------------------------
  276. /**
  277. * VST3 low-level pointer thingies follow, proceed with care.
  278. */
  279. // --------------------------------------------------------------------------------------------------------------------
  280. // dpf_message (implementation only, declaration already done as needed by UI class)
  281. template<typename T>
  282. struct dpf_message<T>::PrivateData {
  283. std::atomic<int> refcounter;
  284. ScopedPointer<dpf_message>* self;
  285. String id;
  286. const T value;
  287. PrivateData(ScopedPointer<dpf_message>* const s, const char* const id2, T value2)
  288. : refcounter(1),
  289. self(s),
  290. id(id2),
  291. value(value2) {}
  292. };
  293. static V3_API v3_result dpf_message__query_interface(void* self, const v3_tuid iid, void** iface)
  294. {
  295. d_stdout("dpf_message::query_interface => %p %s %p", self, tuid2str(iid), iface);
  296. *iface = NULL;
  297. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  298. static const uint8_t* kSupportedInterfaces[] = {
  299. v3_funknown_iid,
  300. v3_message_iid
  301. };
  302. for (const uint8_t* interface_iid : kSupportedInterfaces)
  303. {
  304. if (v3_tuid_match(interface_iid, iid))
  305. {
  306. *iface = self;
  307. return V3_OK;
  308. }
  309. }
  310. return V3_NO_INTERFACE;
  311. }
  312. template<typename T>
  313. static V3_API uint32_t dpf_message__ref(void* const self)
  314. {
  315. d_stdout("dpf_message::ref => %p", self);
  316. dpf_message<T>* const message = *(dpf_message<T>**)self;
  317. DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, 0);
  318. return ++message->pData->refcounter;
  319. }
  320. template<typename T>
  321. static V3_API uint32_t dpf_message__unref(void* const self)
  322. {
  323. d_stdout("dpf_message::unref => %p", self);
  324. dpf_message<T>* const message = *(dpf_message<T>**)self;
  325. DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, 0);
  326. if (const int refcounter = --message->pData->refcounter)
  327. return refcounter;
  328. dpf_message<T>* const messageptr = message->pData->self->release();
  329. delete message->pData;
  330. delete messageptr;
  331. delete (dpf_message<T>**)self;
  332. return 0;
  333. }
  334. template<typename T>
  335. static V3_API const char* dpf_message__get_message_id(void* const self)
  336. {
  337. d_stdout("dpf_message::get_message_id => %p", self);
  338. dpf_message<T>* const message = *(dpf_message<T>**)self;
  339. DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, nullptr);
  340. return message->pData->id;
  341. }
  342. template<typename T>
  343. static V3_API void dpf_message__set_message_id(void* const self, const char* const id)
  344. {
  345. d_stdout("dpf_message::set_message_id => %p %s", self, id);
  346. dpf_message<T>* const message = *(dpf_message<T>**)self;
  347. DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,);
  348. message->pData->id = id;
  349. }
  350. template<typename T>
  351. static V3_API v3_attribute_list* dpf_message__get_attributes(void* const self)
  352. {
  353. d_stdout("dpf_message::get_attributes => %p", self);
  354. dpf_message<T>* const message = *(dpf_message<T>**)self;
  355. DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, nullptr);
  356. // TODO
  357. return nullptr;
  358. }
  359. template<typename T>
  360. dpf_message<T>::dpf_message(ScopedPointer<dpf_message>* const self, const char* const id, const T value)
  361. : pData(new PrivateData(self, id, value))
  362. {
  363. query_interface = dpf_message__query_interface;
  364. ref = dpf_message__ref<T>;
  365. unref = dpf_message__unref<T>;
  366. msg.get_message_id = dpf_message__get_message_id<T>;
  367. msg.set_message_id = dpf_message__set_message_id<T>;
  368. msg.get_attributes = dpf_message__get_attributes<T>;
  369. }
  370. template struct dpf_message<float>;
  371. // --------------------------------------------------------------------------------------------------------------------
  372. // dpf_plugin_view_content_scale
  373. struct v3_plugin_view_content_scale_cpp : v3_funknown {
  374. v3_plugin_view_content_scale scale;
  375. };
  376. struct dpf_plugin_view_content_scale : v3_plugin_view_content_scale_cpp {
  377. ScopedPointer<UIVst3>& uivst3;
  378. // cached values
  379. float scaleFactor;
  380. dpf_plugin_view_content_scale(ScopedPointer<UIVst3>& v)
  381. : uivst3(v),
  382. scaleFactor(0.0f)
  383. {
  384. query_interface = query_interface_fn;
  385. ref = ref_fn;
  386. unref = unref_fn;
  387. scale.set_content_scale_factor = set_content_scale_factor_fn;
  388. }
  389. // ----------------------------------------------------------------------------------------------------------------
  390. // v3_funknown
  391. static V3_API v3_result query_interface_fn(void* self, const v3_tuid iid, void** iface)
  392. {
  393. d_stdout("dpf_plugin_view_content_scale::query_interface => %p %s %p", self, tuid2str(iid), iface);
  394. *iface = NULL;
  395. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  396. static const uint8_t* kSupportedInterfaces[] = {
  397. v3_funknown_iid,
  398. v3_plugin_view_content_scale_iid
  399. };
  400. for (const uint8_t* interface_iid : kSupportedInterfaces)
  401. {
  402. if (v3_tuid_match(interface_iid, iid))
  403. {
  404. *iface = self;
  405. return V3_OK;
  406. }
  407. }
  408. return V3_NO_INTERFACE;
  409. }
  410. // there is only a single instance of this, so we don't have to care here
  411. static V3_API uint32_t ref_fn(void*) { return 1; };
  412. static V3_API uint32_t unref_fn(void*) { return 0; };
  413. // ----------------------------------------------------------------------------------------------------------------
  414. // v3_plugin_view_content_scale_steinberg
  415. static V3_API v3_result set_content_scale_factor_fn(void* self, float factor)
  416. {
  417. d_stdout("dpf_plugin_view::set_content_scale_factor => %p %f", self, factor);
  418. dpf_plugin_view_content_scale* const scale = *(dpf_plugin_view_content_scale**)self;
  419. DISTRHO_SAFE_ASSERT_RETURN(scale != nullptr, V3_NOT_INITIALISED);
  420. scale->scaleFactor = factor;
  421. if (UIVst3* const uivst3 = scale->uivst3)
  422. return uivst3->setContentScaleFactor(factor);
  423. return V3_NOT_INITIALISED;
  424. }
  425. };
  426. // --------------------------------------------------------------------------------------------------------------------
  427. // dpf_plugin_view
  428. struct v3_plugin_view_cpp : v3_funknown {
  429. v3_plugin_view view;
  430. };
  431. struct dpf_plugin_view : v3_plugin_view_cpp {
  432. std::atomic<int> refcounter;
  433. ScopedPointer<dpf_plugin_view>* self;
  434. ScopedPointer<dpf_plugin_view_content_scale> scale;
  435. ScopedPointer<UIVst3> uivst3;
  436. // cached values
  437. v3_connection_point** const connection;
  438. void* const instancePointer;
  439. double sampleRate;
  440. v3_plugin_frame** frame = nullptr;
  441. dpf_plugin_view(ScopedPointer<dpf_plugin_view>* selfptr,
  442. v3_connection_point** const connectionptr,
  443. void* const instance,
  444. const double sr)
  445. : refcounter(1),
  446. self(selfptr),
  447. connection(connectionptr),
  448. instancePointer(instance),
  449. sampleRate(sr)
  450. {
  451. static const uint8_t* kSupportedInterfacesBase[] = {
  452. v3_funknown_iid,
  453. v3_plugin_view_iid
  454. };
  455. static const char* const kSupportedPlatforms[] = {
  456. #ifdef _WIN32
  457. V3_VIEW_PLATFORM_TYPE_HWND,
  458. #elif defined(__APPLE__)
  459. V3_VIEW_PLATFORM_TYPE_NSVIEW,
  460. #else
  461. V3_VIEW_PLATFORM_TYPE_X11,
  462. #endif
  463. };
  464. // ------------------------------------------------------------------------------------------------------------
  465. // v3_funknown
  466. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  467. {
  468. d_stdout("dpf_plugin_view::query_interface => %p %s %p", self, tuid2str(iid), iface);
  469. *iface = NULL;
  470. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  471. for (const uint8_t* interface_iid : kSupportedInterfacesBase)
  472. {
  473. if (v3_tuid_match(interface_iid, iid))
  474. {
  475. *iface = self;
  476. return V3_OK;
  477. }
  478. }
  479. dpf_plugin_view* const view = *(dpf_plugin_view**)self;
  480. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NO_INTERFACE);
  481. if (v3_tuid_match(v3_plugin_view_content_scale_iid, iid))
  482. {
  483. if (view->scale == nullptr)
  484. view->scale = new dpf_plugin_view_content_scale(view->uivst3);
  485. *iface = &view->scale;
  486. return V3_OK;
  487. }
  488. return V3_NO_INTERFACE;
  489. };
  490. ref = []V3_API(void* self) -> uint32_t
  491. {
  492. d_stdout("dpf_plugin_view::ref => %p", self);
  493. dpf_plugin_view* const view = *(dpf_plugin_view**)self;
  494. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, 0);
  495. return ++view->refcounter;
  496. };
  497. unref = []V3_API(void* self) -> uint32_t
  498. {
  499. d_stdout("dpf_plugin_view::unref => %p", self);
  500. dpf_plugin_view* const view = *(dpf_plugin_view**)self;
  501. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, 0);
  502. if (const int refcounter = --view->refcounter)
  503. return refcounter;
  504. *view->self = nullptr;
  505. delete (dpf_plugin_view**)self;
  506. return 0;
  507. };
  508. // ------------------------------------------------------------------------------------------------------------
  509. // v3_plugin_view
  510. view.is_platform_type_supported = []V3_API(void* self, const char* platform_type) -> v3_result
  511. {
  512. d_stdout("dpf_plugin_view::is_platform_type_supported => %p %s", self, platform_type);
  513. dpf_plugin_view* const view = *(dpf_plugin_view**)self;
  514. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED);
  515. for (size_t i=0; i<ARRAY_SIZE(kSupportedPlatforms); ++i)
  516. {
  517. if (std::strcmp(kSupportedPlatforms[i], platform_type) == 0)
  518. return V3_OK;
  519. }
  520. return V3_NOT_IMPLEMENTED;
  521. };
  522. view.attached = []V3_API(void* self, void* parent, const char* platform_type) -> v3_result
  523. {
  524. d_stdout("dpf_plugin_view::attached => %p %p %s", self, parent, platform_type);
  525. dpf_plugin_view* const view = *(dpf_plugin_view**)self;
  526. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED);
  527. DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 == nullptr, V3_INVALID_ARG);
  528. for (size_t i=0; i<ARRAY_SIZE(kSupportedPlatforms); ++i)
  529. {
  530. if (std::strcmp(kSupportedPlatforms[i], platform_type) == 0)
  531. {
  532. const float scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f;
  533. view->uivst3 = new UIVst3((v3_plugin_view**)view->self,
  534. view->connection,
  535. (uintptr_t)parent,
  536. scaleFactor,
  537. view->sampleRate,
  538. view->instancePointer);
  539. view->uivst3->setFrame(view->frame);
  540. return V3_OK;
  541. }
  542. }
  543. return V3_NOT_IMPLEMENTED;
  544. };
  545. view.removed = []V3_API(void* self) -> v3_result
  546. {
  547. d_stdout("dpf_plugin_view::removed => %p", self);
  548. dpf_plugin_view* const view = *(dpf_plugin_view**)self;
  549. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED);
  550. DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_INVALID_ARG);
  551. view->uivst3 = nullptr;
  552. return V3_OK;
  553. };
  554. view.on_wheel = []V3_API(void* self, float distance) -> v3_result
  555. {
  556. d_stdout("dpf_plugin_view::on_wheel => %p %f", self, distance);
  557. dpf_plugin_view* const view = *(dpf_plugin_view**)self;
  558. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED);
  559. UIVst3* const uivst3 = view->uivst3;
  560. DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED);
  561. return uivst3->onWheel(distance);
  562. };
  563. view.on_key_down = []V3_API(void* self, int16_t key_char, int16_t key_code, int16_t modifiers) -> v3_result
  564. {
  565. d_stdout("dpf_plugin_view::on_key_down => %p %i %i %i", self, key_char, key_code, modifiers);
  566. dpf_plugin_view* const view = *(dpf_plugin_view**)self;
  567. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED);
  568. UIVst3* const uivst3 = view->uivst3;
  569. DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED);
  570. return uivst3->onKeyDown(key_char, key_code, modifiers);
  571. };
  572. view.on_key_up = []V3_API(void* self, int16_t key_char, int16_t key_code, int16_t modifiers) -> v3_result
  573. {
  574. d_stdout("dpf_plugin_view::on_key_up => %p %i %i %i", self, key_char, key_code, modifiers);
  575. dpf_plugin_view* const view = *(dpf_plugin_view**)self;
  576. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED);
  577. UIVst3* const uivst3 = view->uivst3;
  578. DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED);
  579. return uivst3->onKeyUp(key_char, key_code, modifiers);
  580. };
  581. view.get_size = []V3_API(void* self, v3_view_rect* rect) -> v3_result
  582. {
  583. d_stdout("dpf_plugin_view::get_size => %p", self);
  584. dpf_plugin_view* const view = *(dpf_plugin_view**)self;
  585. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED);
  586. if (UIVst3* const uivst3 = view->uivst3)
  587. return uivst3->getSize(rect);
  588. // special case: allow UI to not be attached yet, as a way to get size before window creation
  589. const float scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f;
  590. UIExporter tmpUI(nullptr, 0, view->sampleRate,
  591. nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
  592. view->instancePointer, scaleFactor);
  593. rect->right = tmpUI.getWidth();
  594. rect->bottom = tmpUI.getHeight();
  595. return V3_OK;
  596. };
  597. view.on_size = []V3_API(void* self, v3_view_rect* rect) -> v3_result
  598. {
  599. d_stdout("dpf_plugin_view::on_size => %p %p", self, rect);
  600. dpf_plugin_view* const view = *(dpf_plugin_view**)self;
  601. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED);
  602. UIVst3* const uivst3 = view->uivst3;
  603. DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED);
  604. return uivst3->onSize(rect);
  605. };
  606. view.on_focus = []V3_API(void* self, v3_bool state) -> v3_result
  607. {
  608. d_stdout("dpf_plugin_view::on_focus => %p %u", self, state);
  609. dpf_plugin_view* const view = *(dpf_plugin_view**)self;
  610. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED);
  611. UIVst3* const uivst3 = view->uivst3;
  612. DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED);
  613. return uivst3->onFocus(state);
  614. };
  615. view.set_frame = []V3_API(void* self, v3_plugin_frame** frame) -> v3_result
  616. {
  617. d_stdout("dpf_plugin_view::set_frame => %p %p", self, frame);
  618. dpf_plugin_view* const view = *(dpf_plugin_view**)self;
  619. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED);
  620. view->frame = frame;
  621. if (UIVst3* const uivst3 = view->uivst3)
  622. return uivst3->setFrame(frame);
  623. return V3_NOT_INITIALISED;
  624. };
  625. view.can_resize = []V3_API(void* self) -> v3_result
  626. {
  627. d_stdout("dpf_plugin_view::can_resize => %p", self);
  628. // #if DISTRHO_UI_USER_RESIZABLE
  629. // return V3_OK;
  630. // #else
  631. return V3_NOT_IMPLEMENTED;
  632. // #endif
  633. };
  634. view.check_size_constraint = []V3_API(void* self, v3_view_rect* rect) -> v3_result
  635. {
  636. d_stdout("dpf_plugin_view::check_size_constraint => %p %p", self, rect);
  637. dpf_plugin_view* const view = *(dpf_plugin_view**)self;
  638. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED);
  639. UIVst3* const uivst3 = view->uivst3;
  640. DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED);
  641. return uivst3->checkSizeConstraint(rect);
  642. };
  643. }
  644. };
  645. // --------------------------------------------------------------------------------------------------------------------
  646. // dpf_plugin_view_create (called from plugin side)
  647. v3_funknown** dpf_plugin_view_create(v3_connection_point** connection, void* instancePointer, double sampleRate);
  648. v3_funknown** dpf_plugin_view_create(v3_connection_point** const connection,
  649. void* const instancePointer, const double sampleRate)
  650. {
  651. ScopedPointer<dpf_plugin_view>* const viewptr = new ScopedPointer<dpf_plugin_view>;
  652. *viewptr = new dpf_plugin_view(viewptr, connection, instancePointer, sampleRate);
  653. return (v3_funknown**)viewptr;
  654. }
  655. // --------------------------------------------------------------------------------------------------------------------
  656. END_NAMESPACE_DISTRHO