Refactor FCAD command management
This commit is contained in:
parent
ccc6a89165
commit
990e5a2ef3
48
InitGui.py
48
InitGui.py
|
@ -1,4 +1,5 @@
|
|||
import FreeCAD, FreeCADGui
|
||||
from collections import OrderedDict
|
||||
|
||||
class Assembly3Workbench(FreeCADGui.Workbench):
|
||||
import asm3
|
||||
|
@ -10,38 +11,37 @@ class Assembly3Workbench(FreeCADGui.Workbench):
|
|||
|
||||
def Activated(self):
|
||||
self.observer.attach()
|
||||
from asm3.gui import AsmCmdManager
|
||||
for cmd in AsmCmdManager.getInfo().Types:
|
||||
cmd.workbenchActivated()
|
||||
|
||||
def Deactivated(self):
|
||||
self.observer.detach()
|
||||
from asm3.gui import AsmCmdManager
|
||||
for cmd in AsmCmdManager.getInfo().Types:
|
||||
cmd.workbenchDeactivated()
|
||||
|
||||
def Initialize(self):
|
||||
import asm3
|
||||
cmdInfo = asm3.gui.AsmCmdType.getInfo()
|
||||
cmds = cmdInfo.TypeNames
|
||||
asm3.utils.logger.debug(cmds)
|
||||
self.appendToolbar('asm3',cmds)
|
||||
self.appendMenu('&Assembly3', cmds)
|
||||
self.appendToolbar('asm3 Constraint',
|
||||
asm3.constraint.Constraint.CommandList)
|
||||
self.observer = asm3.gui.SelectionObserver(
|
||||
cmdInfo.Types + asm3.constraint.Constraint.Commands)
|
||||
from asm3.gui import AsmCmdManager,SelectionObserver
|
||||
cmdSet = set()
|
||||
for name,cmds in AsmCmdManager.Toolbars.items():
|
||||
cmdSet.update(cmds)
|
||||
self.appendToolbar(name,[cmd.getName() for cmd in cmds])
|
||||
for name,cmds in AsmCmdManager.Menus.items():
|
||||
cmdSet.update(cmds)
|
||||
self.appendMenu(name,[cmd.getName() for cmd in cmds])
|
||||
self.observer = SelectionObserver(cmdSet)
|
||||
# FreeCADGui.addPreferencePage(
|
||||
# ':/assembly3/ui/assembly3_prefs.ui','Assembly3')
|
||||
|
||||
def ContextMenu(self, _recipient):
|
||||
import asm3
|
||||
cmds = []
|
||||
for cmd in asm3.gui.AsmCmdType.getInfo().Types:
|
||||
if cmd.IsActive:
|
||||
cmds.append(cmd.getName())
|
||||
if cmds:
|
||||
self.appendContextMenu('Assembly',cmds)
|
||||
|
||||
cmds.clear()
|
||||
for cmd in asm3.constraint.Constraint.Commands:
|
||||
if cmd.IsActive:
|
||||
cmds.append(cmd.getName())
|
||||
if cmds:
|
||||
self.appendContextMenu('Constraint',cmds)
|
||||
from asm3.gui import AsmCmdManager
|
||||
menus = OrderedDict()
|
||||
for cmd in AsmCmdManager.getInfo().Types:
|
||||
name = cmd.getContextMenuName()
|
||||
if name:
|
||||
menus.setdefault(name,[]).append(cmd.getName())
|
||||
for name,cmds in menus.items():
|
||||
self.appendContextMenu(name,cmds)
|
||||
|
||||
FreeCADGui.addWorkbench(Assembly3Workbench)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import FreeCAD, FreeCADGui, Part
|
||||
from asm3 import proxy,utils,assembly,solver,constraint,system,gui
|
||||
from asm3 import proxy,utils,gui,solver,constraint,system,assembly
|
||||
from asm3.utils import logger
|
||||
from asm3.assembly import Assembly,AsmConstraint
|
||||
try:
|
||||
from asm3 import sys_slvs
|
||||
except ImportError as e:
|
||||
|
@ -12,6 +11,7 @@ except ImportError as e:
|
|||
logger.error('failed to import sympy: {}'.format(e))
|
||||
|
||||
def test():
|
||||
from asm3.assembly import Assembly
|
||||
doc = FreeCAD.newDocument()
|
||||
cylinder1 = doc.addObject('Part::Cylinder','cylinder1')
|
||||
cylinder1.Visibility = False
|
||||
|
|
|
@ -2,6 +2,7 @@ from future.utils import with_metaclass
|
|||
from collections import namedtuple
|
||||
import FreeCAD, FreeCADGui
|
||||
import asm3.utils as utils
|
||||
from asm3.gui import AsmCmdManager
|
||||
from asm3.utils import logger, objName
|
||||
from asm3.proxy import ProxyType, PropertyInfo, propGet, propGetValue
|
||||
|
||||
|
@ -146,8 +147,21 @@ def _a(solver,partInfo,subname,shape):
|
|||
|
||||
|
||||
class ConstraintCommand:
|
||||
_toolbarName = 'Assembly3 Constraints'
|
||||
_menuGroupName = ''
|
||||
|
||||
def __init__(self,tp):
|
||||
self.tp = tp
|
||||
self._id = 100 + tp._id
|
||||
|
||||
def workbenchActivated(self):
|
||||
pass
|
||||
|
||||
def workbenchDeactivated(self):
|
||||
pass
|
||||
|
||||
def getContextMenuName(self):
|
||||
pass
|
||||
|
||||
def getName(self):
|
||||
return 'asm3Add'+self.tp.getName()
|
||||
|
@ -173,7 +187,7 @@ class ConstraintCommand:
|
|||
else:
|
||||
self.tp._active = True
|
||||
|
||||
def deactive(self):
|
||||
def onClearSelection(self):
|
||||
self.tp._active = False
|
||||
|
||||
class Constraint(ProxyType):
|
||||
|
@ -183,18 +197,11 @@ class Constraint(ProxyType):
|
|||
_typeEnum = 'ConstraintType'
|
||||
_disabled = 'Disabled'
|
||||
|
||||
CommandList = []
|
||||
Commands = []
|
||||
|
||||
def register(cls):
|
||||
super(Constraint,cls).register()
|
||||
@classmethod
|
||||
def register(mcs,cls):
|
||||
super(Constraint,mcs).register(cls)
|
||||
if cls._menuItem:
|
||||
mcs = cls.__class__
|
||||
cmd = ConstraintCommand(cls)
|
||||
name = cmd.getName()
|
||||
mcs.CommandList.append(name)
|
||||
mcs.Commands.append(cmd)
|
||||
FreeCADGui.addCommand(name,cmd)
|
||||
AsmCmdManager.register(ConstraintCommand(cls))
|
||||
|
||||
@classmethod
|
||||
def attach(mcs,obj,checkType=True):
|
||||
|
@ -263,7 +270,7 @@ class Base(with_metaclass(Constraint,object)):
|
|||
_props = []
|
||||
_iconName = 'Assembly_ConstraintGeneral.svg'
|
||||
|
||||
_menuText = 'Add a "{}" constraint'
|
||||
_menuText = 'Create "{}" constraint'
|
||||
_active = False
|
||||
_menuItem = False
|
||||
|
||||
|
|
74
gui.py
74
gui.py
|
@ -1,7 +1,8 @@
|
|||
from future.utils import with_metaclass
|
||||
from collections import OrderedDict
|
||||
import FreeCAD, FreeCADGui
|
||||
import asm3
|
||||
from asm3.utils import logger,objName,addIconToFCAD
|
||||
from asm3.assembly import isTypeOf,Assembly,AsmConstraint,AsmElementLink
|
||||
from asm3.proxy import ProxyType
|
||||
|
||||
class SelectionObserver:
|
||||
|
@ -24,7 +25,7 @@ class SelectionObserver:
|
|||
|
||||
def clearSelection(self,*_args):
|
||||
for cmd in self.cmds:
|
||||
cmd.deactive()
|
||||
cmd.onClearSelection()
|
||||
|
||||
def attach(self):
|
||||
if not self._attached:
|
||||
|
@ -39,21 +40,38 @@ class SelectionObserver:
|
|||
self.clearSelection('')
|
||||
|
||||
|
||||
class AsmCmdType(ProxyType):
|
||||
def register(cls):
|
||||
super(AsmCmdType,cls).register()
|
||||
if cls._id >= 0:
|
||||
FreeCADGui.addCommand(cls.getName(),cls())
|
||||
|
||||
class AsmCmdBase(with_metaclass(AsmCmdType,object)):
|
||||
_id = -1
|
||||
_active = True
|
||||
class AsmCmdManager(ProxyType):
|
||||
Toolbars = OrderedDict()
|
||||
Menus = OrderedDict()
|
||||
_defaultMenuGroupName = '&Assembly3'
|
||||
|
||||
@classmethod
|
||||
def register(mcs,cls):
|
||||
if cls._id < 0:
|
||||
return
|
||||
super(AsmCmdManager,mcs).register(cls)
|
||||
FreeCADGui.addCommand(cls.getName(),cls)
|
||||
if cls._toolbarName:
|
||||
mcs.Toolbars.setdefault(cls._toolbarName,[]).append(cls)
|
||||
if cls._menuGroupName is not None:
|
||||
name = cls._menuGroupName
|
||||
if not name:
|
||||
name = mcs._defaultMenuGroupName
|
||||
mcs.Menus.setdefault(name,[]).append(cls)
|
||||
|
||||
def workbenchActivated(cls):
|
||||
pass
|
||||
|
||||
def workbenchDeactivated(cls):
|
||||
pass
|
||||
|
||||
def getContextMenuName(cls):
|
||||
if cls.IsActive() and cls._contextMenuName:
|
||||
return cls._contextMenuName
|
||||
|
||||
def getName(cls):
|
||||
return 'asm3'+cls.__name__[3:]
|
||||
|
||||
@classmethod
|
||||
def GetResources(cls):
|
||||
return {
|
||||
'Pixmap':addIconToFCAD(cls._iconName),
|
||||
|
@ -61,41 +79,45 @@ class AsmCmdBase(with_metaclass(AsmCmdType,object)):
|
|||
'ToolTip':cls.getToolTip()
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def getMenuText(cls):
|
||||
return cls._menuText
|
||||
|
||||
@classmethod
|
||||
def getToolTip(cls):
|
||||
return getattr(cls,'_tooltip',cls.getMenuText())
|
||||
|
||||
@classmethod
|
||||
def IsActive(cls):
|
||||
if cls._active and cls._id>=0 and FreeCAD.ActiveDocument:
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def checkActive(cls):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def deactive(cls):
|
||||
def onClearSelection(cls):
|
||||
pass
|
||||
|
||||
class AsmCmdBase(with_metaclass(AsmCmdManager,object)):
|
||||
_id = -1
|
||||
_active = True
|
||||
_toolbarName = 'Assembly3'
|
||||
_menuGroupName = ''
|
||||
_contextMenuName = 'Assembly'
|
||||
|
||||
class AsmCmdNew(AsmCmdBase):
|
||||
_id = 0
|
||||
_menuText = 'Create assembly'
|
||||
_iconName = 'Assembly_New_Assembly.svg'
|
||||
|
||||
def Activated(self):
|
||||
Assembly.make()
|
||||
@classmethod
|
||||
def Activated(cls):
|
||||
asm3.assembly.Assembly.make()
|
||||
|
||||
class AsmCmdSolve(AsmCmdBase):
|
||||
_id = 1
|
||||
_menuText = 'Solve constraints'
|
||||
_iconName = 'AssemblyWorkbench.svg'
|
||||
|
||||
def Activated(self):
|
||||
@classmethod
|
||||
def Activated(cls):
|
||||
import asm3.solver as solver
|
||||
solver.solve()
|
||||
|
||||
|
@ -107,17 +129,19 @@ class AsmCmdMove(AsmCmdBase):
|
|||
|
||||
@classmethod
|
||||
def getSelection(cls):
|
||||
from asm3.assembly import isTypeOf,AsmElementLink
|
||||
sels = FreeCADGui.Selection.getSelection()
|
||||
if len(sels)==1 and isTypeOf(sels[0],AsmElementLink):
|
||||
return sels[0].ViewObject
|
||||
|
||||
def Activated(self):
|
||||
vobj = self.getSelection()
|
||||
@classmethod
|
||||
def Activated(cls):
|
||||
vobj = cls.getSelection()
|
||||
if vobj:
|
||||
doc = FreeCADGui.editDocument()
|
||||
if doc:
|
||||
doc.resetEdit()
|
||||
vobj.UseCenterballDragger = self._useCenterballDragger
|
||||
vobj.UseCenterballDragger = cls._useCenterballDragger
|
||||
vobj.doubleClicked()
|
||||
|
||||
@classmethod
|
||||
|
@ -125,7 +149,7 @@ class AsmCmdMove(AsmCmdBase):
|
|||
cls._active = True if cls.getSelection() else False
|
||||
|
||||
@classmethod
|
||||
def deactive(cls):
|
||||
def onClearSelection(cls):
|
||||
cls._active = False
|
||||
|
||||
class AsmCmdAxialMove(AsmCmdMove):
|
||||
|
|
18
proxy.py
18
proxy.py
|
@ -56,7 +56,7 @@ class ProxyType(type):
|
|||
for tp in info.Types:
|
||||
tp._idx = -1
|
||||
mcs.getInfo().Types.append(tp)
|
||||
tp.register()
|
||||
mcs.register(tp)
|
||||
|
||||
@classmethod
|
||||
def getType(mcs,tp):
|
||||
|
@ -181,23 +181,27 @@ class ProxyType(type):
|
|||
|
||||
def __init__(cls, name, bases, attrs):
|
||||
super(ProxyType,cls).__init__(name,bases,attrs)
|
||||
cls._idx = -1
|
||||
mcs = cls.__class__
|
||||
mcs.getInfo().Types.append(cls)
|
||||
cls.register()
|
||||
mcs.register(cls)
|
||||
|
||||
def register(cls):
|
||||
@classmethod
|
||||
def register(mcs,cls):
|
||||
'''
|
||||
Register a class to this meta class
|
||||
|
||||
To make the registration automatic at the class definition time, simply
|
||||
set __metaclass__ of that class to ProxyType of its derived type.
|
||||
|
||||
You can also call this methode directly to register an unrelated class
|
||||
It is defined as a meta class method in order for you to call this
|
||||
method directly to register an unrelated class
|
||||
'''
|
||||
cls._idx = -1
|
||||
mcs.getInfo().Types.append(cls)
|
||||
callback = getattr(cls,'onRegister',None)
|
||||
if callback:
|
||||
callback()
|
||||
if cls._id < 0:
|
||||
return
|
||||
mcs = cls.__class__
|
||||
info = mcs.getInfo()
|
||||
if cls._id in info.TypeMap:
|
||||
raise RuntimeError('Duplicate {} type id {}'.format(
|
||||
|
|
Loading…
Reference in New Issue
Block a user