DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

commit ba550f42fd9f366e633bf0b979a99825791f44ee
parent da528328bf4e13004bfddf9b71e214a5bea97e95
Author: falkTX <falktx@falktx.com>
Date:   Fri, 24 Sep 2021 23:22:15 +0100

VST3: Cleanup UI side, make it appear again

Signed-off-by: falkTX <falktx@falktx.com>

Diffstat:
Mdistrho/DistrhoUIMain.cpp | 2+-
Ddistrho/src/DISTRHOUIVST3.cpp | 666-------------------------------------------------------------------------------
Mdistrho/src/DistrhoPluginVST3.cpp | 37++++++++++++++++++++++++++++---------
Adistrho/src/DistrhoUIVST3.cpp | 718+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 747 insertions(+), 676 deletions(-)

diff --git a/distrho/DistrhoUIMain.cpp b/distrho/DistrhoUIMain.cpp @@ -27,7 +27,7 @@ #elif defined(DISTRHO_PLUGIN_TARGET_VST2) // nothing #elif defined(DISTRHO_PLUGIN_TARGET_VST3) -// nothing +# include "src/DistrhoUIVST3.cpp" #else # error unsupported format #endif diff --git a/distrho/src/DISTRHOUIVST3.cpp b/distrho/src/DISTRHOUIVST3.cpp @@ -1,666 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "DistrhoUIInternal.hpp" - -#include "travesty/audio_processor.h" -#include "travesty/component.h" -#include "travesty/edit_controller.h" -#include "travesty/factory.h" -#include "travesty/view.h" - -#include <atomic> - -// TESTING awful idea dont reuse -#include "../extra/Thread.hpp" - -// #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI -// # undef DISTRHO_PLUGIN_HAS_UI -// # define DISTRHO_PLUGIN_HAS_UI 0 -// #endif -// -// #if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI -// # undef DISTRHO_PLUGIN_HAS_UI -// # define DISTRHO_PLUGIN_HAS_UI 0 -// #endif -// -// #undef DISTRHO_PLUGIN_HAS_UI -// #define DISTRHO_PLUGIN_HAS_UI 1 - -// #if DISTRHO_PLUGIN_HAS_UI -# include "DistrhoUIInternal.hpp" -// #endif - -// -------------------------------------------------------------------------------------------------------------------- - -struct v3_component_handler_cpp : v3_funknown { - v3_component_handler handler; -}; - -START_NAMESPACE_DISTRHO - -// -------------------------------------------------------------------------------------------------------------------- - -#if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT -static const sendNoteFunc sendNoteCallback = nullptr; -#endif -#if ! DISTRHO_PLUGIN_WANT_STATE -static const setStateFunc setStateCallback = nullptr; -#endif - -// -------------------------------------------------------------------------------------------------------------------- -// custom v3_tuid compatible type - -typedef uint32_t dpf_tuid[4]; -static_assert(sizeof(v3_tuid) == sizeof(dpf_tuid), "uid size mismatch"); - -// -------------------------------------------------------------------------------------------------------------------- -// Utility functions - -const char* tuid2str(const v3_tuid iid) -{ - if (v3_tuid_match(iid, v3_funknown_iid)) - return "{v3_funknown}"; - if (v3_tuid_match(iid, v3_plugin_base_iid)) - return "{v3_plugin_base}"; - if (v3_tuid_match(iid, v3_plugin_factory_iid)) - return "{v3_plugin_factory}"; - if (v3_tuid_match(iid, v3_plugin_factory_2_iid)) - return "{v3_plugin_factory_2}"; - if (v3_tuid_match(iid, v3_plugin_factory_3_iid)) - return "{v3_plugin_factory_3}"; - if (v3_tuid_match(iid, v3_component_iid)) - return "{v3_component}"; - if (v3_tuid_match(iid, v3_bstream_iid)) - return "{v3_bstream}"; - if (v3_tuid_match(iid, v3_event_list_iid)) - return "{v3_event_list}"; - if (v3_tuid_match(iid, v3_param_value_queue_iid)) - return "{v3_param_value_queue}"; - if (v3_tuid_match(iid, v3_param_changes_iid)) - return "{v3_param_changes}"; - if (v3_tuid_match(iid, v3_process_context_requirements_iid)) - return "{v3_process_context_requirements}"; - if (v3_tuid_match(iid, v3_audio_processor_iid)) - return "{v3_audio_processor}"; - if (v3_tuid_match(iid, v3_component_handler_iid)) - return "{v3_component_handler}"; - if (v3_tuid_match(iid, v3_edit_controller_iid)) - return "{v3_edit_controller}"; - if (v3_tuid_match(iid, v3_plugin_view_iid)) - return "{v3_plugin_view}"; - if (v3_tuid_match(iid, v3_plugin_frame_iid)) - return "{v3_plugin_frame}"; - if (v3_tuid_match(iid, v3_plugin_view_content_scale_steinberg_iid)) - return "{v3_plugin_view_content_scale_steinberg}"; - if (v3_tuid_match(iid, v3_plugin_view_parameter_finder_iid)) - return "{v3_plugin_view_parameter_finder}"; - /* - if (std::memcmp(iid, dpf_tuid_class, sizeof(dpf_tuid)) == 0) - return "{dpf_tuid_class}"; - if (std::memcmp(iid, dpf_tuid_component, sizeof(dpf_tuid)) == 0) - return "{dpf_tuid_component}"; - if (std::memcmp(iid, dpf_tuid_controller, sizeof(dpf_tuid)) == 0) - return "{dpf_tuid_controller}"; - if (std::memcmp(iid, dpf_tuid_processor, sizeof(dpf_tuid)) == 0) - return "{dpf_tuid_processor}"; - if (std::memcmp(iid, dpf_tuid_view, sizeof(dpf_tuid)) == 0) - return "{dpf_tuid_view}"; - */ - - static char buf[46]; - std::snprintf(buf, sizeof(buf), "{0x%08X,0x%08X,0x%08X,0x%08X}", - (uint32_t)d_cconst(iid[ 0], iid[ 1], iid[ 2], iid[ 3]), - (uint32_t)d_cconst(iid[ 4], iid[ 5], iid[ 6], iid[ 7]), - (uint32_t)d_cconst(iid[ 8], iid[ 9], iid[10], iid[11]), - (uint32_t)d_cconst(iid[12], iid[13], iid[14], iid[15])); - return buf; -} - -// -------------------------------------------------------------------------------------------------------------------- - -class UIVst3 : public Thread -{ -public: - UIVst3(const intptr_t winId, const float scaleFactor, const double sampleRate, void* const instancePointer) - : fUI(this, winId, sampleRate, - editParameterCallback, - setParameterCallback, - setStateCallback, - sendNoteCallback, - setSizeCallback, - nullptr, // TODO file request - nullptr, - instancePointer, - scaleFactor) - { - // TESTING awful idea dont reuse - startThread(); - } - - ~UIVst3() override - { - stopThread(5000); - } - - // ------------------------------------------------------------------- - - // TESTING awful idea dont reuse - void run() override - { - while (! shouldThreadExit()) - { - idle(); - d_msleep(50); - } - } - - void idle() - { - /* - for (uint32_t i=0, count = fPlugin->getParameterCount(); i < count; ++i) - { - if (fUiHelper->parameterChecks[i]) - { - fUiHelper->parameterChecks[i] = false; - fUI.parameterChanged(i, fUiHelper->parameterValues[i]); - } - } - */ - - fUI.plugin_idle(); - } - - int16_t getWidth() const - { - return fUI.getWidth(); - } - - int16_t getHeight() const - { - return fUI.getHeight(); - } - - double getScaleFactor() const - { - return fUI.getScaleFactor(); - } - - void notifyScaleFactorChanged(const double scaleFactor) - { - fUI.notifyScaleFactorChanged(scaleFactor); - } - - // TODO dont use this - void setParameterValueFromDSP(const uint32_t index, const float value) - { - fUI.parameterChanged(index, value); - } - - // ---------------------------------------------------------------------------------------------------------------- - // v3_plugin_view interface calls - - void setFrame(v3_plugin_frame* const f) noexcept - { - frame = f; - } - - void setHandler(v3_component_handler_cpp** const h) noexcept - { - handler = h; - } - - // ---------------------------------------------------------------------------------------------------------------- - -protected: - void editParameter(const uint32_t index, const bool started) const - { - DISTRHO_SAFE_ASSERT_RETURN(handler != nullptr,); - - v3_component_handler_cpp* const chandler = *handler; - DISTRHO_SAFE_ASSERT_RETURN(chandler != nullptr,); - - if (started) - chandler->handler.begin_edit(handler, index); - else - chandler->handler.end_edit(handler, index); - } - - void setParameterValue(const uint32_t index, const float realValue) - { - DISTRHO_SAFE_ASSERT_RETURN(handler != nullptr,); - - v3_component_handler_cpp* const chandler = *handler; - DISTRHO_SAFE_ASSERT_RETURN(chandler != nullptr,); - - const double value = vst3->plainParameterToNormalised(index, realValue); - chandler->handler.perform_edit(handler, index, value); - - // TODO send change to DSP side? - } - - void setSize(uint width, uint height) - { -# ifdef DISTRHO_OS_MAC - const double scaleFactor = fUI.getScaleFactor(); - width /= scaleFactor; - height /= scaleFactor; -# endif - if (frame == nullptr) - return; - - v3_view_rect rect = {}; - rect.right = width; - rect.bottom = height; - (void)rect; - // frame->resize_view(nullptr, uivst3, &rect); - } - -# if DISTRHO_PLUGIN_WANT_MIDI_INPUT - void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity) - { - uint8_t midiData[3]; - midiData[0] = (velocity != 0 ? 0x90 : 0x80) | channel; - midiData[1] = note; - midiData[2] = velocity; - fNotesRingBuffer.writeCustomData(midiData, 3); - fNotesRingBuffer.commitWrite(); - } -# endif - -# if DISTRHO_PLUGIN_WANT_STATE - void setState(const char* const key, const char* const value) - { - // fUiHelper->setStateFromUI(key, value); - } -# endif - -private: - // VST3 stuff - v3_plugin_frame* frame; - v3_component_handler_cpp** handler = nullptr; - - // Plugin UI - UIExporter fUI; - - // ------------------------------------------------------------------- - // Callbacks - - #define handlePtr ((UIVst3*)ptr) - - static void editParameterCallback(void* ptr, uint32_t index, bool started) - { - handlePtr->editParameter(index, started); - } - - static void setParameterCallback(void* ptr, uint32_t rindex, float value) - { - handlePtr->setParameterValue(rindex, value); - } - - static void setSizeCallback(void* ptr, uint width, uint height) - { - handlePtr->setSize(width, height); - } - -# if DISTRHO_PLUGIN_WANT_MIDI_INPUT - static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity) - { - handlePtr->sendNote(channel, note, velocity); - } -# endif - -# if DISTRHO_PLUGIN_WANT_STATE - static void setStateCallback(void* ptr, const char* key, const char* value) - { - handlePtr->setState(key, value); - } -# endif - - #undef handlePtr -}; - -// -------------------------------------------------------------------------------------------------------------------- -// dpf_plugin_view_content_scale - -struct v3_plugin_view_content_scale_steinberg_cpp : v3_funknown { - v3_plugin_view_content_scale_steinberg scale; -}; - -struct dpf_plugin_view_scale : v3_plugin_view_content_scale_steinberg_cpp { - std::atomic<int> refcounter; - ScopedPointer<dpf_plugin_view_scale>* self; - ScopedPointer<UIVst3>& uivst3; - float lastScaleFactor = 0.0f; - - dpf_plugin_view_scale(ScopedPointer<dpf_plugin_view_scale>* s, ScopedPointer<UIVst3>& v) - : refcounter(1), - self(s), - uivst3(v) - { - static const uint8_t* kSupportedInterfaces[] = { - v3_funknown_iid, - v3_plugin_view_content_scale_steinberg_iid - }; - - // ------------------------------------------------------------------------------------------------------------ - // v3_funknown - - query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result - { - d_stdout("dpf_plugin_view_scale::query_interface => %p %s %p", self, tuid2str(iid), iface); - *iface = NULL; - DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); - - for (const uint8_t* interface_iid : kSupportedInterfaces) - { - if (v3_tuid_match(interface_iid, iid)) - { - *iface = self; - return V3_OK; - } - } - - return V3_NO_INTERFACE; - }; - - ref = []V3_API(void* self) -> uint32_t - { - d_stdout("dpf_plugin_view_scale::ref => %p", self); - dpf_plugin_view_scale* const scale = *(dpf_plugin_view_scale**)self; - DISTRHO_SAFE_ASSERT_RETURN(scale != nullptr, 0); - - return ++scale->refcounter; - }; - - unref = []V3_API(void* self) -> uint32_t - { - d_stdout("dpf_plugin_view_scale::unref => %p", self); - dpf_plugin_view_scale* const scale = *(dpf_plugin_view_scale**)self; - DISTRHO_SAFE_ASSERT_RETURN(scale != nullptr, 0); - - if (const int refcounter = --scale->refcounter) - return refcounter; - - *(dpf_plugin_view_scale**)self = nullptr; - *scale->self = nullptr; - return 0; - }; - - // ------------------------------------------------------------------------------------------------------------ - // v3_plugin_view_content_scale_steinberg - - scale.set_content_scale_factor = []V3_API(void* self, float factor) -> v3_result - { - d_stdout("dpf_plugin_view::set_content_scale_factor => %p %f", self, factor); - dpf_plugin_view_scale* const scale = *(dpf_plugin_view_scale**)self; - DISTRHO_SAFE_ASSERT_RETURN(scale != nullptr, V3_NOT_INITIALISED); - - if (UIVst3* const uivst3 = scale->uivst3) - if (d_isNotZero(scale->lastScaleFactor) && d_isNotEqual(scale->lastScaleFactor, factor)) - uivst3->notifyScaleFactorChanged(factor); - - scale->lastScaleFactor = factor; - return V3_OK; - }; - } -}; - -// -------------------------------------------------------------------------------------------------------------------- -// dpf_plugin_view - -struct v3_plugin_view_cpp : v3_funknown { - v3_plugin_view view; -}; - -struct dpf_plugin_view : v3_plugin_view_cpp { - std::atomic<int> refcounter; - ScopedPointer<dpf_plugin_view>* self; - ScopedPointer<dpf_plugin_view_scale> scale; - ScopedPointer<UIVst3> uivst3; - // cached values - v3_component_handler_cpp** handler = nullptr; - v3_plugin_frame* hostframe = nullptr; - - dpf_plugin_view(ScopedPointer<dpf_plugin_view>* s) - : refcounter(1), - self(s) - { - static const uint8_t* kSupportedInterfacesBase[] = { - v3_funknown_iid, - v3_plugin_view_iid - }; - - // ------------------------------------------------------------------------------------------------------------ - // v3_funknown - - query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result - { - d_stdout("dpf_plugin_view::query_interface => %p %s %p", self, tuid2str(iid), iface); - *iface = NULL; - DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); - - for (const uint8_t* interface_iid : kSupportedInterfacesBase) - { - if (v3_tuid_match(interface_iid, iid)) - { - *iface = self; - return V3_OK; - } - } - - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NO_INTERFACE); - - if (v3_tuid_match(v3_plugin_view_content_scale_steinberg_iid, iid)) - { - if (view->scale == nullptr) - view->scale = new dpf_plugin_view_scale(&view->scale, view->uivst3); - *iface = &view->scale; - return V3_OK; - } - - return V3_NO_INTERFACE; - }; - - ref = []V3_API(void* self) -> uint32_t - { - d_stdout("dpf_plugin_view::ref => %p", self); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, 0); - - return ++view->refcounter; - }; - - unref = []V3_API(void* self) -> uint32_t - { - d_stdout("dpf_plugin_view::unref => %p", self); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, 0); - - if (const int refcounter = --view->refcounter) - return refcounter; - - *(dpf_plugin_view**)self = nullptr; - *view->self = nullptr; - return 0; - }; - - // ------------------------------------------------------------------------------------------------------------ - // v3_plugin_view - - view.is_platform_type_supported = []V3_API(void* self, const char* platform_type) -> v3_result - { - d_stdout("dpf_plugin_view::is_platform_type_supported => %p %s", self, platform_type); - const char* const supported[] = { -#ifdef _WIN32 - V3_VIEW_PLATFORM_TYPE_HWND, -#elif defined(__APPLE__) - V3_VIEW_PLATFORM_TYPE_NSVIEW, -#else - V3_VIEW_PLATFORM_TYPE_X11, -#endif - }; - - for (size_t i=0; i<sizeof(supported)/sizeof(supported[0]); ++i) - { - if (std::strcmp(supported[i], platform_type)) - return V3_OK; - } - - return V3_NOT_IMPLEMENTED; - }; - - view.attached = []V3_API(void* self, void* parent, const char* platform_type) -> v3_result - { - d_stdout("dpf_plugin_view::attached => %p %p %s", self, parent, platform_type); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); - DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 == nullptr, V3_INVALID_ARG); - - const double scaleFactor = view->scale != nullptr ? view->scale->lastScaleFactor : 0.0; - view->uivst3 = new UIVst3(view->vst3, view->hostframe, (uintptr_t)parent, scaleFactor); - view->uivst3->setHandler(view->handler); - return V3_OK; - }; - - view.removed = []V3_API(void* self) -> v3_result - { - d_stdout("dpf_plugin_view::removed => %p", self); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); - DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_INVALID_ARG); - view->uivst3 = nullptr; - return V3_OK; - }; - - view.on_wheel = []V3_API(void* self, float distance) -> v3_result - { - d_stdout("dpf_plugin_view::on_wheel => %p %f", self, distance); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); - DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_NOT_INITIALISED); - return V3_NOT_IMPLEMENTED; - }; - - view.on_key_down = []V3_API(void* self, int16_t key_char, int16_t key_code, int16_t modifiers) -> v3_result - { - d_stdout("dpf_plugin_view::on_key_down => %p %i %i %i", self, key_char, key_code, modifiers); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); - DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_NOT_INITIALISED); - return V3_NOT_IMPLEMENTED; - }; - - view.on_key_up = []V3_API(void* self, int16_t key_char, int16_t key_code, int16_t modifiers) -> v3_result - { - d_stdout("dpf_plugin_view::on_key_up => %p %i %i %i", self, key_char, key_code, modifiers); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); - DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_NOT_INITIALISED); - return V3_NOT_IMPLEMENTED; - }; - - view.get_size = []V3_API(void* self, v3_view_rect* rect) -> v3_result - { - d_stdout("dpf_plugin_view::get_size => %p", self); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); - - std::memset(rect, 0, sizeof(v3_view_rect)); - - if (view->uivst3 != nullptr) - { - rect->right = view->uivst3->getWidth(); - rect->bottom = view->uivst3->getHeight(); -# ifdef DISTRHO_OS_MAC - const double scaleFactor = view->uivst3->getScaleFactor(); - rect->right /= scaleFactor; - rect->bottom /= scaleFactor; -# endif - } - else - { - const double scaleFactor = view->scale != nullptr ? view->scale->lastScaleFactor : 0.0; - UIExporter tmpUI(nullptr, 0, view->vst3->getSampleRate(), - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - view->vst3->getInstancePointer(), scaleFactor); - rect->right = tmpUI.getWidth(); - rect->bottom = tmpUI.getHeight(); -# ifdef DISTRHO_OS_MAC - const double scaleFactor = tmpUI.getScaleFactor(); - rect->right /= scaleFactor; - rect->bottom /= scaleFactor; -# endif - tmpUI.quit(); - } - - return V3_NOT_IMPLEMENTED; - }; - - view.set_size = []V3_API(void* self, v3_view_rect*) -> v3_result - { - d_stdout("dpf_plugin_view::set_size => %p", self); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); - DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_NOT_INITIALISED); - return V3_NOT_IMPLEMENTED; - }; - - view.on_focus = []V3_API(void* self, v3_bool state) -> v3_result - { - d_stdout("dpf_plugin_view::on_focus => %p %u", self, state); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); - DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_NOT_INITIALISED); - return V3_NOT_IMPLEMENTED; - }; - - view.set_frame = []V3_API(void* self, v3_plugin_frame* frame) -> v3_result - { - d_stdout("dpf_plugin_view::set_frame => %p", self); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); - - view->hostframe = frame; - - if (view->uivst3 != nullptr) - view->uivst3->setFrame(frame); - - return V3_OK; - }; - - view.can_resize = []V3_API(void* self) -> v3_result - { - d_stdout("dpf_plugin_view::can_resize => %p", self); -#if DISTRHO_UI_USER_RESIZABLE - return V3_OK; -#else - return V3_NOT_IMPLEMENTED; -#endif - }; - - view.check_size_constraint = []V3_API(void* self, v3_view_rect*) -> v3_result - { - d_stdout("dpf_plugin_view::check_size_constraint => %p", self); - return V3_NOT_IMPLEMENTED; - }; - } -}; - -// -------------------------------------------------------------------------------------------------------------------- - -END_NAMESPACE_DISTRHO diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp @@ -291,6 +291,19 @@ public: } // ---------------------------------------------------------------------------------------------------------------- + // stuff called for UI creation + + void* getInstancePointer() const noexcept + { + return fPlugin.getInstancePointer(); + } + + double getSampleRate() const noexcept + { + return fPlugin.getSampleRate(); + } + + // ---------------------------------------------------------------------------------------------------------------- // v3_component interface calls int32_t getBusCount(const int32_t mediaType, const int32_t busDirection) const noexcept @@ -1127,6 +1140,7 @@ private: TimePosition fTimePosition; #endif +#if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST bool requestParameterValueChange(const uint32_t index, const float value) { DISTRHO_SAFE_ASSERT_RETURN(fComponentHandler != nullptr, false); @@ -1142,7 +1156,6 @@ private: return ret; } -#if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST static bool requestParameterValueChangeCallback(void* const ptr, const uint32_t index, const float value) { return ((PluginVst3*)ptr)->requestParameterValueChange(index, value); @@ -1211,6 +1224,13 @@ private: }; +#if DISTRHO_PLUGIN_HAS_UI +// -------------------------------------------------------------------------------------------------------------------- +// dpf_plugin_view_create (called from DSP side) + +v3_funknown** dpf_plugin_view_create(void* instancePointer, double sampleRate); +#endif + // -------------------------------------------------------------------------------------------------------------------- // dpf_edit_controller @@ -1511,15 +1531,14 @@ struct dpf_edit_controller : v3_edit_controller_cpp { dpf_edit_controller* const controller = *(dpf_edit_controller**)self; DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, nullptr); - return nullptr; - -// if (controller->view == nullptr) -// { -// controller->view = new dpf_plugin_view(&controller->view, controller->vst3); -// controller->view->handler = controller->handler; -// } + PluginVst3* const vst3 = controller->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, nullptr); -// return (v3_plugin_view**)&controller->view; +#if DISTRHO_PLUGIN_HAS_UI + return (v3_plugin_view**)dpf_plugin_view_create(vst3->getInstancePointer(), vst3->getSampleRate()); +#else + return nullptr; +#endif }; } }; diff --git a/distrho/src/DistrhoUIVST3.cpp b/distrho/src/DistrhoUIVST3.cpp @@ -0,0 +1,718 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "DistrhoUIInternal.hpp" + +#include "travesty/audio_processor.h" +#include "travesty/component.h" +#include "travesty/edit_controller.h" +#include "travesty/factory.h" +#include "travesty/view.h" + +#include <atomic> + +// TESTING awful idea dont reuse +#include "../extra/Thread.hpp" + +// #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI +// # undef DISTRHO_PLUGIN_HAS_UI +// # define DISTRHO_PLUGIN_HAS_UI 0 +// #endif +// +// #if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI +// # undef DISTRHO_PLUGIN_HAS_UI +// # define DISTRHO_PLUGIN_HAS_UI 0 +// #endif +// +// #undef DISTRHO_PLUGIN_HAS_UI +// #define DISTRHO_PLUGIN_HAS_UI 1 + +// #if DISTRHO_PLUGIN_HAS_UI +# include "DistrhoUIInternal.hpp" +// #endif + +// -------------------------------------------------------------------------------------------------------------------- + +struct v3_component_handler_cpp : v3_funknown { + v3_component_handler handler; +}; + +START_NAMESPACE_DISTRHO + +// -------------------------------------------------------------------------------------------------------------------- + +#if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT +static const sendNoteFunc sendNoteCallback = nullptr; +#endif +#if ! DISTRHO_PLUGIN_WANT_STATE +static const setStateFunc setStateCallback = nullptr; +#endif + +// -------------------------------------------------------------------------------------------------------------------- +// custom v3_tuid compatible type + +typedef uint32_t dpf_tuid[4]; +static_assert(sizeof(v3_tuid) == sizeof(dpf_tuid), "uid size mismatch"); + +// -------------------------------------------------------------------------------------------------------------------- +// Utility functions + +const char* tuid2str(const v3_tuid iid) +{ + if (v3_tuid_match(iid, v3_funknown_iid)) + return "{v3_funknown}"; + if (v3_tuid_match(iid, v3_plugin_base_iid)) + return "{v3_plugin_base}"; + if (v3_tuid_match(iid, v3_plugin_factory_iid)) + return "{v3_plugin_factory}"; + if (v3_tuid_match(iid, v3_plugin_factory_2_iid)) + return "{v3_plugin_factory_2}"; + if (v3_tuid_match(iid, v3_plugin_factory_3_iid)) + return "{v3_plugin_factory_3}"; + if (v3_tuid_match(iid, v3_component_iid)) + return "{v3_component}"; + if (v3_tuid_match(iid, v3_bstream_iid)) + return "{v3_bstream}"; + if (v3_tuid_match(iid, v3_event_list_iid)) + return "{v3_event_list}"; + if (v3_tuid_match(iid, v3_param_value_queue_iid)) + return "{v3_param_value_queue}"; + if (v3_tuid_match(iid, v3_param_changes_iid)) + return "{v3_param_changes}"; + if (v3_tuid_match(iid, v3_process_context_requirements_iid)) + return "{v3_process_context_requirements}"; + if (v3_tuid_match(iid, v3_audio_processor_iid)) + return "{v3_audio_processor}"; + if (v3_tuid_match(iid, v3_component_handler_iid)) + return "{v3_component_handler}"; + if (v3_tuid_match(iid, v3_edit_controller_iid)) + return "{v3_edit_controller}"; + if (v3_tuid_match(iid, v3_plugin_view_iid)) + return "{v3_plugin_view}"; + if (v3_tuid_match(iid, v3_plugin_frame_iid)) + return "{v3_plugin_frame}"; + if (v3_tuid_match(iid, v3_plugin_view_content_scale_steinberg_iid)) + return "{v3_plugin_view_content_scale_steinberg}"; + if (v3_tuid_match(iid, v3_plugin_view_parameter_finder_iid)) + return "{v3_plugin_view_parameter_finder}"; + /* + if (std::memcmp(iid, dpf_tuid_class, sizeof(dpf_tuid)) == 0) + return "{dpf_tuid_class}"; + if (std::memcmp(iid, dpf_tuid_component, sizeof(dpf_tuid)) == 0) + return "{dpf_tuid_component}"; + if (std::memcmp(iid, dpf_tuid_controller, sizeof(dpf_tuid)) == 0) + return "{dpf_tuid_controller}"; + if (std::memcmp(iid, dpf_tuid_processor, sizeof(dpf_tuid)) == 0) + return "{dpf_tuid_processor}"; + if (std::memcmp(iid, dpf_tuid_view, sizeof(dpf_tuid)) == 0) + return "{dpf_tuid_view}"; + */ + + static char buf[46]; + std::snprintf(buf, sizeof(buf), "{0x%08X,0x%08X,0x%08X,0x%08X}", + (uint32_t)d_cconst(iid[ 0], iid[ 1], iid[ 2], iid[ 3]), + (uint32_t)d_cconst(iid[ 4], iid[ 5], iid[ 6], iid[ 7]), + (uint32_t)d_cconst(iid[ 8], iid[ 9], iid[10], iid[11]), + (uint32_t)d_cconst(iid[12], iid[13], iid[14], iid[15])); + return buf; +} + +// -------------------------------------------------------------------------------------------------------------------- + +class UIVst3 : public Thread +{ +public: + UIVst3(const intptr_t winId, const float scaleFactor, const double sampleRate, void* const instancePointer) + : fUI(this, winId, sampleRate, + editParameterCallback, + setParameterCallback, + setStateCallback, + sendNoteCallback, + setSizeCallback, + nullptr, // TODO file request + nullptr, + instancePointer, + scaleFactor), + fFrame(nullptr), + fScaleFactor(scaleFactor) + { + // TESTING awful idea dont reuse + startThread(); + } + + ~UIVst3() override + { + stopThread(5000); + } + + // TESTING awful idea dont reuse + void run() override + { + while (! shouldThreadExit()) + { + fUI.plugin_idle(); + d_msleep(50); + } + } + +// // TODO dont use this +// void setParameterValueFromDSP(const uint32_t index, const float value) +// { +// fUI.parameterChanged(index, value); +// } + +// void setHandler(v3_component_handler_cpp** const h) noexcept +// { +// handler = h; +// } + + // ---------------------------------------------------------------------------------------------------------------- + // v3_plugin_view interface calls + + v3_result onWheel(float /*distance*/) + { + // TODO + return V3_NOT_IMPLEMENTED; + }; + + v3_result onKeyDown(int16_t /*key_char*/, int16_t /*key_code*/, int16_t /*modifiers*/) + { + // TODO + return V3_NOT_IMPLEMENTED; + }; + + v3_result onKeyUp(int16_t /*key_char*/, int16_t /*key_code*/, int16_t /*modifiers*/) + { + // TODO + return V3_NOT_IMPLEMENTED; + }; + + v3_result getSize(v3_view_rect* const rect) const noexcept + { + std::memset(rect, 0, sizeof(v3_view_rect)); + + rect->right = fUI.getWidth(); + rect->bottom = fUI.getHeight(); +#ifdef DISTRHO_OS_MAC + const double scaleFactor = fUI.getScaleFactor(); + rect->right /= scaleFactor; + rect->bottom /= scaleFactor; +#endif + + return V3_OK; + } + + v3_result setSize(v3_view_rect* const /*rect*/) + { + // TODO + return V3_NOT_IMPLEMENTED; + } + + v3_result onFocus(const bool /*state*/) + { + // TODO + return V3_NOT_IMPLEMENTED; + } + + v3_result setFrame(v3_plugin_frame* const frame) noexcept + { + fFrame = frame; + return V3_OK; + } + + v3_result checkSizeConstraint(v3_view_rect* const /*rect*/) + { + // TODO + return V3_NOT_IMPLEMENTED; + } + + // ---------------------------------------------------------------------------------------------------------------- + // v3_plugin_view_content_scale_steinberg interface calls + + v3_result setContentScaleFactor(const float factor) + { + if (d_isEqual(fScaleFactor, factor)) + return V3_OK; + + fScaleFactor = factor; + fUI.notifyScaleFactorChanged(factor); + return V3_OK; + } + + // ---------------------------------------------------------------------------------------------------------------- + +private: + // Plugin UI + UIExporter fUI; + + // VST3 stuff + v3_plugin_frame* fFrame; + // v3_component_handler_cpp** handler = nullptr; + + // Temporary data + float fScaleFactor; + + void editParameter(const uint32_t /*index*/, const bool /*started*/) const + { +// DISTRHO_SAFE_ASSERT_RETURN(handler != nullptr,); +// +// v3_component_handler_cpp* const chandler = *handler; +// DISTRHO_SAFE_ASSERT_RETURN(chandler != nullptr,); +// +// if (started) +// chandler->handler.begin_edit(handler, index); +// else +// chandler->handler.end_edit(handler, index); + } + + static void editParameterCallback(void* ptr, uint32_t index, bool started) + { + ((UIVst3*)ptr)->editParameter(index, started); + } + + void setParameterValue(const uint32_t /*index*/, const float /*realValue*/) + { +// DISTRHO_SAFE_ASSERT_RETURN(handler != nullptr,); +// +// v3_component_handler_cpp* const chandler = *handler; +// DISTRHO_SAFE_ASSERT_RETURN(chandler != nullptr,); + +// const double value = vst3->plainParameterToNormalised(index, realValue); +// chandler->handler.perform_edit(handler, index, value); + + // TODO send change to DSP side? + } + + static void setParameterCallback(void* ptr, uint32_t rindex, float value) + { + ((UIVst3*)ptr)->setParameterValue(rindex, value); + } + + void setSize(uint /*width*/, uint /*height*/) + { +// #ifdef DISTRHO_OS_MAC +// const double scaleFactor = fUI.getScaleFactor(); +// width /= scaleFactor; +// height /= scaleFactor; +// #endif +// if (frame == nullptr) +// return; +// +// v3_view_rect rect = {}; +// rect.right = width; +// rect.bottom = height; +// (void)rect; +// // frame->resize_view(nullptr, uivst3, &rect); + } + + static void setSizeCallback(void* ptr, uint width, uint height) + { + ((UIVst3*)ptr)->setSize(width, height); + } + +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT + void sendNote(const uint8_t /*channel*/, const uint8_t /*note*/, const uint8_t /*velocity*/) + { +// uint8_t midiData[3]; +// midiData[0] = (velocity != 0 ? 0x90 : 0x80) | channel; +// midiData[1] = note; +// midiData[2] = velocity; +// fNotesRingBuffer.writeCustomData(midiData, 3); +// fNotesRingBuffer.commitWrite(); + } + + static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity) + { + ((UIVst3*)ptr)->sendNote(channel, note, velocity); + } +#endif + +#if DISTRHO_PLUGIN_WANT_STATE + void setState(const char* const /*key*/, const char* const /*value*/) + { + // fUiHelper->setStateFromUI(key, value); + } + + static void setStateCallback(void* ptr, const char* key, const char* value) + { + ((UIVst3*)ptr)->setState(key, value); + } +#endif + + #undef handlePtr +}; + +// -------------------------------------------------------------------------------------------------------------------- +// dpf_plugin_view_content_scale + +struct v3_plugin_view_content_scale_steinberg_cpp : v3_funknown { + v3_plugin_view_content_scale_steinberg scale; +}; + +struct dpf_plugin_view_scale : v3_plugin_view_content_scale_steinberg_cpp { + std::atomic<int> refcounter; + ScopedPointer<dpf_plugin_view_scale>* self; + ScopedPointer<UIVst3>& uivst3; + // cached values + float scaleFactor; + + dpf_plugin_view_scale(ScopedPointer<dpf_plugin_view_scale>* s, ScopedPointer<UIVst3>& v) + : refcounter(1), + self(s), + uivst3(v), + scaleFactor(0.0f) + { + static const uint8_t* kSupportedInterfaces[] = { + v3_funknown_iid, + v3_plugin_view_content_scale_steinberg_iid + }; + + // ------------------------------------------------------------------------------------------------------------ + // v3_funknown + + query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result + { + d_stdout("dpf_plugin_view_scale::query_interface => %p %s %p", self, tuid2str(iid), iface); + *iface = NULL; + DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); + + for (const uint8_t* interface_iid : kSupportedInterfaces) + { + if (v3_tuid_match(interface_iid, iid)) + { + *iface = self; + return V3_OK; + } + } + + return V3_NO_INTERFACE; + }; + + ref = []V3_API(void* self) -> uint32_t + { + d_stdout("dpf_plugin_view_scale::ref => %p", self); + dpf_plugin_view_scale* const scale = *(dpf_plugin_view_scale**)self; + DISTRHO_SAFE_ASSERT_RETURN(scale != nullptr, 0); + + return ++scale->refcounter; + }; + + unref = []V3_API(void* self) -> uint32_t + { + d_stdout("dpf_plugin_view_scale::unref => %p", self); + dpf_plugin_view_scale* const scale = *(dpf_plugin_view_scale**)self; + DISTRHO_SAFE_ASSERT_RETURN(scale != nullptr, 0); + + if (const int refcounter = --scale->refcounter) + return refcounter; + + *(dpf_plugin_view_scale**)self = nullptr; + *scale->self = nullptr; + return 0; + }; + + // ------------------------------------------------------------------------------------------------------------ + // v3_plugin_view_content_scale_steinberg + + scale.set_content_scale_factor = []V3_API(void* self, float factor) -> v3_result + { + d_stdout("dpf_plugin_view::set_content_scale_factor => %p %f", self, factor); + dpf_plugin_view_scale* const scale = *(dpf_plugin_view_scale**)self; + DISTRHO_SAFE_ASSERT_RETURN(scale != nullptr, V3_NOT_INITIALISED); + + scale->scaleFactor = factor; + + if (UIVst3* const uivst3 = scale->uivst3) + return uivst3->setContentScaleFactor(factor); + + return V3_NOT_INITIALISED; + }; + } +}; + +// -------------------------------------------------------------------------------------------------------------------- +// dpf_plugin_view + +struct v3_plugin_view_cpp : v3_funknown { + v3_plugin_view view; +}; + +struct dpf_plugin_view : v3_plugin_view_cpp { + std::atomic<int> refcounter; + ScopedPointer<dpf_plugin_view>* self; + ScopedPointer<dpf_plugin_view_scale> scale; + ScopedPointer<UIVst3> uivst3; + // cached values + void* const instancePointer; + double sampleRate; +// v3_component_handler_cpp** handler = nullptr; + v3_plugin_frame* frame = nullptr; + + dpf_plugin_view(ScopedPointer<dpf_plugin_view>* s, void* const instance, const double sr) + : refcounter(1), + self(s), + instancePointer(instance), + sampleRate(sr) + { + static const uint8_t* kSupportedInterfacesBase[] = { + v3_funknown_iid, + v3_plugin_view_iid + }; + + static const char* const kSupportedPlatforms[] = { +#ifdef _WIN32 + V3_VIEW_PLATFORM_TYPE_HWND, +#elif defined(__APPLE__) + V3_VIEW_PLATFORM_TYPE_NSVIEW, +#else + V3_VIEW_PLATFORM_TYPE_X11, +#endif + }; + + // ------------------------------------------------------------------------------------------------------------ + // v3_funknown + + query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result + { + d_stdout("dpf_plugin_view::query_interface => %p %s %p", self, tuid2str(iid), iface); + *iface = NULL; + DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); + + for (const uint8_t* interface_iid : kSupportedInterfacesBase) + { + if (v3_tuid_match(interface_iid, iid)) + { + *iface = self; + return V3_OK; + } + } + + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NO_INTERFACE); + + if (v3_tuid_match(v3_plugin_view_content_scale_steinberg_iid, iid)) + { + if (view->scale == nullptr) + view->scale = new dpf_plugin_view_scale(&view->scale, view->uivst3); + *iface = &view->scale; + return V3_OK; + } + + return V3_NO_INTERFACE; + }; + + ref = []V3_API(void* self) -> uint32_t + { + d_stdout("dpf_plugin_view::ref => %p", self); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, 0); + + return ++view->refcounter; + }; + + unref = []V3_API(void* self) -> uint32_t + { + d_stdout("dpf_plugin_view::unref => %p", self); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, 0); + + if (const int refcounter = --view->refcounter) + return refcounter; + + *(dpf_plugin_view**)self = nullptr; + *view->self = nullptr; + return 0; + }; + + // ------------------------------------------------------------------------------------------------------------ + // v3_plugin_view + + view.is_platform_type_supported = []V3_API(void* self, const char* platform_type) -> v3_result + { + d_stdout("dpf_plugin_view::is_platform_type_supported => %p %s", self, platform_type); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + + for (size_t i=0; i<ARRAY_SIZE(kSupportedPlatforms); ++i) + { + if (std::strcmp(kSupportedPlatforms[i], platform_type) == 0) + return V3_OK; + } + + return V3_NOT_IMPLEMENTED; + }; + + view.attached = []V3_API(void* self, void* parent, const char* platform_type) -> v3_result + { + d_stdout("dpf_plugin_view::attached => %p %p %s", self, parent, platform_type); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 == nullptr, V3_INVALID_ARG); + + for (size_t i=0; i<ARRAY_SIZE(kSupportedPlatforms); ++i) + { + if (std::strcmp(kSupportedPlatforms[i], platform_type) == 0) + { + const float scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f; + view->uivst3 = new UIVst3((uintptr_t)parent, scaleFactor, view->sampleRate, view->instancePointer); + view->uivst3->setFrame(view->frame); + // view->uivst3->setHandler(view->handler); + return V3_OK; + } + } + + return V3_NOT_IMPLEMENTED; + }; + + view.removed = []V3_API(void* self) -> v3_result + { + d_stdout("dpf_plugin_view::removed => %p", self); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_INVALID_ARG); + view->uivst3 = nullptr; + return V3_OK; + }; + + view.on_wheel = []V3_API(void* self, float distance) -> v3_result + { + d_stdout("dpf_plugin_view::on_wheel => %p %f", self, distance); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + + UIVst3* const uivst3 = view->uivst3; + DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); + + return uivst3->onWheel(distance); + }; + + view.on_key_down = []V3_API(void* self, int16_t key_char, int16_t key_code, int16_t modifiers) -> v3_result + { + d_stdout("dpf_plugin_view::on_key_down => %p %i %i %i", self, key_char, key_code, modifiers); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + + UIVst3* const uivst3 = view->uivst3; + DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); + + return uivst3->onKeyDown(key_char, key_code, modifiers); + }; + + view.on_key_up = []V3_API(void* self, int16_t key_char, int16_t key_code, int16_t modifiers) -> v3_result + { + d_stdout("dpf_plugin_view::on_key_up => %p %i %i %i", self, key_char, key_code, modifiers); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + + UIVst3* const uivst3 = view->uivst3; + DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); + + return uivst3->onKeyUp(key_char, key_code, modifiers); + }; + + view.get_size = []V3_API(void* self, v3_view_rect* rect) -> v3_result + { + d_stdout("dpf_plugin_view::get_size => %p", self); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + + // special case: allow UI to not be attached yet, as a way to get size before window creation + + if (UIVst3* const uivst3 = view->uivst3) + return uivst3->getSize(rect); + + const float scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f; + const UIVst3 uivst3(0, scaleFactor, view->sampleRate, view->instancePointer); + return uivst3.getSize(rect); + }; + + view.set_size = []V3_API(void* self, v3_view_rect* rect) -> v3_result + { + d_stdout("dpf_plugin_view::set_size => %p %p", self, rect); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + + UIVst3* const uivst3 = view->uivst3; + DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); + + return uivst3->setSize(rect); + }; + + view.on_focus = []V3_API(void* self, v3_bool state) -> v3_result + { + d_stdout("dpf_plugin_view::on_focus => %p %u", self, state); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + + UIVst3* const uivst3 = view->uivst3; + DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); + + return uivst3->onFocus(state); + }; + + view.set_frame = []V3_API(void* self, v3_plugin_frame* frame) -> v3_result + { + d_stdout("dpf_plugin_view::set_frame => %p %o", self, frame); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + + view->frame = frame; + + if (UIVst3* const uivst3 = view->uivst3) + return uivst3->setFrame(frame); + + return V3_NOT_INITIALISED; + }; + + view.can_resize = []V3_API(void* self) -> v3_result + { + d_stdout("dpf_plugin_view::can_resize => %p", self); +#if DISTRHO_UI_USER_RESIZABLE + return V3_OK; +#else + return V3_NOT_IMPLEMENTED; +#endif + }; + + view.check_size_constraint = []V3_API(void* self, v3_view_rect* rect) -> v3_result + { + d_stdout("dpf_plugin_view::check_size_constraint => %p %p", self, rect); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + + UIVst3* const uivst3 = view->uivst3; + DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); + + return uivst3->checkSizeConstraint(rect); + }; + } +}; + +// -------------------------------------------------------------------------------------------------------------------- +// dpf_plugin_view_create (called from DSP side) + +v3_funknown** dpf_plugin_view_create(void* instancePointer, double sampleRate); + +v3_funknown** dpf_plugin_view_create(void* const instancePointer, const double sampleRate) +{ + ScopedPointer<dpf_plugin_view>* const viewptr = new ScopedPointer<dpf_plugin_view>; + *viewptr = new dpf_plugin_view(viewptr, instancePointer, sampleRate); + return (v3_funknown**)viewptr; +} + +// -------------------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO