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.

1458 lines
37KB

  1. #include <map>
  2. #include <algorithm>
  3. #include <queue>
  4. #include <functional>
  5. #include <osdialog.h>
  6. #include <app/RackWidget.hpp>
  7. #include <widget/TransparentWidget.hpp>
  8. #include <app/RailWidget.hpp>
  9. #include <app/Scene.hpp>
  10. #include <settings.hpp>
  11. #include <plugin.hpp>
  12. #include <engine/Engine.hpp>
  13. #include <context.hpp>
  14. #include <system.hpp>
  15. #include <asset.hpp>
  16. #include <patch.hpp>
  17. #include <helpers.hpp>
  18. namespace rack {
  19. namespace app {
  20. struct RackWidget::Internal {
  21. RailWidget* rail = NULL;
  22. widget::Widget* moduleContainer = NULL;
  23. widget::Widget* cableContainer = NULL;
  24. CableWidget* incompleteCable = NULL;
  25. int nextCableColorId = 0;
  26. /** The last mouse position in the RackWidget */
  27. math::Vec mousePos;
  28. bool selecting = false;
  29. math::Vec selectionStart;
  30. math::Vec selectionEnd;
  31. std::set<ModuleWidget*> selectedModules;
  32. std::map<ModuleWidget*, math::Vec> moduleOldPositions;
  33. };
  34. /** Creates a new Module and ModuleWidget */
  35. static ModuleWidget* moduleWidgetFromJson(json_t* moduleJ) {
  36. plugin::Model* model = plugin::modelFromJson(moduleJ);
  37. assert(model);
  38. INFO("Creating module %s", model->getFullName().c_str());
  39. engine::Module* module = model->createModule();
  40. assert(module);
  41. module->fromJson(moduleJ);
  42. // Create ModuleWidget
  43. INFO("Creating module widget %s", model->getFullName().c_str());
  44. ModuleWidget* moduleWidget = module->model->createModuleWidget(module);
  45. assert(moduleWidget);
  46. return moduleWidget;
  47. }
  48. struct ModuleContainer : widget::Widget {
  49. void draw(const DrawArgs& args) override {
  50. // Draw ModuleWidget shadows
  51. Widget::drawLayer(args, -1);
  52. Widget::draw(args);
  53. }
  54. void drawLayer(const DrawArgs& args, int layer) override {
  55. // Draw lights after translucent rectangle
  56. if (layer == 1) {
  57. Widget::drawLayer(args, 1);
  58. }
  59. }
  60. };
  61. struct CableContainer : widget::TransparentWidget {
  62. void draw(const DrawArgs& args) override {
  63. // Don't draw on layer 0
  64. }
  65. void drawLayer(const DrawArgs& args, int layer) override {
  66. if (layer == 2) {
  67. // Draw Plugs
  68. Widget::draw(args);
  69. // Draw cable lights
  70. nvgSave(args.vg);
  71. nvgGlobalTint(args.vg, color::WHITE);
  72. Widget::drawLayer(args, 1);
  73. nvgRestore(args.vg);
  74. // Draw cable shadows
  75. Widget::drawLayer(args, 2);
  76. // Draw cables
  77. Widget::drawLayer(args, 3);
  78. }
  79. }
  80. };
  81. RackWidget::RackWidget() {
  82. internal = new Internal;
  83. internal->rail = new RailWidget;
  84. addChild(internal->rail);
  85. internal->moduleContainer = new ModuleContainer;
  86. addChild(internal->moduleContainer);
  87. internal->cableContainer = new CableContainer;
  88. addChild(internal->cableContainer);
  89. }
  90. RackWidget::~RackWidget() {
  91. clear();
  92. delete internal;
  93. }
  94. void RackWidget::step() {
  95. Widget::step();
  96. }
  97. void RackWidget::draw(const DrawArgs& args) {
  98. float b = settings::rackBrightness;
  99. // Draw rack rails and modules
  100. Widget::draw(args);
  101. // Draw translucent dark rectangle
  102. if (b < 1.f) {
  103. // Get zoom level
  104. float t[6];
  105. nvgCurrentTransform(args.vg, t);
  106. float zoom = t[3];
  107. float radius = 300.0 / zoom;
  108. float brightness = 0.2f;
  109. // Draw mouse spotlight
  110. nvgBeginPath(args.vg);
  111. nvgRect(args.vg, 0.0, 0.0, VEC_ARGS(box.size));
  112. nvgFillPaint(args.vg, nvgRadialGradient(args.vg, VEC_ARGS(internal->mousePos), 0.0, radius, nvgRGBAf(0, 0, 0, 1.f - b - brightness), nvgRGBAf(0, 0, 0, 1.f - b)));
  113. nvgFill(args.vg);
  114. }
  115. // Draw lights and halos
  116. Widget::drawLayer(args, 1);
  117. // Tint all draws after this point
  118. nvgGlobalTint(args.vg, nvgRGBAf(b, b, b, 1));
  119. // Draw cables
  120. Widget::drawLayer(args, 2);
  121. // Draw selection rectangle
  122. if (internal->selecting) {
  123. nvgBeginPath(args.vg);
  124. math::Rect selectionBox = math::Rect::fromCorners(internal->selectionStart, internal->selectionEnd);
  125. nvgRect(args.vg, RECT_ARGS(selectionBox));
  126. nvgFillColor(args.vg, nvgRGBAf(1, 0, 0, 0.25));
  127. nvgFill(args.vg);
  128. nvgStrokeWidth(args.vg, 2.0);
  129. nvgStrokeColor(args.vg, nvgRGBAf(1, 0, 0, 0.5));
  130. nvgStroke(args.vg);
  131. }
  132. }
  133. void RackWidget::onHover(const HoverEvent& e) {
  134. // Set before calling children's onHover()
  135. internal->mousePos = e.pos;
  136. OpaqueWidget::onHover(e);
  137. }
  138. void RackWidget::onHoverKey(const HoverKeyEvent& e) {
  139. OpaqueWidget::onHoverKey(e);
  140. }
  141. void RackWidget::onButton(const ButtonEvent& e) {
  142. Widget::onButton(e);
  143. e.stopPropagating();
  144. if (e.isConsumed())
  145. return;
  146. if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) {
  147. APP->scene->browser->show();
  148. e.consume(this);
  149. }
  150. if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT) {
  151. e.consume(this);
  152. }
  153. }
  154. void RackWidget::onDragStart(const DragStartEvent& e) {
  155. if (e.button == GLFW_MOUSE_BUTTON_LEFT) {
  156. // Deselect all modules
  157. updateSelectionFromRect();
  158. internal->selecting = true;
  159. internal->selectionStart = internal->mousePos;
  160. internal->selectionEnd = internal->mousePos;
  161. }
  162. }
  163. void RackWidget::onDragEnd(const DragEndEvent& e) {
  164. if (e.button == GLFW_MOUSE_BUTTON_LEFT) {
  165. internal->selecting = false;
  166. }
  167. }
  168. void RackWidget::onDragHover(const DragHoverEvent& e) {
  169. // Set before calling children's onDragHover()
  170. internal->mousePos = e.pos;
  171. if (internal->selecting) {
  172. internal->selectionEnd = internal->mousePos;
  173. updateSelectionFromRect();
  174. }
  175. OpaqueWidget::onDragHover(e);
  176. }
  177. widget::Widget* RackWidget::getModuleContainer() {
  178. return internal->moduleContainer;
  179. }
  180. widget::Widget* RackWidget::getCableContainer() {
  181. return internal->cableContainer;
  182. }
  183. math::Vec RackWidget::getMousePos() {
  184. return internal->mousePos;
  185. }
  186. void RackWidget::clear() {
  187. // This isn't required because removing all ModuleWidgets should remove all cables, but do it just in case.
  188. clearCables();
  189. // Remove ModuleWidgets
  190. for (ModuleWidget* mw : getModules()) {
  191. removeModule(mw);
  192. delete mw;
  193. }
  194. }
  195. static void RackWidget_updateExpanders(RackWidget* that) {
  196. for (widget::Widget* w : that->internal->moduleContainer->children) {
  197. math::Vec pLeft = w->box.pos.div(RACK_GRID_SIZE).round();
  198. math::Vec pRight = w->box.getTopRight().div(RACK_GRID_SIZE).round();
  199. ModuleWidget* mwLeft = NULL;
  200. ModuleWidget* mwRight = NULL;
  201. // Find adjacent modules
  202. for (widget::Widget* w2 : that->internal->moduleContainer->children) {
  203. if (w2 == w)
  204. continue;
  205. math::Vec p2Left = w2->box.pos.div(RACK_GRID_SIZE).round();
  206. math::Vec p2Right = w2->box.getTopRight().div(RACK_GRID_SIZE).round();
  207. // Check if this is a left module
  208. if (p2Right.equals(pLeft)) {
  209. mwLeft = dynamic_cast<ModuleWidget*>(w2);
  210. }
  211. // Check if this is a right module
  212. if (p2Left.equals(pRight)) {
  213. mwRight = dynamic_cast<ModuleWidget*>(w2);
  214. }
  215. }
  216. ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
  217. mw->module->leftExpander.moduleId = mwLeft ? mwLeft->module->id : -1;
  218. mw->module->rightExpander.moduleId = mwRight ? mwRight->module->id : -1;
  219. }
  220. }
  221. void RackWidget::mergeJson(json_t* rootJ) {
  222. // modules
  223. json_t* modulesJ = json_object_get(rootJ, "modules");
  224. if (!modulesJ)
  225. return;
  226. size_t moduleIndex;
  227. json_t* moduleJ;
  228. json_array_foreach(modulesJ, moduleIndex, moduleJ) {
  229. // module
  230. json_t* idJ = json_object_get(moduleJ, "id");
  231. if (!idJ)
  232. continue;
  233. int64_t id = json_integer_value(idJ);
  234. // TODO Legacy v0.6?
  235. ModuleWidget* mw = getModule(id);
  236. if (!mw) {
  237. WARN("Cannot find ModuleWidget %lld", (long long) id);
  238. continue;
  239. }
  240. // pos
  241. math::Vec pos = mw->box.pos.minus(RACK_OFFSET);
  242. pos = pos.div(RACK_GRID_SIZE).round();
  243. json_t* posJ = json_pack("[i, i]", (int) pos.x, (int) pos.y);
  244. json_object_set_new(moduleJ, "pos", posJ);
  245. }
  246. // cables
  247. json_t* cablesJ = json_object_get(rootJ, "cables");
  248. if (!cablesJ)
  249. return;
  250. size_t cableIndex;
  251. json_t* cableJ;
  252. json_array_foreach(cablesJ, cableIndex, cableJ) {
  253. // cable
  254. json_t* idJ = json_object_get(cableJ, "id");
  255. if (!idJ)
  256. continue;
  257. int64_t id = json_integer_value(idJ);
  258. CableWidget* cw = getCable(id);
  259. if (!cw) {
  260. WARN("Cannot find CableWidget %lld", (long long) id);
  261. continue;
  262. }
  263. cw->mergeJson(cableJ);
  264. }
  265. }
  266. void RackWidget::fromJson(json_t* rootJ) {
  267. // version
  268. std::string version;
  269. json_t* versionJ = json_object_get(rootJ, "version");
  270. if (versionJ)
  271. version = json_string_value(versionJ);
  272. bool legacyV05 = false;
  273. if (string::startsWith(version, "0.3.") || string::startsWith(version, "0.4.") || string::startsWith(version, "0.5.") || version == "dev") {
  274. legacyV05 = true;
  275. }
  276. // modules
  277. json_t* modulesJ = json_object_get(rootJ, "modules");
  278. if (!modulesJ)
  279. return;
  280. size_t moduleIndex;
  281. json_t* moduleJ;
  282. json_array_foreach(modulesJ, moduleIndex, moduleJ) {
  283. // Get module ID
  284. json_t* idJ = json_object_get(moduleJ, "id");
  285. int64_t id;
  286. if (idJ)
  287. id = json_integer_value(idJ);
  288. else
  289. id = moduleIndex;
  290. // Get Module
  291. engine::Module* module = APP->engine->getModule(id);
  292. if (!module) {
  293. WARN("Cannot find Module %lld", (long long) id);
  294. continue;
  295. }
  296. // Create ModuleWidget
  297. INFO("Creating module widget %s", module->model->getFullName().c_str());
  298. ModuleWidget* mw = module->model->createModuleWidget(module);
  299. // pos
  300. json_t* posJ = json_object_get(moduleJ, "pos");
  301. double x = 0.0, y = 0.0;
  302. json_unpack(posJ, "[F, F]", &x, &y);
  303. math::Vec pos = math::Vec(x, y);
  304. if (legacyV05) {
  305. // In <=v0.5, positions were in pixel units
  306. }
  307. else {
  308. pos = pos.mult(RACK_GRID_SIZE);
  309. }
  310. pos = pos.plus(RACK_OFFSET);
  311. setModulePosNearest(mw, pos);
  312. internal->moduleContainer->addChild(mw);
  313. }
  314. RackWidget_updateExpanders(this);
  315. // cables
  316. json_t* cablesJ = json_object_get(rootJ, "cables");
  317. // In <=v0.6, cables were called wires
  318. if (!cablesJ)
  319. cablesJ = json_object_get(rootJ, "wires");
  320. if (!cablesJ)
  321. return;
  322. size_t cableIndex;
  323. json_t* cableJ;
  324. json_array_foreach(cablesJ, cableIndex, cableJ) {
  325. // Get cable ID
  326. json_t* idJ = json_object_get(cableJ, "id");
  327. int64_t id;
  328. // In <=v0.6, the cable ID was the index in the array.
  329. if (idJ)
  330. id = json_integer_value(idJ);
  331. else
  332. id = cableIndex;
  333. // Get Cable
  334. engine::Cable* cable = APP->engine->getCable(id);
  335. if (!cable) {
  336. WARN("Cannot find Cable %lld", (long long) id);
  337. continue;
  338. }
  339. // Create CableWidget
  340. CableWidget* cw = new CableWidget;
  341. try {
  342. cw->setCable(cable);
  343. cw->fromJson(cableJ);
  344. // In <=v1, cable colors were not serialized, so choose one from the available colors.
  345. if (cw->color.a == 0.f) {
  346. cw->color = getNextCableColor();
  347. }
  348. }
  349. catch (Exception& e) {
  350. delete cw;
  351. // If creating CableWidget fails, remove Cable from Engine.
  352. APP->engine->removeCable(cable);
  353. delete cable;
  354. continue;
  355. }
  356. addCable(cw);
  357. }
  358. }
  359. struct PasteJsonReturn {
  360. std::map<int64_t, int64_t> newModuleIds;
  361. };
  362. static PasteJsonReturn RackWidget_pasteJson(RackWidget* that, json_t* rootJ, history::ComplexAction* complexAction) {
  363. that->deselectAll();
  364. std::map<int64_t, int64_t> newModuleIds;
  365. // modules
  366. json_t* modulesJ = json_object_get(rootJ, "modules");
  367. if (!modulesJ)
  368. return {};
  369. size_t moduleIndex;
  370. json_t* moduleJ;
  371. json_array_foreach(modulesJ, moduleIndex, moduleJ) {
  372. json_t* idJ = json_object_get(moduleJ, "id");
  373. if (!idJ)
  374. continue;
  375. int64_t id = json_integer_value(idJ);
  376. engine::Module::jsonStripIds(moduleJ);
  377. ModuleWidget* mw;
  378. try {
  379. mw = moduleWidgetFromJson(moduleJ);
  380. }
  381. catch (Exception& e) {
  382. WARN("%s", e.what());
  383. continue;
  384. }
  385. assert(mw);
  386. assert(mw->module);
  387. APP->engine->addModule(mw->module);
  388. // pos
  389. json_t* posJ = json_object_get(moduleJ, "pos");
  390. double x = 0.0, y = 0.0;
  391. json_unpack(posJ, "[F, F]", &x, &y);
  392. math::Vec pos = math::Vec(x, y);
  393. pos = pos.mult(RACK_GRID_SIZE);
  394. mw->box.pos = pos.plus(RACK_OFFSET);
  395. that->internal->moduleContainer->addChild(mw);
  396. that->select(mw);
  397. newModuleIds[id] = mw->module->id;
  398. }
  399. // This calls RackWidget_updateExpanders()
  400. that->setSelectionPosNearest(math::Vec(0, 0));
  401. // Add positioned selected modules to history
  402. for (ModuleWidget* mw : that->getSelected()) {
  403. // history::ModuleAdd
  404. history::ModuleAdd* h = new history::ModuleAdd;
  405. h->setModule(mw);
  406. complexAction->push(h);
  407. }
  408. // cables
  409. json_t* cablesJ = json_object_get(rootJ, "cables");
  410. if (cablesJ) {
  411. size_t cableIndex;
  412. json_t* cableJ;
  413. json_array_foreach(cablesJ, cableIndex, cableJ) {
  414. engine::Cable::jsonStripIds(cableJ);
  415. // Remap old module IDs to new IDs
  416. json_t* inputModuleIdJ = json_object_get(cableJ, "inputModuleId");
  417. if (!inputModuleIdJ)
  418. continue;
  419. int64_t inputModuleId = json_integer_value(inputModuleIdJ);
  420. inputModuleId = get(newModuleIds, inputModuleId, -1);
  421. if (inputModuleId < 0)
  422. continue;
  423. json_object_set(cableJ, "inputModuleId", json_integer(inputModuleId));
  424. json_t* outputModuleIdJ = json_object_get(cableJ, "outputModuleId");
  425. if (!outputModuleIdJ)
  426. continue;
  427. int64_t outputModuleId = json_integer_value(outputModuleIdJ);
  428. outputModuleId = get(newModuleIds, outputModuleId, -1);
  429. if (outputModuleId < 0)
  430. continue;
  431. json_object_set(cableJ, "outputModuleId", json_integer(outputModuleId));
  432. // Create Cable
  433. engine::Cable* cable = new engine::Cable;
  434. try {
  435. cable->fromJson(cableJ);
  436. APP->engine->addCable(cable);
  437. }
  438. catch (Exception& e) {
  439. WARN("Cannot paste cable: %s", e.what());
  440. delete cable;
  441. continue;
  442. }
  443. // Create CableWidget
  444. app::CableWidget* cw = new app::CableWidget;
  445. cw->setCable(cable);
  446. cw->fromJson(cableJ);
  447. that->addCable(cw);
  448. // history::CableAdd
  449. history::CableAdd* h = new history::CableAdd;
  450. h->setCable(cw);
  451. complexAction->push(h);
  452. }
  453. }
  454. return {newModuleIds};
  455. }
  456. void RackWidget::pasteJsonAction(json_t* rootJ) {
  457. history::ComplexAction* complexAction = new history::ComplexAction;
  458. complexAction->name = "paste modules";
  459. DEFER({
  460. if (!complexAction->isEmpty())
  461. APP->history->push(complexAction);
  462. else
  463. delete complexAction;
  464. });
  465. RackWidget_pasteJson(this, rootJ, complexAction);
  466. }
  467. void RackWidget::pasteModuleJsonAction(json_t* moduleJ) {
  468. engine::Module::jsonStripIds(moduleJ);
  469. ModuleWidget* mw;
  470. try {
  471. mw = moduleWidgetFromJson(moduleJ);
  472. }
  473. catch (Exception& e) {
  474. WARN("%s", e.what());
  475. return;
  476. }
  477. assert(mw);
  478. assert(mw->module);
  479. APP->engine->addModule(mw->module);
  480. addModuleAtMouse(mw);
  481. // history::ModuleAdd
  482. history::ModuleAdd* h = new history::ModuleAdd;
  483. h->name = "paste module";
  484. h->setModule(mw);
  485. APP->history->push(h);
  486. }
  487. void RackWidget::pasteClipboardAction() {
  488. const char* json = glfwGetClipboardString(APP->window->win);
  489. if (!json) {
  490. WARN("Could not get text from clipboard.");
  491. return;
  492. }
  493. json_error_t error;
  494. json_t* rootJ = json_loads(json, 0, &error);
  495. if (!rootJ) {
  496. WARN("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
  497. return;
  498. }
  499. DEFER({json_decref(rootJ);});
  500. json_t* modulesJ = json_object_get(rootJ, "modules");
  501. if (modulesJ) {
  502. // JSON is a selection of modules
  503. pasteJsonAction(rootJ);
  504. }
  505. else {
  506. // JSON is a single module
  507. pasteModuleJsonAction(rootJ);
  508. }
  509. }
  510. void RackWidget::addModule(ModuleWidget* m) {
  511. assert(m);
  512. // Module must be 3U high and at least 1HP wide
  513. if (m->box.size.x < RACK_GRID_WIDTH / 2)
  514. throw Exception("Module %s width is %g px, must be at least %g px", m->model->getFullName().c_str(), m->box.size.x, RACK_GRID_WIDTH);
  515. if (m->box.size.y != RACK_GRID_HEIGHT)
  516. throw Exception("Module %s height is %g px, must be %g px", m->model->getFullName().c_str(), m->box.size.y, RACK_GRID_HEIGHT);
  517. internal->moduleContainer->addChild(m);
  518. RackWidget_updateExpanders(this);
  519. }
  520. void RackWidget::addModuleAtMouse(ModuleWidget* mw) {
  521. assert(mw);
  522. // Move module nearest to the mouse position
  523. math::Vec pos = internal->mousePos.minus(mw->box.size.div(2));
  524. setModulePosNearest(mw, pos);
  525. addModule(mw);
  526. }
  527. void RackWidget::removeModule(ModuleWidget* m) {
  528. // Unset touchedParamWidget
  529. if (touchedParam) {
  530. ModuleWidget* touchedModule = touchedParam->getAncestorOfType<ModuleWidget>();
  531. if (touchedModule == m)
  532. touchedParam = NULL;
  533. }
  534. // Disconnect cables
  535. m->disconnect();
  536. // Deselect module if selected
  537. internal->selectedModules.erase(m);
  538. // Remove module from ModuleContainer
  539. internal->moduleContainer->removeChild(m);
  540. }
  541. bool RackWidget::requestModulePos(ModuleWidget* mw, math::Vec pos) {
  542. // Check intersection with other modules
  543. math::Rect mwBox = math::Rect(pos, mw->box.size);
  544. for (widget::Widget* w2 : internal->moduleContainer->children) {
  545. // Don't intersect with self
  546. if (mw == w2)
  547. continue;
  548. // Check intersection
  549. math::Rect w2Box = w2->box;
  550. if (mwBox.intersects(w2Box))
  551. return false;
  552. }
  553. // Accept requested position
  554. mw->setPosition(mwBox.pos);
  555. RackWidget_updateExpanders(this);
  556. return true;
  557. }
  558. static math::Vec eachNearestGridPos(math::Vec pos, std::function<bool(math::Vec pos)> f) {
  559. // Dijkstra's algorithm to generate a sorted list of Vecs closest to `pos`.
  560. // Comparison of distance of Vecs to `pos`
  561. auto cmpNearest = [&](const math::Vec& a, const math::Vec& b) {
  562. return a.minus(pos).square() > b.minus(pos).square();
  563. };
  564. // Comparison of dictionary order of Vecs
  565. auto cmp = [](const math::Vec& a, const math::Vec& b) {
  566. if (a.y != b.y)
  567. return a.y < b.y;
  568. return a.x < b.x;
  569. };
  570. // Priority queue sorted by distance from `pos`
  571. std::priority_queue<math::Vec, std::vector<math::Vec>, decltype(cmpNearest)> queue(cmpNearest);
  572. // Set of already-tested Vecs
  573. std::set<math::Vec, decltype(cmp)> visited(cmp);
  574. // Seed priority queue with closest Vec
  575. math::Vec closestPos = pos.div(RACK_GRID_SIZE).round().mult(RACK_GRID_SIZE);
  576. queue.push(closestPos);
  577. while (!queue.empty()) {
  578. math::Vec testPos = queue.top();
  579. // Check testPos
  580. if (f(testPos))
  581. return testPos;
  582. // Move testPos to visited set
  583. queue.pop();
  584. visited.insert(testPos);
  585. // Add adjacent Vecs
  586. static const std::vector<math::Vec> deltas = {
  587. math::Vec(1, 0).mult(RACK_GRID_SIZE),
  588. math::Vec(0, 1).mult(RACK_GRID_SIZE),
  589. math::Vec(-1, 0).mult(RACK_GRID_SIZE),
  590. math::Vec(0, -1).mult(RACK_GRID_SIZE),
  591. };
  592. for (math::Vec delta : deltas) {
  593. math::Vec newPos = testPos.plus(delta);
  594. if (visited.find(newPos) == visited.end()) {
  595. queue.push(newPos);
  596. }
  597. }
  598. }
  599. // We failed to find a box. This shouldn't happen on an infinite rack.
  600. assert(false);
  601. return math::Vec();
  602. }
  603. void RackWidget::setModulePosNearest(ModuleWidget* mw, math::Vec pos) {
  604. eachNearestGridPos(pos, [&](math::Vec pos) -> bool {
  605. return requestModulePos(mw, pos);
  606. });
  607. }
  608. void RackWidget::setModulePosForce(ModuleWidget* mw, math::Vec pos) {
  609. mw->setPosition(pos.div(RACK_GRID_SIZE).round().mult(RACK_GRID_SIZE));
  610. // Comparison of center X coordinates
  611. auto cmp = [&](const widget::Widget * a, const widget::Widget * b) {
  612. return a->box.pos.x + a->box.size.x / 2 < b->box.pos.x + b->box.size.x / 2;
  613. };
  614. // Collect modules to the left and right of `mw`
  615. std::set<widget::Widget*, decltype(cmp)> leftModules(cmp);
  616. std::set<widget::Widget*, decltype(cmp)> rightModules(cmp);
  617. for (widget::Widget* w2 : internal->moduleContainer->children) {
  618. if (w2 == mw)
  619. continue;
  620. // Modules must be on the same row as `mw`
  621. if (w2->box.pos.y != mw->box.pos.y)
  622. continue;
  623. if (cmp(w2, mw))
  624. leftModules.insert(w2);
  625. else
  626. rightModules.insert(w2);
  627. }
  628. // Shove left modules
  629. float xLimit = mw->box.pos.x;
  630. for (auto it = leftModules.rbegin(); it != leftModules.rend(); it++) {
  631. widget::Widget* w = *it;
  632. math::Vec newPos = w->box.pos;
  633. newPos.x = xLimit - w->box.size.x;
  634. newPos.x = std::round(newPos.x / RACK_GRID_WIDTH) * RACK_GRID_WIDTH;
  635. if (w->box.pos.x < newPos.x)
  636. break;
  637. w->setPosition(newPos);
  638. xLimit = newPos.x;
  639. }
  640. // Shove right modules
  641. xLimit = mw->box.pos.x + mw->box.size.x;
  642. for (auto it = rightModules.begin(); it != rightModules.end(); it++) {
  643. widget::Widget* w = *it;
  644. math::Vec newPos = w->box.pos;
  645. newPos.x = xLimit;
  646. newPos.x = std::round(newPos.x / RACK_GRID_WIDTH) * RACK_GRID_WIDTH;
  647. if (w->box.pos.x > newPos.x)
  648. break;
  649. w->setPosition(newPos);
  650. xLimit = newPos.x + w->box.size.x;
  651. }
  652. RackWidget_updateExpanders(this);
  653. }
  654. ModuleWidget* RackWidget::getModule(int64_t moduleId) {
  655. for (widget::Widget* w : internal->moduleContainer->children) {
  656. ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
  657. assert(mw);
  658. if (mw->module->id == moduleId)
  659. return mw;
  660. }
  661. return NULL;
  662. }
  663. std::vector<ModuleWidget*> RackWidget::getModules() {
  664. std::vector<ModuleWidget*> mws;
  665. mws.reserve(internal->moduleContainer->children.size());
  666. for (widget::Widget* w : internal->moduleContainer->children) {
  667. ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
  668. assert(mw);
  669. mws.push_back(mw);
  670. }
  671. mws.shrink_to_fit();
  672. return mws;
  673. }
  674. bool RackWidget::hasModules() {
  675. return internal->moduleContainer->children.empty();
  676. }
  677. void RackWidget::updateModuleOldPositions() {
  678. internal->moduleOldPositions.clear();
  679. for (ModuleWidget* mw : getModules()) {
  680. internal->moduleOldPositions[mw] = mw->getPosition();
  681. }
  682. }
  683. history::ComplexAction* RackWidget::getModuleDragAction() {
  684. history::ComplexAction* h = new history::ComplexAction;
  685. h->name = "move modules";
  686. for (ModuleWidget* mw : getModules()) {
  687. // Create ModuleMove action if the module was moved.
  688. auto it = internal->moduleOldPositions.find(mw);
  689. if (it == internal->moduleOldPositions.end())
  690. continue;
  691. math::Vec oldPos = it->second;
  692. if (!oldPos.equals(mw->box.pos)) {
  693. history::ModuleMove* mmh = new history::ModuleMove;
  694. mmh->moduleId = mw->module->id;
  695. mmh->oldPos = oldPos;
  696. mmh->newPos = mw->box.pos;
  697. h->push(mmh);
  698. }
  699. }
  700. return h;
  701. }
  702. void RackWidget::updateSelectionFromRect() {
  703. math::Rect selectionBox = math::Rect::fromCorners(internal->selectionStart, internal->selectionEnd);
  704. deselectAll();
  705. for (ModuleWidget* mw : getModules()) {
  706. bool selected = internal->selecting && selectionBox.intersects(mw->box);
  707. if (selected)
  708. select(mw);
  709. }
  710. }
  711. void RackWidget::selectAll() {
  712. internal->selectedModules.clear();
  713. for (widget::Widget* w : internal->moduleContainer->children) {
  714. ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
  715. assert(mw);
  716. internal->selectedModules.insert(mw);
  717. }
  718. }
  719. void RackWidget::deselectAll() {
  720. internal->selectedModules.clear();
  721. }
  722. void RackWidget::select(ModuleWidget* mw, bool selected) {
  723. if (selected) {
  724. internal->selectedModules.insert(mw);
  725. }
  726. else {
  727. auto it = internal->selectedModules.find(mw);
  728. if (it != internal->selectedModules.end())
  729. internal->selectedModules.erase(it);
  730. }
  731. }
  732. bool RackWidget::hasSelection() {
  733. return !internal->selectedModules.empty();
  734. }
  735. const std::set<ModuleWidget*>& RackWidget::getSelected() {
  736. return internal->selectedModules;
  737. }
  738. bool RackWidget::isSelected(ModuleWidget* mw) {
  739. auto it = internal->selectedModules.find(mw);
  740. return (it != internal->selectedModules.end());
  741. }
  742. json_t* RackWidget::selectionToJson(bool cables) {
  743. json_t* rootJ = json_object();
  744. std::set<engine::Module*> modules;
  745. // modules
  746. json_t* modulesJ = json_array();
  747. for (ModuleWidget* mw : getSelected()) {
  748. json_t* moduleJ = mw->toJson();
  749. // pos
  750. math::Vec pos = mw->box.pos.minus(RACK_OFFSET);
  751. pos = pos.div(RACK_GRID_SIZE).round();
  752. json_t* posJ = json_pack("[i, i]", (int) pos.x, (int) pos.y);
  753. json_object_set_new(moduleJ, "pos", posJ);
  754. json_array_append_new(modulesJ, moduleJ);
  755. modules.insert(mw->getModule());
  756. }
  757. json_object_set_new(rootJ, "modules", modulesJ);
  758. if (cables) {
  759. // cables
  760. json_t* cablesJ = json_array();
  761. for (CableWidget* cw : getCompleteCables()) {
  762. // Only add cables attached on both ends to selected modules
  763. engine::Cable* cable = cw->getCable();
  764. if (!cable || !cable->inputModule || !cable->outputModule)
  765. continue;
  766. const auto inputIt = modules.find(cable->inputModule);
  767. if (inputIt == modules.end())
  768. continue;
  769. const auto outputIt = modules.find(cable->outputModule);
  770. if (outputIt == modules.end())
  771. continue;
  772. json_t* cableJ = cable->toJson();
  773. cw->mergeJson(cableJ);
  774. json_array_append_new(cablesJ, cableJ);
  775. }
  776. json_object_set_new(rootJ, "cables", cablesJ);
  777. }
  778. return rootJ;
  779. }
  780. static const char SELECTION_FILTERS[] = "VCV Rack module selection (.vcvs):vcvs";
  781. void RackWidget::loadSelection(std::string path) {
  782. FILE* file = std::fopen(path.c_str(), "r");
  783. if (!file)
  784. throw Exception("Could not load selection file %s", path.c_str());
  785. DEFER({std::fclose(file);});
  786. INFO("Loading selection %s", path.c_str());
  787. json_error_t error;
  788. json_t* rootJ = json_loadf(file, 0, &error);
  789. if (!rootJ)
  790. throw Exception("File is not a valid selection file. JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
  791. DEFER({json_decref(rootJ);});
  792. pasteJsonAction(rootJ);
  793. }
  794. void RackWidget::loadSelectionDialog() {
  795. std::string selectionDir = asset::user("selections");
  796. system::createDirectories(selectionDir);
  797. osdialog_filters* filters = osdialog_filters_parse(SELECTION_FILTERS);
  798. DEFER({osdialog_filters_free(filters);});
  799. char* pathC = osdialog_file(OSDIALOG_OPEN, selectionDir.c_str(), NULL, filters);
  800. if (!pathC) {
  801. // No path selected
  802. return;
  803. }
  804. DEFER({std::free(pathC);});
  805. try {
  806. loadSelection(pathC);
  807. }
  808. catch (Exception& e) {
  809. osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, e.what());
  810. }
  811. }
  812. void RackWidget::saveSelection(std::string path) {
  813. INFO("Saving selection %s", path.c_str());
  814. json_t* rootJ = selectionToJson();
  815. assert(rootJ);
  816. DEFER({json_decref(rootJ);});
  817. engine::Module::jsonStripIds(rootJ);
  818. FILE* file = std::fopen(path.c_str(), "w");
  819. if (!file) {
  820. std::string message = string::f("Could not save selection to file %s", path.c_str());
  821. osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
  822. return;
  823. }
  824. DEFER({std::fclose(file);});
  825. json_dumpf(rootJ, file, JSON_INDENT(2));
  826. }
  827. void RackWidget::saveSelectionDialog() {
  828. std::string selectionDir = asset::user("selections");
  829. system::createDirectories(selectionDir);
  830. osdialog_filters* filters = osdialog_filters_parse(SELECTION_FILTERS);
  831. DEFER({osdialog_filters_free(filters);});
  832. char* pathC = osdialog_file(OSDIALOG_SAVE, selectionDir.c_str(), "Untitled.vcvs", filters);
  833. if (!pathC) {
  834. // No path selected
  835. return;
  836. }
  837. DEFER({std::free(pathC);});
  838. std::string path = pathC;
  839. // Automatically append .vcvs extension
  840. if (system::getExtension(path) != ".vcvs")
  841. path += ".vcvs";
  842. saveSelection(path);
  843. }
  844. void RackWidget::copyClipboardSelection() {
  845. json_t* rootJ = selectionToJson();
  846. DEFER({json_decref(rootJ);});
  847. char* moduleJson = json_dumps(rootJ, JSON_INDENT(2));
  848. DEFER({std::free(moduleJson);});
  849. glfwSetClipboardString(APP->window->win, moduleJson);
  850. }
  851. void RackWidget::resetSelectionAction() {
  852. history::ComplexAction* complexAction = new history::ComplexAction;
  853. complexAction->name = "reset modules";
  854. for (ModuleWidget* mw : getSelected()) {
  855. assert(mw->module);
  856. // history::ModuleChange
  857. history::ModuleChange* h = new history::ModuleChange;
  858. h->moduleId = mw->module->id;
  859. h->oldModuleJ = mw->toJson();
  860. APP->engine->resetModule(mw->module);
  861. h->newModuleJ = mw->toJson();
  862. complexAction->push(h);
  863. }
  864. APP->history->push(complexAction);
  865. }
  866. void RackWidget::randomizeSelectionAction() {
  867. history::ComplexAction* complexAction = new history::ComplexAction;
  868. complexAction->name = "randomize modules";
  869. for (ModuleWidget* mw : getSelected()) {
  870. assert(mw->module);
  871. // history::ModuleChange
  872. history::ModuleChange* h = new history::ModuleChange;
  873. h->moduleId = mw->module->id;
  874. h->oldModuleJ = mw->toJson();
  875. APP->engine->randomizeModule(mw->module);
  876. h->newModuleJ = mw->toJson();
  877. complexAction->push(h);
  878. }
  879. APP->history->push(complexAction);
  880. }
  881. void RackWidget::disconnectSelectionAction() {
  882. history::ComplexAction* complexAction = new history::ComplexAction;
  883. complexAction->name = "disconnect cables";
  884. for (ModuleWidget* mw : getSelected()) {
  885. mw->appendDisconnectActions(complexAction);
  886. }
  887. if (!complexAction->isEmpty())
  888. APP->history->push(complexAction);
  889. else
  890. delete complexAction;
  891. }
  892. void RackWidget::cloneSelectionAction(bool cloneCables) {
  893. json_t* rootJ = selectionToJson(cloneCables);
  894. DEFER({json_decref(rootJ);});
  895. history::ComplexAction* complexAction = new history::ComplexAction;
  896. complexAction->name = "duplicate modules";
  897. DEFER({
  898. if (!complexAction->isEmpty())
  899. APP->history->push(complexAction);
  900. else
  901. delete complexAction;
  902. });
  903. auto p = RackWidget_pasteJson(this, rootJ, complexAction);
  904. // Clone cables attached to inputs of selected modules but outputs of non-selected modules
  905. if (cloneCables) {
  906. for (CableWidget* cw : getCompleteCables()) {
  907. auto inputIt = p.newModuleIds.find(cw->getCable()->inputModule->id);
  908. if (inputIt == p.newModuleIds.end())
  909. continue;
  910. auto outputIt = p.newModuleIds.find(cw->getCable()->outputModule->id);
  911. if (outputIt != p.newModuleIds.end())
  912. continue;
  913. int64_t clonedInputModuleId = inputIt->second;
  914. engine::Module* clonedInputModule = APP->engine->getModule(clonedInputModuleId);
  915. // Create cable attached to cloned ModuleWidget's input
  916. engine::Cable* clonedCable = new engine::Cable;
  917. clonedCable->inputModule = clonedInputModule;
  918. clonedCable->inputId = cw->cable->inputId;
  919. clonedCable->outputModule = cw->cable->outputModule;
  920. clonedCable->outputId = cw->cable->outputId;
  921. APP->engine->addCable(clonedCable);
  922. app::CableWidget* clonedCw = new app::CableWidget;
  923. clonedCw->setCable(clonedCable);
  924. clonedCw->color = cw->color;
  925. APP->scene->rack->addCable(clonedCw);
  926. // history::CableAdd
  927. history::CableAdd* hca = new history::CableAdd;
  928. hca->setCable(clonedCw);
  929. complexAction->push(hca);
  930. }
  931. }
  932. }
  933. void RackWidget::bypassSelectionAction(bool bypassed) {
  934. history::ComplexAction* complexAction = new history::ComplexAction;
  935. complexAction->name = bypassed ? "bypass modules" : "un-bypass modules";
  936. for (ModuleWidget* mw : getSelected()) {
  937. assert(mw->module);
  938. if (mw->module->isBypassed() == bypassed)
  939. continue;
  940. // history::ModuleBypass
  941. history::ModuleBypass* h = new history::ModuleBypass;
  942. h->moduleId = mw->module->id;
  943. h->bypassed = bypassed;
  944. complexAction->push(h);
  945. APP->engine->bypassModule(mw->module, bypassed);
  946. }
  947. if (!complexAction->isEmpty())
  948. APP->history->push(complexAction);
  949. else
  950. delete complexAction;
  951. }
  952. bool RackWidget::isSelectionBypassed() {
  953. for (ModuleWidget* mw : getSelected()) {
  954. if (!mw->getModule()->isBypassed())
  955. return false;
  956. }
  957. return true;
  958. }
  959. void RackWidget::deleteSelectionAction() {
  960. history::ComplexAction* complexAction = new history::ComplexAction;
  961. complexAction->name = "remove modules";
  962. // Copy selected set since removing ModuleWidgets modifies it.
  963. std::set<ModuleWidget*> selectedModules = getSelected();
  964. for (ModuleWidget* mw : selectedModules) {
  965. mw->appendDisconnectActions(complexAction);
  966. // history::ModuleRemove
  967. history::ModuleRemove* moduleRemove = new history::ModuleRemove;
  968. moduleRemove->setModule(mw);
  969. complexAction->push(moduleRemove);
  970. removeModule(mw);
  971. delete mw;
  972. }
  973. APP->history->push(complexAction);
  974. }
  975. bool RackWidget::requestSelectionPos(math::Vec delta) {
  976. // Calculate new positions
  977. std::map<widget::Widget*, math::Rect> mwBoxes;
  978. for (ModuleWidget* mw : getSelected()) {
  979. math::Rect mwBox = mw->box;
  980. mwBox.pos += delta;
  981. mwBoxes[mw] = mwBox;
  982. }
  983. // Check intersection with other modules
  984. for (widget::Widget* w2 : internal->moduleContainer->children) {
  985. // Don't intersect with selected modules
  986. auto it = mwBoxes.find(w2);
  987. if (it != mwBoxes.end())
  988. continue;
  989. math::Rect w2Box = w2->box;
  990. // Check intersection with all selected modules
  991. for (const auto& pair : mwBoxes) {
  992. if (pair.second.intersects(w2Box))
  993. return false;
  994. }
  995. }
  996. // Accept requested position
  997. for (const auto& pair : mwBoxes) {
  998. pair.first->setPosition(pair.second.pos);
  999. }
  1000. RackWidget_updateExpanders(this);
  1001. return true;
  1002. }
  1003. void RackWidget::setSelectionPosNearest(math::Vec delta) {
  1004. eachNearestGridPos(delta, [&](math::Vec delta) -> bool {
  1005. return requestSelectionPos(delta);
  1006. });
  1007. }
  1008. void RackWidget::appendSelectionContextMenu(ui::Menu* menu) {
  1009. int n = getSelected().size();
  1010. menu->addChild(createMenuLabel(string::f("%d selected %s", n, n == 1 ? "module" : "modules")));
  1011. // Enable alwaysConsume of menu items if the number of selected modules changes
  1012. // Select all
  1013. menu->addChild(createMenuItem("Select all", RACK_MOD_CTRL_NAME "+A", [=]() {
  1014. selectAll();
  1015. }, false, true));
  1016. // Deselect
  1017. menu->addChild(createMenuItem("Deselect", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+A", [=]() {
  1018. deselectAll();
  1019. }, n == 0, true));
  1020. // Copy
  1021. menu->addChild(createMenuItem("Copy", RACK_MOD_CTRL_NAME "+C", [=]() {
  1022. copyClipboardSelection();
  1023. }, n == 0));
  1024. // Paste
  1025. menu->addChild(createMenuItem("Paste", RACK_MOD_CTRL_NAME "+V", [=]() {
  1026. pasteClipboardAction();
  1027. }, false, true));
  1028. // Save
  1029. menu->addChild(createMenuItem("Save selection as", "", [=]() {
  1030. saveSelectionDialog();
  1031. }, n == 0));
  1032. // Initialize
  1033. menu->addChild(createMenuItem("Initialize", RACK_MOD_CTRL_NAME "+I", [=]() {
  1034. resetSelectionAction();
  1035. }, n == 0));
  1036. // Randomize
  1037. menu->addChild(createMenuItem("Randomize", RACK_MOD_CTRL_NAME "+R", [=]() {
  1038. randomizeSelectionAction();
  1039. }, n == 0));
  1040. // Disconnect cables
  1041. menu->addChild(createMenuItem("Disconnect cables", RACK_MOD_CTRL_NAME "+U", [=]() {
  1042. disconnectSelectionAction();
  1043. }, n == 0));
  1044. // Bypass
  1045. std::string bypassText = RACK_MOD_CTRL_NAME "+E";
  1046. bool bypassed = (n > 0) && isSelectionBypassed();
  1047. if (bypassed)
  1048. bypassText += " " CHECKMARK_STRING;
  1049. menu->addChild(createMenuItem("Bypass", bypassText, [=]() {
  1050. bypassSelectionAction(!bypassed);
  1051. }, n == 0, true));
  1052. // Duplicate
  1053. menu->addChild(createMenuItem("Duplicate", RACK_MOD_CTRL_NAME "+D", [=]() {
  1054. cloneSelectionAction(false);
  1055. }, n == 0));
  1056. // Duplicate with cables
  1057. menu->addChild(createMenuItem("└ with cables", RACK_MOD_SHIFT_NAME "+" RACK_MOD_CTRL_NAME "+D", [=]() {
  1058. cloneSelectionAction(true);
  1059. }, n == 0));
  1060. // Delete
  1061. menu->addChild(createMenuItem("Delete", "Backspace/Delete", [=]() {
  1062. deleteSelectionAction();
  1063. }, n == 0, true));
  1064. }
  1065. void RackWidget::clearCables() {
  1066. internal->incompleteCable = NULL;
  1067. internal->cableContainer->clearChildren();
  1068. }
  1069. void RackWidget::clearCablesAction() {
  1070. // Add CableRemove for every cable to a ComplexAction
  1071. history::ComplexAction* complexAction = new history::ComplexAction;
  1072. complexAction->name = "clear cables";
  1073. for (CableWidget* cw : getCompleteCables()) {
  1074. // history::CableRemove
  1075. history::CableRemove* h = new history::CableRemove;
  1076. h->setCable(cw);
  1077. complexAction->push(h);
  1078. }
  1079. if (!complexAction->isEmpty())
  1080. APP->history->push(complexAction);
  1081. else
  1082. delete complexAction;
  1083. clearCables();
  1084. }
  1085. void RackWidget::clearCablesOnPort(PortWidget* port) {
  1086. for (CableWidget* cw : getCablesOnPort(port)) {
  1087. // Check if cable is connected to port
  1088. if (cw == internal->incompleteCable) {
  1089. internal->incompleteCable = NULL;
  1090. internal->cableContainer->removeChild(cw);
  1091. }
  1092. else {
  1093. removeCable(cw);
  1094. }
  1095. delete cw;
  1096. }
  1097. }
  1098. void RackWidget::addCable(CableWidget* cw) {
  1099. assert(cw->isComplete());
  1100. internal->cableContainer->addChild(cw);
  1101. }
  1102. void RackWidget::removeCable(CableWidget* cw) {
  1103. assert(cw->isComplete());
  1104. internal->cableContainer->removeChild(cw);
  1105. }
  1106. CableWidget* RackWidget::getIncompleteCable() {
  1107. return internal->incompleteCable;
  1108. }
  1109. void RackWidget::setIncompleteCable(CableWidget* cw) {
  1110. if (internal->incompleteCable) {
  1111. internal->cableContainer->removeChild(internal->incompleteCable);
  1112. delete internal->incompleteCable;
  1113. internal->incompleteCable = NULL;
  1114. }
  1115. if (cw) {
  1116. internal->cableContainer->addChild(cw);
  1117. internal->incompleteCable = cw;
  1118. }
  1119. }
  1120. CableWidget* RackWidget::releaseIncompleteCable() {
  1121. if (!internal->incompleteCable)
  1122. return NULL;
  1123. CableWidget* cw = internal->incompleteCable;
  1124. internal->cableContainer->removeChild(internal->incompleteCable);
  1125. internal->incompleteCable = NULL;
  1126. return cw;
  1127. }
  1128. CableWidget* RackWidget::getTopCable(PortWidget* port) {
  1129. for (auto it = internal->cableContainer->children.rbegin(); it != internal->cableContainer->children.rend(); it++) {
  1130. CableWidget* cw = dynamic_cast<CableWidget*>(*it);
  1131. assert(cw);
  1132. if (cw->inputPort == port || cw->outputPort == port)
  1133. return cw;
  1134. }
  1135. return NULL;
  1136. }
  1137. CableWidget* RackWidget::getCable(int64_t cableId) {
  1138. for (widget::Widget* w : internal->cableContainer->children) {
  1139. CableWidget* cw = dynamic_cast<CableWidget*>(w);
  1140. assert(cw);
  1141. if (!cw->cable)
  1142. continue;
  1143. if (cw->cable->id == cableId)
  1144. return cw;
  1145. }
  1146. return NULL;
  1147. }
  1148. std::vector<CableWidget*> RackWidget::getCompleteCables() {
  1149. std::vector<CableWidget*> cws;
  1150. cws.reserve(internal->cableContainer->children.size());
  1151. for (widget::Widget* w : internal->cableContainer->children) {
  1152. CableWidget* cw = dynamic_cast<CableWidget*>(w);
  1153. assert(cw);
  1154. if (cw->isComplete())
  1155. cws.push_back(cw);
  1156. }
  1157. cws.shrink_to_fit();
  1158. return cws;
  1159. }
  1160. std::vector<CableWidget*> RackWidget::getCablesOnPort(PortWidget* port) {
  1161. assert(port);
  1162. std::vector<CableWidget*> cws;
  1163. for (widget::Widget* w : internal->cableContainer->children) {
  1164. CableWidget* cw = dynamic_cast<CableWidget*>(w);
  1165. assert(cw);
  1166. if (cw->inputPort == port || cw->outputPort == port) {
  1167. cws.push_back(cw);
  1168. }
  1169. }
  1170. return cws;
  1171. }
  1172. std::vector<CableWidget*> RackWidget::getCompleteCablesOnPort(PortWidget* port) {
  1173. assert(port);
  1174. std::vector<CableWidget*> cws;
  1175. for (widget::Widget* w : internal->cableContainer->children) {
  1176. CableWidget* cw = dynamic_cast<CableWidget*>(w);
  1177. assert(cw);
  1178. if (!cw->isComplete())
  1179. continue;
  1180. if (cw->inputPort == port || cw->outputPort == port) {
  1181. cws.push_back(cw);
  1182. }
  1183. }
  1184. return cws;
  1185. }
  1186. int RackWidget::getNextCableColorId() {
  1187. return internal->nextCableColorId;
  1188. }
  1189. void RackWidget::setNextCableColorId(int id) {
  1190. internal->nextCableColorId = id;
  1191. }
  1192. NVGcolor RackWidget::getNextCableColor() {
  1193. if (settings::cableColors.empty())
  1194. return color::WHITE;
  1195. int id = internal->nextCableColorId++;
  1196. if (id >= (int) settings::cableColors.size())
  1197. id = 0;
  1198. if (internal->nextCableColorId >= (int) settings::cableColors.size())
  1199. internal->nextCableColorId = 0;
  1200. return settings::cableColors[id];
  1201. }
  1202. ParamWidget* RackWidget::getTouchedParam() {
  1203. return touchedParam;
  1204. }
  1205. void RackWidget::setTouchedParam(ParamWidget* pw) {
  1206. touchedParam = pw;
  1207. }
  1208. } // namespace app
  1209. } // namespace rack