diff --git a/CMakeLists.txt b/CMakeLists.txt index f4dabf7657..5b177362e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,12 @@ if(NOT FREECAD_LIBPACK_USE OR FREECAD_LIBPACK_CHECKFILE_CLBUNDLER) find_package(ZLIB REQUIRED) find_package(PyCXX REQUIRED) SetupOpenCasCade() + if(BUILD_GUI) + # Do this before the check for SMESH because it depends on vtk + # that may have its own OpenGL check but possibly fails and leaves + # OPENGL_gl_LIBRARY empty that results into linker errors + SetupOpenGL() + endif(BUILD_GUI) SetupSalomeSMESH() if (BUILD_FEM_NETGEN) find_package(NETGEN) @@ -64,7 +70,6 @@ if(NOT FREECAD_LIBPACK_USE OR FREECAD_LIBPACK_CHECKFILE_CLBUNDLER) SetupFreetype() if(BUILD_GUI) - SetupOpenGL() SetupCoin3D() SetupSpaceball() SetupShibokenAndPyside() diff --git a/cMake/FreeCAD_Helpers/PrintFinalReport.cmake b/cMake/FreeCAD_Helpers/PrintFinalReport.cmake index 744fdd8ce9..96ea7de919 100644 --- a/cMake/FreeCAD_Helpers/PrintFinalReport.cmake +++ b/cMake/FreeCAD_Helpers/PrintFinalReport.cmake @@ -163,6 +163,7 @@ macro(PrintFinalReport) message(STATUS "Freetype: disabled") endif(FREECAD_USE_FREETYPE) + message(STATUS "OpenGL: ${OPENGL_gl_LIBRARY}") message(STATUS "OpenGLU: ${OPENGL_glu_LIBRARY} [${OPENGL_glu_LIBRARY}][${OPENGL_INCLUDE_DIR}]") message(STATUS "Coin3D: [${COIN3D_LIBRARIES}] [${COIN3D_INCLUDE_DIRS}]") diff --git a/src/Gui/Action.cpp b/src/Gui/Action.cpp index 368b06bce3..f759c4cd04 100644 --- a/src/Gui/Action.cpp +++ b/src/Gui/Action.cpp @@ -531,6 +531,7 @@ void WorkbenchComboBox::onWorkbenchActivated(const QString& name) WorkbenchGroup::WorkbenchGroup ( Command* pcCmd, QObject * parent ) : ActionGroup( pcCmd, parent ) { + // Start a list with 50 elements but extend it when requested for (int i=0; i<50; i++) { QAction* action = _group->addAction(QLatin1String("")); action->setVisible(false); @@ -590,7 +591,7 @@ void WorkbenchGroup::refreshWorkbenchList() QStringList items = Application::Instance->workbenches(); QStringList enabled_wbs_list = DlgWorkbenchesImp::load_enabled_workbenches(); QStringList disabled_wbs_list = DlgWorkbenchesImp::load_disabled_workbenches(); - int i=0; + QStringList enable_wbs; // Go through the list of enabled workbenches and verify that they really exist because // it might be possible that a workbench has been removed after setting up the list of @@ -598,7 +599,7 @@ void WorkbenchGroup::refreshWorkbenchList() for (QStringList::Iterator it = enabled_wbs_list.begin(); it != enabled_wbs_list.end(); ++it) { int index = items.indexOf(*it); if (index >= 0) { - setWorkbenchData(i++, *it); + enable_wbs << *it; items.removeAt(index); } } @@ -613,8 +614,22 @@ void WorkbenchGroup::refreshWorkbenchList() // Now add the remaining workbenches of 'items'. They have been added to the application // after setting up the list of enabled workbenches. - for (QStringList::Iterator it = items.begin(); it != items.end(); ++it) { - setWorkbenchData(i++, *it); + enable_wbs.append(items); + QList workbenches = _group->actions(); + int numActions = workbenches.size(); + int extend = enable_wbs.size() - numActions; + if (extend > 0) { + for (int i=0; iaddAction(QLatin1String("")); + action->setCheckable(true); + action->setData(QVariant(numActions++)); // set the index + } + } + + // Show all enabled wb + int index = 0; + for (QStringList::Iterator it = enable_wbs.begin(); it != enable_wbs.end(); ++it) { + setWorkbenchData(index++, *it); } } @@ -633,21 +648,31 @@ void WorkbenchGroup::slotActivateWorkbench(const char* /*name*/) void WorkbenchGroup::slotAddWorkbench(const char* name) { QList workbenches = _group->actions(); + QAction* action = nullptr; for (QList::Iterator it = workbenches.begin(); it != workbenches.end(); ++it) { if (!(*it)->isVisible()) { - QString wb = QString::fromLatin1(name); - QPixmap px = Application::Instance->workbenchIcon(wb); - QString text = Application::Instance->workbenchMenuText(wb); - QString tip = Application::Instance->workbenchToolTip(wb); - (*it)->setIcon(px); - (*it)->setObjectName(wb); - (*it)->setText(text); - (*it)->setToolTip(tip); - (*it)->setStatusTip(tr("Select the '%1' workbench").arg(wb)); - (*it)->setVisible(true); // do this at last + action = *it; break; } } + + if (!action) { + int index = workbenches.size(); + action = _group->addAction(QLatin1String("")); + action->setCheckable(true); + action->setData(QVariant(index)); // set the index + } + + QString wb = QString::fromLatin1(name); + QPixmap px = Application::Instance->workbenchIcon(wb); + QString text = Application::Instance->workbenchMenuText(wb); + QString tip = Application::Instance->workbenchToolTip(wb); + action->setIcon(px); + action->setObjectName(wb); + action->setText(text); + action->setToolTip(tip); + action->setStatusTip(tr("Select the '%1' workbench").arg(wb)); + action->setVisible(true); // do this at last } void WorkbenchGroup::slotRemoveWorkbench(const char* name) diff --git a/src/Mod/Arch/ArchRoof.py b/src/Mod/Arch/ArchRoof.py index cb81df88a5..3a422a513c 100644 --- a/src/Mod/Arch/ArchRoof.py +++ b/src/Mod/Arch/ArchRoof.py @@ -438,8 +438,9 @@ class _Roof(ArchComponent.Component): rel = profilCurr["idrel"] if i != rel and 0 <= rel < numEdges: profilRel = self.profilsDico[rel] - # do not use data from the relative profile if it in turn references a relative profile: - if 0 <= profilRel["idrel"] < numEdges: + # do not use data from the relative profile if it in turn references a relative profile + # other than itself: + if 0 <= profilRel["idrel"] < numEdges and rel != profilRel["idrel"]: hgt = self.calcHeight(i) profilCurr["height"] = hgt elif ang == 0.0 and run == 0.0: diff --git a/src/Mod/Fem/App/FemMesh.cpp b/src/Mod/Fem/App/FemMesh.cpp index 24e847d7b7..13ea8419dd 100644 --- a/src/Mod/Fem/App/FemMesh.cpp +++ b/src/Mod/Fem/App/FemMesh.cpp @@ -629,19 +629,64 @@ std::set FemMesh::getSurfaceNodes(long /*ElemId*/, short /*FaceId*/, float */ std::list > FemMesh::getVolumesByFace(const TopoDS_Face &face) const { - //TODO: This function is broken with SMESH7 as it is impossible to iterate volume faces std::list > result; std::set nodes_on_face = getNodesByFace(face); +#if SMESH_VERSION_MAJOR >= 7 + // SMDS_MeshVolume::facesIterator() is broken with SMESH7 as it is impossible to iterate volume faces + // In SMESH9 this function has been removed + // + std::map< int, std::set > face_nodes; + + // get faces that contribute to 'nodes_on_face' with all of its nodes + SMDS_FaceIteratorPtr face_iter = myMesh->GetMeshDS()->facesIterator(); + while (face_iter && face_iter->more()) { + const SMDS_MeshFace* face = face_iter->next(); + SMDS_NodeIteratorPtr node_iter = face->nodeIterator(); + + // all nodes of the current face must be part of 'nodes_on_face' + std::set node_ids; + while (node_iter && node_iter->more()) { + const SMDS_MeshNode* node = node_iter->next(); + node_ids.insert(node->GetID()); + } + + std::vector element_face_nodes; + std::set_intersection(nodes_on_face.begin(), nodes_on_face.end(), node_ids.begin(), node_ids.end(), + std::back_insert_iterator >(element_face_nodes)); + + if (element_face_nodes.size() == node_ids.size()) { + face_nodes[face->GetID()] = node_ids; + } + } + + // get all nodes of a volume and check which faces contribute to it with all of its nodes SMDS_VolumeIteratorPtr vol_iter = myMesh->GetMeshDS()->volumesIterator(); while (vol_iter->more()) { const SMDS_MeshVolume* vol = vol_iter->next(); -#if SMESH_VERSION_MAJOR >= 9 - throw Base::NotImplementedError("Port FemMesh::getVolumesByFace to smesh >= 9.x"); - SMDS_ElemIteratorPtr face_iter = nullptr; //TODO: + SMDS_NodeIteratorPtr node_iter = vol->nodeIterator(); + std::set node_ids; + while (node_iter && node_iter->more()) { + const SMDS_MeshNode* node = node_iter->next(); + node_ids.insert(node->GetID()); + } + + for (const auto& it : face_nodes) { + std::vector element_face_nodes; + std::set_intersection(node_ids.begin(), node_ids.end(), it.second.begin(), it.second.end(), + std::back_insert_iterator >(element_face_nodes)); + + // For curved faces it is possible that a volume contributes more than one face + if (element_face_nodes.size() == it.second.size()) { + result.emplace_back(vol->GetID(), it.first); + } + } + } #else + SMDS_VolumeIteratorPtr vol_iter = myMesh->GetMeshDS()->volumesIterator(); + while (vol_iter->more()) { + const SMDS_MeshVolume* vol = vol_iter->next(); SMDS_ElemIteratorPtr face_iter = vol->facesIterator(); -#endif while (face_iter && face_iter->more()) { const SMDS_MeshFace* face = static_cast(face_iter->next()); @@ -662,6 +707,7 @@ std::list > FemMesh::getVolumesByFace(const TopoDS_Face &fac } } } +#endif result.sort(); return result; diff --git a/src/Mod/OpenSCAD/Resources/icons/OpenSCAD_MirrorMeshFeature.svg b/src/Mod/OpenSCAD/Resources/icons/OpenSCAD_MirrorMeshFeature.svg index 7ac85058af..0375c8227b 100644 --- a/src/Mod/OpenSCAD/Resources/icons/OpenSCAD_MirrorMeshFeature.svg +++ b/src/Mod/OpenSCAD/Resources/icons/OpenSCAD_MirrorMeshFeature.svg @@ -1,6 +1,4 @@ - - + width="64px" + height="64px" + id="svg3364" + version="1.1"> + OpenSCAD_MirrorMeshFeature + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id="metadata3369"> image/svg+xml - + OpenSCAD_MirrorMeshFeature + + + [bitacovir] + + + Part_Mirror + 2021/01/05 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + Work based on a design made by [agryson] Alexander Gryson + + - - - + + + + + + + + + + + + + + + + + diff --git a/src/Mod/OpenSCAD/Resources/icons/OpenSCAD_ScaleMeshFeature.svg b/src/Mod/OpenSCAD/Resources/icons/OpenSCAD_ScaleMeshFeature.svg index 7f2f535826..e16fcb38ec 100644 --- a/src/Mod/OpenSCAD/Resources/icons/OpenSCAD_ScaleMeshFeature.svg +++ b/src/Mod/OpenSCAD/Resources/icons/OpenSCAD_ScaleMeshFeature.svg @@ -1,6 +1,4 @@ - - + id="svg2766" + height="64px" + width="64px"> + OpenSCAD_ScaleMeshFeature - + id="defs2768"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id="metadata5370"> image/svg+xml - + OpenSCAD_ScaleMeshFeature + + 12-01-2021 + + + [bitacovir] + + + + + FreeCAD LGPL2+ + + + + + FreeCAD + + + + + + + Based on a wmayer's design + + + + + green square + arrow + dotted line + + + + + - + id="g954" + transform="matrix(0.53865293,-0.53865293,0.53865293,0.53865293,-32.932436,50.082417)"> + + + + + + + + + + diff --git a/src/Mod/PartDesign/Gui/CommandBody.cpp b/src/Mod/PartDesign/Gui/CommandBody.cpp index e2ec2313de..f3efffb205 100644 --- a/src/Mod/PartDesign/Gui/CommandBody.cpp +++ b/src/Mod/PartDesign/Gui/CommandBody.cpp @@ -316,6 +316,7 @@ CmdPartDesignMigrate::CmdPartDesignMigrate() sToolTipText = QT_TR_NOOP("Migrate document to the modern PartDesign workflow"); sWhatsThis = "PartDesign_Migrate"; sStatusTip = sToolTipText; + sPixmap = "PartDesign_Migrate"; } void CmdPartDesignMigrate::activated(int iMsg) @@ -665,7 +666,7 @@ CmdPartDesignMoveFeature::CmdPartDesignMoveFeature() sToolTipText = QT_TR_NOOP("Moves the selected object to another body"); sWhatsThis = "PartDesign_MoveFeature"; sStatusTip = sToolTipText; - sPixmap = ""; + sPixmap = "PartDesign_MoveFeature"; } void CmdPartDesignMoveFeature::activated(int iMsg) @@ -827,7 +828,7 @@ CmdPartDesignMoveFeatureInTree::CmdPartDesignMoveFeatureInTree() sToolTipText = QT_TR_NOOP("Moves the selected object and insert it after another object"); sWhatsThis = "PartDesign_MoveFeatureInTree"; sStatusTip = sToolTipText; - sPixmap = ""; + sPixmap = "PartDesign_MoveFeatureInTree"; } void CmdPartDesignMoveFeatureInTree::activated(int iMsg) diff --git a/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc b/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc index e938ccfa43..729a9c3b9a 100644 --- a/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc +++ b/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc @@ -28,7 +28,10 @@ icons/PartDesign_InvoluteGear.svg icons/PartDesign_Line.svg icons/PartDesign_LinearPattern.svg + icons/PartDesign_Migrate.svg icons/PartDesign_Mirrored.svg + icons/PartDesign_MoveFeature.svg + icons/PartDesign_MoveFeatureInTree.svg icons/PartDesign_MoveTip.svg icons/PartDesign_MultiTransform.svg icons/PartDesign_Pad.svg diff --git a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Migrate.svg b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Migrate.svg new file mode 100644 index 0000000000..1af7b19cda --- /dev/null +++ b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Migrate.svg @@ -0,0 +1,758 @@ + + + PartDesign_Migrate + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + PartDesign_Migrate + 12-01-2021 + + + [bitacovir] + + + + + + + + + + + + + + FreeCAD LGPL2+ + + + + + FreeCAD + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_MoveFeature.svg b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_MoveFeature.svg new file mode 100644 index 0000000000..7f116953c2 --- /dev/null +++ b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_MoveFeature.svg @@ -0,0 +1,551 @@ + + + PartDesign_MoveFeature + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + PartDesign_MoveFeature + 12-01-2021 + + + [bitacovir] + + + + + FreeCAD LGPL2+ + + + + + FreeCAD + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_MoveFeatureInTree.svg b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_MoveFeatureInTree.svg new file mode 100644 index 0000000000..bf19bb2bd5 --- /dev/null +++ b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_MoveFeatureInTree.svg @@ -0,0 +1,524 @@ + + + PartDesign_MoveFeatureInTree + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + PartDesign_MoveFeatureInTree + + + [bitacovir] + + + OpenSCAD_RemoveSubtree + 12-01-2021 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Path/Gui/Resources/panels/PathEdit.ui b/src/Mod/Path/Gui/Resources/panels/PathEdit.ui index d71044c96f..44d768ff13 100644 --- a/src/Mod/Path/Gui/Resources/panels/PathEdit.ui +++ b/src/Mod/Path/Gui/Resources/panels/PathEdit.ui @@ -31,8 +31,8 @@ 0 0 - 549 - 628 + 146 + 378 @@ -112,8 +112,8 @@ 0 0 - 98 - 28 + 96 + 26 @@ -281,7 +281,7 @@ G54 - Checked + Unchecked @@ -431,8 +431,8 @@ 0 0 - 536 - 1291 + 545 + 896 @@ -1002,8 +1002,8 @@ 0 0 - 419 - 548 + 213 + 321 @@ -1096,7 +1096,7 @@ - + <html><head/><body><p>ClearanceHeightOffset - can be used by expressions to set the default ClearanceHeight for new operations.</p><p><br/></p><p>Default: &quot;3 mm&quot;</p></body></html> @@ -1123,7 +1123,7 @@ - + <html><head/><body><p>SafeHeightOffset can be for expressions to set the SafeHeight for new operations.</p><p><br/></p><p>Default: &quot;5 mm&quot;</p></body></html> @@ -1185,8 +1185,8 @@ 0 0 - 549 - 628 + 317 + 173 @@ -1285,8 +1285,8 @@ 0 0 - 208 - 160 + 138 + 112 @@ -1310,7 +1310,7 @@ - + 0 @@ -1330,7 +1330,7 @@ - + 0 diff --git a/src/Mod/Path/PathScripts/PathJob.py b/src/Mod/Path/PathScripts/PathJob.py index a6c027b722..8ddf574c13 100644 --- a/src/Mod/Path/PathScripts/PathJob.py +++ b/src/Mod/Path/PathScripts/PathJob.py @@ -56,6 +56,9 @@ class JobTemplate: PostProcessor = 'Post' PostProcessorArgs = 'PostArgs' PostProcessorOutputFile = 'Output' + Fixtures = 'Fixtures' + OrderOutputBy = 'OrderOutputBy' + SplitOutput = 'SplitOutput' SetupSheet = 'SetupSheet' Stock = 'Stock' # TCs are grouped under Tools in a job, the template refers to them directly though @@ -121,7 +124,6 @@ class ObjectJob: obj.addProperty("App::PropertyLink", "Stock", "Base", QtCore.QT_TRANSLATE_NOOP("PathJob", "Solid object to be used as stock.")) obj.addProperty("App::PropertyLink", "Operations", "Base", QtCore.QT_TRANSLATE_NOOP("PathJob", "Compound path of all operations in the order they are processed.")) - #obj.addProperty("App::PropertyLinkList", "ToolController", "Base", QtCore.QT_TRANSLATE_NOOP("PathJob", "Collection of tool controllers available for this job.")) obj.addProperty("App::PropertyBool", "SplitOutput", "Output", QtCore.QT_TRANSLATE_NOOP("PathJob", "Split output into multiple gcode files")) obj.addProperty("App::PropertyEnumeration", "OrderOutputBy", "WCS", QtCore.QT_TRANSLATE_NOOP("PathJob", "If multiple WCS, order the output this way")) @@ -350,6 +352,15 @@ class ObjectJob: if attrs.get(JobTemplate.Stock): obj.Stock = PathStock.CreateFromTemplate(obj, attrs.get(JobTemplate.Stock)) + if attrs.get(JobTemplate.Fixtures): + obj.Fixtures = [x for y in attrs.get(JobTemplate.Fixtures) for x in y] + + if attrs.get(JobTemplate.OrderOutputBy): + obj.OrderOutputBy = attrs.get(JobTemplate.OrderOutputBy) + + if attrs.get(JobTemplate.SplitOutput): + obj.SplitOutput = attrs.get(JobTemplate.SplitOutput) + PathLog.debug("setting tool controllers (%d)" % len(tcs)) obj.Tools.Group = tcs else: @@ -364,6 +375,9 @@ class ObjectJob: if obj.PostProcessor: attrs[JobTemplate.PostProcessor] = obj.PostProcessor attrs[JobTemplate.PostProcessorArgs] = obj.PostProcessorArgs + attrs[JobTemplate.Fixtures] = [{f: True} for f in obj.Fixtures] + attrs[JobTemplate.OrderOutputBy] = obj.OrderOutputBy + attrs[JobTemplate.SplitOutput] = obj.SplitOutput if obj.PostProcessorOutputFile: attrs[JobTemplate.PostProcessorOutputFile] = obj.PostProcessorOutputFile attrs[JobTemplate.GeometryTolerance] = str(obj.GeometryTolerance.Value) diff --git a/src/Mod/Path/PathScripts/PathSetupSheet.py b/src/Mod/Path/PathScripts/PathSetupSheet.py index 87203d6a95..9cdfb0596c 100644 --- a/src/Mod/Path/PathScripts/PathSetupSheet.py +++ b/src/Mod/Path/PathScripts/PathSetupSheet.py @@ -34,7 +34,7 @@ __doc__ = "A container for all default values and job specific configuration val _RegisteredOps = {} -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) +PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) # PathLog.trackModule(PathLog.thisModule()) @@ -55,11 +55,15 @@ class Template: StartDepthExpression = 'StartDepthExpression' FinalDepthExpression = 'FinalDepthExpression' StepDownExpression = 'StepDownExpression' + Fixtures = 'Fixtures' + OrderOutputBy = 'OrderOutputBy' + SplitOutput = 'SplitOutput' All = [HorizRapid, VertRapid, CoolantMode, SafeHeightOffset, SafeHeightExpression, ClearanceHeightOffset, ClearanceHeightExpression, StartDepthExpression, FinalDepthExpression, StepDownExpression] def _traverseTemplateAttributes(attrs, codec): + PathLog.debug(attrs) coded = {} for key, value in PathUtil.keyValueIter(attrs): if type(value) == dict: diff --git a/src/Mod/Path/PathScripts/PathSetupSheetGui.py b/src/Mod/Path/PathScripts/PathSetupSheetGui.py index 7b06816ed7..d2ceb3956b 100644 --- a/src/Mod/Path/PathScripts/PathSetupSheetGui.py +++ b/src/Mod/Path/PathScripts/PathSetupSheetGui.py @@ -26,7 +26,6 @@ import PathScripts.PathGui as PathGui import PathScripts.PathIconViewProvider as PathIconViewProvider import PathScripts.PathLog as PathLog import PathScripts.PathSetupSheet as PathSetupSheet -# import PathScripts.PathSetupSheetOpPrototype as PathSetupSheetOpPrototype import PathScripts.PathSetupSheetOpPrototypeGui as PathSetupSheetOpPrototypeGui import PathScripts.PathUtil as PathUtil @@ -37,18 +36,22 @@ __author__ = "sliptonic (Brad Collette)" __url__ = "https://www.freecadweb.org" __doc__ = "Task panel editor for a SetupSheet" + # Qt translation handling def translate(context, text, disambig=None): return QtCore.QCoreApplication.translate(context, text, disambig) + LOGLEVEL = False + if LOGLEVEL: PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) PathLog.trackModule(PathLog.thisModule()) else: PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) + class ViewProvider: '''ViewProvider for a SetupSheet. It's sole job is to provide an icon and invoke the TaskPanel on edit.''' @@ -100,14 +103,11 @@ class ViewProvider: def doubleClicked(self, vobj): self.setEdit(vobj) + class Delegate(QtGui.QStyledItemDelegate): PropertyRole = QtCore.Qt.UserRole + 1 EditorRole = QtCore.Qt.UserRole + 2 - - #def paint(self, painter, option, index): - # #PathLog.track(index.column(), type(option)) - def createEditor(self, parent, option, index): # pylint: disable=unused-argument if index.data(self.EditorRole) is None: @@ -130,6 +130,7 @@ class Delegate(QtGui.QStyledItemDelegate): # pylint: disable=unused-argument widget.setGeometry(option.rect) + class OpTaskPanel: '''Editor for an operation's property default values. The implementation is a simplified generic property editor with basically 3 fields @@ -168,16 +169,16 @@ class OpTaskPanel: self.model = QtGui.QStandardItemModel(len(self.props), 3, self.form) self.model.setHorizontalHeaderLabels(['Set', 'Property', 'Value']) - for i,name in enumerate(self.props): + for i, name in enumerate(self.props): prop = self.prototype.getProperty(name) isset = hasattr(self.obj, self.propertyName(name)) if isset: prop.setValue(getattr(self.obj, self.propertyName(name))) self.model.setData(self.model.index(i, 0), isset, QtCore.Qt.EditRole) - self.model.setData(self.model.index(i, 1), name, QtCore.Qt.EditRole) - self.model.setData(self.model.index(i, 2), prop, Delegate.PropertyRole) - self.model.setData(self.model.index(i, 2), prop.displayString(), QtCore.Qt.DisplayRole) + self.model.setData(self.model.index(i, 1), name, QtCore.Qt.EditRole) + self.model.setData(self.model.index(i, 2), prop, Delegate.PropertyRole) + self.model.setData(self.model.index(i, 2), prop.displayString(), QtCore.Qt.DisplayRole) self.model.item(i, 0).setCheckable(True) self.model.item(i, 0).setText('') @@ -206,7 +207,7 @@ class OpTaskPanel: def accept(self): propertiesCreatedRemoved = False - for i,name in enumerate(self.props): + for i, name in enumerate(self.props): prop = self.prototype.getProperty(name) propName = self.propertyName(name) enabled = self.model.item(i, 0).checkState() == QtCore.Qt.Checked @@ -229,7 +230,7 @@ class OpsDefaultEditor: def __init__(self, obj, form): self.form = form self.obj = obj - self.ops = sorted([OpTaskPanel(self.obj, name, op) for name, op in PathUtil.keyValueIter(PathSetupSheet._RegisteredOps)], key = lambda op: op.name) # pylint: disable=protected-access + self.ops = sorted([OpTaskPanel(self.obj, name, op) for name, op in PathUtil.keyValueIter(PathSetupSheet._RegisteredOps)], key=lambda op: op.name) if form: parent = form.tabOpDefaults for op in self.ops: @@ -245,10 +246,6 @@ class OpsDefaultEditor: def accept(self): if any([op.accept() for op in self.ops]): PathLog.track() - #sel = FreeCADGui.Selection.getSelection() - #FreeCADGui.Selection.clearSelection() - #for o in sel: - # FreeCADGui.Selection.addSelection(o) def getFields(self): pass @@ -264,7 +261,7 @@ class OpsDefaultEditor: self.currentOp = self.form.opDefaultOp.itemData(current) self.currentOp.form.show() - def updateModel(self, recomp = True): + def updateModel(self, recomp=True): PathLog.track() self.getFields() self.updateUI() @@ -281,6 +278,7 @@ class OpsDefaultEditor: if self.form: self.form.opDefaultOp.currentIndexChanged.connect(self.updateUI) + class GlobalEditor(object): '''Editor for the global properties which affect almost every operation.''' @@ -293,7 +291,6 @@ class GlobalEditor(object): self.safeHeightOffs = None self.rapidHorizontal = None self.rapidVertical = None - #self.coolantMode = None def reject(self): pass @@ -308,16 +305,15 @@ class GlobalEditor(object): if val != value: PathUtil.setProperty(self.obj, name, value) - updateExpression('StartDepthExpression', self.form.setupStartDepthExpr) - updateExpression('FinalDepthExpression', self.form.setupFinalDepthExpr) - updateExpression('StepDownExpression', self.form.setupStepDownExpr) - updateExpression('ClearanceHeightExpression', self.form.setupClearanceHeightExpr) - updateExpression('SafeHeightExpression', self.form.setupSafeHeightExpr) + updateExpression('StartDepthExpression', self.form.setupStartDepthExpr) + updateExpression('FinalDepthExpression', self.form.setupFinalDepthExpr) + updateExpression('StepDownExpression', self.form.setupStepDownExpr) + updateExpression('ClearanceHeightExpression', self.form.setupClearanceHeightExpr) + updateExpression('SafeHeightExpression', self.form.setupSafeHeightExpr) self.clearanceHeightOffs.updateProperty() self.safeHeightOffs.updateProperty() self.rapidVertical.updateProperty() self.rapidHorizontal.updateProperty() - #self.coolantMode.updateProperty() self.obj.CoolantMode = self.form.setupCoolantMode.currentText() def selectInComboBox(self, name, combo): @@ -330,18 +326,18 @@ class GlobalEditor(object): def updateUI(self): PathLog.track() - self.form.setupStartDepthExpr.setText( self.obj.StartDepthExpression) - self.form.setupFinalDepthExpr.setText( self.obj.FinalDepthExpression) - self.form.setupStepDownExpr.setText( self.obj.StepDownExpression) - self.form.setupClearanceHeightExpr.setText( self.obj.ClearanceHeightExpression) - self.form.setupSafeHeightExpr.setText( self.obj.SafeHeightExpression) + self.form.setupStartDepthExpr.setText(self.obj.StartDepthExpression) + self.form.setupFinalDepthExpr.setText(self.obj.FinalDepthExpression) + self.form.setupStepDownExpr.setText(self.obj.StepDownExpression) + self.form.setupClearanceHeightExpr.setText(self.obj.ClearanceHeightExpression) + self.form.setupSafeHeightExpr.setText(self.obj.SafeHeightExpression) self.clearanceHeightOffs.updateSpinBox() self.safeHeightOffs.updateSpinBox() self.rapidVertical.updateSpinBox() self.rapidHorizontal.updateSpinBox() self.selectInComboBox(self.obj.CoolantMode, self.form.setupCoolantMode) - def updateModel(self, recomp = True): + def updateModel(self, recomp=True): PathLog.track() self.getFields() self.updateUI() @@ -359,6 +355,7 @@ class GlobalEditor(object): self.form.setupCoolantMode.addItems(self.obj.CoolantModes) self.setFields() + class TaskPanel: '''TaskPanel for the SetupSheet - if it is being edited directly.''' @@ -387,8 +384,6 @@ class TaskPanel: FreeCADGui.ActiveDocument.resetEdit() FreeCADGui.Control.closeDialog() FreeCAD.ActiveDocument.recompute() - #FreeCADGui.Selection.removeObserver(self.s) - #FreeCAD.ActiveDocument.recompute() def getFields(self): self.globalEditor.getFields() @@ -411,11 +406,13 @@ class TaskPanel: self.globalEditor.setupUi() self.opsEditor.setupUi() -def Create(name = 'SetupSheet'): - '''Create(name = 'SetupSheet') ... creates a new setup sheet''' + +def Create(name='SetupSheet'): + '''Create(name='SetupSheet') ... creates a new setup sheet''' FreeCAD.ActiveDocument.openTransaction(translate("Path_Job", "Create Job")) ssheet = PathSetupSheet.Create(name) PathIconViewProvider.Attach(ssheet, name) return ssheet + PathIconViewProvider.RegisterViewProvider('SetupSheet', ViewProvider) diff --git a/src/Mod/TechDraw/App/DrawViewDimension.cpp b/src/Mod/TechDraw/App/DrawViewDimension.cpp index 2d1ca70dfa..f848373005 100644 --- a/src/Mod/TechDraw/App/DrawViewDimension.cpp +++ b/src/Mod/TechDraw/App/DrawViewDimension.cpp @@ -647,11 +647,11 @@ bool DrawViewDimension::isMultiValueSchema(void) const } Base::UnitSystem uniSys = Base::UnitsApi::getSchema(); - if ( (uniSys == Base::UnitSystem::ImperialBuilding) && - !angularMeasure ) { + if ((uniSys == Base::UnitSystem::ImperialBuilding) && + !angularMeasure) { result = true; } else if ((uniSys == Base::UnitSystem::ImperialCivil) && - angularMeasure) { + !angularMeasure) { result = true; } return result; @@ -736,6 +736,13 @@ std::string DrawViewDimension::formatValue(qreal value, QString qFormatSpec, int qMultiValueStr = formatPrefix + qGenPrefix + displaySub + formatSuffix; } formattedValue = qMultiValueStr; + } else if (isMultiValueSchema()) { + qMultiValueStr = qUserString; + if (!genPrefix.empty()) { + //qUserString from Quantity includes units - prefix + R + nnn ft + suffix + qMultiValueStr = formatPrefix + qUserString + formatSuffix; + } + return qMultiValueStr.toStdString(); } else { if (formatSpecifier.isEmpty()) { Base::Console().Warning("Warning - no numeric format in Format Spec %s - %s\n", @@ -810,16 +817,6 @@ std::string DrawViewDimension::formatValue(qreal value, QString qFormatSpec, int } } - if ((unitSystem == Base::UnitSystem::ImperialBuilding) && - !angularMeasure) { - qMultiValueStr = formattedValue; - if (!genPrefix.empty()) { - //qUserString from Quantity includes units - prefix + R + nnn ft + suffix - qMultiValueStr = formatPrefix + qGenPrefix + qUserString + formatSuffix; - } - formattedValue = qMultiValueStr; - } - result = formattedValue.toStdString(); if (partial == 0) { diff --git a/src/Mod/TechDraw/Gui/MDIViewPage.cpp b/src/Mod/TechDraw/Gui/MDIViewPage.cpp index 771814912d..324134ed78 100644 --- a/src/Mod/TechDraw/Gui/MDIViewPage.cpp +++ b/src/Mod/TechDraw/Gui/MDIViewPage.cpp @@ -312,10 +312,14 @@ void MDIViewPage::closeEvent(QCloseEvent* ev) void MDIViewPage::attachTemplate(TechDraw::DrawTemplate *obj) { m_view->setPageTemplate(obj); - double width = obj->Width.getValue(); - double height = obj->Height.getValue(); - m_paperSize = getPaperSize(int(round(width)),int(round(height))); - if (width > height) { + pagewidth = obj->Width.getValue(); + pageheight = obj->Height.getValue(); +#if QT_VERSION >= 0x050300 + m_paperSize = QPageSize::id(QSizeF(pagewidth, pageheight), QPageSize::Millimeter, QPageSize::FuzzyOrientationMatch); +#else + m_paperSize = getPaperSize(int(round(pagewidth)), int(round(pageheight))); +#endif + if (pagewidth > pageheight) { #if QT_VERSION >= 0x050300 m_orientation = QPageLayout::Landscape; #else @@ -496,17 +500,6 @@ void MDIViewPage::fixOrphans(bool force) } } } - - // Update all the QGIVxxxx - // WF: why do we do this? views should be keeping themselves up to date. -// const std::vector &upviews = m_view->getViews(); -// for(std::vector::const_iterator it = upviews.begin(); it != upviews.end(); ++it) { -// Base::Console().Message("TRACE - MDIVP::fixOrphans - updating a QGIVxxxx\n"); -// if((*it)->getViewObject()->isTouched() || -// forceUpdate) { -// (*it)->updateView(forceUpdate); -// } -// } } //NOTE: this doesn't add missing views. see fixOrphans() @@ -530,6 +523,7 @@ void MDIViewPage::redraw1View(TechDraw::DrawView* dv) } } } + void MDIViewPage::findMissingViews(const std::vector &list, std::vector &missing) { for(std::vector::const_iterator it = list.begin(); it != list.end(); ++it) { @@ -692,7 +686,11 @@ void MDIViewPage::printPdf(std::string file) #endif } #if QT_VERSION >= 0x050300 - printer.setPageSize(QPageSize(m_paperSize)); + if (m_paperSize == QPageSize::Custom) { + printer.setPageSize(QPageSize(QSizeF(pagewidth, pageheight), QPageSize::Millimeter)); + } else { + printer.setPageSize(QPageSize(m_paperSize)); + } #else printer.setPaperSize(m_paperSize); #endif @@ -704,7 +702,11 @@ void MDIViewPage::print() QPrinter printer(QPrinter::HighResolution); printer.setFullPage(true); #if QT_VERSION >= 0x050300 - printer.setPageSize(QPageSize(m_paperSize)); + if (m_paperSize == QPageSize::Custom) { + printer.setPageSize(QPageSize(QSizeF(pagewidth, pageheight), QPageSize::Millimeter)); + } else { + printer.setPageSize(QPageSize(m_paperSize)); + } printer.setPageOrientation(m_orientation); #else printer.setPaperSize(m_paperSize); @@ -721,7 +723,11 @@ void MDIViewPage::printPreview() QPrinter printer(QPrinter::HighResolution); printer.setFullPage(true); #if QT_VERSION >= 0x050300 - printer.setPageSize(QPageSize(m_paperSize)); + if (m_paperSize == QPageSize::Custom) { + printer.setPageSize(QPageSize(QSizeF(pagewidth, pageheight), QPageSize::Millimeter)); + } else { + printer.setPageSize(QPageSize(m_paperSize)); + } printer.setPageOrientation(m_orientation); #else printer.setPaperSize(m_paperSize); @@ -750,13 +756,9 @@ void MDIViewPage::print(QPrinter* printer) // a certain scaling effect can be observed and the content becomes smaller. QPaintEngine::Type paintType = printer->paintEngine()->type(); if (printer->outputFormat() == QPrinter::NativeFormat) { - int w = printer->widthMM(); - int h = printer->heightMM(); #if QT_VERSION >= 0x050300 - QPageSize::PageSizeId psPrtCalcd = getPaperSize(w, h); QPageSize::PageSizeId psPrtSetting = printer->pageLayout().pageSize().id(); #else - QPrinter::PaperSize psPrtCalcd = getPaperSize(w, h); QPrinter::PaperSize psPrtSetting = printer->paperSize(); #endif @@ -776,15 +778,7 @@ void MDIViewPage::print(QPrinter* printer) if (ret != QMessageBox::Yes) return; } - else if (doPrint && psPrtCalcd != m_paperSize) { - int ret = QMessageBox::warning(this, tr("Different paper size"), - tr("The printer uses a different paper size than the drawing.\n" - "Do you want to continue?"), - QMessageBox::Yes | QMessageBox::No); - if (ret != QMessageBox::Yes) - return; - } - else if (doPrint && psPrtSetting != m_paperSize) { + if (doPrint && psPrtSetting != m_paperSize) { int ret = QMessageBox::warning(this, tr("Different paper size"), tr("The printer uses a different paper size than the drawing.\n" "Do you want to continue?"), @@ -850,11 +844,8 @@ void MDIViewPage::print(QPrinter* printer) static_cast (blockConnection(false)); } -#if QT_VERSION >= 0x050300 -QPageSize::PageSizeId MDIViewPage::getPaperSize(int w, int h) const -#else +#if QT_VERSION < 0x050300 QPrinter::PaperSize MDIViewPage::getPaperSize(int w, int h) const -#endif { static const float paperSizes[][2] = { {210, 297}, // A4 @@ -889,49 +880,29 @@ QPrinter::PaperSize MDIViewPage::getPaperSize(int w, int h) const {279.4f, 431.8f} // Tabloid (29) causes trouble with orientation on PDF export }; -#if QT_VERSION >= 0x050300 - QPageSize::PageSizeId ps = QPageSize::Custom; -#else QPrinter::PaperSize ps = QPrinter::Custom; -#endif for (int i=0; i<30; i++) { if (std::abs(paperSizes[i][0]-w) <= 1 && std::abs(paperSizes[i][1]-h) <= 1) { -#if QT_VERSION >= 0x050300 - ps = static_cast(i); -#else ps = static_cast(i); -#endif break; } else //handle landscape & portrait w/h if (std::abs(paperSizes[i][0]-h) <= 1 && std::abs(paperSizes[i][1]-w) <= 1) { -#if QT_VERSION >= 0x050300 - ps = static_cast(i); -#else ps = static_cast(i); -#endif break; } } -#if QT_VERSION >= 0x050300 - if (ps == QPageSize::Ledger) { //check if really Tabloid - if (w < 431) { - ps = QPageSize::Tabloid; - } - } -#else if (ps == QPrinter::Ledger) { //check if really Tabloid if (w < 431) { ps = QPrinter::Tabloid; } } -#endif - return ps; } +#endif PyObject* MDIViewPage::getPyObject() { diff --git a/src/Mod/TechDraw/Gui/MDIViewPage.h b/src/Mod/TechDraw/Gui/MDIViewPage.h index 9cf6864b05..1cd011562d 100644 --- a/src/Mod/TechDraw/Gui/MDIViewPage.h +++ b/src/Mod/TechDraw/Gui/MDIViewPage.h @@ -128,9 +128,7 @@ protected: void contextMenuEvent(QContextMenuEvent *event); void closeEvent(QCloseEvent*); -#if QT_VERSION >= 0x050300 - QPageSize::PageSizeId getPaperSize(int w, int h) const; -#else +#if QT_VERSION < 0x050300 QPrinter::PaperSize getPaperSize(int w, int h) const; #endif @@ -171,6 +169,7 @@ private: QPrinter::Orientation m_orientation; QPrinter::PaperSize m_paperSize; #endif + qreal pagewidth, pageheight; ViewProviderPage *m_vpPage; QList m_qgSceneSelected; //items in selection order