Draft: migrate Layer object and function to the new structure
Move `make_layer` to `draftmake`; `Layer` and `LayerContainer` to `draftobjects`; `ViewProviderLayer` and `ViewProviderLayerContainer` to `draftviewproviders`. The make function and the classes are imported in `Draft.py` to support the usage of the older `VisGroup`.
This commit is contained in:
@@ -117,6 +117,7 @@ SET(Draft_make_functions
|
||||
draftmake/make_facebinder.py
|
||||
draftmake/make_fillet.py
|
||||
draftmake/make_label.py
|
||||
draftmake/make_layer.py
|
||||
draftmake/make_line.py
|
||||
draftmake/make_orthoarray.py
|
||||
draftmake/make_patharray.py
|
||||
@@ -150,6 +151,7 @@ SET(Draft_objects
|
||||
draftobjects/fillet.py
|
||||
draftobjects/draftlink.py
|
||||
draftobjects/label.py
|
||||
draftobjects/layer.py
|
||||
draftobjects/dimension.py
|
||||
draftobjects/patharray.py
|
||||
draftobjects/point.py
|
||||
@@ -179,6 +181,7 @@ SET(Draft_view_providers
|
||||
draftviewproviders/view_fillet.py
|
||||
draftviewproviders/view_draftlink.py
|
||||
draftviewproviders/view_label.py
|
||||
draftviewproviders/view_layer.py
|
||||
draftviewproviders/view_dimension.py
|
||||
draftviewproviders/view_point.py
|
||||
draftviewproviders/view_rectangle.py
|
||||
|
||||
@@ -368,10 +368,15 @@ from draftmake.make_fillet import make_fillet
|
||||
if App.GuiUp:
|
||||
from draftviewproviders.view_fillet import ViewProviderFillet
|
||||
|
||||
# Layers
|
||||
from DraftLayer import Layer as _VisGroup
|
||||
from DraftLayer import ViewProviderLayer as _ViewProviderVisGroup
|
||||
from DraftLayer import makeLayer
|
||||
from draftobjects.layer import (Layer,
|
||||
_VisGroup)
|
||||
|
||||
from draftmake.make_layer import (make_layer,
|
||||
makeLayer)
|
||||
|
||||
if App.GuiUp:
|
||||
from draftviewproviders.view_layer import (ViewProviderLayer,
|
||||
_ViewProviderVisGroup)
|
||||
|
||||
# Annotation objects
|
||||
from draftobjects.dimension import (LinearDimension,
|
||||
|
||||
@@ -45,8 +45,10 @@ is only required to migrate old objects created in that time
|
||||
with the 0.19 development version.
|
||||
|
||||
Since this module is only used to migrate older objects, it is only temporary,
|
||||
and will be removed after one year of the original introduction of the tool,
|
||||
that is, in August 2020.
|
||||
and will be removed after one year, that is, in January 2021.
|
||||
|
||||
The explanation of the migration methods is in the wiki page:
|
||||
https://wiki.freecadweb.org/Scripted_objects_migration
|
||||
"""
|
||||
## @package DraftFillet
|
||||
# \ingroup DRAFT
|
||||
@@ -54,7 +56,7 @@ that is, in August 2020.
|
||||
#
|
||||
# This module is only required to migrate old objects created
|
||||
# from August 2019 to February 2020. It will be removed definitely
|
||||
# in August 2020, as the new Fillet object should be available.
|
||||
# in January 2021, as the new Fillet object should be available.
|
||||
|
||||
import FreeCAD as App
|
||||
import draftobjects.fillet
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
|
||||
# * Copyright (c) 2014 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2020 Eliud Cabrera Castillo <e.cabrera-castillo@tum.de> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
@@ -20,423 +21,42 @@
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""Provides the Layer object.
|
||||
"""Provides the Layer object. This module is deprecated.
|
||||
|
||||
The original Layer object was a VisGroup, but it was renamed to Layer
|
||||
in the development cycle of 0.19.
|
||||
In 6f896d8f22 (April 2014) the `Layer` object was created,
|
||||
but in 4e595bd7bb (June 2014) it was renamed to `VisGroup`.
|
||||
However, it was not used a lot, so in commit 5ee99ca4e (June 2019)
|
||||
it was renamed again to `Layer`, but this time it was improved to behave
|
||||
more like a proper layer system to control the visual properties
|
||||
of the contained objects. All new code was moved to this module.
|
||||
|
||||
With the reorganization of the entire Draft workbench, the Layer object
|
||||
and associated viewprovider, make function, and Gui Command
|
||||
have been moved to the appropriate directories `draftobjects`,
|
||||
`draftviewproviders`, `draftmake`, and `draftguitools`.
|
||||
Therefore, this module is only required to migrate old objects
|
||||
created with v0.18 and earlier, and certain development version of v0.19.
|
||||
|
||||
Since this module is only used to migrate older objects, it is only temporary,
|
||||
and will be removed after one year, that is, in July 2021.
|
||||
|
||||
The explanation of the migration methods is in the wiki page:
|
||||
https://wiki.freecadweb.org/Scripted_objects_migration
|
||||
"""
|
||||
## @package DraftLayer
|
||||
# \ingroup DRAFT
|
||||
# \brief Provides the Layer object
|
||||
|
||||
import FreeCAD
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
|
||||
|
||||
def translate(ctx, txt):
|
||||
return txt
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctx, txt):
|
||||
return txt
|
||||
|
||||
|
||||
"""This module contains everything related to Draft Layers"""
|
||||
|
||||
|
||||
def makeLayer(name=None, linecolor=None, drawstyle=None, shapecolor=None, transparency=None):
|
||||
"""makeLayer([name,linecolor,drawstyle,shapecolor,transparency]):
|
||||
creates a Layer object in the active document
|
||||
"""
|
||||
if not FreeCAD.ActiveDocument:
|
||||
FreeCAD.Console.PrintError(translate("draft", "No active document. Aborting") + "\n")
|
||||
return
|
||||
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython", "Layer")
|
||||
Layer(obj)
|
||||
if name:
|
||||
obj.Label = name
|
||||
else:
|
||||
obj.Label = translate("draft", "Layer")
|
||||
if FreeCAD.GuiUp:
|
||||
ViewProviderLayer(obj.ViewObject)
|
||||
if linecolor:
|
||||
obj.ViewObject.LineColor = linecolor
|
||||
if drawstyle:
|
||||
obj.ViewObject.DrawStyle = drawstyle
|
||||
if shapecolor:
|
||||
obj.ViewObject.ShapeColor = shapecolor
|
||||
if transparency:
|
||||
obj.ViewObject.Transparency = transparency
|
||||
getLayerContainer().addObject(obj)
|
||||
return obj
|
||||
|
||||
|
||||
def getLayerContainer():
|
||||
"""getLayerContainer(): returns a group object to put layers in"""
|
||||
for obj in FreeCAD.ActiveDocument.Objects:
|
||||
if obj.Name == "LayerContainer":
|
||||
return obj
|
||||
obj = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroupPython", "LayerContainer")
|
||||
obj.Label = translate("draft", "Layers")
|
||||
LayerContainer(obj)
|
||||
if FreeCAD.GuiUp:
|
||||
ViewProviderLayerContainer(obj.ViewObject)
|
||||
return obj
|
||||
|
||||
|
||||
class Layer:
|
||||
"""The Draft Layer object"""
|
||||
|
||||
def __init__(self, obj):
|
||||
self.Type = "Layer"
|
||||
obj.Proxy = self
|
||||
self.Object = obj
|
||||
self.setProperties(obj)
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
self.setProperties(obj)
|
||||
|
||||
def setProperties(self, obj):
|
||||
if "Group" not in obj.PropertiesList:
|
||||
obj.addProperty(
|
||||
"App::PropertyLinkList",
|
||||
"Group",
|
||||
"Layer",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The objects that are part of this layer")
|
||||
)
|
||||
|
||||
def __getstate__(self):
|
||||
return self.Type
|
||||
|
||||
def __setstate__(self, state):
|
||||
if state:
|
||||
self.Type = state
|
||||
|
||||
def execute(self, obj):
|
||||
pass
|
||||
|
||||
def addObject(self, obj, child):
|
||||
g = obj.Group
|
||||
if child not in g:
|
||||
g.append(child)
|
||||
obj.Group = g
|
||||
|
||||
|
||||
class ViewProviderLayer:
|
||||
"""A View Provider for the Layer object"""
|
||||
|
||||
def __init__(self, vobj):
|
||||
vobj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"OverrideLineColorChildren",
|
||||
"Layer",
|
||||
QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"If on, the child objects of this layer will match its visual aspects"
|
||||
)
|
||||
)
|
||||
vobj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"OverrideShapeColorChildren",
|
||||
"Layer",
|
||||
QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"If on, the child objects of this layer will match its visual aspects"
|
||||
)
|
||||
)
|
||||
vobj.addProperty(
|
||||
"App::PropertyColor",
|
||||
"LineColor",
|
||||
"Layer",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The line color of the children of this layer")
|
||||
)
|
||||
vobj.addProperty(
|
||||
"App::PropertyColor",
|
||||
"ShapeColor",
|
||||
"Layer",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The shape color of the children of this layer")
|
||||
)
|
||||
vobj.addProperty(
|
||||
"App::PropertyFloat",
|
||||
"LineWidth",
|
||||
"Layer",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The line width of the children of this layer")
|
||||
)
|
||||
vobj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"DrawStyle",
|
||||
"Layer",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The draw style of the children of this layer")
|
||||
)
|
||||
vobj.addProperty(
|
||||
"App::PropertyInteger",
|
||||
"Transparency",
|
||||
"Layer",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The transparency of the children of this layer")
|
||||
)
|
||||
vobj.DrawStyle = ["Solid", "Dashed", "Dotted", "Dashdot"]
|
||||
|
||||
vobj.OverrideLineColorChildren = True
|
||||
vobj.OverrideShapeColorChildren = True
|
||||
c = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View").GetUnsigned("DefaultShapeLineColor", 255)
|
||||
vobj.LineColor = (((c >> 24) & 0xFF) / 255, ((c >> 16) & 0xFF) / 255, ((c >> 8) & 0xFF) / 255)
|
||||
w = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View").GetInt("DefaultShapeLineWidth", 2)
|
||||
vobj.LineWidth = w
|
||||
c = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View").GetUnsigned("DefaultShapeColor", 4294967295)
|
||||
vobj.ShapeColor = (((c >> 24) & 0xFF) / 255, ((c >> 16) & 0xFF) / 255, ((c >> 8) & 0xFF) / 255)
|
||||
vobj.DrawStyle = "Solid"
|
||||
|
||||
vobj.Proxy = self
|
||||
|
||||
def getIcon(self):
|
||||
if hasattr(self, "icondata"):
|
||||
return self.icondata
|
||||
import Draft_rc
|
||||
return ":/icons/Draft_Layer.svg"
|
||||
|
||||
def attach(self, vobj):
|
||||
self.Object = vobj.Object
|
||||
from pivy import coin
|
||||
sep = coin.SoGroup()
|
||||
vobj.addDisplayMode(sep, "Default")
|
||||
return
|
||||
|
||||
def claimChildren(self):
|
||||
if hasattr(self, "Object") and hasattr(self.Object, "Group"):
|
||||
return self.Object.Group
|
||||
|
||||
def getDisplayModes(self, vobj):
|
||||
return ["Default"]
|
||||
|
||||
def getDefaultDisplayMode(self):
|
||||
return "Default"
|
||||
|
||||
def setDisplayMode(self, mode):
|
||||
return mode
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
return None
|
||||
|
||||
def updateData(self, obj, prop):
|
||||
if prop == "Group":
|
||||
self.onChanged(obj.ViewObject, "LineColor")
|
||||
|
||||
def onChanged(self, vobj, prop):
|
||||
if hasattr(vobj, "OverrideLineColorChildren") and vobj.OverrideLineColorChildren:
|
||||
if hasattr(vobj, "Object") and hasattr(vobj.Object, "Group"):
|
||||
for o in vobj.Object.Group:
|
||||
if o.ViewObject:
|
||||
for p in ["LineColor", "ShapeColor", "LineWidth", "DrawStyle", "Transparency"]:
|
||||
if p == "ShapeColor":
|
||||
if hasattr(vobj, "OverrideShapeColorChildren") and vobj.OverrideShapeColorChildren:
|
||||
if hasattr(vobj, p):
|
||||
# see forum topic https://forum.freecadweb.org/viewtopic.php?f=23&t=42197
|
||||
setattr(o.ViewObject, p, getattr(vobj, p))
|
||||
else:
|
||||
if hasattr(vobj, p) and hasattr(o.ViewObject, p):
|
||||
setattr(o.ViewObject, p, getattr(vobj, p))
|
||||
|
||||
# give line color to texts
|
||||
if hasattr(vobj, "LineColor") and hasattr(o.ViewObject, "TextColor"):
|
||||
o.ViewObject.TextColor = vobj.LineColor
|
||||
|
||||
if (prop == "Visibility") and hasattr(vobj, "Visibility"):
|
||||
if hasattr(vobj, "Object") and hasattr(vobj.Object, "Group"):
|
||||
for o in vobj.Object.Group:
|
||||
if o.ViewObject and hasattr(o.ViewObject, "Visibility"):
|
||||
o.ViewObject.Visibility = vobj.Visibility
|
||||
|
||||
if (prop in ["LineColor", "ShapeColor"]) and hasattr(vobj, "LineColor") and hasattr(vobj, "ShapeColor"):
|
||||
from PySide import QtCore, QtGui
|
||||
lc = vobj.LineColor
|
||||
sc = vobj.ShapeColor
|
||||
lc = QtGui.QColor(int(lc[0] * 255), int(lc[1] * 255), int(lc[2] * 255))
|
||||
sc = QtGui.QColor(int(sc[0] * 255), int(sc[1] * 255), int(sc[2] * 255))
|
||||
p1 = QtCore.QPointF(2, 17)
|
||||
p2 = QtCore.QPointF(13, 8)
|
||||
p3 = QtCore.QPointF(30, 15)
|
||||
p4 = QtCore.QPointF(20, 25)
|
||||
im = QtGui.QImage(32, 32, QtGui.QImage.Format_ARGB32)
|
||||
im.fill(QtCore.Qt.transparent)
|
||||
pt = QtGui.QPainter(im)
|
||||
pt.setBrush(QtGui.QBrush(sc, QtCore.Qt.SolidPattern))
|
||||
pt.drawPolygon([p1, p2, p3, p4])
|
||||
pt.setPen(QtGui.QPen(lc, 2, QtCore.Qt.SolidLine, QtCore.Qt.FlatCap))
|
||||
pt.drawPolygon([p1, p2, p3, p4])
|
||||
pt.end()
|
||||
ba = QtCore.QByteArray()
|
||||
b = QtCore.QBuffer(ba)
|
||||
b.open(QtCore.QIODevice.WriteOnly)
|
||||
im.save(b, "XPM")
|
||||
self.icondata = ba.data().decode("latin1")
|
||||
vobj.signalChangeIcon()
|
||||
|
||||
def canDragObject(self, obj):
|
||||
return True
|
||||
|
||||
def canDragObjects(self):
|
||||
return True
|
||||
|
||||
def dragObject(self, vobj, otherobj):
|
||||
if hasattr(vobj.Object, "Group"):
|
||||
if otherobj in vobj.Object.Group:
|
||||
g = vobj.Object.Group
|
||||
g.remove(otherobj)
|
||||
vobj.Object.Group = g
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def canDropObject(self, obj):
|
||||
|
||||
if hasattr(obj, "Proxy") and isinstance(obj.Proxy, Layer):
|
||||
# for now, prevent stacking layers
|
||||
return False
|
||||
return True
|
||||
|
||||
def canDropObjects(self):
|
||||
|
||||
return True
|
||||
|
||||
def dropObject(self, vobj, otherobj):
|
||||
|
||||
if hasattr(vobj.Object, "Group"):
|
||||
if otherobj not in vobj.Object.Group:
|
||||
if not (hasattr(otherobj, "Proxy") and isinstance(otherobj.Proxy, Layer)):
|
||||
# for now, prevent stacking layers
|
||||
g = vobj.Object.Group
|
||||
g.append(otherobj)
|
||||
vobj.Object.Group = g
|
||||
# remove from all other layers (not automatic)
|
||||
for parent in otherobj.InList:
|
||||
if hasattr(parent, "Proxy") and isinstance(parent.Proxy, Layer):
|
||||
if otherobj in parent.Group:
|
||||
if parent != vobj.Object:
|
||||
g = parent.Group
|
||||
g.remove(otherobj)
|
||||
parent.Group = g
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def setupContextMenu(self, vobj, menu):
|
||||
|
||||
from PySide import QtCore, QtGui
|
||||
import Draft_rc
|
||||
action1 = QtGui.QAction(
|
||||
QtGui.QIcon(":/icons/button_right.svg"),
|
||||
translate("draft", "Activate this layer"),
|
||||
menu
|
||||
)
|
||||
action1.triggered.connect(self.activate)
|
||||
menu.addAction(action1)
|
||||
action2 = QtGui.QAction(
|
||||
QtGui.QIcon(":/icons/Draft_SelectGroup.svg"),
|
||||
translate("draft", "Select contents"),
|
||||
menu
|
||||
)
|
||||
action2.triggered.connect(self.selectcontents)
|
||||
menu.addAction(action2)
|
||||
|
||||
def activate(self):
|
||||
|
||||
if hasattr(self, "Object"):
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
FreeCADGui.Selection.addSelection(self.Object)
|
||||
FreeCADGui.runCommand("Draft_AutoGroup")
|
||||
|
||||
def selectcontents(self):
|
||||
|
||||
if hasattr(self, "Object"):
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
for o in self.Object.Group:
|
||||
FreeCADGui.Selection.addSelection(o)
|
||||
|
||||
|
||||
class LayerContainer:
|
||||
"""The Layer Container"""
|
||||
|
||||
def __init__(self, obj):
|
||||
|
||||
self.Type = "LayerContainer"
|
||||
obj.Proxy = self
|
||||
|
||||
def execute(self, obj):
|
||||
|
||||
g = obj.Group
|
||||
g.sort(key=lambda o: o.Label)
|
||||
obj.Group = g
|
||||
|
||||
def __getstate__(self):
|
||||
|
||||
if hasattr(self, "Type"):
|
||||
return self.Type
|
||||
|
||||
def __setstate__(self, state):
|
||||
|
||||
if state:
|
||||
self.Type = state
|
||||
|
||||
|
||||
class ViewProviderLayerContainer:
|
||||
"""A View Provider for the Layer Container"""
|
||||
|
||||
def __init__(self, vobj):
|
||||
|
||||
vobj.Proxy = self
|
||||
|
||||
def getIcon(self):
|
||||
|
||||
import Draft_rc
|
||||
return ":/icons/Draft_Layer.svg"
|
||||
|
||||
def attach(self, vobj):
|
||||
|
||||
self.Object = vobj.Object
|
||||
|
||||
def setupContextMenu(self, vobj, menu):
|
||||
|
||||
import Draft_rc
|
||||
from PySide import QtCore, QtGui
|
||||
action1 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_Layer.svg"), "Merge duplicates", menu)
|
||||
action1.triggered.connect(self.mergeByName)
|
||||
menu.addAction(action1)
|
||||
|
||||
def mergeByName(self):
|
||||
|
||||
if hasattr(self, "Object") and hasattr(self.Object, "Group"):
|
||||
layers = [o for o in self.Object.Group if (hasattr(o, "Proxy") and isinstance(o.Proxy, Layer))]
|
||||
todelete = []
|
||||
for layer in layers:
|
||||
if layer.Label[-1].isdigit() and layer.Label[-2].isdigit() and layer.Label[-3].isdigit():
|
||||
orig = None
|
||||
for ol in layer:
|
||||
if ol.Label == layer.Label[:-3].strip():
|
||||
orig = ol
|
||||
break
|
||||
if orig:
|
||||
for par in layer.InList:
|
||||
for prop in par.PropertiesList:
|
||||
if getattr(par, prop) == layer:
|
||||
FreeCAD.Console.PrintMessage(
|
||||
"Changed property '" + prop + "' of object " + par.Label + " from " + layer.Label + " to " + orig.Label + "\n")
|
||||
setattr(par, prop, orig)
|
||||
todelete.append(layer)
|
||||
for tod in todelete:
|
||||
if not tod.InList:
|
||||
FreeCAD.Console.PrintMessage("Merging duplicate layer " + tod.Label + "\n")
|
||||
FreeCAD.ActiveDocument.removeObject(tod.Name)
|
||||
elif (len(tod.InList) == 1) and (tod.InList[0].isDerivedFrom("App::DocumentObjectGroup")):
|
||||
FreeCAD.Console.PrintMessage("Merging duplicate layer " + tod.Label + "\n")
|
||||
FreeCAD.ActiveDocument.removeObject(tod.Name)
|
||||
else:
|
||||
FreeCAD.Console.PrintMessage("Unable to delete layer " + tod.Label + ": InList not empty\n")
|
||||
|
||||
def __getstate__(self):
|
||||
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
|
||||
return None
|
||||
# \brief Provides the Layer object. This module is deprecated.
|
||||
#
|
||||
# This module is only required to migrate old objects created
|
||||
# with v0.18 and earlier and with certain development version of v0.19.
|
||||
# It will be removed definitely in January 2021.
|
||||
import FreeCAD as App
|
||||
|
||||
from draftobjects.layer import (Layer,
|
||||
_VisGroup,
|
||||
LayerContainer)
|
||||
|
||||
if App.GuiUp:
|
||||
from draftviewproviders.view_layer import (ViewProviderLayer,
|
||||
_ViewProviderVisGroup,
|
||||
ViewProviderLayerContainer)
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""Provides tools for creating Layers with the Draft Workbench."""
|
||||
"""Provides GUI tools to create Layer objects."""
|
||||
## @package gui_layers
|
||||
# \ingroup draftguitools
|
||||
# \brief Provides tools for creating Layers with the Draft Workbench.
|
||||
# \brief Provides GUI tools to create Layer objects.
|
||||
|
||||
## \addtogroup draftguitools
|
||||
# @{
|
||||
@@ -66,7 +66,7 @@ class Layer(gui_base.GuiCommandSimplest):
|
||||
|
||||
self.doc.openTransaction("Create Layer")
|
||||
Gui.addModule("Draft")
|
||||
Gui.doCommand('_layer_ = Draft.makeLayer()')
|
||||
Gui.doCommand('_layer_ = Draft.make_layer()')
|
||||
Gui.doCommand('FreeCAD.ActiveDocument.recompute()')
|
||||
self.doc.commitTransaction()
|
||||
|
||||
|
||||
256
src/Mod/Draft/draftmake/make_layer.py
Normal file
256
src/Mod/Draft/draftmake/make_layer.py
Normal file
@@ -0,0 +1,256 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2014 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2020 Eliud Cabrera Castillo <e.cabrera-castillo@tum.de> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""Provides functions to create Layer objects."""
|
||||
## @package make_layer
|
||||
# \ingroup draftmake
|
||||
# \brief Provides functions to create Layer objects.
|
||||
|
||||
## \addtogroup draftmake
|
||||
# @{
|
||||
import FreeCAD as App
|
||||
import draftutils.utils as utils
|
||||
|
||||
from draftutils.messages import _msg, _err
|
||||
from draftutils.translate import _tr, translate
|
||||
from draftobjects.layer import (Layer,
|
||||
LayerContainer)
|
||||
|
||||
if App.GuiUp:
|
||||
from draftviewproviders.view_layer import (ViewProviderLayer,
|
||||
ViewProviderLayerContainer)
|
||||
|
||||
view_group = App.ParamGet("User parameter:BaseApp/Preferences/View")
|
||||
|
||||
|
||||
def get_layer_container():
|
||||
"""Return a group object to put layers in.
|
||||
|
||||
Returns
|
||||
-------
|
||||
App::DocumentObjectGroupPython
|
||||
The existing group object named `'LayerContainer'`
|
||||
of type `LayerContainer`.
|
||||
If it doesn't exist it will create it with this default Name.
|
||||
"""
|
||||
found, doc = utils.find_doc(App.activeDocument())
|
||||
if not found:
|
||||
_err(_tr("No active document. Aborting."))
|
||||
return None
|
||||
|
||||
for obj in doc.Objects:
|
||||
if obj.Name == "LayerContainer":
|
||||
return obj
|
||||
|
||||
new_obj = doc.addObject("App::DocumentObjectGroupPython",
|
||||
"LayerContainer")
|
||||
new_obj.Label = translate("draft", "Layers")
|
||||
|
||||
LayerContainer(new_obj)
|
||||
|
||||
if App.GuiUp:
|
||||
ViewProviderLayerContainer(new_obj.ViewObject)
|
||||
|
||||
return new_obj
|
||||
|
||||
|
||||
def getLayerContainer():
|
||||
"""Get the Layer container. DEPRECATED. Use 'get_layer_container'."""
|
||||
utils.use_instead("get_layer_container")
|
||||
|
||||
return get_layer_container()
|
||||
|
||||
|
||||
def make_layer(name=None,
|
||||
line_color=None, shape_color=None,
|
||||
line_width=2.0,
|
||||
draw_style="Solid", transparency=0):
|
||||
"""Create a Layer object in the active document.
|
||||
|
||||
If a layer container named `'LayerContainer'` does not exist,
|
||||
it is created with this name.
|
||||
|
||||
A layer controls the view properties of the objects inside the layer,
|
||||
so all parameters except for `name` only apply if the graphical interface
|
||||
is up.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name: str, optional
|
||||
It is used to set the layer's `Label` (user editable).
|
||||
It defaults to `None`, in which case the `Label`
|
||||
is set to `'Layer'` or to its translation in the current language.
|
||||
|
||||
line_color: tuple, optional
|
||||
It defaults to `None`, in which case it uses the value of the parameter
|
||||
`User parameter:BaseApp/Preferences/View/DefaultShapeLineColor`.
|
||||
If it is given, it should be a tuple of three
|
||||
floating point values from 0.0 to 1.0.
|
||||
|
||||
shape_color: tuple, optional
|
||||
It defaults to `None`, in which case it uses the value of the parameter
|
||||
`User parameter:BaseApp/Preferences/View/DefaultShapeColor`.
|
||||
If it is given, it should be a tuple of three
|
||||
floating point values from 0.0 to 1.0.
|
||||
|
||||
line_width: float, optional
|
||||
It defaults to 2.0.
|
||||
It determines the width of the edges of the objects contained
|
||||
in the layer.
|
||||
|
||||
draw_style: str, optional
|
||||
It defaults to `'Solid'`.
|
||||
It determines the style of the edges of the objects contained
|
||||
in the layer.
|
||||
If it is given, it should be 'Solid', 'Dashed', 'Dotted',
|
||||
or 'Dashdot'.
|
||||
|
||||
transparency: int, optional
|
||||
It defaults to 0.
|
||||
It should be an integer value from 0 (completely opaque)
|
||||
to 100 (completely transparent).
|
||||
|
||||
Return
|
||||
------
|
||||
App::FeaturePython
|
||||
A scripted object of type `'Layer'`.
|
||||
This object does not have a `Shape` attribute.
|
||||
Modifying the view properties of this object will affect the objects
|
||||
inside of it.
|
||||
|
||||
None
|
||||
If there is a problem it will return `None`.
|
||||
"""
|
||||
_name = "make_layer"
|
||||
utils.print_header(_name, _tr("Layer"))
|
||||
|
||||
found, doc = utils.find_doc(App.activeDocument())
|
||||
if not found:
|
||||
_err(_tr("No active document. Aborting."))
|
||||
return None
|
||||
|
||||
if name:
|
||||
_msg("name: {}".format(name))
|
||||
try:
|
||||
utils.type_check([(name, str)], name=_name)
|
||||
except TypeError:
|
||||
_err(_tr("Wrong input: it must be a string."))
|
||||
return None
|
||||
else:
|
||||
name = translate("draft", "Layer")
|
||||
|
||||
_info_color = ("Wrong input: "
|
||||
"must be a tuple of three floats 0.0 to 1.0.")
|
||||
if line_color:
|
||||
_msg("line_color: {}".format(line_color))
|
||||
try:
|
||||
utils.type_check([(line_color, tuple)], name=_name)
|
||||
except TypeError:
|
||||
_err(_tr(_info_color))
|
||||
return None
|
||||
|
||||
if not all(isinstance(color, (int, float)) for color in line_color):
|
||||
_err(_tr(_info_color))
|
||||
return None
|
||||
else:
|
||||
c = view_group.GetUnsigned("DefaultShapeLineColor", 255)
|
||||
line_color = (((c >> 24) & 0xFF) / 255,
|
||||
((c >> 16) & 0xFF) / 255,
|
||||
((c >> 8) & 0xFF) / 255)
|
||||
|
||||
if shape_color:
|
||||
_msg("shape_color: {}".format(shape_color))
|
||||
try:
|
||||
utils.type_check([(shape_color, tuple)], name=_name)
|
||||
except TypeError:
|
||||
_err(_tr(_info_color))
|
||||
return None
|
||||
|
||||
if not all(isinstance(color, (int, float)) for color in shape_color):
|
||||
_err(_tr(_info_color))
|
||||
return None
|
||||
else:
|
||||
c = view_group.GetUnsigned("DefaultShapeColor", 4294967295)
|
||||
shape_color = (((c >> 24) & 0xFF) / 255,
|
||||
((c >> 16) & 0xFF) / 255,
|
||||
((c >> 8) & 0xFF) / 255)
|
||||
|
||||
_msg("line_width: {}".format(line_width))
|
||||
try:
|
||||
utils.type_check([(line_width, (int, float))], name=_name)
|
||||
line_width = float(abs(line_width))
|
||||
except TypeError:
|
||||
_err(_tr("Wrong input: must be a number."))
|
||||
return None
|
||||
|
||||
_info_style = ("Wrong input: "
|
||||
"must be 'Solid', 'Dashed', 'Dotted', or 'Dashdot'.")
|
||||
_msg("draw_style: {}".format(draw_style))
|
||||
try:
|
||||
utils.type_check([(draw_style, str)], name=_name)
|
||||
except TypeError:
|
||||
_err(_tr(_info_style))
|
||||
return None
|
||||
|
||||
if draw_style not in ('Solid', 'Dashed', 'Dotted', 'Dashdot'):
|
||||
_err(_tr(_info_style))
|
||||
return None
|
||||
|
||||
_msg("transparency: {}".format(transparency))
|
||||
try:
|
||||
utils.type_check([(transparency, (int, float))], name=_name)
|
||||
transparency = int(abs(transparency))
|
||||
except TypeError:
|
||||
_err(_tr("Wrong input: must be a number between 0 and 100."))
|
||||
return None
|
||||
|
||||
new_obj = doc.addObject("App::FeaturePython", "Layer")
|
||||
Layer(new_obj)
|
||||
|
||||
new_obj.Label = name
|
||||
|
||||
if App.GuiUp:
|
||||
ViewProviderLayer(new_obj.ViewObject)
|
||||
|
||||
new_obj.ViewObject.LineColor = line_color
|
||||
new_obj.ViewObject.ShapeColor = shape_color
|
||||
new_obj.ViewObject.LineWidth = line_width
|
||||
new_obj.ViewObject.DrawStyle = draw_style
|
||||
new_obj.ViewObject.Transparency = transparency
|
||||
|
||||
container = get_layer_container()
|
||||
container.addObject(new_obj)
|
||||
|
||||
return new_obj
|
||||
|
||||
|
||||
def makeLayer(name=None, linecolor=None, drawstyle=None,
|
||||
shapecolor=None, transparency=None):
|
||||
"""Create a Layer. DEPRECATED. Use 'make_layer'."""
|
||||
utils.use_instead("make_layer")
|
||||
|
||||
return make_layer(name,
|
||||
linecolor, shapecolor,
|
||||
draw_style=drawstyle, transparency=transparency)
|
||||
|
||||
## @}
|
||||
120
src/Mod/Draft/draftobjects/layer.py
Normal file
120
src/Mod/Draft/draftobjects/layer.py
Normal file
@@ -0,0 +1,120 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2014 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2020 Eliud Cabrera Castillo <e.cabrera-castillo@tum.de> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""Provides the object code for the Layer object."""
|
||||
## @package layer
|
||||
# \ingroup draftobjects
|
||||
# \brief Provides the object code for the Layer object.
|
||||
|
||||
## \addtogroup draftobjects
|
||||
# @{
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
|
||||
class Layer:
|
||||
"""The Layer object.
|
||||
|
||||
This class is normally used to extend a base `App::FeaturePython` object.
|
||||
"""
|
||||
|
||||
def __init__(self, obj):
|
||||
self.Type = "Layer"
|
||||
self.Object = obj
|
||||
self.set_properties(obj)
|
||||
|
||||
obj.Proxy = self
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
"""Execute code when the document is restored.
|
||||
|
||||
Add properties that don't exist.
|
||||
"""
|
||||
self.set_properties(obj)
|
||||
|
||||
def set_properties(self, obj):
|
||||
"""Set properties only if they don't exist."""
|
||||
if "Group" not in obj.PropertiesList:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The objects that are part of this layer")
|
||||
obj.addProperty("App::PropertyLinkList",
|
||||
"Group",
|
||||
"Layer",
|
||||
_tip)
|
||||
|
||||
def __getstate__(self):
|
||||
"""Return a tuple of objects to save or None."""
|
||||
return self.Type
|
||||
|
||||
def __setstate__(self, state):
|
||||
"""Set the internal properties from the restored state."""
|
||||
if state:
|
||||
self.Type = state
|
||||
|
||||
def execute(self, obj):
|
||||
"""Execute when the object is created or recomputed. Do nothing."""
|
||||
pass
|
||||
|
||||
def addObject(self, obj, child):
|
||||
"""Add an object to this object if not in the Group property."""
|
||||
group = obj.Group
|
||||
if child not in group:
|
||||
group.append(child)
|
||||
obj.Group = group
|
||||
|
||||
|
||||
# Alias for compatibility with v0.18 and earlier
|
||||
_VisGroup = Layer
|
||||
|
||||
|
||||
class LayerContainer:
|
||||
"""The container object for layers.
|
||||
|
||||
This class is normally used to extend
|
||||
a base `App::DocumentObjectGroupPython` object.
|
||||
"""
|
||||
|
||||
def __init__(self, obj):
|
||||
self.Type = "LayerContainer"
|
||||
obj.Proxy = self
|
||||
|
||||
def execute(self, obj):
|
||||
"""Execute when the object is created or recomputed.
|
||||
|
||||
Update the value of `Group` by sorting the contained layers
|
||||
by `Label`.
|
||||
"""
|
||||
group = obj.Group
|
||||
group.sort(key=lambda layer: layer.Label)
|
||||
obj.Group = group
|
||||
|
||||
def __getstate__(self):
|
||||
"""Return a tuple of objects to save or None."""
|
||||
if hasattr(self, "Type"):
|
||||
return self.Type
|
||||
|
||||
def __setstate__(self, state):
|
||||
"""Set the internal properties from the restored state."""
|
||||
if state:
|
||||
self.Type = state
|
||||
|
||||
## @}
|
||||
457
src/Mod/Draft/draftviewproviders/view_layer.py
Normal file
457
src/Mod/Draft/draftviewproviders/view_layer.py
Normal file
@@ -0,0 +1,457 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2014 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2020 Eliud Cabrera Castillo <e.cabrera-castillo@tum.de> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""Provides the viewprovider code for the Layer object."""
|
||||
## @package view_layer
|
||||
# \ingroup draftviewproviders
|
||||
# \brief Provides the viewprovider code for the Layer object.
|
||||
|
||||
## \addtogroup draftviewproviders
|
||||
# @{
|
||||
import pivy.coin as coin
|
||||
import PySide.QtCore as QtCore
|
||||
import PySide.QtGui as QtGui
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
|
||||
from draftutils.messages import _msg
|
||||
from draftutils.translate import translate
|
||||
from draftobjects.layer import Layer
|
||||
|
||||
|
||||
class ViewProviderLayer:
|
||||
"""The viewprovider for the Layer object."""
|
||||
|
||||
def __init__(self, vobj):
|
||||
self.Object = vobj.Object
|
||||
self.set_properties(vobj)
|
||||
|
||||
vobj.Proxy = self
|
||||
|
||||
def set_properties(self, vobj):
|
||||
"""Set the properties only if they don't already exist."""
|
||||
properties = vobj.PropertiesList
|
||||
self.set_override_options(vobj, properties)
|
||||
self.set_visual_properties(vobj, properties)
|
||||
|
||||
def set_override_options(self, vobj, properties):
|
||||
"""Set property options only if they don't already exist."""
|
||||
if "OverrideLineColorChildren" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"If it is true, the objects contained "
|
||||
"within this layer will adopt "
|
||||
"the line color of the layer")
|
||||
vobj.addProperty("App::PropertyBool",
|
||||
"OverrideLineColorChildren",
|
||||
"Layer",
|
||||
_tip)
|
||||
vobj.OverrideLineColorChildren = True
|
||||
|
||||
if "OverrideShapeColorChildren" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"If it is true, the objects contained "
|
||||
"within this layer will adopt "
|
||||
"the line color of the layer")
|
||||
vobj.addProperty("App::PropertyBool",
|
||||
"OverrideShapeColorChildren",
|
||||
"Layer",
|
||||
_tip)
|
||||
vobj.OverrideShapeColorChildren = True
|
||||
|
||||
def set_visual_properties(self, vobj, properties):
|
||||
"""Set visual properties only if they don't already exist."""
|
||||
view_group = App.ParamGet("User parameter:BaseApp/Preferences/View")
|
||||
|
||||
if "LineColor" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The line color of the objects "
|
||||
"contained within this layer")
|
||||
vobj.addProperty("App::PropertyColor",
|
||||
"LineColor",
|
||||
"Layer",
|
||||
_tip)
|
||||
|
||||
c = view_group.GetUnsigned("DefaultShapeLineColor", 255)
|
||||
vobj.LineColor = (((c >> 24) & 0xFF) / 255,
|
||||
((c >> 16) & 0xFF) / 255,
|
||||
((c >> 8) & 0xFF) / 255)
|
||||
|
||||
if "ShapeColor" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The shape color of the objects "
|
||||
"contained within this layer")
|
||||
vobj.addProperty("App::PropertyColor",
|
||||
"ShapeColor",
|
||||
"Layer",
|
||||
_tip)
|
||||
|
||||
c = view_group.GetUnsigned("DefaultShapeColor", 4294967295)
|
||||
vobj.ShapeColor = (((c >> 24) & 0xFF) / 255,
|
||||
((c >> 16) & 0xFF) / 255,
|
||||
((c >> 8) & 0xFF) / 255)
|
||||
|
||||
if "LineWidth" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The line width of the objects contained "
|
||||
"within this layer")
|
||||
vobj.addProperty("App::PropertyFloat",
|
||||
"LineWidth",
|
||||
"Layer",
|
||||
_tip)
|
||||
|
||||
width = view_group.GetInt("DefaultShapeLineWidth", 2)
|
||||
vobj.LineWidth = width
|
||||
|
||||
if "DrawStyle" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The draw style of the objects contained "
|
||||
"within this layer")
|
||||
vobj.addProperty("App::PropertyEnumeration",
|
||||
"DrawStyle",
|
||||
"Layer",
|
||||
_tip)
|
||||
vobj.DrawStyle = ["Solid", "Dashed", "Dotted", "Dashdot"]
|
||||
vobj.DrawStyle = "Solid"
|
||||
|
||||
if "Transparency" not in properties:
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The transparency of the objects "
|
||||
"contained within this layer")
|
||||
vobj.addProperty("App::PropertyInteger",
|
||||
"Transparency",
|
||||
"Layer",
|
||||
_tip)
|
||||
vobj.Transparency = 0
|
||||
|
||||
def getIcon(self):
|
||||
"""Return the path to the icon used by the viewprovider.
|
||||
|
||||
Normally it returns the basic Layer icon, but if `icondata` exists
|
||||
it is the modified icon with the line and shape colors of the layer.
|
||||
"""
|
||||
if hasattr(self, "icondata"):
|
||||
return self.icondata
|
||||
return ":/icons/Draft_Layer.svg"
|
||||
|
||||
def attach(self, vobj):
|
||||
"""Set up the scene sub-graph of the viewprovider."""
|
||||
self.Object = vobj.Object
|
||||
sep = coin.SoGroup()
|
||||
vobj.addDisplayMode(sep, "Default")
|
||||
|
||||
def claimChildren(self):
|
||||
"""Return objects that will be placed under it in the tree view.
|
||||
|
||||
These are the elements of the `Group` property of the Proxy object.
|
||||
"""
|
||||
if hasattr(self, "Object") and hasattr(self.Object, "Group"):
|
||||
return self.Object.Group
|
||||
|
||||
def getDisplayModes(self, vobj):
|
||||
"""Return the display modes that this viewprovider supports."""
|
||||
return ["Default"]
|
||||
|
||||
def getDefaultDisplayMode(self):
|
||||
"""Return the default display mode."""
|
||||
return "Default"
|
||||
|
||||
def setDisplayMode(self, mode):
|
||||
"""Return the saved display mode."""
|
||||
return mode
|
||||
|
||||
def __getstate__(self):
|
||||
"""Return a tuple of objects to save or None."""
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
"""Set the internal properties from the restored state."""
|
||||
return None
|
||||
|
||||
def updateData(self, obj, prop):
|
||||
"""Execute when a property from the Proxy class is changed."""
|
||||
if prop == "Group":
|
||||
for _prop in ("LineColor", "ShapeColor", "LineWidth",
|
||||
"DrawStyle", "Transparency", "Visibility"):
|
||||
self.onChanged(obj.ViewObject, _prop)
|
||||
|
||||
def change_view_properties(self, vobj, prop):
|
||||
"""Iterate over the contents and change the properties."""
|
||||
obj = vobj.Object
|
||||
|
||||
# Return if the property does not exist
|
||||
if not hasattr(vobj, prop):
|
||||
return
|
||||
|
||||
for target_obj in obj.Group:
|
||||
target_vobj = target_obj.ViewObject
|
||||
|
||||
# If the override properties are not set return without change
|
||||
if prop == "LineColor" and not vobj.OverrideLineColorChildren:
|
||||
return
|
||||
elif prop == "ShapeColor" and not vobj.OverrideShapeColorChildren:
|
||||
return
|
||||
|
||||
# This checks that the property exists in the target object,
|
||||
# and then sets the target property accordingly
|
||||
if hasattr(target_vobj, prop):
|
||||
setattr(target_vobj, prop, getattr(vobj, prop))
|
||||
else:
|
||||
continue
|
||||
|
||||
# Use the line color for the text color if it exists
|
||||
if prop == "LineColor":
|
||||
if hasattr(target_vobj, "TextColor"):
|
||||
target_vobj.TextColor = vobj.LineColor
|
||||
if hasattr(target_vobj, "FontColor"):
|
||||
target_vobj.FontColor = vobj.LineColor
|
||||
|
||||
def onChanged(self, vobj, prop):
|
||||
"""Execute when a view property is changed."""
|
||||
if prop in ("LineColor", "ShapeColor", "LineWidth",
|
||||
"DrawStyle", "Transparency", "Visibility"):
|
||||
self.change_view_properties(vobj, prop)
|
||||
|
||||
if (prop in ("LineColor", "ShapeColor")
|
||||
and hasattr(vobj, "LineColor")
|
||||
and hasattr(vobj, "ShapeColor")):
|
||||
# This doesn't do anything to the objects inside the layer,
|
||||
# it just uses the defined Line and Shape colors
|
||||
# to paint the layer icon accordingly in the tree view
|
||||
l_color = vobj.LineColor
|
||||
s_color = vobj.ShapeColor
|
||||
|
||||
l_color = QtGui.QColor(int(l_color[0] * 255),
|
||||
int(l_color[1] * 255),
|
||||
int(l_color[2] * 255))
|
||||
s_color = QtGui.QColor(int(s_color[0] * 255),
|
||||
int(s_color[1] * 255),
|
||||
int(s_color[2] * 255))
|
||||
p1 = QtCore.QPointF(2, 17)
|
||||
p2 = QtCore.QPointF(13, 8)
|
||||
p3 = QtCore.QPointF(30, 15)
|
||||
p4 = QtCore.QPointF(20, 25)
|
||||
|
||||
image = QtGui.QImage(32, 32, QtGui.QImage.Format_ARGB32)
|
||||
image.fill(QtCore.Qt.transparent)
|
||||
|
||||
pt = QtGui.QPainter(image)
|
||||
pt.setBrush(QtGui.QBrush(s_color, QtCore.Qt.SolidPattern))
|
||||
pt.drawPolygon([p1, p2, p3, p4])
|
||||
pt.setPen(QtGui.QPen(l_color, 2,
|
||||
QtCore.Qt.SolidLine, QtCore.Qt.FlatCap))
|
||||
pt.drawPolygon([p1, p2, p3, p4])
|
||||
pt.end()
|
||||
|
||||
byte_array = QtCore.QByteArray()
|
||||
buffer = QtCore.QBuffer(byte_array)
|
||||
buffer.open(QtCore.QIODevice.WriteOnly)
|
||||
image.save(buffer, "XPM")
|
||||
|
||||
self.icondata = byte_array.data().decode("latin1")
|
||||
vobj.signalChangeIcon()
|
||||
|
||||
def canDragObject(self, obj):
|
||||
"""Return True to allow dragging one object from the Layer."""
|
||||
return True
|
||||
|
||||
def canDragObjects(self):
|
||||
"""Return True to allow dragging many objects from the Layer."""
|
||||
return True
|
||||
|
||||
def dragObject(self, vobj, otherobj):
|
||||
"""Remove the object that was dragged from the layer."""
|
||||
if hasattr(vobj.Object, "Group") and otherobj in vobj.Object.Group:
|
||||
group = vobj.Object.Group
|
||||
group.remove(otherobj)
|
||||
vobj.Object.Group = group
|
||||
App.ActiveDocument.recompute()
|
||||
|
||||
def canDropObject(self, obj):
|
||||
"""Return true to allow dropping one object.
|
||||
|
||||
If the object being dropped is itself a `'Layer'`, return `False`
|
||||
to prevent dropping a layer inside a layer, at least for now.
|
||||
"""
|
||||
if hasattr(obj, "Proxy") and isinstance(obj.Proxy, Layer):
|
||||
return False
|
||||
return True
|
||||
|
||||
def canDropObjects(self):
|
||||
"""Return true to allow dropping many objects."""
|
||||
return True
|
||||
|
||||
def dropObject(self, vobj, otherobj):
|
||||
"""Add object that was dropped into the Layer to the group.
|
||||
|
||||
If the object being dropped is itself a `'Layer'`,
|
||||
return immediately to prevent dropping a layer inside a layer,
|
||||
at least for now.
|
||||
"""
|
||||
if hasattr(otherobj, "Proxy") and isinstance(otherobj.Proxy, Layer):
|
||||
return
|
||||
|
||||
obj = vobj.Object
|
||||
|
||||
if hasattr(obj, "Group") and otherobj not in obj.Group:
|
||||
group = obj.Group
|
||||
group.append(otherobj)
|
||||
obj.Group = group
|
||||
|
||||
# Remove from all other layers (not automatic)
|
||||
for parent in otherobj.InList:
|
||||
if (hasattr(parent, "Proxy")
|
||||
and isinstance(parent.Proxy, Layer)
|
||||
and otherobj in parent.Group
|
||||
and parent != obj):
|
||||
p_group = parent.Group
|
||||
p_group.remove(otherobj)
|
||||
parent.Group = p_group
|
||||
|
||||
App.ActiveDocument.recompute()
|
||||
|
||||
def setupContextMenu(self, vobj, menu):
|
||||
"""Set up actions to perform in the context menu."""
|
||||
action1 = QtGui.QAction(QtGui.QIcon(":/icons/button_right.svg"),
|
||||
translate("draft", "Activate this layer"),
|
||||
menu)
|
||||
action1.triggered.connect(self.activate)
|
||||
menu.addAction(action1)
|
||||
|
||||
action2 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_SelectGroup.svg"),
|
||||
translate("draft", "Select layer contents"),
|
||||
menu)
|
||||
action2.triggered.connect(self.select_contents)
|
||||
menu.addAction(action2)
|
||||
|
||||
def activate(self):
|
||||
"""Activate the selected layer, it becomes the Autogroup."""
|
||||
if hasattr(self, "Object"):
|
||||
Gui.Selection.clearSelection()
|
||||
Gui.Selection.addSelection(self.Object)
|
||||
Gui.runCommand("Draft_AutoGroup")
|
||||
|
||||
def select_contents(self):
|
||||
"""Select the contents of the layer."""
|
||||
if hasattr(self, "Object"):
|
||||
Gui.Selection.clearSelection()
|
||||
for layer_obj in self.Object.Group:
|
||||
Gui.Selection.addSelection(layer_obj)
|
||||
|
||||
|
||||
class ViewProviderLayerContainer:
|
||||
"""The viewprovider for the LayerContainer object."""
|
||||
|
||||
def __init__(self, vobj):
|
||||
self.Object = vobj.Object
|
||||
vobj.Proxy = self
|
||||
|
||||
def getIcon(self):
|
||||
"""Return the path to the icon used by the viewprovider."""
|
||||
return ":/icons/Draft_Layer.svg"
|
||||
|
||||
def attach(self, vobj):
|
||||
"""Set up the scene sub-graph of the viewprovider."""
|
||||
self.Object = vobj.Object
|
||||
|
||||
def setupContextMenu(self, vobj, menu):
|
||||
"""Set up actions to perform in the context menu."""
|
||||
action1 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_Layer.svg"),
|
||||
translate("Draft", "Merge layer duplicates"),
|
||||
menu)
|
||||
action1.triggered.connect(self.merge_by_name)
|
||||
menu.addAction(action1)
|
||||
|
||||
def merge_by_name(self):
|
||||
"""Merge the layers that have the same name."""
|
||||
if not hasattr(self, "Object") or not hasattr(self.Object, "Group"):
|
||||
return
|
||||
|
||||
obj = self.Object
|
||||
|
||||
layers = list()
|
||||
for iobj in obj.Group:
|
||||
if hasattr(iobj, "Proxy") and isinstance(iobj.Proxy, Layer):
|
||||
layers.append(iobj)
|
||||
|
||||
to_delete = list()
|
||||
for layer in layers:
|
||||
# Test the last three characters of the layer's Label to see
|
||||
# if it's a number, like `'Layer017'`
|
||||
if (layer.Label[-1].isdigit()
|
||||
and layer.Label[-2].isdigit()
|
||||
and layer.Label[-3].isdigit()):
|
||||
# If the object inside the layer has the same Label
|
||||
# as the layer, save this object
|
||||
orig = None
|
||||
for ol in layer.OutList:
|
||||
if ol.Label == layer.Label[:-3].strip():
|
||||
orig = ol
|
||||
break
|
||||
|
||||
# Go into the objects that reference this layer object
|
||||
# and set the layer property with the previous `orig`
|
||||
# object found
|
||||
# Editor: when is this possible? Maybe if a layer is inside
|
||||
# another layer? Currently the code doesn't allow this
|
||||
# so maybe this was a previous behavior that was disabled
|
||||
# in `ViewProviderLayer`.
|
||||
if orig:
|
||||
for par in layer.InList:
|
||||
for prop in par.PropertiesList:
|
||||
if getattr(par, prop) == layer:
|
||||
_msg("Changed property '" + prop
|
||||
+ "' of object " + par.Label
|
||||
+ " from " + layer.Label
|
||||
+ " to " + orig.Label)
|
||||
setattr(par, prop, orig)
|
||||
to_delete.append(layer)
|
||||
|
||||
for layer in to_delete:
|
||||
if not layer.InList:
|
||||
_msg("Merging duplicate layer: " + layer.Label)
|
||||
App.ActiveDocument.removeObject(layer.Name)
|
||||
elif len(layer.InList) == 1:
|
||||
first = layer.InList[0]
|
||||
|
||||
if first.isDerivedFrom("App::DocumentObjectGroup"):
|
||||
_msg("Merging duplicate layer: " + layer.Label)
|
||||
App.ActiveDocument.removeObject(layer.Name)
|
||||
else:
|
||||
_msg("InList not empty. "
|
||||
"Unable to delete layer: " + layer.Label)
|
||||
|
||||
def __getstate__(self):
|
||||
"""Return a tuple of objects to save or None."""
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
"""Set the internal properties from the restored state."""
|
||||
return None
|
||||
|
||||
|
||||
# Alias for compatibility with v0.18 and earlier
|
||||
_ViewProviderVisGroup = ViewProviderLayer
|
||||
|
||||
## @}
|
||||
Reference in New Issue
Block a user