32 ui->treeWidget->setColumnCount(11);
33 QTreeWidgetItem* head =
ui->treeWidget->headerItem();
47 head->setToolTip(
idxName,
"The controllers instance name (green: ok, red: active and requested state missmatch or there is an error)");
48 head->setToolTip(
idxClass,
"The controllers class name");
49 head->setToolTip(
idxActive,
"Whether the controller is active (green: ok, red: active and requested state missmatch)");
50 head->setToolTip(
idxRequested,
"Whether the controller is requested (green: ok, red: active and requested state missmatch)");
51 head->setToolTip(
idxError,
"Whether the controller is deactivated due to an error (green: ok, red: there is an error)");
52 head->setToolTip(
idxInternal,
"Whether the controller is internal (e.g. used by the kinematic unit)");
53 head->setToolTip(
idxCtrlDev,
"The control devices used by this controller");
54 head->setToolTip(
idxCtrlMode,
"The controll mode for the control devices used by this controller");
55 head->setToolTip(
idxActivate,
"Button to activate the Controller");
56 head->setToolTip(
idxDeactivate,
"Button to deactivate the Controller");
57 head->setToolTip(
idxDelete,
"Button to delete the Controller");
59 ui->treeWidget->setColumnWidth(
idxName, 400);
71 ui->treeWidget->header()->setResizeMode(
idxActivate, QHeaderView::Fixed);
72 ui->treeWidget->header()->setResizeMode(
idxDeactivate, QHeaderView::Fixed);
73 ui->treeWidget->header()->setResizeMode(
idxDelete, QHeaderView::Fixed);
74 ui->treeWidget->header()->setResizeMode(
idxRequested, QHeaderView::Fixed);
75 ui->treeWidget->header()->setResizeMode(
idxActive, QHeaderView::Fixed);
76 ui->treeWidget->header()->setResizeMode(
idxError, QHeaderView::Fixed);
77 ui->treeWidget->header()->setResizeMode(
idxInternal, QHeaderView::Fixed);
79 ui->pushButtonStopAll->setIcon(QIcon {QString{
":/icons/media-playback-pause.ico"}});
80 ui->pushButtonRemoveAll->setIcon(QIcon {QString{
":/icons/Trash.svg"}});
81 connect(
ui->pushButtonStopAll, SIGNAL(clicked()),
this, SLOT(onPushButtonStopAll_clicked()));
82 connect(
ui->pushButtonRemoveAll, SIGNAL(clicked()),
this, SLOT(onPushButtonRemoveAll_clicked()));
92 std::unique_lock<std::recursive_timed_mutex> guard {
mutex, std::defer_lock};
93 if (!guard.try_lock_for(std::chrono::microseconds(100)))
97 for (
const auto&
status : allStatus)
99 if (statusUpdates[
status.instanceName].timestampUSec <
status.timestampUSec)
104 QMetaObject::invokeMethod(
this,
"updateContent", Qt::QueuedConnection);
110 void NJointControllersWidget::add(
const NJointControllerDescriptionWithStatus& ds)
112 if (!entries.count(ds.description.instanceName))
116 entries.at(ds.description.instanceName)->update(ds.status);
119 void NJointControllersWidget::onPushButtonStopAll_clicked()
123 robotUnit->switchNJointControllerSetup({});
127 void NJointControllersWidget::onPushButtonRemoveAll_clicked()
129 for (
auto& pair : entries)
133 if (pair.second->deletable)
135 pair.second->deleteController();
146 std::unique_lock<std::recursive_timed_mutex> guard {
mutex};
153 auto data = ru->getNJointControllerDescriptionWithStatus(name);
155 if (!entries.count(name))
157 controllersCreated[name] = std::move(
data);
160 QMetaObject::invokeMethod(
this,
"updateContent", Qt::QueuedConnection);
167 std::unique_lock<std::recursive_timed_mutex> guard {
mutex};
168 controllersDeleted.emplace(name);
171 QMetaObject::invokeMethod(
this,
"updateContent", Qt::QueuedConnection);
177 ui->treeWidget->setColumnWidth(
idxName, settings->value(
"ctrlColWName", 400).toInt());
178 ui->treeWidget->setColumnWidth(
idxClass, settings->value(
"ctrlColWClass", 200).toInt());
179 ui->treeWidget->setColumnWidth(
idxCtrlDev, settings->value(
"ctrlColWCDen", 130).toInt());
180 ui->treeWidget->setColumnWidth(
idxCtrlMode, settings->value(
"ctrlColWCMod", 150).toInt());
185 settings->setValue(
"ctrlColWName",
ui->treeWidget->columnWidth(
idxName));
186 settings->setValue(
"ctrlColWClass",
ui->treeWidget->columnWidth(
idxClass));
187 settings->setValue(
"ctrlColWCDen",
ui->treeWidget->columnWidth(
idxCtrlDev));
188 settings->setValue(
"ctrlColWCMod",
ui->treeWidget->columnWidth(
idxCtrlMode));
194 controllersCreated.clear();
195 statusUpdates.clear();
196 controllersDeleted.clear();
201 for (
const auto& pair : controllersCreated)
205 controllersCreated.clear();
206 for (
const auto& pair : statusUpdates)
208 const auto& name = pair.second.instanceName;
209 if (controllersDeleted.count(name))
213 auto it = entries.find(name);
214 if (it != entries.end())
216 it->second->update(pair.second);
220 NJointControllerDescriptionWithStatus stat;
221 stat.status = pair.second;
222 ARMARX_INFO <<
"loding description for the missing entry '" << name <<
"'";
223 stat.description =
robotUnit->getNJointControllerDescription(name);
227 statusUpdates.clear();
228 for (
const auto& name : controllersDeleted)
230 auto it = entries.find(name);
231 if (it != entries.end())
233 it->second->deleteContent();
234 it->second->deleteLater();
238 controllersDeleted.clear();
243 auto temp =
robotUnit->getNJointControllerDescriptionsWithStatuses();
245 std::unique_lock<std::recursive_timed_mutex> guard {
mutex};
246 for (NJointControllerDescriptionWithStatus& ds : temp)
248 controllersCreated[ds.description.instanceName] = std::move(ds);
255 if (controllersCreated.empty())
259 add(controllersCreated.begin()->second);
260 controllersCreated.erase(controllersCreated.begin());
267 deletable {desc.deletable},
271 header =
new QTreeWidgetItem;
272 treeWidget.addTopLevelItem(header);
280 const std::size_t numDev = desc.controlModeAssignment.size();
281 const std::size_t numMod = getMapValues<StringStringDictionary, std::set>(desc.controlModeAssignment).size();
285 QWidget* widgDev =
new QWidget{&parent};
286 QWidget* widgMod =
new QWidget{&parent};
289 QVBoxLayout* layDev =
new QVBoxLayout;
290 QVBoxLayout* layMod =
new QVBoxLayout;
291 layDev->setContentsMargins(0, 0, 0, 0);
292 layMod->setContentsMargins(0, 0, 0, 0);
293 widgDev->setLayout(layDev);
294 widgMod->setLayout(layMod);
295 boxDev =
new QCheckBox{QString::number(numDev) +
" Device" + (numDev > 1 ? QString{
"s"}: QString{
""})};
296 boxMod =
new QCheckBox{QString::number(numMod) +
" Mode" + (numMod > 1 ? QString{
"s"}: QString{
""})};
297 layDev->addWidget(boxDev);
298 layMod->addWidget(boxMod);
301 boxDev->setChecked(
false);
302 boxMod->setChecked(
false);
303 connect(boxDev, SIGNAL(clicked(
bool)),
this, SLOT(hideDeviceList()));
304 connect(boxMod, SIGNAL(clicked(
bool)),
this, SLOT(hideDeviceList()));
306 devsToModes.reserve(desc.controlModeAssignment.size());
307 for (
const auto& pair : desc.controlModeAssignment)
309 QTreeWidgetItem* child =
new QTreeWidgetItem;
310 header->addChild(child);
313 devsToModes.emplace_back(child);
314 child->setHidden(
true);
317 QPushButton* act =
new QPushButton;
318 QPushButton* dec =
new QPushButton;
319 act->setToolTip(
"Activate the Controller");
320 dec->setToolTip(
"Deactivate the Controller");
323 act->setIcon(QIcon {QString{
":/icons/media-playback-start.ico"}});
324 dec->setIcon(QIcon {QString{
":/icons/media-playback-pause.ico"}});
325 act->setFixedWidth(40);
326 dec->setFixedWidth(40);
327 act->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
328 dec->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
329 connect(act, SIGNAL(clicked(
bool)),
this, SLOT(activateController()));
330 connect(dec, SIGNAL(clicked(
bool)),
this, SLOT(deactivateController()));
333 QPushButton* del =
new QPushButton;
335 del->setToolTip(
"Delete the Controller");
336 del->setIcon(QIcon {QString{
":/icons/Trash.svg"}});
337 del->setFixedWidth(40);
338 del->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
339 connect(del, SIGNAL(clicked(
bool)),
this, SLOT(deleteController()));
344 for (
const auto& descr :
controller->getFunctionDescriptions())
346 new NJointControllersWidgetRemoteFunction {treeWidget, *header, descr.first,
controller, descr.second};
391 for (
const auto& elem : devsToModes)
403 for (
const auto& elem : devsToModes)
415 for (
auto item : devsToModes)
424 setDeviceListVisible(vis);
425 header->setHidden(!vis);
428 void NJointControllersWidgetEntry::activateController()
434 void NJointControllersWidgetEntry::deactivateController()
440 void NJointControllersWidgetEntry::deleteController()
446 void NJointControllersWidgetEntry::hideDeviceList()
448 QCheckBox* box =
dynamic_cast<QCheckBox*
>(sender());
451 bool checked = box->isChecked();
452 boxDev->setChecked(checked);
453 boxMod->setChecked(checked);
454 for (QTreeWidgetItem* dev : devsToModes)
456 dev->setHidden(!checked);
460 header->setExpanded(
true);
464 void NJointControllersWidgetEntry::setDeviceListVisible(
bool vis)
466 boxDev->setChecked(vis);
467 boxMod->setChecked(vis);
468 for (QTreeWidgetItem* dev : devsToModes)
470 dev->setHidden(!vis);
475 QTreeWidget& treeWidget,
476 QTreeWidgetItem& header,
477 const std::string& name,
478 const NJointControllerInterfacePrx& ctrl,
486 setObjectName(QString::fromStdString(ctrl->getInstanceName() +
"_" + name));
487 functionHeader =
new QTreeWidgetItem;
488 header.addChild(functionHeader);
489 functionHeader->setFirstColumnSpanned(
true);
490 treeWidget.setItemWidget(functionHeader, 0,
this);
492 QHBoxLayout* l =
new QHBoxLayout;
494 l->setContentsMargins(0, 0, 0, 0);
497 QPushButton*
execute =
new QPushButton;
498 execute->setIcon(QIcon {QString{
":/icons/media-playback-start.ico"}});
499 execute->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
501 execute->setToolTip(
"Execute '" + QString::fromStdString(name) +
"' function");
502 connect(
execute, SIGNAL(clicked(
bool)),
this, SLOT(execFunction()));
506 execOnParamChange =
new QCheckBox {
"Call function on parameter changes"};
507 execOnParamChange->setToolTip(
"Execute '" + QString::fromStdString(name) +
"' function whenever a parameter changes");
508 l->addWidget(execOnParamChange);
512 execOnParamChange->setFixedHeight(0);
513 execOnParamChange->setSizePolicy(execOnParamChange->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed);
516 l->addWidget(
new QLabel{
"Remote function: " + QString::fromStdString(name)});
518 l->addSpacerItem(
new QSpacerItem{0, 0, QSizePolicy::Expanding});
523 QTreeWidgetItem* fnitem =
new QTreeWidgetItem;
524 functionHeader->addChild(fnitem);
525 fnitem->setFirstColumnSpanned(
true);
526 QWidget* container =
new QWidget;
527 treeWidget.setItemWidget(fnitem, 0, container);
528 QHBoxLayout* compress =
new QHBoxLayout;
529 compress->setContentsMargins(0, 0, 0, 0);
530 container->setLayout(compress);
533 paramValues = params->getVariants();
534 params->setContentsMargins(0, 0, 0, 0);
535 compress->addWidget(params);
537 compress->addItem(
new QSpacerItem {0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding});
541 void NJointControllersWidgetRemoteFunction::execFunction()
543 if (paramValues.empty())
549 std::stringstream ss;
550 ss <<
"calling function " << functionName <<
" with parameters:\n";
551 for (
const auto& pair : paramValues)
556 if (pair.second->data)
558 ss <<
" '" << pair.first <<
"' of type " << pair.second->data->ice_id() <<
"\n";
562 ss <<
" '" << pair.first <<
"' nullptr data \n";
567 ss <<
" '" << pair.first <<
"' nullptr\n";
572 ctrl->callDescribedFunction(functionName, paramValues);
577 paramValues[std::move(name)] = std::move(
value);
578 if (execOnParamChange->isChecked())