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.

582 lines
26KB

  1. #include "Features.hpp"
  2. #if USE_NEW_SCOPE
  3. #include <string.h>
  4. #include "trowaSoft.hpp"
  5. #include "trowaSoftComponents.hpp"
  6. #include "trowaSoftUtilities.hpp"
  7. #include "dsp/digital.hpp"
  8. #include "Module_multiScope.hpp"
  9. #include "Widget_multiScope.hpp"
  10. using namespace trowaSoft;
  11. #define SCREW_DIAMETER 15
  12. #define TROWA_WIDGET_TOP_BAR_HEIGHT 15
  13. #define TROWA_SCOPE_INPUT_AREA_WIDTH 365 // 295 265
  14. #define TROWA_SCOPE_MIN_SCOPE_AREA_WIDTH (240 - RACK_GRID_WIDTH) // 240-RACK_GRID_WIDTH
  15. #define TROWA_SCOPE_DISPLAY_AREA_WIDTH 400
  16. #define KNOB_X 0
  17. #define KNOB_Y 1
  18. #define HUE_IX 0
  19. #define SAT_IX 1
  20. #define VAL_IX 2
  21. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  22. // multiScopeWidget()
  23. // Instantiate a multiScope widget.
  24. // @scopeModule : (IN) Pointer to the multiScope module.
  25. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  26. multiScopeWidget::multiScopeWidget(multiScope *scopeModule) : ModuleWidget(scopeModule)
  27. {
  28. bool isPreview = scopeModule == NULL;
  29. // Calculate Sizes:
  30. this->inputAreaWidth = TROWA_SCOPE_INPUT_AREA_WIDTH;
  31. int borderSize = TROWA_WIDGET_TOP_BAR_HEIGHT; // Size of the top and bottom borders
  32. // Minimum widget width:
  33. int w = ((inputAreaWidth + TROWA_SCOPE_MIN_SCOPE_AREA_WIDTH) / RACK_GRID_WIDTH) + 1;
  34. if (w < 16)
  35. w = 16;
  36. int minimumWidgetWidth = w * RACK_GRID_WIDTH; // Smallest we want to ever become
  37. // Scope default width and widget default width
  38. int scopeGraphHeight = RACK_GRID_HEIGHT - borderSize*2;
  39. float scopeGraphDefWidth = 16.0 * scopeGraphHeight / 16.0; // Try to make it 16x9 ...or 16x16 for perfect circle
  40. w = ((inputAreaWidth + scopeGraphDefWidth) / RACK_GRID_WIDTH) + 1;
  41. box.size = Vec(RACK_GRID_WIDTH*w, RACK_GRID_HEIGHT);
  42. //// Create scopeModule:
  43. //multiScope *scopeModule = new multiScope();
  44. //setModule(scopeModule);
  45. // Border color for panels
  46. NVGcolor borderColor = nvgRGBAf(0.25, 0.25, 0.25, 1.0); // nvgRGBAf(0.25, 0.25, 0.25, 1.0);
  47. float borderWidth = 1;
  48. ////////////////////////////////////
  49. // LHS Panel (with controls)
  50. ////////////////////////////////////
  51. {
  52. TS_SVGPanel *svgpanel = new TS_SVGPanel(/*top*/ borderWidth, /*right*/ 0, /*bottom*/ borderWidth, /*left*/ borderWidth);
  53. svgpanel->borderColor = borderColor;
  54. svgpanel->box.size = Vec(inputAreaWidth, RACK_GRID_HEIGHT);
  55. svgpanel->setBackground(SVG::load(assetPlugin(plugin, "res/multiScope.svg")));
  56. addChild(svgpanel);
  57. }
  58. int controlDisplayHeight = 64; // 56
  59. int controlDisplayY = 24;
  60. ////////////////////////////////////
  61. // Labels
  62. ////////////////////////////////////
  63. {
  64. TSScopeLabelArea *area = new TSScopeLabelArea();
  65. area->box.pos = Vec(0, TROWA_SCOPE_CONTROL_START_Y - 14); // wAS 56_24 = 80, OLD CONTROL START WAS 94
  66. area->box.size = Vec(inputAreaWidth, box.size.y - 50);
  67. area->module = scopeModule;
  68. addChild(area);
  69. }
  70. ////////////////////////////////////
  71. // Black background for Scope screen
  72. ////////////////////////////////////
  73. {
  74. screenContainer = new TS_Panel();
  75. screenContainer->backgroundColor = COLOR_BLACK;
  76. screenContainer->originalBackgroundColor = COLOR_BLACK;
  77. screenContainer->box.pos = Vec(inputAreaWidth - 1, 0);
  78. screenContainer->box.size = Vec(box.size.x - inputAreaWidth + 1, box.size.y);
  79. dynamic_cast<TS_Panel*>(screenContainer)->setBorderWidth(/*top*/ borderWidth, /*right*/ 0, /*bottom*/ borderWidth, /*left*/ 0);
  80. dynamic_cast<TS_Panel*>(screenContainer)->borderColor = borderColor;
  81. TS_Panel* screenBg = new TS_Panel();
  82. screenBg->backgroundColor = (isPreview) ? COLOR_BLACK : scopeModule->plotBackgroundColor;
  83. screenBg->originalBackgroundColor = (isPreview) ? COLOR_BLACK : screenBg->backgroundColor;
  84. screenBg->box.pos = Vec(0, RACK_GRID_WIDTH);
  85. screenBg->box.size = Vec(screenContainer->box.size.x - RACK_GRID_WIDTH, screenContainer->box.size.y - 2 * RACK_GRID_WIDTH);
  86. screenContainer->addChild(screenBg);
  87. addChild(screenContainer);
  88. }
  89. Vec tinyBtnSize = Vec(10, 10);
  90. ////////////////////////////////////
  91. // RHS Resize Handle
  92. ////////////////////////////////////
  93. {
  94. TS_SVGPanel *svgpanel = new TS_SVGPanel(/*top*/ borderWidth, /*right*/ borderWidth, /*bottom*/ borderWidth, /*left*/ 0);
  95. svgpanel->box.size = Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT);
  96. svgpanel->borderColor = borderColor;
  97. svgpanel->setBackground(SVG::load(assetPlugin(plugin, "res/multiScope.svg")));
  98. //========== Single Controls ================
  99. // Turn Display On/Off (Default is On)
  100. TS_PadSwitch* displayToggleBtn = dynamic_cast<TS_PadSwitch*>(ParamWidget::create<TS_PadSwitch>(Vec(20, 20), scopeModule, multiScope::INFO_DISPLAY_TOGGLE_PARAM, 0, 1, 1));
  101. displayToggleBtn->box.size = tinyBtnSize;
  102. displayToggleBtn->value = 1.0;
  103. ColorValueLight* displayLED = TS_createColorValueLight<ColorValueLight>(displayToggleBtn->box.pos, scopeModule, multiScope::INFO_DISPLAY_TOGGLE_LED, tinyBtnSize, TROWA_SCOPE_INFO_DISPLAY_ON_COLOR);
  104. // Background Color
  105. TS_PadSwitch* colorDisplayToggleBtn = dynamic_cast<TS_PadSwitch*>(ParamWidget::create<TS_PadSwitch>(Vec(20, 65), scopeModule, multiScope::BGCOLOR_DISPLAY_PARAM, 0, 1, 1));
  106. colorDisplayToggleBtn->box.size = tinyBtnSize;
  107. colorDisplayToggleBtn->value = 1.0;
  108. ColorValueLight* colorDisplayLED = TS_createColorValueLight<ColorValueLight>(colorDisplayToggleBtn->box.pos, scopeModule, multiScope::BGCOLOR_DISPLAY_LED, tinyBtnSize, TROWA_SCOPE_INFO_DISPLAY_ON_COLOR);
  109. TSScopeModuleResizeHandle* rightHandle = new TSScopeModuleResizeHandle(minimumWidgetWidth, svgpanel, displayToggleBtn, displayLED);
  110. rightHandle->colorDisplayToggleBtn = colorDisplayToggleBtn;
  111. rightHandle->colorDisplayToggleLED = colorDisplayLED;
  112. rightHandle->right = true;
  113. rightHandle->box.pos = Vec(box.size.x - rightHandle->box.size.x, 0);
  114. rightHandle->setChildPositions(); // Adjust the positions of our children.
  115. TSScopeSideBarLabelArea* rhsLabels = new TSScopeSideBarLabelArea(rightHandle->box.size);
  116. rhsLabels->box.pos = Vec(0, 0);
  117. rightHandle->addChild(rhsLabels);
  118. this->rightHandle = rightHandle;
  119. addChild(this->rightHandle);
  120. addParam(displayToggleBtn);
  121. addChild(displayLED);
  122. #if ENABLE_BG_COLOR_PICKER
  123. addParam(colorDisplayToggleBtn);
  124. addChild(colorDisplayLED);
  125. #endif
  126. if (!isPreview)
  127. {
  128. scopeModule->lights[multiScope::INFO_DISPLAY_TOGGLE_LED].value = 1.0;
  129. scopeModule->infoDisplayOnTrigger.state = SchmittTrigger::HIGH;
  130. }
  131. }
  132. ////////////////////////////////////
  133. // Scope Display
  134. ////////////////////////////////////
  135. int wIx = 0;
  136. int scopeGraphWidth = box.size.x - inputAreaWidth - this->rightHandle->box.size.x;
  137. for (wIx = 0; wIx < TROWA_SCOPE_NUM_WAVEFORMS; wIx++)
  138. {
  139. //info("Adding scope area %d.", wIx);
  140. multiScopeDisplay* scopeArea = new multiScopeDisplay();
  141. scopeArea->wIx = wIx;
  142. scopeArea->module = scopeModule;
  143. scopeArea->box.pos = Vec(inputAreaWidth - 1, borderSize);
  144. scopeArea->box.size = Vec(scopeGraphWidth, scopeGraphHeight);
  145. addChild(scopeArea);
  146. this->display[wIx] = scopeArea;
  147. }
  148. // Single Controls:
  149. // Color sliders
  150. const int sliderHeight = 20;
  151. const int margin = 10;
  152. int yslider = this->display[0]->box.pos.y + this->display[0]->box.size.y - 3 * (sliderHeight + margin) - margin;
  153. //info("Adding color sliders");
  154. for (int i = 0; i < 3; i++)
  155. {
  156. this->colorSliders[i] = new TS_ColorSlider(Vec(160, sliderHeight));
  157. this->colorSliders[i]->startColorHSL.h = (i == 0) ? 0.0 : 0.5;
  158. this->colorSliders[i]->startColorHSL.s = (i == 1) ? 0.0 : 1.0;
  159. this->colorSliders[i]->startColorHSL.lum = (i == 2) ? 0.0 : 0.5;
  160. this->colorSliders[i]->endColorHSL.h = (i == 0) ? 1.0 : 0.5;
  161. this->colorSliders[i]->endColorHSL.s = (i == 1) ? 1.0 : 1.0;
  162. this->colorSliders[i]->endColorHSL.lum = (i == 2) ? 1.0 : 0.5;
  163. //this->colorSliders[i]->endColor = endColors[i];
  164. this->colorSliders[i]->visible = false;
  165. this->colorSliders[i]->box.pos = Vec(inputAreaWidth + 21, yslider);
  166. addChild(this->colorSliders[i]);
  167. yslider += sliderHeight + margin;
  168. }
  169. ////////////////////////////////////
  170. // Control Display
  171. ////////////////////////////////////
  172. {
  173. TSScopeDisplay* sDisplay = new TSScopeDisplay();
  174. //sDisplay->box.pos = Vec(13, controlDisplayY);;
  175. //sDisplay->box.size = Vec(inputAreaWidth - 13 * 2, controlDisplayHeight);
  176. sDisplay->box.pos = Vec(screenContainer->box.pos.x + 15, controlDisplayY);;
  177. sDisplay->box.size = Vec(scopeGraphWidth - 13 * 2, controlDisplayHeight);
  178. sDisplay->module = scopeModule;
  179. sDisplay->visible = true; // By default show display
  180. float minWidth = TROWA_SCOPE_DISPLAY_AREA_WIDTH - 13 * 2;
  181. sDisplay->originalWidth = (sDisplay->box.size.x > minWidth) ? sDisplay->box.size.x : minWidth;
  182. scopeInfoDisplay = sDisplay;
  183. addChild(sDisplay);
  184. }
  185. ////////////////////////////////////
  186. // Controls:
  187. ////////////////////////////////////
  188. //NVGcolor backColor = nvgRGBAf(0.2, 0.2, 0.2, /*alpha */ 0.7);
  189. //Vec ledSize = Vec(20, 20);
  190. const int xStart = TROWA_SCOPE_CONTROL_START_X;
  191. const int yStart = TROWA_SCOPE_CONTROL_START_Y; // 98
  192. int dx = TROWA_SCOPE_CONTROL_DX; // 35
  193. int dy = TROWA_SCOPE_CONTROL_DY; // 26
  194. int shapeSpacingY = TROWA_SCOPE_CONTROL_SHAPE_SPACING; // 8 An extra amount between shapes
  195. int knobOffset = 5;
  196. int tinyOffset = 5;
  197. int x, y = yStart;
  198. for (wIx = 0; wIx < TROWA_SCOPE_NUM_WAVEFORMS; wIx++)
  199. {
  200. x = xStart;
  201. int y2 = y + dy + knobOffset;
  202. int y3 = y2 + dy;
  203. NVGcolor defaultColor = COLOR_RED;
  204. float defaultHue = 0.0;
  205. NVGcolor defaultFillColor = COLOR_BLUE;
  206. float defaultFillHue = 0.67;
  207. if (!isPreview)
  208. {
  209. defaultColor = scopeModule->waveForms[wIx]->waveColor;
  210. defaultHue = scopeModule->waveForms[wIx]->waveHue;
  211. defaultFillColor = scopeModule->waveForms[wIx]->fillColor;
  212. defaultFillHue = scopeModule->waveForms[wIx]->fillHue;
  213. }
  214. // X Controls:
  215. inputPorts[multiScope::X_INPUT + wIx] = dynamic_cast<TS_Port*>(TS_createInput<TS_Port>(Vec(x, y), scopeModule, multiScope::X_INPUT + wIx, !plugLightsEnabled, defaultColor));
  216. addInput(inputPorts[multiScope::X_INPUT + wIx]);
  217. addParam(ParamWidget::create<TS_TinyBlackKnob>(Vec(x + knobOffset, y2), scopeModule, multiScope::X_POS_PARAM + wIx, TROWA_SCOPE_POS_KNOB_MIN, TROWA_SCOPE_POS_KNOB_MAX, TROWA_SCOPE_POS_X_KNOB_DEF));
  218. // Keep reference to the scale knobs for synching
  219. scaleKnobs[wIx][KNOB_X] = dynamic_cast<TS_TinyBlackKnob*>(ParamWidget::create<TS_TinyBlackKnob>(Vec(x + knobOffset, y3), scopeModule, multiScope::X_SCALE_PARAM + wIx, TROWA_SCOPE_SCALE_KNOB_MIN, TROWA_SCOPE_SCALE_KNOB_MAX, 1.0));
  220. addParam(scaleKnobs[wIx][KNOB_X]);
  221. // X-Y Scale Synchronization:
  222. TS_PadSwitch* linkXYScalesBtn = dynamic_cast<TS_PadSwitch*>(ParamWidget::create<TS_PadSwitch>(Vec(x + knobOffset + 23, y3 + tinyOffset), scopeModule, multiScope::LINK_XY_SCALE_PARAM + wIx, 0, 1, 0));
  223. linkXYScalesBtn->box.size = tinyBtnSize;
  224. addParam(linkXYScalesBtn);
  225. addChild(TS_createColorValueLight<ColorValueLight>(Vec(x + knobOffset + 23, y3 + tinyOffset), scopeModule, multiScope::LINK_XY_SCALE_LED + wIx, tinyBtnSize, TROWA_SCOPE_LINK_XY_SCALE_ON_COLOR));
  226. if (!isPreview)
  227. scopeModule->waveForms[wIx]->lastXYScaleValue = 1.0;
  228. // Y Controls:
  229. x += dx;
  230. inputPorts[multiScope::Y_INPUT + wIx] = dynamic_cast<TS_Port*>(TS_createInput<TS_Port>(Vec(x, y), scopeModule, multiScope::Y_INPUT + wIx, !plugLightsEnabled, defaultColor));
  231. addInput(inputPorts[multiScope::Y_INPUT + wIx]);
  232. addParam(ParamWidget::create<TS_TinyBlackKnob>(Vec(x + knobOffset, y2), scopeModule, multiScope::Y_POS_PARAM + wIx, TROWA_SCOPE_POS_KNOB_MIN, TROWA_SCOPE_POS_KNOB_MAX, TROWA_SCOPE_POS_Y_KNOB_DEF));
  233. // Keep reference to the scale knobs for synching
  234. scaleKnobs[wIx][KNOB_Y] = dynamic_cast<TS_TinyBlackKnob*>(ParamWidget::create<TS_TinyBlackKnob>(Vec(x + knobOffset, y3), scopeModule, multiScope::Y_SCALE_PARAM + wIx, TROWA_SCOPE_SCALE_KNOB_MIN, TROWA_SCOPE_SCALE_KNOB_MAX, 1.0));
  235. addParam(scaleKnobs[wIx][KNOB_Y]);
  236. // Color Controls:
  237. x += dx;
  238. inputPorts[multiScope::COLOR_INPUT + wIx] = dynamic_cast<TS_Port*>(TS_createInput<TS_Port>(Vec(x, y), scopeModule, multiScope::COLOR_INPUT + wIx, !plugLightsEnabled, defaultColor));
  239. addInput(inputPorts[multiScope::COLOR_INPUT + wIx]);
  240. float knobHueVal = rescale(defaultHue, 0, 1.0, TROWA_SCOPE_HUE_KNOB_MIN, TROWA_SCOPE_HUE_KNOB_MAX);
  241. addParam(ParamWidget::create<TS_TinyBlackKnob>(Vec(x + knobOffset, y2 + TROWA_SCOPE_COLOR_KNOB_Y_OFFSET), scopeModule, multiScope::COLOR_PARAM + wIx, TROWA_SCOPE_HUE_KNOB_MIN, TROWA_SCOPE_HUE_KNOB_MAX, knobHueVal));
  242. if (!isPreview)
  243. scopeModule->params[multiScope::COLOR_PARAM + wIx].value = knobHueVal;
  244. #if TROWA_SCOPE_USE_COLOR_LIGHTS
  245. if (!isPreview)
  246. {
  247. scopeModule->waveForms[wIx]->waveLight = TS_createColorValueLight<ColorValueLight>(Vec(x + knobOffset + tinyOffset, y3 + tinyOffset), scopeModule, multiScope::COLOR_LED + wIx, tinyBtnSize, scopeModule->waveForms[wIx]->waveColor, backColor);
  248. addChild(scopeModule->waveForms[wIx]->waveLight);
  249. }
  250. #endif
  251. // Opacity:
  252. x += dx;
  253. inputPorts[multiScope::OPACITY_INPUT + wIx] = dynamic_cast<TS_Port*>(TS_createInput<TS_Port>(Vec(x, y), scopeModule, multiScope::OPACITY_INPUT + wIx, !plugLightsEnabled, defaultColor));
  254. addInput(inputPorts[multiScope::OPACITY_INPUT + wIx]);
  255. addParam(ParamWidget::create<TS_TinyBlackKnob>(Vec(x + knobOffset, y2), scopeModule, multiScope::OPACITY_PARAM + wIx, TROWA_SCOPE_MIN_OPACITY, TROWA_SCOPE_MAX_OPACITY, TROWA_SCOPE_MAX_OPACITY));
  256. // Pen On:
  257. inputPorts[multiScope::PEN_ON_INPUT + wIx] = dynamic_cast<TS_Port*>(TS_createInput<TS_Port>(Vec(x, y3 - knobOffset), scopeModule, multiScope::PEN_ON_INPUT + wIx, !plugLightsEnabled, defaultColor));
  258. addInput(inputPorts[multiScope::PEN_ON_INPUT + wIx]);
  259. // Fill Color Controls:
  260. x += dx;
  261. inputPorts[multiScope::FILL_COLOR_INPUT + wIx] = dynamic_cast<TS_Port*>(TS_createInput<TS_Port>(Vec(x, y), scopeModule, multiScope::FILL_COLOR_INPUT + wIx, !plugLightsEnabled, defaultFillColor));
  262. addInput(inputPorts[multiScope::FILL_COLOR_INPUT + wIx]);
  263. knobHueVal = rescale(defaultFillHue, 0, 1.0, TROWA_SCOPE_HUE_KNOB_MIN, TROWA_SCOPE_HUE_KNOB_MAX);
  264. addParam(ParamWidget::create<TS_TinyBlackKnob>(Vec(x + knobOffset, y2 + TROWA_SCOPE_COLOR_KNOB_Y_OFFSET), scopeModule, multiScope::FILL_COLOR_PARAM + wIx, TROWA_SCOPE_HUE_KNOB_MIN, TROWA_SCOPE_HUE_KNOB_MAX, knobHueVal));
  265. if (!isPreview)
  266. scopeModule->params[multiScope::FILL_COLOR_PARAM + wIx].value = knobHueVal;
  267. // Fill On toggle
  268. // close to knob: Vec(x + knobOffset + tinyOffset, y3 - 7)
  269. TS_PadSwitch* fillBtn = dynamic_cast<TS_PadSwitch*>(ParamWidget::create<TS_PadSwitch>(Vec(x + knobOffset + tinyOffset, y3 - 7), scopeModule, multiScope::FILL_ON_PARAM + wIx, 0, 1, 0));
  270. fillBtn->box.size = tinyBtnSize;
  271. addParam(fillBtn);
  272. this->fillColorLEDs[wIx] = TS_createColorValueLight<ColorValueLight>(Vec(x + knobOffset + tinyOffset, y3 - 7), scopeModule, multiScope::FILL_ON_LED + wIx, tinyBtnSize, defaultFillColor);
  273. addChild(fillColorLEDs[wIx]);
  274. // Fill Opacity:
  275. x += dx;
  276. inputPorts[multiScope::FILL_OPACITY_INPUT + wIx] = dynamic_cast<TS_Port*>(TS_createInput<TS_Port>(Vec(x, y), scopeModule, multiScope::FILL_OPACITY_INPUT + wIx, !plugLightsEnabled, defaultFillColor));
  277. addInput(inputPorts[multiScope::FILL_OPACITY_INPUT + wIx]);
  278. addParam(ParamWidget::create<TS_TinyBlackKnob>(Vec(x + knobOffset, y2), scopeModule, multiScope::FILL_OPACITY_PARAM + wIx, TROWA_SCOPE_MIN_OPACITY, TROWA_SCOPE_MAX_OPACITY, TROWA_SCOPE_MAX_OPACITY));
  279. // Rotation Controls:
  280. x += dx;
  281. inputPorts[multiScope::ROTATION_INPUT + wIx] = dynamic_cast<TS_Port*>(TS_createInput<TS_Port>(Vec(x, y), scopeModule, multiScope::ROTATION_INPUT + wIx, !plugLightsEnabled, defaultColor));
  282. addInput(inputPorts[multiScope::ROTATION_INPUT + wIx]);
  283. addParam(ParamWidget::create<TS_TinyBlackKnob>(Vec(x + knobOffset, y2), scopeModule, multiScope::ROTATION_PARAM + wIx, TROWA_SCOPE_ROT_KNOB_MIN, TROWA_SCOPE_ROT_KNOB_MAX, 0));
  284. TS_PadSwitch* rotModeBtn = dynamic_cast<TS_PadSwitch*>( ParamWidget::create<TS_PadSwitch>(Vec(x + knobOffset + tinyOffset, y3 + tinyOffset), scopeModule, multiScope::ROTATION_MODE_PARAM + wIx, 0, 1, 0) );
  285. rotModeBtn->box.size = tinyBtnSize;
  286. addParam(rotModeBtn);
  287. addChild(TS_createColorValueLight<ColorValueLight>(Vec(x + knobOffset + tinyOffset, y3 + tinyOffset), scopeModule, multiScope::ROT_LED + wIx, tinyBtnSize, TROWA_SCOPE_ABS_ROT_ON_COLOR));
  288. if (!isPreview && scopeModule->waveForms[wIx]->rotMode)
  289. {
  290. rotModeBtn->value = 1.0;
  291. scopeModule->params[multiScope::ROTATION_MODE_PARAM + wIx].value = 1.0;
  292. scopeModule->waveForms[wIx]->rotModeTrigger.state = SchmittTrigger::HIGH;
  293. scopeModule->lights[multiScope::ROT_LED + wIx].value = 1.0;
  294. }
  295. // Time Controls:
  296. x += dx;
  297. inputPorts[multiScope::TIME_INPUT + wIx] = dynamic_cast<TS_Port*>(TS_createInput<TS_Port>(Vec(x, y), scopeModule, multiScope::TIME_INPUT + wIx, !plugLightsEnabled, defaultColor));
  298. addInput(inputPorts[multiScope::TIME_INPUT + wIx]);
  299. addParam(ParamWidget::create<TS_TinyBlackKnob>(Vec(x + knobOffset, y2), scopeModule, multiScope::TIME_PARAM + wIx, TROWA_SCOPE_TIME_KNOB_MIN, TROWA_SCOPE_TIME_KNOB_MAX, TROWA_SCOPE_TIME_KNOB_DEF));
  300. TS_PadSwitch* lissajousBtn = dynamic_cast<TS_PadSwitch*>(ParamWidget::create<TS_PadSwitch>(Vec(x + knobOffset + tinyOffset, y3 + tinyOffset), scopeModule, multiScope::LISSAJOUS_PARAM + wIx, 0, 1, 1));
  301. lissajousBtn->box.size = tinyBtnSize;
  302. lissajousBtn->value = 1.0;
  303. addParam(lissajousBtn);
  304. addChild(TS_createColorValueLight<ColorValueLight>(Vec(x + knobOffset + tinyOffset, y3 + tinyOffset), scopeModule, multiScope::LISSAJOUS_LED + wIx, tinyBtnSize, TROWA_SCOPE_LISSAJOUS_ON_COLOR));
  305. if (!isPreview)
  306. {
  307. scopeModule->params[multiScope::LISSAJOUS_PARAM + wIx].value = 1.0;
  308. scopeModule->waveForms[wIx]->lissajousTrigger.state = SchmittTrigger::HIGH;
  309. scopeModule->lights[multiScope::LISSAJOUS_LED + wIx].value = 1.0;
  310. }
  311. // Thickness:
  312. x += dx;
  313. inputPorts[multiScope::THICKNESS_INPUT + wIx] = dynamic_cast<TS_Port*>(TS_createInput<TS_Port>(Vec(x, y), scopeModule, multiScope::THICKNESS_INPUT + wIx, !plugLightsEnabled, defaultColor));
  314. addInput(inputPorts[multiScope::THICKNESS_INPUT + wIx]);
  315. addParam(ParamWidget::create<TS_TinyBlackKnob>(Vec(x + knobOffset, y2), scopeModule, multiScope::THICKNESS_PARAM + wIx, TROWA_SCOPE_THICKNESS_MIN, TROWA_SCOPE_THICKNESS_MAX, TROWA_SCOPE_THICKNESS_DEF));
  316. // Effect Controls:
  317. //x += dx;
  318. addParam(ParamWidget::create<TS_TinyBlackKnob>(Vec(x + knobOffset, y3), scopeModule, multiScope::EFFECT_PARAM + wIx, TROWA_SCOPE_EFFECT_KNOB_MIN, TROWA_SCOPE_EFFECT_KNOB_MAX, TROWA_SCOPE_EFFECT_KNOB_DEF));
  319. y = y3 + dy + shapeSpacingY; // Extra space between shapes / waveforms
  320. } // end loop
  321. // Screws:
  322. addChild(Widget::create<ScrewBlack>(Vec(0, 0)));
  323. addChild(Widget::create<ScrewBlack>(Vec(0, box.size.y - SCREW_DIAMETER)));
  324. rhsScrews[0] = dynamic_cast<ScrewBlack*>(Widget::create<ScrewBlack>(Vec(box.size.x - SCREW_DIAMETER, 0)));
  325. addChild(rhsScrews[0]);
  326. rhsScrews[1] = dynamic_cast<ScrewBlack*>(Widget::create<ScrewBlack>(Vec(box.size.x - SCREW_DIAMETER, box.size.y - SCREW_DIAMETER)));
  327. addChild(rhsScrews[1]);
  328. if (!isPreview)
  329. {
  330. scopeModule->firstLoad = true;
  331. scopeModule->initialized = true;
  332. }
  333. return;
  334. } // end multiScopeWidget()
  335. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  336. // step(void)
  337. // Resize.
  338. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  339. void multiScopeWidget::step() {
  340. multiScope* scopeModule = dynamic_cast<multiScope*>(module);
  341. static NVGcolor* lastEditColorPtr;
  342. if (scopeModule->initialized)
  343. {
  344. // Display toggle
  345. if (scopeModule->infoDisplayOnTrigger.process(scopeModule->params[multiScope::INFO_DISPLAY_TOGGLE_PARAM].value)) {
  346. scopeInfoDisplay->visible = !scopeInfoDisplay->visible;
  347. }
  348. scopeModule->lights[multiScope::INFO_DISPLAY_TOGGLE_LED].value = (scopeInfoDisplay->visible) ? 1.0 : 0.0;
  349. #if ENABLE_BG_COLOR_PICKER
  350. // Color Picker (On-Screen)
  351. for (int i = 0; i < 3; i++)
  352. {
  353. colorSliders[i]->visible = scopeModule->showColorPicker;
  354. }
  355. if (scopeModule->showColorPicker)
  356. {
  357. if (lastEditColorPtr == NULL || lastEditColorPtr != scopeModule->editColorPointer)
  358. {
  359. if (scopeModule->editColorPointer != NULL)
  360. {
  361. TSColorHSL selectedColor;
  362. trowaSoft::TSColorToHSL(*(scopeModule->editColorPointer), &selectedColor);
  363. // Load new color:
  364. for (int i = 0; i < 3; i++)
  365. {
  366. colorSliders[i]->value = clamp(selectedColor.hsl[i], 0.0f, 1.0f); // first slider is for hue, second is for sat, last is for value
  367. for (int j = i + 1; j < 3; j++)
  368. {
  369. colorSliders[j]->setComponent(i, selectedColor.hsl[i]);
  370. }
  371. }
  372. }
  373. } // end if
  374. else
  375. {
  376. // Read in color
  377. TSColorHSL selectedColor;
  378. for (int i = 0; i < 3; i++)
  379. {
  380. selectedColor.hsl[i] = colorSliders[i]->value;
  381. for (int j = i + 1; j < 3; j++)
  382. {
  383. colorSliders[j]->setComponent(i, selectedColor.hsl[i]);
  384. }
  385. }
  386. // Set our color
  387. if (scopeModule->editColorPointer != NULL)
  388. {
  389. *(scopeModule->editColorPointer) = nvgHSL(selectedColor.h, selectedColor.s, selectedColor.lum);
  390. }
  391. } // end else
  392. lastEditColorPtr = scopeModule->editColorPointer;
  393. } // end if we're showing the color picker
  394. #endif
  395. // Resizing ///////////////////////////////
  396. float width = box.size.x - inputAreaWidth - this->rightHandle->box.size.x;
  397. screenContainer->box.size.x = box.size.x - inputAreaWidth;
  398. TS_Panel* screenBg = screenContainer->getFirstDescendantOfType<TS_Panel>();
  399. if (screenBg)
  400. {
  401. screenBg->box.size.x = screenContainer->box.size.x - RACK_GRID_WIDTH;
  402. // Set background color of plot area:
  403. // Negative Image (Invert Color)
  404. if (scopeModule->negativeImage)
  405. {
  406. screenBg->backgroundColor = ColorInvertToNegative(scopeModule->plotBackgroundColor);
  407. }
  408. else
  409. {
  410. screenBg->backgroundColor = scopeModule->plotBackgroundColor;
  411. }
  412. }
  413. if (width - 15 < scopeInfoDisplay->box.size.x)
  414. {
  415. scopeInfoDisplay->box.size.x = width - 15;
  416. }
  417. else if (width - 15 > scopeInfoDisplay->box.size.x)
  418. {
  419. scopeInfoDisplay->box.size.x = (width - 15 > scopeInfoDisplay->originalWidth) ? scopeInfoDisplay->originalWidth : width - 15;
  420. }
  421. //float height = box.size.y - TROWA_WIDGET_TOP_BAR_HEIGHT * 2;
  422. for (int wIx = 0; wIx < TROWA_SCOPE_NUM_WAVEFORMS; wIx++)
  423. {
  424. display[wIx]->box.size.x = width;
  425. // Change light colors on plugs
  426. if (plugLightsEnabled)
  427. {
  428. //if (scopeModule->waveForms[wIx]->colorChanged) // When reloading from save, this doesn't work :(
  429. {
  430. inputPorts[multiScope::PEN_ON_INPUT + wIx]->setLightColor(scopeModule->waveForms[wIx]->waveColor);
  431. inputPorts[multiScope::OPACITY_INPUT + wIx]->setLightColor(scopeModule->waveForms[wIx]->waveColor);
  432. inputPorts[multiScope::COLOR_INPUT + wIx]->setLightColor(scopeModule->waveForms[wIx]->waveColor);
  433. inputPorts[multiScope::ROTATION_INPUT + wIx]->setLightColor(scopeModule->waveForms[wIx]->waveColor);
  434. inputPorts[multiScope::TIME_INPUT + wIx]->setLightColor(scopeModule->waveForms[wIx]->waveColor);
  435. inputPorts[multiScope::X_INPUT + wIx]->setLightColor(scopeModule->waveForms[wIx]->waveColor);
  436. inputPorts[multiScope::Y_INPUT + wIx]->setLightColor(scopeModule->waveForms[wIx]->waveColor);
  437. inputPorts[multiScope::THICKNESS_INPUT + wIx]->setLightColor(scopeModule->waveForms[wIx]->waveColor);
  438. inputPorts[multiScope::FILL_COLOR_INPUT + wIx]->setLightColor(scopeModule->waveForms[wIx]->fillColor);
  439. inputPorts[multiScope::FILL_OPACITY_INPUT + wIx]->setLightColor(scopeModule->waveForms[wIx]->fillColor);
  440. if (scopeModule->waveForms[wIx]->doFill)
  441. {
  442. fillColorLEDs[wIx]->setColor(scopeModule->waveForms[wIx]->fillColor);
  443. }
  444. }
  445. }
  446. // Adjusting Knobs ///////////////////////////////////////////////
  447. // Link X, Y scales
  448. int srcIx = -1;
  449. if (scopeModule->waveForms[wIx]->linkXYScalesTrigger.process(scopeModule->params[multiScope::LINK_XY_SCALE_PARAM + wIx].value))
  450. {
  451. scopeModule->waveForms[wIx]->linkXYScales = !scopeModule->waveForms[wIx]->linkXYScales;
  452. if (scopeModule->waveForms[wIx]->linkXYScales)
  453. {
  454. // Initial set up - make Y match X
  455. srcIx = KNOB_X;
  456. }
  457. }
  458. else if (scopeModule->waveForms[wIx]->linkXYScales)
  459. {
  460. // Check if any one changed.
  461. if (scopeModule->params[multiScope::X_SCALE_PARAM + wIx].value != scopeModule->waveForms[wIx]->lastXYScaleValue)
  462. srcIx = KNOB_X;
  463. else if (scopeModule->params[multiScope::Y_SCALE_PARAM + wIx].value != scopeModule->waveForms[wIx]->lastXYScaleValue)
  464. srcIx = KNOB_Y;
  465. }
  466. if (srcIx > -1)
  467. {
  468. int destIx = (srcIx == KNOB_X) ? KNOB_Y : KNOB_X;
  469. // Adjust the other knob
  470. float val = scaleKnobs[wIx][srcIx]->value;
  471. //info("Changing SRC: %d; DEST: %d to value of %f.", srcIx, destIx, val);
  472. scaleKnobs[wIx][destIx]->value = val;
  473. scaleKnobs[wIx][destIx]->dirty = true; // Set to dirty.
  474. // Change the value on thhe module param too?
  475. scopeModule->params[multiScope::X_SCALE_PARAM + wIx].value = val;
  476. scopeModule->params[multiScope::Y_SCALE_PARAM + wIx].value = val;
  477. scopeModule->waveForms[wIx]->lastXYScaleValue = val;
  478. }
  479. scopeModule->lights[multiScope::LINK_XY_SCALE_LED + wIx].value = (scopeModule->waveForms[wIx]->linkXYScales) ? 1.0 : 0;
  480. // end adjust Knobs for XY Scale Link //////////////////////////
  481. }
  482. for (int i = 0; i < 2; i++)
  483. {
  484. rhsScrews[i]->box.pos.x = box.size.x - SCREW_DIAMETER; // subtract screw diameter
  485. }
  486. rightHandle->box.pos.x = box.size.x - rightHandle->box.size.x;
  487. rightHandle->setChildPositions(); // Move the items that are artificially "in" this bar (really belong to multiScopeWidget, but should be rendered on top of rightHandle)
  488. ModuleWidget::step();
  489. }
  490. return;
  491. } // end step()
  492. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  493. // toJson(void)
  494. // Save to json.
  495. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  496. json_t *multiScopeWidget::toJson() {
  497. json_t *rootJ = ModuleWidget::toJson();
  498. json_object_set_new(rootJ, "width", json_real(box.size.x));
  499. json_object_set_new(rootJ, "showInfoDisplay", json_integer(scopeInfoDisplay->visible));
  500. return rootJ;
  501. } // end toJson()
  502. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  503. // fromJson()
  504. // Load from json object.
  505. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  506. void multiScopeWidget::fromJson(json_t *rootJ) {
  507. ModuleWidget::fromJson(rootJ);
  508. json_t *widthJ = json_object_get(rootJ, "width");
  509. if (widthJ)
  510. box.size.x = json_number_value(widthJ);
  511. json_t* showInfoJ = json_object_get(rootJ, "showInfoDisplay");
  512. if (showInfoJ)
  513. scopeInfoDisplay->visible = (bool)json_integer_value(showInfoJ);
  514. } // end fromJson()
  515. #endif // use new scope