Merge pull request #8990 from Ondsel-Development/FilletDraftThickness_ui_Consistency

PartDesign: Fillet, Chamfer, Draft, Thickness rework.
This commit is contained in:
Chris Hennes
2023-03-28 09:44:39 -05:00
committed by GitHub
19 changed files with 389 additions and 694 deletions

View File

@@ -109,7 +109,8 @@ App::DocumentObjectExecReturn *Chamfer::execute()
Part::TopoShape TopShape;
try {
TopShape = getBaseShape();
} catch (Base::Exception& e) {
}
catch (Base::Exception& e) {
return new App::DocumentObjectExecReturn(e.what());
}
@@ -130,9 +131,6 @@ App::DocumentObjectExecReturn *Chamfer::execute()
getContinuousEdges(TopShape, SubNames, FaceNames);
if (SubNames.empty())
return new App::DocumentObjectExecReturn("No edges specified");
const int chamferType = ChamferType.getValue();
const double size = Size.getValue();
const double size2 = Size2.getValue();
@@ -145,6 +143,13 @@ App::DocumentObjectExecReturn *Chamfer::execute()
}
this->positionByBaseFeature();
//If no element is selected, then we use a copy of previous feature.
if (SubNames.empty()) {
this->Shape.setValue(TopShape);
return App::DocumentObject::StdReturn;
}
// create an untransformed copy of the basefeature shape
Part::TopoShape baseShape(TopShape);
baseShape.setTransform(Base::Matrix4D());

View File

@@ -102,15 +102,21 @@ App::DocumentObjectExecReturn *Draft::execute()
Part::TopoShape TopShape;
try {
TopShape = getBaseShape();
} catch (Base::Exception& e) {
}
catch (Base::Exception& e) {
return new App::DocumentObjectExecReturn(e.what());
}
// Faces where draft should be applied
// Note: Cannot be const reference currently because of BRepOffsetAPI_DraftAngle::Remove() bug, see below
std::vector<std::string> SubVals = Base.getSubValuesStartsWith("Face");
if (SubVals.empty())
return new App::DocumentObjectExecReturn("No faces specified");
//If no element is selected, then we use a copy of previous feature.
if (SubVals.empty()) {
this->positionByBaseFeature();
this->Shape.setValue(TopShape);
return App::DocumentObject::StdReturn;
}
// Draft angle
double angle = Base::toRadians(Angle.getValue());

View File

@@ -68,7 +68,8 @@ App::DocumentObjectExecReturn *Fillet::execute()
Part::TopoShape TopShape;
try {
TopShape = getBaseShape();
} catch (Base::Exception& e) {
}
catch (Base::Exception& e) {
return new App::DocumentObjectExecReturn(e.what());
}
std::vector<std::string> SubNames = std::vector<std::string>(Base.getSubValues());
@@ -86,9 +87,6 @@ App::DocumentObjectExecReturn *Fillet::execute()
getContinuousEdges(TopShape, SubNames);
if (SubNames.empty())
return new App::DocumentObjectExecReturn("Fillet not possible on selected shapes");
double radius = Radius.getValue();
if(radius <= 0)
@@ -96,6 +94,12 @@ App::DocumentObjectExecReturn *Fillet::execute()
this->positionByBaseFeature();
//If no element is selected, then we use a copy of previous feature.
if (SubNames.empty()) {
this->Shape.setValue(TopShape);
return App::DocumentObject::StdReturn;
}
// create an untransformed copy of the base shape
Part::TopoShape baseShape(TopShape);
baseShape.setTransform(Base::Matrix4D());

View File

@@ -72,8 +72,22 @@ App::DocumentObjectExecReturn *Thickness::execute()
return new App::DocumentObjectExecReturn(e.what());
}
TopTools_ListOfShape closingFaces;
const std::vector<std::string>& subStrings = Base.getSubValues();
//If no element is selected, then we use a copy of previous feature.
if (subStrings.empty()) {
//We must set the placement of the feature in case it's empty.
this->positionByBaseFeature();
this->Shape.setValue(TopShape);
return App::DocumentObject::StdReturn;
}
/* If the feature was empty at some point, then Placement was set by positionByBaseFeature.
* However makeThickSolid apparently requires the placement to be empty, so we have to clear it*/
this->Placement.setValue(Base::Placement());
TopTools_ListOfShape closingFaces;
for (std::vector<std::string>::const_iterator it = subStrings.begin(); it != subStrings.end(); ++it) {
TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(it->c_str()));
closingFaces.Append(face);

View File

