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.

528 lines
14KB

  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 = std::max(0, y0 - 8); y < y0 + 8; y++) {
  392. for (int x = std::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. void RackWidget::step() {
  410. // Expand size to fit modules
  411. Vec moduleSize = moduleContainer->getChildrenBoundingBox().getBottomRight();
  412. // We assume that the size is reset by a parent before calling step(). Otherwise it will grow unbounded.
  413. box.size = box.size.max(moduleSize);
  414. // Adjust size and position of rails
  415. Widget *rail = rails->children.front();
  416. Rect bound = getViewport(Rect(Vec(), box.size));
  417. if (!rails->box.contains(bound)) {
  418. Vec cellMargin = Vec(20, 1);
  419. rails->box.pos = bound.pos.div(RACK_GRID_SIZE).floor().minus(cellMargin).mult(RACK_GRID_SIZE);
  420. rails->box.size = bound.size.plus(cellMargin.mult(RACK_GRID_SIZE).mult(2));
  421. rails->dirty = true;
  422. rail->box.size = rails->box.size;
  423. }
  424. // Autosave every 15 seconds
  425. if (gGuiFrame % (60 * 15) == 0) {
  426. save(assetLocal("autosave.vcv"));
  427. settingsSave(assetLocal("settings.json"));
  428. }
  429. Widget::step();
  430. }
  431. void RackWidget::draw(NVGcontext *vg) {
  432. Widget::draw(vg);
  433. }
  434. void RackWidget::onMouseMove(EventMouseMove &e) {
  435. OpaqueWidget::onMouseMove(e);
  436. lastMousePos = e.pos;
  437. }
  438. void RackWidget::onMouseDown(EventMouseDown &e) {
  439. Widget::onMouseDown(e);
  440. if (e.consumed)
  441. return;
  442. if (e.button == 1) {
  443. appModuleBrowserCreate();
  444. }
  445. e.consumed = true;
  446. e.target = this;
  447. }
  448. void RackWidget::onZoom(EventZoom &e) {
  449. rails->box.size = Vec();
  450. Widget::onZoom(e);
  451. }
  452. } // namespace rack