Mercurial > hg > pub > prymula > com
diff DPF-Prymula-audioplugins/dpf/distrho/src/DistrhoUIPrivateData.hpp @ 3:84e66ea83026
DPF-Prymula-audioplugins-0.231015-2
author | prymula <prymula76@outlook.com> |
---|---|
date | Mon, 16 Oct 2023 21:53:34 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DPF-Prymula-audioplugins/dpf/distrho/src/DistrhoUIPrivateData.hpp Mon Oct 16 21:53:34 2023 +0200 @@ -0,0 +1,514 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2022 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. + */ + +#ifndef DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED +#define DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED + +#include "../DistrhoUI.hpp" + +#ifdef DISTRHO_PLUGIN_TARGET_VST3 +# include "DistrhoPluginVST.hpp" +#endif + +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI +# include "../extra/Sleep.hpp" +// TODO import and use file browser here +#else +# include "../../dgl/src/ApplicationPrivateData.hpp" +# include "../../dgl/src/WindowPrivateData.hpp" +# include "../../dgl/src/pugl.hpp" +#endif + +#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI +# include <map> +# include <string> +#endif + +#if defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_DSSI) +# define DISTRHO_UI_IS_STANDALONE 1 +#else +# define DISTRHO_UI_IS_STANDALONE 0 +#endif + +#if defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP) +# define DISTRHO_UI_USES_SIZE_REQUEST true +#else +# define DISTRHO_UI_USES_SIZE_REQUEST false +#endif + +#ifdef DISTRHO_PLUGIN_TARGET_VST2 +# undef DISTRHO_UI_USER_RESIZABLE +# define DISTRHO_UI_USER_RESIZABLE 0 +#endif + +START_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------- +// Plugin Application, will set class name based on plugin details + +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI +struct PluginApplication +{ + DGL_NAMESPACE::IdleCallback* idleCallback; + UI* ui; + + explicit PluginApplication(const char*) + : idleCallback(nullptr), + ui(nullptr) {} + + void addIdleCallback(DGL_NAMESPACE::IdleCallback* const cb) + { + DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(idleCallback == nullptr,); + + idleCallback = cb; + } + + bool isQuitting() const noexcept + { + return ui->isQuitting(); + } + + bool isStandalone() const noexcept + { + return DISTRHO_UI_IS_STANDALONE; + } + + void exec() + { + while (ui->isRunning()) + { + d_msleep(30); + idleCallback->idleCallback(); + } + + if (! ui->isQuitting()) + ui->close(); + } + + // these are not needed + void idle() {} + void quit() {} + void triggerIdleCallbacks() {} + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) +}; +#else +class PluginApplication : public DGL_NAMESPACE::Application +{ +public: + explicit PluginApplication(const char* className) + : DGL_NAMESPACE::Application(DISTRHO_UI_IS_STANDALONE) + { + #if defined(__MOD_DEVICES__) || !defined(__EMSCRIPTEN__) + if (className == nullptr) + { + className = ( + #ifdef DISTRHO_PLUGIN_BRAND + DISTRHO_PLUGIN_BRAND + #else + DISTRHO_MACRO_AS_STRING(DISTRHO_NAMESPACE) + #endif + "-" DISTRHO_PLUGIN_NAME + ); + } + setClassName(className); + #else + // unused + (void)className; + #endif + } + + void triggerIdleCallbacks() + { + pData->triggerIdleCallbacks(); + } + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) +}; +#endif + +// ----------------------------------------------------------------------- +// Plugin Window, will pass some Window events to UI + +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI +class PluginWindow +{ + UI* const ui; + +public: + explicit PluginWindow(UI* const uiPtr, PluginApplication& app) + : ui(uiPtr) + { + app.ui = ui; + } + + // fetch cached data + uint getWidth() const noexcept { return ui->pData.width; } + uint getHeight() const noexcept { return ui->pData.height; } + double getScaleFactor() const noexcept { return ui->pData.scaleFactor; } + + // direct mappings + void close() { ui->close(); } + void focus() { ui->focus(); } + void show() { ui->show(); } + bool isResizable() const noexcept { return ui->isResizable(); } + bool isVisible() const noexcept { return ui->isVisible(); } + void setTitle(const char* const title) { ui->setTitle(title); } + void setVisible(const bool visible) { ui->setVisible(visible); } + uintptr_t getNativeWindowHandle() const noexcept { return ui->getNativeWindowHandle(); } + void getGeometryConstraints(uint& minimumWidth, uint& minimumHeight, bool& keepAspectRatio) const noexcept + { + minimumWidth = ui->pData.minWidth; + minimumHeight = ui->pData.minHeight; + keepAspectRatio = ui->pData.keepAspectRatio; + } + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) +}; +#else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI +class PluginWindow : public DGL_NAMESPACE::Window +{ + UI* const ui; + bool initializing; + bool receivedReshapeDuringInit; + +public: + explicit PluginWindow(UI* const uiPtr, + PluginApplication& app, + const uintptr_t parentWindowHandle, + const uint width, + const uint height, + const double scaleFactor) + : Window(app, parentWindowHandle, width, height, scaleFactor, + DISTRHO_UI_USER_RESIZABLE, DISTRHO_UI_USES_SIZE_REQUEST, false), + ui(uiPtr), + initializing(true), + receivedReshapeDuringInit(false) + { + if (pData->view == nullptr) + return; + + // this is called just before creating UI, ensuring proper context to it + if (pData->initPost()) + puglBackendEnter(pData->view); + } + + ~PluginWindow() override + { + if (pData->view != nullptr) + puglBackendLeave(pData->view); + } + + // called after creating UI, restoring proper context + void leaveContext() + { + if (pData->view == nullptr) + return; + + if (receivedReshapeDuringInit) + ui->uiReshape(getWidth(), getHeight()); + + initializing = false; + puglBackendLeave(pData->view); + } + + // used for temporary windows (VST/CLAP get size without active/visible view) + void setIgnoreIdleCallbacks(const bool ignore = true) + { + pData->ignoreIdleCallbacks = ignore; + } + + // called right before deleting UI, ensuring correct context + void enterContextForDeletion() + { + if (pData->view != nullptr) + puglBackendEnter(pData->view); + } + + #if defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP) + void setSizeFromHost(const uint width, const uint height) + { + puglSetSizeAndDefault(pData->view, width, height); + } + #endif + + std::vector<DGL_NAMESPACE::ClipboardDataOffer> getClipboardDataOfferTypes() + { + return Window::getClipboardDataOfferTypes(); + } + +protected: + uint32_t onClipboardDataOffer() override + { + DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, 0); + + if (initializing) + return 0; + + return ui->uiClipboardDataOffer(); + } + + void onFocus(const bool focus, const DGL_NAMESPACE::CrossingMode mode) override + { + DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); + + if (initializing) + return; + + ui->uiFocus(focus, mode); + } + + void onReshape(const uint width, const uint height) override + { + DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); + + if (initializing) + { + receivedReshapeDuringInit = true; + return; + } + + ui->uiReshape(width, height); + } + + void onScaleFactorChanged(const double scaleFactor) override + { + DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); + + if (initializing) + return; + + ui->uiScaleFactorChanged(scaleFactor); + } + +# if DISTRHO_UI_FILE_BROWSER + void onFileSelected(const char* filename) override; +# endif + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) +}; +#endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI + +// ----------------------------------------------------------------------- +// UI callbacks + +typedef void (*editParamFunc) (void* ptr, uint32_t rindex, bool started); +typedef void (*setParamFunc) (void* ptr, uint32_t rindex, float value); +typedef void (*setStateFunc) (void* ptr, const char* key, const char* value); +typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8_t velo); +typedef void (*setSizeFunc) (void* ptr, uint width, uint height); +typedef bool (*fileRequestFunc) (void* ptr, const char* key); + +// ----------------------------------------------------------------------- +// UI private data + +struct UI::PrivateData { + // DGL + PluginApplication app; + ScopedPointer<PluginWindow> window; + + // DSP + double sampleRate; + uint32_t parameterOffset; + void* dspPtr; + + // UI + uint bgColor; + uint fgColor; + double scaleFactor; + uintptr_t winId; + #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI + char* uiStateFileKeyRequest; + std::map<std::string,std::string> lastUsedDirnames; + #endif + char* bundlePath; + + // Ignore initial resize events while initializing + bool initializing; + + // Callbacks + void* callbacksPtr; + editParamFunc editParamCallbackFunc; + setParamFunc setParamCallbackFunc; + setStateFunc setStateCallbackFunc; + sendNoteFunc sendNoteCallbackFunc; + setSizeFunc setSizeCallbackFunc; + fileRequestFunc fileRequestCallbackFunc; + + PrivateData(const char* const appClassName) noexcept + : app(appClassName), + window(nullptr), + sampleRate(0), + parameterOffset(0), + dspPtr(nullptr), + bgColor(0), + fgColor(0xffffffff), + scaleFactor(1.0), + winId(0), + #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI + uiStateFileKeyRequest(nullptr), + #endif + bundlePath(nullptr), + initializing(true), + callbacksPtr(nullptr), + editParamCallbackFunc(nullptr), + setParamCallbackFunc(nullptr), + setStateCallbackFunc(nullptr), + sendNoteCallbackFunc(nullptr), + setSizeCallbackFunc(nullptr), + fileRequestCallbackFunc(nullptr) + { + #if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2) + parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS; + #if DISTRHO_PLUGIN_WANT_LATENCY + parameterOffset += 1; + #endif + #endif + + #ifdef DISTRHO_PLUGIN_TARGET_LV2 + #if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE) + parameterOffset += 1; + #endif + #if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) + parameterOffset += 1; + #endif + #endif + + #ifdef DISTRHO_PLUGIN_TARGET_VST3 + parameterOffset += kVst3InternalParameterCount; + #endif + } + + ~PrivateData() noexcept + { + #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI + std::free(uiStateFileKeyRequest); + #endif + std::free(bundlePath); + } + + void editParamCallback(const uint32_t rindex, const bool started) + { + if (editParamCallbackFunc != nullptr) + editParamCallbackFunc(callbacksPtr, rindex, started); + } + + void setParamCallback(const uint32_t rindex, const float value) + { + if (setParamCallbackFunc != nullptr) + setParamCallbackFunc(callbacksPtr, rindex, value); + } + + void setStateCallback(const char* const key, const char* const value) + { + if (setStateCallbackFunc != nullptr) + setStateCallbackFunc(callbacksPtr, key, value); + } + + void sendNoteCallback(const uint8_t channel, const uint8_t note, const uint8_t velocity) + { + if (sendNoteCallbackFunc != nullptr) + sendNoteCallbackFunc(callbacksPtr, channel, note, velocity); + } + + void setSizeCallback(const uint width, const uint height) + { + if (setSizeCallbackFunc != nullptr) + setSizeCallbackFunc(callbacksPtr, width, height); + } + + // implemented below, after PluginWindow + bool fileRequestCallback(const char* const key); + + static UI::PrivateData* s_nextPrivateData; +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI + static ExternalWindow::PrivateData createNextWindow(UI* ui, uint width, uint height, bool adjustForScaleFactor); +#else + static PluginWindow& createNextWindow(UI* ui, uint width, uint height, bool adjustForScaleFactor); +#endif +}; + +// ----------------------------------------------------------------------- +// UI private data fileRequestCallback, which requires PluginWindow definitions + +inline bool UI::PrivateData::fileRequestCallback(const char* const key) +{ + if (fileRequestCallbackFunc != nullptr) + return fileRequestCallbackFunc(callbacksPtr, key); + + #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI + std::free(uiStateFileKeyRequest); + uiStateFileKeyRequest = strdup(key); + DISTRHO_SAFE_ASSERT_RETURN(uiStateFileKeyRequest != nullptr, false); + + char title[0xff]; + snprintf(title, sizeof(title)-1u, DISTRHO_PLUGIN_NAME ": %s", key); + title[sizeof(title)-1u] = '\0'; + + DGL_NAMESPACE::FileBrowserOptions opts; + opts.title = title; + if (lastUsedDirnames.count(key)) + opts.startDir = lastUsedDirnames[key].c_str(); + return window->openFileBrowser(opts); + #endif + + return false; +} + +// ----------------------------------------------------------------------- +// PluginWindow onFileSelected that require UI::PrivateData definitions + +#if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI +inline void PluginWindow::onFileSelected(const char* const filename) +{ + DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); + + if (initializing) + return; + + #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI + if (char* const key = ui->uiData->uiStateFileKeyRequest) + { + ui->uiData->uiStateFileKeyRequest = nullptr; + if (filename != nullptr) + { + // notify DSP + ui->setState(key, filename); + + // notify UI + ui->stateChanged(key, filename); + + // save dirname for next time + if (const char* const lastsep = std::strrchr(filename, DISTRHO_OS_SEP)) + ui->uiData->lastUsedDirnames[key] = std::string(filename, lastsep-filename); + } + std::free(key); + return; + } + #endif + + puglBackendEnter(pData->view); + ui->uiFileBrowserSelected(filename); + puglBackendLeave(pData->view); +} +#endif + +// ----------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO + +#endif // DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED