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.

349 lines
9.8KB

  1. #include <map>
  2. #include <algorithm>
  3. #include "app.hpp"
  4. #include "engine.hpp"
  5. #include "plugin.hpp"
  6. #include "gui.hpp"
  7. namespace rack {
  8. RackWidget::RackWidget() {
  9. moduleContainer = new Widget();
  10. addChild(moduleContainer);
  11. wireContainer = new TransparentWidget();
  12. addChild(wireContainer);
  13. railsImage = Image::load("res/rails.png");
  14. }
  15. RackWidget::~RackWidget() {
  16. }
  17. void RackWidget::clear() {
  18. activeWire = NULL;
  19. wireContainer->clearChildren();
  20. moduleContainer->clearChildren();
  21. }
  22. void RackWidget::savePatch(std::string filename) {
  23. printf("Saving patch %s\n", filename.c_str());
  24. FILE *file = fopen(filename.c_str(), "w");
  25. if (!file)
  26. return;
  27. json_t *root = toJson();
  28. if (root) {
  29. json_dumpf(root, file, JSON_INDENT(2));
  30. json_decref(root);
  31. }
  32. fclose(file);
  33. }
  34. void RackWidget::loadPatch(std::string filename) {
  35. printf("Loading patch %s\n", filename.c_str());
  36. FILE *file = fopen(filename.c_str(), "r");
  37. if (!file)
  38. return;
  39. json_error_t error;
  40. json_t *root = json_loadf(file, 0, &error);
  41. if (root) {
  42. clear();
  43. fromJson(root);
  44. json_decref(root);
  45. }
  46. else {
  47. printf("JSON parsing error at %s %d:%d %s\n", error.source, error.line, error.column, error.text);
  48. }
  49. fclose(file);
  50. }
  51. json_t *RackWidget::toJson() {
  52. // root
  53. json_t *root = json_object();
  54. // version
  55. json_t *versionJ = json_string(gApplicationVersion.c_str());
  56. json_object_set_new(root, "version", versionJ);
  57. // wireOpacity
  58. json_t *wireOpacityJ = json_real(dynamic_cast<RackScene*>(gScene)->toolbar->wireOpacitySlider->value);
  59. json_object_set_new(root, "wireOpacity", wireOpacityJ);
  60. // wireTension
  61. json_t *wireTensionJ = json_real(dynamic_cast<RackScene*>(gScene)->toolbar->wireTensionSlider->value);
  62. json_object_set_new(root, "wireTension", wireTensionJ);
  63. // modules
  64. json_t *modulesJ = json_array();
  65. std::map<ModuleWidget*, int> moduleIds;
  66. int moduleId = 0;
  67. for (Widget *w : moduleContainer->children) {
  68. ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
  69. assert(moduleWidget);
  70. moduleIds[moduleWidget] = moduleId;
  71. moduleId++;
  72. // module
  73. json_t *moduleJ = moduleWidget->toJson();
  74. json_array_append_new(modulesJ, moduleJ);
  75. }
  76. json_object_set_new(root, "modules", modulesJ);
  77. // wires
  78. json_t *wires = json_array();
  79. for (Widget *w : wireContainer->children) {
  80. WireWidget *wireWidget = dynamic_cast<WireWidget*>(w);
  81. assert(wireWidget);
  82. // Only serialize WireWidgets connected on both ends
  83. if (!(wireWidget->outputPort && wireWidget->inputPort))
  84. continue;
  85. // wire
  86. json_t *wire = json_object();
  87. {
  88. // Get the modules at each end of the wire
  89. ModuleWidget *outputModuleWidget = wireWidget->outputPort->getAncestorOfType<ModuleWidget>();
  90. assert(outputModuleWidget);
  91. int outputModuleId = moduleIds[outputModuleWidget];
  92. ModuleWidget *inputModuleWidget = wireWidget->inputPort->getAncestorOfType<ModuleWidget>();
  93. assert(inputModuleWidget);
  94. int inputModuleId = moduleIds[inputModuleWidget];
  95. // Get output/input ports
  96. auto outputIt = std::find(outputModuleWidget->outputs.begin(), outputModuleWidget->outputs.end(), wireWidget->outputPort);
  97. assert(outputIt != outputModuleWidget->outputs.end());
  98. int outputId = outputIt - outputModuleWidget->outputs.begin();
  99. auto inputIt = std::find(inputModuleWidget->inputs.begin(), inputModuleWidget->inputs.end(), wireWidget->inputPort);
  100. assert(inputIt != inputModuleWidget->inputs.end());
  101. int inputId = inputIt - inputModuleWidget->inputs.begin();
  102. json_object_set_new(wire, "outputModuleId", json_integer(outputModuleId));
  103. json_object_set_new(wire, "outputId", json_integer(outputId));
  104. json_object_set_new(wire, "inputModuleId", json_integer(inputModuleId));
  105. json_object_set_new(wire, "inputId", json_integer(inputId));
  106. }
  107. json_array_append_new(wires, wire);
  108. }
  109. json_object_set_new(root, "wires", wires);
  110. return root;
  111. }
  112. void RackWidget::fromJson(json_t *root) {
  113. // version
  114. json_t *versionJ = json_object_get(root, "version");
  115. if (versionJ) {
  116. const char *version = json_string_value(versionJ);
  117. if (gApplicationVersion != version)
  118. printf("JSON version mismatch, attempting to convert JSON version %s to %s\n", version, gApplicationVersion.c_str());
  119. }
  120. // wireOpacity
  121. json_t *wireOpacityJ = json_object_get(root, "wireOpacity");
  122. if (wireOpacityJ)
  123. dynamic_cast<RackScene*>(gScene)->toolbar->wireOpacitySlider->value = json_number_value(wireOpacityJ);
  124. // wireTension
  125. json_t *wireTensionJ = json_object_get(root, "wireTension");
  126. if (wireTensionJ)
  127. dynamic_cast<RackScene*>(gScene)->toolbar->wireTensionSlider->value = json_number_value(wireTensionJ);
  128. // modules
  129. std::map<int, ModuleWidget*> moduleWidgets;
  130. json_t *modulesJ = json_object_get(root, "modules");
  131. if (!modulesJ) return;
  132. size_t moduleId;
  133. json_t *moduleJ;
  134. json_array_foreach(modulesJ, moduleId, moduleJ) {
  135. // Get plugin
  136. json_t *pluginSlugJ = json_object_get(moduleJ, "plugin");
  137. if (!pluginSlugJ) continue;
  138. const char *pluginSlug = json_string_value(pluginSlugJ);
  139. Plugin *plugin = NULL;
  140. for (Plugin *p : gPlugins) {
  141. if (p->slug == pluginSlug) {
  142. plugin = p;
  143. break;
  144. }
  145. }
  146. if (!plugin) continue;
  147. // Get model
  148. json_t *modelSlug = json_object_get(moduleJ, "model");
  149. Model *model = NULL;
  150. for (Model *m : plugin->models) {
  151. if (m->slug == json_string_value(modelSlug)) {
  152. model = m;
  153. break;
  154. }
  155. }
  156. if (!model) continue;
  157. // Create ModuleWidget
  158. ModuleWidget *moduleWidget = model->createModuleWidget();
  159. assert(moduleWidget);
  160. moduleWidget->fromJson(moduleJ);
  161. moduleContainer->addChild(moduleWidget);
  162. moduleWidgets[moduleId] = moduleWidget;
  163. }
  164. // wires
  165. json_t *wiresJ = json_object_get(root, "wires");
  166. if (!wiresJ) return;
  167. size_t wireId;
  168. json_t *wireJ;
  169. json_array_foreach(wiresJ, wireId, wireJ) {
  170. int outputModuleId, outputId;
  171. int inputModuleId, inputId;
  172. int err = json_unpack(wireJ, "{s:i, s:i, s:i, s:i}",
  173. "outputModuleId", &outputModuleId, "outputId", &outputId,
  174. "inputModuleId", &inputModuleId, "inputId", &inputId);
  175. if (err) continue;
  176. // Get ports
  177. ModuleWidget *outputModuleWidget = moduleWidgets[outputModuleId];
  178. if (!outputModuleWidget) continue;
  179. Port *outputPort = outputModuleWidget->outputs[outputId];
  180. if (!outputPort) continue;
  181. ModuleWidget *inputModuleWidget = moduleWidgets[inputModuleId];
  182. if (!inputModuleWidget) continue;
  183. Port *inputPort = inputModuleWidget->inputs[inputId];
  184. if (!inputPort) continue;
  185. // Create WireWidget
  186. WireWidget *wireWidget = new WireWidget();
  187. wireWidget->outputPort = outputPort;
  188. wireWidget->inputPort = inputPort;
  189. outputPort->connectedWire = wireWidget;
  190. inputPort->connectedWire = wireWidget;
  191. wireWidget->updateWire();
  192. // Add wire to rack
  193. wireContainer->addChild(wireWidget);
  194. }
  195. }
  196. void RackWidget::repositionModule(ModuleWidget *module) {
  197. // Create possible positions
  198. int x0 = roundf(module->requestedPos.x / 15);
  199. int y0 = roundf(module->requestedPos.y / 380);
  200. std::vector<Vec> positions;
  201. for (int y = maxi(0, y0 - 2); y < y0 + 2; y++) {
  202. for (int x = maxi(0, x0 - 40); x < x0 + 40; x++) {
  203. positions.push_back(Vec(x*15, y*380));
  204. }
  205. }
  206. // Sort possible positions by distance to the requested position
  207. Vec requestedPos = module->requestedPos;
  208. std::sort(positions.begin(), positions.end(), [requestedPos](Vec a, Vec b) {
  209. return a.minus(requestedPos).norm() < b.minus(requestedPos).norm();
  210. });
  211. // Find a position that does not collide
  212. for (Vec pos : positions) {
  213. Rect newBox = Rect(pos, module->box.size);
  214. bool collides = false;
  215. for (Widget *child2 : moduleContainer->children) {
  216. if (module == child2) continue;
  217. if (newBox.intersects(child2->box)) {
  218. collides = true;
  219. break;
  220. }
  221. }
  222. if (collides) continue;
  223. module->box.pos = pos;
  224. break;
  225. }
  226. }
  227. void RackWidget::step() {
  228. // Resize to be a bit larger than the ScrollWidget viewport
  229. assert(parent);
  230. assert(parent->parent);
  231. Vec moduleSize = moduleContainer->getChildrenBoundingBox().getBottomRight();
  232. Vec viewportSize = parent->parent->box.size.minus(parent->box.pos);
  233. box.size = moduleSize.max(viewportSize).plus(Vec(500, 500));
  234. // Reposition modules
  235. for (Widget *child : moduleContainer->children) {
  236. ModuleWidget *module = dynamic_cast<ModuleWidget*>(child);
  237. assert(module);
  238. if (module->requested) {
  239. repositionModule(module);
  240. module->requested = false;
  241. }
  242. }
  243. // Autosave every 15 seconds
  244. // (This is alpha software, expect crashes!)
  245. if (gGuiFrame % (60*15) == 0) {
  246. savePatch("autosave.json");
  247. }
  248. Widget::step();
  249. }
  250. void RackWidget::draw(NVGcontext *vg) {
  251. nvgBeginPath(vg);
  252. nvgRect(vg, 0.0, 0.0, box.size.x, box.size.y);
  253. // Background color
  254. nvgFillColor(vg, nvgRGBf(0.2, 0.2, 0.2));
  255. nvgFill(vg);
  256. // Rails image
  257. {
  258. int imageWidth, imageHeight;
  259. nvgImageSize(vg, railsImage->handle, &imageWidth, &imageHeight);
  260. NVGpaint paint = nvgImagePattern(vg, 0.0, 0.0, imageWidth, imageHeight, 0.0, railsImage->handle, 1.0);
  261. nvgFillPaint(vg, paint);
  262. nvgFill(vg);
  263. }
  264. Widget::draw(vg);
  265. }
  266. struct AddModuleMenuItem : MenuItem {
  267. Model *model;
  268. Vec modulePos;
  269. void onAction() {
  270. ModuleWidget *moduleWidget = model->createModuleWidget();
  271. moduleWidget->requestedPos = modulePos.minus(moduleWidget->box.getCenter());
  272. moduleWidget->requested = true;
  273. gRackWidget->moduleContainer->addChild(moduleWidget);
  274. }
  275. };
  276. void RackWidget::onMouseDown(int button) {
  277. if (button == 1) {
  278. // Get relative position of the click
  279. Vec modulePos = gMousePos.minus(getAbsolutePos());
  280. MenuOverlay *overlay = new MenuOverlay();
  281. Menu *menu = new Menu();
  282. menu->box.pos = gMousePos;
  283. MenuLabel *menuLabel = new MenuLabel();
  284. menuLabel->text = "Add Module";
  285. menu->pushChild(menuLabel);
  286. for (Plugin *plugin : gPlugins) {
  287. for (Model *model : plugin->models) {
  288. AddModuleMenuItem *item = new AddModuleMenuItem();
  289. item->text = model->plugin->name + ": " + model->name;
  290. item->model = model;
  291. item->modulePos = modulePos;
  292. menu->pushChild(item);
  293. }
  294. }
  295. overlay->addChild(menu);
  296. gScene->setOverlay(overlay);
  297. }
  298. }
  299. } // namespace rack