Add Draft workbench to .pre-commit-config (#24664)

* Add Draft workbench to .pre-commit-config

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
marcuspollio
2025-10-15 11:21:09 +02:00
committed by GitHub
parent 87f88bba30
commit 50e4864efb
225 changed files with 10713 additions and 9269 deletions

View File

@@ -20,8 +20,7 @@
# * USA *
# * *
# ***************************************************************************
"""Provide the grid observer for the Draft and BIM workbenches.
"""
"""Provide the grid observer for the Draft and BIM workbenches."""
import FreeCAD

View File

@@ -63,10 +63,14 @@ def is_group(obj):
Otherwise returns `False`.
"""
typ = utils.get_type(obj)
return ((obj.isDerivedFrom("App::DocumentObjectGroup")
and typ != "LayerContainer")
or typ in ("Project", "Site", "Building",
"Floor", "BuildingPart", "Space"))
return (obj.isDerivedFrom("App::DocumentObjectGroup") and typ != "LayerContainer") or typ in (
"Project",
"Site",
"Building",
"Floor",
"BuildingPart",
"Space",
)
def get_group_names(doc=None):
@@ -171,26 +175,23 @@ def get_windows(obj):
for o in obj.OutList:
out.extend(get_windows(o))
for i in obj.InList:
if (utils.get_type(i.getLinkedObject()) == "Window"
or utils.is_clone(obj, "Window")):
if utils.get_type(i.getLinkedObject()) == "Window" or utils.is_clone(obj, "Window"):
if hasattr(i, "Hosts"):
if obj in i.Hosts:
out.append(i)
elif (utils.get_type(i) == "Rebar"
or utils.is_clone(obj, "Rebar")):
elif utils.get_type(i) == "Rebar" or utils.is_clone(obj, "Rebar"):
if hasattr(i, "Host"):
if obj == i.Host:
out.append(i)
elif (utils.get_type(obj.getLinkedObject()) in ("Window", "Rebar")
or utils.is_clone(obj, ["Window", "Rebar"])):
elif utils.get_type(obj.getLinkedObject()) in ("Window", "Rebar") or utils.is_clone(
obj, ["Window", "Rebar"]
):
out.append(obj)
return out
def get_group_contents(objectslist,
walls=False, addgroups=False,
spaces=False, noarchchild=False):
def get_group_contents(objectslist, walls=False, addgroups=False, spaces=False, noarchchild=False):
"""Return a list of objects from expanding the input groups.
The function accepts any type of object, although it is most useful
@@ -239,15 +240,12 @@ def get_group_contents(objectslist,
for obj in objectslist:
if obj:
if is_group(obj):
if addgroups or (spaces
and utils.get_type(obj) == "Space"):
if addgroups or (spaces and utils.get_type(obj) == "Space"):
newlist.append(obj)
if not (noarchchild
and utils.get_type(obj) in ("Building",
"BuildingPart")):
newlist.extend(get_group_contents(obj.Group,
walls, addgroups,
spaces, noarchchild))
if not (noarchchild and utils.get_type(obj) in ("Building", "BuildingPart")):
newlist.extend(
get_group_contents(obj.Group, walls, addgroups, spaces, noarchchild)
)
else:
# print("adding ", obj.Name)
newlist.append(obj)
@@ -263,15 +261,11 @@ def get_group_contents(objectslist,
return cleanlist
def getGroupContents(objectslist,
walls=False, addgroups=False,
spaces=False, noarchchild=False):
def getGroupContents(objectslist, walls=False, addgroups=False, spaces=False, noarchchild=False):
"""Return a list of objects from groups. DEPRECATED."""
utils.use_instead("get_group_contents")
return get_group_contents(objectslist,
walls, addgroups,
spaces, noarchchild)
return get_group_contents(objectslist, walls, addgroups, spaces, noarchchild)
def get_movable_children(objectslist, recursive=True, _donelist=[]):
@@ -313,19 +307,28 @@ def get_movable_children(objectslist, recursive=True, _donelist=[]):
_donelist.append(obj.Name)
# Skips some objects that should never move their children
if utils.get_type(obj) not in ("App::Part", "PartDesign::Body",
"Clone", "SectionPlane",
"Facebinder", "BuildingPart", "App::Link"):
if utils.get_type(obj) not in (
"App::Part",
"PartDesign::Body",
"Clone",
"SectionPlane",
"Facebinder",
"BuildingPart",
"App::Link",
):
children = obj.OutList
if (hasattr(obj, "Proxy") and obj.Proxy
and hasattr(obj.Proxy, "getSiblings")
and utils.get_type(obj) != "Window"):
if (
hasattr(obj, "Proxy")
and obj.Proxy
and hasattr(obj.Proxy, "getSiblings")
and utils.get_type(obj) != "Window"
):
# children.extend(obj.Proxy.getSiblings(obj))
pass
for child in children:
if hasattr(child, "MoveWithHost") and child.MoveWithHost:
if hasattr(obj, "CloneOf") and obj.CloneOf:
if hasattr(obj, "CloneOf") and obj.CloneOf:
if obj.CloneOf.Name != child.Name:
added.append(child)
else:
@@ -342,4 +345,5 @@ def getMovableChildren(objectslist, recursive=True):
utils.use_instead("get_movable_children")
return get_movable_children(objectslist, recursive)
## @}

View File

@@ -51,6 +51,7 @@ if App.GuiUp:
from pivy import coin
from PySide import QtCore
from PySide import QtGui
# from PySide import QtSvg # for load_texture
@@ -105,9 +106,9 @@ def autogroup(obj):
# check for required conditions for autogroup to work
if not App.GuiUp:
return
if not hasattr(Gui,"draftToolBar"):
if not hasattr(Gui, "draftToolBar"):
return
if not hasattr(Gui.draftToolBar,"autogroup"):
if not hasattr(Gui.draftToolBar, "autogroup"):
return
if Gui.draftToolBar.isConstructionMode():
return
@@ -115,8 +116,8 @@ def autogroup(obj):
# check first for objects that do autogroup themselves
# at the moment only Arch_BuildingPart, which is an App::GeometryPython
for par in App.ActiveDocument.findObjects(Type="App::GeometryPython"):
if hasattr(par.Proxy,"autogroup"):
if par.Proxy.autogroup(par,obj):
if hasattr(par.Proxy, "autogroup"):
if par.Proxy.autogroup(par, obj):
return
# autogroup code
@@ -135,6 +136,7 @@ def autogroup(obj):
# NativeIFC handling
try:
from nativeifc import ifc_tools
parent = Gui.ActiveDocument.ActiveView.getActiveObject("NativeIFC")
ifc_tools.aggregate(obj, parent)
except:
@@ -158,13 +160,11 @@ def autogroup(obj):
return
matrix = parent.getSubObject(sub, retType=4)
if matrix.hasScale() == App.ScaleType.Uniform:
err = translate("draft",
"Unable to insert new object into "
"a scaled part")
err = translate("draft", "Unable to insert new object into " "a scaled part")
App.Console.PrintMessage(err)
return
inverse_placement = App.Placement(matrix.inverse())
if utils.get_type(obj) == 'Point':
if utils.get_type(obj) == "Point":
point_vector = App.Vector(obj.X, obj.Y, obj.Z)
real_point = inverse_placement.multVec(point_vector)
obj.X = real_point.x
@@ -179,7 +179,7 @@ def autogroup(obj):
elif utils.get_type(obj) in ["Label"]:
obj.Placement = App.Placement(inverse_placement.multiply(obj.Placement))
obj.TargetPoint = inverse_placement.multVec(obj.TargetPoint)
elif hasattr(obj,"Placement"):
elif hasattr(obj, "Placement"):
# every object that have a placement is processed here
obj.Placement = App.Placement(inverse_placement.multiply(obj.Placement))
@@ -244,9 +244,9 @@ def dim_symbol(symbol=None, invert=False):
t.translation.setValue((0, -2, 0))
t.center.setValue((0, 2, 0))
if invert:
t.rotation.setValue(coin.SbVec3f((0, 0, 1)), -math.pi/2)
t.rotation.setValue(coin.SbVec3f((0, 0, 1)), -math.pi / 2)
else:
t.rotation.setValue(coin.SbVec3f((0, 0, 1)), math.pi/2)
t.rotation.setValue(coin.SbVec3f((0, 0, 1)), math.pi / 2)
c = coin.SoCone()
c.height.setValue(4)
marker.addChild(t)
@@ -258,8 +258,7 @@ def dim_symbol(symbol=None, invert=False):
h = coin.SoShapeHints()
h.vertexOrdering = h.COUNTERCLOCKWISE
c = coin.SoCoordinate3()
c.point.setValues([(-1, -2, 0), (0, 2, 0),
(1, 2, 0), (0, -2, 0)])
c.point.setValues([(-1, -2, 0), (0, 2, 0), (1, 2, 0), (0, -2, 0)])
f = coin.SoFaceSet()
marker.addChild(h)
marker.addChild(c)
@@ -359,6 +358,7 @@ def get_diffuse_color(objs):
list of tuples
The list will be empty if no valid object is found.
"""
def _get_color(obj):
if hasattr(obj, "ColoredElements"):
if hasattr(obj, "Count") or hasattr(obj, "ElementCount"):
@@ -376,7 +376,9 @@ def get_diffuse_color(objs):
return cols
face_num = len(base.Shape.Faces)
for elm, override in zip(obj.ColoredElements[1], obj.ViewObject.OverrideColorList):
if "Face" in elm: # Examples: "Face3" and "1.Face6". Int before "." is zero-based, other int is 1-based.
if (
"Face" in elm
): # Examples: "Face3" and "1.Face6". Int before "." is zero-based, other int is 1-based.
if "." in elm:
elm0, elm1 = elm.split(".")
i = (int(elm0) * face_num) + int(elm1[4:]) - 1
@@ -394,9 +396,11 @@ def get_diffuse_color(objs):
if obj.ColoredElements is None:
cols += sub_cols
else:
for elm, override in zip(obj.ColoredElements[1], obj.ViewObject.OverrideColorList):
for elm, override in zip(
obj.ColoredElements[1], obj.ViewObject.OverrideColorList
):
if sub.Name + ".Face" in elm:
i = int(elm[(len(sub.Name) + 5):]) - 1
i = int(elm[(len(sub.Name) + 5) :]) - 1
sub_cols[i] = override
cols += sub_cols
return cols
@@ -420,10 +424,14 @@ def get_diffuse_color(objs):
if not isinstance(objs, list):
# Quick check to avoid processing a single object:
obj = objs
if not hasattr(obj, "ColoredElements") \
and hasattr(obj.ViewObject, "DiffuseColor") \
and (len(obj.ViewObject.DiffuseColor) == 1 \
or len(obj.ViewObject.DiffuseColor) == len(obj.Shape.Faces)):
if (
not hasattr(obj, "ColoredElements")
and hasattr(obj.ViewObject, "DiffuseColor")
and (
len(obj.ViewObject.DiffuseColor) == 1
or len(obj.ViewObject.DiffuseColor) == len(obj.Shape.Faces)
)
):
return obj.ViewObject.DiffuseColor
# Create a list for further processing:
objs = [objs]
@@ -454,7 +462,7 @@ def apply_current_style(objs):
anno_style = utils.get_default_annotation_style()
shape_style = utils.get_default_shape_style()
for obj in objs:
if not hasattr(obj, 'ViewObject'):
if not hasattr(obj, "ViewObject"):
continue
vobj = obj.ViewObject
props = vobj.PropertiesList
@@ -554,7 +562,7 @@ def format_object(target, origin=None, ignore_construction=False):
val = getattr(matchrep, p)
if isinstance(val, tuple):
if len(val) != len_faces:
val = (val[0], )
val = (val[0],)
elif hasattr(val, "Value"):
val = val.Value
try:
@@ -778,11 +786,14 @@ def load_texture(filename, size=None, gui=App.GuiUp):
_wrn("load_texture: " + translate("draft", "image is Null"))
if not os.path.exists(filename):
raise FileNotFoundError(-1,
translate("draft", "filename does not exist "
"on the system or "
"in the resource file"),
filename)
raise FileNotFoundError(
-1,
translate(
"draft",
"filename does not exist " "on the system or " "in the resource file",
),
filename,
)
# This is buggy so it was de-activated.
#
@@ -835,8 +846,7 @@ def load_texture(filename, size=None, gui=App.GuiUp):
_bytes = bytes(byteList)
img.setValue(size, numcomponents, _bytes)
except FileNotFoundError as exc:
_wrn("load_texture: {0}, {1}".format(exc.strerror,
exc.filename))
_wrn("load_texture: {0}, {1}".format(exc.strerror, exc.filename))
return None
except Exception as exc:
_wrn(str(exc))
@@ -902,9 +912,11 @@ def get_bbox(obj, debug=False):
_err(translate("draft", "Wrong input: object {} not in document.").format(obj_str))
return None
if (not hasattr(obj, "ViewObject")
or not obj.ViewObject
or not hasattr(obj.ViewObject, "RootNode")):
if (
not hasattr(obj, "ViewObject")
or not obj.ViewObject
or not hasattr(obj.ViewObject, "RootNode")
):
_err(translate("draft", "Does not have 'ViewObject.RootNode'."))
# For Draft Dimensions
@@ -941,21 +953,27 @@ def end_all_events():
if view is None:
return
if view.getNavigationType() in (
"Gui::GestureNavigationStyle", "Gui::MayaGestureNavigationStyle"
"Gui::GestureNavigationStyle",
"Gui::MayaGestureNavigationStyle",
):
return
class DelayEnder:
def __init__(self):
self.delay_is_done = False
def stop(self):
self.delay_is_done = True
ender = DelayEnder()
timer = QtCore.QTimer()
timer.timeout.connect(ender.stop)
timer.setSingleShot(True)
timer.start(100) # 100ms (50ms is too short) timer guarantees the loop below runs at least that long
timer.start(
100
) # 100ms (50ms is too short) timer guarantees the loop below runs at least that long
while not ender.delay_is_done:
QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents)
## @}

View File

@@ -41,32 +41,61 @@ from draftutils import params
from draftutils.init_tools import get_draft_snap_commands
from draftutils.translate import translate
#----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# SCALE WIDGET FUNCTIONS
#----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
draft_scales_metrics = ["1:1000", "1:500", "1:250", "1:200", "1:100",
"1:50", "1:25","1:20", "1:10", "1:5","1:2",
"1:1",
"2:1", "5:1", "10:1", "20:1",
translate("draft", "Custom"),
]
draft_scales_metrics = [
"1:1000",
"1:500",
"1:250",
"1:200",
"1:100",
"1:50",
"1:25",
"1:20",
"1:10",
"1:5",
"1:2",
"1:1",
"2:1",
"5:1",
"10:1",
"20:1",
translate("draft", "Custom"),
]
draft_scales_arch_imperial = ["1/16in=1ft", "3/32in=1ft", "1/8in=1ft",
"3/16in=1ft", "1/4in=1ft","3/8in=1ft",
"1/2in=1ft", "3/4in=1ft", "1in=1ft",
"1.5in=1ft", "3in=1ft",
translate("draft", "Custom"),
]
draft_scales_arch_imperial = [
"1/16in=1ft",
"3/32in=1ft",
"1/8in=1ft",
"3/16in=1ft",
"1/4in=1ft",
"3/8in=1ft",
"1/2in=1ft",
"3/4in=1ft",
"1in=1ft",
"1.5in=1ft",
"3in=1ft",
translate("draft", "Custom"),
]
draft_scales_eng_imperial = ["1in=10ft", "1in=20ft", "1in=30ft",
"1in=40ft", "1in=50ft", "1in=60ft",
"1in=70ft", "1in=80ft", "1in=90ft",
"1in=100ft",
translate("draft", "Custom"),
]
draft_scales_eng_imperial = [
"1in=10ft",
"1in=20ft",
"1in=30ft",
"1in=40ft",
"1in=50ft",
"1in=60ft",
"1in=70ft",
"1in=80ft",
"1in=90ft",
"1in=100ft",
translate("draft", "Custom"),
]
def get_scales(unit_system = 0):
def get_scales(unit_system=0):
"""
returns the list of preset scales according to unit system.
@@ -107,17 +136,18 @@ def scale_to_label(scale):
if f[1] == 1:
return str(f[0]) + ":1"
return str(scale)
f = round(1/scale, 2)
f = round(1 / scale, 2)
f = f.as_integer_ratio()
if f[1] == 1:
return "1:" + str(f[0])
return str(scale)
def label_to_scale(label):
"""
transform a scale string into scale factor as float
"""
try :
try:
scale = float(label)
return scale
except Exception:
@@ -131,14 +161,14 @@ def label_to_scale(label):
try:
num = App.Units.Quantity(f[0]).Value
den = App.Units.Quantity(f[1]).Value
scale = num/den
scale = num / den
return scale
except Exception:
err = translate("draft",
"Unable to convert input into a scale factor")
err = translate("draft", "Unable to convert input into a scale factor")
App.Console.PrintWarning(err)
return None
def _set_scale(action):
"""
triggered by scale pushbutton, set DefaultAnnoScaleMultiplier in preferences
@@ -146,12 +176,11 @@ def _set_scale(action):
mw = Gui.getMainWindow()
sb = mw.statusBar()
scale_widget = sb.findChild(QtWidgets.QToolBar,"draft_scale_widget")
scale_widget = sb.findChild(QtWidgets.QToolBar, "draft_scale_widget")
if action.text() == translate("draft", "Custom"):
title_text = translate("draft", "Set Custom Scale")
dialog_text = translate("draft",
"Set custom annotation scale in format x:x, x=x")
dialog_text = translate("draft", "Set custom annotation scale in format x:x, x=x")
custom_scale = QtWidgets.QInputDialog.getText(None, title_text, dialog_text)
if custom_scale[1]:
print(custom_scale[0])
@@ -169,9 +198,11 @@ def _set_scale(action):
scale = label_to_scale(text_scale)
params.set_param("DefaultAnnoScaleMultiplier", 1 / scale)
#----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# MAIN DRAFT STATUSBAR FUNCTIONS
#----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
def init_draft_statusbar_scale():
"""
@@ -184,8 +215,11 @@ def init_draft_statusbar_scale():
# prevent the widget from showing up in the toolbar area context menu:
scale_widget.toggleViewAction().setVisible(False)
scale_widget.setObjectName("draft_scale_widget")
text = translate("draft", "Draft Scale Widget",
"A context menu action used to show or hide this toolbar widget")
text = translate(
"draft",
"Draft Scale Widget",
"A context menu action used to show or hide this toolbar widget",
)
scale_widget.setWindowTitle(text)
# get scales list according to system units
@@ -210,8 +244,7 @@ def init_draft_statusbar_scale():
gUnits.triggered.connect(_set_scale)
scale_label = scale_to_label(annotation_scale)
scaleLabel.setText(scale_label)
scaleLabel.setToolTip(translate("draft",
"Set the scale used by Draft annotation tools"))
scaleLabel.setToolTip(translate("draft", "Set the scale used by Draft annotation tools"))
scale_widget.addWidget(scaleLabel)
scale_widget.scaleLabel = scaleLabel
@@ -246,8 +279,11 @@ def init_draft_statusbar_snap():
# prevent the widget from showing up in the toolbar area context menu:
snap_widget.toggleViewAction().setVisible(False)
snap_widget.setObjectName("draft_snap_widget")
text = translate("draft", "Draft Snap Widget",
"A context menu action used to show or hide this toolbar widget")
text = translate(
"draft",
"Draft Snap Widget",
"A context menu action used to show or hide this toolbar widget",
)
snap_widget.setWindowTitle(text)
snap_widget.setOrientation(QtCore.Qt.Orientation.Horizontal)
snap_widget.setIconSize(QtCore.QSize(16, 16))
@@ -261,7 +297,7 @@ def init_draft_statusbar_snap():
# lock button:
snap_widget.addAction(Gui.Command.get("Draft_Snap_Lock").getAction()[0])
snap_action = snap_widget.children()[-1]
snap_action.setFixedWidth(40) # Widen the button.
snap_action.setFixedWidth(40) # Widen the button.
snap_widget.addWidget(_spacer())
@@ -280,12 +316,14 @@ def init_draft_statusbar_snap():
# menu for lock button:
for cmd in get_draft_snap_commands():
if cmd not in ["Separator",
"Draft_ToggleGrid",
"Draft_Snap_Lock", # Is automatically added to the menu anyway.
"Draft_Snap_Dimensions",
"Draft_Snap_Ortho",
"Draft_Snap_WorkingPlane"]:
if cmd not in [
"Separator",
"Draft_ToggleGrid",
"Draft_Snap_Lock", # Is automatically added to the menu anyway.
"Draft_Snap_Dimensions",
"Draft_Snap_Ortho",
"Draft_Snap_WorkingPlane",
]:
snap_action.addAction(Gui.Command.get(cmd).getAction()[0])
@@ -352,11 +390,11 @@ def hide_draft_statusbar_snap():
mw = Gui.getMainWindow()
sb = mw.statusBar()
snap_widget = sb.findChild(QtWidgets.QToolBar,"draft_snap_widget")
snap_widget = sb.findChild(QtWidgets.QToolBar, "draft_snap_widget")
if snap_widget is None:
# when switching workbenches, the toolbar sometimes "jumps"
# out of the status bar to any other dock area...
snap_widget = mw.findChild(QtWidgets.QToolBar,"draft_snap_widget")
snap_widget = mw.findChild(QtWidgets.QToolBar, "draft_snap_widget")
if snap_widget:
snap_widget.hide()
@@ -380,4 +418,5 @@ def hide_draft_statusbar():
QtCore.QTimer().singleShot(500, hide_draft_statusbar_scale)
QtCore.QTimer().singleShot(500, hide_draft_statusbar_snap)
## @}

View File

@@ -41,150 +41,164 @@ def get_draft_drawing_commands():
"""Return the drawing commands list."""
from draftguitools import gui_arcs
from draftguitools import gui_beziers
arc_group = gui_arcs.ArcGroup
bez_group = gui_beziers.BezierGroup
return ["Draft_Line",
"Draft_Wire",
"Draft_Fillet",
([QT_TRANSLATE_NOOP("Workbench", "Arc Tools")],
list(arc_group.GetCommands(arc_group))), # tuple len=2: submenu
("Draft_ArcTools", ), # tuple len=1: toolbar flyout
"Draft_Circle",
"Draft_Ellipse",
"Draft_Rectangle",
"Draft_Polygon",
"Draft_BSpline",
([QT_TRANSLATE_NOOP("Workbench", "Bézier Tools")],
list(bez_group.GetCommands(bez_group))),
("Draft_BezierTools", ),
"Draft_Point",
"Draft_Facebinder",
"Draft_ShapeString",
"Draft_Hatch"]
return [
"Draft_Line",
"Draft_Wire",
"Draft_Fillet",
(
[QT_TRANSLATE_NOOP("Workbench", "Arc Tools")],
list(arc_group.GetCommands(arc_group)),
), # tuple len=2: submenu
("Draft_ArcTools",), # tuple len=1: toolbar flyout
"Draft_Circle",
"Draft_Ellipse",
"Draft_Rectangle",
"Draft_Polygon",
"Draft_BSpline",
([QT_TRANSLATE_NOOP("Workbench", "Bézier Tools")], list(bez_group.GetCommands(bez_group))),
("Draft_BezierTools",),
"Draft_Point",
"Draft_Facebinder",
"Draft_ShapeString",
"Draft_Hatch",
]
def get_draft_annotation_commands():
"""Return the annotation commands list."""
return ["Draft_Text",
"Draft_Dimension",
"Draft_Label",
"Draft_AnnotationStyleEditor"]
return ["Draft_Text", "Draft_Dimension", "Draft_Label", "Draft_AnnotationStyleEditor"]
def get_draft_modification_commands():
"""Return the modification commands list."""
from draftguitools import gui_arrays
arr_group = gui_arrays.ArrayGroup
return ["Draft_Move",
"Draft_Rotate",
"Draft_Scale",
"Draft_Mirror",
"Draft_Offset",
"Draft_Trimex",
"Draft_Stretch",
"Separator",
"Draft_Clone",
([QT_TRANSLATE_NOOP("Workbench", "Array Tools")],
list(arr_group.GetCommands(arr_group))), # tuple len=2: submenu
("Draft_ArrayTools", ), # tuple len=1: toolbar flyout
"Separator",
"Draft_Edit",
"Draft_SubelementHighlight",
"Separator",
"Draft_Join",
"Draft_Split",
"Draft_Upgrade",
"Draft_Downgrade",
"Separator",
"Draft_WireToBSpline",
"Draft_Draft2Sketch",
"Draft_Slope",
"Draft_FlipDimension",
"Separator",
"Draft_Shape2DView"]
return [
"Draft_Move",
"Draft_Rotate",
"Draft_Scale",
"Draft_Mirror",
"Draft_Offset",
"Draft_Trimex",
"Draft_Stretch",
"Separator",
"Draft_Clone",
(
[QT_TRANSLATE_NOOP("Workbench", "Array Tools")],
list(arr_group.GetCommands(arr_group)),
), # tuple len=2: submenu
("Draft_ArrayTools",), # tuple len=1: toolbar flyout
"Separator",
"Draft_Edit",
"Draft_SubelementHighlight",
"Separator",
"Draft_Join",
"Draft_Split",
"Draft_Upgrade",
"Draft_Downgrade",
"Separator",
"Draft_WireToBSpline",
"Draft_Draft2Sketch",
"Draft_Slope",
"Draft_FlipDimension",
"Separator",
"Draft_Shape2DView",
]
def get_draft_utility_commands_menu():
"""Return the utility commands list for the menu."""
return ["Draft_SetStyle",
"Draft_ApplyStyle",
"Separator",
"Draft_Layer",
"Draft_LayerManager",
"Draft_AddNamedGroup",
"Draft_SelectGroup",
"Draft_ToggleConstructionMode",
"Separator",
"Draft_AddToLayer",
"Draft_AddToGroup",
"Draft_AddConstruction",
"Separator",
"Draft_ToggleDisplayMode",
"Draft_ToggleGrid",
"Draft_SelectPlane",
"Draft_WorkingPlaneProxy",
"Separator",
"Draft_Heal",
"Draft_ShowSnapBar"]
return [
"Draft_SetStyle",
"Draft_ApplyStyle",
"Separator",
"Draft_Layer",
"Draft_LayerManager",
"Draft_AddNamedGroup",
"Draft_SelectGroup",
"Draft_ToggleConstructionMode",
"Separator",
"Draft_AddToLayer",
"Draft_AddToGroup",
"Draft_AddConstruction",
"Separator",
"Draft_ToggleDisplayMode",
"Draft_ToggleGrid",
"Draft_SelectPlane",
"Draft_WorkingPlaneProxy",
"Separator",
"Draft_Heal",
"Draft_ShowSnapBar",
]
def get_draft_utility_commands_toolbar():
"""Return the utility commands list for the toolbar."""
return ["Draft_LayerManager",
"Draft_AddNamedGroup",
"Draft_SelectGroup",
"Draft_AddToLayer",
"Draft_AddToGroup",
"Draft_AddConstruction",
"Draft_ToggleDisplayMode",
"Draft_WorkingPlaneProxy"]
return [
"Draft_LayerManager",
"Draft_AddNamedGroup",
"Draft_SelectGroup",
"Draft_AddToLayer",
"Draft_AddToGroup",
"Draft_AddConstruction",
"Draft_ToggleDisplayMode",
"Draft_WorkingPlaneProxy",
]
def get_draft_snap_commands():
"""Return the snapping commands list."""
return ["Draft_Snap_Lock",
"Draft_Snap_Endpoint",
"Draft_Snap_Midpoint",
"Draft_Snap_Center",
"Draft_Snap_Angle",
"Draft_Snap_Intersection",
"Draft_Snap_Perpendicular",
"Draft_Snap_Extension",
"Draft_Snap_Parallel",
"Draft_Snap_Special",
"Draft_Snap_Near",
"Draft_Snap_Ortho",
"Draft_Snap_Grid",
"Draft_Snap_WorkingPlane",
"Draft_Snap_Dimensions",
# "Separator", # Removed: if the Python generated BIM snap toolbar
# is displayed in the Draft WB the separator appears
# after the last button. Can be reinstated when the
# BIM WB has a `normal` snap toolbar as well.
"Draft_ToggleGrid"]
return [
"Draft_Snap_Lock",
"Draft_Snap_Endpoint",
"Draft_Snap_Midpoint",
"Draft_Snap_Center",
"Draft_Snap_Angle",
"Draft_Snap_Intersection",
"Draft_Snap_Perpendicular",
"Draft_Snap_Extension",
"Draft_Snap_Parallel",
"Draft_Snap_Special",
"Draft_Snap_Near",
"Draft_Snap_Ortho",
"Draft_Snap_Grid",
"Draft_Snap_WorkingPlane",
"Draft_Snap_Dimensions",
# "Separator", # Removed: if the Python generated BIM snap toolbar
# is displayed in the Draft WB the separator appears
# after the last button. Can be reinstated when the
# BIM WB has a `normal` snap toolbar as well.
"Draft_ToggleGrid",
]
def get_draft_context_commands():
"""Return the context menu commands list."""
return ["Draft_SetStyle",
"Draft_ApplyStyle",
"Separator",
"Draft_Layer",
"Draft_LayerManager",
"Draft_AddNamedGroup",
"Draft_SelectGroup",
"Draft_ToggleConstructionMode",
"Separator",
"Draft_AddToLayer",
"Draft_AddToGroup",
"Draft_AddConstruction",
"Separator",
"Draft_ToggleDisplayMode",
"Draft_ToggleGrid",
"Draft_SelectPlane",
"Draft_WorkingPlaneProxy"]
return [
"Draft_SetStyle",
"Draft_ApplyStyle",
"Separator",
"Draft_Layer",
"Draft_LayerManager",
"Draft_AddNamedGroup",
"Draft_SelectGroup",
"Draft_ToggleConstructionMode",
"Separator",
"Draft_AddToLayer",
"Draft_AddToGroup",
"Draft_AddConstruction",
"Separator",
"Draft_ToggleDisplayMode",
"Draft_ToggleGrid",
"Draft_SelectPlane",
"Draft_WorkingPlaneProxy",
]
def init_toolbar(workbench, toolbar, cmd_list):
@@ -231,4 +245,5 @@ def init_menu(workbench, menu_list, cmd_list):
else:
workbench.appendMenu(menu_list, [cmd])
## @}

View File

@@ -56,10 +56,12 @@ def _log(text, end="\n"):
"""Write messages to the log file including the line ending."""
App.Console.PrintLog(text + end)
def _toolmsg(text, end="\n"):
"""Write messages to the console including the line ending,
only if ToolMessages pref setting is True"""
if params.get_param("ToolMessages"):
App.Console.PrintMessage(text + end)
## @}

View File

@@ -21,7 +21,7 @@
# * *
# ***************************************************************************
""" Contains a parameter observer class and parameter related functions."""
"""Contains a parameter observer class and parameter related functions."""
import os
import PySide.QtCore as QtCore
@@ -29,6 +29,7 @@ import xml.etree.ElementTree as ET
import FreeCAD as App
import Draft_rc
try:
import Arch_rc
except ModuleNotFoundError:
@@ -40,14 +41,23 @@ if App.GuiUp:
import FreeCADGui as Gui
from PySide import QtWidgets
class ParamObserverDraft:
def slotParamChanged(self, param_grp, typ, entry, value):
if entry == "textheight":
_param_observer_callback_tray()
return
if entry in ("gridBorder", "gridShowHuman", "coloredGridAxes", "gridEvery",
"gridSpacing", "gridSize", "gridTransparency", "gridColor"):
if entry in (
"gridBorder",
"gridShowHuman",
"coloredGridAxes",
"gridEvery",
"gridSpacing",
"gridSize",
"gridTransparency",
"gridColor",
):
_param_observer_callback_grid()
return
if entry == "DefaultAnnoScaleMultiplier":
@@ -83,6 +93,7 @@ class ParamObserverView:
_param_observer_callback_snaptextsize()
return
def _param_observer_callback_tray():
if not hasattr(Gui, "draftToolBar"):
return
@@ -96,6 +107,7 @@ def _param_observer_callback_scalemultiplier(value):
# value is a string.
# import has to happen here to avoid circular imports
from draftutils import init_draft_statusbar
if not value:
return
value = float(value)
@@ -103,7 +115,7 @@ def _param_observer_callback_scalemultiplier(value):
return
mw = Gui.getMainWindow()
sb = mw.statusBar()
scale_widget = sb.findChild(QtWidgets.QToolBar,"draft_scale_widget")
scale_widget = sb.findChild(QtWidgets.QToolBar, "draft_scale_widget")
if scale_widget is not None:
scale_label = init_draft_statusbar.scale_to_label(1 / value)
scale_widget.scaleLabel.setText(scale_label)
@@ -138,6 +150,7 @@ def _param_observer_callback_snapbar(value):
def _param_observer_callback_snapwidget():
# import has to happen here to avoid circular imports
from draftutils import init_draft_statusbar
if Gui.activeWorkbench().name() == "DraftWorkbench":
init_draft_statusbar.hide_draft_statusbar()
init_draft_statusbar.show_draft_statusbar()
@@ -146,6 +159,7 @@ def _param_observer_callback_snapwidget():
def _param_observer_callback_scalewidget():
# import has to happen here to avoid circular imports
from draftutils import init_draft_statusbar
if Gui.activeWorkbench().name() == "DraftWorkbench":
init_draft_statusbar.hide_draft_statusbar()
init_draft_statusbar.show_draft_statusbar()
@@ -176,6 +190,7 @@ def _param_observer_callback_svg_pattern():
# imports have to happen here to avoid circular imports
from draftutils import utils
from draftviewproviders import view_base
utils.load_svg_patterns()
if App.ActiveDocument is None:
return
@@ -190,22 +205,30 @@ def _param_observer_callback_svg_pattern():
for obj in doc.Objects:
if hasattr(obj, "ViewObject"):
vobj = obj.ViewObject
if hasattr(vobj, "Pattern") \
and hasattr(vobj, "Proxy") \
and isinstance(vobj.Proxy, view_base.ViewProviderDraft) \
and vobj.getEnumerationsOfProperty("Pattern") != pats:
if (
hasattr(vobj, "Pattern")
and hasattr(vobj, "Proxy")
and isinstance(vobj.Proxy, view_base.ViewProviderDraft)
and vobj.getEnumerationsOfProperty("Pattern") != pats
):
vobjs.append(vobj)
if vobjs:
data.append([doc, vobjs])
if not data:
return
msg = translate("draft",
"""Do you want to update the SVG pattern options
of existing objects in all opened documents?""")
res = QtWidgets.QMessageBox.question(None, "Update SVG patterns", msg,
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
QtWidgets.QMessageBox.No)
msg = translate(
"draft",
"""Do you want to update the SVG pattern options
of existing objects in all opened documents?""",
)
res = QtWidgets.QMessageBox.question(
None,
"Update SVG patterns",
msg,
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
QtWidgets.QMessageBox.No,
)
if res == QtWidgets.QMessageBox.No:
return
@@ -229,11 +252,13 @@ def _param_observer_start():
_param_observer_start_view()
def _param_observer_start_draft(param_grp = App.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")):
def _param_observer_start_draft(
param_grp=App.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft"),
):
param_grp.AttachManager(ParamObserverDraft())
def _param_observer_start_view(param_grp = App.ParamGet("User parameter:BaseApp/Preferences/View")):
def _param_observer_start_view(param_grp=App.ParamGet("User parameter:BaseApp/Preferences/View")):
param_grp.AttachManager(ParamObserverView())
@@ -350,7 +375,7 @@ def _param_from_PrefLineEdit(widget):
for elem in list(widget):
if "name" in elem.keys():
att_name = elem.attrib["name"]
if att_name == "text": # Can be missing.
if att_name == "text": # Can be missing.
value = elem.find("string").text # If text is missing value will be None here.
elif att_name == "prefEntry":
entry = elem.find("cstring").text
@@ -376,6 +401,7 @@ def _param_from_PrefFileChooser(widget):
def _param_from_PrefFontBox(widget):
if App.GuiUp:
from PySide import QtGui
font = QtGui.QFont()
font.setStyleHint(QtGui.QFont.StyleHint.SansSerif)
value = font.defaultFamily()
@@ -403,12 +429,12 @@ def _get_shape_string_font_file():
# Mac fonts: "geneva" and "helvetica"
# Linux fonts: "dejavusans" and "freesans"
favorite_names = ("arial", "geneva", "helvetica", "dejavusans", "freesans")
font_file_sans = None # Font with name containing "sans". 1st fallback.
font_file_sans = None # Font with name containing "sans". 1st fallback.
font_file_alpha = None # Font with name starting with a letter. 2nd fallback.
# Reverse the order of the paths so that user related paths come last:
for path in QtCore.QStandardPaths.standardLocations(QtCore.QStandardPaths.FontsLocation)[::-1]:
# We don't use os.path.join as dir_path has forward slashes even on Windows.
for (dir_path, dir_names, file_names) in os.walk(path):
for dir_path, dir_names, file_names in os.walk(path):
for file_name in file_names:
base_name, ext = [s.lower() for s in os.path.splitext(file_name)]
if not ext in (".ttc", ".ttf"):
@@ -432,8 +458,9 @@ def _get_param_dictionary():
param_dict = {}
hatch_pattern_file = App.getResourceDir().replace("\\", "/").rstrip("/") \
+ "/Mod/TechDraw/PAT/FCPAT.pat"
hatch_pattern_file = (
App.getResourceDir().replace("\\", "/").rstrip("/") + "/Mod/TechDraw/PAT/FCPAT.pat"
)
# Draft parameters that are not in the preferences:
# fmt: off
@@ -633,26 +660,27 @@ def _get_param_dictionary():
}
# fmt: on
# Preferences ui files are stored in resource files.
# For the Draft Workbench: /Mod/Draft/Draft_rc.py
# For the Arch Workbench: /Mod/Arch/Arch_rc.py
for fnm in (":/ui/preferences-draft.ui",
":/ui/preferences-draftinterface.ui",
":/ui/preferences-draftsnap.ui",
":/ui/preferences-drafttexts.ui",
":/ui/preferences-draftvisual.ui",
":/ui/preferences-dwg.ui",
":/ui/preferences-dxf.ui",
":/ui/preferences-oca.ui",
":/ui/preferences-svg.ui",
":/ui/preferences-arch.ui",
":/ui/preferences-archdefaults.ui",
":/ui/preferences-dae.ui",
":/ui/preferences-ifc.ui",
":/ui/preferences-ifc-export.ui",
":/ui/preferences-sh3d-import.ui",
":/ui/preferences-webgl.ui",):
for fnm in (
":/ui/preferences-draft.ui",
":/ui/preferences-draftinterface.ui",
":/ui/preferences-draftsnap.ui",
":/ui/preferences-drafttexts.ui",
":/ui/preferences-draftvisual.ui",
":/ui/preferences-dwg.ui",
":/ui/preferences-dxf.ui",
":/ui/preferences-oca.ui",
":/ui/preferences-svg.ui",
":/ui/preferences-arch.ui",
":/ui/preferences-archdefaults.ui",
":/ui/preferences-dae.ui",
":/ui/preferences-ifc.ui",
":/ui/preferences-ifc-export.ui",
":/ui/preferences-sh3d-import.ui",
":/ui/preferences-webgl.ui",
):
# https://stackoverflow.com/questions/14750997/load-txt-file-from-resources-in-python
fd = QtCore.QFile(fnm)

View File

@@ -122,18 +122,17 @@ class ToDo:
The lists are `itinerary`, `commitlist` and `afteritinerary`.
"""
if _DEBUG:
_msg("Debug: doing delayed tasks.\n"
"itinerary: {0}\n"
"commitlist: {1}\n"
"afteritinerary: {2}\n".format(todo.itinerary,
todo.commitlist,
todo.afteritinerary))
_msg(
"Debug: doing delayed tasks.\n"
"itinerary: {0}\n"
"commitlist: {1}\n"
"afteritinerary: {2}\n".format(todo.itinerary, todo.commitlist, todo.afteritinerary)
)
try:
for f, arg in ToDo.itinerary:
try:
if _DEBUG_inner:
_msg("Debug: executing.\n"
"function: {}\n".format(f))
_msg("Debug: executing.\n" "function: {}\n".format(f))
if arg or (arg is False):
f(arg)
else:
@@ -141,13 +140,14 @@ class ToDo:
except Exception:
_log(traceback.format_exc())
_err(traceback.format_exc())
wrn = ("ToDo.doTasks, Unexpected error:\n"
"{0}\n"
"in {1}({2})".format(sys.exc_info()[0], f, arg))
wrn = (
"ToDo.doTasks, Unexpected error:\n"
"{0}\n"
"in {1}({2})".format(sys.exc_info()[0], f, arg)
)
_wrn(wrn)
except ReferenceError:
_wrn("Debug: ToDo.doTasks: "
"queue contains a deleted object, skipping")
_wrn("Debug: ToDo.doTasks: " "queue contains a deleted object, skipping")
ToDo.itinerary = []
if ToDo.commitlist:
@@ -155,8 +155,7 @@ class ToDo:
ToDo.commitlist = [] # Reset immediately to avoid race condition.
for name, func in commit_list:
if _DEBUG_inner:
_msg("Debug: committing.\n"
"name: {}\n".format(name))
_msg("Debug: committing.\n" "name: {}\n".format(name))
try:
name = str(name)
App.activeDocument().openTransaction(name)
@@ -169,20 +168,20 @@ class ToDo:
except Exception:
_log(traceback.format_exc())
_err(traceback.format_exc())
wrn = ("ToDo.doTasks, Unexpected error:\n"
"{0}\n"
"in {1}".format(sys.exc_info()[0], func))
wrn = (
"ToDo.doTasks, Unexpected error:\n"
"{0}\n"
"in {1}".format(sys.exc_info()[0], func)
)
_wrn(wrn)
# Restack Draft screen widgets after creation
if hasattr(Gui, "Snapper"):
Gui.Snapper.restack()
for f, arg in ToDo.afteritinerary:
try:
if _DEBUG_inner:
_msg("Debug: executing after.\n"
"function: {}\n".format(f))
_msg("Debug: executing after.\n" "function: {}\n".format(f))
if arg:
f(arg)
else:
@@ -190,9 +189,11 @@ class ToDo:
except Exception:
_log(traceback.format_exc())
_err(traceback.format_exc())
wrn = ("ToDo.doTasks, Unexpected error:\n"
"{0}\n"
"in {1}({2})".format(sys.exc_info()[0], f, arg))
wrn = (
"ToDo.doTasks, Unexpected error:\n"
"{0}\n"
"in {1}({2})".format(sys.exc_info()[0], f, arg)
)
_wrn(wrn)
ToDo.afteritinerary = []
@@ -224,8 +225,7 @@ class ToDo:
f(arg)
"""
if _DEBUG:
_msg("Debug: delaying.\n"
"function: {}\n".format(f))
_msg("Debug: delaying.\n" "function: {}\n".format(f))
if ToDo.itinerary == []:
QtCore.QTimer.singleShot(0, ToDo.doTasks)
ToDo.itinerary.append((f, arg))
@@ -254,8 +254,7 @@ class ToDo:
See the attributes of the `ToDo` class for more information.
"""
if _DEBUG:
_msg("Debug: delaying commit.\n"
"commitlist: {}\n".format(cl))
_msg("Debug: delaying commit.\n" "commitlist: {}\n".format(cl))
QtCore.QTimer.singleShot(0, ToDo.doTasks)
ToDo.commitlist = cl
@@ -276,8 +275,7 @@ class ToDo:
and append it to the `afteritinerary` list.
"""
if _DEBUG:
_msg("Debug: delaying after.\n"
"function: {}\n".format(f))
_msg("Debug: delaying after.\n" "function: {}\n".format(f))
if ToDo.afteritinerary == []:
QtCore.QTimer.singleShot(0, ToDo.doTasks)
ToDo.afteritinerary.append((f, arg))

View File

@@ -38,10 +38,10 @@ def get_default_unit(dim):
It is based on the user preferences.
"""
if dim == 'Length':
if dim == "Length":
qty = App.Units.Quantity(1.0, App.Units.Length)
uom = qty.getUserPreferred()[2]
elif dim == 'Angle':
elif dim == "Angle":
qty = App.Units.Quantity(1.0, App.Units.Angle)
uom = qty.getUserPreferred()[2]
else:
@@ -52,15 +52,15 @@ def get_default_unit(dim):
getDefaultUnit = get_default_unit
def make_format_spec(decimals=4, dim='Length'):
def make_format_spec(decimals=4, dim="Length"):
"""Return a string format specifier with decimals for a dimension.
It is based on the user preferences.
"""
if dim == 'Length':
fmt_spec = "%." + str(decimals) + "f " + get_default_unit('Length')
elif dim == 'Angle':
fmt_spec = "%." + str(decimals) + "f " + get_default_unit('Angle')
if dim == "Length":
fmt_spec = "%." + str(decimals) + "f " + get_default_unit("Length")
elif dim == "Angle":
fmt_spec = "%." + str(decimals) + "f " + get_default_unit("Angle")
else:
fmt_spec = "%." + str(decimals) + "f " + "??"
return fmt_spec
@@ -69,8 +69,7 @@ def make_format_spec(decimals=4, dim='Length'):
makeFormatSpec = make_format_spec
def display_external(internal_value,
decimals=None, dim='Length', showUnit=True, unit=None):
def display_external(internal_value, decimals=None, dim="Length", showUnit=True, unit=None):
"""Return a converted value for display, according to the unit schema.
Parameters
@@ -92,7 +91,7 @@ def display_external(internal_value,
A unit string such as `'mm'`, `'cm'`, `'m'`, `'in'`, `'ft'`,
in which to express the returned value.
"""
if dim == 'Length':
if dim == "Length":
q = App.Units.Quantity(internal_value, App.Units.Length)
if not unit:
if decimals is None and showUnit:
@@ -101,7 +100,7 @@ def display_external(internal_value,
conversion = q.getUserPreferred()[1]
uom = q.getUserPreferred()[2]
elif unit.lower() == "arch":
return App.Units.schemaTranslate(q,5)[0].replace("+"," ")
return App.Units.schemaTranslate(q, 5)[0].replace("+", " ")
else:
try:
uom = unit
@@ -110,7 +109,7 @@ def display_external(internal_value,
except Exception:
conversion = q.getUserPreferred()[1]
uom = q.getUserPreferred()[2]
elif dim == 'Angle':
elif dim == "Angle":
q = App.Units.Quantity(internal_value, App.Units.Angle)
if decimals is None:
return q.UserString

View File

@@ -65,25 +65,25 @@ def get_default_annotation_style():
arrow_start_type_index = params.get_param("dimsymbolstart")
arrow_end_type_index = params.get_param("dimsymbolend")
return {
"ArrowSizeStart": ("float", params.get_param("arrowsizestart")),
"ArrowSizeEnd": ("float", params.get_param("arrowsizeend")),
"ArrowTypeStart": ("index", arrow_start_type_index, ARROW_TYPES[arrow_start_type_index]),
"ArrowTypeEnd": ("index", arrow_end_type_index, ARROW_TYPES[arrow_end_type_index]),
"Decimals": ("int", params.get_param("dimPrecision")),
"DimOvershoot": ("float", params.get_param("dimovershoot")),
"ExtLines": ("float", params.get_param("extlines")),
"ExtOvershoot": ("float", params.get_param("extovershoot")),
"FontName": ("font", params.get_param("textfont")),
"FontSize": ("float", params.get_param("textheight")),
"LineColor": ("color", params.get_param("DefaultAnnoLineColor") | 0x000000FF),
"LineSpacing": ("float", params.get_param("LineSpacing")),
"LineWidth": ("int", params.get_param("DefaultAnnoLineWidth")),
"ArrowSizeStart": ("float", params.get_param("arrowsizestart")),
"ArrowSizeEnd": ("float", params.get_param("arrowsizeend")),
"ArrowTypeStart": ("index", arrow_start_type_index, ARROW_TYPES[arrow_start_type_index]),
"ArrowTypeEnd": ("index", arrow_end_type_index, ARROW_TYPES[arrow_end_type_index]),
"Decimals": ("int", params.get_param("dimPrecision")),
"DimOvershoot": ("float", params.get_param("dimovershoot")),
"ExtLines": ("float", params.get_param("extlines")),
"ExtOvershoot": ("float", params.get_param("extovershoot")),
"FontName": ("font", params.get_param("textfont")),
"FontSize": ("float", params.get_param("textheight")),
"LineColor": ("color", params.get_param("DefaultAnnoLineColor") | 0x000000FF),
"LineSpacing": ("float", params.get_param("LineSpacing")),
"LineWidth": ("int", params.get_param("DefaultAnnoLineWidth")),
"ScaleMultiplier": ("float", params.get_param("DefaultAnnoScaleMultiplier")),
"ShowLine": ("bool", params.get_param("DimShowLine")),
"ShowUnit": ("bool", params.get_param("showUnit")),
"TextColor": ("color", params.get_param("DefaultTextColor") | 0x000000FF),
"TextSpacing": ("float", params.get_param("dimspacing")),
"UnitOverride": ("str", params.get_param("overrideUnit"))
"ShowLine": ("bool", params.get_param("DimShowLine")),
"ShowUnit": ("bool", params.get_param("showUnit")),
"TextColor": ("color", params.get_param("DefaultTextColor") | 0x000000FF),
"TextSpacing": ("float", params.get_param("dimspacing")),
"UnitOverride": ("str", params.get_param("overrideUnit")),
}
@@ -99,9 +99,11 @@ def repair_annotation_style(style):
ArrowType has been replaced by ArrowTypeStart and ArrowTypeEnd.
"""
for key in ("ArrowSize", "ArrowType"):
if style.get(key) is not None \
and style.get(key + "Start") is None \
and style.get(key + "End") is None:
if (
style.get(key) is not None
and style.get(key + "Start") is None
and style.get(key + "End") is None
):
style[key + "Start"] = style[key]
style[key + "End"] = style[key]
default = get_default_annotation_style()
@@ -123,25 +125,25 @@ def get_default_shape_style():
display_mode_index = params.get_param("DefaultDisplayMode")
draw_style_index = params.get_param("DefaultDrawStyle")
return {
"DisplayMode": ("index", display_mode_index, DISPLAY_MODES[display_mode_index]),
"DrawStyle": ("index", draw_style_index, DRAW_STYLES[draw_style_index]),
"LineColor": ("color", params.get_param_view("DefaultShapeLineColor") | 0x000000FF),
"LineWidth": ("int", params.get_param_view("DefaultShapeLineWidth")),
"PointColor": ("color", params.get_param_view("DefaultShapeVertexColor") | 0x000000FF),
"PointSize": ("int", params.get_param_view("DefaultShapePointSize")),
"ShapeAppearance": ("material", (get_view_material(), ))
"DisplayMode": ("index", display_mode_index, DISPLAY_MODES[display_mode_index]),
"DrawStyle": ("index", draw_style_index, DRAW_STYLES[draw_style_index]),
"LineColor": ("color", params.get_param_view("DefaultShapeLineColor") | 0x000000FF),
"LineWidth": ("int", params.get_param_view("DefaultShapeLineWidth")),
"PointColor": ("color", params.get_param_view("DefaultShapeVertexColor") | 0x000000FF),
"PointSize": ("int", params.get_param_view("DefaultShapePointSize")),
"ShapeAppearance": ("material", (get_view_material(),)),
}
def get_view_material():
"""Return a ShapeAppearance material with properties based on the preferences."""
material = App.Material()
material.AmbientColor = params.get_param_view("DefaultAmbientColor") | 0x000000FF
material.DiffuseColor = params.get_param_view("DefaultShapeColor") | 0x000000FF
material.AmbientColor = params.get_param_view("DefaultAmbientColor") | 0x000000FF
material.DiffuseColor = params.get_param_view("DefaultShapeColor") | 0x000000FF
material.EmissiveColor = params.get_param_view("DefaultEmissiveColor") | 0x000000FF
material.Shininess = params.get_param_view("DefaultShapeShininess") / 100
material.Shininess = params.get_param_view("DefaultShapeShininess") / 100
material.SpecularColor = params.get_param_view("DefaultSpecularColor") | 0x000000FF
material.Transparency = params.get_param_view("DefaultShapeTransparency") / 100
material.Transparency = params.get_param_view("DefaultShapeTransparency") / 100
return material
@@ -162,13 +164,14 @@ def string_encode_coin(ustr):
"""
try:
from pivy import coin
coin4 = coin.COIN_MAJOR_VERSION >= 4
except (ImportError, AttributeError):
coin4 = False
if coin4:
return ustr.encode('utf-8')
return ustr.encode("utf-8")
else:
return ustr.encode('latin1')
return ustr.encode("latin1")
stringencodecoin = string_encode_coin
@@ -297,8 +300,8 @@ def get_real_name(name):
at least one letter.
"""
for i in range(1, len(name) + 1):
if name[-i] not in '1234567890':
return name[:len(name) - (i - 1)]
if name[-i] not in "1234567890":
return name[: len(name) - (i - 1)]
return name
@@ -327,15 +330,16 @@ def get_type(obj):
or `None` if `obj` is `None`.
"""
import Part
if not obj:
return None
if isinstance(obj, Part.Shape):
return "Shape"
if hasattr(obj, "Class") and "Ifc" in str(obj.Class):
return obj.Class
if hasattr(obj, 'Proxy') and hasattr(obj.Proxy, "Type"):
if hasattr(obj, "Proxy") and hasattr(obj.Proxy, "Type"):
return obj.Proxy.Type
if hasattr(obj, 'TypeId'):
if hasattr(obj, "TypeId"):
return obj.TypeId
return "Unknown"
@@ -536,6 +540,7 @@ def shapify(obj, delete=True):
name = "Wire"
elif len(shape.Edges) == 1:
import DraftGeomUtils
if DraftGeomUtils.geomType(shape.Edges[0]) == "Line":
name = "Line"
else:
@@ -602,13 +607,19 @@ def compare_objects(obj1, obj2):
Any type of scripted object.
"""
if obj1.TypeId != obj2.TypeId:
_msg("'{0}' ({1}), '{2}' ({3}): ".format(obj1.Name, obj1.TypeId,
obj2.Name, obj2.TypeId)
+ translate("draft", "different types") + " (TypeId)")
_msg(
"'{0}' ({1}), '{2}' ({3}): ".format(obj1.Name, obj1.TypeId, obj2.Name, obj2.TypeId)
+ translate("draft", "different types")
+ " (TypeId)"
)
elif getType(obj1) != getType(obj2):
_msg("'{0}' ({1}), '{2}' ({3}): ".format(obj1.Name, get_type(obj1),
obj2.Name, get_type(obj2))
+ translate("draft", "different types") + " (Proxy.Type)")
_msg(
"'{0}' ({1}), '{2}' ({3}): ".format(
obj1.Name, get_type(obj1), obj2.Name, get_type(obj2)
)
+ translate("draft", "different types")
+ " (Proxy.Type)"
)
else:
for p in obj1.PropertiesList:
if p in obj2.PropertiesList:
@@ -616,15 +627,17 @@ def compare_objects(obj1, obj2):
pass
elif p == "Placement":
delta = obj1.Placement.Base.sub(obj2.Placement.Base)
text = translate("draft", "Objects have different placements. "
"Distance between the two base points:")
text = translate(
"draft",
"Objects have different placements. "
"Distance between the two base points:",
)
_msg(text + " " + str(delta.Length))
else:
if getattr(obj1, p) != getattr(obj2, p):
_msg("'{}' ".format(p) + translate("draft", "has a different value"))
else:
_msg("{} ".format(p)
+ translate("draft", "doesn't exist in one of the objects"))
_msg("{} ".format(p) + translate("draft", "doesn't exist in one of the objects"))
compareObjects = compare_objects
@@ -637,6 +650,7 @@ def load_svg_patterns():
attribute.
"""
import importSVG
App.svgpatterns = {}
# Get default patterns in the resource file
@@ -645,7 +659,7 @@ def load_svg_patterns():
file = ":/patterns/" + str(fn)
f = QtCore.QFile(file)
f.open(QtCore.QIODevice.ReadOnly)
p = importSVG.getContents(str(f.readAll()), 'pattern', True)
p = importSVG.getContents(str(f.readAll()), "pattern", True)
if p:
for k in p:
p[k] = [p[k], file]
@@ -657,25 +671,25 @@ def load_svg_patterns():
for f in os.listdir(altpat):
if f[-4:].upper() == ".SVG":
file = os.path.join(altpat, f)
p = importSVG.getContents(file, 'pattern')
p = importSVG.getContents(file, "pattern")
if p:
for k in p:
p[k] = [p[k], file]
App.svgpatterns.update(p)
# Get TechDraw patterns
altpat = os.path.join(App.getResourceDir(),"Mod","TechDraw","Patterns")
altpat = os.path.join(App.getResourceDir(), "Mod", "TechDraw", "Patterns")
if os.path.isdir(altpat):
for f in os.listdir(altpat):
if f[-4:].upper() == ".SVG":
file = os.path.join(altpat, f)
p = importSVG.getContents(file, 'pattern')
p = importSVG.getContents(file, "pattern")
if p:
for k in p:
p[k] = [p[k], file]
else:
# some TD pattern files have no <pattern> definition but can still be used by Draft
p = {f[:-4]:["<pattern></pattern>",file]}
p = {f[:-4]: ["<pattern></pattern>", file]}
App.svgpatterns.update(p)
@@ -714,10 +728,10 @@ def get_rgb(color, testbw=True):
testwb : bool (default = True)
Pure white will be converted into pure black.
"""
r = str(hex(int(color[0]*255)))[2:].zfill(2)
g = str(hex(int(color[1]*255)))[2:].zfill(2)
b = str(hex(int(color[2]*255)))[2:].zfill(2)
col = "#"+r+g+b
r = str(hex(int(color[0] * 255)))[2:].zfill(2)
g = str(hex(int(color[1] * 255)))[2:].zfill(2)
b = str(hex(int(color[2] * 255)))[2:].zfill(2)
col = "#" + r + g + b
if testbw:
if col == "#ffffff":
# print(params.get_param("SvgLinesBlack"))
@@ -757,8 +771,7 @@ def argb_to_rgba(color):
def rgba_to_argb(color):
"""Change byte order of a 4 byte color int from RGBA (FreeCAD) to ARGB (Qt).
"""
"""Change byte order of a 4 byte color int from RGBA (FreeCAD) to ARGB (Qt)."""
return ((color & 0xFFFFFF00) >> 8) + ((color & 0xFF) << 24)
@@ -773,10 +786,7 @@ def get_rgba_tuple(color, typ=1.0):
If float the values in the returned tuple are in the 0.0-1.0 range.
Else the values are in the 0-255 range.
"""
color = ((color >> 24) & 0xFF,
(color >> 16) & 0xFF,
(color >> 8) & 0xFF,
color & 0xFF)
color = ((color >> 24) & 0xFF, (color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF)
if type(typ) == float:
return tuple([x / 255.0 for x in color])
else:
@@ -837,6 +847,7 @@ def _modifiers_process_selection(sels, copy, scale=False, add_movable_children=F
def _modifiers_get_group_contents(obj):
from draftutils import groups
return groups.get_group_contents(obj, addgroups=True, spaces=True, noarchchild=True)
@@ -871,14 +882,20 @@ def _modifiers_filter_objects(objs, copy, scale=False):
if parent.isDerivedFrom("Part::Feature"):
parents.append(parent.Name)
if len(parents) > 1:
message = translate("draft", "%s shares a base with %d other objects. Please check if you want to modify this.") % (obj.Name,len(parents) - 1)
message = translate(
"draft",
"%s shares a base with %d other objects. Please check if you want to modify this.",
) % (obj.Name, len(parents) - 1)
_err(message)
if not scale or utils.get_type(obj.Base) == "Wire":
result.append(obj.Base)
elif not copy \
and hasattr(obj, "Placement") \
and "ReadOnly" in obj.getEditorMode("Placement"):
_err(translate("draft", "%s cannot be modified because its placement is readonly") % obj.Name)
elif (
not copy and hasattr(obj, "Placement") and "ReadOnly" in obj.getEditorMode("Placement")
):
_err(
translate("draft", "%s cannot be modified because its placement is readonly")
% obj.Name
)
elif not scale or is_scalable(obj):
result.append(obj)
return result
@@ -1091,16 +1108,34 @@ def use_instead(function, version=""):
then we should not give a version.
"""
if version:
_wrn(translate("draft", "This function will be deprecated in {}. Please use '{}'.") .format(version, function))
_wrn(
translate("draft", "This function will be deprecated in {}. Please use '{}'.").format(
version, function
)
)
else:
_wrn(translate("draft", "This function will be deprecated. Please use '{}'.") .format(function))
_wrn(
translate("draft", "This function will be deprecated. Please use '{}'.").format(
function
)
)
def pyopen(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None):
def pyopen(
file,
mode="r",
buffering=-1,
encoding=None,
errors=None,
newline=None,
closefd=True,
opener=None,
):
if encoding is None:
encoding = 'utf-8'
encoding = "utf-8"
return open(file, mode, buffering, encoding, errors, newline, closefd, opener)
def toggle_working_plane(obj, action=None, restore=False, dialog=None):
"""Toggle the active state of a working plane object.
@@ -1136,8 +1171,8 @@ def toggle_working_plane(obj, action=None, restore=False, dialog=None):
context = "NativeIFC"
# Check if the object is already active in its context
is_active_arch = (FreeCADGui.ActiveDocument.ActiveView.getActiveObject("Arch") == obj)
is_active_ifc = (FreeCADGui.ActiveDocument.ActiveView.getActiveObject("NativeIFC") == obj)
is_active_arch = FreeCADGui.ActiveDocument.ActiveView.getActiveObject("Arch") == obj
is_active_ifc = FreeCADGui.ActiveDocument.ActiveView.getActiveObject("NativeIFC") == obj
is_active = is_active_arch or is_active_ifc
if is_active:
# Deactivate the object
@@ -1146,8 +1181,11 @@ def toggle_working_plane(obj, action=None, restore=False, dialog=None):
if is_active_ifc:
FreeCADGui.ActiveDocument.ActiveView.setActiveObject("NativeIFC", None)
if hasattr(obj, "ViewObject") and hasattr(obj.ViewObject, "Proxy") and \
hasattr(obj.ViewObject.Proxy, "setWorkingPlane"):
if (
hasattr(obj, "ViewObject")
and hasattr(obj.ViewObject, "Proxy")
and hasattr(obj.ViewObject.Proxy, "setWorkingPlane")
):
obj.ViewObject.Proxy.setWorkingPlane(restore=True)
if action:
action.setChecked(False)
@@ -1157,8 +1195,11 @@ def toggle_working_plane(obj, action=None, restore=False, dialog=None):
else:
# Activate the object
FreeCADGui.ActiveDocument.ActiveView.setActiveObject(context, obj)
if hasattr(obj, "ViewObject") and hasattr(obj.ViewObject, "Proxy") and \
hasattr(obj.ViewObject.Proxy, "setWorkingPlane"):
if (
hasattr(obj, "ViewObject")
and hasattr(obj.ViewObject, "Proxy")
and hasattr(obj.ViewObject.Proxy, "setWorkingPlane")
):
obj.ViewObject.Proxy.setWorkingPlane()
if action:
action.setChecked(True)
@@ -1166,4 +1207,5 @@ def toggle_working_plane(obj, action=None, restore=False, dialog=None):
dialog.buttonActive.setChecked(True)
return True
## @}