From 5ac53f63065735e4947d87a8d9c03d0a07c8347a Mon Sep 17 00:00:00 2001 From: Peter Albrecht <albrecpe@gmail.com> Date: Wed, 15 Nov 2023 13:10:53 +0100 Subject: [PATCH] Copied and adapted PeriodicUpdateWidget --- .../SkillManagerPlugin/CMakeLists.txt | 2 + .../PeriodicUpdateWidget.cpp | 141 ++++++++++++++++++ .../SkillManagerPlugin/PeriodicUpdateWidget.h | 66 ++++++++ 3 files changed, 209 insertions(+) create mode 100644 source/RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.cpp create mode 100644 source/RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.h diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt b/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt index a6d2ff63c..1ee52e845 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt @@ -26,6 +26,7 @@ set(SOURCES aronTreeWidget/modal/AronTreeWidgetModal.cpp ColorPalettes.cpp SkillManagerMonitorWidgetController.cpp + PeriodicUpdateWidget.cpp ) set(HEADERS @@ -51,6 +52,7 @@ set(HEADERS aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModalController.h ColorPalettes.h SkillManagerMonitorWidgetController.h + PeriodicUpdateWidget.h ) set(GUI_UIS diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.cpp new file mode 100644 index 000000000..d039d0d54 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.cpp @@ -0,0 +1,141 @@ +#include "PeriodicUpdateWidget.h" + +#include <cmath> + +#include <QCheckBox> +#include <QDoubleSpinBox> +#include <QHBoxLayout> +#include <QPushButton> +#include <QTimer> + +namespace armarx +{ + PeriodicUpdateWidget::PeriodicUpdateWidget(double frequency, double maxFrequency) + { + setSizePolicy(QSizePolicy::Policy::Minimum, QSizePolicy::Policy::Fixed); + + QLayout* vlayout = new QVBoxLayout(); + QLayout* hlayout = new QHBoxLayout(); + this->setLayout(vlayout); + + const int margin = 0; + hlayout->setContentsMargins(margin, margin, margin, margin); + + _updateButton = new QPushButton("Update", this); + _autoCheckBox = new QCheckBox("Auto Update", this); + _frequencySpinBox = new QDoubleSpinBox(this); + _frequencySpinBox->setValue(frequency); + _frequencySpinBox->setMinimum(0); + _frequencySpinBox->setMaximum(maxFrequency); + _frequencySpinBox->setSingleStep(0.5); + _frequencySpinBox->setSuffix(" Hz"); + + hlayout->addWidget(_updateButton); + hlayout->addWidget(_autoCheckBox); + hlayout->addWidget(_frequencySpinBox); + + vlayout->addItem(hlayout); + + + _timer = new QTimer(this); + _updateTimerFrequency(); + _frequencySpinBox->setEnabled(_autoCheckBox->isChecked()); + + + // Private connections. + connect(_autoCheckBox, &QCheckBox::toggled, this, &This::_toggleAutoUpdates); + connect(_frequencySpinBox, + &QDoubleSpinBox::editingFinished, + this, + &This::_updateTimerFrequency); + + // Public connections. + connect(_updateButton, &QPushButton::pressed, this, &This::updateSingle); + connect(_timer, &QTimer::timeout, this, &This::updatePeriodic); + + connect(this, &This::updateSingle, this, &This::update); + connect(this, &This::updatePeriodic, this, &This::update); + + // See `startTimerIfEnabled` for the signal reasoning. + // qOverload is required because `QTimer::start()` is overloaded. + connect(this, &This::startTimerSignal, _timer, qOverload<>(&QTimer::start)); + connect(this, &This::stopTimerSignal, _timer, &QTimer::stop); + } + + QPushButton* + PeriodicUpdateWidget::updateButton() + { + return _updateButton; + } + + int + PeriodicUpdateWidget::getUpdateIntervalMs() const + { + return static_cast<int>(std::round(1000 / _frequencySpinBox->value())); + } + + void + PeriodicUpdateWidget::startTimerIfEnabled() + { + /* A QTimer can only be started and stopped within its own thread (the thread for which + * it has the greatest affinity). Since this method can be called from any thread, we + * need to take a detour through these signals, which can be emitted from any thread and + * will always be caught in this object's (and thus the timer's) native thread. + */ + if (_autoCheckBox->isChecked()) + { + emit startTimerSignal(); + } + else + { + emit stopTimerSignal(); + } + } + + void + PeriodicUpdateWidget::stopTimer() + { + // See `startTimerIfEnabled` for the signal reasoning. + emit stopTimerSignal(); + } + + void + PeriodicUpdateWidget::_updateTimerFrequency() + { + _timer->setInterval(getUpdateIntervalMs()); + } + + void + PeriodicUpdateWidget::_toggleAutoUpdates(bool enabled) + { + // This method is already a slot, so it doesn't need to use the timer signals. + _frequencySpinBox->setEnabled(enabled); + if (enabled) + { + _timer->start(); + } + else + { + _timer->stop(); + } + } + + QCheckBox* + PeriodicUpdateWidget::autoCheckBox() + { + return _autoCheckBox; + } + + QDoubleSpinBox* + PeriodicUpdateWidget::frequencySpinBox() + { + return _frequencySpinBox; + } + + QTimer* + PeriodicUpdateWidget::timer() + { + return _timer; + } + +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.h new file mode 100644 index 000000000..9d199db39 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.h @@ -0,0 +1,66 @@ +#pragma once + +#include <QWidget> + + +class QCheckBox; +class QDoubleSpinBox; +class QPushButton; +class QTimer; + +namespace armarx +{ + + class PeriodicUpdateWidget : public QWidget + { + Q_OBJECT + using This = PeriodicUpdateWidget; + + public: + PeriodicUpdateWidget(double frequency = 2.0, double maxFrequency = 60); + + + QTimer* timer(); + + QCheckBox* autoCheckBox(); + QDoubleSpinBox* frequencySpinBox(); + QPushButton* updateButton(); + + bool isAutoEnabled() const; + double getUpdateFrequency() const; + int getUpdateIntervalMs() const; + + void startTimerIfEnabled(); + void stopTimer(); + + + public slots: + + signals: + + void update(); + + void updateSingle(); + void updatePeriodic(); + + private slots: + + void _updateTimerFrequency(); + void _toggleAutoUpdates(bool enabled); + + signals: + + void startTimerSignal(); + void stopTimerSignal(); + + private: + QPushButton* _updateButton; + QCheckBox* _autoCheckBox; + QDoubleSpinBox* _frequencySpinBox; + + QPushButton* _collapseAllButton; + + QTimer* _timer; + }; + +} // namespace armarx -- GitLab