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.

410 lines
11KB

  1. #include "app.hpp"
  2. #include "engine.hpp"
  3. #include "plugin.hpp"
  4. #include "gui.hpp"
  5. #include "settings.hpp"
  6. #include "asset.hpp"
  7. #include <map>
  8. #include <algorithm>
  9. #include "../ext/osdialog/osdialog.h"
  10. namespace rack {
  11. RackWidget::RackWidget() {
  12. rails = new FramebufferWidget();
  13. rails->box.size = Vec();
  14. rails->oversample = 1.0;
  15. {
  16. RackRail *rail = new RackRail();
  17. rail->box.size = Vec();
  18. rails->addChild(rail);
  19. }
  20. addChild(rails);
  21. moduleContainer = new Widget();
  22. addChild(moduleContainer);
  23. wireContainer = new WireContainer();
  24. addChild(wireContainer);
  25. }
  26. RackWidget::~RackWidget() {
  27. }
  28. void RackWidget::clear() {
  29. wireContainer->activeWire = NULL;
  30. wireContainer->clearChildren();
  31. moduleContainer->clearChildren();
  32. lastPath = "";
  33. }
  34. void RackWidget::reset() {
  35. if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "Clear your patch and start over?")) {
  36. clear();
  37. loadPatch(assetLocal("template.vcv"));
  38. }
  39. }
  40. void RackWidget::openDialog() {
  41. std::string dir = lastPath.empty() ? assetLocal("") : extractDirectory(lastPath);
  42. char *path = osdialog_file(OSDIALOG_OPEN, dir.c_str(), NULL, NULL);
  43. if (path) {
  44. loadPatch(path);
  45. lastPath = path;
  46. free(path);
  47. }
  48. }
  49. void RackWidget::saveDialog() {
  50. if (!lastPath.empty()) {
  51. savePatch(lastPath);
  52. }
  53. else {
  54. saveAsDialog();
  55. }
  56. }
  57. void RackWidget::saveAsDialog() {
  58. std::string dir = lastPath.empty() ? assetLocal("") : extractDirectory(lastPath);
  59. char *path = osdialog_file(OSDIALOG_SAVE, dir.c_str(), "Untitled.vcv", NULL);
  60. if (path) {
  61. std::string pathStr = path;
  62. free(path);
  63. std::string extension = extractExtension(pathStr);
  64. if (extension.empty()) {
  65. pathStr += ".vcv";
  66. }
  67. savePatch(pathStr);
  68. lastPath = pathStr;
  69. }
  70. }
  71. void RackWidget::savePatch(std::string path) {
  72. info("Saving patch %s", path.c_str());
  73. FILE *file = fopen(path.c_str(), "w");
  74. if (!file)
  75. return;
  76. json_t *rootJ = toJson();
  77. if (rootJ) {
  78. json_dumpf(rootJ, file, JSON_INDENT(2));
  79. json_decref(rootJ);
  80. }
  81. fclose(file);
  82. }
  83. void RackWidget::loadPatch(std::string path) {
  84. info("Loading patch %s", path.c_str());
  85. FILE *file = fopen(path.c_str(), "r");
  86. if (!file) {
  87. // Exit silently
  88. return;
  89. }
  90. json_error_t error;
  91. json_t *rootJ = json_loadf(file, 0, &error);
  92. if (rootJ) {
  93. clear();
  94. fromJson(rootJ);
  95. json_decref(rootJ);
  96. }
  97. else {
  98. std::string message = stringf("JSON parsing error at %s %d:%d %s\n", error.source, error.line, error.column, error.text);
  99. osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
  100. }
  101. fclose(file);
  102. }
  103. json_t *RackWidget::toJson() {
  104. // root
  105. json_t *rootJ = json_object();
  106. // version
  107. json_t *versionJ = json_string(gApplicationVersion.c_str());
  108. json_object_set_new(rootJ, "version", versionJ);
  109. // modules
  110. json_t *modulesJ = json_array();
  111. std::map<ModuleWidget*, int> moduleIds;
  112. int moduleId = 0;
  113. for (Widget *w : moduleContainer->children) {
  114. ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
  115. assert(moduleWidget);
  116. moduleIds[moduleWidget] = moduleId;
  117. moduleId++;
  118. // module
  119. json_t *moduleJ = moduleWidget->toJson();
  120. json_array_append_new(modulesJ, moduleJ);
  121. }
  122. json_object_set_new(rootJ, "modules", modulesJ);
  123. // wires
  124. json_t *wires = json_array();
  125. for (Widget *w : wireContainer->children) {
  126. WireWidget *wireWidget = dynamic_cast<WireWidget*>(w);
  127. assert(wireWidget);
  128. // Only serialize WireWidgets connected on both ends
  129. if (!(wireWidget->outputPort && wireWidget->inputPort))
  130. continue;
  131. // wire
  132. json_t *wire = json_object();
  133. {
  134. // Get the modules at each end of the wire
  135. ModuleWidget *outputModuleWidget = wireWidget->outputPort->getAncestorOfType<ModuleWidget>();
  136. assert(outputModuleWidget);
  137. int outputModuleId = moduleIds[outputModuleWidget];
  138. ModuleWidget *inputModuleWidget = wireWidget->inputPort->getAncestorOfType<ModuleWidget>();
  139. assert(inputModuleWidget);
  140. int inputModuleId = moduleIds[inputModuleWidget];
  141. // Get output/input ports
  142. auto outputIt = std::find(outputModuleWidget->outputs.begin(), outputModuleWidget->outputs.end(), wireWidget->outputPort);
  143. assert(outputIt != outputModuleWidget->outputs.end());
  144. int outputId = outputIt - outputModuleWidget->outputs.begin();
  145. auto inputIt = std::find(inputModuleWidget->inputs.begin(), inputModuleWidget->inputs.end(), wireWidget->inputPort);
  146. assert(inputIt != inputModuleWidget->inputs.end());
  147. int inputId = inputIt - inputModuleWidget->inputs.begin();
  148. json_object_set_new(wire, "outputModuleId", json_integer(outputModuleId));
  149. json_object_set_new(wire, "outputId", json_integer(outputId));
  150. json_object_set_new(wire, "inputModuleId", json_integer(inputModuleId));
  151. json_object_set_new(wire, "inputId", json_integer(inputId));
  152. }
  153. json_array_append_new(wires, wire);
  154. }
  155. json_object_set_new(rootJ, "wires", wires);
  156. return rootJ;
  157. }
  158. void RackWidget::fromJson(json_t *rootJ) {
  159. std::string message;
  160. // version
  161. json_t *versionJ = json_object_get(rootJ, "version");
  162. if (versionJ) {
  163. std::string version = json_string_value(versionJ);
  164. if (!version.empty() && gApplicationVersion != version)
  165. message += stringf("This patch was created with Rack %s. Saving it will convert it to a Rack %s patch.\n\n", version.c_str(), gApplicationVersion.empty() ? "dev" : gApplicationVersion.c_str());
  166. }
  167. // modules
  168. std::map<int, ModuleWidget*> moduleWidgets;
  169. json_t *modulesJ = json_object_get(rootJ, "modules");
  170. if (!modulesJ) return;
  171. size_t moduleId;
  172. json_t *moduleJ;
  173. json_array_foreach(modulesJ, moduleId, moduleJ) {
  174. json_t *pluginSlugJ = json_object_get(moduleJ, "plugin");
  175. if (!pluginSlugJ) continue;
  176. json_t *modelSlugJ = json_object_get(moduleJ, "model");
  177. if (!modelSlugJ) continue;
  178. std::string pluginSlug = json_string_value(pluginSlugJ);
  179. std::string modelSlug = json_string_value(modelSlugJ);
  180. // Search for plugin
  181. Plugin *plugin = NULL;
  182. for (Plugin *p : gPlugins) {
  183. if (p->slug == pluginSlug) {
  184. plugin = p;
  185. break;
  186. }
  187. }
  188. if (!plugin) {
  189. message += stringf("Could not find plugin \"%s\" for module \"%s\"\n", pluginSlug.c_str(), modelSlug.c_str());
  190. continue;
  191. }
  192. // Search for model
  193. Model *model = NULL;
  194. for (Model *m : plugin->models) {
  195. if (m->slug == modelSlug) {
  196. model = m;
  197. break;
  198. }
  199. }
  200. if (!model) {
  201. message += stringf("Could not find module \"%s\" in plugin \"%s\"\n", pluginSlug.c_str(), modelSlug.c_str());
  202. continue;
  203. }
  204. // Create ModuleWidget
  205. ModuleWidget *moduleWidget = model->createModuleWidget();
  206. assert(moduleWidget);
  207. moduleWidget->fromJson(moduleJ);
  208. moduleContainer->addChild(moduleWidget);
  209. moduleWidgets[moduleId] = moduleWidget;
  210. }
  211. // wires
  212. json_t *wiresJ = json_object_get(rootJ, "wires");
  213. if (!wiresJ) return;
  214. size_t wireId;
  215. json_t *wireJ;
  216. json_array_foreach(wiresJ, wireId, wireJ) {
  217. int outputModuleId, outputId;
  218. int inputModuleId, inputId;
  219. int err = json_unpack(wireJ, "{s:i, s:i, s:i, s:i}",
  220. "outputModuleId", &outputModuleId, "outputId", &outputId,
  221. "inputModuleId", &inputModuleId, "inputId", &inputId);
  222. if (err) continue;
  223. // Get ports
  224. ModuleWidget *outputModuleWidget = moduleWidgets[outputModuleId];
  225. if (!outputModuleWidget) continue;
  226. Port *outputPort = outputModuleWidget->outputs[outputId];
  227. if (!outputPort) continue;
  228. ModuleWidget *inputModuleWidget = moduleWidgets[inputModuleId];
  229. if (!inputModuleWidget) continue;
  230. Port *inputPort = inputModuleWidget->inputs[inputId];
  231. if (!inputPort) continue;
  232. // Create WireWidget
  233. WireWidget *wireWidget = new WireWidget();
  234. wireWidget->outputPort = outputPort;
  235. wireWidget->inputPort = inputPort;
  236. wireWidget->updateWire();
  237. // Add wire to rack
  238. wireContainer->addChild(wireWidget);
  239. }
  240. // Display a message if we have something to say
  241. if (!message.empty()) {
  242. osdialog_message(OSDIALOG_INFO, OSDIALOG_OK, message.c_str());
  243. }
  244. }
  245. void RackWidget::addModule(ModuleWidget *m) {
  246. moduleContainer->addChild(m);
  247. }
  248. void RackWidget::deleteModule(ModuleWidget *m) {
  249. moduleContainer->removeChild(m);
  250. }
  251. void RackWidget::cloneModule(ModuleWidget *m) {
  252. // Create new module from model
  253. ModuleWidget *clonedModuleWidget = m->model->createModuleWidget();
  254. // JSON serialization is the most straightforward way to do this
  255. json_t *moduleJ = m->toJson();
  256. clonedModuleWidget->fromJson(moduleJ);
  257. json_decref(moduleJ);
  258. Rect clonedBox = clonedModuleWidget->box;
  259. clonedBox.pos = m->box.pos;
  260. requestModuleBoxNearest(clonedModuleWidget, clonedBox);
  261. addModule(clonedModuleWidget);
  262. }
  263. bool RackWidget::requestModuleBox(ModuleWidget *m, Rect box) {
  264. if (box.pos.x < 0 || box.pos.y < 0)
  265. return false;
  266. for (Widget *child2 : moduleContainer->children) {
  267. if (m == child2) continue;
  268. if (box.intersects(child2->box)) {
  269. return false;
  270. }
  271. }
  272. m->box = box;
  273. return true;
  274. }
  275. bool RackWidget::requestModuleBoxNearest(ModuleWidget *m, Rect box) {
  276. // Create possible positions
  277. int x0 = roundf(box.pos.x / RACK_GRID_WIDTH);
  278. int y0 = roundf(box.pos.y / RACK_GRID_HEIGHT);
  279. std::vector<Vec> positions;
  280. for (int y = maxi(0, y0 - 4); y < y0 + 4; y++) {
  281. for (int x = maxi(0, x0 - 200); x < x0 + 200; x++) {
  282. positions.push_back(Vec(x * RACK_GRID_WIDTH, y * RACK_GRID_HEIGHT));
  283. }
  284. }
  285. // Sort possible positions by distance to the requested position
  286. std::sort(positions.begin(), positions.end(), [box](Vec a, Vec b) {
  287. return a.minus(box.pos).norm() < b.minus(box.pos).norm();
  288. });
  289. // Find a position that does not collide
  290. for (Vec position : positions) {
  291. Rect newBox = box;
  292. newBox.pos = position;
  293. if (requestModuleBox(m, newBox))
  294. return true;
  295. }
  296. return false;
  297. }
  298. void RackWidget::step() {
  299. // Expand size to fit modules
  300. Vec moduleSize = moduleContainer->getChildrenBoundingBox().getBottomRight();
  301. // We assume that the size is reset by a parent before calling step(). Otherwise it will grow unbounded.
  302. box.size = box.size.max(moduleSize);
  303. // Adjust size and position of rails
  304. Widget *rail = rails->children.front();
  305. Rect bound = getViewport(Rect(Vec(), box.size));
  306. if (!rails->box.contains(bound)) {
  307. Vec cellMargin = Vec(20, 1);
  308. rails->box.pos = bound.pos.div(RACK_GRID_SIZE).floor().minus(cellMargin).mult(RACK_GRID_SIZE);
  309. rails->box.size = bound.size.plus(cellMargin.mult(RACK_GRID_SIZE).mult(2));
  310. rails->dirty = true;
  311. rail->box.size = rails->box.size;
  312. }
  313. // Autosave every 15 seconds
  314. if (gGuiFrame % (60 * 15) == 0) {
  315. savePatch(assetLocal("autosave.vcv"));
  316. settingsSave(assetLocal("settings.json"));
  317. }
  318. Widget::step();
  319. }
  320. void RackWidget::draw(NVGcontext *vg) {
  321. Widget::draw(vg);
  322. }
  323. void RackWidget::onMouseMove(EventMouseMove &e) {
  324. OpaqueWidget::onMouseMove(e);
  325. lastMousePos = e.pos;
  326. }
  327. void RackWidget::onMouseDown(EventMouseDown &e) {
  328. Widget::onMouseDown(e);
  329. if (e.consumed)
  330. return;
  331. if (e.button == 1) {
  332. MenuOverlay *overlay = new MenuOverlay();
  333. AddModuleWindow *window = new AddModuleWindow();
  334. // Set center position
  335. window->box.pos = gMousePos.minus(window->box.getCenter());
  336. window->modulePos = lastMousePos;
  337. overlay->addChild(window);
  338. gScene->setOverlay(overlay);
  339. }
  340. e.consumed = true;
  341. e.target = this;
  342. }
  343. void RackWidget::onZoom(EventZoom &e) {
  344. rails->box.size = Vec();
  345. Widget::onZoom(e);
  346. }
  347. } // namespace rack