diff --git a/src/surge-xt/gui/overlays/LuaEditors.cpp b/src/surge-xt/gui/overlays/LuaEditors.cpp index 6a6b76c0b99..8a718aae77c 100644 --- a/src/surge-xt/gui/overlays/LuaEditors.cpp +++ b/src/surge-xt/gui/overlays/LuaEditors.cpp @@ -35,7 +35,6 @@ #include "widgets/MenuCustomComponents.h" #include #include "widgets/OscillatorWaveformDisplay.h" -#include namespace Surge { @@ -166,6 +165,7 @@ CodeEditorContainerWithApply::CodeEditorContainerWithApply(SurgeGUIEditor *ed, S mainDocument = std::make_unique(); mainDocument->addListener(this); + mainDocument->setNewLineCharacters("\n"); tokenizer = std::make_unique(); mainEditor = std::make_unique(*mainDocument, tokenizer.get()); @@ -307,23 +307,37 @@ bool CodeEditorContainerWithApply::keyPressed(const juce::KeyPress &key, juce::C } } -void CodeEditorContainerWithApply::removeStringTrailsFromDocument() +void CodeEditorContainerWithApply::removeTrailingWhitespaceFromDocument() { + const auto caretPos = mainEditor->getCaretPos(); + const auto caretLine = caretPos.getLineNumber(); + const auto numLines = mainEditor->getDocument().getNumLines(); + uint32_t charsRemoved = 0; - /* - this needs some work as the caret position gets all screwed up after clean up - */ + for (int i = 0; i < numLines; i++) + { + juce::CodeDocument::Position lineStart{mainEditor->getDocument(), i, 0}; + auto s = lineStart.getLineText(); + const auto sizeOld = s.length() - 1; // disregard EOL + juce::CodeDocument::Position lineEnd{mainEditor->getDocument(), i, sizeOld}; + + s = s.trimEnd(); - /* - auto caretPos = mainEditor->getCaretPos(); + const auto sizeNew = s.length(); + + if (i <= caretLine && sizeOld > sizeNew) + { + charsRemoved += sizeOld - sizeNew; - std::string s = mainEditor->getDocument().getAllContent().toStdString(); - std::regex pattern("[ \t]+$"); - std::string replacement = ""; - std::string result = std::regex_replace(s, pattern, replacement); - mainEditor->getDocument().replaceAllContent(result); - mainEditor->moveCaretTo(caretPos, false); - */ + if (sizeOld - sizeNew > 0) + { + mainEditor->getDocument().replaceSection(lineStart.getPosition(), + lineEnd.getPosition(), s); + } + } + } + + mainEditor->moveCaretTo(caretPos.movedBy(-charsRemoved), false); } bool CodeEditorContainerWithApply::autoCompleteStringDeclaration(juce::String str) @@ -931,7 +945,8 @@ void FormulaModulatorEditor::onSkinChanged() void FormulaModulatorEditor::applyCode() { - removeStringTrailsFromDocument(); + removeTrailingWhitespaceFromDocument(); + editor->undoManager()->pushFormula(scene, lfo_id, *formulastorage); formulastorage->setFormula(mainDocument->getAllContent().toStdString()); storage->getPatch().isDirty = true; @@ -1110,39 +1125,43 @@ struct WavetablePreviewComponent : public juce::Component, public Surge::GUI::Sk juce::Rectangle drawArea(axisSpaceX, 0, width - axisSpaceX, height); juce::Rectangle vaxisArea(0, 0, axisSpaceX, height); - // auto primaryFont = skin->fontManager->getLatoAtSize(9, juce::Font::bold); - auto secondaryFont = skin->fontManager->getLatoAtSize(7); + auto font = skin->fontManager->getLatoAtSize(8); g.setColour(skin->getColor(Colors::MSEGEditor::Background)); g.fillRect(drawArea); // Vertical axis - std::vector txt = {"1.0", "0.0", "-1.0"}; - g.setFont(secondaryFont); - g.setColour(skin->getColor(Colors::MSEGEditor::Axis::SecondaryText)); - g.drawText(txt[0], vaxisArea.getX() - 3, 4, vaxisArea.getWidth(), 12, - juce::Justification::topRight); - g.drawText(txt[1], vaxisArea.getX() - 3, middle - 12, vaxisArea.getWidth(), 12, - juce::Justification::bottomRight); - g.drawText(txt[2], vaxisArea.getX() - 3, height - 14, vaxisArea.getWidth(), 12, - juce::Justification::centredRight); + if (axisSpaceX > 0) + { + std::vector txt = {"1.0", "0.0", "-1.0"}; + g.setFont(font); + g.setColour(skin->getColor(Colors::MSEGEditor::Axis::SecondaryText)); + g.drawText(txt[0], vaxisArea.getX() - 3, 4, vaxisArea.getWidth(), 12, + juce::Justification::topRight); + g.drawText(txt[1], vaxisArea.getX() - 3, middle - 12, vaxisArea.getWidth(), 12, + juce::Justification::bottomRight); + g.drawText(txt[2], vaxisArea.getX() - 3, height - 14, vaxisArea.getWidth(), 12, + juce::Justification::centredRight); + } if (mode == 0) { // Grid g.setColour(skin->getColor(Colors::MSEGEditor::Grid::SecondaryHorizontal)); + for (float y : {0.25f, 0.75f}) g.drawLine(drawArea.getX() - 8, height * y, width, height * y); g.setColour(skin->getColor(Colors::MSEGEditor::Grid::SecondaryVertical)); + for (float x : {0.25f, 0.5f, 0.75f}) g.drawLine(drawArea.getX() + drawArea.getWidth() * x, 0, drawArea.getX() + drawArea.getWidth() * x, height); // Borders g.setColour(skin->getColor(Colors::MSEGEditor::Grid::Primary)); - g.drawLine(4, 0, width, 0); - g.drawLine(4, height, width, height); + g.drawLine(0, 0, width, 0); + g.drawLine(0, height, width, height); g.drawLine(axisSpaceX, 0, axisSpaceX, height); g.drawLine(width, 0, width, height); g.drawLine(axisSpaceX, middle, width, middle); @@ -1152,6 +1171,7 @@ struct WavetablePreviewComponent : public juce::Component, public Surge::GUI::Sk if (!points.empty()) { float dx = (width - axisSpaceX) / float(points.size() - 1); + for (int i = 0; i < points.size(); ++i) { float xp = dx * i; @@ -1182,39 +1202,59 @@ struct WavetablePreviewComponent : public juce::Component, public Surge::GUI::Sk g.setColour(skin->getColor(Colors::MSEGEditor::Curve)); g.strokePath(p, juce::PathStrokeType(1.0)); } + + // Text + g.setFont(font); + g.setColour(skin->getColor(Colors::MSEGEditor::Axis::Text)); + g.drawText(std::to_string(frameNumber), axisSpaceX + 4, 4, width - 8, height - 8, + juce::Justification::topRight); } else { assert(mode == 1); // there are only two modes right now - // Grid - g.setColour(skin->getColor(Colors::MSEGEditor::Grid::SecondaryHorizontal)); - for (float y : {0.25f, 0.75f}) - g.drawLine(drawArea.getX() - 8, height * y, width, height * y); - - // Borders - g.setColour(skin->getColor(Colors::MSEGEditor::Grid::Primary)); - g.drawLine(4, 0, width, 0); - g.drawLine(4, height, width, height); - g.drawLine(axisSpaceX, 0, axisSpaceX, height); - g.drawLine(width, 0, width, height); - g.drawLine(axisSpaceX, middle, width, middle); auto gs = juce::Graphics::ScopedSaveState(g); g.reduceClipRegion(axisSpaceX, 0, width - axisSpaceX, height); auto xpos = startX; int idx{0}; + for (const auto &cpoint : fsPoints) { g.setColour(skin->getColor(Colors::MSEGEditor::Grid::Primary)); - g.drawVerticalLine(xpos + axisSpaceX, 0, height); auto p = juce::Path(); auto pStroke = juce::Path(); + + // alternate checkerboard bg + auto bgColor = skin->getColor((Colors::MSEGEditor::Background)); + + constexpr double brightnessThresh = 0.1; + constexpr double brightnessDelta = 0.1; + + if (idx % 2 == 1) + { + if (bgColor.getBrightness() < brightnessThresh) + { + g.setColour(bgColor.brighter(brightnessDelta)); + } + else + { + g.setColour(bgColor.darker(brightnessDelta * 2.0)); + } + } + else + { + g.setColour(bgColor); + } + + g.fillRect(xpos + axisSpaceX, 0, height, height); + if (!cpoint.empty()) { float dx = (height) / float(cpoint.size() - 1); float xp{0}; + for (int i = 0; i < cpoint.size(); ++i) { xp = dx * i + xpos; @@ -1253,19 +1293,24 @@ struct WavetablePreviewComponent : public juce::Component, public Surge::GUI::Sk g.strokePath(pStroke, juce::PathStrokeType(1.0)); } - g.setFont(secondaryFont); - g.setColour(skin->getColor(Colors::MSEGEditor::Grid::Primary)); - g.drawText(std::to_string(idx + 1), xpos + axisSpaceX + 4, 2, height - 5, - height - 5, juce::Justification::topLeft); + g.setFont(font); + g.setColour(skin->getColor(Colors::MSEGEditor::Axis::Text)); + g.drawText(std::to_string(idx + 1), xpos + axisSpaceX + 4, 4, height - 8, + height - 8, juce::Justification::topRight); idx++; - g.setColour(skin->getColor(Colors::MSEGEditor::Background)); - g.fillRect(xpos + height + axisSpaceX, 0, fsGap, height); - g.setColour(skin->getColor(Colors::MSEGEditor::Grid::Primary)); g.drawVerticalLine(xpos + height + axisSpaceX, 0, height); + xpos += height + fsGap; } + + // Borders + g.setColour(skin->getColor(Colors::MSEGEditor::Grid::Primary)); + g.drawLine(0, 0, width, 0); + g.drawLine(0, height, width, height); + g.drawLine(axisSpaceX, 0, axisSpaceX, height); + g.drawLine(width, 0, width, height); } } @@ -1407,8 +1452,8 @@ struct WavetablePreviewComponent : public juce::Component, public Surge::GUI::Sk private: int lastDrag; int startX{0}; - static constexpr int fsGap{6}; - static constexpr int axisSpaceX{18}; + static constexpr int fsGap{0}; + static constexpr int axisSpaceX{0}; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WavetablePreviewComponent); }; @@ -1982,7 +2027,8 @@ void WavetableScriptEditor::setupEvaluator() void WavetableScriptEditor::applyCode() { - removeStringTrailsFromDocument(); + removeTrailingWhitespaceFromDocument(); + osc->wavetable_formula = mainDocument->getAllContent().toStdString(); osc->wavetable_formula_res_base = controlArea->resolutionN->getIntValue(); osc->wavetable_formula_nframes = controlArea->framesN->getIntValue(); diff --git a/src/surge-xt/gui/overlays/LuaEditors.h b/src/surge-xt/gui/overlays/LuaEditors.h index eb161b6520b..12f4bce6b3f 100644 --- a/src/surge-xt/gui/overlays/LuaEditors.h +++ b/src/surge-xt/gui/overlays/LuaEditors.h @@ -66,7 +66,7 @@ class CodeEditorContainerWithApply : public OverlayComponent, void buttonClicked(juce::Button *button) override; void codeDocumentTextDeleted(int startIndex, int endIndex) override; void codeDocumentTextInserted(const juce::String &newText, int insertIndex) override; - void removeStringTrailsFromDocument(); + void removeTrailingWhitespaceFromDocument(); bool autoCompleteStringDeclaration(juce::String str); bool keyPressed(const juce::KeyPress &key, Component *originatingComponent) override; diff --git a/src/surge-xt/gui/widgets/OscillatorWaveformDisplay.cpp b/src/surge-xt/gui/widgets/OscillatorWaveformDisplay.cpp index fc6d67eae34..e4a7a6c966c 100644 --- a/src/surge-xt/gui/widgets/OscillatorWaveformDisplay.cpp +++ b/src/surge-xt/gui/widgets/OscillatorWaveformDisplay.cpp @@ -36,6 +36,9 @@ #include "UserDefaults.h" #include "fmt/core.h" +// Change this to 0 to disable WTSE component, to disable for release: change value, test, and push +#define INCLUDE_WT_SCRIPTING_EDITOR 1 + namespace Surge { namespace Widgets @@ -599,11 +602,7 @@ void OscillatorWaveformDisplay::populateMenu(juce::PopupMenu &contextMenu, int s contextMenu.addSeparator(); -// Change this to 0 to disable WTSE component, to disable for release: change value, test, and push -#define INCLUDE_WT_SCRIPTING_EDITOR 1 #if INCLUDE_WT_SCRIPTING_EDITOR - contextMenu.addSeparator(); - auto owts = [this]() { if (sge) sge->showOverlay(SurgeGUIEditor::WTSCRIPT_EDITOR); @@ -716,6 +715,18 @@ void OscillatorWaveformDisplay::createWTMenuItems(juce::PopupMenu &contextMenu, contextMenu.addItem(Surge::GUI::toOSCase(text), action); +#if INCLUDE_WT_SCRIPTING_EDITOR + contextMenu.addSeparator(); + + auto owts = [this]() { + if (sge) + sge->showOverlay(SurgeGUIEditor::WTSCRIPT_EDITOR); + }; + + contextMenu.addItem(Surge::GUI::toOSCase("Wavetable Script Editor..."), owts); + contextMenu.addSeparator(); +#endif + contextMenu.addSeparator(); Surge::Widgets::MenuCenteredBoldLabel::addToMenuAsSectionHeader(contextMenu, "INFO");