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.

572 lines
15KB

  1. #include "app.hpp"
  2. #include "engine.hpp"
  3. #include "plugin.hpp"
  4. #include "window.hpp"
  5. #include "settings.hpp"
  6. #include "asset.hpp"
  7. #include <map>
  8. #include <algorithm>
  9. #include "osdialog.h"
  10. namespace rack {
  11. struct ModuleContainer : Widget {
  12. void draw(NVGcontext *vg) override {
  13. // Draw shadows behind each ModuleWidget first, so the shadow doesn't overlap the front.
  14. for (Widget *child : children) {
  15. if (!child->visible)
  16. continue;
  17. nvgSave(vg);
  18. nvgTranslate(vg, child->box.pos.x, child->box.pos.y);
  19. ModuleWidget *w = dynamic_cast<ModuleWidget*>(child);
  20. w->drawShadow(vg);
  21. nvgRestore(vg);
  22. }
  23. Widget::draw(vg);
  24. }
  25. };
  26. RackWidget::RackWidget() {
  27. rails = new FramebufferWidget();
  28. rails->box.size = Vec();
  29. rails->oversample = 1.0;
  30. {
  31. RackRail *rail = new RackRail();
  32. rail->box.size = Vec();
  33. rails->addChild(rail);
  34. }
  35. addChild(rails);
  36. moduleContainer = new ModuleContainer();
  37. addChild(moduleContainer);
  38. wireContainer = new WireContainer();
  39. addChild(wireContainer);
  40. }
  41. RackWidget::~RackWidget() {
  42. }
  43. void RackWidget::clear() {
  44. wireContainer->activeWire = NULL;
  45. wireContainer->clearChildren();
  46. moduleContainer->clearChildren();
  47. gRackScene->scrollWidget->offset = Vec(0, 0);
  48. }
  49. void RackWidget::reset() {
  50. if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "Clear patch and start over?")) {
  51. clear();
  52. // Fails silently if file does not exist
  53. load(assetLocal("template.vcv"));
  54. lastPath = "";
  55. }
  56. }
  57. void RackWidget::loadDialog() {
  58. std::string dir;
  59. if (lastPath.empty()) {
  60. dir = assetLocal("patches");
  61. systemCreateDirectory(dir);
  62. }
  63. else {
  64. dir = stringDirectory(lastPath);
  65. }
  66. osdialog_filters *filters = osdialog_filters_parse(PATCH_FILTERS.c_str());
  67. char *path = osdialog_file(OSDIALOG_OPEN, dir.c_str(), NULL, filters);
  68. if (path) {
  69. load(path);
  70. lastPath = path;
  71. free(path);
  72. }
  73. osdialog_filters_free(filters);
  74. }
  75. void RackWidget::saveDialog() {
  76. if (!lastPath.empty()) {
  77. save(lastPath);
  78. }
  79. else {
  80. saveAsDialog();
  81. }
  82. }
  83. void RackWidget::saveAsDialog() {
  84. std::string dir;
  85. std::string filename;
  86. if (lastPath.empty()) {
  87. dir = assetLocal("patches");
  88. systemCreateDirectory(dir);
  89. }
  90. else {
  91. dir = stringDirectory(lastPath);
  92. filename = stringFilename(lastPath);
  93. }
  94. osdialog_filters *filters = osdialog_filters_parse(PATCH_FILTERS.c_str());
  95. char *path = osdialog_file(OSDIALOG_SAVE, dir.c_str(), filename.c_str(), filters);
  96. if (path) {
  97. std::string pathStr = path;
  98. free(path);
  99. std::string extension = stringExtension(pathStr);
  100. if (extension.empty()) {
  101. pathStr += ".vcv";
  102. }
  103. save(pathStr);
  104. lastPath = pathStr;
  105. }
  106. osdialog_filters_free(filters);
  107. }
  108. void RackWidget::save(std::string filename) {
  109. info("Saving patch %s", filename.c_str());
  110. json_t *rootJ = toJson();
  111. if (!rootJ)
  112. return;
  113. FILE *file = fopen(filename.c_str(), "w");
  114. if (file) {
  115. json_dumpf(rootJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9));
  116. fclose(file);
  117. }
  118. json_decref(rootJ);
  119. }
  120. void RackWidget::load(std::string filename) {
  121. info("Loading patch %s", filename.c_str());
  122. FILE *file = fopen(filename.c_str(), "r");
  123. if (!file) {
  124. // Exit silently
  125. return;
  126. }
  127. json_error_t error;
  128. json_t *rootJ = json_loadf(file, 0, &error);
  129. if (rootJ) {
  130. clear();
  131. fromJson(rootJ);
  132. json_decref(rootJ);
  133. }
  134. else {
  135. std::string message = stringf("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
  136. osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
  137. }
  138. fclose(file);
  139. }
  140. void RackWidget::revert() {
  141. if (lastPath.empty())
  142. return;
  143. if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "Revert patch to the last saved state?")) {
  144. load(lastPath);
  145. }
  146. }
  147. void RackWidget::disconnect() {
  148. if (!osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK_CANCEL, "Remove all patch cables?"))
  149. return;
  150. for (Widget *w : moduleContainer->children) {
  151. ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
  152. assert(moduleWidget);
  153. moduleWidget->disconnect();
  154. }
  155. }
  156. json_t *RackWidget::toJson() {
  157. // root
  158. json_t *rootJ = json_object();
  159. // version
  160. json_t *versionJ = json_string(gApplicationVersion.c_str());
  161. json_object_set_new(rootJ, "version", versionJ);
  162. // modules
  163. json_t *modulesJ = json_array();
  164. std::map<ModuleWidget*, int> moduleIds;
  165. int moduleId = 0;
  166. for (Widget *w : moduleContainer->children) {
  167. ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
  168. assert(moduleWidget);
  169. moduleIds[moduleWidget] = moduleId;
  170. moduleId++;
  171. // module
  172. json_t *moduleJ = moduleWidget->toJson();
  173. {
  174. // pos
  175. Vec pos = moduleWidget->box.pos.div(RACK_GRID_SIZE).round();
  176. json_t *posJ = json_pack("[i, i]", (int) pos.x, (int) pos.y);
  177. json_object_set_new(moduleJ, "pos", posJ);
  178. }
  179. json_array_append_new(modulesJ, moduleJ);
  180. }
  181. json_object_set_new(rootJ, "modules", modulesJ);
  182. // wires
  183. json_t *wires = json_array();
  184. for (Widget *w : wireContainer->children) {
  185. WireWidget *wireWidget = dynamic_cast<WireWidget*>(w);
  186. assert(wireWidget);
  187. // Only serialize WireWidgets connected on both ends
  188. if (!(wireWidget->outputPort && wireWidget->inputPort))
  189. continue;
  190. // wire
  191. json_t *wire = wireWidget->toJson();
  192. // Get the modules at each end of the wire
  193. ModuleWidget *outputModuleWidget = wireWidget->outputPort->getAncestorOfType<ModuleWidget>();
  194. assert(outputModuleWidget);
  195. int outputModuleId = moduleIds[outputModuleWidget];
  196. ModuleWidget *inputModuleWidget = wireWidget->inputPort->getAncestorOfType<ModuleWidget>();
  197. assert(inputModuleWidget);
  198. int inputModuleId = moduleIds[inputModuleWidget];
  199. // Get output/input ports
  200. int outputId = wireWidget->outputPort->portId;
  201. int inputId = wireWidget->inputPort->portId;
  202. json_object_set_new(wire, "outputModuleId", json_integer(outputModuleId));
  203. json_object_set_new(wire, "outputId", json_integer(outputId));
  204. json_object_set_new(wire, "inputModuleId", json_integer(inputModuleId));
  205. json_object_set_new(wire, "inputId", json_integer(inputId));
  206. json_array_append_new(wires, wire);
  207. }
  208. json_object_set_new(rootJ, "wires", wires);
  209. return rootJ;
  210. }
  211. void RackWidget::fromJson(json_t *rootJ) {
  212. std::string message;
  213. // version
  214. std::string version;
  215. json_t *versionJ = json_object_get(rootJ, "version");
  216. if (versionJ) {
  217. version = json_string_value(versionJ);
  218. }
  219. // Detect old patches with ModuleWidget::params/inputs/outputs indices.
  220. // (We now use Module::params/inputs/outputs indices.)
  221. int legacy = 0;
  222. if (stringStartsWith(version, "0.3.") || stringStartsWith(version, "0.4.") || stringStartsWith(version, "0.5.") || version == "" || version == "dev") {
  223. legacy = 1;
  224. }
  225. if (legacy) {
  226. info("Loading patch using legacy mode %d", legacy);
  227. }
  228. // modules
  229. std::map<int, ModuleWidget*> moduleWidgets;
  230. json_t *modulesJ = json_object_get(rootJ, "modules");
  231. if (!modulesJ) return;
  232. size_t moduleId;
  233. json_t *moduleJ;
  234. json_array_foreach(modulesJ, moduleId, moduleJ) {
  235. // Add "legacy" property if in legacy mode
  236. if (legacy) {
  237. json_object_set(moduleJ, "legacy", json_integer(legacy));
  238. }
  239. ModuleWidget *moduleWidget = moduleFromJson(moduleJ);
  240. if (moduleWidget) {
  241. // pos
  242. json_t *posJ = json_object_get(moduleJ, "pos");
  243. double x, y;
  244. json_unpack(posJ, "[F, F]", &x, &y);
  245. Vec pos = Vec(x, y);
  246. if (legacy && legacy <= 1) {
  247. moduleWidget->box.pos = pos;
  248. }
  249. else {
  250. moduleWidget->box.pos = pos.mult(RACK_GRID_SIZE);
  251. }
  252. moduleWidgets[moduleId] = moduleWidget;
  253. }
  254. else {
  255. json_t *pluginSlugJ = json_object_get(moduleJ, "plugin");
  256. json_t *modelSlugJ = json_object_get(moduleJ, "model");
  257. std::string pluginSlug = json_string_value(pluginSlugJ);
  258. std::string modelSlug = json_string_value(modelSlugJ);
  259. message += stringf("Could not find module \"%s\" of plugin \"%s\"\n", modelSlug.c_str(), pluginSlug.c_str());
  260. }
  261. }
  262. // wires
  263. json_t *wiresJ = json_object_get(rootJ, "wires");
  264. if (!wiresJ) return;
  265. size_t wireId;
  266. json_t *wireJ;
  267. json_array_foreach(wiresJ, wireId, wireJ) {
  268. int outputModuleId = json_integer_value(json_object_get(wireJ, "outputModuleId"));
  269. int outputId = json_integer_value(json_object_get(wireJ, "outputId"));
  270. int inputModuleId = json_integer_value(json_object_get(wireJ, "inputModuleId"));
  271. int inputId = json_integer_value(json_object_get(wireJ, "inputId"));
  272. // Get module widgets
  273. ModuleWidget *outputModuleWidget = moduleWidgets[outputModuleId];
  274. if (!outputModuleWidget) continue;
  275. ModuleWidget *inputModuleWidget = moduleWidgets[inputModuleId];
  276. if (!inputModuleWidget) continue;
  277. // Get port widgets
  278. Port *outputPort = NULL;
  279. Port *inputPort = NULL;
  280. if (legacy && legacy <= 1) {
  281. // Legacy 1 mode
  282. // The index of the "ports" array is the index of the Port in the `outputs` and `inputs` vector.
  283. outputPort = outputModuleWidget->outputs[outputId];
  284. inputPort = inputModuleWidget->inputs[inputId];
  285. }
  286. else {
  287. for (Port *port : outputModuleWidget->outputs) {
  288. if (port->portId == outputId) {
  289. outputPort = port;
  290. break;
  291. }
  292. }
  293. for (Port *port : inputModuleWidget->inputs) {
  294. if (port->portId == inputId) {
  295. inputPort = port;
  296. break;
  297. }
  298. }
  299. }
  300. if (!outputPort || !inputPort)
  301. continue;
  302. // Create WireWidget
  303. WireWidget *wireWidget = new WireWidget();
  304. wireWidget->fromJson(wireJ);
  305. wireWidget->outputPort = outputPort;
  306. wireWidget->inputPort = inputPort;
  307. wireWidget->updateWire();
  308. // Add wire to rack
  309. wireContainer->addChild(wireWidget);
  310. }
  311. // Display a message if we have something to say
  312. if (!message.empty()) {
  313. osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
  314. }
  315. }
  316. ModuleWidget *RackWidget::moduleFromJson(json_t *moduleJ) {
  317. // Get slugs
  318. json_t *pluginSlugJ = json_object_get(moduleJ, "plugin");
  319. if (!pluginSlugJ)
  320. return NULL;
  321. json_t *modelSlugJ = json_object_get(moduleJ, "model");
  322. if (!modelSlugJ)
  323. return NULL;
  324. std::string pluginSlug = json_string_value(pluginSlugJ);
  325. std::string modelSlug = json_string_value(modelSlugJ);
  326. // Get Model
  327. Model *model = pluginGetModel(pluginSlug, modelSlug);
  328. if (!model)
  329. return NULL;
  330. // Create ModuleWidget
  331. ModuleWidget *moduleWidget = model->createModuleWidget();
  332. assert(moduleWidget);
  333. moduleWidget->fromJson(moduleJ);
  334. moduleContainer->addChild(moduleWidget);
  335. return moduleWidget;
  336. }
  337. void RackWidget::pastePresetClipboard() {
  338. const char *moduleJson = glfwGetClipboardString(gWindow);
  339. if (!moduleJson) {
  340. warn("Could not get text from clipboard.");
  341. return;
  342. }
  343. json_error_t error;
  344. json_t *moduleJ = json_loads(moduleJson, 0, &error);
  345. if (moduleJ) {
  346. ModuleWidget *moduleWidget = moduleFromJson(moduleJ);
  347. // Set moduleWidget position
  348. Rect newBox = moduleWidget->box;
  349. newBox.pos = lastMousePos.minus(newBox.size.div(2));
  350. requestModuleBoxNearest(moduleWidget, newBox);
  351. json_decref(moduleJ);
  352. }
  353. else {
  354. warn("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
  355. }
  356. }
  357. void RackWidget::addModule(ModuleWidget *m) {
  358. moduleContainer->addChild(m);
  359. m->create();
  360. }
  361. void RackWidget::deleteModule(ModuleWidget *m) {
  362. m->_delete();
  363. moduleContainer->removeChild(m);
  364. }
  365. void RackWidget::cloneModule(ModuleWidget *m) {
  366. // JSON serialization is the most straightforward way to do this
  367. json_t *moduleJ = m->toJson();
  368. ModuleWidget *clonedModuleWidget = moduleFromJson(moduleJ);
  369. json_decref(moduleJ);
  370. Rect clonedBox = clonedModuleWidget->box;
  371. clonedBox.pos = m->box.pos;
  372. requestModuleBoxNearest(clonedModuleWidget, clonedBox);
  373. }
  374. bool RackWidget::requestModuleBox(ModuleWidget *m, Rect box) {
  375. if (box.pos.x < 0 || box.pos.y < 0)
  376. return false;
  377. for (Widget *child2 : moduleContainer->children) {
  378. if (m == child2) continue;
  379. if (box.intersects(child2->box)) {
  380. return false;
  381. }
  382. }
  383. m->box = box;
  384. return true;
  385. }
  386. bool RackWidget::requestModuleBoxNearest(ModuleWidget *m, Rect box) {
  387. // Create possible positions
  388. int x0 = roundf(box.pos.x / RACK_GRID_WIDTH);
  389. int y0 = roundf(box.pos.y / RACK_GRID_HEIGHT);
  390. std::vector<Vec> positions;
  391. for (int y = max(0, y0 - 8); y < y0 + 8; y++) {
  392. for (int x = max(0, x0 - 400); x < x0 + 400; x++) {
  393. positions.push_back(Vec(x * RACK_GRID_WIDTH, y * RACK_GRID_HEIGHT));
  394. }
  395. }
  396. // Sort possible positions by distance to the requested position
  397. std::sort(positions.begin(), positions.end(), [box](Vec a, Vec b) {
  398. return a.minus(box.pos).norm() < b.minus(box.pos).norm();
  399. });
  400. // Find a position that does not collide
  401. for (Vec position : positions) {
  402. Rect newBox = box;
  403. newBox.pos = position;
  404. if (requestModuleBox(m, newBox))
  405. return true;
  406. }
  407. return false;
  408. }
  409. bool RackWidget::pushModule(ModuleWidget *m, bool pushLeft) {
  410. // calculate desired position
  411. Rect newBox = m->box;
  412. if (pushLeft) {
  413. newBox.pos.x -= RACK_GRID_WIDTH;
  414. } else {
  415. newBox.pos.x += RACK_GRID_WIDTH;
  416. }
  417. // can't be pushed over the left border
  418. if (newBox.pos.x < 0.0f) return false;
  419. // get intersection widget after moving
  420. Widget *iw = NULL;
  421. int count = 0;
  422. for (Widget *child2 : moduleContainer->children) {
  423. if (m == child2) continue;
  424. if (newBox.intersects(child2->box)) {
  425. iw = child2;
  426. count++;
  427. }
  428. }
  429. // if a module is higher than one grid unit, it can push only one module, otherwise we would need a rollback,
  430. // if e.g. one of two modules can't be pushed
  431. if (count > 1) return false;
  432. // if there is any intersected widget, try to push it recursively
  433. if (iw) {
  434. ModuleWidget *w2 = dynamic_cast<ModuleWidget*>(iw);
  435. if (pushModule(w2, pushLeft)) {
  436. // if successful, set new position for this widget
  437. m->box = newBox;
  438. return true;
  439. } else {
  440. return false;
  441. }
  442. } else {
  443. // no intersection, just set the new position
  444. m->box = newBox;
  445. return true;
  446. }
  447. }
  448. void RackWidget::step() {
  449. // Expand size to fit modules
  450. Vec moduleSize = moduleContainer->getChildrenBoundingBox().getBottomRight();
  451. // We assume that the size is reset by a parent before calling step(). Otherwise it will grow unbounded.
  452. box.size = box.size.max(moduleSize);
  453. // Adjust size and position of rails
  454. Widget *rail = rails->children.front();
  455. Rect bound = getViewport(Rect(Vec(), box.size));
  456. if (!rails->box.contains(bound)) {
  457. Vec cellMargin = Vec(20, 1);
  458. rails->box.pos = bound.pos.div(RACK_GRID_SIZE).floor().minus(cellMargin).mult(RACK_GRID_SIZE);
  459. rails->box.size = bound.size.plus(cellMargin.mult(RACK_GRID_SIZE).mult(2));
  460. rails->dirty = true;
  461. rail->box.size = rails->box.size;
  462. }
  463. // Autosave every 15 seconds
  464. if (gGuiFrame % (60 * 15) == 0) {
  465. save(assetLocal("autosave.vcv"));
  466. settingsSave(assetLocal("settings.json"));
  467. }
  468. Widget::step();
  469. }
  470. void RackWidget::draw(NVGcontext *vg) {
  471. Widget::draw(vg);
  472. }
  473. void RackWidget::onMouseMove(EventMouseMove &e) {
  474. OpaqueWidget::onMouseMove(e);
  475. lastMousePos = e.pos;
  476. }
  477. void RackWidget::onMouseDown(EventMouseDown &e) {
  478. Widget::onMouseDown(e);
  479. if (e.consumed)
  480. return;
  481. if (e.button == 1) {
  482. appModuleBrowserCreate();
  483. }
  484. e.consumed = true;
  485. e.target = this;
  486. }
  487. void RackWidget::onZoom(EventZoom &e) {
  488. rails->box.size = Vec();
  489. Widget::onZoom(e);
  490. }
  491. } // namespace rack