From fa70cb751c4d9b51823fc58b54de747eb751edd0 Mon Sep 17 00:00:00 2001
From: Jan NIJS <dr.oblivium@gmail.com>
Date: Sun, 29 Apr 2018 19:43:46 +0200
Subject: [PATCH] LP-597 Progress bar for GCS log replay - Resize playPause and
 stop buttons according to the available space for the widget.

- also make pretty
---
 ground/gcs/src/libs/utils/logfile.cpp         | 22 ++---
 ground/gcs/src/plugins/logging/logging.ui     | 50 ++++++++--
 .../plugins/logging/logginggadgetwidget.cpp   | 97 +++++++++++++++----
 .../src/plugins/logging/logginggadgetwidget.h |  4 +
 4 files changed, 133 insertions(+), 40 deletions(-)

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