Merge pull request #33 from lioncash/studio

StudioSetupWidget: Use std::array where applicable
This commit is contained in:
Phillip Stephens 2019-08-28 22:29:36 -07:00 committed by GitHub
commit af3f2a8d0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 151 additions and 87 deletions

View File

@ -14,80 +14,126 @@
using namespace std::literals; using namespace std::literals;
static const EffectIntrospection ReverbStdIntrospective = { struct EffectIntrospection {
struct Field {
enum class Type {
Invalid,
UInt32,
UInt32x8,
Float,
};
Type m_tp{};
std::string_view m_name;
float m_min{};
float m_max{};
float m_default{};
};
amuse::EffectType m_tp;
std::string_view m_name;
std::string_view m_description;
std::array<Field, 7> m_fields;
};
namespace {
constexpr EffectIntrospection ReverbStdIntrospective = {
amuse::EffectType::ReverbStd, amuse::EffectType::ReverbStd,
"Reverb Std"sv, "Reverb Std"sv,
"Standard Reverb"sv, "Standard Reverb"sv,
{{EffectIntrospection::Field::Type::Float, "Coloration"sv, 0.f, 1.f, 0.f}, {
{EffectIntrospection::Field::Type::Float, "Mix"sv, 0.f, 1.f, 0.f}, {{EffectIntrospection::Field::Type::Float, "Coloration"sv, 0.f, 1.f, 0.f},
{EffectIntrospection::Field::Type::Float, "Time"sv, 0.01f, 10.f, 0.01f}, {EffectIntrospection::Field::Type::Float, "Mix"sv, 0.f, 1.f, 0.f},
{EffectIntrospection::Field::Type::Float, "Damping"sv, 0.f, 1.f, 0.f}, {EffectIntrospection::Field::Type::Float, "Time"sv, 0.01f, 10.f, 0.01f},
{EffectIntrospection::Field::Type::Float, "Pre Delay"sv, 0.f, 0.1f, 0.f}}}; {EffectIntrospection::Field::Type::Float, "Damping"sv, 0.f, 1.f, 0.f},
{EffectIntrospection::Field::Type::Float, "Pre Delay"sv, 0.f, 0.1f, 0.f}},
},
};
typedef float (amuse::EffectReverbStd::*ReverbStdGetFunc)() const; using ReverbStdGetFunc = float (amuse::EffectReverbStd::*)() const;
typedef void (amuse::EffectReverbStd::*ReverbStdSetFunc)(float); using ReverbStdSetFunc = void (amuse::EffectReverbStd::*)(float);
static const ReverbStdGetFunc ReverbStdGetters[] = { constexpr std::array<ReverbStdGetFunc, 5> ReverbStdGetters{
&amuse::EffectReverbStd::getColoration, &amuse::EffectReverbStd::getMix, &amuse::EffectReverbStd::getTime, &amuse::EffectReverbStd::getColoration, &amuse::EffectReverbStd::getMix, &amuse::EffectReverbStd::getTime,
&amuse::EffectReverbStd::getDamping, &amuse::EffectReverbStd::getPreDelay}; &amuse::EffectReverbStd::getDamping, &amuse::EffectReverbStd::getPreDelay,
static const ReverbStdSetFunc ReverbStdSetters[] = { };
&amuse::EffectReverbStd::setColoration, &amuse::EffectReverbStd::setMix, &amuse::EffectReverbStd::setTime, constexpr std::array<ReverbStdSetFunc, 5> ReverbStdSetters{
&amuse::EffectReverbStd::setDamping, &amuse::EffectReverbStd::setPreDelay}; &amuse::EffectReverbStd::setColoration, &amuse::EffectReverbStd::setMix, &amuse::EffectReverbStd::setTime,
&amuse::EffectReverbStd::setDamping, &amuse::EffectReverbStd::setPreDelay,
};
static const EffectIntrospection ReverbHiIntrospective = { constexpr EffectIntrospection ReverbHiIntrospective = {
amuse::EffectType::ReverbHi, amuse::EffectType::ReverbHi,
"Reverb Hi"sv, "Reverb Hi"sv,
"High Reverb"sv, "High Reverb"sv,
{{EffectIntrospection::Field::Type::Float, "Coloration"sv, 0.f, 1.f, 0.f}, {
{EffectIntrospection::Field::Type::Float, "Mix"sv, 0.f, 1.f, 0.f}, {{EffectIntrospection::Field::Type::Float, "Coloration"sv, 0.f, 1.f, 0.f},
{EffectIntrospection::Field::Type::Float, "Time"sv, 0.01f, 10.f, 0.01f}, {EffectIntrospection::Field::Type::Float, "Mix"sv, 0.f, 1.f, 0.f},
{EffectIntrospection::Field::Type::Float, "Damping"sv, 0.f, 1.f, 0.f}, {EffectIntrospection::Field::Type::Float, "Time"sv, 0.01f, 10.f, 0.01f},
{EffectIntrospection::Field::Type::Float, "Pre Delay"sv, 0.f, 0.1f, 0.f}, {EffectIntrospection::Field::Type::Float, "Damping"sv, 0.f, 1.f, 0.f},
{EffectIntrospection::Field::Type::Float, "Crosstalk"sv, 0.f, 1.f, 0.f}}}; {EffectIntrospection::Field::Type::Float, "Pre Delay"sv, 0.f, 0.1f, 0.f},
{EffectIntrospection::Field::Type::Float, "Crosstalk"sv, 0.f, 1.f, 0.f}},
},
};
typedef float (amuse::EffectReverbHi::*ReverbHiGetFunc)() const; using ReverbHiGetFunc = float (amuse::EffectReverbHi::*)() const;
typedef void (amuse::EffectReverbHi::*ReverbHiSetFunc)(float); using ReverbHiSetFunc = void (amuse::EffectReverbHi::*)(float);
static const ReverbHiGetFunc ReverbHiGetters[] = { constexpr std::array<ReverbHiGetFunc, 6> ReverbHiGetters{
&amuse::EffectReverbHi::getColoration, &amuse::EffectReverbHi::getMix, &amuse::EffectReverbHi::getTime, &amuse::EffectReverbHi::getColoration, &amuse::EffectReverbHi::getMix, &amuse::EffectReverbHi::getTime,
&amuse::EffectReverbHi::getDamping, &amuse::EffectReverbHi::getPreDelay, &amuse::EffectReverbHi::getCrosstalk}; &amuse::EffectReverbHi::getDamping, &amuse::EffectReverbHi::getPreDelay, &amuse::EffectReverbHi::getCrosstalk,
static const ReverbHiSetFunc ReverbHiSetters[] = { };
constexpr std::array<ReverbHiSetFunc, 6> ReverbHiSetters{
&amuse::EffectReverbHi::setColoration, &amuse::EffectReverbHi::setMix, &amuse::EffectReverbHi::setTime, &amuse::EffectReverbHi::setColoration, &amuse::EffectReverbHi::setMix, &amuse::EffectReverbHi::setTime,
&amuse::EffectReverbHi::setDamping, &amuse::EffectReverbHi::setPreDelay, &amuse::EffectReverbHi::setCrosstalk}; &amuse::EffectReverbHi::setDamping, &amuse::EffectReverbHi::setPreDelay, &amuse::EffectReverbHi::setCrosstalk,
};
static const EffectIntrospection DelayIntrospective = { constexpr EffectIntrospection DelayIntrospective = {
amuse::EffectType::Delay, amuse::EffectType::Delay,
"Delay"sv, "Delay"sv,
"Delay"sv, "Delay"sv,
{ {{
{EffectIntrospection::Field::Type::UInt32x8, "Delay"sv, 10, 5000, 10}, {EffectIntrospection::Field::Type::UInt32x8, "Delay"sv, 10, 5000, 10},
{EffectIntrospection::Field::Type::UInt32x8, "Feedback"sv, 0, 100, 0}, {EffectIntrospection::Field::Type::UInt32x8, "Feedback"sv, 0, 100, 0},
{EffectIntrospection::Field::Type::UInt32x8, "Output"sv, 0, 100, 0}, {EffectIntrospection::Field::Type::UInt32x8, "Output"sv, 0, 100, 0},
}}; }},
};
typedef uint32_t (amuse::EffectDelay::*DelayGetFunc)(int) const; using DelayGetFunc = uint32_t (amuse::EffectDelay::*)(int) const;
typedef void (amuse::EffectDelay::*DelaySetFunc)(int, uint32_t); using DelaySetFunc = void (amuse::EffectDelay::*)(int, uint32_t);
static const DelayGetFunc DelayGetters[] = {&amuse::EffectDelay::getChanDelay, &amuse::EffectDelay::getChanFeedback, constexpr std::array<DelayGetFunc, 3> DelayGetters{
&amuse::EffectDelay::getChanOutput}; &amuse::EffectDelay::getChanDelay,
static const DelaySetFunc DelaySetters[] = {&amuse::EffectDelay::setChanDelay, &amuse::EffectDelay::setChanFeedback, &amuse::EffectDelay::getChanFeedback,
&amuse::EffectDelay::setChanOutput}; &amuse::EffectDelay::getChanOutput,
};
constexpr std::array<DelaySetFunc, 3> DelaySetters{
&amuse::EffectDelay::setChanDelay,
&amuse::EffectDelay::setChanFeedback,
&amuse::EffectDelay::setChanOutput,
};
static const EffectIntrospection ChorusIntrospective = { constexpr EffectIntrospection ChorusIntrospective = {
amuse::EffectType::Chorus, amuse::EffectType::Chorus,
"Chorus"sv, "Chorus"sv,
"Chorus"sv, "Chorus"sv,
{ {{
{EffectIntrospection::Field::Type::UInt32, "Base Delay"sv, 5, 15, 5}, {EffectIntrospection::Field::Type::UInt32, "Base Delay"sv, 5, 15, 5},
{EffectIntrospection::Field::Type::UInt32, "Variation"sv, 0, 5, 0}, {EffectIntrospection::Field::Type::UInt32, "Variation"sv, 0, 5, 0},
{EffectIntrospection::Field::Type::UInt32, "Period"sv, 500, 10000, 500}, {EffectIntrospection::Field::Type::UInt32, "Period"sv, 500, 10000, 500},
}}; }},
};
typedef uint32_t (amuse::EffectChorus::*ChorusGetFunc)() const; using ChorusGetFunc = uint32_t (amuse::EffectChorus::*)() const;
typedef void (amuse::EffectChorus::*ChorusSetFunc)(uint32_t); using ChorusSetFunc = void (amuse::EffectChorus::*)(uint32_t);
static const ChorusGetFunc ChorusGetters[] = {&amuse::EffectChorus::getBaseDelay, &amuse::EffectChorus::getVariation, constexpr std::array<ChorusGetFunc, 3> ChorusGetters{
&amuse::EffectChorus::getPeriod}; &amuse::EffectChorus::getBaseDelay,
static const ChorusSetFunc ChorusSetters[] = {&amuse::EffectChorus::setBaseDelay, &amuse::EffectChorus::setVariation, &amuse::EffectChorus::getVariation,
&amuse::EffectChorus::setPeriod}; &amuse::EffectChorus::getPeriod,
};
constexpr std::array<ChorusSetFunc, 3> ChorusSetters{
&amuse::EffectChorus::setBaseDelay,
&amuse::EffectChorus::setVariation,
&amuse::EffectChorus::setPeriod,
};
static const EffectIntrospection* GetEffectIntrospection(amuse::EffectType type) { constexpr const EffectIntrospection* GetEffectIntrospection(amuse::EffectType type) {
switch (type) { switch (type) {
case amuse::EffectType::ReverbStd: case amuse::EffectType::ReverbStd:
return &ReverbStdIntrospective; return &ReverbStdIntrospective;
@ -103,7 +149,7 @@ static const EffectIntrospection* GetEffectIntrospection(amuse::EffectType type)
} }
template <typename T> template <typename T>
static T GetEffectParm(const amuse::EffectBaseTypeless* effect, int idx, int chanIdx) { T GetEffectParm(const amuse::EffectBaseTypeless* effect, int idx, int chanIdx) {
switch (effect->Isa()) { switch (effect->Isa()) {
case amuse::EffectType::ReverbStd: case amuse::EffectType::ReverbStd:
return (static_cast<const amuse::EffectReverbStdImp<float>*>(effect)->*ReverbStdGetters[idx])(); return (static_cast<const amuse::EffectReverbStdImp<float>*>(effect)->*ReverbStdGetters[idx])();
@ -119,7 +165,7 @@ static T GetEffectParm(const amuse::EffectBaseTypeless* effect, int idx, int cha
} }
template <typename T> template <typename T>
static void SetEffectParm(amuse::EffectBaseTypeless* effect, int idx, int chanIdx, T val) { void SetEffectParm(amuse::EffectBaseTypeless* effect, int idx, int chanIdx, T val) {
switch (effect->Isa()) { switch (effect->Isa()) {
case amuse::EffectType::ReverbStd: case amuse::EffectType::ReverbStd:
(static_cast<amuse::EffectReverbStdImp<float>*>(effect)->*ReverbStdSetters[idx])(val); (static_cast<amuse::EffectReverbStdImp<float>*>(effect)->*ReverbStdSetters[idx])(val);
@ -138,11 +184,28 @@ static void SetEffectParm(amuse::EffectBaseTypeless* effect, int idx, int chanId
} }
} }
static const char* ChanNames[] = { constexpr int NumChanNames = 8;
constexpr std::array<const char*, NumChanNames> ChanNames{
QT_TRANSLATE_NOOP("Uint32X8Popup", "Front Left"), QT_TRANSLATE_NOOP("Uint32X8Popup", "Front Right"), QT_TRANSLATE_NOOP("Uint32X8Popup", "Front Left"), QT_TRANSLATE_NOOP("Uint32X8Popup", "Front Right"),
QT_TRANSLATE_NOOP("Uint32X8Popup", "Rear Left"), QT_TRANSLATE_NOOP("Uint32X8Popup", "Rear Right"), QT_TRANSLATE_NOOP("Uint32X8Popup", "Rear Left"), QT_TRANSLATE_NOOP("Uint32X8Popup", "Rear Right"),
QT_TRANSLATE_NOOP("Uint32X8Popup", "Front Center"), QT_TRANSLATE_NOOP("Uint32X8Popup", "LFE"), QT_TRANSLATE_NOOP("Uint32X8Popup", "Front Center"), QT_TRANSLATE_NOOP("Uint32X8Popup", "LFE"),
QT_TRANSLATE_NOOP("Uint32X8Popup", "Side Left"), QT_TRANSLATE_NOOP("Uint32X8Popup", "Side Right")}; QT_TRANSLATE_NOOP("Uint32X8Popup", "Side Left"), QT_TRANSLATE_NOOP("Uint32X8Popup", "Side Right"),
};
constexpr std::array<const char*, 4> EffectStrings{
QT_TRANSLATE_NOOP("EffectCatalogue", "Reverb Standard"),
QT_TRANSLATE_NOOP("EffectCatalogue", "Reverb High"),
QT_TRANSLATE_NOOP("EffectCatalogue", "Delay"),
QT_TRANSLATE_NOOP("EffectCatalogue", "Chorus"),
};
constexpr std::array<const char*, 4> EffectDocStrings{
QT_TRANSLATE_NOOP("EffectCatalogue", "Reverb Standard"),
QT_TRANSLATE_NOOP("EffectCatalogue", "Reverb High"),
QT_TRANSLATE_NOOP("EffectCatalogue", "Delay"),
QT_TRANSLATE_NOOP("EffectCatalogue", "Chorus"),
};
} // Anonymous namespace
Uint32X8Popup::Uint32X8Popup(int min, int max, QWidget* parent) : QFrame(parent, Qt::Popup) { Uint32X8Popup::Uint32X8Popup(int min, int max, QWidget* parent) : QFrame(parent, Qt::Popup) {
setAttribute(Qt::WA_WindowPropagation); setAttribute(Qt::WA_WindowPropagation);
@ -152,7 +215,7 @@ Uint32X8Popup::Uint32X8Popup(int min, int max, QWidget* parent) : QFrame(parent,
setFrameStyle(combo->style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, combo)); setFrameStyle(combo->style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, combo));
QGridLayout* layout = new QGridLayout; QGridLayout* layout = new QGridLayout;
for (int i = 0; i < 8; ++i) { for (int i = 0; i < NumChanNames; ++i) {
layout->addWidget(new QLabel(tr(ChanNames[i])), i, 0); layout->addWidget(new QLabel(tr(ChanNames[i])), i, 0);
FieldSlider* slider = new FieldSlider(this); FieldSlider* slider = new FieldSlider(this);
m_sliders[i] = slider; m_sliders[i] = slider;
@ -253,7 +316,8 @@ EffectWidget::EffectWidget(QWidget* parent, amuse::EffectBaseTypeless* effect, a
if (m_introspection) { if (m_introspection) {
m_titleLabel.setText(tr(m_introspection->m_name.data())); m_titleLabel.setText(tr(m_introspection->m_name.data()));
m_titleLabel.setToolTip(tr(m_introspection->m_description.data())); m_titleLabel.setToolTip(tr(m_introspection->m_description.data()));
for (int f = 0; f < 7; ++f) {
for (int f = 0; f < int(m_introspection->m_fields.size()); ++f) {
const EffectIntrospection::Field& field = m_introspection->m_fields[f]; const EffectIntrospection::Field& field = m_introspection->m_fields[f];
if (!field.m_name.empty()) { if (!field.m_name.empty()) {
QString fieldName = tr(field.m_name.data()); QString fieldName = tr(field.m_name.data());
@ -272,8 +336,9 @@ EffectWidget::EffectWidget(QWidget* parent, amuse::EffectBaseTypeless* effect, a
case EffectIntrospection::Field::Type::UInt32x8: { case EffectIntrospection::Field::Type::UInt32x8: {
Uint32X8Button* sb = new Uint32X8Button(int(field.m_min), int(field.m_max), this); Uint32X8Button* sb = new Uint32X8Button(int(field.m_min), int(field.m_max), this);
sb->popup()->setProperty("fieldIndex", f); sb->popup()->setProperty("fieldIndex", f);
for (int i = 0; i < 8; ++i) for (int i = 0; i < Uint32X8Popup::NumSliders; ++i) {
sb->popup()->setValue(i, GetEffectParm<uint32_t>(m_effect, f, i)); sb->popup()->setValue(i, GetEffectParm<uint32_t>(m_effect, f, i));
}
connect(sb->popup(), &Uint32X8Popup::valueChanged, this, &EffectWidget::chanNumChanged); connect(sb->popup(), &Uint32X8Popup::valueChanged, this, &EffectWidget::chanNumChanged);
layout->addWidget(sb, 1, f); layout->addWidget(sb, 1, f);
break; break;
@ -295,6 +360,7 @@ EffectWidget::EffectWidget(QWidget* parent, amuse::EffectBaseTypeless* effect, a
} }
} }
} }
mainLayout->addLayout(layout); mainLayout->addLayout(layout);
layout->setRowMinimumHeight(0, 22); layout->setRowMinimumHeight(0, 22);
layout->setRowMinimumHeight(1, 22); layout->setRowMinimumHeight(1, 22);
@ -308,17 +374,30 @@ void EffectWidget::paintEvent(QPaintEvent* event) {
QPainter painter(this); QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::Antialiasing);
QPoint points[] = { const std::array<QPoint, 6> points{{
{1, 20}, {1, 99}, {width() - 1, 99}, {width() - 1, 1}, {20, 1}, {1, 20}, {1, 20},
}; {1, 99},
{width() - 1, 99},
{width() - 1, 1},
{20, 1},
{1, 20},
}};
painter.setBrush(palette().brush(QPalette::Window)); painter.setBrush(palette().brush(QPalette::Window));
painter.drawPolygon(points, 6); painter.drawPolygon(points.data(), int(points.size()));
painter.setPen(QPen(QColor(127, 127, 127), 2.0)); painter.setPen(QPen(QColor(127, 127, 127), 2.0));
painter.drawPolyline(points, 6); painter.drawPolyline(points.data(), int(points.size()));
QPoint headPoints[] = {{1, 20}, {1, 55}, {35, 20}, {width() - 1, 20}, {width() - 1, 1}, {20, 1}, {1, 20}}; const std::array<QPoint, 7> headPoints{{
{1, 20},
{1, 55},
{35, 20},
{width() - 1, 20},
{width() - 1, 1},
{20, 1},
{1, 20},
}};
painter.setBrush(QColor(127, 127, 127)); painter.setBrush(QColor(127, 127, 127));
painter.drawPolygon(headPoints, 7); painter.drawPolygon(headPoints.data(), int(headPoints.size()));
painter.drawRect(17, 51, 32, 32); painter.drawRect(17, 51, 32, 32);
@ -672,14 +751,6 @@ EffectCatalogueItem::EffectCatalogueItem(const EffectCatalogueItem& other, QWidg
EffectCatalogueItem::~EffectCatalogueItem() = default; EffectCatalogueItem::~EffectCatalogueItem() = default;
static const char* EffectStrings[] = {
QT_TRANSLATE_NOOP("EffectCatalogue", "Reverb Standard"), QT_TRANSLATE_NOOP("EffectCatalogue", "Reverb High"),
QT_TRANSLATE_NOOP("EffectCatalogue", "Delay"), QT_TRANSLATE_NOOP("EffectCatalogue", "Chorus")};
static const char* EffectDocStrings[] = {
QT_TRANSLATE_NOOP("EffectCatalogue", "Reverb Standard"), QT_TRANSLATE_NOOP("EffectCatalogue", "Reverb High"),
QT_TRANSLATE_NOOP("EffectCatalogue", "Delay"), QT_TRANSLATE_NOOP("EffectCatalogue", "Chorus")};
EffectCatalogue::EffectCatalogue(QWidget* parent) : QTreeWidget(parent) { EffectCatalogue::EffectCatalogue(QWidget* parent) : QTreeWidget(parent) {
setSelectionMode(QAbstractItemView::NoSelection); setSelectionMode(QAbstractItemView::NoSelection);
setColumnCount(1); setColumnCount(1);
@ -856,8 +927,8 @@ StudioSetupWidget::StudioSetupWidget(QWidget* parent)
setWindowTitle(tr("Studio Setup")); setWindowTitle(tr("Studio Setup"));
setGeometry(0, 0, 900, 450); setGeometry(0, 0, 900, 450);
QScrollArea* scrollAreas[2]; std::array<QScrollArea*, 2> scrollAreas{};
for (int i = 0; i < 2; ++i) { for (size_t i = 0; i < m_listing.size(); ++i) {
m_listing[i] = new EffectListing; m_listing[i] = new EffectListing;
QScrollArea* listingScroll = new QScrollArea; QScrollArea* listingScroll = new QScrollArea;
scrollAreas[i] = listingScroll; scrollAreas[i] = listingScroll;

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <array>
#include <string> #include <string>
#include <QLabel> #include <QLabel>
@ -16,8 +17,6 @@
#include "EditorWidget.hpp" #include "EditorWidget.hpp"
class EffectListing;
namespace amuse { namespace amuse {
class EffectBaseTypeless; class EffectBaseTypeless;
class Studio; class Studio;
@ -26,24 +25,15 @@ class Submix;
enum class EffectType; enum class EffectType;
} // namespace amuse } // namespace amuse
struct EffectIntrospection { class EffectListing;
struct Field {
enum class Type { Invalid, UInt32, UInt32x8, Float }; struct EffectIntrospection;
Type m_tp;
std::string_view m_name;
float m_min, m_max, m_default;
};
amuse::EffectType m_tp;
std::string_view m_name;
std::string_view m_description;
Field m_fields[7];
};
class Uint32X8Popup : public QFrame { class Uint32X8Popup : public QFrame {
Q_OBJECT Q_OBJECT
FieldSlider* m_sliders[8];
public: public:
static constexpr int NumSliders = 8;
explicit Uint32X8Popup(int min, int max, QWidget* parent = Q_NULLPTR); explicit Uint32X8Popup(int min, int max, QWidget* parent = Q_NULLPTR);
~Uint32X8Popup() override; ~Uint32X8Popup() override;
@ -54,6 +44,9 @@ private slots:
signals: signals:
void valueChanged(int chanIdx, int val); void valueChanged(int chanIdx, int val);
private:
std::array<FieldSlider*, NumSliders> m_sliders;
}; };
class Uint32X8Button : public QPushButton { class Uint32X8Button : public QPushButton {
@ -187,7 +180,7 @@ class StudioSetupWidget : public QWidget {
friend class EffectCatalogue; friend class EffectCatalogue;
QSplitter* m_splitter; QSplitter* m_splitter;
QTabWidget* m_tabs; QTabWidget* m_tabs;
EffectListing* m_listing[2]; std::array<EffectListing*, 2> m_listing{};
EffectCatalogue* m_catalogue; EffectCatalogue* m_catalogue;
EffectWidget* m_draggedCmd = nullptr; EffectWidget* m_draggedCmd = nullptr;
EffectCatalogueItem* m_draggedItem = nullptr; EffectCatalogueItem* m_draggedItem = nullptr;