From 99e31ed83c79624aa0a910156bc87f0dd283abf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=84=A1=E5=B8=B8?= <3142324836@qq.com> Date: Fri, 6 Dec 2024 01:20:40 +0800 Subject: [PATCH] Add sequencer track solo button --- src/audioCore/graph/SeqSourceProcessor.cpp | 3 +- .../component/sequencer/SeqTrackComponent.cpp | 14 ++- .../component/sequencer/SeqTrackComponent.h | 2 + .../sequencer/SeqTrackMuteComponent.cpp | 38 +------ .../sequencer/SeqTrackMuteComponent.h | 3 - .../sequencer/SeqTrackSoloComponent.cpp | 103 ++++++++++++++++++ .../sequencer/SeqTrackSoloComponent.h | 26 +++++ src/ui/component/sequencer/SeqView.cpp | 6 +- src/ui/lookAndFeel/LookAndFeelFactory.cpp | 2 + src/ui/lookAndFeel/LookAndFeelFactory.h | 2 +- .../base/SoloButtonLookAndFeel.cpp | 15 +++ .../lookAndFeel/base/SoloButtonLookAndFeel.h | 12 ++ src/ui/misc/CoreActions.cpp | 15 +-- src/ui/misc/CoreActions.h | 3 +- 14 files changed, 184 insertions(+), 60 deletions(-) create mode 100644 src/ui/component/sequencer/SeqTrackSoloComponent.cpp create mode 100644 src/ui/component/sequencer/SeqTrackSoloComponent.h create mode 100644 src/ui/lookAndFeel/base/SoloButtonLookAndFeel.cpp create mode 100644 src/ui/lookAndFeel/base/SoloButtonLookAndFeel.h diff --git a/src/audioCore/graph/SeqSourceProcessor.cpp b/src/audioCore/graph/SeqSourceProcessor.cpp index f1ec847..f6c9335 100644 --- a/src/audioCore/graph/SeqSourceProcessor.cpp +++ b/src/audioCore/graph/SeqSourceProcessor.cpp @@ -55,6 +55,7 @@ SeqSourceProcessor::SeqSourceProcessor(const juce::AudioChannelSet& type) } SeqSourceProcessor::~SeqSourceProcessor() { + this->setSolo(false); this->releaseAudio(); this->releaseMIDI(); } @@ -544,7 +545,7 @@ bool SeqSourceProcessor::getMute() const { } void SeqSourceProcessor::setSolo(bool solo) { - bool shouldChange = (this->isSolo == solo); + bool shouldChange = (this->isSolo != solo); this->isSolo = solo; diff --git a/src/ui/component/sequencer/SeqTrackComponent.cpp b/src/ui/component/sequencer/SeqTrackComponent.cpp index cbffe21..6bedd57 100644 --- a/src/ui/component/sequencer/SeqTrackComponent.cpp +++ b/src/ui/component/sequencer/SeqTrackComponent.cpp @@ -40,6 +40,10 @@ SeqTrackComponent::SeqTrackComponent( this->muteButton = std::make_unique(); this->addChildComponent(this->muteButton.get()); + /** Solo Button */ + this->soloButton = std::make_unique(); + this->addChildComponent(this->soloButton.get()); + /** Input Monitoring Button */ this->inputMonitoringButton = std::make_unique(); this->addChildComponent(this->inputMonitoringButton.get()); @@ -171,6 +175,7 @@ void SeqTrackComponent::updateBlock(int blockIndex) { void SeqTrackComponent::updateMuteSolo() { this->muteButton->update(this->index); + this->soloButton->update(this->index); } void SeqTrackComponent::updateInputMonitoring() { @@ -327,9 +332,16 @@ void SeqTrackComponent::resized() { this->muteButton->setBounds(muteRect); this->muteButton->setVisible(isIOLineShown); + /** Solo Button */ + juce::Rectangle soloRect( + muteRect.getRight() + buttonSplitWidth, inputMonitoringRect.getY(), + ioLineHeight, ioLineHeight); + this->soloButton->setBounds(soloRect); + this->soloButton->setVisible(isIOLineShown); + /** MIDI Output */ juce::Rectangle midiOutputRect( - muteRect.getRight() + buttonSplitWidth, inputMonitoringRect.getY(), + soloRect.getRight() + buttonSplitWidth, inputMonitoringRect.getY(), ioLineHeight, ioLineHeight); this->midiOutput->setBounds(midiOutputRect); this->midiOutput->setVisible(isIOLineShown); diff --git a/src/ui/component/sequencer/SeqTrackComponent.h b/src/ui/component/sequencer/SeqTrackComponent.h index 7027e2d..ff24597 100644 --- a/src/ui/component/sequencer/SeqTrackComponent.h +++ b/src/ui/component/sequencer/SeqTrackComponent.h @@ -2,6 +2,7 @@ #include #include "SeqTrackMuteComponent.h" +#include "SeqTrackSoloComponent.h" #include "SeqTrackInputMonitoringComponent.h" #include "SeqTrackRecComponent.h" #include "SeqTrackIOComponent.h" @@ -78,6 +79,7 @@ class SeqTrackComponent final std::unique_ptr trackName = nullptr; std::unique_ptr muteButton = nullptr; + std::unique_ptr soloButton = nullptr; std::unique_ptr inputMonitoringButton = nullptr; std::unique_ptr recButton = nullptr; diff --git a/src/ui/component/sequencer/SeqTrackMuteComponent.cpp b/src/ui/component/sequencer/SeqTrackMuteComponent.cpp index 33fd79c..7d5210c 100644 --- a/src/ui/component/sequencer/SeqTrackMuteComponent.cpp +++ b/src/ui/component/sequencer/SeqTrackMuteComponent.cpp @@ -84,7 +84,7 @@ void SeqTrackMuteComponent::mouseUp(const juce::MouseEvent& event) { this->changeMute(); } else if (event.mods.isRightButtonDown()) { - this->showMenu(); + this->changeMute(); } } } @@ -102,39 +102,3 @@ void SeqTrackMuteComponent::update(int index) { void SeqTrackMuteComponent::changeMute() { CoreActions::setSeqMute(this->index, !(this->mute)); } - -enum MixerMuteActionType { - Mute = 1, Solo, MuteAll, UnmuteAll -}; - -void SeqTrackMuteComponent::showMenu() { - auto menu = this->createMenu(); - int result = menu.show(); - - switch (result) { - case MixerMuteActionType::Mute: - this->changeMute(); - break; - case MixerMuteActionType::Solo: - CoreActions::setSeqSolo(this->index); - break; - case MixerMuteActionType::MuteAll: - CoreActions::setSeqMuteAll(true); - break; - case MixerMuteActionType::UnmuteAll: - CoreActions::setSeqMuteAll(false); - break; - } -} - -juce::PopupMenu SeqTrackMuteComponent::createMenu() const { - juce::PopupMenu menu; - - menu.addItem(MixerMuteActionType::Mute, TRANS("Mute"), true, this->mute); - menu.addItem(MixerMuteActionType::Solo, TRANS("Solo")); - menu.addSeparator(); - menu.addItem(MixerMuteActionType::MuteAll, TRANS("Mute All")); - menu.addItem(MixerMuteActionType::UnmuteAll, TRANS("Unmute All")); - - return menu; -} diff --git a/src/ui/component/sequencer/SeqTrackMuteComponent.h b/src/ui/component/sequencer/SeqTrackMuteComponent.h index 60845ae..3279892 100644 --- a/src/ui/component/sequencer/SeqTrackMuteComponent.h +++ b/src/ui/component/sequencer/SeqTrackMuteComponent.h @@ -22,9 +22,6 @@ class SeqTrackMuteComponent final bool equivalentMute = false; void changeMute(); - void showMenu(); - - juce::PopupMenu createMenu() const; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SeqTrackMuteComponent) }; diff --git a/src/ui/component/sequencer/SeqTrackSoloComponent.cpp b/src/ui/component/sequencer/SeqTrackSoloComponent.cpp new file mode 100644 index 0000000..a5f3d5b --- /dev/null +++ b/src/ui/component/sequencer/SeqTrackSoloComponent.cpp @@ -0,0 +1,103 @@ +#include "SeqTrackSoloComponent.h" +#include "../../lookAndFeel/LookAndFeelFactory.h" +#include "../../misc/CoreActions.h" +#include "../../Utils.h" +#include "../../../audioCore/AC_API.h" + +SeqTrackSoloComponent::SeqTrackSoloComponent() { + this->setLookAndFeel( + LookAndFeelFactory::getInstance()->getLAFFor(LookAndFeelFactory::SoloButton)); +} + +void SeqTrackSoloComponent::paint(juce::Graphics& g) { + /** Size */ + auto screenSize = utils::getScreenSize(this); + float lineThickness = screenSize.getHeight() * 0.001; + + int buttonWidth = std::min(this->getWidth(), this->getHeight()) - lineThickness; + int buttonHeight = buttonWidth; + + float textFontHeight = buttonWidth * 0.7; + + /** Color */ + auto& laf = this->getLookAndFeel(); + juce::Colour backgroundColor = laf.findColour(this->solo + ? juce::TextButton::ColourIds::buttonOnColourId + : juce::TextButton::ColourIds::buttonColourId); + juce::Colour textColor = laf.findColour(this->solo + ? juce::TextButton::ColourIds::textColourOnId + : juce::TextButton::ColourIds::textColourOffId); + + /** Font */ + juce::Font textFont(juce::FontOptions{ textFontHeight }); + + /** Button */ + juce::Rectangle buttonRect( + this->getWidth() / 2.f - buttonWidth / 2.f, + this->getHeight() / 2.f - buttonHeight / 2.f, + buttonWidth, buttonHeight); + g.setColour(backgroundColor); + g.fillRect(buttonRect); + + g.setColour(textColor); + g.drawRect(buttonRect, lineThickness); + + g.setFont(textFont); + g.drawFittedText("S", buttonRect.toNearestInt(), + juce::Justification::centred, 1, 0.f); +} + +void SeqTrackSoloComponent::mouseDrag(const juce::MouseEvent& event) { + this->mouseMove(event); +} + +void SeqTrackSoloComponent::mouseMove(const juce::MouseEvent& event) { + /** Size */ + auto screenSize = utils::getScreenSize(this); + float lineThickness = screenSize.getHeight() * 0.001; + int buttonWidth = std::min(this->getWidth(), this->getHeight()) - lineThickness; + int buttonHeight = buttonWidth; + juce::Rectangle buttonRect( + this->getWidth() / 2.f - buttonWidth / 2.f, + this->getHeight() / 2.f - buttonHeight / 2.f, + buttonWidth, buttonHeight); + + /** Cursor */ + this->setMouseCursor(buttonRect.contains(event.position) + ? juce::MouseCursor::PointingHandCursor + : juce::MouseCursor::NormalCursor); +} + +void SeqTrackSoloComponent::mouseUp(const juce::MouseEvent& event) { + /** Size */ + auto screenSize = utils::getScreenSize(this); + float lineThickness = screenSize.getHeight() * 0.001; + int buttonWidth = std::min(this->getWidth(), this->getHeight()) - lineThickness; + int buttonHeight = buttonWidth; + juce::Rectangle buttonRect( + this->getWidth() / 2.f - buttonWidth / 2.f, + this->getHeight() / 2.f - buttonHeight / 2.f, + buttonWidth, buttonHeight); + + if (buttonRect.contains(event.position)) { + if (event.mods.isLeftButtonDown()) { + this->changeSolo(); + } + else if (event.mods.isRightButtonDown()) { + this->changeSolo(); + } + } +} + +void SeqTrackSoloComponent::update(int index) { + this->index = index; + if (index > -1) { + this->solo = quickAPI::getSeqTrackSolo(index); + + this->repaint(); + } +} + +void SeqTrackSoloComponent::changeSolo() { + CoreActions::setSeqSolo(this->index, !(this->solo)); +} diff --git a/src/ui/component/sequencer/SeqTrackSoloComponent.h b/src/ui/component/sequencer/SeqTrackSoloComponent.h new file mode 100644 index 0000000..9f9ffbe --- /dev/null +++ b/src/ui/component/sequencer/SeqTrackSoloComponent.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +class SeqTrackSoloComponent final + : public juce::Component, + public juce::SettableTooltipClient { +public: + SeqTrackSoloComponent(); + + void paint(juce::Graphics& g) override; + + void mouseDrag(const juce::MouseEvent& event) override; + void mouseMove(const juce::MouseEvent& event) override; + void mouseUp(const juce::MouseEvent& event) override; + + void update(int index); + +private: + int index = -1; + bool solo = false; + + void changeSolo(); + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SeqTrackSoloComponent) +}; diff --git a/src/ui/component/sequencer/SeqView.cpp b/src/ui/component/sequencer/SeqView.cpp index 22325e0..dfd87aa 100644 --- a/src/ui/component/sequencer/SeqView.cpp +++ b/src/ui/component/sequencer/SeqView.cpp @@ -50,9 +50,9 @@ void SeqView::TrackList::updateBlock(int track, int index) { } } -void SeqView::TrackList::updateMuteSolo(int index) { - if (index >= 0 && index < this->list.size()) { - this->list[index]->updateMuteSolo(); +void SeqView::TrackList::updateMuteSolo(int /*index*/) { + for (auto i : this->list) { + i->updateMuteSolo(); } } diff --git a/src/ui/lookAndFeel/LookAndFeelFactory.cpp b/src/ui/lookAndFeel/LookAndFeelFactory.cpp index 46a5c96..2ae5c3b 100644 --- a/src/ui/lookAndFeel/LookAndFeelFactory.cpp +++ b/src/ui/lookAndFeel/LookAndFeelFactory.cpp @@ -17,6 +17,7 @@ #include "mixer/SideChainLookAndFeel.h" #include "mixer/LevelMeterLookAndFeel.h" #include "base/MuteButtonLookAndFeel.h" +#include "base/SoloButtonLookAndFeel.h" #include "base/RecButtonLookAndFeel.h" #include "mixer/EffectLookAndFeel.h" #include "sequencer/SeqLookAndFeel.h" @@ -85,6 +86,7 @@ void LookAndFeelFactory::initialise() { new SideChainLookAndFeel{}, new LevelMeterLookAndFeel{}, new MuteButtonLookAndFeel{}, + new SoloButtonLookAndFeel{}, new RecButtonLookAndFeel{}, new EffectLookAndFeel{}, new SeqLookAndFeel{}, diff --git a/src/ui/lookAndFeel/LookAndFeelFactory.h b/src/ui/lookAndFeel/LookAndFeelFactory.h index d00caf6..f84efe7 100644 --- a/src/ui/lookAndFeel/LookAndFeelFactory.h +++ b/src/ui/lookAndFeel/LookAndFeelFactory.h @@ -13,7 +13,7 @@ class LookAndFeelFactory final : private juce::DeletedAtShutdown { ToolBar, MainMenu, SysStatus, Time, Controller, Tools, Message, MessageView, PluginView, PluginEditor, ChannelLink, Mixer, Scroller, ColorEditor, SideChain, LevelMeter, - MuteButton, RecButton, Effect, Seq, TimeRuler, SeqTrack, + MuteButton, SoloButton, RecButton, Effect, Seq, TimeRuler, SeqTrack, SeqTrackName, InstrName, SeqBlock, Editor, EditorSwitchBar, Piano, MidiContent, InputMonitoringButton, diff --git a/src/ui/lookAndFeel/base/SoloButtonLookAndFeel.cpp b/src/ui/lookAndFeel/base/SoloButtonLookAndFeel.cpp new file mode 100644 index 0000000..b1387cd --- /dev/null +++ b/src/ui/lookAndFeel/base/SoloButtonLookAndFeel.cpp @@ -0,0 +1,15 @@ +#include "SoloButtonLookAndFeel.h" +#include "../../misc/ColorMap.h" + +SoloButtonLookAndFeel::SoloButtonLookAndFeel() + : MainLookAndFeel() { + /** Button */ + this->setColour(juce::TextButton::ColourIds::buttonColourId, + ColorMap::getInstance()->get("ThemeColorB2")); + this->setColour(juce::TextButton::ColourIds::buttonOnColourId, + juce::Colours::red.withAlpha(0.6f)); + this->setColour(juce::TextButton::ColourIds::textColourOffId, + ColorMap::getInstance()->get("ThemeColorB8")); + this->setColour(juce::TextButton::ColourIds::textColourOnId, + ColorMap::getInstance()->get("ThemeColorB10")); +} diff --git a/src/ui/lookAndFeel/base/SoloButtonLookAndFeel.h b/src/ui/lookAndFeel/base/SoloButtonLookAndFeel.h new file mode 100644 index 0000000..006753b --- /dev/null +++ b/src/ui/lookAndFeel/base/SoloButtonLookAndFeel.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include "../MainLookAndFeel.h" + +class SoloButtonLookAndFeel : public MainLookAndFeel { +public: + SoloButtonLookAndFeel(); + +private: + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SoloButtonLookAndFeel) +}; diff --git a/src/ui/misc/CoreActions.cpp b/src/ui/misc/CoreActions.cpp index c226dfa..056f5aa 100644 --- a/src/ui/misc/CoreActions.cpp +++ b/src/ui/misc/CoreActions.cpp @@ -427,18 +427,9 @@ void CoreActions::setSeqMute(int index, bool mute) { ActionDispatcher::getInstance()->dispatch(std::move(action)); } -void CoreActions::setSeqSolo(int index) { - int trackNum = quickAPI::getSeqTrackNum(); - for (int i = 0; i < trackNum; i++) { - CoreActions::setSeqMute(i, i != index); - } -} - -void CoreActions::setSeqMuteAll(bool mute) { - int trackNum = quickAPI::getSeqTrackNum(); - for (int i = 0; i < trackNum; i++) { - CoreActions::setSeqMute(i, mute); - } +void CoreActions::setSeqSolo(int index, bool solo) { + auto action = std::unique_ptr(new ActionSetSequencerTrackSolo{ index, solo }); + ActionDispatcher::getInstance()->dispatch(std::move(action)); } void CoreActions::setSeqInputMonitoring(int index, bool inputMonitoring) { diff --git a/src/ui/misc/CoreActions.h b/src/ui/misc/CoreActions.h index 57d5ae1..193bd78 100644 --- a/src/ui/misc/CoreActions.h +++ b/src/ui/misc/CoreActions.h @@ -90,8 +90,7 @@ class CoreActions final { static void setSeqMIDIOutputToMixer(int index, int mixerIndex, bool output); static void setSeqAudioOutputToMixer(int index, int channel, int mixerIndex, int dstChannel, bool output); static void setSeqMute(int index, bool mute); - static void setSeqSolo(int index); - static void setSeqMuteAll(bool mute); + static void setSeqSolo(int index, bool solo); static void setSeqInputMonitoring(int index, bool inputMonitoring); static void setSeqRec(int index, quickAPI::RecordState rec); static void setSeqMIDITrack(int index, int midiTrack);