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.

192 lines
4.8KB

  1. #include "app/ModuleBrowser.hpp"
  2. #include "widgets/OpaqueWidget.hpp"
  3. #include "widgets/TransparentWidget.hpp"
  4. #include "widgets/ZoomWidget.hpp"
  5. #include "ui/Label.hpp"
  6. #include "ui/MenuOverlay.hpp"
  7. #include "app/ModuleWidget.hpp"
  8. #include "app/Scene.hpp"
  9. #include "plugin.hpp"
  10. #include "app.hpp"
  11. #include "history.hpp"
  12. #include <set>
  13. #include <algorithm>
  14. namespace rack {
  15. static std::set<Model*> sFavoriteModels;
  16. struct ModuleBox : OpaqueWidget {
  17. Model *model;
  18. bool initialized = false;
  19. void setModel(Model *model) {
  20. this->model = model;
  21. box.size.x = 70.f;
  22. box.size.y = std::ceil(RACK_GRID_SIZE.y * 0.5f);
  23. math::Vec p;
  24. p.y = box.size.y;
  25. box.size.y += 40.0;
  26. Label *nameLabel = new Label;
  27. nameLabel->text = model->name;
  28. nameLabel->box.pos = p;
  29. p.y += nameLabel->box.size.y;
  30. addChild(nameLabel);
  31. Label *pluginLabel = new Label;
  32. pluginLabel->text = model->plugin->name;
  33. pluginLabel->box.pos = p;
  34. p.y += pluginLabel->box.size.y;
  35. addChild(pluginLabel);
  36. }
  37. void draw(NVGcontext *vg) override {
  38. // Lazily create ModuleWidget when drawn
  39. if (!initialized) {
  40. Widget *transparentWidget = new TransparentWidget;
  41. addChild(transparentWidget);
  42. ZoomWidget *zoomWidget = new ZoomWidget;
  43. zoomWidget->setZoom(0.5f);
  44. transparentWidget->addChild(zoomWidget);
  45. ModuleWidget *moduleWidget = model->createModuleWidgetNull();
  46. zoomWidget->addChild(moduleWidget);
  47. float width = std::ceil(moduleWidget->box.size.x * 0.5f);
  48. box.size.x = std::max(box.size.x, width);
  49. initialized = true;
  50. }
  51. OpaqueWidget::draw(vg);
  52. if (app()->event->hoveredWidget == this) {
  53. nvgBeginPath(vg);
  54. nvgRect(vg, 0.0, 0.0, box.size.x, box.size.y);
  55. nvgFillColor(vg, nvgRGBAf(1, 1, 1, 0.25));
  56. nvgFill(vg);
  57. }
  58. }
  59. void onButton(const event::Button &e) override {
  60. if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT) {
  61. // Create module
  62. ModuleWidget *moduleWidget = model->createModuleWidget();
  63. assert(moduleWidget);
  64. app()->scene->rackWidget->addModuleAtMouse(moduleWidget);
  65. // This is a bit nonstandard/unsupported usage, but pretend the moduleWidget was clicked so it can be dragged in the RackWidget
  66. // e.consume(moduleWidget);
  67. // Close Module Browser
  68. ModuleBrowser *moduleBrowser = getAncestorOfType<ModuleBrowser>();
  69. moduleBrowser->visible = false;
  70. // Push ModuleAdd history action
  71. history::ModuleAdd *h = new history::ModuleAdd;
  72. h->model = moduleWidget->model;
  73. h->moduleId = moduleWidget->module->id;
  74. h->pos = moduleWidget->box.pos;
  75. app()->history->push(h);
  76. }
  77. OpaqueWidget::onButton(e);
  78. }
  79. };
  80. ModuleBrowser::ModuleBrowser() {
  81. moduleScroll = new ScrollWidget;
  82. addChild(moduleScroll);
  83. moduleLayout = new SequentialLayout;
  84. moduleLayout->spacing = math::Vec(10, 10);
  85. moduleScroll->container->addChild(moduleLayout);
  86. for (Plugin *plugin : plugin::plugins) {
  87. for (Model *model : plugin->models) {
  88. ModuleBox *moduleBox = new ModuleBox;
  89. moduleBox->setModel(model);
  90. moduleLayout->addChild(moduleBox);
  91. }
  92. }
  93. }
  94. void ModuleBrowser::step() {
  95. // TODO resize sidebar
  96. float sidebarWidth = 300.0;
  97. moduleScroll->box.pos.x = sidebarWidth;
  98. moduleScroll->box.size.x = box.size.x - sidebarWidth;
  99. moduleScroll->box.size.y = box.size.y;
  100. moduleLayout->box.size.x = moduleScroll->box.size.x;
  101. moduleLayout->box.size.y = moduleLayout->getChildrenBoundingBox().getBottomRight().y;
  102. OpaqueWidget::step();
  103. }
  104. void ModuleBrowser::draw(NVGcontext *vg) {
  105. bndMenuBackground(vg, 0.0, 0.0, box.size.x, box.size.y, 0);
  106. Widget::draw(vg);
  107. }
  108. void ModuleBrowser::onHoverKey(const event::HoverKey &e) {
  109. if (e.action == GLFW_PRESS) {
  110. switch (e.key) {
  111. case GLFW_KEY_ESCAPE: {
  112. // Close menu
  113. this->visible = false;
  114. e.consume(this);
  115. } break;
  116. }
  117. }
  118. if (!e.getConsumed())
  119. OpaqueWidget::onHoverKey(e);
  120. }
  121. // Global functions
  122. json_t *moduleBrowserToJson() {
  123. json_t *rootJ = json_object();
  124. json_t *favoritesJ = json_array();
  125. for (Model *model : sFavoriteModels) {
  126. json_t *modelJ = json_object();
  127. json_object_set_new(modelJ, "plugin", json_string(model->plugin->slug.c_str()));
  128. json_object_set_new(modelJ, "model", json_string(model->slug.c_str()));
  129. json_array_append_new(favoritesJ, modelJ);
  130. }
  131. json_object_set_new(rootJ, "favorites", favoritesJ);
  132. return rootJ;
  133. }
  134. void moduleBrowserFromJson(json_t *rootJ) {
  135. json_t *favoritesJ = json_object_get(rootJ, "favorites");
  136. if (favoritesJ) {
  137. size_t i;
  138. json_t *favoriteJ;
  139. json_array_foreach(favoritesJ, i, favoriteJ) {
  140. json_t *pluginJ = json_object_get(favoriteJ, "plugin");
  141. json_t *modelJ = json_object_get(favoriteJ, "model");
  142. if (!pluginJ || !modelJ)
  143. continue;
  144. std::string pluginSlug = json_string_value(pluginJ);
  145. std::string modelSlug = json_string_value(modelJ);
  146. Model *model = plugin::getModel(pluginSlug, modelSlug);
  147. if (!model)
  148. continue;
  149. sFavoriteModels.insert(model);
  150. }
  151. }
  152. }
  153. } // namespace rack