Salome HOME
add40ce6abeff8281fb092c603022aa4005db2c9
[modules/shaper.git] / src / PartSet / PartSet_WidgetPoint2d.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        PartSet_WidgetPoint2D.cpp
4 // Created:     25 Apr 2014
5 // Author:      Natalia ERMOLAEVA
6
7 #include "PartSet_WidgetPoint2d.h"
8 #include <PartSet_Tools.h>
9 #include <PartSet_Module.h>
10
11 #include <XGUI_Workshop.h>
12 #include <XGUI_ViewerProxy.h>
13 #include <XGUI_ModuleConnector.h>
14 #include <XGUI_SelectionMgr.h>
15 #include <XGUI_Selection.h>
16 #include <XGUI_OperationMgr.h>
17
18 #include <ModuleBase_DoubleSpinBox.h>
19 #include <ModuleBase_Tools.h>
20 #include <ModuleBase_IViewWindow.h>
21
22 #include <Config_Keywords.h>
23 #include <Config_WidgetAPI.h>
24
25 #include <Events_Loop.h>
26 #include <ModelAPI_Events.h>
27
28 #include <ModelAPI_Feature.h>
29 #include <ModelAPI_Data.h>
30 #include <ModelAPI_Object.h>
31 #include <GeomDataAPI_Point2D.h>
32 #include <GeomAPI_Pnt2d.h>
33
34 #include <SketchPlugin_Feature.h>
35 #include <SketchPlugin_ConstraintCoincidence.h>
36
37 #include <QGroupBox>
38 #include <QGridLayout>
39 #include <QLabel>
40 #include <QEvent>
41 #include <QMouseEvent>
42 #include <QApplication>
43
44 #include <TopoDS.hxx>
45 #include <TopoDS_Vertex.hxx>
46 #include <BRep_Tool.hxx>
47
48 #include <cfloat>
49 #include <climits>
50
51 const double MaxCoordinate = 1e12;
52
53
54 PartSet_WidgetPoint2D::PartSet_WidgetPoint2D(QWidget* theParent, 
55                                               const Config_WidgetAPI* theData,
56                                               const std::string& theParentId)
57     : ModuleBase_ModelWidget(theParent, theData, theParentId)
58 {
59   // the control should accept the focus, so the boolen flag is corrected to be true
60   myIsObligatory = true;
61   //myOptionParam = theData->getProperty(PREVIOUS_FEATURE_PARAM);
62   QString aPageName = QString::fromStdString(theData->getProperty(CONTAINER_PAGE_NAME));
63   myGroupBox = new QGroupBox(aPageName, theParent);
64   myGroupBox->setFlat(false);
65
66   QGridLayout* aGroupLay = new QGridLayout(myGroupBox);
67   ModuleBase_Tools::adjustMargins(aGroupLay);
68   aGroupLay->setColumnStretch(1, 1);
69   {
70     QLabel* aLabel = new QLabel(myGroupBox);
71     aLabel->setText(tr("X"));
72     aLabel->setPixmap(QPixmap(":pictures/x_point.png"));
73     aGroupLay->addWidget(aLabel, 0, 0);
74
75     myXSpin = new ModuleBase_DoubleSpinBox(myGroupBox);
76     myXSpin->setMinimum(-DBL_MAX);
77     myXSpin->setMaximum(DBL_MAX);
78     myXSpin->setToolTip(tr("X"));
79     aGroupLay->addWidget(myXSpin, 0, 1);
80
81     connect(myXSpin, SIGNAL(valueChanged(double)), this, SLOT(onValuesChanged()));
82   }
83   {
84     QLabel* aLabel = new QLabel(myGroupBox);
85     aLabel->setText(tr("Y"));
86     aLabel->setPixmap(QPixmap(":pictures/y_point.png"));
87     aGroupLay->addWidget(aLabel, 1, 0);
88
89     myYSpin = new ModuleBase_DoubleSpinBox(myGroupBox);
90     myYSpin->setMinimum(-DBL_MAX);
91     myYSpin->setMaximum(DBL_MAX);
92     myYSpin->setToolTip(tr("Y"));
93     aGroupLay->addWidget(myYSpin, 1, 1);
94
95     connect(myYSpin, SIGNAL(valueChanged(double)), this, SLOT(onValuesChanged()));
96   }
97   QVBoxLayout* aLayout = new QVBoxLayout(this);
98   ModuleBase_Tools::zeroMargins(aLayout);
99   aLayout->addWidget(myGroupBox);
100   setLayout(aLayout);
101 }
102
103 void PartSet_WidgetPoint2D::reset()
104 {
105   if (!isUseReset())
106     return;
107
108   if (isComputedDefault()) {
109     //return;
110     if (myFeature->compute(myAttributeID))
111       restoreValue();
112   }
113   else {
114     bool isOk;
115     double aDefValue = QString::fromStdString(getDefaultValue()).toDouble(&isOk);
116     // it is important to block the spin box control in order to do not through out the
117     // locking of the validating state.
118     ModuleBase_Tools::setSpinValue(myXSpin, isOk ? aDefValue : 0.0);
119     ModuleBase_Tools::setSpinValue(myYSpin, isOk ? aDefValue : 0.0);
120     storeValueCustom();
121   }
122 }
123
124 PartSet_WidgetPoint2D::~PartSet_WidgetPoint2D()
125 {
126 }
127
128 bool PartSet_WidgetPoint2D::setSelection(const QList<ModuleBase_ViewerPrs>& theValues, int& thePosition)
129 {
130   if (thePosition < 0 || thePosition >= theValues.size())
131     return false;
132   ModuleBase_ViewerPrs aValue = theValues[thePosition];
133   thePosition++;
134
135   Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
136   bool isDone = false;
137   TopoDS_Shape aShape = aValue.shape();
138   double aX, aY;
139   if (getPoint2d(aView, aShape, aX, aY)) {
140     isDone = setPoint(aX, aY);
141   }
142   return isDone;
143 }
144
145 bool PartSet_WidgetPoint2D::setPoint(double theX, double theY)
146 {
147   if (fabs(theX) >= MaxCoordinate)
148     return false;
149   if (fabs(theY) >= MaxCoordinate)
150     return false;
151
152   ModuleBase_Tools::setSpinValue(myXSpin, theX);
153   ModuleBase_Tools::setSpinValue(myYSpin, theY);
154
155   storeValue();
156   return true;
157 }
158
159 bool PartSet_WidgetPoint2D::storeValueCustom() const
160 {
161   std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
162   if (!aData) // can be on abort of sketcher element
163     return false;
164   std::shared_ptr<GeomDataAPI_Point2D> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
165       aData->attribute(attributeID()));
166   
167   PartSet_WidgetPoint2D* that = (PartSet_WidgetPoint2D*) this;
168   bool isBlocked = that->blockSignals(true);
169   bool isImmutable = aPoint->setImmutable(true);
170 #ifdef _DEBUG
171   std::string _attr_name = myAttributeID;
172   double _X = myXSpin->value();
173   double _Y = myYSpin->value();
174 #endif
175   aPoint->setValue(myXSpin->value(), myYSpin->value());
176   // after movement the solver will call the update event: optimization
177   moveObject(myFeature);
178   aPoint->setImmutable(isImmutable);
179   that->blockSignals(isBlocked);
180
181   return true;
182 }
183
184 bool PartSet_WidgetPoint2D::restoreValue()
185 {
186   std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
187   std::shared_ptr<GeomDataAPI_Point2D> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
188       aData->attribute(attributeID()));
189
190 #ifdef _DEBUG
191   std::string _attr_name = myAttributeID;
192   double _X = aPoint->x();
193   double _Y = aPoint->y();
194 #endif
195
196   ModuleBase_Tools::setSpinValue(myXSpin, aPoint->x());
197   ModuleBase_Tools::setSpinValue(myYSpin, aPoint->y());
198   return true;
199 }
200
201 QList<QWidget*> PartSet_WidgetPoint2D::getControls() const
202 {
203   QList<QWidget*> aControls;
204   aControls.append(myXSpin);
205   aControls.append(myYSpin);
206   return aControls;
207 }
208
209
210 void PartSet_WidgetPoint2D::activateCustom()
211 {
212   XGUI_ViewerProxy* aViewer = myWorkshop->viewer();
213   connect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)), 
214           this, SLOT(onMouseMove(ModuleBase_IViewWindow*, QMouseEvent*)));
215   connect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)), 
216           this, SLOT(onMouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)));
217   connect(aViewer, SIGNAL(enterViewPort()), this, SLOT(onLockValidating()));
218   connect(aViewer, SIGNAL(leaveViewPort()), this, SLOT(onUnlockValidating()));
219
220   QIntList aModes;
221   aModes << TopAbs_VERTEX;
222   aModes << TopAbs_EDGE;
223   myWorkshop->moduleConnector()->activateSubShapesSelection(aModes);
224
225   PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
226   if (aModule->isMouseOverWindow())
227     onLockValidating();
228 }
229
230 void PartSet_WidgetPoint2D::deactivate()
231 {
232   ModuleBase_IViewer* aViewer = myWorkshop->viewer();
233   disconnect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)), 
234              this, SLOT(onMouseMove(ModuleBase_IViewWindow*, QMouseEvent*)));
235   disconnect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)), 
236              this, SLOT(onMouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)));
237   disconnect(aViewer, SIGNAL(enterViewPort()), this, SLOT(onLockValidating()));
238   disconnect(aViewer, SIGNAL(leaveViewPort()), this, SLOT(onUnlockValidating()));
239
240   myWorkshop->moduleConnector()->deactivateSubShapesSelection();
241   onUnlockValidating();
242 }
243
244 bool PartSet_WidgetPoint2D::getPoint2d(const Handle(V3d_View)& theView, 
245                                        const TopoDS_Shape& theShape, 
246                                        double& theX, double& theY) const
247 {
248   if (!theShape.IsNull()) {
249     if (theShape.ShapeType() == TopAbs_VERTEX) {
250       const TopoDS_Vertex& aVertex = TopoDS::Vertex(theShape);
251       if (!aVertex.IsNull()) {
252         // A case when point is taken from existing vertex
253         gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
254         PartSet_Tools::convertTo2D(aPoint, mySketch, theView, theX, theY);
255         return true;
256       }
257     }
258   }
259   return false;
260 }
261
262
263 void PartSet_WidgetPoint2D::onMouseRelease(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
264 {
265   // the contex menu release by the right button should not be processed by this widget
266   if (theEvent->button() != Qt::LeftButton)
267     return;
268
269   XGUI_Selection* aSelection = myWorkshop->selector()->selection();
270   Handle(V3d_View) aView = theWnd->v3dView();
271   // TODO: This fragment doesn't work because bug in OCC Viewer. It can be used after fixing.
272   NCollection_List<TopoDS_Shape> aShapes;
273   std::list<ObjectPtr> aObjects;
274   aSelection->selectedShapes(aShapes, aObjects);
275   // if we have selection
276   if (aShapes.Extent() > 0) {
277     TopoDS_Shape aShape = aShapes.First();
278     ObjectPtr aObject = aObjects.front();
279     FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(aObject);
280     if (aSelectedFeature.get() != NULL) {
281       std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
282               std::dynamic_pointer_cast<SketchPlugin_Feature>(aSelectedFeature);
283       if ((!aSPFeature) && (!aShape.IsNull())) {
284         ResultPtr aFixedObject = PartSet_Tools::findFixedObjectByExternal(aShape, aObject, mySketch);
285         if (!aFixedObject.get())
286           aFixedObject = PartSet_Tools::createFixedObjectByExternal(aShape, aObject, mySketch);
287       }
288     }
289     double aX, aY;
290     if (getPoint2d(aView, aShape, aX, aY)) {
291       setPoint(aX, aY);
292
293       PartSet_Tools::setConstraints(mySketch, feature(), attributeID(),aX, aY);
294       emit vertexSelected();
295       emit focusOutWidget(this);
296       return;
297     } else if (aShape.ShapeType() == TopAbs_EDGE) {
298       // Create point-edge coincedence
299       FeaturePtr aFeature = mySketch->addFeature(SketchPlugin_ConstraintCoincidence::ID());
300       std::shared_ptr<ModelAPI_Data> aData = aFeature->data();
301
302       std::shared_ptr<ModelAPI_AttributeRefAttr> aRef1 = std::dynamic_pointer_cast<
303           ModelAPI_AttributeRefAttr>(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
304       AttributePtr aThisAttr = feature()->data()->attribute(attributeID());
305       std::shared_ptr<GeomDataAPI_Point2D> aThisPoint = 
306         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aThisAttr);
307       aRef1->setAttr(aThisPoint);
308
309       std::shared_ptr<ModelAPI_AttributeRefAttr> aRef2 = std::dynamic_pointer_cast<
310           ModelAPI_AttributeRefAttr>(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
311       aRef2->setObject(aObject);
312       aFeature->execute();
313       emit vertexSelected();
314       emit focusOutWidget(this);
315       return;
316     }
317   }
318   // End of Bug dependent fragment
319
320   // A case when point is taken from mouse event
321   gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWnd->v3dView());
322   double aX, anY;
323   PartSet_Tools::convertTo2D(aPoint, mySketch, aView, aX, anY);
324   if (!setPoint(aX, anY))
325     return;
326
327   /// Start alternative code
328   //std::shared_ptr<GeomDataAPI_Point2D> aFeaturePoint = std::dynamic_pointer_cast<
329   //    GeomDataAPI_Point2D>(feature()->data()->attribute(attributeID()));
330   //QList<FeaturePtr> aIgnore;
331   //aIgnore.append(feature());
332
333   //double aTolerance = aView->Convert(7);
334   //std::shared_ptr<GeomDataAPI_Point2D> aAttrPnt = 
335   //  PartSet_Tools::findAttributePoint(mySketch, aX, anY, aTolerance, aIgnore);
336   //if (aAttrPnt.get() != NULL) {
337   //  aFeaturePoint->setValue(aAttrPnt->pnt());
338   //  PartSet_Tools::createConstraint(mySketch, aAttrPnt, aFeaturePoint);
339   //  emit vertexSelected();
340   //}
341   /// End alternative code
342   emit focusOutWidget(this);
343 }
344
345
346 void PartSet_WidgetPoint2D::onMouseMove(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
347 {
348   if (isEditingMode())
349     return;
350
351   gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWnd->v3dView());
352
353   double aX, anY;
354   PartSet_Tools::convertTo2D(aPoint, mySketch, theWnd->v3dView(), aX, anY);
355   setPoint(aX, anY);
356 }
357
358 void PartSet_WidgetPoint2D::onLockValidating()
359 {
360   XGUI_OperationMgr* anOperationMgr = myWorkshop->operationMgr();
361   anOperationMgr->setLockValidating(true);
362   // the Ok button should be disabled in the property panel by moving the mouse point in the viewer
363   // this leads that the user does not try to click Ok and it avoids an incorrect situation that the 
364   // line is moved to the cursor to the Ok button
365   anOperationMgr->setApplyEnabled(false);
366 }
367
368 void PartSet_WidgetPoint2D::onUnlockValidating()
369 {
370   // it is important to restore the validity state in the property panel after leaving the
371   // view port. Unlock the validating.
372   XGUI_OperationMgr* anOperationMgr = myWorkshop->operationMgr();
373   if (anOperationMgr->isValidationLocked()) {
374     anOperationMgr->setLockValidating(false);
375     anOperationMgr->onValidateOperation();
376   }
377 }
378
379 double PartSet_WidgetPoint2D::x() const
380 {
381   return myXSpin->value();
382 }
383
384 double PartSet_WidgetPoint2D::y() const
385 {
386   return myYSpin->value();
387 }
388
389 void PartSet_WidgetPoint2D::onValuesChanged()
390 {
391   myWorkshop->operationMgr()->setLockValidating(false);
392   emit valuesChanged();
393 }