Commit c19372354698f6689f50be839fdb27e4e8449e5c

Authored by David Graeff
Committed by David Gräff
1 parent 0f3e1d63

Use OpenGL 3.2 instead of 3.3 to make it work on MacOSX

Fix:
* Move all GL startup calls to GLScope::fixOpenGLversion
* Depending on OpenGL or ES availability initialize the QSurfaceFormat
* Don't crash if the shader compilation failed. Show a nice message instead.

Optimize:
* Don't write the markers to the GPU each frame update, only
  do this if they actually changed position.

Code style:
* LevelSlider: Don't return a value for set* Methods.
* Don't rely on the LevelSliders step to calculate the marker position in the OpenGL view.
openhantek/src/dsowidget.cpp
@@ -5,8 +5,8 @@ @@ -5,8 +5,8 @@
5 #include <QFileDialog> 5 #include <QFileDialog>
6 #include <QGridLayout> 6 #include <QGridLayout>
7 #include <QLabel> 7 #include <QLabel>
8 -#include <QTimer>  
9 #include <QSignalBlocker> 8 #include <QSignalBlocker>
  9 +#include <QTimer>
10 10
11 #include "dsowidget.h" 11 #include "dsowidget.h"
12 12
@@ -37,11 +37,12 @@ DsoWidget::DsoWidget(DsoSettingsScope *scope, DsoSettingsView *view, const Dso:: @@ -37,11 +37,12 @@ DsoWidget::DsoWidget(DsoSettingsScope *scope, DsoSettingsView *view, const Dso::
37 setupSliders(mainSliders); 37 setupSliders(mainSliders);
38 setupSliders(zoomSliders); 38 setupSliders(zoomSliders);
39 39
40 - connect(mainScope, &GlScope::markerMoved, [this] (int marker, double position) {  
41 - double step = this->mainSliders.markerSlider->step(marker); 40 + connect(mainScope, &GlScope::markerMoved, [this](int marker, double position) {
  41 + double value = std::round(position / MARKER_STEP) * MARKER_STEP;
42 42
43 - this->scope->horizontal.marker[marker] =  
44 - this->mainSliders.markerSlider->setValue(marker, std::round(position / step) * step); 43 + this->scope->horizontal.marker[marker] = value;
  44 + this->mainSliders.markerSlider->setValue(marker, value);
  45 + this->mainScope->markerUpdated();
45 }); 46 });
46 47
47 // The table for the settings 48 // The table for the settings
@@ -175,14 +176,6 @@ DsoWidget::DsoWidget(DsoSettingsScope *scope, DsoSettingsView *view, const Dso:: @@ -175,14 +176,6 @@ DsoWidget::DsoWidget(DsoSettingsScope *scope, DsoSettingsView *view, const Dso::
175 mainLayout->setRowMinimumHeight(row++, 8); 176 mainLayout->setRowMinimumHeight(row++, 8);
176 mainLayout->addLayout(measurementLayout, row++, 0, 1, 5); 177 mainLayout->addLayout(measurementLayout, row++, 0, 1, 5);
177 178
178 - // Apply settings and update measured values  
179 - updateTriggerDetails();  
180 - updateRecordLength(scope->horizontal.recordLength);  
181 - updateFrequencybase(scope->horizontal.frequencybase);  
182 - updateSamplerate(scope->horizontal.samplerate);  
183 - updateTimebase(scope->horizontal.timebase);  
184 - updateZoom(view->zoom);  
185 -  
186 // The widget itself 179 // The widget itself
187 setPalette(palette); 180 setPalette(palette);
188 setBackgroundRole(QPalette::Background); 181 setBackgroundRole(QPalette::Background);
@@ -205,9 +198,6 @@ DsoWidget::DsoWidget(DsoSettingsScope *scope, DsoSettingsView *view, const Dso:: @@ -205,9 +198,6 @@ DsoWidget::DsoWidget(DsoSettingsScope *scope, DsoSettingsView *view, const Dso::
205 zoomScope->update(); 198 zoomScope->update();
206 }); 199 });
207 zoomSliders.markerSlider->setEnabled(false); 200 zoomSliders.markerSlider->setEnabled(false);
208 -  
209 - updateTriggerSource();  
210 - adaptTriggerPositionSlider();  
211 } 201 }
212 202
213 void DsoWidget::setupSliders(DsoWidget::Sliders &sliders) { 203 void DsoWidget::setupSliders(DsoWidget::Sliders &sliders) {
@@ -242,11 +232,10 @@ void DsoWidget::setupSliders(DsoWidget::Sliders &amp;sliders) { @@ -242,11 +232,10 @@ void DsoWidget::setupSliders(DsoWidget::Sliders &amp;sliders) {
242 sliders.triggerLevelSlider = new LevelSlider(Qt::LeftArrow); 232 sliders.triggerLevelSlider = new LevelSlider(Qt::LeftArrow);
243 for (ChannelID channel = 0; channel < spec->channels; ++channel) { 233 for (ChannelID channel = 0; channel < spec->channels; ++channel) {
244 sliders.triggerLevelSlider->addSlider((int)channel); 234 sliders.triggerLevelSlider->addSlider((int)channel);
245 - sliders.triggerLevelSlider->setColor(  
246 - channel,  
247 - (!scope->trigger.special && channel == scope->trigger.source)  
248 - ? view->screen.voltage[channel]  
249 - : view->screen.voltage[channel].darker()); 235 + sliders.triggerLevelSlider->setColor(channel,
  236 + (!scope->trigger.special && channel == scope->trigger.source)
  237 + ? view->screen.voltage[channel]
  238 + : view->screen.voltage[channel].darker());
250 adaptTriggerLevelSlider(sliders, channel); 239 adaptTriggerLevelSlider(sliders, channel);
251 sliders.triggerLevelSlider->setValue(channel, scope->voltage[channel].trigger); 240 sliders.triggerLevelSlider->setValue(channel, scope->voltage[channel].trigger);
252 sliders.triggerLevelSlider->setIndexVisible(channel, scope->voltage[channel].used); 241 sliders.triggerLevelSlider->setIndexVisible(channel, scope->voltage[channel].used);
@@ -257,7 +246,7 @@ void DsoWidget::setupSliders(DsoWidget::Sliders &amp;sliders) { @@ -257,7 +246,7 @@ void DsoWidget::setupSliders(DsoWidget::Sliders &amp;sliders) {
257 for (int marker = 0; marker < MARKER_COUNT; ++marker) { 246 for (int marker = 0; marker < MARKER_COUNT; ++marker) {
258 sliders.markerSlider->addSlider(QString::number(marker + 1), marker); 247 sliders.markerSlider->addSlider(QString::number(marker + 1), marker);
259 sliders.markerSlider->setLimits(marker, -DIVS_TIME / 2, DIVS_TIME / 2); 248 sliders.markerSlider->setLimits(marker, -DIVS_TIME / 2, DIVS_TIME / 2);
260 - sliders.markerSlider->setStep(marker, DIVS_TIME / 100.0); 249 + sliders.markerSlider->setStep(marker, MARKER_STEP);
261 sliders.markerSlider->setValue(marker, scope->horizontal.marker[marker]); 250 sliders.markerSlider->setValue(marker, scope->horizontal.marker[marker]);
262 sliders.markerSlider->setIndexVisible(marker, true); 251 sliders.markerSlider->setIndexVisible(marker, true);
263 } 252 }
@@ -269,9 +258,9 @@ void DsoWidget::setExporterForNextFrame(std::unique_ptr&lt;Exporter&gt; exporter) { @@ -269,9 +258,9 @@ void DsoWidget::setExporterForNextFrame(std::unique_ptr&lt;Exporter&gt; exporter) {
269 258
270 /// \brief Set the trigger level sliders minimum and maximum to the new values. 259 /// \brief Set the trigger level sliders minimum and maximum to the new values.
271 void DsoWidget::adaptTriggerLevelSlider(DsoWidget::Sliders &sliders, ChannelID channel) { 260 void DsoWidget::adaptTriggerLevelSlider(DsoWidget::Sliders &sliders, ChannelID channel) {
272 - sliders.triggerLevelSlider->setLimits(  
273 - (int)channel, (-DIVS_VOLTAGE / 2 - scope->voltage[channel].offset) * scope->gain(channel),  
274 - (DIVS_VOLTAGE / 2 - scope->voltage[channel].offset) * scope->gain(channel)); 261 + sliders.triggerLevelSlider->setLimits((int)channel,
  262 + (-DIVS_VOLTAGE / 2 - scope->voltage[channel].offset) * scope->gain(channel),
  263 + (DIVS_VOLTAGE / 2 - scope->voltage[channel].offset) * scope->gain(channel));
275 sliders.triggerLevelSlider->setStep((int)channel, scope->gain(channel) * 0.05); 264 sliders.triggerLevelSlider->setStep((int)channel, scope->gain(channel) * 0.05);
276 } 265 }
277 266
@@ -292,14 +281,10 @@ void DsoWidget::setMeasurementVisible(ChannelID channel) { @@ -292,14 +281,10 @@ void DsoWidget::setMeasurementVisible(ChannelID channel) {
292 } 281 }
293 282
294 measurementGainLabel[channel]->setVisible(scope->voltage[channel].used); 283 measurementGainLabel[channel]->setVisible(scope->voltage[channel].used);
295 - if (!scope->voltage[channel].used) {  
296 - measurementGainLabel[channel]->setText(QString());  
297 - } 284 + if (!scope->voltage[channel].used) { measurementGainLabel[channel]->setText(QString()); }
298 285
299 measurementMagnitudeLabel[channel]->setVisible(scope->spectrum[channel].used); 286 measurementMagnitudeLabel[channel]->setVisible(scope->spectrum[channel].used);
300 - if (!scope->spectrum[channel].used) {  
301 - measurementMagnitudeLabel[channel]->setText(QString());  
302 - } 287 + if (!scope->spectrum[channel].used) { measurementMagnitudeLabel[channel]->setText(QString()); }
303 } 288 }
304 289
305 /// \brief Update the label about the marker measurements 290 /// \brief Update the label about the marker measurements
@@ -411,16 +396,15 @@ void DsoWidget::updateTriggerSource() { @@ -411,16 +396,15 @@ void DsoWidget::updateTriggerSource() {
411 if (scope->trigger.special || scope->trigger.source >= spec->channels) { 396 if (scope->trigger.special || scope->trigger.source >= spec->channels) {
412 mainSliders.triggerPositionSlider->setColor(0, view->screen.border); 397 mainSliders.triggerPositionSlider->setColor(0, view->screen.border);
413 zoomSliders.triggerPositionSlider->setColor(0, view->screen.border); 398 zoomSliders.triggerPositionSlider->setColor(0, view->screen.border);
414 - }  
415 - else { 399 + } else {
416 mainSliders.triggerPositionSlider->setColor(0, view->screen.voltage[scope->trigger.source]); 400 mainSliders.triggerPositionSlider->setColor(0, view->screen.voltage[scope->trigger.source]);
417 zoomSliders.triggerPositionSlider->setColor(0, view->screen.voltage[scope->trigger.source]); 401 zoomSliders.triggerPositionSlider->setColor(0, view->screen.voltage[scope->trigger.source]);
418 } 402 }
419 403
420 for (ChannelID channel = 0; channel < spec->channels; ++channel) { 404 for (ChannelID channel = 0; channel < spec->channels; ++channel) {
421 QColor color = (!scope->trigger.special && channel == scope->trigger.source) 405 QColor color = (!scope->trigger.special && channel == scope->trigger.source)
422 - ? view->screen.voltage[channel]  
423 - : view->screen.voltage[channel].darker(); 406 + ? view->screen.voltage[channel]
  407 + : view->screen.voltage[channel].darker();
424 mainSliders.triggerLevelSlider->setColor(channel, color); 408 mainSliders.triggerLevelSlider->setColor(channel, color);
425 zoomSliders.triggerLevelSlider->setColor(channel, color); 409 zoomSliders.triggerLevelSlider->setColor(channel, color);
426 } 410 }
@@ -484,8 +468,7 @@ void DsoWidget::updateZoom(bool enabled) { @@ -484,8 +468,7 @@ void DsoWidget::updateZoom(bool enabled) {
484 zoomSliders.offsetSlider->show(); 468 zoomSliders.offsetSlider->show();
485 zoomSliders.triggerPositionSlider->show(); 469 zoomSliders.triggerPositionSlider->show();
486 zoomSliders.triggerLevelSlider->show(); 470 zoomSliders.triggerLevelSlider->show();
487 - }  
488 - else { 471 + } else {
489 zoomSliders.offsetSlider->hide(); 472 zoomSliders.offsetSlider->hide();
490 zoomSliders.triggerPositionSlider->hide(); 473 zoomSliders.triggerPositionSlider->hide();
491 zoomSliders.triggerLevelSlider->hide(); 474 zoomSliders.triggerLevelSlider->hide();
@@ -535,6 +518,20 @@ void DsoWidget::showNew(std::shared_ptr&lt;PPresult&gt; data) { @@ -535,6 +518,20 @@ void DsoWidget::showNew(std::shared_ptr&lt;PPresult&gt; data) {
535 } 518 }
536 } 519 }
537 520
  521 +void DsoWidget::showEvent(QShowEvent *event) {
  522 + QWidget::showEvent(event);
  523 + // Apply settings and update measured values
  524 + updateTriggerDetails();
  525 + updateRecordLength(scope->horizontal.recordLength);
  526 + updateFrequencybase(scope->horizontal.frequencybase);
  527 + updateSamplerate(scope->horizontal.samplerate);
  528 + updateTimebase(scope->horizontal.timebase);
  529 + updateZoom(view->zoom);
  530 +
  531 + updateTriggerSource();
  532 + adaptTriggerPositionSlider();
  533 +}
  534 +
538 /// \brief Handles valueChanged signal from the offset sliders. 535 /// \brief Handles valueChanged signal from the offset sliders.
539 /// \param channel The channel whose offset was changed. 536 /// \param channel The channel whose offset was changed.
540 /// \param value The new offset for the channel. 537 /// \param value The new offset for the channel.
@@ -573,8 +570,7 @@ void DsoWidget::adaptTriggerPositionSlider() { @@ -573,8 +570,7 @@ void DsoWidget::adaptTriggerPositionSlider() {
573 if (m1 != m2 && m1 <= value && value <= m2) { 570 if (m1 != m2 && m1 <= value && value <= m2) {
574 zoomSliders.triggerPositionSlider->setIndexVisible(0, true); 571 zoomSliders.triggerPositionSlider->setIndexVisible(0, true);
575 zoomSliders.triggerPositionSlider->setValue(0, (value - m1) / (m2 - m1)); 572 zoomSliders.triggerPositionSlider->setValue(0, (value - m1) / (m2 - m1));
576 - }  
577 - else { 573 + } else {
578 zoomSliders.triggerPositionSlider->setIndexVisible(0, false); 574 zoomSliders.triggerPositionSlider->setIndexVisible(0, false);
579 } 575 }
580 } 576 }
openhantek/src/dsowidget.h
@@ -42,6 +42,7 @@ class DsoWidget : public QWidget { @@ -42,6 +42,7 @@ class DsoWidget : public QWidget {
42 void showNew(std::shared_ptr<PPresult> data); 42 void showNew(std::shared_ptr<PPresult> data);
43 43
44 protected: 44 protected:
  45 + virtual void showEvent(QShowEvent *event);
45 void setupSliders(Sliders &sliders); 46 void setupSliders(Sliders &sliders);
46 void adaptTriggerLevelSlider(DsoWidget::Sliders &sliders, ChannelID channel); 47 void adaptTriggerLevelSlider(DsoWidget::Sliders &sliders, ChannelID channel);
47 void adaptTriggerPositionSlider(); 48 void adaptTriggerPositionSlider();
openhantek/src/glscope.cpp
@@ -4,12 +4,16 @@ @@ -4,12 +4,16 @@
4 #include <iostream> 4 #include <iostream>
5 5
6 #include <QColor> 6 #include <QColor>
  7 +#include <QCoreApplication>
7 #include <QDebug> 8 #include <QDebug>
8 #include <QMatrix4x4> 9 #include <QMatrix4x4>
  10 +#include <QMessageBox>
9 #include <QMouseEvent> 11 #include <QMouseEvent>
10 #include <QOpenGLShaderProgram> 12 #include <QOpenGLShaderProgram>
  13 +#include <QPainter>
11 14
12 -#include <QOpenGLFunctions_3_3_Core> 15 +// We can't be more modern than OpenGL 3.2 or ES2 because of MacOSX.
  16 +#include <QOpenGLFunctions_3_2_Core>
13 #include <QOpenGLFunctions_ES2> 17 #include <QOpenGLFunctions_ES2>
14 18
15 #include "glscope.h" 19 #include "glscope.h"
@@ -23,7 +27,7 @@ @@ -23,7 +27,7 @@
23 #if defined(QT_OPENGL_ES_2) 27 #if defined(QT_OPENGL_ES_2)
24 typedef QOpenGLFunctions_ES2 OPENGL_VER; 28 typedef QOpenGLFunctions_ES2 OPENGL_VER;
25 #else 29 #else
26 -typedef QOpenGLFunctions_3_3_Core OPENGL_VER; 30 +typedef QOpenGLFunctions_3_2_Core OPENGL_VER;
27 #endif 31 #endif
28 32
29 GlScope *GlScope::createNormal(DsoSettingsScope *scope, DsoSettingsView *view, QWidget *parent) { 33 GlScope *GlScope::createNormal(DsoSettingsScope *scope, DsoSettingsView *view, QWidget *parent) {
@@ -38,6 +42,25 @@ GlScope *GlScope::createZoomed(DsoSettingsScope *scope, DsoSettingsView *view, Q @@ -38,6 +42,25 @@ GlScope *GlScope::createZoomed(DsoSettingsScope *scope, DsoSettingsView *view, Q
38 return s; 42 return s;
39 } 43 }
40 44
  45 +void GlScope::fixOpenGLversion() {
  46 + QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
  47 +
  48 + // Prefer full desktop OpenGL without fixed pipeline
  49 + QSurfaceFormat format;
  50 + format.setSamples(4); // Antia-Aliasing, Multisampling
  51 +#if defined(QT_OPENGL_ES_2)
  52 + format.setVersion(2, 0);
  53 + format.setProfile(QSurfaceFormat::CoreProfile);
  54 + format.setRenderableType(QSurfaceFormat::OpenGLES);
  55 + QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true);
  56 +#else
  57 + format.setVersion(3, 2);
  58 + format.setProfile(QSurfaceFormat::CoreProfile);
  59 + format.setRenderableType(QSurfaceFormat::OpenGL);
  60 +#endif
  61 + QSurfaceFormat::setDefaultFormat(format);
  62 +}
  63 +
41 GlScope::GlScope(DsoSettingsScope *scope, DsoSettingsView *view, QWidget *parent) 64 GlScope::GlScope(DsoSettingsScope *scope, DsoSettingsView *view, QWidget *parent)
42 : QOpenGLWidget(parent), scope(scope), view(view) { 65 : QOpenGLWidget(parent), scope(scope), view(view) {
43 vaMarker.resize(MARKER_COUNT); 66 vaMarker.resize(MARKER_COUNT);
@@ -51,7 +74,7 @@ void GlScope::mousePressEvent(QMouseEvent *event) { @@ -51,7 +74,7 @@ void GlScope::mousePressEvent(QMouseEvent *event) {
51 double distance = DIVS_TIME; 74 double distance = DIVS_TIME;
52 selectedMarker = NO_MARKER; 75 selectedMarker = NO_MARKER;
53 // Capture nearest marker located within snap area (+/- 1% of full scale). 76 // Capture nearest marker located within snap area (+/- 1% of full scale).
54 - for (int marker = 0; marker < MARKER_COUNT; ++marker) { 77 + for (unsigned marker = 0; marker < MARKER_COUNT; ++marker) {
55 if (!scope->horizontal.marker_visible[marker]) continue; 78 if (!scope->horizontal.marker_visible[marker]) continue;
56 if (fabs(scope->horizontal.marker[marker] - position) < std::min(distance, DIVS_TIME / 100.0)) { 79 if (fabs(scope->horizontal.marker[marker] - position) < std::min(distance, DIVS_TIME / 100.0)) {
57 distance = fabs(scope->horizontal.marker[marker] - position); 80 distance = fabs(scope->horizontal.marker[marker] - position);
@@ -89,13 +112,34 @@ void GlScope::mouseReleaseEvent(QMouseEvent *event) { @@ -89,13 +112,34 @@ void GlScope::mouseReleaseEvent(QMouseEvent *event) {
89 event->accept(); 112 event->accept();
90 } 113 }
91 114
  115 +void GlScope::paintEvent(QPaintEvent *event) {
  116 + // Draw error message if OpenGL failed
  117 + if (!shaderCompileSuccess) {
  118 + QPainter painter(this);
  119 + painter.setRenderHint(QPainter::Antialiasing, true);
  120 + QFont font = painter.font();
  121 + font.setPointSize(18);
  122 + painter.setFont(font);
  123 + painter.drawText(rect(), Qt::AlignCenter, errorMessage);
  124 + event->accept();
  125 + } else
  126 + QOpenGLWidget::paintEvent(event);
  127 +}
  128 +
92 void GlScope::initializeGL() { 129 void GlScope::initializeGL() {
93 - auto *gl = context()->versionFunctions<OPENGL_VER>(); 130 + if (!QOpenGLShaderProgram::hasOpenGLShaderPrograms(context())) {
  131 + errorMessage = tr("System does not support OpenGL Shading Language (GLSL)");
  132 + return;
  133 + }
  134 + if (m_program) {
  135 + qWarning() << "OpenGL init called twice!";
  136 + return;
  137 + }
94 138
95 - m_program = std::unique_ptr<QOpenGLShaderProgram>(new QOpenGLShaderProgram(context())); 139 + auto program = std::unique_ptr<QOpenGLShaderProgram>(new QOpenGLShaderProgram(context()));
96 140
97 const char *vshaderES = R"( 141 const char *vshaderES = R"(
98 - #version 330 142 + #version 100
99 attribute highp vec3 vertex; 143 attribute highp vec3 vertex;
100 uniform mat4 matrix; 144 uniform mat4 matrix;
101 void main() 145 void main()
@@ -104,9 +148,14 @@ void GlScope::initializeGL() { @@ -104,9 +148,14 @@ void GlScope::initializeGL() {
104 gl_PointSize = 1.0; 148 gl_PointSize = 1.0;
105 } 149 }
106 )"; 150 )";
  151 + const char *fshaderES = R"(
  152 + #version 100
  153 + uniform highp vec4 colour;
  154 + void main() { gl_FragColor = colour; }
  155 + )";
107 156
108 const char *vshaderCore = R"( 157 const char *vshaderCore = R"(
109 - #version 330 158 + #version 150
110 in highp vec3 vertex; 159 in highp vec3 vertex;
111 uniform mat4 matrix; 160 uniform mat4 matrix;
112 void main() 161 void main()
@@ -116,37 +165,39 @@ void GlScope::initializeGL() { @@ -116,37 +165,39 @@ void GlScope::initializeGL() {
116 } 165 }
117 )"; 166 )";
118 const char *fshaderCore = R"( 167 const char *fshaderCore = R"(
119 - #version 330 168 + #version 150
120 uniform highp vec4 colour; 169 uniform highp vec4 colour;
121 - void main() { gl_FragColor = colour; } 170 + out vec4 flatColor;
  171 + void main() { flatColor = colour; }
122 )"; 172 )";
123 173
124 qDebug() << "compile shaders"; 174 qDebug() << "compile shaders";
125 // Compile vertex shader 175 // Compile vertex shader
126 bool coreShaders = QSurfaceFormat::defaultFormat().profile() == QSurfaceFormat::CoreProfile; 176 bool coreShaders = QSurfaceFormat::defaultFormat().profile() == QSurfaceFormat::CoreProfile;
127 - if (!m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, coreShaders ? vshaderCore : vshaderES) ||  
128 - !m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fshaderCore)) {  
129 - qWarning() << "Failed to compile OpenGL shader programs.\n" << m_program->log(); 177 + if (!program->addShaderFromSourceCode(QOpenGLShader::Vertex, coreShaders ? vshaderCore : vshaderES) ||
  178 + !program->addShaderFromSourceCode(QOpenGLShader::Fragment, coreShaders ? fshaderCore : fshaderES)) {
  179 + errorMessage = "Failed to compile OpenGL shader programs.\n" + program->log();
130 return; 180 return;
131 } 181 }
132 182
133 // Link shader pipeline 183 // Link shader pipeline
134 - if (!m_program->link() || !m_program->bind()) {  
135 - qWarning() << "Failed to link/bind OpenGL shader programs"; 184 + if (!program->link() || !program->bind()) {
  185 + errorMessage = "Failed to link/bind OpenGL shader programs\n" + program->log();
136 return; 186 return;
137 } 187 }
138 188
139 - vertexLocation = m_program->attributeLocation("vertex");  
140 - matrixLocation = m_program->uniformLocation("matrix");  
141 - colorLocation = m_program->uniformLocation("colour"); 189 + vertexLocation = program->attributeLocation("vertex");
  190 + matrixLocation = program->uniformLocation("matrix");
  191 + colorLocation = program->uniformLocation("colour");
142 192
143 if (vertexLocation == -1 || colorLocation == -1 || matrixLocation == -1) { 193 if (vertexLocation == -1 || colorLocation == -1 || matrixLocation == -1) {
144 qWarning() << "Failed to locate shader variable"; 194 qWarning() << "Failed to locate shader variable";
145 return; 195 return;
146 } 196 }
147 197
148 - m_program->bind(); 198 + program->bind();
149 199
  200 + auto *gl = context()->versionFunctions<OPENGL_VER>();
150 gl->glDisable(GL_DEPTH_TEST); 201 gl->glDisable(GL_DEPTH_TEST);
151 gl->glEnable(GL_BLEND); 202 gl->glEnable(GL_BLEND);
152 // Enable depth buffer 203 // Enable depth buffer
@@ -159,7 +210,7 @@ void GlScope::initializeGL() { @@ -159,7 +210,7 @@ void GlScope::initializeGL() {
159 QColor bg = view->screen.background; 210 QColor bg = view->screen.background;
160 gl->glClearColor((GLfloat)bg.redF(), (GLfloat)bg.greenF(), (GLfloat)bg.blueF(), (GLfloat)bg.alphaF()); 211 gl->glClearColor((GLfloat)bg.redF(), (GLfloat)bg.greenF(), (GLfloat)bg.blueF(), (GLfloat)bg.alphaF());
161 212
162 - generateGrid(); 213 + generateGrid(program.get());
163 214
164 { 215 {
165 m_vaoMarker.create(); 216 m_vaoMarker.create();
@@ -168,15 +219,18 @@ void GlScope::initializeGL() { @@ -168,15 +219,18 @@ void GlScope::initializeGL() {
168 m_marker.bind(); 219 m_marker.bind();
169 m_marker.setUsagePattern(QOpenGLBuffer::StaticDraw); 220 m_marker.setUsagePattern(QOpenGLBuffer::StaticDraw);
170 m_marker.allocate(int(vaMarker.size() * sizeof(Line))); 221 m_marker.allocate(int(vaMarker.size() * sizeof(Line)));
171 - m_program->enableAttributeArray(vertexLocation);  
172 - m_program->setAttributeBuffer(vertexLocation, GL_FLOAT, 0, 3, 0); 222 + program->enableAttributeArray(vertexLocation);
  223 + program->setAttributeBuffer(vertexLocation, GL_FLOAT, 0, 3, 0);
173 } 224 }
174 225
175 - m_program->release(); 226 + markerUpdated();
  227 +
  228 + m_program = std::move(program);
  229 + shaderCompileSuccess = true;
176 } 230 }
177 231
178 void GlScope::showData(PPresult *data) { 232 void GlScope::showData(PPresult *data) {
179 - if (!m_program || !m_program->isLinked()) return; 233 + if (!shaderCompileSuccess) return;
180 makeCurrent(); 234 makeCurrent();
181 // Remove too much entries 235 // Remove too much entries
182 while (view->digitalPhosphorDraws() < m_GraphHistory.size()) m_GraphHistory.pop_back(); 236 while (view->digitalPhosphorDraws() < m_GraphHistory.size()) m_GraphHistory.pop_back();
@@ -192,8 +246,23 @@ void GlScope::showData(PPresult *data) { @@ -192,8 +246,23 @@ void GlScope::showData(PPresult *data) {
192 // doneCurrent(); 246 // doneCurrent();
193 } 247 }
194 248
  249 +void GlScope::markerUpdated()
  250 +{
  251 +
  252 + for (unsigned marker = 0; marker < vaMarker.size(); ++marker) {
  253 + if (!scope->horizontal.marker_visible[marker]) continue;
  254 + vaMarker[marker] = {QVector3D((GLfloat)scope->horizontal.marker[marker], -DIVS_VOLTAGE, 0.0f),
  255 + QVector3D((GLfloat)scope->horizontal.marker[marker], DIVS_VOLTAGE, 0.0f)};
  256 + }
  257 +
  258 + // Write coordinates to GPU
  259 + makeCurrent();
  260 + m_marker.bind();
  261 + m_marker.write(0, vaMarker.data(), vaMarker.size() * sizeof(Line));
  262 +}
  263 +
195 void GlScope::paintGL() { 264 void GlScope::paintGL() {
196 - if (!m_program->isLinked()) return; 265 + if (!shaderCompileSuccess) return;
197 266
198 auto *gl = context()->versionFunctions<OPENGL_VER>(); 267 auto *gl = context()->versionFunctions<OPENGL_VER>();
199 268
@@ -231,6 +300,7 @@ void GlScope::paintGL() { @@ -231,6 +300,7 @@ void GlScope::paintGL() {
231 } 300 }
232 301
233 void GlScope::resizeGL(int width, int height) { 302 void GlScope::resizeGL(int width, int height) {
  303 + if (!shaderCompileSuccess) return;
234 auto *gl = context()->versionFunctions<OPENGL_VER>(); 304 auto *gl = context()->versionFunctions<OPENGL_VER>();
235 gl->glViewport(0, 0, (GLint)width, (GLint)height); 305 gl->glViewport(0, 0, (GLint)width, (GLint)height);
236 306
@@ -248,30 +318,7 @@ void GlScope::resizeGL(int width, int height) { @@ -248,30 +318,7 @@ void GlScope::resizeGL(int width, int height) {
248 m_program->release(); 318 m_program->release();
249 } 319 }
250 320
251 -void GlScope::drawGrid() {  
252 - auto *gl = context()->versionFunctions<OPENGL_VER>();  
253 - gl->glLineWidth(1);  
254 -  
255 - // Grid  
256 - m_vaoGrid[0].bind();  
257 - m_program->setUniformValue(colorLocation, view->screen.grid);  
258 - gl->glDrawArrays(GL_POINTS, 0, gridDrawCounts[0]);  
259 - m_vaoGrid[0].release();  
260 -  
261 - // Axes  
262 - m_vaoGrid[1].bind();  
263 - m_program->setUniformValue(colorLocation, view->screen.axes);  
264 - gl->glDrawArrays(GL_LINES, 0, gridDrawCounts[1]);  
265 - m_vaoGrid[1].release();  
266 -  
267 - // Border  
268 - m_vaoGrid[2].bind();  
269 - m_program->setUniformValue(colorLocation, view->screen.border);  
270 - gl->glDrawArrays(GL_LINE_LOOP, 0, gridDrawCounts[2]);  
271 - m_vaoGrid[2].release();  
272 -}  
273 -  
274 -void GlScope::generateGrid() { 321 +void GlScope::generateGrid(QOpenGLShaderProgram *program) {
275 gridDrawCounts[0] = 0; 322 gridDrawCounts[0] = 0;
276 gridDrawCounts[1] = 0; 323 gridDrawCounts[1] = 0;
277 gridDrawCounts[2] = 0; 324 gridDrawCounts[2] = 0;
@@ -286,8 +333,8 @@ void GlScope::generateGrid() { @@ -286,8 +333,8 @@ void GlScope::generateGrid() {
286 m_vaoGrid[0].create(); 333 m_vaoGrid[0].create();
287 QOpenGLVertexArrayObject::Binder b(&m_vaoGrid[0]); 334 QOpenGLVertexArrayObject::Binder b(&m_vaoGrid[0]);
288 m_grid.bind(); 335 m_grid.bind();
289 - m_program->enableAttributeArray(vertexLocation);  
290 - m_program->setAttributeBuffer(vertexLocation, GL_FLOAT, 0, 3, 0); 336 + program->enableAttributeArray(vertexLocation);
  337 + program->setAttributeBuffer(vertexLocation, GL_FLOAT, 0, 3, 0);
291 } 338 }
292 339
293 // Draw vertical lines 340 // Draw vertical lines
@@ -318,8 +365,8 @@ void GlScope::generateGrid() { @@ -318,8 +365,8 @@ void GlScope::generateGrid() {
318 m_vaoGrid[1].create(); 365 m_vaoGrid[1].create();
319 QOpenGLVertexArrayObject::Binder b(&m_vaoGrid[1]); 366 QOpenGLVertexArrayObject::Binder b(&m_vaoGrid[1]);
320 m_grid.bind(); 367 m_grid.bind();
321 - m_program->enableAttributeArray(vertexLocation);  
322 - m_program->setAttributeBuffer(vertexLocation, GL_FLOAT, int(vaGrid.size() * sizeof(QVector3D)), 3); 368 + program->enableAttributeArray(vertexLocation);
  369 + program->setAttributeBuffer(vertexLocation, GL_FLOAT, int(vaGrid.size() * sizeof(QVector3D)), 3);
323 } 370 }
324 371
325 // Axes 372 // Axes
@@ -353,8 +400,8 @@ void GlScope::generateGrid() { @@ -353,8 +400,8 @@ void GlScope::generateGrid() {
353 m_vaoGrid[2].create(); 400 m_vaoGrid[2].create();
354 QOpenGLVertexArrayObject::Binder b(&m_vaoGrid[2]); 401 QOpenGLVertexArrayObject::Binder b(&m_vaoGrid[2]);
355 m_grid.bind(); 402 m_grid.bind();
356 - m_program->enableAttributeArray(vertexLocation);  
357 - m_program->setAttributeBuffer(vertexLocation, GL_FLOAT, int(vaGrid.size() * sizeof(QVector3D)), 3); 403 + program->enableAttributeArray(vertexLocation);
  404 + program->setAttributeBuffer(vertexLocation, GL_FLOAT, int(vaGrid.size() * sizeof(QVector3D)), 3);
358 } 405 }
359 406
360 // Border 407 // Border
@@ -368,6 +415,29 @@ void GlScope::generateGrid() { @@ -368,6 +415,29 @@ void GlScope::generateGrid() {
368 m_grid.release(); 415 m_grid.release();
369 } 416 }
370 417
  418 +void GlScope::drawGrid() {
  419 + auto *gl = context()->versionFunctions<OPENGL_VER>();
  420 + gl->glLineWidth(1);
  421 +
  422 + // Grid
  423 + m_vaoGrid[0].bind();
  424 + m_program->setUniformValue(colorLocation, view->screen.grid);
  425 + gl->glDrawArrays(GL_POINTS, 0, gridDrawCounts[0]);
  426 + m_vaoGrid[0].release();
  427 +
  428 + // Axes
  429 + m_vaoGrid[1].bind();
  430 + m_program->setUniformValue(colorLocation, view->screen.axes);
  431 + gl->glDrawArrays(GL_LINES, 0, gridDrawCounts[1]);
  432 + m_vaoGrid[1].release();
  433 +
  434 + // Border
  435 + m_vaoGrid[2].bind();
  436 + m_program->setUniformValue(colorLocation, view->screen.border);
  437 + gl->glDrawArrays(GL_LINE_LOOP, 0, gridDrawCounts[2]);
  438 + m_vaoGrid[2].release();
  439 +}
  440 +
371 void GlScope::drawMarkers() { 441 void GlScope::drawMarkers() {
372 auto *gl = context()->versionFunctions<OPENGL_VER>(); 442 auto *gl = context()->versionFunctions<OPENGL_VER>();
373 QColor trColor = view->screen.markers; 443 QColor trColor = view->screen.markers;
@@ -375,23 +445,13 @@ void GlScope::drawMarkers() { @@ -375,23 +445,13 @@ void GlScope::drawMarkers() {
375 445
376 m_vaoMarker.bind(); 446 m_vaoMarker.bind();
377 447
378 - for (unsigned marker = 0; marker < vaMarker.size(); ++marker) {  
379 - if (!scope->horizontal.marker_visible[marker]) continue;  
380 - vaMarker[marker] = {QVector3D((GLfloat)scope->horizontal.marker[marker], -DIVS_VOLTAGE, 0.0f),  
381 - QVector3D((GLfloat)scope->horizontal.marker[marker], DIVS_VOLTAGE, 0.0f)};  
382 - }  
383 -  
384 - // Write coordinates to GPU  
385 - m_marker.bind();  
386 - m_marker.write(0, vaMarker.data(), vaMarker.size() * sizeof(Line));  
387 -  
388 // Draw all 448 // Draw all
389 gl->glLineWidth(1); 449 gl->glLineWidth(1);
390 gl->glDrawArrays(GL_LINES, 0, (GLsizei)vaMarker.size() * 2); 450 gl->glDrawArrays(GL_LINES, 0, (GLsizei)vaMarker.size() * 2);
391 - m_marker.release();  
392 451
393 // Draw selected 452 // Draw selected
394 if (selectedMarker != NO_MARKER) { 453 if (selectedMarker != NO_MARKER) {
  454 + qWarning() << selectedMarker;
395 gl->glLineWidth(3); 455 gl->glLineWidth(3);
396 gl->glDrawArrays(GL_LINES, selectedMarker * 2, (GLsizei)2); 456 gl->glDrawArrays(GL_LINES, selectedMarker * 2, (GLsizei)2);
397 } 457 }
openhantek/src/glscope.h
@@ -31,10 +31,16 @@ class GlScope : public QOpenGLWidget { @@ -31,10 +31,16 @@ class GlScope : public QOpenGLWidget {
31 QWidget *parent = 0); 31 QWidget *parent = 0);
32 32
33 /** 33 /**
  34 + * We need at least OpenGL 3.2 with shader version 150 or
  35 + * OpenGL ES 2.0 with shader version 100.
  36 + */
  37 + static void fixOpenGLversion();
  38 + /**
34 * Show new post processed data 39 * Show new post processed data
35 * @param data 40 * @param data
36 */ 41 */
37 void showData(PPresult* data); 42 void showData(PPresult* data);
  43 + void markerUpdated();
38 44
39 protected: 45 protected:
40 /// \brief Initializes the scope widget. 46 /// \brief Initializes the scope widget.
@@ -42,21 +48,23 @@ class GlScope : public QOpenGLWidget { @@ -42,21 +48,23 @@ class GlScope : public QOpenGLWidget {
42 /// \param parent The parent widget. 48 /// \param parent The parent widget.
43 GlScope(DsoSettingsScope *scope, DsoSettingsView *view, QWidget *parent = 0); 49 GlScope(DsoSettingsScope *scope, DsoSettingsView *view, QWidget *parent = 0);
44 virtual ~GlScope(); 50 virtual ~GlScope();
  51 + GlScope(const GlScope&) = delete;
45 52
46 /// \brief Initializes OpenGL output. 53 /// \brief Initializes OpenGL output.
47 - void initializeGL() override; 54 + virtual void initializeGL() override;
48 55
49 /// \brief Draw the graphs, marker and the grid. 56 /// \brief Draw the graphs, marker and the grid.
50 - void paintGL() override; 57 + virtual void paintGL() override;
51 58
52 /// \brief Resize the widget. 59 /// \brief Resize the widget.
53 /// \param width The new width of the widget. 60 /// \param width The new width of the widget.
54 /// \param height The new height of the widget. 61 /// \param height The new height of the widget.
55 - void resizeGL(int width, int height) override; 62 + virtual void resizeGL(int width, int height) override;
56 63
57 - void mousePressEvent(QMouseEvent *event) override;  
58 - void mouseMoveEvent(QMouseEvent *event) override;  
59 - void mouseReleaseEvent(QMouseEvent *event) override; 64 + virtual void mousePressEvent(QMouseEvent *event) override;
  65 + virtual void mouseMoveEvent(QMouseEvent *event) override;
  66 + virtual void mouseReleaseEvent(QMouseEvent *event) override;
  67 + virtual void paintEvent(QPaintEvent *event) override;
60 68
61 /// \brief Draw the grid. 69 /// \brief Draw the grid.
62 void drawGrid(); 70 void drawGrid();
@@ -91,13 +99,15 @@ class GlScope : public QOpenGLWidget { @@ -91,13 +99,15 @@ class GlScope : public QOpenGLWidget {
91 QOpenGLBuffer m_grid; 99 QOpenGLBuffer m_grid;
92 QOpenGLVertexArrayObject m_vaoGrid[3]; 100 QOpenGLVertexArrayObject m_vaoGrid[3];
93 GLsizei gridDrawCounts[3]; 101 GLsizei gridDrawCounts[3];
94 - void generateGrid(); 102 + void generateGrid(QOpenGLShaderProgram *program);
95 103
96 // Graphs 104 // Graphs
97 std::list<Graph> m_GraphHistory; 105 std::list<Graph> m_GraphHistory;
98 unsigned currentGraphInHistory = 0; 106 unsigned currentGraphInHistory = 0;
99 107
100 // OpenGL shader, matrix, var-locations 108 // OpenGL shader, matrix, var-locations
  109 + bool shaderCompileSuccess = false;
  110 + QString errorMessage;
101 std::unique_ptr<QOpenGLShaderProgram> m_program; 111 std::unique_ptr<QOpenGLShaderProgram> m_program;
102 QMatrix4x4 pmvMatrix; ///< projection, view matrix 112 QMatrix4x4 pmvMatrix; ///< projection, view matrix
103 int colorLocation; 113 int colorLocation;
openhantek/src/main.cpp
@@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
24 #include "usb/usbdevice.h" 24 #include "usb/usbdevice.h"
25 #include "viewconstants.h" 25 #include "viewconstants.h"
26 26
  27 +#include "glscope.h"
  28 +
27 #ifndef VERSION 29 #ifndef VERSION
28 #error "You need to run the cmake buildsystem!" 30 #error "You need to run the cmake buildsystem!"
29 #endif 31 #endif
@@ -69,14 +71,8 @@ int main(int argc, char *argv[]) { @@ -69,14 +71,8 @@ int main(int argc, char *argv[]) {
69 QCoreApplication::setApplicationName("OpenHantek"); 71 QCoreApplication::setApplicationName("OpenHantek");
70 QCoreApplication::setApplicationVersion(VERSION); 72 QCoreApplication::setApplicationVersion(VERSION);
71 73
72 - QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true);  
73 - QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true); 74 + GlScope::fixOpenGLversion();
74 75
75 - // Prefer full desktop OpenGL without fixed pipeline  
76 - QSurfaceFormat format;  
77 - format.setProfile(QSurfaceFormat::CoreProfile);  
78 - format.setSamples(4); // Antia-Aliasing, Multisampling  
79 - QSurfaceFormat::setDefaultFormat(format);  
80 QApplication openHantekApplication(argc, argv); 76 QApplication openHantekApplication(argc, argv);
81 77
82 //////// Load translations //////// 78 //////// Load translations ////////
@@ -155,5 +151,10 @@ int main(int argc, char *argv[]) { @@ -155,5 +151,10 @@ int main(int argc, char *argv[]) {
155 151
156 postProcessingThread.quit(); 152 postProcessingThread.quit();
157 postProcessingThread.wait(10000); 153 postProcessingThread.wait(10000);
  154 +
  155 + if (context && device != nullptr) {
  156 + libusb_exit(context);
  157 + }
  158 +
158 return res; 159 return res;
159 } 160 }
openhantek/src/scopesettings.h
@@ -11,6 +11,7 @@ @@ -11,6 +11,7 @@
11 #include <vector> 11 #include <vector>
12 12
13 #define MARKER_COUNT 2 ///< Number of markers 13 #define MARKER_COUNT 2 ///< Number of markers
  14 +#define MARKER_STEP (DIVS_TIME / 100.0)
14 15
15 /// \brief Holds the settings for the horizontal axis. 16 /// \brief Holds the settings for the horizontal axis.
16 struct DsoSettingsScopeHorizontal { 17 struct DsoSettingsScopeHorizontal {
openhantek/src/widgets/levelslider.cpp
@@ -196,17 +196,14 @@ double LevelSlider::maximum(int index) const { @@ -196,17 +196,14 @@ double LevelSlider::maximum(int index) const {
196 /// \param minimum The value a slider has at the bottommost/leftmost position. 196 /// \param minimum The value a slider has at the bottommost/leftmost position.
197 /// \param maximum The value a slider has at the topmost/rightmost position. 197 /// \param maximum The value a slider has at the topmost/rightmost position.
198 /// \return -1 on error, fixValue result on success. 198 /// \return -1 on error, fixValue result on success.
199 -int LevelSlider::setLimits(int index, double minimum, double maximum) {  
200 - if (index < 0 || index >= this->slider.count()) return -1; 199 +void LevelSlider::setLimits(int index, double minimum, double maximum) {
  200 + if (index < 0 || index >= this->slider.count()) return;
201 201
202 this->slider[index]->minimum = minimum; 202 this->slider[index]->minimum = minimum;
203 this->slider[index]->maximum = maximum; 203 this->slider[index]->maximum = maximum;
204 - int result = this->fixValue(index);  
205 - 204 + this->fixValue(index);
206 this->calculateRect(index); 205 this->calculateRect(index);
207 this->repaint(); 206 this->repaint();
208 -  
209 - return result;  
210 } 207 }
211 208
212 /// \brief Return the step width of the sliders. 209 /// \brief Return the step width of the sliders.
@@ -243,8 +240,8 @@ double LevelSlider::value(int index) const { @@ -243,8 +240,8 @@ double LevelSlider::value(int index) const {
243 /// \param index The index of the slider whose value should be set. 240 /// \param index The index of the slider whose value should be set.
244 /// \param value The new value of the slider. 241 /// \param value The new value of the slider.
245 /// \return The new value of the slider. 242 /// \return The new value of the slider.
246 -double LevelSlider::setValue(int index, double value) {  
247 - if (index < 0 || index >= this->slider.count()) return -1; 243 +void LevelSlider::setValue(int index, double value) {
  244 + if (index < 0 || index >= this->slider.count()) return;
248 245
249 // Apply new value 246 // Apply new value
250 this->slider[index]->value = value; 247 this->slider[index]->value = value;
@@ -254,8 +251,6 @@ double LevelSlider::setValue(int index, double value) { @@ -254,8 +251,6 @@ double LevelSlider::setValue(int index, double value) {
254 this->repaint(); 251 this->repaint();
255 252
256 if (this->pressedSlider < 0) emit valueChanged(index, value); 253 if (this->pressedSlider < 0) emit valueChanged(index, value);
257 -  
258 - return this->slider[index]->value;  
259 } 254 }
260 255
261 /// \brief Return the direction of the sliders. 256 /// \brief Return the direction of the sliders.
@@ -563,17 +558,14 @@ int LevelSlider::calculateWidth() { @@ -563,17 +558,14 @@ int LevelSlider::calculateWidth() {
563 /// \brief Fix the value if it's outside the limits. 558 /// \brief Fix the value if it's outside the limits.
564 /// \param index The index of the slider who should be fixed. 559 /// \param index The index of the slider who should be fixed.
565 /// \return 0 when ok, -1 on error, 1 when increased and 2 when decreased. 560 /// \return 0 when ok, -1 on error, 1 when increased and 2 when decreased.
566 -int LevelSlider::fixValue(int index) {  
567 - if (index < 0 || index >= this->slider.count()) return -1; 561 +void LevelSlider::fixValue(int index) {
  562 + if (index < 0 || index >= this->slider.count()) return;
568 563
569 double lowest = qMin(this->slider[index]->minimum, this->slider[index]->maximum); 564 double lowest = qMin(this->slider[index]->minimum, this->slider[index]->maximum);
570 double highest = qMax(this->slider[index]->minimum, this->slider[index]->maximum); 565 double highest = qMax(this->slider[index]->minimum, this->slider[index]->maximum);
571 if (this->slider[index]->value < lowest) { 566 if (this->slider[index]->value < lowest) {
572 this->slider[index]->value = lowest; 567 this->slider[index]->value = lowest;
573 - return 1;  
574 } else if (this->slider[index]->value > highest) { 568 } else if (this->slider[index]->value > highest) {
575 this->slider[index]->value = highest; 569 this->slider[index]->value = highest;
576 - return 2;  
577 } 570 }
578 - return 0;  
579 } 571 }
openhantek/src/widgets/levelslider.h
@@ -51,11 +51,11 @@ class LevelSlider : public QWidget { @@ -51,11 +51,11 @@ class LevelSlider : public QWidget {
51 51
52 double minimum(int index) const; 52 double minimum(int index) const;
53 double maximum(int index) const; 53 double maximum(int index) const;
54 - int setLimits(int index, double minimum, double maximum); 54 + void setLimits(int index, double minimum, double maximum);
55 double step(int index) const; 55 double step(int index) const;
56 double setStep(int index, double step); 56 double setStep(int index, double step);
57 double value(int index) const; 57 double value(int index) const;
58 - double setValue(int index, double value); 58 + void setValue(int index, double value);
59 59
60 // Parameters for all sliders 60 // Parameters for all sliders
61 Qt::ArrowType direction() const; 61 Qt::ArrowType direction() const;
@@ -71,7 +71,7 @@ class LevelSlider : public QWidget { @@ -71,7 +71,7 @@ class LevelSlider : public QWidget {
71 71
72 QRect calculateRect(int sliderId); 72 QRect calculateRect(int sliderId);
73 int calculateWidth(); 73 int calculateWidth();
74 - int fixValue(int index); 74 + void fixValue(int index);
75 75
76 QList<LevelSliderParameters *> slider; ///< The parameters for each slider 76 QList<LevelSliderParameters *> slider; ///< The parameters for each slider
77 int pressedSlider; ///< The currently pressed (moved) slider 77 int pressedSlider; ///< The currently pressed (moved) slider