From 2c75536c7cf156b3aaf80439cdb256e12f4eb08c Mon Sep 17 00:00:00 2001
From: Rainer Kartmann <rainer.kartmann@student.kit.edu>
Date: Tue, 29 Jan 2019 17:02:06 +0100
Subject: [PATCH] Added feature to clear single layers from the
 DebugDrawerViewer

---
 .../DebugDrawerViewerWidget.ui                |  78 +++++++-
 .../DebugDrawerViewerWidgetController.cpp     | 175 ++++++++++++++++++
 .../DebugDrawerViewerWidgetController.h       |  14 ++
 3 files changed, 264 insertions(+), 3 deletions(-)

diff --git a/source/RobotAPI/gui-plugins/DebugDrawerViewer/DebugDrawerViewerWidget.ui b/source/RobotAPI/gui-plugins/DebugDrawerViewer/DebugDrawerViewerWidget.ui
index 9888ab71f..94743fa92 100644
--- a/source/RobotAPI/gui-plugins/DebugDrawerViewer/DebugDrawerViewerWidget.ui
+++ b/source/RobotAPI/gui-plugins/DebugDrawerViewer/DebugDrawerViewerWidget.ui
@@ -7,20 +7,92 @@
     <x>0</x>
     <y>0</y>
     <width>400</width>
-    <height>300</height>
+    <height>94</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>DebugDrawerViewerWidget</string>
   </property>
   <layout class="QGridLayout" name="gridLayout">
-   <item row="0" column="0">
+   <item row="3" column="0">
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QComboBox" name="comboClearLayer">
+       <property name="toolTip">
+        <string>Select a layer to clear</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="btnClearLayer">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="toolTip">
+        <string>Clear the selected layer</string>
+       </property>
+       <property name="text">
+        <string>Clear Layer</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="1" column="0">
     <widget class="QPushButton" name="btnClearAll">
+     <property name="toolTip">
+      <string>Clear all layers</string>
+     </property>
      <property name="text">
-      <string>Remove All Visualizations</string>
+      <string>Clear All Layers</string>
      </property>
     </widget>
    </item>
+   <item row="0" column="0">
+    <spacer name="verticalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="4" column="0">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="2" column="0">
+    <spacer name="verticalSpacer_3">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Preferred</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>20</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
   </layout>
  </widget>
  <resources/>
diff --git a/source/RobotAPI/gui-plugins/DebugDrawerViewer/DebugDrawerViewerWidgetController.cpp b/source/RobotAPI/gui-plugins/DebugDrawerViewer/DebugDrawerViewerWidgetController.cpp
index e4cda5e36..f78aa5d81 100644
--- a/source/RobotAPI/gui-plugins/DebugDrawerViewer/DebugDrawerViewerWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/DebugDrawerViewer/DebugDrawerViewerWidgetController.cpp
@@ -22,6 +22,9 @@
 #include "DebugDrawerViewerWidgetController.h"
 
 #include <ArmarXCore/core/ArmarXManager.h>
+
+#include <QTimer>
+
 #include <string>
 
 
@@ -33,6 +36,9 @@ DebugDrawerViewerWidgetController::DebugDrawerViewerWidgetController()
     rootVisu = nullptr;
     widget.setupUi(getWidget());
 
+    QTimer* timer = new QTimer(this);
+    connect(timer, SIGNAL(timeout()), this, SLOT(updateComboClearLayer()));
+    timer->start(100);
 }
 
 
@@ -55,6 +61,7 @@ void DebugDrawerViewerWidgetController::onInitComponent()
 
     enableMainWidgetAsync(false);
     connect(widget.btnClearAll, SIGNAL(clicked()), this, SLOT(on_btnClearAll_clicked()), Qt::UniqueConnection);
+    connect(widget.btnClearLayer, SIGNAL(clicked()), this, SLOT(on_btnClearLayer_clicked()), Qt::UniqueConnection);
 }
 
 
@@ -109,3 +116,171 @@ void armarx::DebugDrawerViewerWidgetController::on_btnClearAll_clicked()
         debugDrawer->clearAll();
     }
 }
