1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-06 21:54:15 +01:00

LP-597 Progress bar for GCS log replay - Resize playPause and stop buttons according to the available space for the widget.

- also make pretty
This commit is contained in:
Jan NIJS 2018-04-29 19:43:46 +02:00
parent d540c2a043
commit fa70cb751c
4 changed files with 133 additions and 40 deletions

View File

@ -176,8 +176,7 @@ void LogFile::timerFired()
*/ */
while ( m_nextTimeStamp < (m_lastPlayed + (double)(time - m_timeOffset) * m_playbackSpeed) ) { while (m_nextTimeStamp < (m_lastPlayed + (double)(time - m_timeOffset) * m_playbackSpeed)) {
// advance the replay window for the next time period // advance the replay window for the next time period
m_lastPlayed += ((double)(time - m_timeOffset) * m_playbackSpeed); m_lastPlayed += ((double)(time - m_timeOffset) * m_playbackSpeed);
@ -344,12 +343,11 @@ bool LogFile::resumeReplay(quint32 desiredPosition)
Looking for the next log timestamp after the desired position Looking for the next log timestamp after the desired position
has the advantage that it skips over parts of the log has the advantage that it skips over parts of the log
where data might be missing. where data might be missing.
*/ */
for (int i = 0; i < m_timeStamps.size(); i++) { for (int i = 0; i < m_timeStamps.size(); i++) {
if (m_timeStamps.at(i) >= desiredPosition) { if (m_timeStamps.at(i) >= desiredPosition) {
int bytesToSkip = m_timeStampPositions.at(i); int bytesToSkip = m_timeStampPositions.at(i);
bool seek_ok = m_file.seek(bytesToSkip); bool seek_ok = m_file.seek(bytesToSkip);
if (!seek_ok) { if (!seek_ok) {
qWarning() << "LogFile resumeReplay - an error occurred while seeking through the logfile."; qWarning() << "LogFile resumeReplay - an error occurred while seeking through the logfile.";
} }
@ -365,7 +363,7 @@ bool LogFile::resumeReplay(quint32 desiredPosition)
// Set the real-time interval to 0 to start with: // Set the real-time interval to 0 to start with:
m_myTime.restart(); m_myTime.restart();
m_timeOffset = 0; m_timeOffset = 0;
m_replayStatus = PLAYING; m_replayStatus = PLAYING;
@ -409,7 +407,7 @@ bool LogFile::pauseAndResetPosition()
} }
qDebug() << "LogFile - pauseAndResetPosition"; qDebug() << "LogFile - pauseAndResetPosition";
m_timer.stop(); m_timer.stop();
m_replayStatus = STOPPED; m_replayStatus = STOPPED;
m_timeOffset = 0; m_timeOffset = 0;
m_lastPlayed = m_timeStamps.at(0); m_lastPlayed = m_timeStamps.at(0);
@ -467,10 +465,10 @@ bool LogFile::buildIndex()
} }
m_timeStamps.append(timeStamp); m_timeStamps.append(timeStamp);
m_timeStampPositions.append(readPointer); m_timeStampPositions.append(readPointer);
readPointer += TIMESTAMP_SIZE_BYTES; readPointer += TIMESTAMP_SIZE_BYTES;
index++; index++;
m_beginTimeStamp = timeStamp; m_beginTimeStamp = timeStamp;
m_endTimeStamp = timeStamp; m_endTimeStamp = timeStamp;
} }
while (true) { while (true) {
@ -511,7 +509,7 @@ bool LogFile::buildIndex()
if (bytesRead != TIMESTAMP_SIZE_BYTES) { if (bytesRead != TIMESTAMP_SIZE_BYTES) {
qWarning() << "LogFile buildIndex - read timeStamp, readRawData returned unexpected number of bytes:" << bytesRead << "at position" << readPointer << "\n"; qWarning() << "LogFile buildIndex - read timeStamp, readRawData returned unexpected number of bytes:" << bytesRead << "at position" << readPointer << "\n";
return false; return false;
} }
// some validity checks // some validity checks
if (timeStamp < m_endTimeStamp // logfile goes back in time if (timeStamp < m_endTimeStamp // logfile goes back in time
@ -522,7 +520,7 @@ bool LogFile::buildIndex()
m_timeStamps.append(timeStamp); m_timeStamps.append(timeStamp);
m_timeStampPositions.append(readPointer); m_timeStampPositions.append(readPointer);
readPointer += TIMESTAMP_SIZE_BYTES; readPointer += TIMESTAMP_SIZE_BYTES;
index++; index++;
m_endTimeStamp = timeStamp; m_endTimeStamp = timeStamp;
} else { } else {

View File

@ -36,8 +36,8 @@
<item> <item>
<widget class="QPushButton" name="playPauseButton"> <widget class="QPushButton" name="playPauseButton">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>80</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
@ -47,11 +47,17 @@
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
<property name="maximumSize">
<size>
<width>80</width>
<height>16777215</height>
</size>
</property>
<property name="text"> <property name="text">
<string> Play</string> <string> Play</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../logging/res.qrc"> <iconset resource="res.qrc">
<normaloff>:/logging/images/play.png</normaloff>:/logging/images/play.png</iconset> <normaloff>:/logging/images/play.png</normaloff>:/logging/images/play.png</iconset>
</property> </property>
<property name="iconSize"> <property name="iconSize">
@ -65,8 +71,8 @@
<item> <item>
<widget class="QPushButton" name="stopButton"> <widget class="QPushButton" name="stopButton">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>80</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
@ -76,11 +82,17 @@
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
<property name="maximumSize">
<size>
<width>80</width>
<height>16777215</height>
</size>
</property>
<property name="text"> <property name="text">
<string> Stop</string> <string> Stop</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../logging/res.qrc"> <iconset resource="res.qrc">
<normaloff>:/logging/images/stop.png</normaloff>:/logging/images/stop.png</iconset> <normaloff>:/logging/images/stop.png</normaloff>:/logging/images/stop.png</iconset>
</property> </property>
<property name="iconSize"> <property name="iconSize">
@ -113,6 +125,12 @@
</item> </item>
<item> <item>
<widget class="QDoubleSpinBox" name="playbackSpeed"> <widget class="QDoubleSpinBox" name="playbackSpeed">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="decimals"> <property name="decimals">
<number>1</number> <number>1</number>
</property> </property>
@ -203,6 +221,12 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
@ -229,6 +253,12 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
@ -255,6 +285,12 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
@ -283,7 +319,7 @@
</layout> </layout>
</widget> </widget>
<resources> <resources>
<include location="../logging/res.qrc"/> <include location="res.qrc"/>
</resources> </resources>
<connections/> <connections/>
</ui> </ui>

View File

@ -41,6 +41,9 @@ LoggingGadgetWidget::LoggingGadgetWidget(QWidget *parent) : QWidget(parent), log
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
scpPlugin = pm->getObject<ScopeGadgetFactory>(); scpPlugin = pm->getObject<ScopeGadgetFactory>();
// Store preferred button width before manipulating the button appearance
m_preferredButtonWidth = m_logging->playPauseButton->sizeHint().width();
disableButtons(); disableButtons();
// Configure timer to delay application of slider position action for 200ms // Configure timer to delay application of slider position action for 200ms
@ -60,65 +63,92 @@ void LoggingGadgetWidget::setPlugin(LoggingPlugin *p)
loggingPlugin = p; loggingPlugin = p;
LogFile *logFile = loggingPlugin->getLogfile(); LogFile *logFile = loggingPlugin->getLogfile();
// GUI elements to gadgetwidget functions // GUI elements to gadgetwidget functions
connect(m_logging->playPauseButton, &QPushButton::clicked, this, &LoggingGadgetWidget::playPauseButtonAction); connect(m_logging->playPauseButton, &QPushButton::clicked, this, &LoggingGadgetWidget::playPauseButtonAction);
connect(m_logging->stopButton, &QPushButton::clicked, this, &LoggingGadgetWidget::stopButtonAction); connect(m_logging->stopButton, &QPushButton::clicked, this, &LoggingGadgetWidget::stopButtonAction);
connect(m_logging->playBackPosition, &QSlider::valueChanged, this, &LoggingGadgetWidget::sliderMoved); connect(m_logging->playBackPosition, &QSlider::valueChanged, this, &LoggingGadgetWidget::sliderMoved);
connect(m_logging->playbackSpeed, static_cast<void(QDoubleSpinBox::*) (double)>(&QDoubleSpinBox::valueChanged), logFile, &LogFile::setReplaySpeed); connect(m_logging->playbackSpeed, static_cast<void(QDoubleSpinBox::*) (double)>(&QDoubleSpinBox::valueChanged), logFile, &LogFile::setReplaySpeed);
// gadgetwidget functions to logfile actions // gadgetwidget functions to logfile actions
connect(this, &LoggingGadgetWidget::resumeReplay, logFile, &LogFile::resumeReplay); connect(this, &LoggingGadgetWidget::resumeReplay, logFile, &LogFile::resumeReplay);
connect(this, &LoggingGadgetWidget::pauseReplay, logFile, &LogFile::pauseReplay); connect(this, &LoggingGadgetWidget::pauseReplay, logFile, &LogFile::pauseReplay);
connect(this, &LoggingGadgetWidget::pauseAndResetPosition, logFile, &LogFile::pauseAndResetPosition); connect(this, &LoggingGadgetWidget::pauseAndResetPosition, logFile, &LogFile::pauseAndResetPosition);
// gadgetwidget functions to scope actions // gadgetwidget functions to scope actions
connect(this, &LoggingGadgetWidget::resumeReplay, scpPlugin, &ScopeGadgetFactory::startPlotting); connect(this, &LoggingGadgetWidget::resumeReplay, scpPlugin, &ScopeGadgetFactory::startPlotting);
connect(this, &LoggingGadgetWidget::pauseReplay, scpPlugin, &ScopeGadgetFactory::stopPlotting); connect(this, &LoggingGadgetWidget::pauseReplay, scpPlugin, &ScopeGadgetFactory::stopPlotting);
connect(this, &LoggingGadgetWidget::pauseAndResetPosition, scpPlugin, &ScopeGadgetFactory::stopPlotting); connect(this, &LoggingGadgetWidget::pauseAndResetPosition, scpPlugin, &ScopeGadgetFactory::stopPlotting);
// Feedback from logfile to GUI // Feedback from logfile to GUI
connect(loggingPlugin, &LoggingPlugin::stateChanged, this, &LoggingGadgetWidget::stateChanged); connect(loggingPlugin, &LoggingPlugin::stateChanged, this, &LoggingGadgetWidget::stateChanged);
connect(logFile, &LogFile::updateBeginAndEndTimes, this, &LoggingGadgetWidget::updateBeginAndEndTimes); connect(logFile, &LogFile::updateBeginAndEndTimes, this, &LoggingGadgetWidget::updateBeginAndEndTimes);
connect(logFile, &LogFile::playbackPosition, this, &LoggingGadgetWidget::playbackPosition); connect(logFile, &LogFile::playbackPosition, this, &LoggingGadgetWidget::playbackPosition);
connect(logFile, &LogFile::replayStarted, this, &LoggingGadgetWidget::enableButtons); connect(logFile, &LogFile::replayStarted, this, &LoggingGadgetWidget::enableButtons);
connect(logFile, &LogFile::replayFinished, this, &LoggingGadgetWidget::disableButtons); connect(logFile, &LogFile::replayFinished, this, &LoggingGadgetWidget::disableButtons);
// Feedback from logfile to scope // Feedback from logfile to scope
connect(logFile, &LogFile::replayFinished, scpPlugin, &ScopeGadgetFactory::stopPlotting); connect(logFile, &LogFile::replayFinished, scpPlugin, &ScopeGadgetFactory::stopPlotting);
// Perform actions as if the plugin state has been changed
stateChanged(loggingPlugin->getState()); stateChanged(loggingPlugin->getState());
} }
/*
resizeEvent()
Determine button content policy based on button size.
*/
void LoggingGadgetWidget::resizeEvent(QResizeEvent *event)
{
int width = m_logging->playPauseButton->size().width();
if (width < m_preferredButtonWidth) {
m_iconOnlyButtons = true;
} else {
m_iconOnlyButtons = false;
}
updateButtonAppearance();
QWidget::resizeEvent(event);
}
/* /*
setPlayPauseButtonToPlay() setPlayPauseButtonToPlay()
Changes the appearance of the playPause button to the PLAY appearance. Changes the appearance of the playPause button to the PLAY appearance.
*/ */
void LoggingGadgetWidget::setPlayPauseButtonToPlay() void LoggingGadgetWidget::setPlayPauseButtonToPlay()
{ {
m_logging->playPauseButton->setIcon(QIcon(":/logging/images/play.png")); m_logging->playPauseButton->setIcon(QIcon(":/logging/images/play.png"));
m_logging->playPauseButton->setText(tr(" Play")); if (m_iconOnlyButtons) {
m_logging->playPauseButton->setText(QString());
} else {
m_logging->playPauseButton->setText(tr(" Play"));
}
} }
/* /*
setPlayPauseButtonToPlay() setPlayPauseButtonToPause()
Changes the appearance of the playPause button to the PAUSE appearance. Changes the appearance of the playPause button to the PAUSE appearance.
*/ */
void LoggingGadgetWidget::setPlayPauseButtonToPause() void LoggingGadgetWidget::setPlayPauseButtonToPause()
{ {
m_logging->playPauseButton->setIcon(QIcon(":/logging/images/pause.png")); m_logging->playPauseButton->setIcon(QIcon(":/logging/images/pause.png"));
m_logging->playPauseButton->setText(tr(" Pause")); if (m_iconOnlyButtons) {
m_logging->playPauseButton->setText(QString());
} else {
m_logging->playPauseButton->setText(tr(" Pause"));
}
} }
void LoggingGadgetWidget::playPauseButtonAction() void LoggingGadgetWidget::playPauseButtonAction()
{ {
ReplayState replayState = (loggingPlugin->getLogfile())->getReplayStatus(); ReplayState replayState = (loggingPlugin->getLogfile())->getReplayStatus();
if (replayState == PLAYING){ if (replayState == PLAYING) {
emit pauseReplay(); emit pauseReplay();
setPlayPauseButtonToPlay(); setPlayPauseButtonToPlay();
} else { } else {
@ -151,7 +181,7 @@ void LoggingGadgetWidget::stateChanged(LoggingPlugin::State state)
switch (state) { switch (state) {
case LoggingPlugin::IDLE: case LoggingPlugin::IDLE:
status = tr("Idle"); status = tr("Idle");
playbackPosition(0); playbackPosition(0);
break; break;
case LoggingPlugin::LOGGING: case LoggingPlugin::LOGGING:
@ -167,7 +197,7 @@ void LoggingGadgetWidget::stateChanged(LoggingPlugin::State state)
bool playing = loggingPlugin->getLogfile()->isPlaying(); bool playing = loggingPlugin->getLogfile()->isPlaying();
m_logging->stopButton->setEnabled(enabled && playing); m_logging->stopButton->setEnabled(enabled && playing);
m_logging->playPauseButton->setEnabled(enabled); m_logging->playPauseButton->setEnabled(enabled);
if (playing){ if (playing) {
setPlayPauseButtonToPause(); setPlayPauseButtonToPause();
} else { } else {
setPlayPauseButtonToPlay(); setPlayPauseButtonToPlay();
@ -181,8 +211,8 @@ void LoggingGadgetWidget::updateBeginAndEndTimes(quint32 startTimeStamp, quint32
startSec = (startTimeStamp / 1000) % 60; startSec = (startTimeStamp / 1000) % 60;
startMin = startTimeStamp / (60 * 1000); startMin = startTimeStamp / (60 * 1000);
endSec = (endTimeStamp / 1000) % 60; endSec = (endTimeStamp / 1000) % 60;
endMin = endTimeStamp / (60 * 1000); endMin = endTimeStamp / (60 * 1000);
// update start and end labels // update start and end labels
m_logging->startTimeLabel->setText(QString("%1:%2").arg(startMin, 2, 10, QChar('0')).arg(startSec, 2, 10, QChar('0'))); m_logging->startTimeLabel->setText(QString("%1:%2").arg(startMin, 2, 10, QChar('0')).arg(startSec, 2, 10, QChar('0')));
@ -202,7 +232,6 @@ void LoggingGadgetWidget::playbackPosition(quint32 positionTimeStamp)
{ {
// Update position bar, but only if the user is not updating the slider position // Update position bar, but only if the user is not updating the slider position
if (!m_logging->playBackPosition->isSliderDown() && !sliderActionDelay.isActive()) { if (!m_logging->playBackPosition->isSliderDown() && !sliderActionDelay.isActive()) {
// Block signals during slider position update: // Block signals during slider position update:
m_logging->playBackPosition->blockSignals(true); m_logging->playBackPosition->blockSignals(true);
m_logging->playBackPosition->setValue(positionTimeStamp); m_logging->playBackPosition->setValue(positionTimeStamp);
@ -217,8 +246,7 @@ void LoggingGadgetWidget::enableButtons()
{ {
ReplayState replayState = (loggingPlugin->getLogfile())->getReplayStatus(); ReplayState replayState = (loggingPlugin->getLogfile())->getReplayStatus();
switch (replayState) switch (replayState) {
{
case STOPPED: case STOPPED:
m_logging->stopButton->setEnabled(false); m_logging->stopButton->setEnabled(false);
setPlayPauseButtonToPlay(); setPlayPauseButtonToPlay();
@ -240,7 +268,6 @@ void LoggingGadgetWidget::enableButtons()
void LoggingGadgetWidget::disableButtons() void LoggingGadgetWidget::disableButtons()
{ {
m_logging->playPauseButton->setEnabled(false); m_logging->playPauseButton->setEnabled(false);
setPlayPauseButtonToPlay(); setPlayPauseButtonToPlay();
m_logging->stopButton->setEnabled(false); m_logging->stopButton->setEnabled(false);
@ -248,11 +275,40 @@ void LoggingGadgetWidget::disableButtons()
m_logging->playBackPosition->setEnabled(false); m_logging->playBackPosition->setEnabled(false);
} }
void LoggingGadgetWidget::updateButtonAppearance()
{
ReplayState replayState;
if (!loggingPlugin || !loggingPlugin->getLogfile()) {
// loggingPlugin has not been completely initialized: set to STOPPED state
replayState = STOPPED;
} else {
replayState = (loggingPlugin->getLogfile())->getReplayStatus();
}
// Update playPause button appearance
if (replayState == PLAYING) {
// Playing: playPause button must appear as a pause button
setPlayPauseButtonToPause();
} else {
// Stopped or Paused: playPause button must appear as a play button
setPlayPauseButtonToPlay();
}
// Update stop button appearance
if (m_iconOnlyButtons) {
m_logging->stopButton->setText(QString());
} else {
m_logging->stopButton->setText(tr(" Stop"));
}
}
void LoggingGadgetWidget::updatePositionLabel(quint32 positionTimeStamp) void LoggingGadgetWidget::updatePositionLabel(quint32 positionTimeStamp)
{ {
// update position label -> MM:SS // update position label -> MM:SS
int sec = (positionTimeStamp / 1000) % 60; int sec = (positionTimeStamp / 1000) % 60;
int min = positionTimeStamp / (60 * 1000); int min = positionTimeStamp / (60 * 1000);
m_logging->positionTimestampLabel->setText(QString("%1:%2").arg(min, 2, 10, QChar('0')).arg(sec, 2, 10, QChar('0'))); m_logging->positionTimestampLabel->setText(QString("%1:%2").arg(min, 2, 10, QChar('0')).arg(sec, 2, 10, QChar('0')));
} }
@ -273,7 +329,6 @@ void LoggingGadgetWidget::sliderAction()
} }
/** /**
* @} * @}
* @} * @}

View File

@ -68,10 +68,14 @@ private:
LoggingPlugin *loggingPlugin; LoggingPlugin *loggingPlugin;
ScopeGadgetFactory *scpPlugin; ScopeGadgetFactory *scpPlugin;
QTimer sliderActionDelay; QTimer sliderActionDelay;
bool m_iconOnlyButtons;
int m_preferredButtonWidth;
void updatePositionLabel(quint32 positionTimeStamp); void updatePositionLabel(quint32 positionTimeStamp);
void setPlayPauseButtonToPlay(); void setPlayPauseButtonToPlay();
void setPlayPauseButtonToPause(); void setPlayPauseButtonToPause();
void updateButtonAppearance();
void resizeEvent(QResizeEvent *event);
}; };
#endif /* LoggingGADGETWIDGET_H_ */ #endif /* LoggingGADGETWIDGET_H_ */