From c79e8b0b6a0df20586b2c4913a43982c1bf3b753 Mon Sep 17 00:00:00 2001 From: akimaze Date: Sat, 4 Jul 2020 12:26:02 +0200 Subject: [PATCH] Changes from PR #4571. --- plugins/carlabase/carla.cpp | 489 +++++++++++++++++++++++++++++++++--- plugins/carlabase/carla.h | 115 ++++++++- 2 files changed, 571 insertions(+), 33 deletions(-) diff --git a/plugins/carlabase/carla.cpp b/plugins/carlabase/carla.cpp index a6faa4d275d..5fb1049aae6 100644 --- a/plugins/carlabase/carla.cpp +++ b/plugins/carlabase/carla.cpp @@ -25,16 +25,25 @@ #include "carla.h" #include "Engine.h" -#include "Song.h" -#include "gui_templates.h" +#include "GuiApplication.h" #include "InstrumentPlayHandle.h" #include "InstrumentTrack.h" +#include "MainWindow.h" #include "Mixer.h" +#include "Song.h" +#include "gui_templates.h" #include #include #include +#include +#include +#include #include +#include +#include +#include +#include #include #include @@ -134,7 +143,8 @@ CarlaInstrument::CarlaInstrument(InstrumentTrack* const instrumentTrack, const D kIsPatchbay(isPatchbay), fHandle(NULL), fDescriptor(isPatchbay ? carla_get_native_patchbay_plugin() : carla_get_native_rack_plugin()), - fMidiEventCount(0) + fMidiEventCount(0), + m_subWindow(NULL) { fHost.handle = this; fHost.uiName = NULL; @@ -182,6 +192,12 @@ CarlaInstrument::CarlaInstrument(InstrumentTrack* const instrumentTrack, const D InstrumentPlayHandle * iph = new InstrumentPlayHandle( this, instrumentTrack ); Engine::mixer()->addPlayHandle( iph ); + // text filter completion + m_completerModel = new QStringListModel(this); + m_paramsCompleter = new QCompleter(m_completerModel, this); + m_paramsCompleter->setCaseSensitivity(Qt::CaseInsensitive); + m_paramsCompleter->setCompletionMode(QCompleter::PopupCompletion); + connect(Engine::mixer(), SIGNAL(sampleRateChanged()), this, SLOT(sampleRateChanged())); } @@ -211,6 +227,15 @@ CarlaInstrument::~CarlaInstrument() fDescriptor->cleanup(fHandle); fHandle = NULL; + + if (p_subWindow != NULL) { + delete p_subWindow; + p_subWindow = NULL; + } + + if (m_paramModels.isEmpty() == false) { + m_paramModels.clear(); + } } // ------------------------------------------------------------------- @@ -286,14 +311,101 @@ void CarlaInstrument::saveSettings(QDomDocument& doc, QDomElement& parent) return; QDomDocument carlaDoc("carla"); - if (carlaDoc.setContent(QString(state))) { QDomNode n = doc.importNode(carlaDoc.documentElement(), true); parent.appendChild(n); } - std::free(state); + + for (uint32_t i=0; i < m_paramModels.count(); ++i) + { + QString idStr = CARLA_SETTING_PREFIX + QString::number(i); + m_paramModels[i]->saveSettings(doc, parent, idStr); + } +} + +void CarlaInstrument::refreshParams(bool valuesOnly = false, bool init = false) +{ + if (fDescriptor->get_parameter_count != nullptr && + fDescriptor->get_parameter_info != nullptr && + fDescriptor->get_parameter_value != nullptr && + fDescriptor->set_parameter_value != nullptr) + { + uint32_t param_count = fDescriptor->get_parameter_count(fHandle); + + if (!param_count) { + clearKnobModels(); + return; + } + + if (!valuesOnly) + { + clearKnobModels(); + m_paramModels.reserve(param_count); + } + else if (m_paramModels.empty()) + { + return; + } + + QList completerData; + + for (uint32_t i=0; i < param_count; ++i) + { + // https://github.com/falkTX/Carla/tree/master/source/native-plugins source/native-plugins/resources/carla-plugin + float param_value = fDescriptor->get_parameter_value(fHandle, i); + + if (valuesOnly) + { + m_paramModels[i]->setValue(param_value); + continue; + } + + const NativeParameter* paramInfo(fDescriptor->get_parameter_info(fHandle, i)); + + // Get parameter name + QString name = "_NO_NAME_"; + if (paramInfo->name != nullptr){ + name = paramInfo->name; + } + + completerData.push_back(name); + + // current_value, min, max, steps + m_paramModels.push_back(new FloatModel(param_value, paramInfo->ranges.min, + paramInfo->ranges.max, paramInfo->ranges.step, this, name)); + + // Load settings into model. + if (init) + { + QString idStr = CARLA_SETTING_PREFIX + QString::number(i); + m_paramModels[i]->loadSettings(m_settingsElem, idStr); + } + + connect(m_paramModels[i], &FloatModel::dataChanged, this, [=]() {knobModelChanged(i);}, Qt::DirectConnection); + } + // Set completer data + m_completerModel->setStringList(completerData); + } +} + +void CarlaInstrument::clearKnobModels(){ + //Delete the models, this also disconnects all connections (automation and controller connections) + for (uint32_t i=0; i < m_paramModels.count(); ++i) + { + delete m_paramModels[i]; + } + + //Clear the list + m_paramModels.clear(); +} + +void CarlaInstrument::knobModelChanged(uint32_t index) +{ + if (fDescriptor->set_parameter_value != nullptr){ + fDescriptor->set_parameter_value(fHandle, index, m_paramModels[index]->value()); + } } void CarlaInstrument::loadSettings(const QDomElement& elem) @@ -305,6 +417,10 @@ void CarlaInstrument::loadSettings(const QDomElement& elem) carlaDoc.appendChild(carlaDoc.importNode(elem.firstChildElement(), true )); fDescriptor->set_state(fHandle, carlaDoc.toString(0).toUtf8().constData()); + + // Store to load parameter knobs settings when added. + m_settingsElem = const_cast(elem); + refreshParams(false, true); } void CarlaInstrument::play(sampleFrame* workingBuffer) @@ -324,23 +440,17 @@ void CarlaInstrument::play(sampleFrame* workingBuffer) fTimeInfo.playing = s->isPlaying(); fTimeInfo.frame = s->getPlayPos(s->playMode()).frames(Engine::framesPerTick()); fTimeInfo.usecs = s->getMilliseconds()*1000; - fTimeInfo.bbt.bar = s->getBars() + 1; + fTimeInfo.bbt.bar = s->getTacts() + 1; fTimeInfo.bbt.beat = s->getBeat() + 1; fTimeInfo.bbt.tick = s->getBeatTicks(); - fTimeInfo.bbt.barStartTick = ticksPerBeat*s->getTimeSigModel().getNumerator()*s->getBars(); + fTimeInfo.bbt.barStartTick = ticksPerBeat*s->getTimeSigModel().getNumerator()*s->getTacts(); fTimeInfo.bbt.beatsPerBar = s->getTimeSigModel().getNumerator(); fTimeInfo.bbt.beatType = s->getTimeSigModel().getDenominator(); fTimeInfo.bbt.ticksPerBeat = ticksPerBeat; fTimeInfo.bbt.beatsPerMinute = s->getTempo(); -#ifndef _MSC_VER float buf1[bufsize]; float buf2[bufsize]; -#else - float *buf1 = static_cast(_alloca(bufsize * sizeof(float))); - float *buf2 = static_cast(_alloca(bufsize * sizeof(float))); -#endif - float* rBuf[] = { buf1, buf2 }; std::memset(buf1, 0, sizeof(float)*bufsize); std::memset(buf2, 0, sizeof(float)*bufsize); @@ -444,8 +554,7 @@ PluginView* CarlaInstrument::instantiateView(QWidget* parent) // Disable plugin focus per https://bugreports.qt.io/browse/QTBUG-30181 #ifndef CARLA_OS_MAC if (QWidget* const window = parent->window()) - // TODO: Remove cast; Only needed for Qt4 - fHost.uiParentId = (uintptr_t)window->winId(); + fHost.uiParentId = window->winId(); else #endif fHost.uiParentId = 0; @@ -467,10 +576,12 @@ void CarlaInstrument::sampleRateChanged() // ------------------------------------------------------------------- CarlaInstrumentView::CarlaInstrumentView(CarlaInstrument* const instrument, QWidget* const parent) - : InstrumentViewFixedSize(instrument, parent), + : InstrumentView(instrument, parent), fHandle(instrument->fHandle), fDescriptor(instrument->fDescriptor), - fTimerId(fHandle != NULL && fDescriptor->ui_idle != NULL ? startTimer(30) : 0) + fTimerId(fHandle != NULL && fDescriptor->ui_idle != NULL ? startTimer(30) : 0), + m_carlaInstrument(instrument), + p_parent(parent) { setAutoFillBackground(true); @@ -478,20 +589,34 @@ CarlaInstrumentView::CarlaInstrumentView(CarlaInstrument* const instrument, QWid pal.setBrush(backgroundRole(), instrument->kIsPatchbay ? PLUGIN_NAME::getIconPixmap("artwork-patchbay") : PLUGIN_NAME::getIconPixmap("artwork-rack")); setPalette(pal); - QVBoxLayout * l = new QVBoxLayout( this ); - l->setContentsMargins( 20, 180, 10, 10 ); - l->setSpacing( 10 ); + QHBoxLayout * l = new QHBoxLayout(this); + l->setContentsMargins(20, 180, 10, 10); + l->setSpacing(3); + l->setAlignment(Qt::AlignTop); + + // Show GUI button + m_toggleUIButton = new QPushButton(tr("Show GUI"), this); + m_toggleUIButton->setCheckable(true); + m_toggleUIButton->setChecked(false); + m_toggleUIButton->setIcon(embed::getIconPixmap("zoom")); + m_toggleUIButton->setFont(pointSize<8>(m_toggleUIButton->font())); - m_toggleUIButton = new QPushButton( tr( "Show GUI" ), this ); - m_toggleUIButton->setCheckable( true ); - m_toggleUIButton->setChecked( false ); - m_toggleUIButton->setIcon( embed::getIconPixmap( "zoom" ) ); - m_toggleUIButton->setFont( pointSize<8>( m_toggleUIButton->font() ) ); - connect( m_toggleUIButton, SIGNAL( clicked(bool) ), this, SLOT( toggleUI( bool ) ) ); + m_toggleUIButton->setToolTip( + tr("Click here to show or hide the graphical user interface (GUI) of Carla.")); - l->addWidget( m_toggleUIButton ); - l->addStretch(); + // Open params sub window button + m_toggleParamsWindowButton = new QPushButton(tr("Params"), this); + m_toggleParamsWindowButton->setIcon(embed::getIconPixmap("controller")); + m_toggleParamsWindowButton->setCheckable(true); + m_toggleParamsWindowButton->setFont(pointSize<8>(m_toggleParamsWindowButton->font())); + // Add widgets to layout + l->addWidget(m_toggleUIButton); + l->addWidget(m_toggleParamsWindowButton); + + // Connect signals + connect(m_toggleUIButton, SIGNAL(clicked(bool)), this, SLOT(toggleUI(bool))); + connect(m_toggleParamsWindowButton, SIGNAL(clicked(bool)), this, SLOT(toggleParamsWindow())); connect(instrument, SIGNAL(uiClosed()), this, SLOT(uiClosed())); } @@ -524,5 +649,313 @@ void CarlaInstrumentView::timerEvent(QTimerEvent* event) InstrumentView::timerEvent(event); } +void CarlaInstrumentView::toggleParamsWindow() +{ + if (m_carlaInstrument->m_subWindow == NULL) + { + m_carlaInstrument->p_subWindow = new CarlaParamsView(m_carlaInstrument, p_parent); + connect(m_carlaInstrument->m_subWindow, SIGNAL(uiClosed()), this, SLOT(paramsUiClosed())); + } else { + if (m_carlaInstrument->m_subWindow->isVisible()) { + m_carlaInstrument->m_subWindow->hide(); + } else { + m_carlaInstrument->m_subWindow->show(); + } + } +} + +void CarlaInstrumentView::paramsUiClosed() +{ + m_toggleParamsWindowButton->setChecked(false); +} + // ------------------------------------------------------------------- +CarlaParamsView::CarlaParamsView(CarlaInstrument* const instrument, QWidget* const parent) + : InstrumentView(instrument, parent), + m_carlaInstrument(instrument), + m_maxColumns(6), + m_curColumn(0), + m_curRow(0) +{ + // Create central widget + /* ___ centralWidget _______________ QWidget + * | __ verticalLayout _____________ QVBoxLayout + * | | __ m_toolBarLayout __________ QHBoxLayout + * | | | + * | | | option_0 | option_1 .. + * | | |_____________________________ + * | | + * | | __ m_scrollArea _____________ QScrollArea + * | | | __ m_scrollAreaWidgetContent QWidget + * | | | | __ m_scrollAreaLayout ___ QGridLayout + * | | | | | + * | | | | | knob | knob | knob + * | | | | | knob | knob | knob + * | | | | | knob | knob | knob + * | | | | |_________________________ + * | | | |___________________________ + * | | |_____________________________ + * */ + QWidget* centralWidget = new QWidget(this); + QVBoxLayout* verticalLayout = new QVBoxLayout(centralWidget); + + + // Toolbar + m_toolBarLayout = new QHBoxLayout(); + + // Toolbar widgets + // Refresh params button + m_refreshParamsButton = new QPushButton(tr(""), this); + m_refreshParamsButton->setIcon(embed::getIconPixmap("reload")); + m_refreshParamsButton->setToolTip( + tr("Click here to reload the Carla parameter knobs.")); + QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(m_refreshParamsButton->sizePolicy().hasHeightForWidth()); + m_refreshParamsButton->setSizePolicy(sizePolicy); + m_refreshParamsButton->setCheckable(false); + + // Refresh param values button + m_refreshParamValuesButton = new QPushButton(tr("Values"), this); + m_refreshParamValuesButton->setIcon(embed::getIconPixmap("reload")); + m_refreshParamValuesButton->setToolTip( + tr("Click here to update the Carla parameter knob " + "values as they are in the remote Carla instance.")); + sizePolicy.setHeightForWidth(m_refreshParamValuesButton->sizePolicy().hasHeightForWidth()); + m_refreshParamValuesButton->setSizePolicy(sizePolicy); + + // Params filter line edit + m_paramsFilterLineEdit = new QLineEdit(this); + m_paramsFilterLineEdit->setPlaceholderText(tr("Search..")); + m_paramsFilterLineEdit->setCompleter(m_carlaInstrument->m_paramsCompleter); + + // Clear filter line edit button + m_clearFilterButton = new QPushButton(tr(""), this); + m_clearFilterButton->setIcon(embed::getIconPixmap("edit_erase")); + m_clearFilterButton->setToolTip(tr("Clear filter text")); + sizePolicy.setHeightForWidth(m_clearFilterButton->sizePolicy().hasHeightForWidth()); + m_clearFilterButton->setSizePolicy(sizePolicy); + + // Show automated only button + m_automatedOnlyButton = new QPushButton(tr(""), this); + m_automatedOnlyButton->setIcon(embed::getIconPixmap("automation")); + m_automatedOnlyButton->setToolTip( + tr("Only show knobs with a connection.")); + m_automatedOnlyButton->setCheckable(true); + sizePolicy.setHeightForWidth(m_automatedOnlyButton->sizePolicy().hasHeightForWidth()); + m_automatedOnlyButton->setSizePolicy(sizePolicy); + + // Add stuff to toolbar + m_toolBarLayout->addWidget(m_refreshParamsButton); + m_toolBarLayout->addWidget(m_refreshParamValuesButton); + m_toolBarLayout->addWidget(m_paramsFilterLineEdit); + m_toolBarLayout->addWidget(m_clearFilterButton); + m_toolBarLayout->addWidget(m_automatedOnlyButton); + + + // Create scroll area for the knobs + m_scrollArea = new QScrollArea(this); + m_scrollAreaWidgetContent = new QWidget(); + m_scrollAreaLayout = new QGridLayout(m_scrollAreaWidgetContent); + + m_scrollAreaWidgetContent->setLayout(m_scrollAreaLayout); + + m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + m_scrollArea->setWidget(m_scrollAreaWidgetContent); + m_scrollArea->setWidgetResizable(true); + + m_scrollAreaLayout->setContentsMargins(3, 3, 3, 3); + m_scrollAreaLayout->setVerticalSpacing(12); + m_scrollAreaLayout->setHorizontalSpacing(6); + m_scrollAreaLayout->setColumnStretch(m_maxColumns, 1); + + + // Add m_toolBarLayout and m_scrollArea to the verticalLayout. + verticalLayout->addLayout(m_toolBarLayout); + verticalLayout->addWidget(m_scrollArea); + + + // Sub window + CarlaParamsSubWindow* win = new CarlaParamsSubWindow(gui->mainWindow()->workspace()->viewport(), Qt::SubWindow | + Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint); + m_carlaInstrument->m_subWindow = gui->mainWindow()->workspace()->addSubWindow(win); + m_carlaInstrument->m_subWindow->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding); + m_carlaInstrument->m_subWindow->setFixedWidth(800); + m_carlaInstrument->m_subWindow->setMinimumHeight(200); + m_carlaInstrument->m_subWindow->setWidget(centralWidget); + centralWidget->setWindowTitle(m_carlaInstrument->instrumentTrack()->name() + tr(" - Parameters")); + + // Connect signals + connect(m_refreshParamsButton, SIGNAL(clicked(bool)), this, SLOT(onRefreshButton())); + connect(m_refreshParamValuesButton, SIGNAL(clicked(bool)), this, SLOT(onRefreshValuesButton())); + connect(m_paramsFilterLineEdit, SIGNAL(textChanged(const QString)), this, SLOT(filterKnobs())); + connect(m_clearFilterButton, SIGNAL(clicked(bool)), this, SLOT(clearFilterText())); + connect(m_automatedOnlyButton, SIGNAL(toggled(bool)), this, SLOT(filterKnobs())); + + + refreshKnobs(); // Add buttons if there are any already. + m_carlaInstrument->m_subWindow->show(); // Show the subwindow +} + +CarlaParamsView::~CarlaParamsView() +{ + // Close and delete m_subWindow + if (m_carlaInstrument->m_subWindow != NULL ) + { + m_carlaInstrument->m_subWindow->setAttribute(Qt::WA_DeleteOnClose); + m_carlaInstrument->m_subWindow->close(); + + if (m_carlaInstrument->m_subWindow != NULL) + delete m_carlaInstrument->m_subWindow; + m_carlaInstrument->m_subWindow = NULL; + } + + m_carlaInstrument->p_subWindow = NULL; + + // Clear models + if (m_carlaInstrument->m_paramModels.isEmpty() == false) + { + m_carlaInstrument->clearKnobModels(); + } +} + +void CarlaParamsView::clearFilterText() +{ + m_paramsFilterLineEdit->setText(""); +} + +void CarlaParamsView::filterKnobs() +{ + QString text = m_paramsFilterLineEdit->text(); + clearKnobs(); // Remove all knobs from the layout. + + for (uint32_t i=0; i < m_knobs.count(); ++i) + { + // Filter on automation only + if (m_automatedOnlyButton->isChecked()) + { + if (! m_carlaInstrument->m_paramModels[i]->isAutomatedOrControlled()) + { + continue; + } + } + + // Filter on text + if (text != "") + { + if (m_knobs[i]->objectName().contains(text, Qt::CaseInsensitive)) + { + addKnob(i); + } + } else { + addKnob(i); + } + } +} + +void CarlaParamsView::onRefreshButton() +{ + if (m_carlaInstrument->m_paramModels.isEmpty() == false) + { + if (QMessageBox::warning(NULL, + tr("Reload knobs"), + tr("There are already knobs loaded, if any of them " + "are connected to a controller or automation track " + "their connection will be lost. Do you want to " + "continue?"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) != QMessageBox::Yes) + { + return; + } + } + m_carlaInstrument->refreshParams(); + refreshKnobs(); +} + +void CarlaParamsView::onRefreshValuesButton() +{ + m_carlaInstrument->refreshParams(true); +} + +void CarlaParamsView::refreshKnobs() +{ + // Make sure all the knobs are deleted. + for (uint32_t i=0; i < m_knobs.count(); ++i) + { + delete m_knobs[i]; // Delete knob widgets itself. + } + m_knobs.clear(); // Clear the pointer list. + + // Clear the layout (posible spacer). + QLayoutItem *item; + while ((item = m_scrollAreaLayout->takeAt(0))) + { + if (item->widget()) {delete item->widget();} + delete item; + } + + // Reset position data. + m_curColumn = 0; + m_curRow = 0; + + if (!m_carlaInstrument->m_paramModels.count()) { return; } + + // Make room in QList m_knobs + m_knobs.reserve(m_carlaInstrument->m_paramModels.count()); + + for (uint32_t i=0; i < m_carlaInstrument->m_paramModels.count(); ++i) + { + m_knobs.push_back(new Knob(m_scrollAreaWidgetContent)); + QString name = (*m_carlaInstrument->m_paramModels[i]).displayName(); + m_knobs[i]->setHintText(name, ""); + m_knobs[i]->setLabel(name); + m_knobs[i]->setObjectName(name); // this is being used for filtering the knobs. + + // Set the newly created model to the knob. + m_knobs[i]->setModel(m_carlaInstrument->m_paramModels[i]); + + // Add knob to layout + addKnob(i); + } + + // Add spacer so all knobs go to top + QSpacerItem* verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + m_scrollAreaLayout->addItem(verticalSpacer, m_curRow + 1, 0, 1, 1); +} + +void CarlaParamsView::addKnob(uint32_t index) +{ + // Add the new knob to layout + m_scrollAreaLayout->addWidget(m_knobs[index], m_curRow, m_curColumn, Qt::AlignHCenter | Qt::AlignTop); + + // Chances that we did close() on the widget is big, so show it. + m_knobs[index]->show(); + + // Keep track of current column and row index. + if (m_curColumn < m_maxColumns - 1) + { + m_curColumn++; + } else { + m_curColumn = 0; + m_curRow++; + } +} +void CarlaParamsView::clearKnobs() +{ + // Remove knobs from layout. + for (uint32_t i=0; i < m_knobs.count(); ++i) + { + m_knobs[i]->close(); + } + + // Reset position data. + m_curColumn = 0; + m_curRow = 0; +} + +void CarlaParamsView::modelChanged() +{ + refreshKnobs(); +} diff --git a/plugins/carlabase/carla.h b/plugins/carlabase/carla.h index 2c683add935..770239d7c71 100644 --- a/plugins/carlabase/carla.h +++ b/plugins/carlabase/carla.h @@ -25,10 +25,21 @@ #ifndef CARLA_H #define CARLA_H +#define CARLA_MAX_KNOBS 32 +#define CARLA_SETTING_PREFIX "PARAM_KNOB_" + +// qt +#include +#include +#include +#include +#include +#include +#include #include -#include "carlabase_export.h" -#include "CarlaNative.h" +// carla/source/includes +#define REAL_BUILD // FIXME this shouldn't be needed #if CARLA_VERSION_HEX >= 0x010911 #include "CarlaNativePlugin.h" #else @@ -42,12 +53,41 @@ const NativePluginDescriptor* carla_get_native_rack_plugin(); #endif +// lmms/include/ +#include "EffectControls.h" #include "Instrument.h" #include "InstrumentView.h" +#include "Knob.h" +#include "SubWindow.h" +#include "plugin_export.h" class QPushButton; -class CARLABASE_EXPORT CarlaInstrument : public Instrument +class CarlaParamsSubWindow : public SubWindow +{ + Q_OBJECT + +signals: + void uiClosed(); + +public: + CarlaParamsSubWindow(QWidget * _parent, Qt::WindowFlags windowFlags) : + SubWindow(_parent) + { + setAttribute(Qt::WA_DeleteOnClose, false); + setWindowFlags(windowFlags); + } + + virtual void closeEvent(QCloseEvent * event) override + { + emit uiClosed(); + event->accept(); + } +}; + +// ------------------------------------------------------------------- + +class PLUGIN_EXPORT CarlaInstrument : public Instrument { Q_OBJECT @@ -80,6 +120,9 @@ class CARLABASE_EXPORT CarlaInstrument : public Instrument private slots: void sampleRateChanged(); + void refreshParams(bool valuesOnly, bool init); + void clearKnobModels(); + void knobModelChanged(uint32_t index); private: const bool kIsPatchbay; @@ -95,10 +138,22 @@ private slots: // this is only needed because note-offs are being sent during play QMutex fMutex; + QList m_paramModels; + QDomElement m_settingsElem; + QMdiSubWindow* m_subWindow; + QObject* p_subWindow; + + QCompleter* m_paramsCompleter; + QStringListModel* m_completerModel; + friend class CarlaInstrumentView; + friend class CarlaParamsView; }; -class CarlaInstrumentView : public InstrumentViewFixedSize + +// ------------------------------------------------------------------- + +class CarlaInstrumentView : public InstrumentView { Q_OBJECT @@ -109,6 +164,8 @@ class CarlaInstrumentView : public InstrumentViewFixedSize private slots: void toggleUI(bool); void uiClosed(); + void toggleParamsWindow(); + void paramsUiClosed(); private: virtual void modelChanged(); @@ -118,7 +175,55 @@ private slots: const NativePluginDescriptor* fDescriptor; int fTimerId; - QPushButton * m_toggleUIButton; + CarlaInstrument* const m_carlaInstrument; + QWidget* const p_parent; + + QPushButton* m_toggleUIButton; + QPushButton* m_toggleParamsWindowButton; +}; + +// ------------------------------------------------------------------- + +class CarlaParamsView : public InstrumentView +{ + Q_OBJECT +public: + CarlaParamsView(CarlaInstrument* const instrument, QWidget* const parent); + virtual ~CarlaParamsView(); + +signals: + void uiClosed(); + +private slots: + void onRefreshButton(); + void onRefreshValuesButton(); + void refreshKnobs(); + void filterKnobs(); + void clearFilterText(); + +private: + virtual void modelChanged(); + + void addKnob(uint32_t index); + void clearKnobs(); + + CarlaInstrument* const m_carlaInstrument; + QList m_knobs; + + const uint32_t m_maxColumns; + uint32_t m_curColumn; + uint32_t m_curRow; + + QScrollArea* m_scrollArea; + QGridLayout* m_scrollAreaLayout; + QWidget* m_scrollAreaWidgetContent; + QHBoxLayout* m_toolBarLayout; + + QPushButton* m_refreshParamsButton; + QPushButton* m_refreshParamValuesButton; + QLineEdit* m_paramsFilterLineEdit; + QPushButton* m_clearFilterButton; + QPushButton* m_automatedOnlyButton; }; #endif