Salome HOME
Update B-Spline GUI
[modules/shaper.git] / src / PartSet / PartSet_WidgetBSplinePoints.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_WidgetBSplinePoints.h>
21
22 #include <PartSet_CenterPrs.h>
23 #include <PartSet_ExternalObjectsMgr.h>
24 #include <PartSet_Module.h>
25 #include <PartSet_SketcherReentrantMgr.h>
26 #include <PartSet_WidgetPoint2d.h>
27
28 #include <XGUI_Tools.h>
29 #include <XGUI_Workshop.h>
30 #include <XGUI_Displayer.h>
31
32 #include <ModuleBase_ISelection.h>
33 #include <ModuleBase_IViewer.h>
34 #include <ModuleBase_IViewWindow.h>
35 #include <ModuleBase_LabelValue.h>
36 #include <ModuleBase_Tools.h>
37 #include <ModuleBase_ViewerPrs.h>
38 #include <ModuleBase_WidgetValidator.h>
39 #include <ModuleBase_WidgetValidated.h>
40
41 #include <Config_Keywords.h>
42 #include <Config_WidgetAPI.h>
43
44 #include <Events_Loop.h>
45
46 #include <ModelAPI_Events.h>
47 #include <ModelAPI_AttributeDoubleArray.h>
48 #include <ModelAPI_AttributeRefAttrList.h>
49 #include <ModelAPI_CompositeFeature.h>
50
51 #include <GeomDataAPI_Point2D.h>
52 #include <GeomDataAPI_Point2DArray.h>
53
54 #include <GeomAPI_Pnt2d.h>
55 #include <GeomAPI_IPresentable.h>
56
57 #include <SketchPlugin_Feature.h>
58
59 #include <QGridLayout>
60 #include <QGroupBox>
61 #include <QMouseEvent>
62 #include <QGraphicsEffect>
63
64 static const double MaxCoordinate = 1e12;
65
66 PartSet_WidgetBSplinePoints::PartSet_WidgetBSplinePoints(QWidget* theParent,
67                                              ModuleBase_IWorkshop* theWorkshop,
68                                              const Config_WidgetAPI* theData)
69 : ModuleBase_ModelWidget(theParent, theData), myWorkshop(theWorkshop),
70   myValueIsCashed(false), myIsFeatureVisibleInCash(true),
71   myXValueInCash(0), myYValueInCash(0),
72   myPointIndex(0), myFinished(false)
73 {
74   myRefAttribute = theData->getProperty("reference_attribute");
75
76   // the control should accept the focus, so the boolean flag is corrected to be true
77   myIsObligatory = true;
78   QString aPageName = translate(theData->getProperty(CONTAINER_PAGE_NAME));
79   myGroupBox = new QGroupBox(aPageName, theParent);
80   myGroupBox->setFlat(false);
81
82   bool aAcceptVariables = theData->getBooleanAttribute(DOUBLE_WDG_ACCEPT_EXPRESSIONS, true);
83
84   // B-spline weights attribute
85   myWeightsAttr = theData->getProperty("weights");
86
87   QGridLayout* aGroupLay = new QGridLayout(myGroupBox);
88   ModuleBase_Tools::adjustMargins(aGroupLay);
89   aGroupLay->setSpacing(4);
90   aGroupLay->setColumnStretch(1, 1);
91   createNextPoint();
92
93   QVBoxLayout* aLayout = new QVBoxLayout(this);
94   ModuleBase_Tools::zeroMargins(aLayout);
95   aLayout->addWidget(myGroupBox);
96   setLayout(aLayout);
97
98   myWidgetValidator = new ModuleBase_WidgetValidator(this, myWorkshop);
99   myExternalObjectMgr = new PartSet_ExternalObjectsMgr(theData->getProperty("use_external"),
100                                          theData->getProperty("can_create_external"), true);
101 }
102
103 void PartSet_WidgetBSplinePoints::createNextPoint()
104 {
105   storeCurentValue();
106
107   QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
108   int row = (int)myXSpin.size();
109
110   QString aPoleStr = tr("Pole %1");
111   aPoleStr = aPoleStr.arg(myXSpin.size() + 1);
112
113   QGroupBox* aPoleGroupBox = new QGroupBox(aPoleStr, myGroupBox);
114   QGridLayout* aPoleLay = new QGridLayout(aPoleGroupBox);
115   ModuleBase_Tools::adjustMargins(aPoleLay);
116   aPoleLay->setSpacing(2);
117   aPoleLay->setColumnStretch(1, 1);
118
119   myXSpin.push_back(new ModuleBase_LabelValue(aPoleGroupBox, tr("X")));
120   aPoleLay->addWidget(myXSpin.back(), 0, 1);
121   myYSpin.push_back(new ModuleBase_LabelValue(aPoleGroupBox, tr("Y")));
122   aPoleLay->addWidget(myYSpin.back(), 1, 1);
123
124   aGroupLay->addWidget(aPoleGroupBox, row, 1);
125
126   setHighlighted(true);
127 }
128
129 void PartSet_WidgetBSplinePoints::removeLastPoint()
130 {
131   QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
132   aGroupLay->removeWidget(myYSpin.back());
133   aGroupLay->removeWidget(myXSpin.back());
134   aGroupLay->removeWidget(myXSpin.back()->parentWidget());
135   myYSpin.pop_back();
136   myXSpin.pop_back();
137
138   // update B-spline feature attributes
139   storeValueCustom();
140 }
141
142 bool PartSet_WidgetBSplinePoints::isValidSelectionCustom(const ModuleBase_ViewerPrsPtr& theValue)
143 {
144   bool aValid = true;
145
146   PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
147   if (aModule->sketchReentranceMgr()->isInternalEditActive())
148     return true; // when internal edit is started a new feature is created. I has not results, AIS
149
150   // the selection is not possible if the current feature has no presentation for the current
151   // attribute not in AIS not in results. If so, no object in current feature where make
152   // coincidence, so selection is not necessary
153   GeomShapePtr anAISShape;
154   GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(myFeature);
155   if (aPrs.get()) {
156     AISObjectPtr anAIS;
157     anAIS = aPrs->getAISObject(anAIS);
158     if (anAIS.get()) {
159       anAISShape = anAIS->getShape();
160     }
161   }
162   const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = myFeature->results();
163   if (!anAISShape.get() && aResults.empty())
164     return true;
165
166   AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
167   if (aRefAttrList)
168     return isValidSelectionForAttribute_(theValue, myFeature->attribute(attributeID()));
169   return true;
170 }
171
172 bool PartSet_WidgetBSplinePoints::isValidSelectionForAttribute_(
173                                             const ModuleBase_ViewerPrsPtr& theValue,
174                                             const AttributePtr& theAttribute)
175 {
176   bool aValid = false;
177
178   // stores the current values of the widget attribute
179   bool isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked;
180
181   AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
182   ModuleBase_WidgetValidated::blockFeatureAttribute(aRefAttrList, myFeature, true,
183       isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked);
184   myWidgetValidator->storeAttributeValue(aRefAttrList);
185
186   // saves the owner value to the widget attribute
187   aValid = setSelectionCustom(theValue);
188   if (aValid)
189     // checks the attribute validity
190     aValid = myWidgetValidator->isValidAttribute(theAttribute);
191
192   // restores the current values of the widget attribute
193   myWidgetValidator->restoreAttributeValue(aRefAttrList, aValid);
194   myExternalObjectMgr->removeExternal(sketch(), myFeature, myWorkshop, true);
195
196   ModuleBase_WidgetValidated::blockFeatureAttribute(aRefAttrList, myFeature, false,
197       isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked);
198   return aValid;
199 }
200
201 bool PartSet_WidgetBSplinePoints::setSelectionCustom(const ModuleBase_ViewerPrsPtr& theValue)
202 {
203   bool isDone = false;
204   GeomShapePtr aShape = theValue->shape();
205   if (aShape.get() && !aShape->isNull()) {
206     Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
207     const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
208     GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
209     if (aPnt) {
210       fillRefAttribute(aPnt, theValue);
211       isDone = true;
212     }
213     else if (aTDShape.ShapeType() == TopAbs_EDGE) {
214       fillRefAttribute(theValue);
215       isDone = true;
216     }
217   }
218   return isDone;
219 }
220
221 static void fillLabels(std::vector<ModuleBase_LabelValue*>& theLabels, const double theValue)
222 {
223   for (std::vector<ModuleBase_LabelValue*>::iterator anIt = theLabels.begin();
224        anIt != theLabels.end(); ++anIt)
225     (*anIt)->setValue(theValue);
226 }
227
228 bool PartSet_WidgetBSplinePoints::resetCustom()
229 {
230   bool aDone = false;
231   if (!isUseReset() || isComputedDefault())
232     aDone = false;
233   else {
234     if (myValueIsCashed) {
235       // if the restored value should be hidden, aDone = true to set
236       // reset state for the widget in the parent
237       aDone = restoreCurentValue();
238       emit objectUpdated();
239     }
240     else {
241       // it is important to block the spin box control in order to do not through out the
242       // locking of the validating state.
243       fillLabels(myXSpin, 0.0);
244       fillLabels(myYSpin, 0.0);
245
246       storeValueCustom();
247       aDone = true;
248     }
249   }
250   return aDone;
251 }
252
253 PartSet_WidgetBSplinePoints::~PartSet_WidgetBSplinePoints()
254 {
255   delete myExternalObjectMgr;
256 }
257
258 bool PartSet_WidgetBSplinePoints::setPoint(double theX, double theY)
259 {
260   if (fabs(theX) >= MaxCoordinate || fabs(theY) >= MaxCoordinate)
261     return false;
262
263   myXSpin.back()->setValue(theX);
264   myYSpin.back()->setValue(theY);
265
266   storeValue();
267   return true;
268 }
269
270 void PartSet_WidgetBSplinePoints::storePolesAndWeights() const
271 {
272   std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
273   AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
274       aData->attribute(attributeID()));
275   AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
276
277   int aSize = (int)myXSpin.size();
278   aPointArray->setSize(aSize);
279   aWeightsArray->setSize(aSize);
280
281   std::vector<ModuleBase_LabelValue*>::const_iterator aXIt = myXSpin.begin();
282   std::vector<ModuleBase_LabelValue*>::const_iterator aYIt = myYSpin.begin();
283   for (int anIndex = 0; aXIt != myXSpin.end() && aYIt != myYSpin.end(); ++anIndex, ++aXIt, ++aYIt)
284     aPointArray->setPnt(anIndex, (*aXIt)->value(), (*aYIt)->value());
285
286   double aWeight = Config_PropManager::real(SKETCH_TAB_NAME, "spline_weight");
287   for (int anIndex = 0; anIndex < aSize; ++anIndex)
288     aWeightsArray->setValue(anIndex, aWeight);
289 }
290
291 bool PartSet_WidgetBSplinePoints::storeValueCustom()
292 {
293   std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
294   if (!aData || !aData->isValid()) // can be on abort of sketcher element
295     return false;
296   AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
297       aData->attribute(attributeID()));
298   AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
299
300   PartSet_WidgetBSplinePoints* that = (PartSet_WidgetBSplinePoints*) this;
301   bool isBlocked = that->blockSignals(true);
302   bool isImmutable = aPointArray->setImmutable(true);
303
304   if (myFeature->isMacro()) {
305     // Moving points of macro-features has been processed directly (without solver)
306     storePolesAndWeights();
307     updateObject(myFeature);
308
309   } else {
310     if (!aPointArray->isInitialized()) {
311       storePolesAndWeights();
312     }
313
314     std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage(
315         new ModelAPI_ObjectMovedMessage(this));
316     aMessage->setMovedAttribute(aPointArray, aPointArray->size() - 1);
317     aMessage->setOriginalPosition(aPointArray->pnt(aPointArray->size() - 1));
318     aMessage->setCurrentPosition(myXSpin.back()->value(), myYSpin.back()->value());
319     Events_Loop::loop()->send(aMessage);
320   }
321
322   aPointArray->setImmutable(isImmutable);
323   that->blockSignals(isBlocked);
324
325   return true;
326 }
327
328 bool PartSet_WidgetBSplinePoints::restoreValueCustom()
329 {
330   std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
331   AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
332       aData->attribute(attributeID()));
333   AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
334
335   if (aPointArray->isInitialized()) {
336     while (myXSpin.size() < aPointArray->size())
337       createNextPoint();
338
339     std::vector<ModuleBase_LabelValue*>::iterator aXIt = myXSpin.begin();
340     std::vector<ModuleBase_LabelValue*>::iterator aYIt = myYSpin.begin();
341     for (int anIndex = 0; aXIt != myXSpin.end() && aYIt != myYSpin.end();
342          ++anIndex, ++aXIt, ++aYIt) {
343       GeomPnt2dPtr aPoint = aPointArray->pnt(anIndex);
344       (*aXIt)->setValue(aPoint->x());
345       (*aYIt)->setValue(aPoint->y());
346     }
347   }
348   else {
349     if (myXSpin.empty())
350       createNextPoint();
351
352     myXSpin.back()->setValue(0.0);
353     myYSpin.back()->setValue(0.0);
354   }
355
356   return true;
357 }
358
359 static void storeArray(const std::vector<ModuleBase_LabelValue*>& theLabels,
360                        std::vector<double>& theValues)
361 {
362   theValues.clear();
363   theValues.reserve(theLabels.size());
364   for (std::vector<ModuleBase_LabelValue*>::const_iterator anIt = theLabels.begin();
365        anIt != theLabels.end(); ++anIt)
366     theValues.push_back((*anIt)->value());
367 }
368
369 void PartSet_WidgetBSplinePoints::storeCurentValue()
370 {
371   myValueIsCashed = true;
372   myIsFeatureVisibleInCash = XGUI_Displayer::isVisible(
373                        XGUI_Tools::workshop(myWorkshop)->displayer(), myFeature);
374
375   storeArray(myXSpin, myXValueInCash);
376   storeArray(myYSpin, myYValueInCash);
377 }
378
379 static void restoreArray(std::vector<double>& theCacheValues,
380                          std::vector<ModuleBase_LabelValue*>& theLabels)
381 {
382   std::vector<double>::iterator aCIt = theCacheValues.begin();
383   std::vector<ModuleBase_LabelValue*>::iterator anIt = theLabels.begin();
384   for (; anIt != theLabels.end(); ++anIt) {
385     if (aCIt != theCacheValues.end())
386       (*anIt)->setValue(*aCIt++);
387     else
388       (*anIt)->setValue(0.0);
389   }
390   theCacheValues.clear();
391 }
392
393 bool PartSet_WidgetBSplinePoints::restoreCurentValue()
394 {
395   bool aRestoredAndHidden = true;
396
397   bool isVisible = myIsFeatureVisibleInCash;
398
399   myValueIsCashed = false;
400   myIsFeatureVisibleInCash = true;
401   // fill the control widgets by the cashed value
402   restoreArray(myXValueInCash, myXSpin);
403   restoreArray(myYValueInCash, myYSpin);
404
405   // store value to the model
406   storeValueCustom();
407   if (isVisible) {
408     setValueState(Stored);
409     aRestoredAndHidden = false;
410   }
411   else
412     aRestoredAndHidden = true;
413
414   return aRestoredAndHidden;
415 }
416
417 QList<QWidget*> PartSet_WidgetBSplinePoints::getControls() const
418 {
419   QList<QWidget*> aControls;
420   std::vector<ModuleBase_LabelValue*>::const_iterator aXIt = myXSpin.begin();
421   std::vector<ModuleBase_LabelValue*>::const_iterator aYIt = myYSpin.begin();
422   for (; (*aXIt) != myXSpin.back() && (*aYIt) != myYSpin.back(); ++aXIt, ++aYIt) {
423     //aControls.append(*aXIt);
424     //aControls.append(*aYIt);
425     QGraphicsEffect* anEffect = (*aXIt)->graphicsEffect();
426     if (anEffect)
427       anEffect->deleteLater();
428     anEffect = (*aYIt)->graphicsEffect();
429     if (anEffect)
430       anEffect->deleteLater();
431     (*aXIt)->setGraphicsEffect(0);
432     (*aYIt)->setGraphicsEffect(0);
433   }
434   aControls.append(myXSpin.back());
435   aControls.append(myYSpin.back());
436   return aControls;
437 }
438
439 void PartSet_WidgetBSplinePoints::selectionModes(int& theModuleSelectionModes, QIntList& theModes)
440 {
441   theModuleSelectionModes = -1;
442   theModes << TopAbs_VERTEX;
443   theModes << TopAbs_EDGE;
444 }
445
446 void PartSet_WidgetBSplinePoints::deactivate()
447 {
448   // the value of the control should be stored to model if it was not
449   // initialized yet. It is important when we leave this control by Tab key.
450   // It should not be performed by the widget activation as the preview
451   // is visualized with default value. Line point is moved to origin.
452   AttributePtr anAttribute = myFeature->data()->attribute(attributeID());
453   if (anAttribute && !anAttribute->isInitialized())
454     storeValue();
455
456   ModuleBase_ModelWidget::deactivate();
457 }
458
459 void PartSet_WidgetBSplinePoints::mouseReleased(ModuleBase_IViewWindow* theWindow,
460                                                 QMouseEvent* theEvent)
461 {
462   // the contex menu release by the right button should not be processed by this widget
463   if (theEvent->button() != Qt::LeftButton)
464     return;
465
466   ModuleBase_ISelection* aSelection = myWorkshop->selection();
467   Handle(V3d_View) aView = theWindow->v3dView();
468
469   QList<ModuleBase_ViewerPrsPtr> aList = aSelection->getSelected(ModuleBase_ISelection::Viewer);
470   ModuleBase_ViewerPrsPtr aFirstValue =
471     aList.size() > 0 ? aList.first() : ModuleBase_ViewerPrsPtr();
472   if (!aFirstValue.get() && myPreSelected.get()) {
473     aFirstValue = myPreSelected;
474   }
475
476   TopoDS_Shape aSelectedShape;
477   ObjectPtr aSelectedObject;
478
479   // if we have selection and use it
480   if (aFirstValue.get() && isValidSelectionCustom(aFirstValue) &&
481       aFirstValue->shape().get()) { // Trihedron Axis may be selected, but shape is empty
482     GeomShapePtr aGeomShape = aFirstValue->shape();
483     aSelectedShape = aGeomShape->impl<TopoDS_Shape>();
484     aSelectedObject = aFirstValue->object();
485
486     FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(aSelectedObject);
487     std::shared_ptr<SketchPlugin_Feature> aSPFeature;
488     if (aSelectedFeature.get())
489       aSPFeature = std::dynamic_pointer_cast<SketchPlugin_Feature>(aSelectedFeature);
490
491     bool isSketchExternalFeature = aSPFeature.get() && aSPFeature->isExternal();
492     if ((!aSPFeature && !aSelectedShape.IsNull()) || isSketchExternalFeature) {
493       ObjectPtr aFixedObject =
494           PartSet_Tools::findFixedObjectByExternal(aSelectedShape, aSelectedObject, mySketch);
495       if (aFixedObject)
496         aSelectedObject = aFixedObject;
497       else if (!isSketchExternalFeature) {
498         FeaturePtr aCreatedFeature;
499         aSelectedObject = PartSet_Tools::createFixedObjectByExternal(
500             aGeomShape, aSelectedObject, mySketch, false, aCreatedFeature);
501       }
502     }
503   }
504   // The selection could be a center of an external circular object
505   else if (aFirstValue.get() && (!aFirstValue->interactive().IsNull())) {
506     Handle(PartSet_CenterPrs) aAIS =
507         Handle(PartSet_CenterPrs)::DownCast(aFirstValue->interactive());
508     if (!aAIS.IsNull()) {
509       gp_Pnt aPntComp = aAIS->Component()->Pnt();
510       GeomVertexPtr aVertPtr(new GeomAPI_Vertex(aPntComp.X(), aPntComp.Y(), aPntComp.Z()));
511       aSelectedShape = aVertPtr->impl<TopoDS_Shape>();
512
513       aSelectedObject =
514           PartSet_Tools::findFixedObjectByExternal(aSelectedShape, aAIS->object(), mySketch);
515       if (!aSelectedObject.get())
516       {
517         FeaturePtr aCreatedFeature;
518         aSelectedObject = PartSet_Tools::createFixedByExternalCenter(aAIS->object(), aAIS->edge(),
519             aAIS->centerType(), mySketch, false, aCreatedFeature);
520       }
521     }
522   }
523
524   GeomPnt2dPtr aSelectedPoint = PartSet_Tools::getPnt2d(aView, aSelectedShape, mySketch);
525   if (aSelectedPoint) {
526     // nullify selected object to add reference to attribute instead of its owner
527     aSelectedObject = ObjectPtr();
528   }
529   else {
530     aSelectedPoint = PartSet_Tools::getPnt2d(theEvent, theWindow, mySketch);
531     setValueState(Stored); // in case of edge selection, Apply state should also be updated
532   }
533   if (aSelectedObject)
534     fillRefAttribute(aSelectedObject);
535   else
536     fillRefAttribute(aSelectedPoint, aFirstValue);
537
538   // next pole of B-spline
539   createNextPoint();
540 }
541
542 void PartSet_WidgetBSplinePoints::mouseMoved(ModuleBase_IViewWindow* theWindow,
543                                              QMouseEvent* theEvent)
544 {
545   PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
546
547   if (myFinished || isEditingMode() || aModule->sketchReentranceMgr()->isInternalEditActive())
548     return;
549
550   gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView());
551
552   double aX = 0, aY = 0;
553   PartSet_Tools::convertTo2D(aPoint, mySketch, theWindow->v3dView(), aX, aY);
554   if (myState != ModifiedInViewer)
555     storeCurentValue();
556   // we need to block the value state change
557   bool isBlocked = blockValueState(true);
558   setPoint(aX, aY);
559   blockValueState(isBlocked);
560   setValueState(ModifiedInViewer);
561 }
562
563 bool PartSet_WidgetBSplinePoints::processEscape()
564 {
565   bool isProcessed = !isEditingMode();
566   if (isProcessed) {
567     // remove widgets corrsponding to the last pole/weight of B-spline
568     removeLastPoint();
569     myFinished = true;
570
571     emit focusOutWidget(this);
572   }
573   return isProcessed;
574 }
575
576 bool PartSet_WidgetBSplinePoints::useSelectedShapes() const
577 {
578   return true;
579 }
580
581 AttributeRefAttrListPtr PartSet_WidgetBSplinePoints::attributeRefAttrList() const
582 {
583   if (myRefAttribute.empty())
584     return AttributeRefAttrListPtr();
585
586   AttributePtr anAttributeRef = feature()->attribute(myRefAttribute);
587   if (!anAttributeRef.get())
588     return AttributeRefAttrListPtr();
589
590   return std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(anAttributeRef);
591 }
592
593 void PartSet_WidgetBSplinePoints::fillRefAttribute(GeomPnt2dPtr theClickedPoint,
594                               const std::shared_ptr<ModuleBase_ViewerPrs>& theValue)
595 {
596   AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
597   if (!aRefAttrList.get())
598     return;
599
600   FeaturePtr aFeature = feature();
601   std::string anAttribute = attributeID();
602
603   if (aFeature.get()) {
604     AttributePoint2DPtr aClickedFeaturePoint =
605         PartSet_WidgetPoint2D::findFirstEqualPointInSketch(mySketch, aFeature, theClickedPoint);
606     if (aClickedFeaturePoint.get())
607       aRefAttrList->append(aClickedFeaturePoint);
608     else
609       fillRefAttribute(theValue);
610   }
611 }
612
613 void PartSet_WidgetBSplinePoints::fillRefAttribute(const ModuleBase_ViewerPrsPtr& theValue)
614 {
615   ObjectPtr anObject;
616   if (theValue)
617     anObject = getGeomSelection(theValue);
618   fillRefAttribute(anObject);
619 }
620
621 void PartSet_WidgetBSplinePoints::fillRefAttribute(const ObjectPtr& theObject)
622 {
623   AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
624   if (aRefAttrList.get())
625     aRefAttrList->append(theObject);
626 }
627
628 ObjectPtr PartSet_WidgetBSplinePoints::getGeomSelection(const ModuleBase_ViewerPrsPtr& theValue)
629 {
630   ObjectPtr anObject;
631   GeomShapePtr aShape;
632   ModuleBase_ISelection* aSelection = myWorkshop->selection();
633   anObject = aSelection->getResult(theValue);
634   aShape = aSelection->getShape(theValue);
635   myExternalObjectMgr->getGeomSelection(theValue, anObject, aShape, myWorkshop, sketch(), true);
636
637   return anObject;
638 }