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.

1478 lines
38KB

  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(getModuleMoveAction());
  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. mw->setPosition(pos.div(RACK_GRID_SIZE).round().mult(RACK_GRID_SIZE));
  586. // Comparison of X coordinates
  587. auto cmp = [&](const widget::Widget* a, const widget::Widget* b) {
  588. return a->box.pos.x < b->box.pos.x;
  589. };
  590. // Collect modules to the left and right of `mw`
  591. std::set<widget::Widget*, decltype(cmp)> leftModules(cmp);
  592. std::set<widget::Widget*, decltype(cmp)> rightModules(cmp);
  593. for (widget::Widget* w2 : internal->moduleContainer->children) {
  594. // Skip this module
  595. if (w2 == mw)
  596. continue;
  597. // Reset position to old position
  598. auto it = internal->moduleOldPositions.find(w2);
  599. if (it != internal->moduleOldPositions.end()) {
  600. w2->box.pos = it->second;
  601. }
  602. // Modules must be on the same row as `mw`
  603. if (w2->box.getTop() != mw->box.getTop())
  604. continue;
  605. // Insert into leftModules or rightModules
  606. if (w2->box.getCenter().x < mw->box.getCenter().x)
  607. leftModules.insert(w2);
  608. else
  609. rightModules.insert(w2);
  610. }
  611. widget::Widget* leftModule = leftModules.empty() ? NULL : *leftModules.rbegin();
  612. widget::Widget* rightModule = rightModules.empty() ? NULL : *rightModules.begin();
  613. if (leftModule) {
  614. if (leftModule->box.getRight() > mw->box.getLeft()) {
  615. mw->box.pos.x = leftModule->box.getRight();
  616. }
  617. }
  618. if (rightModule) {
  619. if (mw->box.getRight() > rightModule->box.getLeft()) {
  620. mw->box.pos.x = rightModule->box.getLeft() - mw->box.size.x;
  621. }
  622. }
  623. if (leftModule && rightModule) {
  624. // If there isn't enough space between the last leftModule and first rightModule, place module to the right of the leftModule.
  625. if (leftModule->box.getRight() + mw->box.getWidth() > rightModule->box.getLeft()) {
  626. mw->box.pos.x = leftModule->box.getRight();
  627. // Shove right modules
  628. float xLimit = mw->box.getRight();
  629. for (auto it = rightModules.begin(); it != rightModules.end(); it++) {
  630. widget::Widget* w2 = *it;
  631. math::Vec newPos = w2->box.pos;
  632. newPos.x = xLimit;
  633. newPos.x = std::round(newPos.x / RACK_GRID_WIDTH) * RACK_GRID_WIDTH;
  634. if (w2->box.pos.x > newPos.x)
  635. break;
  636. w2->box.pos = newPos;
  637. xLimit = w2->box.getRight();
  638. }
  639. }
  640. }
  641. updateExpanders();
  642. }
  643. ModuleWidget* RackWidget::getModule(int64_t moduleId) {
  644. for (widget::Widget* w : internal->moduleContainer->children) {
  645. ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
  646. assert(mw);
  647. if (mw->module->id == moduleId)
  648. return mw;
  649. }
  650. return NULL;
  651. }
  652. std::vector<ModuleWidget*> RackWidget::getModules() {
  653. std::vector<ModuleWidget*> mws;
  654. mws.reserve(internal->moduleContainer->children.size());
  655. for (widget::Widget* w : internal->moduleContainer->children) {
  656. ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
  657. assert(mw);
  658. mws.push_back(mw);
  659. }
  660. mws.shrink_to_fit();
  661. return mws;
  662. }
  663. bool RackWidget::hasModules() {
  664. return internal->moduleContainer->children.empty();
  665. }
  666. void RackWidget::updateModuleOldPositions() {
  667. internal->moduleOldPositions.clear();
  668. for (ModuleWidget* mw : getModules()) {
  669. internal->moduleOldPositions[mw] = mw->getPosition();
  670. }
  671. }
  672. history::ComplexAction* RackWidget::getModuleMoveAction() {
  673. history::ComplexAction* h = new history::ComplexAction;
  674. h->name = "move modules";
  675. for (ModuleWidget* mw : getModules()) {
  676. // Create ModuleMove action if the module was moved.
  677. auto it = internal->moduleOldPositions.find(mw);
  678. if (it == internal->moduleOldPositions.end())
  679. continue;
  680. math::Vec oldPos = it->second;
  681. if (!oldPos.equals(mw->box.pos)) {
  682. history::ModuleMove* mmh = new history::ModuleMove;
  683. mmh->moduleId = mw->module->id;
  684. mmh->oldPos = oldPos;
  685. mmh->newPos = mw->box.pos;
  686. h->push(mmh);
  687. }
  688. }
  689. return h;
  690. }
  691. void RackWidget::updateSelectionFromRect() {
  692. math::Rect selectionBox = math::Rect::fromCorners(internal->selectionStart, internal->selectionEnd);
  693. deselectAll();
  694. for (ModuleWidget* mw : getModules()) {
  695. bool selected = internal->selecting && selectionBox.intersects(mw->box);
  696. if (selected)
  697. select(mw);
  698. }
  699. }
  700. void RackWidget::selectAll() {
  701. internal->selectedModules.clear();
  702. for (widget::Widget* w : internal->moduleContainer->children) {
  703. ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
  704. assert(mw);
  705. internal->selectedModules.insert(mw);
  706. }
  707. }
  708. void RackWidget::deselectAll() {
  709. internal->selectedModules.clear();
  710. }
  711. void RackWidget::select(ModuleWidget* mw, bool selected) {
  712. if (selected) {
  713. internal->selectedModules.insert(mw);
  714. }
  715. else {
  716. auto it = internal->selectedModules.find(mw);
  717. if (it != internal->selectedModules.end())
  718. internal->selectedModules.erase(it);
  719. }
  720. }
  721. bool RackWidget::hasSelection() {
  722. return !internal->selectedModules.empty();
  723. }
  724. const std::set<ModuleWidget*>& RackWidget::getSelected() {
  725. return internal->selectedModules;
  726. }
  727. bool RackWidget::isSelected(ModuleWidget* mw) {
  728. auto it = internal->selectedModules.find(mw);
  729. return (it != internal->selectedModules.end());
  730. }
  731. json_t* RackWidget::selectionToJson(bool cables) {
  732. json_t* rootJ = json_object();
  733. std::set<engine::Module*> modules;
  734. // modules
  735. json_t* modulesJ = json_array();
  736. for (ModuleWidget* mw : getSelected()) {
  737. json_t* moduleJ = mw->toJson();
  738. // pos
  739. math::Vec pos = mw->box.pos.minus(RACK_OFFSET);
  740. pos = pos.div(RACK_GRID_SIZE).round();
  741. json_t* posJ = json_pack("[i, i]", (int) pos.x, (int) pos.y);
  742. json_object_set_new(moduleJ, "pos", posJ);
  743. json_array_append_new(modulesJ, moduleJ);
  744. modules.insert(mw->getModule());
  745. }
  746. json_object_set_new(rootJ, "modules", modulesJ);
  747. if (cables) {
  748. // cables
  749. json_t* cablesJ = json_array();
  750. for (CableWidget* cw : getCompleteCables()) {
  751. // Only add cables attached on both ends to selected modules
  752. engine::Cable* cable = cw->getCable();
  753. if (!cable || !cable->inputModule || !cable->outputModule)
  754. continue;
  755. const auto inputIt = modules.find(cable->inputModule);
  756. if (inputIt == modules.end())
  757. continue;
  758. const auto outputIt = modules.find(cable->outputModule);
  759. if (outputIt == modules.end())
  760. continue;
  761. json_t* cableJ = cable->toJson();
  762. cw->mergeJson(cableJ);
  763. json_array_append_new(cablesJ, cableJ);
  764. }
  765. json_object_set_new(rootJ, "cables", cablesJ);
  766. }
  767. return rootJ;
  768. }
  769. static const char SELECTION_FILTERS[] = "VCV Rack module selection (.vcvs):vcvs";
  770. void RackWidget::loadSelection(std::string path) {
  771. FILE* file = std::fopen(path.c_str(), "r");
  772. if (!file)
  773. throw Exception("Could not load selection file %s", path.c_str());
  774. DEFER({std::fclose(file);});
  775. INFO("Loading selection %s", path.c_str());
  776. json_error_t error;
  777. json_t* rootJ = json_loadf(file, 0, &error);
  778. if (!rootJ)
  779. 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);
  780. DEFER({json_decref(rootJ);});
  781. pasteJsonAction(rootJ);
  782. }
  783. void RackWidget::loadSelectionDialog() {
  784. std::string selectionDir = asset::user("selections");
  785. system::createDirectories(selectionDir);
  786. osdialog_filters* filters = osdialog_filters_parse(SELECTION_FILTERS);
  787. DEFER({osdialog_filters_free(filters);});
  788. char* pathC = osdialog_file(OSDIALOG_OPEN, selectionDir.c_str(), NULL, filters);
  789. if (!pathC) {
  790. // No path selected
  791. return;
  792. }
  793. DEFER({std::free(pathC);});
  794. try {
  795. loadSelection(pathC);
  796. }
  797. catch (Exception& e) {
  798. osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, e.what());
  799. }
  800. }
  801. void RackWidget::saveSelection(std::string path) {
  802. INFO("Saving selection %s", path.c_str());
  803. json_t* rootJ = selectionToJson();
  804. assert(rootJ);
  805. DEFER({json_decref(rootJ);});
  806. engine::Module::jsonStripIds(rootJ);
  807. FILE* file = std::fopen(path.c_str(), "w");
  808. if (!file) {
  809. std::string message = string::f("Could not save selection to file %s", path.c_str());
  810. osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
  811. return;
  812. }
  813. DEFER({std::fclose(file);});
  814. json_dumpf(rootJ, file, JSON_INDENT(2));
  815. }
  816. void RackWidget::saveSelectionDialog() {
  817. std::string selectionDir = asset::user("selections");
  818. system::createDirectories(selectionDir);
  819. osdialog_filters* filters = osdialog_filters_parse(SELECTION_FILTERS);
  820. DEFER({osdialog_filters_free(filters);});
  821. char* pathC = osdialog_file(OSDIALOG_SAVE, selectionDir.c_str(), "Untitled.vcvs", filters);
  822. if (!pathC) {
  823. // No path selected
  824. return;
  825. }
  826. DEFER({std::free(pathC);});
  827. std::string path = pathC;
  828. // Automatically append .vcvs extension
  829. if (system::getExtension(path) != ".vcvs")
  830. path += ".vcvs";
  831. saveSelection(path);
  832. }
  833. void RackWidget::copyClipboardSelection() {
  834. json_t* rootJ = selectionToJson();
  835. DEFER({json_decref(rootJ);});
  836. char* moduleJson = json_dumps(rootJ, JSON_INDENT(2));
  837. DEFER({std::free(moduleJson);});
  838. glfwSetClipboardString(APP->window->win, moduleJson);
  839. }
  840. void RackWidget::resetSelectionAction() {
  841. history::ComplexAction* complexAction = new history::ComplexAction;
  842. complexAction->name = "reset modules";
  843. for (ModuleWidget* mw : getSelected()) {
  844. assert(mw->module);
  845. // history::ModuleChange
  846. history::ModuleChange* h = new history::ModuleChange;
  847. h->moduleId = mw->module->id;
  848. h->oldModuleJ = mw->toJson();
  849. APP->engine->resetModule(mw->module);
  850. h->newModuleJ = mw->toJson();
  851. complexAction->push(h);
  852. }
  853. APP->history->push(complexAction);
  854. }
  855. void RackWidget::randomizeSelectionAction() {
  856. history::ComplexAction* complexAction = new history::ComplexAction;
  857. complexAction->name = "randomize modules";
  858. for (ModuleWidget* mw : getSelected()) {
  859. assert(mw->module);
  860. // history::ModuleChange
  861. history::ModuleChange* h = new history::ModuleChange;
  862. h->moduleId = mw->module->id;
  863. h->oldModuleJ = mw->toJson();
  864. APP->engine->randomizeModule(mw->module);
  865. h->newModuleJ = mw->toJson();
  866. complexAction->push(h);
  867. }
  868. APP->history->push(complexAction);
  869. }
  870. void RackWidget::disconnectSelectionAction() {
  871. history::ComplexAction* complexAction = new history::ComplexAction;
  872. complexAction->name = "disconnect cables";
  873. for (ModuleWidget* mw : getSelected()) {
  874. mw->appendDisconnectActions(complexAction);
  875. }
  876. if (!complexAction->isEmpty())
  877. APP->history->push(complexAction);
  878. else
  879. delete complexAction;
  880. }
  881. void RackWidget::cloneSelectionAction(bool cloneCables) {
  882. json_t* rootJ = selectionToJson(cloneCables);
  883. DEFER({json_decref(rootJ);});
  884. history::ComplexAction* complexAction = new history::ComplexAction;
  885. complexAction->name = "duplicate modules";
  886. DEFER({
  887. if (!complexAction->isEmpty())
  888. APP->history->push(complexAction);
  889. else
  890. delete complexAction;
  891. });
  892. auto p = RackWidget_pasteJson(this, rootJ, complexAction);
  893. // Clone cables attached to inputs of selected modules but outputs of non-selected modules
  894. if (cloneCables) {
  895. for (CableWidget* cw : getCompleteCables()) {
  896. auto inputIt = p.newModuleIds.find(cw->getCable()->inputModule->id);
  897. if (inputIt == p.newModuleIds.end())
  898. continue;
  899. auto outputIt = p.newModuleIds.find(cw->getCable()->outputModule->id);
  900. if (outputIt != p.newModuleIds.end())
  901. continue;
  902. int64_t clonedInputModuleId = inputIt->second;
  903. engine::Module* clonedInputModule = APP->engine->getModule(clonedInputModuleId);
  904. // Create cable attached to cloned ModuleWidget's input
  905. engine::Cable* clonedCable = new engine::Cable;
  906. clonedCable->inputModule = clonedInputModule;
  907. clonedCable->inputId = cw->cable->inputId;
  908. clonedCable->outputModule = cw->cable->outputModule;
  909. clonedCable->outputId = cw->cable->outputId;
  910. APP->engine->addCable(clonedCable);
  911. app::CableWidget* clonedCw = new app::CableWidget;
  912. clonedCw->setCable(clonedCable);
  913. clonedCw->color = cw->color;
  914. APP->scene->rack->addCable(clonedCw);
  915. // history::CableAdd
  916. history::CableAdd* hca = new history::CableAdd;
  917. hca->setCable(clonedCw);
  918. complexAction->push(hca);
  919. }
  920. }
  921. }
  922. void RackWidget::bypassSelectionAction(bool bypassed) {
  923. history::ComplexAction* complexAction = new history::ComplexAction;
  924. complexAction->name = bypassed ? "bypass modules" : "un-bypass modules";
  925. for (ModuleWidget* mw : getSelected()) {
  926. assert(mw->module);
  927. if (mw->module->isBypassed() == bypassed)
  928. continue;
  929. // history::ModuleBypass
  930. history::ModuleBypass* h = new history::ModuleBypass;
  931. h->moduleId = mw->module->id;
  932. h->bypassed = bypassed;
  933. complexAction->push(h);
  934. APP->engine->bypassModule(mw->module, bypassed);
  935. }
  936. if (!complexAction->isEmpty())
  937. APP->history->push(complexAction);
  938. else
  939. delete complexAction;
  940. }
  941. bool RackWidget::isSelectionBypassed() {
  942. for (ModuleWidget* mw : getSelected()) {
  943. if (!mw->getModule()->isBypassed())
  944. return false;
  945. }
  946. return true;
  947. }
  948. void RackWidget::deleteSelectionAction() {
  949. history::ComplexAction* complexAction = new history::ComplexAction;
  950. complexAction->name = "delete modules";
  951. // Copy selected set since removing ModuleWidgets modifies it.
  952. std::set<ModuleWidget*> selectedModules = getSelected();
  953. for (ModuleWidget* mw : selectedModules) {
  954. mw->appendDisconnectActions(complexAction);
  955. // history::ModuleRemove
  956. history::ModuleRemove* moduleRemove = new history::ModuleRemove;
  957. moduleRemove->setModule(mw);
  958. complexAction->push(moduleRemove);
  959. removeModule(mw);
  960. delete mw;
  961. }
  962. APP->history->push(complexAction);
  963. }
  964. bool RackWidget::requestSelectionPos(math::Vec delta) {
  965. // Calculate new positions
  966. std::map<widget::Widget*, math::Rect> mwBoxes;
  967. for (ModuleWidget* mw : getSelected()) {
  968. math::Rect mwBox = mw->box;
  969. mwBox.pos += delta;
  970. mwBoxes[mw] = mwBox;
  971. }
  972. // Check intersection with other modules
  973. for (widget::Widget* w2 : internal->moduleContainer->children) {
  974. // Don't intersect with selected modules
  975. auto it = mwBoxes.find(w2);
  976. if (it != mwBoxes.end())
  977. continue;
  978. math::Rect w2Box = w2->box;
  979. // Check intersection with all selected modules
  980. for (const auto& pair : mwBoxes) {
  981. if (pair.second.intersects(w2Box))
  982. return false;
  983. }
  984. }
  985. // Accept requested position
  986. for (const auto& pair : mwBoxes) {
  987. pair.first->setPosition(pair.second.pos);
  988. }
  989. updateExpanders();
  990. return true;
  991. }
  992. void RackWidget::setSelectionPosNearest(math::Vec delta) {
  993. eachNearestGridPos(delta, [&](math::Vec delta) -> bool {
  994. return requestSelectionPos(delta);
  995. });
  996. }
  997. void RackWidget::appendSelectionContextMenu(ui::Menu* menu) {
  998. int n = getSelected().size();
  999. menu->addChild(createMenuLabel(string::f("%d selected %s", n, n == 1 ? "module" : "modules")));
  1000. // Enable alwaysConsume of menu items if the number of selected modules changes
  1001. // Select all
  1002. menu->addChild(createMenuItem("Select all", RACK_MOD_CTRL_NAME "+A", [=]() {
  1003. selectAll();
  1004. }, false, true));
  1005. // Deselect
  1006. menu->addChild(createMenuItem("Deselect", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+A", [=]() {
  1007. deselectAll();
  1008. }, n == 0, true));
  1009. // Copy
  1010. menu->addChild(createMenuItem("Copy", RACK_MOD_CTRL_NAME "+C", [=]() {
  1011. copyClipboardSelection();
  1012. }, n == 0));
  1013. // Paste
  1014. menu->addChild(createMenuItem("Paste", RACK_MOD_CTRL_NAME "+V", [=]() {
  1015. pasteClipboardAction();
  1016. }, false, true));
  1017. // Save
  1018. menu->addChild(createMenuItem("Save selection as", "", [=]() {
  1019. saveSelectionDialog();
  1020. }, n == 0));
  1021. // Initialize
  1022. menu->addChild(createMenuItem("Initialize", RACK_MOD_CTRL_NAME "+I", [=]() {
  1023. resetSelectionAction();
  1024. }, n == 0));
  1025. // Randomize
  1026. menu->addChild(createMenuItem("Randomize", RACK_MOD_CTRL_NAME "+R", [=]() {
  1027. randomizeSelectionAction();
  1028. }, n == 0));
  1029. // Disconnect cables
  1030. menu->addChild(createMenuItem("Disconnect cables", RACK_MOD_CTRL_NAME "+U", [=]() {
  1031. disconnectSelectionAction();
  1032. }, n == 0));
  1033. // Bypass
  1034. std::string bypassText = RACK_MOD_CTRL_NAME "+E";
  1035. bool bypassed = (n > 0) && isSelectionBypassed();
  1036. if (bypassed)
  1037. bypassText += " " CHECKMARK_STRING;
  1038. menu->addChild(createMenuItem("Bypass", bypassText, [=]() {
  1039. bypassSelectionAction(!bypassed);
  1040. }, n == 0, true));
  1041. // Duplicate
  1042. menu->addChild(createMenuItem("Duplicate", RACK_MOD_CTRL_NAME "+D", [=]() {
  1043. cloneSelectionAction(false);
  1044. }, n == 0));
  1045. // Duplicate with cables
  1046. menu->addChild(createMenuItem("└ with cables", RACK_MOD_SHIFT_NAME "+" RACK_MOD_CTRL_NAME "+D", [=]() {
  1047. cloneSelectionAction(true);
  1048. }, n == 0));
  1049. // Delete
  1050. menu->addChild(createMenuItem("Delete", "Backspace/Delete", [=]() {
  1051. deleteSelectionAction();
  1052. }, n == 0, true));
  1053. }
  1054. void RackWidget::clearCables() {
  1055. internal->incompleteCable = NULL;
  1056. internal->cableContainer->clearChildren();
  1057. }
  1058. void RackWidget::clearCablesAction() {
  1059. // Add CableRemove for every cable to a ComplexAction
  1060. history::ComplexAction* complexAction = new history::ComplexAction;
  1061. complexAction->name = "clear cables";
  1062. for (CableWidget* cw : getCompleteCables()) {
  1063. // history::CableRemove
  1064. history::CableRemove* h = new history::CableRemove;
  1065. h->setCable(cw);
  1066. complexAction->push(h);
  1067. }
  1068. if (!complexAction->isEmpty())
  1069. APP->history->push(complexAction);
  1070. else
  1071. delete complexAction;
  1072. clearCables();
  1073. }
  1074. void RackWidget::clearCablesOnPort(PortWidget* port) {
  1075. for (CableWidget* cw : getCablesOnPort(port)) {
  1076. // Check if cable is connected to port
  1077. if (cw == internal->incompleteCable) {
  1078. internal->incompleteCable = NULL;
  1079. internal->cableContainer->removeChild(cw);
  1080. }
  1081. else {
  1082. removeCable(cw);
  1083. }
  1084. delete cw;
  1085. }
  1086. }
  1087. void RackWidget::addCable(CableWidget* cw) {
  1088. assert(cw->isComplete());
  1089. internal->cableContainer->addChild(cw);
  1090. }
  1091. void RackWidget::removeCable(CableWidget* cw) {
  1092. assert(cw->isComplete());
  1093. internal->cableContainer->removeChild(cw);
  1094. }
  1095. CableWidget* RackWidget::getIncompleteCable() {
  1096. return internal->incompleteCable;
  1097. }
  1098. void RackWidget::setIncompleteCable(CableWidget* cw) {
  1099. if (internal->incompleteCable) {
  1100. internal->cableContainer->removeChild(internal->incompleteCable);
  1101. delete internal->incompleteCable;
  1102. internal->incompleteCable = NULL;
  1103. }
  1104. if (cw) {
  1105. internal->cableContainer->addChild(cw);
  1106. internal->incompleteCable = cw;
  1107. }
  1108. }
  1109. CableWidget* RackWidget::releaseIncompleteCable() {
  1110. if (!internal->incompleteCable)
  1111. return NULL;
  1112. CableWidget* cw = internal->incompleteCable;
  1113. internal->cableContainer->removeChild(internal->incompleteCable);
  1114. internal->incompleteCable = NULL;
  1115. return cw;
  1116. }
  1117. CableWidget* RackWidget::getTopCable(PortWidget* port) {
  1118. for (auto it = internal->cableContainer->children.rbegin(); it != internal->cableContainer->children.rend(); it++) {
  1119. CableWidget* cw = dynamic_cast<CableWidget*>(*it);
  1120. assert(cw);
  1121. if (cw->inputPort == port || cw->outputPort == port)
  1122. return cw;
  1123. }
  1124. return NULL;
  1125. }
  1126. CableWidget* RackWidget::getCable(int64_t cableId) {
  1127. for (widget::Widget* w : internal->cableContainer->children) {
  1128. CableWidget* cw = dynamic_cast<CableWidget*>(w);
  1129. assert(cw);
  1130. if (!cw->cable)
  1131. continue;
  1132. if (cw->cable->id == cableId)
  1133. return cw;
  1134. }
  1135. return NULL;
  1136. }
  1137. std::vector<CableWidget*> RackWidget::getCompleteCables() {
  1138. std::vector<CableWidget*> cws;
  1139. cws.reserve(internal->cableContainer->children.size());
  1140. for (widget::Widget* w : internal->cableContainer->children) {
  1141. CableWidget* cw = dynamic_cast<CableWidget*>(w);
  1142. assert(cw);
  1143. if (cw->isComplete())
  1144. cws.push_back(cw);
  1145. }
  1146. cws.shrink_to_fit();
  1147. return cws;
  1148. }
  1149. std::vector<CableWidget*> RackWidget::getCablesOnPort(PortWidget* port) {
  1150. assert(port);
  1151. std::vector<CableWidget*> cws;
  1152. for (widget::Widget* w : internal->cableContainer->children) {
  1153. CableWidget* cw = dynamic_cast<CableWidget*>(w);
  1154. assert(cw);
  1155. if (cw->inputPort == port || cw->outputPort == port) {
  1156. cws.push_back(cw);
  1157. }
  1158. }
  1159. return cws;
  1160. }
  1161. std::vector<CableWidget*> RackWidget::getCompleteCablesOnPort(PortWidget* port) {
  1162. assert(port);
  1163. std::vector<CableWidget*> cws;
  1164. for (widget::Widget* w : internal->cableContainer->children) {
  1165. CableWidget* cw = dynamic_cast<CableWidget*>(w);
  1166. assert(cw);
  1167. if (!cw->isComplete())
  1168. continue;
  1169. if (cw->inputPort == port || cw->outputPort == port) {
  1170. cws.push_back(cw);
  1171. }
  1172. }
  1173. return cws;
  1174. }
  1175. int RackWidget::getNextCableColorId() {
  1176. return internal->nextCableColorId;
  1177. }
  1178. void RackWidget::setNextCableColorId(int id) {
  1179. internal->nextCableColorId = id;
  1180. }
  1181. NVGcolor RackWidget::getNextCableColor() {
  1182. if (settings::cableColors.empty())
  1183. return color::WHITE;
  1184. int id = internal->nextCableColorId++;
  1185. if (id >= (int) settings::cableColors.size())
  1186. id = 0;
  1187. if (internal->nextCableColorId >= (int) settings::cableColors.size())
  1188. internal->nextCableColorId = 0;
  1189. return settings::cableColors[id];
  1190. }
  1191. ParamWidget* RackWidget::getTouchedParam() {
  1192. return touchedParam;
  1193. }
  1194. void RackWidget::setTouchedParam(ParamWidget* pw) {
  1195. touchedParam = pw;
  1196. }
  1197. void RackWidget::updateExpanders() {
  1198. for (widget::Widget* w : internal->moduleContainer->children) {
  1199. math::Vec pLeft = w->box.pos.div(RACK_GRID_SIZE).round();
  1200. math::Vec pRight = w->box.getTopRight().div(RACK_GRID_SIZE).round();
  1201. ModuleWidget* mwLeft = NULL;
  1202. ModuleWidget* mwRight = NULL;
  1203. // Find adjacent modules
  1204. for (widget::Widget* w2 : internal->moduleContainer->children) {
  1205. if (w2 == w)
  1206. continue;
  1207. math::Vec p2Left = w2->box.pos.div(RACK_GRID_SIZE).round();
  1208. math::Vec p2Right = w2->box.getTopRight().div(RACK_GRID_SIZE).round();
  1209. // Check if this is a left module
  1210. if (p2Right.equals(pLeft)) {
  1211. mwLeft = dynamic_cast<ModuleWidget*>(w2);
  1212. }
  1213. // Check if this is a right module
  1214. if (p2Left.equals(pRight)) {
  1215. mwRight = dynamic_cast<ModuleWidget*>(w2);
  1216. }
  1217. }
  1218. ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
  1219. mw->module->leftExpander.moduleId = mwLeft ? mwLeft->module->id : -1;
  1220. mw->module->rightExpander.moduleId = mwRight ? mwRight->module->id : -1;
  1221. }
  1222. }
  1223. } // namespace app
  1224. } // namespace rack