Salome HOME
Meet coding style (split too long line)
[modules/shaper.git] / src / PartSet / PartSet_BSplineWidget.cpp
1 // Copyright (C) 2019-2020  CEA/DEN, EDF R&D
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include <PartSet_BSplineWidget.h>
21
22 #include <SketchPlugin_BSpline.h>
23
24 #include <ModuleBase_Tools.h>
25
26 #include <ModelAPI_AttributeDoubleArray.h>
27
28 #include <GeomDataAPI_Point2DArray.h>
29
30 #include <GeomAPI_Pnt2d.h>
31
32 #include <QFormLayout>
33 #include <QGroupBox>
34 #include <QLabel>
35 #include <QVBoxLayout>
36 #include <QScrollArea>
37 #include <QToolButton>
38
39
40 PartSet_BSplineWidget::PartSet_BSplineWidget(
41     QWidget* theParent,
42     const Config_WidgetAPI* theData)
43   : ModuleBase_ModelWidget(theParent, theData)
44 {
45   QVBoxLayout* aMainLayout = new QVBoxLayout(this);
46   aMainLayout->setContentsMargins(0, 0, 0, 0);
47
48   // GroupBox to keep widgets for B-spline poles and weights
49   myPolesGroupBox = new QGroupBox(tr("Poles and weights"), this);
50   aMainLayout->addWidget(myPolesGroupBox);
51
52   QVBoxLayout* aLayout = new QVBoxLayout(myPolesGroupBox);
53   ModuleBase_Tools::adjustMargins(aLayout);
54
55   myScrollArea = new QScrollArea(myPolesGroupBox);
56   myScrollArea->setWidgetResizable(true);
57   myScrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
58   myScrollArea->setFrameStyle(QFrame::NoFrame);
59   aLayout->addWidget(myScrollArea);
60
61   QWidget* aContainer = new QWidget(myScrollArea);
62   QVBoxLayout* aBoxLay = new QVBoxLayout(aContainer);
63   aBoxLay->setContentsMargins(0, 0, 0, 0);
64
65   // layout of GroupBox
66   myPolesWgt = new QWidget(aContainer);
67   QGridLayout* aGroupLayout = new QGridLayout(myPolesWgt);
68   aGroupLayout->setColumnStretch(1, 1);
69   ModuleBase_Tools::adjustMargins(aGroupLayout);
70
71   restoreValueCustom();
72   aBoxLay->addWidget(myPolesWgt);
73   aBoxLay->addStretch(1);
74   myScrollArea->setWidget(aContainer);
75 }
76
77 void PartSet_BSplineWidget::setFeature(const FeaturePtr& theFeature,
78                                             const bool theToStoreValue,
79                                             const bool isUpdateFlushed)
80 {
81   ModuleBase_ModelWidget::setFeature(theFeature, theToStoreValue, isUpdateFlushed);
82   restoreValueCustom();
83 }
84
85 void PartSet_BSplineWidget::deactivate()
86 {
87   ModuleBase_ModelWidget::deactivate();
88   storeValueCustom();
89 }
90
91
92 QList<QWidget*> PartSet_BSplineWidget::getControls() const
93 {
94   QList<QWidget*> aControls;
95   aControls.append(myScrollArea);
96   return aControls;
97 }
98
99 void PartSet_BSplineWidget::storePolesAndWeights() const
100 {
101   std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
102   AttributeDoubleArrayPtr aWeightsArray = aData->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
103
104   std::list<BSplinePoleWidgets>::const_iterator anIt = myPoles.begin();
105   for (int anIndex = 0; anIt != myPoles.end(); ++anIndex, ++anIt) {
106     aWeightsArray->setValue(anIndex, anIt->myWeight->value());
107   }
108 }
109
110 bool PartSet_BSplineWidget::storeValueCustom()
111 {
112   std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
113   if (!aData || !aData->isValid()) // can be on abort of sketcher element
114     return false;
115
116   AttributeDoubleArrayPtr aWeights = aData->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
117
118   bool isBlocked = blockSignals(true);
119   storePolesAndWeights();
120   ModuleBase_Tools::flushUpdated(myFeature);
121   blockSignals(isBlocked);
122
123   updateObject(myFeature);
124   return true;
125 }
126
127 bool PartSet_BSplineWidget::restoreValueCustom()
128 {
129   if (!myFeature)
130     return false;
131
132   DataPtr aData = myFeature->data();
133
134   AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
135       aData->attribute(SketchPlugin_BSpline::POLES_ID()));
136   AttributeDoubleArrayPtr aWeights = aData->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
137
138   while (myPoles.size() < aPoles->size())
139     addPoleWidget();
140
141   std::list<BSplinePoleWidgets>::iterator anIt = myPoles.begin();
142   for (int anIndex = 0; anIt != myPoles.end(); ++anIt, ++anIndex) {
143     GeomPnt2dPtr aPoint = aPoles->pnt(anIndex);
144     anIt->myX->setValue(aPoint->x());
145     anIt->myY->setValue(aPoint->y());
146     bool isBlocked = anIt->myWeight->blockSignals(true);
147     anIt->myWeight->setValue(aWeights->value(anIndex));
148     anIt->myWeight->blockSignals(isBlocked);
149   }
150
151   return true;
152 }
153
154 void PartSet_BSplineWidget::addPoleWidget()
155 {
156   QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myPolesWgt->layout());
157   int aNbPoles = (int)myPoles.size();
158   QString aPoleStr = tr("Pole %1").arg(aNbPoles + 1);
159
160   myPoles.push_back(BSplinePoleWidgets());
161   BSplinePoleWidgets& aPole = myPoles.back();
162   aGroupLay->addWidget(createPoleWidget(aPole, aPoleStr, myPolesWgt), aNbPoles, 1);
163 }
164
165 QGroupBox* PartSet_BSplineWidget::createPoleWidget(BSplinePoleWidgets& thePole,
166   const QString& theName, QWidget* theParent)
167 {
168   QGroupBox* aPoleGroupBox = new QGroupBox(theName, theParent);
169   QGridLayout* aPoleLay = new QGridLayout(aPoleGroupBox);
170   aPoleLay->setSpacing(0);
171   ModuleBase_Tools::zeroMargins(aPoleLay);
172
173   thePole.myX = new ModuleBase_LabelValue(aPoleGroupBox, tr("X"));
174   aPoleLay->addWidget(thePole.myX, 0, 0, 1, 3);
175   thePole.myY = new ModuleBase_LabelValue(aPoleGroupBox, tr("Y"));
176   aPoleLay->addWidget(thePole.myY, 1, 0, 1, 3);
177   thePole.myWeight = new ModuleBase_ParamSpinBox(aPoleGroupBox);
178   thePole.myWeight->setMinimum(0.0);
179
180   aPoleLay->addWidget(new QLabel(tr("Weight :"), aPoleGroupBox), 2, 0);
181   aPoleLay->addWidget(thePole.myWeight, 2, 1);
182   // we should listen textChanged signal as valueChanged do not send when text is modified
183   connect(thePole.myWeight, SIGNAL(textChanged(const QString&)),
184     this, SIGNAL(valuesChanged()));
185
186   thePole.myAddBtn = new QToolButton(aPoleGroupBox);
187   thePole.myAddBtn->setIcon(QIcon(":pictures/add.png"));
188   thePole.myAddBtn->setToolTip(tr("Add a new pole after the current"));
189   aPoleLay->addWidget(thePole.myAddBtn, 2, 2);
190   connect(thePole.myAddBtn, SIGNAL(clicked(bool)), SLOT(onAddPole()));
191
192   return aPoleGroupBox;
193 }
194
195
196 void PartSet_BSplineWidget::onAddPole()
197 {
198   QObject* aObj = sender();
199   std::list<BSplinePoleWidgets>::const_iterator aIt;
200   int aId = 0;
201   bool aFound = false;
202   for (aIt = myPoles.cbegin(); aIt != myPoles.cend(); aIt++, aId++) {
203     if ((*aIt).myAddBtn == aObj) {
204       aFound = true;
205       break;
206     }
207   }
208   if (aFound) {
209     // add a new pole after found Id
210     std::ostringstream anActionName;
211     anActionName << SketchPlugin_BSplineBase::ADD_POLE_ACTION_ID() << "#" << aId;
212     if (feature()->customAction(anActionName.str()))
213       updateObject(feature());
214
215     restoreValueCustom();
216   }
217 }