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.

276 lines
6.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. json_t *ModuleWidget::toJson() {
  37. json_t *rootJ = json_object();
  38. // plugin
  39. json_object_set_new(rootJ, "plugin", json_string(model->plugin->slug.c_str()));
  40. // model
  41. json_object_set_new(rootJ, "model", json_string(model->slug.c_str()));
  42. // pos
  43. json_t *pos = json_pack("[f, f]", (double) box.pos.x, (double) box.pos.y);
  44. json_object_set_new(rootJ, "pos", pos);
  45. // params
  46. json_t *paramsJ = json_array();
  47. for (ParamWidget *paramWidget : params) {
  48. json_t *paramJ = paramWidget->toJson();
  49. json_array_append_new(paramsJ, paramJ);
  50. }
  51. json_object_set_new(rootJ, "params", paramsJ);
  52. // data
  53. if (module) {
  54. json_t *dataJ = module->toJson();
  55. if (dataJ) {
  56. json_object_set_new(rootJ, "data", dataJ);
  57. }
  58. }
  59. return rootJ;
  60. }
  61. void ModuleWidget::fromJson(json_t *rootJ) {
  62. initialize();
  63. // pos
  64. json_t *pos = json_object_get(rootJ, "pos");
  65. double x, y;
  66. json_unpack(pos, "[F, F]", &x, &y);
  67. box.pos = Vec(x, y);
  68. // params
  69. json_t *paramsJ = json_object_get(rootJ, "params");
  70. size_t paramId;
  71. json_t *paramJ;
  72. json_array_foreach(paramsJ, paramId, paramJ) {
  73. if (paramId < params.size()) {
  74. params[paramId]->fromJson(paramJ);
  75. }
  76. }
  77. // data
  78. json_t *dataJ = json_object_get(rootJ, "data");
  79. if (dataJ && module) {
  80. module->fromJson(dataJ);
  81. }
  82. }
  83. void ModuleWidget::disconnect() {
  84. for (Port *input : inputs) {
  85. gRackWidget->wireContainer->removeAllWires(input);
  86. }
  87. for (Port *output : outputs) {
  88. gRackWidget->wireContainer->removeAllWires(output);
  89. }
  90. }
  91. void ModuleWidget::initialize() {
  92. for (ParamWidget *param : params) {
  93. param->setValue(param->defaultValue);
  94. }
  95. if (module) {
  96. module->initialize();
  97. }
  98. }
  99. void ModuleWidget::randomize() {
  100. for (ParamWidget *param : params) {
  101. param->randomize();
  102. }
  103. if (module) {
  104. module->randomize();
  105. }
  106. }
  107. void ModuleWidget::draw(NVGcontext *vg) {
  108. nvgScissor(vg, 0, 0, box.size.x, box.size.y);
  109. Widget::draw(vg);
  110. // CPU usage text
  111. if (0) {
  112. float cpuTime = module ? module->cpuTime : 0.0;
  113. std::string text = stringf("%.1f%%", cpuTime * 100.0);
  114. nvgSave(vg);
  115. nvgBeginPath(vg);
  116. nvgRect(vg, 0.0, 0.0, box.size.x, BND_WIDGET_HEIGHT);
  117. nvgFillColor(vg, nvgRGBf(0.0, 0.0, 0.0));
  118. nvgFill(vg);
  119. nvgBeginPath(vg);
  120. cpuTime = clampf(cpuTime, 0.0, 1.0);
  121. nvgRect(vg, 0.0, 0.0, box.size.x * cpuTime, BND_WIDGET_HEIGHT);
  122. nvgFillColor(vg, nvgHSL(0.33 * cubic(1.0 - cpuTime), 1.0, 0.4));
  123. nvgFill(vg);
  124. bndMenuItem(vg, 0.0, 0.0, box.size.x, BND_WIDGET_HEIGHT, BND_DEFAULT, -1, text.c_str());
  125. nvgRestore(vg);
  126. }
  127. nvgResetScissor(vg);
  128. }
  129. Widget *ModuleWidget::onHoverKey(Vec pos, int key) {
  130. switch (key) {
  131. case GLFW_KEY_DELETE:
  132. case GLFW_KEY_BACKSPACE:
  133. if (!guiIsModPressed() && !guiIsShiftPressed()) {
  134. gRackWidget->deleteModule(this);
  135. this->finalizeEvents();
  136. delete this;
  137. return NULL;
  138. }
  139. break;
  140. case GLFW_KEY_I:
  141. if (guiIsModPressed() && !guiIsShiftPressed())
  142. initialize();
  143. break;
  144. case GLFW_KEY_R:
  145. if (guiIsModPressed() && !guiIsShiftPressed())
  146. randomize();
  147. break;
  148. case GLFW_KEY_D:
  149. if (guiIsModPressed() && !guiIsShiftPressed())
  150. gRackWidget->cloneModule(this);
  151. break;
  152. }
  153. return this;
  154. }
  155. void ModuleWidget::onDragStart() {
  156. dragPos = gMousePos.minus(getAbsolutePos());
  157. }
  158. void ModuleWidget::onDragMove(Vec mouseRel) {
  159. requestedPos = gMousePos.minus(parent->getAbsolutePos()).minus(dragPos);
  160. requested = true;
  161. }
  162. void ModuleWidget::onDragEnd() {
  163. }
  164. struct DisconnectMenuItem : MenuItem {
  165. ModuleWidget *moduleWidget;
  166. void onAction() {
  167. moduleWidget->disconnect();
  168. }
  169. };
  170. struct InitializeMenuItem : MenuItem {
  171. ModuleWidget *moduleWidget;
  172. void onAction() {
  173. moduleWidget->initialize();
  174. }
  175. };
  176. struct RandomizeMenuItem : MenuItem {
  177. ModuleWidget *moduleWidget;
  178. void onAction() {
  179. moduleWidget->randomize();
  180. }
  181. };
  182. struct CloneMenuItem : MenuItem {
  183. ModuleWidget *moduleWidget;
  184. void onAction() {
  185. gRackWidget->cloneModule(moduleWidget);
  186. }
  187. };
  188. struct DeleteMenuItem : MenuItem {
  189. ModuleWidget *moduleWidget;
  190. void onAction() {
  191. gRackWidget->deleteModule(moduleWidget);
  192. moduleWidget->finalizeEvents();
  193. delete moduleWidget;
  194. }
  195. };
  196. Menu *ModuleWidget::createContextMenu() {
  197. Menu *menu = gScene->createMenu();
  198. MenuLabel *menuLabel = new MenuLabel();
  199. menuLabel->text = model->plugin->name + ": " + model->name;
  200. menu->pushChild(menuLabel);
  201. InitializeMenuItem *resetItem = new InitializeMenuItem();
  202. resetItem->text = "Initialize";
  203. resetItem->rightText = GUI_MOD_KEY_NAME "+I";
  204. resetItem->moduleWidget = this;
  205. menu->pushChild(resetItem);
  206. RandomizeMenuItem *randomizeItem = new RandomizeMenuItem();
  207. randomizeItem->text = "Randomize";
  208. randomizeItem->rightText = GUI_MOD_KEY_NAME "+R";
  209. randomizeItem->moduleWidget = this;
  210. menu->pushChild(randomizeItem);
  211. DisconnectMenuItem *disconnectItem = new DisconnectMenuItem();
  212. disconnectItem->text = "Disconnect cables";
  213. disconnectItem->moduleWidget = this;
  214. menu->pushChild(disconnectItem);
  215. CloneMenuItem *cloneItem = new CloneMenuItem();
  216. cloneItem->text = "Duplicate";
  217. cloneItem->rightText = GUI_MOD_KEY_NAME "+D";
  218. cloneItem->moduleWidget = this;
  219. menu->pushChild(cloneItem);
  220. DeleteMenuItem *deleteItem = new DeleteMenuItem();
  221. deleteItem->text = "Delete";
  222. deleteItem->rightText = "Backspace/Delete";
  223. deleteItem->moduleWidget = this;
  224. menu->pushChild(deleteItem);
  225. return menu;
  226. }
  227. void ModuleWidget::onMouseDownOpaque(int button) {
  228. if (button == 1) {
  229. createContextMenu();
  230. }
  231. }
  232. } // namespace rack