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.

323 lines
9.0KB

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