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.

467 lines
12KB

  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. loadPatch(assetLocal("template.vcv"));
  54. lastPath = "";
  55. }
  56. }
  57. void RackWidget::openDialog() {
  58. std::string dir;
  59. if (lastPath.empty()) {
  60. dir = assetLocal("patches");
  61. systemCreateDirectory(dir);
  62. }
  63. else {
  64. dir = stringDirectory(lastPath);
  65. }
  66. char *path = osdialog_file(OSDIALOG_OPEN, dir.c_str(), NULL, NULL);
  67. if (path) {
  68. loadPatch(path);
  69. lastPath = path;
  70. free(path);
  71. }
  72. }
  73. void RackWidget::saveDialog() {
  74. if (!lastPath.empty()) {
  75. savePatch(lastPath);
  76. }
  77. else {
  78. saveAsDialog();
  79. }
  80. }
  81. void RackWidget::saveAsDialog() {
  82. std::string dir;
  83. if (lastPath.empty()) {
  84. dir = assetLocal("patches");
  85. systemCreateDirectory(dir);
  86. }
  87. else {
  88. dir = stringDirectory(lastPath);
  89. }
  90. char *path = osdialog_file(OSDIALOG_SAVE, dir.c_str(), "Untitled.vcv", NULL);
  91. if (path) {
  92. std::string pathStr = path;
  93. free(path);
  94. std::string extension = stringExtension(pathStr);
  95. if (extension.empty()) {
  96. pathStr += ".vcv";
  97. }
  98. savePatch(pathStr);
  99. lastPath = pathStr;
  100. }
  101. }
  102. void RackWidget::savePatch(std::string path) {
  103. info("Saving patch %s", path.c_str());
  104. json_t *rootJ = toJson();
  105. if (!rootJ)
  106. return;
  107. FILE *file = fopen(path.c_str(), "w");
  108. if (file) {
  109. json_dumpf(rootJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9));
  110. fclose(file);
  111. }
  112. json_decref(rootJ);
  113. }
  114. void RackWidget::loadPatch(std::string path) {
  115. info("Loading patch %s", path.c_str());
  116. FILE *file = fopen(path.c_str(), "r");
  117. if (!file) {
  118. // Exit silently
  119. return;
  120. }
  121. json_error_t error;
  122. json_t *rootJ = json_loadf(file, 0, &error);
  123. if (rootJ) {
  124. clear();
  125. fromJson(rootJ);
  126. json_decref(rootJ);
  127. }
  128. else {
  129. std::string message = stringf("JSON parsing error at %s %d:%d %s\n", error.source, error.line, error.column, error.text);
  130. osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
  131. }
  132. fclose(file);
  133. }
  134. void RackWidget::revert() {
  135. if (lastPath.empty())
  136. return;
  137. if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "Revert patch to the last saved state?")) {
  138. loadPatch(lastPath);
  139. }
  140. }
  141. void RackWidget::disconnect() {
  142. if (!osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK_CANCEL, "Remove all patch cables?"))
  143. return;
  144. for (Widget *w : moduleContainer->children) {
  145. ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
  146. assert(moduleWidget);
  147. moduleWidget->disconnect();
  148. }
  149. }
  150. json_t *RackWidget::toJson() {
  151. // root
  152. json_t *rootJ = json_object();
  153. // version
  154. json_t *versionJ = json_string(gApplicationVersion.c_str());
  155. json_object_set_new(rootJ, "version", versionJ);
  156. // modules
  157. json_t *modulesJ = json_array();
  158. std::map<ModuleWidget*, int> moduleIds;
  159. int moduleId = 0;
  160. for (Widget *w : moduleContainer->children) {
  161. ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
  162. assert(moduleWidget);
  163. moduleIds[moduleWidget] = moduleId;
  164. moduleId++;
  165. // module
  166. json_t *moduleJ = moduleWidget->toJson();
  167. json_array_append_new(modulesJ, moduleJ);
  168. }
  169. json_object_set_new(rootJ, "modules", modulesJ);
  170. // wires
  171. json_t *wires = json_array();
  172. for (Widget *w : wireContainer->children) {
  173. WireWidget *wireWidget = dynamic_cast<WireWidget*>(w);
  174. assert(wireWidget);
  175. // Only serialize WireWidgets connected on both ends
  176. if (!(wireWidget->outputPort && wireWidget->inputPort))
  177. continue;
  178. // wire
  179. json_t *wire = wireWidget->toJson();
  180. // Get the modules at each end of the wire
  181. ModuleWidget *outputModuleWidget = wireWidget->outputPort->getAncestorOfType<ModuleWidget>();
  182. assert(outputModuleWidget);
  183. int outputModuleId = moduleIds[outputModuleWidget];
  184. ModuleWidget *inputModuleWidget = wireWidget->inputPort->getAncestorOfType<ModuleWidget>();
  185. assert(inputModuleWidget);
  186. int inputModuleId = moduleIds[inputModuleWidget];
  187. // Get output/input ports
  188. int outputId = wireWidget->outputPort->portId;
  189. int inputId = wireWidget->inputPort->portId;
  190. json_object_set_new(wire, "outputModuleId", json_integer(outputModuleId));
  191. json_object_set_new(wire, "outputId", json_integer(outputId));
  192. json_object_set_new(wire, "inputModuleId", json_integer(inputModuleId));
  193. json_object_set_new(wire, "inputId", json_integer(inputId));
  194. json_array_append_new(wires, wire);
  195. }
  196. json_object_set_new(rootJ, "wires", wires);
  197. return rootJ;
  198. }
  199. void RackWidget::fromJson(json_t *rootJ) {
  200. std::string message;
  201. // version
  202. std::string version;
  203. json_t *versionJ = json_object_get(rootJ, "version");
  204. if (versionJ) {
  205. version = json_string_value(versionJ);
  206. }
  207. // Detect old patches with ModuleWidget::params/inputs/outputs indices.
  208. // (We now use Module::params/inputs/outputs indices.)
  209. int legacy = 0;
  210. if (stringStartsWith(version, "0.3.") || stringStartsWith(version, "0.4.") || stringStartsWith(version, "0.5.") || version == "" || version == "dev") {
  211. legacy = 1;
  212. }
  213. if (legacy) {
  214. info("Loading patch using legacy mode %d", legacy);
  215. }
  216. // modules
  217. std::map<int, ModuleWidget*> moduleWidgets;
  218. json_t *modulesJ = json_object_get(rootJ, "modules");
  219. if (!modulesJ) return;
  220. size_t moduleId;
  221. json_t *moduleJ;
  222. json_array_foreach(modulesJ, moduleId, moduleJ) {
  223. // Add "legacy" property if in legacy mode
  224. if (legacy) {
  225. json_object_set(moduleJ, "legacy", json_integer(legacy));
  226. }
  227. json_t *pluginSlugJ = json_object_get(moduleJ, "plugin");
  228. if (!pluginSlugJ) continue;
  229. json_t *modelSlugJ = json_object_get(moduleJ, "model");
  230. if (!modelSlugJ) continue;
  231. std::string pluginSlug = json_string_value(pluginSlugJ);
  232. std::string modelSlug = json_string_value(modelSlugJ);
  233. Model *model = pluginGetModel(pluginSlug, modelSlug);
  234. if (!model) {
  235. message += stringf("Could not find module \"%s\" of plugin \"%s\"\n", modelSlug.c_str(), pluginSlug.c_str());
  236. continue;
  237. }
  238. // Create ModuleWidget
  239. ModuleWidget *moduleWidget = model->createModuleWidget();
  240. assert(moduleWidget);
  241. moduleWidget->fromJson(moduleJ);
  242. moduleContainer->addChild(moduleWidget);
  243. moduleWidgets[moduleId] = moduleWidget;
  244. }
  245. // wires
  246. json_t *wiresJ = json_object_get(rootJ, "wires");
  247. if (!wiresJ) return;
  248. size_t wireId;
  249. json_t *wireJ;
  250. json_array_foreach(wiresJ, wireId, wireJ) {
  251. int outputModuleId = json_integer_value(json_object_get(wireJ, "outputModuleId"));
  252. int outputId = json_integer_value(json_object_get(wireJ, "outputId"));
  253. int inputModuleId = json_integer_value(json_object_get(wireJ, "inputModuleId"));
  254. int inputId = json_integer_value(json_object_get(wireJ, "inputId"));
  255. // Get module widgets
  256. ModuleWidget *outputModuleWidget = moduleWidgets[outputModuleId];
  257. if (!outputModuleWidget) continue;
  258. ModuleWidget *inputModuleWidget = moduleWidgets[inputModuleId];
  259. if (!inputModuleWidget) continue;
  260. // Get port widgets
  261. Port *outputPort = NULL;
  262. Port *inputPort = NULL;
  263. if (legacy && legacy <= 1) {
  264. // Legacy 1 mode
  265. // The index of the "ports" array is the index of the Port in the `outputs` and `inputs` vector.
  266. outputPort = outputModuleWidget->outputs[outputId];
  267. inputPort = inputModuleWidget->inputs[inputId];
  268. }
  269. else {
  270. for (Port *port : outputModuleWidget->outputs) {
  271. if (port->portId == outputId) {
  272. outputPort = port;
  273. break;
  274. }
  275. }
  276. for (Port *port : inputModuleWidget->inputs) {
  277. if (port->portId == inputId) {
  278. inputPort = port;
  279. break;
  280. }
  281. }
  282. }
  283. if (!outputPort || !inputPort)
  284. continue;
  285. // Create WireWidget
  286. WireWidget *wireWidget = new WireWidget();
  287. wireWidget->fromJson(wireJ);
  288. wireWidget->outputPort = outputPort;
  289. wireWidget->inputPort = inputPort;
  290. wireWidget->updateWire();
  291. // Add wire to rack
  292. wireContainer->addChild(wireWidget);
  293. }
  294. // Display a message if we have something to say
  295. if (!message.empty()) {
  296. osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
  297. }
  298. }
  299. void RackWidget::addModule(ModuleWidget *m) {
  300. moduleContainer->addChild(m);
  301. m->create();
  302. }
  303. void RackWidget::deleteModule(ModuleWidget *m) {
  304. m->_delete();
  305. moduleContainer->removeChild(m);
  306. }
  307. void RackWidget::cloneModule(ModuleWidget *m) {
  308. // Create new module from model
  309. ModuleWidget *clonedModuleWidget = m->model->createModuleWidget();
  310. // JSON serialization is the most straightforward way to do this
  311. json_t *moduleJ = m->toJson();
  312. clonedModuleWidget->fromJson(moduleJ);
  313. json_decref(moduleJ);
  314. Rect clonedBox = clonedModuleWidget->box;
  315. clonedBox.pos = m->box.pos;
  316. requestModuleBoxNearest(clonedModuleWidget, clonedBox);
  317. addModule(clonedModuleWidget);
  318. }
  319. bool RackWidget::requestModuleBox(ModuleWidget *m, Rect box) {
  320. if (box.pos.x < 0 || box.pos.y < 0)
  321. return false;
  322. for (Widget *child2 : moduleContainer->children) {
  323. if (m == child2) continue;
  324. if (box.intersects(child2->box)) {
  325. return false;
  326. }
  327. }
  328. m->box = box;
  329. return true;
  330. }
  331. bool RackWidget::requestModuleBoxNearest(ModuleWidget *m, Rect box) {
  332. // Create possible positions
  333. int x0 = roundf(box.pos.x / RACK_GRID_WIDTH);
  334. int y0 = roundf(box.pos.y / RACK_GRID_HEIGHT);
  335. std::vector<Vec> positions;
  336. for (int y = max(0, y0 - 8); y < y0 + 8; y++) {
  337. for (int x = max(0, x0 - 400); x < x0 + 400; x++) {
  338. positions.push_back(Vec(x * RACK_GRID_WIDTH, y * RACK_GRID_HEIGHT));
  339. }
  340. }
  341. // Sort possible positions by distance to the requested position
  342. std::sort(positions.begin(), positions.end(), [box](Vec a, Vec b) {
  343. return a.minus(box.pos).norm() < b.minus(box.pos).norm();
  344. });
  345. // Find a position that does not collide
  346. for (Vec position : positions) {
  347. Rect newBox = box;
  348. newBox.pos = position;
  349. if (requestModuleBox(m, newBox))
  350. return true;
  351. }
  352. return false;
  353. }
  354. void RackWidget::step() {
  355. // Expand size to fit modules
  356. Vec moduleSize = moduleContainer->getChildrenBoundingBox().getBottomRight();
  357. // We assume that the size is reset by a parent before calling step(). Otherwise it will grow unbounded.
  358. box.size = box.size.max(moduleSize);
  359. // Adjust size and position of rails
  360. Widget *rail = rails->children.front();
  361. Rect bound = getViewport(Rect(Vec(), box.size));
  362. if (!rails->box.contains(bound)) {
  363. Vec cellMargin = Vec(20, 1);
  364. rails->box.pos = bound.pos.div(RACK_GRID_SIZE).floor().minus(cellMargin).mult(RACK_GRID_SIZE);
  365. rails->box.size = bound.size.plus(cellMargin.mult(RACK_GRID_SIZE).mult(2));
  366. rails->dirty = true;
  367. rail->box.size = rails->box.size;
  368. }
  369. // Autosave every 15 seconds
  370. if (gGuiFrame % (60 * 15) == 0) {
  371. savePatch(assetLocal("autosave.vcv"));
  372. settingsSave(assetLocal("settings.json"));
  373. }
  374. Widget::step();
  375. }
  376. void RackWidget::draw(NVGcontext *vg) {
  377. Widget::draw(vg);
  378. }
  379. void RackWidget::onMouseMove(EventMouseMove &e) {
  380. OpaqueWidget::onMouseMove(e);
  381. lastMousePos = e.pos;
  382. }
  383. void RackWidget::onMouseDown(EventMouseDown &e) {
  384. Widget::onMouseDown(e);
  385. if (e.consumed)
  386. return;
  387. if (e.button == 1) {
  388. appModuleBrowserCreate();
  389. }
  390. e.consumed = true;
  391. e.target = this;
  392. }
  393. void RackWidget::onZoom(EventZoom &e) {
  394. rails->box.size = Vec();
  395. Widget::onZoom(e);
  396. }
  397. } // namespace rack