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.

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