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