30 #include <QSpacerItem>
32 #include <QGridLayout>
33 #include <QStyledItemDelegate>
34 #include <QScrollArea>
41 while ((item = layout->takeAt(0)))
46 delete item->layout();
50 delete item->widget();
59 const char*
const REMOTE_TAB_ID =
"remote.tab_id";
60 const char*
const REMOTE_WIDGET_NAME =
"remote.widget_name";
62 struct InternalUpdateGuard
64 InternalUpdateGuard(std::atomic<bool>*
enabled)
70 ~InternalUpdateGuard()
82 widget.remoteTabWidget->clear();
84 widget.comboBoxTabGroups->setVisible(
false);
85 widget.comboBoxTabGroups->addItem(groupAll);
86 widget.comboBoxTabGroups->addItem(groupUngrouped);
88 connect(widget.sendRemoteValuesButton, &QPushButton::clicked,
90 connect(widget.checkBoxGroupTabs, &QCheckBox::clicked,
92 connect(widget.comboBoxTabGroups, QOverload<const QString&>::of(&QComboBox::currentIndexChanged),
97 Qt::QueuedConnection);
100 Qt::QueuedConnection);
103 Qt::QueuedConnection);
106 Qt::QueuedConnection);
108 widget.comboBoxTabGroups->setCurrentIndex(0);
122 dialog->addProxyFinder<RemoteGuiInterfacePrx>({
"RemoteGuiProvider",
"",
"RemoteGui*"});
124 return qobject_cast<SimpleConfigDialog*>(dialog);
129 remoteGuiProviderName = dialog->getProxyName(
"RemoteGuiProvider");
135 remoteGuiProviderName = settings->value(
"remoteGuiProviderName",
"RemoteGuiProvider").toString().toStdString();
140 settings->setValue(
"remoteGuiProviderName", QString::fromStdString(remoteGuiProviderName));
152 remoteGuiProvider = getProxy<RemoteGuiInterfacePrx>(remoteGuiProviderName);
156 std::unique_lock<std::mutex> lock(stateMutex);
157 tabs = remoteGuiProvider->getTabs();
158 tabWidgetStates = remoteGuiProvider->getTabStates();
159 tabValueMap = remoteGuiProvider->getValuesForAllTabs();
166 usingTopic(remoteGuiProvider->getTopicName());
172 std::unique_lock<std::mutex> lock(stateMutex);
173 tabs = remoteGuiProvider->getTabs();
174 tabWidgetStates = remoteGuiProvider->getTabStates();
175 tabValueMap = remoteGuiProvider->getValuesForAllTabs();
177 QString qTabId = QString::fromStdString(tab);
186 std::unique_lock<std::mutex> lock(stateMutex);
187 tabs = remoteGuiProvider->getTabs();
188 tabWidgetStates = remoteGuiProvider->getTabStates();
189 tabValueMap = remoteGuiProvider->getValuesForAllTabs();
197 std::unique_lock<std::mutex> lock(stateMutex);
198 tabWidgetStates[tab] = widgetState;
200 QString qTabId = QString::fromStdString(tab);
207 std::unique_lock<std::mutex> lock(stateMutex);
208 for (
const auto& pair : delta)
210 tabValueMap[tab][pair.first] = pair.second;
211 tabDirtyMap[tab][pair.first] = pair.second;
214 QString qTabId = QString::fromStdString(tab);
223 std::unique_lock<std::mutex> lock(stateMutex);
228 removeObsoleteTabs();
233 std::unique_lock<std::mutex> lock(stateMutex);
236 for (
auto& tabWidget : tabs)
238 QString qid = QString::fromStdString(tabWidget.first);
244 removeObsoleteTabs();
252 std::unique_lock<std::mutex> lock(stateMutex);
271 QWidget* widget = qobject_cast<QWidget*>(sender());
274 ARMARX_WARNING <<
"Expected a widget as sender of onGuiStateChanged()";
278 std::string
id = widget->property(REMOTE_TAB_ID).toString().toStdString();
279 std::string name = widget->property(REMOTE_WIDGET_NAME).toString().toStdString();
281 std::unique_lock<std::mutex> lock(stateMutex);
295 RemoteGui::ValueVariant& currentValue = tabValueMap.at(
id).at(name);
299 RemoteGui::ValueVariant newValue = widgetHandler.
handleGuiChange(*desc, widget);
301 if (newValue != currentValue)
303 currentValue = newValue;
310 const int index = widget.remoteTabWidget->currentIndex();
311 QString currentTabText = widget.remoteTabWidget->tabText(
index);
314 remoteGuiProvider->setValues(tabId, tabValueMap[tabId]);
317 void RemoteGuiWidgetController::createTab(std::string
const& tabId)
322 ARMARX_INFO <<
"Updating GUI for tab '" << tabId <<
"'";
325 QString qTabId = QString::fromStdString(tabId);
326 QWidget* tabHolder =
nullptr;
327 for (
const auto& pair : qtTabs)
329 TabData
const&
data = pair.second;
330 if (
data.fullName() == tabId)
336 QGridLayout* layout =
nullptr;
340 QScrollArea* scrollArea = qobject_cast<QScrollArea*>(tabHolder);
341 if (scrollArea && scrollArea->widget())
343 layout = qobject_cast<QGridLayout*>(scrollArea->widget()->layout());
353 QScrollArea* scrollArea =
new QScrollArea(widget.remoteTabWidget);
354 scrollArea->setObjectName(qTabId);
355 scrollArea->setWidgetResizable(
true);
356 layout =
new QGridLayout(scrollArea);
357 layout->setContentsMargins(0, 0, 0, 0);
358 QWidget* scrollAreaWidgetContents =
new QWidget;
359 scrollArea->setWidget(scrollAreaWidgetContents);
360 scrollAreaWidgetContents->setLayout(layout);
361 tabHolder = scrollArea;
364 auto&
data = qtTabs[tabId];
368 const auto fname =
data.fullName();
369 std::size_t idx = fname.find(
'_');
370 while (idx != std::string::npos)
372 data.groups.emplace(fname.substr(0, idx));
373 idx = fname.find(
'_', idx + 1);
377 if (activeGroup == groupAll ||
378 (
data.groups.empty() && activeGroup == groupUngrouped))
381 widget.remoteTabWidget->addTab(tabHolder, qTabId);
383 else if (
data.groups.count(activeGroup))
385 widget.remoteTabWidget->addTab(tabHolder, QString::fromStdString(
data.name(activeGroup)));
388 for (
const auto& group :
data.groups)
390 if (tabsPerGroup.count(group))
392 ++tabsPerGroup.at(group);
396 tabsPerGroup[group] = 1;
397 const auto box = widget.comboBoxTabGroups;
398 box->blockSignals(
true);
399 box->addItem(QString::fromStdString(group));
400 box->blockSignals(
false);
407 guiWidgets[tabId].clear();
408 QWidget* newTab = createWidgetFromDescription(tabId, widgetP);
410 newTab->setParent(tabHolder);
411 layout->addWidget(newTab, 0, 0);
412 layout->addItem(
new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding), 1, 1);
413 layout->addItem(
new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 1);
416 void RemoteGuiWidgetController::removeObsoleteTabs()
418 for (
auto iter = qtTabs.begin(); iter != qtTabs.end();)
420 std::string
const& tabId = iter->first;
421 TabData
const&
data = iter->second;
423 if (tabs.count(tabId) > 0)
430 QString qTabId = QString::fromStdString(tabId);
432 QWidget* tabHolder =
data.w;
433 tabHolder->deleteLater();
434 QTabWidget* tab = widget.remoteTabWidget;
435 int i =
data.findTabIndex(tab);
441 for (
const std::string& group :
data.groups)
443 std::size_t& tabCount = tabsPerGroup.at(group);
447 tabsPerGroup.erase(group);
448 QComboBox* box = widget.comboBoxTabGroups;
449 int boxIdx = box->findText(QString::fromStdString(group));
453 box->blockSignals(
true);
454 box->setCurrentIndex(0);
455 box->removeItem(boxIdx);
456 box->blockSignals(
false);
459 box->setCurrentIndex(0);
463 iter = qtTabs.erase(iter);
464 guiWidgets.erase(tabId);
470 void RemoteGuiWidgetController::updateWidgets(std::string
const& tabId)
473 RemoteGui::WidgetStateMap
const& states = tabWidgetStates.at(tabId);
474 std::map<std::string, QWidget*>
const& widgets = guiWidgets.at(tabId);
476 for (
auto& nameState : states)
478 std::string
const& name = nameState.first;
479 RemoteGui::WidgetState
const& state = nameState.second;
480 QWidget* widget = widgets.at(name);
482 widget->setHidden(state.hidden);
483 widget->setDisabled(state.disabled);
487 void RemoteGuiWidgetController::updateState(std::string
const& tabId)
490 std::unique_lock<std::mutex> lock(stateMutex);
493 InternalUpdateGuard guard(&internalUpdate);
496 std::map<std::string, QWidget*>
const& widgets = guiWidgets.at(tabId);
497 RemoteGui::WidgetMap
const& widgetDesc = guiDescriptions.at(tabId);
501 std::string
const& name = pair.first;
502 RemoteGui::ValueVariant
const&
value = pair.second;
504 QWidget* widget = widgets.at(name);
507 widgetHandler.updateGui(*desc, widget,
value);
509 tabDirtyMap.at(tabId).clear();
512 static void setNameProp(QWidget* w, QString
const& name, QString
const&
id)
514 if (w->property(REMOTE_WIDGET_NAME).toString() ==
"")
516 w->setProperty(REMOTE_WIDGET_NAME, name);
517 w->setProperty(REMOTE_TAB_ID,
id);
518 for (
auto child : w->findChildren<QWidget*>(QString{}, Qt::FindDirectChildrenOnly))
520 setNameProp(child, name,
id);
525 QWidget* RemoteGuiWidgetController::createWidgetFromDescription(
const std::string& tabId,
const RemoteGui::WidgetPtr& desc)
528 QWidget* widget =
nullptr;
531 bool useDefaultValue =
values.count(desc->name) == 0;
532 RemoteGui::ValueVariant
const& initialValue = useDefaultValue ? desc->defaultValue :
values[desc->name];
537 return this->createWidgetFromDescription(tabId, desc);
543 InternalUpdateGuard guard(&internalUpdate);
546 widget = widgetHandler.createWidget(*desc, initialValue, createChild,
552 setNameProp(widget, QString::fromStdString(desc->name), QString::fromStdString(tabId));
555 if (!desc->name.empty())
558 auto result = guiWidgets[tabId].emplace(desc->name, widget);
559 bool inserted = result.second;
562 guiDescriptions[tabId][desc->name] = desc;
563 values[desc->name] = initialValue;
568 ARMARX_WARNING <<
"Tried to add a widget with duplicate name '" << desc->name
569 <<
"' to remote tab ID '" << tabId <<
"'";
578 widget.widgetTopBar->setVisible(
false);
579 widget.remoteTabWidget->tabBar()->setVisible(
false);
584 widget.widgetTopBar->setVisible(
true);
585 widget.remoteTabWidget->tabBar()->setVisible(
true);
588 void RemoteGuiWidgetController::doAutoUpdate(std::string
const&
id)
590 if (widget.autoUpdateCheckBox->checkState() == Qt::Checked)
592 remoteGuiProvider->setValues(
id, tabValueMap[
id]);
598 widget.comboBoxTabGroups->setEnabled(checked);
599 widget.comboBoxTabGroups->setVisible(checked);
600 widget.comboBoxTabGroups->setCurrentIndex(0);
605 activeGroup = group.toStdString();
606 auto tab = widget.remoteTabWidget;
613 for (
const auto& pair : qtTabs)
615 TabData
const&
data = pair.second;
617 if (activeGroup == groupAll ||
618 (
data.groups.empty() && activeGroup == groupUngrouped))
621 tab->addTab(
data.w, QString::fromStdString(
data.fullName()));
623 else if (!
data.groups.empty() &&
data.groups.count(activeGroup))
625 tab->addTab(
data.w, QString::fromStdString(
data.name(activeGroup)));
630 std::string RemoteGuiWidgetController::TabData::fullName()
const
632 return w->objectName().toStdString();
635 std::string RemoteGuiWidgetController::TabData::name(
const std::string& pre)
const
637 return fullName().substr(pre.size() + 1);
640 int RemoteGuiWidgetController::TabData::findTabIndex(QTabWidget* tab)
const
642 for (
auto idx = 0; idx < tab->count(); ++idx)
644 if (w == tab->widget(idx))