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.

1664 lines
44KB

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