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.

1024 lines
26KB

  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 <app/ModuleBrowser.hpp>
  11. #include <settings.hpp>
  12. #include <plugin.hpp>
  13. #include <engine/Engine.hpp>
  14. #include <context.hpp>
  15. #include <asset.hpp>
  16. #include <patch.hpp>
  17. #include <helpers.hpp>
  18. namespace rack {
  19. namespace app {
  20. /** Creates a new Module and ModuleWidget */
  21. static ModuleWidget* moduleWidgetFromJson(json_t* moduleJ) {
  22. plugin::Model* model = plugin::modelFromJson(moduleJ);
  23. assert(model);
  24. engine::Module* module = model->createModule();
  25. assert(module);
  26. module->fromJson(moduleJ);
  27. // Create ModuleWidget
  28. ModuleWidget* moduleWidget = module->model->createModuleWidget(module);
  29. assert(moduleWidget);
  30. return moduleWidget;
  31. }
  32. struct ModuleContainer : widget::Widget {
  33. void draw(const DrawArgs& args) override {
  34. // Draw shadows behind each ModuleWidget first, so the shadow doesn't overlap the front of other ModuleWidgets.
  35. for (widget::Widget* child : children) {
  36. ModuleWidget* w = dynamic_cast<ModuleWidget*>(child);
  37. assert(w);
  38. nvgSave(args.vg);
  39. nvgTranslate(args.vg, child->box.pos.x, child->box.pos.y);
  40. w->drawShadow(args);
  41. nvgRestore(args.vg);
  42. }
  43. Widget::draw(args);
  44. }
  45. };
  46. struct CableContainer : widget::TransparentWidget {
  47. void draw(const DrawArgs& args) override {
  48. // Draw Plugs
  49. Widget::draw(args);
  50. // Draw cable shadows
  51. DrawArgs args1 = args;
  52. args1.layer = 1;
  53. Widget::draw(args1);
  54. // Draw cables
  55. DrawArgs args2 = args;
  56. args2.layer = 2;
  57. Widget::draw(args2);
  58. }
  59. };
  60. struct RackWidget::Internal {
  61. RailWidget* rail = NULL;
  62. widget::Widget* moduleContainer = NULL;
  63. widget::Widget* cableContainer = NULL;
  64. /** The last mouse position in the RackWidget */
  65. math::Vec mousePos;
  66. bool selecting = false;
  67. math::Vec selectionStart;
  68. math::Vec selectionEnd;
  69. };
  70. RackWidget::RackWidget() {
  71. internal = new Internal;
  72. internal->rail = new RailWidget;
  73. addChild(internal->rail);
  74. internal->moduleContainer = new ModuleContainer;
  75. addChild(internal->moduleContainer);
  76. internal->cableContainer = new CableContainer;
  77. addChild(internal->cableContainer);
  78. }
  79. RackWidget::~RackWidget() {
  80. clear();
  81. delete internal;
  82. }
  83. void RackWidget::step() {
  84. Widget::step();
  85. }
  86. void RackWidget::draw(const DrawArgs& args) {
  87. // Darken all children by user setting
  88. float b = settings::rackBrightness;
  89. nvgGlobalTint(args.vg, nvgRGBAf(b, b, b, 1));
  90. Widget::draw(args);
  91. // Draw selection rectangle
  92. if (internal->selecting) {
  93. nvgBeginPath(args.vg);
  94. math::Rect selectionBox = math::Rect::fromCorners(internal->selectionStart, internal->selectionEnd);
  95. nvgRect(args.vg, RECT_ARGS(selectionBox));
  96. nvgFillColor(args.vg, nvgRGBAf(1, 0, 0, 0.25));
  97. nvgFill(args.vg);
  98. nvgStrokeWidth(args.vg, 2.0);
  99. nvgStrokeColor(args.vg, nvgRGBAf(1, 0, 0, 0.5));
  100. nvgStroke(args.vg);
  101. }
  102. }
  103. void RackWidget::onHover(const HoverEvent& e) {
  104. // Set before calling children's onHover()
  105. internal->mousePos = e.pos;
  106. OpaqueWidget::onHover(e);
  107. }
  108. void RackWidget::onHoverKey(const HoverKeyEvent& e) {
  109. OpaqueWidget::onHoverKey(e);
  110. if (e.isConsumed())
  111. return;
  112. if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
  113. if (e.keyName == "v" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  114. pastePresetClipboardAction();
  115. e.consume(this);
  116. }
  117. }
  118. }
  119. void RackWidget::onButton(const ButtonEvent& e) {
  120. Widget::onButton(e);
  121. e.stopPropagating();
  122. if (e.isConsumed())
  123. return;
  124. if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) {
  125. APP->scene->moduleBrowser->show();
  126. e.consume(this);
  127. }
  128. if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT) {
  129. e.consume(this);
  130. }
  131. }
  132. void RackWidget::onDragStart(const DragStartEvent& e) {
  133. if (e.button == GLFW_MOUSE_BUTTON_LEFT) {
  134. // Deselect all modules
  135. updateModuleSelections();
  136. internal->selecting = true;
  137. internal->selectionStart = internal->mousePos;
  138. internal->selectionEnd = internal->mousePos;
  139. }
  140. }
  141. void RackWidget::onDragEnd(const DragEndEvent& e) {
  142. if (e.button == GLFW_MOUSE_BUTTON_LEFT) {
  143. internal->selecting = false;
  144. }
  145. }
  146. void RackWidget::onDragHover(const DragHoverEvent& e) {
  147. // Set before calling children's onDragHover()
  148. internal->mousePos = e.pos;
  149. if (internal->selecting) {
  150. internal->selectionEnd = internal->mousePos;
  151. updateModuleSelections();
  152. }
  153. OpaqueWidget::onDragHover(e);
  154. }
  155. widget::Widget* RackWidget::getModuleContainer() {
  156. return internal->moduleContainer;
  157. }
  158. widget::Widget* RackWidget::getCableContainer() {
  159. return internal->cableContainer;
  160. }
  161. math::Vec RackWidget::getMousePos() {
  162. return internal->mousePos;
  163. }
  164. void RackWidget::clear() {
  165. // This isn't required because removing all ModuleWidgets should remove all cables, but do it just in case.
  166. clearCables();
  167. // Remove ModuleWidgets
  168. for (ModuleWidget* mw : getModules()) {
  169. removeModule(mw);
  170. delete mw;
  171. }
  172. }
  173. void RackWidget::mergeJson(json_t* rootJ) {
  174. // Get module offset so modules are aligned to (0, 0) when the patch is loaded.
  175. math::Vec moduleOffset = math::Vec(INFINITY, INFINITY);
  176. for (widget::Widget* w : internal->moduleContainer->children) {
  177. moduleOffset = moduleOffset.min(w->box.pos);
  178. }
  179. if (internal->moduleContainer->children.empty()) {
  180. moduleOffset = RACK_OFFSET;
  181. }
  182. // modules
  183. json_t* modulesJ = json_object_get(rootJ, "modules");
  184. if (!modulesJ)
  185. return;
  186. size_t moduleIndex;
  187. json_t* moduleJ;
  188. json_array_foreach(modulesJ, moduleIndex, moduleJ) {
  189. // module
  190. json_t* idJ = json_object_get(moduleJ, "id");
  191. if (!idJ)
  192. continue;
  193. int64_t id = json_integer_value(idJ);
  194. // TODO Legacy v0.6?
  195. ModuleWidget* moduleWidget = getModule(id);
  196. if (!moduleWidget) {
  197. WARN("Cannot find ModuleWidget %" PRId64, id);
  198. continue;
  199. }
  200. // pos
  201. math::Vec pos = moduleWidget->box.pos.minus(moduleOffset);
  202. pos = pos.div(RACK_GRID_SIZE).round();
  203. json_t* posJ = json_pack("[i, i]", (int) pos.x, (int) pos.y);
  204. json_object_set_new(moduleJ, "pos", posJ);
  205. }
  206. // cables
  207. json_t* cablesJ = json_object_get(rootJ, "cables");
  208. if (!cablesJ)
  209. return;
  210. size_t cableIndex;
  211. json_t* cableJ;
  212. json_array_foreach(cablesJ, cableIndex, cableJ) {
  213. // cable
  214. json_t* idJ = json_object_get(cableJ, "id");
  215. if (!idJ)
  216. continue;
  217. int64_t id = json_integer_value(idJ);
  218. CableWidget* cw = getCable(id);
  219. if (!cw) {
  220. WARN("Cannot find CableWidget %" PRId64, id);
  221. continue;
  222. }
  223. json_t* cwJ = cw->toJson();
  224. // Merge cable JSON object
  225. json_object_update(cableJ, cwJ);
  226. json_decref(cwJ);
  227. }
  228. }
  229. void RackWidget::fromJson(json_t* rootJ) {
  230. // version
  231. std::string version;
  232. json_t* versionJ = json_object_get(rootJ, "version");
  233. if (versionJ)
  234. version = json_string_value(versionJ);
  235. bool legacyV05 = false;
  236. if (string::startsWith(version, "0.3.") || string::startsWith(version, "0.4.") || string::startsWith(version, "0.5.") || version == "dev") {
  237. legacyV05 = true;
  238. }
  239. // modules
  240. json_t* modulesJ = json_object_get(rootJ, "modules");
  241. if (!modulesJ)
  242. return;
  243. size_t moduleIndex;
  244. json_t* moduleJ;
  245. json_array_foreach(modulesJ, moduleIndex, moduleJ) {
  246. // Get module ID
  247. json_t* idJ = json_object_get(moduleJ, "id");
  248. int64_t id;
  249. if (idJ)
  250. id = json_integer_value(idJ);
  251. else
  252. id = moduleIndex;
  253. // Get Module
  254. engine::Module* module = APP->engine->getModule(id);
  255. if (!module) {
  256. WARN("Cannot find Module %" PRId64, id);
  257. continue;
  258. }
  259. // Create ModuleWidget
  260. ModuleWidget* moduleWidget = module->model->createModuleWidget(module);
  261. // pos
  262. json_t* posJ = json_object_get(moduleJ, "pos");
  263. double x = 0.0, y = 0.0;
  264. json_unpack(posJ, "[F, F]", &x, &y);
  265. math::Vec pos = math::Vec(x, y);
  266. if (legacyV05) {
  267. // In <=v0.5, positions were in pixel units
  268. moduleWidget->box.pos = pos;
  269. }
  270. else {
  271. moduleWidget->box.pos = pos.mult(RACK_GRID_SIZE);
  272. }
  273. moduleWidget->box.pos = moduleWidget->box.pos.plus(RACK_OFFSET);
  274. addModule(moduleWidget);
  275. }
  276. // cables
  277. json_t* cablesJ = json_object_get(rootJ, "cables");
  278. // In <=v0.6, cables were called wires
  279. if (!cablesJ)
  280. cablesJ = json_object_get(rootJ, "wires");
  281. if (!cablesJ)
  282. return;
  283. size_t cableIndex;
  284. json_t* cableJ;
  285. json_array_foreach(cablesJ, cableIndex, cableJ) {
  286. // Get cable ID
  287. json_t* idJ = json_object_get(cableJ, "id");
  288. int64_t id;
  289. if (idJ)
  290. id = json_integer_value(idJ);
  291. else
  292. id = cableIndex;
  293. // Get Cable
  294. engine::Cable* cable = APP->engine->getCable(id);
  295. if (!cable) {
  296. WARN("Cannot find Cable %" PRId64, id);
  297. continue;
  298. }
  299. // Create CableWidget
  300. CableWidget* cw = new CableWidget;
  301. cw->setCable(cable);
  302. cw->fromJson(cableJ);
  303. // In <=v1, cable colors were not serialized, so choose one from the available colors.
  304. if (cw->color.a == 0.f) {
  305. cw->setNextCableColor();
  306. }
  307. addCable(cw);
  308. }
  309. }
  310. void RackWidget::pastePresetClipboardAction() {
  311. const char* moduleJson = glfwGetClipboardString(APP->window->win);
  312. if (!moduleJson) {
  313. WARN("Could not get text from clipboard.");
  314. return;
  315. }
  316. json_error_t error;
  317. json_t* moduleJ = json_loads(moduleJson, 0, &error);
  318. if (!moduleJ) {
  319. WARN("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
  320. return;
  321. }
  322. DEFER({json_decref(moduleJ);});
  323. // Because we are creating a new module, we don't want to use the IDs from the JSON.
  324. json_object_del(moduleJ, "id");
  325. json_object_del(moduleJ, "leftModuleId");
  326. json_object_del(moduleJ, "rightModuleId");
  327. ModuleWidget* mw;
  328. try {
  329. mw = moduleWidgetFromJson(moduleJ);
  330. }
  331. catch (Exception& e) {
  332. WARN("%s", e.what());
  333. return;
  334. }
  335. assert(mw);
  336. assert(mw->module);
  337. APP->engine->addModule(mw->module);
  338. addModuleAtMouse(mw);
  339. // history::ModuleAdd
  340. history::ModuleAdd* h = new history::ModuleAdd;
  341. h->setModule(mw);
  342. APP->history->push(h);
  343. }
  344. static void RackWidget_updateExpanders(RackWidget* that) {
  345. for (widget::Widget* w : that->internal->moduleContainer->children) {
  346. math::Vec pLeft = w->box.pos.div(RACK_GRID_SIZE).round();
  347. math::Vec pRight = w->box.getTopRight().div(RACK_GRID_SIZE).round();
  348. ModuleWidget* mwLeft = NULL;
  349. ModuleWidget* mwRight = NULL;
  350. // Find adjacent modules
  351. for (widget::Widget* w2 : that->internal->moduleContainer->children) {
  352. if (w2 == w)
  353. continue;
  354. math::Vec p2Left = w2->box.pos.div(RACK_GRID_SIZE).round();
  355. math::Vec p2Right = w2->box.getTopRight().div(RACK_GRID_SIZE).round();
  356. // Check if this is a left module
  357. if (p2Right.equals(pLeft)) {
  358. mwLeft = dynamic_cast<ModuleWidget*>(w2);
  359. }
  360. // Check if this is a right module
  361. if (p2Left.equals(pRight)) {
  362. mwRight = dynamic_cast<ModuleWidget*>(w2);
  363. }
  364. }
  365. ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
  366. mw->module->leftExpander.moduleId = mwLeft ? mwLeft->module->id : -1;
  367. mw->module->rightExpander.moduleId = mwRight ? mwRight->module->id : -1;
  368. }
  369. }
  370. void RackWidget::addModule(ModuleWidget* m) {
  371. assert(m);
  372. // Module must be 3U high and at least 1HP wide
  373. if (m->box.size.x < RACK_GRID_WIDTH / 2)
  374. 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);
  375. if (m->box.size.y != RACK_GRID_HEIGHT)
  376. throw Exception("Module %s height is %g px, must be %g px", m->model->getFullName().c_str(), m->box.size.y, RACK_GRID_HEIGHT);
  377. internal->moduleContainer->addChild(m);
  378. RackWidget_updateExpanders(this);
  379. }
  380. void RackWidget::addModuleAtMouse(ModuleWidget* mw) {
  381. assert(mw);
  382. // Move module nearest to the mouse position
  383. math::Vec pos = internal->mousePos.minus(mw->box.size.div(2));
  384. setModulePosNearest(mw, pos);
  385. addModule(mw);
  386. }
  387. void RackWidget::removeModule(ModuleWidget* m) {
  388. // Unset touchedParamWidget
  389. if (touchedParam) {
  390. ModuleWidget* touchedModule = touchedParam->getAncestorOfType<ModuleWidget>();
  391. if (touchedModule == m)
  392. touchedParam = NULL;
  393. }
  394. // Disconnect cables
  395. m->disconnect();
  396. // Remove module from ModuleContainer
  397. internal->moduleContainer->removeChild(m);
  398. }
  399. bool RackWidget::requestModulePos(ModuleWidget* mw, math::Vec pos) {
  400. // Check intersection with other modules
  401. math::Rect mwBox = math::Rect(pos, mw->box.size);
  402. for (widget::Widget* w2 : internal->moduleContainer->children) {
  403. // Don't intersect with self
  404. if (mw == w2)
  405. continue;
  406. // Check intersection
  407. math::Rect w2Box = w2->box;
  408. if (mwBox.intersects(w2Box))
  409. return false;
  410. }
  411. // Accept requested position
  412. mw->setPosition(mwBox.pos);
  413. RackWidget_updateExpanders(this);
  414. return true;
  415. }
  416. static void eachNearestGridPos(math::Vec pos, std::function<bool(math::Vec pos)> f) {
  417. // Dijkstra's algorithm to generate a sorted list of Vecs closest to `pos`.
  418. // Comparison of distance of Vecs to `pos`
  419. auto cmpNearest = [&](const math::Vec & a, const math::Vec & b) {
  420. return a.minus(pos).square() > b.minus(pos).square();
  421. };
  422. // Comparison of dictionary order of Vecs
  423. auto cmp = [&](const math::Vec & a, const math::Vec & b) {
  424. if (a.x != b.x)
  425. return a.x < b.x;
  426. return a.y < b.y;
  427. };
  428. // Priority queue sorted by distance from `pos`
  429. std::priority_queue<math::Vec, std::vector<math::Vec>, decltype(cmpNearest)> queue(cmpNearest);
  430. // Set of already-tested Vecs
  431. std::set<math::Vec, decltype(cmp)> visited(cmp);
  432. // Seed priority queue with closest Vec
  433. math::Vec closestPos = pos.div(RACK_GRID_SIZE).round().mult(RACK_GRID_SIZE);
  434. queue.push(closestPos);
  435. while (!queue.empty()) {
  436. math::Vec testPos = queue.top();
  437. // Check testPos
  438. if (f(testPos))
  439. return;
  440. // Move testPos to visited set
  441. queue.pop();
  442. visited.insert(testPos);
  443. // Add adjacent Vecs
  444. static const std::vector<math::Vec> deltas = {
  445. math::Vec(-1, 0).mult(RACK_GRID_SIZE),
  446. math::Vec(1, 0).mult(RACK_GRID_SIZE),
  447. math::Vec(0, -1).mult(RACK_GRID_SIZE),
  448. math::Vec(0, 1).mult(RACK_GRID_SIZE),
  449. };
  450. for (math::Vec delta : deltas) {
  451. math::Vec newPos = testPos.plus(delta);
  452. if (visited.find(newPos) == visited.end()) {
  453. queue.push(newPos);
  454. }
  455. }
  456. }
  457. // We failed to find a box. This shouldn't happen on an infinite rack.
  458. assert(false);
  459. }
  460. void RackWidget::setModulePosNearest(ModuleWidget* mw, math::Vec pos) {
  461. eachNearestGridPos(pos, [&](math::Vec pos) -> bool {
  462. return requestModulePos(mw, pos);
  463. });
  464. }
  465. void RackWidget::setModulePosForce(ModuleWidget* mw, math::Vec pos) {
  466. mw->setPosition(pos.div(RACK_GRID_SIZE).round().mult(RACK_GRID_SIZE));
  467. // Comparison of center X coordinates
  468. auto cmp = [&](const widget::Widget * a, const widget::Widget * b) {
  469. return a->box.pos.x + a->box.size.x / 2 < b->box.pos.x + b->box.size.x / 2;
  470. };
  471. // Collect modules to the left and right of `mw`
  472. std::set<widget::Widget*, decltype(cmp)> leftModules(cmp);
  473. std::set<widget::Widget*, decltype(cmp)> rightModules(cmp);
  474. for (widget::Widget* w2 : internal->moduleContainer->children) {
  475. if (w2 == mw)
  476. continue;
  477. // Modules must be on the same row as `mw`
  478. if (w2->box.pos.y != mw->box.pos.y)
  479. continue;
  480. if (cmp(w2, mw))
  481. leftModules.insert(w2);
  482. else
  483. rightModules.insert(w2);
  484. }
  485. // Shove left modules
  486. float xLimit = mw->box.pos.x;
  487. for (auto it = leftModules.rbegin(); it != leftModules.rend(); it++) {
  488. widget::Widget* w = *it;
  489. math::Vec newPos = w->box.pos;
  490. newPos.x = xLimit - w->box.size.x;
  491. newPos.x = std::round(newPos.x / RACK_GRID_WIDTH) * RACK_GRID_WIDTH;
  492. if (w->box.pos.x < newPos.x)
  493. break;
  494. w->setPosition(newPos);
  495. xLimit = newPos.x;
  496. }
  497. // Shove right modules
  498. xLimit = mw->box.pos.x + mw->box.size.x;
  499. for (auto it = rightModules.begin(); it != rightModules.end(); it++) {
  500. widget::Widget* w = *it;
  501. math::Vec newPos = w->box.pos;
  502. newPos.x = xLimit;
  503. newPos.x = std::round(newPos.x / RACK_GRID_WIDTH) * RACK_GRID_WIDTH;
  504. if (w->box.pos.x > newPos.x)
  505. break;
  506. w->setPosition(newPos);
  507. xLimit = newPos.x + w->box.size.x;
  508. }
  509. RackWidget_updateExpanders(this);
  510. }
  511. ModuleWidget* RackWidget::getModule(int64_t moduleId) {
  512. for (widget::Widget* w : internal->moduleContainer->children) {
  513. ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
  514. assert(mw);
  515. if (mw->module->id == moduleId)
  516. return mw;
  517. }
  518. return NULL;
  519. }
  520. std::list<ModuleWidget*> RackWidget::getModules() {
  521. std::list<ModuleWidget*> mws;
  522. for (widget::Widget* w : internal->moduleContainer->children) {
  523. ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
  524. assert(mw);
  525. mws.push_back(mw);
  526. }
  527. return mws;
  528. }
  529. bool RackWidget::hasModules() {
  530. return internal->moduleContainer->children.empty();
  531. }
  532. void RackWidget::updateModuleOldPositions() {
  533. // Set all modules' oldPos field from their current position.
  534. for (ModuleWidget* mw : getModules()) {
  535. mw->oldPos() = mw->box.pos;
  536. }
  537. }
  538. history::ComplexAction* RackWidget::getModuleDragAction() {
  539. history::ComplexAction* h = new history::ComplexAction;
  540. for (ModuleWidget* mw : getModules()) {
  541. // Create ModuleMove action if the module was moved.
  542. math::Vec oldPos = mw->oldPos();
  543. if (!oldPos.equals(mw->box.pos)) {
  544. history::ModuleMove* mmh = new history::ModuleMove;
  545. mmh->moduleId = mw->module->id;
  546. mmh->oldPos = oldPos;
  547. mmh->newPos = mw->box.pos;
  548. h->push(mmh);
  549. }
  550. }
  551. return h;
  552. }
  553. void RackWidget::updateModuleSelections() {
  554. math::Rect selectionBox = math::Rect::fromCorners(internal->selectionStart, internal->selectionEnd);
  555. for (ModuleWidget* mw : getModules()) {
  556. bool selected = internal->selecting && selectionBox.intersects(mw->box);
  557. mw->selected() = selected;
  558. }
  559. }
  560. void RackWidget::deselectModules() {
  561. for (ModuleWidget* mw : getModules()) {
  562. mw->selected() = false;
  563. }
  564. }
  565. void RackWidget::selectAllModules() {
  566. for (ModuleWidget* mw : getModules()) {
  567. mw->selected() = true;
  568. }
  569. }
  570. bool RackWidget::hasSelectedModules() {
  571. for (widget::Widget* w : internal->moduleContainer->children) {
  572. ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
  573. assert(mw);
  574. if (mw->selected())
  575. return true;
  576. }
  577. return false;
  578. }
  579. int RackWidget::getNumSelectedModules() {
  580. int count = 0;
  581. for (widget::Widget* w : internal->moduleContainer->children) {
  582. ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
  583. assert(mw);
  584. if (mw->selected())
  585. count++;
  586. }
  587. return count;
  588. }
  589. std::list<ModuleWidget*> RackWidget::getSelectedModules() {
  590. std::list<ModuleWidget*> mws;
  591. for (widget::Widget* w : internal->moduleContainer->children) {
  592. ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
  593. assert(mw);
  594. if (mw->selected())
  595. mws.push_back(mw);
  596. }
  597. return mws;
  598. }
  599. void RackWidget::resetSelectedModulesAction() {
  600. history::ComplexAction* complexAction = new history::ComplexAction;
  601. complexAction->name = "reset modules";
  602. for (ModuleWidget* mw : getSelectedModules()) {
  603. assert(mw->module);
  604. // history::ModuleChange
  605. history::ModuleChange* h = new history::ModuleChange;
  606. h->moduleId = mw->module->id;
  607. h->oldModuleJ = mw->toJson();
  608. APP->engine->resetModule(mw->module);
  609. h->newModuleJ = mw->toJson();
  610. complexAction->push(h);
  611. }
  612. APP->history->push(complexAction);
  613. }
  614. void RackWidget::randomizeSelectedModulesAction() {
  615. history::ComplexAction* complexAction = new history::ComplexAction;
  616. complexAction->name = "randomize modules";
  617. for (ModuleWidget* mw : getSelectedModules()) {
  618. assert(mw->module);
  619. // history::ModuleChange
  620. history::ModuleChange* h = new history::ModuleChange;
  621. h->moduleId = mw->module->id;
  622. h->oldModuleJ = mw->toJson();
  623. APP->engine->randomizeModule(mw->module);
  624. h->newModuleJ = mw->toJson();
  625. complexAction->push(h);
  626. }
  627. APP->history->push(complexAction);
  628. }
  629. void RackWidget::disconnectSelectedModulesAction() {
  630. history::ComplexAction* complexAction = new history::ComplexAction;
  631. complexAction->name = "disconnect cables";
  632. for (ModuleWidget* mw : getSelectedModules()) {
  633. mw->appendDisconnectActions(complexAction);
  634. }
  635. if (!complexAction->isEmpty())
  636. APP->history->push(complexAction);
  637. else
  638. delete complexAction;
  639. }
  640. void RackWidget::cloneSelectedModulesAction() {
  641. // TODO
  642. }
  643. void RackWidget::bypassSelectedModulesAction(bool bypassed) {
  644. history::ComplexAction* complexAction = new history::ComplexAction;
  645. complexAction->name = bypassed ? "bypass modules" : "un-bypass modules";
  646. for (ModuleWidget* mw : getSelectedModules()) {
  647. assert(mw->module);
  648. if (mw->module->isBypassed() == bypassed)
  649. continue;
  650. // history::ModuleBypass
  651. history::ModuleBypass* h = new history::ModuleBypass;
  652. h->moduleId = mw->module->id;
  653. h->bypassed = bypassed;
  654. complexAction->push(h);
  655. APP->engine->bypassModule(mw->module, bypassed);
  656. }
  657. if (!complexAction->isEmpty())
  658. APP->history->push(complexAction);
  659. else
  660. delete complexAction;
  661. }
  662. bool RackWidget::areSelectedModulesBypassed() {
  663. for (ModuleWidget* mw : getSelectedModules()) {
  664. if (!mw->getModule()->isBypassed())
  665. return false;
  666. }
  667. return true;
  668. }
  669. void RackWidget::deleteSelectedModulesAction() {
  670. history::ComplexAction* complexAction = new history::ComplexAction;
  671. complexAction->name = "remove modules";
  672. for (ModuleWidget* mw : getSelectedModules()) {
  673. mw->appendDisconnectActions(complexAction);
  674. // history::ModuleRemove
  675. history::ModuleRemove* moduleRemove = new history::ModuleRemove;
  676. moduleRemove->setModule(mw);
  677. complexAction->push(moduleRemove);
  678. removeModule(mw);
  679. delete mw;
  680. }
  681. APP->history->push(complexAction);
  682. }
  683. bool RackWidget::requestSelectedModulePos(math::Vec delta) {
  684. // Check intersection with other modules
  685. std::map<widget::Widget*, math::Rect> mwBoxes;
  686. for (ModuleWidget* mw : getSelectedModules()) {
  687. math::Rect mwBox = mw->box;
  688. mwBox.pos += delta;
  689. mwBoxes[mw] = mwBox;
  690. }
  691. for (widget::Widget* w2 : internal->moduleContainer->children) {
  692. // Don't intersect with selected modules
  693. auto it = mwBoxes.find(w2);
  694. if (it != mwBoxes.end())
  695. continue;
  696. math::Rect w2Box = w2->box;
  697. // Check intersection with all selected modules
  698. for (const auto& pair : mwBoxes) {
  699. if (pair.second.intersects(w2Box))
  700. return false;
  701. }
  702. }
  703. // Accept requested position
  704. for (const auto& pair : mwBoxes) {
  705. pair.first->setPosition(pair.second.pos);
  706. }
  707. RackWidget_updateExpanders(this);
  708. return true;
  709. }
  710. void RackWidget::setSelectedModulesPosNearest(math::Vec delta) {
  711. eachNearestGridPos(delta, [&](math::Vec delta) -> bool {
  712. return requestSelectedModulePos(delta);
  713. });
  714. }
  715. void RackWidget::appendSelectionContextMenu(ui::Menu* menu) {
  716. int n = getNumSelectedModules();
  717. menu->addChild(createMenuLabel(string::f("%d selected %s", n, n == 1 ? "module" : "modules")));
  718. // Select all
  719. menu->addChild(createMenuItem("Select all", RACK_MOD_CTRL_NAME "+A", [=]() {
  720. selectAllModules();
  721. }));
  722. // Deselect
  723. menu->addChild(createMenuItem("Deselect", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+A", [=]() {
  724. deselectModules();
  725. }, n == 0));
  726. // Initialize
  727. menu->addChild(createMenuItem("Initialize", RACK_MOD_CTRL_NAME "+I", [=]() {
  728. resetSelectedModulesAction();
  729. }, n == 0));
  730. // Randomize
  731. menu->addChild(createMenuItem("Randomize", RACK_MOD_CTRL_NAME "+R", [=]() {
  732. randomizeSelectedModulesAction();
  733. }, n == 0));
  734. // Disconnect cables
  735. menu->addChild(createMenuItem("Disconnect cables", RACK_MOD_CTRL_NAME "+U", [=]() {
  736. disconnectSelectedModulesAction();
  737. }, n == 0));
  738. // Duplicate
  739. menu->addChild(createMenuItem("Duplicate", RACK_MOD_CTRL_NAME "+D", [=]() {
  740. cloneSelectedModulesAction();
  741. }, n == 0));
  742. // Bypass
  743. std::string bypassText = RACK_MOD_CTRL_NAME "+E";
  744. bool bypassed = (n > 0) && areSelectedModulesBypassed();
  745. if (bypassed)
  746. bypassText += " " CHECKMARK_STRING;
  747. menu->addChild(createMenuItem("Bypass", bypassText, [=]() {
  748. bypassSelectedModulesAction(!bypassed);
  749. }, n == 0));
  750. // Delete
  751. menu->addChild(createMenuItem("Delete", "Backspace/Delete", [=]() {
  752. deleteSelectedModulesAction();
  753. }, n == 0));
  754. }
  755. void RackWidget::clearCables() {
  756. incompleteCable = NULL;
  757. internal->cableContainer->clearChildren();
  758. }
  759. void RackWidget::clearCablesAction() {
  760. // Add CableRemove for every cable to a ComplexAction
  761. history::ComplexAction* complexAction = new history::ComplexAction;
  762. complexAction->name = "clear cables";
  763. for (CableWidget* cw : getCompleteCables()) {
  764. // history::CableRemove
  765. history::CableRemove* h = new history::CableRemove;
  766. h->setCable(cw);
  767. complexAction->push(h);
  768. }
  769. if (!complexAction->isEmpty())
  770. APP->history->push(complexAction);
  771. else
  772. delete complexAction;
  773. clearCables();
  774. }
  775. void RackWidget::clearCablesOnPort(PortWidget* port) {
  776. for (CableWidget* cw : getCablesOnPort(port)) {
  777. // Check if cable is connected to port
  778. if (cw == incompleteCable) {
  779. incompleteCable = NULL;
  780. internal->cableContainer->removeChild(cw);
  781. }
  782. else {
  783. removeCable(cw);
  784. }
  785. delete cw;
  786. }
  787. }
  788. void RackWidget::addCable(CableWidget* cw) {
  789. assert(cw->isComplete());
  790. internal->cableContainer->addChild(cw);
  791. }
  792. void RackWidget::removeCable(CableWidget* cw) {
  793. assert(cw->isComplete());
  794. internal->cableContainer->removeChild(cw);
  795. }
  796. void RackWidget::setIncompleteCable(CableWidget* cw) {
  797. if (incompleteCable) {
  798. internal->cableContainer->removeChild(incompleteCable);
  799. delete incompleteCable;
  800. incompleteCable = NULL;
  801. }
  802. if (cw) {
  803. internal->cableContainer->addChild(cw);
  804. incompleteCable = cw;
  805. }
  806. }
  807. CableWidget* RackWidget::releaseIncompleteCable() {
  808. if (!incompleteCable)
  809. return NULL;
  810. CableWidget* cw = incompleteCable;
  811. internal->cableContainer->removeChild(incompleteCable);
  812. incompleteCable = NULL;
  813. return cw;
  814. }
  815. CableWidget* RackWidget::getTopCable(PortWidget* port) {
  816. for (auto it = internal->cableContainer->children.rbegin(); it != internal->cableContainer->children.rend(); it++) {
  817. CableWidget* cw = dynamic_cast<CableWidget*>(*it);
  818. assert(cw);
  819. if (cw->inputPort == port || cw->outputPort == port)
  820. return cw;
  821. }
  822. return NULL;
  823. }
  824. CableWidget* RackWidget::getCable(int64_t cableId) {
  825. for (widget::Widget* w : internal->cableContainer->children) {
  826. CableWidget* cw = dynamic_cast<CableWidget*>(w);
  827. assert(cw);
  828. if (!cw->cable)
  829. continue;
  830. if (cw->cable->id == cableId)
  831. return cw;
  832. }
  833. return NULL;
  834. }
  835. std::list<CableWidget*> RackWidget::getCompleteCables() {
  836. std::list<CableWidget*> cws;
  837. for (widget::Widget* w : internal->cableContainer->children) {
  838. CableWidget* cw = dynamic_cast<CableWidget*>(w);
  839. assert(cw);
  840. if (cw->isComplete())
  841. cws.push_back(cw);
  842. }
  843. return cws;
  844. }
  845. std::list<CableWidget*> RackWidget::getCablesOnPort(PortWidget* port) {
  846. assert(port);
  847. std::list<CableWidget*> cws;
  848. for (widget::Widget* w : internal->cableContainer->children) {
  849. CableWidget* cw = dynamic_cast<CableWidget*>(w);
  850. assert(cw);
  851. if (cw->inputPort == port || cw->outputPort == port) {
  852. cws.push_back(cw);
  853. }
  854. }
  855. return cws;
  856. }
  857. } // namespace app
  858. } // namespace rack