diff --git a/CMakeLists.txt b/CMakeLists.txt index 303f47ab0acb..57ae4e1703d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -852,6 +852,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/waveform/widgets/rgbwaveformwidget.cpp src/waveform/widgets/softwarewaveformwidget.cpp src/waveform/widgets/waveformwidgetabstract.cpp + src/waveform/widgets/waveformwidgettype.cpp src/widget/controlwidgetconnection.cpp src/widget/hexspinbox.cpp src/widget/paintable.cpp diff --git a/res/skins/Deere (64 Samplers)/skin.xml b/res/skins/Deere (64 Samplers)/skin.xml index 41e4c8e9e04c..4b9aa89a9f22 100644 --- a/res/skins/Deere (64 Samplers)/skin.xml +++ b/res/skins/Deere (64 Samplers)/skin.xml @@ -18,7 +18,7 @@ 1 1 1 - 1 + 0 1 1 1 diff --git a/res/skins/Deere/skin.xml b/res/skins/Deere/skin.xml index a03d2764507a..219d8b24affc 100644 --- a/res/skins/Deere/skin.xml +++ b/res/skins/Deere/skin.xml @@ -18,7 +18,7 @@ 1 1 1 - 1 + 0 1 1 1 diff --git a/res/skins/LateNight/skin.xml b/res/skins/LateNight/skin.xml index a668ad00ccc6..e842ca687cf7 100644 --- a/res/skins/LateNight/skin.xml +++ b/res/skins/LateNight/skin.xml @@ -49,7 +49,7 @@ 1 1 1 - 1 + 0 1 0 diff --git a/res/skins/Shade/skin.xml b/res/skins/Shade/skin.xml index 3bf5c1179055..3bdc5d012ef1 100644 --- a/res/skins/Shade/skin.xml +++ b/res/skins/Shade/skin.xml @@ -62,8 +62,8 @@ 8 1 - 1 - 1 + 0 + 0 0 0 0 diff --git a/res/skins/Tango (64 Samplers)/skin.xml b/res/skins/Tango (64 Samplers)/skin.xml index 120f3f5a7987..125937124dc5 100644 --- a/res/skins/Tango (64 Samplers)/skin.xml +++ b/res/skins/Tango (64 Samplers)/skin.xml @@ -49,7 +49,7 @@ 1 1 1 - 1 + 0 1 0 0 diff --git a/res/skins/Tango/skin.xml b/res/skins/Tango/skin.xml index 6d6eba0b6adb..4a14ee9d8cb7 100644 --- a/res/skins/Tango/skin.xml +++ b/res/skins/Tango/skin.xml @@ -49,7 +49,7 @@ 1 1 1 - 1 + 0 1 0 0 diff --git a/src/mixxx.cpp b/src/mixxx.cpp index 3f3a4bfa07a7..23e40984d4a9 100644 --- a/src/mixxx.cpp +++ b/src/mixxx.cpp @@ -1559,8 +1559,11 @@ void MixxxMainWindow::checkDirectRendering() { UserSettingsPointer pConfig = m_pSettingsManager->settings(); - if (!factory->isOpenGlAvailable() && !factory->isOpenGlesAvailable() && - pConfig->getValueString(ConfigKey("[Direct Rendering]", "Warned")) != QString("yes")) { + bool openGlEnabled = pConfig->getValue(ConfigKey("[Waveform]", "OpenGlEnabled"), + WaveformWidgetFactory::defaultOpenGlEnabled); + + if (openGlEnabled && !factory->isOpenGlAvailable() && !factory->isOpenGlesAvailable() && + pConfig->getValueString(ConfigKey("[Direct Rendering]", "Warned")) != QString("yes")) { QMessageBox::warning( 0, tr("OpenGL Direct Rendering"), tr("Direct rendering is not enabled on your machine.

" diff --git a/src/preferences/dialog/dlgprefwaveform.cpp b/src/preferences/dialog/dlgprefwaveform.cpp index 2c79c91f24c6..cace6a520b9d 100644 --- a/src/preferences/dialog/dlgprefwaveform.cpp +++ b/src/preferences/dialog/dlgprefwaveform.cpp @@ -21,14 +21,18 @@ DlgPrefWaveform::DlgPrefWaveform(QWidget* pParent, MixxxMainWindow* pMixxx, waveformOverviewComboBox->addItem(tr("HSV")); // "1" waveformOverviewComboBox->addItem(tr("RGB")); // "2" - // Populate waveform options. WaveformWidgetFactory* factory = WaveformWidgetFactory::instance(); - QVector handles = factory->getAvailableTypes(); - for (int i = 0; i < handles.size(); ++i) { - waveformTypeComboBox->addItem(handles[i].getDisplayName(), - handles[i].getType()); + if (factory->isOpenGlAvailable() || factory->isOpenGlesAvailable()) { + openGlStatusIcon->setText(factory->getOpenGLVersion()); + } else { + openGlStatusIcon->setText(tr("OpenGL not available") + ": " + factory->getOpenGLVersion()); } + connect(openGLEnabledCheckBox, + &QCheckBox::stateChanged, + this, + &DlgPrefWaveform::openGlEnabledChanged); + // Populate zoom options. for (int i = static_cast(WaveformWidgetRenderer::s_waveformMinZoom); i <= static_cast(WaveformWidgetRenderer::s_waveformMaxZoom); @@ -136,19 +140,19 @@ DlgPrefWaveform::~DlgPrefWaveform() { } void DlgPrefWaveform::slotUpdate() { - WaveformWidgetFactory* factory = WaveformWidgetFactory::instance(); + m_openGlEnabled = m_pConfig->getValue(ConfigKey("[Waveform]", "OpenGlEnabled"), + WaveformWidgetFactory::defaultOpenGlEnabled); + openGLEnabledCheckBox->setChecked(m_openGlEnabled); - if (factory->isOpenGlAvailable() || factory->isOpenGlesAvailable()) { - openGlStatusIcon->setText(factory->getOpenGLVersion()); - } else { - openGlStatusIcon->setText(tr("OpenGL not available") + ": " + factory->getOpenGLVersion()); - } + populateWaveformTypeCombobox(); - WaveformWidgetType::Type currentType = factory->getType(); - int currentIndex = waveformTypeComboBox->findData(currentType); - if (currentIndex != -1 && waveformTypeComboBox->currentIndex() != currentIndex) { - waveformTypeComboBox->setCurrentIndex(currentIndex); - } + WaveformWidgetFactory* factory = WaveformWidgetFactory::instance(); + + auto waveType = static_cast( + m_pConfig->getValue(ConfigKey("[Waveform]", "WaveformType"), + static_cast(factory->chooseWidgetType(m_openGlEnabled)))); + waveformTypeComboBox->setCurrentIndex( + waveformTypeComboBox->findData(waveType)); frameRateSpinBox->setValue(factory->getFrameRate()); frameRateSlider->setValue(factory->getFrameRate()); @@ -194,18 +198,25 @@ void DlgPrefWaveform::slotApply() { waveformSettings.setWaveformCachingEnabled(enableWaveformCaching->isChecked()); waveformSettings.setWaveformGenerationWithAnalysisEnabled( enableWaveformGenerationWithAnalysis->isChecked()); -} -void DlgPrefWaveform::slotResetToDefaults() { - WaveformWidgetFactory* factory = WaveformWidgetFactory::instance(); + bool openGlWasEnabled = m_pConfig->getValue(ConfigKey("[Waveform]", "OpenGlEnabled"), + WaveformWidgetFactory::defaultOpenGlEnabled); - // Get the default we ought to use based on whether the user has OpenGL or - // not. - WaveformWidgetType::Type defaultType = factory->autoChooseWidgetType(); - int defaultIndex = waveformTypeComboBox->findData(defaultType); - if (defaultIndex != -1 && waveformTypeComboBox->currentIndex() != defaultIndex) { - waveformTypeComboBox->setCurrentIndex(defaultIndex); + if (m_openGlEnabled != openGlWasEnabled) { + m_pConfig->setValue(ConfigKey("[Waveform]", "OpenGlEnabled"), m_openGlEnabled); +#ifdef __APPLE__ + QMessageBox::information(this, + tr("Information"), + tr("Mixxx must be restarted to %1 OpenGL.") + .arg(m_openGlEnabled ? tr("enable") : tr("disable"))); +#else + m_pMixxx->rebootMixxxView(); +#endif } +} + +void DlgPrefWaveform::slotResetToDefaults() { + openGLEnabledCheckBox->setChecked(WaveformWidgetFactory::defaultOpenGlEnabled); allVisualGain->setValue(1.0); lowVisualGain->setValue(1.0); @@ -239,6 +250,35 @@ void DlgPrefWaveform::slotResetToDefaults() { playMarkerPositionSlider->setValue(50); } +void DlgPrefWaveform::openGlEnabledChanged(bool checked) { + m_openGlEnabled = checked; + populateWaveformTypeCombobox(); + pickDefaultWaveformType(); +} + +void DlgPrefWaveform::populateWaveformTypeCombobox() { + waveformTypeComboBox->blockSignals(true); + waveformTypeComboBox->clear(); + + WaveformWidgetFactory* factory = WaveformWidgetFactory::instance(); + QVector handles = factory->getAvailableTypes(m_openGlEnabled); + for (int i = 0; i < handles.size(); ++i) { + waveformTypeComboBox->addItem(handles[i].getDisplayName(), + handles[i].getType()); + } + + waveformTypeComboBox->blockSignals(false); +} + +void DlgPrefWaveform::pickDefaultWaveformType() { + WaveformWidgetFactory* factory = WaveformWidgetFactory::instance(); + WaveformWidgetType::Type defaultType = factory->chooseWidgetType(m_openGlEnabled); + int defaultIndex = waveformTypeComboBox->findData(defaultType); + if (defaultIndex != -1 && waveformTypeComboBox->currentIndex() != defaultIndex) { + waveformTypeComboBox->setCurrentIndex(defaultIndex); + } +} + void DlgPrefWaveform::notifyRebootNecessary() { // make the fact that you have to restart mixxx more obvious QMessageBox::information( @@ -253,19 +293,27 @@ void DlgPrefWaveform::slotSetWaveformEndRender(int endTime) { WaveformWidgetFactory::instance()->setEndOfTrackWarningTime(endTime); } -void DlgPrefWaveform::slotSetWaveformType(int index) { - // Ignore sets for -1 since this happens when we clear the combobox. - if (index < 0) { +void DlgPrefWaveform::slotSetWaveformType(int comboboxIndex) { + Q_UNUSED(comboboxIndex); + + auto waveType = static_cast( + waveformTypeComboBox->currentData().toInt()); + + bool openGlWasEnabled = m_pConfig->getValue(ConfigKey("[Waveform]", "OpenGlEnabled"), + WaveformWidgetFactory::defaultOpenGlEnabled); + if (m_openGlEnabled != openGlWasEnabled) { + m_pConfig->setValue(ConfigKey("[Waveform]", "WaveformType"), static_cast(waveType)); return; } - WaveformWidgetFactory::instance()->setWidgetTypeFromHandle(index); + + WaveformWidgetFactory::instance()->setWidgetType(waveType); #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) && defined __WINDOWS__ // This regenerates the waveforms twice because of a bug found on Windows // where the first one fails. // The problem is that the window of the widget thinks that it is not exposed. // (https://doc.qt.io/qt-5/qwindow.html#exposeEvent ) // TODO: Remove this when it has been fixed upstream. - WaveformWidgetFactory::instance()->setWidgetTypeFromHandle(index, true); + WaveformWidgetFactory::instance()->reloadWaveforms(); #endif } diff --git a/src/preferences/dialog/dlgprefwaveform.h b/src/preferences/dialog/dlgprefwaveform.h index 339038d07ad0..c4a79eb9bba4 100644 --- a/src/preferences/dialog/dlgprefwaveform.h +++ b/src/preferences/dialog/dlgprefwaveform.h @@ -24,8 +24,9 @@ class DlgPrefWaveform : public DlgPreferencePage, public Ui::DlgPrefWaveformDlg void slotSetWaveformEndRender(int endTime); private slots: + void openGlEnabledChanged(bool checked); void slotSetFrameRate(int frameRate); - void slotSetWaveformType(int index); + void slotSetWaveformType(int comboboxIndex); void slotSetWaveformOverviewType(int index); void slotSetDefaultZoom(int index); void slotSetZoomSynchronization(bool checked); @@ -40,10 +41,14 @@ class DlgPrefWaveform : public DlgPreferencePage, public Ui::DlgPrefWaveformDlg void slotSetPlayMarkerPosition(int position); private: + void populateWaveformTypeCombobox(); + void pickDefaultWaveformType(); void initWaveformControl(); void calculateCachedWaveformDiskUsage(); void notifyRebootNecessary(); + bool m_openGlEnabled; + UserSettingsPointer m_pConfig; Library* m_pLibrary; MixxxMainWindow* m_pMixxx; diff --git a/src/preferences/dialog/dlgprefwaveformdlg.ui b/src/preferences/dialog/dlgprefwaveformdlg.ui index 8c9a08bba65f..99615c56e450 100644 --- a/src/preferences/dialog/dlgprefwaveformdlg.ui +++ b/src/preferences/dialog/dlgprefwaveformdlg.ui @@ -6,8 +6,8 @@ 0 0 - 677 - 528 + 723 + 625 @@ -16,156 +16,33 @@ - - - - Visual gain - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - allVisualGain - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - 0 - - - 60 - - - 30 - - - Qt::Horizontal - - - - - - - Normalize waveform overview - - - - - - - Displays which OpenGL version is supported by the current platform. - - - - - - - - - - Highlight the waveforms when the last seconds of a track remains. - - - seconds - - - 0 - - - 60 - - - 30 - - - - - + + - Average frame rate + OpenGL Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - Frame rate - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + 100 - - frameRateSlider + + 90 - - - - - - - - Qt::Horizontal - - - - - - - OpenGL status - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - - - Waveform type - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - waveformTypeComboBox - - - - + @@ -297,7 +174,23 @@ - + + + + + + + 6 + + + Beat grid opacity + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + The waveform overview shows the waveform envelope of the entire track. @@ -305,48 +198,55 @@ Select from different types of displays for the waveform overview, which differ - - - - The waveform shows the waveform envelope of the track near the current playback position. -Select from different types of displays for the waveform, which differ primarily in the level of detail shown in the waveform. + + + + Play marker position - - - - - + + - Waveform overview type + Caching + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + - Displays the actual frame rate. + Moves the play marker position on the waveforms to the left, right or center (default). - - + + 0 - - - - - - End of track warning + + 100 - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + 50 - - endOfTrackWarningTimeSlider + + Qt::Horizontal - + @@ -374,16 +274,35 @@ Select from different types of displays for the waveform, which differ primarily - - - - + + + + Frame rate - - fps + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + frameRateSlider + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + - 10 + 0 60 @@ -391,9 +310,12 @@ Select from different types of displays for the waveform, which differ primarily 30 + + Qt::Horizontal + - + Default zoom level @@ -406,27 +328,141 @@ Select from different types of displays for the waveform, which differ primarily - - + + - Synchronize zoom level across all waveform displays. + - Synchronize zoom level across all waveforms + Average frame rate + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - + + + + + 0 + 0 + + + + + - Caching + Waveform type - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + waveformTypeComboBox + + + + + + + Qt::Horizontal - + + + + + + + Waveform overview type + + + + + + + End of track warning + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + endOfTrackWarningTimeSlider + + + + + + + + + + fps + + + 10 + + + 60 + + + 30 + + + + + + + Set amount of opacity on beat grid lines. + + + % + + + 100 + + + 90 + + + + + + + Normalize waveform overview + + + + + + + The waveform shows the waveform envelope of the track near the current playback position. +Select from different types of displays for the waveform, which differ primarily in the level of detail shown in the waveform. + + + + + + + Highlight the waveforms when the last seconds of a track remains. + + + seconds + + + 0 + + + 60 + + + 30 + + + + @@ -471,86 +507,53 @@ Select from different types of displays for the waveform, which differ primarily - - + + - - - - 6 + Synchronize zoom level across all waveform displays. - Beat grid opacity - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + Synchronize zoom level across all waveforms - - - - 100 + + + + + + + Visual gain - - 90 + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - Qt::Horizontal + + allVisualGain - - - - Set amount of opacity on beat grid lines. - - - % - - - 100 - - - 90 + + + + Enabled - - - - Play marker position - - - - - + + - Moves the play marker position on the waveforms to the left, right or center (default). - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - 0 - - - 100 + Displays which OpenGL version is supported by the current platform. - - 50 + + - - Qt::Horizontal + + + + + + diff --git a/src/skin/legacyskinparser.cpp b/src/skin/legacyskinparser.cpp index 011882bbd467..52e361e46f04 100644 --- a/src/skin/legacyskinparser.cpp +++ b/src/skin/legacyskinparser.cpp @@ -504,7 +504,7 @@ QList LegacySkinParser::parseNode(const QDomElement& node) { result.append(pOuterWidget); } } else if (nodeName == "SliderComposed") { - result = wrapWidget(parseStandardWidget(node)); + result = wrapWidget(parseRenderTimedWidget(node)); } else if (nodeName == "PushButton") { result = wrapWidget(parseStandardWidget(node)); } else if (nodeName == "EffectPushButton") { @@ -545,9 +545,9 @@ QList LegacySkinParser::parseNode(const QDomElement& node) { } else if (nodeName == "Label") { result = wrapWidget(parseLabelWidget(node)); } else if (nodeName == "Knob") { - result = wrapWidget(parseStandardWidget(node)); + result = wrapWidget(parseRenderTimedWidget(node)); } else if (nodeName == "KnobComposed") { - result = wrapWidget(parseStandardWidget(node)); + result = wrapWidget(parseRenderTimedWidget(node)); } else if (nodeName == "TableView") { result = wrapWidget(parseTableView(node)); } else if (nodeName == "CoverArt") { @@ -875,6 +875,20 @@ T* LegacySkinParser::parseStandardWidget(const QDomElement& element) { return pWidget; } +template +T* LegacySkinParser::parseRenderTimedWidget(const QDomElement& element) { + bool openGlEnabled = m_pConfig->getValue( + ConfigKey("[Waveform]", "OpenGlEnabled"), WaveformWidgetFactory::defaultOpenGlEnabled); + T* pWidget = new T(m_pParent, openGlEnabled); + commonWidgetSetup(element, pWidget); + pWidget->setup(element, *m_pContext); + pWidget->installEventFilter(m_pKeyboard); + pWidget->installEventFilter( + m_pControllerManager->getControllerLearningEventFilter()); + pWidget->Init(); + return pWidget; +} + template QWidget* LegacySkinParser::parseLabelWidget(const QDomElement& element) { T* pLabel = new T(m_pParent); @@ -1204,11 +1218,16 @@ QWidget* LegacySkinParser::parseSpinny(const QDomElement& node) { auto waveformWidgetFactory = WaveformWidgetFactory::instance(); - if (!waveformWidgetFactory->isOpenGlAvailable() && - !waveformWidgetFactory->isOpenGlesAvailable()) { + bool openGlEnabled = m_pConfig->getValue(ConfigKey("[Waveform]", "OpenGlEnabled"), + WaveformWidgetFactory::defaultOpenGlEnabled); + + if (!openGlEnabled || + (!waveformWidgetFactory->isOpenGlAvailable() && + !waveformWidgetFactory->isOpenGlesAvailable())) { WLabel* dummy = new WLabel(m_pParent); //: Shown when Spinny can not be displayed. Please keep \n unchanged - dummy->setText(tr("No OpenGL\nsupport.")); + dummy->setText(tr("OpenGL\ndisabled")); + commonWidgetSetup(node, dummy); return dummy; } diff --git a/src/skin/legacyskinparser.h b/src/skin/legacyskinparser.h index 546ebea840b3..5cebe4e6e36d 100644 --- a/src/skin/legacyskinparser.h +++ b/src/skin/legacyskinparser.h @@ -72,6 +72,9 @@ class LegacySkinParser : public QObject, public SkinParser { template T* parseStandardWidget(const QDomElement& element); + template + T* parseRenderTimedWidget(const QDomElement& element); + // Label widgets. template QWidget* parseLabelWidget(const QDomElement& element); diff --git a/src/util/widgetrendertimer.cpp b/src/util/widgetrendertimer.cpp index 7f8e81f78fb8..579d71ee4889 100644 --- a/src/util/widgetrendertimer.cpp +++ b/src/util/widgetrendertimer.cpp @@ -3,9 +3,11 @@ #include "util/time.h" WidgetRenderTimer::WidgetRenderTimer(mixxx::Duration renderFrequency, - mixxx::Duration inactivityTimeout) + mixxx::Duration inactivityTimeout, + bool openGlEnabled) : m_renderFrequency(renderFrequency), m_inactivityTimeout(inactivityTimeout), + m_openGlEnabled(openGlEnabled), m_guiTickTimer(this) { connect(&m_guiTickTimer, &GuiTickTimer::timeout, this, &WidgetRenderTimer::guiTick); } @@ -22,8 +24,16 @@ void WidgetRenderTimer::guiTick() { } void WidgetRenderTimer::activity() { - m_lastActivity = mixxx::Time::elapsed(); - if (!m_guiTickTimer.isActive()) { - m_guiTickTimer.start(m_renderFrequency); +#ifdef __APPLE__ + if (m_openGlEnabled) { + m_lastActivity = mixxx::Time::elapsed(); + if (!m_guiTickTimer.isActive()) { + m_guiTickTimer.start(m_renderFrequency); + } + } else { + emit update(); } +#else + emit update(); +#endif } diff --git a/src/util/widgetrendertimer.h b/src/util/widgetrendertimer.h index 25fc2f3cc8ae..ce7886185fb2 100644 --- a/src/util/widgetrendertimer.h +++ b/src/util/widgetrendertimer.h @@ -30,7 +30,8 @@ class WidgetRenderTimer : public QObject { Q_OBJECT public: WidgetRenderTimer(mixxx::Duration renderFrequency, - mixxx::Duration inactivityTimeout); + mixxx::Duration inactivityTimeout, + bool openGlEnabled); // Call this method whenever the widget's state has changed such that a // re-render is necessary. @@ -49,6 +50,7 @@ class WidgetRenderTimer : public QObject { private: const mixxx::Duration m_renderFrequency; const mixxx::Duration m_inactivityTimeout; + bool m_openGlEnabled; GuiTickTimer m_guiTickTimer; mixxx::Duration m_lastActivity; mixxx::Duration m_lastRender; diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 17988e5856b8..95b8adea5791 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -94,12 +94,22 @@ WaveformWidgetHolder::WaveformWidgetHolder(WaveformWidgetAbstract* waveformWidge /////////////////////////////////////////// +// The deprecated QGLWidget API is not working well with modern Macs, +// but these machines generally have good enough CPUs that software rendering +// works okay enough. +// https://bugs.launchpad.net/mixxx/+bug/1906287 +// TODO: enable OpenGL by default on macOS when switching to QOpenGLWidget +#if defined(__APPLE__) +const bool WaveformWidgetFactory::defaultOpenGlEnabled = false; +#else +const bool WaveformWidgetFactory::defaultOpenGlEnabled = true; +#endif + WaveformWidgetFactory::WaveformWidgetFactory() // Set an empty waveform initially. We will set the correct one when skin load finishes. // Concretely, we want to set a non-GL waveform when loading the skin so that the window // loads correctly. : m_type(WaveformWidgetType::EmptyWaveform), - m_configType(WaveformWidgetType::EmptyWaveform), m_config(0), m_skipRender(false), m_frameRate(30), @@ -280,12 +290,14 @@ bool WaveformWidgetFactory::setConfig(UserSettingsPointer config) { return false; } + m_openGlEnabled = m_config->getValue( + ConfigKey("[Waveform]", "OpenGlEnabled"), defaultOpenGlEnabled); + bool ok = false; int frameRate = m_config->getValue(ConfigKey("[Waveform]","FrameRate"), m_frameRate); m_frameRate = math_clamp(frameRate, 1, 120); - int endTime = m_config->getValueString(ConfigKey("[Waveform]","EndOfTrackWarningTime")).toInt(&ok); if (ok) { setEndOfTrackWarningTime(endTime); @@ -309,13 +321,13 @@ bool WaveformWidgetFactory::setConfig(UserSettingsPointer config) { int beatGridAlpha = m_config->getValue(ConfigKey("[Waveform]", "beatGridAlpha"), m_beatGridAlpha); setDisplayBeatGridAlpha(beatGridAlpha); - WaveformWidgetType::Type type = static_cast( - m_config->getValueString(ConfigKey("[Waveform]","WaveformType")).toInt(&ok)); - // Store the widget type on m_configType for later initialization. - // We will initialize the objects later because of a problem with GL on QT 5.14.2 on Windows - if (!ok || !setWidgetType(type, &m_configType)) { - setWidgetType(autoChooseWidgetType(), &m_configType); + auto waveType = static_cast( + config->getValue(ConfigKey("[Waveform]", "WaveformType"), + static_cast(chooseWidgetType(m_openGlEnabled)))); + if (!typeSupported(waveType)) { + waveType = chooseWidgetType(m_openGlEnabled); } + setWidgetType(waveType); for (int i = 0; i < FilterCount; i++) { double visualGain = m_config->getValueString( @@ -364,13 +376,13 @@ void WaveformWidgetFactory::addTimerListener(WVuMeter* pWidget) { } void WaveformWidgetFactory::slotSkinLoaded() { - setWidgetTypeFromConfig(); + reloadWaveforms(); #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) && defined __WINDOWS__ // This regenerates the waveforms twice because of a bug found on Windows // where the first one fails. // The problem is that the window of the widget thinks that it is not exposed. // (https://doc.qt.io/qt-5/qwindow.html#exposeEvent ) - setWidgetTypeFromConfig(); + reloadWaveforms(); #endif } @@ -446,70 +458,31 @@ int WaveformWidgetFactory::getVSyncType() { return m_vSyncType; } -bool WaveformWidgetFactory::setWidgetType(WaveformWidgetType::Type type) { - return setWidgetType(type, &m_type); -} - -bool WaveformWidgetFactory::setWidgetType( - WaveformWidgetType::Type type, - WaveformWidgetType::Type* pCurrentType) { - if (type == *pCurrentType) { - return true; - } - - // check if type is acceptable - int index = findHandleIndexFromType(type); - if (index > -1) { - // type is acceptable - *pCurrentType = type; - if (m_config) { - m_config->setValue( - ConfigKey("[Waveform]", "WaveformType"), - static_cast(*pCurrentType)); +bool WaveformWidgetFactory::typeSupported(WaveformWidgetType::Type type) { + for (int i = 0; i < m_availableWaveformWidgetHandles.size(); i++) { + if (m_availableWaveformWidgetHandles[i].getType() == type) { + return true; } - return true; - } - - // fallback - *pCurrentType = WaveformWidgetType::EmptyWaveform; - if (m_config) { - m_config->setValue( - ConfigKey("[Waveform]", "WaveformType"), - static_cast(*pCurrentType)); } return false; } -bool WaveformWidgetFactory::setWidgetTypeFromConfig() { - int empty = findHandleIndexFromType(WaveformWidgetType::EmptyWaveform); - int desired = findHandleIndexFromType(m_configType); - if (desired == -1) { - desired = empty; - } - return setWidgetTypeFromHandle(desired, true); -} - -bool WaveformWidgetFactory::setWidgetTypeFromHandle(int handleIndex, bool force) { - if (handleIndex < 0 || handleIndex >= m_waveformWidgetHandles.size()) { - qDebug() << "WaveformWidgetFactory::setWidgetType - invalid handle --> use of 'EmptyWaveform'"; - // fallback empty type - setWidgetType(WaveformWidgetType::EmptyWaveform); - return false; +void WaveformWidgetFactory::setWidgetType(WaveformWidgetType::Type type) { + if (type == m_type) { + return; } - WaveformWidgetAbstractHandle& handle = m_waveformWidgetHandles[handleIndex]; - if (handle.m_type == m_type && !force) { - qDebug() << "WaveformWidgetFactory::setWidgetType - type already in use"; - return true; + VERIFY_OR_DEBUG_ASSERT(typeSupported(type)) { + type = chooseWidgetType(m_openGlEnabled); } - // change the type - setWidgetType(handle.m_type); + m_type = type; + m_config->setValue(ConfigKey("[Waveform]", "WaveformType"), static_cast(m_type)); + reloadWaveforms(); +} +void WaveformWidgetFactory::reloadWaveforms() { m_skipRender = true; - //qDebug() << "recreate start"; - - //re-create/setup all waveform widgets for (auto& holder : m_waveformWidgetHolders) { WaveformWidgetAbstract* previousWidget = holder.m_waveformWidget; TrackPointer pTrack = previousWidget->getTrackInfo(); @@ -534,10 +507,7 @@ bool WaveformWidgetFactory::setWidgetTypeFromHandle(int handleIndex, bool force) widget->getWidget()->show(); viewer->update(); } - m_skipRender = false; - //qDebug() << "recreate done"; - return true; } void WaveformWidgetFactory::setDefaultZoom(double zoom) { @@ -732,20 +702,21 @@ void WaveformWidgetFactory::swap() { m_vsyncThread->vsyncSlotFinished(); } -WaveformWidgetType::Type WaveformWidgetFactory::autoChooseWidgetType() const { +WaveformWidgetType::Type WaveformWidgetFactory::chooseWidgetType(bool openGlEnabled) const { //default selection - if (m_openGlAvailable) { + if (openGlEnabled) { if (m_openGLShaderAvailable) { return WaveformWidgetType::GLSLRGBWaveform; } else { return WaveformWidgetType::GLRGBWaveform; } } - return WaveformWidgetType::SoftwareWaveform; + return WaveformWidgetType::RGBWaveform; } void WaveformWidgetFactory::evaluateWidgets() { - m_waveformWidgetHandles.clear(); + m_allWaveformWidgetHandles.clear(); + m_availableWaveformWidgetHandles.clear(); for (int type = 0; type < WaveformWidgetType::Count_WaveformwidgetType; type++) { QString widgetName; bool useOpenGl; @@ -866,30 +837,24 @@ void WaveformWidgetFactory::evaluateWidgets() { continue; } + if (useOpenGLShaders) { + widgetName += " " + tr("(GLSL)"); + } else if (useOpenGl) { + widgetName += " " + tr("(GL)"); + } + bool active = true; if (isOpenGlAvailable()) { if (useOpenGles && !useOpenGl) { active = false; } else if (useOpenGLShaders && !isOpenGlShaderAvailable()) { active = false; - } else { - if (useOpenGLShaders) { - widgetName += " " + tr("(GLSL)"); - } else if (useOpenGl) { - widgetName += " " + tr("(GL)"); - } } } else if (isOpenGlesAvailable()) { if (useOpenGl && !useOpenGles) { active = false; } else if (useOpenGLShaders && !isOpenGlShaderAvailable()) { active = false; - } else { - if (useOpenGLShaders) { - widgetName += " " + tr("(GLSL ES)"); - } else if (useOpenGles) { - widgetName += " " + tr("(GL ES)"); - } } } else { // No sufficiant GL supptor @@ -902,13 +867,16 @@ void WaveformWidgetFactory::evaluateWidgets() { active = false; } - if (active) { - // add new handle for each available widget type - WaveformWidgetAbstractHandle handle; - handle.m_displayString = widgetName; - handle.m_type = (WaveformWidgetType::Type)type; + // add new handle for each available widget type + WaveformWidgetAbstractHandle handle; + handle.m_displayString = widgetName; + handle.m_type = (WaveformWidgetType::Type)type; + if (!developerOnly || (developerOnly && CmdlineArgs::Instance().getDeveloper())) { + m_allWaveformWidgetHandles.push_back(handle); + } - m_waveformWidgetHandles.push_back(handle); + if (active) { + m_availableWaveformWidgetHandles.push_back(handle); } } } @@ -1015,25 +983,20 @@ void WaveformWidgetFactory::startVSync(GuiTick* pGuiTick, VisualsManager* pVisua m_vsyncThread->start(QThread::NormalPriority); } -void WaveformWidgetFactory::getAvailableVSyncTypes(QList >* pList) { - m_vsyncThread->getAvailableVSyncTypes(pList); -} - -WaveformWidgetType::Type WaveformWidgetFactory::findTypeFromHandleIndex(int index) { - WaveformWidgetType::Type type = WaveformWidgetType::Count_WaveformwidgetType; - if (index >= 0 && index < m_waveformWidgetHandles.size()) { - type = m_waveformWidgetHandles[index].m_type; +const QVector +WaveformWidgetFactory::getAvailableTypes(bool openGlEnabled) const { + QVector types; + for (int i = 0; i < m_allWaveformWidgetHandles.size(); ++i) { + auto waveType = m_allWaveformWidgetHandles[i].getType(); + if (openGlEnabled && WaveformWidgetType::openGlTypes.contains(waveType)) { + types.append(m_allWaveformWidgetHandles[i]); + } else if (!openGlEnabled && !WaveformWidgetType::openGlTypes.contains(waveType)) { + types.append(m_allWaveformWidgetHandles[i]); + } } - return type; + return types; } -int WaveformWidgetFactory::findHandleIndexFromType(WaveformWidgetType::Type type) { - int index = -1; - for (int i = 0; i < m_waveformWidgetHandles.size(); i++) { - WaveformWidgetAbstractHandle& handle = m_waveformWidgetHandles[i]; - if (handle.m_type == type) { - index = i; - } - } - return index; +void WaveformWidgetFactory::getAvailableVSyncTypes(QList >* pList) { + m_vsyncThread->getAvailableVSyncTypes(pList); } diff --git a/src/waveform/waveformwidgetfactory.h b/src/waveform/waveformwidgetfactory.h index 8d106347769d..e8a76e991d74 100644 --- a/src/waveform/waveformwidgetfactory.h +++ b/src/waveform/waveformwidgetfactory.h @@ -60,6 +60,8 @@ class WaveformWidgetFactory : public QObject, public Singleton getAvailableTypes() const { return m_waveformWidgetHandles;} + const QVector getAvailableTypes(bool openGlEnabled) const; void getAvailableVSyncTypes(QList >* list); void destroyWidgets(); @@ -129,7 +120,7 @@ class WaveformWidgetFactory : public QObject, public Singleton m_waveformWidgetHandles; + QVector m_availableWaveformWidgetHandles; + QVector m_allWaveformWidgetHandles; //Currently in use widgets/visual/node std::vector m_waveformWidgetHolders; WaveformWidgetType::Type m_type; - WaveformWidgetType::Type m_configType; UserSettingsPointer m_config; @@ -178,6 +166,7 @@ class WaveformWidgetFactory : public QObject, public Singleton WaveformWidgetType::openGlTypes = { + QtSimpleWaveform, + QtWaveform, + GLSimpleWaveform, + GLFilteredWaveform, + GLSLFilteredWaveform, + GLVSyncTest, + GLRGBWaveform, + GLSLRGBWaveform, + QtVSyncTest, + QtHSVWaveform, + QtRGBWaveform, +}; diff --git a/src/waveform/widgets/waveformwidgettype.h b/src/waveform/widgets/waveformwidgettype.h index 5d87a67ece17..cb282ea0fcbf 100644 --- a/src/waveform/widgets/waveformwidgettype.h +++ b/src/waveform/widgets/waveformwidgettype.h @@ -1,5 +1,6 @@ -#ifndef WAVEFORMWIDGETTYPE_H -#define WAVEFORMWIDGETTYPE_H +#pragma once + +#include class WaveformWidgetType { public: @@ -24,6 +25,6 @@ class WaveformWidgetType { QtRGBWaveform, Count_WaveformwidgetType // Also used as invalid value }; -}; -#endif // WAVEFORMWIDGETTYPE_H + static const QSet openGlTypes; +}; diff --git a/src/widget/wknob.cpp b/src/widget/wknob.cpp index 974c7224964d..cc376070ca3a 100644 --- a/src/widget/wknob.cpp +++ b/src/widget/wknob.cpp @@ -22,10 +22,11 @@ #include "util/duration.h" #include "widget/wknob.h" -WKnob::WKnob(QWidget* pParent) +WKnob::WKnob(QWidget* pParent, bool openGlEnabled) : WDisplay(pParent), m_renderTimer(mixxx::Duration::fromMillis(20), - mixxx::Duration::fromSeconds(1)) { + mixxx::Duration::fromSeconds(1), + openGlEnabled) { connect(&m_renderTimer, &WidgetRenderTimer::update, this, @@ -50,9 +51,5 @@ void WKnob::wheelEvent(QWheelEvent* e) { } void WKnob::inputActivity() { -#ifdef __APPLE__ m_renderTimer.activity(); -#else - update(); -#endif } diff --git a/src/widget/wknob.h b/src/widget/wknob.h index 3e56b4f979cb..a5a4138272a5 100644 --- a/src/widget/wknob.h +++ b/src/widget/wknob.h @@ -18,7 +18,7 @@ class WKnob : public WDisplay { Q_OBJECT public: - explicit WKnob(QWidget* pParent=nullptr); + explicit WKnob(QWidget* pParent = nullptr, bool openGlEnabled = false); protected: void wheelEvent(QWheelEvent *e) override; diff --git a/src/widget/wknobcomposed.cpp b/src/widget/wknobcomposed.cpp index e2fbb98c1f32..f6a12eb61d3d 100644 --- a/src/widget/wknobcomposed.cpp +++ b/src/widget/wknobcomposed.cpp @@ -6,7 +6,7 @@ #include "widget/wknobcomposed.h" #include "widget/wskincolor.h" -WKnobComposed::WKnobComposed(QWidget* pParent) +WKnobComposed::WKnobComposed(QWidget* pParent, bool openGlEnabled) : WWidget(pParent), m_dCurrentAngle(140.0), m_dMinAngle(-230.0), @@ -20,7 +20,8 @@ WKnobComposed::WKnobComposed(QWidget* pParent) m_arcReversed(false), m_arcPenCap(Qt::FlatCap), m_renderTimer(mixxx::Duration::fromMillis(20), - mixxx::Duration::fromSeconds(1)) { + mixxx::Duration::fromSeconds(1), + openGlEnabled) { connect(&m_renderTimer, &WidgetRenderTimer::update, this, @@ -222,9 +223,5 @@ void WKnobComposed::wheelEvent(QWheelEvent* e) { } void WKnobComposed::inputActivity() { -#ifdef __APPLE__ m_renderTimer.activity(); -#else - update(); -#endif } diff --git a/src/widget/wknobcomposed.h b/src/widget/wknobcomposed.h index 489c5db9a170..5e783b596eb4 100644 --- a/src/widget/wknobcomposed.h +++ b/src/widget/wknobcomposed.h @@ -21,7 +21,7 @@ class WKnobComposed : public WWidget { Q_OBJECT public: - explicit WKnobComposed(QWidget* pParent=nullptr); + explicit WKnobComposed(QWidget* pParent = nullptr, bool openGlEnabled = false); void setup(const QDomNode& node, const SkinContext& context); diff --git a/src/widget/wslidercomposed.cpp b/src/widget/wslidercomposed.cpp index 0c28df5b6183..ce01d72e89b0 100644 --- a/src/widget/wslidercomposed.cpp +++ b/src/widget/wslidercomposed.cpp @@ -28,27 +28,28 @@ #include "util/duration.h" #include "util/math.h" -WSliderComposed::WSliderComposed(QWidget * parent) - : WWidget(parent), - m_bRightButtonPressed(false), - m_dHandleLength(0.0), - m_dSliderLength(0.0), - m_bHorizontal(false), - m_dBarWidth(0.0), - m_dBarBgWidth(0.0), - m_dBarStart(0.0), - m_dBarEnd(0.0), - m_dBarBgStart(0.0), - m_dBarBgEnd(0.0), - m_dBarAxisPos(0.0), - m_bBarUnipolar(true), - m_barColor(nullptr), - m_barBgColor(nullptr), - m_barPenCap(Qt::FlatCap), - m_pSlider(nullptr), - m_pHandle(nullptr), - m_renderTimer(mixxx::Duration::fromMillis(20), - mixxx::Duration::fromSeconds(1)) { +WSliderComposed::WSliderComposed(QWidget* pParent, bool openGlEnabled) + : WWidget(pParent), + m_bRightButtonPressed(false), + m_dHandleLength(0.0), + m_dSliderLength(0.0), + m_bHorizontal(false), + m_dBarWidth(0.0), + m_dBarBgWidth(0.0), + m_dBarStart(0.0), + m_dBarEnd(0.0), + m_dBarBgStart(0.0), + m_dBarBgEnd(0.0), + m_dBarAxisPos(0.0), + m_bBarUnipolar(true), + m_barColor(nullptr), + m_barBgColor(nullptr), + m_barPenCap(Qt::FlatCap), + m_pSlider(nullptr), + m_pHandle(nullptr), + m_renderTimer(mixxx::Duration::fromMillis(20), + mixxx::Duration::fromSeconds(1), + openGlEnabled) { connect(&m_renderTimer, &WidgetRenderTimer::update, this, @@ -374,9 +375,5 @@ double WSliderComposed::calculateHandleLength() { } void WSliderComposed::inputActivity() { -#ifdef __APPLE__ m_renderTimer.activity(); -#else - update(); -#endif } diff --git a/src/widget/wslidercomposed.h b/src/widget/wslidercomposed.h index df1782326324..2d1cebd088ac 100644 --- a/src/widget/wslidercomposed.h +++ b/src/widget/wslidercomposed.h @@ -41,7 +41,7 @@ class WSliderComposed : public WWidget { Q_OBJECT public: - explicit WSliderComposed(QWidget* parent = nullptr); + explicit WSliderComposed(QWidget* parent = nullptr, bool openGlEnabled = false); ~WSliderComposed() override; void setup(const QDomNode& node, const SkinContext& context);