diff --git a/src/Mod/Part/Gui/Command.cpp b/src/Mod/Part/Gui/Command.cpp index 436ba6130a..d0f5099f96 100644 --- a/src/Mod/Part/Gui/Command.cpp +++ b/src/Mod/Part/Gui/Command.cpp @@ -2396,7 +2396,7 @@ CmdPartProjectionOnSurface::CmdPartProjectionOnSurface() void CmdPartProjectionOnSurface::activated(int iMsg) { Q_UNUSED(iMsg); - PartGui::TaskProjectionOnSurface* dlg = new PartGui::TaskProjectionOnSurface(); + auto dlg = new PartGui::TaskProjectOnSurface(getDocument(nullptr)); Gui::Control().showDialog(dlg); } diff --git a/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp b/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp index 1baf8ccb54..f685db0d89 100644 --- a/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp +++ b/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp @@ -45,6 +45,7 @@ #include #include +#include #include #include #include @@ -59,8 +60,9 @@ using namespace PartGui; +namespace { ////////////////////////////////////////////////////////////////////////// -class DlgProjectionOnSurface::EdgeSelection: public Gui::SelectionFilterGate +class EdgeSelection: public Gui::SelectionFilterGate { public: bool canSelect = false; @@ -93,7 +95,7 @@ public: }; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -class DlgProjectionOnSurface::FaceSelection: public Gui::SelectionFilterGate +class FaceSelection: public Gui::SelectionFilterGate { public: bool canSelect = false; @@ -125,7 +127,7 @@ public: } }; ////////////////////////////////////////////////////////////////////////// - +} DlgProjectionOnSurface::DlgProjectionOnSurface(QWidget* parent) : QWidget(parent) @@ -1184,4 +1186,413 @@ void TaskProjectionOnSurface::clicked(int id) } } +// ------------------------------------------------------------------------------------------------ + +DlgProjectOnSurface::DlgProjectOnSurface(Part::ProjectOnSurface* feature, QWidget* parent) + : QWidget(parent) + , ui(new Ui::DlgProjectionOnSurface) + , filterEdge(nullptr) + , filterFace(nullptr) + , feature(feature) +{ + ui->setupUi(this); + ui->doubleSpinBoxExtrudeHeight->setValue(feature->Height.getValue()); + ui->doubleSpinBoxSolidDepth->setValue(feature->Offset.getValue()); + fetchDirection(); + fetchMode(); + setupConnections(); + + ui->pushButtonAddEdge->setCheckable(true); + ui->pushButtonAddFace->setCheckable(true); + ui->pushButtonAddProjFace->setCheckable(true); + ui->pushButtonAddWire->setCheckable(true); +} + +DlgProjectOnSurface::~DlgProjectOnSurface() +{ + if (filterFace || filterEdge) { + Gui::Selection().rmvSelectionGate(); + } +} + +void DlgProjectOnSurface::setupConnections() +{ + // clang-format off + connect(ui->pushButtonAddFace, &QPushButton::clicked, + this, &DlgProjectOnSurface::onAddFaceClicked); + connect(ui->pushButtonAddEdge, &QPushButton::clicked, + this, &DlgProjectOnSurface::onAddEdgeClicked); + connect(ui->pushButtonGetCurrentCamDir, &QPushButton::clicked, + this, &DlgProjectOnSurface::onGetCurrentCamDirClicked); + connect(ui->pushButtonDirX, &QPushButton::clicked, + this, &DlgProjectOnSurface::onDirXClicked); + connect(ui->pushButtonDirY, &QPushButton::clicked, + this, &DlgProjectOnSurface::onDirYClicked); + connect(ui->pushButtonDirZ, &QPushButton::clicked, + this, &DlgProjectOnSurface::onDirZClicked); + connect(ui->pushButtonAddProjFace, &QPushButton::clicked, + this, &DlgProjectOnSurface::onAddProjFaceClicked); + connect(ui->radioButtonShowAll, &QRadioButton::clicked, + this, &DlgProjectOnSurface::onShowAllClicked); + connect(ui->radioButtonFaces, &QRadioButton::clicked, + this, &DlgProjectOnSurface::onFacesClicked); + connect(ui->radioButtonEdges, &QRadioButton::clicked, + this, &DlgProjectOnSurface::onEdgesClicked); + connect(ui->doubleSpinBoxExtrudeHeight, qOverload(&QDoubleSpinBox::valueChanged), + this, &DlgProjectOnSurface::onExtrudeHeightValueChanged); + connect(ui->pushButtonAddWire, &QPushButton::clicked, + this, &DlgProjectOnSurface::onAddWireClicked); + connect(ui->doubleSpinBoxSolidDepth, qOverload(&QDoubleSpinBox::valueChanged), + this, &DlgProjectOnSurface::onSolidDepthValueChanged); + // clang-format off +} + +void DlgProjectOnSurface::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + // clang-format off + if (msg.Type == Gui::SelectionChanges::AddSelection) { + if (selectionMode == SelectionMode::AddFace || + selectionMode == SelectionMode::AddEdge) { + addSelection(msg); + } + else if (selectionMode == SelectionMode::AddWire) { + addWire(msg); + } + else if (selectionMode == SelectionMode::SupportFace) { + ui->pushButtonAddProjFace->setChecked(false); + setSupportFace(msg); + onAddProjFaceClicked(); + } + } + // clang-format on +} + +void DlgProjectOnSurface::accept() +{ + if (!feature.expired()) { + auto document = feature->getDocument(); + document->commitTransaction(); + document->recompute(); + } +} + +void DlgProjectOnSurface::reject() +{ + if (!feature.expired()) { + auto document = feature->getDocument(); + document->abortTransaction(); + } +} + +void DlgProjectOnSurface::onAddProjFaceClicked() +{ + if (ui->pushButtonAddProjFace->isChecked()) { + selectionMode = SelectionMode::SupportFace; + if (!filterFace) { + filterFace = new FaceSelection(); + Gui::Selection().addSelectionGate(filterFace); + } + } + else { + selectionMode = SelectionMode::None; + Gui::Selection().rmvSelectionGate(); + filterFace = nullptr; + } +} + +void DlgProjectOnSurface::onAddFaceClicked() +{ + if (ui->pushButtonAddFace->isChecked()) { + selectionMode = SelectionMode::AddFace; + if (!filterFace) { + filterFace = new FaceSelection(); + Gui::Selection().addSelectionGate(filterFace); + } + } + else { + selectionMode = SelectionMode::None; + Gui::Selection().rmvSelectionGate(); + filterFace = nullptr; + } +} + +void DlgProjectOnSurface::onAddWireClicked() +{ + if (ui->pushButtonAddWire->isChecked()) { + selectionMode = SelectionMode::AddWire; + if (!filterEdge) { + filterEdge = new EdgeSelection(); + Gui::Selection().addSelectionGate(filterEdge); + } + ui->radioButtonEdges->setChecked(true); + onEdgesClicked(); + } + else { + selectionMode = SelectionMode::None; + Gui::Selection().rmvSelectionGate(); + filterEdge = nullptr; + } +} + +void DlgProjectOnSurface::onAddEdgeClicked() +{ + if (ui->pushButtonAddEdge->isChecked()) { + selectionMode = SelectionMode::AddEdge; + if (!filterEdge) { + filterEdge = new EdgeSelection(); + Gui::Selection().addSelectionGate(filterEdge); + } + ui->radioButtonEdges->setChecked(true); + onEdgesClicked(); + } + else { + selectionMode = SelectionMode::None; + Gui::Selection().rmvSelectionGate(); + filterEdge = nullptr; + } +} + +void DlgProjectOnSurface::onGetCurrentCamDirClicked() +{ + auto mainWindow = Gui::getMainWindow(); + + auto mdiObject = dynamic_cast(mainWindow->activeWindow()); + if (!mdiObject) { + return; + } + auto camerRotation = mdiObject->getViewer()->getCameraOrientation(); + + SbVec3f lookAt(0, 0, -1); + camerRotation.multVec(lookAt, lookAt); + + float valX {}; + float valY {}; + float valZ {}; + lookAt.getValue(valX, valY, valZ); + + ui->doubleSpinBoxDirX->setValue(valX); + ui->doubleSpinBoxDirY->setValue(valY); + ui->doubleSpinBoxDirZ->setValue(valZ); + setDirection(); +} + +void DlgProjectOnSurface::onDirXClicked() +{ + auto currentVal = ui->doubleSpinBoxDirX->value(); + ui->doubleSpinBoxDirX->setValue(currentVal > 0 ? -1 : 1); + ui->doubleSpinBoxDirY->setValue(0); + ui->doubleSpinBoxDirZ->setValue(0); + setDirection(); +} + +void DlgProjectOnSurface::onDirYClicked() +{ + auto currentVal = ui->doubleSpinBoxDirY->value(); + ui->doubleSpinBoxDirX->setValue(0); + ui->doubleSpinBoxDirY->setValue(currentVal > 0 ? -1 : 1); + ui->doubleSpinBoxDirZ->setValue(0); + setDirection(); +} + +void DlgProjectOnSurface::onDirZClicked() +{ + auto currentVal = ui->doubleSpinBoxDirZ->value(); + ui->doubleSpinBoxDirX->setValue(0); + ui->doubleSpinBoxDirY->setValue(0); + ui->doubleSpinBoxDirZ->setValue(currentVal > 0 ? -1 : 1); + setDirection(); +} + +void DlgProjectOnSurface::setDirection() +{ + if (!feature.expired()) { + auto xVal = ui->doubleSpinBoxDirX->value(); + auto yVal = ui->doubleSpinBoxDirY->value(); + auto zVal = ui->doubleSpinBoxDirZ->value(); + feature->Direction.setValue(Base::Vector3d(xVal, yVal, zVal)); + feature->recomputeFeature(); + } +} + +void DlgProjectOnSurface::addWire(const Gui::SelectionChanges& msg) +{ + auto isEdgePartOf = [](const TopoDS_Shape& wire, const TopoDS_Shape& edge) { + for (TopExp_Explorer xp(wire, TopAbs_EDGE); xp.More(); xp.Next()) { + if (edge.IsSame(xp.Current())) { + return true; + } + } + + return false; + }; + if (selectionMode != SelectionMode::AddWire) { + return; + } + + Gui::SelectionObject selObj(msg); + if (!selObj.hasSubNames()) { + return; + } + + Part::TopoShape part = Part::Feature::getTopoShape(selObj.getObject()); + if (part.isNull()) { + return; + } + + std::string subName = selObj.getSubNames().front(); + TopoDS_Shape edge = part.getSubShape(subName.c_str(), true); + if (edge.IsNull() || edge.ShapeType() != TopAbs_EDGE) { + return; + } + + int index = 1; + const TopoDS_Shape& shape = part.getShape(); + for (TopExp_Explorer xp(shape, TopAbs_WIRE); xp.More(); xp.Next()) { + if (isEdgePartOf(xp.Current(), edge)) { + std::string name{"Wire"}; + name += std::to_string(index); + addSelection(msg, name); + break; + } + index++; + } +} + +void DlgProjectOnSurface::addSelection(const Gui::SelectionChanges& msg, + const std::string& subName) +{ + if (!feature.expired()) { + Gui::SelectionObject selObj(msg); + feature->Projection.addValue(selObj.getObject(), {subName}); + } +} + +void DlgProjectOnSurface::addSelection(const Gui::SelectionChanges& msg) +{ + if (!feature.expired()) { + Gui::SelectionObject selObj(msg); + feature->Projection.addValue(selObj.getObject(), selObj.getSubNames()); + } +} + +void DlgProjectOnSurface::setSupportFace(const Gui::SelectionChanges& msg) +{ + Gui::SelectionObject selObj(msg); + if (!feature.expired()) { + feature->SupportFace.setValue(selObj.getObject(), selObj.getSubNames()); + feature->recomputeFeature(); + } +} + +void DlgProjectOnSurface::fetchDirection() +{ + if (!feature.expired()) { + auto dir = feature->Direction.getValue(); + ui->doubleSpinBoxDirX->setValue(dir.x); + ui->doubleSpinBoxDirY->setValue(dir.y); + ui->doubleSpinBoxDirZ->setValue(dir.z); + } +} + +void DlgProjectOnSurface::fetchMode() +{ + if (!feature.expired()) { + if (strcmp(feature->Mode.getValueAsString(), Part::ProjectOnSurface::AllMode) == 0) { + ui->radioButtonShowAll->setChecked(true); + } + else if (strcmp(feature->Mode.getValueAsString(), Part::ProjectOnSurface::FacesMode) == 0) { + ui->radioButtonFaces->setChecked(true); + } + else if (strcmp(feature->Mode.getValueAsString(), Part::ProjectOnSurface::EdgesMode) == 0) { + ui->radioButtonEdges->setChecked(true); + } + } +} + +void DlgProjectOnSurface::onShowAllClicked() +{ + if (!feature.expired()) { + feature->Mode.setValue(Part::ProjectOnSurface::AllMode); + feature->recomputeFeature(); + } +} + +void DlgProjectOnSurface::onFacesClicked() +{ + if (!feature.expired()) { + feature->Mode.setValue(Part::ProjectOnSurface::FacesMode); + feature->recomputeFeature(); + } +} + +void DlgProjectOnSurface::onEdgesClicked() +{ + if (!feature.expired()) { + feature->Mode.setValue(Part::ProjectOnSurface::EdgesMode); + feature->recomputeFeature(); + } +} + +void DlgProjectOnSurface::onExtrudeHeightValueChanged(double value) +{ + if (!feature.expired()) { + feature->Height.setValue(value); + feature->recomputeFeature(); + } +} + +void DlgProjectOnSurface::onSolidDepthValueChanged(double value) +{ + if (!feature.expired()) { + feature->Offset.setValue(value); + feature->recomputeFeature(); + } +} + +// --------------------------------------- + +TaskProjectOnSurface::TaskProjectOnSurface(App::Document* doc) +{ + setDocumentName(doc->getName()); + doc->openTransaction(QT_TRANSLATE_NOOP("Command", "Project on surface")); + auto obj = doc->addObject("Part::ProjectOnSurface", "Projection"); + auto feature = dynamic_cast(obj); + widget = new DlgProjectOnSurface(feature); + taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("Part_ProjectionOnSurface"), + widget->windowTitle(), true, nullptr); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskProjectOnSurface::TaskProjectOnSurface(Part::ProjectOnSurface* feature) + : widget(new DlgProjectOnSurface(feature)) + , taskbox(new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("Part_ProjectionOnSurface"), + widget->windowTitle(), + true, + nullptr)) +{ + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +void TaskProjectOnSurface::resetEdit() +{ + std::string document = getDocumentName(); + Gui::doCommandT(Gui::Command::Gui, "Gui.getDocument('%s').resetEdit()", document); +} + +bool TaskProjectOnSurface::accept() +{ + widget->accept(); + resetEdit(); + return true; +} + +bool TaskProjectOnSurface::reject() +{ + widget->reject(); + resetEdit(); + return true; +} + #include "moc_DlgProjectionOnSurface.cpp" diff --git a/src/Mod/Part/Gui/DlgProjectionOnSurface.h b/src/Mod/Part/Gui/DlgProjectionOnSurface.h index 4a4f6c10bc..537a62d025 100644 --- a/src/Mod/Part/Gui/DlgProjectionOnSurface.h +++ b/src/Mod/Part/Gui/DlgProjectionOnSurface.h @@ -33,7 +33,7 @@ #include #include #include -#include +#include namespace PartGui @@ -147,11 +147,8 @@ private: App::Document* m_partDocument = nullptr; double m_lastDepthVal; - class EdgeSelection; - EdgeSelection* filterEdge; - - class FaceSelection; - FaceSelection* filterFace; + Gui::SelectionFilterGate* filterEdge; + Gui::SelectionFilterGate* filterFace; }; class TaskProjectionOnSurface: public Gui::TaskView::TaskDialog @@ -176,6 +173,86 @@ private: Gui::TaskView::TaskBox* taskbox = nullptr; }; +// ------------------------------------------------------------------------------------------------ + +class DlgProjectOnSurface : public QWidget, + public Gui::SelectionObserver +{ + Q_OBJECT + +public: + explicit DlgProjectOnSurface(Part::ProjectOnSurface* feature, QWidget* parent = nullptr); + ~DlgProjectOnSurface() override; + + void accept(); + void reject(); + + // from Gui::SelectionObserver + void onSelectionChanged(const Gui::SelectionChanges& msg) override; + +private: + enum SelectionMode { + None, + SupportFace, + AddFace, + AddWire, + AddEdge + }; + void setupConnections(); + void onAddFaceClicked(); + void onAddEdgeClicked(); + void onGetCurrentCamDirClicked(); + void onDirXClicked(); + void onDirYClicked(); + void onDirZClicked(); + void onAddProjFaceClicked(); + void onShowAllClicked(); + void onFacesClicked(); + void onEdgesClicked(); + void onExtrudeHeightValueChanged(double arg1); + void onAddWireClicked(); + void onSolidDepthValueChanged(double arg1); + void setDirection(); + void addWire(const Gui::SelectionChanges& msg); + void addSelection(const Gui::SelectionChanges& msg); + void addSelection(const Gui::SelectionChanges& msg, const std::string& subName); + void setSupportFace(const Gui::SelectionChanges& msg); + void fetchDirection(); + void fetchMode(); + +private: + std::unique_ptr ui; + Gui::SelectionFilterGate* filterEdge; + Gui::SelectionFilterGate* filterFace; + App::WeakPtrT feature; + SelectionMode selectionMode = SelectionMode::None; +}; + +class TaskProjectOnSurface: public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + explicit TaskProjectOnSurface(App::Document*); + explicit TaskProjectOnSurface(Part::ProjectOnSurface*); + +public: + bool accept() override; + bool reject() override; + + QDialogButtonBox::StandardButtons getStandardButtons() const override + { + return QDialogButtonBox::Ok | QDialogButtonBox::Cancel; + } + +private: + void resetEdit(); + +private: + DlgProjectOnSurface* widget = nullptr; + Gui::TaskView::TaskBox* taskbox = nullptr; +}; + } // namespace PartGui #endif // PARTGUI_DLGPROJECTIONONSURFACE_H diff --git a/src/Mod/Part/Gui/ViewProviderProjectOnSurface.cpp b/src/Mod/Part/Gui/ViewProviderProjectOnSurface.cpp index a262735bf2..831c681f2c 100644 --- a/src/Mod/Part/Gui/ViewProviderProjectOnSurface.cpp +++ b/src/Mod/Part/Gui/ViewProviderProjectOnSurface.cpp @@ -48,3 +48,39 @@ ViewProviderProjectOnSurface::ViewProviderProjectOnSurface() } ViewProviderProjectOnSurface::~ViewProviderProjectOnSurface() = default; + +void ViewProviderProjectOnSurface::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) +{ + QAction* act = menu->addAction(QObject::tr("Edit projection"), receiver, member); + act->setData(QVariant((int)ViewProvider::Default)); + + ViewProviderPart::setupContextMenu(menu, receiver, member); +} + +bool ViewProviderProjectOnSurface::setEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default) { + if (Gui::Control().activeDialog()) { + return false; + } + + if (auto feature = dynamic_cast(getObject())) { + Gui::Control().showDialog(new TaskProjectOnSurface(feature)); + return true; + } + + return false; + } + + return ViewProviderPart::setEdit(ModNum); +} + +void ViewProviderProjectOnSurface::unsetEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default) { + Gui::Control().closeDialog(); + } + else { + ViewProviderPart::unsetEdit(ModNum); + } +} diff --git a/src/Mod/Part/Gui/ViewProviderProjectOnSurface.h b/src/Mod/Part/Gui/ViewProviderProjectOnSurface.h index c50ec32686..1575afb299 100644 --- a/src/Mod/Part/Gui/ViewProviderProjectOnSurface.h +++ b/src/Mod/Part/Gui/ViewProviderProjectOnSurface.h @@ -41,6 +41,10 @@ public: ViewProviderProjectOnSurface(); /// destructor ~ViewProviderProjectOnSurface() override; + + void setupContextMenu(QMenu* menu, QObject* receiver, const char* member) override; + bool setEdit(int ModNum) override; + void unsetEdit(int ModNum) override; }; } // namespace PartGui