From 72bba68c2b9c554e13b8994c722e331dd326d1a9 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 26 Nov 2012 21:10:09 +0100 Subject: [PATCH] Add thickness function --- src/App/Document.cpp | 8 + src/App/Document.h | 2 + src/Gui/Command.cpp | 20 ++ src/Gui/Command.h | 4 + src/Gui/Document.cpp | 7 +- src/Gui/Document.h | 2 + src/Mod/Part/App/AppPart.cpp | 1 + src/Mod/Part/App/PartFeatures.cpp | 73 +++- src/Mod/Part/App/PartFeatures.h | 30 +- src/Mod/Part/Gui/AppPartGui.cpp | 1 + src/Mod/Part/Gui/CMakeLists.txt | 3 + src/Mod/Part/Gui/Command.cpp | 67 ++++ src/Mod/Part/Gui/Resources/Part.qrc | 1 + .../Gui/Resources/icons/Part_Thickness.svg | 156 +++++++++ src/Mod/Part/Gui/TaskOffset.cpp | 4 + src/Mod/Part/Gui/TaskOffset.ui | 73 ++-- src/Mod/Part/Gui/TaskThickness.cpp | 313 ++++++++++++++++++ src/Mod/Part/Gui/TaskThickness.h | 87 +++++ src/Mod/Part/Gui/ViewProviderMirror.cpp | 82 +++++ src/Mod/Part/Gui/ViewProviderMirror.h | 20 ++ src/Mod/Part/Gui/Workbench.cpp | 5 +- 21 files changed, 926 insertions(+), 33 deletions(-) create mode 100644 src/Mod/Part/Gui/Resources/icons/Part_Thickness.svg create mode 100644 src/Mod/Part/Gui/TaskThickness.cpp create mode 100644 src/Mod/Part/Gui/TaskThickness.h diff --git a/src/App/Document.cpp b/src/App/Document.cpp index abea1441b..6f6a344c6 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -345,6 +345,14 @@ void Document::abortTransaction() } } +bool Document::hasPendingTransaction() const +{ + if (d->activeUndoTransaction) + return true; + else + return false; +} + void Document::clearUndos() { if (d->activeUndoTransaction) diff --git a/src/App/Document.h b/src/App/Document.h index c8dd9d830..a5eec2ddf 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -208,6 +208,8 @@ public: void commitTransaction(); /// Abort the actually running transaction. void abortTransaction(); + /// Check if a transaction is open + bool hasPendingTransaction() const; /// Set the Undo limit in Byte! void setUndoLimit(unsigned int UndoMemSize=0); /// Returns the actual memory consumption of the Undo redo stuff. diff --git a/src/Gui/Command.cpp b/src/Gui/Command.cpp index f66adf95e..2e1082ca2 100644 --- a/src/Gui/Command.cpp +++ b/src/Gui/Command.cpp @@ -23,6 +23,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include # include # include # include @@ -389,6 +390,11 @@ void Command::abortCommand(void) Gui::Application::Instance->activeDocument()->abortCommand(); } +bool Command::hasPendingCommand(void) +{ + return Gui::Application::Instance->activeDocument()->hasPendingCommand(); +} + bool Command::_blockCmd = false; void Command::blockCommand(bool block) @@ -447,6 +453,20 @@ void Command::copyVisual(const char* to, const char* attr_to, const char* from, doCommand(Gui,"Gui.ActiveDocument.%s.%s=Gui.ActiveDocument.%s.%s", to, attr_to, from, attr_from); } +std::string Command::getPythonTuple(const std::string& name, const std::vector& subnames) +{ + std::stringstream str; + std::vector::const_iterator last = --subnames.end(); + str << "(App.ActiveDocument." << name << ",["; + for (std::vector::const_iterator it = subnames.begin();it!=subnames.end();++it){ + str << "\"" << *it << "\""; + if (it != last) + str << ","; + } + str << "])"; + return str.str(); +} + const std::string Command::strToPython(const char* Str) { return Base::InterpreterSingleton::strToPython(Str); diff --git a/src/Gui/Command.h b/src/Gui/Command.h index 5cd3c3c54..5c5035bdd 100644 --- a/src/Gui/Command.h +++ b/src/Gui/Command.h @@ -209,6 +209,8 @@ public: static void commitCommand(void); /// Abort the Undo transaction on the active document static void abortCommand(void); + /// Check if an Undo transaction is open on the active document + static bool hasPendingCommand(void); /// Updates the (active) document (propagate changes) static void updateActive(void); /// Updates the (all or listed) documents (propagate changes) @@ -237,6 +239,8 @@ public: static void runCommand(DoCmd_Type eType,const char* sCmd); static void copyVisual(const char* to, const char* attr, const char* from); static void copyVisual(const char* to, const char* attr_to, const char* from, const char* attr_from); + /// Get Python tuple from object and sub-elements + static std::string getPythonTuple(const std::string& name, const std::vector& subnames); /// import an external module only once //static void addModule(const char* sModuleName); /// translate a string to a python string literal (needed e.g. in file names for windows...) diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index 4bab9e58b..ef2e72793 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -1090,7 +1090,12 @@ void Document::commitCommand(void) void Document::abortCommand(void) { - getDocument()->abortTransaction(); + getDocument()->abortTransaction(); +} + +bool Document::hasPendingCommand(void) const +{ + return getDocument()->hasPendingTransaction(); } /// Get a string vector with the 'Undo' actions diff --git a/src/Gui/Document.h b/src/Gui/Document.h index dc1acd875..a6b933f20 100644 --- a/src/Gui/Document.h +++ b/src/Gui/Document.h @@ -181,6 +181,8 @@ public: void commitCommand(void); /// Abort the Undo transaction on the document void abortCommand(void); + /// Check if an Undo transaction is open + bool hasPendingCommand(void) const; /// Get an Undo string vector with the Undo names std::vector getUndoVector(void) const; /// Get an Redo string vector with the Redo names diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index a31156dc1..ac22ca8cc 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -199,6 +199,7 @@ void PartExport initPart() Part::Loft ::init(); Part::Sweep ::init(); Part::Offset ::init(); + Part::Thickness ::init(); // Geometry types Part::Geometry ::init(); diff --git a/src/Mod/Part/App/PartFeatures.cpp b/src/Mod/Part/App/PartFeatures.cpp index 71c732bf7..8be9d8ced 100644 --- a/src/Mod/Part/App/PartFeatures.cpp +++ b/src/Mod/Part/App/PartFeatures.cpp @@ -375,11 +375,6 @@ short Offset::mustExecute() const return 0; } -void Offset::onChanged(const App::Property* prop) -{ - Part::Feature::onChanged(prop); -} - App::DocumentObjectExecReturn *Offset::execute(void) { App::DocumentObject* source = Source.getValue(); @@ -399,3 +394,71 @@ App::DocumentObjectExecReturn *Offset::execute(void) this->Shape.setValue(shape); return App::DocumentObject::StdReturn; } + +// ---------------------------------------------------------------------------- + +const char* Part::Thickness::ModeEnums[]= {"Skin","Pipe", "RectoVerso",NULL}; +const char* Part::Thickness::JoinEnums[]= {"Arc","Tangent", "Intersection",NULL}; + +PROPERTY_SOURCE(Part::Thickness, Part::Feature) + +Thickness::Thickness() +{ + ADD_PROPERTY_TYPE(Faces,(0),"Thickness",App::Prop_None,"Source shape"); + ADD_PROPERTY_TYPE(Value,(1.0),"Thickness",App::Prop_None,"Thickness value"); + ADD_PROPERTY_TYPE(Mode,(long(0)),"Thickness",App::Prop_None,"Mode"); + Mode.setEnums(ModeEnums); + ADD_PROPERTY_TYPE(Join,(long(0)),"Thickness",App::Prop_None,"Join type"); + Join.setEnums(JoinEnums); + ADD_PROPERTY_TYPE(Intersection,(false),"Thickness",App::Prop_None,"Intersection"); + ADD_PROPERTY_TYPE(SelfIntersection,(false),"Thickness",App::Prop_None,"Self Intersection"); +} + +short Thickness::mustExecute() const +{ + if (Faces.isTouched()) + return 1; + if (Value.isTouched()) + return 1; + if (Mode.isTouched()) + return 1; + if (Join.isTouched()) + return 1; + if (Intersection.isTouched()) + return 1; + if (SelfIntersection.isTouched()) + return 1; + return 0; +} + +App::DocumentObjectExecReturn *Thickness::execute(void) +{ + App::DocumentObject* source = Faces.getValue(); + if (!(source && source->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))) + return new App::DocumentObjectExecReturn("No source shape linked."); + const TopoShape& shape = static_cast(source)->Shape.getShape(); + if (shape.isNull()) + return new App::DocumentObjectExecReturn("Source shape is empty."); + if (shape._Shape.ShapeType() != TopAbs_SOLID) + return new App::DocumentObjectExecReturn("Source shape is not a solid."); + + TopTools_ListOfShape closingFaces; + const std::vector& subStrings = Faces.getSubValues(); + for (std::vector::const_iterator it = subStrings.begin(); it != subStrings.end(); ++it) { + TopoDS_Face face = TopoDS::Face(shape.getSubShape(it->c_str())); + closingFaces.Append(face); + } + + double thickness = Value.getValue(); + double tol = Precision::Confusion(); + bool inter = Intersection.getValue(); + bool self = SelfIntersection.getValue(); + short mode = (short)Mode.getValue(); + short join = (short)Join.getValue(); + + if (fabs(thickness) > 2*tol) + this->Shape.setValue(shape.makeThickSolid(closingFaces, thickness, tol, inter, self, mode, join)); + else + this->Shape.setValue(shape); + return App::DocumentObject::StdReturn; +} diff --git a/src/Mod/Part/App/PartFeatures.h b/src/Mod/Part/App/PartFeatures.h index 1a26bd40b..b1c69f2af 100644 --- a/src/Mod/Part/App/PartFeatures.h +++ b/src/Mod/Part/App/PartFeatures.h @@ -132,8 +132,34 @@ public: } //@} -protected: - void onChanged (const App::Property* prop); +private: + static const char* ModeEnums[]; + static const char* JoinEnums[]; +}; + +class Thickness : public Part::Feature +{ + PROPERTY_HEADER(Part::Thickness); + +public: + Thickness(); + + App::PropertyLinkSub Faces; + App::PropertyFloat Value; + App::PropertyEnumeration Mode; + App::PropertyEnumeration Join; + App::PropertyBool Intersection; + App::PropertyBool SelfIntersection; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + const char* getViewProviderName(void) const { + return "PartGui::ViewProviderThickness"; + } + //@} private: static const char* ModeEnums[]; diff --git a/src/Mod/Part/Gui/AppPartGui.cpp b/src/Mod/Part/Gui/AppPartGui.cpp index e030eaae1..17b65090a 100644 --- a/src/Mod/Part/Gui/AppPartGui.cpp +++ b/src/Mod/Part/Gui/AppPartGui.cpp @@ -106,6 +106,7 @@ void PartGuiExport initPartGui() PartGui::ViewProviderLoft ::init(); PartGui::ViewProviderSweep ::init(); PartGui::ViewProviderOffset ::init(); + PartGui::ViewProviderThickness ::init(); PartGui::ViewProviderCustom ::init(); PartGui::ViewProviderCustomPython ::init(); PartGui::ViewProviderBoolean ::init(); diff --git a/src/Mod/Part/Gui/CMakeLists.txt b/src/Mod/Part/Gui/CMakeLists.txt index e138c13ec..15f0d3335 100644 --- a/src/Mod/Part/Gui/CMakeLists.txt +++ b/src/Mod/Part/Gui/CMakeLists.txt @@ -43,6 +43,7 @@ set(PartGui_MOC_HDRS TaskLoft.h TaskOffset.h TaskSweep.h + TaskThickness.h TaskCheckGeometry.h ) fc_wrap_cpp(PartGui_MOC_SRCS ${PartGui_MOC_HDRS}) @@ -166,6 +167,8 @@ SET(PartGui_SRCS TaskSweep.cpp TaskSweep.h TaskSweep.ui + TaskThickness.cpp + TaskThickness.h TaskCheckGeometry.cpp TaskCheckGeometry.h ) diff --git a/src/Mod/Part/Gui/Command.cpp b/src/Mod/Part/Gui/Command.cpp index 3db0f6c63..7c0673766 100644 --- a/src/Mod/Part/Gui/Command.cpp +++ b/src/Mod/Part/Gui/Command.cpp @@ -1035,6 +1035,72 @@ bool CmdPartOffset::isActive(void) //-------------------------------------------------------------------------------------- +DEF_STD_CMD_A(CmdPartThickness); + +CmdPartThickness::CmdPartThickness() + : Command("Part_Thickness") +{ + sAppModule = "Part"; + sGroup = QT_TR_NOOP("Part"); + sMenuText = QT_TR_NOOP("Thickness..."); + sToolTipText = QT_TR_NOOP("Utility to apply a thickness"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Part_Thickness"; +} + +void CmdPartThickness::activated(int iMsg) +{ + Gui::SelectionFilter faceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1.."); + if (!faceFilter.match()) { + QMessageBox::warning(Gui::getMainWindow(), + QApplication::translate("CmdPartThickness", "Wrong selection"), + QApplication::translate("CmdPartThickness", "Selected one or more faces of a shape")); + return; + } + + // get the selected object + const std::vector& result = faceFilter.Result[0]; + std::string selection = result.front().getAsPropertyLinkSubString(); + + const Part::Feature* shape = static_cast(result.front().getObject()); + if (shape->Shape.getValue().IsNull()) + return; + if (shape->Shape.getValue().ShapeType() != TopAbs_SOLID) { + QMessageBox::warning(Gui::getMainWindow(), + QApplication::translate("CmdPartThickness", "Wrong selection"), + QApplication::translate("CmdPartThickness", "Selected shape is not a solid")); + return; + } + + std::string thick = getUniqueObjectName("Thickness"); + + openCommand("Make Thickness"); + doCommand(Doc,"App.ActiveDocument.addObject(\"Part::Thickness\",\"%s\")",thick.c_str()); + doCommand(Doc,"App.ActiveDocument.%s.Faces = %s" ,thick.c_str(), selection.c_str()); + doCommand(Doc,"App.ActiveDocument.%s.Value = 1.0",thick.c_str()); + updateActive(); + if (isActiveObjectValid()) + doCommand(Gui,"Gui.ActiveDocument.hide(\"%s\")",shape->getNameInDocument()); + doCommand(Gui,"Gui.ActiveDocument.setEdit('%s')",thick.c_str()); + + //commitCommand(); + adjustCameraPosition(); + + copyVisual(thick.c_str(), "ShapeColor", shape->getNameInDocument()); + copyVisual(thick.c_str(), "LineColor" , shape->getNameInDocument()); + copyVisual(thick.c_str(), "PointColor", shape->getNameInDocument()); +} + +bool CmdPartThickness::isActive(void) +{ + Base::Type partid = Base::Type::fromName("Part::Feature"); + bool objectsSelected = Gui::Selection().countObjectsOfType(partid) > 0; + return (objectsSelected && !Gui::Control().activeDialog()); +} + +//-------------------------------------------------------------------------------------- + DEF_STD_CMD_A(CmdShapeInfo); CmdShapeInfo::CmdShapeInfo() @@ -1306,5 +1372,6 @@ void CreatePartCommands(void) rcCmdMgr.addCommand(new CmdPartLoft()); rcCmdMgr.addCommand(new CmdPartSweep()); rcCmdMgr.addCommand(new CmdPartOffset()); + rcCmdMgr.addCommand(new CmdPartThickness()); rcCmdMgr.addCommand(new CmdCheckGeometry()); } diff --git a/src/Mod/Part/Gui/Resources/Part.qrc b/src/Mod/Part/Gui/Resources/Part.qrc index 61315158a..9246ffeb3 100644 --- a/src/Mod/Part/Gui/Resources/Part.qrc +++ b/src/Mod/Part/Gui/Resources/Part.qrc @@ -27,6 +27,7 @@ icons/Part_ShapeInfo.svg icons/Part_Sphere.svg icons/Part_Sweep.svg + icons/Part_Thickness.svg icons/Part_Torus.svg icons/preferences-part_design.svg icons/Tree_Part.svg diff --git a/src/Mod/Part/Gui/Resources/icons/Part_Thickness.svg b/src/Mod/Part/Gui/Resources/icons/Part_Thickness.svg new file mode 100644 index 000000000..f674c05f5 --- /dev/null +++ b/src/Mod/Part/Gui/Resources/icons/Part_Thickness.svg @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/Mod/Part/Gui/TaskOffset.cpp b/src/Mod/Part/Gui/TaskOffset.cpp index 3741b792b..5e7ded50f 100644 --- a/src/Mod/Part/Gui/TaskOffset.cpp +++ b/src/Mod/Part/Gui/TaskOffset.cpp @@ -67,6 +67,8 @@ public: OffsetWidget::OffsetWidget(Part::Offset* offset, QWidget* parent) : d(new Private()) { + if (!Gui::Command::hasPendingCommand()) + Gui::Command::openCommand("Edit offset"); Gui::Application::Instance->runPythonCode("from FreeCAD import Base"); Gui::Application::Instance->runPythonCode("import Part"); @@ -75,6 +77,7 @@ OffsetWidget::OffsetWidget(Part::Offset* offset, QWidget* parent) d->ui.spinOffset->setValue(d->offset->Value.getValue()); d->ui.spinOffset->setRange(-INT_MAX, INT_MAX); d->ui.spinOffset->setSingleStep(0.1); + d->ui.facesButton->hide(); } OffsetWidget::~OffsetWidget() @@ -177,6 +180,7 @@ bool OffsetWidget::reject() // roll back the done things Gui::Command::abortCommand(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); + Gui::Command::updateActive(); return true; } diff --git a/src/Mod/Part/Gui/TaskOffset.ui b/src/Mod/Part/Gui/TaskOffset.ui index 3cd639c69..5b6333ddf 100644 --- a/src/Mod/Part/Gui/TaskOffset.ui +++ b/src/Mod/Part/Gui/TaskOffset.ui @@ -6,8 +6,8 @@ 0 0 - 256 - 260 + 264 + 244 @@ -21,7 +21,7 @@ - + @@ -31,7 +31,7 @@ - + @@ -57,7 +57,7 @@ - + @@ -83,30 +83,13 @@ - + Self-intersection - - - - Qt::Horizontal - - - - - - - Update view - - - true - - - @@ -114,6 +97,50 @@ + + + + + + + + + + + Faces + + + + + + + Qt::Horizontal + + + + 152 + 20 + + + + + + + + Qt::Horizontal + + + + + + + Update view + + + true + + + diff --git a/src/Mod/Part/Gui/TaskThickness.cpp b/src/Mod/Part/Gui/TaskThickness.cpp new file mode 100644 index 000000000..cc0fa1230 --- /dev/null +++ b/src/Mod/Part/Gui/TaskThickness.cpp @@ -0,0 +1,313 @@ +/*************************************************************************** + * Copyright (c) 2012 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +# include +# include +# include +#endif + +#include "ui_TaskOffset.h" +#include "TaskThickness.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +using namespace PartGui; + +class ThicknessWidget::Private +{ +public: + Ui_TaskOffset ui; + QEventLoop loop; + QString text; + std::string selection; + Part::Thickness* thickness; + bool edit; + Private() : edit(false) + { + } + ~Private() + { + } + + class FaceSelection : public Gui::SelectionFilterGate + { + const App::DocumentObject* object; + public: + FaceSelection(const App::DocumentObject* obj) + : Gui::SelectionFilterGate((Gui::SelectionFilter*)0), object(obj) + { + } + bool allow(App::Document*pDoc, App::DocumentObject*pObj, const char*sSubName) + { + if (pObj != this->object) + return false; + if (!sSubName || sSubName[0] == '\0') + return false; + std::string element(sSubName); + return element.substr(0,4) == "Face"; + } + }; +}; + +/* TRANSLATOR PartGui::ThicknessWidget */ + +ThicknessWidget::ThicknessWidget(Part::Thickness* thickness, QWidget* parent) + : d(new Private()) +{ + if (!Gui::Command::hasPendingCommand()) { + d->edit = true; + Gui::Command::openCommand("Edit thickness"); + } + Gui::Application::Instance->runPythonCode("from FreeCAD import Base"); + Gui::Application::Instance->runPythonCode("import Part"); + + d->thickness = thickness; + d->ui.setupUi(this); + d->ui.spinOffset->setValue(d->thickness->Value.getValue()); + d->ui.spinOffset->setRange(-INT_MAX, INT_MAX); + d->ui.spinOffset->setSingleStep(0.1); + d->ui.labelOffset->setText(tr("Thickness")); + d->ui.fillOffset->hide(); +} + +ThicknessWidget::~ThicknessWidget() +{ + delete d; +} + +Part::Thickness* ThicknessWidget::getObject() const +{ + return d->thickness; +} + +void ThicknessWidget::on_spinOffset_valueChanged(double val) +{ + d->thickness->Value.setValue((float)val); + if (d->ui.updateView->isChecked()) + d->thickness->getDocument()->recomputeFeature(d->thickness); +} + +void ThicknessWidget::on_modeType_activated(int val) +{ + d->thickness->Mode.setValue(val); + if (d->ui.updateView->isChecked()) + d->thickness->getDocument()->recomputeFeature(d->thickness); +} + +void ThicknessWidget::on_joinType_activated(int val) +{ + d->thickness->Join.setValue((float)val); + if (d->ui.updateView->isChecked()) + d->thickness->getDocument()->recomputeFeature(d->thickness); +} + +void ThicknessWidget::on_intersection_toggled(bool on) +{ + d->thickness->Intersection.setValue(on); + if (d->ui.updateView->isChecked()) + d->thickness->getDocument()->recomputeFeature(d->thickness); +} + +void ThicknessWidget::on_selfIntersection_toggled(bool on) +{ + d->thickness->SelfIntersection.setValue(on); + if (d->ui.updateView->isChecked()) + d->thickness->getDocument()->recomputeFeature(d->thickness); +} + +void ThicknessWidget::on_facesButton_clicked() +{ + if (!d->loop.isRunning()) { + QList c = this->findChildren(); + for (QList::iterator it = c.begin(); it != c.end(); ++it) + (*it)->setEnabled(false); + d->ui.facesButton->setEnabled(true); + d->ui.labelFaces->setText(tr("Select faces of the source object and press 'Done'")); + d->ui.labelFaces->setEnabled(true); + d->text = d->ui.facesButton->text(); + d->ui.facesButton->setText(tr("Done")); + + Gui::Application::Instance->showViewProvider(d->thickness->Faces.getValue()); + Gui::Application::Instance->hideViewProvider(d->thickness); + Gui::Selection().clearSelection(); + Gui::Selection().addSelectionGate(new Private::FaceSelection(d->thickness->Faces.getValue())); + d->loop.exec(); + } + else { + QList c = this->findChildren(); + for (QList::iterator it = c.begin(); it != c.end(); ++it) + (*it)->setEnabled(true); + d->ui.facesButton->setText(d->text); + d->ui.labelFaces->clear(); + d->loop.quit(); + + d->selection = Gui::Command::getPythonTuple + (d->thickness->Faces.getValue()->getNameInDocument(), d->thickness->Faces.getSubValues()); + std::vector sel = Gui::Selection().getSelectionEx(); + for (std::vector::iterator it = sel.begin(); it != sel.end(); ++it) { + if (it->getObject() == d->thickness->Faces.getValue()) { + d->thickness->Faces.setValue(it->getObject(), it->getSubNames()); + d->selection = it->getAsPropertyLinkSubString(); + break; + } + } + + Gui::Selection().rmvSelectionGate(); + Gui::Application::Instance->showViewProvider(d->thickness); + Gui::Application::Instance->hideViewProvider(d->thickness->Faces.getValue()); + if (d->ui.updateView->isChecked()) + d->thickness->getDocument()->recomputeFeature(d->thickness); + } +} + +void ThicknessWidget::on_updateView_toggled(bool on) +{ + if (on) { + d->thickness->getDocument()->recomputeFeature(d->thickness); + } +} + +bool ThicknessWidget::accept() +{ + if (d->loop.isRunning()) + return false; + + std::string name = d->thickness->getNameInDocument(); + try { + if (!d->selection.empty()) { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Faces = %s", + name.c_str(),d->selection.c_str()); + } + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Value = %f", + name.c_str(),d->ui.spinOffset->value()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Mode = %i", + name.c_str(),d->ui.modeType->currentIndex()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Join = %i", + name.c_str(),d->ui.joinType->currentIndex()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Intersection = %s", + name.c_str(),d->ui.intersection->isChecked() ? "True" : "False"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.SelfIntersection = %s", + name.c_str(),d->ui.selfIntersection->isChecked() ? "True" : "False"); + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + if (!d->thickness->isValid()) + throw Base::Exception(d->thickness->getStatusString()); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); + Gui::Command::commitCommand(); + } + catch (const Base::Exception& e) { + QMessageBox::warning(this, tr("Input error"), QString::fromAscii(e.what())); + return false; + } + + return true; +} + +bool ThicknessWidget::reject() +{ + if (d->loop.isRunning()) + return false; + // object has been created right before opening this panel + if (d->edit == false) { + App::DocumentObject* source = d->thickness->Faces.getValue(); + if (source){ + Gui::Application::Instance->getViewProvider(source)->show(); + } + } + + // roll back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); + Gui::Command::updateActive(); + + return true; +} + +void ThicknessWidget::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + d->ui.retranslateUi(this); + d->ui.labelOffset->setText(tr("Thickness")); + } +} + + +/* TRANSLATOR PartGui::TaskThickness */ + +TaskThickness::TaskThickness(Part::Thickness* offset) +{ + widget = new ThicknessWidget(offset); + widget->setWindowTitle(ThicknessWidget::tr("Thickness")); + taskbox = new Gui::TaskView::TaskBox( + Gui::BitmapFactory().pixmap("Part_Thickness"), + widget->windowTitle(), true, 0); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskThickness::~TaskThickness() +{ +} + +Part::Thickness* TaskThickness::getObject() const +{ + return widget->getObject(); +} + +void TaskThickness::open() +{ +} + +void TaskThickness::clicked(int) +{ +} + +bool TaskThickness::accept() +{ + return widget->accept(); +} + +bool TaskThickness::reject() +{ + return widget->reject(); +} + +#include "moc_TaskThickness.cpp" diff --git a/src/Mod/Part/Gui/TaskThickness.h b/src/Mod/Part/Gui/TaskThickness.h new file mode 100644 index 000000000..ab383cfdf --- /dev/null +++ b/src/Mod/Part/Gui/TaskThickness.h @@ -0,0 +1,87 @@ +/*************************************************************************** + * Copyright (c) 2012 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef PARTGUI_TASKTHICKNESS_H +#define PARTGUI_TASKTHICKNESS_H + +#include +#include + +namespace Part { class Thickness; } +namespace PartGui { + +class ThicknessWidget : public QWidget +{ + Q_OBJECT + +public: + ThicknessWidget(Part::Thickness*, QWidget* parent = 0); + ~ThicknessWidget(); + + bool accept(); + bool reject(); + Part::Thickness* getObject() const; + +private Q_SLOTS: + void on_spinOffset_valueChanged(double); + void on_modeType_activated(int); + void on_joinType_activated(int); + void on_intersection_toggled(bool); + void on_selfIntersection_toggled(bool); + void on_facesButton_clicked(); + void on_updateView_toggled(bool); + +private: + void changeEvent(QEvent *e); + +private: + class Private; + Private* d; +}; + +class TaskThickness : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskThickness(Part::Thickness*); + ~TaskThickness(); + +public: + void open(); + bool accept(); + bool reject(); + void clicked(int); + Part::Thickness* getObject() const; + + QDialogButtonBox::StandardButtons getStandardButtons() const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } + +private: + ThicknessWidget* widget; + Gui::TaskView::TaskBox* taskbox; +}; + +} //namespace PartGui + +#endif // PARTGUI_TASKTHICKNESS_H diff --git a/src/Mod/Part/Gui/ViewProviderMirror.cpp b/src/Mod/Part/Gui/ViewProviderMirror.cpp index 3e25af0e5..00af752d4 100644 --- a/src/Mod/Part/Gui/ViewProviderMirror.cpp +++ b/src/Mod/Part/Gui/ViewProviderMirror.cpp @@ -47,6 +47,7 @@ #include "ViewProviderMirror.h" #include "DlgFilletEdges.h" #include "TaskOffset.h" +#include "TaskThickness.h" using namespace PartGui; @@ -477,3 +478,84 @@ bool ViewProviderOffset::onDelete(const std::vector &) return true; } + +// --------------------------------------- + +PROPERTY_SOURCE(PartGui::ViewProviderThickness, PartGui::ViewProviderPart) + +ViewProviderThickness::ViewProviderThickness() +{ + sPixmap = "Part_Thickness"; +} + +ViewProviderThickness::~ViewProviderThickness() +{ +} + +void ViewProviderThickness::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) +{ + QAction* act; + act = menu->addAction(QObject::tr("Edit thickness"), receiver, member); + act->setData(QVariant((int)ViewProvider::Default)); + PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member); +} + +bool ViewProviderThickness::setEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default ) { + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); + TaskThickness* thicknessDlg = qobject_cast(dlg); + if (thicknessDlg && thicknessDlg->getObject() != this->getObject()) + thicknessDlg = 0; // another pad left open its task panel + if (dlg && !thicknessDlg) { + if (dlg->canClose()) + Gui::Control().closeDialog(); + else + return false; + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // start the edit dialog + if (thicknessDlg) + Gui::Control().showDialog(thicknessDlg); + else + Gui::Control().showDialog(new TaskThickness(static_cast(getObject()))); + + return true; + } + else { + return ViewProviderPart::setEdit(ModNum); + } +} + +void ViewProviderThickness::unsetEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default) { + // when pressing ESC make sure to close the dialog + Gui::Control().closeDialog(); + } + else { + PartGui::ViewProviderPart::unsetEdit(ModNum); + } +} + +std::vector ViewProviderThickness::claimChildren() const +{ + std::vector child; + child.push_back(static_cast(getObject())->Faces.getValue()); + return child; +} + +bool ViewProviderThickness::onDelete(const std::vector &) +{ + // get the support and Sketch + Part::Thickness* thickness = static_cast(getObject()); + App::DocumentObject* source = thickness->Faces.getValue(); + if (source){ + Gui::Application::Instance->getViewProvider(source)->show(); + } + + return true; +} diff --git a/src/Mod/Part/Gui/ViewProviderMirror.h b/src/Mod/Part/Gui/ViewProviderMirror.h index 407e06851..c747d74b6 100644 --- a/src/Mod/Part/Gui/ViewProviderMirror.h +++ b/src/Mod/Part/Gui/ViewProviderMirror.h @@ -158,6 +158,26 @@ protected: virtual void unsetEdit(int ModNum); }; +class ViewProviderThickness : public ViewProviderPart +{ + PROPERTY_HEADER(PartGui::ViewProviderThickness); + +public: + /// constructor + ViewProviderThickness(); + /// destructor + virtual ~ViewProviderThickness(); + + /// grouping handling + std::vector claimChildren(void)const; + void setupContextMenu(QMenu*, QObject*, const char*); + bool onDelete(const std::vector &); + +protected: + virtual bool setEdit(int ModNum); + virtual void unsetEdit(int ModNum); +}; + } // namespace PartGui diff --git a/src/Mod/Part/Gui/Workbench.cpp b/src/Mod/Part/Gui/Workbench.cpp index 3563c82ed..9aa0cd85e 100644 --- a/src/Mod/Part/Gui/Workbench.cpp +++ b/src/Mod/Part/Gui/Workbench.cpp @@ -72,7 +72,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Part_SimpleCopy" << "Part_RefineShape" << "Part_CheckGeometry" << "Separator" << "Part_Boolean" << "Part_CrossSections" << "Part_Extrude" << "Part_Revolve" << "Part_Mirror" << "Part_Fillet" << "Part_Chamfer" - << "Part_RuledSurface" << "Part_Loft" << "Part_Sweep" << "Part_Offset"; + << "Part_RuledSurface" << "Part_Loft" << "Part_Sweep" + << "Part_Offset" << "Part_Thickness"; return root; } @@ -90,7 +91,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const tool->setCommand("Part tools"); *tool << "Part_Extrude" << "Part_Revolve" << "Part_Mirror" << "Part_Fillet" << "Part_Chamfer" << "Part_RuledSurface" << "Part_Loft" << "Part_Sweep" - << "Part_Offset"; + << "Part_Offset" << "Part_Thickness"; Gui::ToolBarItem* boolop = new Gui::ToolBarItem(root); boolop->setCommand("Boolean");