From f96d374250c460e410df334de5b01edb0fe75379 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 15 Apr 2017 19:06:35 +0200 Subject: [PATCH] improve usability of surface function --- src/Mod/Surface/Gui/Command.cpp | 100 +-------- src/Mod/Surface/Gui/SurfaceFilling.cpp | 290 +++++++++++++++++++------ src/Mod/Surface/Gui/SurfaceFilling.h | 138 +++++++----- src/Mod/Surface/Gui/SurfaceFilling.ui | 43 +++- 4 files changed, 359 insertions(+), 212 deletions(-) diff --git a/src/Mod/Surface/Gui/Command.cpp b/src/Mod/Surface/Gui/Command.cpp index 31a54eea1e..8e4adea597 100644 --- a/src/Mod/Surface/Gui/Command.cpp +++ b/src/Mod/Surface/Gui/Command.cpp @@ -156,8 +156,8 @@ CmdSurfaceBSurf::CmdSurfaceBSurf() { sAppModule = "Surface"; sGroup = QT_TR_NOOP("Surface"); - sMenuText = QT_TR_NOOP("Bezier or BSpline surface"); - sToolTipText = QT_TR_NOOP("Creates a surface from 2, 3 or 4 Bezier or B-spline curves"); + sMenuText = QT_TR_NOOP("Fill boundary curves"); + sToolTipText = QT_TR_NOOP("Creates a surface from two, three or four boundary edges"); sWhatsThis = "Surface_BSurf"; sStatusTip = sToolTipText; sPixmap = "BSplineSurf"; @@ -165,102 +165,16 @@ CmdSurfaceBSurf::CmdSurfaceBSurf() bool CmdSurfaceBSurf::isActive(void) { - std::vector Sel = getSelection().getSelection(); - std::size_t size = Sel.size(); - if (size < 1 || size > 4) { - return false; - } - - for (std::vector::iterator it = Sel.begin(); it != Sel.end(); ++it) { - if (!((*it).pObject->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))) { - return false; - } - } - - return true; + return hasActiveDocument(); } void CmdSurfaceBSurf::activated(int iMsg) { - Surface::ShapeValidator validator; - std::vector Sel = getSelection().getSelection(); - if (Sel.size() > 4) { - QMessageBox::warning(Gui::getMainWindow(), - qApp->translate("Surface_BSurf", "Error"), - qApp->translate("Surface_BSurf", "Too many selected objects.")); - return; - } + std::string FeatName = getUniqueObjectName("Surface"); - std::vector SelEx = Gui::Selection().getSelectionEx(); - for (std::vector::iterator it = SelEx.begin(); it != SelEx.end(); ++it) { - if (!(it->isObjectTypeOf(Part::Feature::getClassTypeId()))) { - QMessageBox::warning(Gui::getMainWindow(), - qApp->translate("Surface_BSurf", "Error"), - qApp->translate("Surface_BSurf", "Selected object is not a feature.")); - return; - } - - Part::TopoShape ts = static_cast(it->getObject())->Shape.getShape(); - try { - const std::vector& sub = it->getSubNames(); - for (auto it : sub) - validator.checkAndAdd(ts, it.c_str()); - } - catch(Standard_Failure sf) { - QMessageBox::warning(Gui::getMainWindow(), - qApp->translate("Surface_BSurf", "Error"), - QString::fromLatin1(sf.GetMessageString())); - return; - } - } - - switch(validator.numEdges()) { - case 2: - //QMessageBox::warning(Gui::getMainWindow(), - // qApp->translate("Surface_BSurf", "Warning"), - // qApp->translate("Surface_BSurf", "Surfaces with two edges may fail for some fill types.")); - break; - case 3: // no message - case 4: - break; - default: - QMessageBox::warning(Gui::getMainWindow(), - qApp->translate("Surface_BSurf", "Error"), - qApp->translate("Surface_BSurf", "This tool requires 2, 3 or 4 curves.")); - return; - } - - std::stringstream out; - for (std::vector::iterator it = SelEx.begin(); it != SelEx.end(); ++it) { - out << it->getAsPropertyLinkSubString() << ","; - } - - std::string linklist = out.str(); - - // check which was activated - if (validator.isBezier()) { - std::string FeatName = getUniqueObjectName("BezierSurface"); - - openCommand("Create Bezier surface"); - doCommand(Doc, "App.ActiveDocument.addObject(\"Surface::BezierSurface\",\"%s\")", FeatName.c_str()); - // invalid fill type meaning the surface is just created and cancel should delete it - doCommand(Doc, "App.ActiveDocument.ActiveObject.FillType=0"); - doCommand(Doc, "App.ActiveDocument.ActiveObject.BoundaryList = [%s]", linklist.c_str()); - doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", FeatName.c_str()); - updateActive(); - } - - if (validator.isBSpline()) { - std::string FeatName = getUniqueObjectName("BSplineSurface"); - - openCommand("Create B-spline surface"); - doCommand(Doc, "App.ActiveDocument.addObject(\"Surface::BSplineSurface\",\"%s\")", FeatName.c_str()); - // invalid fill type meaning the surface is just created and cancel should delete it - doCommand(Doc, "App.ActiveDocument.ActiveObject.FillType=0"); - doCommand(Doc, "App.ActiveDocument.ActiveObject.BoundaryList = [%s]", linklist.c_str()); - doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", FeatName.c_str()); - updateActive(); - } + openCommand("Create surface"); + doCommand(Doc, "App.ActiveDocument.addObject(\"Surface::BSplineSurface\",\"%s\")", FeatName.c_str()); + doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", FeatName.c_str()); } void CreateSurfaceCommands(void) diff --git a/src/Mod/Surface/Gui/SurfaceFilling.cpp b/src/Mod/Surface/Gui/SurfaceFilling.cpp index 60894d4546..0fa8ace9c8 100644 --- a/src/Mod/Surface/Gui/SurfaceFilling.cpp +++ b/src/Mod/Surface/Gui/SurfaceFilling.cpp @@ -1,5 +1,6 @@ /*************************************************************************** * Copyright (c) 2015 Balázs Bámer * + * Werner Mayer * * * * This file is part of the FreeCAD CAx development system. * * * @@ -23,13 +24,15 @@ #include "PreCompiled.h" #include #include +#include #include #include #include #include #include -#include +#include +#include #include #include @@ -39,16 +42,43 @@ using namespace SurfaceGui; -PROPERTY_SOURCE(SurfaceGui::ViewProviderSurfaceFeature, PartGui::ViewProviderPart) +PROPERTY_SOURCE(SurfaceGui::ViewProviderSurfaceFeature, PartGui::ViewProviderSpline) namespace SurfaceGui { +bool EdgeSelection::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; + std::string element(sSubName); + if (element.substr(0,4) != "Edge") + return false; + auto links = editedObject->BoundaryList.getSubListValues(); + for (auto it : links) { + if (it.first == pObj) { + for (auto jt : it.second) { + if (jt == sSubName) + return !appendEdges; + } + } + } + + return appendEdges; +} + +// ---------------------------------------------------------------------------- + void ViewProviderSurfaceFeature::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) { QAction* act; act = menu->addAction(QObject::tr("Edit filling"), receiver, member); act->setData(QVariant((int)ViewProvider::Default)); - PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member); + PartGui::ViewProviderSpline::setupContextMenu(menu, receiver, member); } bool ViewProviderSurfaceFeature::setEdit(int ModNum) @@ -75,7 +105,7 @@ bool ViewProviderSurfaceFeature::setEdit(int ModNum) return true; } else { - return ViewProviderPart::setEdit(ModNum); + return ViewProviderSpline::setEdit(ModNum); } } @@ -86,7 +116,7 @@ void ViewProviderSurfaceFeature::unsetEdit(int ModNum) QTimer::singleShot(0, &Gui::Control(), SLOT(closeDialog())); } else { - PartGui::ViewProviderPart::unsetEdit(ModNum); + PartGui::ViewProviderSpline::unsetEdit(ModNum); } } @@ -95,10 +125,13 @@ QIcon ViewProviderSurfaceFeature::getIcon(void) const return Gui::BitmapFactory().pixmap("BSplineSurf"); } +// ---------------------------------------------------------------------------- + SurfaceFilling::SurfaceFilling(ViewProviderSurfaceFeature* vp, Surface::SurfaceFeature* obj) { ui = new Ui_SurfaceFilling(); ui->setupUi(this); + selectionMode = None; this->vp = vp; setEditedObject(obj); } @@ -116,32 +149,45 @@ SurfaceFilling::~SurfaceFilling() void SurfaceFilling::setEditedObject(Surface::SurfaceFeature* obj) { editedObject = obj; - oldFillType = (FillType_t)(editedObject->FillType.getValue()); - switch(oldFillType) + long curtype = editedObject->FillType.getValue(); + switch(curtype) { - case StretchStyle: + case 1: // StretchStyle ui->fillType_stretch->setChecked(true); break; - case CoonsStyle: + case 2: // CoonsStyle ui->fillType_coons->setChecked(true); break; - case CurvedStyle: + case 3: // CurvedStyle ui->fillType_curved->setChecked(true); break; + default: + break; } - fillType = oldFillType; -} -FillType_t SurfaceFilling::getFillType() const -{ - FillType_t ret; - if (ui->fillType_stretch->isChecked()) - ret = StretchStyle; - else if (ui->fillType_coons->isChecked()) - ret = CoonsStyle; - else - ret = CurvedStyle; - return ret; + auto objects = editedObject->BoundaryList.getValues(); + auto element = editedObject->BoundaryList.getSubValues(); + auto it = objects.begin(); + auto jt = element.begin(); + + App::Document* doc = editedObject->getDocument(); + for (; it != objects.end() && jt != element.end(); ++it, ++jt) { + QListWidgetItem* item = new QListWidgetItem(ui->listWidget); + ui->listWidget->addItem(item); + + QString text = QString::fromLatin1("%1.%2") + .arg(QString::fromUtf8((*it)->Label.getValue())) + .arg(QString::fromStdString(*jt)); + item->setText(text); + + QList data; + data << QByteArray(doc->getName()); + data << QByteArray((*it)->getNameInDocument()); + data << QByteArray(jt->c_str()); + item->setData(Qt::UserRole, data); + } + + attachDocument(Gui::Application::Instance->getDocument(doc)); } void SurfaceFilling::changeEvent(QEvent *e) @@ -154,57 +200,180 @@ void SurfaceFilling::changeEvent(QEvent *e) } } -void SurfaceFilling::accept() +void SurfaceFilling::open() { - // applies the changes - apply(); + if (!Gui::Command::hasPendingCommand()) { + std::string Msg("Edit "); + Msg += editedObject->Label.getValue(); + Gui::Command::openCommand(Msg.c_str()); + } +} + +void SurfaceFilling::slotUndoDocument(const Gui::Document&) +{ + //Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); +} + +void SurfaceFilling::slotRedoDocument(const Gui::Document&) +{ + //Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); +} + +bool SurfaceFilling::accept() +{ + selectionMode = None; + Gui::Selection().rmvSelectionGate(); + + int count = ui->listWidget->count(); + if (count > 4) { + QMessageBox::warning(this, + tr("Too many edges"), + tr("The tool requires two, three or four edges")); + return false; + } + else if (count < 2) { + QMessageBox::warning(this, + tr("Too less edges"), + tr("The tool requires two, three or four edges")); + return false; + } + + if (editedObject->mustExecute()) + editedObject->recomputeFeature(); + if (!editedObject->isValid()) { + QMessageBox::warning(this, tr("Invalid object"), + QString::fromLatin1(editedObject->getStatusString())); + return false; + } + Gui::Command::commitCommand(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); + Gui::Command::updateActive(); + return true; } -void SurfaceFilling::reject() +bool SurfaceFilling::reject() { - if (oldFillType == InvalidStyle) { - Gui::Command::abortCommand(); - } - else { - // if the object fill type was changed, reset the old one - if (editedObject->FillType.getValue() != oldFillType) { - editedObject->FillType.setValue(oldFillType); - } - - Gui::Command::commitCommand(); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); - } + selectionMode = None; + Gui::Selection().rmvSelectionGate(); + Gui::Command::abortCommand(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); -} - -void SurfaceFilling::apply() -{ - // apply the change only if it is a real change - if (editedObject->FillType.getValue() != fillType) { - editedObject->FillType.setValue(fillType); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); - } + Gui::Command::updateActive(); + return true; } void SurfaceFilling::on_fillType_stretch_clicked() { - fillType = StretchStyle; + long curtype = editedObject->FillType.getValue(); + if (curtype != 1) { + editedObject->FillType.setValue(1); + editedObject->recomputeFeature(); + if (!editedObject->isValid()) { + Base::Console().Error("Surface filling: %s", editedObject->getStatusString()); + } + } } void SurfaceFilling::on_fillType_coons_clicked() { - fillType = CoonsStyle; + long curtype = editedObject->FillType.getValue(); + if (curtype != 2) { + editedObject->FillType.setValue(2); + editedObject->recomputeFeature(); + if (!editedObject->isValid()) { + Base::Console().Error("Surface filling: %s", editedObject->getStatusString()); + } + } } void SurfaceFilling::on_fillType_curved_clicked() { - fillType = CurvedStyle; + long curtype = editedObject->FillType.getValue(); + if (curtype != 3) { + editedObject->FillType.setValue(3); + editedObject->recomputeFeature(); + if (!editedObject->isValid()) { + Base::Console().Error("Surface filling: %s", editedObject->getStatusString()); + } + } } -// --------------------------------------- +void SurfaceFilling::on_buttonEdgeAdd_clicked() +{ + selectionMode = Append; + Gui::Selection().addSelectionGate(new EdgeSelection(true, editedObject)); +} + +void SurfaceFilling::on_buttonEdgeRemove_clicked() +{ + selectionMode = Remove; + Gui::Selection().addSelectionGate(new EdgeSelection(false, editedObject)); +} + +void SurfaceFilling::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (selectionMode == None) + return; + + if (msg.Type == Gui::SelectionChanges::AddSelection) { + if (selectionMode == Append) { + QListWidgetItem* item = new QListWidgetItem(ui->listWidget); + ui->listWidget->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); + + auto objects = editedObject->BoundaryList.getValues(); + objects.push_back(sel.getObject()); + auto element = editedObject->BoundaryList.getSubValues(); + element.push_back(msg.pSubName); + editedObject->BoundaryList.setValues(objects, element); + } + else { + Gui::SelectionObject sel(msg); + QList data; + data << QByteArray(msg.pDocName); + data << QByteArray(msg.pObjectName); + data << QByteArray(msg.pSubName); + for (int i=0; ilistWidget->count(); i++) { + QListWidgetItem* item = ui->listWidget->item(i); + if (item && item->data(Qt::UserRole) == data) { + ui->listWidget->takeItem(i); + delete item; + } + } + + App::DocumentObject* obj = sel.getObject(); + std::string sub = msg.pSubName; + auto objects = editedObject->BoundaryList.getValues(); + auto element = editedObject->BoundaryList.getSubValues(); + auto it = objects.begin(); + auto jt = element.begin(); + for (; it != objects.end() && jt != element.end(); ++it, ++jt) { + if (*it == obj && *jt == sub) { + objects.erase(it); + element.erase(jt); + editedObject->BoundaryList.setValues(objects, element); + break; + } + } + } + + editedObject->recomputeFeature(); + } +} + +// ---------------------------------------------------------------------------- TaskSurfaceFilling::TaskSurfaceFilling(ViewProviderSurfaceFeature* vp, Surface::SurfaceFeature* obj) { @@ -227,24 +396,19 @@ void TaskSurfaceFilling::setEditedObject(Surface::SurfaceFeature* obj) widget->setEditedObject(obj); } +void TaskSurfaceFilling::open() +{ + widget->open(); +} + bool TaskSurfaceFilling::accept() { - widget->accept(); - return true; + return widget->accept(); } bool TaskSurfaceFilling::reject() { - widget->reject(); - return true; -} - -// Apply clicked -void TaskSurfaceFilling::clicked(int id) -{ - if (id == QDialogButtonBox::Apply) { - widget->apply(); - } + return widget->reject(); } } diff --git a/src/Mod/Surface/Gui/SurfaceFilling.h b/src/Mod/Surface/Gui/SurfaceFilling.h index 55f78feede..bb6f782089 100644 --- a/src/Mod/Surface/Gui/SurfaceFilling.h +++ b/src/Mod/Surface/Gui/SurfaceFilling.h @@ -25,79 +25,109 @@ #include #include +#include +#include #include #include -#include +#include #include namespace SurfaceGui { - - class Ui_SurfaceFilling; - class ViewProviderSurfaceFeature : public PartGui::ViewProviderPart +class EdgeSelection : public Gui::SelectionFilterGate +{ +public: + EdgeSelection(bool appendEdges, Surface::SurfaceFeature* editedObject) + : Gui::SelectionFilterGate(static_cast(nullptr)) + , appendEdges(appendEdges) + , editedObject(editedObject) { - PROPERTY_HEADER(SurfaceGui::ViewProviderSurfaceFeature); - public: - virtual void setupContextMenu(QMenu*, QObject*, const char*); - virtual bool setEdit(int ModNum); - virtual void unsetEdit(int ModNum); - QIcon getIcon(void) const; - }; + } + /** + * Allow the user to pick only edges. + */ + bool allow(App::Document* pDoc, App::DocumentObject* pObj, const char* sSubName); - class SurfaceFilling : public QWidget - { - Q_OBJECT +private: + bool appendEdges; + Surface::SurfaceFeature* editedObject; +}; - protected: - FillType_t fillType, oldFillType; - Surface::SurfaceFeature* editedObject; +class Ui_SurfaceFilling; - private: - Ui_SurfaceFilling* ui; - Base::BoundBox3d bbox; - ViewProviderSurfaceFeature* vp; +class ViewProviderSurfaceFeature : public PartGui::ViewProviderSpline +{ + PROPERTY_HEADER(SurfaceGui::ViewProviderSurfaceFeature); +public: + virtual void setupContextMenu(QMenu*, QObject*, const char*); + virtual bool setEdit(int ModNum); + virtual void unsetEdit(int ModNum); + QIcon getIcon(void) const; +}; - public: - SurfaceFilling(ViewProviderSurfaceFeature* vp, Surface::SurfaceFeature* obj); - ~SurfaceFilling(); - void accept(); - void reject(); - void apply(); - void setEditedObject(Surface::SurfaceFeature* obj); +class SurfaceFilling : public QWidget, + public Gui::SelectionObserver, + public Gui::DocumentObserver +{ + Q_OBJECT - protected: - void changeEvent(QEvent *e); +protected: + enum SelectionMode { None, Append, Remove }; + SelectionMode selectionMode; + Surface::SurfaceFeature* editedObject; - private Q_SLOTS: - void on_fillType_stretch_clicked(); - void on_fillType_coons_clicked(); - void on_fillType_curved_clicked(); - FillType_t getFillType() const; - }; +private: + Ui_SurfaceFilling* ui; + ViewProviderSurfaceFeature* vp; - class TaskSurfaceFilling : public Gui::TaskView::TaskDialog - { - Q_OBJECT +public: + SurfaceFilling(ViewProviderSurfaceFeature* vp, Surface::SurfaceFeature* obj); + ~SurfaceFilling(); - public: - TaskSurfaceFilling(ViewProviderSurfaceFeature* vp, Surface::SurfaceFeature* obj); - ~TaskSurfaceFilling(); - void setEditedObject(Surface::SurfaceFeature* obj); + void open(); + bool accept(); + bool reject(); + void setEditedObject(Surface::SurfaceFeature* obj); - public: - bool accept(); - bool reject(); - void clicked(int id); +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); - virtual QDialogButtonBox::StandardButtons getStandardButtons() const - { return QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel; } +private Q_SLOTS: + void on_fillType_stretch_clicked(); + void on_fillType_coons_clicked(); + void on_fillType_curved_clicked(); + void on_buttonEdgeAdd_clicked(); + void on_buttonEdgeRemove_clicked(); +}; - private: - SurfaceFilling* widget; - Gui::TaskView::TaskBox* taskbox; - ViewProviderSurfaceFeature* view; - }; +class TaskSurfaceFilling : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskSurfaceFilling(ViewProviderSurfaceFeature* vp, Surface::SurfaceFeature* obj); + ~TaskSurfaceFilling(); + void setEditedObject(Surface::SurfaceFeature* obj); + +public: + void open(); + bool accept(); + bool reject(); + + virtual QDialogButtonBox::StandardButtons getStandardButtons() const + { return QDialogButtonBox::Ok | QDialogButtonBox::Cancel; } + +private: + SurfaceFilling* widget; + Gui::TaskView::TaskBox* taskbox; + ViewProviderSurfaceFeature* view; +}; } //namespace Surface diff --git a/src/Mod/Surface/Gui/SurfaceFilling.ui b/src/Mod/Surface/Gui/SurfaceFilling.ui index 80a756a7c7..7917dfe5f7 100644 --- a/src/Mod/Surface/Gui/SurfaceFilling.ui +++ b/src/Mod/Surface/Gui/SurfaceFilling.ui @@ -7,7 +7,7 @@ 0 0 277 - 144 + 467 @@ -20,7 +20,7 @@ Filling - + Fill type: @@ -59,6 +59,45 @@ + + + + + + true + + + + 0 + 0 + + + + Add Edge + + + false + + + + + + + + 0 + 0 + + + + Remove Edge + + + + + + + +