FreeCAD / src /Mod /PartDesign /Gui /TaskExtrudeParameters.cpp
AbdulElahGwaith's picture
Upload folder using huggingface_hub
985c397 verified
/***************************************************************************
* Copyright (c) 2021 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* 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 <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;
/* TRANSLATOR PartDesignGui::TaskExtrudeParameters */
TaskExtrudeParameters::TaskExtrudeParameters(
ViewProviderExtrude* SketchBasedView,
QWidget* parent,
const std::string& pixmapname,
const QString& parname
)
: TaskSketchBasedParameters(SketchBasedView, parent, pixmapname, parname)
, propReferenceAxis(nullptr)
, ui(new Ui_TaskPadPocketParameters)
{
// we need a separate container widget to add all controls to
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();
// --- Global, Non-Side-Specific Setup ---
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());
// --- Per-Side Setup using the Helper ---
setupSideDialog(m_side1);
setupSideDialog(m_side2);
// --- Final Global UI State Setup ---
translateSidesList(extrude->SideType.getValue());
connectSlots();
this->propReferenceAxis = &(extrude->ReferenceAxis);
updateUI(Side::First);
setupGizmos();
// trigger recompute to ensure external geometry references update correctly.
// see freecad issue #25794
tryRecomputeFeature();
}
void TaskExtrudeParameters::setupSideDialog(SideController& side)
{
// --- Get initial values from the correct side's properties ---
Base::Quantity length = side.Length->getQuantityValue();
Base::Quantity offset = side.Offset->getQuantityValue();
Base::Quantity taper = side.TaperAngle->getQuantityValue();
int typeIndex = side.Type->getValue();
// The Type/Type2 properties are stuck with the deprecated 'TwoLength' mode.
// Because enums do not store text just an index. So this create
// a inconsistence between the UI and the property.
if (typeIndex > static_cast<int>(Mode::ToShape)) {
typeIndex--;
}
// --- Set up UI widgets with initial values ---
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);
// --- Bind UI widgets to the correct properties ---
side.lengthEdit->bind(*side.Length);
side.offsetEdit->bind(*side.Offset);
side.taperEdit->bind(*side.TaperAngle);
// --- Handle "Up to face" label logic ---
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) { // starts_with
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()));
// --- Update shape-related UI ---
updateShapeName(side.lineShapeName, *side.UpToShape);
updateShapeFaces(side.listWidgetReferences, *side.UpToShape);
// --- Set up the mode combobox and list widget context menu ---
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>();
// --- Initialize Side 1 Controller ---
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;
// --- Initialize Side 2 Controller ---
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);
});
};
// Use the lambda to connect slots for both sides
connectSideSlots(m_side1, Side::First, &TaskExtrudeParameters::onModeChanged_Side1);
connectSideSlots(m_side2, Side::Second, &TaskExtrudeParameters::onModeChanged_Side2);
// clang-format off
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);
// clang-format on
}
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 {
// recompute and update the direction
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:
// no-op
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();
// update direction combobox
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;
}
// Get the base shape from the correct side's property
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;
}
// Add or remove the face from the list
if (const auto positionInList = std::ranges::find(faces, subName); positionInList != faces.end()) {
faces.erase(positionInList); // Remove it if it exists
}
else {
faces.push_back(subName); // Add it if it's new
}
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));
// Turn off reference selection mode
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();
// we can have sketches or faces
// for sketches just get the sketch normal
auto pcFeat = getObject<PartDesign::ProfileBased>();
Part::Part2DObject* pcSketch = dynamic_cast<Part::Part2DObject*>(pcFeat->Profile.getValue());
// for faces we test if it is verified and if we can get its normal
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);
}
// add the other entries
addAxisToCombo(nullptr, std::string(), tr("Select reference…"));
// we start with the sketch normal as proposal for the custom direction
if (pcSketch) {
addAxisToCombo(pcSketch, "N_Axis", tr("Custom direction"));
}
else if (hasFace) {
addAxisToCombo(pcFeat->Profile.getValue(), std::string(), tr("Custom direction"), false);
}
}
// add current link, if not in list
// first, figure out the item number for current axis
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 the axis is not yet listed in the combobox
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;
// the axis is not the normal, thus enable along direction
ui->checkBoxAlongDirection->setEnabled(true);
// we don't have custom direction thus disable its settings
ui->XDirectionEdit->setEnabled(false);
ui->YDirectionEdit->setEnabled(false);
ui->ZDirectionEdit->setEnabled(false);
}
// highlight either current index or set custom direction
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 we have a face, we leave the link empty since we cannot
// store the face normal as sublink
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());
// --- Global UI visibility based on SidesMode ---
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);
// --- Configure each side using the helper method ---
// Side 1 is always conceptually visible, and we pass whether it should receive focus.
updateSideUI(m_side1, type, mode1, true, (side == Side::First));
// Side 2 is only visible if in TwoSides mode, and we pass whether it should receive focus.
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
)
{
// Default states for all controls for this side
bool isLengthVisible = false;
bool isOffsetVisible = false;
bool isTaperVisible = false;
bool isFaceVisible = false;
bool isShapeVisible = false;
// This logic block is a direct translation of the original 'if/else if' chain
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);
// Go into reference selection mode if no face has been selected yet
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);
}
}
}
// Apply visibility based on the logic above AND the parent visibility.
// This single 'isParentVisible' check correctly hides all of Side 2's UI at once.
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); // Ensure button is unchecked when hidden
}
s.upToShapeList->setVisible(isParentVisible && isShapeVisible);
}
void TaskExtrudeParameters::onDirectionCBChanged(int num)
{
if (axesInList.empty()) {
return;
}
// we use this scheme for 'num'
// 0: normal to sketch or face
// 1: selection mode
// 2: custom
// 3-x: edges selected in the 3D model
// check the axis
// when the link is empty we are either in selection mode
// or we are normal to a face
App::PropertyLinkSub& lnk = *(axesInList[num]);
if (num == DirectionModes::Select) {
// to distinguish that this is the direction selection
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);
}
// in case the user is in selection mode, but changed his mind before selecting anything
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();
// checking for case of a null vector is done in FeatureExtrude.cpp
// if there was a null vector, the normal vector of the sketch is used.
// therefore the vector component edits must be updated
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>();
// we don't want to execute the onChanged edits, but just update their contents
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;
// Covered by the default option
// case DirectionModes::Select:
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);
// update the direction
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()) {
// Note: It is possible that a face of an object is directly padded/pocketed without
// defining a profile shape
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()) {
// if user cleared the text field then also clear the properties
lineEdit->setProperty("FeatureName", QVariant());
lineEdit->setProperty("FaceName", QVariant());
}
else {
// expect that the label of an object is used
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);
// Save all items
QStringList items;
for (int i = 0; i < ui->directionCB->count(); i++) {
items << ui->directionCB->itemText(i);
}
// Translate direction items
int index = ui->directionCB->currentIndex();
ui->retranslateUi(proxy);
// Keep custom items
for (int i = 0; i < ui->directionCB->count(); i++) {
items.pop_front();
}
ui->directionCB->addItems(items);
ui->directionCB->setCurrentIndex(index);
// Translate mode items
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()
{
// save the user values to history
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);
}
// Handle deprecated 'TwoLength' mode.
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)
{
// implement in sub-class
}
void TaskExtrudeParameters::translateModeList(QComboBox*, int)
{
// implement in sub-class
}
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;
// Important note: This code assumes that nothing other than alongSketchNormal
// and symmetric option influence the multFactor. If some custom gizmos changes
// it then that also should be handled properly here
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"