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.

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