diff --git a/ground/gcs/src/libs/utils/logfile.cpp b/ground/gcs/src/libs/utils/logfile.cpp index cc70f1198..ffb0d97c8 100644 --- a/ground/gcs/src/libs/utils/logfile.cpp +++ b/ground/gcs/src/libs/utils/logfile.cpp @@ -165,7 +165,7 @@ void LogFile::timerFired() /* 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 : real-time interval since start of playback (in ms) - now() @@ -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 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 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) { - int bytesToSkip = m_timeStampPositions.at(i); - bool seek_ok = m_file.seek(bytesToSkip); + bool seek_ok = m_file.seek(bytesToSkip); if (!seek_ok) { 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: m_myTime.restart(); - m_timeOffset = 0; + m_timeOffset = 0; m_replayStatus = PLAYING; @@ -409,7 +407,7 @@ bool LogFile::pauseAndResetPosition() } qDebug() << "LogFile - pauseAndResetPosition"; m_timer.stop(); - m_replayStatus = STOPPED; + m_replayStatus = STOPPED; m_timeOffset = 0; m_lastPlayed = m_timeStamps.at(0); @@ -467,10 +465,10 @@ bool LogFile::buildIndex() } m_timeStamps.append(timeStamp); m_timeStampPositions.append(readPointer); - readPointer += TIMESTAMP_SIZE_BYTES; + readPointer += TIMESTAMP_SIZE_BYTES; index++; m_beginTimeStamp = timeStamp; - m_endTimeStamp = timeStamp; + m_endTimeStamp = timeStamp; } while (true) { @@ -511,7 +509,7 @@ bool LogFile::buildIndex() if (bytesRead != TIMESTAMP_SIZE_BYTES) { qWarning() << "LogFile buildIndex - read timeStamp, readRawData returned unexpected number of bytes:" << bytesRead << "at position" << readPointer << "\n"; return false; - } + } // some validity checks if (timeStamp < m_endTimeStamp // logfile goes back in time @@ -522,7 +520,7 @@ bool LogFile::buildIndex() m_timeStamps.append(timeStamp); m_timeStampPositions.append(readPointer); - readPointer += TIMESTAMP_SIZE_BYTES; + readPointer += TIMESTAMP_SIZE_BYTES; index++; m_endTimeStamp = timeStamp; } else { diff --git a/ground/gcs/src/plugins/logging/logging.ui b/ground/gcs/src/plugins/logging/logging.ui index ed7dbbe6f..421ecb2cd 100644 --- a/ground/gcs/src/plugins/logging/logging.ui +++ b/ground/gcs/src/plugins/logging/logging.ui @@ -36,8 +36,8 @@ - - 0 + + 80 0 @@ -47,11 +47,17 @@ 0 + + + 80 + 16777215 + + Play - + :/logging/images/play.png:/logging/images/play.png @@ -65,8 +71,8 @@ - - 0 + + 80 0 @@ -76,11 +82,17 @@ 0 + + + 80 + 16777215 + + Stop - + :/logging/images/stop.png:/logging/images/stop.png @@ -113,6 +125,12 @@ + + + 0 + 0 + + 1 @@ -203,6 +221,12 @@ 0 + + + 40 + 0 + + @@ -229,6 +253,12 @@ 0 + + + 40 + 0 + + @@ -255,6 +285,12 @@ 0 + + + 40 + 0 + + @@ -283,7 +319,7 @@ - + diff --git a/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp b/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp index 5fdc2773f..945c8f3f2 100644 --- a/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp +++ b/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp @@ -41,6 +41,9 @@ LoggingGadgetWidget::LoggingGadgetWidget(QWidget *parent) : QWidget(parent), log ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); scpPlugin = pm->getObject(); + // Store preferred button width before manipulating the button appearance + m_preferredButtonWidth = m_logging->playPauseButton->sizeHint().width(); + disableButtons(); // Configure timer to delay application of slider position action for 200ms @@ -60,65 +63,92 @@ void LoggingGadgetWidget::setPlugin(LoggingPlugin *p) loggingPlugin = p; 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->stopButton, &QPushButton::clicked, this, &LoggingGadgetWidget::stopButtonAction); connect(m_logging->playBackPosition, &QSlider::valueChanged, this, &LoggingGadgetWidget::sliderMoved); connect(m_logging->playbackSpeed, static_cast(&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::pauseReplay, logFile, &LogFile::pauseReplay); 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::pauseReplay, 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(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 + // Feedback from logfile to scope connect(logFile, &LogFile::replayFinished, scpPlugin, &ScopeGadgetFactory::stopPlotting); - + // Perform actions as if the plugin state has been changed 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() 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")); + 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. -*/ + */ void LoggingGadgetWidget::setPlayPauseButtonToPause() { 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() { ReplayState replayState = (loggingPlugin->getLogfile())->getReplayStatus(); - if (replayState == PLAYING){ + if (replayState == PLAYING) { emit pauseReplay(); setPlayPauseButtonToPlay(); } else { @@ -151,7 +181,7 @@ void LoggingGadgetWidget::stateChanged(LoggingPlugin::State state) switch (state) { case LoggingPlugin::IDLE: - status = tr("Idle"); + status = tr("Idle"); playbackPosition(0); break; case LoggingPlugin::LOGGING: @@ -167,7 +197,7 @@ void LoggingGadgetWidget::stateChanged(LoggingPlugin::State state) bool playing = loggingPlugin->getLogfile()->isPlaying(); m_logging->stopButton->setEnabled(enabled && playing); m_logging->playPauseButton->setEnabled(enabled); - if (playing){ + if (playing) { setPlayPauseButtonToPause(); } else { setPlayPauseButtonToPlay(); @@ -181,8 +211,8 @@ void LoggingGadgetWidget::updateBeginAndEndTimes(quint32 startTimeStamp, quint32 startSec = (startTimeStamp / 1000) % 60; startMin = startTimeStamp / (60 * 1000); - endSec = (endTimeStamp / 1000) % 60; - endMin = endTimeStamp / (60 * 1000); + endSec = (endTimeStamp / 1000) % 60; + endMin = endTimeStamp / (60 * 1000); // update start and end labels 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 if (!m_logging->playBackPosition->isSliderDown() && !sliderActionDelay.isActive()) { - // Block signals during slider position update: m_logging->playBackPosition->blockSignals(true); m_logging->playBackPosition->setValue(positionTimeStamp); @@ -217,8 +246,7 @@ void LoggingGadgetWidget::enableButtons() { ReplayState replayState = (loggingPlugin->getLogfile())->getReplayStatus(); - switch (replayState) - { + switch (replayState) { case STOPPED: m_logging->stopButton->setEnabled(false); setPlayPauseButtonToPlay(); @@ -240,7 +268,6 @@ void LoggingGadgetWidget::enableButtons() void LoggingGadgetWidget::disableButtons() { - m_logging->playPauseButton->setEnabled(false); setPlayPauseButtonToPlay(); m_logging->stopButton->setEnabled(false); @@ -248,11 +275,40 @@ void LoggingGadgetWidget::disableButtons() 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) { // 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'))); } @@ -273,7 +329,6 @@ void LoggingGadgetWidget::sliderAction() } - /** * @} * @} diff --git a/ground/gcs/src/plugins/logging/logginggadgetwidget.h b/ground/gcs/src/plugins/logging/logginggadgetwidget.h index 34491936e..d2603472e 100644 --- a/ground/gcs/src/plugins/logging/logginggadgetwidget.h +++ b/ground/gcs/src/plugins/logging/logginggadgetwidget.h @@ -68,10 +68,14 @@ private: LoggingPlugin *loggingPlugin; ScopeGadgetFactory *scpPlugin; QTimer sliderActionDelay; + bool m_iconOnlyButtons; + int m_preferredButtonWidth; void updatePositionLabel(quint32 positionTimeStamp); void setPlayPauseButtonToPlay(); void setPlayPauseButtonToPause(); + void updateButtonAppearance(); + void resizeEvent(QResizeEvent *event); }; #endif /* LoggingGADGETWIDGET_H_ */