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.

629 lines
16KB

  1. #include <map>
  2. #include <algorithm>
  3. #include "app/RackWidget.hpp"
  4. #include "app/RackRail.hpp"
  5. #include "app/Scene.hpp"
  6. #include "app/ModuleBrowser.hpp"
  7. #include "osdialog.h"
  8. #include "settings.hpp"
  9. #include "asset.hpp"
  10. #include "system.hpp"
  11. #include "plugin.hpp"
  12. #include "engine/Engine.hpp"
  13. #include "app.hpp"
  14. namespace rack {
  15. struct ModuleContainer : Widget {
  16. void draw(NVGcontext *vg) override {
  17. // Draw shadows behind each ModuleWidget first, so the shadow doesn't overlap the front of other ModuleWidgets.
  18. for (Widget *child : children) {
  19. if (!child->visible)
  20. continue;
  21. nvgSave(vg);
  22. nvgTranslate(vg, child->box.pos.x, child->box.pos.y);
  23. ModuleWidget *w = dynamic_cast<ModuleWidget*>(child);
  24. assert(w);
  25. w->drawShadow(vg);
  26. nvgRestore(vg);
  27. }
  28. Widget::draw(vg);
  29. }
  30. };
  31. RackWidget::RackWidget() {
  32. rails = new FramebufferWidget;
  33. rails->box.size = math::Vec();
  34. rails->oversample = 1.0;
  35. {
  36. RackRail *rail = new RackRail;
  37. rail->box.size = math::Vec();
  38. rails->addChild(rail);
  39. }
  40. addChild(rails);
  41. moduleContainer = new ModuleContainer;
  42. addChild(moduleContainer);
  43. cableContainer = new CableContainer;
  44. addChild(cableContainer);
  45. }
  46. RackWidget::~RackWidget() {
  47. clear();
  48. }
  49. void RackWidget::clear() {
  50. cableContainer->activeCable = NULL;
  51. cableContainer->clearChildren();
  52. // Remove ModuleWidgets
  53. std::list<Widget*> widgets = moduleContainer->children;
  54. for (Widget *w : widgets) {
  55. ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
  56. assert(moduleWidget);
  57. removeModule(moduleWidget);
  58. }
  59. app()->scene->scrollWidget->offset = math::Vec(0, 0);
  60. }
  61. void RackWidget::reset() {
  62. if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "Clear patch and start over?")) {
  63. clear();
  64. // Fails silently if file does not exist
  65. load(asset::user("template.vcv"));
  66. lastPath = "";
  67. }
  68. }
  69. void RackWidget::loadDialog() {
  70. std::string dir;
  71. if (lastPath.empty()) {
  72. dir = asset::user("patches");
  73. system::createDirectory(dir);
  74. }
  75. else {
  76. dir = string::directory(lastPath);
  77. }
  78. osdialog_filters *filters = osdialog_filters_parse(PATCH_FILTERS.c_str());
  79. DEFER({
  80. osdialog_filters_free(filters);
  81. });
  82. char *path = osdialog_file(OSDIALOG_OPEN, dir.c_str(), NULL, filters);
  83. if (!path) {
  84. // Fail silently
  85. return;
  86. }
  87. DEFER({
  88. free(path);
  89. });
  90. load(path);
  91. lastPath = path;
  92. }
  93. void RackWidget::saveDialog() {
  94. if (!lastPath.empty()) {
  95. save(lastPath);
  96. }
  97. else {
  98. saveAsDialog();
  99. }
  100. }
  101. void RackWidget::saveAsDialog() {
  102. std::string dir;
  103. std::string filename;
  104. if (lastPath.empty()) {
  105. dir = asset::user("patches");
  106. system::createDirectory(dir);
  107. }
  108. else {
  109. dir = string::directory(lastPath);
  110. filename = string::filename(lastPath);
  111. }
  112. osdialog_filters *filters = osdialog_filters_parse(PATCH_FILTERS.c_str());
  113. DEFER({
  114. osdialog_filters_free(filters);
  115. });
  116. char *path = osdialog_file(OSDIALOG_SAVE, dir.c_str(), filename.c_str(), filters);
  117. if (!path) {
  118. // Fail silently
  119. return;
  120. }
  121. DEFER({
  122. free(path);
  123. });
  124. std::string pathStr = path;
  125. if (string::extension(pathStr).empty()) {
  126. pathStr += ".vcv";
  127. }
  128. save(pathStr);
  129. lastPath = pathStr;
  130. }
  131. void RackWidget::saveTemplate() {
  132. if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "Overwrite template patch?")) {
  133. save(asset::user("template.vcv"));
  134. }
  135. }
  136. void RackWidget::save(std::string filename) {
  137. INFO("Saving patch %s", filename.c_str());
  138. json_t *rootJ = toJson();
  139. if (!rootJ)
  140. return;
  141. DEFER({
  142. json_decref(rootJ);
  143. });
  144. FILE *file = fopen(filename.c_str(), "w");
  145. if (!file) {
  146. // Fail silently
  147. return;
  148. }
  149. DEFER({
  150. fclose(file);
  151. });
  152. json_dumpf(rootJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9));
  153. }
  154. void RackWidget::load(std::string filename) {
  155. INFO("Loading patch %s", filename.c_str());
  156. FILE *file = fopen(filename.c_str(), "r");
  157. if (!file) {
  158. // Exit silently
  159. return;
  160. }
  161. DEFER({
  162. fclose(file);
  163. });
  164. json_error_t error;
  165. json_t *rootJ = json_loadf(file, 0, &error);
  166. if (!rootJ) {
  167. std::string message = string::f("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
  168. osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
  169. return;
  170. }
  171. DEFER({
  172. json_decref(rootJ);
  173. });
  174. clear();
  175. fromJson(rootJ);
  176. }
  177. void RackWidget::revert() {
  178. if (lastPath.empty())
  179. return;
  180. if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "Revert patch to the last saved state?")) {
  181. load(lastPath);
  182. }
  183. }
  184. void RackWidget::disconnect() {
  185. if (!osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK_CANCEL, "Remove all patch cables?"))
  186. return;
  187. cableContainer->removeAllCables(NULL);
  188. }
  189. json_t *RackWidget::toJson() {
  190. // root
  191. json_t *rootJ = json_object();
  192. // version
  193. json_t *versionJ = json_string(APP_VERSION.c_str());
  194. json_object_set_new(rootJ, "version", versionJ);
  195. // modules
  196. json_t *modulesJ = json_array();
  197. for (Widget *w : moduleContainer->children) {
  198. ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
  199. assert(moduleWidget);
  200. // module
  201. json_t *moduleJ = moduleWidget->toJson();
  202. {
  203. // id
  204. json_object_set_new(moduleJ, "id", json_integer(moduleWidget->module->id));
  205. // pos
  206. math::Vec pos = moduleWidget->box.pos.div(RACK_GRID_SIZE).round();
  207. json_t *posJ = json_pack("[i, i]", (int) pos.x, (int) pos.y);
  208. json_object_set_new(moduleJ, "pos", posJ);
  209. }
  210. json_array_append_new(modulesJ, moduleJ);
  211. }
  212. json_object_set_new(rootJ, "modules", modulesJ);
  213. // cables
  214. json_t *cablesJ = json_array();
  215. for (Widget *w : cableContainer->children) {
  216. CableWidget *cableWidget = dynamic_cast<CableWidget*>(w);
  217. assert(cableWidget);
  218. PortWidget *outputPort = cableWidget->outputPort;
  219. PortWidget *inputPort = cableWidget->inputPort;
  220. // Only serialize CableWidgets connected on both ends
  221. if (!(outputPort && inputPort))
  222. continue;
  223. Cable *cable = cableWidget->cable;
  224. assert(cable);
  225. // cable
  226. json_t *cableJ = cableWidget->toJson();
  227. assert(outputPort->module);
  228. assert(inputPort->module);
  229. json_object_set_new(cableJ, "id", json_integer(cable->id));
  230. json_object_set_new(cableJ, "outputModuleId", json_integer(outputPort->module->id));
  231. json_object_set_new(cableJ, "outputId", json_integer(outputPort->portId));
  232. json_object_set_new(cableJ, "inputModuleId", json_integer(inputPort->module->id));
  233. json_object_set_new(cableJ, "inputId", json_integer(inputPort->portId));
  234. json_array_append_new(cablesJ, cableJ);
  235. }
  236. json_object_set_new(rootJ, "cables", cablesJ);
  237. return rootJ;
  238. }
  239. void RackWidget::fromJson(json_t *rootJ) {
  240. std::string message;
  241. // version
  242. std::string version;
  243. json_t *versionJ = json_object_get(rootJ, "version");
  244. if (versionJ)
  245. version = json_string_value(versionJ);
  246. if (version != APP_VERSION) {
  247. INFO("Patch made with Rack version %s, current Rack version is %s", version.c_str(), APP_VERSION.c_str());
  248. }
  249. // Detect old patches with ModuleWidget::params/inputs/outputs indices.
  250. // (We now use Module::params/inputs/outputs indices.)
  251. int legacy = 0;
  252. if (string::startsWith(version, "0.3.") || string::startsWith(version, "0.4.") || string::startsWith(version, "0.5.") || version == "" || version == "dev") {
  253. legacy = 1;
  254. }
  255. else if (string::startsWith(version, "0.6.")) {
  256. legacy = 2;
  257. }
  258. if (legacy) {
  259. INFO("Loading patch using legacy mode %d", legacy);
  260. }
  261. // modules
  262. json_t *modulesJ = json_object_get(rootJ, "modules");
  263. if (!modulesJ)
  264. return;
  265. std::map<int, ModuleWidget*> moduleWidgets;
  266. size_t moduleIndex;
  267. json_t *moduleJ;
  268. json_array_foreach(modulesJ, moduleIndex, moduleJ) {
  269. // Add "legacy" property if in legacy mode
  270. if (legacy) {
  271. json_object_set(moduleJ, "legacy", json_integer(legacy));
  272. }
  273. ModuleWidget *moduleWidget = moduleFromJson(moduleJ);
  274. if (moduleWidget) {
  275. // id
  276. json_t *idJ = json_object_get(moduleJ, "id");
  277. int id = 0;
  278. if (idJ)
  279. id = json_integer_value(idJ);
  280. // pos
  281. json_t *posJ = json_object_get(moduleJ, "pos");
  282. double x, y;
  283. json_unpack(posJ, "[F, F]", &x, &y);
  284. math::Vec pos = math::Vec(x, y);
  285. if (legacy && legacy <= 1) {
  286. // Before 0.6, positions were in pixel units
  287. moduleWidget->box.pos = pos;
  288. }
  289. else {
  290. moduleWidget->box.pos = pos.mult(RACK_GRID_SIZE);
  291. }
  292. if (legacy && legacy <= 2) {
  293. // Before 1.0, the module ID was the index in the "modules" array
  294. moduleWidgets[moduleIndex] = moduleWidget;
  295. }
  296. else {
  297. moduleWidgets[id] = moduleWidget;
  298. }
  299. addModule(moduleWidget);
  300. }
  301. else {
  302. json_t *pluginSlugJ = json_object_get(moduleJ, "plugin");
  303. json_t *modelSlugJ = json_object_get(moduleJ, "model");
  304. std::string pluginSlug = json_string_value(pluginSlugJ);
  305. std::string modelSlug = json_string_value(modelSlugJ);
  306. message += string::f("Could not find module \"%s\" of plugin \"%s\"\n", modelSlug.c_str(), pluginSlug.c_str());
  307. }
  308. }
  309. // cables
  310. json_t *cablesJ = json_object_get(rootJ, "cables");
  311. // Before 1.0, cables were called wires
  312. if (!cablesJ)
  313. cablesJ = json_object_get(rootJ, "wires");
  314. assert(cablesJ);
  315. size_t cableIndex;
  316. json_t *cableJ;
  317. json_array_foreach(cablesJ, cableIndex, cableJ) {
  318. int outputModuleId = json_integer_value(json_object_get(cableJ, "outputModuleId"));
  319. int outputId = json_integer_value(json_object_get(cableJ, "outputId"));
  320. int inputModuleId = json_integer_value(json_object_get(cableJ, "inputModuleId"));
  321. int inputId = json_integer_value(json_object_get(cableJ, "inputId"));
  322. // Get module widgets
  323. ModuleWidget *outputModuleWidget = moduleWidgets[outputModuleId];
  324. if (!outputModuleWidget) continue;
  325. ModuleWidget *inputModuleWidget = moduleWidgets[inputModuleId];
  326. if (!inputModuleWidget) continue;
  327. // Get port widgets
  328. PortWidget *outputPort = NULL;
  329. PortWidget *inputPort = NULL;
  330. if (legacy && legacy <= 1) {
  331. // Before 0.6, the index of the "ports" array was the index of the PortWidget in the `outputs` and `inputs` vector.
  332. outputPort = outputModuleWidget->outputs[outputId];
  333. inputPort = inputModuleWidget->inputs[inputId];
  334. }
  335. else {
  336. for (PortWidget *port : outputModuleWidget->outputs) {
  337. if (port->portId == outputId) {
  338. outputPort = port;
  339. break;
  340. }
  341. }
  342. for (PortWidget *port : inputModuleWidget->inputs) {
  343. if (port->portId == inputId) {
  344. inputPort = port;
  345. break;
  346. }
  347. }
  348. }
  349. if (!outputPort || !inputPort)
  350. continue;
  351. // Create CableWidget
  352. CableWidget *cableWidget = new CableWidget;
  353. cableWidget->fromJson(cableJ);
  354. cableWidget->outputPort = outputPort;
  355. cableWidget->inputPort = inputPort;
  356. cableWidget->updateCable();
  357. // Add cable to rack
  358. cableContainer->addChild(cableWidget);
  359. }
  360. // Display a message if we have something to say
  361. if (!message.empty()) {
  362. osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
  363. }
  364. }
  365. ModuleWidget *RackWidget::moduleFromJson(json_t *moduleJ) {
  366. // Get slugs
  367. json_t *pluginSlugJ = json_object_get(moduleJ, "plugin");
  368. if (!pluginSlugJ)
  369. return NULL;
  370. json_t *modelSlugJ = json_object_get(moduleJ, "model");
  371. if (!modelSlugJ)
  372. return NULL;
  373. std::string pluginSlug = json_string_value(pluginSlugJ);
  374. std::string modelSlug = json_string_value(modelSlugJ);
  375. // Get Model
  376. Model *model = plugin::getModel(pluginSlug, modelSlug);
  377. if (!model)
  378. return NULL;
  379. // Create ModuleWidget
  380. ModuleWidget *moduleWidget = model->createModuleWidget();
  381. assert(moduleWidget);
  382. moduleWidget->fromJson(moduleJ);
  383. return moduleWidget;
  384. }
  385. void RackWidget::pastePresetClipboard() {
  386. const char *moduleJson = glfwGetClipboardString(app()->window->win);
  387. if (!moduleJson) {
  388. WARN("Could not get text from clipboard.");
  389. return;
  390. }
  391. json_error_t error;
  392. json_t *moduleJ = json_loads(moduleJson, 0, &error);
  393. if (moduleJ) {
  394. ModuleWidget *moduleWidget = moduleFromJson(moduleJ);
  395. json_decref(moduleJ);
  396. addModule(moduleWidget);
  397. // Set moduleWidget position
  398. math::Rect newBox = moduleWidget->box;
  399. newBox.pos = lastMousePos.minus(newBox.size.div(2));
  400. requestModuleBoxNearest(moduleWidget, newBox);
  401. }
  402. else {
  403. WARN("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
  404. }
  405. }
  406. void RackWidget::addModule(ModuleWidget *m) {
  407. // Add module to ModuleContainer
  408. assert(m);
  409. assert(m->module);
  410. moduleContainer->addChild(m);
  411. // Add module to Engine
  412. app()->engine->addModule(m->module);
  413. }
  414. void RackWidget::addModuleAtMouse(ModuleWidget *m) {
  415. assert(m);
  416. // Move module nearest to the mouse position
  417. m->box.pos = lastMousePos.minus(m->box.size.div(2));
  418. requestModuleBoxNearest(m, m->box);
  419. addModule(m);
  420. }
  421. void RackWidget::removeModule(ModuleWidget *m) {
  422. // Disconnect cables
  423. m->disconnect();
  424. // Remove module from Engine
  425. assert(m->module);
  426. app()->engine->removeModule(m->module);
  427. // Remove module from ModuleContainer
  428. moduleContainer->removeChild(m);
  429. }
  430. bool RackWidget::requestModuleBox(ModuleWidget *m, math::Rect box) {
  431. if (box.pos.x < 0 || box.pos.y < 0)
  432. return false;
  433. for (Widget *child2 : moduleContainer->children) {
  434. if (m == child2) continue;
  435. if (box.intersects(child2->box)) {
  436. return false;
  437. }
  438. }
  439. m->box = box;
  440. return true;
  441. }
  442. bool RackWidget::requestModuleBoxNearest(ModuleWidget *m, math::Rect box) {
  443. // Create possible positions
  444. int x0 = std::round(box.pos.x / RACK_GRID_WIDTH);
  445. int y0 = std::round(box.pos.y / RACK_GRID_HEIGHT);
  446. std::vector<math::Vec> positions;
  447. for (int y = std::max(0, y0 - 8); y < y0 + 8; y++) {
  448. for (int x = std::max(0, x0 - 400); x < x0 + 400; x++) {
  449. positions.push_back(math::Vec(x * RACK_GRID_WIDTH, y * RACK_GRID_HEIGHT));
  450. }
  451. }
  452. // Sort possible positions by distance to the requested position
  453. std::sort(positions.begin(), positions.end(), [box](math::Vec a, math::Vec b) {
  454. return a.minus(box.pos).norm() < b.minus(box.pos).norm();
  455. });
  456. // Find a position that does not collide
  457. for (math::Vec position : positions) {
  458. math::Rect newBox = box;
  459. newBox.pos = position;
  460. if (requestModuleBox(m, newBox))
  461. return true;
  462. }
  463. return false;
  464. }
  465. ModuleWidget *RackWidget::getModule(int moduleId) {
  466. for (Widget *w : moduleContainer->children) {
  467. ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
  468. assert(moduleWidget);
  469. if (moduleWidget->module->id == moduleId)
  470. return moduleWidget;
  471. }
  472. return NULL;
  473. }
  474. void RackWidget::step() {
  475. // Expand size to fit modules
  476. math::Vec moduleSize = moduleContainer->getChildrenBoundingBox().getBottomRight();
  477. // We assume that the size is reset by a parent before calling step(). Otherwise it will grow unbounded.
  478. box.size = box.size.max(moduleSize);
  479. // Adjust size and position of rails
  480. Widget *rail = rails->children.front();
  481. math::Rect bound = getViewport(math::Rect(math::Vec(), box.size));
  482. if (!rails->box.contains(bound)) {
  483. math::Vec cellMargin = math::Vec(20, 1);
  484. rails->box.pos = bound.pos.div(RACK_GRID_SIZE).floor().minus(cellMargin).mult(RACK_GRID_SIZE);
  485. rails->box.size = bound.size.plus(cellMargin.mult(RACK_GRID_SIZE).mult(2));
  486. rails->dirty = true;
  487. rail->box.size = rails->box.size;
  488. }
  489. // Autosave every 15 seconds
  490. int frame = app()->window->frame;
  491. if (frame > 0 && frame % (60 * 15) == 0) {
  492. save(asset::user("autosave.vcv"));
  493. settings::save(asset::user("settings.json"));
  494. }
  495. Widget::step();
  496. }
  497. void RackWidget::draw(NVGcontext *vg) {
  498. Widget::draw(vg);
  499. }
  500. void RackWidget::onHover(const event::Hover &e) {
  501. // Scroll with arrow keys
  502. float arrowSpeed = 30.0;
  503. if ((app()->window->getMods() & WINDOW_MOD_MASK) == (WINDOW_MOD_CTRL |GLFW_MOD_SHIFT))
  504. arrowSpeed /= 16.0;
  505. else if ((app()->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL)
  506. arrowSpeed *= 4.0;
  507. else if ((app()->window->getMods() & WINDOW_MOD_MASK) == GLFW_MOD_SHIFT)
  508. arrowSpeed /= 4.0;
  509. ScrollWidget *scrollWidget = app()->scene->scrollWidget;
  510. if (glfwGetKey(app()->window->win, GLFW_KEY_LEFT) == GLFW_PRESS) {
  511. scrollWidget->offset.x -= arrowSpeed;
  512. }
  513. if (glfwGetKey(app()->window->win, GLFW_KEY_RIGHT) == GLFW_PRESS) {
  514. scrollWidget->offset.x += arrowSpeed;
  515. }
  516. if (glfwGetKey(app()->window->win, GLFW_KEY_UP) == GLFW_PRESS) {
  517. scrollWidget->offset.y -= arrowSpeed;
  518. }
  519. if (glfwGetKey(app()->window->win, GLFW_KEY_DOWN) == GLFW_PRESS) {
  520. scrollWidget->offset.y += arrowSpeed;
  521. }
  522. OpaqueWidget::onHover(e);
  523. lastMousePos = e.pos;
  524. }
  525. void RackWidget::onDragHover(const event::DragHover &e) {
  526. OpaqueWidget::onDragHover(e);
  527. lastMousePos = e.pos;
  528. }
  529. void RackWidget::onButton(const event::Button &e) {
  530. OpaqueWidget::onButton(e);
  531. if (e.getConsumed() == this) {
  532. if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) {
  533. app()->scene->moduleBrowser->visible = true;
  534. }
  535. }
  536. }
  537. void RackWidget::onZoom(const event::Zoom &e) {
  538. rails->box.size = math::Vec();
  539. OpaqueWidget::onZoom(e);
  540. }
  541. } // namespace rack