--- qsampler/trunk/src/qsamplerMainForm.cpp 2010/07/22 08:12:12 2113 +++ qsampler/trunk/src/qsamplerMainForm.cpp 2019/10/01 08:35:49 3613 @@ -1,8 +1,8 @@ // qsamplerMainForm.cpp // /**************************************************************************** - Copyright (C) 2004-2010, rncbc aka Rui Nuno Capela. All rights reserved. - Copyright (C) 2007, 2008 Christian Schoenebeck + Copyright (C) 2004-2019, rncbc aka Rui Nuno Capela. All rights reserved. + Copyright (C) 2007,2008,2015 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -35,8 +35,10 @@ #include "qsamplerOptionsForm.h" #include "qsamplerDeviceStatusForm.h" +#include +#include + #include -#include #include #include @@ -56,19 +58,16 @@ #include #include -#if QT_VERSION < 0x040500 +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) +#include +#endif + +#if QT_VERSION < QT_VERSION_CHECK(4, 5, 0) namespace Qt { const WindowFlags WindowCloseButtonHint = WindowFlags(0x08000000); -#if QT_VERSION < 0x040200 -const WindowFlags CustomizeWindowHint = WindowFlags(0x02000000); -#endif } #endif -#ifdef HAVE_SIGNAL_H -#include -#endif - #ifdef CONFIG_LIBGIG #include #endif @@ -88,39 +87,51 @@ // All winsock apps needs this. -#if defined(WIN32) +#if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) static WSADATA _wsaData; +#undef HAVE_SIGNAL_H #endif //------------------------------------------------------------------------- // LADISH Level 1 support stuff. -#ifdef HAVE_SIGNAL_H +#if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H) #include +#include #include #include - #include // File descriptor for SIGUSR1 notifier. -static int g_fdUsr1[2]; +static int g_fdSigusr1[2] = { -1, -1 }; // Unix SIGUSR1 signal handler. static void qsampler_sigusr1_handler ( int /* signo */ ) { char c = 1; - (::write(g_fdUsr1[0], &c, sizeof(c)) > 0); + (::write(g_fdSigusr1[0], &c, sizeof(c)) > 0); +} + +// File descriptor for SIGTERM notifier. +static int g_fdSigterm[2] = { -1, -1 }; + +// Unix SIGTERM signal handler. +static void qsampler_sigterm_handler ( int /* signo */ ) +{ + char c = 1; + + (::write(g_fdSigterm[0], &c, sizeof(c)) > 0); } #endif // HAVE_SIGNAL_H //------------------------------------------------------------------------- -// qsampler -- namespace +// QSampler -- namespace namespace QSampler { @@ -140,8 +151,7 @@ //------------------------------------------------------------------------- -// LscpEvent -- specialty for LSCP callback comunication. - +// QSampler::LscpEvent -- specialty for LSCP callback comunication. class LscpEvent : public QEvent { @@ -156,8 +166,8 @@ } // Accessors. - lscp_event_t event() { return m_event; } - QString& data() { return m_data; } + lscp_event_t event() { return m_event; } + const QString& data() { return m_data; } private: @@ -169,10 +179,30 @@ //------------------------------------------------------------------------- -// qsamplerMainForm -- Main window form implementation. +// QSampler::Workspace -- Main window workspace (MDI Area) decl. + +class Workspace : public QMdiArea +{ +public: + + Workspace(MainForm *pMainForm) : QMdiArea(pMainForm) {} + +protected: + + void resizeEvent(QResizeEvent *) + { + MainForm *pMainForm = static_cast (parentWidget()); + if (pMainForm) + pMainForm->channelsArrangeAuto(); + } +}; + + +//------------------------------------------------------------------------- +// QSampler::MainForm -- Main window form implementation. // Kind of singleton reference. -MainForm* MainForm::g_pMainForm = NULL; +MainForm *MainForm::g_pMainForm = nullptr; MainForm::MainForm ( QWidget *pParent ) : QMainWindow(pParent) @@ -183,26 +213,27 @@ g_pMainForm = this; // Initialize some pointer references. - m_pOptions = NULL; + m_pOptions = nullptr; // All child forms are to be created later, not earlier than setup. - m_pMessages = NULL; - m_pInstrumentListForm = NULL; - m_pDeviceForm = NULL; + m_pMessages = nullptr; + m_pInstrumentListForm = nullptr; + m_pDeviceForm = nullptr; // We'll start clean. m_iUntitled = 0; + m_iDirtySetup = 0; m_iDirtyCount = 0; - m_pServer = NULL; - m_pClient = NULL; + m_pServer = nullptr; + m_pClient = nullptr; m_iStartDelay = 0; m_iTimerDelay = 0; m_iTimerSlot = 0; -#ifdef HAVE_SIGNAL_H +#if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H) // Set to ignore any fatal "Broken pipe" signals. ::signal(SIGPIPE, SIG_IGN); @@ -210,25 +241,48 @@ // LADISH Level 1 suport. // Initialize file descriptors for SIGUSR1 socket notifier. - ::socketpair(AF_UNIX, SOCK_STREAM, 0, g_fdUsr1); - m_pUsr1Notifier - = new QSocketNotifier(g_fdUsr1[1], QSocketNotifier::Read, this); + ::socketpair(AF_UNIX, SOCK_STREAM, 0, g_fdSigusr1); + m_pSigusr1Notifier + = new QSocketNotifier(g_fdSigusr1[1], QSocketNotifier::Read, this); - QObject::connect(m_pUsr1Notifier, + QObject::connect(m_pSigusr1Notifier, SIGNAL(activated(int)), SLOT(handle_sigusr1())); // Install SIGUSR1 signal handler. - struct sigaction usr1; - usr1.sa_handler = qsampler_sigusr1_handler; - ::sigemptyset(&usr1.sa_mask); - usr1.sa_flags = 0; - usr1.sa_flags |= SA_RESTART; - ::sigaction(SIGUSR1, &usr1, NULL); + struct sigaction sigusr1; + sigusr1.sa_handler = qsampler_sigusr1_handler; + sigemptyset(&sigusr1.sa_mask); + sigusr1.sa_flags = 0; + sigusr1.sa_flags |= SA_RESTART; + ::sigaction(SIGUSR1, &sigusr1, nullptr); + + // Initialize file descriptors for SIGTERM socket notifier. + ::socketpair(AF_UNIX, SOCK_STREAM, 0, g_fdSigterm); + m_pSigtermNotifier + = new QSocketNotifier(g_fdSigterm[1], QSocketNotifier::Read, this); + + QObject::connect(m_pSigtermNotifier, + SIGNAL(activated(int)), + SLOT(handle_sigterm())); + + // Install SIGTERM signal handler. + struct sigaction sigterm; + sigterm.sa_handler = qsampler_sigterm_handler; + sigemptyset(&sigterm.sa_mask); + sigterm.sa_flags = 0; + sigterm.sa_flags |= SA_RESTART; + ::sigaction(SIGTERM, &sigterm, nullptr); + ::sigaction(SIGQUIT, &sigterm, nullptr); + + // Ignore SIGHUP/SIGINT signals. + ::signal(SIGHUP, SIG_IGN); + ::signal(SIGINT, SIG_IGN); #else // HAVE_SIGNAL_H - m_pUsr1Notifier = NULL; + m_pSigusr1Notifier = nullptr; + m_pSigtermNotifier = nullptr; #endif // !HAVE_SIGNAL_H @@ -251,13 +305,10 @@ QObject::connect(m_pVolumeSlider, SIGNAL(valueChanged(int)), SLOT(volumeChanged(int))); - //m_ui.channelsToolbar->setHorizontallyStretchable(true); - //m_ui.channelsToolbar->setStretchableWidget(m_pVolumeSlider); m_ui.channelsToolbar->addWidget(m_pVolumeSlider); // Volume spin-box m_ui.channelsToolbar->addSeparator(); m_pVolumeSpinBox = new QSpinBox(m_ui.channelsToolbar); - m_pVolumeSpinBox->setMaximumHeight(24); m_pVolumeSpinBox->setSuffix(" %"); m_pVolumeSpinBox->setMinimum(0); m_pVolumeSpinBox->setMaximum(100); @@ -269,12 +320,13 @@ #endif // Make it an MDI workspace. - m_pWorkspace = new QWorkspace(this); - m_pWorkspace->setScrollBarsEnabled(true); + m_pWorkspace = new Workspace(this); + m_pWorkspace->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + m_pWorkspace->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); // Set the activation connection. QObject::connect(m_pWorkspace, - SIGNAL(windowActivated(QWidget *)), - SLOT(activateStrip(QWidget *))); + SIGNAL(subWindowActivated(QMdiSubWindow *)), + SLOT(activateStrip(QMdiSubWindow *))); // Make it shine :-) setCentralWidget(m_pWorkspace); @@ -303,7 +355,7 @@ m_statusItem[QSAMPLER_STATUS_SESSION] = pLabel; statusBar()->addWidget(pLabel); -#if defined(WIN32) +#if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) WSAStartup(MAKEWORD(1, 1), &_wsaData); #endif @@ -391,6 +443,11 @@ QObject::connect(m_ui.channelsMenu, SIGNAL(aboutToShow()), SLOT(channelsMenuAboutToShow())); +#ifdef CONFIG_VOLUME + QObject::connect(m_ui.channelsToolbar, + SIGNAL(orientationChanged(Qt::Orientation)), + SLOT(channelsToolbarOrientation(Qt::Orientation))); +#endif } // Destructor. @@ -399,13 +456,15 @@ // Do final processing anyway. processServerExit(); -#if defined(WIN32) +#if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) WSACleanup(); #endif -#ifdef HAVE_SIGNAL_H - if (m_pUsr1Notifier) - delete m_pUsr1Notifier; +#if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H) + if (m_pSigusr1Notifier) + delete m_pSigusr1Notifier; + if (m_pSigtermNotifier) + delete m_pSigtermNotifier; #endif // Finally drop any widgets around... @@ -434,7 +493,7 @@ #endif // Pseudo-singleton reference shut-down. - g_pMainForm = NULL; + g_pMainForm = nullptr; } @@ -472,6 +531,7 @@ updateMessagesFont(); updateMessagesLimit(); updateMessagesCapture(); + // Set the visibility signal. QObject::connect(m_pMessages, SIGNAL(visibilityChanged(bool)), @@ -537,7 +597,6 @@ || m_ui.channelsToolbar->isVisible()); m_pOptions->bStatusbar = statusBar()->isVisible(); // Save the dock windows state. - const QString sDockables = saveState().toBase64().data(); m_pOptions->settings().setValue("/Layout/DockWindows", saveState()); // And the children, and the main windows state,. m_pOptions->saveWidgetGeometry(m_pDeviceForm); @@ -571,7 +630,7 @@ void MainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent ) { // Accept external drags only... - if (pDragEnterEvent->source() == NULL + if (pDragEnterEvent->source() == nullptr && pDragEnterEvent->mimeData()->hasUrls()) { pDragEnterEvent->accept(); } else { @@ -580,7 +639,7 @@ } -void MainForm::dropEvent ( QDropEvent* pDropEvent ) +void MainForm::dropEvent ( QDropEvent *pDropEvent ) { // Accept externally originated drops only... if (pDropEvent->source()) @@ -595,7 +654,7 @@ if (QFileInfo(sPath).exists()) { // Try to create a new channel from instrument file... Channel *pChannel = new Channel(); - if (pChannel == NULL) + if (pChannel == nullptr) return; // Start setting the instrument filename... pChannel->setInstrument(sPath, 0); @@ -636,7 +695,7 @@ updateAllChannelStrips(true); break; case LSCP_EVENT_CHANNEL_INFO: { - int iChannelID = pLscpEvent->data().toInt(); + const int iChannelID = pLscpEvent->data().toInt(); ChannelStrip *pChannelStrip = channelStrip(iChannelID); if (pChannelStrip) channelStripChanged(pChannelStrip); @@ -691,17 +750,30 @@ // LADISH Level 1 -- SIGUSR1 signal handler. void MainForm::handle_sigusr1 (void) { -#ifdef HAVE_SIGNAL_H +#if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H) char c; - if (::read(g_fdUsr1[1], &c, sizeof(c)) > 0) + if (::read(g_fdSigusr1[1], &c, sizeof(c)) > 0) saveSession(false); #endif } +void MainForm::handle_sigterm (void) +{ +#if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H) + + char c; + + if (::read(g_fdSigterm[1], &c, sizeof(c)) > 0) + close(); + +#endif +} + + void MainForm::updateViewMidiDeviceStatusMenu (void) { m_ui.viewMidiDeviceStatusMenu->clear(); @@ -727,7 +799,7 @@ //------------------------------------------------------------------------- -// qsamplerMainForm -- Brainless public property accessors. +// QSampler::MainForm -- Brainless public property accessors. // The global options settings property. Options *MainForm::options (void) const @@ -751,12 +823,12 @@ //------------------------------------------------------------------------- -// qsamplerMainForm -- Session file stuff. +// QSampler::MainForm -- Session file stuff. // Format the displayable session filename. QString MainForm::sessionName ( const QString& sFilename ) { - bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath); + const bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath); QString sSessionName = sFilename; if (sSessionName.isEmpty()) sSessionName = tr("Untitled") + QString::number(m_iUntitled); @@ -780,7 +852,7 @@ m_iUntitled++; // Stabilize form. - m_sFilename = QString::null; + m_sFilename = QString(); m_iDirtyCount = 0; appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename))); stabilizeForm(); @@ -792,12 +864,12 @@ // Open an existing sampler session. bool MainForm::openSession (void) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return false; // Ask for the filename to open... QString sFilename = QFileDialog::getOpenFileName(this, - QSAMPLER_TITLE ": " + tr("Open Session"), // Caption. + tr("Open Session"), // Caption. m_pOptions->sSessionDir, // Start here. tr("LSCP Session files") + " (*.lscp)" // Filter (LSCP files) ); @@ -818,7 +890,7 @@ // Save current sampler session with another name. bool MainForm::saveSession ( bool bPrompt ) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return false; QString sFilename = m_sFilename; @@ -830,7 +902,7 @@ sFilename = m_pOptions->sSessionDir; // Prompt the guy... sFilename = QFileDialog::getSaveFileName(this, - QSAMPLER_TITLE ": " + tr("Save Session"), // Caption. + tr("Save Session"), // Caption. sFilename, // Start here. tr("LSCP Session files") + " (*.lscp)" // Filter (LSCP files) ); @@ -840,10 +912,11 @@ // Enforce .lscp extension... if (QFileInfo(sFilename).suffix().isEmpty()) sFilename += ".lscp"; + #if 0 // Check if already exists... if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) { if (QMessageBox::warning(this, - QSAMPLER_TITLE ": " + tr("Warning"), + tr("Warning"), tr("The file already exists:\n\n" "\"%1\"\n\n" "Do you want to replace it?") @@ -852,6 +925,7 @@ == QMessageBox::No) return false; } + #endif } // Save it right away. @@ -867,7 +941,7 @@ // Are we dirty enough to prompt it? if (m_iDirtyCount > 0) { switch (QMessageBox::warning(this, - QSAMPLER_TITLE ": " + tr("Warning"), + tr("Warning"), tr("The current session has been changed:\n\n" "\"%1\"\n\n" "Do you want to save the changes?") @@ -890,15 +964,18 @@ if (bClose) { // Remove all channel strips from sight... m_pWorkspace->setUpdatesEnabled(false); - QWidgetList wlist = m_pWorkspace->windowList(); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip *pChannelStrip = (ChannelStrip*) wlist.at(iChannel); + const QList& wlist + = m_pWorkspace->subWindowList(); + foreach (QMdiSubWindow *pMdiSubWindow, wlist) { + ChannelStrip *pChannelStrip + = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) { Channel *pChannel = pChannelStrip->channel(); if (bForce && pChannel) pChannel->removeChannel(); delete pChannelStrip; } + delete pMdiSubWindow; } m_pWorkspace->setUpdatesEnabled(true); // We're now clean, for sure. @@ -912,7 +989,7 @@ // Load a session from specific file path. bool MainForm::loadSessionFile ( const QString& sFilename ) { - if (m_pClient == NULL) + if (m_pClient == nullptr) return false; // Open and read from real file. @@ -988,7 +1065,7 @@ // Save current session to specific file path. bool MainForm::saveSessionFile ( const QString& sFilename ) { - if (m_pClient == NULL) + if (m_pClient == nullptr) return false; // Check whether server is apparently OK... @@ -1010,13 +1087,11 @@ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // Write the file. - int iErrors = 0; + int iErrors = 0; QTextStream ts(&file); ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl; - ts << "# " << tr("Version") - << ": " QSAMPLER_VERSION << endl; - ts << "# " << tr("Build") - << ": " __DATE__ " " __TIME__ << endl; + ts << "# " << tr("Version") << ": " CONFIG_BUILD_VERSION << endl; +// ts << "# " << tr("Build") << ": " CONFIG_BUILD_DATE << endl; ts << "#" << endl; ts << "# " << tr("File") << ": " << QFileInfo(sFilename).fileName() << endl; @@ -1029,16 +1104,19 @@ // It is assumed that this new kind of device+session file // will be loaded from a complete initialized server... int *piDeviceIDs; - int iDevice; + int i, iDevice; ts << "RESET" << endl; // Audio device mapping. - QMap audioDeviceMap; + QMap audioDeviceMap; iDevice = 0; piDeviceIDs = Device::getDevices(m_pClient, Device::Audio); - for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) { - ts << endl; - Device device(Device::Audio, piDeviceIDs[iDevice]); + for (i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; ++i) { + Device device(Device::Audio, piDeviceIDs[i]); + // Avoid plug-in driver devices... + if (device.driverName().toUpper() == "PLUGIN") + continue; // Audio device specification... + ts << endl; ts << "# " << device.deviceTypeName() << " " << device.driverName() << " " << tr("Device") << " " << iDevice << endl; ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName(); @@ -1069,18 +1147,21 @@ iPort++; } // Audio device index/id mapping. - audioDeviceMap[device.deviceID()] = iDevice; + audioDeviceMap.insert(device.deviceID(), iDevice++); // Try to keep it snappy :) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } // MIDI device mapping. - QMap midiDeviceMap; + QMap midiDeviceMap; iDevice = 0; piDeviceIDs = Device::getDevices(m_pClient, Device::Midi); - for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) { - ts << endl; - Device device(Device::Midi, piDeviceIDs[iDevice]); + for (i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; ++i) { + Device device(Device::Midi, piDeviceIDs[i]); + // Avoid plug-in driver devices... + if (device.driverName().toUpper() == "PLUGIN") + continue; // MIDI device specification... + ts << endl; ts << "# " << device.deviceTypeName() << " " << device.driverName() << " " << tr("Device") << " " << iDevice << endl; ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName(); @@ -1111,7 +1192,7 @@ iPort++; } // MIDI device index/id mapping. - midiDeviceMap[device.deviceID()] = iDevice; + midiDeviceMap.insert(device.deviceID(), iDevice++); // Try to keep it snappy :) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } @@ -1122,7 +1203,7 @@ QMap midiInstrumentMap; int *piMaps = ::lscp_list_midi_instrument_maps(m_pClient); for (int iMap = 0; piMaps && piMaps[iMap] >= 0; iMap++) { - int iMidiMap = piMaps[iMap]; + const int iMidiMap = piMaps[iMap]; const char *pszMapName = ::lscp_get_midi_instrument_map_name(m_pClient, iMidiMap); ts << "# " << tr("MIDI instrument map") << " " << iMap; @@ -1174,80 +1255,90 @@ } ts << endl; // Check for errors... - if (pInstrs == NULL && ::lscp_client_get_errno(m_pClient)) { + if (pInstrs == nullptr && ::lscp_client_get_errno(m_pClient)) { appendMessagesClient("lscp_list_midi_instruments"); iErrors++; } // MIDI strument index/id mapping. - midiInstrumentMap[iMidiMap] = iMap; + midiInstrumentMap.insert(iMidiMap, iMap); } // Check for errors... - if (piMaps == NULL && ::lscp_client_get_errno(m_pClient)) { + if (piMaps == nullptr && ::lscp_client_get_errno(m_pClient)) { appendMessagesClient("lscp_list_midi_instrument_maps"); iErrors++; } #endif // CONFIG_MIDI_INSTRUMENT - // Sampler channel mapping. - QWidgetList wlist = m_pWorkspace->windowList(); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip - = static_cast (wlist.at(iChannel)); + // Sampler channel mapping... + int iChannelID = 0; + const QList& wlist + = m_pWorkspace->subWindowList(); + foreach (QMdiSubWindow *pMdiSubWindow, wlist) { + ChannelStrip *pChannelStrip + = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) { Channel *pChannel = pChannelStrip->channel(); if (pChannel) { - ts << "# " << tr("Channel") << " " << iChannel << endl; + // Avoid "artifial" plug-in devices... + const int iAudioDevice = pChannel->audioDevice(); + if (!audioDeviceMap.contains(iAudioDevice)) + continue; + const int iMidiDevice = pChannel->midiDevice(); + if (!midiDeviceMap.contains(iMidiDevice)) + continue; + // Go for regular, canonical devices... + ts << "# " << tr("Channel") << " " << iChannelID << endl; ts << "ADD CHANNEL" << endl; if (audioDeviceMap.isEmpty()) { - ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel + ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannelID << " " << pChannel->audioDriver() << endl; } else { - ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannel - << " " << audioDeviceMap[pChannel->audioDevice()] << endl; + ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannelID + << " " << audioDeviceMap.value(iAudioDevice) << endl; } if (midiDeviceMap.isEmpty()) { - ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannel + ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannelID << " " << pChannel->midiDriver() << endl; } else { - ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannel - << " " << midiDeviceMap[pChannel->midiDevice()] << endl; + ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannelID + << " " << midiDeviceMap.value(iMidiDevice) << endl; } - ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel + ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannelID << " " << pChannel->midiPort() << endl; - ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " "; + ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannelID << " "; if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL) ts << "ALL"; else ts << pChannel->midiChannel(); ts << endl; ts << "LOAD ENGINE " << pChannel->engineName() - << " " << iChannel << endl; + << " " << iChannelID << endl; if (pChannel->instrumentStatus() < 100) ts << "# "; ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' " - << pChannel->instrumentNr() << " " << iChannel << endl; + << pChannel->instrumentNr() << " " << iChannelID << endl; ChannelRoutingMap::ConstIterator audioRoute; for (audioRoute = pChannel->audioRouting().begin(); audioRoute != pChannel->audioRouting().end(); ++audioRoute) { - ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannel + ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannelID << " " << audioRoute.key() << " " << audioRoute.value() << endl; } - ts << "SET CHANNEL VOLUME " << iChannel + ts << "SET CHANNEL VOLUME " << iChannelID << " " << pChannel->volume() << endl; if (pChannel->channelMute()) - ts << "SET CHANNEL MUTE " << iChannel << " 1" << endl; + ts << "SET CHANNEL MUTE " << iChannelID << " 1" << endl; if (pChannel->channelSolo()) - ts << "SET CHANNEL SOLO " << iChannel << " 1" << endl; -#ifdef CONFIG_MIDI_INSTRUMENT - if (pChannel->midiMap() >= 0) { - ts << "SET CHANNEL MIDI_INSTRUMENT_MAP " << iChannel - << " " << midiInstrumentMap[pChannel->midiMap()] << endl; + ts << "SET CHANNEL SOLO " << iChannelID << " 1" << endl; + #ifdef CONFIG_MIDI_INSTRUMENT + const int iMidiMap = pChannel->midiMap(); + if (midiInstrumentMap.contains(iMidiMap)) { + ts << "SET CHANNEL MIDI_INSTRUMENT_MAP " << iChannelID + << " " << midiInstrumentMap.value(iMidiMap) << endl; } -#endif -#ifdef CONFIG_FXSEND - int iChannelID = pChannel->channelID(); + #endif + #ifdef CONFIG_FXSEND int *piFxSends = ::lscp_list_fxsends(m_pClient, iChannelID); for (int iFxSend = 0; piFxSends && piFxSends[iFxSend] >= 0; @@ -1255,7 +1346,7 @@ lscp_fxsend_info_t *pFxSendInfo = ::lscp_get_fxsend_info( m_pClient, iChannelID, piFxSends[iFxSend]); if (pFxSendInfo) { - ts << "CREATE FX_SEND " << iChannel + ts << "CREATE FX_SEND " << iChannelID << " " << pFxSendInfo->midi_controller; if (pFxSendInfo->name) ts << " '" << pFxSendInfo->name << "'"; @@ -1265,24 +1356,26 @@ piRouting && piRouting[iAudioSrc] >= 0; iAudioSrc++) { ts << "SET FX_SEND AUDIO_OUTPUT_CHANNEL " - << iChannel + << iChannelID << " " << iFxSend << " " << iAudioSrc << " " << piRouting[iAudioSrc] << endl; } -#ifdef CONFIG_FXSEND_LEVEL - ts << "SET FX_SEND LEVEL " << iChannel + #ifdef CONFIG_FXSEND_LEVEL + ts << "SET FX_SEND LEVEL " << iChannelID << " " << iFxSend << " " << pFxSendInfo->level << endl; -#endif + #endif } // Check for errors... else if (::lscp_client_get_errno(m_pClient)) { appendMessagesClient("lscp_get_fxsend_info"); iErrors++; } } -#endif + #endif ts << endl; + // Go for next channel... + ++iChannelID; } } // Try to keep it snappy :) @@ -1334,7 +1427,7 @@ //------------------------------------------------------------------------- -// qsamplerMainForm -- File Action slots. +// QSampler::MainForm -- File Action slots. // Create a new sampler session. void MainForm::fileNew (void) @@ -1358,7 +1451,7 @@ // Retrive filename index from action data... QAction *pAction = qobject_cast (sender()); if (pAction && m_pOptions) { - int iIndex = pAction->data().toInt(); + const int iIndex = pAction->data().toInt(); if (iIndex >= 0 && iIndex < m_pOptions->recentFiles.count()) { QString sFilename = m_pOptions->recentFiles[iIndex]; // Check if we can safely close the current session... @@ -1388,20 +1481,38 @@ // Reset the sampler instance. void MainForm::fileReset (void) { - if (m_pClient == NULL) + if (m_pClient == nullptr) return; // Ask user whether he/she want's an internal sampler reset... - if (QMessageBox::warning(this, - QSAMPLER_TITLE ": " + tr("Warning"), - tr("Resetting the sampler instance will close\n" - "all device and channel configurations.\n\n" - "Please note that this operation may cause\n" - "temporary MIDI and Audio disruption.\n\n" - "Do you want to reset the sampler engine now?"), - QMessageBox::Ok | QMessageBox::Cancel) - == QMessageBox::Cancel) - return; + if (m_pOptions && m_pOptions->bConfirmReset) { + const QString& sTitle = tr("Warning"); + const QString& sText = tr( + "Resetting the sampler instance will close\n" + "all device and channel configurations.\n\n" + "Please note that this operation may cause\n" + "temporary MIDI and Audio disruption.\n\n" + "Do you want to reset the sampler engine now?"); + #if 0 + if (QMessageBox::warning(this, sTitle, sText, + QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) + return; + #else + QMessageBox mbox(this); + mbox.setIcon(QMessageBox::Warning); + mbox.setWindowTitle(sTitle); + mbox.setText(sText); + mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + QCheckBox cbox(tr("Don't ask this again")); + cbox.setChecked(false); + cbox.blockSignals(true); + mbox.addButton(&cbox, QMessageBox::ActionRole); + if (mbox.exec() == QMessageBox::Cancel) + return; + if (cbox.isChecked()) + m_pOptions->bConfirmReset = false; + #endif + } // Trye closing the current session, first... if (!closeSession(true)) @@ -1426,22 +1537,41 @@ // Restart the client/server instance. void MainForm::fileRestart (void) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return; bool bRestart = true; // Ask user whether he/she want's a complete restart... // (if we're currently up and running) - if (bRestart && m_pClient) { - bRestart = (QMessageBox::warning(this, - QSAMPLER_TITLE ": " + tr("Warning"), - tr("New settings will be effective after\n" + if (m_pOptions && m_pOptions->bConfirmRestart) { + const QString& sTitle = tr("Warning"); + const QString& sText = tr( + "New settings will be effective after\n" "restarting the client/server connection.\n\n" "Please note that this operation may cause\n" "temporary MIDI and Audio disruption.\n\n" - "Do you want to restart the connection now?"), - QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok); + "Do you want to restart the connection now?"); + #if 0 + if (QMessageBox::warning(this, sTitle, sText, + QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) + bRestart = false; + #else + QMessageBox mbox(this); + mbox.setIcon(QMessageBox::Warning); + mbox.setWindowTitle(sTitle); + mbox.setText(sText); + mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + QCheckBox cbox(tr("Don't ask this again")); + cbox.setChecked(false); + cbox.blockSignals(true); + mbox.addButton(&cbox, QMessageBox::ActionRole); + if (mbox.exec() == QMessageBox::Cancel) + bRestart = false; + else + if (cbox.isChecked()) + m_pOptions->bConfirmRestart = false; + #endif } // Are we still for it? @@ -1463,17 +1593,24 @@ //------------------------------------------------------------------------- -// qsamplerMainForm -- Edit Action slots. +// QSampler::MainForm -- Edit Action slots. // Add a new sampler channel. void MainForm::editAddChannel (void) { - if (m_pClient == NULL) + ++m_iDirtySetup; + addChannelStrip(); + --m_iDirtySetup; +} + +void MainForm::addChannelStrip (void) +{ + if (m_pClient == nullptr) return; // Just create the channel instance... Channel *pChannel = new Channel(); - if (pChannel == NULL) + if (pChannel == nullptr) return; // Before we show it up, may be we'll @@ -1491,8 +1628,7 @@ } // Do we auto-arrange? - if (m_pOptions && m_pOptions->bAutoArrange) - channelsArrange(); + channelsArrangeAuto(); // Make that an overall update. m_iDirtyCount++; @@ -1503,28 +1639,51 @@ // Remove current sampler channel. void MainForm::editRemoveChannel (void) { - if (m_pClient == NULL) + ++m_iDirtySetup; + removeChannelStrip(); + --m_iDirtySetup; +} + +void MainForm::removeChannelStrip (void) +{ + if (m_pClient == nullptr) return; - ChannelStrip* pChannelStrip = activeChannelStrip(); - if (pChannelStrip == NULL) + ChannelStrip *pChannelStrip = activeChannelStrip(); + if (pChannelStrip == nullptr) return; Channel *pChannel = pChannelStrip->channel(); - if (pChannel == NULL) + if (pChannel == nullptr) return; // Prompt user if he/she's sure about this... if (m_pOptions && m_pOptions->bConfirmRemove) { - if (QMessageBox::warning(this, - QSAMPLER_TITLE ": " + tr("Warning"), - tr("About to remove channel:\n\n" + const QString& sTitle = tr("Warning"); + const QString& sText = tr( + "About to remove channel:\n\n" "%1\n\n" "Are you sure?") - .arg(pChannelStrip->windowTitle()), - QMessageBox::Ok | QMessageBox::Cancel) - == QMessageBox::Cancel) + .arg(pChannelStrip->windowTitle()); + #if 0 + if (QMessageBox::warning(this, sTitle, sText, + QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) + return; + #else + QMessageBox mbox(this); + mbox.setIcon(QMessageBox::Warning); + mbox.setWindowTitle(sTitle); + mbox.setText(sText); + mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + QCheckBox cbox(tr("Don't ask this again")); + cbox.setChecked(false); + cbox.blockSignals(true); + mbox.addButton(&cbox, QMessageBox::ActionRole); + if (mbox.exec() == QMessageBox::Cancel) return; + if (cbox.isChecked()) + m_pOptions->bConfirmRemove = false; + #endif } // Remove the existing sampler channel. @@ -1532,11 +1691,7 @@ return; // Just delete the channel strip. - delete pChannelStrip; - - // Do we auto-arrange? - if (m_pOptions && m_pOptions->bAutoArrange) - channelsArrange(); + destroyChannelStrip(pChannelStrip); // We'll be dirty, for sure... m_iDirtyCount++; @@ -1547,11 +1702,11 @@ // Setup current sampler channel. void MainForm::editSetupChannel (void) { - if (m_pClient == NULL) + if (m_pClient == nullptr) return; - ChannelStrip* pChannelStrip = activeChannelStrip(); - if (pChannelStrip == NULL) + ChannelStrip *pChannelStrip = activeChannelStrip(); + if (pChannelStrip == nullptr) return; // Just invoque the channel strip procedure. @@ -1562,11 +1717,11 @@ // Edit current sampler channel. void MainForm::editEditChannel (void) { - if (m_pClient == NULL) + if (m_pClient == nullptr) return; - ChannelStrip* pChannelStrip = activeChannelStrip(); - if (pChannelStrip == NULL) + ChannelStrip *pChannelStrip = activeChannelStrip(); + if (pChannelStrip == nullptr) return; // Just invoque the channel strip procedure. @@ -1577,11 +1732,11 @@ // Reset current sampler channel. void MainForm::editResetChannel (void) { - if (m_pClient == NULL) + if (m_pClient == nullptr) return; - ChannelStrip* pChannelStrip = activeChannelStrip(); - if (pChannelStrip == NULL) + ChannelStrip *pChannelStrip = activeChannelStrip(); + if (pChannelStrip == nullptr) return; // Just invoque the channel strip procedure. @@ -1592,15 +1747,17 @@ // Reset all sampler channels. void MainForm::editResetAllChannels (void) { - if (m_pClient == NULL) + if (m_pClient == nullptr) return; // Invoque the channel strip procedure, // for all channels out there... m_pWorkspace->setUpdatesEnabled(false); - QWidgetList wlist = m_pWorkspace->windowList(); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel); + const QList& wlist + = m_pWorkspace->subWindowList(); + foreach (QMdiSubWindow *pMdiSubWindow, wlist) { + ChannelStrip *pChannelStrip + = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) pChannelStrip->channelReset(); } @@ -1609,7 +1766,7 @@ //------------------------------------------------------------------------- -// qsamplerMainForm -- View Action slots. +// QSampler::MainForm -- View Action slots. // Show/hide the main program window menubar. void MainForm::viewMenubar ( bool bOn ) @@ -1659,7 +1816,7 @@ // Show/hide the MIDI instrument list-view form. void MainForm::viewInstruments (void) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return; if (m_pInstrumentListForm) { @@ -1678,7 +1835,7 @@ // Show/hide the device configurator form. void MainForm::viewDevices (void) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return; if (m_pDeviceForm) { @@ -1697,37 +1854,37 @@ // Show options dialog. void MainForm::viewOptions (void) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return; OptionsForm* pOptionsForm = new OptionsForm(this); if (pOptionsForm) { // Check out some initial nullities(tm)... - ChannelStrip* pChannelStrip = activeChannelStrip(); + ChannelStrip *pChannelStrip = activeChannelStrip(); if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip) m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString(); if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages) m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString(); // To track down deferred or immediate changes. - QString sOldServerHost = m_pOptions->sServerHost; - int iOldServerPort = m_pOptions->iServerPort; - int iOldServerTimeout = m_pOptions->iServerTimeout; - bool bOldServerStart = m_pOptions->bServerStart; - QString sOldServerCmdLine = m_pOptions->sServerCmdLine; - bool bOldMessagesLog = m_pOptions->bMessagesLog; - QString sOldMessagesLogPath = m_pOptions->sMessagesLogPath; - QString sOldDisplayFont = m_pOptions->sDisplayFont; - bool bOldDisplayEffect = m_pOptions->bDisplayEffect; - int iOldMaxVolume = m_pOptions->iMaxVolume; - QString sOldMessagesFont = m_pOptions->sMessagesFont; - bool bOldKeepOnTop = m_pOptions->bKeepOnTop; - bool bOldStdoutCapture = m_pOptions->bStdoutCapture; - int bOldMessagesLimit = m_pOptions->bMessagesLimit; - int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines; - bool bOldCompletePath = m_pOptions->bCompletePath; - bool bOldInstrumentNames = m_pOptions->bInstrumentNames; - int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles; - int iOldBaseFontSize = m_pOptions->iBaseFontSize; + const QString sOldServerHost = m_pOptions->sServerHost; + const int iOldServerPort = m_pOptions->iServerPort; + const int iOldServerTimeout = m_pOptions->iServerTimeout; + const bool bOldServerStart = m_pOptions->bServerStart; + const QString sOldServerCmdLine = m_pOptions->sServerCmdLine; + const bool bOldMessagesLog = m_pOptions->bMessagesLog; + const QString sOldMessagesLogPath = m_pOptions->sMessagesLogPath; + const QString sOldDisplayFont = m_pOptions->sDisplayFont; + const bool bOldDisplayEffect = m_pOptions->bDisplayEffect; + const int iOldMaxVolume = m_pOptions->iMaxVolume; + const QString sOldMessagesFont = m_pOptions->sMessagesFont; + const bool bOldKeepOnTop = m_pOptions->bKeepOnTop; + const bool bOldStdoutCapture = m_pOptions->bStdoutCapture; + const int bOldMessagesLimit = m_pOptions->bMessagesLimit; + const int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines; + const bool bOldCompletePath = m_pOptions->bCompletePath; + const bool bOldInstrumentNames = m_pOptions->bInstrumentNames; + const int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles; + const int iOldBaseFontSize = m_pOptions->iBaseFontSize; // Load the current setup settings. pOptionsForm->setup(m_pOptions); // Show the setup dialog... @@ -1739,7 +1896,7 @@ (!bOldKeepOnTop && m_pOptions->bKeepOnTop) || (iOldBaseFontSize != m_pOptions->iBaseFontSize)) { QMessageBox::information(this, - QSAMPLER_TITLE ": " + tr("Information"), + tr("Information"), tr("Some settings may be only effective\n" "next time you start this program.")); updateMessagesCapture(); @@ -1790,34 +1947,29 @@ //------------------------------------------------------------------------- -// qsamplerMainForm -- Channels action slots. +// QSampler::MainForm -- Channels action slots. // Arrange channel strips. void MainForm::channelsArrange (void) { // Full width vertical tiling - QWidgetList wlist = m_pWorkspace->windowList(); + const QList& wlist + = m_pWorkspace->subWindowList(); if (wlist.isEmpty()) return; m_pWorkspace->setUpdatesEnabled(false); int y = 0; - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel); - /* if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) { - // Prevent flicker... - pChannelStrip->hide(); - pChannelStrip->showNormal(); - } */ - pChannelStrip->adjustSize(); - int iWidth = m_pWorkspace->width(); - if (iWidth < pChannelStrip->width()) - iWidth = pChannelStrip->width(); - // int iHeight = pChannelStrip->height() - // + pChannelStrip->parentWidget()->baseSize().height(); - int iHeight = pChannelStrip->parentWidget()->frameGeometry().height(); - pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight); - y += iHeight; + foreach (QMdiSubWindow *pMdiSubWindow, wlist) { + pMdiSubWindow->adjustSize(); + const QRect& frameRect + = pMdiSubWindow->frameGeometry(); + int w = m_pWorkspace->width(); + if (w < frameRect.width()) + w = frameRect.width(); + const int h = frameRect.height(); + pMdiSubWindow->setGeometry(0, y, w, h); + y += h; } m_pWorkspace->setUpdatesEnabled(true); @@ -1828,20 +1980,26 @@ // Auto-arrange channel strips. void MainForm::channelsAutoArrange ( bool bOn ) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return; // Toggle the auto-arrange flag. m_pOptions->bAutoArrange = bOn; // If on, update whole workspace... - if (m_pOptions->bAutoArrange) + channelsArrangeAuto(); +} + + +void MainForm::channelsArrangeAuto (void) +{ + if (m_pOptions && m_pOptions->bAutoArrange) channelsArrange(); } //------------------------------------------------------------------------- -// qsamplerMainForm -- Help Action slots. +// QSampler::MainForm -- Help Action slots. // Show information about the Qt toolkit. void MainForm::helpAboutQt (void) @@ -1853,72 +2011,55 @@ // Show information about application program. void MainForm::helpAbout (void) { - // Stuff the about box text... - QString sText = "

