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.

217 lines
5.1KB

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