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.

722 lines
20KB

  1. #include "SubControls.hpp"
  2. #include <map>
  3. #include <algorithm>
  4. #include "global_pre.hpp"
  5. #include "global_ui.hpp"
  6. #include "app.hpp"
  7. #include "window.hpp"
  8. #include "osdialog.h"
  9. #include "util/common.hpp"
  10. namespace rack_plugin_SubmarineUtility {
  11. struct ModBrowserWidget;
  12. struct ListElement {
  13. ModBrowserWidget *mbw;
  14. virtual void onAction(EventAction &e) { debug ("Not Implemented"); }
  15. virtual std::string GetLabelOne() { return std::string("Label 1"); };
  16. virtual std::string GetLabelTwo() { return std::string("Label 2"); };
  17. };
  18. struct TextButton : SubControls::ButtonBase {
  19. std::string label1;
  20. std::string label2;
  21. std::shared_ptr<ListElement> element;
  22. float label1Width = 0;
  23. float label2Width = 0;
  24. void CalculateSizes(NVGcontext *vg, float zoom) {
  25. nvgFontFaceId(vg, rack::global_ui->window.gGuiFont->handle);
  26. nvgFontSize(vg, 13 * zoom);
  27. float bounds[4];
  28. nvgTextBounds(vg, zoom, box.size.y / 2, label1.c_str(), NULL, bounds);
  29. label1Width = bounds[2] - bounds[0];
  30. nvgTextBounds(vg, zoom, box.size.y / 2, label2.c_str(), NULL, bounds);
  31. label2Width = bounds[2] - bounds[0];
  32. }
  33. void draw (NVGcontext *vg) override {
  34. float zoom = 1.0f / clamp(RACK_PLUGIN_UI_RACKSCENE->zoomWidget->zoom, 0.25f, 1.0f);
  35. //if (label1Width == 0.0f)
  36. CalculateSizes(vg, zoom);
  37. if (RACK_PLUGIN_UI_DRAGGED_WIDGET == this) {
  38. nvgBeginPath(vg);
  39. nvgRect(vg, 0, 0, box.size.x - 2, box.size.y);
  40. nvgFillColor(vg, nvgRGB(0x40, 0x40, 0x40));
  41. nvgFill(vg);
  42. }
  43. nvgFontFaceId(vg, rack::global_ui->window.gGuiFont->handle);
  44. nvgFontSize(vg, 13 * zoom);
  45. // Draw secondary text
  46. nvgFillColor(vg, nvgRGB(0x80, 0x80, 0x80));
  47. nvgTextAlign(vg, NVG_ALIGN_MIDDLE | NVG_ALIGN_RIGHT);
  48. nvgText(vg, box.size.x - zoom, box.size.y / 2, label2.c_str(), NULL);
  49. // If text overlaps, feather out overlap
  50. if (label1Width + label2Width > box.size.x) {
  51. NVGpaint grad;
  52. if (RACK_PLUGIN_UI_DRAGGED_WIDGET == this) {
  53. nvgFillColor(vg, nvgRGB(0x40, 0x40, 0x40));
  54. grad = nvgLinearGradient(vg, label1Width, 0, label1Width + 10, 0, nvgRGBA(0x20, 0x20, 0x20, 0xff), nvgRGBA(0x20, 0x20, 0x20, 0));
  55. }
  56. else {
  57. nvgFillColor(vg, nvgRGB(0, 0, 0));
  58. grad = nvgLinearGradient(vg, label1Width, 0, label1Width + 10, 0, nvgRGBA(0, 0, 0, 0xff), nvgRGBA(0, 0, 0, 0));
  59. }
  60. nvgBeginPath(vg);
  61. nvgRect(vg, box.size.x - label2Width, 0, label1Width - box.size.x + label2Width, box.size.y);
  62. nvgFill(vg);
  63. nvgBeginPath(vg);
  64. nvgRect(vg, label1Width, 0, 10, box.size.y);
  65. nvgFillPaint(vg, grad);
  66. nvgFill(vg);
  67. }
  68. // Draw primary text
  69. nvgFillColor(vg, nvgRGB(0xff, 0xff, 0xff));
  70. nvgTextAlign(vg, NVG_ALIGN_MIDDLE);
  71. nvgText(vg, zoom, box.size.y / 2, label1.c_str(), NULL);
  72. Component::draw(vg);
  73. }
  74. void GetLabels() {
  75. label1 = element->GetLabelOne();
  76. label2 = element->GetLabelTwo();
  77. }
  78. void onAction(EventAction &e) override {
  79. element->onAction(e);
  80. }
  81. };
  82. // Icons
  83. struct MBIconWidget : SubControls::ButtonBase,SVGWidget {
  84. ModBrowserWidget *mbw;
  85. };
  86. struct PluginIcon : MBIconWidget {
  87. int selected = 0;
  88. PluginIcon() {
  89. box.size.x = 30;
  90. box.size.y = 30;
  91. }
  92. void onAction(EventAction &e) override;
  93. };
  94. struct TagIcon : MBIconWidget {
  95. int selected = 0;
  96. TagIcon() {
  97. box.size.x = 30;
  98. box.size.y = 30;
  99. }
  100. void onAction(EventAction &e) override;
  101. };
  102. struct FavIcon : MBIconWidget {
  103. int selected = 0;
  104. FavIcon() {
  105. box.size.x = 30;
  106. box.size.y = 30;
  107. }
  108. void onAction(EventAction &e) override;
  109. };
  110. struct LoadIcon : MBIconWidget {
  111. int selected = 0;
  112. LoadIcon() {
  113. box.size.x = 30;
  114. box.size.y = 30;
  115. }
  116. void onAction(EventAction &e) override;
  117. };
  118. struct MinimizeIcon : MBIconWidget {
  119. MinimizeIcon() {
  120. box.size.x = 30;
  121. box.size.y = 30;
  122. }
  123. void onAction(EventAction &e) override;
  124. };
  125. // Elements
  126. struct ModelElement : ListElement {
  127. Model *model;
  128. std::string GetLabelOne() override {
  129. return model->name;
  130. }
  131. std::string GetLabelTwo() override {
  132. #undef plugin
  133. return model->plugin->slug;
  134. #define plugin "SubmarineUtility"
  135. }
  136. void onAction(EventAction &e) override;
  137. };
  138. struct PluginElement : ListElement {
  139. std::string label;
  140. std::string GetLabelOne() override {
  141. return label;
  142. }
  143. std::string GetLabelTwo() override;
  144. void onAction(EventAction &e) override;
  145. };
  146. struct TagElement : ListElement {
  147. unsigned int tag;
  148. std::string GetLabelOne() override {
  149. return gTagNames[tag];
  150. }
  151. std::string GetLabelTwo() override;
  152. void onAction(EventAction &e) override;
  153. };
  154. struct PluginBackElement : ListElement {
  155. std::string label2;
  156. std::string GetLabelOne() override {
  157. return std::string("\xe2\x86\x90 Back");
  158. }
  159. std::string GetLabelTwo() override {
  160. return label2;
  161. }
  162. void onAction(EventAction &e) override;
  163. };
  164. struct TagBackElement : ListElement {
  165. std::string label2;
  166. std::string GetLabelOne() override {
  167. return std::string("\xe2\x86\x90 Back");
  168. }
  169. std::string GetLabelTwo() override {
  170. return label2;
  171. }
  172. void onAction(EventAction &e) override;
  173. };
  174. struct ModBrowserWidget : SubControls::SizeableModuleWidget {
  175. Widget *scrollContainer;
  176. ScrollWidget *scrollWidget;
  177. PluginIcon *pluginIcon;
  178. TagIcon *tagIcon;
  179. FavIcon *favIcon;
  180. LoadIcon *loadIcon;
  181. MinimizeIcon *minimizeIcon;
  182. float width;
  183. float zoom = 1.0f;
  184. std::list<std::shared_ptr<PluginElement>> pluginList;
  185. std::list<std::shared_ptr<TagElement>> tagList;
  186. std::list<std::shared_ptr<ModelElement>> modelList;
  187. std::string allfilters;
  188. std::string lastPath;
  189. ModBrowserWidget(Module *module) : SubControls::SizeableModuleWidget(module) {
  190. moduleName = "Module Browser";
  191. zoom = clamp(RACK_PLUGIN_UI_RACKSCENE->zoomWidget->zoom, 0.25f, 1.0f);
  192. allfilters.assign(PATCH_FILTERS);
  193. allfilters.append(";");
  194. allfilters.append(PRESET_FILTERS);
  195. pluginIcon = Widget::create<PluginIcon>(Vec(2, 2));
  196. pluginIcon->selected = 1;
  197. pluginIcon->mbw = this;
  198. pluginIcon->setSVG(SVG::load(assetPlugin(plugin, "res/plugin.svg")));
  199. backPanel->addChild(pluginIcon);
  200. tagIcon = Widget::create<TagIcon>(Vec(34, 2));
  201. tagIcon->mbw = this;
  202. tagIcon->setSVG(SVG::load(assetPlugin(plugin, "res/tag.svg")));
  203. backPanel->addChild(tagIcon);
  204. favIcon = Widget::create<FavIcon>(Vec(66, 2));
  205. favIcon->mbw = this;
  206. favIcon->setSVG(SVG::load(assetPlugin(plugin, "res/favorite.svg")));
  207. backPanel->addChild(favIcon);
  208. loadIcon = Widget::create<LoadIcon>(Vec(98, 2));
  209. loadIcon->mbw = this;
  210. loadIcon->setSVG(SVG::load(assetPlugin(plugin, "res/load.svg")));
  211. backPanel->addChild(loadIcon);
  212. minimizeIcon = Widget::create<MinimizeIcon>(Vec(130, 2));
  213. minimizeIcon->mbw = this;
  214. minimizeIcon->setSVG(SVG::load(assetPlugin(plugin, "res/min.svg")));
  215. backPanel->addChild(minimizeIcon);
  216. scrollWidget = Widget::create<ScrollWidget>(Vec(0, 35));
  217. scrollWidget->box.size.x = box.size.x - 20;
  218. scrollWidget->box.size.y = box.size.y - 65;
  219. width = scrollWidget->box.size.x - 20;
  220. backPanel->addChild(scrollWidget);
  221. scrollContainer = scrollWidget->container;
  222. for (unsigned int i = 1; i < NUM_TAGS; i++) {
  223. std::shared_ptr<TagElement> te = std::make_shared<TagElement>();
  224. te->mbw = this;
  225. te->tag = i;
  226. tagList.push_back(te);
  227. }
  228. // Sort Tags (probably already sorted)
  229. tagList.sort([](std::shared_ptr<TagElement> te1, std::shared_ptr<TagElement> te2) { return gTagNames[te1->tag].compare(gTagNames[te2->tag]) < 0; } );
  230. #undef plugin
  231. for (Plugin *plugin : rack::global->plugin.gPlugins) {
  232. for (Model *model : plugin->models) {
  233. std::shared_ptr<ModelElement> me = std::make_shared<ModelElement>();
  234. me->mbw = this;
  235. me->model = model;
  236. modelList.push_back(me);
  237. int found = false;
  238. for (std::shared_ptr<PluginElement> pe : pluginList) {
  239. if (!pe->label.compare(me->model->author)) {
  240. found = true;
  241. break;
  242. }
  243. }
  244. if (!found) {
  245. std::shared_ptr<PluginElement> pe = std::make_shared<PluginElement>();
  246. pe->mbw = this;
  247. pe->label.assign(me->model->author);
  248. pluginList.push_back(pe);
  249. }
  250. }
  251. }
  252. // Sort Plugins/Authors
  253. pluginList.sort([](std::shared_ptr<PluginElement> pe1, std::shared_ptr<PluginElement> pe2) { return stringLowercase(pe1->label).compare(stringLowercase(pe2->label)) < 0; } );
  254. AddPlugins();
  255. }
  256. void ResetIcons() {
  257. pluginIcon->selected = 0;
  258. tagIcon->selected = 0;
  259. favIcon->selected = 0;
  260. }
  261. void onResize() override {
  262. scrollWidget->box.size.x = box.size.x - 20;
  263. SetListWidth();
  264. }
  265. void SetListWidth() {
  266. float width = scrollContainer->parent->box.size.x;
  267. float size = 15.0f / zoom;
  268. if (scrollContainer->children.size() * size > scrollContainer->parent->box.size.y)
  269. width -= 13;
  270. float position = 0;
  271. for (Widget *w : scrollContainer->children) {
  272. w->box.pos.y = position;
  273. w->box.size.x = width;
  274. position += w->box.size.y = size;
  275. }
  276. }
  277. void AddElement(std::shared_ptr<ListElement> le, float y) {
  278. TextButton *tb = Widget::create<TextButton>(Vec(0, y));
  279. tb->element = le;
  280. tb->GetLabels();
  281. tb->box.size.x = width;
  282. tb->box.size.y = 15;
  283. scrollContainer->addChild(tb);
  284. }
  285. void AddPlugins() {
  286. scrollContainer->clearChildren();
  287. unsigned int y = 0;
  288. for (std::shared_ptr<PluginElement> pe : pluginList) {
  289. AddElement(pe, y);
  290. y += 15;
  291. }
  292. SetListWidth();
  293. }
  294. void AddTags() {
  295. scrollContainer->clearChildren();
  296. unsigned int y = 0;
  297. for (std::shared_ptr<TagElement> te : tagList) {
  298. AddElement(te, y);
  299. y += 15;
  300. }
  301. SetListWidth();
  302. }
  303. void AddFavorites() {
  304. scrollContainer->clearChildren();
  305. unsigned int y = 0;
  306. FILE *file = fopen(assetLocal("settings.json").c_str(), "r");
  307. if (!file)
  308. return;
  309. json_error_t error;
  310. json_t *rootJ = json_loadf(file, 0, &error);
  311. if (!rootJ) {
  312. warn("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
  313. fclose(file);
  314. return;
  315. }
  316. json_t *modb = json_object_get(rootJ, "moduleBrowser");
  317. if (modb) {
  318. json_t *favoritesJ = json_object_get(modb, "favorites");
  319. if (favoritesJ) {
  320. size_t i;
  321. json_t *favoriteJ;
  322. json_array_foreach(favoritesJ, i, favoriteJ) {
  323. json_t *pluginJ = json_object_get(favoriteJ, "plugin");
  324. json_t *modelJ = json_object_get(favoriteJ, "model");
  325. if (!pluginJ || !modelJ)
  326. continue;
  327. std::string pluginSlug = json_string_value(pluginJ);
  328. std::string modelSlug = json_string_value(modelJ);
  329. Model *model = pluginGetModel(pluginSlug, modelSlug);
  330. if (!model)
  331. continue;
  332. for (std::shared_ptr<ModelElement> me : modelList) {
  333. if (me->model == model) {
  334. AddElement(me, y);
  335. y += 15;
  336. }
  337. }
  338. }
  339. }
  340. }
  341. json_decref(rootJ);
  342. fclose(file);
  343. SetListWidth();
  344. }
  345. void AddModels(std::string author) {
  346. scrollContainer->clearChildren();
  347. std::shared_ptr<PluginBackElement> pbe = std::make_shared<PluginBackElement>();
  348. pbe->mbw = this;
  349. pbe->label2 = author;
  350. AddElement(pbe, 0);
  351. unsigned int y = 15;
  352. for (std::shared_ptr<ModelElement> me : modelList) {
  353. if (!me->model->author.compare(author)) {
  354. AddElement(me, y);
  355. y += 15;
  356. }
  357. }
  358. SetListWidth();
  359. }
  360. void AddModels(unsigned int tag) {
  361. scrollContainer->clearChildren();
  362. std::shared_ptr<TagBackElement> tbe = std::make_shared<TagBackElement>();
  363. tbe->mbw = this;
  364. tbe->label2 = gTagNames[tag];
  365. AddElement(tbe, 0);
  366. unsigned int y = 15;
  367. for (std::shared_ptr<ModelElement> me : modelList) {
  368. for (ModelTag mt : me->model->tags) {
  369. if (mt == tag) {
  370. AddElement(me, y);
  371. y += 15;
  372. }
  373. }
  374. }
  375. SetListWidth();
  376. }
  377. void Load() {
  378. if (lastPath.empty()) {
  379. if (RACK_PLUGIN_UI_RACKWIDGET->lastPath.empty()) {
  380. lastPath = assetLocal("patches");
  381. systemCreateDirectory(lastPath);
  382. }
  383. else {
  384. lastPath = stringDirectory(RACK_PLUGIN_UI_RACKWIDGET->lastPath);
  385. }
  386. }
  387. osdialog_filters *filters = osdialog_filters_parse(allfilters.c_str());
  388. char *path = osdialog_file(OSDIALOG_OPEN, lastPath.c_str(), NULL, filters);
  389. if (path) {
  390. Load(path);
  391. lastPath = stringDirectory(path);
  392. free(path);
  393. }
  394. osdialog_filters_free(filters);
  395. }
  396. void Load(std::string filename) {
  397. FILE *file = fopen(filename.c_str(), "r");
  398. if (!file) {
  399. debug("Unable to open patch %s", filename.c_str());
  400. return;
  401. }
  402. json_error_t error;
  403. json_t *rootJ = json_loadf(file, 0, &error);
  404. if (rootJ) {
  405. Load(rootJ);
  406. json_decref(rootJ);
  407. }
  408. else {
  409. std::string message = stringf("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
  410. osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
  411. }
  412. fclose(file);
  413. }
  414. void LoadPreset(json_t *rootJ) {
  415. ModuleWidget *moduleWidget = RACK_PLUGIN_UI_RACKWIDGET->moduleFromJson(rootJ);
  416. if (moduleWidget) {
  417. moduleWidget->box.pos = RACK_PLUGIN_UI_RACKWIDGET->lastMousePos.minus(moduleWidget->box.size.div(2));
  418. RACK_PLUGIN_UI_RACKWIDGET->requestModuleBoxNearest(moduleWidget, moduleWidget->box);
  419. }
  420. }
  421. void Load(json_t *rootJ) {
  422. std::string message;
  423. Rect newBox;
  424. newBox.pos.x = -1;
  425. //load modules
  426. std::map<int, ModuleWidget *> moduleWidgets;
  427. json_t *modulesJ = json_object_get(rootJ, "modules");
  428. if (!modulesJ) {
  429. LoadPreset(rootJ);
  430. return;
  431. }
  432. std::vector<Widget *> existingWidgets;
  433. for (Widget *child : RACK_PLUGIN_UI_RACKWIDGET->moduleContainer->children) {
  434. existingWidgets.push_back(child);
  435. }
  436. size_t moduleId;
  437. json_t *moduleJ;
  438. json_array_foreach(modulesJ, moduleId, moduleJ) {
  439. ModuleWidget *moduleWidget = RACK_PLUGIN_UI_RACKWIDGET->moduleFromJson(moduleJ);
  440. if (moduleWidget) {
  441. json_t *posJ = json_object_get(moduleJ, "pos");
  442. double x, y;
  443. json_unpack(posJ, "[F, F]", &x, &y);
  444. Vec pos = Vec(x,y);
  445. moduleWidget->box.pos = pos.mult(RACK_GRID_SIZE);
  446. moduleWidgets[moduleId] = moduleWidget;
  447. if (newBox.pos.x == -1) {
  448. newBox.pos.x = moduleWidget->box.pos.x;
  449. newBox.pos.y = moduleWidget->box.pos.y;
  450. newBox.size.x = moduleWidget->box.size.x;
  451. newBox.size.y = moduleWidget->box.size.y;
  452. }
  453. else {
  454. Rect mbox = moduleWidget->box;
  455. if (mbox.pos.x < newBox.pos.x) {
  456. newBox.size.x += newBox.pos.x - mbox.pos.x;
  457. newBox.pos.x = mbox.pos.x;
  458. }
  459. if (mbox.pos.y < newBox.pos.y) {
  460. newBox.size.y += newBox.pos.y - mbox.pos.y;
  461. newBox.pos.y = mbox.pos.y;
  462. }
  463. if ((mbox.pos.x + mbox.size.x) > (newBox.pos.x + newBox.size.x)) {
  464. newBox.size.x = mbox.pos.x + mbox.size.x - newBox.pos.x;
  465. }
  466. if ((mbox.pos.y + mbox.size.y) > (newBox.pos.y + newBox.size.y)) {
  467. newBox.size.y = mbox.pos.y + mbox.size.y - newBox.pos.y;
  468. }
  469. }
  470. }
  471. }
  472. //find space for modules and arrange
  473. Rect space = FindSpace(existingWidgets, newBox);
  474. if (space.pos.x == -1) {
  475. // oooh noes!!! couldn't find space for these widgets
  476. warn("Module browser could not find space to load patch");
  477. for (const auto& kvp : moduleWidgets) {
  478. RACK_PLUGIN_UI_RACKWIDGET->deleteModule(kvp.second);
  479. kvp.second->finalizeEvents();
  480. delete kvp.second;
  481. }
  482. return;
  483. }
  484. // Move modules into space
  485. float dx = space.pos.x - newBox.pos.x;
  486. float dy = space.pos.y - newBox.pos.y;
  487. for (const auto& kvp : moduleWidgets) {
  488. kvp.second->box.pos.x += dx;
  489. kvp.second->box.pos.y += dy;
  490. }
  491. //wires
  492. json_t *wiresJ = json_object_get(rootJ, "wires");
  493. if (!wiresJ) return;
  494. size_t wireId;
  495. json_t *wireJ;
  496. json_array_foreach(wiresJ, wireId, wireJ) {
  497. int outputModuleId = json_integer_value(json_object_get(wireJ, "outputModuleId"));
  498. int outputId = json_integer_value(json_object_get(wireJ, "outputId"));
  499. int inputModuleId = json_integer_value(json_object_get(wireJ, "inputModuleId"));
  500. int inputId = json_integer_value(json_object_get(wireJ, "inputId"));
  501. ModuleWidget *outputModuleWidget = moduleWidgets[outputModuleId];
  502. if (!outputModuleWidget) continue;
  503. ModuleWidget *inputModuleWidget = moduleWidgets[inputModuleId];
  504. if (!inputModuleWidget) continue;
  505. Port *outputPort = NULL;
  506. Port *inputPort = NULL;
  507. for (Port *port : outputModuleWidget->outputs) {
  508. if (port->portId == outputId) {
  509. outputPort = port;
  510. break;
  511. }
  512. }
  513. for (Port *port : inputModuleWidget->inputs) {
  514. if (port->portId == inputId) {
  515. inputPort = port;
  516. break;
  517. }
  518. }
  519. if (!outputPort || !inputPort)
  520. continue;
  521. WireWidget *wireWidget = new WireWidget();
  522. wireWidget->fromJson(wireJ);
  523. wireWidget->outputPort = outputPort;
  524. wireWidget->inputPort = inputPort;
  525. wireWidget->updateWire();
  526. RACK_PLUGIN_UI_RACKWIDGET->wireContainer->addChild(wireWidget);
  527. }
  528. }
  529. Rect FindSpace(std::vector<Widget *> existingWidgets, Rect box) {
  530. int x0 = roundf(box.pos.x / RACK_GRID_WIDTH);
  531. int y0 = roundf(box.pos.y / RACK_GRID_HEIGHT);
  532. std::vector<Vec> positions;
  533. for (int y = max(0, y0 - 8); y < y0 + 8; y++) {
  534. for (int x = max(0, x0 - 400); x < x0 + 400; x++) {
  535. positions.push_back(Vec(x * RACK_GRID_WIDTH, y * RACK_GRID_HEIGHT));
  536. }
  537. }
  538. std::sort(positions.begin(), positions.end(), [box](Vec a, Vec b) {
  539. return a.minus(box.pos).norm() < b.minus(box.pos).norm();
  540. });
  541. for (Vec position : positions) {
  542. Rect newBox = box;
  543. newBox.pos = position;
  544. int collide = false;
  545. for (Widget *child : existingWidgets) {
  546. if (newBox.intersects(child->box)) {
  547. collide = true;
  548. break;
  549. }
  550. }
  551. if (!collide) {
  552. return newBox;
  553. }
  554. }
  555. Rect failed;
  556. failed.pos.x = -1;
  557. return failed;
  558. }
  559. void step() override {
  560. float thisZoom = clamp(RACK_PLUGIN_UI_RACKSCENE->zoomWidget->zoom, 0.25f, 1.0f);
  561. if (thisZoom != zoom) {
  562. zoom = thisZoom;
  563. SetListWidth();
  564. }
  565. stabilized = true;
  566. ModuleWidget::step();
  567. }
  568. };
  569. // Icon onAction
  570. void PluginIcon::onAction(EventAction &e) {
  571. mbw->ResetIcons();
  572. mbw->pluginIcon->selected = 1;
  573. mbw->AddPlugins();
  574. }
  575. void TagIcon::onAction(EventAction &e) {
  576. mbw->ResetIcons();
  577. mbw->tagIcon->selected = 1;
  578. mbw->AddTags();
  579. }
  580. void FavIcon::onAction(EventAction &e) {
  581. mbw->pluginIcon->selected = 0;
  582. mbw->favIcon->selected = 1;
  583. mbw->AddFavorites();
  584. }
  585. void LoadIcon::onAction(EventAction &e) {
  586. mbw->Load();
  587. }
  588. void MinimizeIcon::onAction(EventAction &e) {
  589. mbw->Minimize(true);
  590. }
  591. // Element onAction
  592. void PluginElement::onAction(EventAction &e) {
  593. mbw->AddModels(label);
  594. }
  595. std::string PluginElement::GetLabelTwo() {
  596. unsigned int count = 0;
  597. for (std::shared_ptr<ModelElement> me : mbw->modelList) {
  598. if (!label.compare(me->model->author))
  599. count++;
  600. }
  601. return std::to_string(count).append(" Modules");
  602. }
  603. void TagElement::onAction(EventAction &e) {
  604. mbw->AddModels(tag);
  605. }
  606. std::string TagElement::GetLabelTwo() {
  607. unsigned int count = 0;
  608. for (std::shared_ptr<ModelElement> me : mbw->modelList) {
  609. for (ModelTag mt : me->model->tags) {
  610. if (mt == tag) {
  611. count++;
  612. }
  613. }
  614. }
  615. return std::to_string(count).append(" Modules");
  616. }
  617. void ModelElement::onAction(EventAction &e) {
  618. ModuleWidget *moduleWidget = model->createModuleWidget();
  619. if (!moduleWidget)
  620. return;
  621. RACK_PLUGIN_UI_RACKWIDGET->addModule(moduleWidget);
  622. moduleWidget->box.pos = RACK_PLUGIN_UI_RACKWIDGET->lastMousePos.minus(moduleWidget->box.size.div(2));
  623. RACK_PLUGIN_UI_RACKWIDGET->requestModuleBoxNearest(moduleWidget, moduleWidget->box);
  624. }
  625. void PluginBackElement::onAction(EventAction &e) {
  626. mbw->AddPlugins();
  627. }
  628. void TagBackElement::onAction(EventAction &e) {
  629. mbw->AddTags();
  630. }
  631. struct Blank2 : ModuleWidget {
  632. Blank2(Module *module) : ModuleWidget(module) {
  633. box.size = Vec(RACK_GRID_WIDTH * 5, RACK_GRID_HEIGHT * 2);
  634. {
  635. Panel *panel = new LightPanel();
  636. panel->box.size = box.size;
  637. addChild(panel);
  638. }
  639. }
  640. };
  641. struct Blank3 : ModuleWidget {
  642. Blank3(Module *module) : ModuleWidget(module) {
  643. box.size = Vec(RACK_GRID_WIDTH * 5, RACK_GRID_HEIGHT * 3);
  644. {
  645. Panel *panel = new LightPanel();
  646. panel->box.size = box.size;
  647. addChild(panel);
  648. }
  649. }
  650. };
  651. struct Blank5 : ModuleWidget {
  652. Blank5(Module *module) : ModuleWidget(module) {
  653. box.size = Vec(RACK_GRID_WIDTH * 5, RACK_GRID_HEIGHT * 5);
  654. {
  655. Panel *panel = new LightPanel();
  656. panel->box.size = box.size;
  657. addChild(panel);
  658. }
  659. }
  660. };
  661. } // namespace rack_plugin_SubmarineUtility
  662. using namespace rack_plugin_SubmarineUtility;
  663. RACK_PLUGIN_MODEL_INIT(SubmarineUtility, ModBrowser) {
  664. Model *modelModBrowser = Model::create<Module, ModBrowserWidget>("Submarine (Utilities)", "ModBrowser", "Module Browser", UTILITY_TAG);
  665. return modelModBrowser;
  666. }