/*************************************************************************** * Copyright (c) 2015 Stefan Tröger * * * * 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 #endif #include #include #include #include #include #include #include #include #include #include "ViewProviderShapeBinder.h" #include "TaskShapeBinder.h" FC_LOG_LEVEL_INIT("ShapeBinder",true,true) using namespace PartDesignGui; PROPERTY_SOURCE(PartDesignGui::ViewProviderShapeBinder,PartGui::ViewProviderPart) ViewProviderShapeBinder::ViewProviderShapeBinder() { sPixmap = "PartDesign_ShapeBinder.svg"; //make the viewprovider more datum like AngularDeflection.setStatus(App::Property::Hidden, true); Deviation.setStatus(App::Property::Hidden, true); DrawStyle.setStatus(App::Property::Hidden, true); Lighting.setStatus(App::Property::Hidden, true); LineColor.setStatus(App::Property::Hidden, true); LineWidth.setStatus(App::Property::Hidden, true); PointColor.setStatus(App::Property::Hidden, true); PointSize.setStatus(App::Property::Hidden, true); DisplayMode.setStatus(App::Property::Hidden, true); //get the datum coloring scheme // set default color for datums (golden yellow with 60% transparency) ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath ( "User parameter:BaseApp/Preferences/Mod/PartDesign"); unsigned long shcol = hGrp->GetUnsigned ( "DefaultDatumColor", 0xFFD70099 ); App::Color col ( (uint32_t) shcol ); ShapeColor.setValue(col); LineColor.setValue(col); PointColor.setValue(col); Transparency.setValue(60); LineWidth.setValue(1); } ViewProviderShapeBinder::~ViewProviderShapeBinder() { } bool ViewProviderShapeBinder::setEdit(int ModNum) { // TODO Share code with other view providers (2015-09-11, Fat-Zer) if (ModNum == ViewProvider::Default || ModNum == 1) { // When double-clicking on the item for this pad the // object unsets and sets its edit mode without closing // the task panel Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); TaskDlgShapeBinder *sbDlg = qobject_cast(dlg); if (dlg && !sbDlg) { QMessageBox msgBox; msgBox.setText(QObject::tr("A dialog is already open in the task panel")); msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?")); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::Yes); int ret = msgBox.exec(); if (ret == QMessageBox::Yes) Gui::Control().reject(); else return false; } // clear the selection (convenience) Gui::Selection().clearSelection(); // start the edit dialog // another pad left open its task panel if (sbDlg) Gui::Control().showDialog(sbDlg); else Gui::Control().showDialog(new TaskDlgShapeBinder(this,ModNum == 1)); return true; } else { return ViewProviderPart::setEdit(ModNum); } } void ViewProviderShapeBinder::unsetEdit(int ModNum) { PartGui::ViewProviderPart::unsetEdit(ModNum); } void ViewProviderShapeBinder::highlightReferences(const bool on, bool /*auxiliary*/) { App::GeoFeature* obj = nullptr; std::vector subs; if (getObject()->isDerivedFrom(PartDesign::ShapeBinder::getClassTypeId())) PartDesign::ShapeBinder::getFilteredReferences(&static_cast(getObject())->Support, obj, subs); else return; // stop if not a Part feature was found if (!obj || !obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) return; PartGui::ViewProviderPart* svp = dynamic_cast( Gui::Application::Instance->getViewProvider(obj)); if (svp == NULL) return; if (on) { if (!subs.empty() && originalLineColors.empty()) { TopTools_IndexedMapOfShape eMap; TopExp::MapShapes(static_cast(obj)->Shape.getValue(), TopAbs_EDGE, eMap); originalLineColors = svp->LineColorArray.getValues(); std::vector lcolors = originalLineColors; lcolors.resize(eMap.Extent(), svp->LineColor.getValue()); TopExp::MapShapes(static_cast(obj)->Shape.getValue(), TopAbs_FACE, eMap); originalFaceColors = svp->DiffuseColor.getValues(); std::vector fcolors = originalFaceColors; fcolors.resize(eMap.Extent(), svp->ShapeColor.getValue()); for (std::string e : subs) { // Note: stoi may throw, but it strictly shouldn't happen if(e.compare(0, 4, "Edge") == 0) { int idx = std::stoi(e.substr(4)) - 1; assert ( idx>=0 ); if ( idx < (ssize_t) lcolors.size() ) lcolors[idx] = App::Color(1.0,0.0,1.0); // magenta } else if(e.compare(0, 4, "Face") == 0) { int idx = std::stoi(e.substr(4)) - 1; assert ( idx>=0 ); if ( idx < (ssize_t) fcolors.size() ) fcolors[idx] = App::Color(1.0,0.0,1.0); // magenta } } svp->LineColorArray.setValues(lcolors); svp->DiffuseColor.setValues(fcolors); } } else { if (!subs.empty() && !originalLineColors.empty()) { svp->LineColorArray.setValues(originalLineColors); originalLineColors.clear(); svp->DiffuseColor.setValues(originalFaceColors); originalFaceColors.clear(); } } } void ViewProviderShapeBinder::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) { Q_UNUSED(receiver) Q_UNUSED(member) QAction* act; act = menu->addAction(QObject::tr("Edit shape binder")); act->setData(QVariant((int)ViewProvider::Default)); Gui::ActionFunction* func = new Gui::ActionFunction(menu); func->trigger(act, [this]() { QString text = QObject::tr("Edit %1").arg(QString::fromUtf8(getObject()->Label.getValue())); Gui::Command::openCommand(text.toUtf8()); Gui::Document* document = this->getDocument(); if (document) { document->setEdit(this, ViewProvider::Default); } }); } //===================================================================================== PROPERTY_SOURCE(PartDesignGui::ViewProviderSubShapeBinder,PartGui::ViewProviderPart) ViewProviderSubShapeBinder::ViewProviderSubShapeBinder() { sPixmap = "PartDesign_SubShapeBinder.svg"; ADD_PROPERTY_TYPE(UseBinderStyle, (false), "",(App::PropertyType)(App::Prop_None), ""); } void ViewProviderSubShapeBinder::attach(App::DocumentObject *obj) { UseBinderStyle.setValue(boost::istarts_with(obj->getNameInDocument(),"binder")); ViewProviderPart::attach(obj); } void ViewProviderSubShapeBinder::onChanged(const App::Property *prop) { if(prop == &UseBinderStyle && (!getObject() || !getObject()->isRestoring())) { App::Color shapeColor,lineColor,pointColor; int transparency, linewidth; if(UseBinderStyle.getValue()) { //get the datum coloring scheme // set default color for datums (golden yellow with 60% transparency) static ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath ( "User parameter:BaseApp/Preferences/Mod/PartDesign"); shapeColor.setPackedValue(hGrp->GetUnsigned ( "DefaultDatumColor", 0xFFD70099 )); lineColor = shapeColor; pointColor = shapeColor; transparency = 60; linewidth = 1; } else { shapeColor.setPackedValue(Gui::ViewParams::instance()->getDefaultShapeColor()); lineColor.setPackedValue(Gui::ViewParams::instance()->getDefaultShapeLineColor()); pointColor = lineColor; transparency = 0; linewidth = Gui::ViewParams::instance()->getDefaultShapeLineWidth(); } ShapeColor.setValue(shapeColor); LineColor.setValue(lineColor); PointColor.setValue(pointColor); Transparency.setValue(transparency); LineWidth.setValue(linewidth); } ViewProviderPart::onChanged(prop); } bool ViewProviderSubShapeBinder::canDropObjectEx(App::DocumentObject *, App::DocumentObject *, const char *, const std::vector &) const { return true; } std::string ViewProviderSubShapeBinder::dropObjectEx(App::DocumentObject *obj, App::DocumentObject *owner, const char *subname, const std::vector &elements) { auto self = dynamic_cast(getObject()); if(!self) return std::string(); std::map > values; if(!subname) subname = ""; std::string sub(subname); if(sub.empty()) values[owner?owner:obj] = elements; else { std::vector subs; if(elements.size()) { subs.reserve(elements.size()); for(auto &element : elements) subs.push_back(sub+element); }else subs.push_back(sub); values[owner?owner:obj] = std::move(subs); } self->setLinks(std::move(values),QApplication::keyboardModifiers()==Qt::ControlModifier); if(self->Relative.getValue()) updatePlacement(false); return std::string(); } bool ViewProviderSubShapeBinder::doubleClicked() { updatePlacement(true); return true; } void ViewProviderSubShapeBinder::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) { QAction* act; act = menu->addAction(QObject::tr("Synchronize"), receiver, member); act->setData(QVariant((int)Synchronize)); act = menu->addAction(QObject::tr("Select bound object"), receiver, member); act->setData(QVariant((int)SelectObject)); ViewProviderPart::setupContextMenu(menu,receiver,member); } bool ViewProviderSubShapeBinder::setEdit(int ModNum) { switch(ModNum) { case Synchronize: updatePlacement(true); break; case SelectObject: { auto self = dynamic_cast(getObject()); if(!self || !self->Support.getValue()) break; Gui::Selection().selStackPush(); Gui::Selection().clearSelection(); for(auto &link : self->Support.getSubListValues()) { auto obj = link.getValue(); if(!obj || !obj->getNameInDocument()) continue; const auto &subs = link.getSubValues(); if(subs.size()) Gui::Selection().addSelections(obj->getDocument()->getName(), obj->getNameInDocument(),subs); else Gui::Selection().addSelection(obj->getDocument()->getName(), obj->getNameInDocument()); } Gui::Selection().selStackPush(); break; } default: return ViewProviderPart::setEdit(ModNum); } return false; } void ViewProviderSubShapeBinder::updatePlacement(bool transaction) { auto self = dynamic_cast(getObject()); if(!self || !self->Support.getValue()) return; std::vector mats; bool relative = self->Relative.getValue(); App::DocumentObject *parent = 0; std::string parentSub; if(relative && self->getParents().size()) { const auto &sel = Gui::Selection().getSelection("",0); if(sel.size()!=1 || !sel[0].pObject || sel[0].pObject->getSubObject(sel[0].SubName)!=self) { FC_WARN("invalid selection"); } else { parent = sel[0].pObject; parentSub = sel[0].SubName; } } if(!transaction) { if(relative) self->Context.setValue(parent,parentSub.c_str()); self->update(PartDesign::SubShapeBinder::UpdateForced); return; } App::GetApplication().setActiveTransaction("Sync binder"); try{ if(relative) self->Context.setValue(parent,parentSub.c_str()); self->update(PartDesign::SubShapeBinder::UpdateForced); App::GetApplication().closeActiveTransaction(); return; }catch(Base::Exception &e) { e.ReportException(); }catch(Standard_Failure &e) { std::ostringstream str; Standard_CString msg = e.GetMessageString(); str << typeid(e).name() << " "; if (msg) {str << msg;} else {str << "No OCCT Exception Message";} FC_ERR(str.str()); } App::GetApplication().closeActiveTransaction(true); } std::vector ViewProviderSubShapeBinder::claimChildren(void) const { std::vector ret; auto self = Base::freecad_dynamic_cast(getObject()); if(self && self->ClaimChildren.getValue() && self->Support.getValue()) { std::set objSet; for(auto &l : self->Support.getSubListValues()) { auto obj = l.getValue(); if(!obj) continue; const auto &subs = l.getSubValues(); if(subs.empty()) { if(objSet.insert(obj).second) ret.push_back(obj); continue; } for(auto &sub : subs) { auto sobj = obj->getSubObject(sub.c_str()); if(sobj && objSet.insert(sobj).second) ret.push_back(sobj); } } } return ret; } //////////////////////////////////////////////////////////////////////////////////////// namespace Gui { PROPERTY_SOURCE_TEMPLATE(PartDesignGui::ViewProviderSubShapeBinderPython, PartDesignGui::ViewProviderSubShapeBinder) template class PartDesignGuiExport ViewProviderPythonFeatureT; }