diff --git a/src/Mod/Sketcher/Gui/ConstraintFilters.h b/src/Mod/Sketcher/Gui/ConstraintFilters.h index 68370e2c71..c5158ce917 100644 --- a/src/Mod/Sketcher/Gui/ConstraintFilters.h +++ b/src/Mod/Sketcher/Gui/ConstraintFilters.h @@ -30,7 +30,13 @@ namespace SketcherGui { namespace ConstraintFilter { - enum FilterValue { + // FilterValue and SpecialFilterValue are the filters used for Constraint Filtering in the Constraint's Widget. + // FilterValue includes the filters used for the Multi-Filter dialog (SpecialFilterValue is not part of the multi-filter). + // + // The values are hardcoded to be the same as the indices in the combobox and viewlist. Addition of an element here requires + // the addition of the corresponding entry there and vice versa. + + enum class FilterValue { All = 0, Geometric = 1, Datums = 2, @@ -55,48 +61,87 @@ namespace ConstraintFilter { Angle = 21, SnellsLaw = 22, InternalAlignment = 23, - NumFilterValue + NumFilterValue // SpecialFilterValue shall start at the same index as this }; - enum SpecialFilterValue { - Multiple = 24, - Selection = 25, - AssociatedConstraints = 26, + constexpr auto FilterValueLength = static_cast>(FilterValue::NumFilterValue); + + enum class SpecialFilterValue { + Multiple = FilterValueLength, // = 24 + Selection, // = 25 + AssociatedConstraints, // = 26 NumSpecialFilterValue }; - constexpr std::array< std::bitset, FilterValue::NumFilterValue> filterAggregates { - 1 << FilterValue::All | 1 << FilterValue::Geometric | 1 << FilterValue::Datums | 1 << FilterValue::Named | 1 << FilterValue::NonDriving | - 1 << FilterValue::Horizontal | 1 << FilterValue::Vertical | 1 << FilterValue::Coincident | 1 << FilterValue::PointOnObject | - 1 << FilterValue::Parallel | 1 << FilterValue::Perpendicular | 1 << FilterValue::Tangent | 1 << FilterValue::Equality | - 1 << FilterValue::Symmetric | 1 << FilterValue::Block | 1 << FilterValue::Distance | 1 << FilterValue::HorizontalDistance | - 1 << FilterValue::VerticalDistance | 1 << FilterValue::Radius | 1 << FilterValue::Weight | 1 << FilterValue::Diameter | - 1 << FilterValue::Angle | 1 << FilterValue::SnellsLaw | 1 << FilterValue::InternalAlignment, // All = All other groups are covered (0) - 1 << FilterValue::Geometric | 1 << FilterValue::Horizontal | 1 << FilterValue::Vertical | 1 << FilterValue::Coincident | - 1 << FilterValue::PointOnObject | 1 << FilterValue::Parallel | 1 << FilterValue::Perpendicular | 1 << FilterValue::Tangent | - 1 << FilterValue::Equality | 1 << FilterValue::Symmetric | 1 << FilterValue::Block | 1 << FilterValue::InternalAlignment, // Geometric = All others not being datums (1) - 1 << FilterValue::Datums | 1 << FilterValue::Distance | 1 << FilterValue::HorizontalDistance | 1 << FilterValue::VerticalDistance | 1 << FilterValue::Radius | 1 << FilterValue::Weight | 1 << FilterValue::Diameter | 1 << FilterValue::Angle | 1 << FilterValue::SnellsLaw, // Datum = all others not being geometric (2) - 1 << FilterValue::Named, // Named = Just this (3) - 1 << FilterValue::NonDriving, // NonDriving = Just this (4) - 1 << FilterValue::Coincident, // Coincident = Just this (5) - 1 << FilterValue::PointOnObject, // PointOnObject = Just this (6) - 1 << FilterValue::Vertical, // Vertical = Just this (7) - 1 << FilterValue::Horizontal, // Horizontal = Just this (8) - 1 << FilterValue::Parallel, // Parallel = Just this (9) - 1 << FilterValue::Perpendicular, // Perpendicular = Just this (10) - 1 << FilterValue::Tangent, // Tangent = Just this (11) - 1 << FilterValue::Equality, // Equality = Just this (12) - 1 << FilterValue::Symmetric, // Symmetric = Just this (13) - 1 << FilterValue::Block, // Block = Just this (14) - 1 << FilterValue::HorizontalDistance, // HorizontalDistance = Just this (15) - 1 << FilterValue::VerticalDistance, // VerticalDistance = Just this (16) - 1 << FilterValue::Distance, // Distance = Just this (17) - 1 << FilterValue::Radius, // Radius = Just this (18) - 1 << FilterValue::Weight, // Weight = Just this (19) - 1 << FilterValue::Diameter, // Diameter = Just this (20) - 1 << FilterValue::Angle, // Angle = Just this (21) - 1 << FilterValue::SnellsLaw, // SnellsLaw = Just this (22) - 1 << FilterValue::InternalAlignment, // InternalAlignment = Just this (23) + constexpr auto SpecialFilterValue = static_cast>(SpecialFilterValue::NumSpecialFilterValue); + + /// A std::bitset sized to provide one bit per FilterValue value + using FilterValueBitset = std::bitset; + + /// Helper function to retrieve the underlying integral type of a filter value + template + inline auto getFilterIntegral(T filterValue) { + return static_cast>(filterValue); + } + + /// Helper function to test whether a provided integral value corresponds to the provided filter value + template + inline bool isFilterMatch(T filterValue, std::underlying_type_t integralTypeValue) { + + auto underlyingFilterValue = static_cast>(filterValue); + + return (underlyingFilterValue == integralTypeValue); + } + + /// Helper function to test whether a FilterValue value is set in a FilterValueBitset + inline bool checkFilterBitset(FilterValueBitset set, FilterValue filter) + { + auto underlyingFilterValue = static_cast>(filter); + + return set[underlyingFilterValue]; + } + + /// Helper function expanding a parameter pack value of enum classes to create a integral underlying type having + /// the bits corresponding to the parameter pack set + template + constexpr decltype(auto) buildBitset(Args... args) { + return (... | (1 << static_cast>(args))); + } + + /// Array of FilterValue bit sets of size the the number of FilterValues indicating for each FilterValue, which other + /// FilterValues are comprised therein. It defines the dependencies between filters. + constexpr std::array< FilterValueBitset, FilterValueLength> filterAggregates { + buildBitset(FilterValue::All, FilterValue::Geometric, FilterValue::Datums, FilterValue::Named, FilterValue::NonDriving, FilterValue::Horizontal, + FilterValue::Vertical, FilterValue::Coincident, FilterValue::PointOnObject, FilterValue::Parallel, FilterValue::Perpendicular, + FilterValue::Tangent, FilterValue::Equality, FilterValue::Symmetric, FilterValue::Block, FilterValue::Distance, + FilterValue::HorizontalDistance, FilterValue::VerticalDistance, FilterValue::Radius, FilterValue::Weight, FilterValue::Diameter, + FilterValue::Angle, FilterValue::SnellsLaw, FilterValue::InternalAlignment), // All = All other groups are covered (0) + buildBitset(FilterValue::Geometric, FilterValue::Horizontal, FilterValue::Vertical, FilterValue::Coincident, FilterValue::PointOnObject, + FilterValue::Parallel, FilterValue::Perpendicular, FilterValue::Tangent, FilterValue::Equality, FilterValue::Symmetric, + FilterValue::Block, FilterValue::InternalAlignment), // Geometric = All others not being datums (1) + buildBitset(FilterValue::Datums, FilterValue::Distance, FilterValue::HorizontalDistance, FilterValue::VerticalDistance, FilterValue::Radius, + FilterValue::Weight, FilterValue::Diameter, FilterValue::Angle, FilterValue::SnellsLaw), // Datum = all others not being geometric (2) + buildBitset(FilterValue::Named), // Named = Just this (3) + buildBitset(FilterValue::NonDriving), // NonDriving = Just this (4) + buildBitset(FilterValue::Coincident), // Coincident = Just this (5) + buildBitset(FilterValue::PointOnObject), // PointOnObject = Just this (6) + buildBitset(FilterValue::Vertical), // Vertical = Just this (7) + buildBitset(FilterValue::Horizontal), // Horizontal = Just this (8) + buildBitset(FilterValue::Parallel), // Parallel = Just this (9) + buildBitset(FilterValue::Perpendicular), // Perpendicular = Just this (10) + buildBitset(FilterValue::Tangent), // Tangent = Just this (11) + buildBitset(FilterValue::Equality), // Equality = Just this (12) + buildBitset(FilterValue::Symmetric), // Symmetric = Just this (13) + buildBitset(FilterValue::Block), // Block = Just this (14) + buildBitset(FilterValue::HorizontalDistance), // HorizontalDistance = Just this (15) + buildBitset(FilterValue::VerticalDistance), // VerticalDistance = Just this (16) + buildBitset(FilterValue::Distance), // Distance = Just this (17) + buildBitset(FilterValue::Radius), // Radius = Just this (18) + buildBitset(FilterValue::Weight), // Weight = Just this (19) + buildBitset(FilterValue::Diameter), // Diameter = Just this (20) + buildBitset(FilterValue::Angle), // Angle = Just this (21) + buildBitset(FilterValue::SnellsLaw), // SnellsLaw = Just this (22) + buildBitset(FilterValue::InternalAlignment) // InternalAlignment = Just this (23) }; } diff --git a/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.cpp b/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.cpp index 88beca930f..db57c3a17e 100644 --- a/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.cpp +++ b/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.cpp @@ -60,7 +60,7 @@ ConstraintMultiFilterDialog::~ConstraintMultiFilterDialog() { } -void ConstraintMultiFilterDialog::setMultiFilter(const std::bitset & bitset) +void ConstraintMultiFilterDialog::setMultiFilter(const FilterValueBitset & bitset) { ui->listMultiFilter->blockSignals(true); for(int i = 0; i < ui->listMultiFilter->count(); i++) { @@ -74,9 +74,9 @@ void ConstraintMultiFilterDialog::setMultiFilter(const std::bitsetlistMultiFilter->blockSignals(false); } -std::bitset ConstraintMultiFilterDialog::getMultiFilter() +FilterValueBitset ConstraintMultiFilterDialog::getMultiFilter() { - std::bitset tmpBitset; + FilterValueBitset tmpBitset; for(int i = 0; i < ui->listMultiFilter->count(); i++) { QListWidgetItem* item = ui->listMultiFilter->item(i); @@ -116,7 +116,7 @@ void ConstraintMultiFilterDialog::on_listMultiFilter_itemChanged(QListWidgetItem if(filterAggregates[i][filterindex]) { // only for groups comprising the changed filter bool mustBeChecked = true; - for(int j = 0; j < FilterValue::NumFilterValue; j++) { + for(int j = 0; j < FilterValueLength; j++) { if (i == j) continue; diff --git a/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.h b/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.h index 20e8a31212..a3ccdebe15 100644 --- a/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.h +++ b/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.h @@ -40,8 +40,8 @@ public: ConstraintMultiFilterDialog(void); ~ConstraintMultiFilterDialog(); - void setMultiFilter(const std::bitset & bitset); - std::bitset getMultiFilter(); + void setMultiFilter(const FilterValueBitset & bitset); + FilterValueBitset getMultiFilter(); public Q_SLOTS: void on_listMultiFilter_itemChanged(QListWidgetItem * item); diff --git a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp index cd67fc5f72..7e3d84711e 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp @@ -811,8 +811,8 @@ void TaskSketcherConstrains::on_multipleFilterButton_clicked(bool) int filterindex = ui->comboBoxFilter->currentIndex(); - if(filterindex != ConstraintFilter::SpecialFilterValue::Multiple) { - ui->comboBoxFilter->setCurrentIndex(ConstraintFilter::SpecialFilterValue::Multiple); // Change filter to multi filter selection + if(!isFilterMatch(ConstraintFilter::SpecialFilterValue::Multiple, filterindex)) { + ui->comboBoxFilter->setCurrentIndex(getFilterIntegral(ConstraintFilter::SpecialFilterValue::Multiple)); // Change filter to multi filter selection } mf.setMultiFilter(multiFilterStatus); @@ -1048,10 +1048,10 @@ void TaskSketcherConstrains::on_comboBoxFilter_currentIndexChanged(int filterind selectionFilter.clear(); // reset the stored selection filter associatedConstraintsFilter.clear(); - if(filterindex == ConstraintFilter::SpecialFilterValue::Selection) { + if(isFilterMatch(ConstraintFilter::SpecialFilterValue::Selection, filterindex)) { updateSelectionFilter(); } - else if(filterindex == ConstraintFilter::SpecialFilterValue::AssociatedConstraints) { + else if(isFilterMatch(ConstraintFilter::SpecialFilterValue::AssociatedConstraints, filterindex)) { updateAssociatedConstraintsFilter(); } @@ -1312,103 +1312,96 @@ bool TaskSketcherConstrains::isConstraintFiltered(QListWidgetItem * item) int Filter = ui->comboBoxFilter->currentIndex(); + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); bool hideInternalAlignment = hGrp->GetBool("HideInternalAlignment",false); bool visible = true; - bool showAll = (Filter == FilterValue::All); - bool showGeometric = (Filter == FilterValue::Geometric); - bool showDatums = (Filter == FilterValue::Datums && constraint->isDriving); - bool showNamed = (Filter == FilterValue::Named && !(constraint->Name.empty())); - bool showNonDriving = (Filter == FilterValue::NonDriving && !constraint->isDriving); + bool showAll = isFilterMatch(FilterValue::All, Filter); + bool showGeometric = isFilterMatch(FilterValue::Geometric, Filter); + bool showDatums = (isFilterMatch(FilterValue::Datums, Filter) && constraint->isDriving); + bool showNamed = (isFilterMatch(FilterValue::Named, Filter) && !(constraint->Name.empty())); + bool showNonDriving = (isFilterMatch(FilterValue::NonDriving, Filter) && !constraint->isDriving); + + auto geometricVisible = [showAll, showGeometric, showNamed, Filter, this](FilterValue filtervalue) { + return showAll || showGeometric || showNamed || isFilterMatch(filtervalue, Filter) || + (isFilterMatch(SpecialFilterValue::Multiple, Filter) && checkFilterBitset(multiFilterStatus, filtervalue)); + }; + + auto datumVisible = [showAll, showDatums, showNamed, showNonDriving, Filter, this](FilterValue filtervalue) { + return showAll || showDatums || showNamed || showNonDriving || isFilterMatch(filtervalue, Filter) || + (isFilterMatch(SpecialFilterValue::Multiple, Filter) && checkFilterBitset(multiFilterStatus, filtervalue)); + }; switch(constraint->Type) { case Sketcher::Horizontal: - visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Horizontal) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Horizontal]); + visible = geometricVisible(FilterValue::Horizontal); break; case Sketcher::Vertical: - visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Vertical) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Vertical]); + visible = geometricVisible(FilterValue::Vertical); break; case Sketcher::Coincident: - visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Coincident) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Coincident]); + visible = geometricVisible(FilterValue::Coincident); break; case Sketcher::PointOnObject: - visible = showAll || showGeometric || showNamed || (Filter == FilterValue::PointOnObject) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::PointOnObject]); + visible = geometricVisible(FilterValue::PointOnObject); break; case Sketcher::Parallel: - visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Parallel) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Parallel]); + visible = geometricVisible(FilterValue::Parallel); break; case Sketcher::Perpendicular: - visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Perpendicular) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Perpendicular]); + visible = geometricVisible(FilterValue::Perpendicular); break; case Sketcher::Tangent: - visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Tangent) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Tangent]); + visible = geometricVisible(FilterValue::Tangent); break; case Sketcher::Equal: - visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Equality) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Equality]); + visible = geometricVisible(FilterValue::Equality); break; case Sketcher::Symmetric: - visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Symmetric) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Symmetric]); + visible = geometricVisible(FilterValue::Symmetric); break; case Sketcher::Block: - visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Block) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Block]); + visible = geometricVisible(FilterValue::Block); break; case Sketcher::Distance: - visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::Distance) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Distance]); + visible = datumVisible(FilterValue::Distance); break; case Sketcher::DistanceX: - visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::HorizontalDistance) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::HorizontalDistance]); + visible = datumVisible(FilterValue::HorizontalDistance); break; case Sketcher::DistanceY: - visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::VerticalDistance) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::VerticalDistance]); + visible = datumVisible(FilterValue::VerticalDistance); break; case Sketcher::Radius: - visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::Radius) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Radius]); + visible = datumVisible(FilterValue::Radius); break; case Sketcher::Weight: - visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::Weight) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Weight]); + visible = datumVisible(FilterValue::Weight); break; case Sketcher::Diameter: - visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::Diameter) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Diameter]); + visible = datumVisible(FilterValue::Diameter); break; case Sketcher::Angle: - visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::Angle) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Angle]); + visible = datumVisible(FilterValue::Angle); break; case Sketcher::SnellsLaw: - visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::SnellsLaw) || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::SnellsLaw]); + visible = datumVisible(FilterValue::SnellsLaw); break; case Sketcher::InternalAlignment: - visible = (( showAll || showGeometric || showNamed || Filter == FilterValue::InternalAlignment || - (Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::InternalAlignment])) && - (!hideInternalAlignment || (Filter == FilterValue::InternalAlignment))); + visible = geometricVisible(FilterValue::InternalAlignment) && + (!hideInternalAlignment || isFilterMatch(FilterValue::InternalAlignment,Filter)); default: break; } // Constraint Type independent, selection filter - visible = visible || (Filter == SpecialFilterValue::Selection && + visible = visible || (isFilterMatch(SpecialFilterValue::Selection, Filter) && std::find(selectionFilter.begin(), selectionFilter.end(), it->ConstraintNbr) != selectionFilter.end()); // Constraint Type independent, associated Constraints Filter - visible = visible || (Filter == SpecialFilterValue::AssociatedConstraints && + visible = visible || (isFilterMatch(SpecialFilterValue::AssociatedConstraints, Filter) && std::find(associatedConstraintsFilter.begin(), associatedConstraintsFilter.end(), it->ConstraintNbr) != associatedConstraintsFilter.end()); return !visible; @@ -1477,7 +1470,7 @@ void TaskSketcherConstrains::changeEvent(QEvent *e) template bool TaskSketcherConstrains::isFilter(T filterValue) { - return (ui->comboBoxFilter->currentIndex() == filterValue); + return isFilterMatch(filterValue, ui->comboBoxFilter->currentIndex()); } diff --git a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.h b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.h index 00e9d1715d..8a04dbfe87 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.h +++ b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.h @@ -134,9 +134,9 @@ private: QWidget* proxy; bool inEditMode; std::unique_ptr ui; - std::bitset multiFilterStatus; - std::vector selectionFilter; - std::vector associatedConstraintsFilter; + ConstraintFilter::FilterValueBitset multiFilterStatus; // Stores the filters to be aggregated to form the multifilter. + std::vector selectionFilter; // holds the constraint ids of the selected constraints + std::vector associatedConstraintsFilter; // holds the constraint ids of the constraints associated with the selected geometry }; } //namespace SketcherGui