| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| #include <QSignalBlocker>
|
| #include <QAction>
|
|
|
|
|
| #include <App/Document.h>
|
| #include <Base/Tools.h>
|
| #include <Base/UnitsApi.h>
|
| #include <Gui/Command.h>
|
| #include <Gui/Tools.h>
|
| #include <Gui/Inventor/Draggers/Gizmo.h>
|
| #include <Gui/Inventor/Draggers/SoLinearDragger.h>
|
| #include <Gui/Inventor/Draggers/SoRotationDragger.h>
|
| #include <Mod/PartDesign/App/FeatureExtrude.h>
|
| #include <Mod/Part/App/GizmoHelper.h>
|
|
|
| #include "ui_TaskPadPocketParameters.h"
|
| #include "TaskExtrudeParameters.h"
|
| #include "TaskTransformedParameters.h"
|
| #include "ReferenceSelection.h"
|
|
|
|
|
| using namespace PartDesignGui;
|
| using namespace Gui;
|
|
|
|
|
|
|
| TaskExtrudeParameters::TaskExtrudeParameters(
|
| ViewProviderExtrude* SketchBasedView,
|
| QWidget* parent,
|
| const std::string& pixmapname,
|
| const QString& parname
|
| )
|
| : TaskSketchBasedParameters(SketchBasedView, parent, pixmapname, parname)
|
| , propReferenceAxis(nullptr)
|
| , ui(new Ui_TaskPadPocketParameters)
|
| {
|
|
|
| proxy = new QWidget(this);
|
| ui->setupUi(proxy);
|
| handleLineFaceNameNo(ui->lineFaceName);
|
| handleLineFaceNameNo(ui->lineFaceName2);
|
|
|
| Gui::ButtonGroup* group = new Gui::ButtonGroup(this);
|
| group->addButton(ui->checkBoxReversed);
|
| group->setExclusive(true);
|
|
|
| this->groupLayout()->addWidget(proxy);
|
| }
|
|
|
| void TaskExtrudeParameters::setupDialog()
|
| {
|
| auto createRemoveAction = [this]() -> QAction* {
|
| auto action = new QAction(tr("Remove"), this);
|
| action->setShortcut(Gui::QtTools::deleteKeySequence());
|
| action->setShortcutVisibleInContextMenu(true);
|
| return action;
|
| };
|
|
|
| unselectShapeFaceAction = createRemoveAction();
|
| unselectShapeFaceAction2 = createRemoveAction();
|
|
|
| createSideControllers();
|
|
|
|
|
| auto extrude = getObject<PartDesign::FeatureExtrude>();
|
|
|
| int UserDecimals = Base::UnitsApi::getDecimals();
|
| ui->XDirectionEdit->setDecimals(UserDecimals);
|
| ui->YDirectionEdit->setDecimals(UserDecimals);
|
| ui->ZDirectionEdit->setDecimals(UserDecimals);
|
|
|
| ui->checkBoxAlongDirection->setChecked(extrude->AlongSketchNormal.getValue());
|
|
|
| ui->XDirectionEdit->setValue(extrude->Direction.getValue().x);
|
| ui->YDirectionEdit->setValue(extrude->Direction.getValue().y);
|
| ui->ZDirectionEdit->setValue(extrude->Direction.getValue().z);
|
|
|
| ui->XDirectionEdit->bind(App::ObjectIdentifier::parse(extrude, "Direction.x"));
|
| ui->YDirectionEdit->bind(App::ObjectIdentifier::parse(extrude, "Direction.y"));
|
| ui->ZDirectionEdit->bind(App::ObjectIdentifier::parse(extrude, "Direction.z"));
|
|
|
| ui->checkBoxReversed->setChecked(extrude->Reversed.getValue());
|
|
|
|
|
| setupSideDialog(m_side1);
|
| setupSideDialog(m_side2);
|
|
|
|
|
| translateSidesList(extrude->SideType.getValue());
|
|
|
| connectSlots();
|
|
|
| this->propReferenceAxis = &(extrude->ReferenceAxis);
|
| updateUI(Side::First);
|
|
|
| setupGizmos();
|
|
|
|
|
|
|
| tryRecomputeFeature();
|
| }
|
|
|
| void TaskExtrudeParameters::setupSideDialog(SideController& side)
|
| {
|
|
|
| Base::Quantity length = side.Length->getQuantityValue();
|
| Base::Quantity offset = side.Offset->getQuantityValue();
|
| Base::Quantity taper = side.TaperAngle->getQuantityValue();
|
| int typeIndex = side.Type->getValue();
|
|
|
|
|
|
|
| if (typeIndex > static_cast<int>(Mode::ToShape)) {
|
| typeIndex--;
|
| }
|
|
|
|
|
| side.lengthEdit->setValue(length);
|
| side.offsetEdit->setValue(offset);
|
| side.taperEdit->setMinimum(side.TaperAngle->getMinimum());
|
| side.taperEdit->setMaximum(side.TaperAngle->getMaximum());
|
| side.taperEdit->setSingleStep(side.TaperAngle->getStepSize());
|
| side.taperEdit->setValue(taper);
|
|
|
|
|
| side.lengthEdit->bind(*side.Length);
|
| side.offsetEdit->bind(*side.Offset);
|
| side.taperEdit->bind(*side.TaperAngle);
|
|
|
|
|
| App::DocumentObject* faceObj = side.UpToFace->getValue();
|
| std::vector<std::string> subStrings = side.UpToFace->getSubValues();
|
| std::string upToFaceName;
|
| int faceId = -1;
|
| if (faceObj && !subStrings.empty()) {
|
| upToFaceName = subStrings.front();
|
| if (upToFaceName.rfind("Face", 0) == 0) {
|
| faceId = std::atoi(&upToFaceName[4]);
|
| }
|
| }
|
|
|
| if (faceObj && PartDesign::Feature::isDatum(faceObj)) {
|
| side.lineFaceName->setText(QString::fromUtf8(faceObj->Label.getValue()));
|
| side.lineFaceName->setProperty("FeatureName", QByteArray(faceObj->getNameInDocument()));
|
| }
|
| else if (faceObj && faceId >= 0) {
|
| side.lineFaceName->setText(QStringLiteral("%1:%2%3").arg(
|
| QString::fromUtf8(faceObj->Label.getValue()),
|
| tr("Face"),
|
| QString::number(faceId)
|
| ));
|
| side.lineFaceName->setProperty("FeatureName", QByteArray(faceObj->getNameInDocument()));
|
| }
|
| else {
|
| side.lineFaceName->clear();
|
| side.lineFaceName->setProperty("FeatureName", QVariant());
|
| }
|
| side.lineFaceName->setProperty("FaceName", QByteArray(upToFaceName.c_str()));
|
|
|
|
|
| updateShapeName(side.lineShapeName, *side.UpToShape);
|
| updateShapeFaces(side.listWidgetReferences, *side.UpToShape);
|
|
|
|
|
| translateModeList(side.changeMode, typeIndex);
|
|
|
| side.listWidgetReferences->addAction(side.unselectShapeFaceAction);
|
| side.listWidgetReferences->setContextMenuPolicy(Qt::ActionsContextMenu);
|
| side.checkBoxAllFaces->setChecked(side.listWidgetReferences->count() == 0);
|
| }
|
|
|
| void TaskExtrudeParameters::createSideControllers()
|
| {
|
| auto extrude = getObject<PartDesign::FeatureExtrude>();
|
|
|
|
|
| m_side1.changeMode = ui->changeMode;
|
| m_side1.labelLength = ui->labelLength;
|
| m_side1.labelOffset = ui->labelOffset;
|
| m_side1.labelTaperAngle = ui->labelTaperAngle;
|
| m_side1.lengthEdit = ui->lengthEdit;
|
| m_side1.offsetEdit = ui->offsetEdit;
|
| m_side1.taperEdit = ui->taperEdit;
|
| m_side1.lineFaceName = ui->lineFaceName;
|
| m_side1.buttonFace = ui->buttonFace;
|
| m_side1.lineShapeName = ui->lineShapeName;
|
| m_side1.buttonShape = ui->buttonShape;
|
| m_side1.listWidgetReferences = ui->listWidgetReferences;
|
| m_side1.buttonShapeFace = ui->buttonShapeFace;
|
| m_side1.checkBoxAllFaces = ui->checkBoxAllFaces;
|
| m_side1.upToShapeList = ui->upToShapeList;
|
| m_side1.upToShapeFaces = ui->upToShapeFaces;
|
| m_side1.unselectShapeFaceAction = unselectShapeFaceAction;
|
|
|
| m_side1.Type = &extrude->Type;
|
| m_side1.Length = &extrude->Length;
|
| m_side1.Offset = &extrude->Offset;
|
| m_side1.TaperAngle = &extrude->TaperAngle;
|
| m_side1.UpToFace = &extrude->UpToFace;
|
| m_side1.UpToShape = &extrude->UpToShape;
|
|
|
|
|
| m_side2.changeMode = ui->changeMode2;
|
| m_side2.labelLength = ui->labelLength2;
|
| m_side2.labelOffset = ui->labelOffset2;
|
| m_side2.labelTaperAngle = ui->labelTaperAngle2;
|
| m_side2.lengthEdit = ui->lengthEdit2;
|
| m_side2.offsetEdit = ui->offsetEdit2;
|
| m_side2.taperEdit = ui->taperEdit2;
|
| m_side2.lineFaceName = ui->lineFaceName2;
|
| m_side2.buttonFace = ui->buttonFace2;
|
| m_side2.lineShapeName = ui->lineShapeName2;
|
| m_side2.buttonShape = ui->buttonShape2;
|
| m_side2.listWidgetReferences = ui->listWidgetReferences2;
|
| m_side2.buttonShapeFace = ui->buttonShapeFace2;
|
| m_side2.checkBoxAllFaces = ui->checkBoxAllFaces2;
|
| m_side2.upToShapeList = ui->upToShapeList2;
|
| m_side2.upToShapeFaces = ui->upToShapeFaces2;
|
| m_side2.unselectShapeFaceAction = unselectShapeFaceAction2;
|
|
|
| m_side2.Type = &extrude->Type2;
|
| m_side2.Length = &extrude->Length2;
|
| m_side2.Offset = &extrude->Offset2;
|
| m_side2.TaperAngle = &extrude->TaperAngle2;
|
| m_side2.UpToFace = &extrude->UpToFace2;
|
| m_side2.UpToShape = &extrude->UpToShape2;
|
| }
|
|
|
| void TaskExtrudeParameters::readValuesFromHistory()
|
| {
|
| ui->lengthEdit->setToLastUsedValue();
|
| ui->lengthEdit->selectNumber();
|
| ui->lengthEdit2->setToLastUsedValue();
|
| ui->lengthEdit2->selectNumber();
|
| ui->offsetEdit->setToLastUsedValue();
|
| ui->offsetEdit->selectNumber();
|
| ui->offsetEdit2->setToLastUsedValue();
|
| ui->offsetEdit2->selectNumber();
|
| ui->taperEdit->setToLastUsedValue();
|
| ui->taperEdit->selectNumber();
|
| ui->taperEdit2->setToLastUsedValue();
|
| ui->taperEdit2->selectNumber();
|
| }
|
|
|
| void TaskExtrudeParameters::connectSlots()
|
| {
|
| QMetaObject::connectSlotsByName(this);
|
|
|
| auto connectSideSlots = [this](auto& side, Side sideEnum, auto modeChangedSlot) {
|
| connect(
|
| side.lengthEdit,
|
| qOverload<double>(&Gui::PrefQuantitySpinBox::valueChanged),
|
| this,
|
| [this, sideEnum](double val) { onLengthChanged(val, sideEnum); }
|
| );
|
| connect(
|
| side.offsetEdit,
|
| qOverload<double>(&Gui::PrefQuantitySpinBox::valueChanged),
|
| this,
|
| [this, sideEnum](double val) { onOffsetChanged(val, sideEnum); }
|
| );
|
| connect(
|
| side.taperEdit,
|
| qOverload<double>(&Gui::PrefQuantitySpinBox::valueChanged),
|
| this,
|
| [this, sideEnum](double val) { onTaperChanged(val, sideEnum); }
|
| );
|
| connect(side.changeMode, qOverload<int>(&QComboBox::currentIndexChanged), this, modeChangedSlot);
|
| connect(side.buttonFace, &QToolButton::toggled, this, [this, sideEnum](bool checked) {
|
| onSelectFaceToggle(checked, sideEnum);
|
| });
|
| connect(side.lineFaceName, &QLineEdit::textEdited, this, [this, sideEnum](const QString& text) {
|
| onFaceName(text, sideEnum);
|
| });
|
| connect(side.checkBoxAllFaces, &QCheckBox::toggled, this, [this, sideEnum](bool checked) {
|
| onAllFacesToggled(checked, sideEnum);
|
| });
|
| connect(side.buttonShape, &QToolButton::toggled, this, [this, sideEnum](bool checked) {
|
| onSelectShapeToggle(checked, sideEnum);
|
| });
|
| connect(side.buttonShapeFace, &QToolButton::toggled, this, [this, sideEnum](bool checked) {
|
| onSelectShapeFacesToggle(checked, sideEnum);
|
| });
|
| connect(side.unselectShapeFaceAction, &QAction::triggered, this, [this, sideEnum]() {
|
| onUnselectShapeFacesTrigger(sideEnum);
|
| });
|
| };
|
|
|
|
|
| connectSideSlots(m_side1, Side::First, &TaskExtrudeParameters::onModeChanged_Side1);
|
| connectSideSlots(m_side2, Side::Second, &TaskExtrudeParameters::onModeChanged_Side2);
|
|
|
|
|
| connect(ui->directionCB, qOverload<int>(&QComboBox::activated),
|
| this, &TaskExtrudeParameters::onDirectionCBChanged);
|
| connect(ui->checkBoxAlongDirection, &QCheckBox::toggled,
|
| this, &TaskExtrudeParameters::onAlongSketchNormalChanged);
|
| connect(ui->XDirectionEdit, qOverload<double>(&QDoubleSpinBox::valueChanged),
|
| this, &TaskExtrudeParameters::onXDirectionEditChanged);
|
| connect(ui->YDirectionEdit, qOverload<double>(&QDoubleSpinBox::valueChanged),
|
| this, &TaskExtrudeParameters::onYDirectionEditChanged);
|
| connect(ui->ZDirectionEdit, qOverload<double>(&QDoubleSpinBox::valueChanged),
|
| this, &TaskExtrudeParameters::onZDirectionEditChanged);
|
| connect(ui->checkBoxReversed, &QCheckBox::toggled,
|
| this, &TaskExtrudeParameters::onReversedChanged);
|
| connect(ui->sidesMode, qOverload<int>(&QComboBox::currentIndexChanged),
|
| this, &TaskExtrudeParameters::onSidesModeChanged);
|
| connect(ui->checkBoxUpdateView, &QCheckBox::toggled,
|
| this, &TaskExtrudeParameters::onUpdateView);
|
|
|
| }
|
|
|
| void TaskExtrudeParameters::onModeChanged_Side1(int index)
|
| {
|
| onModeChanged(index, Side::First);
|
| setGizmoPositions();
|
| }
|
|
|
| void TaskExtrudeParameters::onModeChanged_Side2(int index)
|
| {
|
| onModeChanged(index, Side::Second);
|
| setGizmoPositions();
|
| }
|
|
|
| void TaskExtrudeParameters::onSelectShapeFacesToggle(bool checked, Side side)
|
| {
|
| auto& sideCtrl = getSideController(side);
|
| if (checked) {
|
| setSelectionMode(SelectShapeFaces, side);
|
| sideCtrl.buttonShapeFace->setText(tr("Preview"));
|
| }
|
| else {
|
| setSelectionMode(None);
|
| sideCtrl.buttonShapeFace->setText(tr("Select Faces"));
|
| }
|
| }
|
|
|
| void PartDesignGui::TaskExtrudeParameters::onUnselectShapeFacesTrigger(Side side)
|
| {
|
| auto& sideCtrl = getSideController(side);
|
|
|
| auto selected = sideCtrl.listWidgetReferences->selectedItems();
|
| auto faces = getShapeFaces(*sideCtrl.UpToShape);
|
|
|
|
|
| faces.erase(std::remove_if(faces.begin(), faces.end(), [selected](const std::string& face) {
|
| for (auto& item : selected) {
|
| if (item->text().toStdString() == face) {
|
| return true;
|
| }
|
| }
|
|
|
| return false;
|
| }));
|
|
|
| sideCtrl.UpToShape->setValue(sideCtrl.UpToShape->getValue(), faces);
|
|
|
| updateShapeFaces(sideCtrl.listWidgetReferences, *sideCtrl.UpToShape);
|
| }
|
|
|
| void TaskExtrudeParameters::setSelectionMode(SelectionMode mode, Side side)
|
| {
|
| if (selectionMode == mode && activeSelectionSide == side) {
|
| return;
|
| }
|
|
|
| const auto updateCheckedForSide = [mode, side](
|
| Side relatedSide,
|
| QAbstractButton* buttonFace,
|
| QAbstractButton* buttonShape,
|
| QAbstractButton* buttonShapeFace
|
| ) {
|
| buttonFace->setChecked(mode == SelectFace && side == relatedSide);
|
| buttonShape->setChecked(mode == SelectShape && side == relatedSide);
|
| buttonShapeFace->setChecked(mode == SelectShapeFaces && side == relatedSide);
|
| };
|
| updateCheckedForSide(Side::First, ui->buttonFace, ui->buttonShape, ui->buttonShapeFace);
|
| updateCheckedForSide(Side::Second, ui->buttonFace2, ui->buttonShape2, ui->buttonShapeFace2);
|
|
|
| selectionMode = mode;
|
| activeSelectionSide = side;
|
|
|
| switch (mode) {
|
| case SelectShape:
|
| onSelectReference(AllowSelection::WHOLE);
|
| Gui::Selection().addSelectionGate(new SelectionFilterGate("SELECT Part::Feature COUNT 1"));
|
| break;
|
| case SelectFace:
|
| onSelectReference(AllowSelection::FACE);
|
| break;
|
| case SelectShapeFaces: {
|
| onSelectReference(AllowSelection::FACE);
|
| auto& sideCtrl = getSideController(activeSelectionSide);
|
| getViewObject<ViewProviderExtrude>()->highlightShapeFaces(
|
| getShapeFaces(*sideCtrl.UpToShape)
|
| );
|
| break;
|
| }
|
| case SelectReferenceAxis:
|
| onSelectReference(AllowSelection::EDGE | AllowSelection::PLANAR | AllowSelection::CIRCLE);
|
| break;
|
| default:
|
| getViewObject<ViewProviderExtrude>()->highlightShapeFaces({});
|
| onSelectReference(AllowSelection::NONE);
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::tryRecomputeFeature()
|
| {
|
| try {
|
|
|
| recomputeFeature();
|
| }
|
| catch (const Base::Exception& e) {
|
| e.reportException();
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
|
| {
|
| auto& sideCtrl = getSideController(activeSelectionSide);
|
|
|
| if (msg.Type == Gui::SelectionChanges::AddSelection) {
|
| switch (selectionMode) {
|
| case SelectShape:
|
| selectedShape(msg, sideCtrl);
|
| break;
|
| case SelectShapeFaces:
|
| selectedShapeFace(msg, sideCtrl);
|
| break;
|
|
|
| case SelectFace:
|
| selectedFace(msg, sideCtrl);
|
| break;
|
|
|
| case SelectReferenceAxis:
|
| selectedReferenceAxis(msg);
|
| break;
|
|
|
| default:
|
|
|
| break;
|
| }
|
| }
|
| else if (msg.Type == Gui::SelectionChanges::ClrSelection) {
|
| if (selectionMode == SelectFace) {
|
| clearFaceName(sideCtrl.lineFaceName);
|
| }
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::selectedReferenceAxis(const Gui::SelectionChanges& msg)
|
| {
|
| std::vector<std::string> edge;
|
| App::DocumentObject* selObj;
|
|
|
| if (getReferencedSelection(getObject(), msg, selObj, edge) && selObj) {
|
| setSelectionMode(None);
|
|
|
| propReferenceAxis->setValue(selObj, edge);
|
| tryRecomputeFeature();
|
|
|
|
|
| fillDirectionCombo();
|
|
|
| setGizmoPositions();
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::selectedShapeFace(const Gui::SelectionChanges& msg, SideController& side)
|
| {
|
| auto extrude = getObject<PartDesign::FeatureExtrude>();
|
| auto document = extrude->getDocument();
|
|
|
| if (strcmp(msg.pDocName, document->getName()) != 0) {
|
| return;
|
| }
|
|
|
|
|
| auto base = static_cast<Part::Feature*>(side.UpToShape->getValue());
|
| if (!base) {
|
| base = static_cast<Part::Feature*>(extrude);
|
| }
|
| else if (strcmp(msg.pObjectName, base->getNameInDocument()) != 0) {
|
| return;
|
| }
|
|
|
| std::vector<std::string> faces = getShapeFaces(*side.UpToShape);
|
| const std::string subName(msg.pSubName);
|
|
|
| if (subName.empty()) {
|
| return;
|
| }
|
|
|
|
|
| if (const auto positionInList = std::ranges::find(faces, subName); positionInList != faces.end()) {
|
| faces.erase(positionInList);
|
| }
|
| else {
|
| faces.push_back(subName);
|
| }
|
|
|
| side.UpToShape->setValue(base, faces);
|
|
|
| updateShapeFaces(side.listWidgetReferences, *side.UpToShape);
|
|
|
| tryRecomputeFeature();
|
| }
|
|
|
| void PartDesignGui::TaskExtrudeParameters::selectedFace(
|
| const Gui::SelectionChanges& msg,
|
| SideController& side
|
| )
|
| {
|
| QString refText = onAddSelection(msg, *side.UpToFace);
|
|
|
| if (refText.length() > 0) {
|
| QSignalBlocker block(side.lineFaceName);
|
|
|
| side.lineFaceName->setText(refText);
|
| side.lineFaceName->setProperty("FeatureName", QByteArray(msg.pObjectName));
|
| side.lineFaceName->setProperty("FaceName", QByteArray(msg.pSubName));
|
|
|
|
|
| side.buttonFace->setChecked(false);
|
| }
|
| else {
|
| clearFaceName(side.lineFaceName);
|
| }
|
|
|
| setSelectionMode(None);
|
| }
|
|
|
| void PartDesignGui::TaskExtrudeParameters::selectedShape(
|
| const Gui::SelectionChanges& msg,
|
| SideController& side
|
| )
|
| {
|
| auto document = getObject()->getDocument();
|
|
|
| if (strcmp(msg.pDocName, document->getName()) != 0) {
|
| return;
|
| }
|
|
|
| Gui::Selection().clearSelection();
|
|
|
| auto ref = document->getObject(msg.pObjectName);
|
|
|
| side.UpToShape->setValue(ref);
|
|
|
| side.checkBoxAllFaces->setChecked(true);
|
|
|
| setSelectionMode(None);
|
|
|
| updateShapeName(side.lineShapeName, *side.UpToShape);
|
| updateShapeFaces(side.listWidgetReferences, *side.UpToShape);
|
|
|
| tryRecomputeFeature();
|
| }
|
|
|
| void TaskExtrudeParameters::clearFaceName(QLineEdit* lineEdit)
|
| {
|
| QSignalBlocker block(lineEdit);
|
| lineEdit->clear();
|
| lineEdit->setProperty("FeatureName", QVariant());
|
| lineEdit->setProperty("FaceName", QVariant());
|
| }
|
|
|
| void TaskExtrudeParameters::updateShapeName(QLineEdit* lineEdit, App::PropertyLinkSubList& prop)
|
| {
|
| QSignalBlocker block(lineEdit);
|
|
|
| auto shape = prop.getValue();
|
|
|
| if (shape) {
|
| lineEdit->setText(QString::fromStdString(shape->getFullName()));
|
| }
|
| else {
|
| lineEdit->setText({});
|
| lineEdit->setPlaceholderText(tr("No shape selected"));
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::updateShapeFaces(QListWidget* list, App::PropertyLinkSubList& prop)
|
| {
|
| auto faces = getShapeFaces(prop);
|
|
|
| list->clear();
|
| for (auto& ref : faces) {
|
| list->addItem(QString::fromStdString(ref));
|
| }
|
|
|
| if (selectionMode == SelectShapeFaces) {
|
| getViewObject<ViewProviderExtrude>()->highlightShapeFaces(faces);
|
| }
|
| }
|
|
|
| std::vector<std::string> PartDesignGui::TaskExtrudeParameters::getShapeFaces(
|
| App::PropertyLinkSubList& prop
|
| )
|
| {
|
| std::vector<std::string> faces;
|
|
|
| auto allRefs = prop.getSubValues();
|
|
|
| std::copy_if(allRefs.begin(), allRefs.end(), std::back_inserter(faces), [](const std::string& ref) {
|
| return boost::starts_with(ref, "Face");
|
| });
|
|
|
| return faces;
|
| }
|
|
|
| void TaskExtrudeParameters::onLengthChanged(double len, Side side)
|
| {
|
| getSideController(side).Length->setValue(len);
|
| tryRecomputeFeature();
|
| }
|
|
|
| void TaskExtrudeParameters::onOffsetChanged(double len, Side side)
|
| {
|
| getSideController(side).Offset->setValue(len);
|
| tryRecomputeFeature();
|
| }
|
|
|
| void TaskExtrudeParameters::onTaperChanged(double angle, Side side)
|
| {
|
| getSideController(side).TaperAngle->setValue(angle);
|
| tryRecomputeFeature();
|
| }
|
|
|
| bool TaskExtrudeParameters::hasProfileFace(PartDesign::ProfileBased* profile) const
|
| {
|
| try {
|
| Part::Feature* pcFeature = profile->getVerifiedObject();
|
| Base::Vector3d SketchVector = profile->getProfileNormal();
|
| Q_UNUSED(pcFeature)
|
| Q_UNUSED(SketchVector)
|
| return true;
|
| }
|
| catch (const Base::Exception&) {
|
| }
|
|
|
| return false;
|
| }
|
|
|
| void TaskExtrudeParameters::fillDirectionCombo()
|
| {
|
| Base::StateLocker lock(getUpdateBlockRef(), true);
|
|
|
| if (axesInList.empty()) {
|
| bool hasFace = false;
|
| ui->directionCB->clear();
|
|
|
|
|
| auto pcFeat = getObject<PartDesign::ProfileBased>();
|
| Part::Part2DObject* pcSketch = dynamic_cast<Part::Part2DObject*>(pcFeat->Profile.getValue());
|
|
|
| if (!pcSketch) {
|
| hasFace = hasProfileFace(pcFeat);
|
| }
|
|
|
| if (pcSketch) {
|
| addAxisToCombo(pcSketch, "N_Axis", tr("Sketch normal"));
|
| }
|
| else if (hasFace) {
|
| addAxisToCombo(pcFeat->Profile.getValue(), std::string(), tr("Face normal"), false);
|
| }
|
|
|
|
|
| addAxisToCombo(nullptr, std::string(), tr("Select reference…"));
|
|
|
|
|
| if (pcSketch) {
|
| addAxisToCombo(pcSketch, "N_Axis", tr("Custom direction"));
|
| }
|
| else if (hasFace) {
|
| addAxisToCombo(pcFeat->Profile.getValue(), std::string(), tr("Custom direction"), false);
|
| }
|
| }
|
|
|
|
|
|
|
| int indexOfCurrent = -1;
|
| App::DocumentObject* ax = propReferenceAxis->getValue();
|
| const std::vector<std::string>& subList = propReferenceAxis->getSubValues();
|
| for (size_t i = 0; i < axesInList.size(); i++) {
|
| if (ax == axesInList[i]->getValue() && subList == axesInList[i]->getSubValues()) {
|
| indexOfCurrent = i;
|
| break;
|
| }
|
| }
|
|
|
| if (indexOfCurrent == -1 && ax) {
|
| assert(subList.size() <= 1);
|
| std::string sub;
|
| if (!subList.empty()) {
|
| sub = subList[0];
|
| }
|
| addAxisToCombo(ax, sub, getRefStr(ax, subList));
|
| indexOfCurrent = axesInList.size() - 1;
|
|
|
| ui->checkBoxAlongDirection->setEnabled(true);
|
|
|
| ui->XDirectionEdit->setEnabled(false);
|
| ui->YDirectionEdit->setEnabled(false);
|
| ui->ZDirectionEdit->setEnabled(false);
|
| }
|
|
|
|
|
| auto extrude = getObject<PartDesign::FeatureExtrude>();
|
| bool hasCustom = extrude->UseCustomVector.getValue();
|
| if (indexOfCurrent != -1 && !hasCustom) {
|
| ui->directionCB->setCurrentIndex(indexOfCurrent);
|
| updateDirectionEdits();
|
| setDirectionMode(indexOfCurrent);
|
| }
|
| if (hasCustom) {
|
| ui->directionCB->setCurrentIndex(DirectionModes::Custom);
|
| setDirectionMode(ui->directionCB->currentIndex());
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::addAxisToCombo(
|
| App::DocumentObject* linkObj,
|
| std::string linkSubname,
|
| QString itemText,
|
| bool hasSketch
|
| )
|
| {
|
| this->ui->directionCB->addItem(itemText);
|
| this->axesInList.emplace_back(new App::PropertyLinkSub);
|
| App::PropertyLinkSub& lnk = *(axesInList.back());
|
|
|
|
|
| if (hasSketch) {
|
| lnk.setValue(linkObj, std::vector<std::string>(1, linkSubname));
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::updateWholeUI(Type type, Side side)
|
| {
|
| SidesMode sidesMode = static_cast<SidesMode>(ui->sidesMode->currentIndex());
|
| Mode mode1 = static_cast<Mode>(ui->changeMode->currentIndex());
|
| Mode mode2 = static_cast<Mode>(ui->changeMode2->currentIndex());
|
|
|
|
|
| const bool isSide2GroupVisible = (sidesMode == SidesMode::TwoSides);
|
| ui->side1Label->setVisible(isSide2GroupVisible);
|
| ui->side2Label->setVisible(isSide2GroupVisible);
|
| ui->line2->setVisible(isSide2GroupVisible);
|
| ui->typeLabel2->setVisible(isSide2GroupVisible);
|
| ui->changeMode2->setVisible(isSide2GroupVisible);
|
|
|
|
|
|
|
| updateSideUI(m_side1, type, mode1, true, (side == Side::First));
|
|
|
| updateSideUI(m_side2, type, mode2, isSide2GroupVisible, (side == Side::Second));
|
|
|
| ui->checkBoxReversed->setEnabled(sidesMode != SidesMode::Symmetric || mode1 != Mode::Dimension);
|
| }
|
|
|
| void TaskExtrudeParameters::updateSideUI(
|
| const SideController& s,
|
| Type featureType,
|
| Mode sideMode,
|
| bool isParentVisible,
|
| bool setFocus
|
| )
|
| {
|
|
|
| bool isLengthVisible = false;
|
| bool isOffsetVisible = false;
|
| bool isTaperVisible = false;
|
| bool isFaceVisible = false;
|
| bool isShapeVisible = false;
|
|
|
|
|
| if (sideMode == Mode::Dimension) {
|
| isLengthVisible = true;
|
| isTaperVisible = true;
|
| if (setFocus) {
|
| s.lengthEdit->selectNumber();
|
| QMetaObject::invokeMethod(s.lengthEdit, "setFocus", Qt::QueuedConnection);
|
| }
|
| }
|
| else if (sideMode == Mode::ThroughAll && featureType == Type::Pocket) {
|
| isTaperVisible = true;
|
| }
|
| else if (sideMode == Mode::ToLast && featureType == Type::Pad) {
|
| isOffsetVisible = true;
|
| }
|
| else if (sideMode == Mode::ToFirst) {
|
| isOffsetVisible = true;
|
| }
|
| else if (sideMode == Mode::ToFace) {
|
| isOffsetVisible = true;
|
| isFaceVisible = true;
|
| if (setFocus) {
|
| QMetaObject::invokeMethod(s.lineFaceName, "setFocus", Qt::QueuedConnection);
|
|
|
| if (s.lineFaceName->property("FeatureName").isNull()) {
|
| s.buttonFace->setChecked(true);
|
| }
|
| }
|
| }
|
| else if (sideMode == Mode::ToShape) {
|
| isShapeVisible = true;
|
| if (setFocus) {
|
| if (!s.checkBoxAllFaces->isChecked()) {
|
| s.buttonShapeFace->setChecked(true);
|
| }
|
| }
|
| }
|
|
|
|
|
|
|
| const bool finalLengthVisible = isParentVisible && isLengthVisible;
|
| s.labelLength->setVisible(finalLengthVisible);
|
| s.lengthEdit->setVisible(finalLengthVisible);
|
| s.lengthEdit->setEnabled(finalLengthVisible);
|
|
|
| const bool finalOffsetVisible = isParentVisible && isOffsetVisible;
|
| s.labelOffset->setVisible(finalOffsetVisible);
|
| s.offsetEdit->setVisible(finalOffsetVisible);
|
| s.offsetEdit->setEnabled(finalOffsetVisible);
|
|
|
| const bool finalTaperVisible = isParentVisible && isTaperVisible;
|
| s.labelTaperAngle->setVisible(finalTaperVisible);
|
| s.taperEdit->setVisible(finalTaperVisible);
|
| s.taperEdit->setEnabled(finalTaperVisible);
|
|
|
| s.buttonFace->setVisible(isParentVisible && isFaceVisible);
|
| s.lineFaceName->setVisible(isParentVisible && isFaceVisible);
|
| if (!isFaceVisible) {
|
| s.buttonFace->setChecked(false);
|
| }
|
|
|
| s.upToShapeList->setVisible(isParentVisible && isShapeVisible);
|
| }
|
|
|
| void TaskExtrudeParameters::onDirectionCBChanged(int num)
|
| {
|
| if (axesInList.empty()) {
|
| return;
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| App::PropertyLinkSub& lnk = *(axesInList[num]);
|
|
|
| if (num == DirectionModes::Select) {
|
|
|
| setSelectionMode(SelectReferenceAxis);
|
| setDirectionMode(num);
|
| }
|
| else if (auto extrude = getObject<PartDesign::FeatureExtrude>()) {
|
| if (lnk.getValue()) {
|
| if (!extrude->getDocument()->isIn(lnk.getValue())) {
|
| Base::Console().error("Object was deleted\n");
|
| return;
|
| }
|
| propReferenceAxis->Paste(lnk);
|
| }
|
|
|
|
|
| setSelectionMode(None);
|
| setDirectionMode(num);
|
|
|
| extrude->ReferenceAxis.setValue(lnk.getValue(), lnk.getSubValues());
|
| tryRecomputeFeature();
|
| updateDirectionEdits();
|
|
|
| setGizmoPositions();
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::onAlongSketchNormalChanged(bool on)
|
| {
|
| if (auto extrude = getObject<PartDesign::FeatureExtrude>()) {
|
| extrude->AlongSketchNormal.setValue(on);
|
| tryRecomputeFeature();
|
|
|
| setGizmoPositions();
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::onAllFacesToggled(bool on, Side side)
|
| {
|
| auto& sideCtrl = getSideController(side);
|
| sideCtrl.upToShapeFaces->setVisible(!on);
|
| sideCtrl.buttonShapeFace->setChecked(false);
|
|
|
| if (on) {
|
| if (auto extrude = getObject<PartDesign::FeatureExtrude>()) {
|
| extrude->UpToShape.setValue(extrude->UpToShape.getValue());
|
| updateShapeFaces(sideCtrl.listWidgetReferences, *sideCtrl.UpToShape);
|
| tryRecomputeFeature();
|
| }
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::onXDirectionEditChanged(double len)
|
| {
|
| if (auto extrude = getObject<PartDesign::FeatureExtrude>()) {
|
| extrude->Direction
|
| .setValue(len, extrude->Direction.getValue().y, extrude->Direction.getValue().z);
|
| tryRecomputeFeature();
|
|
|
|
|
|
|
| updateDirectionEdits();
|
| setGizmoPositions();
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::onYDirectionEditChanged(double len)
|
| {
|
| if (auto extrude = getObject<PartDesign::FeatureExtrude>()) {
|
| extrude->Direction
|
| .setValue(extrude->Direction.getValue().x, len, extrude->Direction.getValue().z);
|
| tryRecomputeFeature();
|
| updateDirectionEdits();
|
| setGizmoPositions();
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::onZDirectionEditChanged(double len)
|
| {
|
| if (auto extrude = getObject<PartDesign::FeatureExtrude>()) {
|
| extrude->Direction
|
| .setValue(extrude->Direction.getValue().x, extrude->Direction.getValue().y, len);
|
| tryRecomputeFeature();
|
| updateDirectionEdits();
|
| setGizmoPositions();
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::updateDirectionEdits()
|
| {
|
| auto extrude = getObject<PartDesign::FeatureExtrude>();
|
|
|
| QSignalBlocker xdir(ui->XDirectionEdit);
|
| QSignalBlocker ydir(ui->YDirectionEdit);
|
| QSignalBlocker zdir(ui->ZDirectionEdit);
|
| ui->XDirectionEdit->setValue(extrude->Direction.getValue().x);
|
| ui->YDirectionEdit->setValue(extrude->Direction.getValue().y);
|
| ui->ZDirectionEdit->setValue(extrude->Direction.getValue().z);
|
| }
|
|
|
| void TaskExtrudeParameters::setDirectionMode(int index)
|
| {
|
| auto extrude = getObject<PartDesign::FeatureExtrude>();
|
| if (!extrude) {
|
| return;
|
| }
|
|
|
| switch (index) {
|
|
|
| case DirectionModes::Normal:
|
| ui->groupBoxDirection->hide();
|
|
|
| extrude->UseCustomVector.setValue(false);
|
| ui->XDirectionEdit->setEnabled(false);
|
| ui->YDirectionEdit->setEnabled(false);
|
| ui->ZDirectionEdit->setEnabled(false);
|
|
|
| ui->checkBoxAlongDirection->setEnabled(false);
|
| ui->checkBoxAlongDirection->hide();
|
|
|
| break;
|
|
|
|
|
|
|
|
|
| case DirectionModes::Custom:
|
| ui->groupBoxDirection->show();
|
|
|
| extrude->UseCustomVector.setValue(true);
|
| ui->XDirectionEdit->setEnabled(true);
|
| ui->YDirectionEdit->setEnabled(true);
|
| ui->ZDirectionEdit->setEnabled(true);
|
|
|
| ui->checkBoxAlongDirection->setEnabled(true);
|
| ui->checkBoxAlongDirection->show();
|
| break;
|
|
|
| default:
|
| ui->groupBoxDirection->show();
|
|
|
| updateDirectionEdits();
|
|
|
| extrude->UseCustomVector.setValue(false);
|
| ui->XDirectionEdit->setEnabled(false);
|
| ui->YDirectionEdit->setEnabled(false);
|
| ui->ZDirectionEdit->setEnabled(false);
|
|
|
| ui->checkBoxAlongDirection->setEnabled(true);
|
| ui->checkBoxAlongDirection->show();
|
| break;
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::onReversedChanged(bool on)
|
| {
|
| if (auto extrude = getObject<PartDesign::FeatureExtrude>()) {
|
| extrude->Reversed.setValue(on);
|
|
|
| tryRecomputeFeature();
|
| updateDirectionEdits();
|
|
|
| setGizmoPositions();
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::getReferenceAxis(App::DocumentObject*& obj, std::vector<std::string>& sub) const
|
| {
|
| if (axesInList.empty()) {
|
| throw Base::RuntimeError("Not initialized!");
|
| }
|
|
|
| int num = ui->directionCB->currentIndex();
|
| const App::PropertyLinkSub& lnk = *(axesInList[num]);
|
| if (!lnk.getValue()) {
|
|
|
|
|
| obj = nullptr;
|
| sub.clear();
|
| }
|
| else {
|
| auto pcDirection = getObject<PartDesign::ProfileBased>();
|
| if (!pcDirection->getDocument()->isIn(lnk.getValue())) {
|
| throw Base::RuntimeError("Object was deleted");
|
| }
|
|
|
| obj = lnk.getValue();
|
| sub = lnk.getSubValues();
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::onSelectFaceToggle(const bool checked, Side side)
|
| {
|
| auto& sideCtrl = getSideController(side);
|
| if (checked) {
|
| handleLineFaceNameClick(sideCtrl.lineFaceName);
|
| setSelectionMode(SelectFace, side);
|
| }
|
| else {
|
| handleLineFaceNameNo(sideCtrl.lineFaceName);
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::onSelectShapeToggle(bool checked, Side side)
|
| {
|
| auto& sideCtrl = getSideController(side);
|
| if (checked) {
|
| setSelectionMode(SelectShape, side);
|
| sideCtrl.lineShapeName->setText({});
|
| sideCtrl.lineShapeName->setPlaceholderText(tr("Click on a shape in the model"));
|
| }
|
| else {
|
| setSelectionMode(None);
|
| updateShapeName(sideCtrl.lineShapeName, *sideCtrl.UpToShape);
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::onFaceName(const QString& text, Side side)
|
| {
|
| auto& sideCtrl = getSideController(side);
|
| changeFaceName(sideCtrl.lineFaceName, text);
|
| }
|
|
|
| void TaskExtrudeParameters::changeFaceName(QLineEdit* lineEdit, const QString& text)
|
| {
|
| if (text.isEmpty()) {
|
|
|
| lineEdit->setProperty("FeatureName", QVariant());
|
| lineEdit->setProperty("FaceName", QVariant());
|
| }
|
| else {
|
|
|
| QStringList parts = text.split(QChar::fromLatin1(':'));
|
| QString label = parts[0];
|
| QVariant name = objectNameByLabel(label, lineEdit->property("FeatureName"));
|
| if (name.isValid()) {
|
| parts[0] = name.toString();
|
| QString uptoface = parts.join(QStringLiteral(":"));
|
| lineEdit->setProperty("FeatureName", name);
|
| lineEdit->setProperty("FaceName", setUpToFace(uptoface));
|
| }
|
| else {
|
| lineEdit->setProperty("FeatureName", QVariant());
|
| lineEdit->setProperty("FaceName", QVariant());
|
| }
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::translateFaceName(QLineEdit* lineEdit)
|
| {
|
| handleLineFaceNameNo(lineEdit);
|
| QVariant featureName = lineEdit->property("FeatureName");
|
| if (featureName.isValid()) {
|
| QStringList parts = lineEdit->text().split(QChar::fromLatin1(':'));
|
| QByteArray upToFace = lineEdit->property("FaceName").toByteArray();
|
| int faceId = -1;
|
| bool ok = false;
|
| if (upToFace.indexOf("Face") == 0) {
|
| faceId = upToFace.remove(0, 4).toInt(&ok);
|
| }
|
|
|
| if (ok) {
|
| lineEdit->setText(QStringLiteral("%1:%2%3").arg(parts[0], tr("Face")).arg(faceId));
|
| }
|
| else {
|
| lineEdit->setText(parts[0]);
|
| }
|
| }
|
| }
|
|
|
| double TaskExtrudeParameters::getOffset() const
|
| {
|
| return ui->offsetEdit->value().getValue();
|
| }
|
|
|
| double TaskExtrudeParameters::getOffset2() const
|
| {
|
| return ui->offsetEdit2->value().getValue();
|
| }
|
|
|
| bool TaskExtrudeParameters::getAlongSketchNormal() const
|
| {
|
| return ui->checkBoxAlongDirection->isChecked();
|
| }
|
|
|
| bool TaskExtrudeParameters::getCustom() const
|
| {
|
| return (ui->directionCB->currentIndex() == DirectionModes::Custom);
|
| }
|
|
|
| std::string TaskExtrudeParameters::getReferenceAxis() const
|
| {
|
| std::vector<std::string> sub;
|
| App::DocumentObject* obj;
|
| getReferenceAxis(obj, sub);
|
| return buildLinkSingleSubPythonStr(obj, sub);
|
| }
|
|
|
| double TaskExtrudeParameters::getXDirection() const
|
| {
|
| return ui->XDirectionEdit->value();
|
| }
|
|
|
| double TaskExtrudeParameters::getYDirection() const
|
| {
|
| return ui->YDirectionEdit->value();
|
| }
|
|
|
| double TaskExtrudeParameters::getZDirection() const
|
| {
|
| return ui->ZDirectionEdit->value();
|
| }
|
|
|
| bool TaskExtrudeParameters::getReversed() const
|
| {
|
| return ui->checkBoxReversed->isChecked();
|
| }
|
|
|
| int TaskExtrudeParameters::getMode() const
|
| {
|
| return ui->changeMode->currentIndex();
|
| }
|
|
|
| int TaskExtrudeParameters::getMode2() const
|
| {
|
| return ui->changeMode2->currentIndex();
|
| }
|
|
|
| int TaskExtrudeParameters::getSidesMode() const
|
| {
|
| return ui->sidesMode->currentIndex();
|
| }
|
|
|
| QString TaskExtrudeParameters::getFaceName(QLineEdit* lineEdit) const
|
| {
|
| QVariant featureName = lineEdit->property("FeatureName");
|
| if (featureName.isValid()) {
|
| QString faceName = lineEdit->property("FaceName").toString();
|
| return getFaceReference(featureName.toString(), faceName);
|
| }
|
|
|
| return QStringLiteral("None");
|
| }
|
|
|
| void TaskExtrudeParameters::changeEvent(QEvent* e)
|
| {
|
| TaskBox::changeEvent(e);
|
| if (e->type() == QEvent::LanguageChange) {
|
| QSignalBlocker length(ui->lengthEdit);
|
| QSignalBlocker length2(ui->lengthEdit2);
|
| QSignalBlocker offset(ui->offsetEdit);
|
| QSignalBlocker offset2(ui->offsetEdit2);
|
| QSignalBlocker taper(ui->taperEdit);
|
| QSignalBlocker taper2(ui->taperEdit2);
|
| QSignalBlocker xdir(ui->XDirectionEdit);
|
| QSignalBlocker ydir(ui->YDirectionEdit);
|
| QSignalBlocker zdir(ui->ZDirectionEdit);
|
| QSignalBlocker dir(ui->directionCB);
|
| QSignalBlocker face(ui->lineFaceName);
|
| QSignalBlocker face2(ui->lineFaceName2);
|
| QSignalBlocker mode(ui->changeMode);
|
| QSignalBlocker mode2(ui->changeMode2);
|
| QSignalBlocker sidesMode(ui->sidesMode);
|
|
|
|
|
| QStringList items;
|
| for (int i = 0; i < ui->directionCB->count(); i++) {
|
| items << ui->directionCB->itemText(i);
|
| }
|
|
|
|
|
| int index = ui->directionCB->currentIndex();
|
| ui->retranslateUi(proxy);
|
|
|
|
|
| for (int i = 0; i < ui->directionCB->count(); i++) {
|
| items.pop_front();
|
| }
|
| ui->directionCB->addItems(items);
|
| ui->directionCB->setCurrentIndex(index);
|
|
|
|
|
| translateModeList(ui->changeMode, ui->changeMode->currentIndex());
|
| translateModeList(ui->changeMode2, ui->changeMode2->currentIndex());
|
| translateSidesList(ui->sidesMode->currentIndex());
|
|
|
| translateFaceName(ui->lineFaceName);
|
| translateFaceName(ui->lineFaceName2);
|
| }
|
| }
|
|
|
| void TaskExtrudeParameters::saveHistory()
|
| {
|
|
|
| ui->lengthEdit->pushToHistory();
|
| ui->lengthEdit2->pushToHistory();
|
| ui->offsetEdit->pushToHistory();
|
| ui->offsetEdit2->pushToHistory();
|
| ui->taperEdit->pushToHistory();
|
| ui->taperEdit2->pushToHistory();
|
| }
|
|
|
| void TaskExtrudeParameters::applyParameters()
|
| {
|
| auto obj = getObject();
|
|
|
| QString facename = QStringLiteral("None");
|
| QString facename2 = QStringLiteral("None");
|
| if (static_cast<Mode>(getMode()) == Mode::ToFace) {
|
| facename = getFaceName(ui->lineFaceName);
|
| }
|
| if (static_cast<Mode>(getMode2()) == Mode::ToFace) {
|
| facename2 = getFaceName(ui->lineFaceName2);
|
| }
|
|
|
|
|
| int type1 = getMode();
|
| if (static_cast<Mode>(type1) == Mode::ToShape) {
|
| type1++;
|
| }
|
| int type2 = getMode2();
|
| if (static_cast<Mode>(type2) == Mode::ToShape) {
|
| type2++;
|
| }
|
|
|
| ui->lengthEdit->apply();
|
| ui->lengthEdit2->apply();
|
| ui->taperEdit->apply();
|
| ui->taperEdit2->apply();
|
| FCMD_OBJ_CMD(obj, "UseCustomVector = " << (getCustom() ? 1 : 0));
|
| FCMD_OBJ_CMD(
|
| obj,
|
| "Direction = (" << getXDirection() << ", " << getYDirection() << ", " << getZDirection() << ")"
|
| );
|
| FCMD_OBJ_CMD(obj, "ReferenceAxis = " << getReferenceAxis());
|
| FCMD_OBJ_CMD(obj, "AlongSketchNormal = " << (getAlongSketchNormal() ? 1 : 0));
|
| FCMD_OBJ_CMD(obj, "SideType = " << getSidesMode());
|
| FCMD_OBJ_CMD(obj, "Type = " << type1);
|
| FCMD_OBJ_CMD(obj, "Type2 = " << type2);
|
| FCMD_OBJ_CMD(obj, "UpToFace = " << facename.toUtf8().data());
|
| FCMD_OBJ_CMD(obj, "UpToFace2 = " << facename2.toUtf8().data());
|
| FCMD_OBJ_CMD(obj, "Reversed = " << (getReversed() ? 1 : 0));
|
| FCMD_OBJ_CMD(obj, "Offset = " << getOffset());
|
| FCMD_OBJ_CMD(obj, "Offset2 = " << getOffset2());
|
| }
|
|
|
| void TaskExtrudeParameters::onSidesModeChanged(int index)
|
| {
|
| auto extrude = getObject<PartDesign::FeatureExtrude>();
|
| switch (static_cast<SidesMode>(index)) {
|
| case SidesMode::OneSide:
|
| extrude->SideType.setValue("One side");
|
| updateUI(Side::First);
|
| break;
|
| case SidesMode::TwoSides:
|
| extrude->SideType.setValue("Two sides");
|
| updateUI(Side::Second);
|
| break;
|
| case SidesMode::Symmetric:
|
| extrude->SideType.setValue("Symmetric");
|
| updateUI(Side::First);
|
| break;
|
| }
|
|
|
| recomputeFeature();
|
| }
|
|
|
| void TaskExtrudeParameters::updateUI(Side)
|
| {
|
|
|
| }
|
|
|
| void TaskExtrudeParameters::translateModeList(QComboBox*, int)
|
| {
|
|
|
| }
|
|
|
| void TaskExtrudeParameters::translateSidesList(int index)
|
| {
|
| ui->sidesMode->clear();
|
| ui->sidesMode->addItem(tr("One sided"));
|
| ui->sidesMode->addItem(tr("Two sided"));
|
| ui->sidesMode->addItem(tr("Symmetric"));
|
| ui->sidesMode->setCurrentIndex(index);
|
| }
|
|
|
| void TaskExtrudeParameters::handleLineFaceNameClick(QLineEdit* lineEdit)
|
| {
|
| lineEdit->setPlaceholderText(tr("Click on a face in the model"));
|
| }
|
|
|
| void TaskExtrudeParameters::handleLineFaceNameNo(QLineEdit* lineEdit)
|
| {
|
| lineEdit->setPlaceholderText(tr("No face selected"));
|
| }
|
|
|
| void TaskExtrudeParameters::setupGizmos()
|
| {
|
| if (GizmoContainer::isEnabled() == false) {
|
| return;
|
| }
|
|
|
| lengthGizmo1 = new Gui::LinearGizmo(ui->lengthEdit);
|
| lengthGizmo2 = new Gui::LinearGizmo(ui->lengthEdit2);
|
| taperAngleGizmo1 = new Gui::RotationGizmo(ui->taperEdit);
|
| taperAngleGizmo2 = new Gui::RotationGizmo(ui->taperEdit2);
|
|
|
| connect(ui->sidesMode, qOverload<int>(&QComboBox::currentIndexChanged), [this](int) {
|
| setGizmoPositions();
|
| });
|
|
|
| gizmoContainer = GizmoContainer::create(
|
| {lengthGizmo1, lengthGizmo2, taperAngleGizmo1, taperAngleGizmo2},
|
| vp
|
| );
|
|
|
| setGizmoPositions();
|
| }
|
|
|
| void TaskExtrudeParameters::setGizmoPositions()
|
| {
|
| if (!gizmoContainer) {
|
| return;
|
| }
|
|
|
| auto extrude = getObject<PartDesign::FeatureExtrude>();
|
| if (!extrude || extrude->isError()) {
|
| gizmoContainer->visible = false;
|
| return;
|
| }
|
| gizmoContainer->visible = true;
|
|
|
| PartDesign::TopoShape shape = extrude->getProfileShape();
|
| Base::Vector3d center = getMidPointFromProfile(shape);
|
| std::string sideType = std::string(extrude->SideType.getValueAsString());
|
| std::string extrudeType = std::string(extrude->Type.getValueAsString());
|
| std::string extrudeType2 = std::string(extrude->Type2.getValueAsString());
|
| double dir = extrude->Reversed.getValue() ? -1 : 1;
|
|
|
| lengthGizmo1->Gizmo::setDraggerPlacement(center, extrude->Direction.getValue() * dir);
|
| lengthGizmo1->setVisibility(extrudeType == "Length");
|
| taperAngleGizmo1->placeOverLinearGizmo(lengthGizmo1);
|
| taperAngleGizmo1->setVisibility(extrudeType == "Length");
|
| lengthGizmo2->Gizmo::setDraggerPlacement(center, -extrude->Direction.getValue() * dir);
|
| lengthGizmo2->setVisibility(sideType == "Two sides" && extrudeType2 == "Length");
|
| taperAngleGizmo2->placeOverLinearGizmo(lengthGizmo2);
|
| taperAngleGizmo2->setVisibility(sideType == "Two sides" && extrudeType2 == "Length");
|
|
|
| Base::Vector3d padDir = extrude->Direction.getValue().Normalized();
|
| Base::Vector3d sketchDir = extrude->getProfileNormal().Normalized();
|
|
|
| double lengthFactor = padDir.Dot(sketchDir);
|
| double multFactor = (sideType == "Symmetric") ? 0.5 : 1.0;
|
|
|
|
|
|
|
|
|
| if (extrude->AlongSketchNormal.getValue()) {
|
| lengthGizmo1->setMultFactor(multFactor / lengthFactor);
|
| lengthGizmo2->setMultFactor(multFactor / lengthFactor);
|
| }
|
| else {
|
| lengthGizmo1->setMultFactor(multFactor);
|
| lengthGizmo2->setMultFactor(multFactor);
|
| }
|
|
|
| gizmoContainer->calculateScaleAndOrientation();
|
| }
|
|
|
| TaskDlgExtrudeParameters::TaskDlgExtrudeParameters(PartDesignGui::ViewProviderExtrude* vp)
|
| : TaskDlgSketchBasedParameters(vp)
|
| {}
|
|
|
| bool TaskDlgExtrudeParameters::accept()
|
| {
|
| getTaskParameters()->setSelectionMode(TaskExtrudeParameters::None);
|
|
|
| return TaskDlgSketchBasedParameters::accept();
|
| }
|
|
|
| bool TaskDlgExtrudeParameters::reject()
|
| {
|
| getTaskParameters()->setSelectionMode(TaskExtrudeParameters::None);
|
|
|
| return TaskDlgSketchBasedParameters::reject();
|
| }
|
|
|
| #include "moc_TaskExtrudeParameters.cpp"
|
|
|