ComputerscareILoveCookies.cpp (25334B)
1 #include "Computerscare.hpp" 2 #include "dtpulse.hpp" 3 4 #include <string> 5 #include <sstream> 6 #include <iomanip> 7 8 struct ComputerscareILoveCookies; 9 struct CookiesTF2; 10 struct CookiesSmallDisplay; 11 struct CookiesCurrentStepDisplay; 12 13 const int numFields = 6; 14 const int numKnobRows = 13; 15 const int numKnobColumns = 2; 16 const int numInputRows = 13; 17 const int numInputColumns = 2; 18 19 const int numKnobs = numKnobRows * numKnobColumns; 20 const int numInputs = numInputRows * numInputColumns; 21 const std::vector<NVGcolor> outlineColorMap = {COLOR_COMPUTERSCARE_RED, COLOR_COMPUTERSCARE_YELLOW, COLOR_COMPUTERSCARE_BLUE}; 22 23 const std::string uppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 24 25 struct ComputerscareILoveCookies : Module { 26 enum ParamIds { 27 KNOB_PARAM, 28 MANUAL_CLOCK_PARAM = KNOB_PARAM + numKnobs, 29 MANUAL_RESET_PARAM, 30 INDIVIDUAL_RESET_PARAM, 31 NUM_PARAMS = INDIVIDUAL_RESET_PARAM + numFields 32 }; 33 enum InputIds { 34 GLOBAL_CLOCK_INPUT, 35 GLOBAL_RESET_INPUT, 36 CLOCK_INPUT, 37 RESET_INPUT = CLOCK_INPUT + numFields, 38 SIGNAL_INPUT = RESET_INPUT + numFields , 39 NUM_INPUTS = SIGNAL_INPUT + numInputs 40 }; 41 enum OutputIds { 42 TRG_OUTPUT, 43 FIRST_STEP_OUTPUT = TRG_OUTPUT + numFields, 44 NUM_OUTPUTS = FIRST_STEP_OUTPUT + numFields 45 }; 46 enum LightIds { 47 SWITCH_LIGHTS, 48 NUM_LIGHTS = SWITCH_LIGHTS + (numKnobs + numInputs) * numFields 49 }; 50 51 rack::dsp::SchmittTrigger globalClockTrigger; 52 rack::dsp::SchmittTrigger globalResetTriggerInput; 53 54 rack::dsp::SchmittTrigger globalManualClockTrigger; 55 rack::dsp::SchmittTrigger globalManualResetTrigger; 56 57 rack::dsp::SchmittTrigger clockTriggers[numFields]; 58 rack::dsp::SchmittTrigger resetTriggers[numFields]; 59 60 rack::dsp::SchmittTrigger manualResetTriggers[numFields]; 61 62 SmallLetterDisplay* smallLetterDisplays[numFields]; 63 SmallLetterDisplay* currentWorkingStepDisplays[numFields]; 64 65 AbsoluteSequence newABS[numFields]; 66 AbsoluteSequence newABSQueue[numFields]; 67 68 std::string currentFormula[numFields]; 69 std::string currentTextFieldValue[numFields]; 70 71 std::string upcomingFormula[numFields]; 72 std::string lastValue[numFields]; 73 74 75 bool manualSet[numFields]; 76 bool inError[numFields]; 77 bool shouldChange[numFields] = {false}; 78 bool changeImminent[numFields] = {false}; 79 80 int activeKnobIndex[numFields] = {0}; 81 82 int knobRangeEnum = 0; 83 84 int checkCounter = 0; 85 int checkCounterLimit = 10000; 86 87 bool jsonLoaded = false; 88 89 std::vector<ParamWidget*> smallLetterKnobs; 90 91 ComputerscareILoveCookies() { 92 config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); 93 for (int i = 0; i < numFields; i++) { 94 manualSet[i] = false; 95 inError[i] = false; 96 97 currentFormula[i] = ""; 98 lastValue[i] = ""; 99 setNextAbsoluteSequence(i); 100 checkIfShouldChange(i); 101 resetOneOfThem(i); 102 103 std::string rowi = std::to_string(i + 1); 104 105 configButton(INDIVIDUAL_RESET_PARAM + i, "Reset Row " + rowi ); 106 107 configInput(CLOCK_INPUT + i, "Row " + rowi + " Clock"); 108 configInput(RESET_INPUT + i, "Row " + rowi + " Reset"); 109 110 configOutput(TRG_OUTPUT + i, "Row " + rowi + " CV"); 111 configOutput(FIRST_STEP_OUTPUT + i, "Row " + rowi + " End of Cycle"); 112 } 113 for (int k = 0; k < numKnobs; k++) { 114 configParam( KNOB_PARAM + k, 0.f, 10.f, 0.0f, string::f("knob %c", knoblookup[k])); 115 116 configInput(SIGNAL_INPUT + k, string::f("%c", uppercaseLetters.at(k))); 117 } 118 119 configButton(MANUAL_CLOCK_PARAM, "Manual Clock Advance"); 120 configButton(MANUAL_RESET_PARAM, "Manual Reset"); 121 122 configInput(GLOBAL_CLOCK_INPUT, "Global Clock"); 123 configInput(GLOBAL_RESET_INPUT, "Global Reset"); 124 125 } 126 json_t *dataToJson() override { 127 json_t *rootJ = json_object(); 128 129 json_t *sequencesJ = json_array(); 130 json_t *knobRangeJ = json_integer(knobRangeEnum); 131 132 for (int i = 0; i < numFields; i++) { 133 json_t *sequenceJ = json_string(currentTextFieldValue[i].c_str()); 134 json_array_append_new(sequencesJ, sequenceJ); 135 136 137 } 138 json_object_set_new(rootJ, "sequences", sequencesJ); 139 json_object_set_new(rootJ, "knobRange", knobRangeJ); 140 141 return rootJ; 142 } 143 144 void dataFromJson(json_t *rootJ) override { 145 std::string val; 146 int count; 147 json_t *sequencesJ = json_object_get(rootJ, "sequences"); 148 if (sequencesJ) { 149 for (int i = 0; i < numFields; i++) { 150 151 json_t *sequenceJ = json_array_get(sequencesJ, i); 152 if (sequenceJ) { 153 val = json_string_value(sequenceJ); 154 155 // currentFormula[i] = val; 156 //currentTextFieldValue[i] = val; 157 currentTextFieldValue[i] = val; 158 159 manualSet[i] = true; 160 } 161 } 162 jsonLoaded = true; 163 } 164 else { 165 json_t *textJLegacy = json_object_get(rootJ, "data"); 166 if (textJLegacy) { 167 json_t *seqJLegacy = json_object_get(textJLegacy, "sequences"); 168 169 if (seqJLegacy) { 170 for (int i = 0; i < numFields; i++) { 171 json_t *sequenceJ = json_array_get(seqJLegacy, i); 172 if (sequenceJ) 173 val = json_string_value(sequenceJ); 174 // currentFormula[i] = val; 175 //lastValue[i] = val; 176 currentTextFieldValue[i] = val; 177 //upcomingFormula[i]=val; 178 manualSet[i] = true; 179 180 } 181 } 182 } 183 } 184 json_t *knobRangeJ = json_object_get(rootJ, "knobRange"); 185 if (knobRangeJ) { 186 knobRangeEnum = json_integer_value(knobRangeJ); 187 } 188 189 190 } 191 void process(const ProcessArgs &args) override; 192 193 194 195 void onRandomize() override { 196 } 197 void randomizeShuffle() { 198 199 } 200 void wiggleKnobs() { 201 for (int i = 0; i < numKnobs; i++) { 202 float prev = params[KNOB_PARAM + i].getValue(); 203 if (random::uniform() < 0.7) { 204 float rv = (10 * random::uniform() + 2 * prev) / 3; 205 params[KNOB_PARAM + i].setValue(rv); 206 } 207 } 208 } 209 std::string randomCookieFormula() { 210 std::string mainlookup = knoblookup; 211 std::string str = ""; 212 std::string randchar = ""; 213 214 float ru; 215 int length = 0; 216 length = floor(random::uniform() * 12) + 2; 217 str = ""; 218 for (int j = 0; j < length; j++) { 219 randchar = mainlookup[floor(random::uniform() * mainlookup.size())]; 220 str = str + randchar; 221 ru = random::uniform(); 222 if (ru < 0.1) { 223 str = "(" + str + ")"; 224 } 225 } 226 return str; 227 } 228 229 void randomizeAllFields() { 230 for (int i = 0; i < numFields; i++) { 231 randomizeAField(i); 232 } 233 } 234 235 void randomizeAField(int i) { 236 currentTextFieldValue[i] = randomCookieFormula(); 237 manualSet[i] = true; 238 setNextAbsoluteSequence(i); 239 240 241 } 242 void setNextAbsoluteSequence(int index) { 243 newABSQueue[index] = AbsoluteSequence(upcomingFormula[index], knobandinputlookup); 244 shouldChange[index] = true; 245 } 246 void setAbsoluteSequenceFromQueue(int index) { 247 newABS[index] = newABSQueue[index]; 248 currentFormula[index] = upcomingFormula[index]; 249 newABS[index].incrementAndCheck(); 250 } 251 void checkIfShouldChange(int index) { 252 if (shouldChange[index]) { 253 setAbsoluteSequenceFromQueue(index); 254 shouldChange[index] = false; 255 } 256 } 257 258 void incrementInternalStep(int i) { 259 newABS[i].incrementAndCheck(); 260 if (newABS[i].readHead == 0) { 261 setChangeImminent(i, false); 262 checkIfShouldChange(i); 263 } 264 } 265 266 void resetOneOfThem(int i) { 267 newABS[i].readHead = -1; 268 } 269 void setChangeImminent(int i, bool value) { 270 changeImminent[i] = value; 271 } 272 std::string getDisplayString(int index) { 273 std::string lhs = std::to_string(this->newABS[index].readHead + 1); 274 std::string rhs = std::to_string(this->newABS[index].numTokens); 275 276 padTo(lhs, 3, ' '); 277 padTo(rhs, 3, ' '); 278 279 std::string val = lhs + "\n" + rhs; 280 281 return val; 282 } 283 float mapKnobValue(float rawValue, int rowIndex) { 284 // raw value is between 0 and +10 285 286 float mappedValue = 0.f; 287 int mapEnum = knobRangeEnum; 288 switch (mapEnum) { 289 case 0: mappedValue = rawValue; break;//0..10 290 case 1: mappedValue = mapValue(rawValue, 0.f, 0.5); break;//0..5 291 case 2: mappedValue = mapValue(rawValue, 0.f, 0.2); break;//0..2 292 case 3: mappedValue = mapValue(rawValue, 0.f, 0.1); break;//0..1 293 294 295 case 4: mappedValue = mapValue(rawValue, -5, 2.f); break;//-10..10 296 case 5: mappedValue = mapValue(rawValue, -5, 1.f); break;//-5..5 297 298 case 6: mappedValue = mapValue(rawValue, -5, 0.4); break;//-2..2 299 300 case 7: mappedValue = mapValue(rawValue, -5, 0.2); break;//-1..1 301 } 302 return mappedValue; 303 } 304 float mapValue(float input, float offset, float multiplier) { 305 return (input + offset) * multiplier; 306 } 307 void checkTextField(int channel) { 308 std::string textFieldValue = currentTextFieldValue[channel]; 309 310 if (textFieldValue != currentFormula[channel] && textFieldValue != upcomingFormula[channel]) { 311 312 AbsoluteSequence pendingSequence = AbsoluteSequence(textFieldValue, knobandinputlookup); 313 if (!pendingSequence.inError && matchParens(textFieldValue)) { 314 upcomingFormula[channel] = textFieldValue; 315 setNextAbsoluteSequence(channel); 316 inError[channel] = false; 317 } 318 else { 319 inError[channel] = true; 320 } 321 } 322 323 } 324 325 }; 326 327 328 void ComputerscareILoveCookies::process(const ProcessArgs &args) { 329 330 331 bool globalGateIn = globalClockTrigger.isHigh(); 332 bool activeStep = 0; 333 bool atFirstStep = false; 334 bool globalTriggerClocked = globalClockTrigger.process(inputs[GLOBAL_CLOCK_INPUT].getVoltage()); 335 bool globalManualResetClicked = globalManualResetTrigger.process(params[MANUAL_RESET_PARAM].getValue()); 336 bool globalManualClockClicked = globalManualClockTrigger.process(params[MANUAL_CLOCK_PARAM].getValue()); 337 bool currentTriggerIsHigh; 338 bool currentTriggerClocked; 339 bool globalResetTriggered = globalResetTriggerInput.process(inputs[GLOBAL_RESET_INPUT].getVoltage() / 2.f); 340 bool currentResetActive; 341 bool currentResetTriggered; 342 bool currentManualResetClicked; 343 bool outputConnected; 344 float knobRawValue = 0.f; 345 float inV[16] = {10.f}; 346 347 if (checkCounter > checkCounterLimit) { 348 if (!jsonLoaded) { 349 for (int i = 0; i < numFields; i++) { 350 //currentTextFieldValue[i] = i < numFields - 1 ? std::to_string(i + 1) : "abcd"; 351 manualSet[i] = true; 352 } 353 for (int i = 0; i < numFields; i++) { 354 checkTextField(i); 355 checkIfShouldChange(i); 356 } 357 jsonLoaded = true; 358 } 359 else { 360 for (int i = 0; i < numFields; i++) { 361 checkTextField(i); 362 } 363 } 364 checkCounter = 0; 365 } 366 checkCounter++; 367 368 for (int i = 0; i < numFields; i++) { 369 activeStep = false; 370 currentResetActive = inputs[RESET_INPUT + i].isConnected(); 371 outputConnected = outputs[TRG_OUTPUT + i].isConnected(); 372 373 currentResetTriggered = resetTriggers[i].process(inputs[RESET_INPUT + i].getVoltage() / 2.f); 374 currentManualResetClicked = manualResetTriggers[i].process(params[INDIVIDUAL_RESET_PARAM + i].getValue()); 375 376 currentTriggerIsHigh = clockTriggers[i].isHigh(); 377 currentTriggerClocked = clockTriggers[i].process(inputs[CLOCK_INPUT + i].getVoltage()); 378 379 if (true) { 380 if (inputs[CLOCK_INPUT + i].isConnected()) { 381 if (currentTriggerClocked) { 382 incrementInternalStep(i); 383 activeKnobIndex[i] = newABS[i].peekWorkingStep(); 384 } 385 } 386 else { 387 if ((inputs[GLOBAL_CLOCK_INPUT].isConnected() && globalTriggerClocked) || globalManualClockClicked) { 388 incrementInternalStep(i); 389 activeKnobIndex[i] = newABS[i].peekWorkingStep(); 390 } 391 } 392 if ((currentResetActive && currentResetTriggered) || (!currentResetActive && globalResetTriggered)) { 393 resetOneOfThem(i); 394 } 395 396 atFirstStep = (newABS[i].readHead == 0); 397 398 if (globalManualResetClicked || currentManualResetClicked) { 399 setChangeImminent(i, true); 400 resetOneOfThem(i); 401 } 402 if ( (currentResetActive && currentResetTriggered) || (!currentResetActive && globalResetTriggered)) { 403 resetOneOfThem(i); 404 setChangeImminent(i, false); 405 } 406 else { 407 if (atFirstStep && !currentResetActive && !inputs[GLOBAL_RESET_INPUT].isConnected()) { 408 //checkIfShouldChange(i); 409 } 410 } 411 } 412 if (outputConnected) { 413 if (activeKnobIndex[i] < 0) { 414 outputs[TRG_OUTPUT + i].setChannels(1); 415 outputs[TRG_OUTPUT + i].setVoltage(0.f); 416 } 417 else if (activeKnobIndex[i] < 26) { 418 outputs[TRG_OUTPUT + i].setChannels(1); 419 knobRawValue = params[activeKnobIndex[i]].getValue(); 420 outputs[TRG_OUTPUT + i].setVoltage(mapKnobValue(knobRawValue, i)); 421 } 422 else if (activeKnobIndex[i] < 52) { 423 outputs[TRG_OUTPUT + i].setChannels(inputs[SIGNAL_INPUT + activeKnobIndex[i] - 26].getChannels()); 424 inputs[SIGNAL_INPUT + activeKnobIndex[i] - 26].readVoltages(inV); 425 outputs[TRG_OUTPUT + i].writeVoltages(inV); 426 } 427 else if (activeKnobIndex[i] < 78) { 428 outputs[TRG_OUTPUT + i].setChannels(1); 429 outputs[TRG_OUTPUT + i].setVoltage(newABS[i].exactFloats[activeKnobIndex[i] - 52]); 430 } 431 else if (activeKnobIndex[i] < 104) { 432 outputs[TRG_OUTPUT + i].setChannels(1); 433 outputs[TRG_OUTPUT + i].setVoltage(2.22); 434 } 435 else { 436 outputs[TRG_OUTPUT + i].setChannels(1); 437 outputs[TRG_OUTPUT + i].setVoltage(0.f); 438 } 439 } 440 if (inputs[CLOCK_INPUT + i].isConnected()) { 441 outputs[FIRST_STEP_OUTPUT + i].setVoltage((currentTriggerIsHigh && atFirstStep) ? 10.f : 0.0f); 442 } 443 else { 444 outputs[FIRST_STEP_OUTPUT + i].setVoltage((globalGateIn && atFirstStep) ? 10.f : 0.0f); 445 } 446 } 447 } 448 449 450 struct WiggleKnobsMenuItem : MenuItem { 451 ComputerscareILoveCookies *cookies; 452 void onAction(const event::Action &e) override { 453 cookies->wiggleKnobs(); 454 } 455 }; 456 struct RandomizeTextFieldsMenuItem : MenuItem { 457 ComputerscareILoveCookies *cookies; 458 void onAction(const event::Action &e) override { 459 srand(time(0)); 460 cookies->randomizeAllFields(); 461 462 } 463 }; 464 struct CookiesKnobRangeItem : MenuItem { 465 ComputerscareILoveCookies *cookies; 466 int knobRangeEnum; 467 void onAction(const event::Action &e) override { 468 cookies->knobRangeEnum = knobRangeEnum; 469 } 470 void step() override { 471 rightText = CHECKMARK(cookies->knobRangeEnum == knobRangeEnum); 472 MenuItem::step(); 473 } 474 }; 475 struct CookiesTF2 : ComputerscareTextField 476 { 477 ComputerscareILoveCookies *module; 478 int rowIndex = 0; 479 480 CookiesTF2(int i) 481 { 482 rowIndex = i; 483 dimWithRoom = false; 484 ComputerscareTextField(); 485 }; 486 void draw(const DrawArgs &args) override 487 { 488 if (module) 489 { 490 if (module->manualSet[rowIndex]) { 491 text = module->currentTextFieldValue[rowIndex]; 492 module->manualSet[rowIndex] = false; 493 } 494 std::string value = text.c_str(); 495 module->currentTextFieldValue[rowIndex] = value; 496 inError = module->inError[rowIndex]; 497 } 498 else { 499 text = "we,love{}@9,cook(ies)"; 500 } 501 ComputerscareTextField::draw(args); 502 } 503 }; 504 505 struct CookiesSmallDisplay : SmallLetterDisplay 506 { 507 ComputerscareILoveCookies *module; 508 int type; 509 int index; 510 CookiesSmallDisplay(int i) 511 { 512 index = i; 513 SmallLetterDisplay(); 514 }; 515 void draw(const DrawArgs &args) 516 { 517 //this->setNumDivisionsString(); 518 if (module) 519 { 520 value = module->getDisplayString(index); 521 blink = module->shouldChange[index]; 522 doubleblink = module->changeImminent[index]; 523 SmallLetterDisplay::draw(args); 524 } 525 else { 526 value = "4\n20"; 527 SmallLetterDisplay::draw(args); 528 } 529 } 530 531 }; 532 struct CookiesCurrentStepDisplay : SmallLetterDisplay 533 { 534 ComputerscareILoveCookies *module; 535 int type; 536 int index; 537 CookiesCurrentStepDisplay(int i) 538 { 539 index = i; 540 fontSize = 26; 541 textAlign = 4; 542 SmallLetterDisplay(); 543 }; 544 void draw(const DrawArgs &args) 545 { 546 if (module) 547 { 548 value = module->newABS[index].getWorkingStepDisplay(); 549 550 SmallLetterDisplay::draw(args); 551 } 552 } 553 554 }; 555 556 struct ComputerscareILoveCookiesWidget : ModuleWidget { 557 558 double verticalSpacing = 18.4; 559 int verticalStart = 24; 560 double xStart = 41; 561 int index = 0; 562 int inputindex = 0; 563 double knobPosX = 0.0; 564 double knobPosY = 0.0; 565 double knobXStart = 20; 566 double knobYStart = 2; 567 double knobRowWidth = 11; 568 double knobColumnHeight = 9.58; 569 570 double inputPosX = 0.0; 571 double inputPosY = 0.0; 572 double inputXStart = 0; 573 double inputYStart = 0; 574 double inputRowWidth = 9.4; 575 double inputColumnHeight = 9.7; 576 577 ComputerscareILoveCookiesWidget(ComputerscareILoveCookies *module) { 578 setModule(module); 579 setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ComputerscareILoveCookiesPanel.svg"))); 580 581 for (int i = 0; i < numKnobRows; i++) { 582 for (int j = 0; j < numKnobColumns; j++) { 583 knobPosX = knobXStart + j * knobRowWidth; 584 knobPosY = knobYStart + i * knobColumnHeight + j * 2.0; 585 index = numKnobColumns * i + j; 586 587 588 //label for knob a-z 589 smallLetterDisplay = new SmallLetterDisplay(); 590 smallLetterDisplay->box.pos = mm2px(Vec(knobPosX + 6, knobPosY - 2)); 591 smallLetterDisplay->box.size = Vec(20, 20); 592 smallLetterDisplay->value = knoblookup[index]; 593 594 addChild(smallLetterDisplay); 595 596 ParamWidget* knob = createParam<SmoothKnob>(mm2px(Vec(knobPosX, knobPosY)), module, ComputerscareILoveCookies::KNOB_PARAM + index); 597 598 //module->smallLetterKnobs.push_back(knob); 599 addParam(knob); 600 601 } 602 } 603 for (int k = 0; k < numInputRows; k++) { 604 for (int m = 0; m < numInputColumns; m++) { 605 inputPosX = inputXStart + m * inputRowWidth; 606 inputPosY = inputYStart + k * inputColumnHeight + m * 2.0; 607 inputindex = numInputColumns * k + m; 608 609 if (m % 2) { 610 addInput(createInput<InPort>(mm2px(Vec(inputPosX , inputPosY)), module, ComputerscareILoveCookies::SIGNAL_INPUT + inputindex)); 611 } 612 else { 613 addInput(createInput<PointingUpPentagonPort>(mm2px(Vec(inputPosX , inputPosY)), module, ComputerscareILoveCookies::SIGNAL_INPUT + inputindex)); 614 } 615 616 //label for input A-Z 617 smallLetterDisplay = new SmallLetterDisplay(); 618 smallLetterDisplay->box.pos = mm2px(Vec(inputPosX + 6, inputPosY - 1)); 619 smallLetterDisplay->box.size = Vec(20, 20); 620 smallLetterDisplay->value = inputlookup[inputindex]; 621 622 addChild(smallLetterDisplay); 623 //module->smallLetterDisplays[i] = smallLetterDisplay; 624 } 625 } 626 627 //global clock input 628 addInput(createInput<InPort>(mm2px(Vec(2 + xStart , 0)), module, ComputerscareILoveCookies::GLOBAL_CLOCK_INPUT)); 629 630 //global reset input 631 addInput(createInput<InPort>(mm2px(Vec(12 + xStart , 0)), module, ComputerscareILoveCookies::GLOBAL_RESET_INPUT)); 632 addParam(createParam<ComputerscareResetButton>(mm2px(Vec(12 + xStart , 9)), module, ComputerscareILoveCookies::MANUAL_RESET_PARAM)); 633 addParam(createParam<ComputerscareClockButton>(mm2px(Vec(2 + xStart , 9)), module, ComputerscareILoveCookies::MANUAL_CLOCK_PARAM)); 634 635 636 for (int i = 0; i < numFields; i++) { 637 //first-step output 638 addOutput(createOutput<OutPort>(mm2px(Vec(42 + xStart , verticalStart + verticalSpacing * i - 11)), module, ComputerscareILoveCookies::FIRST_STEP_OUTPUT + i)); 639 640 //individual output 641 addOutput(createOutput<OutPort>(mm2px(Vec(54 + xStart , verticalStart + verticalSpacing * i - 11)), module, ComputerscareILoveCookies::TRG_OUTPUT + i)); 642 643 //individual clock input 644 addInput(createInput<InPort>(mm2px(Vec(2 + xStart, verticalStart + verticalSpacing * i - 10)), module, ComputerscareILoveCookies::CLOCK_INPUT + i)); 645 646 //individual reset input 647 addInput(createInput<InPort>(mm2px(Vec(12 + xStart, verticalStart + verticalSpacing * i - 10)), module, ComputerscareILoveCookies::RESET_INPUT + i)); 648 649 //sequence input field 650 textField = new CookiesTF2(i); 651 textField->box.pos = mm2px(Vec(1 + xStart, verticalStart + verticalSpacing * i)); 652 textField->box.size = mm2px(Vec(63, 7)); 653 textField->multiline = false; 654 textField->color = nvgRGB(0xC0, 0xE7, 0xDE); 655 textField->module = module; 656 addChild(textField); 657 cookiesTextFields[i] = textField; 658 659 //active/total steps display 660 cookiesSmallDisplay = new CookiesSmallDisplay(i); 661 cookiesSmallDisplay->box.pos = mm2px(Vec(21 + xStart, verticalStart - 9.2 + verticalSpacing * i)); 662 cookiesSmallDisplay->box.size = Vec(60, 30); 663 cookiesSmallDisplay->baseColor = COLOR_COMPUTERSCARE_LIGHT_GREEN; 664 cookiesSmallDisplay->value = "?\n?"; 665 addChild(cookiesSmallDisplay); 666 cookiesSmallDisplay->module = module; 667 cookiesSmallDisplays[i] = cookiesSmallDisplay; 668 669 //active/total steps display 670 currentWorkingStepDisplay = new CookiesCurrentStepDisplay(i); 671 currentWorkingStepDisplay->box.pos = mm2px(Vec(11 + xStart, verticalStart - 7.0 + verticalSpacing * i)); 672 currentWorkingStepDisplay->box.size = mm2px(Vec(2, 10)); 673 674 currentWorkingStepDisplay->value = "?"; 675 currentWorkingStepDisplay->module = module; 676 addChild(currentWorkingStepDisplay); 677 currentWorkingStepDisplays[i] = currentWorkingStepDisplay; 678 679 addParam(createParam<ComputerscareInvisibleButton>(mm2px(Vec(21 + xStart, verticalStart - 9.9 + verticalSpacing * i)), module, ComputerscareILoveCookies::INDIVIDUAL_RESET_PARAM + i)); 680 } 681 cookies = module; 682 } 683 684 685 /*void fromJson(json_t *rootJ) override 686 { std::string val; 687 ModuleWidget::fromJson(rootJ); 688 json_t *sequencesJ = json_object_get(rootJ, "sequences");//legacy 689 if (sequencesJ) { 690 for (int i = 0; i < numFields; i++) { 691 json_t *sequenceJ = json_array_get(sequencesJ, i); 692 if (sequenceJ) { 693 val = json_string_value(sequenceJ); 694 cookies->currentTextFieldValue[i] = val; 695 cookies->manualSet[i] = true; 696 } 697 } 698 cookies->jsonLoaded = true; 699 } 700 else { 701 json_t *textJLegacy = json_object_get(rootJ, "data"); 702 if (textJLegacy) { 703 json_t *seqJLegacy = json_object_get(textJLegacy, "sequences"); 704 705 if (seqJLegacy) { 706 for (int i = 0; i < numFields; i++) { 707 json_t *sequenceJ = json_array_get(seqJLegacy, i); 708 if (sequenceJ) 709 val = json_string_value(sequenceJ); 710 cookiesTextFields[i]->text = val; 711 cookies->currentFormula[i] = val; 712 } 713 } 714 } 715 } 716 }*/ 717 718 719 ComputerscareILoveCookies *cookies; 720 721 CookiesTF2 *textField; 722 CookiesTF2 *cookiesTextFields[numFields]; 723 724 725 726 CookiesSmallDisplay* cookiesSmallDisplay; 727 CookiesSmallDisplay* cookiesSmallDisplays[numFields]; 728 729 SmallLetterDisplay* smallLetterDisplay; 730 731 CookiesCurrentStepDisplay* currentWorkingStepDisplay; 732 CookiesCurrentStepDisplay* currentWorkingStepDisplays[numFields]; 733 734 735 void appendContextMenu(Menu *menu) override; 736 }; 737 738 void ComputerscareILoveCookiesWidget::appendContextMenu(Menu *menu) { 739 ComputerscareILoveCookies *cookiesModule = dynamic_cast<ComputerscareILoveCookies *>(this->module); 740 741 MenuLabel *spacerLabel = new MenuLabel(); 742 menu->addChild(spacerLabel); 743 744 MenuLabel *modeLabel = new MenuLabel(); 745 modeLabel->text = "Premium Randomizations"; 746 menu->addChild(modeLabel); 747 748 WiggleKnobsMenuItem *wiggleKnobsMenuItem = new WiggleKnobsMenuItem(); 749 wiggleKnobsMenuItem->text = "Wiggle Knobs"; 750 wiggleKnobsMenuItem->cookies = cookiesModule; 751 menu->addChild(wiggleKnobsMenuItem); 752 753 RandomizeTextFieldsMenuItem *randomizeTextFieldsMenuItem = new RandomizeTextFieldsMenuItem(); 754 randomizeTextFieldsMenuItem->text = "Randomize Text Fields"; 755 randomizeTextFieldsMenuItem->cookies = cookiesModule; 756 menu->addChild(randomizeTextFieldsMenuItem); 757 758 759 menu->addChild(construct<MenuLabel>()); 760 menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Knob Range")); 761 menu->addChild(construct<CookiesKnobRangeItem>(&MenuItem::text, " 0v ... +10v", &CookiesKnobRangeItem::cookies, cookiesModule, &CookiesKnobRangeItem::knobRangeEnum, 0)); 762 menu->addChild(construct<CookiesKnobRangeItem>(&MenuItem::text, " 0v ... +5v", &CookiesKnobRangeItem::cookies, cookiesModule, &CookiesKnobRangeItem::knobRangeEnum, 1)); 763 menu->addChild(construct<CookiesKnobRangeItem>(&MenuItem::text, " 0v ... +2v", &CookiesKnobRangeItem::cookies, cookiesModule, &CookiesKnobRangeItem::knobRangeEnum, 2)); 764 menu->addChild(construct<CookiesKnobRangeItem>(&MenuItem::text, " 0v ... +1v", &CookiesKnobRangeItem::cookies, cookiesModule, &CookiesKnobRangeItem::knobRangeEnum, 3)); 765 menu->addChild(construct<CookiesKnobRangeItem>(&MenuItem::text, "-10v ... +10v", &CookiesKnobRangeItem::cookies, cookiesModule, &CookiesKnobRangeItem::knobRangeEnum, 4)); 766 menu->addChild(construct<CookiesKnobRangeItem>(&MenuItem::text, " -5v ... +5v", &CookiesKnobRangeItem::cookies, cookiesModule, &CookiesKnobRangeItem::knobRangeEnum, 5)); 767 menu->addChild(construct<CookiesKnobRangeItem>(&MenuItem::text, " -2v ... +2v", &CookiesKnobRangeItem::cookies, cookiesModule, &CookiesKnobRangeItem::knobRangeEnum, 6)); 768 menu->addChild(construct<CookiesKnobRangeItem>(&MenuItem::text, " -1v ... +1v", &CookiesKnobRangeItem::cookies, cookiesModule, &CookiesKnobRangeItem::knobRangeEnum, 7)); 769 770 }; 771 772 773 774 775 776 777 Model *modelComputerscareILoveCookies = createModel<ComputerscareILoveCookies, ComputerscareILoveCookiesWidget>("computerscare-i-love-cookies");