From b4ee9b62aed37a9a8128b394ddd11f880bb3a335 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Mon, 16 May 2022 09:34:14 +0200 Subject: [PATCH 01/13] Arch: Fixed default component type for new windows --- src/Mod/Arch/ArchWindow.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index 56799c8db9..21cd99c3c5 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -96,7 +96,11 @@ def makeWindow(baseobj=None,width=None,height=None,parts=None,name=None): else: if baseobj: if baseobj.getLinkedObject().isDerivedFrom("Part::Part2DObject"): + # create default component if baseobj.Shape.Wires: + tp = "Frame" + if len(baseobj.Shape.Wires) == 1: + tp = "Panel" i = 0 ws = '' for w in baseobj.Shape.Wires: @@ -104,7 +108,7 @@ def makeWindow(baseobj=None,width=None,height=None,parts=None,name=None): if ws: ws += "," ws += "Wire" + str(i) i += 1 - obj.WindowParts = ["Default","Frame",ws,"1","0"] + obj.WindowParts = ["Default",tp,ws,"1","0"] else: # bind properties from base obj if existing for prop in ["Height","Width","Subvolume","Tag","Description","Material"]: From 4107b007812897f31907cdacbccb712f2fd690d9 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 16 May 2022 10:18:42 +0200 Subject: [PATCH 02/13] Sketch: fixes #6890: Problem with Grid size preference --- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index ea079e60ee..8900cecc78 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -134,7 +134,7 @@ void ViewProviderSketch::ParameterObserver::updateGridSize(const std::string & s ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General"); - Client.GridSize.setValue(Base::Quantity::parse(QString::fromLatin1(hGrp->GetGroup("GridSize")->GetASCII("Hist0", "10.0").c_str())).getValue()); + Client.GridSize.setValue(Base::Quantity::parse(QString::fromLatin1(hGrp->GetGroup("GridSize")->GetASCII("GridSize", "10.0").c_str())).getValue()); } void ViewProviderSketch::ParameterObserver::updateEscapeKeyBehaviour(const std::string & string, App::Property * property) From c72d865b6e6532cef84751313cb66d587878d7b7 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Mon, 16 May 2022 10:42:09 +0200 Subject: [PATCH 03/13] Arch: Fixed mistake in last commit --- src/Mod/Arch/ArchWindow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index 21cd99c3c5..4f8a840116 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -100,7 +100,7 @@ def makeWindow(baseobj=None,width=None,height=None,parts=None,name=None): if baseobj.Shape.Wires: tp = "Frame" if len(baseobj.Shape.Wires) == 1: - tp = "Panel" + tp = "Solid Panel" i = 0 ws = '' for w in baseobj.Shape.Wires: From a506827d39bb7d024211073502cfe1d60e451a75 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Mon, 16 May 2022 08:56:52 +0800 Subject: [PATCH 04/13] App: Fix Origin::extensionGetSubObject() --- src/App/Origin.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/App/Origin.cpp b/src/App/Origin.cpp index 4db67ca653..2d98938eb1 100644 --- a/src/App/Origin.cpp +++ b/src/App/Origin.cpp @@ -219,7 +219,12 @@ bool Origin::OriginExtension::extensionGetSubObject(DocumentObject *&ret, const ret = obj->getOriginFeature(name.c_str()); if (!ret) return false; - ret = ret->getSubObject(subname + name.size() + 1, pyobj, mat, true, depth+1); + const char *dot = strchr(subname, '.'); + if (dot) + subname = dot+1; + else + subname = ""; + ret = ret->getSubObject(subname, pyobj, mat, true, depth+1); return true; } catch (const Base::Exception& e) { From f4a0387dc9d36c76ed1360d9405fa4490729c624 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 16 May 2022 11:29:18 +0200 Subject: [PATCH 05/13] Test: unit test for sub-objects related to PR #6888 --- src/Mod/Test/Document.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Mod/Test/Document.py b/src/Mod/Test/Document.py index 3b7ca66a33..904aea809a 100644 --- a/src/Mod/Test/Document.py +++ b/src/Mod/Test/Document.py @@ -306,6 +306,17 @@ class DocumentBasicCases(unittest.TestCase): self.assertEqual(obj.getSubObject(("XY_Plane", "YZ_Plane"), retType=4)[0], obj.getSubObject("XY_Plane", retType=4)) self.assertEqual(obj.getSubObject(("XY_Plane", "YZ_Plane"), retType=4)[1], obj.getSubObject("YZ_Plane", retType=4)) + # Create a second origin object + obj2 = self.Doc.addObject("App::Origin", "Origin2") + self.Doc.recompute() + + # Use the names of the origin's out-list + for i in obj2.OutList: + self.assertEqual(obj2.getSubObject(i.Name, retType=1).Name, i.Name) + # Add a '.' to the names + for i in obj2.OutList: + self.assertEqual(obj2.getSubObject(i.Name + '.', retType=1).Name, i.Name) + def testExtensions(self): #we try to create a normal python object and add an extension to it obj = self.Doc.addObject("App::DocumentObject", "Extension_1") From d85cea7e7d9ad7df734c3869e9830340307c6656 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Mon, 16 May 2022 13:21:52 +0200 Subject: [PATCH 06/13] Arch: fixed window for good this time --- src/Mod/Arch/ArchWindow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index 4f8a840116..d7048a2f70 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -100,7 +100,7 @@ def makeWindow(baseobj=None,width=None,height=None,parts=None,name=None): if baseobj.Shape.Wires: tp = "Frame" if len(baseobj.Shape.Wires) == 1: - tp = "Solid Panel" + tp = "Solid panel" i = 0 ws = '' for w in baseobj.Shape.Wires: From 4393dfae8c7485f017f0b61ac9daece7373dab6c Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 16 May 2022 13:33:32 +0200 Subject: [PATCH 07/13] Test: [skip ci] unit test for Commands related to PR #6889 --- src/Mod/Test/Workbench.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Mod/Test/Workbench.py b/src/Mod/Test/Workbench.py index d382421ea6..9b9d83a0b4 100755 --- a/src/Mod/Test/Workbench.py +++ b/src/Mod/Test/Workbench.py @@ -24,6 +24,7 @@ # Workbench test module import FreeCAD, FreeCADGui, os, unittest +import tempfile from PySide2 import QtWidgets, QtCore from PySide2.QtWidgets import QApplication @@ -79,3 +80,16 @@ class WorkbenchTestCase(unittest.TestCase): def tearDown(self): FreeCADGui.activateWorkbench(self.Active.name()) FreeCAD.Console.PrintLog(self.Active.name()) + +class CommandTestCase(unittest.TestCase): + def testPR6889(self): + # Fixes a crash + TempPath = tempfile.gettempdir() + macroName = TempPath + os.sep + "testmacro.py" + macroFile = open(macroName, "w") + macroFile.write("print ('Hello, World!')") + macroFile.close() + + name = FreeCADGui.Command.createCustomCommand(macroName) + cmd = FreeCADGui.Command.get(name) + cmd.run() From 3215c8a4264056bf4b4aa9adffe67ef596e70a35 Mon Sep 17 00:00:00 2001 From: marioalexis Date: Sun, 15 May 2022 09:59:16 -0300 Subject: [PATCH 08/13] Gui: Improve docstrings in CommandPy.xml --- src/Gui/CommandPy.xml | 109 ++++++++++++++++++--------------------- src/Gui/CommandPyImp.cpp | 46 +++++++++-------- 2 files changed, 74 insertions(+), 81 deletions(-) diff --git a/src/Gui/CommandPy.xml b/src/Gui/CommandPy.xml index 0556da17f3..2f416f5c1f 100644 --- a/src/Gui/CommandPy.xml +++ b/src/Gui/CommandPy.xml @@ -15,116 +15,107 @@ - Get a given command by name or None if it doesn't exist. -get(string) -> Command - + get(name) -> Gui.Command or None\n +Get a given command by name or None if it doesn't exist.\n +name : str\n Command name. - Update active status of all commands. -update() -> None - + update() -> None\n +Update active status of all commands. - Returns the name of all commands. -listAll() -> list of strings - + listAll() -> list of str\n +Returns the name of all commands. - Returns a list of all commands, filtered by shortcut. -listByShortcut(string, bool bUseRegExp=False) -> list of strings --- -Shortcuts are converted to uppercase and spaces removed prior to comparison. - + listByShortcut(string, useRegExp=False) -> list of str\n +Returns a list of all commands, filtered by shortcut. +Shortcuts are converted to uppercase and spaces removed +prior to comparison.\n +string : str\n Shortcut to be searched. +useRegExp : bool\n Filter using regular expression. - Runs the given command. -run() -> None - + run(item=0) -> None\n +Runs the given command.\n +item : int\n Item to be run. - Returns True if the command is active, False otherwise. -isActive() -> bool - + isActive() -> bool\n +Returns True if the command is active, False otherwise. - Returns string representing shortcut key accelerator for command. -getShortcut() -> string - + getShortcut() -> str\n +Returns string representing shortcut key accelerator for command. - Sets shortcut for given command, returns bool True for success. -setShortcut(string) -> bool - + setShortcut(string) -> bool\n +Sets shortcut for given command, returns True for success.\n +string : str\n Shortcut to be set. - Resets shortcut for given command back to the default, returns bool True for success. -resetShortcut() -> bool - + resetShortcut() -> bool\n +Resets shortcut for given command back to the default, returns True for success. - Return information about this command. -getInfo() -> list of strings --- -Usage: menuText, tooltipText, whatsThisText, statustipText, pixmapText, shortcutText. - + getInfo() -> dict\n +Return information about this command. - Return the associated QAction object. -getAction() -> list of QAction + getAction() -> list of QAction\n +Return the associated QAction object. - + - Create a custom command for a macro -createCustomCommand(macrofile, menuText, tooltipText, whatsThisText, statustipText, pixmapText, shortcutText) -> str --- -Only the macrofile argument is required, and should be the name of the macro file. All other arguments are -passed on to the command creation routines if they are provided. All arguments except the first accept None. - -Returns the name of the created custom command. - + createCustomCommand(macroFile, menuText, toolTip, whatsThis, statusTip, pixmap, shortcut) -> str\n +Create a custom command for a macro. Returns name of the created command.\n +macroFile : str\n Macro file. +menuText : str\n Menu text. Optional. +toolTip : str\n Tool tip text. Optional. +whatsThis : str\n `What's this?` text. Optional. +statusTip : str\n Status tip text. Optional. +pixmap : str\n Pixmap name. Optional. +shortcut : str\n Shortcut key sequence. Optional. - Remove the custom command if it exists -removeCustomCommand(name) -> bool --- -Given the name of a custom command, this removes that command. It is not an error -to remove a non-existent command, the function simply does nothing in that case. - -Returns True if something was removed, or False if not. - + removeCustomCommand(name) -> bool\n +Remove the custom command if it exists. +Given the name of a custom command, this removes that command. +It is not an error to remove a non-existent command, the function +simply does nothing in that case. +Returns True if something was removed, or False if not.\n +name : str\n Command name. - Find the name of a custom command, given a macro name -findCustomCommand(name) -> Optional[str] --- -Given the name of a macro, return the name of the custom command for that macro, or -None if there is no command matching that macro script name. - + findCustomCommand(name) -> str or None\n +Given the name of a macro, return the name of the custom command for that macro +or None if there is no command matching that macro script name.\n +name : str\n Macro name. diff --git a/src/Gui/CommandPyImp.cpp b/src/Gui/CommandPyImp.cpp index 527c5a8638..9a8b07fe6b 100644 --- a/src/Gui/CommandPyImp.cpp +++ b/src/Gui/CommandPyImp.cpp @@ -33,7 +33,7 @@ #include "Window.h" #include "PythonWrapper.h" -// inclusion of the generated files (generated out of AreaPy.xml) +// inclusion of the generated files (generated out of CommandPy.xml) #include "CommandPy.h" #include "CommandPy.cpp" @@ -86,8 +86,8 @@ PyObject* CommandPy::listAll(PyObject *args) PyObject* CommandPy::listByShortcut(PyObject *args) { char* shortcut_to_find; - bool bIsRegularExp = false; - if (!PyArg_ParseTuple(args, "s|b", &shortcut_to_find, &bIsRegularExp)) + PyObject* bIsRegularExp = Py_False; + if (!PyArg_ParseTuple(args, "s|O!", &shortcut_to_find, &PyBool_Type, &bIsRegularExp)) return nullptr; std::vector cmds = Application::Instance->commandManager().getAllCommands(); @@ -96,7 +96,7 @@ PyObject* CommandPy::listByShortcut(PyObject *args) Action* action = c->getAction(); if (action){ QString spc = QString::fromLatin1(" "); - if(bIsRegularExp){ + if(PyObject_IsTrue(bIsRegularExp)){ QRegExp re = QRegExp(QString::fromLatin1(shortcut_to_find)); re.setCaseSensitivity(Qt::CaseInsensitive); if (!re.isValid()){ @@ -105,7 +105,7 @@ PyObject* CommandPy::listByShortcut(PyObject *args) throw Py::RuntimeError(str.str()); } - if (re.indexIn(action->shortcut().toString().remove(spc).toUpper()) != -1){ + if (re.indexIn(action->shortcut().toString().remove(spc).toUpper()) != -1) { matches.push_back(c->getName()); } } @@ -261,7 +261,8 @@ PyObject* CommandPy::getInfo(PyObject *args) Command* cmd = this->getCommandPtr(); if (cmd) { Action* action = cmd->getAction(); - PyObject* pyList = PyList_New(6); + PyObject* pyDict = PyDict_New(); + const char* cmdName = cmd->getName(); const char* menuTxt = cmd->getMenuText(); const char* tooltipTxt = cmd->getToolTipText(); const char* whatsThisTxt = cmd->getWhatsThis(); @@ -271,19 +272,21 @@ PyObject* CommandPy::getInfo(PyObject *args) if (action) shortcutTxt = action->shortcut().toString().toStdString(); + PyObject* strCmdName = PyUnicode_FromString(cmdName); PyObject* strMenuTxt = PyUnicode_FromString(menuTxt ? menuTxt : ""); PyObject* strTooltipTxt = PyUnicode_FromString(tooltipTxt ? tooltipTxt : ""); PyObject* strWhatsThisTxt = PyUnicode_FromString(whatsThisTxt ? whatsThisTxt : ""); PyObject* strStatustipTxt = PyUnicode_FromString(statustipTxt ? statustipTxt : ""); PyObject* strPixMapTxt = PyUnicode_FromString(pixMapTxt ? pixMapTxt : ""); PyObject* strShortcutTxt = PyUnicode_FromString(!shortcutTxt.empty() ? shortcutTxt.c_str() : ""); - PyList_SetItem(pyList, 0, strMenuTxt); - PyList_SetItem(pyList, 1, strTooltipTxt); - PyList_SetItem(pyList, 2, strWhatsThisTxt); - PyList_SetItem(pyList, 3, strStatustipTxt); - PyList_SetItem(pyList, 4, strPixMapTxt); - PyList_SetItem(pyList, 5, strShortcutTxt); - return pyList; + PyDict_SetItemString(pyDict, "name", strCmdName); + PyDict_SetItemString(pyDict, "menuText", strMenuTxt); + PyDict_SetItemString(pyDict, "toolTip", strTooltipTxt); + PyDict_SetItemString(pyDict, "whatsThis", strWhatsThisTxt); + PyDict_SetItemString(pyDict, "statusTip", strStatustipTxt); + PyDict_SetItemString(pyDict, "pixmap", strPixMapTxt); + PyDict_SetItemString(pyDict, "shortcut", strShortcutTxt); + return pyDict; } else { PyErr_Format(Base::PyExc_FC_GeneralError, "No such command"); @@ -322,16 +325,18 @@ PyObject* CommandPy::getAction(PyObject *args) } -PyObject* CommandPy::createCustomCommand(PyObject* args) +PyObject* CommandPy::createCustomCommand(PyObject* args, PyObject* kw) { - const char* macroFile = nullptr; + const char* macroFile; const char* menuTxt = nullptr; const char* tooltipTxt = nullptr; const char* whatsthisTxt = nullptr; const char* statustipTxt = nullptr; const char* pixmapTxt = nullptr; const char* shortcutTxt = nullptr; - if (!PyArg_ParseTuple(args, "s|zzzzzz", ¯oFile, &menuTxt, &tooltipTxt, &whatsthisTxt, &statustipTxt, &pixmapTxt, &shortcutTxt)) + static char* kwlist[] = {"macroFile", "menuText", "toolTip", "whatsThis","statusTip", "pixmap", "shortcut", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, kw, "s|zzzzzz", kwlist, ¯oFile, &menuTxt, + &tooltipTxt, &whatsthisTxt, &statustipTxt, &pixmapTxt, &shortcutTxt)) return nullptr; auto name = Application::Instance->commandManager().newMacroName(); @@ -400,13 +405,10 @@ PyObject* CommandPy::findCustomCommand(PyObject* args) return false; }); - if (action != macros.end()) { + if (action != macros.end()) return PyUnicode_FromString((*action)->getName()); - } - else { - Py_INCREF(Py_None); - return Py_None; - } + else + Py_Return; } PyObject *CommandPy::getCustomAttributes(const char* /*attr*/) const From 88fb277481e0a60f7070ed9d79af9275713fc7c4 Mon Sep 17 00:00:00 2001 From: marioalexis Date: Sun, 15 May 2022 23:26:36 -0300 Subject: [PATCH 09/13] Gui: Fix crash when invoke command with sMenuText equal to nullptr --- src/Gui/Command.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Gui/Command.cpp b/src/Gui/Command.cpp index 15717aebc4..a3ae291cfa 100644 --- a/src/Gui/Command.cpp +++ b/src/Gui/Command.cpp @@ -369,7 +369,7 @@ void Command::invoke(int i, TriggerSource trigger) { CommandTrigger cmdTrigger(_trigger,trigger); if (displayText.empty()) { - displayText = getMenuText(); + displayText = getMenuText() ? getMenuText() : ""; boost::replace_all(displayText,"&",""); if (displayText.empty()) displayText = getName(); From 34b0fc7a42c0abe70bbc9b83803f17fbc518d450 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 16 May 2022 14:54:18 +0200 Subject: [PATCH 10/13] Gui: use Py_ssize_t instead of ssize_t in AbstractSplitViewPy::sequence_item --- src/Gui/SplitView3DInventor.cpp | 2 +- src/Gui/SplitView3DInventor.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Gui/SplitView3DInventor.cpp b/src/Gui/SplitView3DInventor.cpp index 51c424f0f1..1f058250dd 100644 --- a/src/Gui/SplitView3DInventor.cpp +++ b/src/Gui/SplitView3DInventor.cpp @@ -719,7 +719,7 @@ Py::Object AbstractSplitViewPy::getViewer(const Py::Tuple& args) } } -Py::Object AbstractSplitViewPy::sequence_item(ssize_t viewIndex) +Py::Object AbstractSplitViewPy::sequence_item(Py_ssize_t viewIndex) { AbstractSplitView* view = getSplitViewPtr(); if (viewIndex >= view->getSize() || viewIndex < 0) diff --git a/src/Gui/SplitView3DInventor.h b/src/Gui/SplitView3DInventor.h index 51247ef71d..7cac36de13 100644 --- a/src/Gui/SplitView3DInventor.h +++ b/src/Gui/SplitView3DInventor.h @@ -98,7 +98,7 @@ public: Py::Object viewTop(const Py::Tuple&); Py::Object viewIsometric(const Py::Tuple&); Py::Object getViewer(const Py::Tuple&); - Py::Object sequence_item(ssize_t); + Py::Object sequence_item(Py_ssize_t); Py::Object close(const Py::Tuple&); int sequence_length(); From 3aa2920e33fa8e77cf750598bf15a18e839a8b3b Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Mon, 16 May 2022 11:10:04 -0500 Subject: [PATCH 11/13] Draft: fix SVG rotation around non-origin center Fixes #6869 --- src/Mod/Draft/importSVG.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Mod/Draft/importSVG.py b/src/Mod/Draft/importSVG.py index 5af8786cde..e01dc52944 100644 --- a/src/Mod/Draft/importSVG.py +++ b/src/Mod/Draft/importSVG.py @@ -1591,14 +1591,15 @@ class svgHandler(xml.sax.ContentHandler): cy = 0 angle = argsplit[0] if len(argsplit) >= 3: + # Rotate around a non-origin centerpoint (note: SVG y axis is opposite FreeCAD y axis) cx = argsplit[1] cy = argsplit[2] - m.move(Vector(cx, -cy, 0)) + m.move(Vector(-cx, cy, 0)) # Reposition for rotation # Mirroring one axis is equal to changing the direction # of rotation m.rotateZ(math.radians(-angle)) if len(argsplit) >= 3: - m.move(Vector(-cx, cy, 0)) + m.move(Vector(cx, -cy, 0)) # Reverse repositioning elif transformation == 'skewX': _m = FreeCAD.Matrix(1, -math.tan(math.radians(argsplit[0]))) From ad067cdf7e1c16bfeda47d041106edc75b8a2153 Mon Sep 17 00:00:00 2001 From: luz paz Date: Mon, 16 May 2022 15:46:25 -0400 Subject: [PATCH 12/13] [TestWB] fix source comment typo in [skip ci] --- src/Mod/Test/Gui/UnitTestImp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Test/Gui/UnitTestImp.cpp b/src/Mod/Test/Gui/UnitTestImp.cpp index 8262ea97ac..6adc37262c 100644 --- a/src/Mod/Test/Gui/UnitTestImp.cpp +++ b/src/Mod/Test/Gui/UnitTestImp.cpp @@ -306,7 +306,7 @@ void UnitTestDialog::setProgressFraction(float fraction, const QString& color) } /** - * Emtpies the error listview. + * Empties the error listview. */ void UnitTestDialog::clearErrorList() { From 7e7d368bba64d65afd21b0bd595bc344378b656b Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 4 May 2022 17:55:24 +0200 Subject: [PATCH 13/13] Import: fixes #5793: DXF export (Autodesk DXF 2D type) doesn't add any UNITS field inside the dxf file --- src/Mod/Import/DxfPlate/header14.rub | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Mod/Import/DxfPlate/header14.rub b/src/Mod/Import/DxfPlate/header14.rub index a6cf3fa447..229889048e 100644 --- a/src/Mod/Import/DxfPlate/header14.rub +++ b/src/Mod/Import/DxfPlate/header14.rub @@ -31,6 +31,14 @@ $CMLSTYLE 2 STANDARD 9 +$LUNITS + 70 +2 + 9 +$INSUNITS + 70 +4 + 9 $PEXTMAX 10 50