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);