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.

320 lines
7.3KB

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