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.

607 lines
15KB

  1. #include "app/RackWidget.hpp"
  2. #include "widget/TransparentWidget.hpp"
  3. #include "app/RackRail.hpp"
  4. #include "app/Scene.hpp"
  5. #include "app/ModuleBrowser.hpp"
  6. #include "settings.hpp"
  7. #include "plugin.hpp"
  8. #include "engine/Engine.hpp"
  9. #include "app.hpp"
  10. #include "asset.hpp"
  11. #include "patch.hpp"
  12. #include "osdialog.h"
  13. #include <map>
  14. #include <algorithm>
  15. #include <queue>
  16. namespace rack {
  17. namespace app {
  18. static ModuleWidget *moduleFromJson(json_t *moduleJ) {
  19. // Get slugs
  20. json_t *pluginSlugJ = json_object_get(moduleJ, "plugin");
  21. if (!pluginSlugJ)
  22. return NULL;
  23. json_t *modelSlugJ = json_object_get(moduleJ, "model");
  24. if (!modelSlugJ)
  25. return NULL;
  26. std::string pluginSlug = json_string_value(pluginSlugJ);
  27. std::string modelSlug = json_string_value(modelSlugJ);
  28. // Get Model
  29. plugin::Model *model = plugin::getModel(pluginSlug, modelSlug);
  30. if (!model)
  31. return NULL;
  32. // Create ModuleWidget
  33. ModuleWidget *moduleWidget = model->createModuleWidget();
  34. assert(moduleWidget);
  35. moduleWidget->fromJson(moduleJ);
  36. return moduleWidget;
  37. }
  38. struct ModuleContainer : widget::Widget {
  39. void draw(const DrawArgs &args) override {
  40. // Draw shadows behind each ModuleWidget first, so the shadow doesn't overlap the front of other ModuleWidgets.
  41. for (widget::Widget *child : children) {
  42. ModuleWidget *w = dynamic_cast<ModuleWidget*>(child);
  43. assert(w);
  44. nvgSave(args.vg);
  45. nvgTranslate(args.vg, child->box.pos.x, child->box.pos.y);
  46. w->drawShadow(args);
  47. nvgRestore(args.vg);
  48. }
  49. Widget::draw(args);
  50. }
  51. };
  52. struct CableContainer : widget::TransparentWidget {
  53. void draw(const DrawArgs &args) override {
  54. Widget::draw(args);
  55. // Draw cable plugs
  56. for (widget::Widget *w : children) {
  57. CableWidget *cw = dynamic_cast<CableWidget*>(w);
  58. assert(cw);
  59. cw->drawPlugs(args);
  60. }
  61. }
  62. };
  63. RackWidget::RackWidget() {
  64. railFb = new widget::FramebufferWidget;
  65. railFb->box.size = math::Vec();
  66. railFb->oversample = 1.0;
  67. {
  68. RackRail *rail = new RackRail;
  69. rail->box.size = math::Vec();
  70. railFb->addChild(rail);
  71. }
  72. addChild(railFb);
  73. moduleContainer = new ModuleContainer;
  74. addChild(moduleContainer);
  75. cableContainer = new CableContainer;
  76. addChild(cableContainer);
  77. }
  78. RackWidget::~RackWidget() {
  79. clear();
  80. }
  81. void RackWidget::step() {
  82. Widget::step();
  83. }
  84. void RackWidget::draw(const DrawArgs &args) {
  85. // Resize and reposition the RackRail to align on the grid.
  86. math::Rect railBox;
  87. railBox.pos = args.clipBox.pos.div(BUS_BOARD_GRID_SIZE).floor().mult(BUS_BOARD_GRID_SIZE);
  88. railBox.size = args.clipBox.size.div(BUS_BOARD_GRID_SIZE).ceil().plus(math::Vec(1, 1)).mult(BUS_BOARD_GRID_SIZE);
  89. if (!railFb->box.size.isEqual(railBox.size)) {
  90. railFb->dirty = true;
  91. }
  92. railFb->box = railBox;
  93. RackRail *rail = railFb->getFirstDescendantOfType<RackRail>();
  94. rail->box.size = railFb->box.size;
  95. Widget::draw(args);
  96. }
  97. void RackWidget::onHover(const event::Hover &e) {
  98. // Set before calling children's onHover()
  99. mousePos = e.pos;
  100. OpaqueWidget::onHover(e);
  101. }
  102. void RackWidget::onHoverKey(const event::HoverKey &e) {
  103. OpaqueWidget::onHoverKey(e);
  104. if (e.isConsumed())
  105. return;
  106. if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
  107. switch (e.key) {
  108. case GLFW_KEY_V: {
  109. if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
  110. pastePresetClipboardAction();
  111. }
  112. e.consume(this);
  113. } break;
  114. }
  115. }
  116. }
  117. void RackWidget::onDragHover(const event::DragHover &e) {
  118. // Set before calling children's onDragHover()
  119. mousePos = e.pos;
  120. OpaqueWidget::onDragHover(e);
  121. }
  122. void RackWidget::onButton(const event::Button &e) {
  123. Widget::onButton(e);
  124. e.stopPropagating();
  125. if (e.isConsumed())
  126. return;
  127. if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) {
  128. APP->scene->moduleBrowser->show();
  129. e.consume(this);
  130. }
  131. }
  132. void RackWidget::clear() {
  133. // This isn't required because removing all ModuleWidgets should remove all cables, but do it just in case.
  134. clearCables();
  135. // Remove ModuleWidgets
  136. std::list<widget::Widget*> widgets = moduleContainer->children;
  137. for (widget::Widget *w : widgets) {
  138. ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
  139. assert(moduleWidget);
  140. removeModule(moduleWidget);
  141. delete moduleWidget;
  142. }
  143. }
  144. json_t *RackWidget::toJson() {
  145. // root
  146. json_t *rootJ = json_object();
  147. // Get module offset so modules are aligned to (0, 0) when the patch is loaded.
  148. math::Vec moduleOffset = math::Vec(INFINITY, INFINITY);
  149. for (widget::Widget *w : moduleContainer->children) {
  150. moduleOffset = moduleOffset.min(w->box.pos);
  151. }
  152. if (moduleContainer->children.empty()) {
  153. moduleOffset = RACK_OFFSET;
  154. }
  155. // modules
  156. json_t *modulesJ = json_array();
  157. for (widget::Widget *w : moduleContainer->children) {
  158. ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
  159. assert(moduleWidget);
  160. // module
  161. json_t *moduleJ = moduleWidget->toJson();
  162. {
  163. // id
  164. json_object_set_new(moduleJ, "id", json_integer(moduleWidget->module->id));
  165. // pos
  166. math::Vec pos = moduleWidget->box.pos.minus(moduleOffset);
  167. pos = pos.div(RACK_GRID_SIZE).round();
  168. json_t *posJ = json_pack("[i, i]", (int) pos.x, (int) pos.y);
  169. json_object_set_new(moduleJ, "pos", posJ);
  170. }
  171. json_array_append_new(modulesJ, moduleJ);
  172. }
  173. json_object_set_new(rootJ, "modules", modulesJ);
  174. // cables
  175. json_t *cablesJ = json_array();
  176. for (widget::Widget *w : cableContainer->children) {
  177. CableWidget *cw = dynamic_cast<CableWidget*>(w);
  178. assert(cw);
  179. // Only serialize complete cables
  180. if (!cw->isComplete())
  181. continue;
  182. json_t *cableJ = cw->toJson();
  183. {
  184. // id
  185. json_object_set_new(rootJ, "id", json_integer(cw->cable->id));
  186. }
  187. json_array_append_new(cablesJ, cableJ);
  188. }
  189. json_object_set_new(rootJ, "cables", cablesJ);
  190. return rootJ;
  191. }
  192. void RackWidget::fromJson(json_t *rootJ) {
  193. // modules
  194. json_t *modulesJ = json_object_get(rootJ, "modules");
  195. if (!modulesJ)
  196. return;
  197. size_t moduleIndex;
  198. json_t *moduleJ;
  199. json_array_foreach(modulesJ, moduleIndex, moduleJ) {
  200. ModuleWidget *moduleWidget = moduleFromJson(moduleJ);
  201. if (moduleWidget) {
  202. // Before 1.0, the module ID was the index in the "modules" array
  203. if (APP->patch->isLegacy(2)) {
  204. moduleWidget->module->id = moduleIndex;
  205. }
  206. // id
  207. json_t *idJ = json_object_get(moduleJ, "id");
  208. if (idJ)
  209. moduleWidget->module->id = json_integer_value(idJ);
  210. // pos
  211. json_t *posJ = json_object_get(moduleJ, "pos");
  212. double x, y;
  213. json_unpack(posJ, "[F, F]", &x, &y);
  214. math::Vec pos = math::Vec(x, y);
  215. if (APP->patch->isLegacy(1)) {
  216. // Before 0.6, positions were in pixel units
  217. moduleWidget->box.pos = pos;
  218. }
  219. else {
  220. moduleWidget->box.pos = pos.mult(RACK_GRID_SIZE);
  221. }
  222. moduleWidget->box.pos = moduleWidget->box.pos.plus(RACK_OFFSET);
  223. addModule(moduleWidget);
  224. }
  225. else {
  226. json_t *pluginSlugJ = json_object_get(moduleJ, "plugin");
  227. json_t *modelSlugJ = json_object_get(moduleJ, "model");
  228. std::string pluginSlug = json_string_value(pluginSlugJ);
  229. std::string modelSlug = json_string_value(modelSlugJ);
  230. APP->patch->warningLog += string::f("Could not find module \"%s\" of plugin \"%s\"\n", modelSlug.c_str(), pluginSlug.c_str());
  231. }
  232. }
  233. // cables
  234. json_t *cablesJ = json_object_get(rootJ, "cables");
  235. // Before 1.0, cables were called wires
  236. if (!cablesJ)
  237. cablesJ = json_object_get(rootJ, "wires");
  238. assert(cablesJ);
  239. size_t cableIndex;
  240. json_t *cableJ;
  241. json_array_foreach(cablesJ, cableIndex, cableJ) {
  242. // Create a unserialize cable
  243. CableWidget *cw = new CableWidget;
  244. cw->fromJson(cableJ);
  245. if (!cw->isComplete()) {
  246. delete cw;
  247. continue;
  248. }
  249. // Before 1.0, cables IDs were not used, so just use the index of the "cables" array.
  250. if (APP->patch->isLegacy(2)) {
  251. cw->cable->id = cableIndex;
  252. }
  253. // id
  254. json_t *idJ = json_object_get(cableJ, "id");
  255. if (idJ)
  256. cw->cable->id = json_integer_value(idJ);
  257. addCable(cw);
  258. }
  259. }
  260. void RackWidget::pastePresetClipboardAction() {
  261. const char *moduleJson = glfwGetClipboardString(APP->window->win);
  262. if (!moduleJson) {
  263. WARN("Could not get text from clipboard.");
  264. return;
  265. }
  266. json_error_t error;
  267. json_t *moduleJ = json_loads(moduleJson, 0, &error);
  268. if (moduleJ) {
  269. ModuleWidget *mw = moduleFromJson(moduleJ);
  270. json_decref(moduleJ);
  271. addModuleAtMouse(mw);
  272. // history::ModuleAdd
  273. history::ModuleAdd *h = new history::ModuleAdd;
  274. h->setModule(mw);
  275. APP->history->push(h);
  276. }
  277. else {
  278. WARN("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
  279. }
  280. }
  281. static void RackWidget_updateAdjacent(RackWidget *that) {
  282. for (widget::Widget *w : that->moduleContainer->children) {
  283. math::Vec pLeft = w->box.pos.div(RACK_GRID_SIZE).round();
  284. math::Vec pRight = w->box.getTopRight().div(RACK_GRID_SIZE).round();
  285. ModuleWidget *mwLeft = NULL;
  286. ModuleWidget *mwRight = NULL;
  287. // Find adjacent modules
  288. for (widget::Widget *w2 : that->moduleContainer->children) {
  289. if (w2 == w)
  290. continue;
  291. math::Vec p2Left = w2->box.pos.div(RACK_GRID_SIZE).round();
  292. math::Vec p2Right = w2->box.getTopRight().div(RACK_GRID_SIZE).round();
  293. // Check if this is a left module
  294. if (p2Right.isEqual(pLeft)) {
  295. mwLeft = dynamic_cast<ModuleWidget*>(w2);
  296. }
  297. // Check if this is a right module
  298. if (p2Left.isEqual(pRight)) {
  299. mwRight = dynamic_cast<ModuleWidget*>(w2);
  300. }
  301. }
  302. ModuleWidget *mw = dynamic_cast<ModuleWidget*>(w);
  303. mw->module->rightModuleId = mwRight ? mwRight->module->id : -1;
  304. mw->module->leftModuleId = mwLeft ? mwLeft->module->id : -1;
  305. }
  306. }
  307. void RackWidget::addModule(ModuleWidget *m) {
  308. // Add module to ModuleContainer
  309. assert(m);
  310. // Module must be 3U high and at least 1HP wide
  311. assert(m->box.size.x >= RACK_GRID_WIDTH);
  312. assert(m->box.size.y == RACK_GRID_HEIGHT);
  313. moduleContainer->addChild(m);
  314. if (m->module) {
  315. // Add module to Engine
  316. APP->engine->addModule(m->module);
  317. }
  318. RackWidget_updateAdjacent(this);
  319. }
  320. void RackWidget::addModuleAtMouse(ModuleWidget *mw) {
  321. assert(mw);
  322. // Move module nearest to the mouse position
  323. math::Vec pos = mousePos.minus(mw->box.size.div(2));
  324. requestModulePosNearest(mw, pos);
  325. addModule(mw);
  326. }
  327. void RackWidget::removeModule(ModuleWidget *m) {
  328. // Unset touchedParamWidget
  329. if (touchedParam) {
  330. ModuleWidget *touchedModule = touchedParam->getAncestorOfType<ModuleWidget>();
  331. if (touchedModule == m)
  332. touchedParam = NULL;
  333. }
  334. // Disconnect cables
  335. m->disconnect();
  336. if (m->module) {
  337. // Remove module from Engine
  338. APP->engine->removeModule(m->module);
  339. }
  340. // Remove module from ModuleContainer
  341. moduleContainer->removeChild(m);
  342. }
  343. bool RackWidget::requestModulePos(ModuleWidget *mw, math::Vec pos) {
  344. // Check intersection with other modules
  345. math::Rect mwBox = math::Rect(pos, mw->box.size);
  346. for (widget::Widget *mw2 : moduleContainer->children) {
  347. // Don't intersect with self
  348. if (mw == mw2)
  349. continue;
  350. // Don't intersect with invisible modules
  351. if (!mw2->visible)
  352. continue;
  353. // Check intersection
  354. if (mwBox.isIntersecting(mw2->box)) {
  355. return false;
  356. }
  357. }
  358. // Accept requested position
  359. mw->box = mwBox;
  360. RackWidget_updateAdjacent(this);
  361. return true;
  362. }
  363. bool RackWidget::requestModulePosNearest(ModuleWidget *mw, math::Vec pos) {
  364. // Dijkstra's algorithm to generate a sorted list of Vecs closest to `pos`.
  365. // Comparison of distance of Vecs to `pos`
  366. auto cmpNearest = [&](const math::Vec &a, const math::Vec &b) {
  367. return a.minus(pos).square() > b.minus(pos).square();
  368. };
  369. // Comparison of dictionary order of Vecs
  370. auto cmp = [&](const math::Vec &a, const math::Vec &b) {
  371. if (a.x != b.x)
  372. return a.x < b.x;
  373. return a.y < b.y;
  374. };
  375. // Priority queue sorted by distance from `pos`
  376. std::priority_queue<math::Vec, std::vector<math::Vec>, decltype(cmpNearest)> queue(cmpNearest);
  377. // Set of already-tested Vecs
  378. std::set<math::Vec, decltype(cmp)> visited(cmp);
  379. // Seed priority queue with closest Vec
  380. math::Vec closestPos = pos.div(RACK_GRID_SIZE).round().mult(RACK_GRID_SIZE);
  381. queue.push(closestPos);
  382. while (!queue.empty()) {
  383. math::Vec testPos = queue.top();
  384. // Check testPos
  385. if (requestModulePos(mw, testPos))
  386. return true;
  387. // Move testPos to visited set
  388. queue.pop();
  389. visited.insert(testPos);
  390. // Add adjacent Vecs
  391. static const std::vector<math::Vec> deltas = {
  392. math::Vec(-1, 0).mult(RACK_GRID_SIZE),
  393. math::Vec(1, 0).mult(RACK_GRID_SIZE),
  394. math::Vec(0, -1).mult(RACK_GRID_SIZE),
  395. math::Vec(0, 1).mult(RACK_GRID_SIZE),
  396. };
  397. for (math::Vec delta : deltas) {
  398. math::Vec newPos = testPos.plus(delta);
  399. if (visited.find(newPos) == visited.end()) {
  400. queue.push(newPos);
  401. }
  402. }
  403. }
  404. // We failed to find a box. This shouldn't happen on an infinite rack.
  405. assert(0);
  406. return false;
  407. }
  408. ModuleWidget *RackWidget::getModule(int moduleId) {
  409. for (widget::Widget *w : moduleContainer->children) {
  410. ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
  411. assert(moduleWidget);
  412. if (moduleWidget->module->id == moduleId)
  413. return moduleWidget;
  414. }
  415. return NULL;
  416. }
  417. bool RackWidget::isEmpty() {
  418. return moduleContainer->children.empty();
  419. }
  420. void RackWidget::clearCables() {
  421. for (widget::Widget *w : cableContainer->children) {
  422. CableWidget *cw = dynamic_cast<CableWidget*>(w);
  423. assert(cw);
  424. if (!cw->isComplete())
  425. continue;
  426. APP->engine->removeCable(cw->cable);
  427. }
  428. incompleteCable = NULL;
  429. cableContainer->clearChildren();
  430. }
  431. void RackWidget::clearCablesAction() {
  432. // Add CableRemove for every cable to a ComplexAction
  433. history::ComplexAction *complexAction = new history::ComplexAction;
  434. complexAction->name = "clear cables";
  435. for (widget::Widget *w : cableContainer->children) {
  436. CableWidget *cw = dynamic_cast<CableWidget*>(w);
  437. assert(cw);
  438. if (!cw->isComplete())
  439. continue;
  440. // history::CableRemove
  441. history::CableRemove *h = new history::CableRemove;
  442. h->setCable(cw);
  443. complexAction->push(h);
  444. }
  445. APP->history->push(complexAction);
  446. clearCables();
  447. }
  448. void RackWidget::clearCablesOnPort(PortWidget *port) {
  449. for (CableWidget *cw : getCablesOnPort(port)) {
  450. // Check if cable is connected to port
  451. if (cw == incompleteCable) {
  452. incompleteCable = NULL;
  453. cableContainer->removeChild(cw);
  454. }
  455. else {
  456. removeCable(cw);
  457. }
  458. delete cw;
  459. }
  460. }
  461. void RackWidget::addCable(CableWidget *w) {
  462. assert(w->isComplete());
  463. APP->engine->addCable(w->cable);
  464. cableContainer->addChild(w);
  465. }
  466. void RackWidget::removeCable(CableWidget *w) {
  467. assert(w->isComplete());
  468. APP->engine->removeCable(w->cable);
  469. cableContainer->removeChild(w);
  470. }
  471. void RackWidget::setIncompleteCable(CableWidget *w) {
  472. if (incompleteCable) {
  473. cableContainer->removeChild(incompleteCable);
  474. delete incompleteCable;
  475. incompleteCable = NULL;
  476. }
  477. if (w) {
  478. cableContainer->addChild(w);
  479. incompleteCable = w;
  480. }
  481. }
  482. CableWidget *RackWidget::releaseIncompleteCable() {
  483. CableWidget *cw = incompleteCable;
  484. cableContainer->removeChild(incompleteCable);
  485. incompleteCable = NULL;
  486. return cw;
  487. }
  488. CableWidget *RackWidget::getTopCable(PortWidget *port) {
  489. for (auto it = cableContainer->children.rbegin(); it != cableContainer->children.rend(); it++) {
  490. CableWidget *cw = dynamic_cast<CableWidget*>(*it);
  491. assert(cw);
  492. // Ignore incomplete cables
  493. if (!cw->isComplete())
  494. continue;
  495. if (cw->inputPort == port || cw->outputPort == port)
  496. return cw;
  497. }
  498. return NULL;
  499. }
  500. CableWidget *RackWidget::getCable(int cableId) {
  501. for (widget::Widget *w : cableContainer->children) {
  502. CableWidget *cw = dynamic_cast<CableWidget*>(w);
  503. assert(cw);
  504. if (cw->cable->id == cableId)
  505. return cw;
  506. }
  507. return NULL;
  508. }
  509. std::list<CableWidget*> RackWidget::getCablesOnPort(PortWidget *port) {
  510. assert(port);
  511. std::list<CableWidget*> cables;
  512. for (widget::Widget *w : cableContainer->children) {
  513. CableWidget *cw = dynamic_cast<CableWidget*>(w);
  514. assert(cw);
  515. if (cw->inputPort == port || cw->outputPort == port) {
  516. cables.push_back(cw);
  517. }
  518. }
  519. return cables;
  520. }
  521. } // namespace app
  522. } // namespace rack