From 937d226f4f86b9ef684da17005521703412a5471 Mon Sep 17 00:00:00 2001 From: luzpaz Date: Sat, 21 Jan 2023 18:02:30 +0000 Subject: [PATCH] ShowWB: fix header uniformity Make headers uniform + remote trailing whitespace --- src/Mod/Show/Containers.py | 73 ++++---- src/Mod/Show/DepGraphTools.py | 23 ++- src/Mod/Show/SceneDetail.py | 34 ++-- src/Mod/Show/SceneDetails/Camera.py | 9 +- src/Mod/Show/SceneDetails/ClipPlane.py | 13 +- src/Mod/Show/SceneDetails/ObjectClipPlane.py | 19 +- src/Mod/Show/SceneDetails/Pickability.py | 15 +- src/Mod/Show/SceneDetails/VProperty.py | 11 +- src/Mod/Show/SceneDetails/Workbench.py | 11 +- src/Mod/Show/ShowUtils.py | 9 +- src/Mod/Show/TVObserver.py | 11 +- src/Mod/Show/TVStack.py | 61 ++++--- src/Mod/Show/mTempoVis.py | 173 +++++++++---------- 13 files changed, 223 insertions(+), 239 deletions(-) diff --git a/src/Mod/Show/Containers.py b/src/Mod/Show/Containers.py index 29fea509ba..29c3acb3bc 100644 --- a/src/Mod/Show/Containers.py +++ b/src/Mod/Show/Containers.py @@ -1,6 +1,5 @@ #/*************************************************************************** -# * Copyright (c) Victor Titov (DeepSOIC) * -# * (vv.titov@gmail.com) 2018 * +# * Copyright (c) 2018 Victor Titov (DeepSOIC) * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -27,24 +26,24 @@ class Container(object): """Container class: a unified interface for container objects, such as Group, Part, Body, or Document. This is a temporary implementation.""" Object = None #DocumentObject or Document, the actual container - + def __init__(self, obj): self.Object = obj - + def self_check(self): if self.Object is None: raise ValueError("Null!") if not isAContainer(self.Object, links_too= True): raise NotAContainerError(self.Object) - + def getAllChildren(self): """Returns all objects directly contained by the container. all = static + dynamic.""" return self.getStaticChildren() + self.getDynamicChildren() - + def getStaticChildren(self): - """Returns children tightly bound to the container, such as Origin. The key thing + """Returns children tightly bound to the container, such as Origin. The key thing about them is that they are not supposed to be removed or added from/to the container.""" - + self.self_check() container = self.Object if container.isDerivedFrom('App::Document'): @@ -66,7 +65,7 @@ class Container(object): """Returns dynamic children, i.e. the stuff that can be removed from the container.""" self.self_check() container = self.Object - + if container.isDerivedFrom('App::Document'): # find all objects not contained by any Part or Body result = set(container.Objects) @@ -92,28 +91,28 @@ class Container(object): return result raise RuntimeError("getDynamicChildren: unexpected container type!") - + def isACS(self): """isACS(): returns true if the container forms internal coordinate system.""" self.self_check() container = self.Object - + if container.isDerivedFrom('App::Document'): - return True #Document is a special thing... is it a CS or not is a matter of coding convenience. + return True #Document is a special thing... is it a CS or not is a matter of coding convenience. elif container.hasExtension('App::GeoFeatureGroupExtension'): return True elif container.hasChildElement(): # Link return True else: return False - + def isAVisGroup(self): """isAVisGroup(): returns True if the container consumes viewproviders of children, and thus affects their visibility.""" self.self_check() container = self.Object - + if container.isDerivedFrom('App::Document'): - return True #Document is a special thing... Return value is a matter of coding convenience. + return True #Document is a special thing... Return value is a matter of coding convenience. elif container.hasExtension('App::GeoFeatureGroupExtension'): return True elif container.isDerivedFrom('App::Origin'): @@ -122,7 +121,7 @@ class Container(object): return True else: return False - + def getCSChildren(self): if not self.isACS(): raise TypeError("Container is not a coordinate system") @@ -148,22 +147,22 @@ class Container(object): def hasObject(self, obj): """Returns True if the container contains specified object directly.""" return obj in self.getAllChildren() - + def hasObjectRecursive(self, obj): return self.Object in ContainerChain(obj) def _getMetacontainerChildren(container, isrightcontainer_func): - """Gathers up children of metacontainer - a container structure formed by containers of specific type. + """Gathers up children of metacontainer - a container structure formed by containers of specific type. For example, coordinate systems form a kind of container structure. - + container: instance of Container class isrightcontainer_func: a function f(cnt)->bool, where cnt is a Container object.""" - + result = [] list_traversing_now = [container] #list of Container instances list_to_be_traversed_next = [] #list of Container instances visited_containers = set([container.Object]) #set of DocumentObjects - + while len(list_traversing_now) > 0: list_to_be_traversed_next = [] for itcnt in list_traversing_now: @@ -175,19 +174,19 @@ def _getMetacontainerChildren(container, isrightcontainer_func): if not isrightcontainer_func(newcnt): list_to_be_traversed_next.append(newcnt) list_traversing_now = list_to_be_traversed_next - + return result - - + + def isAContainer(obj, links_too = False): - '''isAContainer(obj, links_too): returns True if obj is an object container, such as - Group, Part, Body. The important characteristic of an object being a - container is that it can be activated to receive new objects. Documents + '''isAContainer(obj, links_too): returns True if obj is an object container, such as + Group, Part, Body. The important characteristic of an object being a + container is that it can be activated to receive new objects. Documents are considered containers, too. - If links_too, App::Link objects are considered containers, too. Then, container tree + If links_too, App::Link objects are considered containers, too. Then, container tree isn't necessarily a tree.''' - + if obj.isDerivedFrom('App::Document'): return True if obj.hasExtension('App::GroupExtension'): @@ -208,27 +207,27 @@ def ContainerOf(obj): if cnt is not None and dep is not cnt: raise ContainerTreeError("Container tree is not a tree") cnt = dep - if cnt is None: + if cnt is None: return obj.Document return cnt - + def getVisGroupOf(obj): chain = VisGroupChain(obj) return chain[-1] #from Part-o-magic... over-engineered, but proven to work def ContainerChain(feat): - '''ContainerChain(feat): container path to feat (not including feat itself). - Last container directly contains the feature. + '''ContainerChain(feat): container path to feat (not including feat itself). + Last container directly contains the feature. Example of output: [,,,]''' - + if feat.isDerivedFrom('App::Document'): return [] - + list_traversing_now = [feat] set_of_deps = set() list_of_deps = [] - + while len(list_traversing_now) > 0: list_to_be_traversed_next = [] for feat in list_traversing_now: @@ -241,7 +240,7 @@ def ContainerChain(feat): if len(list_to_be_traversed_next) > 1: raise ContainerTreeError("Container tree is not a tree") list_traversing_now = list_to_be_traversed_next - + return [feat.Document] + list_of_deps[::-1] def CSChain(feat): diff --git a/src/Mod/Show/DepGraphTools.py b/src/Mod/Show/DepGraphTools.py index df19a0eba3..324c556829 100644 --- a/src/Mod/Show/DepGraphTools.py +++ b/src/Mod/Show/DepGraphTools.py @@ -1,6 +1,5 @@ #/*************************************************************************** -# * Copyright (c) Victor Titov (DeepSOIC) * -# * (vv.titov@gmail.com) 2016 * +# * Copyright (c) 2016 Victor Titov (DeepSOIC) * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -22,13 +21,13 @@ # ***************************************************************************/ def getAllDependencies(feat): - '''getAllDependencies(feat): gets all features feat depends on, directly or indirectly. - Returns a list, with deepest dependencies last. feat is not included in the list, except + '''getAllDependencies(feat): gets all features feat depends on, directly or indirectly. + Returns a list, with deepest dependencies last. feat is not included in the list, except if the feature depends on itself (dependency loop).''' list_traversing_now = [feat] set_of_deps = set() list_of_deps = [] - + while len(list_traversing_now) > 0: list_to_be_traversed_next = [] for feat in list_traversing_now: @@ -37,19 +36,19 @@ def getAllDependencies(feat): set_of_deps.add(dep) list_of_deps.append(dep) list_to_be_traversed_next.append(dep) - + list_traversing_now = list_to_be_traversed_next - + return list_of_deps def getAllDependent(feat): - '''getAllDependent(feat): gets all features that depend on feat, directly or indirectly. - Returns a list, with deepest dependencies last. feat is not included in the list, except + '''getAllDependent(feat): gets all features that depend on feat, directly or indirectly. + Returns a list, with deepest dependencies last. feat is not included in the list, except if the feature depends on itself (dependency loop).''' list_traversing_now = [feat] set_of_deps = set() list_of_deps = [] - + while len(list_traversing_now) > 0: list_to_be_traversed_next = [] for feat in list_traversing_now: @@ -58,7 +57,7 @@ def getAllDependent(feat): set_of_deps.add(dep) list_of_deps.append(dep) list_to_be_traversed_next.append(dep) - + list_traversing_now = list_to_be_traversed_next - + return list_of_deps diff --git a/src/Mod/Show/SceneDetail.py b/src/Mod/Show/SceneDetail.py index 73333589d2..18ccef672f 100644 --- a/src/Mod/Show/SceneDetail.py +++ b/src/Mod/Show/SceneDetail.py @@ -1,6 +1,5 @@ #/*************************************************************************** -# * Copyright (c) Victor Titov (DeepSOIC) * -# * (vv.titov@gmail.com) 2019 * +# * Copyright (c) 2019 Victor Titov (DeepSOIC) * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -25,7 +24,7 @@ class SceneDetail(object): """SceneDetail class: abstract class for tempovis scene save/restore plug-in. An implementation must provide: * data storage (as "data" attribute of the object) * constructor (preferably, with value for stored data as optional argument) - * methods to apply values to actual scene (apply_data), + * methods to apply values to actual scene (apply_data), * ...and to read out the state of the detail in the actual scene (scene_value) * keying, for identifying two detail instances that affect the exact same thing * class_id string, which is required for keying @@ -34,30 +33,30 @@ class SceneDetail(object): * info on if the modification affects what is saved to disk, and thus should be undone temporarily for file writing. """ class_id = '' - + data = None doc = None - - ## Storage field for TV. Mild restore means that the saved state won't be restored - # if the current state differs from the state requested via last TempoVis.modify(...) call. - # This is a default, it may be changed per-instance. - mild_restore = False - + + ## Storage field for TV. Mild restore means that the saved state won't be restored + # if the current state differs from the state requested via last TempoVis.modify(...) call. + # This is a default, it may be changed per-instance. + mild_restore = False + def set_doc(self, doc): self.doc = doc - + # - key = None #a string or something alike to use to store/find the entry in TempoVis. For example, a string "{object_name}.{property_name}". + key = None #a string or something alike to use to store/find the entry in TempoVis. For example, a string "{object_name}.{property_name}". affects_persistence = False #True indicate that the changes will be recorded if the doc is saved, and that this detail should be restored for saving - + def scene_value(self): """scene_value(): returns the value from the scene""" raise NotImplementedError() - + def apply_data(self, val): """apply a value to scene""" raise NotImplementedError() - + ## Equality test. Override if data attributes can't be directly compared def __eq__(self, other): if isinstance(other, self.__class__): @@ -66,13 +65,12 @@ class SceneDetail(object): raise TypeError('{self} can\'t be compared with {other}' .format(self= repr(self), other= repr(other))) # - + # @property def full_key(self): return (self.class_id, self.doc.Name if self.doc else None, self.key) - + def __ne__(self, other): return not self.__eq__(other) - \ No newline at end of file diff --git a/src/Mod/Show/SceneDetails/Camera.py b/src/Mod/Show/SceneDetails/Camera.py index 1b2325fc43..20efeb689e 100644 --- a/src/Mod/Show/SceneDetails/Camera.py +++ b/src/Mod/Show/SceneDetails/Camera.py @@ -1,6 +1,5 @@ #/*************************************************************************** -# * Copyright (c) Victor Titov (DeepSOIC) * -# * (vv.titov@gmail.com) 2019 * +# * Copyright (c) 2019 Victor Titov (DeepSOIC) * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -28,11 +27,11 @@ import FreeCADGui class Camera(SceneDetail): """Camera(doc): TempoVis plugin for saving and restoring camera.""" class_id = 'SDCamera' - + def __init__(self, doc): self.doc = doc self.key = 'the_cam' - + def _viewer(self): gdoc = FreeCADGui.getDocument(self.doc.Name) v = gdoc.activeView() @@ -42,7 +41,7 @@ class Camera(SceneDetail): def scene_value(self): return self._viewer().getCamera() - + def apply_data(self, val): self._viewer().setCamera(val) diff --git a/src/Mod/Show/SceneDetails/ClipPlane.py b/src/Mod/Show/SceneDetails/ClipPlane.py index 1231ebd10e..e1a7d383a3 100644 --- a/src/Mod/Show/SceneDetails/ClipPlane.py +++ b/src/Mod/Show/SceneDetails/ClipPlane.py @@ -1,6 +1,5 @@ #/*************************************************************************** -# * Copyright (c) Victor Titov (DeepSOIC) * -# * (vv.titov@gmail.com) 2019 * +# * Copyright (c) 2019 Victor Titov (DeepSOIC) * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -28,12 +27,12 @@ import FreeCADGui as Gui class ClipPlane(SceneDetail): """ClipPlane(document, enable = None, placement = None, offset = 0.0): TempoVis plugin for applying clipping plane to whole project except edit root. - enable can be 0 for disable, 1 for enable, and -1 for toggle + enable can be 0 for disable, 1 for enable, and -1 for toggle (FIXME: toggle value support is a hack for while we can't read out the current state).""" - + class_id = 'SDClipPlane' key = '' - + def __init__(self, document, enable = None, placement = None, offset = 0.0): self.doc = document if enable is not None: @@ -42,10 +41,10 @@ class ClipPlane(SceneDetail): dir = placement.Rotation.multVec(App.Vector(0,0,1)) placement.Base = placement.Base + dir*offset self.data = (enable, placement) - + def scene_value(self): return (0, None) #hack. For until there is a way to easily query the plane, this should be good enough. - + def apply_data(self, val): enable, pla = val if enable != 0: diff --git a/src/Mod/Show/SceneDetails/ObjectClipPlane.py b/src/Mod/Show/SceneDetails/ObjectClipPlane.py index eeb721ec4f..0220a84d09 100644 --- a/src/Mod/Show/SceneDetails/ObjectClipPlane.py +++ b/src/Mod/Show/SceneDetails/ObjectClipPlane.py @@ -1,6 +1,5 @@ #/*************************************************************************** -# * Copyright (c) Victor Titov (DeepSOIC) * -# * (vv.titov@gmail.com) 2019 * +# * Copyright (c) 2019 Victor Titov (DeepSOIC) * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -31,14 +30,14 @@ class ObjectClipPlane(SceneDetail): class_id = 'SDObjectClipPlane' propname = '' objname = '' - + def __init__(self, object, enable = None, placement = None, offset = 0.0): self.objname = object.Name self.doc = object.Document - self.key = self.objname + self.key = self.objname if enable is not None: self.data = self.val(enable, placement, offset) - + def scene_value(self): vp = self.doc.getObject(self.objname).ViewObject cp = getClipPlaneNode(vp, make_if_missing= False) @@ -50,7 +49,7 @@ class ObjectClipPlane(SceneDetail): D = pln.getDistanceFromOrigin() normal = tuple(pln.getNormal()) return enable, (normal, D) - + def apply_data(self, val): enable, pldef = val vp = self.doc.getObject(self.objname).ViewObject @@ -62,12 +61,12 @@ class ObjectClipPlane(SceneDetail): v, d = pldef cp.plane.setValue(coin.SbPlane(coin.SbVec3f(*v), d)) cp.on.setValue(enable) - + def val(self, enable, placement = None, offset = 0.0): - """val(enable, placement = None, offset = 0.0): constructs a value from convenient - parameters. Placement is in global CS. The cutting will be by XY plane of Placement; + """val(enable, placement = None, offset = 0.0): constructs a value from convenient + parameters. Placement is in global CS. The cutting will be by XY plane of Placement; the stuff in negative Z is visible and the stuff in positive Z is invisible.""" - + pldef = None if enable: obj = self.doc.getObject(self.objname) diff --git a/src/Mod/Show/SceneDetails/Pickability.py b/src/Mod/Show/SceneDetails/Pickability.py index 0dd668b1b9..95aed9ea10 100644 --- a/src/Mod/Show/SceneDetails/Pickability.py +++ b/src/Mod/Show/SceneDetails/Pickability.py @@ -1,6 +1,5 @@ #/*************************************************************************** -# * Copyright (c) Victor Titov (DeepSOIC) * -# * (vv.titov@gmail.com) 2019 * +# * Copyright (c) 2019 Victor Titov (DeepSOIC) * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -24,7 +23,7 @@ from Show.SceneDetail import SceneDetail class Pickability(SceneDetail): - """Pickability(object, pickstyle = None):Plugin for TempoVis for altering pick style + """Pickability(object, pickstyle = None):Plugin for TempoVis for altering pick style of objects (i.e., selectability). pickstyle may be: PS_REGULAR = 0 # selectable @@ -33,17 +32,17 @@ class Pickability(SceneDetail): class_id = 'SDPickability' propname = '' objname = '' - + def __init__(self, object, pickstyle = None): self.objname = object.Name self.doc = object.Document - self.key = self.objname + self.key = self.objname if pickstyle is not None: self.data = pickstyle - + def scene_value(self): return getPickStyle(self.doc.getObject(self.objname).ViewObject) - + def apply_data(self, val): setPickStyle(self.doc.getObject(self.objname).ViewObject, val) @@ -65,7 +64,7 @@ def getPickStyleNode(viewprovider, make_if_missing = True): pick_style.style.setValue(coin.SoPickStyle.SHAPE) viewprovider.RootNode.insertChild(pick_style, 0) return pick_style - + def getPickStyle(viewprovider): ps = getPickStyleNode(viewprovider, make_if_missing= False) diff --git a/src/Mod/Show/SceneDetails/VProperty.py b/src/Mod/Show/SceneDetails/VProperty.py index d404a71275..35bb26e9d8 100644 --- a/src/Mod/Show/SceneDetails/VProperty.py +++ b/src/Mod/Show/SceneDetails/VProperty.py @@ -1,6 +1,5 @@ #/*************************************************************************** -# * Copyright (c) Victor Titov (DeepSOIC) * -# * (vv.titov@gmail.com) 2019 * +# * Copyright (c) 2019 Victor Titov (DeepSOIC) * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -25,13 +24,13 @@ from Show.SceneDetail import SceneDetail class VProperty(SceneDetail): """VProperty(object, propname, val = None): plugin for TempoVis to alter ViewProvider properties""" - + class_id = 'SDVProperty' affects_persistence = True propname = '' objname = '' mild_restore = True - + def __init__(self, object, propname, val = None): self.objname = object.Name self.propname = propname @@ -40,9 +39,9 @@ class VProperty(SceneDetail): self.data = val if propname == 'LinkVisibility': #seems to not be a property self.affects_persistence = False - + def scene_value(self): return getattr(self.doc.getObject(self.objname).ViewObject, self.propname) - + def apply_data(self, val): setattr(self.doc.getObject(self.objname).ViewObject, self.propname, val) diff --git a/src/Mod/Show/SceneDetails/Workbench.py b/src/Mod/Show/SceneDetails/Workbench.py index 11929d6f70..13a5b4e9a7 100644 --- a/src/Mod/Show/SceneDetails/Workbench.py +++ b/src/Mod/Show/SceneDetails/Workbench.py @@ -1,6 +1,5 @@ #/*************************************************************************** -# * Copyright (c) Victor Titov (DeepSOIC) * -# * (vv.titov@gmail.com) 2019 * +# * Copyright (c) 2019 Victor Titov (DeepSOIC) * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -26,19 +25,19 @@ from Show.SceneDetail import SceneDetail import FreeCADGui class Workbench(SceneDetail): - """Workbench(wb = None): Plugin for TempoVis for changing active workbench. + """Workbench(wb = None): Plugin for TempoVis for changing active workbench. wb: string, a name of a workbench (e.g. 'SketcherWorkbench')""" class_id = 'SDWorkbench' mild_restore = True - + def __init__(self, wb = None): self.key = 'workbench' if wb is not None: self.data = wb - + def scene_value(self): return FreeCADGui.activeWorkbench().name() - + def apply_data(self, val): FreeCADGui.activateWorkbench(val) diff --git a/src/Mod/Show/ShowUtils.py b/src/Mod/Show/ShowUtils.py index da20e6a51a..06f903f59e 100644 --- a/src/Mod/Show/ShowUtils.py +++ b/src/Mod/Show/ShowUtils.py @@ -1,6 +1,5 @@ #/*************************************************************************** -# * Copyright (c) Victor Titov (DeepSOIC) * -# * (vv.titov@gmail.com) 2019 * +# * Copyright (c) 2019 Victor Titov (DeepSOIC) * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -20,11 +19,11 @@ # * Suite 330, Boston, MA 02111-1307, USA * # * * # ***************************************************************************/ - + def is3DObject(obj): - """is3DObject(obj): tests if the object has some 3d geometry. + """is3DObject(obj): tests if the object has some 3d geometry. TempoVis is made only for objects in 3d view, so all objects that don't pass this check are ignored by TempoVis.""" - + # See "Gui Problem Sketcher and TechDraw" https://forum.freecadweb.org/viewtopic.php?f=3&t=22797 # observation: all viewproviders have transform node, then a switch node. If that switch node contains something, the object has something in 3d view. diff --git a/src/Mod/Show/TVObserver.py b/src/Mod/Show/TVObserver.py index 32fabfc843..e0c4b65a8b 100644 --- a/src/Mod/Show/TVObserver.py +++ b/src/Mod/Show/TVObserver.py @@ -1,6 +1,5 @@ #/*************************************************************************** -# * Copyright (c) Victor Titov (DeepSOIC) * -# * (vv.titov@gmail.com) 2019 * +# * Copyright (c) 2019 Victor Titov (DeepSOIC) * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -26,18 +25,18 @@ import FreeCAD class TVObserver(object): def __init__(self): FreeCAD.addDocumentObserver(self) - + def stop(self): FreeCAD.removeDocumentObserver(self) - + def slotStartSaveDocument(self, doc, filepath): from . import TVStack TVStack._slotStartSaveDocument(doc) - + def slotFinishSaveDocument(self, doc, filepath): from . import TVStack TVStack._slotFinishSaveDocument(doc) - + def slotDeletedDocument(self, doc): from . import TVStack TVStack._slotDeletedDocument(doc) diff --git a/src/Mod/Show/TVStack.py b/src/Mod/Show/TVStack.py index b7366caef9..b803e60acf 100644 --- a/src/Mod/Show/TVStack.py +++ b/src/Mod/Show/TVStack.py @@ -1,6 +1,5 @@ #/*************************************************************************** -# * Copyright (c) Victor Titov (DeepSOIC) * -# * (vv.titov@gmail.com) 2019 * +# * Copyright (c) 2019 Victor Titov (DeepSOIC) * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -29,7 +28,7 @@ class TVStack(object): index_LUT = None # Key = id(tempovis_instance). Value = index in the stack. stack = None #list of weakrefs to TV instances. Using weakrefs, so that TempoVis can self-destruct if forgotten. document = None - + _rewind_tv = None def __init__(self, document): @@ -44,11 +43,11 @@ class TVStack(object): idtv = id(tv) ref = weakref.ref(tv, (lambda _, idtv=idtv, self=self : self._destruction(idtv))) self.stack.insert(index, ref) - + self.rebuild_index(index) tv._inserted(self, index) - + def _destruction(self, idtv): # the tempovis itself is destroyed already. Purge it from the stack (it should have withdrawn itself, but just in case). try: @@ -60,7 +59,7 @@ class TVStack(object): self.stack.pop(index) self.index_LUT.pop(idtv) self.rebuild_index(index) - + def withdraw(self, tv): idtv = id(tv) index = self.index_LUT[idtv] @@ -68,21 +67,21 @@ class TVStack(object): self.index_LUT.pop(idtv) self.rebuild_index(index) - + tv = ref() if tv: tv._withdrawn(self, index) - + def value_after(self, tv, detail): - """value_after(tv, detail): returns tuple (tv1, detail), or None. - Here, tv1 is the tv that remembers the value, and detail is reference to recorded - data in tv1. None is returned, if no TVs in the stack after the provided one have + """value_after(tv, detail): returns tuple (tv1, detail), or None. + Here, tv1 is the tv that remembers the value, and detail is reference to recorded + data in tv1. None is returned, if no TVs in the stack after the provided one have recorded a change to this detail. - - tv can be None, then, the function returns the original value of the detail, or + + tv can be None, then, the function returns the original value of the detail, or None, if the current value matches the original.""" from . import mTempoVis - + index = self.index_LUT[id(tv)] if tv is not None else -1 for tvref in self.stack[index + 1 : ]: tv = tvref() @@ -90,14 +89,14 @@ class TVStack(object): if tv.has(detail): return (tv, tv.data[detail.full_key]) return None - + def rebuild_index(self, start = 0): if start == 0: self.index_LUT = {} for i in range(start, len(self.stack)): self.index_LUT[id(self.stack[i]())] = i - - + + def purge_dead(self): """removes dead TV instances from the stack""" n = 0 @@ -108,18 +107,18 @@ class TVStack(object): if n > 0: self.rebuild_index() return n - + def dissolve(self): """silently cleans all TVs, so that they won't restore.""" for ref in self.stack: if ref() is not None: ref().forget() - + def unwindForSaving(self): from . import mTempoVis self.rewindAfterSaving() #just in case there was a failed save before. - + details = {} #dict of detail original values. Key = detail key; value = detail instance with data representing the original value for ref in self.stack: tv = ref() @@ -127,26 +126,26 @@ class TVStack(object): if not key in details: if detail.affects_persistence: details[detail.full_key] = detail - + self._rewind_tv = mTempoVis.TempoVis(self.document, None) for key, detail in details.items(): self._rewind_tv.modify(detail) - + def rewindAfterSaving(self): if self._rewind_tv is not None: self._rewind_tv.restore() self._rewind_tv = None - + def getSplitSequence(self, tv): """getSplitSequence(tv): returns (list_before, list_after), neither list includes tv.""" index = self.index_LUT[id(tv)] - def deref(lst): + def deref(lst): return [ref() for ref in lst] return deref(self.stack[0:index]), deref(self.stack[index+1:]) - + def __getitem__(self, index): return self.stack[index]() - + def __len__(self): return len(self.stack) @@ -157,23 +156,23 @@ class TVStack(object): def __reversed__(self): for ref in reversed(self.stack): yield ref() - + def restoreAll(self): for ref in reversed(self.stack): ref().restore() - + def byTag(self, tag): return [ref() for ref in self.stack if ref().tag == tag] - + def mainStack(document, create_if_missing = True): """mainStack(document, create_if_missing = True):returns the main TVStack instance for provided document""" docname = document.Name - + if create_if_missing: if not docname in global_stacks: global_stacks[docname] = TVStack(document) - + return global_stacks.get(docname, None) def _slotDeletedDocument(document): diff --git a/src/Mod/Show/mTempoVis.py b/src/Mod/Show/mTempoVis.py index b38bd217eb..1e40a2dc44 100644 --- a/src/Mod/Show/mTempoVis.py +++ b/src/Mod/Show/mTempoVis.py @@ -1,6 +1,5 @@ #/*************************************************************************** -# * Copyright (c) Victor Titov (DeepSOIC) * -# * (vv.titov@gmail.com) 2016 * +# * Copyright (c) 2016 Victor Titov (DeepSOIC) * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -21,7 +20,7 @@ # * * # ***************************************************************************/ -# module is named mTempoVis, because Show.TimpoVis exposes the class as its member, and hides the module TempoVis.py. +# module is named mTempoVis, because Show.TimpoVis exposes the class as its member, and hides the module TempoVis.py from . import Containers @@ -37,7 +36,7 @@ Log = lambda msg: App.Console.PrintLog(msg + "\n") from copy import copy S_EMPTY = 0 # TV is initialized, but no changes were done through it -S_ACTIVE = 1 # TV has something to be undone +S_ACTIVE = 1 # TV has something to be undone S_RESTORED = 2 # TV has been restored S_INTERNAL = 3 # TV instance is being used by another TV instance as a redo data storage @@ -61,15 +60,15 @@ class TempoVis(object): then restoring all visibilities after editing. Constructors: - TempoVis(document, stack = MAINSTACK, **kwargs): creates a new TempoVis. - + TempoVis(document, stack = MAINSTACK, **kwargs): creates a new TempoVis. + document: required. Objects not belonging to the document can't be modified via TempoVis. - + stack: optional. Which stack to insert this new TV into. Can be: - a TVStack instance (then, the new TV is added to the top of the stack), - MAINSTACK special value (a global stack for the document will be used), or + a TVStack instance (then, the new TV is added to the top of the stack), + MAINSTACK special value (a global stack for the document will be used), or None (then, the TV is not in any stack, and can be manually instertd into one if desired). - + Any additional keyword args are assigned as attributes. You can use it to immediately set a tag, for example.''' document = None @@ -77,47 +76,47 @@ class TempoVis(object): data = None # dict. key = ("class_id","key"), value = instance of SceneDetail data_requested = None #same as data, but stores (wanted) values passed to modify() - + state = S_EMPTY - + tag = '' #stores any user-defined string for identification purposes def _init_attrs(self): '''initialize member variables to empty values (needed because we can't use mutable initial values when initializing member variables in class definition)''' self.data = {} self.data_requested = {} - + # def __init__(self, document, stack = MAINSTACK, **kwargs): self._init_attrs() self.document = document - + if stack is MAINSTACK: stack = TVStack.mainStack(document) - + if stack is None: pass else: stack.insert(self) - + for key,val in kwargs.items(): setattr(self, key, val) - + def __del__(self): if self.state == S_ACTIVE: self.restore(ultimate= True) - + def has(self, detail): '''has(self, detail): returns True if this TV has this detail value saved. example: tv.has(VProperty(obj, "Visibility"))''' return detail.full_key in self.data - + def stored_val(self, detail): '''stored_val(self, detail): returns value of detail remembered by this TV. If not, raises KeyError.''' return self.data[detail.full_key].data def save(self, detail, mild_restore = False): - '''save(detail, mild_restore = False):saves the scene detail to be restored. + '''save(detail, mild_restore = False):saves the scene detail to be restored. The detail is saved only once; repeated calls are ignored. mild_restore: internal, do not use.''' self._change() @@ -133,36 +132,36 @@ class TempoVis(object): stored_dt.mild_restore = False def modify(self, detail, mild_restore = None): - '''modify(detail, mild_restore = True): modifies scene detail through this TV. + '''modify(detail, mild_restore = True): modifies scene detail through this TV. The value is provided as an instance of SceneDetail implementation. - The procedure takes care to account for the stack - that is, if in a TV applied - later than this one this detail was changed too, the value saved therein is altered, + The procedure takes care to account for the stack - that is, if in a TV applied + later than this one this detail was changed too, the value saved therein is altered, rather than applied to the scene. - - mild_restore: if True, when restoring later, checks if the value was changed + + mild_restore: if True, when restoring later, checks if the value was changed by user after last call to modify(), and doesn't restore if it was changed. - + Example: tv.modify(VProperty(obj, "Visibility", True))''' self._change() - + if mild_restore is not None: detail.mild_restore = mild_restore - + # save current self.save(detail, detail.mild_restore) - + # apply tv1, curr = self._value_after(detail) if tv1 is not None: tv1.data[detail.full_key].data = detail.data else: detail.apply_data(detail.data) - + # and record. if detail.mild_restore: self.data_requested[detail.full_key] = copy(detail) - + def restoreDetail(self, detail, ultimate = False): '''restoreDetail(detail, ultimate = False): restores a specific scene detail. ultimate: if true, the saved value is cleaned out. @@ -173,15 +172,15 @@ class TempoVis(object): self._restore_detail(detail) if ultimate: self.forgetDetail(detail) - - + + def forgetDetail(self, detail): '''forgetDetail(detail): ditches a saved detail value, making the change done through this TV permanent.''' self.data.pop(detail.full_key, None) self.data_requested.pop(detail.full_key, None) - + def forget(self): - '''forget(self): clears this TV, making all changes done through it permanent. + '''forget(self): clears this TV, making all changes done through it permanent. Also, withdraws the TV from the stack.''' self.state = S_EMPTY self.data = {} @@ -190,15 +189,15 @@ class TempoVis(object): def restore(self, ultimate = True): '''restore(ultimate = True): undoes all changes done through this tempovis / restores saved scene details. - ultimate: if true, the saved values are cleaned out, and the TV is withdrawn from + ultimate: if true, the saved values are cleaned out, and the TV is withdrawn from the stack. If false, the TV will still remember stuff, and restore can be called again. ''' if self.state == S_RESTORED: return if self.state != S_INTERNAL and ultimate: - self.state = S_RESTORED - + self.state = S_RESTORED + for key, detail in self.data.items(): try: self._restoreDetail(detail) @@ -209,9 +208,9 @@ class TempoVis(object): self.data = {} if self.is_in_stack: self.stack.withdraw(self) - + # - + # def _inserted(self, stack, index): '''calles when this tv is inserted into a stack''' @@ -224,15 +223,15 @@ class TempoVis(object): return self.stack is not None # - # + # def modifyVPProperty(self, doc_obj_or_list, prop_names, new_value = JUST_SAVE, mild_restore = None): '''modifyVPProperty(doc_obj_or_list, prop_names, new_value = JUST_SAVE, mild_restore = None): modifies prop_name property of ViewProvider of doc_obj_or_list, and remembers original value of the property. Original values will be restored upon TempoVis deletion, or call to restore(). - + mild_restore: test if user changed the value manually when restoring the TV.''' - + if self.state == S_RESTORED: Wrn("Attempting to use a TV that has been restored. There must be a problem with code.") return @@ -264,7 +263,7 @@ class TempoVis(object): def restoreVPProperty(self, doc_obj_or_list, prop_names): '''restoreVPProperty(doc_obj_or_list, prop_name, new_value): restores specific property changes.''' from .SceneDetails.VProperty import VProperty - + if not hasattr(doc_obj_or_list, '__iter__'): doc_obj_or_list = [doc_obj_or_list] if not isinstance(prop_names,(tuple,list)): @@ -279,7 +278,7 @@ class TempoVis(object): def saveBodyVisibleFeature(self, doc_obj_or_list): - """saveBodyVisibleFeature(self, doc_obj_or_list): saves Visibility of currently + """saveBodyVisibleFeature(self, doc_obj_or_list): saves Visibility of currently visible feature, for every body of PartDesign features in the provided list.""" if not hasattr(doc_obj_or_list, '__iter__'): doc_obj_or_list = [doc_obj_or_list] @@ -297,7 +296,7 @@ class TempoVis(object): return objs def show(self, doc_obj_or_list, links_too = True, mild_restore = None): - '''show(doc_obj_or_list, links_too = True): shows objects (sets their Visibility to True). + '''show(doc_obj_or_list, links_too = True): shows objects (sets their Visibility to True). doc_obj_or_list can be a document object, or a list of document objects. If links_too is True, all Links of the objects are also hidden, by setting LinkVisibility attribute of each object.''' doc_obj_or_list = self._3D_objects(doc_obj_or_list) @@ -320,15 +319,15 @@ class TempoVis(object): from .Containers import isAContainer from .DepGraphTools import getAllDependencies, getAllDependent if subname: - # a link-path was provided. doc_obj has nothing to do with the object we want + # a link-path was provided. doc_obj has nothing to do with the object we want # to collect dependencies from. So, replace it with the one pointed by link-path. cnt_chain = doc_obj.getSubObjectList(subname) doc_obj = cnt_chain[-1].getLinkedObject() - # cnt_chain can either end with the object (e.g. if a sketch is in a part, and - # a link is to a part), or it may be a Link object (if we have a straight or + # cnt_chain can either end with the object (e.g. if a sketch is in a part, and + # a link is to a part), or it may be a Link object (if we have a straight or # even nested Link to the sketch). # - # I don't know why do we need that isAContainer check here, but I'm leaving it, + # I don't know why do we need that isAContainer check here, but I'm leaving it, # realthunder must be knowing his business --DeepSOIC cnt_chain = [ o for o in cnt_chain if o==cnt_chain[-1] or isAContainer(o, links_too= True) ] @@ -364,7 +363,7 @@ class TempoVis(object): self._change() from .SceneDetails.Camera import Camera self.save(Camera(self.document)) - + def restoreCamera(self, ultimate = False): from .SceneDetails.Camera import Camera dt = Camera(self.document) @@ -373,17 +372,17 @@ class TempoVis(object): def setUnpickable(self, doc_obj_or_list, actual_pick_style = 2): #2 is coin.SoPickStyle.UNPICKABLE '''setUnpickable(doc_obj_or_list, actual_pick_style = 2): sets object unpickable (transparent to clicks). doc_obj_or_list: object or list of objects to alter (App) - actual_pick_style: optional parameter, specifying the actual pick style: + actual_pick_style: optional parameter, specifying the actual pick style: 0 = regular, 1 = bounding box, 2 (default) = unpickable. - - Implementation detail: uses SoPickStyle node. If viewprovider already has a node - of this type as direct child, one is used. Otherwise, new one is created and - inserted as the very first node, and remains there even after restore()/deleting + + Implementation detail: uses SoPickStyle node. If viewprovider already has a node + of this type as direct child, one is used. Otherwise, new one is created and + inserted as the very first node, and remains there even after restore()/deleting tempovis. ''' - + from .SceneDetails.Pickability import Pickability from .ShowUtils import is3DObject - + if not hasattr(doc_obj_or_list, '__iter__'): doc_obj_or_list = [doc_obj_or_list] for doc_obj in doc_obj_or_list: @@ -392,20 +391,20 @@ class TempoVis(object): dt = Pickability(doc_obj, actual_pick_style) self.modify(dt) - def clipPlane(self, doc_obj_or_list, enable, placement, offset = 0.02): + def clipPlane(self, doc_obj_or_list, enable, placement, offset = 0.02): '''clipPlane(doc_obj_or_list, enable, placement, offset): slices off the object with a clipping plane. doc_obj_or_list: object or list of objects to alter (App) - enable: True if you want clipping, False if you want to remove clipping: + enable: True if you want clipping, False if you want to remove clipping: placement: XY plane of local coordinates of the placement is the clipping plane. The placement must be in document's global coordinate system. offset: shifts the plane. Positive offset reveals more of the object. - - Implementation detail: uses SoClipPlane node. If viewprovider already has a node - of this type as direct child, one is used. Otherwise, new one is created and + + Implementation detail: uses SoClipPlane node. If viewprovider already has a node + of this type as direct child, one is used. Otherwise, new one is created and inserted as the very first node. The node is left, but disabled when tempovis is restoring.''' - + from .SceneDetails.ObjectClipPlane import ObjectClipPlane from .ShowUtils import is3DObject - + if not hasattr(doc_obj_or_list, '__iter__'): doc_obj_or_list = [doc_obj_or_list] for doc_obj in doc_obj_or_list: @@ -413,14 +412,14 @@ class TempoVis(object): continue dt = ObjectClipPlane(doc_obj, enable, placement, offset) self.modify(dt) - + @staticmethod def allVisibleObjects(aroundObject): - '''allVisibleObjects(aroundObject): returns list of objects that have to be toggled invisible for only aroundObject to remain. + '''allVisibleObjects(aroundObject): returns list of objects that have to be toggled invisible for only aroundObject to remain. If a whole container can be made invisible, it is returned, instead of its child objects.''' from .ShowUtils import is3DObject from . import Containers - + chain = Containers.VisGroupChain(aroundObject) result = [] for i in range(len(chain)): @@ -434,13 +433,13 @@ class TempoVis(object): if container.isChildVisible(obj): result.append(obj) return result - + def sketchClipPlane(self, sketch, enable = None, reverted = False): - '''sketchClipPlane(sketch, enable = None): Clips all objects by plane of sketch. + '''sketchClipPlane(sketch, enable = None): Clips all objects by plane of sketch. If enable argument is omitted, calling the routine repeatedly will toggle clipping plane.''' - + from .SceneDetails.ClipPlane import ClipPlane - + editDoc = Gui.editDocument() if editDoc is None: doc = sketch.Document @@ -457,14 +456,14 @@ class TempoVis(object): if enable: # clip plane shall be disabled so new placement can be applied self.modify(ClipPlane(doc, 0)) - + self.modify(ClipPlane(doc, toggle, pla, 0.02)) sketch.ViewObject.SectionView = enable if enable is not None else not sketch.ViewObject.SectionView - + def activateWorkbench(self, wb_name): from .SceneDetails.Workbench import Workbench self.modify(Workbench(wb_name)) - + # # @@ -482,7 +481,7 @@ class TempoVis(object): else: #modify saved detail of higher TV tv1.data[detail.full_key].data = p.data - + def _purge_milds(self, detail): """_purge_milds(detail): wipes out detail from earlier TVs if the detail is mild-restore.""" if not self.is_in_stack: @@ -502,13 +501,13 @@ class TempoVis(object): self.state = S_ACTIVE if self.state == S_RESTORED: Wrn("Attempting to use a TV that has been restored. There must be a problem with code.") - self.tv_redo = None + self.tv_redo = None def _value_after(self, detail, query_scene = False): - '''_value_current(detail): returns (tv, detail1). SceneDetail instance holds "current" value of - scene detail (current from the context of this TV; i.e. either the current scene + '''_value_current(detail): returns (tv, detail1). SceneDetail instance holds "current" value of + scene detail (current from the context of this TV; i.e. either the current scene status, or the saved state from upper TVs). - If no upper TV has saved the detail value, returns either (None, None), or + If no upper TV has saved the detail value, returns either (None, None), or (None, detail1) if query_scene is True, where detail1 holds value from the scene.''' def scene_value(): if query_scene: @@ -517,7 +516,7 @@ class TempoVis(object): return (None, cpy) else: return (None, None) - + if self.is_in_stack: va = self.stack.value_after(self, detail) if va is None: @@ -526,20 +525,18 @@ class TempoVis(object): return va else: return scene_value() - + def _3D_objects(self, doc_obj_or_list): """_3D_objects(doc_obj_or_list): returns list of objects that are in 3d view.""" from .ShowUtils import is3DObject - + if not hasattr(doc_obj_or_list, '__iter__'): doc_obj_or_list = [doc_obj_or_list] - + return [obj for obj in doc_obj_or_list if is3DObject(obj)] - + def __getstate__(self): return None - + def __setstate__(self, state): self._init_attrs() - -