Complete support for drag and drop
This commit is contained in:
parent
6b91e11daf
commit
2274fec363
258
assembly.py
258
assembly.py
|
@ -28,13 +28,16 @@ def isTypeOf(obj,tp,resolve=False):
|
||||||
|
|
||||||
def checkType(obj,tp,resolve=False):
|
def checkType(obj,tp,resolve=False):
|
||||||
if not isTypeOf(obj,tp,resolve):
|
if not isTypeOf(obj,tp,resolve):
|
||||||
raise TypeError('Expect object "{}" to be of type "{}"'.format(
|
raise TypeError('Expect object {} to be of type "{}"'.format(
|
||||||
objName(obj),tp.__name__))
|
objName(obj),tp.__name__))
|
||||||
|
|
||||||
def getProxy(obj,tp):
|
def getProxy(obj,tp):
|
||||||
checkType(obj,tp)
|
checkType(obj,tp)
|
||||||
return obj.Proxy
|
return obj.Proxy
|
||||||
|
|
||||||
|
# For faking selection obtained from Gui.getSelectionEx()
|
||||||
|
Selection = namedtuple('AsmSelection',('Object','SubElementNames'))
|
||||||
|
|
||||||
class AsmBase(object):
|
class AsmBase(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.Object = None
|
self.Object = None
|
||||||
|
@ -86,6 +89,15 @@ class ViewProviderAsmBase(object):
|
||||||
if cls._iconName:
|
if cls._iconName:
|
||||||
return utils.getIcon(cls)
|
return utils.getIcon(cls)
|
||||||
|
|
||||||
|
def canDropObjects(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def canDragObjects(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def canDragAndDropObject(self,_obj):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class AsmGroup(AsmBase):
|
class AsmGroup(AsmBase):
|
||||||
def linkSetup(self,obj):
|
def linkSetup(self,obj):
|
||||||
|
@ -115,6 +127,9 @@ class ViewProviderAsmGroup(ViewProviderAsmBase):
|
||||||
def doubleClicked(self, _vobj):
|
def doubleClicked(self, _vobj):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def canDropObject(self,_child):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class AsmPartGroup(AsmGroup):
|
class AsmPartGroup(AsmGroup):
|
||||||
def __init__(self,parent):
|
def __init__(self,parent):
|
||||||
|
@ -139,12 +154,19 @@ class ViewProviderAsmPartGroup(ViewProviderAsmBase):
|
||||||
def onDelete(self,_obj,_subs):
|
def onDelete(self,_obj,_subs):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def canDropObject(self,obj):
|
def canDropObjectEx(self,obj,_owner,_subname):
|
||||||
return isTypeOf(obj,Assembly) or not isTypeOf(obj,AsmBase)
|
return isTypeOf(obj,Assembly) or not isTypeOf(obj,AsmBase)
|
||||||
|
|
||||||
def canDropObjects(self):
|
def canDragObject(self,_obj):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def canDragObjects(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def canDragAndDropObject(self,_obj):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class AsmElement(AsmBase):
|
class AsmElement(AsmBase):
|
||||||
def __init__(self,parent):
|
def __init__(self,parent):
|
||||||
self.shape = None
|
self.shape = None
|
||||||
|
@ -237,17 +259,24 @@ class AsmElement(AsmBase):
|
||||||
'The selections must have a common (grand)parent assembly')
|
'The selections must have a common (grand)parent assembly')
|
||||||
|
|
||||||
sel = sels[0]
|
sel = sels[0]
|
||||||
subs = sel.SubElementNames
|
subs = list(sel.SubElementNames)
|
||||||
|
if not subs:
|
||||||
|
raise RuntimeError('no sub object in selection')
|
||||||
if len(subs)>2:
|
if len(subs)>2:
|
||||||
raise RuntimeError('At most two selection is allowed.\n'
|
raise RuntimeError('At most two selection is allowed.\n'
|
||||||
'The first selection must be a sub element belonging to some '
|
'The first selection must be a sub element belonging to some '
|
||||||
'assembly. The optional second selection must be an element '
|
'assembly. The optional second selection must be an element '
|
||||||
'belonging to the same assembly of the first selection')
|
'belonging to the same assembly of the first selection')
|
||||||
|
if len(subs)==2:
|
||||||
|
if len(subs[0])<len(subs[1]):
|
||||||
|
subs = [subs[1],subs[2]]
|
||||||
|
|
||||||
subElement = subs[0].split('.')[-1]
|
if subs[0][-1] == '.':
|
||||||
|
subElement = utils.deduceSelectedElement(sel.Object,subs[0])
|
||||||
if not subElement:
|
if not subElement:
|
||||||
raise RuntimeError(
|
raise RuntimeError('no sub element (face, edge, vertex) in '
|
||||||
'Please select a sub element belonging to some assembly')
|
'{}.{}'.format(sel.Object.Name,subs[0]))
|
||||||
|
subs[0] += subElement
|
||||||
|
|
||||||
link = Assembly.findPartGroup(sel.Object,subs[0])
|
link = Assembly.findPartGroup(sel.Object,subs[0])
|
||||||
if not link:
|
if not link:
|
||||||
|
@ -276,14 +305,17 @@ class AsmElement(AsmBase):
|
||||||
def make(selection=None,name='Element'):
|
def make(selection=None,name='Element'):
|
||||||
if not selection:
|
if not selection:
|
||||||
selection = AsmElement.getSelection()
|
selection = AsmElement.getSelection()
|
||||||
|
if not selection.Subname or selection.Subname[-1]=='.':
|
||||||
|
raise RuntimeError('Subname must refer to a sub-element')
|
||||||
assembly = getProxy(selection.Assembly,Assembly)
|
assembly = getProxy(selection.Assembly,Assembly)
|
||||||
element = selection.Element
|
element = selection.Element
|
||||||
if not element:
|
if not element:
|
||||||
elements = assembly.getElementGroup()
|
elements = assembly.getElementGroup()
|
||||||
# try to search the element group for an existing element
|
# try to search the element group for an existing element
|
||||||
for e in elements.Group:
|
for e in elements.Group:
|
||||||
if getProxy(e,AsmElement).getSubName() == selection.Subname:
|
sub = logger.catch('',e.Proxy.getSubName)
|
||||||
return element
|
if sub == selection.Subname:
|
||||||
|
return e
|
||||||
element = elements.Document.addObject("App::FeaturePython",
|
element = elements.Document.addObject("App::FeaturePython",
|
||||||
name,AsmElement(elements),None,True)
|
name,AsmElement(elements),None,True)
|
||||||
ViewProviderAsmElement(element.ViewObject)
|
ViewProviderAsmElement(element.ViewObject)
|
||||||
|
@ -307,6 +339,20 @@ class ViewProviderAsmElement(ViewProviderAsmBase):
|
||||||
def getDefaultColor(self):
|
def getDefaultColor(self):
|
||||||
return (60.0/255.0,1.0,1.0)
|
return (60.0/255.0,1.0,1.0)
|
||||||
|
|
||||||
|
def canDropObjectEx(self,_obj,owner,subname):
|
||||||
|
# check if is dropping a sub-element
|
||||||
|
if not subname or subname[-1]=='.':
|
||||||
|
return False
|
||||||
|
proxy = self.ViewObject.Object.Proxy
|
||||||
|
return proxy.getAssembly().getPartGroup()==owner
|
||||||
|
|
||||||
|
def dropObjectEx(self,vobj,_obj,_owner,subname):
|
||||||
|
obj = vobj.Object
|
||||||
|
AsmElement.make(AsmElement.Selection(
|
||||||
|
Assembly=obj.Proxy.getAssembly().Object,
|
||||||
|
Element=obj, Subname=subname))
|
||||||
|
|
||||||
|
|
||||||
PartInfo = namedtuple('AsmPartInfo', ('Parent','SubnameRef','Part',
|
PartInfo = namedtuple('AsmPartInfo', ('Parent','SubnameRef','Part',
|
||||||
'PartName','Placement','Object','Subname','Shape'))
|
'PartName','Placement','Object','Subname','Shape'))
|
||||||
|
|
||||||
|
@ -517,7 +563,9 @@ class AsmElementLink(AsmBase):
|
||||||
logger.debug('shape subname {} -> {}'.format(subname,sub))
|
logger.debug('shape subname {} -> {}'.format(subname,sub))
|
||||||
return sub
|
return sub
|
||||||
|
|
||||||
def prepareLink(self,owner,subname):
|
def prepareLink(self,owner,subname,checkOnly=False):
|
||||||
|
if not owner or not subname:
|
||||||
|
raise RuntimeError('no owner or subname')
|
||||||
assembly = self.getAssembly()
|
assembly = self.getAssembly()
|
||||||
sobj = owner.getSubObject(subname,1)
|
sobj = owner.getSubObject(subname,1)
|
||||||
if not sobj:
|
if not sobj:
|
||||||
|
@ -550,6 +598,11 @@ class AsmElementLink(AsmBase):
|
||||||
if not isTypeOf(ret[-1].Object,AsmPartGroup):
|
if not isTypeOf(ret[-1].Object,AsmPartGroup):
|
||||||
raise RuntimeError('Invalid element link ' + subname)
|
raise RuntimeError('Invalid element link ' + subname)
|
||||||
|
|
||||||
|
if checkOnly:
|
||||||
|
if not ret[-1].Subname or ret[-1].Subname[-1]=='.':
|
||||||
|
raise RuntimeError('Subname must refer to a sub-element')
|
||||||
|
return True
|
||||||
|
|
||||||
# call AsmElement.make to either create a new element, or an existing
|
# call AsmElement.make to either create a new element, or an existing
|
||||||
# element if there is one
|
# element if there is one
|
||||||
element = AsmElement.make(AsmElement.Selection(
|
element = AsmElement.make(AsmElement.Selection(
|
||||||
|
@ -566,7 +619,16 @@ class AsmElementLink(AsmBase):
|
||||||
|
|
||||||
def setLink(self,owner,subname):
|
def setLink(self,owner,subname):
|
||||||
obj = self.Object
|
obj = self.Object
|
||||||
obj.setLink(*self.prepareLink(owner,subname))
|
owner,subname = self.prepareLink(owner,subname)
|
||||||
|
for sibling in self.parent.Object.Group:
|
||||||
|
if sibling == self.Object:
|
||||||
|
continue
|
||||||
|
linked = sibling.LinkedObject
|
||||||
|
if isinstance(linked,tuple) and \
|
||||||
|
linked[0]==owner and linked[1]==subname:
|
||||||
|
raise RuntimeError('duplicate element link {} in constraint '
|
||||||
|
'{}'.format(objName(sibling),objName(self.parent.Object)))
|
||||||
|
obj.setLink(owner,subname)
|
||||||
linked = obj.getLinkedObject(False)
|
linked = obj.getLinkedObject(False)
|
||||||
if linked and linked!=obj:
|
if linked and linked!=obj:
|
||||||
label = linked.Label.split('_')
|
label = linked.Label.split('_')
|
||||||
|
@ -607,7 +669,7 @@ class AsmElementLink(AsmBase):
|
||||||
setupUndo(part.Document,undoDocs,undoName)
|
setupUndo(part.Document,undoDocs,undoName)
|
||||||
part.Placement = pla
|
part.Placement = pla
|
||||||
|
|
||||||
MakeInfo = namedtuple('AsmElementLinkSelection',
|
MakeInfo = namedtuple('AsmElementLinkMakeInfo',
|
||||||
('Constraint','Owner','Subname'))
|
('Constraint','Owner','Subname'))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -627,6 +689,17 @@ class ViewProviderAsmElementLink(ViewProviderAsmBase):
|
||||||
def doubleClicked(self,_vobj):
|
def doubleClicked(self,_vobj):
|
||||||
return movePart()
|
return movePart()
|
||||||
|
|
||||||
|
def canDropObjectEx(self,_obj,owner,subname):
|
||||||
|
if logger.catchTrace('Cannot drop to AsmLink {}'.format(
|
||||||
|
objName(self.ViewObject.Object)),
|
||||||
|
self.ViewObject.Object.Proxy.prepareLink,
|
||||||
|
owner, subname, True):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def dropObjectEx(self,vobj,_obj,owner,subname):
|
||||||
|
vobj.Object.Proxy.setLink(owner,subname)
|
||||||
|
|
||||||
|
|
||||||
class AsmConstraint(AsmGroup):
|
class AsmConstraint(AsmGroup):
|
||||||
|
|
||||||
|
@ -700,54 +773,69 @@ class AsmConstraint(AsmGroup):
|
||||||
return
|
return
|
||||||
shapes.append(info.Shape)
|
shapes.append(info.Shape)
|
||||||
elements.append(o)
|
elements.append(o)
|
||||||
Constraint.check(obj,shapes)
|
Constraint.check(obj,shapes,True)
|
||||||
self.elements = elements
|
self.elements = elements
|
||||||
return self.elements
|
return self.elements
|
||||||
|
|
||||||
Selection = namedtuple('ConstraintSelection',
|
Selection = namedtuple('AsmConstraintSelection',
|
||||||
('SelObject','SelSubname','Assembly','Constraint','Elements'))
|
('SelObject','SelSubname','Assembly','Constraint','Elements'))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getSelection(typeid=0):
|
def getSelection(typeid=0,sels=None):
|
||||||
'''
|
'''
|
||||||
Parse Gui.Selection for making a constraint
|
Parse Gui.Selection for making a constraint
|
||||||
|
|
||||||
The selected elements must all belong to the same immediate parent
|
The selected elements must all belong to the same immediate parent
|
||||||
assembly.
|
assembly.
|
||||||
'''
|
'''
|
||||||
|
if not sels:
|
||||||
sels = FreeCADGui.Selection.getSelectionEx('',False)
|
sels = FreeCADGui.Selection.getSelectionEx('',False)
|
||||||
if not sels:
|
if not sels:
|
||||||
raise RuntimeError('no selection')
|
raise RuntimeError('no selection')
|
||||||
if len(sels)>1:
|
if len(sels)>1:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
'The selections must have a common (grand)parent assembly')
|
'The selections must have a common (grand)parent assembly')
|
||||||
|
subs = sels[0].SubElementNames
|
||||||
|
if not subs:
|
||||||
|
raise RuntimeError('no sub-object in selection')
|
||||||
|
if len(subs)>2:
|
||||||
|
raise RuntimeError('too many selection')
|
||||||
|
if len(subs)==2:
|
||||||
|
sobj = sels[0].Object.getSubObject(subs[1],1)
|
||||||
|
if isTypeOf(sobj,(AsmConstraintGroup,Assembly,AsmConstraint)):
|
||||||
|
subs = (subs[1],subs[0])
|
||||||
|
|
||||||
sel = sels[0]
|
sel = sels[0]
|
||||||
cstr = None
|
cstr = None
|
||||||
elements = []
|
elements = []
|
||||||
assembly = None
|
assembly = None
|
||||||
selSubname = None
|
selSubname = None
|
||||||
for sub in sel.SubElementNames:
|
for sub in subs:
|
||||||
sobj = sel.Object.getSubObject(sub,1)
|
sobj = sel.Object.getSubObject(sub,1)
|
||||||
if not sobj:
|
if not sobj:
|
||||||
raise RuntimeError('Cannot find sub-object "{}" of {}'.format(
|
raise RuntimeError('Cannot find sub-object {}.{}'.format(
|
||||||
sub,sel.Object))
|
sel.Object.Name,sub))
|
||||||
ret = Assembly.find(sel.Object,sub,
|
ret = Assembly.find(sel.Object,sub,
|
||||||
recursive=True,relativeToChild=False)
|
recursive=True,relativeToChild=False)
|
||||||
if not ret:
|
if not ret:
|
||||||
raise RuntimeError('Selection {}.{} is not from an '
|
raise RuntimeError('Selection {}.{} is not from an '
|
||||||
'assembly'.format(sel.Object.Name,sub))
|
'assembly'.format(sel.Object.Name,sub))
|
||||||
if not assembly:
|
|
||||||
# check if the selection is a constraint group or a constraint
|
# check if the selection is a constraint group or a constraint
|
||||||
if isTypeOf(sobj,(AsmConstraintGroup,Assembly,AsmConstraint)):
|
if isTypeOf(sobj,(AsmConstraintGroup,Assembly,AsmConstraint)):
|
||||||
|
if assembly:
|
||||||
|
raise RuntimeError('no element selection')
|
||||||
assembly = ret[-1].Assembly
|
assembly = ret[-1].Assembly
|
||||||
selSubname = sub[:-len(ret[-1].Subname)]
|
selSubname = sub[:-len(ret[-1].Subname)]
|
||||||
if isTypeOf(sobj,AsmConstraint):
|
if isTypeOf(sobj,AsmConstraint):
|
||||||
cstr = sobj
|
cstr = sobj
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if not assembly:
|
||||||
assembly = ret[0].Assembly
|
assembly = ret[0].Assembly
|
||||||
selSubname = sub[:-len(ret[0].Subname)]
|
selSubname = sub[:-len(ret[0].Subname)]
|
||||||
|
found = ret[0]
|
||||||
|
else:
|
||||||
found = None
|
found = None
|
||||||
for r in ret:
|
for r in ret:
|
||||||
if r.Assembly == assembly:
|
if r.Assembly == assembly:
|
||||||
|
@ -755,22 +843,30 @@ class AsmConstraint(AsmGroup):
|
||||||
break
|
break
|
||||||
if not found:
|
if not found:
|
||||||
raise RuntimeError('Selection {}.{} is not from the target '
|
raise RuntimeError('Selection {}.{} is not from the target '
|
||||||
'assembly {}'.format(sel.Object.Name,sub,objName(assembly)))
|
'assembly {}'.format(
|
||||||
|
sel.Object.Name,sub,objName(assembly)))
|
||||||
|
|
||||||
# because we call Assembly.find() above with relativeToChild=False,
|
# because we call Assembly.find() above with relativeToChild=False,
|
||||||
# we shall adjust the element subname by popping the first '.'
|
# we shall adjust the element subname by popping the first '.'
|
||||||
sub = found.Subname
|
sub = found.Subname
|
||||||
sub = sub[sub.index('.')+1:]
|
sub = sub[sub.index('.')+1:]
|
||||||
|
if sub[-1] == '.' and not isTypeOf(sobj,(Assembly,AsmConstraint,
|
||||||
|
AsmConstraintGroup,AsmElement,AsmElementLink)):
|
||||||
|
# Too bad, its a full selection, let's guess the sub element
|
||||||
|
subElement = utils.deduceSelectedElement(found.Object,sub)
|
||||||
|
if not subElement:
|
||||||
|
raise RuntimeError('no sub element (face, edge, vertex) in '
|
||||||
|
'{}.{}'.format(found.Object.Name,sub))
|
||||||
|
sub += subElement
|
||||||
|
|
||||||
elements.append((found.Object,sub))
|
elements.append((found.Object,sub))
|
||||||
|
|
||||||
check = None
|
if not Constraint.isDisabled(cstr):
|
||||||
if cstr and not Constraint.isDisabled(cstr):
|
if cstr:
|
||||||
typeid = Constraint.getTypeID(cstr)
|
typeid = Constraint.getTypeID(cstr)
|
||||||
info = cstr.Proxy.getInfo()
|
check = [o.Proxy.getInfo().Shape for o in cstr.Group] + elements
|
||||||
check = [o.getShape() for o in info.Elements] + elements
|
|
||||||
else:
|
else:
|
||||||
check = elements
|
check = elements
|
||||||
if check:
|
|
||||||
Constraint.check(typeid,check)
|
Constraint.check(typeid,check)
|
||||||
|
|
||||||
return AsmConstraint.Selection(SelObject=sel.Object,
|
return AsmConstraint.Selection(SelObject=sel.Object,
|
||||||
|
@ -795,7 +891,10 @@ class AsmConstraint(AsmGroup):
|
||||||
doc.openTransaction('Assembly make constraint')
|
doc.openTransaction('Assembly make constraint')
|
||||||
cstr = constraints.Document.addObject("App::FeaturePython",
|
cstr = constraints.Document.addObject("App::FeaturePython",
|
||||||
name,AsmConstraint(constraints),None,True)
|
name,AsmConstraint(constraints),None,True)
|
||||||
ViewProviderAsmConstraint(cstr.ViewObject)
|
proxy = ViewProviderAsmConstraint(cstr.ViewObject)
|
||||||
|
logger.debug('cstr viewobject {},{},{},{}'.format(
|
||||||
|
id(proxy),id(cstr.ViewObject.Proxy),
|
||||||
|
id(proxy.ViewObject),id(cstr.ViewObject)))
|
||||||
constraints.setLink({-1:cstr})
|
constraints.setLink({-1:cstr})
|
||||||
Constraint.setTypeID(cstr,typeid)
|
Constraint.setTypeID(cstr,typeid)
|
||||||
|
|
||||||
|
@ -809,13 +908,15 @@ class AsmConstraint(AsmGroup):
|
||||||
if undo:
|
if undo:
|
||||||
doc.commitTransaction()
|
doc.commitTransaction()
|
||||||
|
|
||||||
|
if sel.SelObject:
|
||||||
FreeCADGui.Selection.clearSelection()
|
FreeCADGui.Selection.clearSelection()
|
||||||
subname = sel.SelSubname
|
subname = sel.SelSubname
|
||||||
if subname:
|
if subname:
|
||||||
subname += '.'
|
subname += '.'
|
||||||
subname += sel.Assembly.Proxy.getConstraintGroup().Name + '.' + \
|
subname += sel.Assembly.Proxy.getConstraintGroup().Name + \
|
||||||
cstr.Name + '.'
|
'.' + cstr.Name + '.'
|
||||||
FreeCADGui.Selection.addSelection(sel.SelObject,subname)
|
FreeCADGui.Selection.addSelection(sel.SelObject,subname)
|
||||||
|
FreeCADGui.runCommand('Std_TreeSelection')
|
||||||
return cstr
|
return cstr
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -837,6 +938,44 @@ class ViewProviderAsmConstraint(ViewProviderAsmGroup):
|
||||||
def getIcon(self):
|
def getIcon(self):
|
||||||
return Constraint.getIcon(self.ViewObject.Object)
|
return Constraint.getIcon(self.ViewObject.Object)
|
||||||
|
|
||||||
|
def _getSelection(self,owner,subname):
|
||||||
|
if not owner:
|
||||||
|
raise RuntimeError('no owner')
|
||||||
|
parent = getattr(owner.Proxy,'parent',None)
|
||||||
|
if isinstance(parent,AsmConstraintGroup):
|
||||||
|
# This can happen when we are dropping another element link from the
|
||||||
|
# same constraint group, in which case, 'owner' here will be the
|
||||||
|
# parent constraint of the dropping element link
|
||||||
|
subname = owner.Name + '.' + subname
|
||||||
|
owner = parent.Object
|
||||||
|
parent = parent.parent # ascend to the parent assembly
|
||||||
|
if not isinstance(parent,Assembly):
|
||||||
|
raise RuntimeError('not from the same assembly')
|
||||||
|
subname = owner.Name + '.' + subname
|
||||||
|
obj = self.ViewObject.Object
|
||||||
|
mysub = parent.getConstraintGroup().Name + '.' + obj.Name + '.'
|
||||||
|
sel = [Selection(Object=parent.Object,SubElementNames=[subname,mysub])]
|
||||||
|
typeid = Constraint.getTypeID(obj)
|
||||||
|
return AsmConstraint.getSelection(typeid,sel)
|
||||||
|
|
||||||
|
def canDropObjectEx(self,_obj,owner,subname):
|
||||||
|
cstr = self.ViewObject.Object
|
||||||
|
if logger.catchTrace('Cannot drop to AsmConstraint {}'.format(cstr),
|
||||||
|
self._getSelection,owner,subname):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def dropObjectEx(self,_vobj,_obj,owner,subname):
|
||||||
|
sel = self._getSelection(owner,subname)
|
||||||
|
cstr = self.ViewObject.Object
|
||||||
|
typeid = Constraint.getTypeID(cstr)
|
||||||
|
sel = AsmConstraint.Selection(SelObject=None,
|
||||||
|
SelSubname=None,
|
||||||
|
Assembly=sel.Assembly,
|
||||||
|
Constraint=cstr,
|
||||||
|
Elements=sel.Elements)
|
||||||
|
AsmConstraint.make(typeid,sel,undo=False)
|
||||||
|
|
||||||
|
|
||||||
class AsmConstraintGroup(AsmGroup):
|
class AsmConstraintGroup(AsmGroup):
|
||||||
def __init__(self,parent):
|
def __init__(self,parent):
|
||||||
|
@ -864,6 +1003,9 @@ class AsmConstraintGroup(AsmGroup):
|
||||||
class ViewProviderAsmConstraintGroup(ViewProviderAsmBase):
|
class ViewProviderAsmConstraintGroup(ViewProviderAsmBase):
|
||||||
_iconName = 'Assembly_Assembly_Constraints_Tree.svg'
|
_iconName = 'Assembly_Assembly_Constraints_Tree.svg'
|
||||||
|
|
||||||
|
def canDropObjects(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class AsmElementGroup(AsmGroup):
|
class AsmElementGroup(AsmGroup):
|
||||||
def __init__(self,parent):
|
def __init__(self,parent):
|
||||||
|
@ -876,6 +1018,9 @@ class AsmElementGroup(AsmGroup):
|
||||||
for o in obj.Group:
|
for o in obj.Group:
|
||||||
getProxy(o,AsmElement).parent = self
|
getProxy(o,AsmElement).parent = self
|
||||||
|
|
||||||
|
def getAssembly(self):
|
||||||
|
return self.parent
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def make(parent,name='Elements'):
|
def make(parent,name='Elements'):
|
||||||
obj = parent.Document.addObject("App::FeaturePython",name,
|
obj = parent.Document.addObject("App::FeaturePython",name,
|
||||||
|
@ -891,24 +1036,17 @@ class ViewProviderAsmElementGroup(ViewProviderAsmBase):
|
||||||
def onDelete(self,_obj,_subs):
|
def onDelete(self,_obj,_subs):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def canDragObject(self,_obj):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def canDragObjects(self):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def canDragAndDropObject(self,_obj):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def canDropObjectEx(self,_obj,owner,subname):
|
def canDropObjectEx(self,_obj,owner,subname):
|
||||||
# check if is dropping a sub-element
|
# check if is dropping a sub-element
|
||||||
if subname.rfind('.')+1 == len(subname):
|
if not subname or subname[-1]=='.':
|
||||||
return False
|
return False
|
||||||
return self.ViewObject.Object.Proxy.parent.getPartGroup()==owner
|
proxy = self.ViewObject.Object.Proxy
|
||||||
|
return proxy.getAssembly().getPartGroup()==owner
|
||||||
|
|
||||||
def dropObjectEx(self,vobj,_obj,_owner,subname):
|
def dropObjectEx(self,vobj,_obj,_owner,subname):
|
||||||
AsmElement.make(AsmElement.Selection(
|
AsmElement.make(AsmElement.Selection(
|
||||||
vobj.Object.Proxy.parent.Object,None,subname))
|
Assembly=vobj.Object.Proxy.getAssembly().Object,
|
||||||
|
Element=None, Subname=subname))
|
||||||
|
|
||||||
|
|
||||||
BuildShapeNone = 'None'
|
BuildShapeNone = 'None'
|
||||||
|
@ -1341,6 +1479,9 @@ def getMovingPartInfo():
|
||||||
if not sels:
|
if not sels:
|
||||||
raise RuntimeError('no selection')
|
raise RuntimeError('no selection')
|
||||||
|
|
||||||
|
if not sels[0].SubElementNames:
|
||||||
|
raise RuntimeError('no sub object in selection')
|
||||||
|
|
||||||
if len(sels)>1 or len(sels[0].SubElementNames)>2:
|
if len(sels)>1 or len(sels[0].SubElementNames)>2:
|
||||||
raise RuntimeError('too many selection')
|
raise RuntimeError('too many selection')
|
||||||
|
|
||||||
|
@ -1401,24 +1542,29 @@ class ViewProviderAssembly(ViewProviderAsmGroup):
|
||||||
self._movingPart = None
|
self._movingPart = None
|
||||||
super(ViewProviderAssembly,self).__init__(vobj)
|
super(ViewProviderAssembly,self).__init__(vobj)
|
||||||
|
|
||||||
def canDragObject(self,_child):
|
def _convertSubname(self,owner,subname):
|
||||||
|
sub = subname.split('.')
|
||||||
|
if not sub:
|
||||||
|
return
|
||||||
|
me = self.ViewObject.Object
|
||||||
|
partGroup = me.Proxy.getPartGroup().ViewObject
|
||||||
|
if sub == me.Name:
|
||||||
|
return partGroup,partGroup,subname[len[sub]+1:]
|
||||||
|
return partGroup,owner,subname
|
||||||
|
|
||||||
|
def canDropObjectEx(self,obj,owner,subname):
|
||||||
|
info = self._convertSubname(owner,subname)
|
||||||
|
if not info:
|
||||||
return False
|
return False
|
||||||
|
partGroup,owner,subname = info
|
||||||
def canDragObjects(self):
|
return partGroup.canDropObject(obj,owner,subname)
|
||||||
return False
|
|
||||||
|
|
||||||
@property
|
|
||||||
def PartGroup(self):
|
|
||||||
return self.ViewObject.Object.Proxy.getPartGroup()
|
|
||||||
|
|
||||||
def canDropObject(self,obj):
|
|
||||||
self.PartGroup.ViewObject.canDropObject(obj)
|
|
||||||
|
|
||||||
def canDropObjects(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def dropObjectEx(self,_vobj,obj,owner,subname):
|
def dropObjectEx(self,_vobj,obj,owner,subname):
|
||||||
self.PartGroup.ViewObject.dropObject(obj,owner,subname)
|
info = self._convertSubname(owner,subname)
|
||||||
|
if not info:
|
||||||
|
return False
|
||||||
|
partGroup,owner,subname = info
|
||||||
|
partGroup.dropObject(obj,owner,subname)
|
||||||
|
|
||||||
def getIcon(self):
|
def getIcon(self):
|
||||||
return System.getIcon(self.ViewObject.Object)
|
return System.getIcon(self.ViewObject.Object)
|
||||||
|
|
|
@ -218,8 +218,8 @@ class Constraint(ProxyType):
|
||||||
return getattr(obj,mcs._disabled,False)
|
return getattr(obj,mcs._disabled,False)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def check(mcs,tp,group):
|
def check(mcs,tp,group,checkCount=False):
|
||||||
mcs.getType(tp).check(group)
|
mcs.getType(tp).check(group,checkCount)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def prepare(mcs,obj,solver):
|
def prepare(mcs,obj,solver):
|
||||||
|
@ -260,6 +260,7 @@ class Constraint(ProxyType):
|
||||||
ret = {}
|
ret = {}
|
||||||
for obj in cstrs:
|
for obj in cstrs:
|
||||||
cstr = mcs.getProxy(obj)
|
cstr = mcs.getProxy(obj)
|
||||||
|
if cstr.hasFixedPart(obj):
|
||||||
for info in cstr.getFixedTransform(obj):
|
for info in cstr.getFixedTransform(obj):
|
||||||
found = True
|
found = True
|
||||||
ret[info.Part] = info
|
ret[info.Part] = info
|
||||||
|
@ -331,32 +332,33 @@ class Base(with_metaclass(Constraint,object)):
|
||||||
@classmethod
|
@classmethod
|
||||||
def getEntityDef(cls,group,checkCount,obj=None):
|
def getEntityDef(cls,group,checkCount,obj=None):
|
||||||
entities = cls._entityDef
|
entities = cls._entityDef
|
||||||
if len(group) != len(entities):
|
if len(group) == len(entities):
|
||||||
|
return entities
|
||||||
|
if cls._workplane and len(group)==len(entities)+1:
|
||||||
|
return list(entities) + [_w]
|
||||||
if not checkCount and len(group)<len(entities):
|
if not checkCount and len(group)<len(entities):
|
||||||
return entities[:len(group)]
|
return entities[:len(group)]
|
||||||
if cls._workplane and len(group)==len(entities)+1:
|
|
||||||
entities = list(entities)
|
|
||||||
entities.append(_w)
|
|
||||||
else:
|
|
||||||
if not obj:
|
if not obj:
|
||||||
name = cls.getName()
|
name = cls.getName()
|
||||||
else:
|
else:
|
||||||
name += cstrName(obj)
|
name += cstrName(obj)
|
||||||
raise RuntimeError('Constraint {} has wrong number of '
|
if len(group)<len(entities):
|
||||||
'elements {}, expecting {}'.format(
|
msg = entities[len(group)](None,None,None,None)
|
||||||
name,len(group),len(entities)))
|
raise RuntimeError('Constraint {} expects a {} element of '
|
||||||
return entities
|
'{}'.format(name,_ordinal[len(group)],msg))
|
||||||
|
raise RuntimeError('Constraint {} has too many elements, expecting '
|
||||||
|
'only {}'.format(name,len(entities)))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def check(cls,group):
|
def check(cls,group,checkCount=False):
|
||||||
entities = cls.getEntityDef(group,False)
|
entities = cls.getEntityDef(group,checkCount)
|
||||||
for i,e in enumerate(entities):
|
for i,e in enumerate(entities):
|
||||||
o = group[i]
|
o = group[i]
|
||||||
msg = e(None,None,None,o)
|
msg = e(None,None,None,o)
|
||||||
if not msg:
|
if not msg:
|
||||||
continue
|
continue
|
||||||
if i == len(cls._entityDef):
|
if i == len(cls._entityDef):
|
||||||
raise RuntimeError('Constraint "{}" requires the optional {} '
|
raise RuntimeError('Constraint "{}" requires an optional {} '
|
||||||
'element to be a planar face for defining a '
|
'element to be a planar face for defining a '
|
||||||
'workplane'.format(cls.getName(), _ordinal[i], msg))
|
'workplane'.format(cls.getName(), _ordinal[i], msg))
|
||||||
raise RuntimeError('Constraint "{}" requires the {} element to be'
|
raise RuntimeError('Constraint "{}" requires the {} element to be'
|
||||||
|
@ -475,7 +477,7 @@ class Locked(Base):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def check(cls,group):
|
def check(cls,group,_checkCount=False):
|
||||||
if not all([utils.isElement(o) for o in group]):
|
if not all([utils.isElement(o) for o in group]):
|
||||||
raise RuntimeError('Constraint "{}" requires all children to be '
|
raise RuntimeError('Constraint "{}" requires all children to be '
|
||||||
'of element (Vertex, Edge or Face)'.format(cls.getName()))
|
'of element (Vertex, Edge or Face)'.format(cls.getName()))
|
||||||
|
@ -486,7 +488,7 @@ class BaseMulti(Base):
|
||||||
_entityDef = (_wa,)
|
_entityDef = (_wa,)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def check(cls,group):
|
def check(cls,group,_checkCount=False):
|
||||||
if len(group)<2:
|
if len(group)<2:
|
||||||
raise RuntimeError('Constraint "{}" requires at least two '
|
raise RuntimeError('Constraint "{}" requires at least two '
|
||||||
'elements'.format(cls.getName()))
|
'elements'.format(cls.getName()))
|
||||||
|
|
16
utils.py
16
utils.py
|
@ -61,6 +61,22 @@ def isLine(param):
|
||||||
else:
|
else:
|
||||||
return isinstance(param,Part.Line)
|
return isinstance(param,Part.Line)
|
||||||
|
|
||||||
|
def deduceSelectedElement(obj,subname):
|
||||||
|
shape = obj.getSubObject(subname)
|
||||||
|
if not shape:
|
||||||
|
return
|
||||||
|
count = len(shape.Faces)
|
||||||
|
if count==1:
|
||||||
|
return 'Face1'
|
||||||
|
elif not count:
|
||||||
|
count = len(shape.Edges)
|
||||||
|
if count==1:
|
||||||
|
return 'Edge1'
|
||||||
|
elif not count:
|
||||||
|
count = len(shape.Vertexes)
|
||||||
|
if count==1:
|
||||||
|
return 'Vertex1'
|
||||||
|
|
||||||
def getElement(obj,tp):
|
def getElement(obj,tp):
|
||||||
if isinstance(obj,tuple):
|
if isinstance(obj,tuple):
|
||||||
obj = obj[0].getSubObject(obj[1])
|
obj = obj[0].getSubObject(obj[1])
|
||||||
|
|
Loading…
Reference in New Issue
Block a user