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.

317 lines
7.2KB

  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. // manufacturer
  50. json_object_set_new(rootJ, "manufacturer", json_string(model->manufacturerSlug.c_str()));
  51. // model
  52. json_object_set_new(rootJ, "model", json_string(model->slug.c_str()));
  53. // pos
  54. json_t *posJ = json_pack("[f, f]", (double) box.pos.x, (double) box.pos.y);
  55. json_object_set_new(rootJ, "pos", posJ);
  56. // params
  57. json_t *paramsJ = json_array();
  58. for (ParamWidget *paramWidget : params) {
  59. json_t *paramJ = paramWidget->toJson();
  60. json_array_append_new(paramsJ, paramJ);
  61. }
  62. json_object_set_new(rootJ, "params", paramsJ);
  63. // data
  64. if (module) {
  65. json_t *dataJ = module->toJson();
  66. if (dataJ) {
  67. json_object_set_new(rootJ, "data", dataJ);
  68. }
  69. }
  70. return rootJ;
  71. }
  72. void ModuleWidget::fromJson(json_t *rootJ) {
  73. // pos
  74. json_t *posJ = json_object_get(rootJ, "pos");
  75. double x, y;
  76. json_unpack(posJ, "[F, F]", &x, &y);
  77. box.pos = Vec(x, y);
  78. // params
  79. json_t *paramsJ = json_object_get(rootJ, "params");
  80. size_t paramId;
  81. json_t *paramJ;
  82. json_array_foreach(paramsJ, paramId, paramJ) {
  83. if (paramId < params.size()) {
  84. params[paramId]->fromJson(paramJ);
  85. }
  86. }
  87. // data
  88. json_t *dataJ = json_object_get(rootJ, "data");
  89. if (dataJ && module) {
  90. module->fromJson(dataJ);
  91. }
  92. }
  93. void ModuleWidget::disconnect() {
  94. for (Port *input : inputs) {
  95. gRackWidget->wireContainer->removeAllWires(input);
  96. }
  97. for (Port *output : outputs) {
  98. gRackWidget->wireContainer->removeAllWires(output);
  99. }
  100. }
  101. void ModuleWidget::reset() {
  102. for (ParamWidget *param : params) {
  103. param->setValue(param->defaultValue);
  104. }
  105. if (module) {
  106. module->reset();
  107. }
  108. }
  109. void ModuleWidget::randomize() {
  110. for (ParamWidget *param : params) {
  111. param->randomize();
  112. }
  113. if (module) {
  114. module->randomize();
  115. }
  116. }
  117. void ModuleWidget::draw(NVGcontext *vg) {
  118. nvgScissor(vg, 0, 0, box.size.x, box.size.y);
  119. Widget::draw(vg);
  120. // CPU usage text
  121. if (0) {
  122. float cpuTime = module ? module->cpuTime : 0.0;
  123. std::string text = stringf("%.1f%%", cpuTime * 100.0);
  124. nvgSave(vg);
  125. nvgBeginPath(vg);
  126. nvgRect(vg, 0.0, 0.0, box.size.x, BND_WIDGET_HEIGHT);
  127. nvgFillColor(vg, nvgRGBf(0.0, 0.0, 0.0));
  128. nvgFill(vg);
  129. nvgBeginPath(vg);
  130. cpuTime = clampf(cpuTime, 0.0, 1.0);
  131. nvgRect(vg, 0.0, 0.0, box.size.x * cpuTime, BND_WIDGET_HEIGHT);
  132. nvgFillColor(vg, nvgHSL(0.33 * cubic(1.0 - cpuTime), 1.0, 0.4));
  133. nvgFill(vg);
  134. bndMenuItem(vg, 0.0, 0.0, box.size.x, BND_WIDGET_HEIGHT, BND_DEFAULT, -1, text.c_str());
  135. nvgRestore(vg);
  136. }
  137. nvgResetScissor(vg);
  138. }
  139. void ModuleWidget::onMouseDown(EventMouseDown &e) {
  140. Widget::onMouseDown(e);
  141. if (e.consumed)
  142. return;
  143. if (e.button == 1) {
  144. createContextMenu();
  145. }
  146. e.consumed = true;
  147. e.target = this;
  148. }
  149. void ModuleWidget::onMouseMove(EventMouseMove &e) {
  150. OpaqueWidget::onMouseMove(e);
  151. // Don't delete the ModuleWidget if a TextField is focused
  152. if (!gFocusedWidget) {
  153. // 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.
  154. if (glfwGetKey(gWindow, GLFW_KEY_DELETE) == GLFW_PRESS || glfwGetKey(gWindow, GLFW_KEY_BACKSPACE) == GLFW_PRESS) {
  155. if (!guiIsModPressed() && !guiIsShiftPressed()) {
  156. gRackWidget->deleteModule(this);
  157. this->finalizeEvents();
  158. delete this;
  159. // Kinda sketchy because events will be passed further down the tree
  160. return;
  161. }
  162. }
  163. }
  164. }
  165. void ModuleWidget::onHoverKey(EventHoverKey &e) {
  166. switch (e.key) {
  167. case GLFW_KEY_I:
  168. if (guiIsModPressed() && !guiIsShiftPressed()) {
  169. reset();
  170. e.consumed = true;
  171. return;
  172. }
  173. break;
  174. case GLFW_KEY_R:
  175. if (guiIsModPressed() && !guiIsShiftPressed()) {
  176. randomize();
  177. e.consumed = true;
  178. return;
  179. }
  180. break;
  181. case GLFW_KEY_D:
  182. if (guiIsModPressed() && !guiIsShiftPressed()) {
  183. gRackWidget->cloneModule(this);
  184. e.consumed = true;
  185. return;
  186. }
  187. break;
  188. }
  189. Widget::onHoverKey(e);
  190. }
  191. void ModuleWidget::onDragStart(EventDragStart &e) {
  192. dragPos = gRackWidget->lastMousePos.minus(box.pos);
  193. }
  194. void ModuleWidget::onDragEnd(EventDragEnd &e) {
  195. }
  196. void ModuleWidget::onDragMove(EventDragMove &e) {
  197. Rect newBox = box;
  198. newBox.pos = gRackWidget->lastMousePos.minus(dragPos);
  199. gRackWidget->requestModuleBoxNearest(this, newBox);
  200. }
  201. struct DisconnectMenuItem : MenuItem {
  202. ModuleWidget *moduleWidget;
  203. void onAction(EventAction &e) override {
  204. moduleWidget->disconnect();
  205. }
  206. };
  207. struct ResetMenuItem : MenuItem {
  208. ModuleWidget *moduleWidget;
  209. void onAction(EventAction &e) override {
  210. moduleWidget->reset();
  211. }
  212. };
  213. struct RandomizeMenuItem : MenuItem {
  214. ModuleWidget *moduleWidget;
  215. void onAction(EventAction &e) override {
  216. moduleWidget->randomize();
  217. }
  218. };
  219. struct CloneMenuItem : MenuItem {
  220. ModuleWidget *moduleWidget;
  221. void onAction(EventAction &e) override {
  222. gRackWidget->cloneModule(moduleWidget);
  223. }
  224. };
  225. struct DeleteMenuItem : MenuItem {
  226. ModuleWidget *moduleWidget;
  227. void onAction(EventAction &e) override {
  228. gRackWidget->deleteModule(moduleWidget);
  229. moduleWidget->finalizeEvents();
  230. delete moduleWidget;
  231. }
  232. };
  233. Menu *ModuleWidget::createContextMenu() {
  234. Menu *menu = gScene->createMenu();
  235. MenuLabel *menuLabel = new MenuLabel();
  236. menuLabel->text = model->manufacturerName + " " + model->name;
  237. menu->pushChild(menuLabel);
  238. ResetMenuItem *resetItem = new ResetMenuItem();
  239. resetItem->text = "Initialize";
  240. resetItem->rightText = GUI_MOD_KEY_NAME "+I";
  241. resetItem->moduleWidget = this;
  242. menu->pushChild(resetItem);
  243. RandomizeMenuItem *randomizeItem = new RandomizeMenuItem();
  244. randomizeItem->text = "Randomize";
  245. randomizeItem->rightText = GUI_MOD_KEY_NAME "+R";
  246. randomizeItem->moduleWidget = this;
  247. menu->pushChild(randomizeItem);
  248. DisconnectMenuItem *disconnectItem = new DisconnectMenuItem();
  249. disconnectItem->text = "Disconnect cables";
  250. disconnectItem->moduleWidget = this;
  251. menu->pushChild(disconnectItem);
  252. CloneMenuItem *cloneItem = new CloneMenuItem();
  253. cloneItem->text = "Duplicate";
  254. cloneItem->rightText = GUI_MOD_KEY_NAME "+D";
  255. cloneItem->moduleWidget = this;
  256. menu->pushChild(cloneItem);
  257. DeleteMenuItem *deleteItem = new DeleteMenuItem();
  258. deleteItem->text = "Delete";
  259. deleteItem->rightText = "Backspace/Delete";
  260. deleteItem->moduleWidget = this;
  261. menu->pushChild(deleteItem);
  262. return menu;
  263. }
  264. } // namespace rack