diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index a6fb49143..d6b4b9489 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -102,12 +102,37 @@ App::DocumentObject* Body::getTipSolidFeature() return *it; } +App::DocumentObject* Body::getNextSolidFeature() +{ + std::vector features = Model.getValues(); + if (features.empty()) return NULL; + if (Tip.getValue() == features.back()) return NULL; + + std::vector::const_iterator it = std::find(features.begin(), features.end(), Tip.getValue()); + it++; // Move beyond the Tip + + // Skip sketches + while (!(*it)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + it++; + if (it == features.end()) + return NULL; + } + + return *it; +} + const bool Body::hasFeature(const App::DocumentObject* f) { std::vector features = Model.getValues(); return std::find(features.begin(), features.end(), f) != features.end(); } +const bool Body::insertMode() { + std::vector features = Model.getValues(); + if (features.empty()) return false; + return Tip.getValue() != features.back(); +} + App::DocumentObjectExecReturn *Body::execute(void) { std::vector children = Model.getValues(); diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 8fc28d5c9..49f22d4be 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -66,14 +66,25 @@ public: */ App::DocumentObject *getTipSolidFeature(); + /** + * Return the next solid feature after the Tip feature (so this only makes sense in insert mode) + * This is used by Sketchbased features in insert mode to re-route the Base property + * NOTE: Currently only PartDesign features are accepted as nextSolidFeatures + */ + App::DocumentObject *getNextSolidFeature(); + /// Return the shape of the feature preceding this feature const Part::TopoShape getPreviousSolid(const PartDesign::Feature* f); /// Return true if the feature belongs to this body const bool hasFeature(const App::DocumentObject *f); + /// Returns true if we are inserting into the feature tree instead of appending at the end + const bool insertMode(); + PyObject *getPyObject(void); + }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 31be55b6f..473e6effc 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -143,6 +144,7 @@ void CmdPartDesignBody::activated(int iMsg) doCommand(Doc,"import PartDesignGui"); doCommand(Gui,"PartDesignGui.setActivePart(App.ActiveDocument.ActiveObject)"); // Make the "Create sketch" prompt appear in the task panel + doCommand(Gui,"Gui.Selection.clearSelection()"); doCommand(Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); updateActive(); @@ -153,6 +155,53 @@ bool CmdPartDesignBody::isActive(void) return hasActiveDocument(); } +//=========================================================================== +// PartDesign_MoveTip +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignMoveTip); + +CmdPartDesignMoveTip::CmdPartDesignMoveTip() + : Command("PartDesign_MoveTip") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Insert here"); + sToolTipText = QT_TR_NOOP("Move insert point to selected feature"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_MoveTip"; +} + +void CmdPartDesignMoveTip::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = getBody(); + if(!pcActiveBody) return; + + std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); + if (features.empty()) return; + Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(pcActiveBody); + //ViewProviderBody* vpBody; + //if (vp != NULL) + // vpBody = static_cast(vp); + std::vector bodyChildren = vp->claimChildren(); + + openCommand("Move insert point to selected feature"); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),features.front()->getNameInDocument()); + + // Adjust visibility + for (std::vector::const_iterator f = bodyChildren.begin(); f != bodyChildren.end(); f++) { + if ((*f) == pcActiveBody->Tip.getValue()) + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", (*f)->getNameInDocument()); + else + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", (*f)->getNameInDocument()); + } +} + +bool CmdPartDesignMoveTip::isActive(void) +{ + return hasActiveDocument(); +} + //=========================================================================== // PartDesign_Sketch //=========================================================================== @@ -227,11 +276,26 @@ void CmdPartDesignNewSketch::activated(int iMsg) // create Sketch on Face std::string FeatName = getUniqueObjectName("Sketch"); + App::DocumentObject* nextSolidFeature = pcActiveBody->getNextSolidFeature(); openCommand("Create a Sketch on Face"); doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + if (nextSolidFeature != NULL) { + // Insert mode + doCommand(Doc,"m = App.activeDocument().%s.Model; " + "m.insert(m.index(App.activeDocument().%s.Tip) + 1, App.activeDocument().%s);" + "App.activeDocument().%s.Model = m", + pcActiveBody->getNameInDocument(), + pcActiveBody->getNameInDocument(),FeatName.c_str(), + pcActiveBody->getNameInDocument()); + } else { + doCommand(Doc,"App.activeDocument().%s.Model = " + "App.activeDocument().%s.Model + [App.activeDocument().%s]", + pcActiveBody->getNameInDocument(), + pcActiveBody->getNameInDocument(),FeatName.c_str()); + } + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s", + pcActiveBody->getNameInDocument(),FeatName.c_str()); doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the sketch placement based on its support //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); @@ -294,13 +358,27 @@ void CmdPartDesignNewSketch::activated(int iMsg) std::string FeatName = getUniqueObjectName("Sketch"); std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + ", [])"; + App::DocumentObject* nextSolidFeature = pcActiveBody->getNextSolidFeature(); openCommand("Create a new Sketch"); doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); - doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); + doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + if (nextSolidFeature != NULL) { + // Insert mode + doCommand(Doc,"m = App.activeDocument().%s.Model; " + "m.insert(m.index(App.activeDocument().%s.Tip) + 1, App.activeDocument().%s);" + "App.activeDocument().%s.Model = m", + pcActiveBody->getNameInDocument(), + pcActiveBody->getNameInDocument(),FeatName.c_str(), + pcActiveBody->getNameInDocument()); + } else { + doCommand(Doc,"App.activeDocument().%s.Model = " + "App.activeDocument().%s.Model + [App.activeDocument().%s]", + pcActiveBody->getNameInDocument(), + pcActiveBody->getNameInDocument(),FeatName.c_str()); + } + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); } } @@ -329,12 +407,13 @@ bool CmdPartDesignNewSketch::isActive(void) firstValidSketch = sketches.end(); for (std::vector::iterator s = sketches.begin(); s != sketches.end(); s++) { + //Base::Console().Error("Checking sketch %s\n", (*s)->getNameInDocument()); // Check whether this sketch is already being used by another feature // Body features don't count... std::vector inList = (*s)->getInList(); std::vector::iterator o = inList.begin(); while (o != inList.end()) { - Base::Console().Error("InList: %s\n", (*o)->getNameInDocument()); + //Base::Console().Error("Inlist: %s\n", (*o)->getNameInDocument()); if ((*o)->getTypeId().isDerivedFrom(PartDesign::Body::getClassTypeId())) o = inList.erase(o); else @@ -417,15 +496,37 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, // Find valid Body feature to set as the base feature prevSolidFeature = pcActiveBody->getTipSolidFeature(); + App::DocumentObject* nextSolidFeature = pcActiveBody->getNextSolidFeature(); FeatName = cmd->getUniqueObjectName(which.c_str()); cmd->openCommand((std::string("Make ") + which).c_str()); cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")",which.c_str(), FeatName.c_str()); if (prevSolidFeature != NULL) - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Base = App.activeDocument().%s",FeatName.c_str(),prevSolidFeature->getNameInDocument()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); + // Set Base property to previous feature + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Base = App.activeDocument().%s", + FeatName.c_str(),prevSolidFeature->getNameInDocument()); + if (nextSolidFeature != NULL) { + // Insert mode + cmd->doCommand(cmd->Doc,"m = App.activeDocument().%s.Model; " + "m.insert(m.index(App.activeDocument().%s.Tip) + 1, App.activeDocument().%s);" + "App.activeDocument().%s.Model = m", + pcActiveBody->getNameInDocument(), + pcActiveBody->getNameInDocument(),FeatName.c_str(), + pcActiveBody->getNameInDocument()); + // Reroute Base property of the next feature to this feature + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Base = App.activeDocument().%s", + nextSolidFeature->getNameInDocument(), FeatName.c_str()); + } else { + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Model = " + "App.activeDocument().%s.Model + [App.activeDocument().%s]", + pcActiveBody->getNameInDocument(), + pcActiveBody->getNameInDocument(),FeatName.c_str()); + } + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s", + pcActiveBody->getNameInDocument(),FeatName.c_str()); + + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s", + FeatName.c_str(),sketch->getNameInDocument()); } void finishSketchBased(const Gui::Command* cmd, @@ -448,6 +549,8 @@ void finishSketchBased(const Gui::Command* cmd, // #0001721: use '0' as edit value to avoid switching off selection in // ViewProviderGeometryObject::setEditViewer cmd->doCommand(cmd->Gui,"Gui.activeDocument().setEdit('%s', 0)", FeatName.c_str()); + cmd->doCommand(cmd->Gui,"Gui.Selection.clearSelection()"); + cmd->doCommand(cmd->Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); PartDesign::Body *pcActiveBody = getBody(); if (pcActiveBody) { @@ -1355,4 +1458,5 @@ void CreatePartDesignCommands(void) rcCmdMgr.addCommand(new CmdPartDesignPolarPattern()); //rcCmdMgr.addCommand(new CmdPartDesignScaled()); rcCmdMgr.addCommand(new CmdPartDesignMultiTransform()); + rcCmdMgr.addCommand(new CmdPartDesignMoveTip()); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index 8942fe356..4d48ab309 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -132,7 +132,7 @@ std::vector ViewProviderBody::claimChildren(void)const std::vector ViewProviderBody::claimChildren3D(void)const { - std::vector children = static_cast(getObject())->Model.getValues(); + //std::vector children = static_cast(getObject())->Model.getValues(); //Base::Console().Error("Body 3D claimed children:\n"); //for (std::vector::const_iterator o = children.begin(); o != children.end(); o++) // Base::Console().Error("%s\n", (*o)->getNameInDocument()); diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 088cb1a0c..85c547e32 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -36,6 +36,7 @@ #include #include +#include using namespace PartDesignGui; @@ -60,6 +61,15 @@ Workbench::~Workbench() { } +void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) const +{ + if (strcmp(recipient,"Tree") == 0) + { + if (Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) > 0 ) + *item << "PartDesign_MoveTip"; + } +} + void Workbench::activated() { Gui::Workbench::activated(); diff --git a/src/Mod/PartDesign/Gui/Workbench.h b/src/Mod/PartDesign/Gui/Workbench.h index 02220f870..f7cc4b97a 100644 --- a/src/Mod/PartDesign/Gui/Workbench.h +++ b/src/Mod/PartDesign/Gui/Workbench.h @@ -26,6 +26,12 @@ #include +namespace Gui { + +class MenuItem; + +} + namespace PartDesignGui { /** @@ -44,6 +50,9 @@ public: /** Run some actions when the workbench gets deactivated. */ virtual void deactivated(); + /// Add custom entries to the context menu + virtual void setupContextMenu(const char* recipient, Gui::MenuItem*) const; + protected: Gui::MenuItem* setupMenuBar() const; Gui::ToolBarItem* setupToolBars() const;