I held on for as long as I could, but plugin host caching needs it Signed-off-by: falkTX <falktx@falktx.com>tags/23.07
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
| @@ -97,3 +97,11 @@ void async_dialog_message(const char* message, std::function<void()> action); | |||||
| // opens a text input dialog, message and text can be null | // opens a text input dialog, message and text can be null | ||||
| // action is always triggered on close (newText can be null), must be freed if not null | // action is always triggered on close (newText can be null), must be freed if not null | ||||
| void async_dialog_text_input(const char* message, const char* text, std::function<void(char* newText)> action); | void async_dialog_text_input(const char* message, const char* text, std::function<void(char* newText)> action); | ||||
| // Cardinal specific config dir (might be equal to userDir) | |||||
| namespace rack { | |||||
| namespace asset { | |||||
| extern std::string configDir; | |||||
| std::string config(std::string filename = ""); | |||||
| } | |||||
| } | |||||
| @@ -76,15 +76,15 @@ | |||||
| #endif | #endif | ||||
| #if CARDINAL_VARIANT_FX | #if CARDINAL_VARIANT_FX | ||||
| # define CARDINAL_TEMPLATE_NAME "init/fx.vcv" | |||||
| # define CARDINAL_VARIANT_NAME "fx" | |||||
| #elif CARDINAL_VARIANT_MINI | #elif CARDINAL_VARIANT_MINI | ||||
| # define CARDINAL_TEMPLATE_NAME "init/mini.vcv" | |||||
| # define CARDINAL_VARIANT_NAME "mini" | |||||
| #elif CARDINAL_VARIANT_NATIVE | #elif CARDINAL_VARIANT_NATIVE | ||||
| # define CARDINAL_TEMPLATE_NAME "init/native.vcv" | |||||
| # define CARDINAL_VARIANT_NAME "native" | |||||
| #elif CARDINAL_VARIANT_SYNTH | #elif CARDINAL_VARIANT_SYNTH | ||||
| # define CARDINAL_TEMPLATE_NAME "init/synth.vcv" | |||||
| # define CARDINAL_VARIANT_NAME "synth" | |||||
| #else | #else | ||||
| # define CARDINAL_TEMPLATE_NAME "init/main.vcv" | |||||
| # define CARDINAL_VARIANT_NAME "main" | |||||
| #endif | #endif | ||||
| #ifdef DISTRHO_OS_WASM | #ifdef DISTRHO_OS_WASM | ||||
| @@ -379,12 +379,8 @@ Initializer::Initializer(const CardinalBasePlugin* const plugin, const CardinalB | |||||
| using namespace rack; | using namespace rack; | ||||
| settings::allowCursorLock = false; | settings::allowCursorLock = false; | ||||
| settings::autoCheckUpdates = false; | |||||
| settings::autosaveInterval = 0; | |||||
| settings::devMode = true; | settings::devMode = true; | ||||
| settings::isPlugin = true; | settings::isPlugin = true; | ||||
| settings::skipLoadOnLaunch = true; | |||||
| settings::showTipsOnLaunch = false; | |||||
| settings::windowPos = math::Vec(0, 0); | settings::windowPos = math::Vec(0, 0); | ||||
| #ifdef HEADLESS_BEHAVIOUR | #ifdef HEADLESS_BEHAVIOUR | ||||
| settings::headless = true; | settings::headless = true; | ||||
| @@ -446,27 +442,58 @@ Initializer::Initializer(const CardinalBasePlugin* const plugin, const CardinalB | |||||
| #elif defined(ARCH_MAC) | #elif defined(ARCH_MAC) | ||||
| asset::systemDir = "/Library/Application Support/Cardinal"; | asset::systemDir = "/Library/Application Support/Cardinal"; | ||||
| #elif defined(ARCH_WIN) | #elif defined(ARCH_WIN) | ||||
| const std::string commonprogfiles = getSpecialPath(kSpecialPathCommonProgramFiles); | |||||
| if (! commonprogfiles.empty()) | |||||
| asset::systemDir = system::join(commonprogfiles, "Cardinal"); | |||||
| asset::systemDir = system::join(getSpecialPath(kSpecialPathCommonProgramFiles), "Cardinal"); | |||||
| #else | #else | ||||
| asset::systemDir = CARDINAL_PLUGIN_PREFIX "/share/cardinal"; | asset::systemDir = CARDINAL_PLUGIN_PREFIX "/share/cardinal"; | ||||
| #endif | #endif | ||||
| asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); | asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| asset::userDir = asset::systemDir; | |||||
| if (asset::userDir.empty()) | |||||
| { | |||||
| #if defined(DISTRHO_OS_WASM) | |||||
| asset::userDir = "/userfiles"; | |||||
| #elif defined(ARCH_MAC) | |||||
| asset::userDir = system::join(homeDir(), "Documents", "Cardinal"); | |||||
| #elif defined(ARCH_WIN) | |||||
| asset::userDir = system::join(getSpecialPath(kSpecialPathMyDocuments), "Cardinal"); | |||||
| #else | |||||
| if (const char* const xdgEnv = getenv("XDG_DOCUMENTS_DIR")) | |||||
| asset::userDir = system::join(xdgEnv, "Cardinal"); | |||||
| else | |||||
| asset::userDir = system::join(homeDir(), "Documents", "Cardinal"); | |||||
| #endif | |||||
| system::createDirectory(asset::userDir); | |||||
| } | } | ||||
| #ifndef CARDINAL_COMMON_DSP_ONLY | |||||
| if (asset::configDir.empty()) | |||||
| { | |||||
| #if defined(ARCH_MAC) || defined(ARCH_WIN) || defined(DISTRHO_OS_WASM) | |||||
| asset::configDir = asset::userDir; | |||||
| #else | |||||
| if (const char* const xdgEnv = getenv("XDG_CONFIG_HOME")) | |||||
| asset::configDir = system::join(xdgEnv, "Cardinal"); | |||||
| else | |||||
| asset::configDir = system::join(homeDir(), ".config", "Cardinal"); | |||||
| system::createDirectory(asset::configDir); | |||||
| #endif | |||||
| } | |||||
| #endif | |||||
| if (settings::settingsPath.empty()) | |||||
| settings::settingsPath = asset::config(CARDINAL_VARIANT_NAME ".json"); | |||||
| const std::string patchesPath = asset::patchesPath(); | const std::string patchesPath = asset::patchesPath(); | ||||
| #ifdef DISTRHO_OS_WASM | #ifdef DISTRHO_OS_WASM | ||||
| templatePath = system::join(patchesPath, CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME); | |||||
| templatePath = system::join(patchesPath, CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME ".vcv"); | |||||
| factoryTemplatePath = system::join(patchesPath, "templates/" CARDINAL_VARIANT_NAME ".vcv"); | |||||
| #else | #else | ||||
| templatePath = system::join(patchesPath, CARDINAL_TEMPLATE_NAME); | |||||
| templatePath = asset::user("templates/" CARDINAL_VARIANT_NAME ".vcv"); | |||||
| factoryTemplatePath = system::join(patchesPath, "templates/" CARDINAL_VARIANT_NAME ".vcv"); | |||||
| #endif | #endif | ||||
| factoryTemplatePath = system::join(patchesPath, CARDINAL_TEMPLATE_NAME); | |||||
| // Log environment | // Log environment | ||||
| INFO("%s %s %s, compatible with Rack version %s", APP_NAME.c_str(), APP_EDITION.c_str(), CARDINAL_VERSION.c_str(), APP_VERSION.c_str()); | INFO("%s %s %s, compatible with Rack version %s", APP_NAME.c_str(), APP_EDITION.c_str(), CARDINAL_VERSION.c_str(), APP_VERSION.c_str()); | ||||
| @@ -502,6 +529,27 @@ Initializer::Initializer(const CardinalBasePlugin* const plugin, const CardinalB | |||||
| INFO("Initializing plugin browser DB"); | INFO("Initializing plugin browser DB"); | ||||
| app::browserInit(); | app::browserInit(); | ||||
| if (! plugin->isDummyInstance()) | |||||
| { | |||||
| INFO("Loading settings"); | |||||
| settings::load(); | |||||
| } | |||||
| // enforce settings that do not make sense as anything else | |||||
| settings::safeMode = false; | |||||
| settings::token.clear(); | |||||
| settings::windowMaximized = false; | |||||
| settings::windowPos = math::Vec(0, 0); | |||||
| settings::pixelRatio = 0.0; | |||||
| settings::sampleRate = 0; | |||||
| settings::threadCount = 1; | |||||
| settings::frameSwapInterval = 1; | |||||
| settings::autosaveInterval = 0; | |||||
| settings::skipLoadOnLaunch = true; | |||||
| settings::autoCheckUpdates = false; | |||||
| settings::showTipsOnLaunch = false; | |||||
| settings::tipIndex = -1; | |||||
| #ifdef CARDINAL_INIT_OSC_THREAD | #ifdef CARDINAL_INIT_OSC_THREAD | ||||
| INFO("Initializing OSC Remote control"); | INFO("Initializing OSC Remote control"); | ||||
| const char* port; | const char* port; | ||||
| @@ -538,6 +586,9 @@ Initializer::~Initializer() | |||||
| } | } | ||||
| #endif | #endif | ||||
| INFO("Save settings"); | |||||
| settings::save(); | |||||
| INFO("Clearing asset paths"); | INFO("Clearing asset paths"); | ||||
| asset::bundlePath.clear(); | asset::bundlePath.clear(); | ||||
| asset::systemDir.clear(); | asset::systemDir.clear(); | ||||
| @@ -596,6 +647,8 @@ std::string getSpecialPath(const SpecialPath type) | |||||
| case kSpecialPathAppData: | case kSpecialPathAppData: | ||||
| csidl = CSIDL_APPDATA; | csidl = CSIDL_APPDATA; | ||||
| break; | break; | ||||
| case kSpecialPathMyDocuments: | |||||
| csidl = CSIDL_MYDOCUMENTS; | |||||
| default: | default: | ||||
| return {}; | return {}; | ||||
| } | } | ||||
| @@ -617,14 +670,14 @@ char* patchStorageSlug = nullptr; | |||||
| std::string homeDir() | std::string homeDir() | ||||
| { | { | ||||
| # ifdef ARCH_WIN | |||||
| #ifdef ARCH_WIN | |||||
| return getSpecialPath(kSpecialPathUserProfile); | return getSpecialPath(kSpecialPathUserProfile); | ||||
| # else | |||||
| #else | |||||
| if (const char* const home = getenv("HOME")) | if (const char* const home = getenv("HOME")) | ||||
| return home; | return home; | ||||
| if (struct passwd* const pwd = getpwuid(getuid())) | if (struct passwd* const pwd = getpwuid(getuid())) | ||||
| return pwd->pw_dir; | return pwd->pw_dir; | ||||
| # endif | |||||
| #endif | |||||
| return {}; | return {}; | ||||
| } | } | ||||
| @@ -719,15 +772,38 @@ void loadSelectionDialog() | |||||
| }); | }); | ||||
| } | } | ||||
| void loadTemplateDialog() | |||||
| void loadTemplate(const bool factory) | |||||
| { | { | ||||
| #ifndef HEADLESS_BEHAVIOUR | |||||
| promptClear("The current patch is unsaved. Clear it and start a new patch?", []() { | |||||
| APP->patch->loadTemplate(); | |||||
| try { | |||||
| APP->patch->load(factory ? APP->patch->factoryTemplatePath : APP->patch->templatePath); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| // if user template failed, try the factory one | |||||
| if (!factory) | |||||
| return loadTemplate(true); | |||||
| if (remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote()) | |||||
| if (remoteDetails->autoDeploy) | |||||
| remoteUtils::sendFullPatchToRemote(remoteDetails); | |||||
| const std::string message = string::f("Could not load template patch, clearing rack: %s", e.what()); | |||||
| asyncDialog::create(message.c_str()); | |||||
| APP->patch->clear(); | |||||
| APP->patch->clearAutosave(); | |||||
| } | |||||
| // load() sets the patch's original patch, but we don't want to use that. | |||||
| APP->patch->path.clear(); | |||||
| APP->history->setSaved(); | |||||
| if (remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote()) | |||||
| if (remoteDetails->autoDeploy) | |||||
| remoteUtils::sendFullPatchToRemote(remoteDetails); | |||||
| } | |||||
| void loadTemplateDialog(const bool factory) | |||||
| { | |||||
| #ifndef HEADLESS_BEHAVIOUR | |||||
| promptClear("The current patch is unsaved. Clear it and start a new patch?", [factory]() { | |||||
| loadTemplate(factory); | |||||
| }); | }); | ||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -772,9 +848,14 @@ static void saveAsDialog(const bool uncompressed) | |||||
| { | { | ||||
| std::string dir; | std::string dir; | ||||
| if (! APP->patch->path.empty()) | if (! APP->patch->path.empty()) | ||||
| { | |||||
| dir = system::getDirectory(APP->patch->path); | dir = system::getDirectory(APP->patch->path); | ||||
| } | |||||
| else | else | ||||
| dir = homeDir(); | |||||
| { | |||||
| dir = asset::user("patches"); | |||||
| system::createDirectories(dir); | |||||
| } | |||||
| CardinalPluginContext* const pcontext = static_cast<CardinalPluginContext*>(APP); | CardinalPluginContext* const pcontext = static_cast<CardinalPluginContext*>(APP); | ||||
| DISTRHO_SAFE_ASSERT_RETURN(pcontext != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(pcontext != nullptr,); | ||||
| @@ -806,6 +887,21 @@ void saveAsDialogUncompressed() | |||||
| #endif | #endif | ||||
| } | } | ||||
| void saveTemplateDialog() | |||||
| { | |||||
| asyncDialog::create("Overwrite template patch?", []{ | |||||
| rack::system::createDirectories(system::getDirectory(APP->patch->templatePath)); | |||||
| try { | |||||
| APP->patch->save(APP->patch->templatePath); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| asyncDialog::create(string::f("Could not save template patch: %s", e.what()).c_str()); | |||||
| return; | |||||
| } | |||||
| }); | |||||
| } | |||||
| void openBrowser(const std::string& url) | void openBrowser(const std::string& url) | ||||
| { | { | ||||
| #ifdef DISTRHO_OS_WASM | #ifdef DISTRHO_OS_WASM | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
| @@ -44,6 +44,7 @@ enum SpecialPath { | |||||
| kSpecialPathCommonProgramFiles, | kSpecialPathCommonProgramFiles, | ||||
| kSpecialPathProgramFiles, | kSpecialPathProgramFiles, | ||||
| kSpecialPathAppData, | kSpecialPathAppData, | ||||
| kSpecialPathMyDocuments, | |||||
| }; | }; | ||||
| std::string getSpecialPath(SpecialPath type); | std::string getSpecialPath(SpecialPath type); | ||||
| #endif | #endif | ||||
| @@ -54,6 +55,8 @@ extern char* patchRemoteURL; | |||||
| extern char* patchStorageSlug; | extern char* patchStorageSlug; | ||||
| #endif | #endif | ||||
| std::string homeDir(); | |||||
| } // namespace rack | } // namespace rack | ||||
| // ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
| @@ -63,11 +66,13 @@ namespace patchUtils { | |||||
| void loadDialog(); | void loadDialog(); | ||||
| void loadPathDialog(const std::string& path, bool asTemplate = false); | void loadPathDialog(const std::string& path, bool asTemplate = false); | ||||
| void loadSelectionDialog(); | void loadSelectionDialog(); | ||||
| void loadTemplateDialog(); | |||||
| void loadTemplate(bool factory); | |||||
| void loadTemplateDialog(bool factory); | |||||
| void revertDialog(); | void revertDialog(); | ||||
| void saveDialog(const std::string& path); | void saveDialog(const std::string& path); | ||||
| void saveAsDialog(); | void saveAsDialog(); | ||||
| void saveAsDialogUncompressed(); | void saveAsDialogUncompressed(); | ||||
| void saveTemplateDialog(); | |||||
| void appendSelectionContextMenu(rack::ui::Menu* menu); | void appendSelectionContextMenu(rack::ui::Menu* menu); | ||||
| void openBrowser(const std::string& url); | void openBrowser(const std::string& url); | ||||
| @@ -198,20 +198,20 @@ public: | |||||
| fWasBypassed(false) | fWasBypassed(false) | ||||
| { | { | ||||
| #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) | #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) | ||||
| fWindowParameters[kWindowParameterShowTooltips] = 1.0f; | |||||
| fWindowParameters[kWindowParameterCableOpacity] = 50.0f; | |||||
| fWindowParameters[kWindowParameterCableTension] = 75.0f; | |||||
| fWindowParameters[kWindowParameterRackBrightness] = 100.0f; | |||||
| fWindowParameters[kWindowParameterHaloBrightness] = 25.0f; | |||||
| fWindowParameters[kWindowParameterShowTooltips] = rack::settings::tooltips ? 1.f : 0.f; | |||||
| fWindowParameters[kWindowParameterCableOpacity] = std::min(100.f, std::max(0.f, rack::settings::cableOpacity * 100)); | |||||
| fWindowParameters[kWindowParameterCableTension] = std::min(100.f, std::max(0.f, rack::settings::cableTension * 100)); | |||||
| fWindowParameters[kWindowParameterRackBrightness] = std::min(100.f, std::max(0.f, rack::settings::rackBrightness * 100)); | |||||
| fWindowParameters[kWindowParameterHaloBrightness] = std::min(100.f, std::max(0.f, rack::settings::haloBrightness * 100)); | |||||
| fWindowParameters[kWindowParameterKnobMode] = 0.0f; | fWindowParameters[kWindowParameterKnobMode] = 0.0f; | ||||
| fWindowParameters[kWindowParameterWheelKnobControl] = 0.0f; | |||||
| fWindowParameters[kWindowParameterWheelSensitivity] = 1.0f; | |||||
| fWindowParameters[kWindowParameterLockModulePositions] = 0.0f; | |||||
| fWindowParameters[kWindowParameterWheelKnobControl] = rack::settings::knobScroll ? 1.f : 0.f; | |||||
| fWindowParameters[kWindowParameterWheelSensitivity] = std::min(10.f, std::max(0.1f, rack::settings::knobScrollSensitivity * 1000)); | |||||
| fWindowParameters[kWindowParameterLockModulePositions] = rack::settings::lockModules ? 1.f : 0.f; | |||||
| fWindowParameters[kWindowParameterUpdateRateLimit] = 0.0f; | fWindowParameters[kWindowParameterUpdateRateLimit] = 0.0f; | ||||
| fWindowParameters[kWindowParameterBrowserSort] = 3.0f; | fWindowParameters[kWindowParameterBrowserSort] = 3.0f; | ||||
| fWindowParameters[kWindowParameterBrowserZoom] = 50.0f; | fWindowParameters[kWindowParameterBrowserZoom] = 50.0f; | ||||
| fWindowParameters[kWindowParameterInvertZoom] = 0.0f; | |||||
| fWindowParameters[kWindowParameterSqueezeModulePositions] = 1.0f; | |||||
| fWindowParameters[kWindowParameterInvertZoom] = rack::settings::invertZoom ? 1.f : 0.f; | |||||
| fWindowParameters[kWindowParameterSqueezeModulePositions] = rack::settings::squeezeModules ? 1.f : 0.f; | |||||
| #endif | #endif | ||||
| #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| std::memset(fMiniReportValues, 0, sizeof(fMiniReportValues)); | std::memset(fMiniReportValues, 0, sizeof(fMiniReportValues)); | ||||
| @@ -283,8 +283,6 @@ public: | |||||
| { | { | ||||
| context->patch->loadTemplate(); | context->patch->loadTemplate(); | ||||
| context->scene->rackScroll->reset(); | context->scene->rackScroll->reset(); | ||||
| // swap to factory template after first load | |||||
| context->patch->templatePath = context->patch->factoryTemplatePath; | |||||
| } | } | ||||
| #ifdef CARDINAL_INIT_OSC_THREAD | #ifdef CARDINAL_INIT_OSC_THREAD | ||||
| @@ -463,7 +461,7 @@ protected: | |||||
| #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| parameter.hints |= kParameterIsHidden; | parameter.hints |= kParameterIsHidden; | ||||
| #endif | #endif | ||||
| parameter.ranges.def = 1.0f; | |||||
| parameter.ranges.def = rack::settings::tooltips ? 1.f : 0.f; | |||||
| parameter.ranges.min = 0.0f; | parameter.ranges.min = 0.0f; | ||||
| parameter.ranges.max = 1.0f; | parameter.ranges.max = 1.0f; | ||||
| break; | break; | ||||
| @@ -475,7 +473,7 @@ protected: | |||||
| #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| parameter.hints |= kParameterIsHidden; | parameter.hints |= kParameterIsHidden; | ||||
| #endif | #endif | ||||
| parameter.ranges.def = 50.0f; | |||||
| parameter.ranges.def = std::min(100.f, std::max(0.f, rack::settings::cableOpacity * 100)); | |||||
| parameter.ranges.min = 0.0f; | parameter.ranges.min = 0.0f; | ||||
| parameter.ranges.max = 100.0f; | parameter.ranges.max = 100.0f; | ||||
| break; | break; | ||||
| @@ -487,7 +485,7 @@ protected: | |||||
| #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| parameter.hints |= kParameterIsHidden; | parameter.hints |= kParameterIsHidden; | ||||
| #endif | #endif | ||||
| parameter.ranges.def = 75.0f; | |||||
| parameter.ranges.def = std::min(100.f, std::max(0.f, rack::settings::cableTension * 100)); | |||||
| parameter.ranges.min = 0.0f; | parameter.ranges.min = 0.0f; | ||||
| parameter.ranges.max = 100.0f; | parameter.ranges.max = 100.0f; | ||||
| break; | break; | ||||
| @@ -499,7 +497,7 @@ protected: | |||||
| #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| parameter.hints |= kParameterIsHidden; | parameter.hints |= kParameterIsHidden; | ||||
| #endif | #endif | ||||
| parameter.ranges.def = 100.0f; | |||||
| parameter.ranges.def = std::min(100.f, std::max(0.f, rack::settings::rackBrightness * 100)); | |||||
| parameter.ranges.min = 0.0f; | parameter.ranges.min = 0.0f; | ||||
| parameter.ranges.max = 100.0f; | parameter.ranges.max = 100.0f; | ||||
| break; | break; | ||||
| @@ -511,7 +509,7 @@ protected: | |||||
| #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| parameter.hints |= kParameterIsHidden; | parameter.hints |= kParameterIsHidden; | ||||
| #endif | #endif | ||||
| parameter.ranges.def = 25.0f; | |||||
| parameter.ranges.def = std::min(100.f, std::max(0.f, rack::settings::haloBrightness * 100)); | |||||
| parameter.ranges.min = 0.0f; | parameter.ranges.min = 0.0f; | ||||
| parameter.ranges.max = 100.0f; | parameter.ranges.max = 100.0f; | ||||
| break; | break; | ||||
| @@ -542,7 +540,7 @@ protected: | |||||
| #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| parameter.hints |= kParameterIsHidden; | parameter.hints |= kParameterIsHidden; | ||||
| #endif | #endif | ||||
| parameter.ranges.def = 0.0f; | |||||
| parameter.ranges.def = rack::settings::knobScroll ? 1.f : 0.f; | |||||
| parameter.ranges.min = 0.0f; | parameter.ranges.min = 0.0f; | ||||
| parameter.ranges.max = 1.0f; | parameter.ranges.max = 1.0f; | ||||
| break; | break; | ||||
| @@ -553,7 +551,7 @@ protected: | |||||
| #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| parameter.hints |= kParameterIsHidden; | parameter.hints |= kParameterIsHidden; | ||||
| #endif | #endif | ||||
| parameter.ranges.def = 1.0f; | |||||
| parameter.ranges.def = std::min(10.f, std::max(0.1f, rack::settings::knobScrollSensitivity * 1000)); | |||||
| parameter.ranges.min = 0.1f; | parameter.ranges.min = 0.1f; | ||||
| parameter.ranges.max = 10.0f; | parameter.ranges.max = 10.0f; | ||||
| break; | break; | ||||
| @@ -564,7 +562,7 @@ protected: | |||||
| #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| parameter.hints |= kParameterIsHidden; | parameter.hints |= kParameterIsHidden; | ||||
| #endif | #endif | ||||
| parameter.ranges.def = 0.0f; | |||||
| parameter.ranges.def = rack::settings::lockModules ? 1.f : 0.f; | |||||
| parameter.ranges.min = 0.0f; | parameter.ranges.min = 0.0f; | ||||
| parameter.ranges.max = 1.0f; | parameter.ranges.max = 1.0f; | ||||
| break; | break; | ||||
| @@ -650,7 +648,7 @@ protected: | |||||
| #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| parameter.hints |= kParameterIsHidden; | parameter.hints |= kParameterIsHidden; | ||||
| #endif | #endif | ||||
| parameter.ranges.def = 0.0f; | |||||
| parameter.ranges.def = rack::settings::invertZoom ? 1.f : 0.f; | |||||
| parameter.ranges.min = 0.0f; | parameter.ranges.min = 0.0f; | ||||
| parameter.ranges.max = 1.0f; | parameter.ranges.max = 1.0f; | ||||
| break; | break; | ||||
| @@ -661,7 +659,7 @@ protected: | |||||
| #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| parameter.hints |= kParameterIsHidden; | parameter.hints |= kParameterIsHidden; | ||||
| #endif | #endif | ||||
| parameter.ranges.def = 1.0f; | |||||
| parameter.ranges.def = rack::settings::squeezeModules ? 1.f : 0.f; | |||||
| parameter.ranges.min = 0.0f; | parameter.ranges.min = 0.0f; | ||||
| parameter.ranges.max = 1.0f; | parameter.ranges.max = 1.0f; | ||||
| break; | break; | ||||
| @@ -277,8 +277,8 @@ static void downloadRemotePatchSucceeded(const char* const filename) | |||||
| return; | return; | ||||
| } | } | ||||
| context->patch->path.clear(); | |||||
| context->scene->rackScroll->reset(); | context->scene->rackScroll->reset(); | ||||
| context->patch->path = ""; | |||||
| context->history->setSaved(); | context->history->setSaved(); | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -415,8 +415,16 @@ public: | |||||
| setGeometryConstraints(648 * scaleFactor, 538 * scaleFactor); | setGeometryConstraints(648 * scaleFactor, 538 * scaleFactor); | ||||
| if (scaleFactor != 1.0) | |||||
| if (rack::isStandalone() && rack::system::exists(rack::settings::settingsPath)) | |||||
| { | |||||
| const double width = std::max(648.f, rack::settings::windowSize.x) * scaleFactor; | |||||
| const double height = std::max(538.f, rack::settings::windowSize.y) * scaleFactor; | |||||
| setSize(width, height); | |||||
| } | |||||
| else if (scaleFactor != 1.0) | |||||
| { | |||||
| setSize(DISTRHO_UI_DEFAULT_WIDTH * scaleFactor, DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor); | setSize(DISTRHO_UI_DEFAULT_WIDTH * scaleFactor, DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor); | ||||
| } | |||||
| rack::window::WindowSetPluginUI(context->window, this); | rack::window::WindowSetPluginUI(context->window, this); | ||||
| @@ -1137,10 +1145,15 @@ protected: | |||||
| WindowSetInternalSize(context->window, rack::math::Vec(ev.size.getWidth(), ev.size.getHeight())); | WindowSetInternalSize(context->window, rack::math::Vec(ev.size.getWidth(), ev.size.getHeight())); | ||||
| const double scaleFactor = getScaleFactor(); | const double scaleFactor = getScaleFactor(); | ||||
| char sizeString[64]; | |||||
| std::snprintf(sizeString, sizeof(sizeString), "%d:%d", | |||||
| (int)(ev.size.getWidth() / scaleFactor), (int)(ev.size.getHeight() / scaleFactor)); | |||||
| const int width = static_cast<int>(ev.size.getWidth() / scaleFactor + 0.5); | |||||
| const int height = static_cast<int>(ev.size.getHeight() / scaleFactor + 0.5); | |||||
| char sizeString[64] = {}; | |||||
| std::snprintf(sizeString, sizeof(sizeString), "%d:%d", width, height); | |||||
| setState("windowSize", sizeString); | setState("windowSize", sizeString); | ||||
| if (rack::isStandalone()) | |||||
| rack::settings::windowSize = rack::math::Vec(width, height); | |||||
| } | } | ||||
| void uiFocus(const bool focus, CrossingMode) override | void uiFocus(const bool focus, CrossingMode) override | ||||
| @@ -1212,7 +1225,10 @@ protected: | |||||
| } | } | ||||
| context->patch->path = sfilename; | context->patch->path = sfilename; | ||||
| context->patch->pushRecentPath(sfilename); | |||||
| context->history->setSaved(); | context->history->setSaved(); | ||||
| rack::settings::save(); | |||||
| } | } | ||||
| #if 0 | #if 0 | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
| * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
| @@ -36,10 +36,19 @@ extern bool forceBlackScrew; | |||||
| extern bool forceSilverScrew; | extern bool forceSilverScrew; | ||||
| #endif | #endif | ||||
| std::string userDir; // ignored | |||||
| std::string configDir; // points to writable config dir (might be equal to userDir) | |||||
| std::string userDir; // points to common writable dir | |||||
| std::string systemDir; // points to plugin resources dir (or installed/local Rack dir) | std::string systemDir; // points to plugin resources dir (or installed/local Rack dir) | ||||
| std::string bundlePath; // points to plugin manifests dir (or empty) | std::string bundlePath; // points to plugin manifests dir (or empty) | ||||
| std::string config(std::string filename) { | |||||
| return system::join(configDir, filename); | |||||
| } | |||||
| std::string user(std::string filename) { | |||||
| return system::join(userDir, filename); | |||||
| } | |||||
| // get rid of "res/" prefix | // get rid of "res/" prefix | ||||
| static inline std::string& trim(std::string& s) | static inline std::string& trim(std::string& s) | ||||
| { | { | ||||
| @@ -48,11 +57,6 @@ static inline std::string& trim(std::string& s) | |||||
| return s; | return s; | ||||
| } | } | ||||
| // ignored, returns the same as `system` | |||||
| std::string user(std::string filename) { | |||||
| return system(filename); | |||||
| } | |||||
| // get system resource, trimming "res/" prefix if we are loaded as a plugin bundle | // get system resource, trimming "res/" prefix if we are loaded as a plugin bundle | ||||
| std::string system(std::string filename) { | std::string system(std::string filename) { | ||||
| #ifndef HEADLESS | #ifndef HEADLESS | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
| @@ -127,20 +127,33 @@ struct FileButton : MenuButton { | |||||
| menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); | menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); | ||||
| #ifndef DISTRHO_OS_WASM | #ifndef DISTRHO_OS_WASM | ||||
| const char* const NewShortcut = RACK_MOD_CTRL_NAME "+N"; | |||||
| constexpr const char* const NewShortcut = RACK_MOD_CTRL_NAME "+N"; | |||||
| #else | #else | ||||
| const char* const NewShortcut = ""; | |||||
| constexpr const char* const NewShortcut = ""; | |||||
| #endif | #endif | ||||
| menu->addChild(createMenuItem("New", NewShortcut, []() { | menu->addChild(createMenuItem("New", NewShortcut, []() { | ||||
| patchUtils::loadTemplateDialog(); | |||||
| patchUtils::loadTemplateDialog(false); | |||||
| })); | })); | ||||
| #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| #ifndef DISTRHO_OS_WASM | #ifndef DISTRHO_OS_WASM | ||||
| menu->addChild(createMenuItem("New (factory template)", "", []() { | |||||
| patchUtils::loadTemplateDialog(true); | |||||
| })); | |||||
| menu->addChild(createMenuItem("Open / Import...", RACK_MOD_CTRL_NAME "+O", []() { | menu->addChild(createMenuItem("Open / Import...", RACK_MOD_CTRL_NAME "+O", []() { | ||||
| patchUtils::loadDialog(); | patchUtils::loadDialog(); | ||||
| })); | })); | ||||
| menu->addChild(createSubmenuItem("Open recent", "", [](ui::Menu* menu) { | |||||
| for (const std::string& path : settings::recentPatchPaths) { | |||||
| std::string name = system::getStem(path); | |||||
| menu->addChild(createMenuItem(name, "", [=]() { | |||||
| patchUtils::loadPathDialog(path, false); | |||||
| })); | |||||
| } | |||||
| }, settings::recentPatchPaths.empty())); | |||||
| menu->addChild(createMenuItem("Save", RACK_MOD_CTRL_NAME "+S", []() { | menu->addChild(createMenuItem("Save", RACK_MOD_CTRL_NAME "+S", []() { | ||||
| // NOTE: will do nothing if path is empty, intentionally | // NOTE: will do nothing if path is empty, intentionally | ||||
| patchUtils::saveDialog(APP->patch->path); | patchUtils::saveDialog(APP->patch->path); | ||||
| @@ -172,6 +185,10 @@ struct FileButton : MenuButton { | |||||
| patchUtils::revertDialog(); | patchUtils::revertDialog(); | ||||
| }, APP->patch->path.empty())); | }, APP->patch->path.empty())); | ||||
| menu->addChild(createMenuItem("Overwrite template", "", []() { | |||||
| patchUtils::saveTemplateDialog(); | |||||
| })); | |||||
| #if defined(HAVE_LIBLO) || ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if defined(HAVE_LIBLO) || ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| #ifdef __MOD_DEVICES__ | #ifdef __MOD_DEVICES__ | ||||
| #define REMOTE_NAME "MOD" | #define REMOTE_NAME "MOD" | ||||
| @@ -728,6 +745,12 @@ struct HelpButton : MenuButton { | |||||
| menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
| menu->addChild(createMenuItem("Open user folder", "", [=]() { | |||||
| system::openDirectory(asset::user("")); | |||||
| })); | |||||
| menu->addChild(new ui::MenuSeparator); | |||||
| menu->addChild(createMenuLabel("Cardinal " + APP_EDITION + " " + CARDINAL_VERSION)); | menu->addChild(createMenuLabel("Cardinal " + APP_EDITION + " " + CARDINAL_VERSION)); | ||||
| menu->addChild(createMenuLabel("Rack " + APP_VERSION + " Compatible")); | menu->addChild(createMenuLabel("Rack " + APP_VERSION + " Compatible")); | ||||
| } | } | ||||
| @@ -261,7 +261,7 @@ void Scene::onHoverKey(const HoverKeyEvent& e) { | |||||
| if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | ||||
| // DEBUG("key '%d '%c' scancode %d '%c' keyName '%s'", e.key, e.key, e.scancode, e.scancode, e.keyName.c_str()); | // DEBUG("key '%d '%c' scancode %d '%c' keyName '%s'", e.key, e.key, e.scancode, e.scancode, e.keyName.c_str()); | ||||
| if (e.keyName == "n" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { | if (e.keyName == "n" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { | ||||
| patchUtils::loadTemplateDialog(); | |||||
| patchUtils::loadTemplateDialog(false); | |||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| if (e.keyName == "q" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { | if (e.keyName == "q" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { | ||||