From 3e8120d532821e351e7a6e8298644007273d7baa Mon Sep 17 00:00:00 2001 From: Hyunin Song Date: Mon, 28 May 2018 13:47:53 +0900 Subject: [PATCH 01/20] Make "Clear this track" undoable Fixes #4375 --- src/core/Track.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 8af5393dc..fa500da33 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1813,6 +1813,7 @@ void TrackOperationsWidget::cloneTrack() void TrackOperationsWidget::clearTrack() { Track * t = m_trackView->getTrack(); + t->addJournalCheckPoint(); t->lock(); t->deleteTCOs(); t->unlock(); From a2cb7e96ea057de604003ecdc70745a80e4b40e0 Mon Sep 17 00:00:00 2001 From: Lukas W Date: Sat, 10 Feb 2018 13:24:59 +0100 Subject: [PATCH 02/20] Fix VST sub-window creation glitches in project loading Fixes bugs where during project loading (observed with VST effects), empty widgets and sub-windows would be left floating around. These were caused by inconsistencies between the way VST UIs were created when loading a project and when adding an effect in an existing project. In some situations, this caused createUI to be called twice, leaving over multiple empty widgets. This commit refactors some code in order to avoid creating unnecessary sub- windows, which aren't needed with VST effects, but were still created, usually being invisible. All sub-window related code was moved out of VstPlugin into vestige.cpp, which is the only place where sub-window VSTs are actually used. A new sub-class of VstPlugin, VstInstrumentPlugin, now handles VST sub-windows and is used by vestigeInstrument. "guivisible" attribute loading was moved out of VstPlugin as well and is now done in VstEffectControls' and vestigeInstrument's loadSettings method respectively. This causes some minor code duplication unfortunately. Closes #4110 --- plugins/VstEffect/VstEffectControlDialog.cpp | 26 ++-- plugins/VstEffect/VstEffectControlDialog.h | 3 +- plugins/VstEffect/VstEffectControls.cpp | 14 +- plugins/VstEffect/VstEffectControls.h | 6 +- plugins/vestige/vestige.cpp | 62 ++++++++- plugins/vst_base/VstPlugin.cpp | 136 +++++-------------- plugins/vst_base/VstPlugin.h | 15 +- 7 files changed, 136 insertions(+), 126 deletions(-) diff --git a/plugins/VstEffect/VstEffectControlDialog.cpp b/plugins/VstEffect/VstEffectControlDialog.cpp index 34ad097c9..ad2666392 100644 --- a/plugins/VstEffect/VstEffectControlDialog.cpp +++ b/plugins/VstEffect/VstEffectControlDialog.cpp @@ -45,6 +45,7 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) : EffectControlDialog( _ctl ), m_pluginWidget( NULL ), + m_plugin( NULL ), tbLabel( NULL ) { @@ -62,16 +63,10 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) : embed_vst = m_plugin->embedMethod() != "none"; if (embed_vst) { - m_plugin->createUI( nullptr, true ); - m_pluginWidget = m_plugin->pluginWidget( false ); - -#ifdef LMMS_BUILD_WIN32 - if( !m_pluginWidget ) - { - m_pluginWidget = m_plugin->pluginWidget( false ); + if (! m_plugin->pluginWidget()) { + m_plugin->createUI(nullptr); } -#endif - + m_pluginWidget = m_plugin->pluginWidget(); } } @@ -79,7 +74,7 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) : { setWindowTitle( m_plugin->name() ); - QPushButton * btn = new QPushButton( tr( "Show/hide" ) ); + QPushButton * btn = new QPushButton( tr( "Show/hide" )); if (embed_vst) { btn->setCheckable( true ); @@ -95,6 +90,7 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) : btn->setMaximumWidth( 78 ); btn->setMinimumHeight( 24 ); btn->setMaximumHeight( 24 ); + m_togglePluginButton = btn; m_managePluginButton = new PixmapButton( this, "" ); m_managePluginButton->setCheckable( false ); @@ -295,6 +291,14 @@ void VstEffectControlDialog::togglePluginUI( bool checked ) return; } - m_plugin->toggleUI(); + if ( m_togglePluginButton->isChecked() != checked ) { + m_togglePluginButton->setChecked( checked ); + } + + if ( checked ) { + m_plugin->showUI(); + } else { + m_plugin->hideUI(); + } } diff --git a/plugins/VstEffect/VstEffectControlDialog.h b/plugins/VstEffect/VstEffectControlDialog.h index ddbbef878..e20915019 100644 --- a/plugins/VstEffect/VstEffectControlDialog.h +++ b/plugins/VstEffect/VstEffectControlDialog.h @@ -54,6 +54,7 @@ protected: private: QWidget * m_pluginWidget; + QPushButton * m_togglePluginButton; PixmapButton * m_openPresetButton; PixmapButton * m_rolLPresetButton; PixmapButton * m_rolRPresetButton; @@ -64,7 +65,7 @@ private: QLabel * tbLabel; -private slots: +public slots: void togglePluginUI( bool checked ); } ; diff --git a/plugins/VstEffect/VstEffectControls.cpp b/plugins/VstEffect/VstEffectControls.cpp index 92688545b..ef5a59463 100644 --- a/plugins/VstEffect/VstEffectControls.cpp +++ b/plugins/VstEffect/VstEffectControls.cpp @@ -40,7 +40,8 @@ VstEffectControls::VstEffectControls( VstEffect * _eff ) : m_subWindow( NULL ), knobFModel( NULL ), ctrHandle( NULL ), - lastPosInMenu (0) + lastPosInMenu (0), + m_vstGuiVisible ( true ) // m_presetLabel ( NULL ) { } @@ -64,6 +65,8 @@ void VstEffectControls::loadSettings( const QDomElement & _this ) m_effect->m_pluginMutex.lock(); if( m_effect->m_plugin != NULL ) { + m_vstGuiVisible = _this.attribute( "guivisible" ).toInt(); + m_effect->m_plugin->loadSettings( _this ); const QMap & dump = m_effect->m_plugin->parameterDump(); @@ -144,6 +147,15 @@ int VstEffectControls::controlCount() +EffectControlDialog *VstEffectControls::createView() +{ + auto dialog = new VstEffectControlDialog( this ); + dialog->togglePluginUI( m_vstGuiVisible ); + return dialog; +} + + + void VstEffectControls::managePlugin( void ) { diff --git a/plugins/VstEffect/VstEffectControls.h b/plugins/VstEffect/VstEffectControls.h index 7328f2f42..e4f099fd1 100644 --- a/plugins/VstEffect/VstEffectControls.h +++ b/plugins/VstEffect/VstEffectControls.h @@ -59,10 +59,7 @@ public: virtual int controlCount(); - virtual EffectControlDialog * createView() - { - return new VstEffectControlDialog( this ); - } + virtual EffectControlDialog * createView(); protected slots: @@ -96,6 +93,7 @@ private: friend class VstEffectControlDialog; friend class manageVSTEffectView; + bool m_vstGuiVisible; } ; diff --git a/plugins/vestige/vestige.cpp b/plugins/vestige/vestige.cpp index db9cf5bba..c54c6c3a8 100644 --- a/plugins/vestige/vestige.cpp +++ b/plugins/vestige/vestige.cpp @@ -24,6 +24,8 @@ #include "vestige.h" +#include + #include #include #include @@ -73,6 +75,57 @@ Plugin::Descriptor PLUGIN_EXPORT vestige_plugin_descriptor = } +class vstSubWin : public QMdiSubWindow +{ +public: + vstSubWin( QWidget * _parent ) : + QMdiSubWindow( _parent ) + { + setAttribute( Qt::WA_DeleteOnClose, false ); + setWindowFlags( Qt::WindowCloseButtonHint ); + } + + virtual ~vstSubWin() + { + } + + virtual void closeEvent( QCloseEvent * e ) + { + // ignore close-events - for some reason otherwise the VST GUI + // remains hidden when re-opening + hide(); + e->ignore(); + } +}; + + +class VstInstrumentPlugin : public VstPlugin +{ +public: + using VstPlugin::VstPlugin; + + void createUI( QWidget *parent ) override + { + Q_UNUSED(parent); + VstPlugin::createUI( nullptr ); + if ( embedMethod() != "none" ) { + m_pluginSubWindow.reset(new vstSubWin( gui->mainWindow()->workspace() )); + m_pluginSubWindow->setWidget(pluginWidget()); + } + } + + /// Overwrite editor() to return the sub window instead of the embed widget + /// itself. This makes toggleUI() and related functions toggle the + /// sub window's visibility. + QWidget* editor() override + { + return m_pluginSubWindow.get(); + } +private: + unique_ptr m_pluginSubWindow; +}; + + QPixmap * VestigeInstrumentView::s_artwork = NULL; QPixmap * manageVestigeInstrumentView::s_artwork = NULL; @@ -127,6 +180,12 @@ void vestigeInstrument::loadSettings( const QDomElement & _this ) { m_plugin->loadSettings( _this ); + if ( _this.attribute( "guivisible" ).toInt() ) { + m_plugin->showUI(); + } else { + m_plugin->hideUI(); + } + const QMap & dump = m_plugin->parameterDump(); paramCount = dump.size(); char paramStr[35]; @@ -267,7 +326,7 @@ void vestigeInstrument::loadFile( const QString & _file ) } m_pluginMutex.lock(); - m_plugin = new VstPlugin( m_pluginDLL ); + m_plugin = new VstInstrumentPlugin( m_pluginDLL ); if( m_plugin->failed() ) { m_pluginMutex.unlock(); @@ -278,6 +337,7 @@ void vestigeInstrument::loadFile( const QString & _file ) return; } + m_plugin->createUI(nullptr); m_plugin->showUI(); if( set_ch_name ) diff --git a/plugins/vst_base/VstPlugin.cpp b/plugins/vst_base/VstPlugin.cpp index 5c7504dd1..32230cd8d 100644 --- a/plugins/vst_base/VstPlugin.cpp +++ b/plugins/vst_base/VstPlugin.cpp @@ -62,28 +62,6 @@ #include "templates.h" #include "FileDialog.h" -class vstSubWin : public QMdiSubWindow -{ -public: - vstSubWin( QWidget * _parent ) : - QMdiSubWindow( _parent ) - { - setAttribute( Qt::WA_DeleteOnClose, false ); - } - - virtual ~vstSubWin() - { - } - - virtual void closeEvent( QCloseEvent * e ) - { - // ignore close-events - for some reason otherwise the VST GUI - // remains hidden when re-opening - hide(); - e->ignore(); - } -} ; - VstPlugin::VstPlugin( const QString & _plugin ) : m_plugin( _plugin ), @@ -124,7 +102,6 @@ VstPlugin::VstPlugin( const QString & _plugin ) : VstPlugin::~VstPlugin() { - delete m_pluginSubWindow; delete m_pluginWidget; } @@ -174,41 +151,8 @@ void VstPlugin::tryLoad( const QString &remoteVstPluginExecutable ) -void VstPlugin::hideEditor() -{ - QWidget * w = pluginWidget(); - if( w ) - { - w->hide(); - } -} - - - - -void VstPlugin::toggleEditor() -{ - QWidget * w = pluginWidget(); - if( w ) - { - w->setVisible( !w->isVisible() ); - } -} - - - - void VstPlugin::loadSettings( const QDomElement & _this ) { - if( _this.attribute( "guivisible" ).toInt() ) - { - showUI(); - } - else - { - hideUI(); - } - const int num_params = _this.attribute( "numparams" ).toInt(); // if it exists try to load settings chunk if( _this.hasAttribute( "chunk" ) ) @@ -286,7 +230,7 @@ void VstPlugin::toggleUI() } else if (pluginWidget()) { - toggleEditor(); + toggleEditorVisibility(); } } @@ -362,21 +306,9 @@ void VstPlugin::setParameterDump( const QMap & _pdump ) unlock(); } -QWidget *VstPlugin::pluginWidget(bool _top_widget) +QWidget *VstPlugin::pluginWidget() { - if ( m_embedMethod == "none" || !m_pluginWidget ) - { - return nullptr; - } - - if ( _top_widget && m_pluginWidget->parentWidget() == m_pluginSubWindow ) - { - return m_pluginSubWindow; - } - else - { - return m_pluginWidget; - } + return m_pluginWidget; } @@ -458,6 +390,10 @@ bool VstPlugin::processMessage( const message & _m ) } +QWidget *VstPlugin::editor() +{ + return m_pluginWidget; +} void VstPlugin::openPreset( ) @@ -579,15 +515,10 @@ void VstPlugin::showUI() } else if ( m_embedMethod != "headless" ) { - if (! pluginWidget()) { - createUI( NULL, false ); - } - - QWidget * w = pluginWidget(); - if( w ) - { - w->show(); + if (! editor()) { + qWarning() << "VstPlugin::showUI called before VstPlugin::createUI"; } + toggleEditorVisibility( true ); } } @@ -599,7 +530,7 @@ void VstPlugin::hideUI() } else if ( pluginWidget() != nullptr ) { - hideEditor(); + toggleEditorVisibility( false ); } } @@ -654,22 +585,39 @@ QByteArray VstPlugin::saveChunk() return a; } -void VstPlugin::createUI( QWidget * parent, bool isEffect ) +void VstPlugin::toggleEditorVisibility( int visible ) { + QWidget* w = editor(); + if ( ! w ) { + return; + } + + if ( visible < 0 ) { + visible = ! w->isVisible(); + } + w->setVisible( visible ); +} + +void VstPlugin::createUI( QWidget * parent ) +{ + if ( m_pluginWidget ) { + qWarning() << "VstPlugin::createUI called twice"; + m_pluginWidget->setParent( parent ); + return; + } + if( m_pluginWindowID == 0 ) { return; } QWidget* container = nullptr; - m_pluginSubWindow = new vstSubWin( gui->mainWindow()->workspace() ); - auto sw = m_pluginSubWindow.data(); #if QT_VERSION >= 0x050100 if (m_embedMethod == "qt" ) { QWindow* vw = QWindow::fromWinId(m_pluginWindowID); - container = QWidget::createWindowContainer(vw, sw ); + container = QWidget::createWindowContainer(vw, parent ); container->installEventFilter(this); } else #endif @@ -708,7 +656,7 @@ void VstPlugin::createUI( QWidget * parent, bool isEffect ) #ifdef LMMS_BUILD_LINUX if (m_embedMethod == "xembed" ) { - QX11EmbedContainer * embedContainer = new QX11EmbedContainer( sw ); + QX11EmbedContainer * embedContainer = new QX11EmbedContainer( parent ); connect(embedContainer, SIGNAL(clientIsEmbedded()), this, SLOT(handleClientEmbed())); embedContainer->embedClient( m_pluginWindowID ); container = embedContainer; @@ -716,29 +664,13 @@ void VstPlugin::createUI( QWidget * parent, bool isEffect ) #endif { qCritical() << "Unknown embed method" << m_embedMethod; - delete m_pluginSubWindow; return; } container->setFixedSize( m_pluginGeometry ); container->setWindowTitle( name() ); - if( parent == NULL ) - { - m_pluginWidget = container; - - sw->setWidget(container); - - if( isEffect ) - { - sw->setAttribute( Qt::WA_TranslucentBackground ); - sw->setWindowFlags( Qt::FramelessWindowHint ); - } - else - { - sw->setWindowFlags( Qt::WindowCloseButtonHint ); - } - }; + m_pluginWidget = container; container->setFixedSize( m_pluginGeometry ); } diff --git a/plugins/vst_base/VstPlugin.h b/plugins/vst_base/VstPlugin.h index f3d6bea8e..9e8b39771 100644 --- a/plugins/vst_base/VstPlugin.h +++ b/plugins/vst_base/VstPlugin.h @@ -54,8 +54,10 @@ public: return m_pluginWindowID != 0; } - void hideEditor(); - void toggleEditor(); + /// Same as pluginWidget(), but can be overwritten in sub-classes to modify + /// behavior the UI. This is used in VstInstrumentPlugin to wrap the VST UI + /// in a QMdiSubWindow + virtual QWidget* editor(); inline const QString & name() const { @@ -93,7 +95,7 @@ public: void setParameterDump( const QMap & _pdump ); - QWidget * pluginWidget( bool _top_widget = true ); + QWidget * pluginWidget(); virtual void loadSettings( const QDomElement & _this ); virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ); @@ -103,9 +105,8 @@ public: return "vstplugin"; } - void toggleUI() override; - void createUI( QWidget *parent, bool isEffect ); + virtual void createUI(QWidget *parent); bool eventFilter(QObject *obj, QEvent *event); QString embedMethod() const; @@ -123,6 +124,7 @@ public slots: void showUI() override; void hideUI() override; + void toggleUI() override; void handleClientEmbed(); @@ -130,9 +132,10 @@ private: void loadChunk( const QByteArray & _chunk ); QByteArray saveChunk(); + void toggleEditorVisibility(int visible = -1); + QString m_plugin; QPointer m_pluginWidget; - QPointer m_pluginSubWindow; int m_pluginWindowID; QSize m_pluginGeometry; const QString m_embedMethod; From 1220374a7f03d91baae50abb665d8bed0f49c43b Mon Sep 17 00:00:00 2001 From: Lukas W Date: Sat, 10 Feb 2018 13:47:40 +0100 Subject: [PATCH 03/20] Fix effect dialog layout glitches QMdiSubWindow::setSizePolicy doesn't have any effect because QMdiSubWindow uses a layout. This patch uses QMdiSubWindow::layout()->setSizeConstraint instead. This may cause effects that don't have a layout and don't implement sizeHint() to now be resizable. For effects that do though, it fixes the size constraint. --- src/gui/widgets/EffectView.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/EffectView.cpp b/src/gui/widgets/EffectView.cpp index 0a5e46b3f..5faae3517 100644 --- a/src/gui/widgets/EffectView.cpp +++ b/src/gui/widgets/EffectView.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "EffectView.h" #include "DummyEffect.h" @@ -109,7 +110,9 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) : { m_subWindow = gui->mainWindow()->addWindowedWidget( m_controlView ); m_subWindow->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); - m_subWindow->setFixedSize( m_subWindow->size() ); + if (m_subWindow->layout()) { + m_subWindow->layout()->setSizeConstraint(QLayout::SetFixedSize); + } Qt::WindowFlags flags = m_subWindow->windowFlags(); flags &= ~Qt::WindowMaximizeButtonHint; From 55da698d7c864397c695583ff9da8c1a76718e8f Mon Sep 17 00:00:00 2001 From: DomClark Date: Sat, 24 Mar 2018 15:04:37 +0000 Subject: [PATCH 04/20] Fix X11 embedding on Qt4 --- plugins/VstEffect/VstEffectControlDialog.cpp | 2 +- plugins/vestige/vestige.cpp | 4 +++- plugins/vst_base/VstPlugin.cpp | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/plugins/VstEffect/VstEffectControlDialog.cpp b/plugins/VstEffect/VstEffectControlDialog.cpp index ad2666392..ea2581349 100644 --- a/plugins/VstEffect/VstEffectControlDialog.cpp +++ b/plugins/VstEffect/VstEffectControlDialog.cpp @@ -64,7 +64,7 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) : if (embed_vst) { if (! m_plugin->pluginWidget()) { - m_plugin->createUI(nullptr); + m_plugin->createUI(this); } m_pluginWidget = m_plugin->pluginWidget(); } diff --git a/plugins/vestige/vestige.cpp b/plugins/vestige/vestige.cpp index c54c6c3a8..9ea053e8e 100644 --- a/plugins/vestige/vestige.cpp +++ b/plugins/vestige/vestige.cpp @@ -107,10 +107,12 @@ public: void createUI( QWidget *parent ) override { Q_UNUSED(parent); - VstPlugin::createUI( nullptr ); if ( embedMethod() != "none" ) { m_pluginSubWindow.reset(new vstSubWin( gui->mainWindow()->workspace() )); + VstPlugin::createUI( m_pluginSubWindow.get() ); m_pluginSubWindow->setWidget(pluginWidget()); + } else { + VstPlugin::createUI( nullptr ); } } diff --git a/plugins/vst_base/VstPlugin.cpp b/plugins/vst_base/VstPlugin.cpp index 32230cd8d..d9d9cc9f7 100644 --- a/plugins/vst_base/VstPlugin.cpp +++ b/plugins/vst_base/VstPlugin.cpp @@ -656,6 +656,10 @@ void VstPlugin::createUI( QWidget * parent ) #ifdef LMMS_BUILD_LINUX if (m_embedMethod == "xembed" ) { + if (parent) + { + parent->setAttribute(Qt::WA_NativeWindow); + } QX11EmbedContainer * embedContainer = new QX11EmbedContainer( parent ); connect(embedContainer, SIGNAL(clientIsEmbedded()), this, SLOT(handleClientEmbed())); embedContainer->embedClient( m_pluginWindowID ); @@ -671,8 +675,6 @@ void VstPlugin::createUI( QWidget * parent ) container->setWindowTitle( name() ); m_pluginWidget = container; - - container->setFixedSize( m_pluginGeometry ); } bool VstPlugin::eventFilter(QObject *obj, QEvent *event) From 49dcd385f5f545210532338c98aa5bac17a13517 Mon Sep 17 00:00:00 2001 From: DomClark Date: Fri, 13 Apr 2018 00:24:41 +0100 Subject: [PATCH 05/20] Fix VST effect load crash on non-primary monitor --- src/gui/SubWindow.cpp | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/gui/SubWindow.cpp b/src/gui/SubWindow.cpp index 284e116d8..0a0effc45 100644 --- a/src/gui/SubWindow.cpp +++ b/src/gui/SubWindow.cpp @@ -113,8 +113,11 @@ void SubWindow::paintEvent( QPaintEvent * ) p.drawLine( width() - 1, m_titleBarHeight, width() - 1, height() - 1 ); // window icon - QPixmap winicon( widget()->windowIcon().pixmap( m_buttonSize ) ); - p.drawPixmap( 3, 3, m_buttonSize.width(), m_buttonSize.height(), winicon ); + if( widget() ) + { + QPixmap winicon( widget()->windowIcon().pixmap( m_buttonSize ) ); + p.drawPixmap( 3, 3, m_buttonSize.width(), m_buttonSize.height(), winicon ); + } } @@ -267,25 +270,31 @@ void SubWindow::adjustTitleBar() // we're keeping the restore button around if we open projects // from older versions that have saved minimized windows m_restoreBtn->setVisible( isMaximized() || isMinimized() ); - - // title QLabel adjustments - m_windowTitle->setAlignment( Qt::AlignHCenter ); - m_windowTitle->setFixedWidth( widget()->width() - ( menuButtonSpace + buttonBarWidth ) ); - m_windowTitle->move( menuButtonSpace, - ( m_titleBarHeight / 2 ) - ( m_windowTitle->sizeHint().height() / 2 ) - 1 ); - - // if minimized we can't use widget()->width(). We have to hard code the width, - // as the width of all minimized windows is the same. if( isMinimized() ) { m_restoreBtn->move( m_maximizeBtn->isHidden() ? middleButtonPos : leftButtonPos ); - m_windowTitle->setFixedWidth( 120 ); } - // truncate the label string if the window is to small. Adds "..." - elideText( m_windowTitle, widget()->windowTitle() ); - m_windowTitle->setTextInteractionFlags( Qt::NoTextInteraction ); - m_windowTitle->adjustSize(); + if( widget() ) + { + // title QLabel adjustments + m_windowTitle->setAlignment( Qt::AlignHCenter ); + m_windowTitle->setFixedWidth( widget()->width() - ( menuButtonSpace + buttonBarWidth ) ); + m_windowTitle->move( menuButtonSpace, + ( m_titleBarHeight / 2 ) - ( m_windowTitle->sizeHint().height() / 2 ) - 1 ); + + // if minimized we can't use widget()->width(). We have to hard code the width, + // as the width of all minimized windows is the same. + if( isMinimized() ) + { + m_windowTitle->setFixedWidth( 120 ); + } + + // truncate the label string if the window is to small. Adds "..." + elideText( m_windowTitle, widget()->windowTitle() ); + m_windowTitle->setTextInteractionFlags( Qt::NoTextInteraction ); + m_windowTitle->adjustSize(); + } } From ee18011dc73cc93504aa461937e81e3fa72c7968 Mon Sep 17 00:00:00 2001 From: DomClark Date: Fri, 13 Apr 2018 00:33:08 +0100 Subject: [PATCH 06/20] Fix toggling UI for non-embedded VST effects --- plugins/VstEffect/VstEffectControlDialog.cpp | 4 ++-- plugins/vst_base/RemoteVstPlugin.cpp | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/plugins/VstEffect/VstEffectControlDialog.cpp b/plugins/VstEffect/VstEffectControlDialog.cpp index ea2581349..ef033ddb1 100644 --- a/plugins/VstEffect/VstEffectControlDialog.cpp +++ b/plugins/VstEffect/VstEffectControlDialog.cpp @@ -82,8 +82,8 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) : connect( btn, SIGNAL( toggled( bool ) ), SLOT( togglePluginUI( bool ) ) ); } else { - connect( btn, SIGNAL( clicked( bool ) ), - SLOT( togglePluginUI( bool ) ) ); + connect( btn, SIGNAL( clicked() ), + m_plugin.data(), SLOT( toggleUI() ) ); } btn->setMinimumWidth( 78 ); diff --git a/plugins/vst_base/RemoteVstPlugin.cpp b/plugins/vst_base/RemoteVstPlugin.cpp index 71ebf74c0..bca09b1a2 100644 --- a/plugins/vst_base/RemoteVstPlugin.cpp +++ b/plugins/vst_base/RemoteVstPlugin.cpp @@ -293,8 +293,8 @@ public: static DWORD WINAPI processingThread( LPVOID _param ); static bool setupMessageWindow(); static DWORD WINAPI guiEventLoop(); - static LRESULT CALLBACK messageWndProc( HWND hwnd, UINT uMsg, - WPARAM wParam, LPARAM lParam ); + static LRESULT CALLBACK wndProc( HWND hwnd, UINT uMsg, + WPARAM wParam, LPARAM lParam ); private: @@ -1884,8 +1884,6 @@ bool RemoteVstPlugin::setupMessageWindow() __MessageHwnd = CreateWindowEx( 0, "LVSL", "dummy", 0, 0, 0, 0, 0, NULL, NULL, hInst, NULL ); - SetWindowLongPtr( __MessageHwnd, GWLP_WNDPROC, - reinterpret_cast( RemoteVstPlugin::messageWndProc ) ); // install GUI update timer SetTimer( __MessageHwnd, 1000, 50, NULL ); @@ -1910,7 +1908,7 @@ DWORD WINAPI RemoteVstPlugin::guiEventLoop() -LRESULT CALLBACK RemoteVstPlugin::messageWndProc( HWND hwnd, UINT uMsg, +LRESULT CALLBACK RemoteVstPlugin::wndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { if( uMsg == WM_TIMER && __plugin->isInitialized() ) @@ -2004,7 +2002,7 @@ int main( int _argc, char * * _argv ) WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; - wc.lpfnWndProc = DefWindowProc; + wc.lpfnWndProc = RemoteVstPlugin::wndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; From fcc883f8873974cdb8f3f09e715912a8ec039139 Mon Sep 17 00:00:00 2001 From: DomClark Date: Fri, 20 Apr 2018 21:57:55 +0100 Subject: [PATCH 07/20] Preserve VST GUI positions and keep them on top --- plugins/vst_base/RemoteVstPlugin.cpp | 41 ++++++++++++++++++++++------ plugins/vst_base/VstPlugin.cpp | 22 ++++++++++++++- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/plugins/vst_base/RemoteVstPlugin.cpp b/plugins/vst_base/RemoteVstPlugin.cpp index bca09b1a2..4e8f34ac8 100644 --- a/plugins/vst_base/RemoteVstPlugin.cpp +++ b/plugins/vst_base/RemoteVstPlugin.cpp @@ -134,6 +134,8 @@ public: void init( const std::string & _plugin_file ); void initEditor(); + void showEditor(); + void hideEditor(); void destroyEditor(); virtual void process( const sampleFrame * _in, sampleFrame * _out ); @@ -507,27 +509,28 @@ bool RemoteVstPlugin::processMessage( const message & _m ) switch( _m.id ) { case IdShowUI: - initEditor(); + showEditor(); return true; case IdHideUI: - destroyEditor(); + hideEditor(); return true; case IdToggleUI: - if( m_window ) + if( m_window && IsWindowVisible( m_window ) ) { - destroyEditor(); + hideEditor(); } else { - initEditor(); + showEditor(); } return true; case IdIsUIVisible: + bool visible = m_window && IsWindowVisible( m_window ); sendMessage( message( IdIsUIVisible ) - .addInt( m_window ? 1 : 0 ) ); + .addInt( visible ? 1 : 0 ) ); return true; } } @@ -709,7 +712,7 @@ void RemoteVstPlugin::initEditor() dwStyle = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX; } - m_window = CreateWindowEx( 0, "LVSL", pluginName(), + m_window = CreateWindowEx( WS_EX_APPWINDOW, "LVSL", pluginName(), dwStyle, 0, 0, 10, 10, NULL, NULL, hInst, NULL ); if( m_window == NULL ) @@ -733,7 +736,7 @@ void RemoteVstPlugin::initEditor() pluginDispatch( effEditTop ); if (! EMBED) { - ShowWindow( m_window, SW_SHOWNORMAL ); + showEditor(); } #ifdef LMMS_BUILD_LINUX @@ -747,6 +750,26 @@ void RemoteVstPlugin::initEditor() +void RemoteVstPlugin::showEditor() { + if( !EMBED && !HEADLESS && m_window ) + { + ShowWindow( m_window, SW_SHOWNORMAL ); + } +} + + + + +void RemoteVstPlugin::hideEditor() { + if( !EMBED && !HEADLESS && m_window ) + { + ShowWindow( m_window, SW_HIDE ); + } +} + + + + void RemoteVstPlugin::destroyEditor() { if( m_window == NULL ) @@ -1947,7 +1970,7 @@ LRESULT CALLBACK RemoteVstPlugin::wndProc( HWND hwnd, UINT uMsg, } else if( uMsg == WM_SYSCOMMAND && wParam == SC_CLOSE ) { - __plugin->destroyEditor(); + __plugin->hideEditor(); return 0; } diff --git a/plugins/vst_base/VstPlugin.cpp b/plugins/vst_base/VstPlugin.cpp index d9d9cc9f7..26c789275 100644 --- a/plugins/vst_base/VstPlugin.cpp +++ b/plugins/vst_base/VstPlugin.cpp @@ -34,9 +34,9 @@ #include #ifdef LMMS_BUILD_LINUX +# include # if QT_VERSION < 0x050000 # include -# include # else # include "X11EmbedContainer.h" # include @@ -62,6 +62,10 @@ #include "templates.h" #include "FileDialog.h" +#ifdef LMMS_BUILD_LINUX +# include +#endif + VstPlugin::VstPlugin( const QString & _plugin ) : m_plugin( _plugin ), @@ -324,6 +328,22 @@ bool VstPlugin::processMessage( const message & _m ) case IdVstPluginWindowID: m_pluginWindowID = _m.getInt(); + if( m_embedMethod == "none" ) + { +#ifdef LMMS_BUILD_WIN32 + // We're changing the owner, not the parent, + // so this is legal despite MSDN's warning + SetWindowLongPtr( (HWND)(intptr_t) m_pluginWindowID, + GWLP_HWNDPARENT, + (LONG_PTR) gui->mainWindow()->winId() ); +#endif + +#ifdef LMMS_BUILD_LINUX + XSetTransientForHint( QX11Info::display(), + m_pluginWindowID, + gui->mainWindow()->winId() ); +#endif + } break; case IdVstPluginEditorGeometry: From 8e9f74df377dca8303d497e731065a3b05a82152 Mon Sep 17 00:00:00 2001 From: DomClark Date: Fri, 20 Apr 2018 22:03:11 +0100 Subject: [PATCH 08/20] Minor fixes From MSDN: "In WM_SYSCOMMAND messages, the four low-order bits of the wParam parameter are used internally by the system. To obtain the correct result when testing the value of wParam, an application must combine the value 0xFFF0 with the wParam value by using the bitwise AND operator." Also calculate the required window size using AdjustWindowRect, rather than hard-coding some constants. --- plugins/vst_base/RemoteVstPlugin.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/vst_base/RemoteVstPlugin.cpp b/plugins/vst_base/RemoteVstPlugin.cpp index 4e8f34ac8..a51ac9d9a 100644 --- a/plugins/vst_base/RemoteVstPlugin.cpp +++ b/plugins/vst_base/RemoteVstPlugin.cpp @@ -730,8 +730,10 @@ void RemoteVstPlugin::initEditor() m_windowWidth = er->right - er->left; m_windowHeight = er->bottom - er->top; - SetWindowPos( m_window, 0, 0, 0, m_windowWidth + 8, - m_windowHeight + 26, SWP_NOACTIVATE | + RECT windowSize = { 0, 0, m_windowWidth, m_windowHeight }; + AdjustWindowRect( &windowSize, dwStyle, false ); + SetWindowPos( m_window, 0, 0, 0, windowSize.right - windowSize.left, + windowSize.bottom - windowSize.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER ); pluginDispatch( effEditTop ); @@ -1968,7 +1970,7 @@ LRESULT CALLBACK RemoteVstPlugin::wndProc( HWND hwnd, UINT uMsg, break; } } - else if( uMsg == WM_SYSCOMMAND && wParam == SC_CLOSE ) + else if( uMsg == WM_SYSCOMMAND && (wParam & 0xfff0) == SC_CLOSE ) { __plugin->hideEditor(); return 0; From b8086319759dd40e2a957ca69998b73897b48132 Mon Sep 17 00:00:00 2001 From: Lukas W Date: Sun, 29 Apr 2018 08:02:25 +0200 Subject: [PATCH 09/20] VST: Add workaround for small effect window on project load --- plugins/VstEffect/VstEffectControlDialog.cpp | 12 +++++++++++- plugins/VstEffect/VstEffectControlDialog.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/plugins/VstEffect/VstEffectControlDialog.cpp b/plugins/VstEffect/VstEffectControlDialog.cpp index ef033ddb1..8445e97cc 100644 --- a/plugins/VstEffect/VstEffectControlDialog.cpp +++ b/plugins/VstEffect/VstEffectControlDialog.cpp @@ -41,7 +41,6 @@ #include #include - VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) : EffectControlDialog( _ctl ), m_pluginWidget( NULL ), @@ -274,6 +273,17 @@ void VstEffectControlDialog::paintEvent( QPaintEvent * ) } } +void VstEffectControlDialog::showEvent(QShowEvent *_se) +{ + EffectControlDialog::showEvent( _se ); + // Workaround for a (unexplained) bug where on project-load the effect + // control window has size 0 and would only restore to the proper size upon + // moving the window or interacting with it. + if (parentWidget()) { + parentWidget()->adjustSize(); + } +} + diff --git a/plugins/VstEffect/VstEffectControlDialog.h b/plugins/VstEffect/VstEffectControlDialog.h index e20915019..3cd9af360 100644 --- a/plugins/VstEffect/VstEffectControlDialog.h +++ b/plugins/VstEffect/VstEffectControlDialog.h @@ -50,6 +50,7 @@ public: protected: virtual void paintEvent( QPaintEvent * _pe ); + virtual void showEvent( QShowEvent* _se ) override; private: QWidget * m_pluginWidget; From 55d3fbc9085c19a0ca4976328358a03ebb886da9 Mon Sep 17 00:00:00 2001 From: Hyunin Song Date: Sun, 20 May 2018 15:40:36 +0900 Subject: [PATCH 10/20] Fix RemoteVstPlugin not exiting when effect removed --- plugins/VstEffect/VstEffectControlDialog.cpp | 7 ++++++- src/gui/widgets/EffectView.cpp | 11 ----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/plugins/VstEffect/VstEffectControlDialog.cpp b/plugins/VstEffect/VstEffectControlDialog.cpp index 8445e97cc..14866ec56 100644 --- a/plugins/VstEffect/VstEffectControlDialog.cpp +++ b/plugins/VstEffect/VstEffectControlDialog.cpp @@ -289,7 +289,12 @@ void VstEffectControlDialog::showEvent(QShowEvent *_se) VstEffectControlDialog::~VstEffectControlDialog() { - //delete m_pluginWidget; +#if !(QT_VERSION < 0x050000 && defined(LMMS_BUILD_LINUX)) + if (m_pluginWidget && layout()) { + layout()->removeWidget(m_pluginWidget); + m_pluginWidget->setParent(nullptr); + } +#endif } diff --git a/src/gui/widgets/EffectView.cpp b/src/gui/widgets/EffectView.cpp index 5faae3517..6c74a459c 100644 --- a/src/gui/widgets/EffectView.cpp +++ b/src/gui/widgets/EffectView.cpp @@ -164,18 +164,7 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) : EffectView::~EffectView() { - -#ifdef LMMS_BUILD_LINUX - delete m_subWindow; -#else - if( m_subWindow ) - { - // otherwise on win32 build VST GUI can get lost - m_subWindow->hide(); - } -#endif - } From 235e8eef6fef278dee2dbe0869256aa915afb068 Mon Sep 17 00:00:00 2001 From: Hyunin Song Date: Sun, 20 May 2018 15:45:50 +0900 Subject: [PATCH 11/20] Allow controlling VST effects without own GUI --- plugins/VstEffect/VstEffectControlDialog.cpp | 8 ++++---- plugins/VstEffect/VstEffectControls.cpp | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/plugins/VstEffect/VstEffectControlDialog.cpp b/plugins/VstEffect/VstEffectControlDialog.cpp index 14866ec56..84548bfde 100644 --- a/plugins/VstEffect/VstEffectControlDialog.cpp +++ b/plugins/VstEffect/VstEffectControlDialog.cpp @@ -62,14 +62,14 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) : embed_vst = m_plugin->embedMethod() != "none"; if (embed_vst) { - if (! m_plugin->pluginWidget()) { + if (m_plugin->hasEditor() && ! m_plugin->pluginWidget()) { m_plugin->createUI(this); } m_pluginWidget = m_plugin->pluginWidget(); } } - if ( m_plugin && (!embed_vst || m_pluginWidget) ) + if (m_plugin) { setWindowTitle( m_plugin->name() ); @@ -218,7 +218,7 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) : int newSize = 0; - if (embed_vst) { + if (m_pluginWidget) { newSize = m_pluginWidget->width() + 20; } newSize = std::max(newSize, 250); @@ -234,7 +234,7 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) : l->addItem( new QSpacerItem( newSize - 20, 30, QSizePolicy::Fixed, QSizePolicy::Fixed ), 1, 0 ); l->addWidget( resize, 2, 0, 1, 1, Qt::AlignCenter ); - if (embed_vst) { + if (m_pluginWidget) { l->addWidget( m_pluginWidget, 3, 0, 1, 1, Qt::AlignCenter ); } l->setRowStretch( 5, 1 ); diff --git a/plugins/VstEffect/VstEffectControls.cpp b/plugins/VstEffect/VstEffectControls.cpp index ef5a59463..4e5aa1a5c 100644 --- a/plugins/VstEffect/VstEffectControls.cpp +++ b/plugins/VstEffect/VstEffectControls.cpp @@ -141,8 +141,7 @@ void VstEffectControls::saveSettings( QDomDocument & _doc, QDomElement & _this ) int VstEffectControls::controlCount() { - return m_effect->m_plugin != NULL && - m_effect->m_plugin->hasEditor() ? 1 : 0; + return m_effect->m_plugin != NULL ? 1 : 0; } From 24ae559de55bf09d3caf2d5594dcfec8a679e67b Mon Sep 17 00:00:00 2001 From: Hyunin Song Date: Wed, 23 May 2018 20:24:12 +0900 Subject: [PATCH 12/20] Fix crash when re-opening VST effect manage dialog Unset Qt::WA_DeleteOnClose for the dialog to avoid deletion when closed --- plugins/VstEffect/VstEffectControls.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/VstEffect/VstEffectControls.cpp b/plugins/VstEffect/VstEffectControls.cpp index 4e5aa1a5c..21d940ddc 100644 --- a/plugins/VstEffect/VstEffectControls.cpp +++ b/plugins/VstEffect/VstEffectControls.cpp @@ -317,7 +317,7 @@ manageVSTEffectView::manageVSTEffectView( VstEffect * _eff, VstEffectControls * m_vi->m_subWindow->setWidget(m_vi->m_scrollArea); m_vi->m_subWindow->setWindowTitle( _eff->m_plugin->name() + tr( " - VST parameter control" ) ); m_vi->m_subWindow->setWindowIcon( PLUGIN_NAME::getIconPixmap( "logo" ) ); - //m_vi->m_subWindow->setAttribute(Qt::WA_DeleteOnClose); + m_vi->m_subWindow->setAttribute(Qt::WA_DeleteOnClose, false); l->setContentsMargins( 20, 10, 10, 10 ); From 75a65021004681402e9b4a03463eb19c18ecdab7 Mon Sep 17 00:00:00 2001 From: Hyunin Song Date: Wed, 30 May 2018 19:14:06 +0900 Subject: [PATCH 13/20] Fix Mallets crash when STK rawwave files can't be loaded --- plugins/stk/mallets/mallets.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/stk/mallets/mallets.h b/plugins/stk/mallets/mallets.h index 649b8ff45..3928c531c 100644 --- a/plugins/stk/mallets/mallets.h +++ b/plugins/stk/mallets/mallets.h @@ -85,7 +85,7 @@ public: inline ~malletsSynth() { - m_voice->noteOff( 0.0 ); + if (m_voice) {m_voice->noteOff(0.0);} delete[] m_delay; delete m_voice; } From 1349d45d72d74b83d30cdf8a092b51e2e1b73afe Mon Sep 17 00:00:00 2001 From: Hyunin Song Date: Fri, 1 Jun 2018 09:04:01 +0900 Subject: [PATCH 14/20] Bump version to 1.2.0-rc6 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f269ee64..da5be324a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ SET(PROJECT_COPYRIGHT "2008-${PROJECT_YEAR} ${PROJECT_AUTHOR}") SET(VERSION_MAJOR "1") SET(VERSION_MINOR "2") SET(VERSION_RELEASE "0") -SET(VERSION_STAGE "rc5") +SET(VERSION_STAGE "rc6") SET(VERSION_BUILD "0") SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_RELEASE}") IF(VERSION_STAGE) From d3c90a81b916ae6f7a49bf402ce3271d06f41e22 Mon Sep 17 00:00:00 2001 From: Lukas W Date: Fri, 1 Jun 2018 13:53:14 +0200 Subject: [PATCH 15/20] Fix automation processing priority Fixes regression from 75077f6200a5aee3a5821aae48a3b8466ed8714a that caused global automation tracks to have priority in processing. Adds a test checking for the desired behaviour. Fixes #4268 --- src/core/Song.cpp | 2 +- tests/src/tracks/AutomationTrackTest.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 5f8e75320..9936585ab 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -816,7 +816,7 @@ AutomationPattern * Song::tempoAutomationPattern() AutomatedValueMap Song::automatedValuesAt(MidiTime time, int tcoNum) const { - return TrackContainer::automatedValuesFromTracks(TrackList(tracks()) << m_globalAutomationTrack, time, tcoNum); + return TrackContainer::automatedValuesFromTracks(TrackList{m_globalAutomationTrack} << tracks(), time, tcoNum); } diff --git a/tests/src/tracks/AutomationTrackTest.cpp b/tests/src/tracks/AutomationTrackTest.cpp index bd5257253..ef204963d 100644 --- a/tests/src/tracks/AutomationTrackTest.cpp +++ b/tests/src/tracks/AutomationTrackTest.cpp @@ -195,6 +195,30 @@ private slots: QCOMPARE(song->automatedValuesAt(5)[&model], 0.5f); QCOMPARE(song->automatedValuesAt(MidiTime::ticksPerTact() + 5)[&model], 0.5f); } + + void testGlobalAutomation() + { + // Global automation should not have priority, see https://github.com/LMMS/lmms/issues/4268 + // Tests regression caused by 75077f6200a5aee3a5821aae48a3b8466ed8714a + auto song = Engine::getSong(); + + auto globalTrack = song->globalAutomationTrack(); + AutomationPattern globalPattern(globalTrack); + + AutomationTrack localTrack(song); + AutomationPattern localPattern(&localTrack); + + FloatModel model; + globalPattern.setProgressionType(AutomationPattern::DiscreteProgression); + localPattern.setProgressionType(AutomationPattern::DiscreteProgression); + globalPattern.addObject(&model); + localPattern.addObject(&model); + globalPattern.putValue(0, 100.0f, false); + localPattern.putValue(0, 50.0f, false); + + QCOMPARE(song->automatedValuesAt(0)[&model], 50.0f); + } + } AutomationTrackTest; #include "AutomationTrackTest.moc" From 0d7ea273dc782ed6146891d77f55e6096f7a008e Mon Sep 17 00:00:00 2001 From: Douglas <34612565+DouglasDGI@users.noreply.github.com> Date: Fri, 1 Jun 2018 21:41:52 -0600 Subject: [PATCH 16/20] Initialize peak controller last sample with base value (#4382) * Bug fix in peak_controller_effect.cpp This change makes it so that when an LMMS project is loaded, each knob connected to a Peak Controller will be set to the Peak Controller's Base value, rather than its minimum possible value. --- plugins/peak_controller_effect/peak_controller_effect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/peak_controller_effect/peak_controller_effect.cpp b/plugins/peak_controller_effect/peak_controller_effect.cpp index d4d81b137..87f6cc600 100644 --- a/plugins/peak_controller_effect/peak_controller_effect.cpp +++ b/plugins/peak_controller_effect/peak_controller_effect.cpp @@ -64,7 +64,7 @@ PeakControllerEffect::PeakControllerEffect( Effect( &peakcontrollereffect_plugin_descriptor, _parent, _key ), m_effectId( rand() ), m_peakControls( this ), - m_lastSample( 0 ), + m_lastSample( m_peakControls.m_baseModel.value() ), //sets the value to the Peak Controller's Base value (rather than 0 like in previous versions) m_autoController( NULL ) { m_autoController = new PeakController( Engine::getSong(), this ); From a9b5b92a2b39b4062f08c00812792d28e2ae770e Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Sun, 3 Jun 2018 21:35:36 +0900 Subject: [PATCH 17/20] Deselect FX channel's name text when losing focus (#4293) --- src/gui/widgets/FxLine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/widgets/FxLine.cpp b/src/gui/widgets/FxLine.cpp index c6e6fd9ae..6cb6363c3 100644 --- a/src/gui/widgets/FxLine.cpp +++ b/src/gui/widgets/FxLine.cpp @@ -262,6 +262,7 @@ void FxLine::renameChannel() void FxLine::renameFinished() { m_inRename = false; + m_renameLineEdit->deselect(); m_renameLineEdit->setReadOnly( true ); m_renameLineEdit->setFixedWidth( 65 ); m_lcd->show(); From 3bf3fab0e33b7bb199b2c4b32b1ccd0e1da096ca Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Sun, 3 Jun 2018 22:12:28 +0900 Subject: [PATCH 18/20] Piano roll: Fix some crashes when no pattern is open (#4392) --- src/gui/editors/PianoRoll.cpp | 39 +++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 888425ddc..486a2e826 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -949,6 +949,8 @@ void PianoRoll::clearSelectedNotes() void PianoRoll::shiftSemiTone( int amount ) // shift notes by amount semitones { + if (!hasValidPattern()) {return;} + bool useAllNotes = ! isSelection(); for( Note *note : m_pattern->notes() ) { @@ -973,6 +975,8 @@ void PianoRoll::shiftSemiTone( int amount ) // shift notes by amount semitones void PianoRoll::shiftPos( int amount ) //shift notes pos by amount { + if (!hasValidPattern()) {return;} + bool useAllNotes = ! isSelection(); bool first = true; @@ -1063,12 +1067,18 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) { // shift selection up an octave // if nothing selected, shift _everything_ - shiftSemiTone( 12 * direction ); + if (hasValidPattern()) + { + shiftSemiTone( 12 * direction ); + } } else if((ke->modifiers() & Qt::ShiftModifier) && m_action == ActionNone) { // Move selected notes up by one semitone - shiftSemiTone( 1 * direction ); + if (hasValidPattern()) + { + shiftSemiTone( 1 * direction ); + } } else { @@ -1098,22 +1108,32 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) if( ke->modifiers() & Qt::ControlModifier && m_action == ActionNone ) { // Move selected notes by one bar to the left - shiftPos( direction * MidiTime::ticksPerTact() ); + if (hasValidPattern()) + { + shiftPos( direction * MidiTime::ticksPerTact() ); + } } else if( ke->modifiers() & Qt::ShiftModifier && m_action == ActionNone) { // move notes - bool quantized = ! ( ke->modifiers() & Qt::AltModifier ); - int amt = quantized ? quantization() : 1; - shiftPos( direction * amt ); + if (hasValidPattern()) + { + bool quantized = ! ( ke->modifiers() & Qt::AltModifier ); + int amt = quantized ? quantization() : 1; + shiftPos( direction * amt ); + } } else if( ke->modifiers() & Qt::AltModifier) { // switch to editing a pattern adjacent to this one in the song editor - Pattern * p = direction > 0 ? m_pattern->nextPattern() : m_pattern->previousPattern(); - if(p != NULL) + if (hasValidPattern()) { - setCurrentPattern(p); + Pattern * p = direction > 0 ? m_pattern->nextPattern() + : m_pattern->previousPattern(); + if(p != NULL) + { + setCurrentPattern(p); + } } } else @@ -3188,6 +3208,7 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) if( we->x() > noteEditLeft() && we->x() < noteEditRight() && we->y() > noteEditTop() && we->y() < noteEditBottom() ) { + if (!hasValidPattern()) {return;} // get values for going through notes int pixel_range = 8; int x = we->x() - WHITE_KEY_WIDTH; From 2f19fa11c886374adcc74990e52d3ed0473fbf08 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Tue, 5 Jun 2018 17:39:04 +0900 Subject: [PATCH 19/20] Piano roll: reset editing mode when lost focus (#4393) --- src/gui/editors/PianoRoll.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 486a2e826..6950c0005 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -177,6 +177,7 @@ PianoRoll::PianoRoll() : m_startKey( INITIAL_START_KEY ), m_lastKey( 0 ), m_editMode( ModeDraw ), + m_ctrlMode( ModeDraw ), m_mouseDownRight( false ), m_scrollBack( false ), m_barLineColor( 0, 0, 0 ), @@ -3343,8 +3344,9 @@ void PianoRoll::focusOutEvent( QFocusEvent * ) m_pattern->instrumentTrack()->pianoModel()->midiEventProcessor()->processInEvent( MidiEvent( MidiNoteOff, -1, i, 0 ) ); m_pattern->instrumentTrack()->pianoModel()->setKeyState( i, false ); } - update(); } + m_editMode = m_ctrlMode; + update(); } @@ -3552,7 +3554,7 @@ void PianoRoll::verScrolled( int new_pos ) void PianoRoll::setEditMode(int mode) { - m_editMode = (EditModes) mode; + m_ctrlMode = m_editMode = (EditModes) mode; } From 407973ad6f304c9af07dd50fa94fe498df188896 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Wed, 13 Jun 2018 14:50:27 +0900 Subject: [PATCH 20/20] Fix crash when loading project with missing peak controller effect (#4391) * Fix crash when loading project with missing peak controller effect * Don't load/save dummy controller connections --- src/core/AutomatableModel.cpp | 3 ++- src/core/ControllerConnection.cpp | 7 ++++++- src/core/Song.cpp | 15 ++++++++++++--- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index e2a088e04..0b2a1522b 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -110,7 +110,8 @@ void AutomatableModel::saveSettings( QDomDocument& doc, QDomElement& element, co element.setAttribute( name, m_value ); } - if( m_controllerConnection ) + if( m_controllerConnection && m_controllerConnection->getController()->type() + != Controller::DummyController ) { QDomElement controllerElement; diff --git a/src/core/ControllerConnection.cpp b/src/core/ControllerConnection.cpp index 280ed709c..4f04cbc20 100644 --- a/src/core/ControllerConnection.cpp +++ b/src/core/ControllerConnection.cpp @@ -162,6 +162,11 @@ void ControllerConnection::finalizeConnections() c->setController( Engine::getSong()-> controllers().at( c->m_controllerId ) ); } + else if (c->getController()->type() == Controller::DummyController) + { + delete c; + --i; + } } } @@ -199,7 +204,7 @@ void ControllerConnection::loadSettings( const QDomElement & _this ) } else { - if( _this.attribute( "id" ).toInt() >= 0 ) + if( _this.attribute( "id", "-1" ).toInt() >= 0 ) { m_controllerId = _this.attribute( "id" ).toInt(); } diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 9936585ab..be0c7dddc 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -1122,6 +1122,11 @@ void Song::loadProject( const QString & fileName ) // now that everything is loaded ControllerConnection::finalizeConnections(); + // Remove dummy controllers that was added for correct connections + m_controllers.erase(std::remove_if(m_controllers.begin(), m_controllers.end(), + [](Controller* c){return c->type() == Controller::DummyController;}), + m_controllers.end()); + // resolve all IDs so that autoModels are automated AutomationPattern::resolveAllIDs(); @@ -1289,9 +1294,13 @@ void Song::restoreControllerStates( const QDomElement & element ) while( !node.isNull() && !isCancelled() ) { Controller * c = Controller::create( node.toElement(), this ); - Q_ASSERT( c != NULL ); - - addController( c ); + if (c) {addController(c);} + else + { + // Fix indices to ensure correct connections + m_controllers.append(Controller::create( + Controller::DummyController, this)); + } node = node.nextSibling(); }