1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-20 10:54:14 +01:00

LP-597 Progress bar for GCS log replay - switch to double-function button for Play/Pause

- remove separate play and pause buttons, combine these functions in one playPause button.
- update icons & button texts
- move resources (icons) to logging plugin's own images folder
- explain why looking for the next timestamp after the last played one is useful.
  It causes the replay process to jump over parts of the logfile where no data has been recorded
  and jumps straight to the first timestamp after that part of the log where data is missing.
This commit is contained in:
Jan NIJS 2018-04-28 14:56:36 +02:00
parent c53e99ee41
commit ef3cb8bf46
10 changed files with 241 additions and 354 deletions

View File

@ -154,46 +154,29 @@ void LogFile::timerFired()
if (m_replayStatus != PLAYING) {
return;
}
m_timer_tick++;
if ( m_timer_tick % 100 == 0 ) {
qDebug() << "----------------------------------------------------------";
qDebug() << "LogFile::timerFired() -> Tick = " << m_timer_tick;
}
if (m_file.bytesAvailable() > 4) {
int time;
time = m_myTime.elapsed();
/*
This code generates an advancing window. All samples that fit in the window
This code generates an advancing playback window. All samples that fit the window
are replayed. The window is about the size of the timer interval: 10 ms.
Description of used variables:
time : time passed since start of playback (in ms) - current
m_timeOffset : time passed since start of playback (in ms) - when timerFired() was previously run
m_lastPlayed : next log timestamp to advance to (in ms)
m_nextTimeStamp : timestamp of most recently read log entry (in ms)
m_playbackSpeed : 1 .. 10 replay speedup factor
time : real-time interval since start of playback (in ms) - now()
m_timeOffset : real-time interval since start of playback (in ms) - when timerFired() was previously run
m_nextTimeStamp : read log until this log timestamp has been reached (in ms)
m_lastPlayed : log referenced timestamp advanced to during previous cycle (in ms)
m_playbackSpeed : 0.1 .. 1.0 .. 10 replay speedup factor
*/
while ( m_nextTimeStamp < (m_lastPlayed + (double)(time - m_timeOffset) * m_playbackSpeed) ) {
// if ( m_timer_tick % 100 == 0 ) {
// if ( true ) {
// qDebug() << "LogFile::timerFired() -> m_lastPlayed = " << m_lastPlayed;
// qDebug() << "LogFile::timerFired() -> m_nextTimeStamp = " << m_nextTimeStamp;
// qDebug() << "LogFile::timerFired() -> time = " << time;
// qDebug() << "LogFile::timerFired() -> m_timeOffset = " << m_timeOffset;
// qDebug() << "---";
// qDebug() << "LogFile::timerFired() -> m_nextTimeStamp = " << m_nextTimeStamp;
// qDebug() << "LogFile::timerFired() -> (m_lastPlayed + (double)(time - m_timeOffset) * m_playbackSpeed) = " << (m_lastPlayed + (double)(time - m_timeOffset) * m_playbackSpeed);
// qDebug() << "---";
// }
// advance the replay window for the next time period
m_lastPlayed += ((double)(time - m_timeOffset) * m_playbackSpeed);
// read data size
@ -229,7 +212,7 @@ void LogFile::timerFired()
// rate-limit slider bar position updates to 10 updates per second
if (m_timer_tick % 10 == 0) {
emit replayPosition(m_nextTimeStamp);
emit playbackPosition(m_nextTimeStamp);
}
// read next timestamp
if (m_file.bytesAvailable() < (qint64)sizeof(m_nextTimeStamp)) {
@ -269,13 +252,11 @@ bool LogFile::isPlaying() const
* Starts a timer: m_timer
*
* This function and the stopReplay() function should only ever be called from the same thread.
* This is required for correctly controlling the timer.
* This is required for correct control of the timer.
*
*/
bool LogFile::startReplay()
{
qDebug() << "startReplay(): start of function, current Thread ID is: " << QThread::currentThreadId();
// Walk through logfile and create timestamp index
// Don't start replay if there was a problem indexing the logfile.
if (!buildIndex()) {
@ -325,8 +306,6 @@ bool LogFile::startReplay()
*/
bool LogFile::stopReplay()
{
qDebug() << "stopReplay(): start of function, current Thread ID is: " << QThread::currentThreadId();
if (!m_file.isOpen() || !m_timer.isActive()) {
return false;
}
@ -338,41 +317,59 @@ bool LogFile::stopReplay()
return true;
}
/**
* SLOT: restartReplay()
* SLOT: resumeReplay()
*
* This function starts replay from the begining of the currently opened logfile.
* Resumes replay from the given position.
* If no position is given, resumes from the last position
*
*/
void LogFile::restartReplay()
bool LogFile::resumeReplay(quint32 desiredPosition)
{
qDebug() << "restartReplay(): start of function, current Thread ID is: " << QThread::currentThreadId();
if (m_timer.isActive()) {
return false;
}
resumeReplayFrom(0);
// Clear the playout buffer:
m_mutex.lock();
m_dataBuffer.clear();
m_mutex.unlock();
qDebug() << "restartReplay(): end of function, current Thread ID is: " << QThread::currentThreadId();
m_file.seek(0);
/* Skip through the logfile until we reach the desired position.
Looking for the next log timestamp after the desired position
has the advantage that it skips over parts of the log
where data might be missing.
*/
for (int i = 0; i < m_timeStamps.size(); i++) {
if (m_timeStamps.at(i) >= desiredPosition) {
m_file.seek(m_timeStampPositions.at(i));
m_lastPlayed = m_timeStamps.at(i);
break;
}
}
m_file.read((char *)&m_nextTimeStamp, sizeof(m_nextTimeStamp));
// Real-time timestamps don't not need to match the log timestamps.
// However the delta between real-time variables "m_timeOffset" and "m_myTime" is important.
// This delta determines the number of log entries replayed per cycle.
// Set the real-time interval to 0 to start with:
m_myTime.restart();
m_timeOffset = 0;
m_replayStatus = PLAYING;
m_timer.start();
// Notify UI that playback has resumed
emit replayStarted();
return true;
}
/**
* SLOT: haltReplay()
*
* Stops replay without storing the current playback position
*
*/
void LogFile::haltReplay()
{
qDebug() << "haltReplay(): start of function, current Thread ID is: " << QThread::currentThreadId();
qDebug() << "haltReplay() time = m_myTime.elapsed() = " << m_myTime.elapsed();
qDebug() << "haltReplay() m_timeOffset = " << m_timeOffset;
qDebug() << "haltReplay() m_nextTimeStamp = " << m_nextTimeStamp;
qDebug() << "haltReplay() m_lastPlayed = " << m_lastPlayed;
m_replayStatus = STOPPED;
qDebug() << "haltReplay(): end of function, current Thread ID is: " << QThread::currentThreadId();
}
/**
* SLOT: pauseReplay()
*
@ -381,13 +378,6 @@ void LogFile::haltReplay()
*/
bool LogFile::pauseReplay()
{
qDebug() << "pauseReplay(): start of function, current Thread ID is: " << QThread::currentThreadId();
qDebug() << "pauseReplay() time = m_myTime.elapsed() = " << m_myTime.elapsed();
qDebug() << "pauseReplay() m_timeOffset = " << m_timeOffset;
qDebug() << "pauseReplay() m_nextTimeStamp = " << m_nextTimeStamp;
qDebug() << "pauseReplay() m_lastPlayed = " << m_lastPlayed;
if (!m_timer.isActive()) {
return false;
}
@ -401,99 +391,27 @@ bool LogFile::pauseReplay()
}
/**
* SLOT: resumeReplay()
* SLOT: pauseAndResetPosition()
*
* Resumes replay from the stored playback position
* Pauses replay and resets the playback position to the start of the logfile
*
*/
bool LogFile::resumeReplay()
bool LogFile::pauseAndResetPosition()
{
qDebug() << "resumeReplay(): start of function, current Thread ID is: " << QThread::currentThreadId();
m_mutex.lock();
m_dataBuffer.clear();
m_mutex.unlock();
m_file.seek(0);
for (int i = 0; i < m_timeStamps.size(); ++i) {
if (m_timeStamps.at(i) >= m_lastPlayed) {
m_file.seek(m_timeStampPositions.at(i));
break;
}
}
m_file.read((char *)&m_nextTimeStamp, sizeof(m_nextTimeStamp));
m_myTime.restart();
m_myTime = m_myTime.addMSecs(-m_timeOffset); // Set startpoint this far back in time.
qDebug() << "resumeReplay() time = m_myTime.elapsed() = " << m_myTime.elapsed();
qDebug() << "resumeReplay() m_timeOffset = " << m_timeOffset;
qDebug() << "resumeReplay() m_nextTimeStamp = " << m_nextTimeStamp;
qDebug() << "resumeReplay() m_lastPlayed = " << m_lastPlayed;
qDebug() << "resumeReplay(): end of function, current Thread ID is: " << QThread::currentThreadId();
if (m_timer.isActive()) {
if (!m_file.isOpen() || !m_timer.isActive()) {
return false;
}
qDebug() << "LogFile - resumeReplay";
m_timeOffset = m_myTime.elapsed();
m_timer.start();
m_replayStatus = PLAYING;
m_timer.stop();
m_replayStatus = STOPPED;
m_timeOffset = 0;
m_lastPlayed = m_timeStamps.at(0);
m_previousTimeStamp = 0;
m_nextTimeStamp = 0;
// Notify UI that replay has been resumed
emit replayStarted();
return true;
}
/**
* SLOT: resumeReplayFrom()
*
* Resumes replay from the given position
*
*/
void LogFile::resumeReplayFrom(quint32 desiredPosition)
{
qDebug() << "resumeReplayFrom(): start of function, current Thread ID is: " << QThread::currentThreadId();
m_mutex.lock();
m_dataBuffer.clear();
m_mutex.unlock();
m_file.seek(0);
qint32 i;
for (i = 0; i < m_timeStamps.size(); ++i) {
if (m_timeStamps.at(i) >= desiredPosition) {
m_file.seek(m_timeStampPositions.at(i));
m_lastPlayed = m_timeStamps.at(i);
break;
}
}
m_file.read((char *)&m_nextTimeStamp, sizeof(m_nextTimeStamp));
if (m_nextTimeStamp != m_timeStamps.at(i)) {
qDebug() << "resumeReplayFrom() m_nextTimeStamp != m_timeStamps.at(i) -> " << m_nextTimeStamp << " != " << m_timeStamps.at(i);
}
// m_timeOffset = (m_lastPlayed - m_nextTimeStamp) / m_playbackSpeed;
m_timeOffset = 0;
m_myTime.restart();
// m_myTime = m_myTime.addMSecs(-m_timeOffset); // Set startpoint this far back in time.
// TODO: The above line is a possible memory leak. I'm not sure how to handle this correctly.
qDebug() << "resumeReplayFrom() time = m_myTime.elapsed() = " << m_myTime.elapsed();
qDebug() << "resumeReplayFrom() m_timeOffset = " << m_timeOffset;
qDebug() << "resumeReplayFrom() m_nextTimeStamp = " << m_nextTimeStamp;
qDebug() << "resumeReplayFrom() m_lastPlayed = " << m_lastPlayed;
m_replayStatus = PLAYING;
emit replayStarted();
qDebug() << "resumeReplayFrom(): end of function, current Thread ID is: " << QThread::currentThreadId();
}
/**
* FUNCTION: getReplayStatus()
*
@ -532,7 +450,6 @@ bool LogFile::buildIndex()
dataStream.readRawData((char *)&timeStamp, 4);
m_timeStamps.append(timeStamp);
m_timeStampPositions.append(readPointer);
qDebug() << "LogFile::buildIndex() element index = " << index << " \t-> timestamp = " << timeStamp << " \t-> bytes in file = " << readPointer;
readPointer += 4;
index++;
m_beginTimeStamp = timeStamp;
@ -569,13 +486,11 @@ bool LogFile::buildIndex()
// read the next timestamp
if (totalSize - readPointer >= 4) {
dataStream.readRawData((char *)&timeStamp, 4);
qDebug() << "LogFile::buildIndex() element index = " << index << " \t-> timestamp = " << timeStamp << " \t-> bytes in file = " << readPointer;
// some validity checks
if (timeStamp < m_endTimeStamp // logfile goes back in time
|| (timeStamp - m_endTimeStamp) > (60 * 60 * 1000)) { // gap of more than 60 minutes)
qDebug() << "Error: Logfile corrupted! Unlikely timestamp " << timeStamp << " after " << m_endTimeStamp;
// return false;
}
m_timeStamps.append(timeStamp);
@ -589,9 +504,6 @@ bool LogFile::buildIndex()
}
}
qDebug() << "buildIndex() -> first timestamp in log = " << m_beginTimeStamp;
qDebug() << "buildIndex() -> last timestamp in log = " << m_endTimeStamp;
emit updateBeginAndEndtimes(m_beginTimeStamp, m_endTimeStamp);
// reset the read pointer to the start of the file
@ -599,20 +511,3 @@ bool LogFile::buildIndex()
return true;
}
/**
* FUNCTION: setReplaySpeed()
*
* Update the replay speed.
*
* FIXME: currently, changing the replay speed, while skipping through the logfile
* with the position bar causes position alignment to be lost.
*
*/
void LogFile::setReplaySpeed(double val)
{
m_playbackSpeed = val;
qDebug() << "Playback speed is now " << QString("%1").arg(m_playbackSpeed, 4, 'f', 2, QChar('0'));
}

View File

@ -81,14 +81,17 @@ public:
ReplayState getReplayStatus();
public slots:
void setReplaySpeed(double val);
void setReplaySpeed(double val)
{
m_playbackSpeed = val;
qDebug() << "Playback speed is now" << m_playbackSpeed;
};
bool startReplay();
bool stopReplay();
bool resumeReplay(quint32);
bool pauseReplay();
bool resumeReplay();
void resumeReplayFrom(quint32);
void restartReplay();
void haltReplay();
bool pauseAndResetPosition();
protected slots:
void timerFired();
@ -96,7 +99,7 @@ protected slots:
signals:
void replayStarted();
void replayFinished();
void replayPosition(quint32);
void playbackPosition(quint32);
void updateBeginAndEndtimes(quint32, quint32);
protected:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 970 B

View File

@ -24,3 +24,5 @@ OTHER_FILES += LoggingGadget.pluginspec
FORMS += logging.ui
RESOURCES += \
res.qrc

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>439</width>
<height>150</height>
<height>118</height>
</rect>
</property>
<property name="sizePolicy">
@ -19,22 +19,22 @@
<property name="minimumSize">
<size>
<width>100</width>
<height>150</height>
<height>118</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,1">
<item>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0">
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="2,2,2,0,0,0">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,2,0,0,2,0,0">
<property name="sizeConstraint">
<enum>QLayout::SetNoConstraint</enum>
</property>
<item>
<widget class="QPushButton" name="playButton">
<widget class="QPushButton" name="playPauseButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -48,35 +48,18 @@
</size>
</property>
<property name="text">
<string>Play</string>
<string> Play</string>
</property>
<property name="icon">
<iconset resource="../notify/res.qrc">
<normaloff>:/notify/images/play.png</normaloff>:/notify/images/play.png</iconset>
<iconset resource="../logging/res.qrc">
<normaloff>:/logging/images/play.png</normaloff>:/logging/images/play.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pauseButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<property name="iconSize">
<size>
<width>30</width>
<height>0</height>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="text">
<string>Pause</string>
</property>
<property name="icon">
<iconset resource="../notify/res.qrc">
<normaloff>:/notify/images/stop.png</normaloff>:/notify/images/stop.png</iconset>
</property>
</widget>
</item>
<item>
@ -94,11 +77,17 @@
</size>
</property>
<property name="text">
<string>Stop</string>
<string> Stop</string>
</property>
<property name="icon">
<iconset resource="../notify/res.qrc">
<normaloff>:/notify/images/delete.png</normaloff>:/notify/images/delete.png</iconset>
<iconset resource="../logging/res.qrc">
<normaloff>:/logging/images/stop.png</normaloff>:/logging/images/stop.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
</widget>
</item>
@ -115,6 +104,45 @@
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Playback speed:</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="playbackSpeed">
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
@ -137,49 +165,6 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Playback speed:</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="playbackSpeed">
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>0.10000000000000</double>
</property>
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.10000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QSlider" name="playBackPosition">
<property name="tracking">
@ -290,7 +275,7 @@
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<height>5</height>
</size>
</property>
</spacer>
@ -298,7 +283,7 @@
</layout>
</widget>
<resources>
<include location="../notify/res.qrc"/>
<include location="../logging/res.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -43,12 +43,11 @@ LoggingGadgetWidget::LoggingGadgetWidget(QWidget *parent) : QWidget(parent), log
disableButtons();
// Configure timer to delay application of slider position action for 200ms
sliderActionDelay.setSingleShot(true);
sliderActionDelay.setInterval(200); // Delay for 200 ms
sliderActionDelay.setInterval(200);
connect(&sliderActionDelay, SIGNAL(timeout()), this, SLOT(sendResumeReplayFrom()));
m_storedPosition = 0;
connect(&sliderActionDelay, SIGNAL(timeout()), this, SLOT(sliderAction()));
}
LoggingGadgetWidget::~LoggingGadgetWidget()
@ -59,83 +58,90 @@ LoggingGadgetWidget::~LoggingGadgetWidget()
void LoggingGadgetWidget::setPlugin(LoggingPlugin *p)
{
loggingPlugin = p;
connect(p->getLogfile(), SIGNAL(updateBeginAndEndtimes(quint32, quint32)), this, SLOT(updateBeginAndEndtimes(quint32, quint32)));
connect(p->getLogfile(), SIGNAL(replayPosition(quint32)), this, SLOT(replayPosition(quint32)));
connect(m_logging->playBackPosition, SIGNAL(valueChanged(int)), this, SLOT(sliderMoved(int)));
connect(this, SIGNAL(resumeReplayFrom(quint32)), p->getLogfile(), SLOT(resumeReplayFrom(quint32)));
connect(this, SIGNAL(startReplay()), p->getLogfile(), SLOT(restartReplay()));
connect(this, SIGNAL(stopReplay()), p->getLogfile(), SLOT(haltReplay()));
connect(this, SIGNAL(pauseReplay()), p->getLogfile(), SLOT(pauseReplay()));
connect(this, SIGNAL(resumeReplay()), p->getLogfile(), SLOT(resumeReplay()));
connect(this, SIGNAL(startReplay()), scpPlugin, SLOT(startPlotting()));
connect(this, SIGNAL(stopReplay()), scpPlugin, SLOT(stopPlotting()));
connect(this, SIGNAL(pauseReplay()), scpPlugin, SLOT(stopPlotting()));
connect(this, SIGNAL(resumeReplay()), scpPlugin, SLOT(startPlotting()));
connect(m_logging->playButton, SIGNAL(clicked()), this, SLOT(playButton()));
connect(m_logging->pauseButton, SIGNAL(clicked()), this, SLOT(pauseButton()));
connect(m_logging->stopButton, SIGNAL(clicked()), this, SLOT(stopButton()));
connect(p->getLogfile(), SIGNAL(replayStarted()), this, SLOT(enableButtons()));
connect(p->getLogfile(), SIGNAL(replayFinished()), this, SLOT(disableButtons()));
connect(p->getLogfile(), SIGNAL(replayFinished()), scpPlugin, SLOT(stopPlotting()));
connect(m_logging->playbackSpeed, SIGNAL(valueChanged(double)), p->getLogfile(), SLOT(setReplaySpeed(double)));
connect(m_logging->playButton, &QPushButton::clicked, scpPlugin, &ScopeGadgetFactory::startPlotting);
connect(m_logging->pauseButton, &QPushButton::clicked, scpPlugin, &ScopeGadgetFactory::stopPlotting);
LogFile *logFile = loggingPlugin->getLogfile();
connect(m_logging->playButton, &QPushButton::clicked, logFile, &LogFile::resumeReplay);
connect(m_logging->pauseButton, &QPushButton::clicked, logFile, &LogFile::pauseReplay);
// GUI elements to gadgetwidget functions
connect(m_logging->playPauseButton, &QPushButton::clicked, this, &LoggingGadgetWidget::playPauseButtonAction);
connect(m_logging->stopButton, &QPushButton::clicked, this, &LoggingGadgetWidget::stopButtonAction);
connect(m_logging->playBackPosition, &QSlider::valueChanged, this, &LoggingGadgetWidget::sliderMoved);
connect(m_logging->playbackSpeed, static_cast<void(QDoubleSpinBox::*) (double)>(&QDoubleSpinBox::valueChanged), logFile, &LogFile::setReplaySpeed);
// gadgetwidget functions to logfile actions
connect(this, &LoggingGadgetWidget::resumeReplay, logFile, &LogFile::resumeReplay);
connect(this, &LoggingGadgetWidget::pauseReplay, logFile, &LogFile::pauseReplay);
connect(this, &LoggingGadgetWidget::pauseAndResetPosition, logFile, &LogFile::pauseAndResetPosition);
// gadgetwidget functions to scope actions
connect(this, &LoggingGadgetWidget::resumeReplay, scpPlugin, &ScopeGadgetFactory::startPlotting);
connect(this, &LoggingGadgetWidget::pauseReplay, scpPlugin, &ScopeGadgetFactory::stopPlotting);
connect(this, &LoggingGadgetWidget::pauseAndResetPosition, scpPlugin, &ScopeGadgetFactory::stopPlotting);
// Feedback from logfile to GUI
connect(loggingPlugin, &LoggingPlugin::stateChanged, this, &LoggingGadgetWidget::stateChanged);
connect(logFile, &LogFile::updateBeginAndEndtimes, this, &LoggingGadgetWidget::updateBeginAndEndtimes);
connect(logFile, &LogFile::playbackPosition, this, &LoggingGadgetWidget::playbackPosition);
connect(logFile, &LogFile::replayStarted, this, &LoggingGadgetWidget::enableButtons);
connect(logFile, &LogFile::replayFinished, this, &LoggingGadgetWidget::disableButtons);
// Feedback from logfile to scope
connect(logFile, &LogFile::replayFinished, scpPlugin, &ScopeGadgetFactory::stopPlotting);
stateChanged(loggingPlugin->getState());
}
void LoggingGadgetWidget::playButton()
{
ReplayState replayState = (loggingPlugin->getLogfile())->getReplayStatus();
if (replayState == STOPPED) {
emit startReplay();
} else if (replayState == PAUSED) {
emit resumeReplay();
}
m_logging->playButton->setEnabled(false);
m_logging->pauseButton->setEnabled(true);
m_logging->stopButton->setEnabled(true);
/*
setPlayPauseButtonToPlay()
Changes the appearance of the playPause button to the PLAY appearance.
*/
void LoggingGadgetWidget::setPlayPauseButtonToPlay()
{
m_logging->playPauseButton->setIcon(QIcon(":/logging/images/play.png"));
m_logging->playPauseButton->setText(tr(" Play"));
}
void LoggingGadgetWidget::pauseButton()
/*
setPlayPauseButtonToPlay()
Changes the appearance of the playPause button to the PAUSE appearance.
*/
void LoggingGadgetWidget::setPlayPauseButtonToPause()
{
m_logging->playPauseButton->setIcon(QIcon(":/logging/images/pause.png"));
m_logging->playPauseButton->setText(tr(" Pause"));
}
void LoggingGadgetWidget::playPauseButtonAction()
{
ReplayState replayState = (loggingPlugin->getLogfile())->getReplayStatus();
if (replayState == PLAYING) {
if (replayState == PLAYING){
emit pauseReplay();
setPlayPauseButtonToPlay();
} else {
emit resumeReplay(m_logging->playBackPosition->value());
setPlayPauseButtonToPause();
}
m_logging->playButton->setEnabled(true);
m_logging->pauseButton->setEnabled(false);
m_logging->stopButton->setEnabled(true);
}
void LoggingGadgetWidget::stopButton()
void LoggingGadgetWidget::stopButtonAction()
{
ReplayState replayState = (loggingPlugin->getLogfile())->getReplayStatus();
if (replayState != STOPPED) {
emit stopReplay();
emit pauseAndResetPosition();
}
m_logging->playButton->setEnabled(true);
m_logging->pauseButton->setEnabled(false);
m_logging->stopButton->setEnabled(false);
setPlayPauseButtonToPlay();
replayPosition(0);
// Block signals while setting the slider to the start position
m_logging->playBackPosition->blockSignals(true);
m_logging->playBackPosition->setValue(m_logging->playBackPosition->minimum());
m_logging->playBackPosition->blockSignals(false);
}
void LoggingGadgetWidget::stateChanged(LoggingPlugin::State state)
@ -146,6 +152,7 @@ void LoggingGadgetWidget::stateChanged(LoggingPlugin::State state)
switch (state) {
case LoggingPlugin::IDLE:
status = tr("Idle");
playbackPosition(0);
break;
case LoggingPlugin::LOGGING:
status = tr("Logging");
@ -158,9 +165,13 @@ void LoggingGadgetWidget::stateChanged(LoggingPlugin::State state)
m_logging->statusLabel->setText(status);
bool playing = loggingPlugin->getLogfile()->isPlaying();
m_logging->playButton->setEnabled(enabled && !playing);
m_logging->pauseButton->setEnabled(enabled && playing);
m_logging->stopButton->setEnabled(enabled && playing);
m_logging->playPauseButton->setEnabled(enabled);
if (playing){
setPlayPauseButtonToPause();
} else {
setPlayPauseButtonToPlay();
}
}
void LoggingGadgetWidget::updateBeginAndEndtimes(quint32 startTimeStamp, quint32 endTimeStamp)
@ -187,16 +198,17 @@ void LoggingGadgetWidget::updateBeginAndEndtimes(quint32 startTimeStamp, quint32
m_logging->playBackPosition->setTickPosition(QSlider::TicksBothSides);
}
void LoggingGadgetWidget::replayPosition(quint32 positionTimeStamp)
void LoggingGadgetWidget::playbackPosition(quint32 positionTimeStamp)
{
// Update position bar, but only if the user is not updating the slider position
if (!m_logging->playBackPosition->isSliderDown() && !sliderActionDelay.isActive()) {
// Block signals during slider position update:
m_logging->playBackPosition->blockSignals(true);
m_logging->playBackPosition->setValue(positionTimeStamp);
m_logging->playBackPosition->blockSignals(false);
// update current position label
// update position label
updatePositionLabel(positionTimeStamp);
}
}
@ -208,73 +220,59 @@ void LoggingGadgetWidget::enableButtons()
switch (replayState)
{
case STOPPED:
m_logging->playButton->setEnabled(true);
m_logging->pauseButton->setEnabled(false);
m_logging->stopButton->setEnabled(false);
setPlayPauseButtonToPlay();
break;
case PLAYING:
m_logging->playButton->setEnabled(false);
m_logging->pauseButton->setEnabled(true);
m_logging->stopButton->setEnabled(true);
setPlayPauseButtonToPause();
break;
case PAUSED:
m_logging->playButton->setEnabled(true);
m_logging->pauseButton->setEnabled(false);
m_logging->stopButton->setEnabled(true);
setPlayPauseButtonToPlay();
break;
}
m_logging->playPauseButton->setEnabled(true);
m_logging->playBackPosition->setEnabled(true);
}
void LoggingGadgetWidget::disableButtons()
{
// m_logging->startTimeLabel->setText(QString(""));
// m_logging->endTimeLabel->setText(QString(""));
m_logging->playButton->setEnabled(false);
m_logging->pauseButton->setEnabled(false);
m_logging->playPauseButton->setEnabled(false);
setPlayPauseButtonToPlay();
m_logging->stopButton->setEnabled(false);
m_logging->playBackPosition->setEnabled(false);
}
void LoggingGadgetWidget::sliderMoved(int position)
{
qDebug() << "sliderMoved(): start of function, stored position was: " << m_storedPosition;
m_storedPosition = position;
// pause
emit pauseButton();
updatePositionLabel(position);
// Start or restarts a time-out after which replay is resumed from the new position.
sliderActionDelay.start();
qDebug() << "sliderMoved(): end of function, stored position is now: " << m_storedPosition;
}
void LoggingGadgetWidget::updatePositionLabel(quint32 positionTimeStamp)
{
// update position timestamp label
// update position label -> MM:SS
int sec = (positionTimeStamp / 1000) % 60;
int min = positionTimeStamp / (60 * 1000);
m_logging->positionTimestampLabel->setText(QString("%1:%2").arg(min, 2, 10, QChar('0')).arg(sec, 2, 10, QChar('0')));
}
void LoggingGadgetWidget::sendResumeReplayFrom()
void LoggingGadgetWidget::sliderMoved(int position)
{
qDebug() << "sendResumeReplayFrom(): start of function, stored position is: " << m_storedPosition;
// pause playback while the user is dragging the slider to change position
emit pauseReplay();
emit resumeReplayFrom(m_storedPosition);
updatePositionLabel(position);
emit resumeReplay();
qDebug() << "sendResumeReplayFrom(): end of function, stored position is: " << m_storedPosition;
// Start or restarts a time-out after which replay will resume from the new position.
sliderActionDelay.start();
}
void LoggingGadgetWidget::sliderAction()
{
emit resumeReplay(m_logging->playBackPosition->value());
}
/**
* @}

View File

@ -50,31 +50,28 @@ public:
protected slots:
void stateChanged(LoggingPlugin::State state);
void updateBeginAndEndtimes(quint32 startTimeStamp, quint32 endTimeStamp);
void replayPosition(quint32 positionTimeStamp);
void playButton();
void pauseButton();
void stopButton();
void playbackPosition(quint32 positionTimeStamp);
void playPauseButtonAction();
void stopButtonAction();
void enableButtons();
void disableButtons();
void sliderMoved(int);
void sendResumeReplayFrom();
void sliderAction();
signals:
void startReplay();
void stopReplay();
void resumeReplay(quint32 positionTimeStamp);
void pauseReplay();
void resumeReplay();
void resumeReplayFrom(quint32 positionTimeStamp);
void pauseAndResetPosition();
private:
Ui_Logging *m_logging;
LoggingPlugin *loggingPlugin;
ScopeGadgetFactory *scpPlugin;
QTimer sliderActionDelay;
quint32 m_storedPosition;
void updatePositionLabel(quint32 positionTimeStamp);
void setPlayPauseButtonToPlay();
void setPlayPauseButtonToPause();
};
#endif /* LoggingGADGETWIDGET_H_ */

View File

@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/logging">
<file>images/play.png</file>
<file>images/pause.png</file>
<file>images/stop.png</file>
</qresource>
</RCC>