From 9d721c9bc683b002222660b5243786facaf94671 Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Mon, 18 Aug 2025 17:34:15 +0200 Subject: [PATCH 1/2] Refactor RadioDataWidget as it is a bad design 1) RadioDataWidget is now renamed as OptionGroupWidget. 2) Both OptionGroupWidget and SelectableItemWidget are now in their own .h/.cpp files 3) The switch of behavior depending on the number of alternative is removed Because there is no reason justifying that a widget for a data field would totally change its rendering/behavior depending on the number of alternatives. If the Radio choices behavior is needed (which I doubt) it is easy to re-implement it on a per-component-data basis using BaseData::setWidget/getWidget. Signed-off-by: Damien Marchal --- CMakeLists.txt | 6 +- src/sofa/qt/SimpleDataWidget.cpp | 210 ------------------ src/sofa/qt/SimpleDataWidget.h | 57 ----- .../qt/datawidgets/OptionsGroupWidget.cpp | 68 ++++++ src/sofa/qt/datawidgets/OptionsGroupWidget.h | 53 +++++ .../qt/datawidgets/SelectableItemWidget.cpp | 83 +++++++ .../qt/datawidgets/SelectableItemWidget.h | 50 +++++ 7 files changed, 259 insertions(+), 268 deletions(-) create mode 100644 src/sofa/qt/datawidgets/OptionsGroupWidget.cpp create mode 100644 src/sofa/qt/datawidgets/OptionsGroupWidget.h create mode 100644 src/sofa/qt/datawidgets/SelectableItemWidget.cpp create mode 100644 src/sofa/qt/datawidgets/SelectableItemWidget.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ddef33..b38cbd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,7 +162,9 @@ set(MOC_HEADER_FILES ${SRC_ROOT}/SofaVideoRecorderManager.h ${SRC_ROOT}/SofaPluginManager.h ${SRC_ROOT}/SofaSceneGraphWidget.h - ${SRC_ROOT}/WDoubleLineEdit.h + ${SRC_ROOT}/WDoubleLineEdit.h + ${SRC_ROOT}/datawidgets/OptionsGroupWidget.h + ${SRC_ROOT}/datawidgets/SelectableItemWidget.h ) set(HEADER_FILES ${SRC_ROOT}/config.h.in @@ -222,6 +224,8 @@ set(SOURCE_FILES ${SRC_ROOT}/SofaSceneGraphWidget.cpp ${SRC_ROOT}/viewer/VisualModelPolicy.cpp ${SRC_ROOT}/QtDataRepository.cpp + ${SRC_ROOT}/datawidgets/OptionsGroupWidget.cpp + ${SRC_ROOT}/datawidgets/SelectableItemWidget.cpp ) set(UI_FILES ${SRC_ROOT}/AboutDialog.ui diff --git a/src/sofa/qt/SimpleDataWidget.cpp b/src/sofa/qt/SimpleDataWidget.cpp index 49fd61c..04ef352 100644 --- a/src/sofa/qt/SimpleDataWidget.cpp +++ b/src/sofa/qt/SimpleDataWidget.cpp @@ -139,214 +139,4 @@ Creator> > > DWClass_CRSCVec3d("default",true); Creator> > > DWClass_CRSCVec6d("default",true); -//////////////////////////////////////////////////////////////// -/// OptionsGroup support -//////////////////////////////////////////////////////////////// - -//these functions must be written here for effect of writeToData -Creator DWClass_OptionsGroup("default",true); - -bool RadioDataWidget::createWidgets() -{ - QVBoxLayout* layout = new QVBoxLayout(this); - const sofa::helper::OptionsGroup m_radiotrick = getData()->getValue(); - const unsigned int LIMIT_NUM_BUTTON=4; - buttonMode=m_radiotrick.size() < LIMIT_NUM_BUTTON; - if (buttonMode) - { - buttonList=new QButtonGroup(this); - - for(unsigned int i=0; isetChecked(true); - layout->addWidget(m_radiobutton); - buttonList->addButton(m_radiobutton,i); - } - connect(buttonList, SIGNAL(buttonClicked(int)), this, SLOT(setWidgetDirty())) ; - } - else - { - comboList=new QComboBox(this); - comboList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - - const sofa::helper::OptionsGroup m_radiotrick = getData()->getValue(); - QStringList list; - for(unsigned int i=0; iinsertItems(0, list); - - comboList->setCurrentIndex(m_radiotrick.getSelectedId()); - - connect(comboList, SIGNAL(activated(int)), this, SLOT(setWidgetDirty())); - layout->addWidget(comboList); - - } - - return true; -} -void RadioDataWidget::setDataReadOnly(bool readOnly) -{ - if (buttonMode) - { - const QList buttons = buttonList->buttons(); - for (int i = 0; i < buttons.size(); ++i) - { - buttons.at(i)->setEnabled(!readOnly); - } - } - else - { - comboList->setEnabled(!readOnly); - } -} - -void RadioDataWidget::readFromData() -{ - const sofa::helper::OptionsGroup m_radiotrick = getData()->getValue(); - - if (buttonMode) - { - buttonList->button(m_radiotrick.getSelectedId())->setChecked(true); - } - else - { - comboList->setCurrentIndex(m_radiotrick.getSelectedId()); - } -} -void RadioDataWidget::writeToData() -{ - sofa::helper::OptionsGroup m_radiotrick = getData()->getValue(); - if (buttonMode) - { - m_radiotrick.setSelectedItem((unsigned int)buttonList->checkedId ()); - } - else - { - m_radiotrick.setSelectedItem((unsigned int)comboList->currentIndex()); - } - - this->getData()->setValue(m_radiotrick); -} - -Creator DWClass_SelectableItem("default",true); - -SelectableItemWidget::SelectableItemWidget(QWidget* parent, const char* name, - core::BaseData* m_data, const helper::BaseSelectableItem* item) -: TDataWidget(parent, name, m_data, item) -, m_selectableItem(item) -{} - -bool SelectableItemWidget::createWidgets() -{ - if ((Tdata && Tdata->getValueTypeString() != "SelectableItem") || - (baseData && baseData->getValueTypeString() != "SelectableItem")) - { - return false; - } - - QVBoxLayout* layout = new QVBoxLayout(this); - static constexpr unsigned int LIMIT_NUM_BUTTON = 4; - - assert(m_selectableItem); - const std::size_t nbItems = m_selectableItem->getNumberOfItems(); - m_buttonMode = nbItems < LIMIT_NUM_BUTTON; - const auto* items = m_selectableItem->getItemsData(); - - const auto getItem = [](const sofa::helper::Item* item) - { - std::stringstream ss; - ss << item->key; - if (!item->description.empty()) - { - ss << " (" << item->description << ")"; - } - return ss.str(); - }; - - if (m_buttonMode) - { - m_buttonList = new QButtonGroup(this); - - for (std::size_t i = 0; i < nbItems; i++) - { - const helper::Item* item_i = items + i; - - QRadioButton * m_radiobutton = new QRadioButton(QString(getItem(item_i).c_str()), this); - if (i == m_selectableItem->getSelectedId()) - { - m_radiobutton->setChecked(true); - } - layout->addWidget(m_radiobutton); - m_buttonList->addButton(m_radiobutton, i); - } - connect(m_buttonList, SIGNAL(buttonClicked(int)), this, SLOT(setWidgetDirty())) ; - } - else - { - m_comboList=new QComboBox(this); - m_comboList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - - QStringList list; - for (std::size_t i = 0; i < nbItems; i++) - { - const helper::Item* item_i = items + i; - list << getItem(item_i).c_str(); - } - - m_comboList->insertItems(0, list); - - m_comboList->setCurrentIndex(m_selectableItem->getSelectedId()); - - connect(m_comboList, SIGNAL(activated(int)), this, SLOT(setWidgetDirty())); - layout->addWidget(m_comboList); - - } - - return true; -} - -void SelectableItemWidget::setDataReadOnly(const bool readOnly) -{ - if (m_buttonMode) - { - const QList buttons = m_buttonList->buttons(); - for (auto& button : buttons) - { - button->setEnabled(!readOnly); - } - } - else - { - m_comboList->setEnabled(!readOnly); - } -} - -void SelectableItemWidget::readFromData() -{ - if (m_buttonMode) - { - m_buttonList->button(m_selectableItem->getSelectedId())->setChecked(true); - } - else - { - m_comboList->setCurrentIndex(m_selectableItem->getSelectedId()); - } -} - -void SelectableItemWidget::writeToData() -{ - if (m_buttonMode) - { - const_cast(m_selectableItem)->setSelectedId(static_cast(m_buttonList->checkedId())); - } - else - { - const_cast(m_selectableItem)->setSelectedId(static_cast(m_comboList->currentIndex())); - } -} - - } //namespace sofa::qt diff --git a/src/sofa/qt/SimpleDataWidget.h b/src/sofa/qt/SimpleDataWidget.h index 492adfa..a0a8450 100644 --- a/src/sofa/qt/SimpleDataWidget.h +++ b/src/sofa/qt/SimpleDataWidget.h @@ -24,7 +24,6 @@ #include "ModifyObject.h" #include #include -//#include #include #include #include @@ -971,60 +970,4 @@ class data_widget_trait -{ - Q_OBJECT -public : - - ///The class constructor takes a TData since it creates - ///a widget for a that particular data type. - RadioDataWidget(QWidget* parent, const char* name, - core::objectmodel::Data* m_data) - : TDataWidget(parent,name,m_data) {} - - ///In this method we create the widgets and perform the signal / slots connections. - virtual bool createWidgets(); - virtual void setDataReadOnly(bool readOnly); - -protected: - ///Implements how update the widgets knowing the data value. - virtual void readFromData(); - - ///Implements how to update the data, knowing the widget value. - virtual void writeToData(); - - QButtonGroup *buttonList; - QComboBox *comboList; - bool buttonMode; -}; - -class SelectableItemWidget final : public TDataWidget -{ - Q_OBJECT -public : - - SelectableItemWidget(QWidget* parent, const char* name, - core::BaseData* m_data, const helper::BaseSelectableItem* item); - - bool createWidgets() override; - void setDataReadOnly(bool readOnly) override; - -protected: - void readFromData() override; - - void writeToData() override; - - QButtonGroup *m_buttonList { nullptr }; - QComboBox *m_comboList { nullptr }; - bool m_buttonMode { false }; - - const helper::BaseSelectableItem* m_selectableItem { nullptr }; -}; - - } //namespace sofa::qt diff --git a/src/sofa/qt/datawidgets/OptionsGroupWidget.cpp b/src/sofa/qt/datawidgets/OptionsGroupWidget.cpp new file mode 100644 index 0000000..63c8b05 --- /dev/null +++ b/src/sofa/qt/datawidgets/OptionsGroupWidget.cpp @@ -0,0 +1,68 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU General Public License as published by the Free * +* Software Foundation; either version 2 of the License, or (at your option) * +* any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * +* more details. * +* * +* You should have received a copy of the GNU General Public License along * +* with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ + +#include +#include + +namespace sofa::qt +{ +//these functions must be written here for effect of writeToData +Creator DWClass_OptionsGroup("default",true); + +bool OptionsGroupWidget::createWidgets() +{ + QVBoxLayout* layout = new QVBoxLayout(this); + + comboList=new QComboBox(this); + comboList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + + auto optiongroup = getData()->getValue(); + QStringList list; + for(unsigned int i=0; iinsertItems(0, list); + comboList->setCurrentIndex(optiongroup.getSelectedId()); + + connect(comboList, SIGNAL(activated(int)), this, SLOT(setWidgetDirty())); + layout->addWidget(comboList); + + return true; +} +void OptionsGroupWidget::setDataReadOnly(bool readOnly) +{ + comboList->setEnabled(!readOnly); +} + +void OptionsGroupWidget::readFromData() +{ + auto optiongroup = getData()->getValue(); + comboList->setCurrentIndex(optiongroup.getSelectedId()); +} + +void OptionsGroupWidget::writeToData() +{ + auto optiongroup = getData()->getValue(); + optiongroup.setSelectedItem(static_cast(comboList->currentIndex())); + getData()->setValue(optiongroup); +} + +} //namespace sofa::qt diff --git a/src/sofa/qt/datawidgets/OptionsGroupWidget.h b/src/sofa/qt/datawidgets/OptionsGroupWidget.h new file mode 100644 index 0000000..76f459c --- /dev/null +++ b/src/sofa/qt/datawidgets/OptionsGroupWidget.h @@ -0,0 +1,53 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU General Public License as published by the Free * +* Software Foundation; either version 2 of the License, or (at your option) * +* any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * +* more details. * +* * +* You should have received a copy of the GNU General Public License along * +* with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once + +#include +#include + +namespace sofa::qt +{ + +class OptionsGroupWidget : public TDataWidget +{ + Q_OBJECT +public : + + OptionsGroupWidget(QWidget* parent, const char* name, + core::objectmodel::Data* m_data) + : TDataWidget(parent,name,m_data) {} + + ///In this method we create the widgets and perform the signal / slots connections. + virtual bool createWidgets(); + virtual void setDataReadOnly(bool readOnly); + +protected: + ///Implements how update the widgets knowing the data value. + virtual void readFromData(); + + ///Implements how to update the data, knowing the widget value. + virtual void writeToData(); + + QComboBox *comboList; +}; + +} //namespace sofa::qt diff --git a/src/sofa/qt/datawidgets/SelectableItemWidget.cpp b/src/sofa/qt/datawidgets/SelectableItemWidget.cpp new file mode 100644 index 0000000..76be459 --- /dev/null +++ b/src/sofa/qt/datawidgets/SelectableItemWidget.cpp @@ -0,0 +1,83 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU General Public License as published by the Free * +* Software Foundation; either version 2 of the License, or (at your option) * +* any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * +* more details. * +* * +* You should have received a copy of the GNU General Public License along * +* with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ + +#include +#include + +namespace sofa::qt +{ + +Creator DWClass_SelectableItem("default",true); + +SelectableItemWidget::SelectableItemWidget(QWidget* parent, const char* name, + core::BaseData* m_data, const helper::BaseSelectableItem* item) +: TDataWidget(parent, name, m_data, item) +, m_selectableItem(item) +{} + +bool SelectableItemWidget::createWidgets() +{ + if ((Tdata && Tdata->getValueTypeString() != "SelectableItem") || + (baseData && baseData->getValueTypeString() != "SelectableItem")) + { + return false; + } + + QVBoxLayout* layout = new QVBoxLayout(this); + + assert(m_selectableItem); + const std::size_t nbItems = m_selectableItem->getNumberOfItems(); + const auto* items = m_selectableItem->getItemsData(); + + m_comboList=new QComboBox(this); + m_comboList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + + for (std::size_t i = 0; i < nbItems; i++) + { + m_comboList->addItem(QString::fromUtf8(items[i].key)); + m_comboList->setItemData(i, QString::fromUtf8(items[i].description), Qt::ToolTipRole); + } + m_comboList->setCurrentIndex(m_selectableItem->getSelectedId()); + + connect(m_comboList, SIGNAL(activated(int)), this, SLOT(setWidgetDirty())); + layout->addWidget(m_comboList); + + return true; +} + +void SelectableItemWidget::setDataReadOnly(const bool readOnly) +{ + m_comboList->setEnabled(!readOnly); +} + +void SelectableItemWidget::readFromData() +{ + m_comboList->setCurrentIndex(m_selectableItem->getSelectedId()); +} + +void SelectableItemWidget::writeToData() +{ + const_cast(m_selectableItem)->setSelectedId(static_cast(m_comboList->currentIndex())); +} + + +} //namespace sofa::qt diff --git a/src/sofa/qt/datawidgets/SelectableItemWidget.h b/src/sofa/qt/datawidgets/SelectableItemWidget.h new file mode 100644 index 0000000..208084c --- /dev/null +++ b/src/sofa/qt/datawidgets/SelectableItemWidget.h @@ -0,0 +1,50 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU General Public License as published by the Free * +* Software Foundation; either version 2 of the License, or (at your option) * +* any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * +* more details. * +* * +* You should have received a copy of the GNU General Public License along * +* with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once + +#include +#include + +namespace sofa::qt +{ + +class SelectableItemWidget final : public TDataWidget +{ + Q_OBJECT + +public : + SelectableItemWidget(QWidget* parent, const char* name, + core::BaseData* m_data, const helper::BaseSelectableItem* item); + + bool createWidgets() override; + void setDataReadOnly(bool readOnly) override; + +protected: + void readFromData() override; + void writeToData() override; + + QComboBox *m_comboList { nullptr }; + const helper::BaseSelectableItem* m_selectableItem { nullptr }; +}; + + +} //namespace sofa::qt From 9810b92c08280d8f74ece900ecc399cd27802103 Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Thu, 25 Sep 2025 12:33:45 +0200 Subject: [PATCH 2/2] FIX compilation issue related to Qt5 support. --- src/sofa/qt/datawidgets/SelectableItemWidget.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sofa/qt/datawidgets/SelectableItemWidget.cpp b/src/sofa/qt/datawidgets/SelectableItemWidget.cpp index 76be459..497f824 100644 --- a/src/sofa/qt/datawidgets/SelectableItemWidget.cpp +++ b/src/sofa/qt/datawidgets/SelectableItemWidget.cpp @@ -53,8 +53,10 @@ bool SelectableItemWidget::createWidgets() for (std::size_t i = 0; i < nbItems; i++) { - m_comboList->addItem(QString::fromUtf8(items[i].key)); - m_comboList->setItemData(i, QString::fromUtf8(items[i].description), Qt::ToolTipRole); + auto key = items[i].key; + auto desc = items[i].description; + m_comboList->addItem(QString::fromUtf8(key.data(), key.size())); + m_comboList->setItemData(i, QString::fromUtf8(desc.data(), desc.size()), Qt::ToolTipRole); } m_comboList->setCurrentIndex(m_selectableItem->getSelectedId());