\n"; - sText += "" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "
\n"; - sText += "
\n"; - sText += tr("Version") + ": " QSAMPLER_VERSION "
\n"; - sText += "" + tr("Build") + ": " __DATE__ " " __TIME__ "
\n"; + QStringList list; #ifdef CONFIG_DEBUG - sText += ""; - sText += tr("Debugging option enabled."); - sText += "
"; + list << tr("Debugging option enabled."); #endif #ifndef CONFIG_LIBGIG - sText += ""; - sText += tr("GIG (libgig) file support disabled."); - sText += "
"; + list << tr("GIG (libgig) file support disabled."); #endif #ifndef CONFIG_INSTRUMENT_NAME - sText += ""; - sText += tr("LSCP (liblscp) instrument_name support disabled."); - sText += "
"; + list << tr("LSCP (liblscp) instrument_name support disabled."); #endif #ifndef CONFIG_MUTE_SOLO - sText += ""; - sText += tr("Sampler channel Mute/Solo support disabled."); - sText += "
"; + list << tr("Sampler channel Mute/Solo support disabled."); #endif #ifndef CONFIG_AUDIO_ROUTING - sText += ""; - sText += tr("LSCP (liblscp) audio_routing support disabled."); - sText += "
"; + list << tr("LSCP (liblscp) audio_routing support disabled."); #endif #ifndef CONFIG_FXSEND - sText += ""; - sText += tr("Sampler channel Effect Sends support disabled."); - sText += "
"; + list << tr("Sampler channel Effect Sends support disabled."); #endif #ifndef CONFIG_VOLUME - sText += ""; - sText += tr("Global volume support disabled."); - sText += "
"; + list << tr("Global volume support disabled."); #endif #ifndef CONFIG_MIDI_INSTRUMENT - sText += ""; - sText += tr("MIDI instrument mapping support disabled."); - sText += "
"; + list << tr("MIDI instrument mapping support disabled."); #endif #ifndef CONFIG_EDIT_INSTRUMENT - sText += ""; - sText += tr("Instrument editing support disabled."); - sText += "
"; + list << tr("Instrument editing support disabled."); #endif #ifndef CONFIG_EVENT_CHANNEL_MIDI - sText += ""; - sText += tr("Channel MIDI event support disabled."); - sText += "
"; + list << tr("Channel MIDI event support disabled."); #endif #ifndef CONFIG_EVENT_DEVICE_MIDI - sText += ""; - sText += tr("Device MIDI event support disabled."); - sText += "
"; + list << tr("Device MIDI event support disabled."); #endif #ifndef CONFIG_MAX_VOICES - sText += ""; - sText += tr("Runtime max. voices / disk streams support disabled."); - sText += "
"; + list << tr("Runtime max. voices / disk streams support disabled."); #endif + + // Stuff the about box text... + QString sText = "

