diff --git a/source/ArmarXGui/applications/ArmarXGui/ArmarXGuiApp.h b/source/ArmarXGui/applications/ArmarXGui/ArmarXGuiApp.h index 99998cb83406455e91d4060e5b393ce40f11afce..59014ea8ce3897f374ed9a5d34117e6580ac51f9 100644 --- a/source/ArmarXGui/applications/ArmarXGui/ArmarXGuiApp.h +++ b/source/ArmarXGui/applications/ArmarXGui/ArmarXGuiApp.h @@ -23,22 +23,16 @@ #pragma once -// ArmarX - -#include <ArmarXCore/core/system/ImportExportComponent.h> -#include <ArmarXGui/applications/ArmarXGui/Widgets/ui_ExceptionDialog.h> - -//SoQt -#include <Inventor/Qt/SoQt.h> +#include <string> -//Qt #include <QApplication> -#include "ArmarXMainWindow.h" - -#include <string> +#include <ArmarXCore/core/system/ImportExportComponent.h> +#include <ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.h> +#include <ArmarXGui/applications/ArmarXGui/Widgets/ui_ExceptionDialog.h> +#include <Inventor/Qt/SoQt.h> namespace armarx { @@ -48,16 +42,13 @@ namespace armarx /** * ArmarXGuiApp property definition container. */ - class ArmarXGuiAppPropertyDefinitions: - public ApplicationPropertyDefinitions + class ArmarXGuiAppPropertyDefinitions : public ApplicationPropertyDefinitions { public: ArmarXGuiAppPropertyDefinitions(std::string prefix); }; - - class ArmarXQApplication : - public QApplication + class ArmarXQApplication : public QApplication { Q_OBJECT public: @@ -70,12 +61,12 @@ namespace armarx public slots: void showException(QString exceptionReason); + protected: QDialog exceptionDialog; Ui_ExceptionDialog exceptionDialogHandler; }; - /** \class ArmarXGuiApp \brief The main ArmarX gui application. @@ -103,7 +94,8 @@ namespace armarx /** * Configures the app, sets Qt up */ - void setup(const ManagedIceObjectRegistryInterfacePtr& registry, Ice::PropertiesPtr properties) override; + void setup(const ManagedIceObjectRegistryInterfacePtr& registry, + Ice::PropertiesPtr properties) override; int run(int argc, char* argv[]) override; /** @@ -114,9 +106,11 @@ namespace armarx /** * @see PropertyUser::createPropertyDefinitions() */ - armarx::PropertyDefinitionsPtr createPropertyDefinitions() override + armarx::PropertyDefinitionsPtr + createPropertyDefinitions() override { - return armarx::PropertyDefinitionsPtr(new ArmarXGuiAppPropertyDefinitions(getDomainName())); + return armarx::PropertyDefinitionsPtr( + new ArmarXGuiAppPropertyDefinitions(getDomainName())); } private slots: @@ -136,5 +130,4 @@ namespace armarx int argc; char** argv; }; -} - +} // namespace armarx diff --git a/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.cpp b/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.cpp index 299e2841bd8c8ff1104c8580ae75e6e80ff959b8..15efec06d8841eba075db4c008c5fc597a04ced9 100644 --- a/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.cpp +++ b/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.cpp @@ -21,24 +21,9 @@ * @copyright http://www.gnu.org/licenses/gpl-2.0.txt * GNU General Public License */ -#include "ArmarXMainWindow.h" - -#include <ArmarXGui/applications/ArmarXGui/ui_ArmarXMainWindow.h> - -#include "Widgets/TitlebarWidget.h" -#include "Widgets/ViewerWidget.h" -#include "Widgets/WidgetNameDialog.h" -// ArmarX -#include <ArmarXCore/core/ArmarXObjectScheduler.h> -#include <ArmarXCore/core/Component.h> -#include <ArmarXCore/core/logging/LogSender.h> -#include <ArmarXCore/core/system/ArmarXDataPath.h> -#include <ArmarXCore/core/system/cmake/CMakePackageFinder.h> - -#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h> +#include "ArmarXMainWindow.h" -// Qt #include <filesystem> #include <optional> #include <sstream> @@ -89,11 +74,22 @@ #include <SimoxUtility/algorithm/string/string_tools.h> +#include <ArmarXCore/core/ArmarXObjectScheduler.h> +#include <ArmarXCore/core/Component.h> +#include <ArmarXCore/core/logging/LogSender.h> +#include <ArmarXCore/core/system/ArmarXDataPath.h> +#include <ArmarXCore/core/system/cmake/CMakePackageFinder.h> + #include <ArmarXGui/applications/ArmarXGui/Widgets/GuiUseCaseSelector.h> +#include <ArmarXGui/applications/ArmarXGui/ui_ArmarXMainWindow.h> +#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h> #include <ArmarXGui/libraries/ArmarXGuiBase/widgets/InfixCompleter.h> #include <ArmarXGui/libraries/ArmarXGuiBase/widgets/InfixFilterModel.h> #include <ArmarXGui/libraries/ArmarXGuiBase/widgets/TipDialog.h> +#include "Widgets/TitlebarWidget.h" +#include "Widgets/ViewerWidget.h" +#include "Widgets/WidgetNameDialog.h" #include <Inventor/Qt/viewers/SoQtExaminerViewer.h> #include <Inventor/nodes/SoPerspectiveCamera.h> //#include <omp.h> @@ -191,6 +187,11 @@ namespace armarx ArmarXComponentWidgetController::createInstance<EmergencyStopWidget>()); this->registry->addObject(ManagedIceObjectPtr::dynamicCast(emergencyStopWidget)); + // Battery widget + batteryWidget = BatteryWidgetPtr::dynamicCast( + ArmarXComponentWidgetController::createInstance<BatteryWidget>()); + this->registry->addObject(ManagedIceObjectPtr::dynamicCast(batteryWidget)); + // plugins QSet<QString> pluginDirs; @@ -1250,6 +1251,11 @@ namespace armarx // EmergencyStop ui->toolBar->addWidget(emergencyStopWidget->getButtonWidget()); + // Battery Widget + ui->toolBar->addWidget(batteryWidget->getBatteryWidget()); + + ui->toolBar->addSeparator(); + ui->toolBar->setIconSize(QSize(256, 24)); QMap<QString, QAction*> actionsForToolBar; diff --git a/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.h b/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.h index d274cba2c857ead6947f8d977c4c92e87b62e2f1..b3152ba29fdf939c713bc5e2caff351d683c2255 100644 --- a/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.h +++ b/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.h @@ -23,29 +23,25 @@ */ #pragma once -#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h> -#include <ArmarXGui/libraries/ArmarXGuiBase/PluginCache.h> - -// Qt #include <QAction> #include <QDir> #include <QDockWidget> #include <QMainWindow> #include <QPluginLoader> - -// Coin3D & SoQt -#include <Inventor/nodes/SoNode.h> -#include <Inventor/nodes/SoSeparator.h> - -// ArmarX #include <QSplashScreen> #include <ArmarXCore/core/application/Application.h> #include <ArmarXCore/core/logging/Logging.h> #include <ArmarXCore/core/services/tasks/RunningTask.h> -#include "Widgets/EmergencyStopWidget.h" -#include "Widgets/ViewerWidget.h" +#include <ArmarXGui/applications/ArmarXGui/Widgets/BatteryWidget.h> +#include <ArmarXGui/applications/ArmarXGui/Widgets/EmergencyStopWidget.h> +#include <ArmarXGui/applications/ArmarXGui/Widgets/ViewerWidget.h> +#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h> +#include <ArmarXGui/libraries/ArmarXGuiBase/PluginCache.h> + +#include <Inventor/nodes/SoNode.h> +#include <Inventor/nodes/SoSeparator.h> class QToolButton; class QLabel; @@ -246,6 +242,7 @@ namespace armarx // Emergency Stop EmergencyStopWidgetPtr emergencyStopWidget; + BatteryWidgetPtr batteryWidget; QAction* leaveFullScreenActionF11; QAction* leaveFullScreenActionEsc; diff --git a/source/ArmarXGui/applications/ArmarXGui/CMakeLists.txt b/source/ArmarXGui/applications/ArmarXGui/CMakeLists.txt index a060898531cd9d9de8c35d087a99bfa395f0ba96..48a5431048eb7c0dcbb33af3d3f74f5809a55683 100644 --- a/source/ArmarXGui/applications/ArmarXGui/CMakeLists.txt +++ b/source/ArmarXGui/applications/ArmarXGui/CMakeLists.txt @@ -21,6 +21,7 @@ set(SOURCES ArmarXGuiApp.cpp Widgets/UseCaseSelectorItem.cpp Widgets/GuiUseCaseSelector.cpp Widgets/EmergencyStopWidget.cpp + Widgets/BatteryWidget.cpp ) set(HEADERS ArmarXGuiApp.h @@ -31,6 +32,7 @@ set(HEADERS ArmarXGuiApp.h Widgets/UseCaseSelectorItem.h Widgets/GuiUseCaseSelector.h Widgets/EmergencyStopWidget.h + Widgets/BatteryWidget.h ArmarXMainWindow.ui Widgets/ViewerWidget.ui diff --git a/source/ArmarXGui/applications/ArmarXGui/Widgets/BatteryWidget.cpp b/source/ArmarXGui/applications/ArmarXGui/Widgets/BatteryWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad94bcbb62724831ef69a5461a398544283480ab --- /dev/null +++ b/source/ArmarXGui/applications/ArmarXGui/Widgets/BatteryWidget.cpp @@ -0,0 +1,364 @@ +#include "BatteryWidget.h" + +#include <QToolTip> + +namespace armarx +{ + + constexpr std::string_view battery_master_default_name = "DiagnosticsUnit"; + + BatteryIcon::BatteryIcon(QWidget* parent) : QWidget(parent) + { + QSizePolicy policy{QSizePolicy::Policy::Fixed, QSizePolicy::Policy::Fixed}; + setSizePolicy(policy); + } + + void + BatteryIcon::paintEvent(QPaintEvent* event) + { + QWidget::paintEvent(event); + + int filled = std::clamp(percentage, 0, 100); // between 0 and 100 + QColor fg(0, 200, 0); + + if (filled < 15) + { + fg = QColor(200, 0, 0); + } + else if (filled < 45) + { + fg = QColor(200, 100, 0); + } + + if (state != dto::BatteryState::discharging) + { + fg = QColor(255, 255, 255); + } + + // Draw inner and cap. + QColor bg(fg.red() * .6, fg.green() * .6, fg.blue() * .6); + int ht = event->rect().height(); + int wd = ht / 2 - 1; + QPainter painter; + painter.setRenderHint(QPainter::Antialiasing, true); + painter.begin(this); + int m = 1 * ht / 10 + 1; + QRect cap(QPoint(m, m), QPoint(wd - m, 2 * m)); + painter.fillRect(cap, filled == 100 ? fg : bg); + QRect body(QPoint(0, 2 * m), QPoint(wd, ht - m)); + painter.fillRect(body, bg); + float dist = (1.0 - filled * .01); + QRect bodyFull(QPoint(0, 2 * m + dist * (ht - 3 * m)), QPoint(wd, ht - m)); + painter.fillRect(bodyFull, fg); + + // Draw a border. + int lWd = ht / 40; + QRect a; + a = QRect(QPoint(m, m), QPoint(wd - m, m + lWd)); + painter.fillRect(a, bg); + a = QRect(QPoint(wd - m - lWd, m), QPoint(wd - m, 2 * m + lWd)); + painter.fillRect(a, bg); + a = QRect(QPoint(wd - m - lWd, 2 * m), QPoint(wd, 2 * m + lWd)); + painter.fillRect(a, bg); + a = QRect(QPoint(wd - lWd, 2 * m), QPoint(wd, ht - m)); + painter.fillRect(a, bg); + a = QRect(QPoint(0, ht - m - lWd), QPoint(wd, ht - m)); + painter.fillRect(a, bg); + a = QRect(QPoint(0, 2 * m), QPoint(lWd, ht - m)); + painter.fillRect(a, bg); + a = QRect(QPoint(0, 2 * m), QPoint(m + lWd, 2 * m + lWd)); + painter.fillRect(a, bg); + a = QRect(QPoint(m, m), QPoint(m + lWd, 2 * m + lWd)); + painter.fillRect(a, bg); + + // Draw lightning if charging. + if (state == dto::BatteryState::charging) + { + QPolygon poly; + float lHeight = .6 * ht; + int xOff = .1 * ht + 1; + int yOff = .2 * ht + 1; + poly << QPoint(xOff + 7 * lHeight / 20, yOff) + << QPoint(xOff + 5 * lHeight / 20, yOff + 4.5 * lHeight / 10) + << QPoint(xOff + 10 * lHeight / 20, yOff + 4.5 * lHeight / 10) + << QPoint(xOff + 3 * lHeight / 20, yOff + lHeight) + << QPoint(xOff + 5 * lHeight / 20, yOff + 5.5 * lHeight / 10) + << QPoint(xOff + 0 * lHeight / 20, yOff + 5.5 * lHeight / 10) + << QPoint(xOff + 7 * lHeight / 20, yOff); + QPainterPath path; + path.addPolygon(poly); + painter.fillPath(path, QColor(40, 40, 40)); + } + + // Draw cross if unavailable. + if (state == dto::BatteryState::unavailable) + { + int u = .1 * wd; + QPolygon poly; + poly << QPoint(u, .1 * ht) << QPoint(wd - 2 * u, .9 * ht) << QPoint(wd - u, .9 * ht) + << QPoint(2 * u, .1 * ht) << QPoint(u, .1 * ht); + QPainterPath path; + path.addPolygon(poly); + painter.fillPath(path, QColor(200, 0, 0)); + QPolygon poly2; + poly2 << QPoint(wd - 2 * u, .1 * ht) << QPoint(wd - u, .1 * ht) + << QPoint(2 * u, .9 * ht) << QPoint(u, .9 * ht) << QPoint(wd - 2 * u, .1 * ht); + QPainterPath path2; + path2.addPolygon(poly2); + painter.fillPath(path2, QColor(200, 0, 0)); + } + + painter.end(); + } + + void + BatteryIcon::setPercentage(int percentage) + { + this->percentage = std::clamp(percentage, 0, 100); + } + + void + BatteryIcon::setState(dto::BatteryState state) + { + this->state = state; + } + + QSize + BatteryIcon::sizeHint() const + { + return QSize{16, 32}; + } + + BatteryWidget::BatteryWidget(QWidget* parent, ArmarXMainWindow* mainWindow) : + mainWindow(mainWindow), timer(new QTimer(this)) + { + qRegisterMetaType<dto::BatteryStatus>("dto::BatteryStatus"); + QGridLayout* layout = new QGridLayout(this->getWidget()); + this->getWidget()->setContentsMargins(4, 0, 0, 0); + icon = new BatteryIcon(); + layout->addWidget(icon, 0, 0); + layout->setContentsMargins(0, 0, 0, 0); + this->getWidget()->setLayout(layout); + icon->setVisible(true); + lbl = new QLabel(); + txtPercentage = QString("%1%").arg(lastStatus.energyFromFullCharge_pct); + lbl->setText(txtPercentage); + lbl->setVisible(false); + layout->addWidget(lbl, 0, 1); + + qRegisterMetaType<dto::BatteryState>("BatteryState"); + + timer->setInterval(std::chrono::milliseconds(1'000)); + connect(timer, &QTimer::timeout, this, &BatteryWidget::updateBatteryStatus); + connect(this, &BatteryWidget::startPeriodicStateUpdate, timer, qOverload<>(&QTimer::start)); + connect(this, &BatteryWidget::stopPeriodicStateUpdate, timer, &QTimer::stop); + + QString style = QString("QToolTip {" + // StyleSheet for tool tip + " background: white;" + " padding: 3px;" + "}"); + getWidget()->setStyleSheet(style); + + updateTooltip(); + } + + QWidget* + BatteryWidget::getBatteryWidget() + { + return this->getWidget(); + } + + void + BatteryWidget::updateTooltip() + { + dto::BatteryState state = lastStatus.state; + + QString text; + + if (state == dto::BatteryState::unavailable) + { + text = "No battery detected."; + } + else if (state == dto::BatteryState::full) + { + text = "Battery fully charged."; + } + else + { + QString status; + switch (state) + { + case dto::BatteryState::charging: + status = "charging"; + break; + case dto::BatteryState::discharging: + status = "discharging"; + break; + case dto::BatteryState::full: + status = "full"; + break; + case dto::BatteryState::notCharging: + status = "not charging"; + break; + case dto::BatteryState::unavailable: + status = "unavailable"; + break; + } + + QString detailedReport; + { + QString charge = QString(" - Charge: %1<br>").arg(txtPercentage); + + QString energy = QString(" - Energy: %2 Wh / %3 Wh<br>") + .arg(lastStatus.energy_Wh, 0, 'f', 1) + .arg(lastStatus.fullChargeEnergy_Wh, 0, 'f', 1); + + QString power = QString(" - %1: %2 W (%3 A, %4 V)<br>") + .arg(state == dto::BatteryState::charging ? "Charging power" + : "Provided power") + .arg(std::abs(lastStatus.power_W), 0, 'f', 1) + .arg(std::abs(lastStatus.current_A), 0, 'f', 1) + .arg(lastStatus.voltage_V, 0, 'f', 1); + + bool showPrognosis = + state == dto::BatteryState::charging or state == dto::BatteryState::discharging; + QString prognosis = ""; + if (showPrognosis) + { + QString fullOrEmpty = state == dto::BatteryState::charging ? "Full" : "Empty"; + prognosis = QString(" - %1 in: ≈ %2 h <br>") + .arg(fullOrEmpty) + .arg(lastStatus.remainingTime_h, 0, 'f', 1); + } + + QString temperature = QString(" - Temperature: %6 °C<br>") + .arg(lastStatus.temperature_degC, 0, 'f', 1); + + QString health = QString(" - Health: %7%") + .arg(lastStatus.fullEnergyFromDesignEnergy_pct, 0, 'f', 1); + + detailedReport = QString("%1%2%3%4%5%6") + .arg(charge, energy, power, prognosis, temperature, health); + } + + QString errorsText = + lastStatus.hasError + ? "<br><b><font color='red'>Battery error occured! Check the logs.</font></b>" + : ""; + + text = QString("Battery %1.<br>%2%3").arg(status).arg(detailedReport).arg(errorsText); + } + + getWidget()->setToolTip(text); + + if (not QToolTip::isVisible()) + { + return; + } + + QPoint p = getWidget()->mapFromGlobal(QCursor::pos()); + + if (p.x() >= 0 and p.y() >= 0 and p.x() < getWidget()->width() and + p.y() < getWidget()->height()) + { + QToolTip::showText(QCursor::pos(), text); + } + } + + void + BatteryWidget::onInitComponent() + { + usingProxy(std::string{battery_master_default_name}); + } + + void + BatteryWidget::onConnectComponent() + { + QMetaObject::invokeMethod(icon, "setVisible", Qt::QueuedConnection, Q_ARG(bool, true)); + + ARMARX_INFO << "Battery widget connected."; + batteryManagement = getProxy<armarx::BatteryManagementInterfacePrx>( + std::string{battery_master_default_name}); + + emit startPeriodicStateUpdate(); + } + + void + BatteryWidget::onDisconnectComponent() + { + ARMARX_IMPORTANT + << "Battery widget disconnected. This is expected if the earlier connected " + "robot unit shut down."; + + QMetaObject::invokeMethod(this, + "setBatteryStatus", + Qt::QueuedConnection, + Q_ARG(dto::BatteryStatus, invalidStatus)); + + emit stopPeriodicStateUpdate(); + } + + void + BatteryWidget::loadSettings(QSettings* settings) + { + ; + } + + void + BatteryWidget::saveSettings(QSettings* settings) + { + ; + } + + void + BatteryWidget::updateBatteryStatus() + { + dto::BatteryStatus newStatus; + + try + { + newStatus = batteryManagement->getBatteryStatus(); + } + catch (...) + { + ARMARX_DEBUG << deactivateSpam(60) << "Failed to get current battery percentage"; + newStatus.state = dto::BatteryState::unavailable; + } + + QMetaObject::invokeMethod( + this, "setBatteryStatus", Qt::QueuedConnection, Q_ARG(dto::BatteryStatus, newStatus)); + } + + void + BatteryWidget::setBatteryStatus(dto::BatteryStatus batteryStatus) + { + lastStatus = batteryStatus; + + icon->setPercentage(lastStatus.energyFromFullCharge_pct); + txtPercentage = QString("%1%").arg(lastStatus.energyFromFullCharge_pct, 0, 'f', 1); + lbl->setText(txtPercentage); + + dto::BatteryState state = lastStatus.state; + + icon->setState(state); + if (state == dto::BatteryState::unavailable) + { + lbl->setVisible(false); + } + else + { + lbl->setVisible(true); + } + + updateTooltip(); + icon->update(); + } + + std::string + BatteryWidget::getDefaultName() const + { + return "BatteryWidget" + iceNameUUID; + } + +} // namespace armarx diff --git a/source/ArmarXGui/applications/ArmarXGui/Widgets/BatteryWidget.h b/source/ArmarXGui/applications/ArmarXGui/Widgets/BatteryWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..a05f3d5552de88bb678a6fca9f1a371f4f0c9f7f --- /dev/null +++ b/source/ArmarXGui/applications/ArmarXGui/Widgets/BatteryWidget.h @@ -0,0 +1,111 @@ +#pragma once + +#include <QGridLayout> +#include <QLabel> +#include <QPaintEvent> +#include <QPainter> +#include <QPainterPath> +#include <QTimer> +#include <QWidget> + +#include <IceUtil/UUID.h> + +#include <ArmarXCore/core/IceGridAdmin.h> +#include <ArmarXCore/interface/components/BatteryManagementInterface.h> + +#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h> + +Q_DECLARE_METATYPE(armarx::dto::BatteryStatus) + +namespace armarx +{ + class ArmarXMainWindow; + + class BatteryIcon : public QWidget + { + Q_OBJECT + public: + explicit BatteryIcon(QWidget* parent = 0); + + void paintEvent(QPaintEvent* event) Q_DECL_OVERRIDE; + + void setPercentage(int percentage); + + void setState(dto::BatteryState state); + + QSize sizeHint() const Q_DECL_OVERRIDE; + + private: + int percentage = 0; + dto::BatteryState state = dto::BatteryState::unavailable; + }; + + class BatteryWidget : public ArmarXComponentWidgetControllerTemplate<BatteryWidget> + { + Q_OBJECT + public: + explicit BatteryWidget(QWidget* parent = 0, ArmarXMainWindow* mainWindow = 0); + + QWidget* getBatteryWidget(); + + signals: + void startPeriodicStateUpdate(); + void stopPeriodicStateUpdate(); + + public slots: + void updateBatteryStatus(); + + void updateTooltip(); + + void setBatteryStatus(dto::BatteryStatus batteryStatus); + + // ManagedIceObject interface + protected: + void onInitComponent() override; + void onConnectComponent() override; + void onDisconnectComponent() override; + std::string getDefaultName() const override; + + private: + ArmarXMainWindow* mainWindow; + QGridLayout* layout; + BatteryIcon* icon; + QLabel* lbl; + QString txtPercentage; + QTimer* timer; + + armarx::BatteryManagementInterfacePrx batteryManagement; + + dto::BatteryStatus const invalidStatus{.name = "invalid", + .state = dto::BatteryState::unavailable, + .designEnergy_Wh = -1, + .fullChargeEnergy_Wh = -1, + .energy_Wh = -1, + .energyFromFullCharge_pct = 0, + .fullEnergyFromDesignEnergy_pct = 0, + .temperature_degC = -1, + .ratedVoltage_V = -1, + .voltage_V = -1, + .current_A = -1, + .power_W = -1, + .remainingTime_h = -1, + .hasError = false, + .error = ""}; + + dto::BatteryStatus lastStatus = invalidStatus; + + // ArmarXWidgetController interface + public: + static QString + GetWidgetName() + { + return "BatteryWidget"; + } + + void loadSettings(QSettings* settings) override; + void saveSettings(QSettings* settings) override; + std::string iceNameUUID = IceUtil::generateUUID(); + }; + + using BatteryWidgetPtr = IceInternal::Handle<BatteryWidget>; +} // namespace armarx