From b47bb78fa221c0035d134fee43b35f1ed79ff4a6 Mon Sep 17 00:00:00 2001 From: Andrei-Fabian-Pop Date: Wed, 25 Sep 2024 11:27:19 +0300 Subject: [PATCH] iio-widgets: Add optional runtime reconfiguration Signed-off-by: Andrei-Fabian-Pop --- gui/include/gui/widgets/menucombo.h | 1 + gui/src/widgets/menucombo.cpp | 2 + .../guistrategy/comboguistrategy.h | 3 + .../guistrategy/editableguistrategy.h | 2 + .../guistrategy/guistrategyinterface.h | 6 + .../guistrategy/rangeguistrategy.h | 1 + .../guistrategy/switchguistrategy.h | 1 + .../iio-widgets/iioconfigurationpopup.h | 46 +++++ iio-widgets/include/iio-widgets/iiowidget.h | 114 ++++++++++- .../include/iio-widgets/iiowidgetbuilder.h | 12 ++ .../include/iio-widgets/iiowidgetselector.h | 30 +++ .../src/guistrategy/comboguistrategy.cpp | 21 +- .../src/guistrategy/editableguistrategy.cpp | 10 +- .../src/guistrategy/rangeguistrategy.cpp | 2 + .../src/guistrategy/switchguistrategy.cpp | 2 + iio-widgets/src/iioconfigurationpopup.cpp | 184 ++++++++++++++++++ iio-widgets/src/iiowidget.cpp | 116 ++++++++++- iio-widgets/src/iiowidgetbuilder.cpp | 9 + iio-widgets/src/iiowidgetselector.cpp | 37 ++++ iioutil/include/iioutil/connection.h | 3 + iioutil/include/iioutil/iioitem.h | 76 ++++++++ iioutil/include/iioutil/iiotreescan.h | 25 +++ iioutil/src/connection.cpp | 8 + iioutil/src/iioitem.cpp | 93 +++++++++ iioutil/src/iiotreescan.cpp | 72 +++++++ .../src/menus/channelattributesmenu.cpp | 5 +- .../src/iioexplorer/clidetailsview.cpp | 15 +- .../src/iioexplorer/iioexplorerinstrument.cpp | 2 +- .../src/iioexplorer/watchlistentry.cpp | 20 +- .../src/iioexplorer/watchlistview.cpp | 2 +- plugins/swiot/src/ad74413r/buffermenu.cpp | 113 +++-------- tmp/grutil/src/grdeviceaddon.cpp | 3 +- tmp/grutil/src/grtimechanneladdon.cpp | 2 +- 33 files changed, 904 insertions(+), 134 deletions(-) create mode 100644 iio-widgets/include/iio-widgets/iioconfigurationpopup.h create mode 100644 iio-widgets/include/iio-widgets/iiowidgetselector.h create mode 100644 iio-widgets/src/iioconfigurationpopup.cpp create mode 100644 iio-widgets/src/iiowidgetselector.cpp create mode 100644 iioutil/include/iioutil/iioitem.h create mode 100644 iioutil/include/iioutil/iiotreescan.h create mode 100644 iioutil/src/iioitem.cpp create mode 100644 iioutil/src/iiotreescan.cpp diff --git a/gui/include/gui/widgets/menucombo.h b/gui/include/gui/widgets/menucombo.h index fee949df32..75ab9e7948 100644 --- a/gui/include/gui/widgets/menucombo.h +++ b/gui/include/gui/widgets/menucombo.h @@ -19,6 +19,7 @@ class SCOPY_GUI_EXPORT MenuCombo : public QWidget MenuCombo(QString title, QWidget *parent = nullptr); virtual ~MenuCombo(); + QLabel *label(); QComboBox *combo(); void applyStylesheet(); diff --git a/gui/src/widgets/menucombo.cpp b/gui/src/widgets/menucombo.cpp index cf8195c62b..1f59c2cf4c 100644 --- a/gui/src/widgets/menucombo.cpp +++ b/gui/src/widgets/menucombo.cpp @@ -46,6 +46,8 @@ MenuCombo::MenuCombo(QString title, QWidget *parent) } MenuCombo::~MenuCombo() {} + +QLabel *MenuCombo::label() { return m_label; } QComboBox *MenuCombo::combo() { return m_combo; } void MenuCombo::applyStylesheet() diff --git a/iio-widgets/include/iio-widgets/guistrategy/comboguistrategy.h b/iio-widgets/include/iio-widgets/guistrategy/comboguistrategy.h index c7d8d9c36c..e1f103f644 100644 --- a/iio-widgets/include/iio-widgets/guistrategy/comboguistrategy.h +++ b/iio-widgets/include/iio-widgets/guistrategy/comboguistrategy.h @@ -49,6 +49,7 @@ class SCOPY_IIO_WIDGETS_EXPORT ComboAttrUi : public QObject, public GuiStrategyI public Q_SLOTS: void receiveData(QString currentData, QString optionalData) override; + void changeName(QString name) override; Q_SIGNALS: void displayedNewData(QString data, QString optionalData) override; @@ -58,6 +59,8 @@ public Q_SLOTS: private: QWidget *m_ui; QComboBox *m_comboWidget; + MenuCombo *m_menuCombo; + QLabel *m_compactLabel; bool m_isCompact; }; } // namespace scopy diff --git a/iio-widgets/include/iio-widgets/guistrategy/editableguistrategy.h b/iio-widgets/include/iio-widgets/guistrategy/editableguistrategy.h index 5b749eeb68..c69cb6c790 100644 --- a/iio-widgets/include/iio-widgets/guistrategy/editableguistrategy.h +++ b/iio-widgets/include/iio-widgets/guistrategy/editableguistrategy.h @@ -49,6 +49,7 @@ class SCOPY_IIO_WIDGETS_EXPORT EditableGuiStrategy : public QObject, public GuiS public Q_SLOTS: void receiveData(QString currentData, QString optionalData) override; + void changeName(QString name) override; Q_SIGNALS: void displayedNewData(QString data, QString optionalData) override; @@ -57,6 +58,7 @@ public Q_SLOTS: private: QWidget *m_ui; + QLabel *m_titleLabel; MenuLineEdit *m_lineEdit; QString m_lastEmittedText; }; diff --git a/iio-widgets/include/iio-widgets/guistrategy/guistrategyinterface.h b/iio-widgets/include/iio-widgets/guistrategy/guistrategyinterface.h index 06f7fbcbe7..8c7b9b71f4 100644 --- a/iio-widgets/include/iio-widgets/guistrategy/guistrategyinterface.h +++ b/iio-widgets/include/iio-widgets/guistrategy/guistrategyinterface.h @@ -56,6 +56,12 @@ public Q_SLOTS: * */ virtual void receiveData(QString currentData, QString optionalData) = 0; + /** + * @brief changeName Changes the title of the UI strategy + * @param name The new name/title of the UI strategy + */ + virtual void changeName(QString name) = 0; + Q_SIGNALS: /** * @brief This signal is emitted when the ui strategy receives new data from external sources, diff --git a/iio-widgets/include/iio-widgets/guistrategy/rangeguistrategy.h b/iio-widgets/include/iio-widgets/guistrategy/rangeguistrategy.h index ee5106f4eb..e6d9f7e359 100644 --- a/iio-widgets/include/iio-widgets/guistrategy/rangeguistrategy.h +++ b/iio-widgets/include/iio-widgets/guistrategy/rangeguistrategy.h @@ -52,6 +52,7 @@ class SCOPY_IIO_WIDGETS_EXPORT RangeAttrUi : public QObject, public GuiStrategyI public Q_SLOTS: void receiveData(QString currentData, QString optionalData) override; + void changeName(QString name) override; Q_SIGNALS: void displayedNewData(QString data, QString optionalData) override; diff --git a/iio-widgets/include/iio-widgets/guistrategy/switchguistrategy.h b/iio-widgets/include/iio-widgets/guistrategy/switchguistrategy.h index 4887fbde55..0eae950934 100644 --- a/iio-widgets/include/iio-widgets/guistrategy/switchguistrategy.h +++ b/iio-widgets/include/iio-widgets/guistrategy/switchguistrategy.h @@ -50,6 +50,7 @@ class SCOPY_IIO_WIDGETS_EXPORT SwitchAttrUi : public QObject, public GuiStrategy public Q_SLOTS: void receiveData(QString currentData, QString optionalData) override; + void changeName(QString name) override; Q_SIGNALS: void displayedNewData(QString data, QString optionalData) override; diff --git a/iio-widgets/include/iio-widgets/iioconfigurationpopup.h b/iio-widgets/include/iio-widgets/iioconfigurationpopup.h new file mode 100644 index 0000000000..bcce6ac46a --- /dev/null +++ b/iio-widgets/include/iio-widgets/iioconfigurationpopup.h @@ -0,0 +1,46 @@ +#ifndef IIOCONFIGURATIONPOPUP_H +#define IIOCONFIGURATIONPOPUP_H + +#include "iiowidgetselector.h" +#include "scopy-iio-widgets_export.h" +#include +#include +#include +#include +#include +#include +#include + +namespace scopy { +class SCOPY_IIO_WIDGETS_EXPORT IIOConfigurationPopup : public QWidget +{ + Q_OBJECT +public: + explicit IIOConfigurationPopup(iio_context *ctx, QWidget *parent = nullptr); + explicit IIOConfigurationPopup(iio_device *dev, QWidget *parent = nullptr); + explicit IIOConfigurationPopup(iio_channel *chnl, QWidget *parent = nullptr); + ~IIOConfigurationPopup(); + + void enableTintedOverlay(bool enable = true); + +Q_SIGNALS: + void selectButtonClicked(IIOItem *selected); + void exitButtonClicked(); + +protected Q_SLOTS: + void modelSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected); + +protected: + void init(); + void initUI(); + + gui::TintedOverlay *m_tintedOverlay; + QLabel *m_titleLabel; + IIOWidgetSelector *m_widgetSelector; + QPushButton *m_exitButton; + QPushButton *m_selectButton; + IIOItem *m_root; +}; +} // namespace scopy + +#endif // IIOCONFIGURATIONPOPUP_H diff --git a/iio-widgets/include/iio-widgets/iiowidget.h b/iio-widgets/include/iio-widgets/iiowidget.h index 87c0d8d30d..6d70e250a3 100644 --- a/iio-widgets/include/iio-widgets/iiowidget.h +++ b/iio-widgets/include/iio-widgets/iiowidget.h @@ -22,11 +22,14 @@ #define SCOPY_IIOWIDGET_H #include +#include "iioconfigurationpopup.h" #include "iiowidgetdata.h" #include "utils.h" #include #include #include +#include +#include #include "guistrategy/guistrategyinterface.h" #include "datastrategy/datastrategyinterface.h" #include "scopy-iio-widgets_export.h" @@ -82,16 +85,11 @@ class SCOPY_IIO_WIDGETS_EXPORT IIOWidget : public QWidget void writeAsync(QString data); /** - * @brief Returns the UI of the IIOWidget - * @return GuiStrategyInterface - * */ - GuiStrategyInterface *getUiStrategy(); - - /** - * @brief Returns the data save/load strategy - * @return DataStretegyInterface - * */ - DataStrategyInterface *getDataStrategy(); + * @brief swapDataStrategy Disconnects the current Data Strategy and connects the new Data Strategy. + * @param dataStrategy The new Data Strategy that will be connected to the UIC. + * @return The old Data Strategy. + */ + DataStrategyInterface *swapDataStrategy(DataStrategyInterface *dataStrategy); /** * @brief Returns the recipe that this widget is based on. This is optional, currently serves as a way to pass @@ -129,6 +127,51 @@ class SCOPY_IIO_WIDGETS_EXPORT IIOWidget : public QWidget void setUItoDataConversion(std::function func); void setDataToUIConversion(std::function func); + /** + * @brief setConfigurable A configurable widget will have a wheel button on the right and it will allow the + * use to modify the underlying data strategy at runtime. + * @param isConfigurable If true, the widget is configurable at runtime. The default is false. + */ + void setConfigurable(bool isConfigurable); + + /** + * @brief setUIEnabled Enables/Disables the UI. + * @param isEnabled True if the UI should be enabled, false if it should be disabled. + */ + void setUIEnabled(bool isEnabled); + + /** + * @brief optionalData Calls the optionalData function from the data strategy. + * @return QString representing the optional data. + */ + QString optionalData() const; + + /** + * @brief data Calls the data functipm from the data strategy. + * @return QString represrnting the data. + */ + QString data() const; + + /** + * @brief isDSInstanceOf Checks whether the current data strategy is an instance of the specified type. + * @return True if the type specified coincides with the type of the data strategy. + */ + template + bool isDSInstanceOf() const + { + return dynamic_cast(m_dataStrategy) != nullptr; + } + + /** + * @brief isUISInstanceO Checks wheter the current UI strategy is an instance of the specified type. + * @return True if the type specified coincides with the type of the UI strategy. + */ + template + bool isUISInstanceOf() const + { + return dynamic_cast(m_uiStrategy) != nullptr; + } + Q_SIGNALS: /** * @brief Emits the current state of the IIOWidget system and a string containing a more @@ -136,6 +179,49 @@ class SCOPY_IIO_WIDGETS_EXPORT IIOWidget : public QWidget * */ void currentStateChanged(State currentState, QString explanation = ""); + /** + * @brief sendData Forwards the sendData signal from the Data Strategy (emits the newly read data). + * @param data The data read. + * @param dataOptions The data from the optional attribute read. + */ + void sendData(QString data, QString dataOptions); + + /** + * @brief emitStatus Forwarded signal from the Data Strategy for emitting the status of + * the operation that was just performed. + * @param timestamp QDateTime that holds the timestamp + * @param oldData The data that is present in the iio-widget before the operation + * @param newData The new data that was given to the operation + * @param returnCode int representing the return code of that operation + * @param isReadOp Boolean value set to true if the operation is a read + * operation and false if it is a write operation. + */ + void emitStatus(QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp); + + /** + * @brief This signal is emitted before a write operation + * @param oldData String containing the data what is present before the write + * @param newData String containing the data that will be written + * */ + void aboutToWrite(QString oldData, QString newData); + + /** + * @brief This will be the signal that the user changed the data, it is forwarded from the UI strategy. + * */ + void emitData(QString data); + + /** + * @brief This signal is emitted when the ui strategy receives new data from external sources, + * not from the user. + * @param data The data that will be displayed. + * @param optionalData The data options, if available. Empty string if the parameter is not + * necessary in this case. + * */ + void displayedNewData(QString data, QString optionalData); + +public Q_SLOTS: + void changeTitle(QString title); + protected Q_SLOTS: void saveData(QString data); void emitDataStatus(QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp); @@ -148,14 +234,17 @@ protected Q_SLOTS: protected: void initialize(); + void reconfigure(); void setLastOperationTimestamp(QDateTime timestamp); void setLastOperationState(IIOWidget::State state); + // Core variables GuiStrategyInterface *m_uiStrategy; DataStrategyInterface *m_dataStrategy; IIOWidgetFactoryRecipe m_recipe; + // Logged data QString m_lastData; SmallProgressBar *m_progressBar; QDateTime *m_lastOpTimestamp; @@ -165,6 +254,11 @@ protected Q_SLOTS: /* Conversion functions */ std::function m_UItoDS; std::function m_DStoUI; + + // Optional configuration + QPushButton *m_configBtn; + IIOConfigurationPopup *m_configPopup; + bool m_isConfigurable; }; } // namespace scopy diff --git a/iio-widgets/include/iio-widgets/iiowidgetbuilder.h b/iio-widgets/include/iio-widgets/iiowidgetbuilder.h index 7b9657654c..bb374dacca 100644 --- a/iio-widgets/include/iio-widgets/iiowidgetbuilder.h +++ b/iio-widgets/include/iio-widgets/iiowidgetbuilder.h @@ -98,6 +98,17 @@ class SCOPY_IIO_WIDGETS_EXPORT IIOWidgetBuilder : public QObject */ IIOWidgetBuilder &includeDebugAttributes(bool isIncluded); + /** + * @brief configMode Sets the IIOWidget to be configurable. This way, a + * wheel button will be created next to the IIOWidget. Once pressed, + * this button will allow the user to select a new attribute and the + * new data strategy will use that. + * @param isConfigurable If set to true, the IIOWidget will be configurable. + * Default is false. + * @return + */ + IIOWidgetBuilder &configMode(bool isConfigurable); + /** * @brief Sets the context that will be used, if no iio_device or iio_channel * is set, the build functions will work with the context. @@ -170,6 +181,7 @@ class SCOPY_IIO_WIDGETS_EXPORT IIOWidgetBuilder : public QObject Connection *m_connection; bool m_isCompact; bool m_includeDebugAttrs; + bool m_isConfigurable; struct iio_context *m_context; struct iio_device *m_device; struct iio_channel *m_channel; diff --git a/iio-widgets/include/iio-widgets/iiowidgetselector.h b/iio-widgets/include/iio-widgets/iiowidgetselector.h new file mode 100644 index 0000000000..ea22d9092c --- /dev/null +++ b/iio-widgets/include/iio-widgets/iiowidgetselector.h @@ -0,0 +1,30 @@ +#ifndef IIOWIDGETSELECTOR_H +#define IIOWIDGETSELECTOR_H + +#include +#include +#include +#include +#include +#include + +namespace scopy { +class IIOWidgetSelector : public QFrame +{ + Q_OBJECT +public: + IIOWidgetSelector(IIOItem *root, QWidget *parent = nullptr); + ~IIOWidgetSelector(); + QTreeView *getTree() const; + QStandardItemModel *getModel() const; + +Q_SIGNALS: + void itemSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected); + +private: + QTreeView *m_treeView; + QStandardItemModel *m_model; +}; +} // namespace scopy + +#endif // IIOWIDGETSELECTOR_H diff --git a/iio-widgets/src/guistrategy/comboguistrategy.cpp b/iio-widgets/src/guistrategy/comboguistrategy.cpp index bf916cf1e7..af709c1981 100644 --- a/iio-widgets/src/guistrategy/comboguistrategy.cpp +++ b/iio-widgets/src/guistrategy/comboguistrategy.cpp @@ -34,26 +34,26 @@ ComboAttrUi::ComboAttrUi(IIOWidgetFactoryRecipe recipe, bool isCompact, QObject m_ui->setLayout(new QHBoxLayout(m_ui)); m_ui->layout()->setContentsMargins(0, 0, 0, 0); - auto label = new QLabel(recipe.data, m_ui); - StyleHelper::IIOCompactLabel(label, "IIOTitleLabel"); + m_compactLabel = new QLabel(recipe.data, m_ui); + StyleHelper::IIOCompactLabel(m_compactLabel, "IIOTitleLabel"); m_comboWidget = new QComboBox(m_ui); m_comboWidget->setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy::AdjustToContents); StyleHelper::IIOComboBox(m_comboWidget, "IIOComboBox"); m_comboWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); - m_ui->layout()->addWidget(label); + m_ui->layout()->addWidget(m_compactLabel); m_ui->layout()->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Preferred)); m_ui->layout()->addWidget(m_comboWidget); } else { m_ui->setLayout(new QVBoxLayout(m_ui)); m_ui->layout()->setContentsMargins(0, 0, 0, 0); - auto comboMenuWidget = new MenuCombo(recipe.data, m_ui); - m_comboWidget = comboMenuWidget->combo(); + m_menuCombo = new MenuCombo(recipe.data, m_ui); + m_comboWidget = m_menuCombo->combo(); StyleHelper::IIOComboBox(m_comboWidget, "IIOComboBox"); - m_ui->layout()->addWidget(comboMenuWidget); + m_ui->layout()->addWidget(m_menuCombo); } connect(m_comboWidget, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int index) { @@ -97,4 +97,13 @@ void ComboAttrUi::receiveData(QString currentData, QString optionalData) Q_EMIT displayedNewData(currentData, optionalData); } +void ComboAttrUi::changeName(QString name) +{ + if(m_isCompact) { + m_compactLabel->setText(name); + } else { + m_menuCombo->label()->setText(name); + } +} + #include "moc_comboguistrategy.cpp" diff --git a/iio-widgets/src/guistrategy/editableguistrategy.cpp b/iio-widgets/src/guistrategy/editableguistrategy.cpp index 0175290ce1..90771f96f6 100644 --- a/iio-widgets/src/guistrategy/editableguistrategy.cpp +++ b/iio-widgets/src/guistrategy/editableguistrategy.cpp @@ -28,20 +28,20 @@ EditableGuiStrategy::EditableGuiStrategy(IIOWidgetFactoryRecipe recipe, bool isC , m_lineEdit(new MenuLineEdit(m_ui)) { m_recipe = recipe; - QLabel *label = new QLabel(recipe.data, m_ui); + m_titleLabel = new QLabel(recipe.data, m_ui); if(isCompact) { m_ui->setLayout(new QHBoxLayout(m_ui)); - StyleHelper::IIOCompactLabel(label, "TitleLabel"); + StyleHelper::IIOCompactLabel(m_titleLabel, "TitleLabel"); m_lineEdit->edit()->setAlignment(Qt::AlignRight); } else { m_ui->setLayout(new QVBoxLayout(m_ui)); - StyleHelper::MenuSmallLabel(label, "MenuSmallLabel"); + StyleHelper::MenuSmallLabel(m_titleLabel, "MenuSmallLabel"); } StyleHelper::IIOLineEdit(m_lineEdit->edit(), "IIOLineEdit"); m_ui->layout()->setContentsMargins(0, 0, 0, 0); - m_ui->layout()->addWidget(label); + m_ui->layout()->addWidget(m_titleLabel); m_ui->layout()->addWidget(m_lineEdit); connect(m_lineEdit->edit(), &QLineEdit::editingFinished, this, [this]() { @@ -75,4 +75,6 @@ void EditableGuiStrategy::receiveData(QString currentData, QString optionalData) Q_EMIT displayedNewData(currentData, optionalData); } +void EditableGuiStrategy::changeName(QString name) { m_titleLabel->setText(name); } + #include "moc_editableguistrategy.cpp" diff --git a/iio-widgets/src/guistrategy/rangeguistrategy.cpp b/iio-widgets/src/guistrategy/rangeguistrategy.cpp index 9c426c4fa0..1039473189 100644 --- a/iio-widgets/src/guistrategy/rangeguistrategy.cpp +++ b/iio-widgets/src/guistrategy/rangeguistrategy.cpp @@ -122,6 +122,8 @@ void RangeAttrUi::receiveData(QString currentData, QString optionalData) Q_EMIT displayedNewData(currentData, optionalData); } +void RangeAttrUi::changeName(QString name) { m_spinBox->setTitle(name); } + double RangeAttrUi::tryParse(QString number, bool *success) { // Try to parse as double first diff --git a/iio-widgets/src/guistrategy/switchguistrategy.cpp b/iio-widgets/src/guistrategy/switchguistrategy.cpp index 94610b2e9a..71571e6e3c 100644 --- a/iio-widgets/src/guistrategy/switchguistrategy.cpp +++ b/iio-widgets/src/guistrategy/switchguistrategy.cpp @@ -78,4 +78,6 @@ void SwitchAttrUi::receiveData(QString currentData, QString optionalData) Q_EMIT displayedNewData(currentData, optionalData); } +void SwitchAttrUi::changeName(QString name) { m_menuBigSwitch->setText(name); } + #include "moc_switchguistrategy.cpp" diff --git a/iio-widgets/src/iioconfigurationpopup.cpp b/iio-widgets/src/iioconfigurationpopup.cpp new file mode 100644 index 0000000000..68ea66a3f9 --- /dev/null +++ b/iio-widgets/src/iioconfigurationpopup.cpp @@ -0,0 +1,184 @@ +#include "iioconfigurationpopup.h" + +#include +#include +#include +#include + +using namespace scopy; + +Q_LOGGING_CATEGORY(CAT_IIOCONFIGURATIONPOPUP, "IIOConfigurationPopup") + +IIOConfigurationPopup::IIOConfigurationPopup(iio_context *ctx, QWidget *parent) + : QWidget{parent} + , m_tintedOverlay(nullptr) + , m_widgetSelector(nullptr) +{ + Connection *conn = ConnectionProvider::open(ctx); + IIOTreeScan *scan = conn->iioTreeScan(); + m_root = scan->getRoot(); + m_widgetSelector = new IIOWidgetSelector(m_root, this); + connect(m_widgetSelector, &IIOWidgetSelector::itemSelectionChanged, this, + &IIOConfigurationPopup::modelSelectionChanged); + m_widgetSelector->hide(); + + init(); +} + +IIOConfigurationPopup::IIOConfigurationPopup(iio_device *dev, QWidget *parent) + : QWidget{parent} + , m_tintedOverlay(nullptr) + , m_widgetSelector(nullptr) +{ + const iio_context *ctx = iio_device_get_context(dev); + Connection *conn = ConnectionProvider::open(const_cast(ctx)); + IIOTreeScan *scan = conn->iioTreeScan(); + m_root = scan->getRoot(); + m_widgetSelector = new IIOWidgetSelector(m_root, this); + connect(m_widgetSelector, &IIOWidgetSelector::itemSelectionChanged, this, + &IIOConfigurationPopup::modelSelectionChanged); + m_widgetSelector->hide(); + + init(); +} + +IIOConfigurationPopup::IIOConfigurationPopup(iio_channel *chnl, QWidget *parent) + : QWidget{parent} + , m_tintedOverlay(nullptr) + , m_widgetSelector(nullptr) +{ + const iio_device *dev = iio_channel_get_device(chnl); + const iio_context *ctx = iio_device_get_context(dev); + Connection *conn = ConnectionProvider::open(const_cast(ctx)); + IIOTreeScan *scan = conn->iioTreeScan(); + m_root = scan->getRoot(); + m_widgetSelector = new IIOWidgetSelector(m_root, this); + connect(m_widgetSelector, &IIOWidgetSelector::itemSelectionChanged, this, + &IIOConfigurationPopup::modelSelectionChanged); + m_widgetSelector->hide(); + + init(); +} + +IIOConfigurationPopup::~IIOConfigurationPopup() { delete m_tintedOverlay; } + +void IIOConfigurationPopup::enableTintedOverlay(bool enable) +{ + if(enable) { + delete m_tintedOverlay; + + m_widgetSelector->show(); + m_tintedOverlay = new gui::TintedOverlay(parentWidget()); + m_tintedOverlay->show(); + raise(); + show(); + move(parentWidget()->rect().center() - rect().center()); + } else { + delete m_tintedOverlay; + m_tintedOverlay = nullptr; + } +} + +void IIOConfigurationPopup::modelSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected) +{ + Q_UNUSED(deselected) + + if(selected.indexes().isEmpty()) { + qWarning(CAT_IIOCONFIGURATIONPOPUP) << "Selected index cannot be found."; + return; + } + + // There will be only one selected + QModelIndex index = selected.indexes().first(); + QStandardItem *item = m_widgetSelector->getModel()->itemFromIndex(index); + + IIOItem *iioItem = dynamic_cast(item); + if(!iioItem) { + qWarning(CAT_IIOCONFIGURATIONPOPUP) << "Received item is not an IIOItem."; + return; + } + + switch(iioItem->type()) { + case IIOItem::CHANNEL_ATTR: + case IIOItem::DEVICE_ATTR: + case IIOItem::CONTEXT_ATTR: + m_selectButton->setEnabled(true); + break; + default: + m_selectButton->setEnabled(false); + break; + } +} + +void IIOConfigurationPopup::init() +{ + initUI(); + QObject::connect(m_selectButton, &QPushButton::clicked, this, [&] { + const QModelIndex currentIndex = m_widgetSelector->getTree()->selectionModel()->currentIndex(); + if(!currentIndex.isValid()) { + qWarning(CAT_IIOCONFIGURATIONPOPUP) << "Current selection index is not valid."; + return; + } + + QStandardItem *item = m_widgetSelector->getModel()->itemFromIndex(currentIndex); + if(!item) { + qWarning(CAT_IIOCONFIGURATIONPOPUP) << "Cannot get current item from index."; + return; + } + + IIOItem *iioItem = dynamic_cast(item); + if(!iioItem) { + qWarning(CAT_IIOCONFIGURATIONPOPUP) << "Cannot cast QStandardItem to IIOItem."; + return; + } + + Q_EMIT selectButtonClicked(iioItem); + }); + QObject::connect(m_exitButton, &QPushButton::clicked, this, &IIOConfigurationPopup::exitButtonClicked); + m_selectButton->setDisabled(true); +} + +void IIOConfigurationPopup::initUI() +{ + this->setObjectName("PopupWidget"); + this->setStyleSheet(""); + this->resize(500, 300); + auto verticalLayout = new QVBoxLayout(this); + verticalLayout->setContentsMargins(0, 0, 0, 0); + this->setLayout(verticalLayout); + + auto backgroundWidget = new QWidget(this); + auto backgroundLayout = new QVBoxLayout(backgroundWidget); + verticalLayout->addWidget(backgroundWidget); + + m_titleLabel = new QLabel(backgroundWidget); + m_titleLabel->setObjectName("titleLabel"); + m_titleLabel->setText("Select a replacement attribute."); + + auto buttonGroup = new QWidget(backgroundWidget); + auto buttonGroupLayout = new QHBoxLayout(buttonGroup); + buttonGroupLayout->setContentsMargins(0, 0, 0, 0); + buttonGroupLayout->setSpacing(10); + + m_selectButton = new QPushButton("Select", buttonGroup); + m_selectButton->setObjectName("selectButton"); + + m_exitButton = new QPushButton("Exit", buttonGroup); + m_exitButton->setObjectName("exitButton"); + + buttonGroupLayout->addWidget(m_exitButton); + buttonGroupLayout->addWidget(m_selectButton); + + backgroundLayout->addWidget(m_titleLabel); + backgroundLayout->addWidget(m_widgetSelector); + backgroundLayout->addWidget(buttonGroup); + + backgroundWidget->setLayout(backgroundLayout); + + StyleHelper::TutorialChapterTitleLabel(m_titleLabel, "titleLabel"); + StyleHelper::BlueButton(m_selectButton, "selectButton"); + StyleHelper::BlueButton(m_exitButton, "exitButton"); + StyleHelper::OverlayMenu(this, "IIOConfigurationPopupOverlay"); +} + +#include "moc_iioconfigurationpopup.cpp" diff --git a/iio-widgets/src/iiowidget.cpp b/iio-widgets/src/iiowidget.cpp index 04b62808e2..9a3e59125f 100644 --- a/iio-widgets/src/iiowidget.cpp +++ b/iio-widgets/src/iiowidget.cpp @@ -19,8 +19,15 @@ */ #include "iiowidget.h" +#include "channelattrdatastrategy.h" +#include "contextattrdatastrategy.h" +#include "deviceattrdatastrategy.h" +#include "iiowidgetselector.h" +#include #include +#include #include +#include using namespace scopy; @@ -31,11 +38,13 @@ IIOWidget::IIOWidget(GuiStrategyInterface *uiStrategy, DataStrategyInterface *da , m_uiStrategy(uiStrategy) , m_dataStrategy(dataStrategy) , m_progressBar(new SmallProgressBar(this)) + , m_configBtn(new QPushButton(this)) , m_lastOpTimestamp(nullptr) , m_lastOpState(nullptr) , m_lastReturnCode(0) , m_UItoDS(nullptr) , m_DStoUI(nullptr) + , m_isConfigurable(false) { setLayout(new QVBoxLayout(this)); layout()->setContentsMargins(0, 0, 0, 0); @@ -86,6 +95,51 @@ void IIOWidget::readAsync() { m_dataStrategy->readAsync(); } void IIOWidget::writeAsync(QString data) { m_dataStrategy->writeAsync(data); } +DataStrategyInterface *IIOWidget::swapDataStrategy(DataStrategyInterface *dataStrategy) +{ + QWidget *dataStrategyWidget = dynamic_cast(m_dataStrategy); + QWidget *uiStrategyWidget = dynamic_cast(m_uiStrategy); + QWidget *newDataStrategyWidget = dynamic_cast(dataStrategy); + + // disconnect old data strategy + disconnect(dataStrategyWidget, SIGNAL(emitStatus(QDateTime, QString, QString, int, bool)), this, + SLOT(emitDataStatus(QDateTime, QString, QString, int, bool))); + disconnect(uiStrategyWidget, SIGNAL(requestData()), dataStrategyWidget, SLOT(readAsync())); + disconnect(dataStrategyWidget, SIGNAL(sendData(QString, QString)), uiStrategyWidget, + SLOT(receiveData(QString, QString))); + disconnect(dataStrategyWidget, SIGNAL(sendData(QString, QString)), this, + SLOT(storeReadInfo(QString, QString))); // TODO: maybe do something with this slot.. + disconnect(dataStrategyWidget, SIGNAL(sendData(QString, QString)), this, SIGNAL(sendData(QString, QString))); + disconnect(dataStrategyWidget, SIGNAL(emitStatus(QDateTime, QString, QString, int, bool)), this, + SIGNAL(emitStatus(QDateTime, QString, QString, int, bool))); + disconnect(dataStrategyWidget, SIGNAL(aboutToWrite(QString, QString)), this, + SIGNAL(aboutToWrite(QString, QString))); + disconnect(uiStrategyWidget, SIGNAL(emitData(QString)), this, SIGNAL(emitData(QString))); + disconnect(uiStrategyWidget, SIGNAL(displayedNewData(QString, QString)), this, + SIGNAL(displayedNewData(QString, QString))); + + // connect new data strategy + connect(newDataStrategyWidget, SIGNAL(emitStatus(QDateTime, QString, QString, int, bool)), this, + SLOT(emitDataStatus(QDateTime, QString, QString, int, bool))); + connect(uiStrategyWidget, SIGNAL(requestData()), newDataStrategyWidget, SLOT(readAsync())); + connect(newDataStrategyWidget, SIGNAL(sendData(QString, QString)), uiStrategyWidget, + SLOT(receiveData(QString, QString))); + connect(newDataStrategyWidget, SIGNAL(sendData(QString, QString)), this, SLOT(storeReadInfo(QString, QString))); + connect(dataStrategyWidget, SIGNAL(sendData(QString, QString)), this, SIGNAL(sendData(QString, QString))); + connect(dataStrategyWidget, SIGNAL(emitStatus(QDateTime, QString, QString, int, bool)), this, + SIGNAL(emitStatus(QDateTime, QString, QString, int, bool))); + connect(dataStrategyWidget, SIGNAL(aboutToWrite(QString, QString)), this, + SIGNAL(aboutToWrite(QString, QString))); + connect(uiStrategyWidget, SIGNAL(emitData(QString)), this, SIGNAL(emitData(QString))); + connect(uiStrategyWidget, SIGNAL(displayedNewData(QString, QString)), this, + SIGNAL(displayedNewData(QString, QString))); + + // save the new data strategy and return the old one + DataStrategyInterface *oldDS = m_dataStrategy; + m_dataStrategy = dataStrategy; + return oldDS; +} + void IIOWidget::saveData(QString data) { setLastOperationState(IIOWidget::Busy); @@ -97,6 +151,8 @@ void IIOWidget::saveData(QString data) m_dataStrategy->writeAsync(data); } +void IIOWidget::changeTitle(QString title) { m_uiStrategy->changeName(title); } + void IIOWidget::emitDataStatus(QDateTime timestamp, QString oldData, QString newData, int status, bool isReadOp) { // The read operation will not be shown as a status here as it will overlap with the @@ -133,10 +189,6 @@ void IIOWidget::emitDataStatus(QDateTime timestamp, QString oldData, QString new timer->start(4000); } -GuiStrategyInterface *IIOWidget::getUiStrategy() { return m_uiStrategy; } - -DataStrategyInterface *IIOWidget::getDataStrategy() { return m_dataStrategy; } - IIOWidgetFactoryRecipe IIOWidget::getRecipe() { return m_recipe; } void IIOWidget::setRecipe(IIOWidgetFactoryRecipe recipe) { m_recipe = recipe; } @@ -151,6 +203,18 @@ void IIOWidget::setUItoDataConversion(std::function func) { m_ void IIOWidget::setDataToUIConversion(std::function func) { m_DStoUI = func; } +void IIOWidget::setConfigurable(bool isConfigurable) +{ + m_isConfigurable = isConfigurable; + m_configBtn->setVisible(m_isConfigurable); +} + +void IIOWidget::setUIEnabled(bool isEnabled) { m_uiStrategy->ui()->setEnabled(isEnabled); } + +QString IIOWidget::optionalData() const { return m_dataStrategy->optionalData(); } + +QString IIOWidget::data() const { return m_dataStrategy->data(); } + void IIOWidget::startTimer(QString data) { m_lastData = data; @@ -184,6 +248,50 @@ void IIOWidget::convertDStoUI(QString data, QString optionalData) void IIOWidget::initialize() { m_dataStrategy->readAsync(); } +void IIOWidget::reconfigure() +{ + // display the popup and switch the DS + if(m_recipe.context) { + m_configPopup = new IIOConfigurationPopup(m_recipe.context, qApp->activeWindow()); + } else if(m_recipe.device) { + m_configPopup = new IIOConfigurationPopup(m_recipe.device, qApp->activeWindow()); + } else if(m_recipe.channel) { + m_configPopup = new IIOConfigurationPopup(m_recipe.channel, qApp->activeWindow()); + } else { + qCritical(CAT_IIOWIDGET) << "No available context/device/channel"; + } + + connect(m_configPopup, &IIOConfigurationPopup::exitButtonClicked, this, + [&]() { m_configPopup->deleteLater(); }); + connect(m_configPopup, &IIOConfigurationPopup::selectButtonClicked, this, [&](IIOItem *item) { + DataStrategyInterface *dsCreated = nullptr; + switch(item->type()) { + case IIOItem::CHANNEL_ATTR: + dsCreated = new ChannelAttrDataStrategy({.channel = item->chnl(), .data = item->name()}, this); + break; + case IIOItem::DEVICE_ATTR: + dsCreated = new DeviceAttrDataStrategy({.device = item->dev(), .data = item->name()}, this); + break; + case IIOItem::CONTEXT_ATTR: + dsCreated = new ContextAttrDataStrategy({.context = item->ctx(), .data = item->name()}, this); + default: + break; + } + + if(!dsCreated) { + qWarning(CAT_IIOWIDGET) << "Could not create a new data strategy."; + return; + } + + m_uiStrategy->changeName(item->name().toUpper()); + DataStrategyInterface *oldDS = swapDataStrategy(dsCreated); + dsCreated->readAsync(); + delete oldDS; + delete m_configPopup; + }); + m_configPopup->enableTintedOverlay(true); +} + void IIOWidget::setLastOperationTimestamp(QDateTime timestamp) { if(m_lastOpTimestamp == nullptr) { diff --git a/iio-widgets/src/iiowidgetbuilder.cpp b/iio-widgets/src/iiowidgetbuilder.cpp index c3e2bed926..e6bfe1741b 100644 --- a/iio-widgets/src/iiowidgetbuilder.cpp +++ b/iio-widgets/src/iiowidgetbuilder.cpp @@ -42,6 +42,7 @@ IIOWidgetBuilder::IIOWidgetBuilder(QObject *parent) , m_connection(nullptr) , m_isCompact(false) , m_includeDebugAttrs(Preferences::get("debugger_v2_include_debugfs").toBool()) + , m_isConfigurable(false) , m_context(nullptr) , m_device(nullptr) , m_channel(nullptr) @@ -85,6 +86,7 @@ IIOWidget *IIOWidgetBuilder::buildSingle() IIOWidget *widget = new IIOWidget(ui, ds, m_widgetParent); widget->setRecipe(m_generatedRecipe); + widget->setConfigurable(m_isConfigurable); return widget; } @@ -206,6 +208,7 @@ void IIOWidgetBuilder::clear() { m_connection = nullptr; m_isCompact = false; + m_isConfigurable = false; m_context = nullptr; m_device = nullptr; m_channel = nullptr; @@ -235,6 +238,12 @@ IIOWidgetBuilder &IIOWidgetBuilder::includeDebugAttributes(bool isIncluded) return *this; } +IIOWidgetBuilder &IIOWidgetBuilder::configMode(bool isConfigurable) +{ + m_isConfigurable = isConfigurable; + return *this; +} + IIOWidgetBuilder &IIOWidgetBuilder::context(iio_context *context) { m_context = context; diff --git a/iio-widgets/src/iiowidgetselector.cpp b/iio-widgets/src/iiowidgetselector.cpp new file mode 100644 index 0000000000..25451f71df --- /dev/null +++ b/iio-widgets/src/iiowidgetselector.cpp @@ -0,0 +1,37 @@ +#include "iiowidgetselector.h" + +#include +#include + +using namespace scopy; + +IIOWidgetSelector::IIOWidgetSelector(IIOItem *root, QWidget *parent) + : QFrame(parent) +{ + setLayout(new QVBoxLayout(this)); + layout()->setContentsMargins(0, 0, 0, 0); + m_treeView = new QTreeView(this); + m_model = new QStandardItemModel(m_treeView); + m_model->appendRow(root); + m_treeView->setModel(m_model); + m_treeView->expand(m_model->index(0, 0)); + m_treeView->setHeaderHidden(true); + layout()->addWidget(m_treeView); + StyleHelper::TreeViewDebugger(m_treeView, "TreeView"); + setStyleSheet("background-color: " + StyleHelper::getColor("ScopyBackground")); + + connect(m_treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, + &IIOWidgetSelector::itemSelectionChanged); +} + +IIOWidgetSelector::~IIOWidgetSelector() +{ + // This should be done so that the root item is not deleted when the model is deleted + m_model->takeRow(0); +} + +QTreeView *IIOWidgetSelector::getTree() const { return m_treeView; } + +QStandardItemModel *IIOWidgetSelector::getModel() const { return m_model; } + +#include "moc_iiowidgetselector.cpp" diff --git a/iioutil/include/iioutil/connection.h b/iioutil/include/iioutil/connection.h index c6d8688167..e7e6dbee37 100644 --- a/iioutil/include/iioutil/connection.h +++ b/iioutil/include/iioutil/connection.h @@ -2,6 +2,7 @@ #define CONNECTION_H #include "scopy-iioutil_export.h" #include "commandqueue.h" +#include "iiotreescan.h" #include #include @@ -14,6 +15,7 @@ class SCOPY_IIOUTIL_EXPORT Connection : public QObject const QString &uri() const; CommandQueue *commandQueue() const; + IIOTreeScan *iioTreeScan() const; struct iio_context *context() const; int refCount() const; @@ -57,6 +59,7 @@ class SCOPY_IIOUTIL_EXPORT Connection : public QObject friend class ConnectionProvider; QString m_uri; CommandQueue *m_commandQueue; + IIOTreeScan *m_iioTreeScan; struct iio_context *m_context; int m_refCount = 0; }; diff --git a/iioutil/include/iioutil/iioitem.h b/iioutil/include/iioutil/iioitem.h new file mode 100644 index 0000000000..fe7b637fe5 --- /dev/null +++ b/iioutil/include/iioutil/iioitem.h @@ -0,0 +1,76 @@ +#ifndef IIOITEM_H +#define IIOITEM_H + +#include "scopy-iioutil_export.h" +#include +#include +#include + +namespace scopy { +class SCOPY_IIOUTIL_EXPORT IIOItem : public QStandardItem +{ +public: + // User defined types should be > 1000, the rest are Qt reserved + // In order to ensure that the user cannot enter a type and a + // different iio struct, we will separate the types in 3 enums + enum IIOTypeCtx + { + CONTEXT = 1001, + CONTEXT_ATTR = 1002, + }; + + enum IIOTypeDev + { + DEVICE = 1003, + DEVICE_ATTR = 1004, + }; + + enum IIOTypeChnl + { + CHANNEL = 1005, + CHANNEL_ATTR = 1006, + }; + + IIOItem(QString name, QString id, IIOTypeCtx type, iio_context *ctx, IIOItem *parent = nullptr); + IIOItem(QString name, QString id, IIOTypeDev type, iio_device *dev, IIOItem *parent = nullptr); + IIOItem(QString name, QString id, IIOTypeChnl type, iio_channel *chnl, IIOItem *parent = nullptr); + virtual ~IIOItem(); + int type() const override; + + // Navigation functions + int childCount() const; + void addChild(IIOItem *item); + void removeChild(IIOItem *item); + IIOItem *child(int index) const; + IIOItem *child(QString name) const; + IIOItem *parent() const; + void setParent(IIOItem *parent); + + // Data functions + QString name() const; + QString id() const; + + iio_context *ctx() const; + void setCtx(iio_context *newCtx); + + iio_device *dev() const; + void setDev(iio_device *newDev); + + iio_channel *chnl() const; + void setChnl(iio_channel *newChnl); + +private: + int m_type; + IIOItem *m_parent; + QList m_children; + + struct iio_context *m_ctx; + struct iio_device *m_dev; + struct iio_channel *m_chnl; + + QString m_name; + QString m_id; +}; +} // namespace scopy + +#endif // IIOITEM_H diff --git a/iioutil/include/iioutil/iiotreescan.h b/iioutil/include/iioutil/iiotreescan.h new file mode 100644 index 0000000000..1dc81b4537 --- /dev/null +++ b/iioutil/include/iioutil/iiotreescan.h @@ -0,0 +1,25 @@ +#ifndef IIOTREESCAN_H +#define IIOTREESCAN_H + +#include +#include "iioitem.h" +#include +#include "scopy-iioutil_export.h" + +#include + +namespace scopy { +class SCOPY_IIOUTIL_EXPORT IIOTreeScan : public QObject +{ + Q_OBJECT +public: + explicit IIOTreeScan(struct iio_context *ctx, QObject *parent = nullptr); + ~IIOTreeScan(); + IIOItem *getRoot(); + +private: + IIOItem *m_rootItem; +}; +} // namespace scopy + +#endif // IIOTREESCAN_H diff --git a/iioutil/src/connection.cpp b/iioutil/src/connection.cpp index 7c12757631..5022bb007b 100644 --- a/iioutil/src/connection.cpp +++ b/iioutil/src/connection.cpp @@ -7,6 +7,7 @@ Connection::Connection(QString uri) this->m_uri = uri; this->m_context = nullptr; this->m_commandQueue = nullptr; + this->m_iioTreeScan = nullptr; this->m_refCount = 0; } @@ -16,6 +17,10 @@ Connection::~Connection() delete this->m_commandQueue; this->m_commandQueue = nullptr; } + if(this->m_iioTreeScan) { + delete this->m_iioTreeScan; + this->m_iioTreeScan = nullptr; + } if(this->m_context) { iio_context_destroy(this->m_context); this->m_context = nullptr; @@ -26,6 +31,8 @@ const QString &Connection::uri() const { return m_uri; } CommandQueue *Connection::commandQueue() const { return m_commandQueue; } +IIOTreeScan *Connection::iioTreeScan() const { return m_iioTreeScan; } + iio_context *Connection::context() const { return m_context; } int Connection::refCount() const { return m_refCount; } @@ -36,6 +43,7 @@ void Connection::open() this->m_context = iio_create_context_from_uri(this->m_uri.toStdString().c_str()); if(this->m_context) { this->m_commandQueue = new CommandQueue(); + this->m_iioTreeScan = new IIOTreeScan(this->m_context); this->m_refCount++; } } else { diff --git a/iioutil/src/iioitem.cpp b/iioutil/src/iioitem.cpp new file mode 100644 index 0000000000..ad08de3809 --- /dev/null +++ b/iioutil/src/iioitem.cpp @@ -0,0 +1,93 @@ +#include "iioitem.h" + +using namespace scopy; + +IIOItem::IIOItem(QString name, QString id, IIOTypeCtx type, iio_context *ctx, IIOItem *parent) + : QStandardItem((id.isEmpty()) ? name : id + ((name.isEmpty()) ? " " : ": " + name)) + , m_name(name) + , m_id(id) + , m_type(type) + , m_ctx(ctx) + , m_parent(parent) +{} + +IIOItem::IIOItem(QString name, QString id, IIOTypeDev type, iio_device *dev, IIOItem *parent) + : QStandardItem((id.isEmpty()) ? name : id + ((name.isEmpty()) ? " " : ": " + name)) + , m_name(name) + , m_id(id) + , m_type(type) + , m_dev(dev) + , m_parent(parent) +{} + +IIOItem::IIOItem(QString name, QString id, IIOTypeChnl type, iio_channel *chnl, IIOItem *parent) + : QStandardItem((id.isEmpty()) ? name : id + ((name.isEmpty()) ? " " : ": " + name)) + , m_name(name) + , m_id(id) + , m_type(type) + , m_chnl(chnl) + , m_parent(parent) +{} + +IIOItem::~IIOItem() {} + +int IIOItem::type() const { return m_type; } + +int IIOItem::childCount() const { return m_children.size(); } + +void IIOItem::addChild(IIOItem *item) +{ + item->setParent(this); + appendRow(item); + m_children.append(item); // Maintain out own list for easy access +} + +void IIOItem::removeChild(IIOItem *item) +{ + int row = m_children.indexOf(item); + if(row >= 0) { + removeRow(row); + m_children.removeAt(row); + delete item; + } +} + +IIOItem *IIOItem::child(int index) const +{ + if(index >= 0 && index < m_children.size()) { + return m_children.at(index); + } + + return nullptr; +} + +IIOItem *IIOItem::child(QString name) const +{ + for(int i = 0; i < m_children.size(); ++i) { + if(m_children.at(i)->name() == name) { + return m_children.at(i); + } + } + + return nullptr; +} + +IIOItem *IIOItem::parent() const { return m_parent; } + +void IIOItem::setParent(IIOItem *parent) { m_parent = parent; } + +QString IIOItem::name() const { return m_name; } + +QString IIOItem::id() const { return m_id; } + +iio_context *IIOItem::ctx() const { return m_ctx; } + +void IIOItem::setCtx(iio_context *newCtx) { m_ctx = newCtx; } + +iio_device *IIOItem::dev() const { return m_dev; } + +void IIOItem::setDev(iio_device *newDev) { m_dev = newDev; } + +iio_channel *IIOItem::chnl() const { return m_chnl; } + +void IIOItem::setChnl(iio_channel *newChnl) { m_chnl = newChnl; } diff --git a/iioutil/src/iiotreescan.cpp b/iioutil/src/iiotreescan.cpp new file mode 100644 index 0000000000..f7707b4ae7 --- /dev/null +++ b/iioutil/src/iiotreescan.cpp @@ -0,0 +1,72 @@ +#include "iiotreescan.h" +#include +#include +#include + +Q_LOGGING_CATEGORY(CAT_IIOTREESCAN, "IIOTreeScan") + +using namespace scopy; + +IIOTreeScan::IIOTreeScan(iio_context *ctx, QObject *parent) + : QObject{parent} +{ + m_rootItem = new IIOItem(iio_context_get_name(ctx), "", IIOItem::CONTEXT, ctx, nullptr); + m_rootItem->setEditable(false); + + int ctxAttrs = iio_context_get_attrs_count(ctx); + for(int i = 0; i < ctxAttrs; ++i) { + const char *ctxAttrName; + const char *ctxAttrValue; + int res = iio_context_get_attr(ctx, i, &ctxAttrName, &ctxAttrValue); + if(res < 0) { + qWarning(CAT_IIOTREESCAN) << "Error when reading the context attr" << i; + continue; + } + IIOItem *item = new IIOItem(ctxAttrName, "", IIOItem::CONTEXT_ATTR, ctx, m_rootItem); + item->setEditable(false); + m_rootItem->addChild(item); + } + + int ctxDevs = iio_context_get_devices_count(ctx); + for(int i = 0; i < ctxDevs; ++i) { + iio_device *dev = iio_context_get_device(ctx, i); + QString devName = iio_device_get_name(dev); + QString devId = iio_device_get_id(dev); + IIOItem *devItem = new IIOItem(devName, devId, IIOItem::DEVICE, dev, m_rootItem); + devItem->setEditable(false); + + int devAttrCount = iio_device_get_attrs_count(dev); + for(int j = 0; j < devAttrCount; ++j) { + QString devAttrName = iio_device_get_attr(dev, j); + IIOItem *devAttrItem = new IIOItem(devAttrName, "", IIOItem::DEVICE_ATTR, dev, devItem); + devAttrItem->setEditable(false); + devItem->addChild(devAttrItem); + } + + int devChannelCount = iio_device_get_channels_count(dev); + for(int j = 0; j < devChannelCount; ++j) { + iio_channel *chnl = iio_device_get_channel(dev, j); + QString channelName = iio_channel_get_name(chnl); + QString channelId = iio_channel_get_id(chnl); + IIOItem *chnlItem = new IIOItem(channelName, channelId, IIOItem::CHANNEL, chnl, devItem); + chnlItem->setEditable(false); + + int chnlAttrCount = iio_channel_get_attrs_count(chnl); + for(int k = 0; k < chnlAttrCount; ++k) { + QString channelAttrName = iio_channel_get_attr(chnl, k); + IIOItem *chnlAttrItem = + new IIOItem(channelAttrName, "", IIOItem::CHANNEL_ATTR, chnl, chnlItem); + chnlAttrItem->setEditable(false); + chnlItem->addChild(chnlAttrItem); + } + devItem->addChild(chnlItem); + } + m_rootItem->addChild(devItem); + } +} + +IIOTreeScan::~IIOTreeScan() { qDebug(CAT_IIOTREESCAN) << "IIOTreeScan object dtor"; } + +IIOItem *IIOTreeScan::getRoot() { return m_rootItem; } + +#include "moc_iiotreescan.cpp" diff --git a/plugins/datalogger/src/menus/channelattributesmenu.cpp b/plugins/datalogger/src/menus/channelattributesmenu.cpp index e78c94bb0f..51cd5a28f5 100644 --- a/plugins/datalogger/src/menus/channelattributesmenu.cpp +++ b/plugins/datalogger/src/menus/channelattributesmenu.cpp @@ -39,7 +39,10 @@ ChannelAttributesMenu::ChannelAttributesMenu(DataMonitorModel *model, QWidget *p if(qobject_cast(model)) { QList attrWidgets = - IIOWidgetBuilder().channel(dynamic_cast(model)->iioChannel()).buildAll(); + IIOWidgetBuilder() + .channel(dynamic_cast(model)->iioChannel()) + .parent(parent) + .buildAll(); for(auto w : attrWidgets) { attrLayout->addWidget(w); diff --git a/plugins/debugger/src/iioexplorer/clidetailsview.cpp b/plugins/debugger/src/iioexplorer/clidetailsview.cpp index 9f560de4b7..078491e380 100644 --- a/plugins/debugger/src/iioexplorer/clidetailsview.cpp +++ b/plugins/debugger/src/iioexplorer/clidetailsview.cpp @@ -85,12 +85,11 @@ void CliDetailsView::setupUi() void CliDetailsView::setupChannelAttr() { IIOWidget *w = m_channelIIOItem->getIIOWidgets()[0]; - DataStrategyInterface *ds = w->getDataStrategy(); m_currentText.append(tabs(4) + "attr " + QString::number(m_noChnlAttributes) + ": " + m_channelIIOItem->name() + - " value: " + ds->data() + "\n"); + " value: " + w->data() + "\n"); ++m_noChnlAttributes; - QString channelOptData = ds->optionalData(); + QString channelOptData = w->optionalData(); if(!channelOptData.isEmpty()) { m_currentText.append(tabs(4) + "attr " + QString::number(m_noChnlAttributes) + ": " + w->getRecipe().iioDataOptions + " value: " + channelOptData + "\n"); @@ -126,13 +125,11 @@ void CliDetailsView::setupChannel() void CliDetailsView::setupDeviceAttr() { IIOWidget *w = m_deviceIIOItem->getIIOWidgets()[0]; - DataStrategyInterface *ds = w->getDataStrategy(); - m_deviceAttrsString.append(tabs(4) + "attr " + QString::number(m_noDevAttributes) + ": " + - m_deviceIIOItem->name() + " value: " + ds->data() + "\n"); + m_deviceIIOItem->name() + " value: " + w->data() + "\n"); ++m_noDevAttributes; - QString deviceOptData = ds->optionalData(); + QString deviceOptData = w->optionalData(); if(!deviceOptData.isEmpty()) { m_deviceAttrsString.append(tabs(4) + "attr " + QString::number(m_noDevAttributes) + ": " + w->getRecipe().iioDataOptions + " value: " + deviceOptData + "\n"); @@ -182,8 +179,8 @@ void CliDetailsView::setupDevice() void CliDetailsView::setupContextAttr() { ++m_noCtxAttributes; - m_currentText.append(tabs(1) + m_contextIIOItem->name() + ": " + - m_contextIIOItem->getIIOWidgets()[0]->getDataStrategy()->data() + "\n"); + m_currentText.append(tabs(1) + m_contextIIOItem->name() + ": " + m_contextIIOItem->getIIOWidgets()[0]->data() + + "\n"); } void CliDetailsView::setupContext() diff --git a/plugins/debugger/src/iioexplorer/iioexplorerinstrument.cpp b/plugins/debugger/src/iioexplorer/iioexplorerinstrument.cpp index 4803700cb3..250fb805ed 100644 --- a/plugins/debugger/src/iioexplorer/iioexplorerinstrument.cpp +++ b/plugins/debugger/src/iioexplorer/iioexplorerinstrument.cpp @@ -290,7 +290,7 @@ void IIOExplorerInstrument::triggerReadOnAllChildItems(QStandardItem *item) QList iioWidgets = IIOitem->getIIOWidgets(); for(int i = 0; i < iioWidgets.size(); ++i) { qInfo(CAT_DEBUGGERIIOMODEL) << "Reading " << IIOitem->path(); - iioWidgets.at(i)->getDataStrategy()->readAsync(); + iioWidgets.at(i)->readAsync(); } } else { // not a leaf node, continue recursion diff --git a/plugins/debugger/src/iioexplorer/watchlistentry.cpp b/plugins/debugger/src/iioexplorer/watchlistentry.cpp index a424546962..c143f3096e 100644 --- a/plugins/debugger/src/iioexplorer/watchlistentry.cpp +++ b/plugins/debugger/src/iioexplorer/watchlistentry.cpp @@ -76,8 +76,9 @@ void WatchListEntry::setupUi() void WatchListEntry::setupWidget(IIOWidget *widget) { // if you can cast the uiStrategy to combo, this value ui will be a combo, otherwise it will be a lineedit - GuiStrategyInterface *ui = dynamic_cast(widget->getUiStrategy()); - if(ui) { + // GuiStrategyInterface *ui = dynamic_cast(widget->getUiStrategy()); + bool isCombo = widget->isDSInstanceOf(); + if(isCombo) { // https://forum.qt.io/topic/139728/can-t-set-qcombobox-qslider-margins // QFrame because QWidget does not have the paintEvent implemented QFrame *wrapper = new QFrame(); @@ -95,13 +96,12 @@ void WatchListEntry::setupWidget(IIOWidget *widget) })css"); wrapper->layout()->addWidget(m_combo); - QString options = widget->getDataStrategy()->optionalData(); + QString options = widget->optionalData(); QStringList list = options.split(" ", Qt::SkipEmptyParts); - m_combo->addItems(widget->getDataStrategy()->optionalData().split(" ", Qt::SkipEmptyParts)); - m_combo->setCurrentText(widget->getDataStrategy()->data()); - QObject::connect(m_combo, &QComboBox::currentTextChanged, this, [this, widget, options](QString text) { - widget->getDataStrategy()->writeAsync(text); - }); + m_combo->addItems(widget->optionalData().split(" ", Qt::SkipEmptyParts)); + m_combo->setCurrentText(widget->data()); + QObject::connect(m_combo, &QComboBox::currentTextChanged, this, + [this, widget, options](QString text) { widget->writeAsync(text); }); m_valueUi = wrapper; } else { m_lineedit = new QLineEdit(); @@ -112,10 +112,10 @@ void WatchListEntry::setupWidget(IIOWidget *widget) background-color: transparent; font-size: 13px; })css"); - m_lineedit->setText(widget->getDataStrategy()->data()); + m_lineedit->setText(widget->data()); QObject::connect(m_lineedit, &QLineEdit::editingFinished, this, [this, widget]() { QString text = m_lineedit->text(); - widget->getDataStrategy()->writeAsync(text); + widget->writeAsync(text); }); m_valueUi = m_lineedit; } diff --git a/plugins/debugger/src/iioexplorer/watchlistview.cpp b/plugins/debugger/src/iioexplorer/watchlistview.cpp index 9e2f8d7dd9..8e22d180a0 100644 --- a/plugins/debugger/src/iioexplorer/watchlistview.cpp +++ b/plugins/debugger/src/iioexplorer/watchlistview.cpp @@ -163,7 +163,7 @@ void WatchListView::refreshWatchlist() type == IIOStandardItem::ChannelAttribute) { // leaf node IIOWidget *iioWidget = object->item()->getIIOWidgets()[0]; - iioWidget->getDataStrategy()->readAsync(); + iioWidget->readAsync(); } } } diff --git a/plugins/swiot/src/ad74413r/buffermenu.cpp b/plugins/swiot/src/ad74413r/buffermenu.cpp index 921dae215c..af1431bfe7 100644 --- a/plugins/swiot/src/ad74413r/buffermenu.cpp +++ b/plugins/swiot/src/ad74413r/buffermenu.cpp @@ -46,13 +46,10 @@ BufferMenu::BufferMenu(QWidget *parent, QString chnlFunction, Connection *conn, .parent(this) .buildSingle(); addMenuWidget(m_samplingFreq); - connect(dynamic_cast(m_samplingFreq->getUiStrategy()), &ComboAttrUi::displayedNewData, - this, + connect(m_samplingFreq, &IIOWidget::displayedNewData, this, [this](QString data, QString optionalData) { Q_EMIT samplingFrequencyUpdated(data.toInt()); }); - connect(dynamic_cast(m_samplingFreq->getUiStrategy()), &ComboAttrUi::emitData, this, - &BufferMenu::freqChangeStart); - connect(dynamic_cast(m_samplingFreq->getDataStrategy()), - &CmdQChannelAttrDataStrategy::emitStatus, this, &BufferMenu::freqChangeEnd); + connect(m_samplingFreq, &IIOWidget::emitData, this, &BufferMenu::freqChangeStart); + connect(m_samplingFreq, &IIOWidget::emitStatus, this, &BufferMenu::freqChangeEnd); } } @@ -72,10 +69,7 @@ void BufferMenu::onBroadcastThreshold() {} void BufferMenu::onDiagSamplingChange() {} -void BufferMenu::onRunBtnsPressed(bool en) -{ - dynamic_cast(m_samplingFreq->getUiStrategy())->ui()->setEnabled(!en); -} +void BufferMenu::onRunBtnsPressed(bool en) { m_samplingFreq->setUIEnabled(!en); } void BufferMenu::setOffsetScalePair(const std::pair &newOffsetScalePair) { @@ -101,14 +95,7 @@ CurrentInLoopMenu::CurrentInLoopMenu(QWidget *parent, QString chnlFunction, Conn .optionsValues("[0 1 8191]") .parent(this) .buildSingle(); - QLayoutItem *item = dacCode->getUiStrategy()->ui()->layout()->itemAt(0); - TitleSpinBox *dacSpin = nullptr; - if(item) { - dacSpin = dynamic_cast(item->widget()); - } - if(dacSpin) { - dacSpin->setTitle("DAC_CODE"); - } + dacCode->changeTitle("DAC_CODE"); addMenuWidget(dacCode); QWidget *cnvtWidget = new QWidget(this); @@ -121,10 +108,8 @@ CurrentInLoopMenu::CurrentInLoopMenu(QWidget *parent, QString chnlFunction, Conn cnvtLayout->addWidget(m_cnvtLabel); addMenuWidget(cnvtWidget); - connect(dynamic_cast(dacCode->getUiStrategy()), &RangeAttrUi::emitData, this, - &CurrentInLoopMenu::updateCnvtLabel); - connect(dynamic_cast(dacCode->getDataStrategy()), - &CmdQChannelAttrDataStrategy::sendData, this, &CurrentInLoopMenu::updateCnvtLabel); + connect(dacCode, &IIOWidget::emitData, this, &CurrentInLoopMenu::updateCnvtLabel); + connect(dacCode, &IIOWidget::sendData, this, &CurrentInLoopMenu::updateCnvtLabel); } CurrentInLoopMenu::~CurrentInLoopMenu() {} @@ -158,11 +143,8 @@ DigitalInLoopMenu::DigitalInLoopMenu(QWidget *parent, QString chnlFunction, Conn .buildSingle(); addMenuWidget(m_threshold); - CmdQChannelAttrDataStrategy *dataStrategy = - dynamic_cast(m_threshold->getDataStrategy()); - connect(dynamic_cast(m_threshold->getUiStrategy()), &EditableGuiStrategy::emitData, this, - &BufferMenu::thresholdChangeStart); - connect(dataStrategy, &CmdQChannelAttrDataStrategy::emitStatus, this, &DigitalInLoopMenu::onEmitStatus); + connect(m_threshold, &IIOWidget::emitData, this, &BufferMenu::thresholdChangeStart); + connect(m_threshold, &IIOWidget::emitStatus, this, &DigitalInLoopMenu::onEmitStatus); // dac code - output channel IIOWidget *dacCode = IIOWidgetBuilder() .connection(const_cast(m_connection)) @@ -171,14 +153,7 @@ DigitalInLoopMenu::DigitalInLoopMenu(QWidget *parent, QString chnlFunction, Conn .optionsValues("[0 1 8191]") .parent(this) .buildSingle(); - QLayoutItem *item = dacCode->getUiStrategy()->ui()->layout()->itemAt(0); - TitleSpinBox *dacSpin = nullptr; - if(item) { - dacSpin = dynamic_cast(item->widget()); - } - if(dacSpin) { - dacSpin->setTitle("DAC_CODE"); - } + dacCode->changeTitle("DAC_CODE"); addMenuWidget(dacCode); QWidget *cnvtWidget = new QWidget(this); @@ -191,10 +166,8 @@ DigitalInLoopMenu::DigitalInLoopMenu(QWidget *parent, QString chnlFunction, Conn cnvtLayout->addWidget(m_cnvtLabel); addMenuWidget(cnvtWidget); - connect(dynamic_cast(dacCode->getUiStrategy()), &RangeAttrUi::emitData, this, - &DigitalInLoopMenu::updateCnvtLabel); - connect(dynamic_cast(dacCode->getDataStrategy()), - &CmdQChannelAttrDataStrategy::sendData, this, &DigitalInLoopMenu::updateCnvtLabel); + connect(dacCode, &IIOWidget::emitData, this, &DigitalInLoopMenu::updateCnvtLabel); + connect(dacCode, &IIOWidget::sendData, this, &DigitalInLoopMenu::updateCnvtLabel); } DigitalInLoopMenu::~DigitalInLoopMenu() {} @@ -214,17 +187,12 @@ void DigitalInLoopMenu::updateCnvtLabel(QString data) m_cnvtLabel->setText(QString::number(convertedData) + " mA"); } -void DigitalInLoopMenu::onBroadcastThreshold() -{ - CmdQChannelAttrDataStrategy *dataStrategy = - dynamic_cast(m_threshold->getDataStrategy()); - dataStrategy->readAsync(); -} +void DigitalInLoopMenu::onBroadcastThreshold() { m_threshold->readAsync(); } void DigitalInLoopMenu::onRunBtnsPressed(bool en) { BufferMenu::onRunBtnsPressed(en); - m_threshold->getUiStrategy()->ui()->setEnabled(!en); + m_threshold->setUIEnabled(!en); } void DigitalInLoopMenu::onEmitStatus(QDateTime timestamp, QString oldData, QString newData, int retCode, bool readOp) @@ -251,14 +219,7 @@ VoltageOutMenu::VoltageOutMenu(QWidget *parent, QString chnlFunction, Connection .optionsValues("[0 1 8191]") .parent(this) .buildSingle(); - QLayoutItem *item = dacCode->getUiStrategy()->ui()->layout()->itemAt(0); - TitleSpinBox *dacSpin = nullptr; - if(item) { - dacSpin = dynamic_cast(item->widget()); - } - if(dacSpin) { - dacSpin->setTitle("DAC_CODE"); - } + dacCode->changeTitle("DAC_CODE"); addMenuWidget(dacCode); QWidget *cnvtWidget = new QWidget(this); @@ -271,10 +232,8 @@ VoltageOutMenu::VoltageOutMenu(QWidget *parent, QString chnlFunction, Connection cnvtLayout->addWidget(m_cnvtLabel); addMenuWidget(cnvtWidget); - connect(dynamic_cast(dacCode->getUiStrategy()), &RangeAttrUi::emitData, this, - &VoltageOutMenu::updateCnvtLabel); - connect(dynamic_cast(dacCode->getDataStrategy()), - &CmdQChannelAttrDataStrategy::sendData, this, &VoltageOutMenu::updateCnvtLabel); + connect(dacCode, &IIOWidget::emitData, this, &VoltageOutMenu::updateCnvtLabel); + connect(dacCode, &IIOWidget::sendData, this, &VoltageOutMenu::updateCnvtLabel); // slew - output channel IIOWidget *slewOptions = IIOWidgetBuilder() @@ -338,14 +297,7 @@ CurrentOutMenu::CurrentOutMenu(QWidget *parent, QString chnlFunction, Connection .optionsValues("[0 1 8191]") .parent(this) .buildSingle(); - QLayoutItem *item = dacCode->getUiStrategy()->ui()->layout()->itemAt(0); - TitleSpinBox *dacSpin = nullptr; - if(item) { - dacSpin = dynamic_cast(item->widget()); - } - if(dacSpin) { - dacSpin->setTitle("DAC_CODE"); - } + dacCode->changeTitle("DAC_CODE"); addMenuWidget(dacCode); QWidget *cnvtWidget = new QWidget(this); @@ -358,10 +310,8 @@ CurrentOutMenu::CurrentOutMenu(QWidget *parent, QString chnlFunction, Connection cnvtLayout->addWidget(m_cnvtLabel); addMenuWidget(cnvtWidget); - connect(dynamic_cast(dacCode->getUiStrategy()), &RangeAttrUi::emitData, this, - &CurrentOutMenu::updateCnvtLabel); - connect(dynamic_cast(dacCode->getDataStrategy()), - &CmdQChannelAttrDataStrategy::sendData, this, &CurrentOutMenu::updateCnvtLabel); + connect(dacCode, &IIOWidget::emitData, this, &CurrentOutMenu::updateCnvtLabel); + connect(dacCode, &IIOWidget::sendData, this, &CurrentOutMenu::updateCnvtLabel); // slew - output channel IIOWidget *slewOptions = IIOWidgetBuilder() @@ -428,15 +378,14 @@ DiagnosticMenu::DiagnosticMenu(QWidget *parent, QString chnlFunction, Connection .buildSingle(); addMenuWidget(diagOptions); - connect(dynamic_cast(diagOptions->getUiStrategy()), &ComboAttrUi::displayedNewData, this, + connect(diagOptions, &IIOWidget::displayedNewData, this, [=, this](QString data, QString dataOptions) { Q_EMIT diagnosticFunctionUpdated(); }); - connect(dynamic_cast(m_samplingFreq->getDataStrategy()), - &CmdQChannelAttrDataStrategy::emitStatus, this, &DiagnosticMenu::onSamplingFreqWrite); + connect(m_samplingFreq, &IIOWidget::emitStatus, this, &DiagnosticMenu::onSamplingFreqWrite); } DiagnosticMenu::~DiagnosticMenu() {} -void DiagnosticMenu::onDiagSamplingChange() { m_samplingFreq->getDataStrategy()->readAsync(); } +void DiagnosticMenu::onDiagSamplingChange() { m_samplingFreq->readAsync(); } void DiagnosticMenu::onSamplingFreqWrite(QDateTime timestamp, QString oldData, QString newData, int retCode, bool readOp) @@ -471,26 +420,18 @@ DigitalInMenu::DigitalInMenu(QWidget *parent, QString chnlFunction, Connection * .parent(this) .buildSingle(); addMenuWidget(m_threshold); - CmdQChannelAttrDataStrategy *dataStrategy = - dynamic_cast(m_threshold->getDataStrategy()); - connect(dynamic_cast(m_threshold->getUiStrategy()), &EditableGuiStrategy::emitData, this, - &BufferMenu::thresholdChangeStart); - connect(dataStrategy, &CmdQChannelAttrDataStrategy::emitStatus, this, &DigitalInMenu::onEmitStatus); + connect(m_threshold, &IIOWidget::emitData, this, &BufferMenu::thresholdChangeStart); + connect(m_threshold, &IIOWidget::emitStatus, this, &DigitalInMenu::onEmitStatus); } DigitalInMenu::~DigitalInMenu() {} -void DigitalInMenu::onBroadcastThreshold() -{ - CmdQChannelAttrDataStrategy *dataStrategy = - dynamic_cast(m_threshold->getDataStrategy()); - dataStrategy->readAsync(); -} +void DigitalInMenu::onBroadcastThreshold() { m_threshold->readAsync(); } void DigitalInMenu::onRunBtnsPressed(bool en) { BufferMenu::onRunBtnsPressed(en); - m_threshold->getUiStrategy()->ui()->setEnabled(!en); + m_threshold->setUIEnabled(!en); } void DigitalInMenu::onEmitStatus(QDateTime timestamp, QString oldData, QString newData, int retCode, bool readOp) diff --git a/tmp/grutil/src/grdeviceaddon.cpp b/tmp/grutil/src/grdeviceaddon.cpp index 45bc945e39..3b4af9383b 100644 --- a/tmp/grutil/src/grdeviceaddon.cpp +++ b/tmp/grutil/src/grdeviceaddon.cpp @@ -27,7 +27,7 @@ QWidget *GRDeviceAddon::createAttrMenu(QWidget *parent) MenuSectionWidget *attrContainer = new MenuSectionWidget(parent); MenuCollapseSection *attr = new MenuCollapseSection("ATTRIBUTES", MenuCollapseSection::MHCW_NONE, attrContainer); - QList attrWidgets = IIOWidgetBuilder().device(m_src->iioDev()).buildAll(); + QList attrWidgets = IIOWidgetBuilder().device(m_src->iioDev()).parent(parent).buildAll(); const struct iio_context *ctx = iio_device_get_context(m_src->iioDev()); attrWidgets.append(IIOWidgetBuilder() .context(const_cast(ctx)) @@ -35,6 +35,7 @@ QWidget *GRDeviceAddon::createAttrMenu(QWidget *parent) .attribute("Triggers") .uiStrategy(IIOWidgetBuilder::UIS::ComboUi) .dataStrategy(IIOWidgetBuilder::DS::TriggerData) + .parent(parent) .buildSingle()); auto layout = new QVBoxLayout(); diff --git a/tmp/grutil/src/grtimechanneladdon.cpp b/tmp/grutil/src/grtimechanneladdon.cpp index d35608db18..20ae393313 100644 --- a/tmp/grutil/src/grtimechanneladdon.cpp +++ b/tmp/grutil/src/grtimechanneladdon.cpp @@ -193,7 +193,7 @@ QWidget *GRTimeChannelAddon::createAttrMenu(QWidget *parent) MenuSectionWidget *attrcontainer = new MenuSectionWidget(parent); MenuCollapseSection *attr = new MenuCollapseSection("ATTRIBUTES", MenuCollapseSection::MHCW_NONE, attrcontainer); - QList attrWidgets = IIOWidgetBuilder().channel(grch()->channel()).buildAll(); + QList attrWidgets = IIOWidgetBuilder().channel(grch()->channel()).parent(parent).buildAll(); auto layout = new QVBoxLayout(); layout->setSpacing(10);