diff --git a/include/EffectCategory.h b/include/EffectCategory.h new file mode 100644 index 00000000000..19c4376b2b1 --- /dev/null +++ b/include/EffectCategory.h @@ -0,0 +1,49 @@ +/* + * EffectCategory - Associates an effect to a category (for grouping/filtering afterwards) + * + * This file is part of LMMS - https://lmms.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#ifndef LMMS_EFFECT_CATEGORY_H +#define LMMS_EFFECT_CATEGORY_H + +#include +#include + +#include "lmms_export.h" +namespace lmms +{ + +class LMMS_EXPORT EffectCategory +{ +public: + static EffectCategory* instance(); + QString getCategoryName(QString effectName); + QStringList getCategories(); +private: + static std::unique_ptr s_instance; + QStringList m_categories; + QStringList getCategoriesFromMap(std::map map); +}; + +// Short-hand function +LMMS_EXPORT EffectCategory* getEffectCategory(); + +} // namespace lmms +#endif // LMMS_EFFECT_CATEGORY_H diff --git a/include/EffectSelectDialog.h b/include/EffectSelectDialog.h index 6f0e09b8a5f..1c061c34a11 100644 --- a/include/EffectSelectDialog.h +++ b/include/EffectSelectDialog.h @@ -20,7 +20,6 @@ * License along with this program (see COPYING); if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. - * */ #ifndef LMMS_GUI_EFFECT_SELECT_DIALOG_H @@ -32,6 +31,7 @@ #include #include #include +#include class QScrollArea; class QTableView; @@ -40,11 +40,11 @@ class QLineEdit; namespace lmms::gui { -class DualColumnFilterProxyModel : public QSortFilterProxyModel +class MultipleColumnFilterProxyModel : public QSortFilterProxyModel { Q_OBJECT public: - DualColumnFilterProxyModel(QObject* parent = nullptr) : QSortFilterProxyModel(parent) + MultipleColumnFilterProxyModel(QObject* parent = nullptr) : QSortFilterProxyModel(parent) { } @@ -54,27 +54,36 @@ class DualColumnFilterProxyModel : public QSortFilterProxyModel invalidateFilter(); } + void setEffectCategoryFilter(const QString& filter) + { + m_effectCategoryFilter = filter; + invalidateFilter(); + } + protected: bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override { QModelIndex nameIndex = sourceModel()->index(source_row, 0, source_parent); - QModelIndex typeIndex = sourceModel()->index(source_row, 1, source_parent); + QModelIndex categoryIndex = sourceModel()->index(source_row, 1, source_parent); + QModelIndex typeIndex = sourceModel()->index(source_row, 2, source_parent); QString name = sourceModel()->data(nameIndex, Qt::DisplayRole).toString(); + QString category = sourceModel()->data(categoryIndex, Qt::DisplayRole).toString(); QString type = sourceModel()->data(typeIndex, Qt::DisplayRole).toString(); QRegularExpression nameRegularExpression(filterRegularExpression()); nameRegularExpression.setPatternOptions(QRegularExpression::CaseInsensitiveOption); bool nameFilterPassed = nameRegularExpression.match(name).capturedStart() != -1; - bool typeFilterPassed = type.contains(m_effectTypeFilter, Qt::CaseInsensitive); + bool categoryFilterPassed = category.contains(m_effectCategoryFilter, Qt::CaseInsensitive); - return nameFilterPassed && typeFilterPassed; + return nameFilterPassed && typeFilterPassed && categoryFilterPassed; } private: QString m_effectTypeFilter; + QString m_effectCategoryFilter; }; @@ -98,11 +107,14 @@ protected slots: EffectKey m_currentSelection; QStandardItemModel m_sourceModel; - DualColumnFilterProxyModel m_model; + MultipleColumnFilterProxyModel m_model; QWidget* m_descriptionWidget; QTableView* m_pluginList; QScrollArea* m_scrollArea; QLineEdit* m_filterEdit; + QHBoxLayout* buildFiltersLayout(); + QHBoxLayout* buildTypeFilterLayout(); + QHBoxLayout* buildCategoryFilterLayout(); }; } // namespace lmms::gui diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 036ba0cd671..db9645c9b1d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -21,6 +21,7 @@ set(LMMS_SRCS core/DataFile.cpp core/DrumSynth.cpp core/Effect.cpp + core/EffectCategory.cpp core/EffectChain.cpp core/Engine.cpp core/EnvelopeAndLfoParameters.cpp diff --git a/src/core/EffectCategory.cpp b/src/core/EffectCategory.cpp new file mode 100644 index 00000000000..174399a53f4 --- /dev/null +++ b/src/core/EffectCategory.cpp @@ -0,0 +1,332 @@ +/* + * EffectCategory - Associates an effect to a category (for grouping/filtering afterwards) + * + * This file is part of LMMS - https://lmms.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include "EffectCategory.h" + +#include +#include + +namespace lmms { + +const std::map lmmsEffects = +{ + {"Amplifier", QObject::tr("Amplifier")}, + {"BassBooster", QObject::tr("Equalization")}, + {"Bitcrush", QObject::tr("Bitcrush")}, + {"Compressor", QObject::tr("Compressor")}, + {"Crossover Equalizer", QObject::tr("Equalization")}, + {"Delay", QObject::tr("Delay")}, + {"Dispersion", QObject::tr("Filter")}, + {"Dual Filter", QObject::tr("Filter")}, + {"Dynamics Processor", QObject::tr("Distortion")}, + {"Equalizer", QObject::tr("Equalization")}, + {"Flanger", QObject::tr("Flanger")}, + {"Frequency Shifter", QObject::tr("Pitch")}, + {"Granular Pitch Shifter", QObject::tr("Pitch")}, + {"LOMM", QObject::tr("Distortion")}, + {"Multitap Echo", QObject::tr("Delay")}, + {"Oscilloscope", QObject::tr("Tool")}, + {"Peak Controller", QObject::tr("Automation")}, + {"ReverbSC", QObject::tr("Reverb")}, + {"Slew Distortion", QObject::tr("Distortion")}, + {"Spectrum Analyzer", QObject::tr("Tool")}, + {"Stereo Matrix", QObject::tr("Stereo")}, + {"StereoEnhancer Effect", QObject::tr("Stereo")}, + {"Vectorscope", QObject::tr("Tool")}, + {"Waveshaper Effect", QObject::tr("Distortion")} +}; + +const std::map ladspaEffects = +{ + {"4 x 4 pole allpass", QObject::tr("Filter")}, + {"AM pitchshifter", QObject::tr("Pitch")}, + {"Aliasing", QObject::tr("Distortion")}, + {"Allpass delay line, cubic spline interpolation", QObject::tr("Delay")}, + {"Allpass delay line, linear interpolation", QObject::tr("Delay")}, + {"Allpass delay line, noninterpolating", QObject::tr("Delay")}, + {"Amplifier (Mono)", QObject::tr("Amplifier")}, + {"Amplifier (Stereo)", QObject::tr("Amplifier")}, + {"Artificial latency", QObject::tr("Other")}, + {"Audio Divider (Suboctave Generator)", QObject::tr("Distortion")}, + {"Auto phaser", QObject::tr("Phaser")}, + {"Barry's Satan Maximiser", QObject::tr("Distortion")}, + {"C* AmpIII - Tube amp", QObject::tr("Amplifier")}, + {"C* AmpIV - Tube amp + tone controls", QObject::tr("Amplifier")}, + {"C* AmpV - Tube amp", QObject::tr("Amplifier")}, + {"C* AmpVTS - Tube amp + Tone stack", QObject::tr("Amplifier")}, + {"C* AutoFilter - Self-modulating resonant filter", QObject::tr("Filter")}, + {"C* AutoWah - Resonant envelope-following filter", QObject::tr("Wah")}, + {"C* CabinetI - Loudspeaker cabinet emulation", QObject::tr("Amplifier")}, + {"C* CabinetII - Refined loudspeaker cabinet emulation", QObject::tr("Amplifier")}, + {"C* CabinetIII - Simplistic loudspeaker cabinet emulation", QObject::tr("Amplifier")}, + {"C* CabinetIV - Idealised loudspeaker cabinet", QObject::tr("Amplifier")}, + {"C* ChorusI - Mono chorus/flanger", QObject::tr("Chorus")}, + {"C* ChorusII - Mono chorus/flanger modulated by a fractal", QObject::tr("Chorus")}, + {"C* Clip - Hard clipper, 8x oversampled", QObject::tr("Distortion")}, + {"C* Compress - Mono compressor", QObject::tr("Compressor")}, + {"C* CompressX2 - Stereo compressor and saturating limiter", QObject::tr("Compressor")}, + {"C* Eq - 10-band equalizer", QObject::tr("Equalization")}, + {"C* Eq10 - 10-band equaliser", QObject::tr("Equalization")}, + {"C* Eq10X2 - Stereo 10-band equaliser", QObject::tr("Equalization")}, + {"C* Eq2x2 - stereo 10-band equalizer", QObject::tr("Equalization")}, + {"C* Eq4p - 4-band parametric shelving equaliser", QObject::tr("Equalization")}, + {"C* EqFA4p - 4-band parametric eq", QObject::tr("Equalization")}, + {"C* Narrower - Stereo image width reduction", QObject::tr("Stereo")}, + {"C* Noisegate - Attenuating hum and noise", QObject::tr("Gate")}, + {"C* PhaserI - Mono phaser", QObject::tr("Phaser")}, + {"C* PhaserII - Mono phaser modulated by a Lorenz fractal", QObject::tr("Phaser")}, + {"C* Plate2x2 - Versatile plate reverb, stereo inputs", QObject::tr("Reverb")}, + {"C* PlateX2 - Versatile plate reverb, stereo inputs", QObject::tr("Reverb")}, + {"C* PreampIII - Tube preamp emulation", QObject::tr("Amplifier")}, + {"C* PreampIV - Tube preamp emulation + tone controls", QObject::tr("Amplifier")}, + {"C* Saturate - Various static nonlinearities, 8x oversampled", QObject::tr("Distortion")}, + {"C* Spice - Not an exciter", QObject::tr("Equalization")}, + {"C* SpiceX2 - Not an exciter either", QObject::tr("Equalization")}, + {"C* SweepVFI - Resonant filter swept by a Lorenz fractal", QObject::tr("Filter")}, + {"C* SweepVFII - Resonant filter, f and Q swept by a Lorenz fractal", QObject::tr("Filter")}, + {"C* ToneStack - Tone stack emulation", QObject::tr("Filter")}, + {"C* ToneStackLT - Tone stack emulation, lattice filter 44.1", QObject::tr("Filter")}, + {"Calf Analyzer LADSPA", QObject::tr("Tool")}, + {"Calf Bass Enhancer LADSPA", QObject::tr("Equalization")}, + {"Calf Compensation Delay Line LADSPA", QObject::tr("Delay")}, + {"Calf Compressor LADSPA", QObject::tr("Compressor")}, + {"Calf Crusher LADSPA", QObject::tr("Distortion")}, + {"Calf Deesser LADSPA", QObject::tr("Deesser")}, + {"Calf Emphasis LADSPA", QObject::tr("Filter")}, + {"Calf Envelope Filter LADSPA", QObject::tr("Wah")}, + {"Calf Equalizer 12 Band LADSPA", QObject::tr("Equalization")}, + {"Calf Equalizer 30 Band LADSPA", QObject::tr("Equalization")}, + {"Calf Equalizer 5 Band LADSPA", QObject::tr("Equalization")}, + {"Calf Equalizer 8 Band LADSPA", QObject::tr("Equalization")}, + {"Calf Exciter LADSPA", QObject::tr("Distortion")}, + {"Calf Filter LADSPA", QObject::tr("Filter")}, + {"Calf Filterclavier LADSPA", QObject::tr("Filter")}, + {"Calf Flanger LADSPA", QObject::tr("Flanger")}, + {"Calf Gate LADSPA", QObject::tr("Gate")}, + {"Calf Haas Stereo Enhancer LADSPA", QObject::tr("Stereo")}, + {"Calf Limiter LADSPA", QObject::tr("Limiter")}, + {"Calf Mono Compressor LADSPA", QObject::tr("Compressor")}, + {"Calf Multi Chorus LADSPA", QObject::tr("Chorus")}, + {"Calf Multi Spread LADSPA", QObject::tr("Stereo")}, + {"Calf Multiband Compressor LADSPA", QObject::tr("Compressor")}, + {"Calf Multiband Enhancer LADSPA", QObject::tr("Distortion")}, + {"Calf Multiband Gate LADSPA", QObject::tr("Gate")}, + {"Calf Multiband Limiter LADSPA", QObject::tr("Limiter")}, + {"Calf Phaser LADSPA", QObject::tr("Phaser")}, + {"Calf Psychoachoustic Clipper LADSPA", QObject::tr("Distortion")}, + {"Calf Pulsator LADSPA", QObject::tr("Stereo")}, + {"Calf Reverb LADSPA", QObject::tr("Reverb")}, + {"Calf Reverse Delay LADSPA", QObject::tr("Delay")}, + {"Calf Ring Modulator LADSPA", QObject::tr("LFO")}, + {"Calf Rotary Speaker LADSPA", QObject::tr("Stereo")}, + {"Calf Saturator LADSPA", QObject::tr("Distortion")}, + {"Calf Sidechain Compressor LADSPA", QObject::tr("Compressor")}, + {"Calf Sidechain Gate LADSPA", QObject::tr("Gate")}, + {"Calf Sidechain Limiter LADSPA", QObject::tr("Limiter")}, + {"Calf Stereo Tools LADSPA", QObject::tr("Stereo")}, + {"Calf Tape Simulator LADSPA", QObject::tr("Distortion")}, + {"Calf Transient Designer LADSPA", QObject::tr("Equalization")}, + {"Calf Vintage Delay LADSPA", QObject::tr("Delay")}, + {"Canyon Delay", QObject::tr("Delay")}, + {"Chebyshev distortion", QObject::tr("Distortion")}, + {"Comb Filter", QObject::tr("Filter")}, + {"Comb delay line, cubic spline interpolation", QObject::tr("Delay")}, + {"Comb delay line, linear interpolation", QObject::tr("Delay")}, + {"Comb delay line, noninterpolating", QObject::tr("Delay")}, + {"Constant Signal Generator", QObject::tr("Tool")}, + {"Crossover distortion", QObject::tr("Distortion")}, + {"DC Offset Remover", QObject::tr("Tool")}, + {"DJ EQ", QObject::tr("Equalization")}, + {"DJ EQ (mono)", QObject::tr("Equalization")}, + {"DJ flanger", QObject::tr("Flanger")}, + {"Debug Plugin", QObject::tr("Tool")}, + {"Decimator", QObject::tr("Distortion")}, + {"Declipper", QObject::tr("Distortion")}, + {"Delayorama", QObject::tr("Delay")}, + {"Diode Processor", QObject::tr("Distortion")}, + {"Disintegrator", QObject::tr("Distortion")}, + {"Dyson compressor", QObject::tr("Compressor")}, + {"Echo Delay Line (Maximum Delay 0.01s)", QObject::tr("Delay")}, + {"Echo Delay Line (Maximum Delay 0.1s)", QObject::tr("Delay")}, + {"Echo Delay Line (Maximum Delay 1s)", QObject::tr("Delay")}, + {"Echo Delay Line (Maximum Delay 5s)", QObject::tr("Delay")}, + {"Echo Delay Line (Maximum Delay 60s)", QObject::tr("Delay")}, + {"Exponential signal decay", QObject::tr("Delay")}, + {"Fast Lookahead limiter", QObject::tr("Limiter")}, + {"Fast overdrive", QObject::tr("Distortion")}, + {"Feedback Delay Line (Maximum Delay 0.01s)", QObject::tr("Delay")}, + {"Feedback Delay Line (Maximum Delay 0.1s)", QObject::tr("Delay")}, + {"Feedback Delay Line (Maximum Delay 1s)", QObject::tr("Delay")}, + {"Feedback Delay Line (Maximum Delay 5s)", QObject::tr("Delay")}, + {"Feedback Delay Line (Maximum Delay 60s)", QObject::tr("Delay")}, + {"Flanger", QObject::tr("Flanger")}, + {"Foldover distortion", QObject::tr("Distortion")}, + {"Fractionally Addressed Delay Line", QObject::tr("Delay")}, + {"Freeverb (Version 3)", QObject::tr("Reverb")}, + {"GLAME Butterworth Highpass", QObject::tr("Filter")}, + {"GLAME Butterworth Lowpass", QObject::tr("Filter")}, + {"GSM simulator", QObject::tr("Distortion")}, + {"Gate", QObject::tr("Gate")}, + {"Giant Flange", QObject::tr("Flanger")}, + {"Glame Bandpass Analog Filter", QObject::tr("Filter")}, + {"Glame Bandpass Filter", QObject::tr("Filter")}, + {"Glame Highpass Filter", QObject::tr("Filter")}, + {"Glame Lowpass Filter", QObject::tr("Filter")}, + {"Gong beater", QObject::tr("Other")}, + {"Gong model", QObject::tr("Other")}, + {"Granular Scatter Processor", QObject::tr("Stereo")}, + {"Hard Gate", QObject::tr("Gate")}, + {"Hard Limiter", QObject::tr("Limiter")}, + {"Harmonic generator", QObject::tr("Other")}, + {"Hermes Filter", QObject::tr("Filter")}, + {"High Pass Filter (One Pole)", QObject::tr("Filter")}, + {"Higher Quality Pitch Scaler", QObject::tr("Pitch")}, + {"Identity (Audio)", QObject::tr("Tool")}, + {"Impulse convolver", QObject::tr("Reverb")}, + {"Inverter", QObject::tr("Tool")}, + {"Karaoke", QObject::tr("Tool")}, + {"L/C/R Delay", QObject::tr("Delay")}, + {"LFO Phaser", QObject::tr("Phaser")}, + {"LS Filter", QObject::tr("Filter")}, + {"Lo Fi", QObject::tr("Distortion")}, + {"Low Pass Filter (One Pole)", QObject::tr("Filter")}, + {"Mag's Notch Filter", QObject::tr("Filter")}, + {"Matrix Spatialiser", QObject::tr("Stereo")}, + {"Modulatable delay", QObject::tr("Delay")}, + {"Multiband EQ", QObject::tr("Equalization")}, + {"Multivoice Chorus", QObject::tr("Chorus")}, + {"Pitch Scaler", QObject::tr("Pitch")}, + {"Pointer cast distortion", QObject::tr("Distortion")}, + {"Rate shifter", QObject::tr("Pitch")}, + {"Retro Flanger", QObject::tr("Flanger")}, + {"Reverse Delay (5s max)", QObject::tr("Delay")}, + {"Ringmod with LFO", QObject::tr("LFO")}, + {"Ringmod with two inputs", QObject::tr("LFO")}, + {"SC1", QObject::tr("Compressor")}, + {"SC4", QObject::tr("Compressor")}, + {"SC4 mono", QObject::tr("Compressor")}, + {"SE4", QObject::tr("Stereo")}, + {"Signal sifter", QObject::tr("Distortion")}, + {"Simple Compressor (Peak Envelope Tracking)", QObject::tr("Compressor")}, + {"Simple Compressor (RMS Envelope Tracking)", QObject::tr("Compressor")}, + {"Simple Expander (Peak Envelope Tracking)", QObject::tr("Stereo")}, + {"Simple Expander (RMS Envelope Tracking)", QObject::tr("Stereo")}, + {"Simple Limiter (Peak Envelope Tracking)", QObject::tr("Limiter")}, + {"Simple Limiter (RMS Envelope Tracking)", QObject::tr("Limiter")}, + {"Simple amplifier", QObject::tr("Amplifier")}, + {"Simple delay line, cubic spline interpolation", QObject::tr("Delay")}, + {"Simple delay line, linear interpolation", QObject::tr("Delay")}, + {"Simple delay line, noninterpolating", QObject::tr("Delay")}, + {"Single band parametric", QObject::tr("Filter")}, + {"Sinus wavewrapper", QObject::tr("Distortion")}, + {"Smooth Decimator", QObject::tr("Distortion")}, + {"State Variable Filter", QObject::tr("Filter")}, + {"Stereo Gate", QObject::tr("Gate")}, + {"TAP AutoPanner", QObject::tr("Stereo")}, + {"TAP Chorus/Flanger", QObject::tr("Flanger")}, + {"TAP DeEsser", QObject::tr("Deesser")}, + {"TAP Dynamics (M)", QObject::tr("Distortion")}, + {"TAP Dynamics (St)", QObject::tr("Distortion")}, + {"TAP Equalizer", QObject::tr("Equalization")}, + {"TAP Equalizer/BW", QObject::tr("Equalization")}, + {"TAP Fractal Doubler", QObject::tr("Delay")}, + {"TAP Pink/Fractal Noise", QObject::tr("Noise")}, + {"TAP Pitch Shifter", QObject::tr("Pitch")}, + {"TAP Reflector", QObject::tr("Delay")}, + {"TAP Reverberator", QObject::tr("Delay")}, + {"TAP Rotary Speaker", QObject::tr("Stereo")}, + {"TAP Scaling Limiter", QObject::tr("Limiter")}, + {"TAP Sigmoid Booster", QObject::tr("Equalization")}, + {"TAP Stereo Echo", QObject::tr("Stereo")}, + {"TAP Tremolo", QObject::tr("Pitch")}, + {"TAP TubeWarmth", QObject::tr("Amplifier")}, + {"TAP Vibrato", QObject::tr("Pitch")}, + {"Tape Delay Simulation", QObject::tr("Delay")}, + {"Transient mangler", QObject::tr("Other")}, + {"Triple band parametric with shelves", QObject::tr("Equalization")}, + {"VCF 303", QObject::tr("Filter")}, + {"Valve rectifier", QObject::tr("Distortion")}, + {"Valve saturation", QObject::tr("Distortion")}, + {"Vocoder", QObject::tr("Vocoder")}, + {"VyNil (Vinyl Effect)", QObject::tr("Distortion")}, + {"Wave Shaper (Sine-Based)", QObject::tr("Distortion")}, + {"Wave shaper", QObject::tr("Distortion")}, + {"z-1", QObject::tr("Delay")}, +}; +const QString defaultCategory = "Other"; + +std::unique_ptr EffectCategory::s_instance; +QStringList m_categories; + +EffectCategory* EffectCategory::instance() +{ + if (s_instance == nullptr) + { + s_instance = std::make_unique(); + } + return s_instance.get(); +} + +EffectCategory* getEffectCategory() +{ + return EffectCategory::instance(); +} + +QString EffectCategory::getCategoryName(QString effectName) +{ + if (lmmsEffects.find(effectName) != lmmsEffects.end()) { return lmmsEffects.at(effectName); } + if (ladspaEffects.find(effectName) != ladspaEffects.end()) { return ladspaEffects.at(effectName); } + return defaultCategory; +} + +QStringList EffectCategory::getCategories() +{ + if (m_categories.isEmpty()) + { + m_categories = getCategoriesFromMap(lmmsEffects); + QStringList ladspaCategories = getCategoriesFromMap(ladspaEffects); + for (const QString& category : ladspaCategories) + { + if (!m_categories.contains(category)) + { + m_categories.append(category); + } + } + } + m_categories.sort(); + return m_categories; +} + +QStringList EffectCategory::getCategoriesFromMap(std::map map) +{ + auto* categories = new QStringList(); + for (auto& it : map) + { + if (!categories->contains(it.second)) + { + categories->append(it.second); + } + } + return *categories; +} + +} // namespace lmms diff --git a/src/gui/modals/EffectSelectDialog.cpp b/src/gui/modals/EffectSelectDialog.cpp index 26bcade00ab..0ddd1a2a843 100644 --- a/src/gui/modals/EffectSelectDialog.cpp +++ b/src/gui/modals/EffectSelectDialog.cpp @@ -24,10 +24,6 @@ */ #include "EffectSelectDialog.h" -#include "DummyEffect.h" -#include "EffectChain.h" -#include "embed.h" -#include "PluginFactory.h" #include #include @@ -42,34 +38,39 @@ #include #include #include +#include +#include +#include +#include "DummyEffect.h" +#include "EffectCategory.h" +#include "EffectChain.h" +#include "PluginFactory.h" +#include "embed.h" -namespace lmms::gui +namespace lmms::gui { -EffectSelectDialog::EffectSelectDialog(QWidget* parent) : - QDialog(parent), - m_effectKeys(), - m_currentSelection(), - m_sourceModel(), - m_model(), - m_descriptionWidget(nullptr), - m_pluginList(new QTableView(this)), - m_scrollArea(new QScrollArea(this)) +EffectSelectDialog::EffectSelectDialog(QWidget* parent) + : QDialog(parent) + , m_effectKeys() + , m_currentSelection() + , m_sourceModel() + , m_model() + , m_descriptionWidget(nullptr) + , m_pluginList(new QTableView(this)) + , m_scrollArea(new QScrollArea(this)) { setWindowTitle(tr("Add effect")); resize(640, 480); - + setWindowIcon(embed::getIconPixmap("setup_audio")); // Query effects EffectKeyList subPluginEffectKeys; for (const auto desc : getPluginFactory()->descriptors(Plugin::Type::Effect)) { - if (desc->subPluginFeatures) - { - desc->subPluginFeatures->listSubPluginKeys(desc, subPluginEffectKeys); - } + if (desc->subPluginFeatures) { desc->subPluginFeatures->listSubPluginKeys(desc, subPluginEffectKeys); } else { m_effectKeys << EffectKey(desc, desc->name); @@ -79,7 +80,8 @@ EffectSelectDialog::EffectSelectDialog(QWidget* parent) : // Fill the source model m_sourceModel.setHorizontalHeaderItem(0, new QStandardItem(tr("Name"))); - m_sourceModel.setHorizontalHeaderItem(1, new QStandardItem(tr("Type"))); + m_sourceModel.setHorizontalHeaderItem(1, new QStandardItem(tr("Category"))); + m_sourceModel.setHorizontalHeaderItem(2, new QStandardItem(tr("Type"))); int row = 0; for (EffectKeyList::ConstIterator it = m_effectKeys.begin(); it != m_effectKeys.end(); ++it) { @@ -96,7 +98,8 @@ EffectSelectDialog::EffectSelectDialog(QWidget* parent) : type = "LMMS"; } m_sourceModel.setItem(row, 0, new QStandardItem(name)); - m_sourceModel.setItem(row, 1, new QStandardItem(type)); + m_sourceModel.setItem(row, 1, new QStandardItem(getEffectCategory()->getCategoryName(name))); + m_sourceModel.setItem(row, 2, new QStandardItem(type)); ++row; } @@ -106,30 +109,6 @@ EffectSelectDialog::EffectSelectDialog(QWidget* parent) : QHBoxLayout* mainLayout = new QHBoxLayout(this); - QVBoxLayout* leftSectionLayout = new QVBoxLayout(); - - QStringList buttonLabels = { tr("All"), "LMMS", "LADSPA", "LV2", "VST" }; - QStringList buttonSearchString = { "", "LMMS", "LADSPA", "LV2", "VST" }; - - for (int i = 0; i < buttonLabels.size(); ++i) - { - const QString& label = buttonLabels[i]; - const QString& searchString = buttonSearchString[i]; - - QPushButton* button = new QPushButton(label, this); - button->setFixedSize(50, 50); - button->setFocusPolicy(Qt::NoFocus); - leftSectionLayout->addWidget(button); - - connect(button, &QPushButton::clicked, this, [this, searchString] { - m_model.setEffectTypeFilter(searchString); - updateSelection(); - }); - } - - leftSectionLayout->addStretch();// Add stretch to the button layout to push buttons to the top - mainLayout->addLayout(leftSectionLayout); - m_filterEdit = new QLineEdit(this); connect(m_filterEdit, &QLineEdit::textChanged, this, [this](const QString& text) { m_model.setFilterRegularExpression(QRegularExpression(text, QRegularExpression::CaseInsensitiveOption)); @@ -146,7 +125,7 @@ EffectSelectDialog::EffectSelectDialog(QWidget* parent) : m_pluginList->setSelectionBehavior(QAbstractItemView::SelectRows); m_pluginList->setSelectionMode(QAbstractItemView::SingleSelection); m_pluginList->setSortingEnabled(true); - m_pluginList->sortByColumn(0, Qt::AscendingOrder); // Initial sort by column 0 (Name) + m_pluginList->sortByColumn(0, Qt::AscendingOrder); // Initial sort by column 0 (Name) m_pluginList->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); m_pluginList->verticalHeader()->hide(); m_pluginList->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); @@ -170,6 +149,7 @@ EffectSelectDialog::EffectSelectDialog(QWidget* parent) : QVBoxLayout* rightSectionLayout = new QVBoxLayout(); rightSectionLayout->addWidget(m_filterEdit); + rightSectionLayout->addLayout(buildFiltersLayout()); rightSectionLayout->addWidget(m_pluginList); rightSectionLayout->addWidget(m_scrollArea); rightSectionLayout->addWidget(buttonBox); @@ -179,12 +159,10 @@ EffectSelectDialog::EffectSelectDialog(QWidget* parent) : auto selectionModel = new QItemSelectionModel(&m_model); m_pluginList->setSelectionModel(selectionModel); - connect(selectionModel, &QItemSelectionModel::currentRowChanged, - this, &EffectSelectDialog::rowChanged); + connect(selectionModel, &QItemSelectionModel::currentRowChanged, this, &EffectSelectDialog::rowChanged); + + connect(m_pluginList, &QTableView::doubleClicked, this, &EffectSelectDialog::acceptSelection); - connect(m_pluginList, &QTableView::doubleClicked, - this, &EffectSelectDialog::acceptSelection); - setModal(true); installEventFilter(this); @@ -192,7 +170,6 @@ EffectSelectDialog::EffectSelectDialog(QWidget* parent) : show(); } - Effect* EffectSelectDialog::instantiateSelectedPlugin(EffectChain* parent) { Effect* result = nullptr; @@ -200,19 +177,13 @@ Effect* EffectSelectDialog::instantiateSelectedPlugin(EffectChain* parent) { result = Effect::instantiate(m_currentSelection.desc->name, parent, &m_currentSelection); } - if (!result) - { - result = new DummyEffect(parent, QDomElement()); - } + if (!result) { result = new DummyEffect(parent, QDomElement()); } return result; } void EffectSelectDialog::acceptSelection() { - if (m_currentSelection.isValid()) - { - accept(); - } + if (m_currentSelection.isValid()) { accept(); } } void EffectSelectDialog::rowChanged(const QModelIndex& idx, const QModelIndex&) @@ -264,8 +235,7 @@ void EffectSelectDialog::rowChanged(const QModelIndex& idx, const QModelIndex&) subLayout->setContentsMargins(0, 0, 0, 0); subLayout->setSpacing(8); - m_currentSelection.desc->subPluginFeatures-> - fillDescriptionWidget(subWidget, &m_currentSelection); + m_currentSelection.desc->subPluginFeatures->fillDescriptionWidget(subWidget, &m_currentSelection); for (QWidget* w : subWidget->findChildren()) { if (w->parent() == subWidget) @@ -291,7 +261,6 @@ void EffectSelectDialog::rowChanged(const QModelIndex& idx, const QModelIndex&) tr("Description: "), qApp->translate("PluginBrowser", descriptor.description) .toHtmlEscaped() ); - auto label = new QLabel(labelText, m_descriptionWidget); label->setWordWrap(true); textWidgetLayout->addWidget(label); @@ -308,17 +277,17 @@ void EffectSelectDialog::updateSelection() if (m_pluginList->selectionModel()->selection().size() <= 0) { // Then select our first item - m_pluginList->selectionModel()-> - select(m_model.index(0, 0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + m_pluginList->selectionModel()->select( + m_model.index(0, 0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); rowChanged(m_model.index(0, 0), QModelIndex()); } } -bool EffectSelectDialog::eventFilter(QObject *obj, QEvent *event) +bool EffectSelectDialog::eventFilter(QObject* obj, QEvent* event) { if (obj == this && event->type() == QEvent::KeyPress) { - QKeyEvent *keyEvent = static_cast(event); + QKeyEvent* keyEvent = static_cast(event); if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down) { QItemSelectionModel* selectionModel = m_pluginList->selectionModel(); @@ -326,7 +295,7 @@ bool EffectSelectDialog::eventFilter(QObject *obj, QEvent *event) int newRow = (keyEvent->key() == Qt::Key_Up) ? currentRow - 1 : currentRow + 1; int rowCount = m_pluginList->model()->rowCount(); newRow = qBound(0, newRow, rowCount - 1); - + selectionModel->setCurrentIndex(m_pluginList->model()->index(newRow, 0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); m_pluginList->scrollTo(m_pluginList->model()->index(newRow, 0)); @@ -337,4 +306,48 @@ bool EffectSelectDialog::eventFilter(QObject *obj, QEvent *event) return QDialog::eventFilter(obj, event); } +QHBoxLayout* EffectSelectDialog::buildFiltersLayout() +{ + auto* layout = new QHBoxLayout(); + layout->addLayout(buildTypeFilterLayout()); + layout->addLayout(buildCategoryFilterLayout()); + return layout; +} + +QHBoxLayout* EffectSelectDialog::buildTypeFilterLayout() +{ + auto* label = new QLabel(tr("Type")); + auto* buttonFilter = new QComboBox(); + QStringList labels = {tr("All"), "LMMS", "LADSPA", "LV2", "VST"}; + buttonFilter->addItems(labels); + connect(buttonFilter, &QComboBox::textActivated, this, [this](QString value) + { + m_model.setEffectTypeFilter(value == tr("All") ? "" : value); + updateSelection(); + }); + auto* layout = new QHBoxLayout(); + layout->addWidget(label); + layout->addWidget(buttonFilter); + return layout; +} + +QHBoxLayout* EffectSelectDialog::buildCategoryFilterLayout() +{ + auto* label = new QLabel(tr("Category")); + auto* buttonFilter = new QComboBox(); + QStringList categories = getEffectCategory()->getCategories(); + QStringList labels = categories; + labels.push_front(tr("All")); + buttonFilter->addItems(labels); + connect(buttonFilter, &QComboBox::textActivated, this, [this](QString value) + { + m_model.setEffectCategoryFilter(value == tr("All") ? "" : value); + updateSelection(); + }); + auto* layout = new QHBoxLayout(); + layout->addWidget(label); + layout->addWidget(buttonFilter); + return layout; +} + } // namespace lmms::gui