@@ -1541,7 +1541,7 @@ bool CmdPartDesignSubtractiveHelix::isActive()
//===========================================================================
bool dressupGetSelected(Gui::Command* cmd, const std::string& which,
Gui::SelectionObject &selected, bool &useAllEdges)
Gui::SelectionObject &selected, bool &useAllEdges, bool& noSelection)
{
// No PartDesign feature without Body past FreeCAD 0.16
App::Document *doc = cmd->getDocument();
@@ -1556,10 +1556,10 @@ bool dressupGetSelected(Gui::Command* cmd, const std::string& which,
std::vector<Gui::SelectionObject> selection = cmd->getSelection().getSelectionEx();
if (selection.empty()) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Select an edge, face, or body."));
return false;
} else if (selection.size() != 1) {
noSelection = true;
return true;
}
else if (selection.size() != 1) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Select an edge, face, or body from a single body."));
return false;
@@ -1615,12 +1615,6 @@ bool dressupGetSelected(Gui::Command* cmd, const std::string& which,
void finishDressupFeature(const Gui::Command* cmd, const std::string& which,
Part::Feature *base, const std::vector<std::string> & SubNames, const bool useAllEdges)
{
if (SubNames.empty()) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QString::fromStdString(which) + QObject::tr(" not possible on selected faces/edges."));
return;
}
std::ostringstream str;
str << '(' << Gui::Command::getObjectCmd(base) << ",[";
for (std::vector<std::string>::const_iterator it = SubNames.begin();it!=SubNames.end();++it){
@@ -1656,13 +1650,20 @@ void finishDressupFeature(const Gui::Command* cmd, const std::string& which,
void makeChamferOrFillet(Gui::Command* cmd, const std::string& which)
{
bool useAllEdges = false;
bool noSelection = false;
Gui::SelectionObject selected;
if (!dressupGetSelected ( cmd, which, selected, useAllEdges))
if (!dressupGetSelected ( cmd, which, selected, useAllEdges, noSelection))
return;
Part::Feature *base = static_cast<Part::Feature*>(selected.getObject());
std::vector<std::string> SubNames = std::vector<std::string>(selected.getSubNames());
Part::Feature *base;
std::vector<std::string> SubNames;
if (noSelection) {
base = static_cast<Part::Feature*>(PartDesignGui::getBody(true)->Tip.getValue());
}
else {
base = static_cast<Part::Feature*>(selected.getObject());
SubNames = std::vector<std::string>(selected.getSubNames());
}
finishDressupFeature (cmd, which, base, SubNames, useAllEdges);
}
@@ -1746,31 +1747,41 @@ void CmdPartDesignDraft::activated(int iMsg)
Q_UNUSED(iMsg);
Gui::SelectionObject selected;
bool useAllEdges = false;
if (!dressupGetSelected ( this, "Draft", selected, useAllEdges))
bool noSelection = false;
if (!dressupGetSelected ( this, "Draft", selected, useAllEdges, noSelection))
return;
Part::Feature *base = static_cast<Part::Feature*>(selected.getObject());
std::vector<std::string> SubNames = std::vector<std::string>(selected.getSubNames());
const Part::TopoShape& TopShape = base->Shape.getShape();
size_t i = 0;
Part::Feature* base;
std::vector<std::string> SubNames;
if (noSelection) {
base = static_cast<Part::Feature*>(PartDesignGui::getBody(true)->Tip.getValue());
}
else {
base = static_cast<Part::Feature*>(selected.getObject());
SubNames = std::vector<std::string>(selected.getSubNames());
// filter out the edges
while(i < SubNames.size())
{
std::string aSubName = static_cast<std::string>(SubNames.at(i));
const Part::TopoShape& TopShape = base->Shape.getShape();
if (aSubName.compare(0, 4, "Face") == 0) {
// Check for valid face types
TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str()));
BRepAdaptor_Surface sf(face);
if ((sf.GetType() != GeomAbs_Plane) && (sf.GetType() != GeomAbs_Cylinder) && (sf.GetType() != GeomAbs_Cone))
SubNames.erase(SubNames.begin()+i);
} else {
// empty name or any other sub-element
SubNames.erase(SubNames.begin()+i);
// filter out the edges
size_t i = 0;
while (i < SubNames.size())
{
std::string aSubName = SubNames.at(i);
if (aSubName.compare(0, 4, "Face") == 0) {
// Check for valid face types
TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str()));
BRepAdaptor_Surface sf(face);
if ((sf.GetType() != GeomAbs_Plane) && (sf.GetType() != GeomAbs_Cylinder) && (sf.GetType() != GeomAbs_Cone))
SubNames.erase(SubNames.begin() + i);
}
else {
// empty name or any other sub-element
SubNames.erase(SubNames.begin() + i);
}
i++;
}
i++;
}
finishDressupFeature (this, "Draft", base, SubNames, useAllEdges);
@@ -1804,23 +1815,32 @@ void CmdPartDesignThickness::activated(int iMsg)
Q_UNUSED(iMsg);
Gui::SelectionObject selected;
bool useAllEdges = false;
if (!dressupGetSelected ( this, "Thickness", selected, useAllEdges))
bool noSelection = false;
if (!dressupGetSelected ( this, "Thickness", selected, useAllEdges, noSelection))
return;
Part::Feature *base = static_cast<Part::Feature*>(selected.getObject());
std::vector<std::string> SubNames = std::vector<std::string>(selected.getSubNames());
size_t i = 0;
// filter out the edges
while(i < SubNames.size())
{
std::string aSubName = static_cast<std::string>(SubNames.at(i));
Part::Feature* base;
std::vector<std::string> SubNames;
if (noSelection) {
base = static_cast<Part::Feature*>(PartDesignGui::getBody(true)->Tip.getValue());
}
else {
base = static_cast<Part::Feature*>(selected.getObject());
SubNames = std::vector<std::string>(selected.getSubNames());
if (aSubName.compare(0, 4, "Face") != 0) {
// empty name or any other sub-element
SubNames.erase(SubNames.begin()+i);
// filter out the edges
size_t i = 0;
while (i < SubNames.size())
{
std::string aSubName = SubNames.at(i);
if (aSubName.compare(0, 4, "Face") != 0) {
// empty name or any other sub-element
SubNames.erase(SubNames.begin() + i);
}
i++;
}
i++;
}
finishDressupFeature (this, "Thickness", base, SubNames, useAllEdges);

View File

@@ -62,8 +62,7 @@ TaskChamferParameters::TaskChamferParameters(ViewProviderDressUp *DressUpView, Q
bool useAllEdges = pcChamfer->UseAllEdges.getValue();
ui->checkBoxUseAllEdges->setChecked(useAllEdges);
ui->buttonRefAdd->setEnabled(!useAllEdges);
ui->buttonRefRemove->setEnabled(!useAllEdges);
ui->buttonRefSel->setEnabled(!useAllEdges);
ui->listWidgetReferences->setEnabled(!useAllEdges);
QMetaObject::invokeMethod(ui->chamferSize, "setFocus", Qt::QueuedConnection);
@@ -85,15 +84,13 @@ TaskChamferParameters::TaskChamferParameters(ViewProviderDressUp *DressUpView, Q
this, &TaskChamferParameters::onAngleChanged);
connect(ui->flipDirection, &QCheckBox::toggled,
this, &TaskChamferParameters::onFlipDirection);
connect(ui->buttonRefAdd, &QToolButton::toggled,
this, &TaskChamferParameters::onButtonRefAdd);
connect(ui->buttonRefRemove, &QToolButton::toggled,
this, &TaskChamferParameters::onButtonRefRemove);
connect(ui->buttonRefSel, &QToolButton::toggled,
this, &TaskChamferParameters::onButtonRefSel);
connect(ui->checkBoxUseAllEdges, &QCheckBox::toggled,
this, &TaskChamferParameters::onCheckBoxUseAllEdgesToggled);
// Create context menu
createDeleteAction(ui->listWidgetReferences, ui->buttonRefRemove);
createDeleteAction(ui->listWidgetReferences);
connect(deleteAction, &QAction::triggered, this, &TaskChamferParameters::onRefDeleted);
createAddAllEdgesAction(ui->listWidgetReferences);
@@ -106,8 +103,10 @@ TaskChamferParameters::TaskChamferParameters(ViewProviderDressUp *DressUpView, Q
connect(ui->listWidgetReferences, &QListWidget::itemDoubleClicked,
this, &TaskChamferParameters::doubleClicked);
// the dialog can be called on a broken chamfer, then hide the chamfer
hideOnError();
if (strings.size() == 0)
setSelectionMode(refSel);
else
hideOnError();
}
void TaskChamferParameters::setUpUI(PartDesign::Chamfer* pcChamfer)
@@ -155,119 +154,43 @@ void TaskChamferParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
// executed when the user selected something in the CAD object
// adds/deletes the selection accordingly
if (selectionMode == none)
return;
if (msg.Type == Gui::SelectionChanges::AddSelection) {
if (referenceSelected(msg)) {
if (selectionMode == refAdd) {
ui->listWidgetReferences->addItem(QString::fromStdString(msg.pSubName));
// it might be the second one so we can enable the context menu
if (ui->listWidgetReferences->count() > 1) {
deleteAction->setEnabled(true);
deleteAction->setStatusTip(QString());
ui->buttonRefRemove->setEnabled(true);
ui->buttonRefRemove->setToolTip(tr("Click button to enter selection mode,\nclick again to end selection"));
}
}
else {
removeItemFromListWidget(ui->listWidgetReferences, msg.pSubName);
// remove its selection too
Gui::Selection().clearSelection();
// if there is only one item left, it cannot be deleted
if (ui->listWidgetReferences->count() == 1) {
deleteAction->setEnabled(false);
deleteAction->setStatusTip(tr("There must be at least one item"));
ui->buttonRefRemove->setEnabled(false);
ui->buttonRefRemove->setToolTip(tr("There must be at least one item"));
// we must also end the selection mode
exitSelectionMode();
clearButtons(none);
}
}
// highlight existing references for possible further selections
DressUpView->highlightReferences(true);
if (selectionMode == refSel) {
referenceSelected(msg, ui->listWidgetReferences);
}
}
}
void TaskChamferParameters::onCheckBoxUseAllEdgesToggled(bool checked)
{
if(checked)
setSelectionMode(none);
PartDesign::Chamfer* pcChamfer = static_cast<PartDesign::Chamfer*>(DressUpView->getObject());
ui->buttonRefRemove->setEnabled(!checked);
ui->buttonRefAdd->setEnabled(!checked);
ui->buttonRefSel->setEnabled(!checked);
ui->listWidgetReferences->setEnabled(!checked);
pcChamfer->UseAllEdges.setValue(checked);
pcChamfer->getDocument()->recomputeFeature(pcChamfer);
}
void TaskChamferParameters::clearButtons(const selectionModes notThis)
void TaskChamferParameters::setButtons(const selectionModes mode)
{
if (notThis != refAdd) ui->buttonRefAdd->setChecked(false);
if (notThis != refRemove) ui->buttonRefRemove->setChecked(false);
DressUpView->highlightReferences(false);
ui->buttonRefSel->setChecked(mode == refSel);
ui->buttonRefSel->setText(mode == refSel ? btnPreviewStr : btnSelectStr);
}
void TaskChamferParameters::onRefDeleted()
{
// assure we we are not in selection mode
exitSelectionMode();
clearButtons(none);
// delete any selections since the reference(s) might be highlighted
Gui::Selection().clearSelection();
DressUpView->highlightReferences(false);
// get the list of items to be deleted
QList<QListWidgetItem*> selectedList = ui->listWidgetReferences->selectedItems();
// if all items are selected, we must stop because one must be kept to avoid that the feature gets broken
if (selectedList.count() == ui->listWidgetReferences->model()->rowCount()) {
QMessageBox::warning(this, tr("Selection error"), tr("At least one item must be kept."));
return;
}
// get the chamfer object
PartDesign::Chamfer* pcChamfer = static_cast<PartDesign::Chamfer*>(DressUpView->getObject());
App::DocumentObject* base = pcChamfer->Base.getValue();
// get all chamfer references
std::vector<std::string> refs = pcChamfer->Base.getSubValues();
setupTransaction();
// delete the selection backwards to assure the list index keeps valid for the deletion
for (int i = selectedList.count() - 1; i > -1; i--) {
// the ref index is the same as the listWidgetReferences index
// so we can erase using the row number of the element to be deleted
int rowNumber = ui->listWidgetReferences->row(selectedList.at(i));
// erase the reference
refs.erase(refs.begin() + rowNumber);
// remove from the list
ui->listWidgetReferences->model()->removeRow(rowNumber);
}
// update the object
pcChamfer->Base.setValue(base, refs);
// recompute the feature
pcChamfer->recomputeFeature();
// hide the chamfer if there was a computation error
hideOnError();
// if there is only one item left, it cannot be deleted
if (ui->listWidgetReferences->count() == 1) {
deleteAction->setEnabled(false);
deleteAction->setStatusTip(tr("There must be at least one item"));
ui->buttonRefRemove->setEnabled(false);
ui->buttonRefRemove->setToolTip(tr("There must be at least one item"));
}
TaskDressUpParameters::deleteRef(ui->listWidgetReferences);
}
void TaskChamferParameters::onAddAllEdges()
{
TaskDressUpParameters::addAllEdges(ui->listWidgetReferences);
ui->buttonRefRemove->setEnabled(true);
}
void TaskChamferParameters::onTypeChanged(int index)
{
setSelectionMode(none);
PartDesign::Chamfer* pcChamfer = static_cast<PartDesign::Chamfer*>(DressUpView->getObject());
pcChamfer->ChamferType.setValue(index);
ui->stackedWidget->setCurrentIndex(index);
@@ -279,6 +202,7 @@ void TaskChamferParameters::onTypeChanged(int index)
void TaskChamferParameters::onSizeChanged(double len)
{
setSelectionMode(none);
PartDesign::Chamfer* pcChamfer = static_cast<PartDesign::Chamfer*>(DressUpView->getObject());
setupTransaction();
pcChamfer->Size.setValue(len);
@@ -289,6 +213,7 @@ void TaskChamferParameters::onSizeChanged(double len)
void TaskChamferParameters::onSize2Changed(double len)
{
setSelectionMode(none);
PartDesign::Chamfer* pcChamfer = static_cast<PartDesign::Chamfer*>(DressUpView->getObject());
setupTransaction();
pcChamfer->Size2.setValue(len);
@@ -299,6 +224,7 @@ void TaskChamferParameters::onSize2Changed(double len)
void TaskChamferParameters::onAngleChanged(double angle)
{
setSelectionMode(none);
PartDesign::Chamfer* pcChamfer = static_cast<PartDesign::Chamfer*>(DressUpView->getObject());
setupTransaction();
pcChamfer->Angle.setValue(angle);
@@ -309,6 +235,7 @@ void TaskChamferParameters::onAngleChanged(double angle)
void TaskChamferParameters::onFlipDirection(bool flip)
{
setSelectionMode(none);
PartDesign::Chamfer* pcChamfer = static_cast<PartDesign::Chamfer*>(DressUpView->getObject());
setupTransaction();
pcChamfer->FlipDirection.setValue(flip);
@@ -391,6 +318,10 @@ void TaskChamferParameters::apply()
ui->chamferAngle->apply();
break;
}
//Alert user if he created an empty feature
if (ui->listWidgetReferences->count() == 0)
Base::Console().Warning(tr("Empty chamfer created !\n").toStdString().c_str());
}
//**************************************************************************

View File

@@ -55,7 +55,7 @@ private Q_SLOTS:
void onCheckBoxUseAllEdgesToggled(bool checked);
protected:
void clearButtons(const selectionModes notThis) override;
void setButtons(const selectionModes mode) override;
bool event(QEvent *e) override;
void changeEvent(QEvent *e) override;
void onSelectionChanged(const Gui::SelectionChanges& msg) override;

View File

@@ -15,36 +15,18 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QToolButton" name="buttonRefAdd">
<property name="toolTip">
<string>Click button to enter selection mode,
<widget class="QToolButton" name="buttonRefSel">
<property name="toolTip">
<string>Click button to enter selection mode,
click again to end selection</string>
</property>
<property name="text">
<string>Add</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="buttonRefRemove">
<property name="toolTip">
<string>Click button to enter selection mode,
click again to end selection</string>
</property>
<property name="text">
<string>Remove</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</property>
<property name="text">
<string>Select</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listWidgetReferences">

View File

@@ -85,17 +85,15 @@ TaskDraftParameters::TaskDraftParameters(ViewProviderDressUp *DressUpView, QWidg
this, &TaskDraftParameters::onAngleChanged);
connect(ui->checkReverse, &QCheckBox::toggled,
this, &TaskDraftParameters::onReversedChanged);
connect(ui->buttonRefAdd, &QToolButton::toggled,
this, &TaskDraftParameters::onButtonRefAdd);
connect(ui->buttonRefRemove, &QToolButton::toggled,
this, &TaskDraftParameters::onButtonRefRemove);
connect(ui->buttonRefSel, &QToolButton::toggled,
this, &TaskDraftParameters::onButtonRefSel);
connect(ui->buttonPlane, &QToolButton::toggled,
this, &TaskDraftParameters::onButtonPlane);
connect(ui->buttonLine, &QToolButton::toggled,
this, &TaskDraftParameters::onButtonLine);
// Create context menu
createDeleteAction(ui->listWidgetReferences, ui->buttonRefRemove);
createDeleteAction(ui->listWidgetReferences);
connect(deleteAction, &QAction::triggered, this, &TaskDraftParameters::onRefDeleted);
connect(ui->listWidgetReferences, &QListWidget::currentItemChanged,
@@ -113,8 +111,10 @@ TaskDraftParameters::TaskDraftParameters(ViewProviderDressUp *DressUpView, QWidg
strings = pcDraft->PullDirection.getSubValues();
ui->lineLine->setText(getRefStr(ref, strings));
// the dialog can be called on a broken draft, then hide the draft
hideOnError();
if (strings.size() == 0)
setSelectionMode(refSel);
else
hideOnError();
}
void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
@@ -122,39 +122,11 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
// executed when the user selected something in the CAD object
// adds/deletes the selection accordingly
if (selectionMode == none)
return;
if (msg.Type == Gui::SelectionChanges::AddSelection) {
if (referenceSelected(msg)) {
if (selectionMode == refAdd) {
ui->listWidgetReferences->addItem(QString::fromStdString(msg.pSubName));
// it might be the second one so we can enable the context menu
if (ui->listWidgetReferences->count() > 1) {
deleteAction->setEnabled(true);
deleteAction->setStatusTip(QString());
ui->buttonRefRemove->setEnabled(true);
ui->buttonRefRemove->setToolTip(tr("Click button to enter selection mode,\nclick again to end selection"));
}
}
else {
removeItemFromListWidget(ui->listWidgetReferences, msg.pSubName);
// remove its selection too
Gui::Selection().clearSelection();
// if there is only one item left, it cannot be deleted
if (ui->listWidgetReferences->count() == 1) {
deleteAction->setEnabled(false);
deleteAction->setStatusTip(tr("There must be at least one item"));
ui->buttonRefRemove->setEnabled(false);
ui->buttonRefRemove->setToolTip(tr("There must be at least one item"));
// we must also end the selection mode
exitSelectionMode();
clearButtons(none);
}
}
// highlight existing references for possible further selections
DressUpView->highlightReferences(true);
} else if (selectionMode == plane) {
if (selectionMode == refSel) {
referenceSelected(msg, ui->listWidgetReferences);
}
else if (selectionMode == plane) {
PartDesign::Draft* pcDraft = static_cast<PartDesign::Draft*>(DressUpView->getObject());
std::vector<std::string> planes;
App::DocumentObject* selObj;
@@ -170,7 +142,8 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
DressUpView->highlightReferences(true);
// hide the draft if there was a computation error
hideOnError();
} else if (selectionMode == line) {
}
else if (selectionMode == line) {
PartDesign::Draft* pcDraft = static_cast<PartDesign::Draft*>(DressUpView->getObject());
std::vector<std::string> edges;
App::DocumentObject* selObj;
@@ -190,19 +163,18 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
}
}
void TaskDraftParameters::clearButtons(const selectionModes notThis)
void TaskDraftParameters::setButtons(const selectionModes mode)
{
if (notThis != refAdd) ui->buttonRefAdd->setChecked(false);
if (notThis != refRemove) ui->buttonRefRemove->setChecked(false);
if (notThis != line) ui->buttonLine->setChecked(false);
if (notThis != plane) ui->buttonPlane->setChecked(false);
DressUpView->highlightReferences(false);
ui->buttonRefSel->setText(mode == refSel ? btnPreviewStr : btnSelectStr);
ui->buttonRefSel->setChecked(mode == refSel);
ui->buttonLine->setChecked(mode == line);
ui->buttonPlane->setChecked(mode == plane);
}
void TaskDraftParameters::onButtonPlane(bool checked)
{
if (checked) {
clearButtons(plane);
setButtons(plane);
hideObject();
selectionMode = plane;
Gui::Selection().clearSelection();
@@ -215,7 +187,7 @@ void TaskDraftParameters::onButtonPlane(bool checked)
void TaskDraftParameters::onButtonLine(bool checked)
{
if (checked) {
clearButtons(line);
setButtons(line);
hideObject();
selectionMode = line;
Gui::Selection().clearSelection();
@@ -226,54 +198,7 @@ void TaskDraftParameters::onButtonLine(bool checked)
void TaskDraftParameters::onRefDeleted(void)
{
// assure we we are not in selection mode
exitSelectionMode();
clearButtons(none);
// delete any selections since the reference(s) might be highlighted
Gui::Selection().clearSelection();
DressUpView->highlightReferences(false);
// get the list of items to be deleted
QList<QListWidgetItem*> selectedList = ui->listWidgetReferences->selectedItems();
// if all items are selected, we must stop because one must be kept to avoid that the feature gets broken
if (selectedList.count() == ui->listWidgetReferences->model()->rowCount()) {
QMessageBox::warning(this, tr("Selection error"), tr("At least one item must be kept."));
return;
}
// get the draft object
PartDesign::Draft* pcDraft = static_cast<PartDesign::Draft*>(DressUpView->getObject());
App::DocumentObject* base = pcDraft->Base.getValue();
// get all draft references
std::vector<std::string> refs = pcDraft->Base.getSubValues();
setupTransaction();
// delete the selection backwards to assure the list index keeps valid for the deletion
for (int i = selectedList.count() - 1; i > -1; i--) {
// the ref index is the same as the listWidgetReferences index
// so we can erase using the row number of the element to be deleted
int rowNumber = ui->listWidgetReferences->row(selectedList.at(i));
// erase the reference
refs.erase(refs.begin() + rowNumber);
// remove from the list
ui->listWidgetReferences->model()->removeRow(rowNumber);
}
// update the object
pcDraft->Base.setValue(base, refs);
// recompute the feature
pcDraft->recomputeFeature();
// hide the draft if there was a computation error
hideOnError();
// if there is only one item left, it cannot be deleted
if (ui->listWidgetReferences->count() == 1) {
deleteAction->setEnabled(false);
deleteAction->setStatusTip(tr("There must be at least one item"));
ui->buttonRefRemove->setEnabled(false);
ui->buttonRefRemove->setToolTip(tr("There must be at least one item"));
}
TaskDressUpParameters::deleteRef(ui->listWidgetReferences);
}
void TaskDraftParameters::getPlane(App::DocumentObject*& obj, std::vector<std::string>& sub) const
@@ -296,7 +221,7 @@ void TaskDraftParameters::getLine(App::DocumentObject*& obj, std::vector<std::st
void TaskDraftParameters::onAngleChanged(double angle)
{
clearButtons(none);
setButtons(none);
PartDesign::Draft* pcDraft = static_cast<PartDesign::Draft*>(DressUpView->getObject());
setupTransaction();
pcDraft->Angle.setValue(angle);
@@ -311,7 +236,7 @@ double TaskDraftParameters::getAngle(void) const
}
void TaskDraftParameters::onReversedChanged(const bool on) {
clearButtons(none);
setButtons(none);
PartDesign::Draft* pcDraft = static_cast<PartDesign::Draft*>(DressUpView->getObject());
setupTransaction();
pcDraft->Reversed.setValue(on);
@@ -350,6 +275,14 @@ void TaskDraftParameters::changeEvent(QEvent *e)
}
}
void TaskDraftParameters::apply()
{
//Alert user if he created an empty feature
if (ui->listWidgetReferences->count() == 0)
Base::Console().Warning(tr("Empty draft created !\n").toStdString().c_str());
TaskDressUpParameters::apply();
}
//**************************************************************************
//**************************************************************************
@@ -387,6 +320,8 @@ bool TaskDlgDraftParameters::accept()
if (!tobj->isError())
parameter->showObject();
parameter->apply();
std::vector<std::string> strings;
App::DocumentObject* obj;
TaskDraftParameters* draftparameter = static_cast<TaskDraftParameters*>(parameter);

View File

@@ -40,6 +40,8 @@ public:
explicit TaskDraftParameters(ViewProviderDressUp *DressUpView, QWidget *parent=nullptr);
~TaskDraftParameters() override;
void apply() override;
double getAngle() const;
bool getReversed() const;
const std::vector<std::string> getFaces() const;
@@ -54,7 +56,7 @@ private Q_SLOTS:
void onRefDeleted() override;
protected:
void clearButtons(const selectionModes notThis) override;
void setButtons(const selectionModes mode) override;
bool event(QEvent *e) override;
void changeEvent(QEvent *e) override;
void onSelectionChanged(const Gui::SelectionChanges& msg) override;

View File

@@ -15,36 +15,19 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QToolButton" name="buttonRefAdd">
<property name="toolTip">
<string>Click button to enter selection mode,
<widget class="QToolButton" name="buttonRefSel">
<property name="toolTip">
<string>Click button to enter selection mode,
click again to end selection</string>
</property>
<property name="text">
<string>Add face</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="buttonRefRemove">
<property name="toolTip">
<string>Click button to enter selection mode,
click again to end selection</string>
</property>
<property name="text">
<string>Remove face</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</property>
<property name="text">
<string>Select</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listWidgetReferences">

View File

@@ -41,7 +41,6 @@
#include <Gui/Tools.h>
#include <Gui/WaitCursor.h>
#include <Mod/PartDesign/App/Body.h>
#include <Mod/PartDesign/App/FeatureDressUp.h>
#include <Mod/PartDesign/Gui/ReferenceSelection.h>
#include "TaskDressUpParameters.h"
@@ -52,6 +51,9 @@ FC_LOG_LEVEL_INIT("PartDesign",true,true)
using namespace PartDesignGui;
using namespace Gui;
const QString TaskDressUpParameters::btnPreviewStr = tr("Preview");
const QString TaskDressUpParameters::btnSelectStr = tr("Select");
/* TRANSLATOR PartDesignGui::TaskDressUpParameters */
TaskDressUpParameters::TaskDressUpParameters(ViewProviderDressUp *DressUpView, bool selectEdges, bool selectFaces, QWidget *parent)
@@ -95,122 +97,102 @@ void TaskDressUpParameters::setupTransaction()
transactionID = App::GetApplication().setActiveTransaction(n.c_str());
}
bool TaskDressUpParameters::referenceSelected(const Gui::SelectionChanges& msg)
void TaskDressUpParameters::referenceSelected(const Gui::SelectionChanges& msg, QListWidget* widget)
{
if ((msg.Type == Gui::SelectionChanges::AddSelection) && (
(selectionMode == refAdd) || (selectionMode == refRemove))) {
if (strcmp(msg.pDocName, DressUpView->getObject()->getDocument()->getName()) != 0)
return;
if (strcmp(msg.pDocName, DressUpView->getObject()->getDocument()->getName()) != 0)
return false;
Gui::Selection().clearSelection();
PartDesign::DressUp* pcDressUp = static_cast<PartDesign::DressUp*>(DressUpView->getObject());
App::DocumentObject* base = this->getBase();
PartDesign::DressUp* pcDressUp = static_cast<PartDesign::DressUp*>(DressUpView->getObject());
App::DocumentObject* base = this->getBase();
// TODO: Must we make a copy here instead of assigning to const char* ?
const char* fname = base->getNameInDocument();
if (strcmp(msg.pObjectName, fname) != 0)
return false;
// TODO: Must we make a copy here instead of assigning to const char* ?
const char* fname = base->getNameInDocument();
if (strcmp(msg.pObjectName, fname) != 0)
return;
std::string subName(msg.pSubName);
std::vector<std::string> refs = pcDressUp->Base.getSubValues();
std::vector<std::string>::iterator f = std::find(refs.begin(), refs.end(), subName);
std::string subName(msg.pSubName);
std::vector<std::string> refs = pcDressUp->Base.getSubValues();
std::vector<std::string>::iterator f = std::find(refs.begin(), refs.end(), subName);
if (selectionMode == refAdd) {
if (f == refs.end())
refs.push_back(subName);
else
return false; // duplicate selection
} else {
if (f != refs.end())
refs.erase(f);
else
return false;
}
DressUpView->highlightReferences(false);
setupTransaction();
pcDressUp->Base.setValue(base, refs);
pcDressUp->getDocument()->recomputeFeature(pcDressUp);
return true;
if (f != refs.end()) { //If it's found then it's in the list so we remove it.
refs.erase(f);
removeItemFromListWidget(widget, msg.pSubName);
}
else { //if it's not found then it's not yet in the list so we add it.
refs.push_back(subName);
widget->addItem(QString::fromStdString(msg.pSubName));
}
return false;
updateFeature(pcDressUp, refs);
}
void TaskDressUpParameters::addAllEdges(QListWidget* widget)
{
PartDesign::DressUp* pcDressUp = static_cast<PartDesign::DressUp*>(DressUpView->getObject());
if (pcDressUp) {
App::DocumentObject* base = pcDressUp->Base.getValue();
if (base) {
Gui::WaitCursor wait;
int count = pcDressUp->getBaseTopoShape().countSubElements("Edge");
std::vector<std::string> edgeNames;
for (int ii = 0; ii < count; ii++){
std::ostringstream edgeName;
edgeName << "Edge" << ii+1;
edgeNames.push_back(edgeName.str());
}
for (std::vector<std::string>::const_iterator it = edgeNames.begin(); it != edgeNames.end(); ++it){
if (widget->findItems(QLatin1String(it->c_str()), Qt::MatchExactly).isEmpty()){
widget->addItem(QLatin1String(it->c_str()));
}
}
pcDressUp->Base.setValue(base, edgeNames);
pcDressUp->getDocument()->recomputeFeature(pcDressUp);
hideObject();
DressUpView->highlightReferences(true);
onButtonRefAdd(true);
if (deleteAction) {
deleteAction->setEnabled(widget->count() > 1);
}
}
Gui::WaitCursor wait;
int count = pcDressUp->getBaseTopoShape().countSubElements("Edge");
std::vector<std::string> edgeNames;
for (int ii = 0; ii < count; ii++){
std::ostringstream edgeName;
edgeName << "Edge" << ii+1;
edgeNames.push_back(edgeName.str());
}
//First we need to clear the widget in case the user had faces selected. Else the faces will still be in widget but not in the feature refs!
QSignalBlocker block(widget);
widget->clear();
for (std::vector<std::string>::const_iterator it = edgeNames.begin(); it != edgeNames.end(); ++it){
widget->addItem(QLatin1String(it->c_str()));
}
updateFeature(pcDressUp, edgeNames);
}
void TaskDressUpParameters::onButtonRefAdd(bool checked)
void TaskDressUpParameters::deleteRef(QListWidget* widget)
{
if (checked) {
clearButtons(refAdd);
hideObject();
selectionMode = refAdd;
if (addAllEdgesAction)
addAllEdgesAction->setEnabled(true);
AllowSelectionFlags allow;
allow.setFlag(AllowSelection::EDGE, allowEdges);
allow.setFlag(AllowSelection::FACE, allowFaces);
Gui::Selection().clearSelection();
Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), allow));
DressUpView->highlightReferences(true);
}
else {
if (addAllEdgesAction)
addAllEdgesAction->setEnabled(false);
exitSelectionMode();
DressUpView->highlightReferences(false);
// delete any selections since the reference(s) being deleted might be highlighted
Gui::Selection().clearSelection();
// get the list of items to be deleted
QList<QListWidgetItem*> selectedList = widget->selectedItems();
PartDesign::DressUp* pcDressUp = static_cast<PartDesign::DressUp*>(DressUpView->getObject());
std::vector<std::string> refs = pcDressUp->Base.getSubValues();
// delete the selection backwards to assure the list index keeps valid for the deletion
QSignalBlocker block(widget);
for (int i = selectedList.count() - 1; i > -1; i--) {
// the ref index is the same as the listWidgetReferences index
// so we can erase using the row number of the element to be deleted
int rowNumber = widget->row(selectedList.at(i));
refs.erase(refs.begin() + rowNumber);
widget->model()->removeRow(rowNumber);
}
updateFeature(pcDressUp, refs);
}
void TaskDressUpParameters::onButtonRefRemove(const bool checked)
void TaskDressUpParameters::updateFeature(PartDesign::DressUp* pcDressUp, const std::vector<std::string>& refs)
{
if (checked) {
clearButtons(refRemove);
hideObject();
selectionMode = refRemove;
AllowSelectionFlags allow;
allow.setFlag(AllowSelection::EDGE, allowEdges);
allow.setFlag(AllowSelection::FACE, allowFaces);
Gui::Selection().clearSelection();
Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), allow));
DressUpView->highlightReferences(true);
}
else {
exitSelectionMode();
if (selectionMode == refSel)
DressUpView->highlightReferences(false);
}
setupTransaction();
pcDressUp->Base.setValue(pcDressUp->Base.getValue(), refs);
pcDressUp->recomputeFeature();
if (selectionMode == refSel)
DressUpView->highlightReferences(true);
else
hideOnError();
}
void TaskDressUpParameters::onButtonRefSel(bool checked)
{
setSelectionMode(checked ? refSel : none);
}
void TaskDressUpParameters::doubleClicked(QListWidgetItem* item) {
@@ -221,14 +203,7 @@ void TaskDressUpParameters::doubleClicked(QListWidgetItem* item) {
wasDoubleClicked = true;
// assure we are not in selection mode
exitSelectionMode();
clearButtons(none);
// assure the fillets are shown
showObject();
// remove any highlights and selections
DressUpView->highlightReferences(false);
Gui::Selection().clearSelection();
setSelectionMode(none);
// enable next possible single-click event after double-click time passed
QTimer::singleShot(QApplication::doubleClickInterval(), this, &TaskDressUpParameters::itemClickedTimeout);
@@ -251,15 +226,16 @@ void TaskDressUpParameters::setSelection(QListWidgetItem* current) {
if (body) {
std::string objName = body->getNameInDocument();
// hide fillet to see the original edge
// (a fillet creates new edges so that the original one is not available)
hideObject();
// highlight all objects in the list
DressUpView->highlightReferences(true);
// clear existing selection because only the current item is highlighted, not all selected ones to keep the overview
Gui::Selection().clearSelection();
// Enter selection mode
if (selectionMode == none)
setSelectionMode(refSel);
else
Gui::Selection().clearSelection();
// highlight the selected item
bool block = this->blockSelection(true);
Gui::Selection().addSelection(docName.c_str(), objName.c_str(), subName.c_str(), 0, 0, 0);
this->blockSelection(block);
}
}
}
@@ -280,13 +256,11 @@ void TaskDressUpParameters::createAddAllEdgesAction(QListWidget* parentList)
addAllEdgesAction->setShortcutVisibleInContextMenu(true);
#endif
parentList->addAction(addAllEdgesAction);
addAllEdgesAction->setEnabled(false);
addAllEdgesAction->setStatusTip(tr("Adds all edges to the list box (active only when in add selection mode)."));
parentList->setContextMenuPolicy(Qt::ActionsContextMenu);
}
void TaskDressUpParameters::createDeleteAction(QListWidget* parentList, QWidget* parentButton)
void TaskDressUpParameters::createDeleteAction(QListWidget* parentList)
{
// creates a context menu, a shortcut for it and connects it to a slot function
@@ -297,13 +271,6 @@ void TaskDressUpParameters::createDeleteAction(QListWidget* parentList, QWidget*
deleteAction->setShortcutVisibleInContextMenu(true);
#endif
parentList->addAction(deleteAction);
// if there is only one item, it cannot be deleted
if (parentList->count() == 1) {
deleteAction->setEnabled(false);
deleteAction->setStatusTip(tr("There must be at least one item"));
parentButton->setEnabled(false);
parentButton->setToolTip(tr("There must be at least one item"));
}
parentList->setContextMenuPolicy(Qt::ActionsContextMenu);
}
@@ -395,12 +362,31 @@ Part::Feature* TaskDressUpParameters::getBase(void) const
return pcDressUp->getBaseObject();
}
void TaskDressUpParameters::exitSelectionMode()
void TaskDressUpParameters::setSelectionMode(selectionModes mode)
{
selectionMode = none;
Gui::Selection().rmvSelectionGate();
selectionMode = mode;
setButtons(mode);
if (mode == none) {
showObject();
Gui::Selection().rmvSelectionGate();
// remove any highlights and selections
DressUpView->highlightReferences(false);
}
else {
hideObject();
AllowSelectionFlags allow;
allow.setFlag(AllowSelection::EDGE, allowEdges);
allow.setFlag(AllowSelection::FACE, allowFaces);
Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), allow));
DressUpView->highlightReferences(true);
}
Gui::Selection().clearSelection();
showObject();
}
//**************************************************************************

View File

@@ -25,6 +25,7 @@
#define GUI_TASKVIEW_TaskDressUpParameters_H
#include <Gui/TaskView/TaskView.h>
#include <Mod/PartDesign/App/FeatureDressUp.h>
#include "TaskFeatureParameters.h"
#include "ViewProviderDressUp.h"
@@ -63,26 +64,27 @@ public:
}
protected Q_SLOTS:
void onButtonRefAdd(const bool checked);
void onButtonRefRemove(const bool checked);
void onButtonRefSel(const bool checked);
void doubleClicked(QListWidgetItem* item);
void setSelection(QListWidgetItem* current);
void itemClickedTimeout();
virtual void onRefDeleted(void) = 0;
void createDeleteAction(QListWidget* parentList, QWidget* parentButton);
void createDeleteAction(QListWidget* parentList);
void createAddAllEdgesAction(QListWidget* parentList);
protected:
void exitSelectionMode();
bool referenceSelected(const Gui::SelectionChanges& msg);
void referenceSelected(const Gui::SelectionChanges& msg, QListWidget* widget);
bool wasDoubleClicked = false;
bool KeyEvent(QEvent *e);
void hideOnError();
void addAllEdges(QListWidget* listWidget);
void deleteRef(QListWidget* listWidget);
void updateFeature(PartDesign::DressUp* pcDressUp, const std::vector<std::string>& refs);
protected:
enum selectionModes { none, refAdd, refRemove, plane, line };
virtual void clearButtons(const selectionModes notThis) = 0;
enum selectionModes { none, refSel, plane, line };
void setSelectionMode(selectionModes mode);
virtual void setButtons(const selectionModes mode) = 0;
static void removeItemFromListWidget(QListWidget* widget, const char* itemstr);
ViewProviderDressUp* getDressUpView() const
@@ -97,6 +99,9 @@ protected:
bool allowFaces, allowEdges;
selectionModes selectionMode;
int transactionID;
static const QString btnPreviewStr;
static const QString btnSelectStr;
};
/// simulation dialog for the TaskView

View File

@@ -52,14 +52,12 @@ TaskFilletParameters::TaskFilletParameters(ViewProviderDressUp *DressUpView, QWi
// we need a separate container widget to add all controls to
proxy = new QWidget(this);
ui->setupUi(proxy);
this->groupLayout()->addWidget(proxy);
PartDesign::Fillet* pcFillet = static_cast<PartDesign::Fillet*>(DressUpView->getObject());
bool useAllEdges = pcFillet->UseAllEdges.getValue();
ui->checkBoxUseAllEdges->setChecked(useAllEdges);
ui->buttonRefAdd->setEnabled(!useAllEdges);
ui->buttonRefRemove->setEnabled(!useAllEdges);
ui->buttonRefSel->setEnabled(!useAllEdges);
ui->listWidgetReferences->setEnabled(!useAllEdges);
double r = pcFillet->Radius.getValue();
@@ -79,15 +77,13 @@ TaskFilletParameters::TaskFilletParameters(ViewProviderDressUp *DressUpView, QWi
connect(ui->filletRadius, qOverload<double>(&Gui::QuantitySpinBox::valueChanged),
this, &TaskFilletParameters::onLengthChanged);
connect(ui->buttonRefAdd, &QToolButton::toggled,
this, &TaskFilletParameters::onButtonRefAdd);
connect(ui->buttonRefRemove, &QToolButton::toggled,
this, &TaskFilletParameters::onButtonRefRemove);
connect(ui->buttonRefSel, &QToolButton::toggled,
this, &TaskFilletParameters::onButtonRefSel);
connect(ui->checkBoxUseAllEdges, &QToolButton::toggled,
this, &TaskFilletParameters::onCheckBoxUseAllEdgesToggled);
// Create context menu
createDeleteAction(ui->listWidgetReferences, ui->buttonRefRemove);
createDeleteAction(ui->listWidgetReferences);
connect(deleteAction, &QAction::triggered, this, &TaskFilletParameters::onRefDeleted);
createAddAllEdgesAction(ui->listWidgetReferences);
@@ -100,8 +96,10 @@ TaskFilletParameters::TaskFilletParameters(ViewProviderDressUp *DressUpView, QWi
connect(ui->listWidgetReferences, &QListWidget::itemDoubleClicked,
this, &TaskFilletParameters::doubleClicked);
// the dialog can be called on a broken fillet, then hide the fillet
hideOnError();
if (strings.size() == 0)
setSelectionMode(refSel);
else
hideOnError();
}
void TaskFilletParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
@@ -109,120 +107,43 @@ void TaskFilletParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
// executed when the user selected something in the CAD object
// adds/deletes the selection accordingly
if (selectionMode == none)
return;
if (msg.Type == Gui::SelectionChanges::AddSelection) {
if (referenceSelected(msg)) {
if (selectionMode == refAdd) {
ui->listWidgetReferences->addItem(QString::fromStdString(msg.pSubName));
// it might be the second one so we can enable the context menu
if (ui->listWidgetReferences->count() > 1) {
deleteAction->setEnabled(true);
deleteAction->setStatusTip(QString());
ui->buttonRefRemove->setEnabled(true);
ui->buttonRefRemove->setToolTip(tr("Click button to enter selection mode,\nclick again to end selection"));
}
}
else {
removeItemFromListWidget(ui->listWidgetReferences, msg.pSubName);
// remove its selection too
Gui::Selection().clearSelection();
// if there is only one item left, it cannot be deleted
if (ui->listWidgetReferences->count() == 1) {
deleteAction->setEnabled(false);
deleteAction->setStatusTip(tr("There must be at least one item"));
ui->buttonRefRemove->setEnabled(false);
ui->buttonRefRemove->setToolTip(tr("There must be at least one item"));
// we must also end the selection mode
exitSelectionMode();
clearButtons(none);
}
}
// highlight existing references for possible further selections
DressUpView->highlightReferences(true);
if (selectionMode == refSel) {
referenceSelected(msg, ui->listWidgetReferences);
}
}
}
void TaskFilletParameters::onCheckBoxUseAllEdgesToggled(bool checked)
{
if (checked)
setSelectionMode(none);
PartDesign::Fillet* pcFillet = static_cast<PartDesign::Fillet*>(DressUpView->getObject());
ui->buttonRefRemove->setEnabled(!checked);
ui->buttonRefAdd->setEnabled(!checked);
ui->buttonRefSel->setEnabled(!checked);
ui->listWidgetReferences->setEnabled(!checked);
pcFillet->UseAllEdges.setValue(checked);
pcFillet->getDocument()->recomputeFeature(pcFillet);
}
void TaskFilletParameters::clearButtons(const selectionModes notThis)
void TaskFilletParameters::setButtons(const selectionModes mode)
{
if (notThis != refAdd) ui->buttonRefAdd->setChecked(false);
if (notThis != refRemove) ui->buttonRefRemove->setChecked(false);
DressUpView->highlightReferences(false);
ui->buttonRefSel->setChecked(mode == refSel);
ui->buttonRefSel->setText(mode == refSel ? btnPreviewStr : btnSelectStr);
}
void TaskFilletParameters::onRefDeleted()
{
// assure we we are not in selection mode
exitSelectionMode();
clearButtons(none);
// delete any selections since the reference(s) might be highlighted
Gui::Selection().clearSelection();
DressUpView->highlightReferences(false);
// get the list of items to be deleted
QList<QListWidgetItem*> selectedList = ui->listWidgetReferences->selectedItems();
// if all items are selected, we must stop because one must be kept to avoid that the feature gets broken
if (selectedList.count() == ui->listWidgetReferences->model()->rowCount()){
QMessageBox::warning(this, tr("Selection error"), tr("At least one item must be kept."));
return;
}
// get the fillet object
PartDesign::Fillet* pcFillet = static_cast<PartDesign::Fillet*>(DressUpView->getObject());
App::DocumentObject* base = pcFillet->Base.getValue();
// get all fillet references
std::vector<std::string> refs = pcFillet->Base.getSubValues();
setupTransaction();
// delete the selection backwards to assure the list index keeps valid for the deletion
for (int i = selectedList.count()-1; i > -1; i--) {
// the ref index is the same as the listWidgetReferences index
// so we can erase using the row number of the element to be deleted
int rowNumber = ui->listWidgetReferences->row(selectedList.at(i));
// erase the reference
refs.erase(refs.begin() + rowNumber);
// remove from the list
ui->listWidgetReferences->model()->removeRow(rowNumber);
}
// update the object
pcFillet->Base.setValue(base, refs);
// recompute the feature
pcFillet->recomputeFeature();
// hide the fillet if there was a computation error
hideOnError();
// if there is only one item left, it cannot be deleted
if (ui->listWidgetReferences->count() == 1) {
deleteAction->setEnabled(false);
deleteAction->setStatusTip(tr("There must be at least one item"));
ui->buttonRefRemove->setEnabled(false);
ui->buttonRefRemove->setToolTip(tr("There must be at least one item"));
}
TaskDressUpParameters::deleteRef(ui->listWidgetReferences);
}
void TaskFilletParameters::onAddAllEdges()
{
TaskDressUpParameters::addAllEdges(ui->listWidgetReferences);
ui->buttonRefRemove->setEnabled(true);
}
void TaskFilletParameters::onLengthChanged(double len)
{
clearButtons(none);
setSelectionMode(none);
PartDesign::Fillet* pcFillet = static_cast<PartDesign::Fillet*>(DressUpView->getObject());
setupTransaction();
pcFillet->Radius.setValue(len);
@@ -267,6 +188,10 @@ void TaskFilletParameters::apply()
//Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Fillet changed"));
ui->filletRadius->apply();
//Alert user if he created an empty feature
if(ui->listWidgetReferences->count() == 0)
Base::Console().Warning(tr("Empty fillet created !\n").toStdString().c_str());
}
//**************************************************************************

View File

@@ -49,7 +49,7 @@ private Q_SLOTS:
protected:
double getLength() const;
void clearButtons(const selectionModes notThis) override;
void setButtons(const selectionModes mode) override;
bool event(QEvent *e) override;
void changeEvent(QEvent *e) override;
void onSelectionChanged(const Gui::SelectionChanges& msg) override;

View File

@@ -15,36 +15,18 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QToolButton" name="buttonRefAdd">
<property name="toolTip">
<string>Click button to enter selection mode,
<widget class="QToolButton" name="buttonRefSel">
<property name="toolTip">
<string>Click button to enter selection mode,
click again to end selection</string>
</property>
<property name="text">
<string>Add</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="buttonRefRemove">
<property name="toolTip">
<string>Click button to enter selection mode,
click again to end selection</string>
</property>
<property name="text">
<string>Remove</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</property>
<property name="text">
<string>Select</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listWidgetReferences">

View File

@@ -86,17 +86,15 @@ TaskThicknessParameters::TaskThicknessParameters(ViewProviderDressUp *DressUpVie
this, &TaskThicknessParameters::onReversedChanged);
connect(ui->checkIntersection, &QCheckBox::toggled,
this, &TaskThicknessParameters::onIntersectionChanged);
connect(ui->buttonRefAdd, &QToolButton::toggled,
this, &TaskThicknessParameters::onButtonRefAdd);
connect(ui->buttonRefRemove, &QToolButton::toggled,
this, &TaskThicknessParameters::onButtonRefRemove);
connect(ui->buttonRefSel, &QToolButton::toggled,
this, &TaskThicknessParameters::onButtonRefSel);
connect(ui->modeComboBox, qOverload<int>(&QComboBox::currentIndexChanged),
this, &TaskThicknessParameters::onModeChanged);
connect(ui->joinComboBox, qOverload<int>(&QComboBox::currentIndexChanged),
this, &TaskThicknessParameters::onJoinTypeChanged);
// Create context menu
createDeleteAction(ui->listWidgetReferences, ui->buttonRefRemove);
createDeleteAction(ui->listWidgetReferences);
connect(deleteAction, &QAction::triggered, this, &TaskThicknessParameters::onRefDeleted);
connect(ui->listWidgetReferences, &QListWidget::currentItemChanged,
@@ -112,8 +110,10 @@ TaskThicknessParameters::TaskThicknessParameters(ViewProviderDressUp *DressUpVie
int join = pcThickness->Join.getValue();
ui->joinComboBox->setCurrentIndex(join);
// the dialog can be called on a broken thickness, then hide the thickness
hideOnError();
if (strings.size() == 0)
setSelectionMode(refSel);
else
hideOnError();
}
void TaskThicknessParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
@@ -121,104 +121,27 @@ void TaskThicknessParameters::onSelectionChanged(const Gui::SelectionChanges& ms
// executed when the user selected something in the CAD object
// adds/deletes the selection accordingly
if (selectionMode == none)
return;
if (msg.Type == Gui::SelectionChanges::AddSelection) {
if (referenceSelected(msg)) {
if (selectionMode == refAdd) {
ui->listWidgetReferences->addItem(QString::fromStdString(msg.pSubName));
// it might be the second one so we can enable the context menu
if (ui->listWidgetReferences->count() > 1) {
deleteAction->setEnabled(true);
deleteAction->setStatusTip(QString());
ui->buttonRefRemove->setEnabled(true);
ui->buttonRefRemove->setToolTip(tr("Click button to enter selection mode,\nclick again to end selection"));
}
}
else {
removeItemFromListWidget(ui->listWidgetReferences, msg.pSubName);
// remove its selection too
Gui::Selection().clearSelection();
// if there is only one item left, it cannot be deleted
if (ui->listWidgetReferences->count() == 1) {
deleteAction->setEnabled(false);
deleteAction->setStatusTip(tr("There must be at least one item"));
ui->buttonRefRemove->setEnabled(false);
ui->buttonRefRemove->setToolTip(tr("There must be at least one item"));
// we must also end the selection mode
exitSelectionMode();
clearButtons(none);
}
}
// highlight existing references for possible further selections
DressUpView->highlightReferences(true);
if (selectionMode == refSel) {
referenceSelected(msg, ui->listWidgetReferences);
}
}
}
void TaskThicknessParameters::clearButtons(const selectionModes notThis)
void TaskThicknessParameters::setButtons(const selectionModes mode)
{
if (notThis != refAdd) ui->buttonRefAdd->setChecked(false);
if (notThis != refRemove) ui->buttonRefRemove->setChecked(false);
DressUpView->highlightReferences(false);
ui->buttonRefSel->setChecked(mode == refSel);
ui->buttonRefSel->setText(mode == refSel ? btnPreviewStr : btnSelectStr);
}
void TaskThicknessParameters::onRefDeleted(void)
{
// assure we we are not in selection mode
exitSelectionMode();
clearButtons(none);
// delete any selections since the reference(s) might be highlighted
Gui::Selection().clearSelection();
DressUpView->highlightReferences(false);
// get the list of items to be deleted
QList<QListWidgetItem*> selectedList = ui->listWidgetReferences->selectedItems();
// if all items are selected, we must stop because one must be kept to avoid that the feature gets broken
if (selectedList.count() == ui->listWidgetReferences->model()->rowCount()) {
QMessageBox::warning(this, tr("Selection error"), tr("At least one item must be kept."));
return;
}
// get the thickness object
PartDesign::Thickness* pcThickness = static_cast<PartDesign::Thickness*>(DressUpView->getObject());
App::DocumentObject* base = pcThickness->Base.getValue();
// get all thickness references
std::vector<std::string> refs = pcThickness->Base.getSubValues();
setupTransaction();
// delete the selection backwards to assure the list index keeps valid for the deletion
for (int i = selectedList.count() - 1; i > -1; i--) {
// the ref index is the same as the listWidgetReferences index
// so we can erase using the row number of the element to be deleted
int rowNumber = ui->listWidgetReferences->row(selectedList.at(i));
// erase the reference
refs.erase(refs.begin() + rowNumber);
// remove from the list
ui->listWidgetReferences->model()->removeRow(rowNumber);
}
// update the object
pcThickness->Base.setValue(base, refs);
// recompute the feature
pcThickness->recomputeFeature();
// hide the thickness if there was a computation error
hideOnError();
// if there is only one item left, it cannot be deleted
if (ui->listWidgetReferences->count() == 1) {
deleteAction->setEnabled(false);
deleteAction->setStatusTip(tr("There must be at least one item"));
ui->buttonRefRemove->setEnabled(false);
ui->buttonRefRemove->setToolTip(tr("There must be at least one item"));
}
TaskDressUpParameters::deleteRef(ui->listWidgetReferences);
}
void TaskThicknessParameters::onValueChanged(double angle)
{
clearButtons(none);
setButtons(none);
PartDesign::Thickness* pcThickness = static_cast<PartDesign::Thickness*>(DressUpView->getObject());
setupTransaction();
pcThickness->Value.setValue(angle);
@@ -229,7 +152,7 @@ void TaskThicknessParameters::onValueChanged(double angle)
void TaskThicknessParameters::onJoinTypeChanged(int join) {
clearButtons(none);
setButtons(none);
PartDesign::Thickness* pcThickness = static_cast<PartDesign::Thickness*>(DressUpView->getObject());
setupTransaction();
pcThickness->Join.setValue(join);
@@ -240,7 +163,7 @@ void TaskThicknessParameters::onJoinTypeChanged(int join) {
void TaskThicknessParameters::onModeChanged(int mode) {
clearButtons(none);
setButtons(none);
PartDesign::Thickness* pcThickness = static_cast<PartDesign::Thickness*>(DressUpView->getObject());
setupTransaction();
pcThickness->Mode.setValue(mode);
@@ -255,7 +178,7 @@ double TaskThicknessParameters::getValue(void) const
}
void TaskThicknessParameters::onReversedChanged(const bool on) {
clearButtons(none);
setButtons(none);
PartDesign::Thickness* pcThickness = static_cast<PartDesign::Thickness*>(DressUpView->getObject());
setupTransaction();
pcThickness->Reversed.setValue(on);
@@ -270,7 +193,7 @@ bool TaskThicknessParameters::getReversed(void) const
}
void TaskThicknessParameters::onIntersectionChanged(const bool on) {
clearButtons(none);
setButtons(none);
PartDesign::Thickness* pcThickness = static_cast<PartDesign::Thickness*>(DressUpView->getObject());
pcThickness->Intersection.setValue(on);
pcThickness->getDocument()->recomputeFeature(pcThickness);
@@ -318,6 +241,12 @@ void TaskThicknessParameters::changeEvent(QEvent *e)
}
}
void TaskThicknessParameters::apply()
{
//Alert user if he created an empty feature
if (ui->listWidgetReferences->count() == 0)
Base::Console().Warning(tr("Empty thickness created !\n").toStdString().c_str());
}
//**************************************************************************
//**************************************************************************
@@ -360,6 +289,8 @@ bool TaskDlgThicknessParameters::accept()
if (!obj->isError())
parameter->showObject();
parameter->apply();
TaskThicknessParameters* draftparameter = static_cast<TaskThicknessParameters*>(parameter);
FCMD_OBJ_CMD(obj,"Value = " << draftparameter->getValue());

View File

@@ -39,6 +39,8 @@ public:
explicit TaskThicknessParameters(ViewProviderDressUp *DressUpView, QWidget *parent=nullptr);
~TaskThicknessParameters() override;
void apply() override;
double getValue(void) const;
bool getReversed(void) const;
bool getIntersection(void) const;
@@ -54,7 +56,7 @@ private Q_SLOTS:
void onRefDeleted(void) override;
protected:
void clearButtons(const selectionModes notThis) override;
void setButtons(const selectionModes mode) override;
bool event(QEvent *e) override;
void changeEvent(QEvent *e) override;
void onSelectionChanged(const Gui::SelectionChanges& msg) override;

View File

@@ -15,36 +15,18 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QToolButton" name="buttonRefAdd">
<property name="toolTip">
<string>Click button to enter selection mode,
<widget class="QToolButton" name="buttonRefSel">
<property name="toolTip">
<string>Click button to enter selection mode,
click again to end selection</string>
</property>
<property name="text">
<string>Add face</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="buttonRefRemove">
<property name="toolTip">
<string>Click button to enter selection mode,
click again to end selection</string>
</property>
<property name="text">
<string>Remove face</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</property>
<property name="text">
<string>Select</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listWidgetReferences">