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.

363 lines
8.4KB

  1. #include "app.hpp"
  2. #include "engine.hpp"
  3. #include "plugin.hpp"
  4. #include "window.hpp"
  5. namespace rack {
  6. ModuleWidget::ModuleWidget(Module *module) {
  7. if (module) {
  8. engineAddModule(module);
  9. }
  10. this->module = module;
  11. }
  12. ModuleWidget::~ModuleWidget() {
  13. // Make sure WireWidget destructors are called *before* removing `module` from the rack.
  14. disconnect();
  15. // Remove and delete the Module instance
  16. if (module) {
  17. engineRemoveModule(module);
  18. delete module;
  19. module = NULL;
  20. }
  21. }
  22. void ModuleWidget::addInput(Port *input) {
  23. assert(input->type == Port::INPUT);
  24. inputs.push_back(input);
  25. addChild(input);
  26. }
  27. void ModuleWidget::addOutput(Port *output) {
  28. assert(output->type == Port::OUTPUT);
  29. outputs.push_back(output);
  30. addChild(output);
  31. }
  32. void ModuleWidget::addParam(ParamWidget *param) {
  33. params.push_back(param);
  34. addChild(param);
  35. }
  36. void ModuleWidget::setPanel(std::shared_ptr<SVG> svg) {
  37. // Remove old panel
  38. if (panel) {
  39. removeChild(panel);
  40. panel = NULL;
  41. }
  42. panel = new SVGPanel();
  43. panel->setBackground(svg);
  44. addChild(panel);
  45. box.size = panel->box.size;
  46. }
  47. json_t *ModuleWidget::toJson() {
  48. json_t *rootJ = json_object();
  49. // plugin
  50. json_object_set_new(rootJ, "plugin", json_string(model->plugin->slug.c_str()));
  51. // version (of plugin)
  52. if (!model->plugin->version.empty())
  53. json_object_set_new(rootJ, "version", json_string(model->plugin->version.c_str()));
  54. // model
  55. json_object_set_new(rootJ, "model", json_string(model->slug.c_str()));
  56. // pos
  57. Vec pos = box.pos.div(RACK_GRID_SIZE).round();
  58. json_t *posJ = json_pack("[i, i]", (int) pos.x, (int) pos.y);
  59. json_object_set_new(rootJ, "pos", posJ);
  60. // params
  61. json_t *paramsJ = json_array();
  62. for (ParamWidget *paramWidget : params) {
  63. json_t *paramJ = paramWidget->toJson();
  64. json_array_append_new(paramsJ, paramJ);
  65. }
  66. json_object_set_new(rootJ, "params", paramsJ);
  67. // data
  68. if (module) {
  69. json_t *dataJ = module->toJson();
  70. if (dataJ) {
  71. json_object_set_new(rootJ, "data", dataJ);
  72. }
  73. }
  74. return rootJ;
  75. }
  76. void ModuleWidget::fromJson(json_t *rootJ) {
  77. // legacy
  78. int legacy = 0;
  79. json_t *legacyJ = json_object_get(rootJ, "legacy");
  80. if (legacyJ)
  81. legacy = json_integer_value(legacyJ);
  82. // pos
  83. json_t *posJ = json_object_get(rootJ, "pos");
  84. double x, y;
  85. json_unpack(posJ, "[F, F]", &x, &y);
  86. Vec pos = Vec(x, y);
  87. if (legacy && legacy <= 1) {
  88. box.pos = pos;
  89. }
  90. else {
  91. box.pos = pos.mult(RACK_GRID_SIZE);
  92. }
  93. // params
  94. json_t *paramsJ = json_object_get(rootJ, "params");
  95. size_t i;
  96. json_t *paramJ;
  97. json_array_foreach(paramsJ, i, paramJ) {
  98. if (legacy && legacy <= 1) {
  99. // The index in the array we're iterating is the index of the ParamWidget in the params vector.
  100. if (i < params.size()) {
  101. // Create upgraded version of param JSON object
  102. json_t *newParamJ = json_object();
  103. json_object_set(newParamJ, "value", paramJ);
  104. params[i]->fromJson(newParamJ);
  105. json_decref(newParamJ);
  106. }
  107. }
  108. else {
  109. // Get paramId
  110. json_t *paramIdJ = json_object_get(paramJ, "paramId");
  111. if (!paramIdJ)
  112. continue;
  113. int paramId = json_integer_value(paramIdJ);
  114. // Find ParamWidget(s) with paramId
  115. for (ParamWidget *paramWidget : params) {
  116. if (paramWidget->paramId == paramId)
  117. paramWidget->fromJson(paramJ);
  118. }
  119. }
  120. }
  121. // data
  122. json_t *dataJ = json_object_get(rootJ, "data");
  123. if (dataJ && module) {
  124. module->fromJson(dataJ);
  125. }
  126. }
  127. void ModuleWidget::disconnect() {
  128. for (Port *input : inputs) {
  129. gRackWidget->wireContainer->removeAllWires(input);
  130. }
  131. for (Port *output : outputs) {
  132. gRackWidget->wireContainer->removeAllWires(output);
  133. }
  134. }
  135. void ModuleWidget::create() {
  136. if (module) {
  137. module->onCreate();
  138. }
  139. }
  140. void ModuleWidget::_delete() {
  141. if (module) {
  142. module->onDelete();
  143. }
  144. }
  145. void ModuleWidget::reset() {
  146. for (ParamWidget *param : params) {
  147. param->reset();
  148. }
  149. if (module) {
  150. module->onReset();
  151. }
  152. }
  153. void ModuleWidget::randomize() {
  154. for (ParamWidget *param : params) {
  155. param->randomize();
  156. }
  157. if (module) {
  158. module->onRandomize();
  159. }
  160. }
  161. void ModuleWidget::draw(NVGcontext *vg) {
  162. nvgScissor(vg, 0, 0, box.size.x, box.size.y);
  163. Widget::draw(vg);
  164. nvgResetScissor(vg);
  165. }
  166. void ModuleWidget::drawShadow(NVGcontext *vg) {
  167. nvgBeginPath(vg);
  168. float r = 20; // Blur radius
  169. float c = 20; // Corner radius
  170. Vec b = Vec(-10, 30); // Offset from each corner
  171. nvgRect(vg, b.x - r, b.y - r, box.size.x - 2*b.x + 2*r, box.size.y - 2*b.y + 2*r);
  172. NVGcolor shadowColor = nvgRGBAf(0, 0, 0, 0.2);
  173. NVGcolor transparentColor = nvgRGBAf(0, 0, 0, 0);
  174. nvgFillPaint(vg, nvgBoxGradient(vg, b.x, b.y, box.size.x - 2*b.x, box.size.y - 2*b.y, c, r, shadowColor, transparentColor));
  175. nvgFill(vg);
  176. }
  177. void ModuleWidget::onMouseDown(EventMouseDown &e) {
  178. Widget::onMouseDown(e);
  179. if (e.consumed)
  180. return;
  181. if (e.button == 1) {
  182. createContextMenu();
  183. }
  184. e.consumed = true;
  185. e.target = this;
  186. }
  187. void ModuleWidget::onMouseMove(EventMouseMove &e) {
  188. OpaqueWidget::onMouseMove(e);
  189. // Don't delete the ModuleWidget if a TextField is focused
  190. if (!gFocusedWidget) {
  191. // Instead of checking key-down events, delete the module even if key-repeat hasn't fired yet and the cursor is hovering over the widget.
  192. if (glfwGetKey(gWindow, GLFW_KEY_DELETE) == GLFW_PRESS || glfwGetKey(gWindow, GLFW_KEY_BACKSPACE) == GLFW_PRESS) {
  193. if (!windowIsModPressed() && !windowIsShiftPressed()) {
  194. gRackWidget->deleteModule(this);
  195. this->finalizeEvents();
  196. delete this;
  197. e.consumed = true;
  198. return;
  199. }
  200. }
  201. }
  202. }
  203. void ModuleWidget::onHoverKey(EventHoverKey &e) {
  204. switch (e.key) {
  205. case GLFW_KEY_I: {
  206. if (windowIsModPressed() && !windowIsShiftPressed()) {
  207. reset();
  208. e.consumed = true;
  209. return;
  210. }
  211. } break;
  212. case GLFW_KEY_R: {
  213. if (windowIsModPressed() && !windowIsShiftPressed()) {
  214. randomize();
  215. e.consumed = true;
  216. return;
  217. }
  218. } break;
  219. case GLFW_KEY_D: {
  220. if (windowIsModPressed() && !windowIsShiftPressed()) {
  221. gRackWidget->cloneModule(this);
  222. e.consumed = true;
  223. return;
  224. }
  225. } break;
  226. case GLFW_KEY_U: {
  227. if (windowIsModPressed() && !windowIsShiftPressed()) {
  228. disconnect();
  229. e.consumed = true;
  230. return;
  231. }
  232. } break;
  233. }
  234. Widget::onHoverKey(e);
  235. }
  236. void ModuleWidget::onDragStart(EventDragStart &e) {
  237. dragPos = gRackWidget->lastMousePos.minus(box.pos);
  238. }
  239. void ModuleWidget::onDragEnd(EventDragEnd &e) {
  240. }
  241. void ModuleWidget::onDragMove(EventDragMove &e) {
  242. Rect newBox = box;
  243. newBox.pos = gRackWidget->lastMousePos.minus(dragPos);
  244. gRackWidget->requestModuleBoxNearest(this, newBox);
  245. }
  246. struct DisconnectMenuItem : MenuItem {
  247. ModuleWidget *moduleWidget;
  248. void onAction(EventAction &e) override {
  249. moduleWidget->disconnect();
  250. }
  251. };
  252. struct ResetMenuItem : MenuItem {
  253. ModuleWidget *moduleWidget;
  254. void onAction(EventAction &e) override {
  255. moduleWidget->reset();
  256. }
  257. };
  258. struct RandomizeMenuItem : MenuItem {
  259. ModuleWidget *moduleWidget;
  260. void onAction(EventAction &e) override {
  261. moduleWidget->randomize();
  262. }
  263. };
  264. struct CloneMenuItem : MenuItem {
  265. ModuleWidget *moduleWidget;
  266. void onAction(EventAction &e) override {
  267. gRackWidget->cloneModule(moduleWidget);
  268. }
  269. };
  270. struct DeleteMenuItem : MenuItem {
  271. ModuleWidget *moduleWidget;
  272. void onAction(EventAction &e) override {
  273. gRackWidget->deleteModule(moduleWidget);
  274. moduleWidget->finalizeEvents();
  275. delete moduleWidget;
  276. }
  277. };
  278. Menu *ModuleWidget::createContextMenu() {
  279. Menu *menu = gScene->createMenu();
  280. MenuLabel *menuLabel = new MenuLabel();
  281. menuLabel->text = model->manufacturer + " " + model->name;
  282. menu->addChild(menuLabel);
  283. ResetMenuItem *resetItem = new ResetMenuItem();
  284. resetItem->text = "Initialize";
  285. resetItem->rightText = WINDOW_MOD_KEY_NAME "+I";
  286. resetItem->moduleWidget = this;
  287. menu->addChild(resetItem);
  288. RandomizeMenuItem *randomizeItem = new RandomizeMenuItem();
  289. randomizeItem->text = "Randomize";
  290. randomizeItem->rightText = WINDOW_MOD_KEY_NAME "+R";
  291. randomizeItem->moduleWidget = this;
  292. menu->addChild(randomizeItem);
  293. DisconnectMenuItem *disconnectItem = new DisconnectMenuItem();
  294. disconnectItem->text = "Disconnect cables";
  295. disconnectItem->rightText = WINDOW_MOD_KEY_NAME "+U";
  296. disconnectItem->moduleWidget = this;
  297. menu->addChild(disconnectItem);
  298. CloneMenuItem *cloneItem = new CloneMenuItem();
  299. cloneItem->text = "Duplicate";
  300. cloneItem->rightText = WINDOW_MOD_KEY_NAME "+D";
  301. cloneItem->moduleWidget = this;
  302. menu->addChild(cloneItem);
  303. DeleteMenuItem *deleteItem = new DeleteMenuItem();
  304. deleteItem->text = "Delete";
  305. deleteItem->rightText = "Backspace/Delete";
  306. deleteItem->moduleWidget = this;
  307. menu->addChild(deleteItem);
  308. appendContextMenu(menu);
  309. return menu;
  310. }
  311. } // namespace rack