From 3f8af3d4e83a79e332ef3bfd86c57398720a4c4d Mon Sep 17 00:00:00 2001 From: zsliu98 Date: Tue, 31 Dec 2024 12:12:25 -0500 Subject: [PATCH] fix(match analyzer panel): use draggers to control low/high cut --- source/gui/dragger2d/dragger_component.cpp | 19 +++--- source/gui/dragger2d/dragger_component.hpp | 10 ++- .../gui/dragger2d/dragger_look_and_feel.hpp | 47 +++++++++++--- source/gui/interface_definitions.hpp | 4 ++ .../match_panel/match_analyzer_panel.cpp | 61 +++++++++++++++---- .../match_panel/match_analyzer_panel.hpp | 22 ++++++- .../curve_panel/match_panel/match_panel.hpp | 4 ++ .../panel/state_panel/match_setting_panel.cpp | 3 - 8 files changed, 132 insertions(+), 38 deletions(-) diff --git a/source/gui/dragger2d/dragger_component.cpp b/source/gui/dragger2d/dragger_component.cpp index 476ea05..a79bec7 100644 --- a/source/gui/dragger2d/dragger_component.cpp +++ b/source/gui/dragger2d/dragger_component.cpp @@ -33,6 +33,10 @@ namespace zlInterface { void Dragger::updateButton() { if (dummyButtonChanged.exchange(false)) { button.setBounds(dummyButton.getBounds()); + auto bound = button.getLocalBounds().toFloat(); + const auto radius = std::min(bound.getHeight(), bound.getWidth()); + bound = bound.withSizeKeepingCentre(radius, radius); + draggerLAF.updatePaths(bound); } } @@ -43,7 +47,6 @@ namespace zlInterface { dummyBound = dummyButton.getBounds(); isShiftDown = event.mods.isShiftDown(); dragger.startDraggingComponent(&preButton, event); - const BailOutChecker checker(this); listeners.callChecked(checker, [&](Dragger::Listener &l) { l.dragStarted(this); }); } @@ -60,26 +63,20 @@ namespace zlInterface { if (event.mods.isCommandDown()) { if (event.mods.isLeftButtonDown()) { constrainer.setXON(false); - constrainer.setYON(true); + constrainer.setYON(yEnabled); } else { - constrainer.setXON(true); + constrainer.setXON(xEnabled); constrainer.setYON(false); } } else { - constrainer.setXON(true); - constrainer.setYON(true); + constrainer.setXON(xEnabled); + constrainer.setYON(yEnabled); } if (!isShiftDown && event.mods.isShiftDown()) { preBound = preButton.getBounds(); dummyBound = dummyButton.getBounds(); isShiftDown = true; } - // if (currentShiftDown && !isShiftDown) { - // dragger.startDraggingComponent(&preButton, event); - // preBound = preButton.getBounds(); - // dummyBound = dummyButton.getBounds(); - // isShiftDown = currentShiftDown; - // } dragger.dragComponent(&preButton, event, nullptr); const auto shift = (preButton.getBounds().getPosition() - preBound.getPosition()).toFloat(); diff --git a/source/gui/dragger2d/dragger_component.hpp b/source/gui/dragger2d/dragger_component.hpp index 8c1ffc7..3b9d691 100644 --- a/source/gui/dragger2d/dragger_component.hpp +++ b/source/gui/dragger2d/dragger_component.hpp @@ -67,10 +67,10 @@ namespace zlInterface { void removeListener(Listener *listener); void setPadding(const float left, const float right, - const float uppper, const float bottom) { + const float upper, const float bottom) { lPadding = left; rPadding = right; - uPadding = uppper; + uPadding = upper; bPadding = bottom; } @@ -78,6 +78,11 @@ namespace zlInterface { DraggerLookAndFeel &getLAF() {return draggerLAF;} + void setXYEnabled(const bool x, const bool y) { + xEnabled = x; + yEnabled = y; + } + private: UIBase &uiBase; @@ -89,6 +94,7 @@ namespace zlInterface { DraggerLookAndFeel draggerLAF; juce::ComponentDragger dragger; DraggerConstrainer constrainer; + bool xEnabled{true}, yEnabled{true}; std::atomic isSelected; std::atomic xPortion, yPortion; diff --git a/source/gui/dragger2d/dragger_look_and_feel.hpp b/source/gui/dragger2d/dragger_look_and_feel.hpp index ea33146..796c842 100644 --- a/source/gui/dragger2d/dragger_look_and_feel.hpp +++ b/source/gui/dragger2d/dragger_look_and_feel.hpp @@ -20,7 +20,9 @@ namespace zlInterface { enum DraggerShape { round, rectangle, - upDownArrow + upDownArrow, + rightArrow, + leftArrow }; explicit DraggerLookAndFeel(UIBase &base) : uiBase(base) { @@ -30,11 +32,6 @@ namespace zlInterface { bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override { if (!active.load()) { return; } - auto bound = button.getLocalBounds().toFloat(); - const auto radius = std::min(bound.getHeight(), bound.getWidth()); - bound = bound.withSizeKeepingCentre(radius, radius); - - updatePaths(bound); if (shouldDrawButtonAsDown || button.getToggleState()) { g.setColour(uiBase.getTextColor()); @@ -54,8 +51,10 @@ namespace zlInterface { } else { g.setColour(juce::Colours::black); } - // g.setColour(colour.withMultipliedBrightness(2.f)); g.setFont(uiBase.getFontSize() * labelScale); + auto bound = button.getLocalBounds().toFloat(); + const auto radius = std::min(bound.getHeight(), bound.getWidth()); + bound = bound.withSizeKeepingCentre(radius, radius); g.drawText(l, bound, juce::Justification::centred); } } @@ -88,6 +87,14 @@ namespace zlInterface { updateUpDownArrowPaths(bound); break; } + case rightArrow: { + updateRightArrowPaths(bound); + break; + } + case leftArrow: { + updateLeftArrowPaths(bound); + break; + } } } @@ -119,6 +126,32 @@ namespace zlInterface { updateOnePath(innerPath, bound); } + void updateRightArrowPaths(juce::Rectangle &bound) { + auto updateOnePath = [](juce::Path &path, const juce::Rectangle &temp) { + const auto center = temp.getCentre(); + path.startNewSubPath(center.getX() + temp.getWidth() * .5f, center.getY()); + path.lineTo(center.getX() - temp.getWidth() * .25f, center.getY() + temp.getHeight() * std::sqrt(3.f) * .25f); + path.lineTo(center.getX() - temp.getWidth() * .25f, center.getY() - temp.getHeight() * std::sqrt(3.f) * .25f); + path.closeSubPath(); + }; + updateOnePath(outlinePath, bound); + bound = bound.withSizeKeepingCentre(bound.getWidth() * .75f, bound.getHeight() * .75f); + updateOnePath(innerPath, bound); + } + + void updateLeftArrowPaths(juce::Rectangle &bound) { + auto updateOnePath = [](juce::Path &path, const juce::Rectangle &temp) { + const auto center = temp.getCentre(); + path.startNewSubPath(center.getX() - temp.getWidth() * .5f, center.getY()); + path.lineTo(center.getX() + temp.getWidth() * .25f, center.getY() + temp.getHeight() * std::sqrt(3.f) * .25f); + path.lineTo(center.getX() + temp.getWidth() * .25f, center.getY() - temp.getHeight() * std::sqrt(3.f) * .25f); + path.closeSubPath(); + }; + updateOnePath(outlinePath, bound); + bound = bound.withSizeKeepingCentre(bound.getWidth() * .75f, bound.getHeight() * .75f); + updateOnePath(innerPath, bound); + } + void setLabel(const char l) { label.store(l); } void setLabelScale(const float x) { labelScale = x; } diff --git a/source/gui/interface_definitions.hpp b/source/gui/interface_definitions.hpp index 5838cee..8a8f5ce 100644 --- a/source/gui/interface_definitions.hpp +++ b/source/gui/interface_definitions.hpp @@ -378,6 +378,10 @@ namespace zlInterface { valueTree.setProperty(identifiers[idx], v, nullptr); } + static bool isProperty(const settingIdx idx, const juce::Identifier &property) { + return property == identifiers[static_cast(idx)]; + } + private: juce::AudioProcessorValueTreeState &state; juce::ValueTree valueTree{"ui_setting"}; diff --git a/source/panel/curve_panel/match_panel/match_analyzer_panel.cpp b/source/panel/curve_panel/match_panel/match_analyzer_panel.cpp index ed21845..aee206f 100644 --- a/source/panel/curve_panel/match_panel/match_analyzer_panel.cpp +++ b/source/panel/curve_panel/match_panel/match_analyzer_panel.cpp @@ -14,16 +14,31 @@ namespace zlPanel { juce::AudioProcessorValueTreeState ¶metersNA, zlInterface::UIBase &base) : analyzerRef(analyzer), parametersNARef(parametersNA), uiBase(base), + lowDragger(base), highDragger(base), labelLAF(uiBase) { parametersNARef.addParameterListener(zlState::maximumDB::ID, this); parameterChanged(zlState::maximumDB::ID, parametersNARef.getRawParameterValue(zlState::maximumDB::ID)->load()); - setInterceptsMouseClicks(false, false); + setInterceptsMouseClicks(false, true); uiBase.getValueTree().addListener(this); runningLabel.setText("Running", juce::dontSendNotification); runningLabel.setJustificationType(juce::Justification::centred); labelLAF.setFontScale(5.f); runningLabel.setLookAndFeel(&labelLAF); addChildComponent(runningLabel); + lowDragger.getLAF().setDraggerShape(zlInterface::DraggerLookAndFeel::DraggerShape::rightArrow); + highDragger.getLAF().setDraggerShape(zlInterface::DraggerLookAndFeel::DraggerShape::leftArrow); + for (auto &d : {&lowDragger, &highDragger}) { + d->setYPortion(.5f); + d->setXYEnabled(true, false); + d->setScale(scale); + d->setActive(true); + d->getButton().setToggleState(true, juce::dontSendNotification); + d->getLAF().setIsSelected(true); + d->setInterceptsMouseClicks(false, true); + d->addListener(this); + addAndMakeVisible(d); + } + lookAndFeelChanged(); } MatchAnalyzerPanel::~MatchAnalyzerPanel() { @@ -32,6 +47,9 @@ namespace zlPanel { } void MatchAnalyzerPanel::paint(juce::Graphics &g) { + for (auto &d : {&lowDragger, &highDragger}) { + d->updateButton(); + } g.fillAll(uiBase.getColourByIdx(zlInterface::backgroundColour).withAlpha(backgroundAlpha)); const auto thickness = uiBase.getFontSize() * 0.2f * uiBase.getSumCurveThickness(); juce::GenericScopedTryLock lock{pathLock}; @@ -50,16 +68,16 @@ namespace zlPanel { g.strokePath(recentPath3, juce::PathStrokeType(thickness * 1.5f, juce::PathStrokeType::curved, juce::PathStrokeType::rounded)); - if (lowCutP > 0.001f) { + if (const auto xP = lowDragger.getXPortion(); xP > 0.001f) { auto bound = getLocalBounds().toFloat(); - bound = bound.removeFromLeft(bound.getWidth() * lowCutP); - g.setColour(uiBase.getBackgroundColor().withAlpha(.5f)); + bound = bound.removeFromLeft(bound.getWidth() * xP); + g.setColour(uiBase.getBackgroundColor().withAlpha(.75f)); g.fillRect(bound); } - if (highCutP < .999f) { + if (const auto yP = highDragger.getXPortion(); yP < .999f) { auto bound = getLocalBounds().toFloat(); - bound = bound.removeFromRight(bound.getWidth() * (1.f - highCutP)); - g.setColour(uiBase.getBackgroundColor().withAlpha(.5f)); + bound = bound.removeFromRight(bound.getWidth() * (1.f - yP)); + g.setColour(uiBase.getBackgroundColor().withAlpha(.75f)); g.fillRect(bound); } } @@ -72,6 +90,8 @@ namespace zlPanel { dBScale.store((1.f + uiBase.getFontSize() * 2.f / bound.getHeight()) * 2.f); runningLabel.setBounds(bound.withSizeKeepingCentre( bound.getWidth() * .5f, uiBase.getFontSize() * 5.f).toNearestInt()); + lowDragger.setBounds(getLocalBounds()); + highDragger.setBounds(getLocalBounds()); } void MatchAnalyzerPanel::updatePaths() { @@ -89,16 +109,19 @@ namespace zlPanel { analyzerRef.checkRun(); } + void MatchAnalyzerPanel::visibilityChanged() { + lowDragger.setXPortion(0.f); + highDragger.setXPortion(1.f); + draggerValueChanged(&lowDragger); + draggerValueChanged(&highDragger); + } + void MatchAnalyzerPanel::valueTreePropertyChanged(juce::ValueTree &, const juce::Identifier &property) { if (property == zlInterface::identifiers[static_cast(zlInterface::settingIdx::matchPanelFit)]) { const auto f = static_cast(uiBase.getProperty(zlInterface::settingIdx::matchPanelFit)); backgroundAlpha = f ? .2f : .5f; showAverage = !f; - } else if (property == zlInterface::identifiers[static_cast(zlInterface::settingIdx::matchLowCut)]) { - lowCutP = static_cast(uiBase.getProperty(zlInterface::settingIdx::matchLowCut)); - } else if (property == zlInterface::identifiers[static_cast(zlInterface::settingIdx::matchHighCut)]) { - highCutP = static_cast(uiBase.getProperty(zlInterface::settingIdx::matchHighCut)); - } else if (property == zlInterface::identifiers[static_cast(zlInterface::settingIdx::matchFitRunning)]) { + } else if (uiBase.isProperty(zlInterface::settingIdx::matchFitRunning, property)) { runningLabel.setVisible(static_cast(uiBase.getProperty(zlInterface::settingIdx::matchFitRunning))); } } @@ -107,4 +130,18 @@ namespace zlPanel { juce::ignoreUnused(parameterID); maximumDB.store(zlState::maximumDB::dBs[static_cast(newValue)]); } + + void MatchAnalyzerPanel::lookAndFeelChanged() { + for (auto &d : {&lowDragger, &highDragger}) { + d->getLAF().setColour(uiBase.getTextColor()); + } + } + + void MatchAnalyzerPanel::draggerValueChanged(zlInterface::Dragger *dragger) { + if (dragger == &lowDragger) { + uiBase.setProperty(zlInterface::settingIdx::matchLowCut, lowDragger.getXPortion()); + } else if (dragger == &highDragger) { + uiBase.setProperty(zlInterface::settingIdx::matchHighCut, highDragger.getXPortion()); + } + } } // zlPanel diff --git a/source/panel/curve_panel/match_panel/match_analyzer_panel.hpp b/source/panel/curve_panel/match_panel/match_analyzer_panel.hpp index af91d45..faed670 100644 --- a/source/panel/curve_panel/match_panel/match_analyzer_panel.hpp +++ b/source/panel/curve_panel/match_panel/match_analyzer_panel.hpp @@ -16,8 +16,9 @@ namespace zlPanel { class MatchAnalyzerPanel final : public juce::Component, - private juce::AudioProcessorValueTreeState::Listener, - private juce::ValueTree::Listener { + private juce::AudioProcessorValueTreeState::Listener, + private juce::ValueTree::Listener, + private zlInterface::Dragger::Listener { public: explicit MatchAnalyzerPanel(zlEqMatch::EqMatchAnalyzer &analyzer, juce::AudioProcessorValueTreeState ¶metersNA, @@ -29,6 +30,8 @@ namespace zlPanel { void resized() override; + void visibilityChanged() override; + void updatePaths(); private: @@ -44,14 +47,27 @@ namespace zlPanel { bool showAverage{true}; std::atomic dBScale{1.f}; std::atomic maximumDB{zlState::maximumDB::dBs[static_cast(zlState::maximumDB::defaultI)]}; - float lowCutP{0.f}, highCutP{1.f}; + zlInterface::Dragger lowDragger, highDragger; zlInterface::NameLookAndFeel labelLAF; juce::Label runningLabel; + static constexpr auto scale = 1.5f; void valueTreePropertyChanged(juce::ValueTree &treeWhosePropertyHasChanged, const juce::Identifier &property) override; void parameterChanged(const juce::String ¶meterID, float newValue) override; + + void lookAndFeelChanged() override; + + void dragStarted(zlInterface::Dragger *dragger) override { + juce::ignoreUnused(dragger); + } + + void dragEnded(zlInterface::Dragger *dragger) override { + juce::ignoreUnused(dragger); + } + + void draggerValueChanged(zlInterface::Dragger *dragger) override; }; } // zlPanel diff --git a/source/panel/curve_panel/match_panel/match_panel.hpp b/source/panel/curve_panel/match_panel/match_panel.hpp index c5cb4e6..346bf9f 100644 --- a/source/panel/curve_panel/match_panel/match_panel.hpp +++ b/source/panel/curve_panel/match_panel/match_panel.hpp @@ -27,6 +27,10 @@ namespace zlPanel { matchAnalyzerPanel.updatePaths(); } + void visibilityChanged() override { + matchAnalyzerPanel.visibilityChanged(); + } + private: zlInterface::UIBase &uiBase; MatchAnalyzerPanel matchAnalyzerPanel; diff --git a/source/panel/state_panel/match_setting_panel.cpp b/source/panel/state_panel/match_setting_panel.cpp index 9965f9d..0848206 100644 --- a/source/panel/state_panel/match_setting_panel.cpp +++ b/source/panel/state_panel/match_setting_panel.cpp @@ -47,9 +47,6 @@ namespace zlPanel { uiBase.setProperty(zlInterface::settingIdx::matchPanelShow, !f); if (!f) { uiBase.setProperty(zlInterface::settingIdx::matchPanelFit, false); - } else { - uiBase.setProperty(zlInterface::settingIdx::matchLowCut, 0.f); - uiBase.setProperty(zlInterface::settingIdx::matchHighCut, 1.f); } } } // zlPanel