From 92b4a7087129df9d69db3d060d81637f9697d289 Mon Sep 17 00:00:00 2001 From: asozinov Date: Mon, 10 Jul 2023 13:14:58 +0100 Subject: [PATCH] [bos #31549] [EDF] (2023-T1) Sketch Visualization of constrains - Added browser which show all constraints in the active sketch. - This browser provide functionality for Delete, Edit and Suppress constraints - Suppressed constraints can be reactivated - for constraints will be added new attribute ConstraintState. If True - constraint active, otherwise - suppressed. This parameter can be used as optional for python script. Example of using: Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint(), is_active = False) Documentationalso will be added --- src/ModuleBase/ModuleBase_IModule.h | 4 + src/ModuleBase/ModuleBase_ISelection.h | 2 +- src/PartSet/PartSet_Module.cpp | 19 + src/PartSet/PartSet_SketcherMgr.cpp | 141 +++- src/PartSet/PartSet_SketcherMgr.h | 11 +- src/SketchAPI/SketchAPI_Constraint.cpp | 3 + src/SketchAPI/SketchAPI_ConstraintAngle.cpp | 4 +- src/SketchAPI/SketchAPI_Sketch.cpp | 82 +- src/SketchAPI/SketchAPI_Sketch.h | 60 +- src/SketchPlugin/SketchPlugin_Constraint.h | 6 + .../SketchPlugin_ConstraintAngle.cpp | 4 + .../SketchPlugin_ConstraintCoincidence.cpp | 4 + .../SketchPlugin_ConstraintCollinear.cpp | 4 + .../SketchPlugin_ConstraintDistance.cpp | 4 + ...ketchPlugin_ConstraintDistanceAlongDir.cpp | 4 + .../SketchPlugin_ConstraintEqual.cpp | 4 + .../SketchPlugin_ConstraintHorizontal.cpp | 4 + .../SketchPlugin_ConstraintLength.cpp | 4 + .../SketchPlugin_ConstraintMiddle.cpp | 4 + .../SketchPlugin_ConstraintMirror.cpp | 4 + .../SketchPlugin_ConstraintParallel.cpp | 4 + .../SketchPlugin_ConstraintPerpendicular.cpp | 4 + .../SketchPlugin_ConstraintRadius.cpp | 4 + .../SketchPlugin_ConstraintRigid.cpp | 4 + .../SketchPlugin_ConstraintTangent.cpp | 4 + .../SketchPlugin_ConstraintVertical.cpp | 4 + .../SketchPlugin_MultiRotation.cpp | 4 + .../SketchPlugin_MultiTranslation.cpp | 4 + src/SketchPlugin/SketchPlugin_Offset.cpp | 4 + src/SketchPlugin/doc/SketchPlugin.rst | 9 + .../doc/images/ConstraintsBrowser.png | Bin 0 -> 39344 bytes .../doc/images/constraints_suppressed.png | Bin 0 -> 6572 bytes .../images/constraints_suppressed_moved.png | Bin 0 -> 7422 bytes .../doc/sketchConstraintsBrowser.rst | 45 ++ .../PlaneGCSSolver/PlaneGCSSolver_Storage.cpp | 59 +- .../PlaneGCSSolver/PlaneGCSSolver_Storage.h | 5 + .../SketchSolver_ConstraintDistance.cpp | 4 + src/SketchSolver/SketchSolver_Group.cpp | 15 + src/SketchSolver/SketchSolver_Storage.h | 6 + src/SketcherPrs/CMakeLists.txt | 9 + src/SketcherPrs/SketcherPrs_Angle.cpp | 3 +- src/SketcherPrs/SketcherPrs_Collinear.h | 2 +- .../SketcherPrs_DimensionStyle.cpp | 48 +- src/SketcherPrs/SketcherPrs_DimensionStyle.h | 5 +- src/SketcherPrs/SketcherPrs_Equal.h | 2 +- src/SketcherPrs/SketcherPrs_HVDirection.h | 7 +- .../SketcherPrs_LengthDimension.cpp | 2 +- src/SketcherPrs/SketcherPrs_Middle.h | 2 +- src/SketcherPrs/SketcherPrs_Mirror.h | 2 +- src/SketcherPrs/SketcherPrs_Offset.h | 2 +- src/SketcherPrs/SketcherPrs_Parallel.h | 2 +- src/SketcherPrs/SketcherPrs_Perpendicular.h | 2 +- src/SketcherPrs/SketcherPrs_Radius.cpp | 2 +- src/SketcherPrs/SketcherPrs_Rigid.h | 2 +- src/SketcherPrs/SketcherPrs_SymbolPrs.cpp | 25 +- src/SketcherPrs/SketcherPrs_SymbolPrs.h | 2 +- src/SketcherPrs/SketcherPrs_Tangent.h | 2 +- src/SketcherPrs/SketcherPrs_Transformation.h | 2 +- src/SketcherPrs/icons/anchor_deactivate.png | Bin 0 -> 356 bytes .../icons/collinear_deactivate.png | Bin 0 -> 303 bytes src/SketcherPrs/icons/equal_deactivate.png | Bin 0 -> 223 bytes .../icons/horisontal_deactivate.png | Bin 0 -> 218 bytes .../icons/middlepoint_deactivate.png | Bin 0 -> 248 bytes src/SketcherPrs/icons/parallel_deactivate.png | Bin 0 -> 219 bytes .../icons/perpendicular_deactivate.png | Bin 0 -> 166 bytes src/SketcherPrs/icons/tangent_deactivate.png | Bin 0 -> 257 bytes src/SketcherPrs/icons/vertical_deactivate.png | Bin 0 -> 200 bytes src/XGUI/CMakeLists.txt | 13 +- src/XGUI/XGUI_ActionsMgr.cpp | 4 +- src/XGUI/XGUI_ContextMenuMgr.cpp | 79 ++ src/XGUI/XGUI_ContextMenuMgr.h | 9 + src/XGUI/XGUI_Displayer.cpp | 17 + src/XGUI/XGUI_Selection.cpp | 34 + src/XGUI/XGUI_Selection.h | 7 + src/XGUI/XGUI_SelectionMgr.cpp | 36 + src/XGUI/XGUI_SelectionMgr.h | 5 +- src/XGUI/XGUI_SketchConstraintsBrowser.cpp | 755 ++++++++++++++++++ src/XGUI/XGUI_SketchConstraintsBrowser.h | 204 +++++ src/XGUI/XGUI_Workshop.cpp | 61 ++ src/XGUI/XGUI_Workshop.h | 22 + src/XGUI/XGUI_msg_fr.ts | 7 + 81 files changed, 1821 insertions(+), 106 deletions(-) create mode 100644 src/SketchPlugin/doc/images/ConstraintsBrowser.png create mode 100644 src/SketchPlugin/doc/images/constraints_suppressed.png create mode 100644 src/SketchPlugin/doc/images/constraints_suppressed_moved.png create mode 100644 src/SketchPlugin/doc/sketchConstraintsBrowser.rst create mode 100644 src/SketcherPrs/icons/anchor_deactivate.png create mode 100644 src/SketcherPrs/icons/collinear_deactivate.png create mode 100644 src/SketcherPrs/icons/equal_deactivate.png create mode 100644 src/SketcherPrs/icons/horisontal_deactivate.png create mode 100644 src/SketcherPrs/icons/middlepoint_deactivate.png create mode 100644 src/SketcherPrs/icons/parallel_deactivate.png create mode 100644 src/SketcherPrs/icons/perpendicular_deactivate.png create mode 100644 src/SketcherPrs/icons/tangent_deactivate.png create mode 100644 src/SketcherPrs/icons/vertical_deactivate.png create mode 100644 src/XGUI/XGUI_SketchConstraintsBrowser.cpp create mode 100644 src/XGUI/XGUI_SketchConstraintsBrowser.h diff --git a/src/ModuleBase/ModuleBase_IModule.h b/src/ModuleBase/ModuleBase_IModule.h index e60281374..ac1ebde44 100644 --- a/src/ModuleBase/ModuleBase_IModule.h +++ b/src/ModuleBase/ModuleBase_IModule.h @@ -149,6 +149,10 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject /// \param theMenu a popup menu to be shown in the object browser virtual void addObjectBrowserMenu(QMenu* theMenu) const {}; + /// Add menu items for constraints browser into the given menu + /// \param theMenu a popup menu to be shown in the constraints browser + virtual void addConstraintBrowserMenu(QMenu* theMenu) const {}; + /// Creates custom widgets for property panel /// \param theType a type of widget /// \param theParent the parent object diff --git a/src/ModuleBase/ModuleBase_ISelection.h b/src/ModuleBase/ModuleBase_ISelection.h index c662231f2..a33e8c708 100644 --- a/src/ModuleBase/ModuleBase_ISelection.h +++ b/src/ModuleBase/ModuleBase_ISelection.h @@ -44,7 +44,7 @@ class MODULEBASE_EXPORT ModuleBase_ISelection { public: /// Types of the selection place, where the selection is obtained - enum SelectionPlace { Browser, Viewer, AllControls }; + enum SelectionPlace { Browser, Viewer, ConstraintsBorwser, AllControls }; virtual ~ModuleBase_ISelection() {} diff --git a/src/PartSet/PartSet_Module.cpp b/src/PartSet/PartSet_Module.cpp index 73113c006..84b28e4d0 100644 --- a/src/PartSet/PartSet_Module.cpp +++ b/src/PartSet/PartSet_Module.cpp @@ -104,6 +104,7 @@ #include #include #include +#include #include #include @@ -998,6 +999,24 @@ bool PartSet_Module::deleteObjects() // the abort leads to selection lost on constraint objects. It can be corrected after #386 issue ModuleBase_ISelection* aSel = workshop()->selection(); QObjectPtrList aSelectedObj = aSel->selectedPresentations(); + + QObjectPtrList aConstrSelectedObj = getWorkshop()->constraintsBrowser()->selectedConstraints(); + // if list not empty, delete only constraints from list + if (!aConstrSelectedObj.isEmpty()) + { + QString aDescription = aWorkshop->contextMenuMgr()->action("DELETE_CMD")->text(); + ModuleBase_Operation* anOpAction = new ModuleBase_Operation(aDescription, this); + + bool isCommitted; + if (!anOpMgr->canStartOperation(anOpAction->id(), isCommitted)) + return true; + + anOpMgr->startOperation(anOpAction); + aWorkshop->deleteFeatures(aConstrSelectedObj); + anOpMgr->commitOperation(); + return true; + } + // if there are no selected objects in the viewer, that means that the selection in another // place cased this method. It is necessary to return the false value to understande in above // method that delete is not processed diff --git a/src/PartSet/PartSet_SketcherMgr.cpp b/src/PartSet/PartSet_SketcherMgr.cpp index d47d1ec75..42075abad 100644 --- a/src/PartSet/PartSet_SketcherMgr.cpp +++ b/src/PartSet/PartSet_SketcherMgr.cpp @@ -31,6 +31,7 @@ #include "PartSet_PreviewSketchPlane.h" #include +#include #include #include #include @@ -108,6 +109,8 @@ #include #include #include +#include +#include #include #include @@ -219,6 +222,11 @@ PartSet_SketcherMgr::~PartSet_SketcherMgr() delete mySketchPlane; } +XGUI_SketchConstraintsBrowser* PartSet_SketcherMgr::constraintsBrowser() +{ + return workshop()->constraintsBrowser(); +} + void PartSet_SketcherMgr::onEnterViewPort() { // 1. if the mouse over window, update the next flag. Do not perform update visibility of @@ -850,6 +858,105 @@ void PartSet_SketcherMgr::onAfterContextMenu() myIsPopupMenuActive = false; } +void PartSet_SketcherMgr::onEditValues() +{ + auto aConstrBrowser = constraintsBrowser(); + + auto anOperMgr = workshop()->operationMgr(); + + ModuleBase_Operation* anOpAction = new ModuleBase_Operation("Edit Constraints value"); + + anOperMgr->startOperation(anOpAction); + int aRow = 0; + QTreeWidgetItemIterator anIter(aConstrBrowser->getViewTree()); + while (*anIter) { + // Change value + auto aData = (*anIter)->data(3, 0); + if (!aData.isNull()) + { + double aNewValue = aData.toDouble(); + auto aName = (*anIter)->data(1, 0).toString(); + FeaturePtr aConstr; + for (int i = 0; i < myCurrentSketch->numberOfSubs(); ++i) + { + auto aFFeat = myCurrentSketch->subFeature(i); + if (aName == QString::fromStdWString(aFFeat->name())) + { + aConstr = aFFeat; + break; + } + } + + aConstr->real("ConstraintValue")->setValue(aNewValue); + + if (aConstr->real("AngleValue")) + aConstr->real("AngleValue")->setValue(aNewValue); + else if (aConstr->real("DistanceValue")) + aConstr->real("DistanceValue")->setValue(aNewValue); + else + aConstr->real("ConstraintValue")->setValue(aNewValue); + } + + ++aRow; + ++anIter; + } + anOperMgr->commitOperation(); + workshop()->viewer()->update(); +} + +// Rename +void PartSet_SketcherMgr::onUpdateConstraintsList() +{ + auto aConstrBrowser = constraintsBrowser(); + + std::vector>> aConstraints; + + CompositeFeaturePtr aComposite = + std::dynamic_pointer_cast(activeSketch()); + int aNumSubs = aComposite->numberOfSubs(); + for (int i = 0; i < aNumSubs; ++i) + { + auto aFeat = aComposite->subFeature(i); + if (aFeat->refattr(SketchPlugin_Constraint::ENTITY_A()) && + (!aFeat->attribute(SketchPlugin_Constraint::ENTITY_B()) || aFeat->refattr(SketchPlugin_Constraint::ENTITY_B()))) + { + std::pair> anElemContr; + anElemContr.first = aFeat; + + anElemContr.second.push_back(aFeat->refattr(SketchPlugin_Constraint::ENTITY_A())); + if (aFeat->attribute(SketchPlugin_Constraint::ENTITY_B())) + anElemContr.second.push_back(aFeat->refattr(SketchPlugin_Constraint::ENTITY_B())); + + aConstraints.push_back(anElemContr); + } + } + aConstrBrowser->UpdateTree(aConstraints); +} + +// Bad way, but it works +void PartSet_SketcherMgr::onDeactivate(bool isNeedDeactivate, std::vector theFeatures) +{ + std::list anUpd; + auto anOperMgr = workshop()->operationMgr(); + + ModuleBase_OperationFeature* anOpAction = new ModuleBase_OperationFeature("Deactivate/Activate"); + anOpAction->setFeature(myCurrentSketch); + startNestedSketch(anOpAction); + anOperMgr->startOperation(anOpAction); + + for (int i = 0; i < theFeatures.size(); ++i) + { + theFeatures[i]->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(isNeedDeactivate); + + static const Events_ID anEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES); + ModelAPI_EventCreator::get()->sendUpdated(theFeatures[i], anEvent, false); + } + + stopNestedSketch(anOpAction); + anOperMgr->commitOperation(); + workshop()->viewer()->update(); +} + void PartSet_SketcherMgr::get2dPoint(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent, Point& thePoint) { @@ -1200,6 +1307,17 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation) PartSet_Fitter* aFitter = new PartSet_Fitter(this); myModule->workshop()->viewer()->setFitter(aFitter); + + auto aDesktop = workshop()->desktop(); + myConstraintsBrowser = workshop()->createConstraintsBrowser(aDesktop); + + // For process edit/delete and deactivate/activate constraints + connect(constraintsBrowser(), SIGNAL(editValues()), this, SLOT(onEditValues())); + connect(constraintsBrowser(), SIGNAL(deleteCosnstraints()), this, SLOT(onUpdateConstraintsList())); + connect(constraintsBrowser(), SIGNAL(deactivate(bool, std::vector)), this, SLOT(onDeactivate(bool, std::vector))); + aDesktop->addDockWidget(Qt::RightDockWidgetArea, myConstraintsBrowser); + + onUpdateConstraintsList(); } void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation) @@ -1274,6 +1392,17 @@ void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation) workshop()->selectionActivate()->updateSelectionFilters(); workshop()->selectionActivate()->updateSelectionModes(); workshop()->viewer()->set2dMode(false); + + disconnect(constraintsBrowser(), SIGNAL(editValues()), this, SLOT(onEditValues())); + disconnect(constraintsBrowser(), SIGNAL(deleteCosnstraints()), this, SLOT(onUpdateConstraintsList())); + disconnect(constraintsBrowser(), SIGNAL(deactivate(bool, std::vector)), this, SLOT(onDeactivate(bool, std::vector))); + + workshop()->desktop()->removeDockWidget(myConstraintsBrowser); + std::vector>> anEmpty; + constraintsBrowser()->UpdateTree(anEmpty); + workshop()->removeConstrBrowser(); + + myConstraintsBrowser->deleteLater(); } void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation) @@ -2266,11 +2395,15 @@ bool isIncludeToResult(const ObjectPtr& theObject) //************************************************************************************** std::vector PartSet_SketcherMgr::colorOfObject(const ObjectPtr& theObject, - const FeaturePtr& theFeature, bool isConstruction) const + const FeaturePtr& theFeature, bool isConstruction, bool isSuppressedConstraint) const { PartSet_OverconstraintListener* aOCListener = myModule->overconstraintListener(); std::string aKind = theFeature->getKind(); + // may be Preference Config_PropManager::color("Visualization", "sketch_deactivated_color"); + if (isSuppressedConstraint) + return { 128, 128, 128 }; + if (aOCListener->isConflictingObject(theObject)) { return Config_PropManager::color("Visualization", "sketch_overconstraint_color"); } @@ -2303,7 +2436,11 @@ void PartSet_SketcherMgr::customizeSketchPresentation(const ObjectPtr& theObject aFeature->data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID()); bool isConstruction = anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value(); - std::vector aColor = colorOfObject(theObject, aFeature, isConstruction); + bool isSupressed = false; + if (aFeature->data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())) + isSupressed = !aFeature->data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->value(); + + std::vector aColor = colorOfObject(theObject, aFeature, isConstruction, isSupressed); if (!aColor.empty()) { // The code below causes redisplay again if (ModelAPI_Session::get()->isOperation()) { diff --git a/src/PartSet/PartSet_SketcherMgr.h b/src/PartSet/PartSet_SketcherMgr.h index 14d88a168..7092ed769 100644 --- a/src/PartSet/PartSet_SketcherMgr.h +++ b/src/PartSet/PartSet_SketcherMgr.h @@ -66,6 +66,7 @@ class ModuleBase_Operation; class XGUI_OperationMgr; class XGUI_Workshop; class XGUI_Displayer; +class XGUI_SketchConstraintsBrowser; class PartSet_ExternalPointsMgr; class AIS_InteractiveObject; @@ -387,6 +388,8 @@ public: /// Returns true if current mode of objects creation is by drag mouse bool isDragModeCreation() const; + // Get constraints browser + XGUI_SketchConstraintsBrowser* constraintsBrowser(); public slots: /// Process sketch plane selected event @@ -396,6 +399,10 @@ public slots: /// \param toShow a state of the check box void onShowPoints(bool toShow); + void onEditValues(); + void onUpdateConstraintsList(); + void onDeactivate(bool isNeedDeactivate, std::vector theFeatures); + private slots: /// Toggle show constraints void onShowConstraintsToggle(int theType, bool theState); @@ -485,7 +492,7 @@ private: XGUI_OperationMgr* operationMgr() const; std::vector colorOfObject(const ObjectPtr& theObject, - const FeaturePtr& aFeature, bool isConstruction) const; + const FeaturePtr& aFeature, bool isConstruction, bool isSuppressedConstraint) const; private: PartSet_Module* myModule; @@ -518,6 +525,8 @@ private: bool myNoDragMoving; QPoint myMousePoint; + + QDockWidget* myConstraintsBrowser; }; diff --git a/src/SketchAPI/SketchAPI_Constraint.cpp b/src/SketchAPI/SketchAPI_Constraint.cpp index 9149d2395..fb4787f36 100644 --- a/src/SketchAPI/SketchAPI_Constraint.cpp +++ b/src/SketchAPI/SketchAPI_Constraint.cpp @@ -228,5 +228,8 @@ void SketchAPI_Constraint::dump(ModelHighAPI_Dumper& theDumper) const theDumper << ", " << isSigned->value(); } + bool isActive = aBase->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->value(); + theDumper << ", is_active = " << isActive; + theDumper << ")" << std::endl; } diff --git a/src/SketchAPI/SketchAPI_ConstraintAngle.cpp b/src/SketchAPI/SketchAPI_ConstraintAngle.cpp index edf90a5d3..016bdb9b1 100644 --- a/src/SketchAPI/SketchAPI_ConstraintAngle.cpp +++ b/src/SketchAPI/SketchAPI_ConstraintAngle.cpp @@ -148,5 +148,7 @@ void SketchAPI_ConstraintAngle::dump(ModelHighAPI_Dumper& theDumper) const theDumper << ", " << aValueAttr; std::string aType = angleTypeToString(aBase); - theDumper << ", type = \"" << aType << "\")" << std::endl; + theDumper << ", type = \"" << aType << "\""; + bool isActive = aBase->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->value(); + theDumper << ", is_active = " << isActive << ")" << std::endl; } diff --git a/src/SketchAPI/SketchAPI_Sketch.cpp b/src/SketchAPI/SketchAPI_Sketch.cpp index 34503d972..1e8aa8bf1 100644 --- a/src/SketchAPI/SketchAPI_Sketch.cpp +++ b/src/SketchAPI/SketchAPI_Sketch.cpp @@ -1010,7 +1010,8 @@ std::shared_ptr SketchAPI_Sketch::setAngle( const ModelHighAPI_RefAttr & theLine1, const ModelHighAPI_RefAttr & theLine2, const ModelHighAPI_Double & theValue, - const std::string& theType) + const std::string& theType, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintAngle::ID()); @@ -1028,6 +1029,7 @@ std::shared_ptr SketchAPI_Sketch::setAngle( fillAttribute(theLine1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); fillAttribute(theLine2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); if (aVersion == SketchPlugin_ConstraintAngle::THE_VERSION_1) { std::string aTypeLC = theType; @@ -1049,7 +1051,8 @@ std::shared_ptr SketchAPI_Sketch::setAngle( std::shared_ptr SketchAPI_Sketch::setAngleComplementary( const ModelHighAPI_RefAttr & theLine1, const ModelHighAPI_RefAttr & theLine2, - const ModelHighAPI_Double & theValue) + const ModelHighAPI_Double & theValue, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintAngle::ID()); @@ -1060,6 +1063,7 @@ std::shared_ptr SketchAPI_Sketch::setAngleComplementary( fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID())); fillAttribute(theLine1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); fillAttribute(theLine2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } @@ -1067,7 +1071,8 @@ std::shared_ptr SketchAPI_Sketch::setAngleComplementary( std::shared_ptr SketchAPI_Sketch::setAngleBackward( const ModelHighAPI_RefAttr & theLine1, const ModelHighAPI_RefAttr & theLine2, - const ModelHighAPI_Double & theValue) + const ModelHighAPI_Double & theValue, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintAngle::ID()); @@ -1078,30 +1083,35 @@ std::shared_ptr SketchAPI_Sketch::setAngleBackward( fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID())); fillAttribute(theLine1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); fillAttribute(theLine2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } std::shared_ptr SketchAPI_Sketch::setCoincident( const ModelHighAPI_RefAttr & thePoint1, - const ModelHighAPI_RefAttr & thePoint2) + const ModelHighAPI_RefAttr & thePoint2, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); fillAttribute(thePoint1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); fillAttribute(thePoint2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } std::shared_ptr SketchAPI_Sketch::setCollinear( const ModelHighAPI_RefAttr & theLine1, - const ModelHighAPI_RefAttr & theLine2) + const ModelHighAPI_RefAttr & theLine2, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintCollinear::ID()); fillAttribute(theLine1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); fillAttribute(theLine2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } @@ -1110,7 +1120,8 @@ std::shared_ptr SketchAPI_Sketch::setDistance( const ModelHighAPI_RefAttr & thePoint, const ModelHighAPI_RefAttr & thePointOrLine, const ModelHighAPI_Double & theValue, - bool isSigned) + bool isSigned, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintDistance::ID()); @@ -1118,6 +1129,7 @@ std::shared_ptr SketchAPI_Sketch::setDistance( fillAttribute(thePointOrLine, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B())); fillAttribute(theValue, aFeature->real(SketchPlugin_Constraint::VALUE())); fillAttribute(isSigned, aFeature->boolean(SketchPlugin_ConstraintDistance::SIGNED())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } @@ -1125,23 +1137,26 @@ std::shared_ptr SketchAPI_Sketch::setDistance( std::shared_ptr SketchAPI_Sketch::setSignedDistance( const ModelHighAPI_RefAttr & thePoint, const ModelHighAPI_RefAttr & thePointOrLine, - const ModelHighAPI_Double & theValue) + const ModelHighAPI_Double & theValue, + bool theIsActive) { - return setDistance(thePoint, thePointOrLine, theValue, true); + return setDistance(thePoint, thePointOrLine, theValue, true, theIsActive); } std::shared_ptr SketchAPI_Sketch::setUnsignedDistance( const ModelHighAPI_RefAttr & thePoint, const ModelHighAPI_RefAttr & thePointOrLine, - const ModelHighAPI_Double & theValue) + const ModelHighAPI_Double & theValue, + bool theIsActive) { - return setDistance(thePoint, thePointOrLine, theValue, false); + return setDistance(thePoint, thePointOrLine, theValue, false, theIsActive); } std::shared_ptr SketchAPI_Sketch::setHorizontalDistance( const ModelHighAPI_RefAttr & thePoint1, const ModelHighAPI_RefAttr & thePoint2, - const ModelHighAPI_Double & theValue) + const ModelHighAPI_Double & theValue, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintDistanceHorizontal::ID()); @@ -1149,6 +1164,7 @@ std::shared_ptr SketchAPI_Sketch::setHorizontalDistance( fillAttribute(thePoint2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B())); fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintDistanceAlongDir::DISTANCE_VALUE_ID())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } @@ -1156,7 +1172,8 @@ std::shared_ptr SketchAPI_Sketch::setHorizontalDistance( std::shared_ptr SketchAPI_Sketch::setVerticalDistance( const ModelHighAPI_RefAttr & thePoint1, const ModelHighAPI_RefAttr & thePoint2, - const ModelHighAPI_Double & theValue) + const ModelHighAPI_Double & theValue, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintDistanceVertical::ID()); @@ -1164,18 +1181,21 @@ std::shared_ptr SketchAPI_Sketch::setVerticalDistance( fillAttribute(thePoint2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B())); fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintDistanceAlongDir::DISTANCE_VALUE_ID())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } std::shared_ptr SketchAPI_Sketch::setEqual( const ModelHighAPI_RefAttr & theObject1, - const ModelHighAPI_RefAttr & theObject2) + const ModelHighAPI_RefAttr & theObject2, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintEqual::ID()); fillAttribute(theObject1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); fillAttribute(theObject2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } @@ -1209,103 +1229,121 @@ std::shared_ptr SketchAPI_Sketch::setFilletWithRadius( } std::shared_ptr SketchAPI_Sketch::setFixed( - const ModelHighAPI_RefAttr & theObject) + const ModelHighAPI_RefAttr & theObject, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintRigid::ID()); fillAttribute(theObject, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } std::shared_ptr SketchAPI_Sketch::setHorizontal( - const ModelHighAPI_RefAttr & theLine) + const ModelHighAPI_RefAttr & theLine, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintHorizontal::ID()); fillAttribute(theLine, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } std::shared_ptr SketchAPI_Sketch::setLength( const ModelHighAPI_RefAttr & theLine, - const ModelHighAPI_Double & theValue) + const ModelHighAPI_Double & theValue, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintLength::ID()); fillAttribute(theLine, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); fillAttribute(theValue, aFeature->real(SketchPlugin_Constraint::VALUE())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } std::shared_ptr SketchAPI_Sketch::setMiddlePoint( const ModelHighAPI_RefAttr & thePoint, - const ModelHighAPI_RefAttr & theLine) + const ModelHighAPI_RefAttr & theLine, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintMiddle::ID()); fillAttribute(thePoint, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); fillAttribute(theLine, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } std::shared_ptr SketchAPI_Sketch::setParallel( const ModelHighAPI_RefAttr & theLine1, - const ModelHighAPI_RefAttr & theLine2) + const ModelHighAPI_RefAttr & theLine2, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintParallel::ID()); fillAttribute(theLine1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); fillAttribute(theLine2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } std::shared_ptr SketchAPI_Sketch::setPerpendicular( const ModelHighAPI_RefAttr & theLine1, - const ModelHighAPI_RefAttr & theLine2) + const ModelHighAPI_RefAttr & theLine2, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintPerpendicular::ID()); fillAttribute(theLine1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); fillAttribute(theLine2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } std::shared_ptr SketchAPI_Sketch::setRadius( const ModelHighAPI_RefAttr & theCircleOrArc, - const ModelHighAPI_Double & theValue) + const ModelHighAPI_Double & theValue, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintRadius::ID()); fillAttribute(theCircleOrArc, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); fillAttribute(theValue, aFeature->real(SketchPlugin_Constraint::VALUE())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } std::shared_ptr SketchAPI_Sketch::setTangent( const ModelHighAPI_RefAttr & theLine, - const ModelHighAPI_RefAttr & theCircle) + const ModelHighAPI_RefAttr & theCircle, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintTangent::ID()); fillAttribute(theLine, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); fillAttribute(theCircle, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } std::shared_ptr SketchAPI_Sketch::setVertical( - const ModelHighAPI_RefAttr & theLine) + const ModelHighAPI_RefAttr & theLine, + bool theIsActive) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintVertical::ID()); fillAttribute(theLine, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); + fillAttribute(theIsActive, aFeature->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())); aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } diff --git a/src/SketchAPI/SketchAPI_Sketch.h b/src/SketchAPI/SketchAPI_Sketch.h index f9c8fdb79..0e8ffce49 100644 --- a/src/SketchAPI/SketchAPI_Sketch.h +++ b/src/SketchAPI/SketchAPI_Sketch.h @@ -420,33 +420,38 @@ public: const ModelHighAPI_RefAttr & theLine1, const ModelHighAPI_RefAttr & theLine2, const ModelHighAPI_Double & theValue, - const std::string& type = std::string()); + const std::string& type = std::string(), + bool is_active = true); /// Set complementary angle SKETCHAPI_EXPORT std::shared_ptr setAngleComplementary( const ModelHighAPI_RefAttr & theLine1, const ModelHighAPI_RefAttr & theLine2, - const ModelHighAPI_Double & theValue); + const ModelHighAPI_Double & theValue, + bool is_active = true); /// Set backward angle (= 360 - angle) SKETCHAPI_EXPORT std::shared_ptr setAngleBackward( const ModelHighAPI_RefAttr & theLine1, const ModelHighAPI_RefAttr & theLine2, - const ModelHighAPI_Double & theValue); + const ModelHighAPI_Double & theValue, + bool is_active = true); /// Set coincident SKETCHAPI_EXPORT std::shared_ptr setCoincident( const ModelHighAPI_RefAttr & thePoint1, - const ModelHighAPI_RefAttr & thePoint2); + const ModelHighAPI_RefAttr & thePoint2, + bool is_active = true); /// Set collinear SKETCHAPI_EXPORT std::shared_ptr setCollinear( const ModelHighAPI_RefAttr & theLine1, - const ModelHighAPI_RefAttr & theLine2); + const ModelHighAPI_RefAttr & theLine2, + bool is_active = true); /// Set distance SKETCHAPI_EXPORT @@ -454,41 +459,47 @@ public: const ModelHighAPI_RefAttr & thePoint, const ModelHighAPI_RefAttr & thePointOrLine, const ModelHighAPI_Double & theValue, - bool isSigned = false); + bool isSigned = false, + bool is_active = true); /// Set signed distance SKETCHAPI_EXPORT std::shared_ptr setSignedDistance( const ModelHighAPI_RefAttr & thePoint, const ModelHighAPI_RefAttr & thePointOrLine, - const ModelHighAPI_Double & theValue); + const ModelHighAPI_Double & theValue, + bool is_active = true); /// Set unsigned distance SKETCHAPI_EXPORT std::shared_ptr setUnsignedDistance( const ModelHighAPI_RefAttr & thePoint, const ModelHighAPI_RefAttr & thePointOrLine, - const ModelHighAPI_Double & theValue); + const ModelHighAPI_Double & theValue, + bool is_active = true); /// Set horizontal distance SKETCHAPI_EXPORT std::shared_ptr setHorizontalDistance( const ModelHighAPI_RefAttr & thePoint1, const ModelHighAPI_RefAttr & thePoint2, - const ModelHighAPI_Double & theValue); + const ModelHighAPI_Double & theValue, + bool is_active = true); /// Set vertical distance SKETCHAPI_EXPORT std::shared_ptr setVerticalDistance( const ModelHighAPI_RefAttr & thePoint1, const ModelHighAPI_RefAttr & thePoint2, - const ModelHighAPI_Double & theValue); + const ModelHighAPI_Double & theValue, + bool is_active = true); /// Set equal SKETCHAPI_EXPORT std::shared_ptr setEqual( const ModelHighAPI_RefAttr & theObject1, - const ModelHighAPI_RefAttr & theObject2); + const ModelHighAPI_RefAttr & theObject2, + bool is_active = true); /// Set fillet SKETCHAPI_EXPORT @@ -504,53 +515,62 @@ public: /// Set fixed SKETCHAPI_EXPORT std::shared_ptr setFixed( - const ModelHighAPI_RefAttr & theObject); + const ModelHighAPI_RefAttr & theObject, + bool is_active = true); /// Set horizontal SKETCHAPI_EXPORT std::shared_ptr setHorizontal( - const ModelHighAPI_RefAttr & theLine); + const ModelHighAPI_RefAttr & theLine, + bool is_active = true); /// Set length SKETCHAPI_EXPORT std::shared_ptr setLength( const ModelHighAPI_RefAttr & theLine, - const ModelHighAPI_Double & theValue); + const ModelHighAPI_Double & theValue, + bool is_active = true); /// Set middle SKETCHAPI_EXPORT std::shared_ptr setMiddlePoint( const ModelHighAPI_RefAttr & thePoint, - const ModelHighAPI_RefAttr & theLine); + const ModelHighAPI_RefAttr & theLine, + bool is_active = true); /// Set parallel SKETCHAPI_EXPORT std::shared_ptr setParallel( const ModelHighAPI_RefAttr & theLine1, - const ModelHighAPI_RefAttr & theLine2); + const ModelHighAPI_RefAttr & theLine2, + bool is_active = true); /// Set perpendicular SKETCHAPI_EXPORT std::shared_ptr setPerpendicular( const ModelHighAPI_RefAttr & theLine1, - const ModelHighAPI_RefAttr & theLine2); + const ModelHighAPI_RefAttr & theLine2, + bool is_active = true); /// Set radius SKETCHAPI_EXPORT std::shared_ptr setRadius( const ModelHighAPI_RefAttr & theCircleOrArc, - const ModelHighAPI_Double & theValue); + const ModelHighAPI_Double & theValue, + bool is_active = true); /// Set tangent SKETCHAPI_EXPORT std::shared_ptr setTangent( const ModelHighAPI_RefAttr & theLine, - const ModelHighAPI_RefAttr & theCircle); + const ModelHighAPI_RefAttr & theCircle, + bool is_active = true); /// Set vertical SKETCHAPI_EXPORT std::shared_ptr setVertical( - const ModelHighAPI_RefAttr & theLine); + const ModelHighAPI_RefAttr & theLine, + bool is_active = true); /// Set constraint value SKETCHAPI_EXPORT diff --git a/src/SketchPlugin/SketchPlugin_Constraint.h b/src/SketchPlugin/SketchPlugin_Constraint.h index 7b5723875..8a2662257 100644 --- a/src/SketchPlugin/SketchPlugin_Constraint.h +++ b/src/SketchPlugin/SketchPlugin_Constraint.h @@ -46,6 +46,12 @@ class SketchPlugin_Constraint : public SketchPlugin_Feature static const std::string MY_FLYOUT_VALUE_PNT("ConstraintFlyoutValuePnt"); return MY_FLYOUT_VALUE_PNT; } + /// State of constraint - Active - true, Suppressed - false + inline static const std::string& CONSTRAINT_ACTIVE() + { + static const std::string MY_STATE("ConstraintState"); + return MY_STATE; + } /// First entity for the constraint inline static const std::string& ENTITY_A() { diff --git a/src/SketchPlugin/SketchPlugin_ConstraintAngle.cpp b/src/SketchPlugin/SketchPlugin_ConstraintAngle.cpp index cdb3309ec..4b8f8f85f 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintAngle.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintAngle.cpp @@ -79,6 +79,10 @@ void SketchPlugin_ConstraintAngle::initAttributes() data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId()); + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); + data()->addAttribute(ANGLE_VALUE_ID(), ModelAPI_AttributeDouble::typeId()); data()->addAttribute(TYPE_ID(), ModelAPI_AttributeInteger::typeId()); diff --git a/src/SketchPlugin/SketchPlugin_ConstraintCoincidence.cpp b/src/SketchPlugin/SketchPlugin_ConstraintCoincidence.cpp index 795eee98d..e1e9fd87a 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintCoincidence.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintCoincidence.cpp @@ -40,6 +40,10 @@ void SketchPlugin_ConstraintCoincidence::initAttributes() { data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId()); + + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); } void SketchPlugin_ConstraintCoincidence::execute() diff --git a/src/SketchPlugin/SketchPlugin_ConstraintCollinear.cpp b/src/SketchPlugin/SketchPlugin_ConstraintCollinear.cpp index e689458e8..75dd96b2c 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintCollinear.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintCollinear.cpp @@ -29,6 +29,10 @@ void SketchPlugin_ConstraintCollinear::initAttributes() { data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId()); + + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); } void SketchPlugin_ConstraintCollinear::execute() diff --git a/src/SketchPlugin/SketchPlugin_ConstraintDistance.cpp b/src/SketchPlugin/SketchPlugin_ConstraintDistance.cpp index 2f2c59b0a..3e8cf3b84 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintDistance.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintDistance.cpp @@ -60,6 +60,10 @@ void SketchPlugin_ConstraintDistance::initAttributes() data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(SIGNED(), ModelAPI_AttributeBoolean::typeId()); + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); + data()->addAttribute(SketchPlugin_ConstraintDistance::LOCATION_TYPE_ID(), ModelAPI_AttributeInteger::typeId()); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), LOCATION_TYPE_ID()); diff --git a/src/SketchPlugin/SketchPlugin_ConstraintDistanceAlongDir.cpp b/src/SketchPlugin/SketchPlugin_ConstraintDistanceAlongDir.cpp index e15b4402c..ff5204313 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintDistanceAlongDir.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintDistanceAlongDir.cpp @@ -56,6 +56,10 @@ void SketchPlugin_ConstraintDistanceAlongDir::initAttributes() data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId()); + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); + data()->addAttribute(LOCATION_TYPE_ID(), ModelAPI_AttributeInteger::typeId()); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), LOCATION_TYPE_ID()); diff --git a/src/SketchPlugin/SketchPlugin_ConstraintEqual.cpp b/src/SketchPlugin/SketchPlugin_ConstraintEqual.cpp index e3637a73e..9dceebd31 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintEqual.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintEqual.cpp @@ -38,6 +38,10 @@ void SketchPlugin_ConstraintEqual::initAttributes() { data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId()); + + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); } void SketchPlugin_ConstraintEqual::execute() diff --git a/src/SketchPlugin/SketchPlugin_ConstraintHorizontal.cpp b/src/SketchPlugin/SketchPlugin_ConstraintHorizontal.cpp index dae341a66..e8d988e33 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintHorizontal.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintHorizontal.cpp @@ -38,6 +38,10 @@ SketchPlugin_ConstraintHorizontal::SketchPlugin_ConstraintHorizontal() void SketchPlugin_ConstraintHorizontal::initAttributes() { data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); + + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); } void SketchPlugin_ConstraintHorizontal::execute() diff --git a/src/SketchPlugin/SketchPlugin_ConstraintLength.cpp b/src/SketchPlugin/SketchPlugin_ConstraintLength.cpp index cfe1da52f..6b706bcba 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintLength.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintLength.cpp @@ -57,6 +57,10 @@ void SketchPlugin_ConstraintLength::initAttributes() data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); + data()->addAttribute(SketchPlugin_ConstraintLength::LOCATION_TYPE_ID(), ModelAPI_AttributeInteger::typeId()); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), LOCATION_TYPE_ID()); diff --git a/src/SketchPlugin/SketchPlugin_ConstraintMiddle.cpp b/src/SketchPlugin/SketchPlugin_ConstraintMiddle.cpp index ad9ab3755..209d325a8 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintMiddle.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintMiddle.cpp @@ -29,6 +29,10 @@ void SketchPlugin_ConstraintMiddle::initAttributes() { data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId()); + + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); } void SketchPlugin_ConstraintMiddle::execute() diff --git a/src/SketchPlugin/SketchPlugin_ConstraintMirror.cpp b/src/SketchPlugin/SketchPlugin_ConstraintMirror.cpp index fbbb8044a..07d6c887d 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintMirror.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintMirror.cpp @@ -50,6 +50,10 @@ void SketchPlugin_ConstraintMirror::initAttributes() registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_B()); ModelAPI_Session::get()->validators()-> registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_C()); + + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); } void SketchPlugin_ConstraintMirror::execute() diff --git a/src/SketchPlugin/SketchPlugin_ConstraintParallel.cpp b/src/SketchPlugin/SketchPlugin_ConstraintParallel.cpp index 2c5977867..b4e588302 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintParallel.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintParallel.cpp @@ -44,6 +44,10 @@ void SketchPlugin_ConstraintParallel::initAttributes() { data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId()); + + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); } void SketchPlugin_ConstraintParallel::execute() diff --git a/src/SketchPlugin/SketchPlugin_ConstraintPerpendicular.cpp b/src/SketchPlugin/SketchPlugin_ConstraintPerpendicular.cpp index 108ee2a16..6b269adea 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintPerpendicular.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintPerpendicular.cpp @@ -43,6 +43,10 @@ void SketchPlugin_ConstraintPerpendicular::initAttributes() { data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId()); + + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); } void SketchPlugin_ConstraintPerpendicular::execute() diff --git a/src/SketchPlugin/SketchPlugin_ConstraintRadius.cpp b/src/SketchPlugin/SketchPlugin_ConstraintRadius.cpp index 6dc1bd1df..5cb56ca3d 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintRadius.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintRadius.cpp @@ -57,6 +57,10 @@ void SketchPlugin_ConstraintRadius::initAttributes() data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId()); + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); + data()->addAttribute(SketchPlugin_ConstraintRadius::LOCATION_TYPE_ID(), ModelAPI_AttributeInteger::typeId()); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), LOCATION_TYPE_ID()); diff --git a/src/SketchPlugin/SketchPlugin_ConstraintRigid.cpp b/src/SketchPlugin/SketchPlugin_ConstraintRigid.cpp index e70c77b37..1c7b9de44 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintRigid.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintRigid.cpp @@ -36,6 +36,10 @@ SketchPlugin_ConstraintRigid::SketchPlugin_ConstraintRigid() void SketchPlugin_ConstraintRigid::initAttributes() { data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); + + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); } void SketchPlugin_ConstraintRigid::execute() diff --git a/src/SketchPlugin/SketchPlugin_ConstraintTangent.cpp b/src/SketchPlugin/SketchPlugin_ConstraintTangent.cpp index 224ac900a..0124690f4 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintTangent.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintTangent.cpp @@ -38,6 +38,10 @@ void SketchPlugin_ConstraintTangent::initAttributes() { data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId()); + + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); } void SketchPlugin_ConstraintTangent::execute() diff --git a/src/SketchPlugin/SketchPlugin_ConstraintVertical.cpp b/src/SketchPlugin/SketchPlugin_ConstraintVertical.cpp index e921e8404..f76363e68 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintVertical.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintVertical.cpp @@ -37,6 +37,10 @@ SketchPlugin_ConstraintVertical::SketchPlugin_ConstraintVertical() void SketchPlugin_ConstraintVertical::initAttributes() { data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); + + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); } void SketchPlugin_ConstraintVertical::execute() diff --git a/src/SketchPlugin/SketchPlugin_MultiRotation.cpp b/src/SketchPlugin/SketchPlugin_MultiRotation.cpp index 4e862e119..3bcec646f 100644 --- a/src/SketchPlugin/SketchPlugin_MultiRotation.cpp +++ b/src/SketchPlugin/SketchPlugin_MultiRotation.cpp @@ -64,6 +64,10 @@ void SketchPlugin_MultiRotation::initAttributes() data()->addAttribute(ROTATION_LIST_ID(), ModelAPI_AttributeRefList::typeId()); data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId()); + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); + ModelAPI_Session::get()->validators()-> registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_A()); ModelAPI_Session::get()->validators()-> diff --git a/src/SketchPlugin/SketchPlugin_MultiTranslation.cpp b/src/SketchPlugin/SketchPlugin_MultiTranslation.cpp index 8a543fcaf..aad921266 100644 --- a/src/SketchPlugin/SketchPlugin_MultiTranslation.cpp +++ b/src/SketchPlugin/SketchPlugin_MultiTranslation.cpp @@ -48,6 +48,10 @@ void SketchPlugin_MultiTranslation::initAttributes() data()->addAttribute(START_POINT_ID(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(END_POINT_ID(), ModelAPI_AttributeRefAttr::typeId()); + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); + data()->addAttribute(NUMBER_OF_OBJECTS_ID(), ModelAPI_AttributeInteger::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefList::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefList::typeId()); diff --git a/src/SketchPlugin/SketchPlugin_Offset.cpp b/src/SketchPlugin/SketchPlugin_Offset.cpp index aabe5babf..90101c95d 100644 --- a/src/SketchPlugin/SketchPlugin_Offset.cpp +++ b/src/SketchPlugin/SketchPlugin_Offset.cpp @@ -79,6 +79,10 @@ void SketchPlugin_Offset::initAttributes() data()->addAttribute(VALUE_ID(), ModelAPI_AttributeDouble::typeId()); data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId()); + // By default set true; + data()->addAttribute(SketchPlugin_Constraint::CONSTRAINT_ACTIVE(), ModelAPI_AttributeBoolean::typeId()); + data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->setValue(true); + // Always initialize approximation to false by default for backward compatibility AttributeBooleanPtr approxAttr = std::dynamic_pointer_cast( data()->addAttribute(APPROX_ID(), ModelAPI_AttributeBoolean::typeId())); diff --git a/src/SketchPlugin/doc/SketchPlugin.rst b/src/SketchPlugin/doc/SketchPlugin.rst index d1c47eb22..e98c502a9 100644 --- a/src/SketchPlugin/doc/SketchPlugin.rst +++ b/src/SketchPlugin/doc/SketchPlugin.rst @@ -53,6 +53,15 @@ After the plane for sketch is selected, the following property panel will be ope - **Change sketch plane** button - allows to change working plane of the current sketch. - **Show remaining DoFs** button - highlights all sketch edges which are not fully constrained. +Also will be opened window with created constraints: + +.. figure:: images/ConstraintsBrowser.png + :align: center + + Sketch constraints browser + +**See** :ref:`sketchConstraintsBrowsers` + Now it is possible to: - create :ref:`sketch objects ` diff --git a/src/SketchPlugin/doc/images/ConstraintsBrowser.png b/src/SketchPlugin/doc/images/ConstraintsBrowser.png new file mode 100644 index 0000000000000000000000000000000000000000..47f40ab971e342329ab6859cafba232d411a90da GIT binary patch literal 39344 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 literal 0 HcmV?d00001 diff --git a/src/SketchPlugin/doc/images/constraints_suppressed.png b/src/SketchPlugin/doc/images/constraints_suppressed.png new file mode 100644 index 0000000000000000000000000000000000000000..66ea1de971ca6988bf2bab3d3043bbdb320e1982 GIT binary patch literal 6572 zcma)Bc{r49+aF7fr7Xoz#xjraL}ROm8Cwh@jEYBUW-KK=WSy}_m>627#*~mHl;SB{ zmKla@F&ShjJ3~wpW8aeO-|ao#<2$}Tzd!C{=Dv>WzRvUfoxkf`uIs@?d#l4D$3;LO z(Bbpe77ic~9|L%ZLI;5nZ5R{{{O|=iSfN10ozQ9EMerXpv>6Cgnkc$`?EvsD9B6$t z2m}&q+JE?30{*=L0v$6uZ(;U#xa<5V_7QG9N^$8l*M{PpcOpYd>y^bNDV6q6F76@d zz^w+$++oIofvj^Q~I_bcg8-)jXDqO;fDweT%V5Z*tqj4co`xCRFPrxgTT z>aWxs8rHq$6cF-JEJ2N%)97m&KaR05o+C~OF(kVuAw4&>y+gE5!NBqbmB42^1mQ;O z&p{{e+6tv(aYFyC?86P)yESgKEmxD#pqc-p?Xx%Z`qpD->UOS^1g}lZBK@L+X;_Gl9Tha zkLhw}-krssiczqBpbB;@O|bqQlA!Ore z^KJVYH~(l%gMd#>{)!~PcohbOR0s0W!1qz>nc;u%Sjm1ive}=?H4eD!&UECA$=;8H zfaeF7j_{jV*;gQB^ADSAN(6VGg^LZBd$SJ2QhL4d+OF6HoDwfb5d*F8DW-}F%AX{( zf*y^qVKPDn4%ah|T=|pBZw8+4;pE6Aolf;9b-l+8mZX}k$LlUx517*gX8TqeB6v@d zIiKHT^dwivYhl@^g=tko1N>esAJN4}_%#Jb3pd>^yZi8qRhI{|4#*vlKXmd9L~T3= zJ0ij`?UqdHrJua(?`OC#hYZMxw9O88NSiW7#N7RUCX$NYX+El!0V=1DazDCtZu(Xn zWW&aD6pMVFKX!kR0iTg1bf1QcZJtI3;UgDYJ0iRmqnLfGH!h4w;PS zW08cG`m6M+3#x?HhR;D_!3AroQ(Br)HYdl4yFfnQK&?Z5H?Z|NxLdd5{`MuUnW(5 zy5s2@FIC8bxc6ROL!Bfh+TN|3`)P6_iWavVZwUUb_A42^fHFcaya`B#FEB_L_Q9^% z%hBJltMLO}#`&#{ug)O78q4@(gtT}RsVTGhNDPDOC^<~22;Ye*D@_nM9#%6t6L zcMOgm_eY7*Up|KD`{?oBrKs`T@hJZr)rdbUy+6Z?i$$s<#+}U6=G>!EVky0A;)m9V z1tgmK9I;3k`RXOJ<3e}i9TNL~bDdM#Q`s!rk<|CJ){`=EiJ$KIfG6wy5!#All@6K5 zdDoYYdXf#(t;r)Zx1k>cQq0!N507MMho(d0Y)_6~mj*cHB0DYy1B>1-Wjdj{ovwik zj}nw6XB)4QeX?`n41sWWauTB7{!67WBhz59IZ5aD((W+d=ABi(&86LBPVdI9y%BPG zzKj_aU;y{en$kX3zcKH_?20Z)a*$O+`wKc4BU(=Un9>%+2~}%r>!B!SuX{O!-!Pb< zi*%^ADvC1phK^1$Fv6(jX_~*KxjZp5Q1&UwvIvu zMHDEYmDeBbtL#zR?k5H?tA8?mpMuS-+DN!_*9|U?h#KCWm1UK8WRP4!E3ehJqNBJg7^BO

+iCEr)$Hd7U7Dgk1?!|kMQ?8ydXl$Dkd~GH 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 literal 0 HcmV?d00001 diff --git a/src/SketchPlugin/doc/images/constraints_suppressed_moved.png b/src/SketchPlugin/doc/images/constraints_suppressed_moved.png new file mode 100644 index 0000000000000000000000000000000000000000..1809edee54a12e9974bc7fc6f4997744352af3b3 GIT binary patch literal 7422 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 Edit... -> Input new values. After press Apply button; +2. In empty place Right click -> Edit... - will be modified all constraints. +3. Double click by constrints value - modify only selected constraint value + +Delete +================ + +Select constraints for delete -> Rightg Click -> Delete. All selected constraints will be deleted + +Deactivate +================ + +.. figure:: images/constraints_suppressed.png + :align: center + + Suppresed constraints + +.. figure:: images/constraints_suppressed_moved.png + :align: center + + Suppresed constraints moved + +This allows you to deactivate and activate already applied constraints. Suppressed constraint allows you keep constraint and check another arrangement of the existing geometry. diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp index deefed48c..eee60125a 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp @@ -66,7 +66,8 @@ void PlaneGCSSolver_Storage::addConstraint( { SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraint); - theSolverConstraint->setId(++myConstraintLastID); + if (theSolverConstraint->id() == 0) + theSolverConstraint->setId(++myConstraintLastID); constraintsToSolver(theSolverConstraint, mySketchSolver); } @@ -515,6 +516,62 @@ bool PlaneGCSSolver_Storage::removeConstraint(ConstraintPtr theConstraint) return true; } +bool PlaneGCSSolver_Storage::changeActiveStatus(ConstraintPtr theConstraint, bool theNewState) +{ + if (theNewState) + { + // activate + auto aPair = myDeactivatedConstraintMap.find(theConstraint); + if (aPair == myDeactivatedConstraintMap.end()) + return false; + + addConstraint(theConstraint, aPair->second); + myDeactivatedConstraintMap.erase(theConstraint); + } + else + { + // suppress + auto aPair = myConstraintMap.find(theConstraint); + if (aPair == myConstraintMap.end()) + return false; + myDeactivatedConstraintMap.insert((*aPair)); + + ConstraintWrapperPtr aCW = aPair->second; + ConstraintID anID = aCW->id(); + mySketchSolver->removeConstraint(anID); + myConstraintMap.erase(theConstraint); + } + myNeedToResolve = true; + notify(theConstraint); + + return true; +} + +bool PlaneGCSSolver_Storage::UpdateDeactivateList() +{ + std::list toRemove; + for (auto& aDeactMap : myDeactivatedConstraintMap) + { + if (!aDeactMap.first->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())) + { + toRemove.push_back(aDeactMap.first); + } + } + for (auto& aRemove : toRemove) + { + myDeactivatedConstraintMap.erase(aRemove); + } + + for (auto& aDeactMap : myDeactivatedConstraintMap) + { + if (aDeactMap.first->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->value()) + { + changeActiveStatus(aDeactMap.first, true); + } + } + return true; +} + void PlaneGCSSolver_Storage::removeInvalidEntities() { PlaneGCSSolver_EntityDestroyer aDestroyer; diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h index 6623376a5..81e4d4b00 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h @@ -70,6 +70,11 @@ public: /// \return \c true if the constraint and all its parameters are removed successfully virtual bool removeConstraint(ConstraintPtr theConstraint); + // Change status of constraints. + virtual bool changeActiveStatus(ConstraintPtr theConstraint, bool theNewState); + + virtual bool UpdateDeactivateList(); + /// \brief Verify, the sketch contains degenerated geometry /// after resolving the set of constraints /// \return STATUS_OK if the geometry is valid, STATUS_DEGENERATED otherwise. diff --git a/src/SketchSolver/SketchSolver_ConstraintDistance.cpp b/src/SketchSolver/SketchSolver_ConstraintDistance.cpp index 590681a86..06b248c9d 100644 --- a/src/SketchSolver/SketchSolver_ConstraintDistance.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintDistance.cpp @@ -215,6 +215,10 @@ void SketchSolver_ConstraintDistance::adjustConstraint() void SketchSolver_ConstraintDistance::update() { ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint); + + if (!aConstraint) + return; + myPrevValue = aConstraint->value(); bool isDistanceAlognDir = diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index 232c8525e..558101c19 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -231,6 +231,21 @@ bool SketchSolver_Group::movePoint(AttributePtr theAttribute, // ============================================================================ bool SketchSolver_Group::resolveConstraints() { + auto aNb = mySketch->numberOfSubs(); + std::list aList; + for (int i = 0; i < aNb; ++i) + if (mySketch->subFeature(i)->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE()) && !mySketch->subFeature(i)->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->value()) + aList.push_back(std::dynamic_pointer_cast(mySketch->subFeature(i))); + + while (aList.size() > 0) + { + auto aConstr = aList.front(); + aList.pop_front(); + myStorage->changeActiveStatus(aConstr, false); + } + + myStorage->UpdateDeactivateList(); + static const int MAX_STACK_SIZE = 5; // check the "Multi" constraints do not drop sketch into infinite loop if (myMultiConstraintUpdateStack > MAX_STACK_SIZE) { diff --git a/src/SketchSolver/SketchSolver_Storage.h b/src/SketchSolver/SketchSolver_Storage.h index 281913257..eef815aec 100644 --- a/src/SketchSolver/SketchSolver_Storage.h +++ b/src/SketchSolver/SketchSolver_Storage.h @@ -103,6 +103,11 @@ public: /// \brief Removes constraint from the storage /// \return \c true if the constraint and all its parameters are removed successfully virtual bool removeConstraint(ConstraintPtr theConstraint) = 0; + + virtual bool changeActiveStatus(ConstraintPtr theConstraint, bool theNewState) = 0; + + virtual bool UpdateDeactivateList() = 0; + /// \brief Removes feature from the storage void removeFeature(FeaturePtr theFeature); /// \brief Removes attribute from the storage @@ -177,6 +182,7 @@ protected: std::map myAttributeMap; UpdaterPtr myUpdaters; + std::map myDeactivatedConstraintMap; }; typedef std::shared_ptr StoragePtr; diff --git a/src/SketcherPrs/CMakeLists.txt b/src/SketcherPrs/CMakeLists.txt index 5315b9c54..c0328f64b 100644 --- a/src/SketcherPrs/CMakeLists.txt +++ b/src/SketcherPrs/CMakeLists.txt @@ -94,14 +94,23 @@ ENDIF() SET(PROJECT_PICTURES icons/collinear.png + icons/collinear_deactivate.png icons/parallel.png + icons/parallel_deactivate.png icons/perpendicular.png + icons/perpendicular_deactivate.png icons/anchor.png + icons/anchor_deactivate.png icons/horisontal.png + icons/horisontal_deactivate.png icons/vertical.png + icons/vertical_deactivate.png icons/equal.png + icons/equal_deactivate.png icons/tangent.png + icons/tangent_deactivate.png icons/middlepoint.png + icons/middlepoint_deactivate.png icons/mirror.png icons/rotate.png icons/translate.png diff --git a/src/SketcherPrs/SketcherPrs_Angle.cpp b/src/SketcherPrs/SketcherPrs_Angle.cpp index 88d57dd1a..3b0f2ecef 100644 --- a/src/SketcherPrs/SketcherPrs_Angle.cpp +++ b/src/SketcherPrs/SketcherPrs_Angle.cpp @@ -48,6 +48,7 @@ /// \param theDimAspect an aspect to be changed /// \param theDimValue an arrow value /// \param theTextSize an arrow value +/// \param theIsActivated state of constraint extern void updateArrows(Handle(Prs3d_DimensionAspect) theDimAspect, double theDimValue, double theTextSize, SketcherPrs_Tools::LocationType theLocationType); @@ -247,7 +248,7 @@ void SketcherPrs_Angle::Compute(const Handle(PrsMgr_PresentationManager3d)& theP SetFlyout(aDist); // Update text visualization: parameter value or parameter text - myStyleListener->updateDimensions(this, myValue); + myStyleListener->updateDimensions(this, myValue, !aData->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->value()); double aTextSize = 0.0; GetValueString(aTextSize); diff --git a/src/SketcherPrs/SketcherPrs_Collinear.h b/src/SketcherPrs/SketcherPrs_Collinear.h index 8cd9a8f34..4e55f83b7 100644 --- a/src/SketcherPrs/SketcherPrs_Collinear.h +++ b/src/SketcherPrs/SketcherPrs_Collinear.h @@ -49,7 +49,7 @@ public: const std::shared_ptr& thePlane); protected: - virtual const char* iconName() const { return "collinear.png"; } + virtual const char* iconName(bool isActiveIcon = true) const { return isActiveIcon ? "collinear.png" : "collinear_deactivate.png"; } virtual void drawLines(const Handle(Prs3d_Presentation)& thePrs, Quantity_Color theColor) const; diff --git a/src/SketcherPrs/SketcherPrs_DimensionStyle.cpp b/src/SketcherPrs/SketcherPrs_DimensionStyle.cpp index 6679e7885..775217b4b 100644 --- a/src/SketcherPrs/SketcherPrs_DimensionStyle.cpp +++ b/src/SketcherPrs/SketcherPrs_DimensionStyle.cpp @@ -64,18 +64,18 @@ SketcherPrs_DimensionStyle::~SketcherPrs_DimensionStyle() } void SketcherPrs_DimensionStyle::updateDimensions(PrsDim_Dimension* theDimension, - const SketcherPrs_DimensionStyle::DimensionValue& theDimensionValue) + const SketcherPrs_DimensionStyle::DimensionValue& theDimensionValue, bool theIsSuppress) { if (!theDimension) return; updateDimensions(theDimension, theDimensionValue.myHasParameters, - theDimensionValue.myTextValue, theDimensionValue.myDoubleValue); + theDimensionValue.myTextValue, theDimensionValue.myDoubleValue, theIsSuppress); } void SketcherPrs_DimensionStyle::updateDimensions(PrsDim_Dimension* theDimension, const bool theHasParameters, const std::string& theTextValue, - const double theDoubleValue) + const double theDoubleValue, bool theIsSuppress) { if (!theDimension) return; @@ -90,13 +90,31 @@ void SketcherPrs_DimensionStyle::updateDimensions(PrsDim_Dimension* theDimension #endif TCollection_ExtendedString aCustomValue; - if (theHasParameters) { - //bool isParameterTextStyle = myStyle == SketcherPrs_ParameterStyleMessage::ParameterText; - bool isParameterTextStyle = - SketcherPrs_Tools::parameterStyle() == SketcherPrs_Tools::ParameterText; - - if (isParameterTextStyle) - aCustomValue = theTextValue.c_str(); + if (theIsSuppress) + { + // for suppressed constraints not need show value + aCustomValue = TCollection_ExtendedString(MyEmptySymbol); + } + else + { + if (theHasParameters) { + //bool isParameterTextStyle = myStyle == SketcherPrs_ParameterStyleMessage::ParameterText; + bool isParameterTextStyle = + SketcherPrs_Tools::parameterStyle() == SketcherPrs_Tools::ParameterText; + + if (isParameterTextStyle) + aCustomValue = theTextValue.c_str(); + else { + // format value string using "sprintf" + TCollection_AsciiString aFormatStr = + theDimension->Attributes()->DimensionAspect()->ValueStringFormat(); + char aFmtBuffer[256]; + sprintf(aFmtBuffer, aFormatStr.ToCString(), theDoubleValue); + aCustomValue = TCollection_ExtendedString(aFmtBuffer); + + aCustomValue.Insert(1, MySigmaSymbol); + } + } else { // format value string using "sprintf" TCollection_AsciiString aFormatStr = @@ -104,18 +122,8 @@ void SketcherPrs_DimensionStyle::updateDimensions(PrsDim_Dimension* theDimension char aFmtBuffer[256]; sprintf (aFmtBuffer, aFormatStr.ToCString(), theDoubleValue); aCustomValue = TCollection_ExtendedString (aFmtBuffer); - - aCustomValue.Insert (1, MySigmaSymbol); } } - else { - // format value string using "sprintf" - TCollection_AsciiString aFormatStr = - theDimension->Attributes()->DimensionAspect()->ValueStringFormat(); - char aFmtBuffer[256]; - sprintf (aFmtBuffer, aFormatStr.ToCString(), theDoubleValue); - aCustomValue = TCollection_ExtendedString (aFmtBuffer); - } #ifdef COMPILATION_CORRECTION theDimension->SetCustomValue(theDoubleValue); #else diff --git a/src/SketcherPrs/SketcherPrs_DimensionStyle.h b/src/SketcherPrs/SketcherPrs_DimensionStyle.h index 32e459021..30a8439f8 100644 --- a/src/SketcherPrs/SketcherPrs_DimensionStyle.h +++ b/src/SketcherPrs/SketcherPrs_DimensionStyle.h @@ -64,7 +64,7 @@ public: /// \param theDimension a modified dimension /// \param theDimensionValue container filled by the model double attribute Standard_EXPORT void updateDimensions(PrsDim_Dimension* theDimension, - const DimensionValue& theDimensionValue); + const DimensionValue& theDimensionValue, bool theIsSuppress/* = false*/); private: /// Visualizes the dimension text or dimension value depending on the has parameters state @@ -72,10 +72,11 @@ private: /// \param theHasParameters if true, the text is shown, else digit /// \param theTextValue a dimension text value /// \param theDoubleValue a dimension digit value + /// \param theIsSuppress a state of constraint (active or not) void updateDimensions(PrsDim_Dimension* theDimension, const bool theHasParameters, const std::string& theTextValue, - const double theDoubleValue); + const double theDoubleValue, bool theIsSuppress/* = false*/); }; #endif \ No newline at end of file diff --git a/src/SketcherPrs/SketcherPrs_Equal.h b/src/SketcherPrs/SketcherPrs_Equal.h index bb1983b9a..867a6d100 100644 --- a/src/SketcherPrs/SketcherPrs_Equal.h +++ b/src/SketcherPrs/SketcherPrs_Equal.h @@ -48,7 +48,7 @@ public: const std::shared_ptr& thePlane); protected: - virtual const char* iconName() const { return "equal.png"; } + virtual const char* iconName(bool isActiveIcon = true) const { return isActiveIcon ? "equal.png" : "equal_deactivate.png"; } virtual void drawLines(const Handle(Prs3d_Presentation)& thePrs, Quantity_Color theColor) const; diff --git a/src/SketcherPrs/SketcherPrs_HVDirection.h b/src/SketcherPrs/SketcherPrs_HVDirection.h index 5ce5ceb23..91deaed0d 100644 --- a/src/SketcherPrs/SketcherPrs_HVDirection.h +++ b/src/SketcherPrs/SketcherPrs_HVDirection.h @@ -51,7 +51,12 @@ public: const std::shared_ptr& thePlane); protected: - virtual const char* iconName() const { return myIsHorisontal? "horisontal.png" : "vertical.png"; } + virtual const char* iconName(bool isActiveIcon = true) const { + if (isActiveIcon) + return myIsHorisontal? "horisontal.png" : "vertical.png"; + else + return myIsHorisontal ? "horisontal_deactivate.png" : "vertical_deactivate.png"; + } /// Redefine this function in order to add additiona lines of constraint base /// \param thePrs a presentation diff --git a/src/SketcherPrs/SketcherPrs_LengthDimension.cpp b/src/SketcherPrs/SketcherPrs_LengthDimension.cpp index f81fe13c2..87ed9bff6 100644 --- a/src/SketcherPrs/SketcherPrs_LengthDimension.cpp +++ b/src/SketcherPrs/SketcherPrs_LengthDimension.cpp @@ -225,7 +225,7 @@ void SketcherPrs_LengthDimension::Compute( updateArrows(DimensionAspect(), GetValue(), aTextSize, aLocationType); // Update text visualization: parameter value or parameter text - myStyleListener->updateDimensions(this, myValue); + myStyleListener->updateDimensions(this, myValue, !myConstraint->data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->value()); PrsDim_LengthDimension::Compute(thePresentationManager, thePresentation, theMode); diff --git a/src/SketcherPrs/SketcherPrs_Middle.h b/src/SketcherPrs/SketcherPrs_Middle.h index 92820adff..204706799 100644 --- a/src/SketcherPrs/SketcherPrs_Middle.h +++ b/src/SketcherPrs/SketcherPrs_Middle.h @@ -48,7 +48,7 @@ public: const std::shared_ptr& thePlane); protected: - virtual const char* iconName() const { return "middlepoint.png"; } + virtual const char* iconName(bool isActiveIcon = true) const { return isActiveIcon ? "middlepoint.png" : "middlepoint_deactivate.png"; } virtual void drawLines(const Handle(Prs3d_Presentation)& thePrs, Quantity_Color theColor) const; diff --git a/src/SketcherPrs/SketcherPrs_Mirror.h b/src/SketcherPrs/SketcherPrs_Mirror.h index e4b021713..0bb6d2880 100644 --- a/src/SketcherPrs/SketcherPrs_Mirror.h +++ b/src/SketcherPrs/SketcherPrs_Mirror.h @@ -47,7 +47,7 @@ public: static bool IsReadyToDisplay(ModelAPI_Feature* theConstraint, const std::shared_ptr& thePlane); protected: - virtual const char* iconName() const { return "mirror.png"; } + virtual const char* iconName(bool /*isActiveIcon*/) const { return "mirror.png"; } virtual void drawLines(const Handle(Prs3d_Presentation)& thePrs, Quantity_Color theColor) const; diff --git a/src/SketcherPrs/SketcherPrs_Offset.h b/src/SketcherPrs/SketcherPrs_Offset.h index 8a479c6fa..e327f8df1 100644 --- a/src/SketcherPrs/SketcherPrs_Offset.h +++ b/src/SketcherPrs/SketcherPrs_Offset.h @@ -49,7 +49,7 @@ public: const std::shared_ptr& thePlane); protected: - virtual const char* iconName() const { return "offset.png"; } + virtual const char* iconName(bool /*isActiveIcon*/) const { return "offset.png"; } virtual void drawLines(const Handle(Prs3d_Presentation)& thePrs, Quantity_Color theColor) const; diff --git a/src/SketcherPrs/SketcherPrs_Parallel.h b/src/SketcherPrs/SketcherPrs_Parallel.h index c85cbfa99..a65ab4849 100644 --- a/src/SketcherPrs/SketcherPrs_Parallel.h +++ b/src/SketcherPrs/SketcherPrs_Parallel.h @@ -48,7 +48,7 @@ public: const std::shared_ptr& thePlane); protected: - virtual const char* iconName() const { return "parallel.png"; } + virtual const char* iconName(bool isActiveIcon = true) const { return isActiveIcon ? "parallel.png" : "parallel_deactivate.png"; } virtual void drawLines(const Handle(Prs3d_Presentation)& thePrs, Quantity_Color theColor) const; diff --git a/src/SketcherPrs/SketcherPrs_Perpendicular.h b/src/SketcherPrs/SketcherPrs_Perpendicular.h index f214c98fe..209b32aa1 100644 --- a/src/SketcherPrs/SketcherPrs_Perpendicular.h +++ b/src/SketcherPrs/SketcherPrs_Perpendicular.h @@ -50,7 +50,7 @@ public: static bool IsReadyToDisplay(ModelAPI_Feature* theConstraint, const std::shared_ptr& thePlane); protected: - virtual const char* iconName() const { return "perpendicular.png"; } + virtual const char* iconName(bool isActiveIcon = true) const { return isActiveIcon ? "perpendicular.png" : "perpendicular_deactivate.png"; } /// Redefine this function in order to add additiona lines of constraint base /// \param thePrs a presentation diff --git a/src/SketcherPrs/SketcherPrs_Radius.cpp b/src/SketcherPrs/SketcherPrs_Radius.cpp index e656da498..ca48ac5fb 100644 --- a/src/SketcherPrs/SketcherPrs_Radius.cpp +++ b/src/SketcherPrs/SketcherPrs_Radius.cpp @@ -160,7 +160,7 @@ void SketcherPrs_Radius::Compute( } SetMeasuredGeometry(myCircle, myAnchorPoint); - myStyleListener->updateDimensions(this, myValue); + myStyleListener->updateDimensions(this, myValue, !myConstraint->data()->boolean(SketchPlugin_Constraint::CONSTRAINT_ACTIVE())->value()); // Update variable aspect parameters (depending on viewer scale) double aTextSize = 0.0; diff --git a/src/SketcherPrs/SketcherPrs_Rigid.h b/src/SketcherPrs/SketcherPrs_Rigid.h index 81b933060..c5bc43696 100644 --- a/src/SketcherPrs/SketcherPrs_Rigid.h +++ b/src/SketcherPrs/SketcherPrs_Rigid.h @@ -51,7 +51,7 @@ public: static bool IsReadyToDisplay(ModelAPI_Feature* theConstraint, const std::shared_ptr& thePlane); protected: - virtual const char* iconName() const { return "anchor.png"; } + virtual const char* iconName(bool isActiveIcon = true) const { return isActiveIcon ? "anchor.png" : "anchor_deactivate.png"; } /// Redefine this function in order to add additiona lines of constraint base /// \param thePrs a presentation diff --git a/src/SketcherPrs/SketcherPrs_SymbolPrs.cpp b/src/SketcherPrs/SketcherPrs_SymbolPrs.cpp index 0d156d22b..f85d679a4 100644 --- a/src/SketcherPrs/SketcherPrs_SymbolPrs.cpp +++ b/src/SketcherPrs/SketcherPrs_SymbolPrs.cpp @@ -159,8 +159,9 @@ SketcherPrs_SymbolPrs::~SketcherPrs_SymbolPrs() //********************************************************************************* Handle(Image_AlienPixMap) SketcherPrs_SymbolPrs::icon() { - if (myIconsMap.count(iconName()) == 1) { - return myIconsMap[iconName()]; + auto isIconType = myConstraint->boolean("ConstraintState")->value(); + if (myIconsMap.count(iconName(isIconType)) == 1) { + return myIconsMap[iconName(isIconType)]; } // Load icon for the presentation std::string aFile; @@ -175,7 +176,7 @@ Handle(Image_AlienPixMap) SketcherPrs_SymbolPrs::icon() } aFile += FSEP; - aFile += iconName(); + aFile += iconName(isIconType); Handle(Image_AlienPixMap) aPixMap = new Image_AlienPixMap(); if (aPixMap->Load(aFile.c_str())) { int aRatio = SketcherPrs_Tools::pixelRatio(); @@ -192,14 +193,14 @@ Handle(Image_AlienPixMap) SketcherPrs_SymbolPrs::icon() } aPixMap = aSizedMap; } - myIconsMap[iconName()] = aPixMap; + myIconsMap[iconName(isIconType)] = aPixMap; return aPixMap; } // The icon for constraint is not found static const char aMsg[] = "Error! constraint images are not found"; std::cout<SetColor(myCustomColor); - } + Handle(Image_AlienPixMap) aIcon = icon(); + if (aIcon.IsNull()) + myAspect = new Graphic3d_AspectMarker3d(); + else + myAspect = new Graphic3d_AspectMarker3d(aIcon); } //********************************************************************************* diff --git a/src/SketcherPrs/SketcherPrs_SymbolPrs.h b/src/SketcherPrs/SketcherPrs_SymbolPrs.h index d83d931a8..5e51b5f54 100644 --- a/src/SketcherPrs/SketcherPrs_SymbolPrs.h +++ b/src/SketcherPrs/SketcherPrs_SymbolPrs.h @@ -109,7 +109,7 @@ protected: const Standard_Integer aMode); /// Returns an icon file name. Has to be redefined in successors - virtual const char* iconName() const = 0; + virtual const char* iconName(bool isActiveIcon = true) const = 0; /// Check and creates if it is necessary myAspect member. /// It has to be called before the object computation diff --git a/src/SketcherPrs/SketcherPrs_Tangent.h b/src/SketcherPrs/SketcherPrs_Tangent.h index 1f61dbecb..547ab1c73 100644 --- a/src/SketcherPrs/SketcherPrs_Tangent.h +++ b/src/SketcherPrs/SketcherPrs_Tangent.h @@ -50,7 +50,7 @@ public: const std::shared_ptr& thePlane); protected: - virtual const char* iconName() const { return "tangent.png"; } + virtual const char* iconName(bool isActiveIcon = true) const { return isActiveIcon ? "tangent.png" : "tangent_deactivate.png"; } virtual void drawLines(const Handle(Prs3d_Presentation)& thePrs, Quantity_Color theColor) const; diff --git a/src/SketcherPrs/SketcherPrs_Transformation.h b/src/SketcherPrs/SketcherPrs_Transformation.h index 387ab2bf2..97f12838a 100644 --- a/src/SketcherPrs/SketcherPrs_Transformation.h +++ b/src/SketcherPrs/SketcherPrs_Transformation.h @@ -50,7 +50,7 @@ public: static bool IsReadyToDisplay(ModelAPI_Feature* theConstraint, const std::shared_ptr& thePlane); protected: - virtual const char* iconName() const { return myIsTranslation? "translate.png" : "rotate.png"; } + virtual const char* iconName(bool /*isActiveIcon*/ ) const { return myIsTranslation ? "translate.png" : "rotate.png"; } /// Redefine this function in order to add additiona lines of constraint base /// \param thePrs a presentation diff --git a/src/SketcherPrs/icons/anchor_deactivate.png b/src/SketcherPrs/icons/anchor_deactivate.png new file mode 100644 index 0000000000000000000000000000000000000000..c03591e15f75a5d3cebe9086fde85405e8a28775 GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&k#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DjSL74G){)!Z!;7?B%#}JL+-U;@rnjHj=U3ZB-$y?MK<8VSy zCs$pEB-d4< zOvyfQR`)atdic23G2^mHtR{c*{qN#GuJDz{9{%(2GoPr* z_usvuqCVZ1RK%61CM>AEpIk#mA}Xx*eEAc6 zVAk40o7QwEO2o<>|Gi1)d}!#-D}SdSZV~Wz?3|pF!zHu=7zhlWu6{1-oD!M<<~5RI literal 0 HcmV?d00001 diff --git a/src/SketcherPrs/icons/collinear_deactivate.png b/src/SketcherPrs/icons/collinear_deactivate.png new file mode 100644 index 0000000000000000000000000000000000000000..19c401385e2ae224b75a54231d3b8fe3daa6955f GIT binary patch literal 303 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!6Tk7jv*HQ$p_fBI6L3`$L#3ha-_cPLO|LI zgO3c$etvj(`2RwuBh0%pr)}hU%5u>sK~A8-#NEx!sq#nTgyrh@CqG`j-+AW>v%@!D zJW6N{U=V6I+Nj;s`EYV`cj9J7mISVePYq3&8BceKYD?(<|9hJ4X)~jTU{ytfN%N6S zn>S15F~OAiZtwl` vFBl??Lpn4XlDJPYs=a!*oGEn@gMbP0l+XkKz%Fw6 literal 0 HcmV?d00001 diff --git a/src/SketcherPrs/icons/equal_deactivate.png b/src/SketcherPrs/icons/equal_deactivate.png new file mode 100644 index 0000000000000000000000000000000000000000..f865127fcae63dad2596086b0b1bb74a7b8bbdc4 GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&k#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DjSL74G){)!Z!V2P)TV~9p@vP4aTpjY$3dW8m~hY!xrx99oa zaOh1=PQq55gg}jso}QLX3Jufy`ww2YFy-N&ozVe;CenQJc0GyB6E<)het*ASg6B(V z;1wZWj$e#y5{(Q#&6NQHf`W~~hr2|z4NMb0GxOZIb!*XzrJ@N53=I5R6@7FYw|WEZ OXYh3Ob6Mw<&;$U1V@bvU literal 0 HcmV?d00001 diff --git a/src/SketcherPrs/icons/horisontal_deactivate.png b/src/SketcherPrs/icons/horisontal_deactivate.png new file mode 100644 index 0000000000000000000000000000000000000000..c11988aead069d850e6ae7a96c0578efb0aa2bc8 GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&k#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DjSL74G){)!Z!V7{k|V~9rZ*7FxR4=C`kT!?rRwyXWz0~^05 zAzzQ1z3hx|%~;5Pq(G|ki|0;@=U!eb6@=W+IqyrHe`~ATRUPRmK`Ul0Y&^bNp!5l+ z-Isgb2EtAX*=z5-ZF|zZTta!(Z3ChGA=3@nGB^MEa^`j0e!;nE`?V{=*6^_dt!D6a L^>bP0l+XkKf2dD5 literal 0 HcmV?d00001 diff --git a/src/SketcherPrs/icons/middlepoint_deactivate.png b/src/SketcherPrs/icons/middlepoint_deactivate.png new file mode 100644 index 0000000000000000000000000000000000000000..bd0ef350dadcc187fe406a2594c4546220105e3e GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!Cp@n#}EtuxBb?9M-+Hm+TVm#Pbtxy)YW`I zQp1v6RsB(v2aEMJE+N-j{xfYjBa;o2rOp2@UQ#CVpfPCE)@fV6@B20{;@Qg&^%HJg zp3y1b^fvWLVU6c&UiE2Q+6zs$TRdN|Rcz})#$z+|9`JB=7!lvI6;>1s;*b3=DjSL74G){)!Z!V1cKLV~9p@@&Q&QC8dAOA08fV|L@#d(EQ)Q zVdEot`}(GzJqdCm4I)i1-n_|Si;j-o5#ycx`hUOtKLZO(YX{c`hUq623KuZ`Uw?l` zqrmay63#Lz4ZenYg&SA`)ebXwc3oujOHW`{naRW4B5G^^bk2_M?B%Q?IY7G^JYD@< J);T3K0RVS!lvI6;>1s;*b3=DjSL74G){)!Z!ptYxqV~9p@vIG17Mg=9MNB!lvI6;>1s;*b3=DjSL74G){)!Z!;51Jc#}JL+sr?su4=eDv_&#s4eK6hrh)qo@ z16yP6CMKbiinG;pSItsaeEgWNdDFGBss^p4XBw`}np1p7@adeD*G}DK|I2bYY^rX4 z#GQ4QSu(Z@NZr|D6n`V#QzWxON#;cp3{CUmO1bB5?FOqn?;@FJY?-^a#v!?VdQxbkO4d_A!Pgg&ebxsLQ01eP$ A&Hw-a literal 0 HcmV?d00001 diff --git a/src/SketcherPrs/icons/vertical_deactivate.png b/src/SketcherPrs/icons/vertical_deactivate.png new file mode 100644 index 0000000000000000000000000000000000000000..201f281c764eb0eed5d1640115d9f3ab164a45d7 GIT binary patch literal 200 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&k#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DjSL74G){)!Z!V63N$V~9rZ-u{c62NZZ*F8j?qGvVMFImt8M zoJ6#yEt0QI_+qm|c?+v?_?#(otD5V}-{0#D^y1ujWQK`1`^61MXIOZ%pXPPH#~9_J sB06!VZOw;U3s(L7wczcfPvsqY>-Sq-n5x>a4QLUAr>mdKI;Vst0Czh^H2?qr literal 0 HcmV?d00001 diff --git a/src/XGUI/CMakeLists.txt b/src/XGUI/CMakeLists.txt index 25a57a530..bb76c8c0c 100644 --- a/src/XGUI/CMakeLists.txt +++ b/src/XGUI/CMakeLists.txt @@ -58,13 +58,14 @@ SET(PROJECT_HEADERS XGUI_Selection.h XGUI_SelectionActivate.h XGUI_SelectionMgr.h + XGUI_SketchConstraintsBrowser.h XGUI_Tools.h XGUI_TransparencyWidget.h XGUI_ViewerProxy.h XGUI_Workshop.h XGUI_WorkshopListener.h - XGUI_InspectionPanel.h - XGUI_CompressFiles.h + XGUI_InspectionPanel.h + XGUI_CompressFiles.h ) SET(PROJECT_MOC_HEADERS @@ -88,11 +89,12 @@ SET(PROJECT_MOC_HEADERS XGUI_PropertyPanel.h XGUI_PropertyPanelSelector.h XGUI_SelectionMgr.h + XGUI_SketchConstraintsBrowser.h XGUI_TransparencyWidget.h XGUI_ViewerProxy.h XGUI_Workshop.h XGUI_WorkshopListener.h - XGUI_InspectionPanel.h + XGUI_InspectionPanel.h ) # sources / moc wrappings @@ -125,13 +127,14 @@ SET(PROJECT_SOURCES XGUI_Selection.cpp XGUI_SelectionActivate.cpp XGUI_SelectionMgr.cpp + XGUI_SketchConstraintsBrowser.cpp XGUI_Tools.cpp XGUI_TransparencyWidget.cpp XGUI_ViewerProxy.cpp XGUI_Workshop.cpp XGUI_WorkshopListener.cpp - XGUI_InspectionPanel.cpp - XGUI_CompressFiles.cpp + XGUI_InspectionPanel.cpp + XGUI_CompressFiles.cpp ) SET(PROJECT_RESOURCES diff --git a/src/XGUI/XGUI_ActionsMgr.cpp b/src/XGUI/XGUI_ActionsMgr.cpp index e803522b4..f6500a801 100644 --- a/src/XGUI/XGUI_ActionsMgr.cpp +++ b/src/XGUI/XGUI_ActionsMgr.cpp @@ -121,7 +121,9 @@ void XGUI_ActionsMgr::updateCommandsStatus() { setAllEnabled(); XGUI_Selection* aSelection = myWorkshop->selector()->selection(); - if (aSelection->getSelected(ModuleBase_ISelection::AllControls).size() > 0) + // If ::ConstraintsBrowser and has Coincodence deleted - fail!!! + if (aSelection->getSelected(ModuleBase_ISelection::AllControls).size() > 0 + && aSelection->getSelected(ModuleBase_ISelection::ConstraintsBorwser).size() == 0) updateOnViewSelection(); FeaturePtr anActiveFeature = FeaturePtr(); diff --git a/src/XGUI/XGUI_ContextMenuMgr.cpp b/src/XGUI/XGUI_ContextMenuMgr.cpp index 9550326bd..cf3904bd2 100644 --- a/src/XGUI/XGUI_ContextMenuMgr.cpp +++ b/src/XGUI/XGUI_ContextMenuMgr.cpp @@ -20,6 +20,7 @@ #include "XGUI_ContextMenuMgr.h" #include "XGUI_Workshop.h" #include "XGUI_ObjectsBrowser.h" +#include "XGUI_SketchConstraintsBrowser.h" #include "XGUI_SelectionMgr.h" #include "XGUI_Displayer.h" #include "XGUI_ViewerProxy.h" @@ -101,6 +102,10 @@ void XGUI_ContextMenuMgr::createActions() anAction->setShortcut(Qt::Key_F2); addAction("RENAME_CMD", anAction); + anAction = ModuleBase_Tools::createAction(QIcon(":pictures/part_ico.png"), tr("Deactivate/Activate"), + aDesktop, this); + addAction("DEACTIVATE_CONSTRAINT_CMD", anAction); + #ifdef HAVE_SALOME anAction = ModuleBase_Tools::createAction(QIcon(":pictures/move_to_end.png"), XGUI_Workshop::MOVE_TO_END_COMMAND, this); @@ -166,6 +171,10 @@ void XGUI_ContextMenuMgr::createActions() aDesktop); addAction("ISOLINES_CMD", anAction); + anAction = ModuleBase_Tools::createAction(QIcon(":pictures/rename_edit.png"), tr("Edit..."), + aDesktop); + addAction("EDIT_CONSTR_CMD", anAction); + anAction = ModuleBase_Tools::createAction(QIcon(), tr("Show Isos"), aDesktop); anAction->setCheckable(true); addAction("SHOW_ISOLINES_CMD", anAction); @@ -251,6 +260,7 @@ void XGUI_ContextMenuMgr::createActions() addAction("SET_VIEW_NORMAL_CMD", anAction); buildObjBrowserMenu(); + buildConstrBrowserMenu(); buildViewerMenu(); } @@ -304,6 +314,8 @@ void XGUI_ContextMenuMgr::onContextMenuRequest(QContextMenuEvent* theEvent) } else if (sender() == myWorkshop->viewer()) { updateViewerMenu(); addViewerMenu(aMenu); + } else if (sender() == myWorkshop->constraintsBrowser()) { + addConstrBrowserMenu(aMenu); } if (aMenu && (aMenu->actions().size() > 0)) { @@ -699,6 +711,11 @@ void XGUI_ContextMenuMgr::connectViewer() SLOT(onContextMenuRequest(QContextMenuEvent*))); } +void XGUI_ContextMenuMgr::connectConstraintsBrowser() +{ + connect(myWorkshop->constraintsBrowser(), SIGNAL(contextMenuRequested(QContextMenuEvent*)), this, + SLOT(onContextMenuRequest(QContextMenuEvent*))); +} void XGUI_ContextMenuMgr::buildObjBrowserMenu() { @@ -820,6 +837,18 @@ void XGUI_ContextMenuMgr::buildObjBrowserMenu() myObjBrowserMenus[ModelAPI_ResultField::ModelAPI_FieldStep::group()] = aList; } +void XGUI_ContextMenuMgr::buildConstrBrowserMenu() +{ + QAction* aSeparator = ModuleBase_Tools::createAction(QIcon(), "", myWorkshop->desktop()); + aSeparator->setSeparator(true); + + QActionsList aList; + + aList.append(action("HIDE_CMD")); + aList.append(action("DELETE_CMD")); + aList.append(action("DEACTIVATE_CONSTRAINT_CMD")); +} + void XGUI_ContextMenuMgr::buildViewerMenu() { QActionsList aList; @@ -886,6 +915,56 @@ void XGUI_ContextMenuMgr::buildViewerMenu() myViewerMenu[ModelAPI_ResultField::ModelAPI_FieldStep::group()] = aList; } +void XGUI_ContextMenuMgr::addConstrBrowserMenu(QMenu* theMenu) const +{ + QActionsList anActions; + QObjectPtrList aObjects = myWorkshop->constraintsBrowser()->selectedObjects(); + + // Check that state foreach constraint. + // If at least 1 is Activa - show Deactivate + // otherwise - show Activate + // + if (aObjects.size() > 0) + { + // It's update START + + // Enable edit only if exist at least 1 dimensional constraint + bool isEditEnabled = false; + foreach(ObjectPtr anObject, aObjects) + { + if (auto aFeat = ModelAPI_Feature::feature(anObject)) + { + if (aFeat->real("ConstraintValue")) + { + isEditEnabled = true; + break; + } + } + } + + action("EDIT_CONSTR_CMD")->setEnabled(isEditEnabled); + action("DELETE_CMD")->setEnabled(true); + action("DEACTIVATE_CONSTRAINT_CMD")->setEnabled(true); + // It's update END + + anActions.append(action("EDIT_CONSTR_CMD")); + anActions.append(action("DELETE_CMD")); + anActions.append(action("DEACTIVATE_CONSTRAINT_CMD")); + } + else + { + // It's update START + action("EDIT_CONSTR_CMD")->setEnabled(true); + // It's update END + + anActions.append(action("EDIT_CONSTR_CMD")); + } + + + theMenu->addActions(anActions); + addFeatures(theMenu); + +} void XGUI_ContextMenuMgr::addObjBrowserMenu(QMenu* theMenu) const { diff --git a/src/XGUI/XGUI_ContextMenuMgr.h b/src/XGUI/XGUI_ContextMenuMgr.h index 3f1112a32..fb41ccbf3 100644 --- a/src/XGUI/XGUI_ContextMenuMgr.h +++ b/src/XGUI/XGUI_ContextMenuMgr.h @@ -67,9 +67,15 @@ Q_OBJECT /// Connect to viewer from workshop. Has to called at creation of viewer. void connectViewer(); + /// Connect to viewer from workshop. Has to called at creation of viewer. + void connectConstraintsBrowser(); + /// Add menu items for Object browser pop-up void addObjBrowserMenu(QMenu*) const; + /// Add menu items for Object browser pop-up + void addConstrBrowserMenu(QMenu*) const; + /// Add menu items for Viewer pop-up void addViewerMenu(QMenu*) const; @@ -126,6 +132,9 @@ signals: /// Creates menu for object browser void buildObjBrowserMenu(); + /// Creates menu for object browser + void buildConstrBrowserMenu(); + /// Creates menu for viewer void buildViewerMenu(); diff --git a/src/XGUI/XGUI_Displayer.cpp b/src/XGUI/XGUI_Displayer.cpp index 6ee3b9348..32b6df969 100644 --- a/src/XGUI/XGUI_Displayer.cpp +++ b/src/XGUI/XGUI_Displayer.cpp @@ -509,6 +509,23 @@ void XGUI_Displayer::setSelected(const QList& theValue #endif } } + else + { + auto aConstrFeature = ModelAPI_Feature::feature(anObject); + if (!aConstrFeature) + continue; + + AISObjectPtr aAisPtr = myWorkshop->displayer()->getAISObject(aConstrFeature); + if (!aAisPtr) + { + aAisPtr = myResult2AISObjectMap.value(aConstrFeature->lastResult()); + if (!aAisPtr) + continue; + } + Handle(AIS_InteractiveObject) aAisObj = aAisPtr->impl(); + + aContext->AddOrRemoveSelected(aAisObj, false); + } } } if (!aShapesToBeSelected.IsEmpty()) diff --git a/src/XGUI/XGUI_Selection.cpp b/src/XGUI/XGUI_Selection.cpp index fab475e49..74c909829 100644 --- a/src/XGUI/XGUI_Selection.cpp +++ b/src/XGUI/XGUI_Selection.cpp @@ -22,6 +22,7 @@ #include "XGUI_Displayer.h" #include "XGUI_ViewerProxy.h" #include "XGUI_ObjectsBrowser.h" +#include "XGUI_SketchConstraintsBrowser.h" #ifndef HAVE_SALOME #include @@ -79,6 +80,10 @@ QList XGUI_Selection::getSelected(const SelectionPlace& case Viewer: getSelectedInViewer(aPresentations); break; + case ConstraintsBorwser: + getSelectedInSketchConstraintsBrowser(aPresentations); + break; + case AllControls: // Get selection from object browser getSelectedInBrowser(aPresentations); @@ -201,6 +206,33 @@ void XGUI_Selection::getSelectedInBrowser(QList& thePre } } +void XGUI_Selection::getSelectedInSketchConstraintsBrowser(QList>& thePresentations) const +{ + QObjectPtrList anObjects; + if (myWorkshop->constraintsBrowser()) + anObjects = myWorkshop->constraintsBrowser()->selectedObjects(); + + if (anObjects.isEmpty()) + return; + + QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end(); + for (; anIt != aLast; anIt++) { + ObjectPtr anObject = *anIt; + if (anObject.get() != NULL) { + auto aConstrFeature = ModelAPI_Feature::feature(anObject); + thePresentations.append(std::shared_ptr( + new ModuleBase_ViewerPrs(anObject, GeomShapePtr(), NULL))); + /* AISObjectPtr aAisPtr = myWorkshop->displayer()->getAISObject(aConstrFeature); + if (!aAisPtr) + continue; + Handle(AIS_InteractiveObject) aAisObj = aAisPtr->impl(); + auto aPrs = std::shared_ptr( + new ModuleBase_ViewerPrs(anObject, GeomShapePtr(), NULL)); + aPrs->setInteractive(aAisObj); + thePresentations.append(aPrs);*/ + } + } +} void XGUI_Selection::fillPresentation(ModuleBase_ViewerPrsPtr& thePrs, const Handle(SelectMgr_EntityOwner)& theOwner) const { @@ -381,6 +413,8 @@ QObjectPtrList XGUI_Selection::selectedObjects() const { if (myWorkshop->objectBrowser()) return myWorkshop->objectBrowser()->selectedObjects(); + if (myWorkshop->constraintsBrowser()) + return myWorkshop->constraintsBrowser()->selectedObjects(); return QObjectPtrList(); } diff --git a/src/XGUI/XGUI_Selection.h b/src/XGUI/XGUI_Selection.h index 58b257998..65d5b5f36 100644 --- a/src/XGUI/XGUI_Selection.h +++ b/src/XGUI/XGUI_Selection.h @@ -103,6 +103,13 @@ protected: /// \param thePresentations an output list of presentation void getSelectedInBrowser(QList>& thePresentations) const; + /// Fills the list of presentations by objects selected in the object browser. + /// ViewerPrs contains only object parameter not empty. + /// If the given list of presentations already has a viewer presentation with the same object + /// as selected in the browser, a new item is not appended to the list of presentations. + /// \param thePresentations an output list of presentation + void getSelectedInSketchConstraintsBrowser(QList>& thePresentations) const; + /// Generates a vertex or edge by the give IO if it is an AIS created on trihedron /// \param theIO a selected object /// \return created shape or empty shape diff --git a/src/XGUI/XGUI_SelectionMgr.cpp b/src/XGUI/XGUI_SelectionMgr.cpp index 80f1d1592..63188daaa 100644 --- a/src/XGUI/XGUI_SelectionMgr.cpp +++ b/src/XGUI/XGUI_SelectionMgr.cpp @@ -21,6 +21,7 @@ #include "XGUI_Workshop.h" #include "XGUI_ObjectsBrowser.h" +#include "XGUI_SketchConstraintsBrowser.h" #include "XGUI_SalomeConnector.h" #include "XGUI_ViewerProxy.h" #include "XGUI_Displayer.h" @@ -83,6 +84,8 @@ void XGUI_SelectionMgr::connectViewers() //Connect to other viewers connect(myWorkshop->viewer(), SIGNAL(selectionChanged()), this, SLOT(onViewerSelection())); + connect(myWorkshop->constraintsBrowser(), SIGNAL(selectionChanged()), this, + SLOT(onSketchConstraintsBrowserSelection())); } //************************************************************** @@ -140,6 +143,39 @@ void XGUI_SelectionMgr::onObjectBrowserSelection() emit selectionChanged(); } +//************************************************************** +void XGUI_SelectionMgr::onSketchConstraintsBrowserSelection() +{ + myLastSelectionPlace = ModuleBase_ISelection::ConstraintsBorwser; + QList aSelectedPrs = + myWorkshop->selector()->selection()->getSelected(ModuleBase_ISelection::ConstraintsBorwser); + XGUI_Displayer* aDisplayer = myWorkshop->displayer(); + if (!myWorkshop->operationMgr()->hasOperation()) { + + ObjectPtr aObject; + FeaturePtr aFeature; + // Select all results of a selected feature in viewer + foreach(ModuleBase_ViewerPrsPtr aPrs, aSelectedPrs) { + aObject = aPrs->object(); + if (aObject.get()) { + aFeature = std::dynamic_pointer_cast(aObject); + if (aFeature.get()) { + std::list allRes; + ModelAPI_Tools::allResults(aFeature, allRes); + std::list::iterator aRes; + for (aRes = allRes.begin(); aRes != allRes.end(); aRes++) { + aSelectedPrs.append(std::shared_ptr( + new ModuleBase_ViewerPrs(*aRes, GeomShapePtr(), NULL))); + } + } + } + } + } + aDisplayer->setSelected(aSelectedPrs); + myWorkshop->updateColorScaleVisibility(); + emit selectionChanged(); +} + //************************************************************** void XGUI_SelectionMgr::onViewerSelection() { diff --git a/src/XGUI/XGUI_SelectionMgr.h b/src/XGUI/XGUI_SelectionMgr.h index 6765efe05..db1f31f7e 100644 --- a/src/XGUI/XGUI_SelectionMgr.h +++ b/src/XGUI/XGUI_SelectionMgr.h @@ -94,9 +94,12 @@ signals: void selectionChanged(); public slots: - /// Reaction on selectio0n in Object browser + /// Reaction on selection in Object browser void onObjectBrowserSelection(); + /// Reaction on selection in Constraints Browser + void onSketchConstraintsBrowserSelection(); + /// Reaction on selectio0n in Viewer void onViewerSelection(); diff --git a/src/XGUI/XGUI_SketchConstraintsBrowser.cpp b/src/XGUI/XGUI_SketchConstraintsBrowser.cpp new file mode 100644 index 000000000..6a7d4f4ec --- /dev/null +++ b/src/XGUI/XGUI_SketchConstraintsBrowser.cpp @@ -0,0 +1,755 @@ +// Copyright (C) 2014-2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "XGUI_SketchConstraintsBrowser.h" +#include "XGUI_Tools.h" +#include "XGUI_DataModel.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef DEBUG_INDXES +#include +#endif + + +#ifdef WIN32 +# define FSEP "\\" +#else +# define FSEP "/" +#endif + +// Type of columns +enum ColumnType { + Col_Icon, + Col_Constraint, + Col_Primitive, + Col_Value +}; + +namespace +{ + QModelIndex GetIndex(QModelIndex theChildIndex) + { + auto aParent = theChildIndex.parent(); + if (aParent.isValid()) + return aParent.model()->index(aParent.row(), 1); + else + return QModelIndex(); + } + + // Retrurn name for constraint attribute + QString GetName(const AttributePtr& theAttribute) + { + QString aName; + + if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) + return aName; + + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(theAttribute); + + auto anObj = aRefAttr->object(); + auto anAttr = aRefAttr->attr(); + if (anAttr) + { + FeaturePtr anAttrA = ModelAPI_Feature::feature(anAttr->owner()); + aName += QString::fromStdWString(anAttrA->name()); + aName += "/"; + aName += QString::fromStdString(anAttr->id()); + } + else if (anObj) + { + FeaturePtr anAttrA = ModelAPI_Feature::feature(anObj); + aName += QString::fromStdWString(anAttrA->name()); + } + + return aName; + } + + std::pair FromSketchKindToName(const std::string& theKind) + { + const std::string& aType = theKind; + if (aType == "SketchConstraintCoincidence" || + aType == "SketchConstraintCoincidenceInternal") + return { "Coincidence", "coincedence.png" }; + else if (aType == "SketchConstraintRigid") + return { "Fixed", "fixed.png" }; + else if (aType == "SketchConstraintHorizontal") + return { "Horizontal", "horisontal.png" }; + else if (aType == "SketchConstraintVertical") + return { "Vertical", "vertical.png" }; + else if (aType == "SketchConstraintAngle") + return { "Angle", "angle_constr.png" }; + else if (aType == "SketchConstraintDistance") + return { "Distance", "distance.png" }; + else if (aType == "SketchConstraintDistanceHorizontal") + return { "Horizontal distance", "distance_h.png" }; + else if (aType == "SketchConstraintDistanceVertical") + return { "Vertical distance", "distance_v.png" }; + else if (aType == "SketchConstraintEqual") + return { "Equal", "equal.png" }; + else if (aType == "SketchConstraintLength") + return { "Length", "length.png" }; + else if (aType == "SketchConstraintMiddle") + return { "Middle point", "middlepoint.png" }; + else if (aType == "SketchConstraintMirror") + return { "Mirror objects", "mirror.png" }; + else if (aType == "SketchConstraintParallel") + return { "Parallel", "parallel.png" }; + else if (aType == "SketchConstraintPerpendicular") + return { "Perpendicular", "perpendicular.png" }; + else if (aType == "SketchConstraintRadius") + return { "Radius", "radius_constr.png" }; + else if (aType == "SketchConstraintCollinear") + return { "Collinear", "collinear.png" }; + else if (aType == "SketchConstraintTangent") + return { "Tangent", "tangent.png" }; + return { "", "" }; + } + + std::string GetIconPath(const std::string& theKind) + { + std::string aFile; + char* anEnv = getenv("SHAPER_ROOT_DIR"); + if (anEnv) { + aFile = std::string(anEnv) + + FSEP + "share" + FSEP + "salome" + FSEP + "resources" + FSEP + "shaper" + FSEP + "icons" + FSEP + "Sketch"; + } + else { + anEnv = getenv("CADBUILDER_ROOT_DIR"); + if (anEnv) + aFile = std::string(anEnv) + FSEP + "plugins" + FSEP + "icons" + FSEP + "Sketch"; + } + + aFile += FSEP; + aFile += FromSketchKindToName(theKind).second; + return aFile; + } +} + +/*! + * \ingroup GUI + * ItemDelegate object in order to redefine items behavior + */ +class XGUI_ConstraintsItemDelegate : public QStyledItemDelegate +{ +public: + /// Constructor + /// \param thaParent a parent + XGUI_ConstraintsItemDelegate(QObject* thaParent) : + QStyledItemDelegate(thaParent) {} + + /// Redefinition of virtual method + /// \param parent a parent widget + /// \param option the item options + /// \param index the current index + virtual QWidget* createEditor(QWidget* parent, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; + + /// Returns True if the given index is editable item + /// \param theIndex an item index + bool isEditable(const QModelIndex& theIndex) const; + + // Return current state for TreeItem + bool GetIsActive(const QModelIndex& index) const; + + // Modify state item + void SetIsActive(QModelIndex& theIndex, bool theIsActive); + + /// Returns currently editing index + QModelIndex editIndex() const { return myEditingIdx; } + + /// Redefinition of virtual method + /// \param painter a painter object + /// \param option the item options + /// \param index the current index + virtual void paint(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; + +protected: + /// Redefinition of virtual method + /// \param option the item options + /// \param index the current index + virtual void initStyleOption(QStyleOptionViewItem* option, + const QModelIndex& index) const; + +private: + mutable QModelIndex myEditingIdx; +}; + +// Implement + +bool XGUI_ConstraintsItemDelegate::GetIsActive(const QModelIndex& index) const +{ + if (!index.parent().isValid()) + return true; + + auto aModel = index.model(); + auto anIndexForCheck = aModel->index(index.row(), 1); + bool myIsActive = index.parent().child(index.row(), 1).data(Qt::UserRole + 1).toBool(); + return myIsActive; +} + +void XGUI_ConstraintsItemDelegate::initStyleOption(QStyleOptionViewItem* option, const QModelIndex& index) const +{ + if (index.parent().isValid()) + { + bool myIsActive = GetIsActive(index); + option->palette.setBrush(QPalette::ColorRole::Text, myIsActive ? Qt::black : Qt::darkGray); + } + + QStyledItemDelegate::initStyleOption(option, index); +} + +void XGUI_ConstraintsItemDelegate::paint(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + QBrush aBrush = painter->brush(); + QPen aPen = painter->pen(); + + Qt::GlobalColor aColor = index.parent().isValid() ? Qt::white : Qt::lightGray; + painter->setBrush(aColor); + painter->setPen(aColor); + + painter->drawRect(option.rect); + painter->setPen(aPen); + + QStyledItemDelegate::paint(painter, option, index); + painter->setBrush(aBrush); +} + +void XGUI_ConstraintsItemDelegate::SetIsActive(QModelIndex& theIndex, bool theIsActive) +{ + bool aBool = theIndex.model()->data(theIndex, Qt::UserRole + 1).toBool(); + theIndex.model()->data(theIndex, Qt::UserRole + 1).setValue(!aBool); +} + +QWidget* XGUI_ConstraintsItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + myEditingIdx = index; + return QStyledItemDelegate::createEditor(parent, option, index); +} + +bool XGUI_ConstraintsItemDelegate::isEditable(const QModelIndex& theIndex) const +{ + QModelIndex aParent = theIndex.parent(); + if (aParent.isValid() && !theIndex.data(0).isNull() && theIndex.column() == 3) + return true; + + return false; +} + +void XGUI_ConstraintsViewTree::closeEditor(QWidget* theEditor, + QAbstractItemDelegate::EndEditHint theHint) +{ + if (theHint == QAbstractItemDelegate::EditNextItem) { + QModelIndex aCurrent = currentIndex(); + QModelIndex aParent = model()->index(0, 0); + int aNbRows = model()->rowCount(aParent); + QModelIndex aIdx; + if (aCurrent.column() == 3) { + QTreeWidget::closeEditor(theEditor, theHint); + return; + } + if (aIdx.isValid()) { + QTreeWidget::closeEditor(theEditor, QAbstractItemDelegate::NoHint); + setCurrentIndex(aIdx); + edit(aIdx); + return; + } + } + QTreeWidget::closeEditor(theEditor, theHint); +} + +//******************************************************************** +XGUI_SketchConstraintsBrowser::XGUI_SketchConstraintsBrowser(QWidget* theParent, XGUI_Workshop* theWorkshop) + : QWidget(theParent), myWorkshop(theWorkshop) +{ + // Attempt create Tree View + myViewTree = new XGUI_ConstraintsViewTree(this); + myViewTree->setColumnCount(4); + QStringList aHeaders; + aHeaders << "" << tr("Constraint") << tr("Primitives") + << tr("Parameter"); + + myViewTree->setHeaderLabels(aHeaders); + myViewTree->setColumnWidth(Col_Icon, 40); + myViewTree->setColumnWidth(Col_Constraint, 160); + myViewTree->setColumnWidth(Col_Primitive, 140); + myViewTree->setColumnWidth(Col_Value, 40); + + myViewTree->setEditTriggers(QAbstractItemView::NoEditTriggers); + myViewTree->setSelectionBehavior(QAbstractItemView::SelectRows); + myViewTree->setSelectionMode(QAbstractItemView::ExtendedSelection); + + connect(myViewTree, SIGNAL(doubleClicked(const QModelIndex&)), + SLOT(onDoubleClick(const QModelIndex&))); + connect(myViewTree, SIGNAL(itemSelectionChanged()), SLOT(onSelectionChanged())); + + myDelegate = new XGUI_ConstraintsItemDelegate(myViewTree); + + myViewTree->setItemDelegate(myDelegate); + + QPalette aTreePalet = myViewTree->palette(); + QColor aTreeBack = aTreePalet.color(QPalette::Base); + + QPalette aPalet; + aPalet.setColor(QPalette::Base, aTreeBack); + aPalet.setColor(QPalette::Window, aTreeBack); + myViewTree->setPalette(aTreePalet); + + connect(myViewTree, SIGNAL(contextMenuRequested(QContextMenuEvent*)), this, + SLOT(onContextMenuRequested(QContextMenuEvent*))); + + myExtInfo = new QCheckBox(tr("Extended Information")); + myExtInfo->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + myExtInfo->setChecked(true); + + // Connect for show/hide extended information + connect(myExtInfo, SIGNAL(toggled(bool)), this, SLOT(SelectStateChanged(bool))); + ModuleBase_Tools::adjustMargins(myExtInfo); + + myLayout = new QVBoxLayout(this); + ModuleBase_Tools::zeroMargins(myLayout); + myLayout->setSpacing(0); + + myLayout->addWidget(myExtInfo); + myLayout->addWidget(myViewTree); + + Events_Loop* aLoop = Events_Loop::loop(); + aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED)); + aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); +} + +XGUI_SketchConstraintsBrowser::~XGUI_SketchConstraintsBrowser() +{ + // For avoid crashes after reopen sketch + Events_Loop* aLoop = Events_Loop::loop(); + aLoop->removeListener(this); +} + +void XGUI_SketchConstraintsBrowser::SelectStateChanged(bool /*theState*/) +{ + // Add process for show columns in edit mode + bool isShowExtInfo = !myExtInfo->isChecked(); + myViewTree->setColumnHidden(Col_Primitive, isShowExtInfo); + myViewTree->setColumnHidden(Col_Value, isShowExtInfo); +} + +// bad first param! Make more easy +bool XGUI_SketchConstraintsBrowser::UpdateTree(const std::vector>>& theList, bool isAddToExist) +{ + if (!isAddToExist) + { + myViewTree->clear(); + myConstrs.clear(); + } + + // Prepare all groups of constraints + for (const auto& anElemConstr : theList) + { + myConstrs[FromSketchKindToName(anElemConstr.first->getKind()).first].push_back({ anElemConstr.first, anElemConstr.second }); + } + + int aRow = 0; + for (const auto& line : myConstrs) + { + //Get icon for group + std::string aFile = GetIconPath(line.second.front().Feature->getKind()); + + if (line.second[0].Attributes.size() == 0) + continue; + + QTreeWidgetItem* anElem = new QTreeWidgetItem(myViewTree); + anElem->setFlags(Qt::ItemIsEnabled); + anElem->setText(Col_Constraint, QString::fromStdString(line.first)); + anElem->setIcon(Col_Icon, QIcon(QString::fromStdString(aFile))); + anElem->setExpanded(true); + auto aStart = line.second.begin(); + for (; aStart != line.second.end(); ++aStart) + { + FeatStruct aFeatStruct; + // + for (const auto& anElemConstr : theList) + { + if (anElemConstr.first == (*aStart).Feature) + { + aFeatStruct.Feature = anElemConstr.first; + aFeatStruct.Attributes = anElemConstr.second; + ++aRow; + break; + } + } + // + QTreeWidgetItem* aSubElem = new QTreeWidgetItem(anElem); + aSubElem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled); + aSubElem->setText(Col_Constraint, QString::fromStdWString((*aStart).Feature->name())); + aSubElem->setData(Col_Constraint, Qt::UserRole + 1, (*aStart).Feature->boolean("ConstraintState")->value()); // Store state of constraints true - activated, false - supressed + + QString aPrimitives; + aPrimitives = GetName(aFeatStruct.Attributes[0]); + if (aFeatStruct.Attributes.size() == 2) + { + aPrimitives += "\n"; + aPrimitives += GetName(aFeatStruct.Attributes[1]); + } + + aSubElem->setText(Col_Primitive, aPrimitives); + if ((*aStart).Feature->real("ConstraintValue")) + { + if ((*aStart).Feature->real("AngleValue")) + aSubElem->setData(Col_Value, Qt::EditRole, (*aStart).Feature->real("AngleValue")->value()); + else if ((*aStart).Feature->real("DistanceValue")) + aSubElem->setData(Col_Value, Qt::EditRole, (*aStart).Feature->real("DistanceValue")->value()); + else + aSubElem->setData(Col_Value, Qt::EditRole, (*aStart).Feature->real("ConstraintValue")->value()); + } + anElem->addChild(aSubElem); + } + + myViewTree->addTopLevelItem(anElem); + } + return true; +} + +//****************************************************** +void XGUI_SketchConstraintsBrowser::processEvent(const std::shared_ptr& theMessage) +{ + if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED) + || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)) + { + std::shared_ptr aUpdMsg = + std::dynamic_pointer_cast(theMessage); + std::set aObjects = aUpdMsg->objects(); + + foreach(ObjectPtr anObjectC, aObjects) + { + auto aCreatedFeature = ModelAPI_Feature::feature(anObjectC); + if (aCreatedFeature && aCreatedFeature->getKind() == "Sketch") + { + // It's for update constraints after creating or updating + emit deleteCosnstraints(); + break; + } + } + } +} + +//*************************************************** +void XGUI_SketchConstraintsBrowser::initialize(ModuleBase_ITreeNode* theRoot) +{ + QItemSelectionModel* aSelMod = myViewTree->selectionModel(); + connect(aSelMod, SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), + this, SLOT(onSelectionChanged(const QItemSelection&, const QItemSelection&))); +} + +//*************************************************** +void XGUI_SketchConstraintsBrowser::onContextMenuRequested(QContextMenuEvent* theEvent) +{ + QModelIndexList aIndexes; + QObjectPtrList aSelectedData = selectedObjects(&aIndexes); + bool toEnable = true; + + foreach(QAction* aCmd, actions()) { + aCmd->setEnabled(toEnable); + } + emit contextMenuRequested(theEvent); +} + +//*************************************************** +void XGUI_SketchConstraintsBrowser::onEditItem() +{ + // Create buttons for edit mode - Move to separat fucntion + myButtons = new QHBoxLayout(this); + QPushButton* anApplyBut = + new QPushButton(QIcon(":pictures/plane_view.png"), tr("Apply")); + connect(anApplyBut, SIGNAL(clicked(bool)), this, SLOT(onCloseEditor())); + QPushButton* aCloseBut = + new QPushButton(QIcon(":pictures/plane_view.png"), tr("Cancel")); + connect(aCloseBut, SIGNAL(clicked(bool)), this, SLOT(onCloseEditor())); + myButtons->addWidget(anApplyBut); + myButtons->addWidget(aCloseBut); + myLayout->addLayout(myButtons); + + myLastState = myExtInfo->isChecked(); + myExtInfo->setChecked(true); + + QObjectPtrList aSelectedData = selectedObjects(); + if (aSelectedData.size() > 0) { + ObjectPtr anObject = aSelectedData.first(); + if (anObject.get()) { // Selection happens in TreeView + // check whether the object can be renamed. There should not be parts which are not loaded + std::set aFeatures; + aFeatures.insert(ModelAPI_Feature::feature(anObject)); + if (!XGUI_Tools::canRemoveOrRename((QWidget*)parent(), aFeatures)) + return; + + // Find index which corresponds the feature + QModelIndex aIndex; + foreach(QModelIndex aIdx, selectedIndexes()) { + if (aIdx.column() == Col_Value) { + aIndex = aIdx; + if (aIndex.isValid()) { + myViewTree->setCurrentIndex(aIndex); + auto aData = aIndex.data(0); + if (!aData.isNull()) + myViewTree->openPersistentEditor(myViewTree->currentItem(), Col_Value); + } + } + } + } + } + else + { + QTreeWidgetItemIterator anIter(myViewTree); + while (*anIter) { + auto aData = (*anIter)->data(Col_Value, 0); + if (!aData.isNull()) + myViewTree->openPersistentEditor((*anIter), Col_Value); + ++anIter; + } + } +} + +void XGUI_SketchConstraintsBrowser::onDeactivateItems() +{ + bool isActivate = true; + std::vector aFeaturesMod; + // This Check need on request COntext Menu step! + foreach(QModelIndex aIdx, selectedIndexes()) + { + if (aIdx.isValid() && aIdx.column() == Col_Constraint) { + auto aBool = aIdx.data(Qt::UserRole + 1).toBool(); + if (aBool) + { + isActivate = false; + break; + } + } + } + + QObjectPtrList aSelectedData = selectedObjects(); + if (aSelectedData.size() > 0) { + ObjectPtr anObject = aSelectedData.first(); + if (anObject.get()) { // Selection happens in TreeView + // check whether the object can be renamed. There should not be parts which are not loaded + std::set aFeatures; + aFeatures.insert(ModelAPI_Feature::feature(anObject)); + if (!XGUI_Tools::canRemoveOrRename((QWidget*)parent(), aFeatures)) + return; + + // Find index which corresponds the feature + foreach(QModelIndex aIdx, selectedIndexes()) { + auto aParent = GetIndex(aIdx); + if (aParent.isValid() && aIdx.isValid() && aIdx.column() == Col_Constraint) { + myViewTree->setCurrentIndex(aIdx); + myViewTree->currentItem()->setData(Col_Constraint, Qt::UserRole + 1, isActivate); + + auto aFeat = myConstrs[aParent.data().toString().toStdString()].at(aIdx.row()).Feature; + aFeaturesMod.push_back(aFeat); + } + } + } + } + + emit deactivate(isActivate, aFeaturesMod); +} + +void XGUI_SketchConstraintsBrowser::onCloseEditor() +{ + // Close editor + QTreeWidgetItemIterator anIter(myViewTree); + while (*anIter) { + myViewTree->closePersistentEditor((*anIter), Col_Value); + ++anIter; + } + myExtInfo->setChecked(myLastState); + + // Send signals for apply uopdates + emit editValues(); + + myButtons->takeAt(1)->widget()->deleteLater(); + myButtons->takeAt(0)->widget()->deleteLater(); + + myButtons->deleteLater(); +} + +void XGUI_SketchConstraintsBrowser::onCloseEditor(QWidget* theEditor, QAbstractItemDelegate::EndEditHint theHint) +{ +} + +//*************************************************** +void XGUI_SketchConstraintsBrowser::setObjectsSelected(const QObjectPtrList& theObjects) +{ + QItemSelectionModel* aSelectModel = myViewTree->selectionModel(); + QModelIndexList aIndexes = aSelectModel->selectedIndexes(); + if (theObjects.size() == 0) { + bool aIsBlock = aSelectModel->blockSignals(true); + aSelectModel->clear(); + aSelectModel->blockSignals(aIsBlock); + foreach(QModelIndex aIdx, aIndexes) { + myViewTree->update(aIdx); + } + return; + } +} + +//*************************************************** +void XGUI_SketchConstraintsBrowser::onSelectionChanged(const QItemSelection& theSelected, + const QItemSelection& theDeselected) +{ + onSelectionChanged(); +} + +//*************************************************** +void XGUI_SketchConstraintsBrowser::onSelectionChanged() +{ + emit selectionChanged(); +} + +//*************************************************** +QObjectPtrList XGUI_SketchConstraintsBrowser::selectedObjects(QModelIndexList* theIndexes) const +{ + QObjectPtrList aList; + QModelIndexList aIndexes = selectedIndexes(); + + foreach(QModelIndex aIdx, aIndexes) { + if (aIdx.column() == Col_Constraint) { + QModelIndex aParentData = GetIndex(aIdx); + if (!aParentData.isValid()) + continue; + + std::string aData = aParentData.data().toString().toStdString(); + ObjectPtr aObject = myConstrs.at(aData).at(aIdx.row()).Feature; + + auto anAttrs = myConstrs.at(aParentData.data().toString().toStdString()).at(aIdx.row()).Attributes; + if (aObject) { + if (!aList.contains(aObject)) + { + aList.append(aObject); + + // Add related primitives to list + for (int anIndex = 0; anIndex < anAttrs.size(); ++anIndex) + { + if (anAttrs[anIndex]->attributeType() == ModelAPI_AttributeRefAttr::typeId()) + { + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(anAttrs[anIndex]); + if (!aRefAttr->attr()) + { + auto aFObj = aRefAttr->object(); + + if (!aList.contains(aFObj)) + { + aList.append(aFObj); + } + } + else + { + aList.append(aRefAttr->attr()->owner()); + } + } + } + + if (theIndexes) + theIndexes->append(aIdx); + } + } + } + } + return aList; +} + +//*************************************************** +QObjectPtrList XGUI_SketchConstraintsBrowser::selectedConstraints(QModelIndexList* theIndexes) const +{ + QObjectPtrList aList; + QModelIndexList aIndexes = selectedIndexes(); + + foreach(QModelIndex aIdx, aIndexes) { + if (aIdx.column() == Col_Constraint) { + QModelIndex aParentData = GetIndex(aIdx); + if (!aParentData.isValid()) + continue; + + std::string aData = aParentData.data().toString().toStdString(); + ObjectPtr aObject = myConstrs.at(aData).at(aIdx.row()).Feature; + if (aObject) { + if (!aList.contains(aObject)) + { + aList.append(aObject); + + if (theIndexes) + theIndexes->append(aIdx); + } + } + } + } + return aList; +} + +//*************************************************** +void XGUI_SketchConstraintsBrowser::onDoubleClick(const QModelIndex& theIndex) +{ + if (myDelegate->isEditable(theIndex)) { + myViewTree->setCurrentIndex(theIndex); + myViewTree->openPersistentEditor(myViewTree->currentItem(), Col_Value); + // Create buttons apply/Close! + onEditItem(); + } +} + +void XGUI_SketchConstraintsBrowser::resizeEvent(QResizeEvent* theEvent) +{ + QWidget::resizeEvent(theEvent); + emit sizeChanged(); +} diff --git a/src/XGUI/XGUI_SketchConstraintsBrowser.h b/src/XGUI/XGUI_SketchConstraintsBrowser.h new file mode 100644 index 000000000..01b794699 --- /dev/null +++ b/src/XGUI/XGUI_SketchConstraintsBrowser.h @@ -0,0 +1,204 @@ +// Copyright (C) 2014-2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef XGUI_SketchConstraintsBrowser_H +#define XGUI_SketchConstraintsBrowser_H + +#include "XGUI.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class ModuleBase_IDocumentDataModel; +class XGUI_DataModel; +class Config_DataModelReader; +class XGUI_Workshop; +class XGUI_ConstraintsItemDelegate; +class ModuleBase_ITreeNode; + +//#define DEBUG_INDXES + +struct FeatStruct +{ + FeaturePtr Feature; + std::vector Attributes; +}; + + +class XGUI_EXPORT XGUI_ConstraintsViewTree : public QTreeWidget +{ + Q_OBJECT +public: + /// Constructor + /// \param theParent a parent widget + XGUI_ConstraintsViewTree(QWidget* theParent = 0) : QTreeWidget(theParent) {} + + /// Returns current data model + XGUI_DataModel* dataModel() const + { + return static_cast(model()); + } + +signals: + //! Emited on context menu request + void contextMenuRequested(QContextMenuEvent* theEvent); + +protected slots: + /// Redefinition of virtual method + virtual void contextMenuEvent(QContextMenuEvent* theEvent) + { + emit contextMenuRequested(theEvent); + } + + void closeEditor(QWidget* theEditor, QAbstractItemDelegate::EndEditHint theHint); + +}; + +/**\class XGUI_SketchConstraintsBrowser + * \ingroup GUI + * \brief Object browser window object. Represents data tree of current data structure + */ +class XGUI_EXPORT XGUI_SketchConstraintsBrowser : public QWidget, public Events_Listener +{ +Q_OBJECT + public: + + // Temporary for more simple modification + XGUI_ConstraintsViewTree* getViewTree() { return myViewTree; } + + // Make more good option + bool UpdateTree(const std::vector>>& theList, bool isAddToExist = false); + + /// Constructor + /// \param theParent a parent widget + XGUI_SketchConstraintsBrowser(QWidget* theParent, XGUI_Workshop* theWorkshop); + virtual ~XGUI_SketchConstraintsBrowser(); + + /// Event Listener method + /// \param theMessage an event message + virtual void processEvent(const std::shared_ptr& theMessage); + + //! Returns list of currently selected constraints and geometries + //! \param theIndexes - output list of corresponded indexes (can be NULL) + QObjectPtrList selectedObjects(QModelIndexList* theIndexes = 0) const; + + //! Returns list of currently selected constraints in browser + //! \param theIndexes - output list of corresponded indexes (can be NULL) + QObjectPtrList selectedConstraints(QModelIndexList* theIndexes = 0) const; + + /// Set selected list of objects + /// \param theObjects list of objects to select + void setObjectsSelected(const QObjectPtrList& theObjects); + + //! Returns currently selected indexes + QModelIndexList selectedIndexes() const + { + if (myViewTree->selectionModel()) + return myViewTree->selectionModel()->selectedIndexes(); + else + return QModelIndexList(); + } + + /// Initialize the Object browser + void initialize(ModuleBase_ITreeNode* theRoot); + + /// Returns current workshop + XGUI_Workshop* workshop() const { return myWorkshop; } + + void onSelectionChanged(); + +public slots: + //! Called on Edit command request + void onEditItem(); + + //! Change state of constraints + void onDeactivateItems(); + +private slots: + void SelectStateChanged(bool theState); + +signals: + //! Emited when selection is changed + void selectionChanged(); + + //! Emited on context menu request + void contextMenuRequested(QContextMenuEvent* theEvent); + + //! Segnal is emitted when user cliks by mouse in header label of object browser + void headerMouseDblClicked(const QModelIndex&); + + //! An signal emitted on resize of the Object Browser + void sizeChanged(); + + void editValues(); + void deleteCosnstraints(); + void deactivate(bool, std::vector); + +protected: + //! redefinition of a virtual method + void resizeEvent(QResizeEvent* theEvent); + + private slots: + /// Show context menu + /// \param theEvent a context menu event + void onContextMenuRequested(QContextMenuEvent* theEvent); + + //! Called when selection in Data Tree is changed + void onSelectionChanged(const QItemSelection& theSelected, const QItemSelection& theDeselected); + + /// Slot for reaction on double click in the table (start editing) +/// \param theIndex the clicked index + void onDoubleClick(const QModelIndex& theIndex); + + /// Slot for reaction on end of cell editing + /// \param theEditor the editor widget + /// \param theHint end of edit type + void onCloseEditor(QWidget* theEditor, QAbstractItemDelegate::EndEditHint theHint); + + void onCloseEditor(); + + private: + XGUI_Workshop* myWorkshop; + + XGUI_ConstraintsViewTree* myViewTree; + QVBoxLayout* myLayout; + QHBoxLayout* myButtons; + + bool myLastState; //Store state of Extended Information CheckBox (need for correct reset after edit constraints) + QCheckBox* myExtInfo; + XGUI_ConstraintsItemDelegate* myDelegate; + + std::map> myConstrs; // string - name of group, vector - constraints from group +}; + +#endif diff --git a/src/XGUI/XGUI_Workshop.cpp b/src/XGUI/XGUI_Workshop.cpp index 6ae78b95d..b32ccd8fd 100644 --- a/src/XGUI/XGUI_Workshop.cpp +++ b/src/XGUI/XGUI_Workshop.cpp @@ -51,6 +51,8 @@ #include #include +#include + #ifdef HAVE_SALOME #include #include @@ -207,6 +209,7 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) : QObject(), myModule(NULL), myObjectBrowser(0), + mySkConstBrwsr(0), myPropertyPanel(0), myFacesPanel(0), myDisplayer(0), @@ -1624,6 +1627,29 @@ QDockWidget* XGUI_Workshop::createObjectBrowser(QWidget* theParent) return aObjDock; } +//****************************************************** +QDockWidget* XGUI_Workshop::createConstraintsBrowser(QWidget* theParent) +{ + QDockWidget* aSkDock = new QDockWidget(theParent); + aSkDock->setAllowedAreas(Qt::LeftDockWidgetArea | + Qt::RightDockWidgetArea); + aSkDock->setWindowTitle(tr("Sketch Constraints Browser")); + aSkDock->setStyleSheet( + "::title { position: relative; padding-left: 5px; text-align: left center }"); + + mySkConstBrwsr = new XGUI_SketchConstraintsBrowser(aSkDock, this); + mySkConstBrwsr->initialize(myModule->rootNode()); + //myModule->customizeObjectBrowser(mySkConstBrwsr); + aSkDock->setWidget(mySkConstBrwsr); + aSkDock->setObjectName("Constraints browser"); + + connect(mySkConstBrwsr, SIGNAL(sizeChanged()), SLOT(onDockSizeChanged())); + + mySelector->connectViewers(); + myContextMenuMgr->connectConstraintsBrowser(); + return aSkDock; +} + //****************************************************** /* * Creates dock widgets, places them in corresponding area @@ -1769,6 +1795,20 @@ void XGUI_Workshop::hideObjectBrowser() myObjectBrowser->parentWidget()->hide(); } +//****************************************************** +void XGUI_Workshop::showConstraintsBrowser() +{ + if (!isSalomeMode()) + mySkConstBrwsr->parentWidget()->show(); +} + +//****************************************************** +void XGUI_Workshop::hideConstraintsBrowser() +{ + if (!isSalomeMode()) + mySkConstBrwsr->parentWidget()->hide(); +} + //****************************************************** void XGUI_Workshop::salomeViewerSelectionChanged() { @@ -1789,6 +1829,10 @@ void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked) deleteObjects(); else if (theId == "CLEAN_HISTORY_CMD") cleanHistory(); + else if (theId == "EDIT_CONSTR_CMD") + editConstraints(); + else if (theId == "DEACTIVATE_CONSTRAINT_CMD") + deactivateCosntraint(); else if (theId == "MOVE_CMD" || theId == "MOVE_SPLIT_CMD") moveObjects(theId == "MOVE_SPLIT_CMD"); else if (theId == "RECOVER_CMD") @@ -2121,6 +2165,23 @@ void XGUI_Workshop::deleteObjects() myDisplayer->updateViewer(); } +void XGUI_Workshop::deactivateCosntraint() +{ + QObjectPtrList anObjects = constraintsBrowser()->selectedObjects(); + + constraintsBrowser()->setObjectsSelected(anObjects); + constraintsBrowser()->onDeactivateItems(); +} + +void XGUI_Workshop::editConstraints() +{ + QObjectPtrList anObjects = constraintsBrowser()->selectedObjects(); + + // restore selection in case if dialog box was shown + constraintsBrowser()->setObjectsSelected(anObjects); + constraintsBrowser()->onEditItem(); +} + //************************************************************** void addRefsToFeature(const FeaturePtr& theFeature, const std::map >& theMainList, diff --git a/src/XGUI/XGUI_Workshop.h b/src/XGUI/XGUI_Workshop.h index b6e25c670..7bc4ecc69 100644 --- a/src/XGUI/XGUI_Workshop.h +++ b/src/XGUI/XGUI_Workshop.h @@ -65,6 +65,7 @@ class XGUI_SelectionMgr; class XGUI_ViewerProxy; class XGUI_WorkshopListener; class XGUI_InspectionPanel; +class XGUI_SketchConstraintsBrowser; class ModuleBase_IModule; class ModuleBase_IViewer; @@ -88,6 +89,12 @@ Q_OBJECT XGUI_Workshop(XGUI_SalomeConnector* theConnector = 0); virtual ~XGUI_Workshop(); + /// Create Sketch constraints browser widget + /// \param theParent a parent of widget + QDockWidget* createConstraintsBrowser(QWidget* theParent); + + void removeConstrBrowser() { mySkConstBrwsr = NULL; } + /// Starting of the application void startApplication(); @@ -153,6 +160,9 @@ Q_OBJECT /// Returns Object browser XGUI_ObjectsBrowser* objectBrowser() const { return myObjectBrowser; } + /// Returns Sketch constraints browser + XGUI_SketchConstraintsBrowser* constraintsBrowser() const { return mySkConstBrwsr; } + /// This method is called by Salome module when selection is changed void salomeViewerSelectionChanged(); @@ -176,6 +186,11 @@ Q_OBJECT /// Delete features void deleteObjects(); + /// Eit constraints + void editConstraints(); + + void deactivateCosntraint(); + /// Searches for selected features unused in other (not selected) features. If one or several /// selected features are found, a warning message proposes to delete them. It contains /// the list of features to be deleted. @@ -412,6 +427,12 @@ signals: /// Hide object Browser void hideObjectBrowser(); + /// Show Sketch constraints Browser + void showConstraintsBrowser(); + + /// Hide Sketch constraints Browser + void hideConstraintsBrowser(); + /// Close document void closeDocument(); @@ -569,6 +590,7 @@ private: AppElements_MainWindow* myMainWindow; ///< desktop window #endif + XGUI_SketchConstraintsBrowser* mySkConstBrwsr; // ~~!!!!~~ ModuleBase_IModule* myModule; ///< current module XGUI_ErrorMgr* myErrorMgr; ///< updator of error message XGUI_ObjectsBrowser* myObjectBrowser; ///< data tree widget diff --git a/src/XGUI/XGUI_msg_fr.ts b/src/XGUI/XGUI_msg_fr.ts index 9d89050d2..db4f19255 100644 --- a/src/XGUI/XGUI_msg_fr.ts +++ b/src/XGUI/XGUI_msg_fr.ts @@ -552,6 +552,13 @@ Panneau de propriété + + XGUI_SketchConstraintsBrowser + + Extended Information + Informations étendues + + XGUI_TransparencyWidget -- 2.39.2