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.

212 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. namespace rack {
  38. namespace plugin {
  39. void Model::fromJson(json_t* rootJ) {
  40. DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr,);
  41. json_t* nameJ = json_object_get(rootJ, "name");
  42. if (nameJ)
  43. name = json_string_value(nameJ);
  44. if (name == "")
  45. throw Exception("No module name for slug %s", slug.c_str());
  46. json_t* descriptionJ = json_object_get(rootJ, "description");
  47. if (descriptionJ)
  48. description = json_string_value(descriptionJ);
  49. // Tags
  50. tagIds.clear();
  51. json_t* tagsJ = json_object_get(rootJ, "tags");
  52. if (tagsJ) {
  53. size_t i;
  54. json_t* tagJ;
  55. json_array_foreach(tagsJ, i, tagJ) {
  56. std::string tag = json_string_value(tagJ);
  57. int tagId = tag::findId(tag);
  58. // Omit duplicates
  59. auto it = std::find(tagIds.begin(), tagIds.end(), tagId);
  60. if (it != tagIds.end())
  61. continue;
  62. if (tagId >= 0)
  63. tagIds.push_back(tagId);
  64. }
  65. }
  66. // manualUrl
  67. json_t* manualUrlJ = json_object_get(rootJ, "manualUrl");
  68. if (manualUrlJ)
  69. manualUrl = json_string_value(manualUrlJ);
  70. // hidden
  71. json_t* hiddenJ = json_object_get(rootJ, "hidden");
  72. // Use `disabled` as an alias which was deprecated in Rack 2.0
  73. if (!hiddenJ)
  74. hiddenJ = json_object_get(rootJ, "disabled");
  75. if (hiddenJ) {
  76. // Don't un-hide Model if already hidden by C++
  77. if (json_boolean_value(hiddenJ))
  78. hidden = true;
  79. }
  80. }
  81. std::string Model::getFullName() {
  82. DISTRHO_SAFE_ASSERT_RETURN(plugin, {});
  83. return plugin->getBrand() + " " + name;
  84. }
  85. std::string Model::getFactoryPresetDirectory() {
  86. return asset::plugin(plugin, system::join("presets", slug));
  87. }
  88. std::string Model::getUserPresetDirectory() {
  89. return asset::user(system::join("presets", plugin->slug, slug));
  90. }
  91. std::string Model::getManualUrl() {
  92. if (!manualUrl.empty())
  93. return manualUrl;
  94. return plugin->manualUrl;
  95. }
  96. void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) {
  97. // plugin
  98. menu->addChild(createMenuItem("Plugin: " + plugin->name, "", [=]() {
  99. system::openBrowser(plugin->pluginUrl);
  100. }, plugin->pluginUrl == ""));
  101. // version
  102. menu->addChild(createMenuLabel("Version: " + plugin->version));
  103. // author
  104. if (plugin->author != "") {
  105. menu->addChild(createMenuItem("Author: " + plugin->author, "", [=]() {
  106. system::openBrowser(plugin->authorUrl);
  107. }, plugin->authorUrl.empty()));
  108. }
  109. // license
  110. std::string license = plugin->license;
  111. if (string::startsWith(license, "https://") || string::startsWith(license, "http://")) {
  112. menu->addChild(createMenuItem("License: Open in browser", "", [=]() {
  113. system::openBrowser(license);
  114. }));
  115. }
  116. else if (license != "") {
  117. menu->addChild(createMenuLabel("License: " + license));
  118. }
  119. // tags
  120. if (!tagIds.empty()) {
  121. menu->addChild(createMenuLabel("Tags:"));
  122. for (int tagId : tagIds) {
  123. menu->addChild(createMenuLabel("• " + tag::getTag(tagId)));
  124. }
  125. }
  126. menu->addChild(new ui::MenuSeparator);
  127. // manual
  128. std::string manualUrl = getManualUrl();
  129. if (manualUrl != "") {
  130. menu->addChild(createMenuItem("User manual", RACK_MOD_CTRL_NAME "+F1", [=]() {
  131. system::openBrowser(manualUrl);
  132. }));
  133. }
  134. // donate
  135. if (plugin->donateUrl != "") {
  136. menu->addChild(createMenuItem("Donate", "", [=]() {
  137. system::openBrowser(plugin->donateUrl);
  138. }));
  139. }
  140. // source code
  141. if (plugin->sourceUrl != "") {
  142. menu->addChild(createMenuItem("Source code", "", [=]() {
  143. system::openBrowser(plugin->sourceUrl);
  144. }));
  145. }
  146. // changelog
  147. if (plugin->changelogUrl != "") {
  148. menu->addChild(createMenuItem("Changelog", "", [=]() {
  149. system::openBrowser(plugin->changelogUrl);
  150. }));
  151. }
  152. // Favorite
  153. std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : "";
  154. if (isFavorite())
  155. favoriteRightText += " " CHECKMARK_STRING;
  156. menu->addChild(createMenuItem("Favorite", favoriteRightText,
  157. [=]() {
  158. setFavorite(!isFavorite());
  159. }
  160. ));
  161. }
  162. bool Model::isFavorite() {
  163. const settings::ModuleInfo* mi = settings::getModuleInfo(plugin->slug, slug);
  164. return mi && mi->favorite;
  165. }
  166. void Model::setFavorite(bool favorite) {
  167. settings::ModuleInfo& mi = settings::moduleInfos[plugin->slug][slug];
  168. mi.favorite = favorite;
  169. }
  170. } // namespace plugin
  171. } // namespace rack