\n"; + sText += "" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "
\n"; + sText += "
\n"; + sText += tr("Version") + ": " CONFIG_BUILD_VERSION "
\n"; +// sText += "" + tr("Build") + ": " CONFIG_BUILD_DATE "
\n"; + if (!list.isEmpty()) { + sText += ""; + sText += list.join("
\n"); + sText += "
"; + } sText += "
\n"; sText += tr("Using") + ": "; sText += ::lscp_client_package(); @@ -1943,12 +2084,12 @@ sText += ""; sText += "

\n"; - QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText); + QMessageBox::about(this, tr("About"), sText); } //------------------------------------------------------------------------- -// qsamplerMainForm -- Main window stabilization. +// QSampler::MainForm -- Main window stabilization. void MainForm::stabilizeForm (void) { @@ -1956,19 +2097,20 @@ QString sSessionName = sessionName(m_sFilename); if (m_iDirtyCount > 0) sSessionName += " *"; - setWindowTitle(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName)); + setWindowTitle(sSessionName); // Update the main menu state... ChannelStrip *pChannelStrip = activeChannelStrip(); - bool bHasClient = (m_pOptions != NULL && m_pClient != NULL); - bool bHasChannel = (bHasClient && pChannelStrip != NULL); - bool bHasChannels = (bHasClient && m_pWorkspace->windowList().count() > 0); + const QList& wlist = m_pWorkspace->subWindowList(); + const bool bHasClient = (m_pOptions != nullptr && m_pClient != nullptr); + const bool bHasChannel = (bHasClient && pChannelStrip != nullptr); + const bool bHasChannels = (bHasClient && wlist.count() > 0); m_ui.fileNewAction->setEnabled(bHasClient); m_ui.fileOpenAction->setEnabled(bHasClient); m_ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0); m_ui.fileSaveAsAction->setEnabled(bHasClient); m_ui.fileResetAction->setEnabled(bHasClient); - m_ui.fileRestartAction->setEnabled(bHasClient || m_pServer == NULL); + m_ui.fileRestartAction->setEnabled(bHasClient || m_pServer == nullptr); m_ui.editAddChannelAction->setEnabled(bHasClient); m_ui.editRemoveChannelAction->setEnabled(bHasChannel); m_ui.editSetupChannelAction->setEnabled(bHasChannel); @@ -2042,7 +2184,7 @@ m_pVolumeSpinBox->setValue(iVolume); // Do it as commanded... - float fVolume = 0.01f * float(iVolume); + const float fVolume = 0.01f * float(iVolume); if (::lscp_set_volume(m_pClient, fVolume) == LSCP_OK) appendMessages(QObject::tr("Volume: %1.").arg(fVolume)); else @@ -2058,7 +2200,7 @@ // Channel change receiver slot. -void MainForm::channelStripChanged(ChannelStrip* pChannelStrip) +void MainForm::channelStripChanged ( ChannelStrip *pChannelStrip ) { // Add this strip to the changed list... if (!m_changedStrips.contains(pChannelStrip)) { @@ -2077,7 +2219,7 @@ void MainForm::updateSession (void) { #ifdef CONFIG_VOLUME - int iVolume = ::lroundf(100.0f * ::lscp_get_volume(m_pClient)); + const int iVolume = ::lroundf(100.0f * ::lscp_get_volume(m_pClient)); m_iVolumeChanging++; m_pVolumeSlider->setValue(iVolume); m_pVolumeSpinBox->setValue(iVolume); @@ -2085,7 +2227,7 @@ #endif #ifdef CONFIG_MIDI_INSTRUMENT // FIXME: Make some room for default instrument maps... - int iMaps = ::lscp_get_midi_instrument_maps(m_pClient); + const int iMaps = ::lscp_get_midi_instrument_maps(m_pClient); if (iMaps < 0) appendMessagesClient("lscp_get_midi_instrument_maps"); else if (iMaps < 1) { @@ -2099,8 +2241,7 @@ updateAllChannelStrips(false); // Do we auto-arrange? - if (m_pOptions && m_pOptions->bAutoArrange) - channelsArrange(); + channelsArrangeAuto(); // Remember to refresh devices and instruments... if (m_pInstrumentListForm) @@ -2109,10 +2250,16 @@ m_pDeviceForm->refreshDevices(); } -void MainForm::updateAllChannelStrips(bool bRemoveDeadStrips) { + +void MainForm::updateAllChannelStrips ( bool bRemoveDeadStrips ) +{ + // Skip if setting up a new channel strip... + if (m_iDirtySetup > 0) + return; + // Retrieve the current channel list. int *piChannelIDs = ::lscp_list_channels(m_pClient); - if (piChannelIDs == NULL) { + if (piChannelIDs == nullptr) { if (::lscp_client_get_errno(m_pClient)) { appendMessagesClient("lscp_list_channels"); appendMessagesError( @@ -2121,46 +2268,52 @@ } else { // Try to (re)create each channel. m_pWorkspace->setUpdatesEnabled(false); - for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) { + for (int iChannel = 0; piChannelIDs[iChannel] >= 0; ++iChannel) { // Check if theres already a channel strip for this one... if (!channelStrip(piChannelIDs[iChannel])) createChannelStrip(new Channel(piChannelIDs[iChannel])); } - // Do we auto-arrange? - if (m_pOptions && m_pOptions->bAutoArrange) - channelsArrange(); - - stabilizeForm(); - + channelsArrangeAuto(); // remove dead channel strips if (bRemoveDeadStrips) { - for (int i = 0; channelStripAt(i); ++i) { - ChannelStrip* pChannelStrip = channelStripAt(i); - bool bExists = false; - for (int j = 0; piChannelIDs[j] >= 0; ++j) { - if (!pChannelStrip->channel()) break; - if (piChannelIDs[j] == pChannelStrip->channel()->channelID()) { - // strip exists, don't touch it - bExists = true; - break; + const QList& wlist + = m_pWorkspace->subWindowList(); + foreach (QMdiSubWindow *pMdiSubWindow, wlist) { + ChannelStrip *pChannelStrip + = static_cast (pMdiSubWindow->widget()); + if (pChannelStrip) { + bool bExists = false; + for (int iChannel = 0; piChannelIDs[iChannel] >= 0; ++iChannel) { + Channel *pChannel = pChannelStrip->channel(); + if (pChannel == nullptr) + break; + if (piChannelIDs[iChannel] == pChannel->channelID()) { + // strip exists, don't touch it + bExists = true; + break; + } } + if (!bExists) + destroyChannelStrip(pChannelStrip); } - if (!bExists) destroyChannelStrip(pChannelStrip); } } m_pWorkspace->setUpdatesEnabled(true); } + + stabilizeForm(); } + // Update the recent files list and menu. void MainForm::updateRecentFiles ( const QString& sFilename ) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return; // Remove from list if already there (avoid duplicates) - int iIndex = m_pOptions->recentFiles.indexOf(sFilename); + const int iIndex = m_pOptions->recentFiles.indexOf(sFilename); if (iIndex >= 0) m_pOptions->recentFiles.removeAt(iIndex); // Put it to front... @@ -2171,7 +2324,7 @@ // Update the recent files list and menu. void MainForm::updateRecentFilesMenu (void) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return; // Time to keep the list under limits. @@ -2199,13 +2352,15 @@ void MainForm::updateInstrumentNames (void) { // Full channel list update... - QWidgetList wlist = m_pWorkspace->windowList(); + const QList& wlist + = m_pWorkspace->subWindowList(); if (wlist.isEmpty()) return; m_pWorkspace->setUpdatesEnabled(false); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip *pChannelStrip = (ChannelStrip *) wlist.at(iChannel); + foreach (QMdiSubWindow *pMdiSubWindow, wlist) { + ChannelStrip *pChannelStrip + = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) pChannelStrip->updateInstrumentName(true); } @@ -2216,25 +2371,28 @@ // Force update of the channels display font. void MainForm::updateDisplayFont (void) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return; // Check if display font is legal. if (m_pOptions->sDisplayFont.isEmpty()) return; + // Realize it. QFont font; if (!font.fromString(m_pOptions->sDisplayFont)) return; // Full channel list update... - QWidgetList wlist = m_pWorkspace->windowList(); + const QList& wlist + = m_pWorkspace->subWindowList(); if (wlist.isEmpty()) return; m_pWorkspace->setUpdatesEnabled(false); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel); + foreach (QMdiSubWindow *pMdiSubWindow, wlist) { + ChannelStrip *pChannelStrip + = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) pChannelStrip->setDisplayFont(font); } @@ -2246,13 +2404,15 @@ void MainForm::updateDisplayEffect (void) { // Full channel list update... - QWidgetList wlist = m_pWorkspace->windowList(); + const QList& wlist + = m_pWorkspace->subWindowList(); if (wlist.isEmpty()) return; m_pWorkspace->setUpdatesEnabled(false); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel); + foreach (QMdiSubWindow *pMdiSubWindow, wlist) { + ChannelStrip *pChannelStrip + = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect); } @@ -2263,7 +2423,7 @@ // Force update of the channels maximum volume setting. void MainForm::updateMaxVolume (void) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return; #ifdef CONFIG_VOLUME @@ -2274,13 +2434,15 @@ #endif // Full channel list update... - QWidgetList wlist = m_pWorkspace->windowList(); + const QList& wlist + = m_pWorkspace->subWindowList(); if (wlist.isEmpty()) return; m_pWorkspace->setUpdatesEnabled(false); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel); + foreach (QMdiSubWindow *pMdiSubWindow, wlist) { + ChannelStrip *pChannelStrip + = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume); } @@ -2289,7 +2451,7 @@ //------------------------------------------------------------------------- -// qsamplerMainForm -- Messages window form handlers. +// QSampler::MainForm -- Messages window form handlers. // Messages output methods. void MainForm::appendMessages( const QString& s ) @@ -2314,25 +2476,41 @@ m_pMessages->appendMessagesText(s); } -void MainForm::appendMessagesError( const QString& s ) +void MainForm::appendMessagesError( const QString& sText ) { if (m_pMessages) m_pMessages->show(); - appendMessagesColor(s.simplified(), "#ff0000"); + appendMessagesColor(sText.simplified(), "#ff0000"); // Make it look responsive...:) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - QMessageBox::critical(this, - QSAMPLER_TITLE ": " + tr("Error"), s, QMessageBox::Cancel); + if (m_pOptions && m_pOptions->bConfirmError) { + const QString& sTitle = tr("Error"); + #if 0 + QMessageBox::critical(this, sTitle, sText, QMessageBox::Cancel); + #else + QMessageBox mbox(this); + mbox.setIcon(QMessageBox::Critical); + mbox.setWindowTitle(sTitle); + mbox.setText(sText); + mbox.setStandardButtons(QMessageBox::Cancel); + QCheckBox cbox(tr("Don't show this again")); + cbox.setChecked(false); + cbox.blockSignals(true); + mbox.addButton(&cbox, QMessageBox::ActionRole); + if (mbox.exec() && cbox.isChecked()) + m_pOptions->bConfirmError = false; + #endif + } } // This is a special message format, just for client results. void MainForm::appendMessagesClient( const QString& s ) { - if (m_pClient == NULL) + if (m_pClient == nullptr) return; appendMessagesColor(s + QString(": %1 (errno=%2)") @@ -2347,7 +2525,7 @@ // Force update of the messages font. void MainForm::updateMessagesFont (void) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return; if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) { @@ -2361,7 +2539,7 @@ // Update messages window line limit. void MainForm::updateMessagesLimit (void) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return; if (m_pMessages) { @@ -2376,7 +2554,7 @@ // Enablement of the messages capture feature. void MainForm::updateMessagesCapture (void) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return; if (m_pMessages) @@ -2385,18 +2563,18 @@ //------------------------------------------------------------------------- -// qsamplerMainForm -- MDI channel strip management. +// QSampler::MainForm -- MDI channel strip management. // The channel strip creation executive. -ChannelStrip* MainForm::createChannelStrip ( Channel *pChannel ) +ChannelStrip *MainForm::createChannelStrip ( Channel *pChannel ) { - if (m_pClient == NULL || pChannel == NULL) - return NULL; + if (m_pClient == nullptr || pChannel == nullptr) + return nullptr; // Add a new channel itema... ChannelStrip *pChannelStrip = new ChannelStrip(); - if (pChannelStrip == NULL) - return NULL; + if (pChannelStrip == nullptr) + return nullptr; // Set some initial channel strip options... if (m_pOptions) { @@ -2404,21 +2582,25 @@ pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect); // We'll need a display font. QFont font; - if (font.fromString(m_pOptions->sDisplayFont)) + if (!m_pOptions->sDisplayFont.isEmpty() && + font.fromString(m_pOptions->sDisplayFont)) pChannelStrip->setDisplayFont(font); // Maximum allowed volume setting. pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume); } // Add it to workspace... - m_pWorkspace->addWindow(pChannelStrip, Qt::FramelessWindowHint); + QMdiSubWindow *pMdiSubWindow + = m_pWorkspace->addSubWindow(pChannelStrip, + Qt::SubWindow | Qt::FramelessWindowHint); + pMdiSubWindow->setAttribute(Qt::WA_DeleteOnClose); // Actual channel strip setup... pChannelStrip->setup(pChannel); QObject::connect(pChannelStrip, - SIGNAL(channelChanged(ChannelStrip*)), - SLOT(channelStripChanged(ChannelStrip*))); + SIGNAL(channelChanged(ChannelStrip *)), + SLOT(channelStripChanged(ChannelStrip *))); // Now we show up us to the world. pChannelStrip->show(); @@ -2430,50 +2612,66 @@ return pChannelStrip; } -void MainForm::destroyChannelStrip(ChannelStrip* pChannelStrip) { + +void MainForm::destroyChannelStrip ( ChannelStrip *pChannelStrip ) +{ + QMdiSubWindow *pMdiSubWindow + = static_cast (pChannelStrip->parentWidget()); + if (pMdiSubWindow == nullptr) + return; + // Just delete the channel strip. delete pChannelStrip; + delete pMdiSubWindow; // Do we auto-arrange? - if (m_pOptions && m_pOptions->bAutoArrange) - channelsArrange(); - - stabilizeForm(); + channelsArrangeAuto(); } + // Retrieve the active channel strip. -ChannelStrip* MainForm::activeChannelStrip (void) +ChannelStrip *MainForm::activeChannelStrip (void) { - return static_cast (m_pWorkspace->activeWindow()); + QMdiSubWindow *pMdiSubWindow = m_pWorkspace->activeSubWindow(); + if (pMdiSubWindow) + return static_cast (pMdiSubWindow->widget()); + else + return nullptr; } // Retrieve a channel strip by index. -ChannelStrip* MainForm::channelStripAt ( int iChannel ) +ChannelStrip *MainForm::channelStripAt ( int iStrip ) { - if (!m_pWorkspace) return NULL; + if (!m_pWorkspace) return nullptr; - QWidgetList wlist = m_pWorkspace->windowList(); + const QList& wlist + = m_pWorkspace->subWindowList(); if (wlist.isEmpty()) - return NULL; + return nullptr; - if (iChannel < 0 || iChannel >= wlist.size()) - return NULL; + if (iStrip < 0 || iStrip >= wlist.count()) + return nullptr; - return dynamic_cast (wlist.at(iChannel)); + QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip); + if (pMdiSubWindow) + return static_cast (pMdiSubWindow->widget()); + else + return nullptr; } // Retrieve a channel strip by sampler channel id. -ChannelStrip* MainForm::channelStrip ( int iChannelID ) +ChannelStrip *MainForm::channelStrip ( int iChannelID ) { - QWidgetList wlist = m_pWorkspace->windowList(); + const QList& wlist + = m_pWorkspace->subWindowList(); if (wlist.isEmpty()) - return NULL; + return nullptr; - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip - = static_cast (wlist.at(iChannel)); + foreach (QMdiSubWindow *pMdiSubWindow, wlist) { + ChannelStrip *pChannelStrip + = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) { Channel *pChannel = pChannelStrip->channel(); if (pChannel && pChannel->channelID() == iChannelID) @@ -2482,7 +2680,7 @@ } // Not found. - return NULL; + return nullptr; } @@ -2493,20 +2691,23 @@ m_ui.channelsMenu->addAction(m_ui.channelsArrangeAction); m_ui.channelsMenu->addAction(m_ui.channelsAutoArrangeAction); - QWidgetList wlist = m_pWorkspace->windowList(); + const QList& wlist + = m_pWorkspace->subWindowList(); if (!wlist.isEmpty()) { m_ui.channelsMenu->addSeparator(); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip - = static_cast (wlist.at(iChannel)); + int iStrip = 0; + foreach (QMdiSubWindow *pMdiSubWindow, wlist) { + ChannelStrip *pChannelStrip + = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) { QAction *pAction = m_ui.channelsMenu->addAction( pChannelStrip->windowTitle(), this, SLOT(channelsMenuActivated())); pAction->setCheckable(true); pAction->setChecked(activeChannelStrip() == pChannelStrip); - pAction->setData(iChannel); + pAction->setData(iStrip); } + ++iStrip; } } } @@ -2517,10 +2718,10 @@ { // Retrive channel index from action data... QAction *pAction = qobject_cast (sender()); - if (pAction == NULL) + if (pAction == nullptr) return; - ChannelStrip* pChannelStrip = channelStripAt(pAction->data().toInt()); + ChannelStrip *pChannelStrip = channelStripAt(pAction->data().toInt()); if (pChannelStrip) { pChannelStrip->showNormal(); pChannelStrip->setFocus(); @@ -2529,7 +2730,7 @@ //------------------------------------------------------------------------- -// qsamplerMainForm -- Timer stuff. +// QSampler::MainForm -- Timer stuff. // Set the pseudo-timer delay schedule. void MainForm::startSchedule ( int iStartDelay ) @@ -2548,7 +2749,7 @@ // Timer slot funtion. void MainForm::timerSlot (void) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return; // Is it the first shot on server start after a few delay? @@ -2570,7 +2771,7 @@ ChannelStrip *pChannelStrip = iter.next(); // If successfull, remove from pending list... if (pChannelStrip->updateChannelInfo()) { - int iChannelStrip = m_changedStrips.indexOf(pChannelStrip); + const int iChannelStrip = m_changedStrips.indexOf(pChannelStrip); if (iChannelStrip >= 0) m_changedStrips.removeAt(iChannelStrip); } @@ -2581,11 +2782,11 @@ if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime) { m_iTimerSlot = 0; // Update the channel stream usage for each strip... - QWidgetList wlist = m_pWorkspace->windowList(); - for (int iChannel = 0; - iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip - = (ChannelStrip*) wlist.at(iChannel); + const QList& wlist + = m_pWorkspace->subWindowList(); + foreach (QMdiSubWindow *pMdiSubWindow, wlist) { + ChannelStrip *pChannelStrip + = static_cast (pMdiSubWindow->widget()); if (pChannelStrip && pChannelStrip->isVisible()) pChannelStrip->updateChannelUsage(); } @@ -2599,12 +2800,12 @@ //------------------------------------------------------------------------- -// qsamplerMainForm -- Server stuff. +// QSampler::MainForm -- Server stuff. // Start linuxsampler server... void MainForm::startServer (void) { - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return; // Aren't already a client, are we? @@ -2614,7 +2815,7 @@ // Is the server process instance still here? if (m_pServer) { if (QMessageBox::warning(this, - QSAMPLER_TITLE ": " + tr("Warning"), + tr("Warning"), tr("Could not start the LinuxSampler server.\n\n" "Maybe it is already started."), QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { @@ -2633,20 +2834,16 @@ // OK. Let's build the startup process... m_pServer = new QProcess(); - bForceServerStop = true; + m_bForceServerStop = true; // Setup stdout/stderr capture... -// if (m_pOptions->bStdoutCapture) { -#if QT_VERSION >= 0x040200 - m_pServer->setProcessChannelMode(QProcess::ForwardedChannels); -#endif - QObject::connect(m_pServer, - SIGNAL(readyReadStandardOutput()), - SLOT(readServerStdout())); - QObject::connect(m_pServer, - SIGNAL(readyReadStandardError()), - SLOT(readServerStdout())); -// } + m_pServer->setProcessChannelMode(QProcess::ForwardedChannels); + QObject::connect(m_pServer, + SIGNAL(readyReadStandardOutput()), + SLOT(readServerStdout())); + QObject::connect(m_pServer, + SIGNAL(readyReadStandardError()), + SLOT(readServerStdout())); // The unforgiveable signal communication... QObject::connect(m_pServer, @@ -2681,45 +2878,51 @@ // Stop linuxsampler server... -void MainForm::stopServer (bool bInteractive) +void MainForm::stopServer ( bool bInteractive ) { // Stop client code. stopClient(); if (m_pServer && bInteractive) { if (QMessageBox::question(this, - QSAMPLER_TITLE ": " + tr("The backend's fate ..."), + tr("The backend's fate ..."), tr("You have the option to keep the sampler backend (LinuxSampler)\n" "running in the background. The sampler would continue to work\n" "according to your current sampler session and you could alter the\n" "sampler session at any time by relaunching QSampler.\n\n" "Do you want LinuxSampler to stop?"), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) - { - bForceServerStop = false; + QMessageBox::Yes | QMessageBox::No, + QMessageBox::Yes) == QMessageBox::No) { + m_bForceServerStop = false; } } + bool bGraceWait = true; + // And try to stop server. - if (m_pServer && bForceServerStop) { + if (m_pServer && m_bForceServerStop) { appendMessages(tr("Server is stopping...")); if (m_pServer->state() == QProcess::Running) { -#if defined(WIN32) + #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) // Try harder... m_pServer->kill(); -#else + #else // Try softly... m_pServer->terminate(); -#endif + bool bFinished = m_pServer->waitForFinished(QSAMPLER_TIMER_MSECS * 1000); + if (bFinished) bGraceWait = false; + #endif } } // Do final processing anyway. else processServerExit(); // Give it some time to terminate gracefully and stabilize... - QTime t; - t.start(); - while (t.elapsed() < QSAMPLER_TIMER_MSECS) - QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + if (bGraceWait) { + QTime t; + t.start(); + while (t.elapsed() < QSAMPLER_TIMER_MSECS) + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + } } @@ -2741,7 +2944,7 @@ if (m_pMessages) m_pMessages->flushStdoutBuffer(); - if (m_pServer && bForceServerStop) { + if (m_pServer && m_bForceServerStop) { if (m_pServer->state() != QProcess::NotRunning) { appendMessages(tr("Server is being forced...")); // Force final server shutdown... @@ -2757,7 +2960,7 @@ tr("Server was stopped with exit status %1.") .arg(m_pServer->exitStatus())); delete m_pServer; - m_pServer = NULL; + m_pServer = nullptr; } // Again, make status visible stable. @@ -2766,14 +2969,14 @@ //------------------------------------------------------------------------- -// qsamplerMainForm -- Client stuff. +// QSampler::MainForm -- Client stuff. // The LSCP client callback procedure. lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, lscp_event_t event, const char *pchData, int cchData, void *pvData ) { MainForm* pMainForm = (MainForm *) pvData; - if (pMainForm == NULL) + if (pMainForm == nullptr) return LSCP_FAILED; // ATTN: DO NOT EVER call any GUI code here, @@ -2790,7 +2993,7 @@ bool MainForm::startClient (void) { // Have it a setup? - if (m_pOptions == NULL) + if (m_pOptions == nullptr) return false; // Aren't we already started, are we? @@ -2804,7 +3007,7 @@ m_pClient = ::lscp_client_create( m_pOptions->sServerHost.toUtf8().constData(), m_pOptions->iServerPort, qsampler_client_callback, this); - if (m_pClient == NULL) { + if (m_pClient == nullptr) { // Is this the first try? // maybe we need to start a local server... if ((m_pServer && m_pServer->state() == QProcess::Running) @@ -2818,6 +3021,7 @@ stabilizeForm(); return false; } + // Just set receive timeout value, blindly. ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout); appendMessages( @@ -2873,7 +3077,7 @@ if (!m_pOptions->sSessionFile.isEmpty()) { // Just load the prabably startup session... if (loadSessionFile(m_pOptions->sSessionFile)) { - m_pOptions->sSessionFile = QString::null; + m_pOptions->sSessionFile = QString(); return true; } } @@ -2889,7 +3093,7 @@ // Stop client... void MainForm::stopClient (void) { - if (m_pClient == NULL) + if (m_pClient == nullptr) return; // Log prepare here. @@ -2921,7 +3125,7 @@ ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO); ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT); ::lscp_client_destroy(m_pClient); - m_pClient = NULL; + m_pClient = nullptr; // Hard-notify instrumnet and device configuration forms, // if visible, that we're running out... @@ -2939,10 +3143,11 @@ // Channel strip activation/selection. -void MainForm::activateStrip ( QWidget *pWidget ) +void MainForm::activateStrip ( QMdiSubWindow *pMdiSubWindow ) { - ChannelStrip *pChannelStrip - = static_cast (pWidget); + ChannelStrip *pChannelStrip = nullptr; + if (pMdiSubWindow) + pChannelStrip = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) pChannelStrip->setSelected(true); @@ -2950,6 +3155,30 @@ } +// Channel toolbar orientation change. +void MainForm::channelsToolbarOrientation ( Qt::Orientation orientation ) +{ +#ifdef CONFIG_VOLUME + m_pVolumeSlider->setOrientation(orientation); + if (orientation == Qt::Horizontal) { + m_pVolumeSlider->setMinimumHeight(24); + m_pVolumeSlider->setMaximumHeight(32); + m_pVolumeSlider->setMinimumWidth(120); + m_pVolumeSlider->setMaximumWidth(640); + m_pVolumeSpinBox->setMaximumWidth(64); + m_pVolumeSpinBox->setButtonSymbols(QSpinBox::UpDownArrows); + } else { + m_pVolumeSlider->setMinimumHeight(120); + m_pVolumeSlider->setMaximumHeight(480); + m_pVolumeSlider->setMinimumWidth(24); + m_pVolumeSlider->setMaximumWidth(32); + m_pVolumeSpinBox->setMaximumWidth(32); + m_pVolumeSpinBox->setButtonSymbols(QSpinBox::NoButtons); + } +#endif +} + + } // namespace QSampler