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.

266 lines
5.9KB

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