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.

357 lines
8.1KB

  1. #include "app.hpp"
  2. #include "engine.hpp"
  3. #include "plugin.hpp"
  4. #include "gui.hpp"
  5. namespace rack {
  6. ModuleWidget::~ModuleWidget() {
  7. // Make sure WireWidget destructors are called *before* removing `module` from the rack.
  8. disconnect();
  9. // Remove and delete the Module instance
  10. setModule(NULL);
  11. }
  12. void ModuleWidget::setModule(Module *module) {
  13. if (this->module) {
  14. engineRemoveModule(this->module);
  15. delete this->module;
  16. }
  17. if (module) {
  18. engineAddModule(module);
  19. }
  20. this->module = module;
  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. json_t *posJ = json_pack("[f, f]", (double) box.pos.x, (double) box.pos.y);
  58. json_object_set_new(rootJ, "pos", posJ);
  59. // params
  60. json_t *paramsJ = json_array();
  61. for (ParamWidget *paramWidget : params) {
  62. json_t *paramJ = paramWidget->toJson();
  63. json_array_append_new(paramsJ, paramJ);
  64. }
  65. json_object_set_new(rootJ, "params", paramsJ);
  66. // data
  67. if (module) {
  68. json_t *dataJ = module->toJson();
  69. if (dataJ) {
  70. json_object_set_new(rootJ, "data", dataJ);
  71. }
  72. }
  73. return rootJ;
  74. }
  75. void ModuleWidget::fromJson(json_t *rootJ) {
  76. // legacy
  77. int legacy = 0;
  78. json_t *legacyJ = json_object_get(rootJ, "legacy");
  79. if (legacyJ)
  80. legacy = json_integer_value(legacyJ);
  81. // pos
  82. json_t *posJ = json_object_get(rootJ, "pos");
  83. double x, y;
  84. json_unpack(posJ, "[F, F]", &x, &y);
  85. box.pos = Vec(x, y);
  86. // params
  87. json_t *paramsJ = json_object_get(rootJ, "params");
  88. size_t i;
  89. json_t *paramJ;
  90. json_array_foreach(paramsJ, i, paramJ) {
  91. if (legacy && legacy <= 1) {
  92. // The index in the array we're iterating is the index of the ParamWidget in the params vector.
  93. if (i < params.size()) {
  94. // Create upgraded version of param JSON object
  95. json_t *newParamJ = json_object();
  96. json_object_set(newParamJ, "value", paramJ);
  97. params[i]->fromJson(newParamJ);
  98. json_decref(newParamJ);
  99. }
  100. }
  101. else {
  102. // Get paramId
  103. json_t *paramIdJ = json_object_get(paramJ, "paramId");
  104. if (!paramIdJ)
  105. continue;
  106. int paramId = json_integer_value(paramIdJ);
  107. // Find ParamWidget(s) with paramId
  108. for (ParamWidget *paramWidget : params) {
  109. if (paramWidget->paramId == paramId)
  110. paramWidget->fromJson(paramJ);
  111. }
  112. }
  113. }
  114. // data
  115. json_t *dataJ = json_object_get(rootJ, "data");
  116. if (dataJ && module) {
  117. module->fromJson(dataJ);
  118. }
  119. }
  120. void ModuleWidget::disconnect() {
  121. for (Port *input : inputs) {
  122. gRackWidget->wireContainer->removeAllWires(input);
  123. }
  124. for (Port *output : outputs) {
  125. gRackWidget->wireContainer->removeAllWires(output);
  126. }
  127. }
  128. void ModuleWidget::create() {
  129. if (module) {
  130. module->onCreate();
  131. }
  132. }
  133. void ModuleWidget::_delete() {
  134. if (module) {
  135. module->onDelete();
  136. }
  137. }
  138. void ModuleWidget::reset() {
  139. for (ParamWidget *param : params) {
  140. param->setValue(param->defaultValue);
  141. }
  142. if (module) {
  143. module->onReset();
  144. }
  145. }
  146. void ModuleWidget::randomize() {
  147. for (ParamWidget *param : params) {
  148. param->randomize();
  149. }
  150. if (module) {
  151. module->onRandomize();
  152. }
  153. }
  154. void ModuleWidget::draw(NVGcontext *vg) {
  155. nvgScissor(vg, 0, 0, box.size.x, box.size.y);
  156. Widget::draw(vg);
  157. // CPU usage text
  158. if (0) {
  159. float cpuTime = module ? module->cpuTime : 0.0;
  160. std::string text = stringf("%.1f%%", cpuTime * 100.0);
  161. nvgSave(vg);
  162. nvgBeginPath(vg);
  163. nvgRect(vg, 0.0, 0.0, box.size.x, BND_WIDGET_HEIGHT);
  164. nvgFillColor(vg, nvgRGBf(0.0, 0.0, 0.0));
  165. nvgFill(vg);
  166. nvgBeginPath(vg);
  167. cpuTime = clampf(cpuTime, 0.0, 1.0);
  168. nvgRect(vg, 0.0, 0.0, box.size.x * cpuTime, BND_WIDGET_HEIGHT);
  169. nvgFillColor(vg, nvgHSL(0.33 * cubic(1.0 - cpuTime), 1.0, 0.4));
  170. nvgFill(vg);
  171. bndMenuItem(vg, 0.0, 0.0, box.size.x, BND_WIDGET_HEIGHT, BND_DEFAULT, -1, text.c_str());
  172. nvgRestore(vg);
  173. }
  174. nvgResetScissor(vg);
  175. }
  176. void ModuleWidget::onMouseDown(EventMouseDown &e) {
  177. Widget::onMouseDown(e);
  178. if (e.consumed)
  179. return;
  180. if (e.button == 1) {
  181. createContextMenu();
  182. }
  183. e.consumed = true;
  184. e.target = this;
  185. }
  186. void ModuleWidget::onMouseMove(EventMouseMove &e) {
  187. OpaqueWidget::onMouseMove(e);
  188. // Don't delete the ModuleWidget if a TextField is focused
  189. if (!gFocusedWidget) {
  190. // 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.
  191. if (glfwGetKey(gWindow, GLFW_KEY_DELETE) == GLFW_PRESS || glfwGetKey(gWindow, GLFW_KEY_BACKSPACE) == GLFW_PRESS) {
  192. if (!guiIsModPressed() && !guiIsShiftPressed()) {
  193. gRackWidget->deleteModule(this);
  194. this->finalizeEvents();
  195. delete this;
  196. e.consumed = true;
  197. return;
  198. }
  199. }
  200. }
  201. }
  202. void ModuleWidget::onHoverKey(EventHoverKey &e) {
  203. switch (e.key) {
  204. case GLFW_KEY_I:
  205. if (guiIsModPressed() && !guiIsShiftPressed()) {
  206. reset();
  207. e.consumed = true;
  208. return;
  209. }
  210. break;
  211. case GLFW_KEY_R:
  212. if (guiIsModPressed() && !guiIsShiftPressed()) {
  213. randomize();
  214. e.consumed = true;
  215. return;
  216. }
  217. break;
  218. case GLFW_KEY_D:
  219. if (guiIsModPressed() && !guiIsShiftPressed()) {
  220. gRackWidget->cloneModule(this);
  221. e.consumed = true;
  222. return;
  223. }
  224. break;
  225. }
  226. Widget::onHoverKey(e);
  227. }
  228. void ModuleWidget::onDragStart(EventDragStart &e) {
  229. dragPos = gRackWidget->lastMousePos.minus(box.pos);
  230. }
  231. void ModuleWidget::onDragEnd(EventDragEnd &e) {
  232. }
  233. void ModuleWidget::onDragMove(EventDragMove &e) {
  234. Rect newBox = box;
  235. newBox.pos = gRackWidget->lastMousePos.minus(dragPos);
  236. gRackWidget->requestModuleBoxNearest(this, newBox);
  237. }
  238. struct DisconnectMenuItem : MenuItem {
  239. ModuleWidget *moduleWidget;
  240. void onAction(EventAction &e) override {
  241. moduleWidget->disconnect();
  242. }
  243. };
  244. struct ResetMenuItem : MenuItem {
  245. ModuleWidget *moduleWidget;
  246. void onAction(EventAction &e) override {
  247. moduleWidget->reset();
  248. }
  249. };
  250. struct RandomizeMenuItem : MenuItem {
  251. ModuleWidget *moduleWidget;
  252. void onAction(EventAction &e) override {
  253. moduleWidget->randomize();
  254. }
  255. };
  256. struct CloneMenuItem : MenuItem {
  257. ModuleWidget *moduleWidget;
  258. void onAction(EventAction &e) override {
  259. gRackWidget->cloneModule(moduleWidget);
  260. }
  261. };
  262. struct DeleteMenuItem : MenuItem {
  263. ModuleWidget *moduleWidget;
  264. void onAction(EventAction &e) override {
  265. gRackWidget->deleteModule(moduleWidget);
  266. moduleWidget->finalizeEvents();
  267. delete moduleWidget;
  268. }
  269. };
  270. Menu *ModuleWidget::createContextMenu() {
  271. Menu *menu = gScene->createMenu();
  272. MenuLabel *menuLabel = new MenuLabel();
  273. menuLabel->text = model->manufacturer + " " + model->name;
  274. menu->addChild(menuLabel);
  275. ResetMenuItem *resetItem = new ResetMenuItem();
  276. resetItem->text = "Initialize";
  277. resetItem->rightText = GUI_MOD_KEY_NAME "+I";
  278. resetItem->moduleWidget = this;
  279. menu->addChild(resetItem);
  280. RandomizeMenuItem *randomizeItem = new RandomizeMenuItem();
  281. randomizeItem->text = "Randomize";
  282. randomizeItem->rightText = GUI_MOD_KEY_NAME "+R";
  283. randomizeItem->moduleWidget = this;
  284. menu->addChild(randomizeItem);
  285. DisconnectMenuItem *disconnectItem = new DisconnectMenuItem();
  286. disconnectItem->text = "Disconnect cables";
  287. disconnectItem->moduleWidget = this;
  288. menu->addChild(disconnectItem);
  289. CloneMenuItem *cloneItem = new CloneMenuItem();
  290. cloneItem->text = "Duplicate";
  291. cloneItem->rightText = GUI_MOD_KEY_NAME "+D";
  292. cloneItem->moduleWidget = this;
  293. menu->addChild(cloneItem);
  294. DeleteMenuItem *deleteItem = new DeleteMenuItem();
  295. deleteItem->text = "Delete";
  296. deleteItem->rightText = "Backspace/Delete";
  297. deleteItem->moduleWidget = this;
  298. menu->addChild(deleteItem);
  299. return menu;
  300. }
  301. } // namespace rack