1 // Copyright (C) 2019-2022 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include <PartSet_BSplineWidget.h>
22 #include <SketchPlugin_BSpline.h>
24 #include <ModuleBase_Tools.h>
26 #include <ModelAPI_AttributeDoubleArray.h>
28 #include <GeomDataAPI_Point2DArray.h>
30 #include <GeomAPI_Pnt2d.h>
32 #include <QFormLayout>
35 #include <QVBoxLayout>
36 #include <QScrollArea>
37 #include <QToolButton>
40 static const double THE_MIN_WEIGHT = 1.e-7;
42 PartSet_BSplineWidget::PartSet_BSplineWidget(
44 const Config_WidgetAPI* theData)
45 : ModuleBase_ModelWidget(theParent, theData)
47 QVBoxLayout* aMainLayout = new QVBoxLayout(this);
48 aMainLayout->setContentsMargins(0, 0, 0, 0);
50 // GroupBox to keep widgets for B-spline poles and weights
51 myPolesGroupBox = new QGroupBox(translate("Poles and weights"), this);
52 aMainLayout->addWidget(myPolesGroupBox);
54 QVBoxLayout* aLayout = new QVBoxLayout(myPolesGroupBox);
55 ModuleBase_Tools::adjustMargins(aLayout);
57 myScrollArea = new QScrollArea(myPolesGroupBox);
58 myScrollArea->setWidgetResizable(true);
59 myScrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
60 myScrollArea->setFrameStyle(QFrame::NoFrame);
61 aLayout->addWidget(myScrollArea);
63 QWidget* aContainer = new QWidget(myScrollArea);
64 QVBoxLayout* aBoxLay = new QVBoxLayout(aContainer);
65 aBoxLay->setContentsMargins(0, 0, 0, 0);
68 myPolesWgt = new QWidget(aContainer);
69 QGridLayout* aGroupLayout = new QGridLayout(myPolesWgt);
70 aGroupLayout->setColumnStretch(1, 1);
71 ModuleBase_Tools::adjustMargins(aGroupLayout);
74 aBoxLay->addWidget(myPolesWgt);
75 aBoxLay->addStretch(1);
76 myScrollArea->setWidget(aContainer);
79 void PartSet_BSplineWidget::setFeature(const FeaturePtr& theFeature,
80 const bool theToStoreValue,
81 const bool isUpdateFlushed)
83 ModuleBase_ModelWidget::setFeature(theFeature, theToStoreValue, isUpdateFlushed);
87 void PartSet_BSplineWidget::deactivate()
89 ModuleBase_ModelWidget::deactivate();
94 QList<QWidget*> PartSet_BSplineWidget::getControls() const
96 QList<QWidget*> aControls;
97 aControls.append(myScrollArea);
101 void PartSet_BSplineWidget::storePolesAndWeights() const
103 std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
104 AttributeDoubleArrayPtr aWeightsArray = aData->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
106 std::list<BSplinePoleWidgets>::const_iterator anIt = myPoles.begin();
107 for (int anIndex = 0; anIt != myPoles.end(); ++anIndex, ++anIt) {
108 double aWeight = anIt->myWeight->value();
109 if (aWeight < THE_MIN_WEIGHT)
110 aWeight = THE_MIN_WEIGHT;
111 aWeightsArray->setValue(anIndex, aWeight);
115 bool PartSet_BSplineWidget::storeValueCustom()
117 std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
118 if (!aData || !aData->isValid()) // can be on abort of sketcher element
121 AttributeDoubleArrayPtr aWeights = aData->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
123 bool isBlocked = blockSignals(true);
124 storePolesAndWeights();
125 ModuleBase_Tools::flushUpdated(myFeature);
126 blockSignals(isBlocked);
128 updateObject(myFeature);
132 bool PartSet_BSplineWidget::restoreValueCustom()
137 DataPtr aData = myFeature->data();
139 AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
140 aData->attribute(SketchPlugin_BSpline::POLES_ID()));
141 AttributeDoubleArrayPtr aWeights = aData->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
143 while ((int)myPoles.size() < aPoles->size())
146 std::list<BSplinePoleWidgets>::iterator anIt = myPoles.begin();
147 for (int anIndex = 0; anIt != myPoles.end(); ++anIt, ++anIndex) {
148 GeomPnt2dPtr aPoint = aPoles->pnt(anIndex);
149 anIt->myX->setValue(aPoint->x());
150 anIt->myY->setValue(aPoint->y());
151 bool isBlocked = anIt->myWeight->blockSignals(true);
152 anIt->myWeight->setValue(aWeights->value(anIndex));
153 anIt->myWeight->blockSignals(isBlocked);
159 void PartSet_BSplineWidget::addPoleWidget()
161 QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myPolesWgt->layout());
162 int aNbPoles = (int)myPoles.size();
163 QString aPoleStr = translate("Pole %1").arg(aNbPoles + 1);
165 myPoles.push_back(BSplinePoleWidgets());
166 BSplinePoleWidgets& aPole = myPoles.back();
167 aGroupLay->addWidget(createPoleWidget(aPole, aPoleStr, myPolesWgt), aNbPoles, 1);
170 QGroupBox* PartSet_BSplineWidget::createPoleWidget(BSplinePoleWidgets& thePole,
171 const QString& theName, QWidget* theParent)
173 QGroupBox* aPoleGroupBox = new QGroupBox(theName, theParent);
174 QGridLayout* aPoleLay = new QGridLayout(aPoleGroupBox);
175 aPoleLay->setSpacing(0);
176 ModuleBase_Tools::zeroMargins(aPoleLay);
178 thePole.myX = new ModuleBase_LabelValue(aPoleGroupBox, tr("X"));
179 aPoleLay->addWidget(thePole.myX, 0, 0, 1, 3);
180 thePole.myY = new ModuleBase_LabelValue(aPoleGroupBox, tr("Y"));
181 aPoleLay->addWidget(thePole.myY, 1, 0, 1, 3);
182 thePole.myWeight = new ModuleBase_ParamSpinBox(aPoleGroupBox);
183 thePole.myWeight->setMinimum(THE_MIN_WEIGHT);
185 aPoleLay->addWidget(new QLabel(translate("Weight :"), aPoleGroupBox), 2, 0);
186 aPoleLay->addWidget(thePole.myWeight, 2, 1);
187 // we should listen textChanged signal as valueChanged do not send when text is modified
188 connect(thePole.myWeight, SIGNAL(textChanged(const QString&)),
189 this, SIGNAL(valuesChanged()));
191 thePole.myAddBtn = new QToolButton(aPoleGroupBox);
192 thePole.myAddBtn->setIcon(QIcon(":pictures/add.png"));
193 thePole.myAddBtn->setToolTip(translate("Add a new pole after the current"));
194 aPoleLay->addWidget(thePole.myAddBtn, 2, 2);
195 connect(thePole.myAddBtn, SIGNAL(clicked(bool)), SLOT(onAddPole()));
197 return aPoleGroupBox;
201 void PartSet_BSplineWidget::onAddPole()
203 QObject* aObj = sender();
204 std::list<BSplinePoleWidgets>::const_iterator aIt;
207 for (aIt = myPoles.cbegin(); aIt != myPoles.cend(); aIt++, aId++) {
208 if ((*aIt).myAddBtn == aObj) {
214 // add a new pole after found Id
215 std::ostringstream anActionName;
216 anActionName << SketchPlugin_BSplineBase::ADD_POLE_ACTION_ID() << "#" << aId;
217 if (feature()->customAction(anActionName.str()))
218 updateObject(feature());
220 restoreValueCustom();