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.

1506 lines
39KB

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