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