Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Effect chain selectors: add empty item to allow clearing the chain #4892

Closed
wants to merge 8 commits into from
1 change: 1 addition & 0 deletions src/effects/chains/quickeffectchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ QuickEffectChain::QuickEffectChain(const QString& group,
SignalProcessingStage::Postfader,
pEffectsManager,
pEffectsMessenger) {
m_isQuickEffectChain = true;
for (int i = 0; i < kNumEffectsPerUnit; ++i) {
addEffectSlot(formatEffectSlotGroup(group, i));
m_effectSlots.at(i)->setEnabled(true);
Expand Down
26 changes: 22 additions & 4 deletions src/effects/effectchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,24 @@ const QString& EffectChain::presetName() const {

void EffectChain::loadChainPreset(EffectChainPresetPointer pPreset) {
slotControlClear(1);
VERIFY_OR_DEBUG_ASSERT(pPreset) {
if (!pPreset) {
// This may happen when a chain is cleared by selecting the empty '---'
// item in WEffectChainPresetSelector or in deck Quick Effect selectors
// in DlgPrefEq.
// Quick Effect chains and other chains need to be treated differently:
// * storing Quick Effect chain presets requires a preset name, otherwise
// (empty name) will cause the default preset being loaded on next start.
// Thus, we name the empty preset kNoEffectString so that the respective
// item is selected in the chain preset selector and also no chain will be
// loaded on next start.
// * storing states of regular [EffectRack1] chains doesn't require a preset
// name, also they can be edited, so kNoEffectString would be incorrect
// after loading an effect. Thus, if this is not a Quick Effetc chain, we
ronso0 marked this conversation as resolved.
Show resolved Hide resolved
// just clear the preset name which in turn clears the chain's preset
// selector and chain name label.
m_presetName = m_isQuickEffectChain ? kNoEffectString : QString();
emit chainPresetChanged(m_presetName);
setControlLoadedPresetIndex(std::nullopt);
return;
}

Expand Down Expand Up @@ -349,9 +366,10 @@ void EffectChain::slotControlLoadedChainPresetRequest(double value) {
loadChainPreset(presetAtIndex(index));
}

void EffectChain::setControlLoadedPresetIndex(uint index) {
// add 1 to make the ControlObject 1-indexed like other ControlObjects
m_pControlLoadedChainPreset->setAndConfirm(index + 1);
void EffectChain::setControlLoadedPresetIndex(std::optional<uint> index) {
// add 1 to make the ControlObject 1-indexed like other ControlObjects.
// if the effect chain is cleared (no valid index), the CO is set 0;
m_pControlLoadedChainPreset->setAndConfirm(index ? *index + 1 : 0);
}

void EffectChain::slotControlNextChainPreset(double value) {
Expand Down
4 changes: 3 additions & 1 deletion src/effects/effectchain.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "engine/channelhandle.h"
#include "util/class.h"
#include "util/memory.h"
#include "util/optional.h"

class ControlPushButton;
class ControlEncoder;
Expand Down Expand Up @@ -90,6 +91,7 @@ class EffectChain : public QObject {

protected:
EffectSlotPointer addEffectSlot(const QString& group);
bool m_isQuickEffectChain = false;

virtual int numPresets() const;

Expand Down Expand Up @@ -141,7 +143,7 @@ class EffectChain : public QObject {
std::unique_ptr<ControlPushButton> m_pControlNextChainPreset;
std::unique_ptr<ControlPushButton> m_pControlPrevChainPreset;

void setControlLoadedPresetIndex(uint index);
void setControlLoadedPresetIndex(std::optional<uint> index);

// These COs do not affect how the effects are processed;
// they are defined here for skins and controller mappings to communicate
Expand Down
39 changes: 34 additions & 5 deletions src/effects/presets/effectchainpresetmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ void EffectChainPresetManager::importPreset() {
EffectChainPresetPointer pPreset(
new EffectChainPreset(doc.documentElement()));
if (!pPreset->isEmpty() && !pPreset->name().isEmpty()) {
// Don't allow '---' because it is used internally for clearing effect
// chains and empty Quick Effect chains
if (pPreset->name() == kNoEffectString) {
pPreset->setName(pPreset->name() +
QLatin1String(" (") + tr("imported") + QLatin1String(")"));
}

while (m_effectChainPresets.contains(pPreset->name())) {
pPreset->setName(pPreset->name() +
QLatin1String(" (") + tr("duplicate") + QLatin1String(")"));
Expand Down Expand Up @@ -230,7 +237,8 @@ void EffectChainPresetManager::renamePreset(const QString& oldName) {

QString newName;
QString errorText;
while (newName.isEmpty() || m_effectChainPresets.contains(newName)) {
while (newName.isEmpty() || m_effectChainPresets.contains(newName) ||
newName == kNoEffectString) {
bool okay = false;
newName = QInputDialog::getText(nullptr,
tr("Rename effect chain preset"),
Expand All @@ -251,6 +259,8 @@ void EffectChainPresetManager::renamePreset(const QString& oldName) {
tr("An effect chain preset named \"%1\" already exists.")
.arg(newName) +
QStringLiteral("\n");
} else if (newName == kNoEffectString) {
errorText = tr("Invalid name \"%1\"").arg(newName) + QStringLiteral("\n");
} else {
errorText = QString();
}
Expand Down Expand Up @@ -371,7 +381,7 @@ void EffectChainPresetManager::savePreset(EffectChainPointer pChainSlot) {
void EffectChainPresetManager::savePreset(EffectChainPresetPointer pPreset) {
QString name;
QString errorText;
while (name.isEmpty() || m_effectChainPresets.contains(name)) {
while (name.isEmpty() || m_effectChainPresets.contains(name) || name == kNoEffectString) {
bool okay = false;
name = QInputDialog::getText(nullptr,
tr("Save preset for effect chain"),
Expand All @@ -391,6 +401,8 @@ void EffectChainPresetManager::savePreset(EffectChainPresetPointer pPreset) {
tr("An effect chain preset named \"%1\" already exists.")
.arg(name) +
QStringLiteral("\n");
} else if (name == kNoEffectString) {
errorText = tr("Invalid name \"%1\"").arg(name) + QStringLiteral("\n");
} else {
errorText = QString();
}
Expand Down Expand Up @@ -444,6 +456,12 @@ void EffectChainPresetManager::importUserPresets() {
EffectChainPresetPointer pEffectChainPreset = loadPresetFromFile(
savedPresetsPath + kFolderDelimiter + filePath);
if (pEffectChainPreset && !pEffectChainPreset->isEmpty()) {
// Don't allow '---' because it is used internally for clearing effect
// chains and empty Quick Effect chains
if (pEffectChainPreset->name() == kNoEffectString) {
pEffectChainPreset->setName(pEffectChainPreset->name() +
QLatin1String(" (") + tr("imported") + QLatin1String(")"));
}
m_effectChainPresets.insert(
pEffectChainPreset->name(), pEffectChainPreset);
}
Expand Down Expand Up @@ -678,9 +696,20 @@ EffectsXmlData EffectChainPresetManager::readEffectsXml(
QDomElement presetNameElement = quickEffectNodeList.at(i).toElement();
if (!presetNameElement.isNull()) {
QString deckGroup = presetNameElement.attribute(QStringLiteral("group"));
auto pPreset = m_effectChainPresets.value(presetNameElement.text());
if (pPreset != nullptr) {
quickEffectPresets.insert(deckGroup, pPreset);
QString presetName = presetNameElement.text();
if (presetName == kNoEffectString) {
// kNoEffectString is not allowed as preset name (import,
// export, save as new), it can only be set by selecting
// kNoEffectString in the Quick Effect slot preset selector
// (skin & EQ preferences).
// Thus, it's safe to use kNoEffectString to explicitly load
// an empty preset.
quickEffectPresets.insert(deckGroup, nullptr);
} else { // any name incl. empty string
auto pPreset = m_effectChainPresets.value(presetName);
if (pPreset != nullptr) {
quickEffectPresets.insert(deckGroup, pPreset);
}
}
}
}
Expand Down
31 changes: 17 additions & 14 deletions src/preferences/dialog/dlgprefeq.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,23 +297,21 @@ void DlgPrefEQ::populateDeckQuickEffectBoxList(
int deck = 0;
for (QComboBox* box : boxList) {
box->clear();
int currentIndex = -1; // Nothing selected

// Add empty item at the top: no effect
box->addItem(kNoEffectString);
// Note: now there's an index offset (items vs. actual presets).
// Compensate with a nullptr in slotQuickEffectChangedOnDeck().

QString deckGroupName = PlayerManager::groupForDeck(deck);
QString unitGroup = QuickEffectChain::formatEffectChainGroup(deckGroupName);
EffectChainPointer pChain = m_pEffectsManager->getEffectChain(unitGroup);

// Add empty item at the top: no effect
box->addItem(kNoEffectString);
int i = 1;
for (const auto& pChainPreset : presetList) {
box->addItem(pChainPreset->name());
if (pChain->presetName() == pChainPreset->name()) {
currentIndex = i;
}
++i;
}
box->setCurrentIndex(currentIndex);

// Nothing selected (-1) if preset name was not found
box->setCurrentIndex(box->findText(pChain->presetName()));
++deck;
}
}
Expand Down Expand Up @@ -490,10 +488,15 @@ void DlgPrefEQ::slotQuickEffectChangedOnDeck(int effectIndex) {
QString deckGroupName = PlayerManager::groupForDeck(deckNumber);
QString unitGroup = QuickEffectChain::formatEffectChainGroup(deckGroupName);
EffectChainPointer pChain = m_pEffectsManager->getEffectChain(unitGroup);
QList<EffectChainPresetPointer> presetList =
m_pChainPresetManager->getQuickEffectPresetsSorted();
if (pChain && effectIndex > 0 && effectIndex <= presetList.size()) {
pChain->loadChainPreset(presetList[effectIndex - 1]);
QList<EffectChainPresetPointer> presetList;
// add nullptr for empty kNoEffectString item so combobox effectIndex
// matches index in presetList
presetList.append(nullptr);
// add available Quick Effect chains
presetList.append(m_pChainPresetManager->getQuickEffectPresetsSorted());

if (pChain && effectIndex > -1 && effectIndex <= presetList.size()) {
pChain->loadChainPreset(presetList[effectIndex]);
}
}

Expand Down
17 changes: 13 additions & 4 deletions src/widget/weffectchainpresetselector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ void WEffectChainPresetSelector::populate() {

QFontMetrics metrics(font());

// This is used to clear the effect chain
addItem(kNoEffectString, kNoEffectString);
setItemData(0, QVariant(tr("No effect chain loaded.")), Qt::ToolTipRole);

QList<EffectChainPresetPointer> presetList;
if (m_bQuickEffectChain) {
presetList = m_pEffectsManager->getChainPresetManager()->getQuickEffectPresetsSorted();
Expand All @@ -76,15 +80,16 @@ void WEffectChainPresetSelector::populate() {
Qt::ElideMiddle,
view()->width() - 2);
addItem(elidedDisplayName, QVariant(pChainPreset->name()));
setItemData(i, pChainPreset->name(), Qt::ToolTipRole);
setItemData(i + 1, pChainPreset->name(), Qt::ToolTipRole);
}

slotChainPresetChanged(m_pChain->presetName());
blockSignals(false);
}

void WEffectChainPresetSelector::slotEffectChainPresetSelected(int index) {
Q_UNUSED(index);
// If kNoEffectString was selected the chain will be cleared.
// See EffectChain::loadChainPreset for details.
m_pChain->loadChainPreset(
m_pChainPresetManager->getPreset(currentData().toString()));
setBaseTooltip(itemData(index, Qt::ToolTipRole).toString());
Expand All @@ -96,8 +101,12 @@ void WEffectChainPresetSelector::slotEffectChainPresetSelected(int index) {
}

void WEffectChainPresetSelector::slotChainPresetChanged(const QString& name) {
setCurrentIndex(findData(name));
setBaseTooltip(name);
// This is called by signal EffectChain::chainPresetChanged(name) emitted by
// EffectChain::loadChainPreset. See that slot for details about the preset
// names being emitted for different chain types.
int newIndex = findData(name);
setCurrentIndex(newIndex);
setBaseTooltip(itemData(newIndex, Qt::ToolTipRole).toString());
}

bool WEffectChainPresetSelector::event(QEvent* pEvent) {
Expand Down