/*************************************************************************** * Copyright (c) 2014 Abdullah Tahiri * * * * 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 "PreCompiled.h" #ifndef _PreComp_ # include # include # include # include # include # include # include # include # include # include # include #endif #include #include #include #include #include #include #include #include #include #include #include #include "TaskSketcherElements.h" #include "ui_TaskSketcherElements.h" #include "ViewProviderSketch.h" using namespace SketcherGui; using namespace Gui::TaskView; /// Inserts a QAction into an existing menu /// ICONSTR is the string of the icon in the resource file /// NAMESTR is the text appearing in the contextual menuAction /// CMDSTR is the string registered in the commandManager /// FUNC is the name of the member function to be executed on selection of the menu item /// ACTSONSELECTION is a true/false value to activate the command only if a selection is made #define CONTEXT_ITEM(ICONSTR,NAMESTR,CMDSTR,FUNC,ACTSONSELECTION) \ QIcon icon_ ## FUNC( Gui::BitmapFactory().pixmap(ICONSTR) ); \ QAction* constr_ ## FUNC = menu.addAction(icon_ ## FUNC,tr(NAMESTR), this, SLOT(FUNC()), \ QKeySequence(QString::fromUtf8(Gui::Application::Instance->commandManager().getCommandByName(CMDSTR)->getAccel()))); \ if(ACTSONSELECTION) constr_ ## FUNC->setEnabled(!items.isEmpty()); else constr_ ## FUNC->setEnabled(true); /// Defines the member function corresponding to the CONTEXT_ITEM macro #define CONTEXT_MEMBER_DEF(CMDSTR,FUNC) \ void ElementView::FUNC(){ \ Gui::Application::Instance->commandManager().runCommandByName(CMDSTR);} class ElementWidgetIcons { private: ElementWidgetIcons() { initIcons(); } public: ElementWidgetIcons(const ElementWidgetIcons &) = delete; ElementWidgetIcons(ElementWidgetIcons &&) = delete; ElementWidgetIcons & operator=(const ElementWidgetIcons &) = delete; ElementWidgetIcons & operator=(ElementWidgetIcons &&) = delete; static const QIcon & getIcon(Base::Type type, Sketcher::PointPos pos, ElementItem::GeometryState icontype = ElementItem::GeometryState::Normal) { static ElementWidgetIcons elementicons; return elementicons.getIconImpl(type, pos, icontype); } private: void initIcons() { icons.emplace(std::piecewise_construct, std::forward_as_tuple(Part::GeomArcOfCircle::getClassTypeId()), std::forward_as_tuple(std::initializer_list>> { { Sketcher::PointPos::none , getMultIcon("Sketcher_Element_Arc_Edge") }, { Sketcher::PointPos::start , getMultIcon("Sketcher_Element_Arc_StartingPoint") }, { Sketcher::PointPos::end , getMultIcon("Sketcher_Element_Arc_EndPoint") }, { Sketcher::PointPos::mid , getMultIcon("Sketcher_Element_Arc_MidPoint") } })); icons.emplace(std::piecewise_construct, std::forward_as_tuple(Part::GeomCircle::getClassTypeId()), std::forward_as_tuple(std::initializer_list>> { { Sketcher::PointPos::none , getMultIcon("Sketcher_Element_Circle_Edge") }, { Sketcher::PointPos::mid , getMultIcon("Sketcher_Element_Circle_MidPoint") }, })); icons.emplace(std::piecewise_construct, std::forward_as_tuple(Part::GeomLineSegment::getClassTypeId()), std::forward_as_tuple(std::initializer_list>> { { Sketcher::PointPos::none , getMultIcon("Sketcher_Element_Line_Edge") }, { Sketcher::PointPos::start , getMultIcon("Sketcher_Element_Line_StartingPoint") }, { Sketcher::PointPos::end , getMultIcon("Sketcher_Element_Line_EndPoint") }, })); icons.emplace(std::piecewise_construct, std::forward_as_tuple(Part::GeomPoint::getClassTypeId()), std::forward_as_tuple(std::initializer_list>> { { Sketcher::PointPos::start , getMultIcon("Sketcher_Element_Point_StartingPoint") }, })); icons.emplace(std::piecewise_construct, std::forward_as_tuple(Part::GeomEllipse::getClassTypeId()), std::forward_as_tuple(std::initializer_list>> { { Sketcher::PointPos::none , getMultIcon("Sketcher_Element_Ellipse_Edge_2") }, { Sketcher::PointPos::mid , getMultIcon("Sketcher_Element_Ellipse_CentrePoint") }, })); icons.emplace(std::piecewise_construct, std::forward_as_tuple(Part::GeomArcOfEllipse::getClassTypeId()), std::forward_as_tuple(std::initializer_list>> { { Sketcher::PointPos::none , getMultIcon("Sketcher_Element_Elliptical_Arc_Edge") }, { Sketcher::PointPos::start , getMultIcon("Sketcher_Element_Elliptical_Arc_Start_Point") }, { Sketcher::PointPos::end , getMultIcon("Sketcher_Element_Elliptical_Arc_End_Point") }, { Sketcher::PointPos::mid , getMultIcon("Sketcher_Element_Elliptical_Arc_Centre_Point") }, })); icons.emplace(std::piecewise_construct, std::forward_as_tuple(Part::GeomArcOfHyperbola::getClassTypeId()), std::forward_as_tuple(std::initializer_list>> { { Sketcher::PointPos::none , getMultIcon("Sketcher_Element_Hyperbolic_Arc_Edge") }, { Sketcher::PointPos::start , getMultIcon("Sketcher_Element_Hyperbolic_Arc_Start_Point") }, { Sketcher::PointPos::end , getMultIcon("Sketcher_Element_Hyperbolic_Arc_End_Point") }, { Sketcher::PointPos::mid , getMultIcon("Sketcher_Element_Hyperbolic_Arc_Centre_Point") }, })); icons.emplace(std::piecewise_construct, std::forward_as_tuple(Part::GeomArcOfParabola::getClassTypeId()), std::forward_as_tuple(std::initializer_list>> { { Sketcher::PointPos::none , getMultIcon("Sketcher_Element_Parabolic_Arc_Edge") }, { Sketcher::PointPos::start , getMultIcon("Sketcher_Element_Parabolic_Arc_Start_Point") }, { Sketcher::PointPos::end , getMultIcon("Sketcher_Element_Parabolic_Arc_End_Point") }, { Sketcher::PointPos::mid , getMultIcon("Sketcher_Element_Parabolic_Arc_Centre_Point") }, })); icons.emplace(std::piecewise_construct, std::forward_as_tuple(Part::GeomBSplineCurve::getClassTypeId()), std::forward_as_tuple(std::initializer_list>> { { Sketcher::PointPos::none , getMultIcon("Sketcher_Element_BSpline_Edge") }, { Sketcher::PointPos::start , getMultIcon("Sketcher_Element_BSpline_StartPoint") }, { Sketcher::PointPos::end , getMultIcon("Sketcher_Element_BSpline_EndPoint") }, })); icons.emplace(std::piecewise_construct, std::forward_as_tuple(Base::Type::badType()), std::forward_as_tuple(std::initializer_list>> { { Sketcher::PointPos::none , getMultIcon("Sketcher_Element_SelectionTypeInvalid") }, })); } const QIcon & getIconImpl(Base::Type type, Sketcher::PointPos pos, ElementItem::GeometryState icontype) { auto typekey = icons.find(type); if( typekey == icons.end()) { // Not supported Geometry Type - Defaults to invalid icon typekey = icons.find(Base::Type::badType()); pos = Sketcher::PointPos::none; } auto poskey = typekey->second.find(pos); if ( poskey == typekey->second.end()) { // invalid PointPos for type - Provide Invalid icon typekey = icons.find(Base::Type::badType()); pos = Sketcher::PointPos::none; poskey = typekey->second.find(pos); } if (icontype == ElementItem::GeometryState::Normal) return std::get<0>(poskey->second); else if (icontype == ElementItem::GeometryState::Construction) return std::get<1>(poskey->second); else if (icontype == ElementItem::GeometryState::External) return std::get<2>(poskey->second); else //internal alignment return std::get<3>(poskey->second); // We should never arrive here, as badtype, PointPos::none must exist. throw Base::ValueError("Icon for Invalid is missing!!"); } std::tuple getMultIcon(const char* name) { int hue, sat, val, alp; QIcon Normal = Gui::BitmapFactory().iconFromTheme(name); QImage imgConstr(Normal.pixmap(qAsConst(Normal).availableSizes()[0]).toImage()); QImage imgExt(imgConstr); QImage imgInt(imgConstr); //Create construction/external/internal icons by changing colors. for(int ix=0 ; ix 127 && hue >= 0) { if (sat > 127 && (hue > 330 || hue < 30)) { //change the color of red points. clr.setHsv((hue + 240) % 360, sat, val, alp); imgConstr.setPixelColor(ix, iy, clr); clr.setHsv((hue + 300) % 360, sat, val, alp); imgExt.setPixelColor(ix, iy, clr); clr.setHsv((hue + 60) % 360, (int) (sat / 3), std::min((int) (val * 8 / 7), 255), alp); imgInt.setPixelColor(ix, iy, clr); } else if (sat < 64 && val > 192) { //change the color of white edges. clr.setHsv(240, (255-sat), val, alp); imgConstr.setPixel(ix, iy, clr.rgba()); clr.setHsv(300, (255-sat), val, alp); imgExt.setPixel(ix, iy, clr.rgba()); clr.setHsv(60, (int) (255-sat) / 2, val, alp); imgInt.setPixel(ix, iy, clr.rgba()); } } } } QIcon Construction = QIcon(QPixmap::fromImage(imgConstr)); QIcon External = QIcon(QPixmap::fromImage(imgExt)); QIcon Internal = QIcon(QPixmap::fromImage(imgInt)); return std::make_tuple(Normal, Construction, External, Internal); } private: std::map>> icons; }; ElementView::ElementView(QWidget *parent) : QListWidget(parent) { ElementItemDelegate* elementItemDelegate = new ElementItemDelegate(this); setItemDelegate(elementItemDelegate); QObject::connect( elementItemDelegate, &ElementItemDelegate::itemHovered, this, &ElementView::onIndexHovered ); } ElementView::~ElementView() { } void ElementView::contextMenuEvent (QContextMenuEvent* event) { QMenu menu; QList items = selectedItems(); // CONTEXT_ITEM(ICONSTR,NAMESTR,CMDSTR,FUNC,ACTSONSELECTION) CONTEXT_ITEM("Constraint_PointOnPoint","Point Coincidence","Sketcher_ConstrainCoincident",doPointCoincidence,true) CONTEXT_ITEM("Constraint_PointOnObject","Point on Object","Sketcher_ConstrainPointOnObject",doPointOnObjectConstraint,true) CONTEXT_ITEM("Constraint_Vertical","Vertical Constraint","Sketcher_ConstrainVertical", doVerticalConstraint,true) CONTEXT_ITEM("Constraint_Horizontal","Horizontal Constraint","Sketcher_ConstrainHorizontal",doHorizontalConstraint,true) CONTEXT_ITEM("Constraint_Parallel","Parallel Constraint","Sketcher_ConstrainParallel",doParallelConstraint,true) CONTEXT_ITEM("Constraint_Perpendicular","Perpendicular Constraint","Sketcher_ConstrainPerpendicular",doPerpendicularConstraint,true) CONTEXT_ITEM("Constraint_Tangent","Tangent Constraint","Sketcher_ConstrainTangent",doTangentConstraint,true) CONTEXT_ITEM("Constraint_EqualLength","Equal Length","Sketcher_ConstrainEqual",doEqualConstraint,true) CONTEXT_ITEM("Constraint_Symmetric","Symmetric","Sketcher_ConstrainSymmetric",doSymmetricConstraint,true) CONTEXT_ITEM("Constraint_Block","Block Constraint","Sketcher_ConstrainBlock",doBlockConstraint,true) CONTEXT_ITEM("Constraint_Lock","Lock Constraint","Sketcher_ConstrainLock",doLockConstraint,true) CONTEXT_ITEM("Constraint_HorizontalDistance","Horizontal Distance","Sketcher_ConstrainDistanceX",doHorizontalDistance,true) CONTEXT_ITEM("Constraint_VerticalDistance","Vertical Distance","Sketcher_ConstrainDistanceY",doVerticalDistance,true) CONTEXT_ITEM("Constraint_Length","Length Constraint","Sketcher_ConstrainDistance",doLengthConstraint,true) CONTEXT_ITEM("Constraint_Radius","Radius Constraint","Sketcher_ConstrainRadius",doRadiusConstraint,true) CONTEXT_ITEM("Constraint_Diameter","Diameter Constraint","Sketcher_ConstrainDiameter",doDiameterConstraint,true) CONTEXT_ITEM("Constraint_Radiam","Radiam Constraint","Sketcher_ConstrainRadiam",doRadiamConstraint,true) CONTEXT_ITEM("Constraint_InternalAngle","Angle Constraint","Sketcher_ConstrainAngle",doAngleConstraint,true) menu.addSeparator(); CONTEXT_ITEM("Sketcher_ToggleConstruction","Toggle construction line","Sketcher_ToggleConstruction",doToggleConstruction,true) menu.addSeparator(); CONTEXT_ITEM("Sketcher_SelectConstraints","Select Constraints","Sketcher_SelectConstraints",doSelectConstraints,true) CONTEXT_ITEM("Sketcher_SelectOrigin","Select Origin","Sketcher_SelectOrigin",doSelectOrigin,false) CONTEXT_ITEM("Sketcher_SelectHorizontalAxis","Select Horizontal Axis","Sketcher_SelectHorizontalAxis",doSelectHAxis,false) CONTEXT_ITEM("Sketcher_SelectVerticalAxis","Select Vertical Axis","Sketcher_SelectVerticalAxis",doSelectVAxis,false) menu.addSeparator(); QAction* remove = menu.addAction(tr("Delete"), this, &ElementView::deleteSelectedItems, QKeySequence(QKeySequence::Delete)); remove->setEnabled(!items.isEmpty()); menu.menuAction()->setIconVisibleInMenu(true); menu.exec(event->globalPos()); } CONTEXT_MEMBER_DEF("Sketcher_ConstrainCoincident",doPointCoincidence) CONTEXT_MEMBER_DEF("Sketcher_ConstrainPointOnObject",doPointOnObjectConstraint) CONTEXT_MEMBER_DEF("Sketcher_ConstrainVertical",doVerticalConstraint) CONTEXT_MEMBER_DEF("Sketcher_ConstrainHorizontal",doHorizontalConstraint) CONTEXT_MEMBER_DEF("Sketcher_ConstrainParallel",doParallelConstraint) CONTEXT_MEMBER_DEF("Sketcher_ConstrainPerpendicular",doPerpendicularConstraint) CONTEXT_MEMBER_DEF("Sketcher_ConstrainTangent",doTangentConstraint) CONTEXT_MEMBER_DEF("Sketcher_ConstrainEqual",doEqualConstraint) CONTEXT_MEMBER_DEF("Sketcher_ConstrainSymmetric",doSymmetricConstraint) CONTEXT_MEMBER_DEF("Sketcher_ConstrainBlock",doBlockConstraint) CONTEXT_MEMBER_DEF("Sketcher_ConstrainLock",doLockConstraint) CONTEXT_MEMBER_DEF("Sketcher_ConstrainDistanceX",doHorizontalDistance) CONTEXT_MEMBER_DEF("Sketcher_ConstrainDistanceY",doVerticalDistance) CONTEXT_MEMBER_DEF("Sketcher_ConstrainDistance",doLengthConstraint) CONTEXT_MEMBER_DEF("Sketcher_ConstrainRadius",doRadiusConstraint) CONTEXT_MEMBER_DEF("Sketcher_ConstrainDiameter",doDiameterConstraint) CONTEXT_MEMBER_DEF("Sketcher_ConstrainRadiam",doRadiamConstraint) CONTEXT_MEMBER_DEF("Sketcher_ConstrainAngle",doAngleConstraint) CONTEXT_MEMBER_DEF("Sketcher_ToggleConstruction",doToggleConstruction) CONTEXT_MEMBER_DEF("Sketcher_SelectConstraints",doSelectConstraints) CONTEXT_MEMBER_DEF("Sketcher_SelectOrigin",doSelectOrigin) CONTEXT_MEMBER_DEF("Sketcher_SelectHorizontalAxis",doSelectHAxis) CONTEXT_MEMBER_DEF("Sketcher_SelectVerticalAxis",doSelectVAxis) void ElementView::deleteSelectedItems() { App::Document* doc = App::GetApplication().getActiveDocument(); if (!doc) return; doc->openTransaction("Delete element"); std::vector sel = Gui::Selection().getSelectionEx(doc->getName()); for (std::vector::iterator ft = sel.begin(); ft != sel.end(); ++ft) { Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(ft->getObject()); if (vp) { vp->onDelete(ft->getSubNames()); } } doc->commitTransaction(); } void ElementView::onIndexHovered(QModelIndex index) { Q_EMIT onItemHovered(itemFromIndex(index)); } ElementItem* ElementView::itemFromIndex(const QModelIndex& index) { return static_cast(QListWidget::itemFromIndex(index)); } /* ElementItem delegate ---------------------------------------------------- */ ElementItemDelegate::ElementItemDelegate(ElementView* parent) : QStyledItemDelegate(parent) { // This class relies on the parent being an ElementView, see getElementtItem } ElementItemDelegate::~ElementItemDelegate() { } void ElementItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { ElementItem* item = getElementtItem(index); if (item) { int height = option.rect.height(); int width = height; //icons are square. int x0 = option.rect.x() + leftMargin; int iconsize = height - 2 * border; int btny = option.rect.y() + border; if (item->isLineSelected || item->isStartingPointSelected || item->isEndPointSelected || item->isMidPointSelected) { //option.state & QStyle::State_Selected auto unselecticon = [&](int iconnumber){ QRect rect{ x0 + border + width*iconnumber, btny, iconsize, iconsize }; painter->fillRect(rect, option.palette.base()); }; painter->fillRect(option.rect, option.palette.highlight()); // paint the item as selected // Repaint individual icons if (!item->isLineSelected) unselecticon(0); if (!item->isStartingPointSelected) unselecticon(1); if (!item->isEndPointSelected) unselecticon(2); if (!item->isMidPointSelected) unselecticon(3); } auto & iconEdge = ElementWidgetIcons::getIcon(item->GeometryType, Sketcher::PointPos::none, item->State); auto & iconStart = ElementWidgetIcons::getIcon(item->GeometryType, Sketcher::PointPos::start, item->State); auto & iconEnd = ElementWidgetIcons::getIcon(item->GeometryType, Sketcher::PointPos::end, item->State); auto & iconMid = ElementWidgetIcons::getIcon(item->GeometryType, Sketcher::PointPos::mid, item->State); //getIcon(item->GeometryType); painter->drawPixmap(x0 + border , btny, iconEdge.pixmap(iconsize, iconsize)); painter->drawPixmap(x0 + border + width , btny, iconStart.pixmap(iconsize, iconsize)); painter->drawPixmap(x0 + border + width * 2 , btny, iconEnd.pixmap(iconsize, iconsize)); painter->drawPixmap(x0 + border + width * 3 , btny, iconMid.pixmap(iconsize, iconsize)); //Label : painter->drawText(x0 + width * 4 + 3 * border, option.rect.y() + height - textBottomMargin, item->label); } } bool ElementItemDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) { using SubElementType = ElementItem::SubElementType; auto getSubElementType = [&](ElementItem* item, int xPos, int width) { bool label = (xPos > option.rect.x() + leftMargin + width * 4 + border); if((xPos < option.rect.x() + leftMargin + width + border) || ( item->GeometryType != Part::GeomPoint::getClassTypeId() && label)) return SubElementType::edge; if(xPos < option.rect.x() + leftMargin + width * 2 + border || ( item->GeometryType == Part::GeomPoint::getClassTypeId() && label)) return SubElementType::start; if(xPos < option.rect.x() + leftMargin + width * 3 + border) return SubElementType::end; else if (xPos < option.rect.x() + leftMargin + width * 4 + border) return SubElementType::mid; else return SubElementType::none; }; if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) { QMouseEvent* mEvent = static_cast(event); ElementItem* item = getElementtItem(index); int xPos = mEvent->pos().x(); int width = option.rect.height(); //icons are square item->clickedOn = getSubElementType(item, xPos, width); if (mEvent->button() == Qt::RightButton) item->rightClicked = true; } else if (event->type() == QEvent::MouseMove) { SubElementType typeUnderMouse; QMouseEvent* mEvent = static_cast(event); int xPos = mEvent->pos().x(); int width = option.rect.height(); //icons are square ElementItem* item = getElementtItem(index); typeUnderMouse = getSubElementType(item, xPos, width); item->hovered = typeUnderMouse; Q_EMIT itemHovered(index); } return QStyledItemDelegate::editorEvent(event, model, option, index); } ElementItem* ElementItemDelegate::getElementtItem(const QModelIndex& index) const{ ElementView* elementView = static_cast(parent()); return elementView->itemFromIndex(index); } /* Filter element list widget ------------------------------------------------------ */ enum class GeoFilterType { NormalGeos, ConstructionGeos, InternalGeos, ExternalGeos, AllGeosTypes, PointGeos, LineGeos, CircleGeos, EllipseGeos, ArcGeos, ArcOfEllipseGeos, HyperbolaGeos, ParabolaGeos, BSplineGeos }; ElementFilterList::ElementFilterList(QWidget* parent) : QListWidget(parent) { ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General"); int filterState = hGrp->GetInt("ElementFilterState", INT_MAX); //INT_MAX = 1111111111111111111111111111111 in binary. for (auto const &filterItem:filterItems) { Q_UNUSED(filterItem); auto it = new QListWidgetItem(); it->setFlags(it->flags() | Qt::ItemIsUserCheckable); bool isChecked = static_cast(filterState & 1); //get the first bit of filterState it->setCheckState(isChecked ? Qt::Checked : Qt::Unchecked); filterState = filterState >> 1; //shift right to get rid of the used bit. addItem(it); } languageChange(); //We need to fix the state of 'All' group checkbox in case it is partially checked. int indexOfAllTypes = static_cast(GeoFilterType::AllGeosTypes); if(item(indexOfAllTypes)->checkState() == Qt::Unchecked) { bool allUnchecked = true; for (int i = indexOfAllTypes + 1; i < count(); i++) { if (item(i)->checkState() == Qt::Checked) { allUnchecked = false; break; } } if (!allUnchecked) item(indexOfAllTypes)->setCheckState(Qt::PartiallyChecked); } } ElementFilterList::~ElementFilterList() { } void ElementFilterList::changeEvent(QEvent* e) { if (e->type() == QEvent::LanguageChange) { languageChange(); } QWidget::changeEvent(e); } void ElementFilterList::languageChange() { assert(static_cast(filterItems.size()) == count()); int i=0; for (auto const &filterItem:filterItems) { auto text = QStringLiteral(" ").repeated(filterItem.second-1) + (filterItem.second > 0 ? QStringLiteral("- ") : QStringLiteral("")) + tr(filterItem.first); item(i++)->setText(text); } } /* TRANSLATOR SketcherGui::TaskSketcherElements */ TaskSketcherElements::TaskSketcherElements(ViewProviderSketch *sketchView) : TaskBox(Gui::BitmapFactory().pixmap("document-new"),tr("Elements"),true, nullptr) , sketchView(sketchView) , ui(new Ui_TaskSketcherElements()) , focusItemIndex(-1) , previouslySelectedItemIndex(-1) , previouslyHoveredItemIndex(-1) , previouslyHoveredType(SubElementType::none) , isNamingBoxChecked(false) { // we need a separate container widget to add all controls to proxy = new QWidget(this); ui->setupUi(proxy); #ifdef Q_OS_MAC QString cmdKey = QString::fromUtf8("\xe2\x8c\x98"); // U+2318 #else // translate the text (it's offered by Qt's translation files) // but avoid being picked up by lupdate const char* ctrlKey = "Ctrl"; QString cmdKey = QShortcut::tr(ctrlKey); #endif Q_UNUSED(cmdKey) ui->listWidgetElements->setSelectionMode(QAbstractItemView::ExtendedSelection); ui->listWidgetElements->setEditTriggers(QListWidget::NoEditTriggers); ui->listWidgetElements->setMouseTracking(true); createFilterButtonActions(); createSettingsButtonActions(); connectSignals(); this->groupLayout()->addWidget(proxy); ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General"); ui->filterBox->setChecked(hGrp->GetBool("ElementFilterEnabled", true)); ui->filterButton->setEnabled(ui->filterBox->isChecked()); slotElementsChanged(); } TaskSketcherElements::~TaskSketcherElements() { connectionElementsChanged.disconnect(); } void TaskSketcherElements::connectSignals() { // connecting the needed signals QObject::connect( ui->listWidgetElements, &ElementView::itemPressed, this, &TaskSketcherElements::onListWidgetElementsItemPressed ); QObject::connect( ui->listWidgetElements, &ElementView::itemEntered, this, &TaskSketcherElements::onListWidgetElementsItemEntered ); QObject::connect( ui->listWidgetElements, &ElementView::onItemHovered, this, &TaskSketcherElements::onListWidgetElementsMouseMoveOnItem ); QObject::connect( filterList, &QListWidget::itemChanged, this, &TaskSketcherElements::onListMultiFilterItemChanged ); QObject::connect( ui->filterBox, &QCheckBox::stateChanged, this, &TaskSketcherElements::onFilterBoxStateChanged ); QObject::connect( ui->settingsButton, &QToolButton::clicked, ui->settingsButton, &QToolButton::showMenu ); QObject::connect( qAsConst(ui->settingsButton)->actions()[0], &QAction::changed, this, &TaskSketcherElements::onSettingsExtendedInformationChanged ); QObject::connect( ui->filterButton, &QToolButton::clicked, ui->filterButton, &QToolButton::showMenu ); connectionElementsChanged = sketchView->signalElementsChanged.connect( boost::bind(&SketcherGui::TaskSketcherElements::slotElementsChanged, this)); } /* filter functions --------------------------------------------------- */ void TaskSketcherElements::createFilterButtonActions() { auto* action = new QWidgetAction(this); filterList = new ElementFilterList(this); action->setDefaultWidget(filterList); qAsConst(ui->filterButton)->addAction(action); } void TaskSketcherElements::onFilterBoxStateChanged(int val) { Q_UNUSED(val); ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General"); hGrp->SetBool("ElementFilterEnabled", ui->filterBox->checkState() == Qt::Checked); ui->filterButton->setEnabled(ui->filterBox->checkState() == Qt::Checked); slotElementsChanged(); } void TaskSketcherElements::onListMultiFilterItemChanged(QListWidgetItem* item) { { QSignalBlocker sigblk(filterList); int index = filterList->row(item); int indexOfAllTypes = static_cast(GeoFilterType::AllGeosTypes); if (index == indexOfAllTypes) { for (int i = indexOfAllTypes + 1; i < filterList->count(); i++) { filterList->item(i)->setCheckState(item->checkState()); } } else if (index > indexOfAllTypes) { bool atLeastOneUnchecked = false; bool atLeastOneChecked = false; for (int i = indexOfAllTypes + 1; i < filterList->count(); i++) { if (filterList->item(i)->checkState() == Qt::Checked) atLeastOneChecked = true; if (filterList->item(i)->checkState() == Qt::Unchecked) atLeastOneUnchecked = true; } if (atLeastOneChecked && atLeastOneUnchecked) filterList->item(indexOfAllTypes)->setCheckState(Qt::PartiallyChecked); else if(atLeastOneUnchecked) filterList->item(indexOfAllTypes)->setCheckState(Qt::Unchecked); else if(atLeastOneChecked) filterList->item(indexOfAllTypes)->setCheckState(Qt::Checked); } } //Save the state of the filter. int filterState = INT_MIN; //INT_MIN = 000000000000000000000000000000 in binary. for (int i = filterList->count() - 1; i >= 0 ; i--) { bool isChecked = filterList->item(i)->checkState() == Qt::Checked; filterState = filterState << 1; //we shift left first, else the list is shifted at the end. filterState = filterState | isChecked; } ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General"); hGrp->SetInt("ElementFilterState", filterState); updateVisibility(); } void TaskSketcherElements::setItemVisibility(QListWidgetItem* it) { ElementItem* item = static_cast(it); if (ui->filterBox->checkState() == Qt::Unchecked) { item->setHidden(false); return; } using GeometryState = ElementItem::GeometryState; if ((filterList->item(static_cast(GeoFilterType::NormalGeos))->checkState() == Qt::Unchecked && item->State == GeometryState::Normal) || (filterList->item(static_cast(GeoFilterType::ConstructionGeos))->checkState() == Qt::Unchecked && item->State == GeometryState::Construction) || (filterList->item(static_cast(GeoFilterType::InternalGeos))->checkState() == Qt::Unchecked && item->State == GeometryState::InternalAlignment) || (filterList->item(static_cast(GeoFilterType::ExternalGeos))->checkState() == Qt::Unchecked && item->State == GeometryState::External) || (filterList->item(static_cast(GeoFilterType::PointGeos))->checkState() == Qt::Unchecked && item->GeometryType == Part::GeomPoint::getClassTypeId()) || (filterList->item(static_cast(GeoFilterType::LineGeos))->checkState() == Qt::Unchecked && item->GeometryType == Part::GeomLineSegment::getClassTypeId()) || (filterList->item(static_cast(GeoFilterType::CircleGeos))->checkState() == Qt::Unchecked && item->GeometryType == Part::GeomCircle::getClassTypeId()) || (filterList->item(static_cast(GeoFilterType::EllipseGeos))->checkState() == Qt::Unchecked && item->GeometryType == Part::GeomEllipse::getClassTypeId()) || (filterList->item(static_cast(GeoFilterType::ArcGeos))->checkState() == Qt::Unchecked && item->GeometryType == Part::GeomArcOfCircle::getClassTypeId()) || (filterList->item(static_cast(GeoFilterType::ArcOfEllipseGeos))->checkState() == Qt::Unchecked && item->GeometryType == Part::GeomArcOfEllipse::getClassTypeId()) || (filterList->item(static_cast(GeoFilterType::HyperbolaGeos))->checkState() == Qt::Unchecked && item->GeometryType == Part::GeomArcOfHyperbola::getClassTypeId()) || (filterList->item(static_cast(GeoFilterType::ParabolaGeos))->checkState() == Qt::Unchecked && item->GeometryType == Part::GeomArcOfParabola::getClassTypeId()) || (filterList->item(static_cast(GeoFilterType::BSplineGeos))->checkState() == Qt::Unchecked && item->GeometryType == Part::GeomBSplineCurve::getClassTypeId()) ) { item->setHidden(true); return; } item->setHidden(false); } void TaskSketcherElements::updateVisibility() { for (int i = 0; i < ui->listWidgetElements->count(); i++) { setItemVisibility(ui->listWidgetElements->item(i)); } } /*------------------*/ void TaskSketcherElements::onSelectionChanged(const Gui::SelectionChanges& msg) { std::string temp; if (msg.Type == Gui::SelectionChanges::ClrSelection) { clearWidget(); } else if (msg.Type == Gui::SelectionChanges::AddSelection || msg.Type == Gui::SelectionChanges::RmvSelection) { bool select = (msg.Type == Gui::SelectionChanges::AddSelection); // is it this object?? if (strcmp(msg.pDocName,sketchView->getSketchObject()->getDocument()->getName())==0 && strcmp(msg.pObjectName,sketchView->getSketchObject()->getNameInDocument())== 0) { if (msg.pSubName) { QString expr = QString::fromLatin1(msg.pSubName); std::string shapetype(msg.pSubName); // if-else edge vertex if (shapetype.size() > 4 && shapetype.substr(0,4) == "Edge") { QRegularExpression rx(QString::fromLatin1("^Edge(\\d+)$")); QRegularExpressionMatch match; boost::ignore_unused(expr.indexOf(rx, 0, &match)); if (match.hasMatch()) { bool ok; int ElementId = match.captured(1).toInt(&ok) - 1; if (ok) { int countItems = ui->listWidgetElements->count(); for (int i=0; i < countItems; i++) { ElementItem* item = static_cast(ui->listWidgetElements->item(i)); if (item->ElementNbr == ElementId) { item->isLineSelected = select; break; } } } } } else if (shapetype.size() > 6 && shapetype.substr(0,6) == "Vertex"){ QRegularExpression rx(QString::fromLatin1("^Vertex(\\d+)$")); QRegularExpressionMatch match; boost::ignore_unused(expr.indexOf(rx, 0, &match)); if (match.hasMatch()) { bool ok; int ElementId = match.captured(1).toInt(&ok) - 1; if (ok) { // Get the GeoID&Pos int GeoId; Sketcher::PointPos PosId; sketchView->getSketchObject()->getGeoVertexIndex(ElementId,GeoId, PosId); int countItems = ui->listWidgetElements->count(); for (int i=0; i < countItems; i++) { ElementItem* item = static_cast(ui->listWidgetElements->item(i)); if (item->ElementNbr == GeoId) { switch(PosId) { case Sketcher::PointPos::start: item->isStartingPointSelected=select; break; case Sketcher::PointPos::end: item->isEndPointSelected=select; break; case Sketcher::PointPos::mid: item->isMidPointSelected=select; break; default: break; } break; } } } } } // update the listwidget { QSignalBlocker sigblk(ui->listWidgetElements); for (int i = 0; i < ui->listWidgetElements->count(); i++) { ElementItem* item = static_cast(ui->listWidgetElements->item(i)); if(item->isSelected()) item->setSelected(false); //if already selected, we need to reset setSelected or it won't draw subelements correctly if selecting several. item->setSelected(item->isLineSelected || item->isStartingPointSelected || item->isEndPointSelected || item->isMidPointSelected); } } } } } else if (msg.Type == Gui::SelectionChanges::SetSelection) { // do nothing here } } void TaskSketcherElements::onListWidgetElementsItemPressed(QListWidgetItem* it) { //We use itemPressed instead of previously used ItemSelectionChanged because if user click on already selected item, ItemSelectionChanged didn't trigger. if (!it) return; ElementItem* itf = static_cast(it); bool rightClickOnSelected = itf->rightClicked && (itf->isLineSelected || itf->isStartingPointSelected || itf->isEndPointSelected || itf->isMidPointSelected); itf->rightClicked = false; if (rightClickOnSelected) //if user right clicked on a selected item, change nothing. return; { QSignalBlocker sigblk(ui->listWidgetElements); bool multipleselection = false; bool multipleconsecutiveselection = false; if (QApplication::keyboardModifiers() == Qt::ControlModifier) multipleselection = true; if (QApplication::keyboardModifiers() == Qt::ShiftModifier) multipleconsecutiveselection = true; if (multipleselection && multipleconsecutiveselection) { // ctrl takes priority over shift functionality multipleselection = true; multipleconsecutiveselection = false; } std::vector elementSubNames; std::string doc_name = sketchView->getSketchObject()->getDocument()->getName(); std::string obj_name = sketchView->getSketchObject()->getNameInDocument(); bool block = this->blockSelection(true); // avoid to be notified by itself Gui::Selection().clearSelection(); for (int i = 0; i < ui->listWidgetElements->count(); i++) { ElementItem* item = static_cast(ui->listWidgetElements->item(i)); if (!multipleselection && !multipleconsecutiveselection ) { //if not multiple selection, then all are disabled but the one that was just selected item->isLineSelected = false; item->isStartingPointSelected = false; item->isEndPointSelected = false; item->isMidPointSelected = false; } if (item == itf) { if (item->clickedOn == SubElementType::mid && (item->GeometryType == Part::GeomArcOfCircle::getClassTypeId() || item->GeometryType == Part::GeomArcOfEllipse::getClassTypeId() || item->GeometryType == Part::GeomArcOfHyperbola::getClassTypeId() || item->GeometryType == Part::GeomArcOfParabola::getClassTypeId() || item->GeometryType == Part::GeomCircle::getClassTypeId() || item->GeometryType == Part::GeomEllipse::getClassTypeId())) { item->isMidPointSelected = !item->isMidPointSelected; } else if (item->clickedOn == SubElementType::start && (item->GeometryType == Part::GeomPoint::getClassTypeId() || item->GeometryType == Part::GeomArcOfCircle::getClassTypeId() || item->GeometryType == Part::GeomArcOfEllipse::getClassTypeId() || item->GeometryType == Part::GeomArcOfHyperbola::getClassTypeId() || item->GeometryType == Part::GeomArcOfParabola::getClassTypeId() || item->GeometryType == Part::GeomLineSegment::getClassTypeId() || item->GeometryType == Part::GeomBSplineCurve::getClassTypeId())) { item->isStartingPointSelected = !item->isStartingPointSelected; } else if (item->clickedOn == SubElementType::end && (item->GeometryType == Part::GeomArcOfCircle::getClassTypeId() || item->GeometryType == Part::GeomArcOfEllipse::getClassTypeId() || item->GeometryType == Part::GeomArcOfHyperbola::getClassTypeId() || item->GeometryType == Part::GeomArcOfParabola::getClassTypeId() || item->GeometryType == Part::GeomLineSegment::getClassTypeId() || item->GeometryType == Part::GeomBSplineCurve::getClassTypeId())) { item->isEndPointSelected = !item->isEndPointSelected; } else if (item->clickedOn == SubElementType::edge && item->GeometryType != Part::GeomPoint::getClassTypeId()){ item->isLineSelected = !item->isLineSelected; } item->clickedOn = SubElementType::none; } else if (multipleconsecutiveselection && previouslySelectedItemIndex >= 0 && !rightClickOnSelected && ((i > focusItemIndex && i < previouslySelectedItemIndex) || (ipreviouslySelectedItemIndex))) { if (item->GeometryType == Part::GeomPoint::getClassTypeId()) { item->isStartingPointSelected = true; } else { item->isLineSelected = true; } } // first update the listwidget. Item is selected if at least one element of the geo is selected. bool selected = item->isLineSelected || item->isStartingPointSelected || item->isEndPointSelected || item->isMidPointSelected; { QSignalBlocker sigblk(ui->listWidgetElements); if (item->isSelected() && selected) { item->setSelected(false);// if already selected and changing or adding subelement, ensure selection change is triggered, which ensures timely repaint item->setSelected(selected); } else { item->setSelected(selected); } } // now the scene std::stringstream ss; if (item->isLineSelected) { ss << "Edge" << item->ElementNbr + 1; elementSubNames.push_back(ss.str()); } auto selectVertex = [&ss, &elementSubNames] (bool subelementselected, int vertexid) { if (subelementselected) { int vertex; ss.str(std::string()); vertex = vertexid; if (vertex != -1) { ss << "Vertex" << vertex + 1; elementSubNames.push_back(ss.str()); } } }; selectVertex(item->isStartingPointSelected, item->StartingVertex); selectVertex(item->isEndPointSelected, item->EndVertex); selectVertex(item->isMidPointSelected, item->MidVertex); } if (!elementSubNames.empty()) { Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), elementSubNames); } this->blockSelection(block); } if (focusItemIndex > -1 && focusItemIndex < ui->listWidgetElements->count()) previouslySelectedItemIndex = focusItemIndex; ui->listWidgetElements->repaint(); } void TaskSketcherElements::onListWidgetElementsItemEntered(QListWidgetItem *item) { ui->listWidgetElements->setFocus(); focusItemIndex = ui->listWidgetElements->row(item); } void TaskSketcherElements::onListWidgetElementsMouseMoveOnItem(QListWidgetItem* it) { ElementItem* item = static_cast(it); if (!item || (ui->listWidgetElements->row(item) == previouslyHoveredItemIndex && item->hovered == previouslyHoveredType) ) return; Gui::Selection().rmvPreselect(); bool validmid = item->hovered == SubElementType::mid && (item->GeometryType == Part::GeomArcOfCircle::getClassTypeId() || item->GeometryType == Part::GeomArcOfEllipse::getClassTypeId() || item->GeometryType == Part::GeomArcOfHyperbola::getClassTypeId() || item->GeometryType == Part::GeomArcOfParabola::getClassTypeId() || item->GeometryType == Part::GeomCircle::getClassTypeId() || item->GeometryType == Part::GeomEllipse::getClassTypeId()); bool validstartpoint = item->hovered == SubElementType::start && (item->GeometryType == Part::GeomPoint::getClassTypeId() || item->GeometryType == Part::GeomArcOfCircle::getClassTypeId() || item->GeometryType == Part::GeomArcOfEllipse::getClassTypeId() || item->GeometryType == Part::GeomArcOfHyperbola::getClassTypeId() || item->GeometryType == Part::GeomArcOfParabola::getClassTypeId() || item->GeometryType == Part::GeomLineSegment::getClassTypeId() || item->GeometryType == Part::GeomBSplineCurve::getClassTypeId()); bool validendpoint = item->hovered == SubElementType::end && (item->GeometryType == Part::GeomArcOfCircle::getClassTypeId() || item->GeometryType == Part::GeomArcOfEllipse::getClassTypeId() || item->GeometryType == Part::GeomArcOfHyperbola::getClassTypeId() || item->GeometryType == Part::GeomArcOfParabola::getClassTypeId() || item->GeometryType == Part::GeomLineSegment::getClassTypeId() || item->GeometryType == Part::GeomBSplineCurve::getClassTypeId()); bool validedge = item->hovered == SubElementType::edge && item->GeometryType != Part::GeomPoint::getClassTypeId(); if (validmid || validstartpoint || validendpoint || validedge) { std::string doc_name = sketchView->getSketchObject()->getDocument()->getName(); std::string obj_name = sketchView->getSketchObject()->getNameInDocument(); std::stringstream ss; auto preselectvertex = [&](int geoid, Sketcher::PointPos pos) { int vertex = sketchView->getSketchObject()->getVertexIndexGeoPos(geoid, pos); if (vertex != -1) { ss << "Vertex" << vertex + 1; Gui::Selection().setPreselect(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); } }; if (item->hovered == SubElementType::start) preselectvertex(item->ElementNbr, Sketcher::PointPos::start); else if (item->hovered == SubElementType::end) preselectvertex(item->ElementNbr, Sketcher::PointPos::end); else if (item->hovered == SubElementType::mid) preselectvertex(item->ElementNbr, Sketcher::PointPos::mid); else if (item->hovered == SubElementType::edge) { ss << "Edge" << item->ElementNbr + 1; Gui::Selection().setPreselect(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); } } previouslyHoveredItemIndex = ui->listWidgetElements->row(item); previouslyHoveredType = item->hovered; } void TaskSketcherElements::leaveEvent (QEvent * event) { Q_UNUSED(event); Gui::Selection().rmvPreselect(); ui->listWidgetElements->clearFocus(); } void TaskSketcherElements::slotElementsChanged(void) { assert(sketchView); // Build up ListView with the elements Sketcher::SketchObject *sketch = sketchView->getSketchObject(); const std::vector< Part::Geometry * > &vals = sketch->Geometry.getValues(); ui->listWidgetElements->clear(); using GeometryState = ElementItem::GeometryState; int i=1; for(std::vector< Part::Geometry * >::const_iterator it= vals.begin();it!=vals.end();++it,++i){ Base::Type type = (*it)->getTypeId(); GeometryState state = GeometryState::Normal; bool construction = Sketcher::GeometryFacade::getConstruction(*it); bool internalAligned = Sketcher::GeometryFacade::isInternalAligned(*it); if (internalAligned) state = GeometryState::InternalAlignment; else if (construction) //Caution, internalAligned geos are construction too. So the 'if' and 'else if' cannot be swapped. state = GeometryState::Construction; ElementItem* itemN = new ElementItem(i - 1, sketchView->getSketchObject()->getVertexIndexGeoPos(i - 1, Sketcher::PointPos::start), sketchView->getSketchObject()->getVertexIndexGeoPos(i - 1, Sketcher::PointPos::mid), sketchView->getSketchObject()->getVertexIndexGeoPos(i - 1, Sketcher::PointPos::end), type, state, type == Part::GeomPoint::getClassTypeId() ? (isNamingBoxChecked ? (tr("Point") + QString::fromLatin1("(Edge%1#ID%2)").arg(i).arg(i - 1)) + (construction ? (QString::fromLatin1("-") + tr("Construction")) : (internalAligned ? (QString::fromLatin1("-") + tr("Internal")) : QString::fromLatin1(""))) : (QString::fromLatin1("%1-").arg(i) + tr("Point"))) : type == Part::GeomLineSegment::getClassTypeId() ? (isNamingBoxChecked ? (tr("Line") + QString::fromLatin1("(Edge%1#ID%2)").arg(i).arg(i - 1)) + (construction ? (QString::fromLatin1("-") + tr("Construction")) : (internalAligned ? (QString::fromLatin1("-") + tr("Internal")) : QString::fromLatin1(""))) : (QString::fromLatin1("%1-").arg(i) + tr("Line"))) : type == Part::GeomArcOfCircle::getClassTypeId() ? (isNamingBoxChecked ? (tr("Arc") + QString::fromLatin1("(Edge%1#ID%2)").arg(i).arg(i - 1)) + (construction ? (QString::fromLatin1("-") + tr("Construction")) : (internalAligned ? (QString::fromLatin1("-") + tr("Internal")) : QString::fromLatin1(""))) : (QString::fromLatin1("%1-").arg(i) + tr("Arc"))) : type == Part::GeomCircle::getClassTypeId() ? (isNamingBoxChecked ? (tr("Circle") + QString::fromLatin1("(Edge%1#ID%2)").arg(i).arg(i - 1)) + (construction ? (QString::fromLatin1("-") + tr("Construction")) : (internalAligned ? (QString::fromLatin1("-") + tr("Internal")) : QString::fromLatin1(""))) : (QString::fromLatin1("%1-").arg(i) + tr("Circle"))) : type == Part::GeomEllipse::getClassTypeId() ? (isNamingBoxChecked ? (tr("Ellipse") + QString::fromLatin1("(Edge%1#ID%2)").arg(i).arg(i - 1)) + (construction ? (QString::fromLatin1("-") + tr("Construction")) : (internalAligned ? (QString::fromLatin1("-") + tr("Internal")) : QString::fromLatin1(""))) : (QString::fromLatin1("%1-").arg(i) + tr("Ellipse"))) : type == Part::GeomArcOfEllipse::getClassTypeId() ? (isNamingBoxChecked ? (tr("Elliptical Arc") + QString::fromLatin1("(Edge%1#ID%2)").arg(i).arg(i - 1)) + (construction ? (QString::fromLatin1("-") + tr("Construction")) : (internalAligned ? (QString::fromLatin1("-") + tr("Internal")) : QString::fromLatin1(""))) : (QString::fromLatin1("%1-").arg(i) + tr("Elliptical Arc"))) : type == Part::GeomArcOfHyperbola::getClassTypeId() ? (isNamingBoxChecked ? (tr("Hyperbolic Arc") + QString::fromLatin1("(Edge%1#ID%2)").arg(i).arg(i - 1)) + (construction ? (QString::fromLatin1("-") + tr("Construction")) : (internalAligned ? (QString::fromLatin1("-") + tr("Internal")) : QString::fromLatin1(""))) : (QString::fromLatin1("%1-").arg(i) + tr("Hyperbolic Arc"))) : type == Part::GeomArcOfParabola::getClassTypeId() ? (isNamingBoxChecked ? (tr("Parabolic Arc") + QString::fromLatin1("(Edge%1#ID%2)").arg(i).arg(i - 1)) + (construction ? (QString::fromLatin1("-") + tr("Construction")) : (internalAligned ? (QString::fromLatin1("-") + tr("Internal")) : QString::fromLatin1(""))) : (QString::fromLatin1("%1-").arg(i) + tr("Parabolic Arc"))) : type == Part::GeomBSplineCurve::getClassTypeId() ? (isNamingBoxChecked ? (tr("BSpline") + QString::fromLatin1("(Edge%1#ID%2)").arg(i).arg(i - 1)) + (construction ? (QString::fromLatin1("-") + tr("Construction")) : (internalAligned ? (QString::fromLatin1("-") + tr("Internal")) : QString::fromLatin1(""))) : (QString::fromLatin1("%1-").arg(i) + tr("BSpline"))) : (isNamingBoxChecked ? (tr("Other") + QString::fromLatin1("(Edge%1#ID%2)").arg(i).arg(i - 1)) + (construction ? (QString::fromLatin1("-") + tr("Construction")) : (internalAligned ? (QString::fromLatin1("-") + tr("Internal")) : QString::fromLatin1(""))) : (QString::fromLatin1("%1-").arg(i) + tr("Other"))) ); ui->listWidgetElements->addItem(itemN); setItemVisibility(itemN); } const std::vector< Part::Geometry * > &ext_vals = sketchView->getSketchObject()->getExternalGeometry(); const std::vector linkobjs = sketchView->getSketchObject()->ExternalGeometry.getValues(); const std::vector linksubs = sketchView->getSketchObject()->ExternalGeometry.getSubValues(); int j=1; for(std::vector< Part::Geometry * >::const_iterator it= ext_vals.begin();it!=ext_vals.end();++it,++i,++j){ Base::Type type = (*it)->getTypeId(); if(j>2) { // we do not want the H and V axes QString linkname; if(isNamingBoxChecked) { if(size_t(j-3) < linkobjs.size() && size_t(j-3) < linksubs.size()) { linkname = QString::fromLatin1("(ExternalEdge%1#ID%2, ").arg(j-2).arg(-j) + QString::fromUtf8(linkobjs[j-3]->getNameInDocument()) + QString::fromLatin1(".") + QString::fromUtf8(linksubs[j-3].c_str()) + QString::fromLatin1(")"); } else { linkname = QString::fromLatin1("(ExternalEdge%1)").arg(j-2); } } GeometryState state = GeometryState::External; ElementItem* itemN = new ElementItem( -j, sketchView->getSketchObject()->getVertexIndexGeoPos(-j, Sketcher::PointPos::start), sketchView->getSketchObject()->getVertexIndexGeoPos(-j, Sketcher::PointPos::mid), sketchView->getSketchObject()->getVertexIndexGeoPos(-j, Sketcher::PointPos::end), type, state, type == Part::GeomPoint::getClassTypeId() ? (isNamingBoxChecked ? (tr("Point") + linkname) : (QString::fromLatin1("%1-").arg(i - 2) + tr("Point"))) : type == Part::GeomLineSegment::getClassTypeId() ? (isNamingBoxChecked ? (tr("Line") + linkname) : (QString::fromLatin1("%1-").arg(i - 2) + tr("Line"))) : type == Part::GeomArcOfCircle::getClassTypeId() ? (isNamingBoxChecked ? (tr("Arc") + linkname) : (QString::fromLatin1("%1-").arg(i - 2) + tr("Arc"))) : type == Part::GeomCircle::getClassTypeId() ? (isNamingBoxChecked ? (tr("Circle") + linkname) : (QString::fromLatin1("%1-").arg(i - 2) + tr("Circle"))) : type == Part::GeomEllipse::getClassTypeId() ? (isNamingBoxChecked ? (tr("Ellipse") + linkname) : (QString::fromLatin1("%1-").arg(i - 2) + tr("Ellipse"))) : type == Part::GeomArcOfEllipse::getClassTypeId() ? (isNamingBoxChecked ? (tr("Elliptical Arc") + linkname) : (QString::fromLatin1("%1-").arg(i - 2) + tr("Elliptical Arc"))) : type == Part::GeomArcOfHyperbola::getClassTypeId() ? (isNamingBoxChecked ? (tr("Hyperbolic Arc") + linkname) : (QString::fromLatin1("%1-").arg(i - 2) + tr("Hyperbolic Arc"))) : type == Part::GeomArcOfParabola::getClassTypeId() ? (isNamingBoxChecked ? (tr("Parabolic Arc") + linkname) : (QString::fromLatin1("%1-").arg(i - 2) + tr("Parabolic Arc"))) : type == Part::GeomBSplineCurve::getClassTypeId() ? (isNamingBoxChecked ? (tr("BSpline") + linkname) : (QString::fromLatin1("%1-").arg(i - 2) + tr("BSpline"))) : (isNamingBoxChecked ? (tr("Other") + linkname) : (QString::fromLatin1("%1-").arg(i - 2) + tr("Other"))) ); ui->listWidgetElements->addItem(itemN); setItemVisibility(itemN); } } } void TaskSketcherElements::clearWidget() { { QSignalBlocker sigblk(ui->listWidgetElements); ui->listWidgetElements->clearSelection(); } // update widget int countItems = ui->listWidgetElements->count(); for (int i=0; i < countItems; i++) { ElementItem* item = static_cast(ui->listWidgetElements->item(i)); item->isLineSelected=false; item->isStartingPointSelected=false; item->isEndPointSelected=false; item->isMidPointSelected=false; } } void TaskSketcherElements::changeEvent(QEvent *e) { TaskBox::changeEvent(e); if (e->type() == QEvent::LanguageChange) { ui->retranslateUi(proxy); } } /* Settings menu ==================================================*/ void TaskSketcherElements::createSettingsButtonActions() { QAction* action = new QAction(tr("Extended information"), this); action->setCheckable(true); ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Elements"); { QSignalBlocker block(this); action->setChecked(hGrp->GetBool("ExtendedNaming", false)); } ui->settingsButton->addAction(action); isNamingBoxChecked = hGrp->GetBool("ExtendedNaming", false); } void TaskSketcherElements::onSettingsExtendedInformationChanged() { QList acts = ui->settingsButton->actions(); isNamingBoxChecked = acts[0]->isChecked(); ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/Elements"); hGrp->SetBool("ExtendedNaming", isNamingBoxChecked); slotElementsChanged(); } #include "moc_TaskSketcherElements.cpp"