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.

226 lines
5.9KB

  1. #include <algorithm>
  2. #include <plugin/Model.hpp>
  3. #include <plugin.hpp>
  4. #include <asset.hpp>
  5. #include <system.hpp>
  6. #include <settings.hpp>
  7. #include <string.hpp>
  8. #include <tag.hpp>
  9. #include <ui/Menu.hpp>
  10. #include <ui/MenuSeparator.hpp>
  11. #include <helpers.hpp>
  12. #include <window/Window.hpp>
  13. namespace rack {
  14. namespace plugin {
  15. void Model::fromJson(json_t* rootJ) {
  16. assert(plugin);
  17. json_t* nameJ = json_object_get(rootJ, "name");
  18. if (nameJ)
  19. name = json_string_value(nameJ);
  20. if (name == "")
  21. throw Exception("Module %s/%s has no name", plugin->slug.c_str(), slug.c_str());
  22. json_t* descriptionJ = json_object_get(rootJ, "description");
  23. if (descriptionJ)
  24. description = json_string_value(descriptionJ);
  25. // Tags
  26. tagIds.clear();
  27. json_t* tagsJ = json_object_get(rootJ, "tags");
  28. if (tagsJ) {
  29. size_t i;
  30. json_t* tagJ;
  31. json_array_foreach(tagsJ, i, tagJ) {
  32. std::string tag = json_string_value(tagJ);
  33. int tagId = tag::findId(tag);
  34. if (tagId < 0) {
  35. // WARN("Module %s/%s has invalid tag \"%s\"", plugin->slug.c_str(), slug.c_str(), tag.c_str());
  36. continue;
  37. }
  38. // Omit duplicates
  39. auto it = std::find(tagIds.begin(), tagIds.end(), tagId);
  40. if (it != tagIds.end()) {
  41. // WARN("Module %s/%s has duplicate tag \"%s\"", plugin->slug.c_str(), slug.c_str(), tag.c_str());
  42. continue;
  43. }
  44. tagIds.push_back(tagId);
  45. }
  46. }
  47. // manualUrl
  48. json_t* manualUrlJ = json_object_get(rootJ, "manualUrl");
  49. if (manualUrlJ)
  50. manualUrl = json_string_value(manualUrlJ);
  51. // modularGridUrl
  52. json_t* modularGridUrlJ = json_object_get(rootJ, "modularGridUrl");
  53. if (modularGridUrlJ)
  54. modularGridUrl = json_string_value(modularGridUrlJ);
  55. // hidden
  56. json_t* hiddenJ = json_object_get(rootJ, "hidden");
  57. // "disabled" was a deprecated alias in Rack <2
  58. if (!hiddenJ)
  59. hiddenJ = json_object_get(rootJ, "disabled");
  60. // "deprecated" was a deprecated alias in Rack <2.2.4
  61. if (!hiddenJ)
  62. hiddenJ = json_object_get(rootJ, "deprecated");
  63. if (hiddenJ) {
  64. // Don't un-hide Model if already hidden by C++
  65. if (json_boolean_value(hiddenJ))
  66. hidden = true;
  67. }
  68. }
  69. std::string Model::getFullName() {
  70. assert(plugin);
  71. return plugin->getBrand() + " " + name;
  72. }
  73. std::string Model::getFactoryPresetDirectory() {
  74. return asset::plugin(plugin, system::join("presets", slug));
  75. }
  76. std::string Model::getUserPresetDirectory() {
  77. return asset::user(system::join("presets", plugin->slug, slug));
  78. }
  79. std::string Model::getManualUrl() {
  80. if (!manualUrl.empty())
  81. return manualUrl;
  82. return plugin->manualUrl;
  83. }
  84. void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) {
  85. // plugin
  86. menu->addChild(createMenuItem(string::translate("Model.plugin") + plugin->name, "", [=]() {
  87. system::openBrowser(plugin->pluginUrl);
  88. }, plugin->pluginUrl == ""));
  89. // version
  90. menu->addChild(createMenuLabel(string::translate("Model.version") + plugin->version));
  91. // author
  92. if (plugin->author != "") {
  93. menu->addChild(createMenuItem(string::translate("Model.author") + plugin->author, "", [=]() {
  94. system::openBrowser(plugin->authorUrl);
  95. }, plugin->authorUrl.empty()));
  96. }
  97. // license
  98. std::string license = plugin->license;
  99. if (string::startsWith(license, "https://") || string::startsWith(license, "http://")) {
  100. menu->addChild(createMenuItem(string::translate("Model.licenseBrowser"), "", [=]() {
  101. system::openBrowser(license);
  102. }));
  103. }
  104. else if (license != "") {
  105. menu->addChild(createMenuLabel(string::translate("Model.license") + license));
  106. }
  107. // tags
  108. if (!tagIds.empty()) {
  109. menu->addChild(createMenuLabel(string::translate("Model.tags")));
  110. for (int tagId : tagIds) {
  111. std::string tag = string::translate("tag." + tag::getTag(tagId));
  112. menu->addChild(createMenuLabel("• " + tag));
  113. }
  114. }
  115. menu->addChild(new ui::MenuSeparator);
  116. // VCV Library page
  117. menu->addChild(createMenuItem(string::translate("Model.library"), "", [=]() {
  118. system::openBrowser("https://library.vcvrack.com/" + plugin->slug + "/" + slug);
  119. }));
  120. // modularGridUrl
  121. if (modularGridUrl != "") {
  122. menu->addChild(createMenuItem(string::translate("Model.modularGrid"), "", [=]() {
  123. system::openBrowser(modularGridUrl);
  124. }));
  125. }
  126. // manual
  127. std::string manualUrl = getManualUrl();
  128. if (manualUrl != "") {
  129. menu->addChild(createMenuItem(string::translate("Model.manual"), widget::getKeyCommandName(GLFW_KEY_F1, RACK_MOD_CTRL), [=]() {
  130. system::openBrowser(manualUrl);
  131. }));
  132. }
  133. // donate
  134. if (plugin->donateUrl != "") {
  135. menu->addChild(createMenuItem(string::translate("Model.donate"), "", [=]() {
  136. system::openBrowser(plugin->donateUrl);
  137. }));
  138. }
  139. // source code
  140. if (plugin->sourceUrl != "") {
  141. menu->addChild(createMenuItem(string::translate("Model.source"), "", [=]() {
  142. system::openBrowser(plugin->sourceUrl);
  143. }));
  144. }
  145. // changelog
  146. if (plugin->changelogUrl != "") {
  147. menu->addChild(createMenuItem(string::translate("Model.changelog"), "", [=]() {
  148. system::openBrowser(plugin->changelogUrl);
  149. }));
  150. }
  151. // author email
  152. if (plugin->authorEmail != "") {
  153. menu->addChild(createMenuItem(string::translate("Model.authorEmail"), string::translate("Model.authorEmailCopy"), [=]() {
  154. glfwSetClipboardString(APP->window->win, plugin->authorEmail.c_str());
  155. }));
  156. }
  157. // plugin folder
  158. if (plugin->path != "") {
  159. menu->addChild(createMenuItem(string::translate("Model.pluginDir"), "", [=]() {
  160. system::openDirectory(plugin->path);
  161. }));
  162. }
  163. // Favorite
  164. std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : "";
  165. if (isFavorite())
  166. favoriteRightText += " " CHECKMARK_STRING;
  167. menu->addChild(createMenuItem(string::translate("Model.favorite"), favoriteRightText,
  168. [=]() {
  169. setFavorite(!isFavorite());
  170. }
  171. ));
  172. }
  173. bool Model::isFavorite() {
  174. const settings::ModuleInfo* mi = settings::getModuleInfo(plugin->slug, slug);
  175. return mi && mi->favorite;
  176. }
  177. void Model::setFavorite(bool favorite) {
  178. settings::ModuleInfo& mi = settings::moduleInfos[plugin->slug][slug];
  179. mi.favorite = favorite;
  180. }
  181. } // namespace plugin
  182. } // namespace rack