You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

214 lines
5.3KB

  1. /*
  2. * DISTRHO Cardinal Plugin
  3. * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 3 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the LICENSE file.
  16. */
  17. /**
  18. * This file is an edited version of VCVRack's plugin/Model.cpp
  19. * Copyright (C) 2016-2021 VCV.
  20. *
  21. * This program is free software: you can redistribute it and/or
  22. * modify it under the terms of the GNU General Public License as
  23. * published by the Free Software Foundation; either version 3 of
  24. * the License, or (at your option) any later version.
  25. */
  26. #include <algorithm>
  27. #include <plugin/Model.hpp>
  28. #include <plugin.hpp>
  29. #include <asset.hpp>
  30. #include <system.hpp>
  31. #include <settings.hpp>
  32. #include <string.hpp>
  33. #include <tag.hpp>
  34. #include <ui/Menu.hpp>
  35. #include <ui/MenuSeparator.hpp>
  36. #include <helpers.hpp>
  37. #include "../CardinalCommon.hpp"
  38. namespace rack {
  39. namespace plugin {
  40. void Model::fromJson(json_t* rootJ) {
  41. DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr,);
  42. json_t* nameJ = json_object_get(rootJ, "name");
  43. if (nameJ)
  44. name = json_string_value(nameJ);
  45. if (name == "")
  46. throw Exception("No module name for slug %s", slug.c_str());
  47. json_t* descriptionJ = json_object_get(rootJ, "description");
  48. if (descriptionJ)
  49. description = json_string_value(descriptionJ);
  50. // Tags
  51. tagIds.clear();
  52. json_t* tagsJ = json_object_get(rootJ, "tags");
  53. if (tagsJ) {
  54. size_t i;
  55. json_t* tagJ;
  56. json_array_foreach(tagsJ, i, tagJ) {
  57. std::string tag = json_string_value(tagJ);
  58. int tagId = tag::findId(tag);
  59. // Omit duplicates
  60. auto it = std::find(tagIds.begin(), tagIds.end(), tagId);
  61. if (it != tagIds.end())
  62. continue;
  63. if (tagId >= 0)
  64. tagIds.push_back(tagId);
  65. }
  66. }
  67. // manualUrl
  68. json_t* manualUrlJ = json_object_get(rootJ, "manualUrl");
  69. if (manualUrlJ)
  70. manualUrl = json_string_value(manualUrlJ);
  71. // hidden
  72. json_t* hiddenJ = json_object_get(rootJ, "hidden");
  73. // Use `disabled` as an alias which was deprecated in Rack 2.0
  74. if (!hiddenJ)
  75. hiddenJ = json_object_get(rootJ, "disabled");
  76. if (hiddenJ) {
  77. // Don't un-hide Model if already hidden by C++
  78. if (json_boolean_value(hiddenJ))
  79. hidden = true;
  80. }
  81. }
  82. std::string Model::getFullName() {
  83. DISTRHO_SAFE_ASSERT_RETURN(plugin, {});
  84. return plugin->getBrand() + " " + name;
  85. }
  86. std::string Model::getFactoryPresetDirectory() {
  87. return asset::plugin(plugin, system::join("presets", slug));
  88. }
  89. std::string Model::getUserPresetDirectory() {
  90. return asset::user(system::join("presets", plugin->slug, slug));
  91. }
  92. std::string Model::getManualUrl() {
  93. if (!manualUrl.empty())
  94. return manualUrl;
  95. return plugin->manualUrl;
  96. }
  97. void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) {
  98. // plugin
  99. menu->addChild(createMenuItem("Plugin: " + plugin->name, "", [=]() {
  100. patchUtils::openBrowser(plugin->pluginUrl);
  101. }, plugin->pluginUrl == ""));
  102. // version
  103. menu->addChild(createMenuLabel("Version: " + plugin->version));
  104. // author
  105. if (plugin->author != "") {
  106. menu->addChild(createMenuItem("Author: " + plugin->author, "", [=]() {
  107. patchUtils::openBrowser(plugin->authorUrl);
  108. }, plugin->authorUrl.empty()));
  109. }
  110. // license
  111. std::string license = plugin->license;
  112. if (string::startsWith(license, "https://") || string::startsWith(license, "http://")) {
  113. menu->addChild(createMenuItem("License: Open in browser", "", [=]() {
  114. patchUtils::openBrowser(license);
  115. }));
  116. }
  117. else if (license != "") {
  118. menu->addChild(createMenuLabel("License: " + license));
  119. }
  120. // tags
  121. if (!tagIds.empty()) {
  122. menu->addChild(createMenuLabel("Tags:"));
  123. for (int tagId : tagIds) {
  124. menu->addChild(createMenuLabel("• " + tag::getTag(tagId)));
  125. }
  126. }
  127. menu->addChild(new ui::MenuSeparator);
  128. // manual
  129. std::string manualUrl = getManualUrl();
  130. if (manualUrl != "") {
  131. menu->addChild(createMenuItem("User manual", RACK_MOD_CTRL_NAME "+F1", [=]() {
  132. patchUtils::openBrowser(manualUrl);
  133. }));
  134. }
  135. // donate
  136. if (plugin->donateUrl != "") {
  137. menu->addChild(createMenuItem("Donate", "", [=]() {
  138. patchUtils::openBrowser(plugin->donateUrl);
  139. }));
  140. }
  141. // source code
  142. if (plugin->sourceUrl != "") {
  143. menu->addChild(createMenuItem("Source code", "", [=]() {
  144. patchUtils::openBrowser(plugin->sourceUrl);
  145. }));
  146. }
  147. // changelog
  148. if (plugin->changelogUrl != "") {
  149. menu->addChild(createMenuItem("Changelog", "", [=]() {
  150. patchUtils::openBrowser(plugin->changelogUrl);
  151. }));
  152. }
  153. // Favorite
  154. std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : "";
  155. if (isFavorite())
  156. favoriteRightText += " " CHECKMARK_STRING;
  157. menu->addChild(createMenuItem("Favorite", favoriteRightText,
  158. [=]() {
  159. setFavorite(!isFavorite());
  160. }
  161. ));
  162. }
  163. bool Model::isFavorite() {
  164. const settings::ModuleInfo* mi = settings::getModuleInfo(plugin->slug, slug);
  165. return mi && mi->favorite;
  166. }
  167. void Model::setFavorite(bool favorite) {
  168. settings::ModuleInfo& mi = settings::moduleInfos[plugin->slug][slug];
  169. mi.favorite = favorite;
  170. }
  171. } // namespace plugin
  172. } // namespace rack