diff --git a/src/Mod/Part/App/BSplineSurfacePyImp.cpp b/src/Mod/Part/App/BSplineSurfacePyImp.cpp index 45701f8a20bc..da7f502fc6a7 100644 --- a/src/Mod/Part/App/BSplineSurfacePyImp.cpp +++ b/src/Mod/Part/App/BSplineSurfacePyImp.cpp @@ -1514,6 +1514,7 @@ PyObject* BSplineSurfacePy::buildFromPolesMultsKnots(PyObject *args, PyObject *k /*! * \code +import math c = Part.Circle() c.Radius=50 c = c.trim(0, math.pi) diff --git a/src/Mod/Surface/App/AppSurface.cpp b/src/Mod/Surface/App/AppSurface.cpp index d9e094487c96..b980c7009799 100644 --- a/src/Mod/Surface/App/AppSurface.cpp +++ b/src/Mod/Surface/App/AppSurface.cpp @@ -33,6 +33,7 @@ #include "FeatureCut.h" #include "FeatureGeomFillSurface.h" #include "FeatureExtend.h" +#include "FeatureSections.h" #include #include @@ -80,6 +81,7 @@ PyMOD_INIT_FUNC(Surface) Surface::Cut ::init(); Surface::GeomFillSurface ::init(); Surface::Extend ::init(); + Surface::Sections ::init(); PyMOD_Return(mod); } diff --git a/src/Mod/Surface/App/CMakeLists.txt b/src/Mod/Surface/App/CMakeLists.txt index 78b8a6218e03..c6bf6d8423fb 100644 --- a/src/Mod/Surface/App/CMakeLists.txt +++ b/src/Mod/Surface/App/CMakeLists.txt @@ -27,6 +27,8 @@ SET(Surface_SRCS FeatureGeomFillSurface.h FeatureFilling.cpp FeatureFilling.h + FeatureSections.cpp + FeatureSections.h FeatureSewing.cpp FeatureSewing.h FeatureCut.cpp diff --git a/src/Mod/Surface/App/FeatureSections.cpp b/src/Mod/Surface/App/FeatureSections.cpp new file mode 100644 index 000000000000..9583f8b31681 --- /dev/null +++ b/src/Mod/Surface/App/FeatureSections.cpp @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (c) 2020 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 +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "FeatureSections.h" +#include +#include + +using namespace Surface; + +PROPERTY_SOURCE(Surface::Sections, Part::Spline) + +Sections::Sections() +{ + ADD_PROPERTY_TYPE(NSections,(nullptr), "Sections", App::Prop_None, "Section curves"); + NSections.setScope(App::LinkScope::Global); +} + +Sections::~Sections() +{ +} + +App::DocumentObjectExecReturn *Sections::execute(void) +{ + TColGeom_SequenceOfCurve curveSeq; + auto edge_obj = NSections.getValues(); + auto edge_sub = NSections.getSubValues(); + if (edge_obj.size() == edge_sub.size()) { + for (std::size_t index = 0; index < edge_obj.size(); index++) { + // get the part object + App::DocumentObject* obj = edge_obj[index]; + const std::string& sub = edge_sub[index]; + if (obj && obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + // get the sub-edge of the part's shape + const Part::TopoShape& shape = static_cast(obj)->Shape.getShape(); + TopoDS_Shape edge = shape.getSubShape(sub.c_str()); + if (!edge.IsNull() && edge.ShapeType() == TopAbs_EDGE) { + BRepAdaptor_Curve curve_adapt(TopoDS::Edge(edge)); + const TopLoc_Location& loc = edge.Location(); + Handle(Geom_TrimmedCurve) hCurve = new Geom_TrimmedCurve(curve_adapt.Curve().Curve(), + curve_adapt.FirstParameter(), + curve_adapt.LastParameter()); + if (!loc.IsIdentity()) { + hCurve->Transform(loc.Transformation()); + } + curveSeq.Append(hCurve); + } + } + } + } + + if (curveSeq.Length() < 2) + return new App::DocumentObjectExecReturn("At least two sections are required."); + + GeomFill_NSections fillOp(curveSeq); + fillOp.ComputeSurface(); + + Handle(Geom_BSplineSurface) aSurf = fillOp.BSplineSurface(); + if (aSurf.IsNull()) + return new App::DocumentObjectExecReturn("Failed to create surface from sections."); + + BRepBuilderAPI_MakeFace mkFace(aSurf +#if OCC_VERSION_HEX >= 0x060502 + , Precision::Confusion() +#endif + ); + + Shape.setValue(mkFace.Face()); + return StdReturn; +} diff --git a/src/Mod/Surface/App/FeatureSections.h b/src/Mod/Surface/App/FeatureSections.h new file mode 100644 index 000000000000..065d693e0c3d --- /dev/null +++ b/src/Mod/Surface/App/FeatureSections.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (c) 2020 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 SURFACE_FEATURESECTIONS_H +#define SURFACE_FEATURESECTIONS_H + +#include +#include +#include +#include + +namespace Surface +{ + +class SurfaceExport Sections : public Part::Spline +{ + PROPERTY_HEADER_WITH_OVERRIDE(Surface::Sections); + +public: + Sections(); + ~Sections(); + + App::PropertyLinkSubList NSections; + + // recalculate the feature + App::DocumentObjectExecReturn *execute(void) override; + /// returns the type name of the view provider + const char* getViewProviderName(void) const override { + return "SurfaceGui::ViewProviderSections"; + } +}; + +}//Namespace Surface + +#endif diff --git a/src/Mod/Surface/App/PreCompiled.h b/src/Mod/Surface/App/PreCompiled.h index f44d96f62764..624b78d3e110 100644 --- a/src/Mod/Surface/App/PreCompiled.h +++ b/src/Mod/Surface/App/PreCompiled.h @@ -61,6 +61,7 @@ //opencascade #include "OpenCascadeAll.h" +#include #endif //_PreComp_ diff --git a/src/Mod/Surface/Gui/AppSurfaceGui.cpp b/src/Mod/Surface/Gui/AppSurfaceGui.cpp index 4410b2a58529..415f001c3ada 100644 --- a/src/Mod/Surface/Gui/AppSurfaceGui.cpp +++ b/src/Mod/Surface/Gui/AppSurfaceGui.cpp @@ -36,6 +36,7 @@ #include "Workbench.h" #include "TaskGeomFillSurface.h" #include "TaskFilling.h" +#include "TaskSections.h" // use a different name to CreateCommand() void CreateSurfaceCommands(void); @@ -79,6 +80,7 @@ PyMOD_INIT_FUNC(SurfaceGui) SurfaceGui::Workbench::init(); SurfaceGui::ViewProviderGeomFillSurface ::init(); SurfaceGui::ViewProviderFilling ::init(); + SurfaceGui::ViewProviderSections ::init(); // SurfaceGui::ViewProviderCut::init(); diff --git a/src/Mod/Surface/Gui/CMakeLists.txt b/src/Mod/Surface/Gui/CMakeLists.txt index 87b157949174..c09ff9601a18 100644 --- a/src/Mod/Surface/Gui/CMakeLists.txt +++ b/src/Mod/Surface/Gui/CMakeLists.txt @@ -28,6 +28,7 @@ set(SurfaceGui_MOC_HDRS TaskFillingUnbound.h TaskFillingVertex.h TaskGeomFillSurface.h + TaskSections.h ) fc_wrap_cpp(SurfaceGui_MOC_SRCS ${SurfaceGui_MOC_HDRS}) SOURCE_GROUP("Moc" FILES ${SurfaceGui_MOC_SRCS}) @@ -43,6 +44,7 @@ SET(SurfaceGui_UIC_SRCS TaskFillingUnbound.ui TaskFillingVertex.ui TaskGeomFillSurface.ui + TaskSections.ui ) if (BUILD_QT5) @@ -62,6 +64,8 @@ SET(SurfaceGui_SRCS TaskFillingVertex.h TaskGeomFillSurface.cpp TaskGeomFillSurface.h + TaskSections.cpp + TaskSections.h AppSurfaceGui.cpp Command.cpp PreCompiled.cpp diff --git a/src/Mod/Surface/Gui/Command.cpp b/src/Mod/Surface/Gui/Command.cpp index 0106c5a8bb5a..89f955ad6e97 100644 --- a/src/Mod/Surface/Gui/Command.cpp +++ b/src/Mod/Surface/Gui/Command.cpp @@ -261,6 +261,35 @@ bool CmdSurfaceExtendFace::isActive(void) return Gui::Selection().countObjectsOfType(Part::Feature::getClassTypeId()) == 1; } +DEF_STD_CMD_A(CmdSurfaceSections) + +CmdSurfaceSections::CmdSurfaceSections() + :Command("Surface_Sections") +{ + sAppModule = "Surface"; + sGroup = QT_TR_NOOP("Surface"); + sMenuText = QT_TR_NOOP("Sections..."); + sToolTipText = QT_TR_NOOP("Creates a surface from a series of section curves"); + sStatusTip = QT_TR_NOOP("Creates a surface from a series of section curves"); + sWhatsThis = "Surface_Sections"; + //sPixmap = "Surface_Sections"; +} + +void CmdSurfaceSections::activated(int iMsg) +{ + Q_UNUSED(iMsg); + std::string FeatName = getUniqueObjectName("Surface"); + + openCommand("Create surface"); + doCommand(Doc, "App.ActiveDocument.addObject(\"Surface::Sections\",\"%s\")", FeatName.c_str()); + doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", FeatName.c_str()); +} + +bool CmdSurfaceSections::isActive(void) +{ + return hasActiveDocument(); +} + void CreateSurfaceCommands(void) { Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); @@ -270,4 +299,5 @@ void CreateSurfaceCommands(void) rcCmdMgr.addCommand(new CmdSurfaceGeomFillSurface()); rcCmdMgr.addCommand(new CmdSurfaceCurveOnMesh()); rcCmdMgr.addCommand(new CmdSurfaceExtendFace()); + rcCmdMgr.addCommand(new CmdSurfaceSections()); } diff --git a/src/Mod/Surface/Gui/TaskSections.cpp b/src/Mod/Surface/Gui/TaskSections.cpp new file mode 100644 index 000000000000..b24425db54cc --- /dev/null +++ b/src/Mod/Surface/Gui/TaskSections.cpp @@ -0,0 +1,603 @@ +/*************************************************************************** + * Copyright (c) 2017 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" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TaskSections.h" +#include "ui_TaskSections.h" + + +using namespace SurfaceGui; + +PROPERTY_SOURCE(SurfaceGui::ViewProviderSections, PartGui::ViewProviderSpline) + +namespace SurfaceGui { + +void ViewProviderSections::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) +{ + QAction* act; + act = menu->addAction(QObject::tr("Edit sections"), receiver, member); + act->setData(QVariant((int)ViewProvider::Default)); + PartGui::ViewProviderSpline::setupContextMenu(menu, receiver, member); +} + +bool ViewProviderSections::setEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default ) { + // When double-clicking on the item for this sketch the + // object unsets and sets its edit mode without closing + // the task panel + + Surface::Sections* obj = static_cast(this->getObject()); + + Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); + + // start the edit dialog + if (dlg) { + TaskSections* tDlg = qobject_cast(dlg); + if (tDlg) + tDlg->setEditedObject(obj); + Gui::Control().showDialog(dlg); + } + else { + Gui::Control().showDialog(new TaskSections(this, obj)); + } + return true; + } + else { + return ViewProviderSpline::setEdit(ModNum); + } +} + +void ViewProviderSections::unsetEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default) { + // when pressing ESC make sure to close the dialog + QTimer::singleShot(0, &Gui::Control(), SLOT(closeDialog())); + } + else { + PartGui::ViewProviderSpline::unsetEdit(ModNum); + } +} + +QIcon ViewProviderSections::getIcon(void) const +{ + return Gui::BitmapFactory().pixmap("BSplineSurf"); +} + +void ViewProviderSections::highlightReferences(ShapeType type, const References& refs, bool on) +{ + for (auto it : refs) { + Part::Feature* base = dynamic_cast(it.first); + if (base) { + PartGui::ViewProviderPartExt* svp = dynamic_cast( + Gui::Application::Instance->getViewProvider(base)); + if (svp) { + switch (type) { + case ViewProviderSections::Vertex: + if (on) { + std::vector colors; + TopTools_IndexedMapOfShape vMap; + TopExp::MapShapes(base->Shape.getValue(), TopAbs_VERTEX, vMap); + colors.resize(vMap.Extent(), svp->PointColor.getValue()); + + for (auto jt : it.second) { + // check again that the index is in range because it's possible that the + // sub-names are invalid + std::size_t idx = static_cast(std::stoi(jt.substr(6)) - 1); + if (idx < colors.size()) + colors[idx] = App::Color(1.0,0.0,1.0); // magenta + } + + svp->setHighlightedPoints(colors); + } + else { + svp->unsetHighlightedPoints(); + } + break; + case ViewProviderSections::Edge: + if (on) { + std::vector colors; + TopTools_IndexedMapOfShape eMap; + TopExp::MapShapes(base->Shape.getValue(), TopAbs_EDGE, eMap); + colors.resize(eMap.Extent(), svp->LineColor.getValue()); + + for (auto jt : it.second) { + std::size_t idx = static_cast(std::stoi(jt.substr(4)) - 1); + // check again that the index is in range because it's possible that the + // sub-names are invalid + if (idx < colors.size()) + colors[idx] = App::Color(1.0,0.0,1.0); // magenta + } + + svp->setHighlightedEdges(colors); + } + else { + svp->unsetHighlightedEdges(); + } + break; + case ViewProviderSections::Face: + if (on) { + std::vector colors; + TopTools_IndexedMapOfShape fMap; + TopExp::MapShapes(base->Shape.getValue(), TopAbs_FACE, fMap); + colors.resize(fMap.Extent(), svp->ShapeColor.getValue()); + + for (auto jt : it.second) { + std::size_t idx = static_cast(std::stoi(jt.substr(4)) - 1); + // check again that the index is in range because it's possible that the + // sub-names are invalid + if (idx < colors.size()) + colors[idx] = App::Color(1.0,0.0,1.0); // magenta + } + + svp->setHighlightedFaces(colors); + } + else { + svp->unsetHighlightedFaces(); + } + break; + } + } + } + } +} + +// ---------------------------------------------------------------------------- + +class SectionsPanel::ShapeSelection : public Gui::SelectionFilterGate +{ +public: + ShapeSelection(SectionsPanel::SelectionMode& mode, Surface::Sections* editedObject) + : Gui::SelectionFilterGate(static_cast(nullptr)) + , mode(mode) + , editedObject(editedObject) + { + } + ~ShapeSelection() + { + mode = SectionsPanel::None; + } + /** + * Allow the user to pick only edges. + */ + bool allow(App::Document*, App::DocumentObject* pObj, const char* sSubName) + { + // don't allow references to itself + if (pObj == editedObject) + return false; + if (!pObj->isDerivedFrom(Part::Feature::getClassTypeId())) + return false; + + if (!sSubName || sSubName[0] == '\0') + return false; + + switch (mode) { + case SectionsPanel::AppendEdge: + return allowEdge(true, pObj, sSubName); + case SectionsPanel::RemoveEdge: + return allowEdge(false, pObj, sSubName); + default: + return false; + } + } + +private: + bool allowEdge(bool appendEdges, App::DocumentObject* pObj, const char* sSubName) + { + std::string element(sSubName); + if (element.substr(0,4) != "Edge") + return false; + + auto links = editedObject->NSections.getSubListValues(); + for (auto it : links) { + if (it.first == pObj) { + for (auto jt : it.second) { + if (jt == sSubName) + return !appendEdges; + } + } + } + + return appendEdges; + } + +private: + SectionsPanel::SelectionMode& mode; + Surface::Sections* editedObject; +}; + +// ---------------------------------------------------------------------------- + +SectionsPanel::SectionsPanel(ViewProviderSections* vp, Surface::Sections* obj) : ui(new Ui_Sections()) +{ + ui->setupUi(this); + ui->statusLabel->clear(); + + selectionMode = None; + this->vp = vp; + checkCommand = true; + setEditedObject(obj); + + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + action->setShortcut(QKeySequence::Delete); + ui->listSections->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onDeleteEdge())); + ui->listSections->setContextMenuPolicy(Qt::ActionsContextMenu); + + connect(ui->listSections->model(), + SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)), this, SLOT(onIndexesMoved())); +} + +/* + * Destroys the object and frees any allocated resources + */ +SectionsPanel::~SectionsPanel() +{ +} + +// stores object pointer, its old fill type and adjusts radio buttons according to it. +void SectionsPanel::setEditedObject(Surface::Sections* fea) +{ + editedObject = fea; + + // get the section edges + auto objects = editedObject->NSections.getValues(); + auto edges = editedObject->NSections.getSubValues(); + auto count = objects.size(); + + App::Document* doc = editedObject->getDocument(); + for (std::size_t i=0; ilistSections); + ui->listSections->addItem(item); + + QString text = QString::fromLatin1("%1.%2") + .arg(QString::fromUtf8(obj->Label.getValue())) + .arg(QString::fromStdString(edge)); + item->setText(text); + + // The user data field of a list widget item + // is a list of five elementa: + // 1. document name + // 2. object name + // 3. sub-element name of the edge + QList data; + data << QByteArray(doc->getName()); + data << QByteArray(obj->getNameInDocument()); + data << QByteArray(edge.c_str()); + item->setData(Qt::UserRole, data); + } + + // attach this document observer + attachDocument(Gui::Application::Instance->getDocument(doc)); +} + +void SectionsPanel::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + } + else { + QWidget::changeEvent(e); + } +} + +void SectionsPanel::open() +{ + checkOpenCommand(); + + // highlight the boundary edges + this->vp->highlightReferences(ViewProviderSections::Edge, + editedObject->NSections.getSubListValues(), true); + + Gui::Selection().clearSelection(); +} + +void SectionsPanel::clearSelection() +{ + Gui::Selection().clearSelection(); +} + +void SectionsPanel::checkOpenCommand() +{ + if (checkCommand && !Gui::Command::hasPendingCommand()) { + std::string Msg("Edit "); + Msg += editedObject->Label.getValue(); + Gui::Command::openCommand(Msg.c_str()); + checkCommand = false; + } +} + +void SectionsPanel::slotUndoDocument(const Gui::Document&) +{ + checkCommand = true; +} + +void SectionsPanel::slotRedoDocument(const Gui::Document&) +{ + checkCommand = true; +} + +void SectionsPanel::slotDeletedObject(const Gui::ViewProviderDocumentObject& Obj) +{ + // If this view provider is being deleted then reset the colors of + // referenced part objects. The dialog will be deleted later. + if (this->vp == &Obj) { + this->vp->highlightReferences(ViewProviderSections::Edge, + editedObject->NSections.getSubListValues(), false); + } +} + +bool SectionsPanel::accept() +{ + selectionMode = None; + Gui::Selection().rmvSelectionGate(); + + if (editedObject->mustExecute()) + editedObject->recomputeFeature(); + if (!editedObject->isValid()) { + QMessageBox::warning(this, tr("Invalid object"), + QString::fromLatin1(editedObject->getStatusString())); + return false; + } + + this->vp->highlightReferences(ViewProviderSections::Edge, + editedObject->NSections.getSubListValues(), false); + + return true; +} + +bool SectionsPanel::reject() +{ + this->vp->highlightReferences(ViewProviderSections::Edge, + editedObject->NSections.getSubListValues(), false); + + selectionMode = None; + Gui::Selection().rmvSelectionGate(); + + return true; +} + +void SectionsPanel::on_buttonEdgeAdd_clicked() +{ + // 'selectionMode' is passed by reference and changed when the filter is deleted + Gui::Selection().addSelectionGate(new ShapeSelection(selectionMode, editedObject)); + selectionMode = AppendEdge; +} + +void SectionsPanel::on_buttonEdgeRemove_clicked() +{ + // 'selectionMode' is passed by reference and changed when the filter is deleted + Gui::Selection().addSelectionGate(new ShapeSelection(selectionMode, editedObject)); + selectionMode = RemoveEdge; +} + +void SectionsPanel::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (selectionMode == None) + return; + + if (msg.Type == Gui::SelectionChanges::AddSelection) { + checkOpenCommand(); + if (selectionMode == AppendEdge) { + QListWidgetItem* item = new QListWidgetItem(ui->listSections); + ui->listSections->addItem(item); + + Gui::SelectionObject sel(msg); + QString text = QString::fromLatin1("%1.%2") + .arg(QString::fromUtf8(sel.getObject()->Label.getValue())) + .arg(QString::fromLatin1(msg.pSubName)); + item->setText(text); + + QList data; + data << QByteArray(msg.pDocName); + data << QByteArray(msg.pObjectName); + data << QByteArray(msg.pSubName); + item->setData(Qt::UserRole, data); + + appendCurve(sel.getObject(), msg.pSubName); + } + else if (selectionMode == RemoveEdge) { + Gui::SelectionObject sel(msg); + QList data; + data << QByteArray(msg.pDocName); + data << QByteArray(msg.pObjectName); + data << QByteArray(msg.pSubName); + + // only the three first elements must match + for (int i=0; ilistSections->count(); i++) { + QListWidgetItem* item = ui->listSections->item(i); + QList userdata = item->data(Qt::UserRole).toList(); + if (userdata.mid(0,3) == data) { + ui->listSections->takeItem(i); + delete item; + break; + } + } + + removeCurve(sel.getObject(), msg.pSubName); + } + + editedObject->recomputeFeature(); + QTimer::singleShot(50, this, SLOT(clearSelection())); + } +} + +void SectionsPanel::onDeleteEdge() +{ + int row = ui->listSections->currentRow(); + QListWidgetItem* item = ui->listSections->takeItem(row); + if (item) { + checkOpenCommand(); + QList data; + data = item->data(Qt::UserRole).toList(); + delete item; + + App::Document* doc = App::GetApplication().getDocument(data[0].toByteArray()); + App::DocumentObject* obj = doc ? doc->getObject(data[1].toByteArray()) : nullptr; + std::string sub = data[2].toByteArray().constData(); + + removeCurve(obj, sub); + editedObject->recomputeFeature(); + } +} + +void SectionsPanel::onIndexesMoved() +{ + QAbstractItemModel* model = qobject_cast(sender()); + if (!model) + return; + + std::vector objects; + std::vector element; + + int rows = model->rowCount(); + for (int i = 0; i < rows; i++) { + QModelIndex index = model->index(i, 0); + QList data; + data = index.data(Qt::UserRole).toList(); + + App::Document* doc = App::GetApplication().getDocument(data[0].toByteArray()); + App::DocumentObject* obj = doc ? doc->getObject(data[1].toByteArray()) : nullptr; + std::string sub = data[2].toByteArray().constData(); + + objects.push_back(obj); + element.push_back(sub); + } + + editedObject->NSections.setValues(objects, element); + editedObject->recomputeFeature(); +} + +void SectionsPanel::appendCurve(App::DocumentObject* obj, const std::string& subname) +{ + auto objects = editedObject->NSections.getValues(); + objects.push_back(obj); + auto element = editedObject->NSections.getSubValues(); + element.push_back(subname); + editedObject->NSections.setValues(objects, element); + + this->vp->highlightReferences(ViewProviderSections::Edge, + editedObject->NSections.getSubListValues(), true); +} + +void SectionsPanel::removeCurve(App::DocumentObject* obj, const std::string& subname) +{ + this->vp->highlightReferences(ViewProviderSections::Edge, + editedObject->NSections.getSubListValues(), false); + + auto objects = editedObject->NSections.getValues(); + auto element = editedObject->NSections.getSubValues(); + + auto it = objects.begin(); + auto jt = element.begin(); + for (; it != objects.end() && jt != element.end(); ++it, ++jt) { + if (*it == obj && *jt == subname) { + objects.erase(it); + element.erase(jt); + editedObject->NSections.setValues(objects, element); + break; + } + } + this->vp->highlightReferences(ViewProviderSections::Edge, + editedObject->NSections.getSubListValues(), true); + +} + +// ---------------------------------------------------------------------------- + +TaskSections::TaskSections(ViewProviderSections* vp, Surface::Sections* obj) +{ + // first task box + widget1 = new SectionsPanel(vp, obj); + Gui::TaskView::TaskBox* taskbox1 = new Gui::TaskView::TaskBox( + Gui::BitmapFactory().pixmap("BezSurf"), + widget1->windowTitle(), true, 0); + taskbox1->groupLayout()->addWidget(widget1); + Content.push_back(taskbox1); +} + +TaskSections::~TaskSections() +{ + // automatically deleted in the sub-class +} + +void TaskSections::setEditedObject(Surface::Sections* obj) +{ + widget1->setEditedObject(obj); +} + +void TaskSections::open() +{ + widget1->open(); +} + +bool TaskSections::accept() +{ + bool ok = widget1->accept(); + if (ok) { + Gui::Command::commitCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); + Gui::Command::updateActive(); + } + + return ok; +} + +bool TaskSections::reject() +{ + bool ok = widget1->reject(); + if (ok) { + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); + Gui::Command::updateActive(); + } + + return ok; +} + +} + +#include "moc_TaskSections.cpp" diff --git a/src/Mod/Surface/Gui/TaskSections.h b/src/Mod/Surface/Gui/TaskSections.h new file mode 100644 index 000000000000..03f1c5635cbf --- /dev/null +++ b/src/Mod/Surface/Gui/TaskSections.h @@ -0,0 +1,128 @@ +/*************************************************************************** + * Copyright (c) 2020 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 SURFACEGUI_TASKSECTIONS_H +#define SURFACEGUI_TASKSECTIONS_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class QListWidgetItem; + +namespace SurfaceGui +{ + +class Ui_Sections; + +class ViewProviderSections : public PartGui::ViewProviderSpline +{ + PROPERTY_HEADER(SurfaceGui::ViewProviderSections); + typedef std::vector References; + +public: + enum ShapeType {Vertex, Edge, Face}; + virtual void setupContextMenu(QMenu*, QObject*, const char*); + virtual bool setEdit(int ModNum); + virtual void unsetEdit(int ModNum); + QIcon getIcon(void) const; + void highlightReferences(ShapeType type, const References& refs, bool on); +}; + +class SectionsPanel : public QWidget, + public Gui::SelectionObserver, + public Gui::DocumentObserver +{ + Q_OBJECT + +protected: + class ShapeSelection; + enum SelectionMode { None, AppendEdge, RemoveEdge }; + SelectionMode selectionMode; + Surface::Sections* editedObject; + bool checkCommand; + +private: + std::unique_ptr ui; + ViewProviderSections* vp; + +public: + SectionsPanel(ViewProviderSections* vp, Surface::Sections* obj); + ~SectionsPanel(); + + void open(); + void checkOpenCommand(); + bool accept(); + bool reject(); + void setEditedObject(Surface::Sections* obj); + +protected: + void changeEvent(QEvent *e); + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + /** Notifies on undo */ + virtual void slotUndoDocument(const Gui::Document& Doc); + /** Notifies on redo */ + virtual void slotRedoDocument(const Gui::Document& Doc); + /** Notifies when the object is about to be removed. */ + virtual void slotDeletedObject(const Gui::ViewProviderDocumentObject& Obj); + +private Q_SLOTS: + void on_buttonEdgeAdd_clicked(); + void on_buttonEdgeRemove_clicked(); + void onDeleteEdge(void); + void clearSelection(); + void onIndexesMoved(); + +private: + void appendCurve(App::DocumentObject*, const std::string& subname); + void removeCurve(App::DocumentObject*, const std::string& subname); +}; + +class TaskSections : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskSections(ViewProviderSections* vp, Surface::Sections* obj); + ~TaskSections(); + void setEditedObject(Surface::Sections* obj); + +public: + void open(); + bool accept(); + bool reject(); + + virtual QDialogButtonBox::StandardButtons getStandardButtons() const + { return QDialogButtonBox::Ok | QDialogButtonBox::Cancel; } + +private: + SectionsPanel* widget1; +}; + +} //namespace SurfaceGui + +#endif // SURFACEGUI_TASKSECTIONS_H diff --git a/src/Mod/Surface/Gui/TaskSections.ui b/src/Mod/Surface/Gui/TaskSections.ui new file mode 100644 index 000000000000..4a32798c86d6 --- /dev/null +++ b/src/Mod/Surface/Gui/TaskSections.ui @@ -0,0 +1,83 @@ + + + SurfaceGui::Sections + + + + 0 + 0 + 293 + 443 + + + + Sections + + + + + + Sections + + + + + + <html><head/><body><p>List can be reordered by dragging</p></body></html> + + + QAbstractItemView::InternalMove + + + + + + + + + true + + + + 0 + 0 + + + + Add Edge + + + false + + + + + + + + 0 + 0 + + + + Remove Edge + + + + + + + + + Status messages + + + + + + + + + + + diff --git a/src/Mod/Surface/Gui/Workbench.cpp b/src/Mod/Surface/Gui/Workbench.cpp index 85db1ea5e90e..ad46792fa649 100644 --- a/src/Mod/Surface/Gui/Workbench.cpp +++ b/src/Mod/Surface/Gui/Workbench.cpp @@ -55,7 +55,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const *surface << "Surface_CurveOnMesh" << "Surface_ExtendFace" << "Surface_Filling" - << "Surface_GeomFillSurface"; + << "Surface_GeomFillSurface" + << "Surface_Sections"; /* *surface << "Surface_Filling"; *surface << "Surface_Cut";*/