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.

386 lines
9.0KB

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