From 1fc003532fee14e57050a72dfdc6f522f7392d0e Mon Sep 17 00:00:00 2001
From: Fabian Paus <fabian.paus@kit.edu>
Date: Tue, 4 Jan 2022 14:25:38 +0100
Subject: [PATCH] ArViz: Add context menu interaction

---
 .../ArViz/ArVizWidgetController.cpp           | 85 +++++++++++++++++--
 .../gui-plugins/ArViz/ArVizWidgetController.h |  2 +-
 2 files changed, 81 insertions(+), 6 deletions(-)

diff --git a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp
index cf6e7bfc7..183592534 100644
--- a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp
@@ -59,9 +59,6 @@ namespace armarx
         updateTimer = new QTimer(this);
         connect(updateTimer, &QTimer::timeout, this, QOverload<>::of(&This::onUpdate));
 
-        timingObserverTimer = new QTimer(this);
-        connect(timingObserverTimer, &QTimer::timeout, this, QOverload<>::of(&This::onTimingObserverUpdate));
-
         replayTimer = new QTimer(this);
         connect(replayTimer, &QTimer::timeout, this, QOverload<>::of(&This::onReplayTimerTick));
 
@@ -175,14 +172,13 @@ namespace armarx
         currentRecordingSelected = false;
         changeMode(ArVizWidgetMode::Live);
 
-        timingObserverTimer->start(33);
         updateTimer->start(33);
     }
 
     void ArVizWidgetController::onDisconnectGui()
     {
-        timingObserverTimer->stop();
         visualizer.stop();
+        updateTimer->stop();
         changeMode(ArVizWidgetMode::NotConnected);
     }
 
@@ -436,6 +432,35 @@ namespace armarx
         visualizer.selection->deselectAll();
     }
 
+    void ArVizWidgetController::onContextMenuClicked()
+    {
+        viz::ElementInteractionData* selected = visualizer.selectedElement;
+        if (selected == nullptr)
+        {
+            ARMARX_WARNING << "Selected element is null, but a context menu option was clicked!";
+            return;
+        }
+
+        QPushButton* clickedButton = static_cast<QPushButton*>(sender());
+
+        QLayout* layout = widget.groupBoxContextMenu->layout();
+        int count = layout->count();
+        for (int i = 0; i < count; ++i)
+        {
+            QPushButton* button = static_cast<QPushButton*>(layout->itemAt(i)->widget());
+            if (button == clickedButton)
+            {
+                viz::data::InteractionFeedback& interaction = visualizer.interactionFeedbackBuffer.emplace_back();
+                interaction.component = selected->layer.first;
+                interaction.layer = selected->layer.second;
+                interaction.element = selected->element;
+                interaction.type = viz::data::InteractionFeedbackType::CONTEXT_MENU_CHOSEN;
+                interaction.chosenContextMenuEntry = i;
+                return;
+            }
+        }
+    }
+
     static QString toQString(viz::ElementInteractionData const& inter)
     {
         std::string id = inter.layer.first + "/"
@@ -450,9 +475,57 @@ namespace armarx
 
         // Show the currently selected element
         QString selectedElementName("<None>");
+        QLayout* contextMenuLayout = widget.groupBoxContextMenu->layout();
         if (visualizer.selectedElement)
         {
             selectedElementName = toQString(*visualizer.selectedElement);
+
+            // Show context menu options if enabled
+            int currentCount = contextMenuLayout->count();
+            viz::data::InteractionDescription const& desc = visualizer.selectedElement->interaction;
+            std::vector<std::string> const& options = desc.contextMenuOptions;
+            int newCount = 0;
+            if (desc.enableFlags & viz::data::InteractionEnableFlags::CONTEXT_MENU)
+            {
+                newCount = (int)options.size();
+            }
+            if (newCount != currentCount)
+            {
+                // Remove all items
+                QLayoutItem* item;
+                while ((item = contextMenuLayout->takeAt( 0 )) != nullptr)
+                {
+                    delete item->widget();
+                    delete item;
+                }
+
+                for (std::string const& option : options)
+                {
+                    QPushButton* button = new QPushButton(
+                                              QString::fromStdString(option),
+                                              widget.groupBoxContextMenu);
+                    connect(button, &QPushButton::clicked, this, &ArVizWidgetController::onContextMenuClicked);
+                    contextMenuLayout->addWidget(button);
+                }
+            }
+            else
+            {
+                for (int i = 0; i < currentCount; ++i)
+                {
+                    QLayoutItem* item = contextMenuLayout->itemAt(i);
+                    QPushButton* button = static_cast<QPushButton*>(item->widget());
+                    button->setText(QString::fromStdString(options[i]));
+                }
+            }
+        }
+        else
+        {
+            QLayoutItem* item;
+            while ((item = contextMenuLayout->takeAt( 0 )) != nullptr)
+            {
+                delete item->widget();
+                delete item;
+            }
         }
         widget.labelSelectedElement->setText(selectedElementName);
 
@@ -468,6 +541,8 @@ namespace armarx
                 widget.listInteractiveElements->addItem(elementID);
             }
         }
+
+        onTimingObserverUpdate();
     }
 
     void ArVizWidgetController::onTimingObserverUpdate()
diff --git a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h
index 27b6cfd52..9fd1fa47f 100644
--- a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h
+++ b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h
@@ -139,6 +139,7 @@ namespace armarx
         void showFilteredLayers(bool visible);
 
         void onDeselectElement();
+        void onContextMenuClicked();
 
         void onUpdate();
         void onTimingObserverUpdate();
@@ -176,7 +177,6 @@ namespace armarx
         QPointer<SimpleConfigDialog> configDialog;
 
         QTimer* updateTimer;
-        QTimer* timingObserverTimer;
         viz::CoinVisualizer_UpdateTiming lastTiming;
         StringVariantBaseMap timingMap;
 
-- 
GitLab