+
+void DebugDrawerViewerWidgetController::on_btnClearLayer_clicked()
+{
+    if (debugDrawer)
+    {
+        int index = widget.comboClearLayer->currentIndex();
+        std::string layerName = widget.comboClearLayer->itemData(index).toString().toStdString();
+
+        if (!layerName.empty())
+        {
+            ARMARX_INFO << "Clearing layer: '" << layerName << "'";
+            debugDrawer->clearLayer(layerName);
+        }
+    }
+}
+
+
+void DebugDrawerViewerWidgetController::updateComboClearLayer()
+{
+    QComboBox* combo = widget.comboClearLayer;
+
+    auto setItalic = [combo](bool italic)
+    {
+        QFont font = combo->font();
+        font.setItalic(italic);
+        combo->setFont(font);
+    };
+
+    auto setHint = [combo, &setItalic](const std::string & hint)
+    {
+        QString itemText(hint.c_str());
+        QString itemData("");
+        setItalic(true);
+
+        if (combo->count() != 1)
+        {
+            combo->clear();
+            combo->insertItem(0, itemText, itemData);
+        }
+        else
+        {
+            combo->setItemText(0, itemText);
+            combo->setItemData(0, itemData);
+        }
+    };
+
+    if (!debugDrawer)
+    {
+        setHint("not connected");
+        return;
+    }
+
+    // fetch layer information
+    LayerInformationSequence layers = debugDrawer->layerInformation();
+
+    if (layers.empty())
+    {
+        setHint("no layers");
+        return;
+    }
+    else if (combo->font().italic())
+    {
+        setItalic(false);
+    }
+
+    const int numLayers = static_cast<int>(layers.size());
+
+    // sort the layers by name
+    std::sort(layers.begin(), layers.end(), [](const LayerInformation & lhs, const LayerInformation & rhs)
+    {
+        for (std::size_t i = 0; i < lhs.layerName.size() && i < lhs.layerName.size(); ++i)
+        {
+            auto lhsLow = std::tolower(lhs.layerName[i]);
+            auto rhsLow = std::tolower(rhs.layerName[i]);
+            if (lhsLow < rhsLow)
+            {
+                return true;
+            }
+            else if (lhsLow > rhsLow)
+            {
+                return false;
+            }
+        }
+        // if one is a prefix of the other, the shorter is the "smaller" one
+        return lhs.layerName.size() < rhs.layerName.size();
+    });
+
+
+    for (int i = 0; i < static_cast<int>(layers.size()); ++i)
+    {
+        const LayerInformation& layer = layers[static_cast<std::size_t>(i)];
+
+        QString layerName(layer.layerName.c_str());
+
+        if (i < combo->count())  // in range
+        {
+            QString itemData = combo->itemData(i).toString();
+
+            // remove deleted layers
+            while (itemData.size() != 0 && itemData < layerName)
+            {
+                // item layer is smaller than next layer
+                // => item layer was deleted
+                ARMARX_INFO << "Removing " << itemData;
+                combo->removeItem(i);
+                itemData = i < combo->count() ? combo->itemData(i).toString() : "";
+            }
+
+            // update existing layer
+            if (itemData == layerName)
+            {
+                ARMARX_INFO << "Updating " << itemData;
+                combo->setItemText(i, makeLayerItemText(layer));
+            }
+            else // (itemData > layerName)
+            {
+                // item layer is further down than current layer
+                // => insert current layer here
+                ARMARX_INFO << "Inserting " << layerName << " before " << itemData;
+                combo->insertItem(i, makeLayerItemText(layer), layerName);
+            }
+        }
+        else  // out of range
+        {
+            ARMARX_INFO << "Inserting " << layerName << " at end";
+            combo->insertItem(i, makeLayerItemText(layer), layerName);
+        }
+
+        // check invariant
+        ARMARX_CHECK_EQUAL(combo->itemData(i).toString(), layerName);
+    }
+
+    // remove excessive items
+    while (combo->count() > numLayers)
+    {
+        combo->removeItem(combo->count() - 1);
+    }
+}
+
+
+
+QString DebugDrawerViewerWidgetController::makeLayerItemText(const LayerInformation& layer)
+{
+    std::vector<std::string> annotations;
+    if (layer.elementCount == 0)
+    {
+        annotations.push_back("empty");
+    }
+    if (!layer.visible)
+    {
+        annotations.push_back("hidden");
+    }
+
+    if (annotations.empty())
+    {
+        return { layer.layerName.c_str() };
+    }
+    else
+    {
+        std::stringstream itemText;
+        itemText << layer.layerName
+                 << " (" << boost::algorithm::join(annotations, ", ") << ")";
+        return { itemText.str().c_str() };
+    }
+}
+
+
+
diff --git a/source/RobotAPI/gui-plugins/DebugDrawerViewer/DebugDrawerViewerWidgetController.h b/source/RobotAPI/gui-plugins/DebugDrawerViewer/DebugDrawerViewerWidgetController.h
index 49544db52..a3e46e54d 100644
--- a/source/RobotAPI/gui-plugins/DebugDrawerViewer/DebugDrawerViewerWidgetController.h
+++ b/source/RobotAPI/gui-plugins/DebugDrawerViewer/DebugDrawerViewerWidgetController.h
@@ -100,6 +100,20 @@ namespace armarx
 
         /// Clear all layers.
         void on_btnClearAll_clicked();
+
+        /// Clear the selected layer.
+        void on_btnClearLayer_clicked();
+
+        /// Fetch the layer information and update the combo box items.
+        void updateComboClearLayer();
+
+
+    private:
+
+        /// Make an item text for a layer entry in the clear layer combo box.
+        static QString makeLayerItemText(const LayerInformation& layer);
+
+
     private:
 
         /// Widget Form
-- 
GitLab