Esempio n. 1
0
class SceneGraphEditor(SceneEditorModule):
    def __init__(self):
        super(SceneGraphEditor, self).__init__()
        self.sceneDirty = False
        self.activeSceneNode = None
        self.refreshScheduled = False
        self.previewing = False
        self.workspaceState = None

    def getName(self):
        return 'scenegraph_editor'

    def getDependency(self):
        return ['scene_editor', 'mock']

    def onLoad(self):
        #UI
        self.windowTitle = 'Scenegraph'
        self.container = self.requestDockWindow('SceneGraphEditor',
                                                title='Scenegraph',
                                                size=(200, 200),
                                                minSize=(200, 200),
                                                dock='left')

        #Components
        self.treeFilter = self.container.addWidget(GenericTreeFilter(
            self.container),
                                                   expanding=False)
        self.tree = self.container.addWidget(
            SceneGraphTreeWidget(self.container,
                                 sorting=True,
                                 editable=True,
                                 multiple_selection=True,
                                 drag_mode='internal'))
        self.treeFilter.setTargetTree(self.tree)
        self.tree.module = self
        self.tool = self.addToolBar('scene_graph', self.container.addToolBar())
        self.delegate = MOAILuaDelegate(self)
        self.delegate.load(getModulePath('SceneGraphEditor.lua'))

        self.entityCreatorMenu = self.addMenu('main/scene/entity_create',
                                              {'label': 'Create Entity'})

        self.componentCreatorMenu = self.addMenu('main/scene/component_create',
                                                 {'label': 'Create Component'})

        #menu
        self.addMenuItem('main/file/open_scene',
                         dict(label='Open Scene', shortcut='ctrl+shift+o'))

        self.addMenuItem('main/file/close_scene',
                         dict(label='Close Scene', shortcut='Ctrl+W'))
        self.addMenuItem('main/scene/save_scene',
                         dict(label='Save', shortcut='Ctrl+S'))
        self.addMenuItem('main/scene/locate_scene_asset',
                         dict(label='Locate Scene Asset'))

        self.addMenu('main/scene/----')

        self.addMenu('component_context', dict(label='Selected Component'))
        self.addMenuItem('component_context/remove_component',
                         dict(label='Remove'))

        self.addMenuItem('component_context/----')

        self.addMenuItem('component_context/copy_component',
                         dict(label='Copy'))
        self.addMenuItem('component_context/paste_component',
                         dict(label='Paste Component Here'))
        self.addMenuItem('component_context/----')

        self.addMenuItem('component_context/move_component_up',
                         dict(label='Move Up'))

        self.addMenuItem('component_context/move_component_down',
                         dict(label='Move Down'))

        self.addMenuItem('component_context/----')
        self.addMenuItem('component_context/edit_component_alias',
                         dict(label='Edit Alias'))

        self.addMenu('main/entity', dict(label='Entity'))
        self.addMenuItem('main/entity/add_empty_entity',
                         dict(label='Create Empty', shortcut='ctrl+alt+N'))
        self.addMenuItem('main/entity/add_entity',
                         dict(label='Create', shortcut='ctrl+shift+N'))
        self.addMenuItem('main/entity/----')
        self.addMenuItem('main/entity/group_entity',
                         dict(label='Group Entites', shortcut='ctrl+G'))
        self.addMenuItem(
            'main/entity/create_group',
            dict(label='Create Empty Group', shortcut='ctrl+shift+G'))
        self.addMenuItem('main/entity/----')
        self.addMenuItem(
            'main/entity/load_prefab',
            dict(label='Load Prefab', shortcut='ctrl+alt+shift+N'))
        self.addMenuItem(
            'main/entity/load_prefab_in_container',
            dict(label='Load Prefab In Container', shortcut='ctrl+shift+='))
        self.addMenuItem('main/entity/----')
        self.addMenuItem('main/entity/remove_entity', dict(label='Remove'))
        self.addMenuItem('main/entity/clone_entity',
                         dict(label='Clone', shortcut='ctrl+d'))
        self.addMenuItem('main/entity/----')
        self.addMenuItem('main/entity/add_component',
                         dict(label='Add Component', shortcut='ctrl+alt+='))
        self.addMenuItem('main/entity/assign_layer',
                         dict(label='Assign Layer', shortcut='ctrl+alt+L'))
        self.addMenuItem('main/entity/toggle_visibility',
                         dict(label='Toggle Visibility', shortcut='ctrl+/'))
        self.addMenuItem('main/entity/freeze_entity_pivot',
                         dict(label='Freeze Pivot'))

        self.addMenuItem('main/entity/----')
        self.addMenuItem('main/find/find_entity',
                         dict(label='Find In Scene', shortcut='ctrl+f'))
        self.addMenuItem('main/find/find_entity_in_group',
                         dict(label='Find In Group', shortcut='ctrl+shift+f'))
        self.addMenuItem('main/find/find_entity_group',
                         dict(label='Find Group', shortcut='ctrl+alt+f'))

        #Toolbars
        self.addTool('scene_graph/select_scene',
                     label='Select Scene',
                     icon='settings')
        self.addTool('scene_graph/----')
        self.addTool('scene_graph/create_group',
                     label='+ Group',
                     icon='add_folder')
        self.addTool('scene_graph/----')
        self.addTool('scene_graph/make_proto',
                     label='Convert To Proto',
                     icon='proto_make')
        self.addTool('scene_graph/create_proto_instance',
                     label='Create Proto Instance',
                     icon='proto_instantiate')
        self.addTool('scene_graph/create_proto_container',
                     label='Create Proto Container',
                     icon='proto_container')
        self.addTool('scene_graph/----')
        self.addTool('scene_graph/fold_all', label='F')
        self.addTool('scene_graph/unfold_all', label='U')
        self.addTool('scene_graph/refresh_tree', label='R')
        # self.addTool( 'scene_graph/load_prefab', label = '+ P' )
        # self.addTool( 'scene_graph/save_prefab', label = '>>P' )

        self.addTool('scene/refresh', label='refresh', icon='refresh')

        #SIGNALS
        signals.connect('moai.clean', self.onMoaiClean)

        signals.connect('scene.clear', self.onSceneClear)
        signals.connect('scene.change', self.onSceneChange)

        signals.connect('selection.changed', self.onSelectionChanged)
        signals.connect('selection.hint', self.onSelectionHint)

        signals.connect('preview.start', self.onPreviewStart)
        signals.connect('preview.stop', self.onPreviewStop)

        # signals.connect( 'animator.start',     self.onAnimatorStart     )
        # signals.connect( 'animator.stop' ,     self.onAnimatorStop      )

        signals.connect('entity.added', self.onEntityAdded)
        signals.connect('entity.removed', self.onEntityRemoved)
        signals.connect('entity.renamed', self.onEntityRenamed)
        signals.connect('entity.modified', self.onEntityModified)
        signals.connect('entity.visible_changed', self.onEntityVisibleChanged)
        signals.connect('entity.pickable_changed',
                        self.onEntityPickableChanged)

        signals.connect('prefab.unlink', self.onPrefabUnlink)
        signals.connect('prefab.relink', self.onPrefabRelink)
        signals.connect('proto.unlink', self.onPrefabUnlink)
        signals.connect('proto.relink', self.onPrefabRelink)

        signals.connect('app.ready', self.postAppReady)

        signals.connect('component.added', self.onComponentAdded)
        signals.connect('component.removed', self.onComponentRemoved)

        signals.connect('project.presave', self.preProjectSave)

        registerSearchEnumerator(sceneObjectSearchEnumerator)
        registerSearchEnumerator(entityNameSearchEnumerator)
        registerSearchEnumerator(componentNameSearchEnumerator)
        registerSearchEnumerator(layerNameSearchEnumerator)

    def onStart(self):
        self.refreshCreatorMenu()

    def postAppReady(self):
        self.openPreviousScene()

    def openPreviousScene(self):
        previousScene = self.getConfig('previous_scene', None)
        if previousScene:
            node = self.getAssetLibrary().getAssetNode(previousScene)
            if node:
                node.edit()

    def onStop(self):
        if self.activeSceneNode:
            self.setConfig('previous_scene',
                           self.activeSceneNode.getNodePath())
        else:
            self.setConfig('previous_scene', False)

    def onSetFocus(self):
        self.container.show()
        self.container.raise_()
        self.container.setFocus()

    def getActiveScene(self):
        return self.delegate.safeCallMethod('editor', 'getScene')

    def getActiveSceneRootGroup(self):
        scene = self.delegate.safeCallMethod('editor', 'getScene')
        if scene:
            return scene.rootGroup
        else:
            return None

    def openScene(self, node, protoNode=None):
        if self.activeSceneNode == node:
            if self.getModule('scene_view'):
                self.getModule('scene_view').setFocus()

            if protoNode:
                self.delegate.safeCallMethod('editor', 'locateProto',
                                             protoNode.getPath())
                if self.getModule('scene_view'):
                    self.getModule('scene_view').focusSelection()

        else:
            if not self.closeScene(): return
            if self.getModule('scene_view'):
                self.getModule('scene_view').makeCanvasCurrent()
            self.activeSceneNode = node
            signals.emitNow('scene.pre_open', node)
            scene = self.delegate.safeCallMethod('editor', 'openScene',
                                                 node.getPath())
            if not scene:
                #todo: raise something
                alertMessage(
                    'error',
                    '%s\n\nfailed to open scene, see console for detailed information.'
                    % node.getPath())
                return False
            signals.emitNow('scene.open', self.activeSceneNode, scene)
            self.setFocus()
            self.editingProtoNode = protoNode
            self.loadWorkspaceState(False)
            self.delegate.safeCallMethod('editor', 'postOpenScene')

    def closeScene(self):
        if not self.activeSceneNode: return True
        if self.sceneDirty:
            res = requestConfirm('scene modified!', 'save scene before close?')
            if res == True:  #save
                self.saveScene()
            elif res == None:  #cancel
                return
            elif res == False:  #no save
                pass

        self.markSceneDirty(False)
        self.tree.clear()
        self.getApp().clearCommandStack('scene_editor')
        self.getSelectionManager().removeSelection(self.getActiveScene())
        signals.emitNow('scene.close', self.activeSceneNode)
        self.delegate.safeCallMethod('editor', 'closeScene')
        self.activeSceneNode = None
        return True

    def onSceneClear(self):
        # self.tree.clear()
        pass

    def markSceneDirty(self, dirty=True):
        if not self.previewing:
            self.sceneDirty = dirty

    def saveWorkspaceState(self):
        self.retainWorkspaceState()
        treeFoldState = self.workspaceState['tree_state']
        containerFoldState = self.workspaceState['container_state']
        entityLockState = self.workspaceState['entity_lock_state']
        self.activeSceneNode.setMetaData('tree_state', treeFoldState)
        self.activeSceneNode.setMetaData('container_state', containerFoldState)
        self.activeSceneNode.setMetaData('entity_lock_state', entityLockState)

    def loadWorkspaceState(self, restoreState=True):
        treeFoldState = self.activeSceneNode.getMetaData('tree_state', None)
        containerFoldState = self.activeSceneNode.getMetaData(
            'container_state', None)
        entityLockState = self.activeSceneNode.getMetaData(
            'entity_lock_state', None)
        self.workspaceState = {
            'tree_state': treeFoldState,
            'container_state': containerFoldState,
            'entity_lock_state': entityLockState
        }
        if restoreState: self.restoreWorkspaceState()

    def retainWorkspaceState(self):
        #tree node foldstate
        treeFoldState = self.tree.saveFoldState()
        #save introspector foldstate
        introspectorFoldState = self.delegate.safeCallMethod(
            'editor', 'saveIntrospectorFoldState')
        entityLockState = self.delegate.safeCallMethod('editor',
                                                       'saveEntityLockState')

        self.workspaceState = {
            'tree_state': treeFoldState,
            'container_state': introspectorFoldState,
            'entity_lock_state': entityLockState
        }

    def restoreWorkspaceState(self):
        if not self.workspaceState: return
        treeState = self.workspaceState.get('tree_state', None)
        if treeState:
            self.tree.loadFoldState(treeState)

        containerState = self.workspaceState.get('container_state', None)
        if containerState:
            self.delegate.safeCallMethod('editor', 'loadIntrospectorFoldState',
                                         containerState)

        lockState = self.workspaceState.get('entity_lock_state', None)
        if lockState:
            self.delegate.safeCallMethod('editor', 'loadEntityLockState',
                                         lockState)

    def onSceneChange(self):
        self.tree.hide()
        self.tree.rebuild()
        self.restoreWorkspaceState()
        self.tree.refreshAllContent()
        self.tree.verticalScrollBar().setValue(0)
        self.tree.show()
        if self.editingProtoNode:
            self.delegate.safeCallMethod('editor', 'locateProto',
                                         self.editingProtoNode.getPath())
            self.editingProtoNode = None
            if self.getModule('scene_view'):
                self.getModule('scene_view').focusSelection()

    def saveScene(self):
        if not self.activeSceneNode: return
        self.markSceneDirty(False)
        signals.emitNow('scene.save')
        self.delegate.safeCallMethod('editor', 'saveScene',
                                     self.activeSceneNode.getAbsFilePath())
        signals.emitNow('scene.saved')
        self.saveWorkspaceState()

    def refreshScene(self):
        if not self.activeSceneNode: return
        if self.previewing: return
        self.refreshScheduled = False
        node = self.activeSceneNode
        self.retainWorkspaceState()
        if self.delegate.safeCallMethod('editor', 'refreshScene'):
            self.restoreWorkspaceState()
        self.refreshCreatorMenu()

    def scheduleRefreshScene(self):
        if not self.activeSceneNode: return
        self.refreshScheduled = True

    def refreshCreatorMenu(self):
        def addEntityMenuItem(name):
            if name == '----':
                self.entityCreatorMenu.addChild('----')
                return
            self.entityCreatorMenu.addChild({
                'name': 'create_entity_' + name,
                'label': name,
                'command': 'scene_editor/create_entity',
                'command_args': dict(name=name)
            })

        def addComponentMenuItem(name):
            if name == '----':
                self.componentCreatorMenu.addChild('----')
                return
            self.componentCreatorMenu.addChild({
                'name': 'create_component_' + name,
                'label': name,
                'command': 'scene_editor/create_component',
                'command_args': dict(name=name)
            })

        self.entityCreatorMenu.clear()
        self.componentCreatorMenu.clear()

        registry = _MOCK.getEntityRegistry()
        #entity
        keys = sorted(registry.keys())
        addEntityMenuItem('Entity')
        addEntityMenuItem('----')
        for entityName in sorted(registry.keys()):
            if entityName != 'Entity': addEntityMenuItem(entityName)

        #component
        registry = _MOCK.getComponentRegistry()
        for comName in sorted(registry.keys()):
            addComponentMenuItem(comName)

    def needUpdate(self):
        return True

    def onUpdate(self):
        if self.refreshScheduled:
            self.refreshScene()

    def preProjectSave(self, prj):
        if self.activeSceneNode:
            _MOCK.game.previewingScene = self.activeSceneNode.getNodePath()

    def onMoaiClean(self):
        self.tree.clear()

    def onTool(self, tool):
        name = tool.name

        if name == 'fold_all':
            self.tree.foldAllItems()

        elif name == 'unfold_all':
            self.tree.expandAllItems()

        elif name == 'refresh_tree':
            self.tree.rebuild()

        elif name == 'refresh':
            self.scheduleRefreshScene()

        elif name == 'make_proto':
            self.makeProto()

        elif name == 'create_proto_instance':
            requestSearchView(info='select a proto to instantiate',
                              context='asset',
                              type='proto',
                              on_selection=lambda obj: self.doCommand(
                                  'scene_editor/create_proto_instance',
                                  proto=obj.getNodePath()))

        elif name == 'create_proto_container':
            requestSearchView(
                info='select a proto to create contained instance',
                context='asset',
                type='proto',
                on_selection=lambda obj: self.doCommand(
                    'scene_editor/create_proto_container',
                    proto=obj.getNodePath()))

        elif name == 'create_group':
            self.doCommand('scene_editor/entity_group_create')

        elif name == 'group_entity':
            self.doCommand('scene_editor/group_entities')

        elif name == 'select_scene':
            self.doCommand('scene_editor/select_scene')

    def onMenu(self, menu):
        name = menu.name
        if name == 'close_scene':
            if self.previewing:
                alertMessage('Warning', 'Stop previewing before closing scene')
                return
            self.closeScene()

        elif name == 'open_scene':
            if self.previewing:
                alertMessage('Warning', 'Stop previewing before opening scene')
                return
            requestSearchView(info='select scene to open',
                              context='asset',
                              type='scene',
                              on_selection=self.openScene)

        elif name == 'save_scene':
            if self.previewing:
                alertMessage('Warning', 'Stop previewing before saving')
                return
            self.saveScene()

        elif name == 'locate_scene_asset':
            if self.activeSceneNode:
                assetBrowser = self.getModule('asset_browser')
                if assetBrowser:
                    assetBrowser.selectAsset(self.activeSceneNode)

        elif name == 'add_entity':
            requestSearchView(info='select entity type to create',
                              context='entity_creation',
                              on_selection=lambda obj: self.doCommand(
                                  'scene_editor/create_entity', name=obj))

        elif name == 'add_component':
            requestSearchView(info='select component type to create',
                              context='component_creation',
                              on_selection=lambda obj: self.doCommand(
                                  'scene_editor/create_component', name=obj))

        elif name == 'add_empty_entity':
            self.doCommand('scene_editor/create_entity', name='Entity')

        elif name == 'load_prefab':
            requestSearchView(info='select a perfab node to instantiate',
                              context='asset',
                              type='prefab',
                              on_selection=lambda obj: self.doCommand(
                                  'scene_editor/create_prefab_entity',
                                  prefab=obj.getNodePath()))

        elif name == 'load_prefab_in_container':
            requestSearchView(
                info='select a perfab node to instantiate( PefabContainer )',
                context='asset',
                type='prefab',
                on_selection=lambda obj: self.doCommand(
                    'scene_editor/create_prefab_container',
                    prefab=obj.getNodePath()))

        elif name == 'remove_entity':
            self.doCommand('scene_editor/remove_entity')

        elif name == 'clone_entity':
            self.doCommand('scene_editor/clone_entity')

        elif name == 'find_entity':
            requestSearchView(
                info='search for entity in current scene',
                context='scene',
                type='entity',
                on_selection=lambda x: self.selectEntity(x, focus_tree=True),
                on_test=self.selectEntity)

        elif name == 'find_entity_in_group':
            requestSearchView(
                info='search for entity in current entity group',
                context='scene',
                type='entity_in_group',
                on_selection=lambda x: self.selectEntity(x, focus_tree=True),
                on_test=self.selectEntity)

        elif name == 'find_entity_group':
            requestSearchView(
                info='search for group in current scene',
                context='scene',
                type='group',
                on_selection=lambda x: self.selectEntity(x, focus_tree=True),
                on_test=self.selectEntity)

        elif name == 'create_group':
            self.doCommand('scene_editor/entity_group_create')

        elif name == 'remove_component':
            context = menu.getContext()
            if context:
                self.doCommand('scene_editor/remove_component', target=context)

        elif name == 'copy_component':
            context = menu.getContext()
            if context:
                self.doCommand('scene_editor/copy_component', target=context)

        elif name == 'edit_component_alias':
            context = menu.getContext()
            if context:
                oldAlias = context._alias or ''
                alias = requestString('Edit Alias', 'Enter Alias:', oldAlias)
                if alias != None:
                    if not alias: alias = False
                    self.doCommand('scene_editor/rename_component',
                                   target=context,
                                   alias=alias)

        elif name == 'assign_layer':
            if not self.tree.getSelection(): return
            requestSearchView(info='select layer to assign',
                              context='scene_layer',
                              type=_MOCK.Entity,
                              on_selection=self.assignEntityLayer)

        elif name == 'toggle_visibility':
            self.doCommand('scene_editor/toggle_entity_visibility')

        elif name == 'freeze_entity_pivot':
            self.doCommand('scene_editor/freeze_entity_pivot')

    def onSelectionChanged(self, selection, key):
        if key != 'scene': return
        if self.tree.syncSelection:
            self.tree.blockSignals(True)
            self.tree.selectNode(None)
            for e in selection:
                self.tree.selectNode(e, add=True)
            self.tree.blockSignals(False)

    def selectEntity(self, target, **option):
        if option.get('focus_tree', False):
            self.tree.setFocus()
        self.changeSelection(target)

    ##----------------------------------------------------------------##
    def renameEntity(self, target, name):
        #TODO:command pattern
        target.setName(target, name)
        signals.emit('entity.modified', target)

    def addEntityNode(self, entity):
        self.tree.addNode(entity, expanded=False)
        self.tree.setNodeExpanded(entity, False)

    def removeEntityNode(self, entity):
        self.tree.removeNode(entity)

    def assignEntityLayer(self, layerName):
        #TODO:command pattern
        if not layerName: return
        self.doCommand('scene_editor/assign_layer', target=layerName)

    def onSelectionHint(self, selection):
        if selection._entity:
            self.changeSelection(selection._entity)
        else:
            self.changeSelection(selection)

    def onPreviewStart(self):
        if not self.activeSceneNode: return
        self.retainWorkspaceState()
        self.delegate.safeCallMethod('editor', 'retainScene')
        self.delegate.safeCallMethod('editor', 'startScenePreview')
        self.previewing = True

    def onPreviewStop(self):
        if not self.activeSceneNode: return
        self.changeSelection(None)
        self.tree.clear()
        self.delegate.safeCallMethod('editor', 'stopScenePreview')
        self.previewing = False
        if self.delegate.safeCallMethod('editor', 'restoreScene'):
            self.restoreWorkspaceState()

    def onAnimatorStart(self):
        self.retainWorkspaceState()
        self.delegate.safeCallMethod('editor', 'retainScene')

    def onAnimatorStop(self):
        self.tree.clear()
        self.delegate.safeCallMethod('editor', 'clearScene')
        if self.delegate.safeCallMethod('editor', 'restoreScene'):
            self.restoreWorkspaceState()

    ##----------------------------------------------------------------##
    def updateEntityPriority(self):
        if not self.activeSceneNode: return
        self.markSceneDirty()

    def onEntityRenamed(self, entity, newname):
        self.tree.refreshNodeContent(entity)
        self.markSceneDirty()

    def onEntityVisibleChanged(self, entity):
        self.tree.refreshNodeContent(entity)

    def onEntityPickableChanged(self, entity):
        self.tree.refreshNodeContent(entity)

    def onEntityAdded(self, entity, context=None):
        if context == 'new':
            self.setFocus()
            pnode = entity.parent
            if pnode:
                self.tree.setNodeExpanded(pnode, True)
            self.tree.setFocus()
            self.tree.editNode(entity)
            self.tree.selectNode(entity)
        signals.emit('scene.update')
        self.markSceneDirty()

    def onEntityRemoved(self, entity):
        signals.emit('scene.update')
        self.markSceneDirty()

    def onEntityModified(self, entity, context=None):
        self.markSceneDirty()

    ##----------------------------------------------------------------##
    def onComponentAdded(self, com, entity):
        signals.emit('scene.update')
        self.markSceneDirty()

    def onComponentRemoved(self, com, entity):
        signals.emit('scene.update')
        self.markSceneDirty()

    ##----------------------------------------------------------------##
    def onPrefabUnlink(self, entity):
        self.tree.refreshNodeContent(entity, updateChildren=True)

    def onPrefabRelink(self, entity):
        self.tree.refreshNodeContent(entity, updateChildren=True)

    def createPrefab(self, targetPrefab):
        selection = self.getSelection()
        if not selection: return
        if len(selection) > 1:
            return alertMessage(
                'multiple entities cannot be converted into prefab')
        target = selection[0]
        self.doCommand('scene_editor/create_prefab',
                       entity=target,
                       prefab=targetPrefab.getNodePath(),
                       file=targetPrefab.getAbsFilePath())

    def makeProto(self):
        selection = self.getSelection()
        if not selection: return
        if len(selection) > 1:
            return alertMessage(
                'multiple entities cannot be converted into Proto')
        target = selection[0]
        if not target: return
        if requestConfirm('convert proto', 'Convert this Entity into Proto?'):
            self.doCommand('scene_editor/make_proto', entity=target)
            self.tree.refreshNodeContent(target)

    def createProtoInstance(self):
        pass

    ##----------------------------------------------------------------##
    def onCopyEntity(self):
        entityGroupData = self.delegate.callMethod(
            'editor', 'makeSceneSelectionCopyData')
        if not entityGroupData: return False
        clip = QtGui.QApplication.clipboard()
        mime = QtCore.QMimeData()
        text = ''
        for s in self.getSelection():
            if text == '':
                text = text + s.name
            else:
                text = text + '\n' + s.name
        mime.setText(text)
        mime.setData(GII_MIME_ENTITY_DATA, entityGroupData.encode('utf-8'))
        clip.setMimeData(mime)
        return True

    def onPasteEntity(self):
        clip = QtGui.QApplication.clipboard()
        mime = clip.mimeData()
        if mime.hasFormat(GII_MIME_ENTITY_DATA):
            data = mime.data(GII_MIME_ENTITY_DATA)
            self.doCommand('scene_editor/paste_entity',
                           data=str(data).decode('utf-8'))

    ##----------------------------------------------------------------##
    def onCopyComponent(self):
        entityGroupData = self.delegate.callMethod('editor',
                                                   'makeEntityCopyData')
        if not entityGroupData: return False
        clip = QtGui.QApplication.clipboard()
        mime = QtCore.QMimeData()
        text = ''
        for s in self.getSelection():
            if text == '':
                text = text + s.name
            else:
                text = text + '\n' + s.name
        mime.setText(text)
        mime.setData(GII_MIME_ENTITY_DATA, str(entityGroupData))
        clip.setMimeData(mime)
        return True

    def onPasteComponent(self):
        clip = QtGui.QApplication.clipboard()
        mime = clip.mimeData()
        if mime.hasFormat(GII_MIME_ENTITY_DATA):
            data = mime.data(GII_MIME_ENTITY_DATA)
            self.doCommand('scene_editor/paste_entity', data=str(data))
Esempio n. 2
0
class AnimatorView(SceneEditorModule):
    name = "animator"
    dependency = ["scene_editor", "mock"]

    def onLoad(self):
        # UI
        self.windowTitle = "Animator"
        self.window = self.requestDockWindow(
            "AnimatorView", title="Animator", size=(120, 120), minSize=(120, 120), dock="bottom"
        )

        self.widget = AnimatorWidget()
        self.window.addWidget(self.widget)
        self.toolbarTarget = self.addToolBar("animator_target", self.widget.toolbarTarget)
        self.toolbarClips = self.addToolBar("animator_clips", self.widget.toolbarClips)
        self.toolbarPlay = self.addToolBar("animator_play", self.widget.toolbarPlay)
        self.toolbarTrack = self.addToolBar("animator_track", self.widget.toolbarTrack)
        # self.toolbarEdit  = self.addToolBar( 'animator_play',  self.widget.toolbarEdit )

        signals.connect("scene.close", self.onSceneClose)
        signals.connect("scene.save", self.preSceneSave)
        signals.connect("scene.saved", self.postSceneSave)

        # addWidgetWithLaytut( toolbar,
        # 	self.widget.containerEditTool )
        self.addTool("animator_target/change_context", label="Change Context", icon="in")
        self.addTool("animator_target/save_data", label="Save Data", icon="save")

        self.addTool("animator_clips/add_clip_group", label="add group", icon="add_folder")
        self.addTool("animator_clips/add_clip", label="add", icon="add")
        self.addTool("animator_clips/remove_clip", label="remove", icon="remove")
        self.addTool("animator_clips/clone_clip", label="clone", icon="clone")

        self.addTool("animator_play/goto_start", label="to start", icon="rewind")
        # self.addTool( 'animator_play/prev_key',   label = 'prev key',      icon = 'previous' )
        self.addTool("animator_play/stop", label="stop", icon="stop")
        self.addTool("animator_play/play", label="play", icon="play", type="check")
        # self.addTool( 'animator_play/next_key',   label = 'next key',      icon = 'next' )
        self.addTool("animator_play/goto_end", label="to end", icon="fast_forward")
        self.addTool("animator_play/----")
        self.addTool("animator_play/toggle_repeat", label="toggle repeat", icon="repeat", type="check")

        # SIGNALS
        self.addTool("animator_track/add_track_group", label="add group", icon="add_folder")
        self.addTool("animator_track/add_track", label="add", icon="add")
        self.addTool("animator_track/remove_track", label="remove", icon="remove")

        #
        signals.connect("selection.changed", self.onSceneSelectionChanged)

        self.delegate = MOAILuaDelegate(self)
        self.delegate.load(_getModulePath("AnimatorView.lua"))

        self.widget.setOwner(self)

        # playback
        self.previewing = False
        self.setEditing(False)

        self.targetAnimator = None
        self.targetClip = None
        self.targetAnimatorData = None
        self.currentTrack = None

        self.previewing = False
        self.previewLoop = False
        self.previewTime = 0.0
        self.previewStep = 1.0 / 60.0

        self.previewTimer = QtCore.QTimer(self.widget)
        self.previewTimer.setInterval(1000.0 / 65)
        self.previewTimer.stop()

        self.previewTimer.timeout.connect(self.onPreviewTimer)

    def onStart(self):
        pass

    def setEditing(self, editing):
        self.widget.timeline.setEnabled(editing)
        self.widget.treeTracks.setEnabled(editing)
        self.findTool("animator_play").setEnabled(editing)
        self.findTool("animator_track").setEnabled(editing)
        self.findTool("animator_clips/add_clip_group").setEnabled(editing)
        self.findTool("animator_clips/add_clip").setEnabled(editing)
        self.findTool("animator_clips/remove_clip").setEnabled(editing)
        self.findTool("animator_clips/clone_clip").setEnabled(editing)

    def setTargetAnimator(self, target):
        self.saveAnimatorData()
        if target == self.targetAnimator:
            return
        if self.previewing:
            self.stopPreview()
        self.targetAnimator = target
        self.targetClip = None
        self.delegate.callMethod("view", "setTargetAnimator", target)
        self.targetAnimatorData = self.delegate.callMethod("view", "getTargetAnimatorData")
        self.widget.rebuild()
        if self.targetAnimator:
            self.setEditing(True)
            signals.emit("animator.start")
        else:
            self.setEditing(False)
            signals.emit("animator.stop")

        path = self.delegate.callMethod("view", "getTargetAnimatorDataPath")
        if path:
            self.window.setWindowTitle("Animator - %s" % path)
        else:
            self.window.setWindowTitle("Animator")
        clip = self.delegate.callMethod("view", "getPreviousTargeClip", target)
        self.enableTool("animator_play", False)
        self.enableTool("animator_track", False)
        if clip:
            self.widget.treeClips.selectNode(clip)
        else:
            self.widget.treeClips.selectFirstItem()
        self.applyTime(0, True)

    def setTargetClip(self, clip):
        wasPreviewing = self.previewing
        if self.previewing:
            self.stopPreview()

        self.targetClip = clip
        self.delegate.callMethod("view", "setTargetClip", clip)
        self.widget.rebuildTimeline()
        self.enableTool("animator_play", bool(clip))
        self.enableTool("animator_track", bool(clip))
        self.applyTime(0, True)
        if wasPreviewing:
            self.startPreview()

    def setCurrentTrack(self, track):
        self.currentTrack = track
        self.delegate.callMethod("view", "setCurrentTrack", track)

    def getClipList(self):
        if self.targetAnimatorData:
            clipList = self.targetAnimatorData.clips
            return [clip for clip in clipList.values()]
        else:
            return []

    def getRootClipGroup(self):
        if self.targetAnimatorData:
            return self.targetAnimatorData.getRootGroup(self.targetAnimatorData)

    def getTrackList(self):
        if self.targetClip:
            trackList = self.targetClip.getTrackList(self.targetClip)
            return [track for track in trackList.values()]
        else:
            return []

    def getMarkerList(self):
        if self.targetClip:
            markerList = self.targetClip.getMarkerList(self.targetClip)
            return [track for track in markerList.values()]
        else:
            return []

    def getClipRoot(self):
        if self.targetClip:
            return self.targetClip.getRoot(self.targetClip)
        else:
            return None

    def addClip(self):
        if not self.targetAnimatorData:
            return
        targetGroup = self.widget.getCurrentClipGroup()
        cmd = self.doCommand(
            "scene_editor/animator_add_clip", animator_data=self.targetAnimatorData, parent_group=targetGroup
        )
        clip = cmd.getResult()
        if clip:
            self.widget.addClip(clip, True)
        return clip

    def addClipGroup(self):
        if not self.targetAnimatorData:
            return
        targetGroup = self.widget.getCurrentClipGroup()
        cmd = self.doCommand(
            "scene_editor/animator_add_clip_group", animator_data=self.targetAnimatorData, parent_group=targetGroup
        )
        group = cmd.getResult()
        if group:
            self.widget.addClip(group, True)
        return group

    def removeClipNode(self):
        for clip in self.widget.treeClips.getSelection():
            if self.doCommand(
                "scene_editor/animator_remove_clip_node", animator_data=self.targetAnimatorData, target_node=clip
            ):
                self.widget.removeClip(clip)

    def cloneClipNode(self):
        if not self.targetClip:
            return
        result = []
        for clip in self.widget.treeClips.getSelection():
            cmd = self.doCommand(
                "scene_editor/animator_clone_clip_node", animator_data=self.targetAnimatorData, target_node=clip
            )
            if cmd:
                cloned = cmd.getResult()
                self.widget.addClip(cloned)
                result.append(cloned)
        return result

    def onObjectEdited(self, obj):
        if self.targetClip:
            self.delegate.callMethod("view", "clearPreviewState")
            self.delegate.callMethod("view", "markClipDirty")

    def onSceneSelectionChanged(self, selection, key):
        if key != "scene":
            return
        # find animator component
        # self.findTargetAnimator()

    def findTargetAnimator(self):
        target = self.delegate.callMethod("view", "findTargetAnimator")
        self.setTargetAnimator(target)
        return target

    def checkTargetAnimator(self):
        if not self.targetAnimator:
            alertMessage("No Animator", "No Animator Selected", "question")
            return False
        return True

    def addMarker(self):
        if not self.targetClip:
            return
        cmd = self.doCommand(
            "scene_editor/animator_add_marker", target_clip=self.targetClip, target_pos=self.widget.getCursorPos()
        )
        if cmd:
            marker = cmd.getResult()
            self.widget.addMarker(marker)

    def addKeyForField(self, target, fieldId):
        if not self.checkTargetAnimator():
            return

        if not self.targetClip:
            self.addClip()
            # alertMessage( 'No Clip', 'You need to select a Clip first', 'question' )
            # return False
        keys = self.delegate.callMethod("view", "addKeyForField", target, fieldId)
        if keys:
            for key in keys.values():
                self.widget.addKey(key, True)

    def addKeyForEvent(self, target, eventId):
        pass

    def addCustomAnimatorTrack(self, target, trackClasId):
        if not self.checkTargetAnimator():
            return

        track = self.delegate.callMethod("view", "addCustomAnimatorTrack", target, trackClasId)
        if track:
            self.widget.addTrack(track)

    def addKeyForSelectedTracks(self):
        # TODO: command
        selectedTracks = self.widget.getTrackSelection()
        for track in selectedTracks:
            keys = self.delegate.callMethod("view", "addKeyForSelectedTrack", track)
            if keys:
                for key in keys.values():
                    self.widget.addKey(key, True)

    def removeSelectedKeys(self):
        # TODO: command
        selectedKeys = self.widget.getKeySelection()
        for key in selectedKeys:
            self.widget.removeKey(key)

    def cloneSelectedKeys(self):
        # TODO: command
        selectedKeys = self.widget.getKeySelection()
        cloned = []
        for key in selectedKeys:
            clonedKey = self.delegate.callMethod("view", "cloneKey", key)
            if clonedKey:
                cloned.append(clonedKey)

        for clonedKey in cloned:
            self.widget.addKey(clonedKey, False)

    def onKeyRemoving(self, key):
        if self.delegate.callMethod("view", "removeKey", key) != False:
            return True

    def onTimelineKeyChanged(self, key, pos, length):
        self.delegate.callMethod("view", "updateTimelineKey", key, pos, length)

    def onTimelineKeyCurveValueChanged(self, key, value):
        self.delegate.callMethod("view", "updateTimelineKeyCurveValue", key, value)

    def onTimelineKeyTweenModeChanged(self, key, mode):
        self.delegate.callMethod("view", "updateTimelineKeyTweenMode", key, mode)

    def onTimelineKeyBezierPointChanged(self, key, bpx0, bpy0, bpx1, bpy1):
        self.delegate.callMethod("view", "updateTimelineKeyBezierPoint", key, bpx0, bpy0, bpx1, bpy1)

    def onTimelineMarkerChanged(self, marker, pos):
        self.delegate.callMethod("view", "updateTimelineMarker", marker, pos)

    def renameTrack(self, track, name):
        self.delegate.callMethod("view", "renameTrack", track, name)

    def renameClip(self, clip, name):
        self.delegate.callMethod("view", "renameClip", clip, name)

    def onTool(self, tool):
        name = tool.name
        if name == "change_context":
            target0 = self.targetAnimator
            target1 = self.findTargetAnimator()
            if (not target0) and (not target1):
                alertMessage("No Animator", "No Animator found in selected entity scope", "question")

        elif name == "save_data":
            self.saveAnimatorData()

        elif name == "add_clip":
            if self.checkTargetAnimator():
                self.addClip()

        elif name == "add_clip_group":
            if self.checkTargetAnimator():
                self.addClipGroup()

        elif name == "remove_clip":
            if self.checkTargetAnimator():
                self.removeClipNode()

        elif name == "clone_clip":
            if self.checkTargetAnimator():
                self.cloneClipNode()

        elif name == "add_track_group":
            group = self.delegate.callMethod("view", "addTrackGroup")
            if group:
                self.widget.addTrack(group, True)

        elif name == "remove_track":
            for track in self.widget.treeTracks.getSelection():
                self.delegate.callMethod("view", "removeTrack", track)
                self.widget.removeTrack(track)
                # preview
        elif name == "goto_start":
            self.gotoStart()
        elif name == "goto_end":
            self.gotoEnd()
        elif name == "play":
            if tool.getValue():
                self.startPreview()
            else:
                self.stopPreview(False)
        elif name == "stop":
            self.stopPreview(True)
        elif name == "toggle_repeat":
            self.delegate.callMethod("view", "togglePreviewRepeat", tool.getValue())

    def getActiveSceneView(self):
        return self.getModule("scene_view")

        # preview

    def startPreview(self):
        self.saveAnimatorData()
        if self.delegate.callMethod("view", "startPreview", self.previewTime):
            self.widget.setCursorMovable(False)
            self.previewing = True
            self.findTool("animator_play/play").setValue(True)
            self.previewTimer.start()
            self.getApp().setMinimalMainLoopBudget()

    def stopPreview(self, rewind=False):
        if self.previewing:
            self.delegate.callMethod("view", "stopPreview")
            self.getApp().resetMainLoopBudget()
            self.widget.setCursorMovable(True)
            self.previewing = False
            self.findTool("animator_play/play").setValue(False)
            self.previewTimer.stop()
            signals.emit("entity.modified", None, "")
        if rewind:
            self.gotoStart()

    def onPreviewTimer(self):
        playing, currentTime = self.delegate.callMethod("view", "doPreviewStep")
        self.previewTime = currentTime
        self.getActiveSceneView().forceUpdate()
        self.widget.setCursorPos(self.previewTime)
        if not playing:
            self.stopPreview()
            # signals.emit( 'entity.modified',  None , '' )

    def gotoStart(self):
        if self.previewing:
            self.delegate.callMethod("view", "applyTime", 0)
        else:
            self.widget.setCursorPos(0, True)

    def gotoEnd(self):
        if self.previewing:
            self.delegate.callMethod("view", "applyTime", 10)
        else:
            self.widget.setCursorPos(10, True)

    def applyTime(self, t, syncCursor=False):
        self.previewTime = self.delegate.callMethod("view", "applyTime", t)
        self.getActiveSceneView().forceUpdate()
        signals.emit("entity.modified", None, "")
        if syncCursor:
            self.widget.setCursorPos(t)

    def saveAnimatorData(self):
        if not self.targetAnimator:
            return
        self.delegate.callMethod("view", "saveData")

    def preSceneSave(self):
        if self.targetAnimator:
            self.delegate.callMethod("view", "restoreEntityState")

    def postSceneSave(self):
        if self.targetAnimator:
            self.applyTime(self.previewTime)

    def onSceneClose(self, scene):
        self.setTargetAnimator(None)

    def refreshTimeline(self):
        self.widget.rebuildTimeline()

    def refreshClipList(self):
        self.widget.rebuildClipList()

    def refreshAll(self):
        self.widget.rebuild()
Esempio n. 3
0
class AnimatorView( SceneEditorModule ):
	name = 'animator'
	dependency = [ 'scene_editor', 'mock' ]

	def onLoad( self ):
		#UI
		self.windowTitle = 'Animator'
		self.window = self.requestDockWindow( 'AnimatorView',
			title     = 'Animator',
			size      = (120,120),
			minSize   = (120,120),
			dock      = 'bottom'
			)
		
		self.widget = AnimatorWidget()
		self.window.addWidget( self.widget )
		self.toolbarTarget = self.addToolBar( 'animator_target', self.widget.toolbarTarget )
		self.toolbarClips  = self.addToolBar( 'animator_clips', self.widget.toolbarClips )
		self.toolbarPlay   = self.addToolBar( 'animator_play',  self.widget.toolbarPlay )
		self.toolbarTrack  = self.addToolBar( 'animator_track', self.widget.toolbarTrack )
		# self.toolbarEdit  = self.addToolBar( 'animator_play',  self.widget.toolbarEdit )

		signals.connect( 'scene.close', self.onSceneClose )
		signals.connect( 'scene.save', self.preSceneSave )
		signals.connect( 'scene.saved', self.postSceneSave )

		# addWidgetWithLaytut( toolbar,
		# 	self.widget.containerEditTool )
		self.addTool( 'animator_target/change_context', label = 'Change Context', icon = 'in' )
		self.addTool( 'animator_target/save_data', label = 'Save Data', icon = 'save' )

		self.addTool( 'animator_clips/add_clip_group',   label = 'add group',    icon = 'add_folder' )
		self.addTool( 'animator_clips/add_clip',    label = 'add',    icon = 'add' )
		self.addTool( 'animator_clips/remove_clip', label = 'remove', icon = 'remove' )
		self.addTool( 'animator_clips/clone_clip', label = 'clone', icon = 'clone' )


		self.addTool( 'animator_play/goto_start', label = 'to start',  icon = 'rewind' )
		# self.addTool( 'animator_play/prev_key',   label = 'prev key',      icon = 'previous' )
		self.addTool( 'animator_play/stop',       label = 'stop',      icon = 'stop' )
		self.addTool( 'animator_play/play',       label = 'play',      icon = 'play',  type = 'check' )
		# self.addTool( 'animator_play/next_key',   label = 'next key',      icon = 'next' )
		self.addTool( 'animator_play/goto_end',   label = 'to end',    icon = 'fast_forward' )
		self.addTool( 'animator_play/toggle_repeat',  label = 'toggle repeat',  icon = 'repeat', type = 'check' )
		self.comboPreviewSpeed = QtGui.QComboBox()
		self.comboPreviewSpeed.addItems([ e[0] for e in PREVIEW_SPEED_OPTIONS ] )			
		self.comboPreviewSpeed.setCurrentIndex( 4 ) #1x
		self.comboPreviewSpeed.currentIndexChanged.connect( self.onPreviewSpeedChange )
		self.addTool( 'animator_play/preview_speed', widget = self.comboPreviewSpeed )
		
		#SIGNALS
		self.addTool( 'animator_track/locate_target', label = 'locate', icon = 'find' )
		self.addTool( 'animator_track/----' )
		self.addTool( 'animator_track/add_track_group',    label = 'add group',    icon = 'add_folder' )
		self.addTool( 'animator_track/add_track',    label = 'add',    icon = 'add' )
		self.addTool( 'animator_track/remove_track', label = 'remove', icon = 'remove' )

		#
		signals.connect( 'selection.changed', self.onSceneSelectionChanged )

		self.delegate = MOAILuaDelegate( self )
		self.delegate.load( _getModulePath( 'AnimatorView.lua' ) )

		self.widget.setOwner( self )

		#playback
		self.previewing = False
		self.setEditing( False )

		self.targetAnimator     = None
		self.targetClip         = None
		self.targetAnimatorData = None
		self.currentTrack       = None

		self.previewing  = False
		self.previewLoop = False
		self.previewTime = 0.0
		self.previewStep = 1.0/60.0

		self.previewTimer  = QtCore.QTimer( self.widget )
		self.previewTimer.setInterval( 1000.0/65 )
		self.previewTimer.stop()

		self.previewTimer.timeout.connect( self.onPreviewTimer )

	def onStart( self ):
		pass

	def setEditing( self, editing ):
		self.widget.timeline.setEnabled( editing )
		self.widget.treeTracks.setEnabled( editing )
		self.findTool( 'animator_play'  ).setEnabled( editing )
		self.findTool( 'animator_track' ).setEnabled( editing )
		self.findTool( 'animator_clips/add_clip_group').setEnabled( editing )
		self.findTool( 'animator_clips/add_clip'      ).setEnabled( editing )
		self.findTool( 'animator_clips/remove_clip'   ).setEnabled( editing )
		self.findTool( 'animator_clips/clone_clip'    ).setEnabled( editing )

	def setTargetAnimator( self, target ):
		self.saveAnimatorData()
		if target == self.targetAnimator: return
		if self.previewing:
			self.stopPreview()
		self.targetAnimator = target
		self.targetClip     = None
		self.delegate.callMethod( 'view', 'setTargetAnimator', target )
		self.targetAnimatorData = self.delegate.callMethod( 'view', 'getTargetAnimatorData' )
		self.widget.rebuild()
		if self.targetAnimator:
			self.setEditing( True )
			signals.emit( 'animator.start' )
		else:
			self.setEditing( False )
			signals.emit( 'animator.stop' )
			
		path = self.delegate.callMethod( 'view', 'getTargetAnimatorDataPath' )
		if path:
			self.window.setWindowTitle( 'Animator - %s' % path )
		else:
			self.window.setWindowTitle( 'Animator' )
		clip = self.delegate.callMethod( 'view', 'getPreviousTargeClip', target )
		self.enableTool( 'animator_play' , False )
		self.enableTool( 'animator_track', False )
		if clip:
			self.widget.treeClips.selectNode( clip )
		else:
			self.widget.treeClips.selectFirstItem()
		self.applyTime( 0, True )

	def setTargetClip( self, clip ):
		wasPreviewing = self.previewing
		if self.previewing:
			self.stopPreview()

		self.targetClip = clip
		self.delegate.callMethod( 'view', 'setTargetClip', clip )
		self.widget.rebuildTimeline()
		self.enableTool( 'animator_play' , bool( clip ) )
		self.enableTool( 'animator_track', bool( clip ) )
		self.applyTime( 0, True )
		if wasPreviewing:
			self.startPreview()

	def setCurrentTrack( self, track ):
		self.currentTrack = track
		self.delegate.callMethod( 'view', 'setCurrentTrack', track )

	def getTargetClipLength( self ):
		return self.delegate.callMethod( 'view', 'getTargetClipLength' )

	def getClipList( self ):
		if self.targetAnimatorData:
			clipList = self.targetAnimatorData.clips
			return [ clip for clip in clipList.values()  ]
		else:
			return []

	def getRootClipGroup( self ):
		if self.targetAnimatorData:
			return self.targetAnimatorData.getRootGroup( self.targetAnimatorData )

	def getTrackList( self ):
		if self.targetClip:
			trackList = self.targetClip.getTrackList( self.targetClip )
			return [ track for track in trackList.values()  ]
		else:
			return []

	def getMarkerList( self ):
		if self.targetClip:
			markerList = self.targetClip.getMarkerList( self.targetClip )
			return [ track for track in markerList.values()  ]
		else:
			return []

	def getClipRoot( self ):
		if self.targetClip:
			return self.targetClip.getRoot( self.targetClip )
		else:
			return None

	def addClip( self ):
		if not self.targetAnimatorData: return
		targetGroup = self.widget.getCurrentClipGroup()
		cmd = self.doCommand( 'scene_editor/animator_add_clip',
			animator_data = self.targetAnimatorData,
			parent_group  = targetGroup
		  )
		clip = cmd.getResult()
		if clip:
			self.widget.addClip( clip, True )
		return clip

	def addClipGroup( self ):
		if not self.targetAnimatorData: return
		targetGroup = self.widget.getCurrentClipGroup()
		cmd = self.doCommand( 'scene_editor/animator_add_clip_group',
			animator_data = self.targetAnimatorData,
			parent_group  = targetGroup
		  )
		group = cmd.getResult()
		if group:
			self.widget.addClip( group, True )
		return group

	def removeClipNode( self ):
		for clip in self.widget.treeClips.getSelection():
			if self.doCommand( 'scene_editor/animator_remove_clip_node',
				animator_data = self.targetAnimatorData,
				target_node   = clip
			):
				self.widget.removeClip( clip )

	def cloneClipNode( self ):
		if not self.targetClip: return
		result = []
		for clip in self.widget.treeClips.getSelection():
			cmd = self.doCommand( 'scene_editor/animator_clone_clip_node',
				animator_data = self.targetAnimatorData,
				target_node   = clip
			)
			if cmd:
				cloned = cmd.getResult()
				self.widget.addClip( cloned )
				result.append( cloned )
		return result

	def onObjectEdited( self, obj ):
		if self.targetClip:
			self.delegate.callMethod( 'view', 'clearPreviewState' )
			self.delegate.callMethod( 'view', 'markClipDirty' )

	def onSceneSelectionChanged( self, selection, key ):
		if key != 'scene': return
		#find animator component
		# self.findTargetAnimator()

	def findTargetAnimator( self ):
		target = self.delegate.callMethod( 'view', 'findTargetAnimator' )
		self.setTargetAnimator( target )
		return target

	def checkTargetAnimator( self ):
		if not self.targetAnimator:
			alertMessage( 'No Animator', 'No Animator Selected', 'question' )
			return False
		return True

	def addMarker( self ):
		if not self.targetClip: return
		cmd = self.doCommand( 'scene_editor/animator_add_marker' ,
				target_clip = self.targetClip,
				target_pos  = self.widget.getCursorPos()
			)
		if cmd:
			marker = cmd.getResult()
			self.widget.addMarker( marker )

	def addKeyForField( self, target, fieldId ):
		if not self.checkTargetAnimator(): return 

		if not self.targetClip:
			self.addClip()
			# alertMessage( 'No Clip', 'You need to select a Clip first', 'question' )
			# return False
		keys = self.delegate.callMethod( 'view', 'addKeyForField', target, fieldId )
		if keys:
			for key in keys.values():
				self.widget.addKey( key, True )

	def addKeyForEvent( self, target, eventId ):
		pass

	def addCustomAnimatorTrack( self, target, trackClasId ):
		if not self.checkTargetAnimator(): return
			
		track = self.delegate.callMethod( 'view', 'addCustomAnimatorTrack', target, trackClasId )
		if track:
			self.widget.addTrack( track )

	def addKeyForSelectedTracks( self ):
		#TODO: command
		selectedTracks = self.widget.getTrackSelection()
		for track in selectedTracks:
			keys = self.delegate.callMethod( 'view', 'addKeyForSelectedTrack', track )
			if keys:
				for key in keys.values():
					self.widget.addKey( key, True )

	def removeSelectedKeys( self ):
		#TODO: command
		selectedKeys = self.widget.getKeySelection()
		for key in selectedKeys:
			self.widget.removeKey( key )

	def cloneSelectedKeys( self ):
		#TODO: command
		selectedKeys = self.widget.getKeySelection()
		cloned = []
		for key in selectedKeys:
			clonedKey = self.delegate.callMethod( 'view', 'cloneKey', key )
			if clonedKey:
				cloned.append( clonedKey )

		for clonedKey in cloned:
			self.widget.addKey( clonedKey, False )

	def onKeyRemoving( self, key ):
		if self.delegate.callMethod( 'view', 'removeKey', key ) != False:
			return True

	def onMarkerRemoving( self, marker ):
		if self.delegate.callMethod( 'view', 'removeMarker', marker ) != False:
			return True

	def onClipLengthChanging( self, t1 ):
		if self.delegate.callMethod( 'view', 'setTargetClipLength', t1 ) != False:
			return True

	def onTimelineKeyChanged( self, key, pos, length ):
		self.delegate.callMethod( 'view', 'updateTimelineKey', key, pos, length )

	def onTimelineKeyCurveValueChanged( self, key, value ):
		self.delegate.callMethod( 'view', 'updateTimelineKeyCurveValue', key, value )

	def onTimelineKeyTweenModeChanged( self, key, mode ):
		self.delegate.callMethod( 'view', 'updateTimelineKeyTweenMode', key, mode )

	def onTimelineKeyBezierPointChanged( self, key, bpx0, bpy0, bpx1, bpy1 ):
		self.delegate.callMethod( 'view', 'updateTimelineKeyBezierPoint', key, bpx0, bpy0, bpx1, bpy1 )

	def onTimelineMarkerChanged( self, marker, pos ):
		self.delegate.callMethod( 'view', 'updateTimelineMarker', marker, pos )

	def toggleTrackActive( self, track ):
		#TODO: command
		# self.module.doCommand( 'scene_editor/toggle_entity_visibility', target = node )
		self.delegate.callMethod( 'view', 'toggleTrackActive', track )


	def renameTrack( self, track, name ):
		self.delegate.callMethod( 'view', 'renameTrack', track, name )

	def renameClip( self, clip, name ):
		self.delegate.callMethod( 'view', 'renameClip', clip, name )

	def onTool( self, tool ):
		name = tool.name
		if name == 'change_context':
			target0 = self.targetAnimator
			target1 = self.findTargetAnimator()
			if ( not target0 ) and ( not target1 ):
				alertMessage( 'No Animator', 'No Animator found in selected entity scope', 'question' )
				
		elif name == 'save_data':
			self.saveAnimatorData()

		elif name == 'add_clip':
			if self.checkTargetAnimator():
				self.addClip()

		elif name == 'add_clip_group':
			if self.checkTargetAnimator():
				self.addClipGroup()

		elif name == 'remove_clip':
			if self.checkTargetAnimator():
				self.removeClipNode()			

		elif name == 'clone_clip':
			if self.checkTargetAnimator():
				self.cloneClipNode()			

		elif name == 'add_track_group':
			group = self.delegate.callMethod( 'view', 'addTrackGroup' )
			if group:
				self.widget.addTrack( group, True )

		elif name == 'remove_track':
			for track in self.widget.treeTracks.getSelection():
				self.delegate.callMethod( 'view', 'removeTrack', track )
				self.widget.removeTrack( track )
		elif name == 'locate_target':
			for track in self.widget.treeTracks.getSelection():
				sceneGraphEditor = self.getModule( 'scenegraph_editor')
				if sceneGraphEditor:
					targetEntity = self.delegate.callMethod( 'view', 'findTrackEntity', track )
					if targetEntity:
						sceneGraphEditor.selectEntity( targetEntity, focus_tree = True )
				#pass
				return

		#preview
		elif name == 'goto_start':
			self.gotoStart()
		elif name == 'goto_end':
			self.gotoEnd()
		elif name == 'play':
			if tool.getValue():
				self.startPreview()
			else:
				self.stopPreview( False )
		elif name == 'stop':
			self.stopPreview( True )
		elif name == 'toggle_repeat':
			self.delegate.callMethod( 'view', 'togglePreviewRepeat', tool.getValue() )
			

	def getActiveSceneView( self ):
		return self.getModule( 'scene_view' )

	#preview
	def startPreview( self ):
		self.saveAnimatorData()
		if self.delegate.callMethod( 'view', 'startPreview', self.previewTime ):
			self.widget.setCursorMovable( False )
			self.previewing = True
			self.findTool( 'animator_play/play' ).setValue( True )
			self.previewTimer.start()
			self.getApp().setMinimalMainLoopBudget()
			
	def stopPreview( self, rewind = False ):		
		if self.previewing:
			self.delegate.callMethod( 'view', 'stopPreview' )
			self.getApp().resetMainLoopBudget()
			self.widget.setCursorMovable( True )
			self.previewing = False
			self.findTool( 'animator_play/play' ).setValue( False )
			self.previewTimer.stop()
			signals.emit( 'entity.modified',  None , '' )
		if rewind:
			self.gotoStart()

	def onPreviewTimer( self ):
		playing, currentTime = self.delegate.callMethod( 'view', 'doPreviewStep' )
		self.previewTime = currentTime
		self.getActiveSceneView().forceUpdate()
		self.widget.setCursorPos( self.previewTime )
		if not playing:
			self.stopPreview()
		# signals.emit( 'entity.modified',  None , '' )

	def gotoStart( self ):
		if self.previewing:
			self.delegate.callMethod( 'view', 'applyTime', 0 )
		else:
			self.widget.setCursorPos( 0, True )

	def gotoEnd( self ):
		if self.previewing:
			self.delegate.callMethod( 'view', 'applyTime', 10 )
		else:
			self.widget.setCursorPos( 10, True )

	def applyTime( self, t, syncCursor = False ):
		self.previewTime = self.delegate.callMethod( 'view', 'applyTime', t )
		self.getActiveSceneView().forceUpdate()
		signals.emit( 'entity.modified',  None , '' )
		if syncCursor:
			self.widget.setCursorPos( t )

	def saveAnimatorData( self ):
		if not self.targetAnimator:
			return
		self.delegate.callMethod( 'view', 'saveData' )

	def preSceneSave( self ):
		if self.targetAnimator:
			self.delegate.callMethod( 'view', 'restoreEntityState' )

	def postSceneSave( self ):
		if self.targetAnimator:
			self.applyTime( self.previewTime )

	def onSceneClose( self, scene ):
		self.setTargetAnimator( None )

	def onPreviewSpeedChange( self, index ):
		label, throttle = PREVIEW_SPEED_OPTIONS[ index ]
		self.delegate.callMethod( 'view', 'setPreviewThrottle', throttle )

	def refreshTimeline( self ):
		self.widget.rebuildTimeline()

	def refreshClipList( self ):
		self.widget.rebuildClipList()

	def refreshAll( self ):
		self.widget.rebuild()
Esempio n. 4
0
class DeckCanvasEditor(SceneEditorModule):
    name = 'deckcanvas_editor'
    dependency = ['mock']

    def onLoad(self):
        self.mainToolBar = self.addToolBar(
            'deckcanvas_tools',
            self.getMainWindow().requestToolBar('deckcanvas_tools'))

        self.addTool('deckcanvas_tools/tool_pen',
                     widget=SceneToolButton('deckcanvas_pen',
                                            label='Deck Canvas Editor',
                                            icon='deckcanvas/pen'))

        self.addTool('deckcanvas_tools/toggle_item_bounds_visible',
                     label='Toggle Item Bounds',
                     icon='deckcanvas/layer',
                     type='check')

        self.findTool('deckcanvas_tools/toggle_item_bounds_visible').setValue(
            True)

        self.delegate = MOAILuaDelegate(self)
        self.delegate.load(_getModulePath('DeckCanvasEditor.lua'))
        signals.connect('selection.changed', self.onSelectionChanged)

        self.toolWindow = self.requestToolWindow('DeckCanvasEditor',
                                                 title='DeckCanvas',
                                                 size=(120, 40),
                                                 minSize=(120, 40))

        self.targetCanvas = None

    def onStart(self):
        self.setEditActive(True)

    def onSetFocus(self):
        self.getModule('scene_editor').setFocus()
        self.container.show()
        self.container.setFocus()

    def updateSelection(self):
        target = self.delegate.callMethod('editor', 'findTargetDeckCanvas')
        self.setTargetCanvas(target)

    def onSelectionChanged(self, selection, key):
        if key == 'scene':
            self.updateSelection()

        elif key == 'asset':
            decks = []
            for node in selection:
                if node.getType().startswith('deck2d.'):
                    decks.append(node.getNodePath())

            self.delegate.callMethod('editor', 'changeDeckSelection', decks)

    def setEditActive(self, active):
        self.enableTool('deckcanvas_tools/tool_pen', active)

    def setTargetCanvas(self, canvas):
        self.delegate.callMethod('editor', 'setTargetCanvas', canvas)
        self.targetCanvas = canvas
        # if not self.targetCanvas:
        # 	self.setEditActive( False )
        # 	return
        # self.setEditActive( True )

    def showToolWindow(self):
        # self.toolWindow.show()
        self.getModule('scene_view').setFocus()

    def hideToolWindow(self):
        # self.toolWindow.hide()
        pass

    def startPenTool(self):
        self.delegate.callMethod('editor', 'startPenTool')

    def onTool(self, tool):
        name = tool.name
        if name == 'toggle_item_bounds_visible':
            _MOCK.setDeckCanvasItemBoundsVisible(bool(tool.getValue()))
            signals.emit('scene.update')
Esempio n. 5
0
class AnimatorView(SceneEditorModule):
    name = 'animator'
    dependency = ['scene_editor', 'mock']

    def onLoad(self):
        #UI
        self.windowTitle = 'Animator'
        self.window = self.requestDockWindow('AnimatorView',
                                             title='Animator',
                                             size=(120, 120),
                                             minSize=(120, 120),
                                             dock='bottom',
                                             icon='play')

        self.widget = AnimatorWidget()
        self.window.addWidget(self.widget)
        self.toolbarTarget = self.addToolBar('animator_target',
                                             self.widget.toolbarTarget)
        self.toolbarClips = self.addToolBar('animator_clips',
                                            self.widget.toolbarClips)
        self.toolbarPlay = self.addToolBar('animator_play',
                                           self.widget.toolbarPlay)
        self.toolbarTrack = self.addToolBar('animator_track',
                                            self.widget.toolbarTrack)
        self.toolbarClipTree = self.addToolBar('animator_clip_tree',
                                               self.widget.toolbarClipTree)
        # self.toolbarEdit  = self.addToolBar( 'animator_play',  self.widget.toolbarEdit )

        signals.connect('scene.close', self.onSceneClose)
        signals.connect('scene.save', self.preSceneSave)
        signals.connect('scene.saved', self.postSceneSave)

        # addWidgetWithLaytut( toolbar,
        # 	self.widget.containerEditTool )
        self.addTool('animator_target/find_animator',
                     label='Find Animator',
                     icon='find')
        self.addTool('animator_target/change_animator',
                     label='Edit Selected Animator',
                     icon='in')
        # self.addTool( 'animator_target/close_animator', label = 'Close Animator', icon = 'in' )
        self.addTool('animator_target/----')
        self.addTool('animator_target/save_data',
                     label='Save Data',
                     icon='save')
        self.addTool('animator_target/----')
        self.addTool('animator_target/extra', label='Extra', icon='dots')

        #
        self.addTool('animator_clips/add_clip_group',
                     label='add group',
                     icon='add_folder')
        self.addTool('animator_clips/add_clip', label='add', icon='add')
        self.addTool('animator_clips/add_clip_tree',
                     label='add tree',
                     icon='add_clip_tree')
        # self.addTool( 'animator_clips/add_clip_list',   label = 'add list',    icon = 'add_clip_list' )
        self.addTool('animator_clips/----')
        self.addTool('animator_clips/remove_clip',
                     label='remove',
                     icon='remove')
        self.addTool('animator_clips/clone_clip', label='clone', icon='clone')

        #
        self.addTool('animator_play/goto_start',
                     label='to start',
                     icon='rewind')
        self.addTool('animator_play/stop', label='stop', icon='stop')
        self.addTool('animator_play/play',
                     label='play',
                     icon='play',
                     type='check')
        self.addTool('animator_play/goto_end',
                     label='to end',
                     icon='fast_forward')
        self.addTool('animator_play/toggle_repeat',
                     label='toggle repeat',
                     icon='repeat',
                     type='check')

        self.comboPreviewSpeed = QtWidgets.QComboBox()
        self.comboPreviewSpeed.addItems([e[0] for e in PREVIEW_SPEED_OPTIONS])
        self.comboPreviewSpeed.setCurrentIndex(4)  #1x
        self.comboPreviewSpeed.currentIndexChanged.connect(
            self.onPreviewSpeedChange)
        self.addTool('animator_play/preview_speed',
                     widget=self.comboPreviewSpeed)

        #
        self.addTool('animator_clip_tree/stop_tree', label='stop', icon='stop')
        self.addTool('animator_clip_tree/play_tree',
                     label='play',
                     icon='play',
                     type='check')
        self.addTool('animator_clip_tree/----', )
        self.addTool('animator_clip_tree/add_clip_tree_node',
                     label='Add node',
                     icon='add')
        self.addTool('animator_clip_tree/remove_clip_tree_node',
                     label='Remove node',
                     icon='remove')

        #SIGNALS
        self.addTool('animator_track/fold_tracks',
                     label='fold all',
                     icon='collapse')
        self.addTool('animator_track/unfold_tracks',
                     label='unfold all',
                     icon='expand')
        self.addTool('animator_track/----')
        self.addTool('animator_track/locate_target',
                     label='locate',
                     icon='find')
        self.addTool('animator_track/retarget',
                     label='retarget',
                     icon='compose')
        self.addTool('animator_track/----')
        self.addTool('animator_track/add_track_group',
                     label='add group',
                     icon='add_folder')
        self.addTool('animator_track/add_track', label='add', icon='add')
        self.addTool('animator_track/remove_track',
                     label='remove',
                     icon='remove')

        #
        self.addShortcut(self.widget, 'Space', self.togglePreview)
        self.addShortcut(self.widget, 'shift+Space', self.restartPreview)
        self.addShortcut(self.widget, 'Escape', self.resetPreview)

        signals.connect('selection.changed', self.onSceneSelectionChanged)

        self.delegate = MOAILuaDelegate(self)
        self.delegate.load(_getModulePath('AnimatorView.lua'))

        self.widget.setOwner(self)

        #playback
        self.previewing = False
        self.setEditing(False)
        self.setReadOnly(False)

        self.targetAnimator = None
        self.targetClip = None
        self.targetAnimatorData = None
        self.currentTrack = None

        self.previewing = False
        self.previewLoop = False
        self.previewTime = 0.0
        self.previewStep = 1.0 / 60.0

        self.previewTimer = QtCore.QTimer()
        self.previewTimer.setTimerType(Qt.PreciseTimer)
        # self.previewTimer  = self.addTimer()
        self.previewTimer.setInterval(1000.0 / 65)
        self.previewTimer.stop()
        self.previewTimer.timeout.connect(self.onPreviewTimer)

        # self.previewTimer.onTick = self.onPreviewTimer

    def onStart(self):
        pass

    def setEditing(self, editing):
        self.widget.timeline.setEnabled(editing)
        self.widget.treeTracks.setEnabled(editing)
        self.findTool('animator_play').setEnabled(editing)
        self.findTool('animator_track').setEnabled(editing)
        self.findTool('animator_clips/add_clip_group').setEnabled(editing)
        self.findTool('animator_clips/add_clip_tree').setEnabled(editing)
        self.findTool('animator_clips/add_clip').setEnabled(editing)
        self.findTool('animator_clips/remove_clip').setEnabled(editing)
        self.findTool('animator_clips/clone_clip').setEnabled(editing)

    def setReadOnly(self, readonly):
        self.readOnly = readonly
        #TODO

    def setTargetAnimator(self, target):
        self.saveAnimatorData()
        if target == self.targetAnimator: return
        if self.previewing:
            self.stopPreview()
        self.targetAnimator = target
        self.targetClip = None
        self.delegate.callMethod('view', 'setTargetAnimator', target)
        self.targetAnimatorData = self.delegate.callMethod(
            'view', 'getTargetAnimatorData')
        self.widget.rebuild()
        if self.targetAnimator:
            self.setEditing(True)
            signals.emit('animator.start')
        else:
            self.setEditing(False)
            signals.emit('animator.stop')

        path = self.delegate.callMethod('view', 'getTargetAnimatorDataPath')
        if path:
            self.window.setWindowTitle('Animator - %s' % path)
        else:
            self.window.setWindowTitle('Animator')
        clip = self.delegate.callMethod('view', 'getPreviousTargeClip', target)
        self.enableTool('animator_play', False)
        self.enableTool('animator_track', False)
        if clip:
            self.widget.treeClips.selectNode(clip)
        else:
            self.widget.treeClips.selectFirstItem()
        self.applyTime(0, True)

    def setTargetClip(self, clip):
        wasPreviewing = self.previewing
        if self.previewing:
            self.stopPreview()

        self.targetClip = clip
        self.delegate.callMethod('view', 'setTargetClip', clip)
        self.widget.rebuildTimeline()
        self.widget.rebuildClipTree()
        self.enableTool('animator_play', bool(clip))
        self.enableTool('animator_track', bool(clip))
        self.applyTime(0, True)
        if wasPreviewing:
            self.startPreview()

    def setCurrentTrack(self, track):
        self.currentTrack = track
        self.delegate.callMethod('view', 'setCurrentTrack', track)

    def getTargetClipLength(self):
        return self.delegate.callMethod('view', 'getTargetClipLength')

    def getClipList(self):
        if self.targetAnimatorData:
            clipList = self.targetAnimatorData.clips
            return [clip for clip in list(clipList.values())]
        else:
            return []

    def getRootClipGroup(self):
        if self.targetAnimatorData:
            return self.targetAnimatorData.getRootGroup(
                self.targetAnimatorData)

    def getTrackList(self):
        if self.targetClip:
            trackList = self.targetClip.getTrackList(self.targetClip)
            return [track for track in list(trackList.values())]
        else:
            return []

    def getMarkerList(self):
        if self.targetClip:
            markerList = self.targetClip.getMarkerList(self.targetClip)
            return [track for track in list(markerList.values())]
        else:
            return []

    def getClipRoot(self):
        if self.targetClip:
            return self.targetClip.getRoot(self.targetClip)
        else:
            return None

    def getClipTreeRoot(self):
        if self.targetClip and isMockInstance(self.targetClip,
                                              'AnimatorClipTree'):
            return self.targetClip.getTreeRoot(self.targetClip)

    def addClip(self):
        if not self.targetAnimatorData: return
        targetGroup = self.widget.getCurrentClipGroup()
        cmd = self.doCommand('scene_editor/animator_add_clip',
                             animator_data=self.targetAnimatorData,
                             parent_group=targetGroup)
        clip = cmd.getResult()
        clip.setFixedLength(clip, 3)
        if clip:
            self.widget.addClip(clip, True)
        return clip

    def addClipTree(self):
        if not self.targetAnimatorData: return
        targetGroup = self.widget.getCurrentClipGroup()
        cmd = self.doCommand('scene_editor/animator_add_clip_tree',
                             animator_data=self.targetAnimatorData,
                             parent_group=targetGroup)
        clip = cmd.getResult()
        if clip:
            self.widget.addClip(clip, True)
        return clip

    def addClipGroup(self):
        if not self.targetAnimatorData: return
        targetGroup = self.widget.getCurrentClipGroup()
        cmd = self.doCommand('scene_editor/animator_add_clip_group',
                             animator_data=self.targetAnimatorData,
                             parent_group=targetGroup)
        group = cmd.getResult()
        if group:
            self.widget.addClip(group, True)
        return group

    def removeClipNode(self):
        for clip in self.widget.treeClips.getSelection():
            if self.doCommand('scene_editor/animator_remove_clip_node',
                              animator_data=self.targetAnimatorData,
                              target_node=clip):
                self.widget.removeClip(clip)

    def cloneClipNode(self):
        if not self.targetClip: return
        result = []
        for clip in self.widget.treeClips.getSelection():
            cmd = self.doCommand('scene_editor/animator_clone_clip_node',
                                 animator_data=self.targetAnimatorData,
                                 target_node=clip)
            if cmd:
                cloned = cmd.getResult()
                self.widget.addClip(cloned, True)
                result.append(cloned)
        return result

    def onObjectEdited(self, obj):
        if self.targetClip:
            self.delegate.callMethod('view', 'clearPreviewState')
            self.delegate.callMethod('view', 'markClipDirty')
            self.refreshPreview()

    def onSceneSelectionChanged(self, selection, key):
        if key != 'scene': return
        #find animator component
        # self.findTargetAnimator()

    def findTargetAnimator(self):
        target = self.delegate.callMethod('view', 'findTargetAnimator')
        self.setTargetAnimator(target)
        return target

    def checkTargetAnimator(self):
        if not self.targetAnimator:
            alertMessage('No Animator', 'No Animator Selected', 'question')
            return False
        return True

    def addMarker(self):
        if not self.targetClip: return
        cmd = self.doCommand('scene_editor/animator_add_marker',
                             target_clip=self.targetClip,
                             target_pos=self.widget.getCursorPos())
        if cmd:
            marker = cmd.getResult()
            self.widget.addMarker(marker)

    def addKeyForField(self, target, fieldId):
        if not self.checkTargetAnimator(): return

        if not self.targetClip:
            self.addClip()
            # alertMessage( 'No Clip', 'You need to select a Clip first', 'question' )
            # return False
        keys = self.delegate.callMethod('view', 'addKeyForField', target,
                                        fieldId)
        if keys:
            for key in list(keys.values()):
                self.widget.addKey(key, True)

    def addKeyForEvent(self, target, eventId):
        pass

    def addCustomAnimatorTrack(self, target, trackClasId):
        if not self.checkTargetAnimator(): return

        track = self.delegate.callMethod('view', 'addCustomAnimatorTrack',
                                         target, trackClasId)
        if track:
            self.widget.addTrack(track)

    def addKeyForSelectedTracks(self):
        #TODO: command
        selectedTracks = self.widget.getTrackSelection()
        for track in selectedTracks:
            keys = self.delegate.callMethod('view', 'addKeyForSelectedTrack',
                                            track)
            if keys:
                for key in list(keys.values()):
                    self.widget.addKey(key, True)

    def removeSelectedKeys(self):
        #TODO: command
        selectedKeys = self.widget.getKeySelection()
        for key in selectedKeys:
            self.widget.removeKey(key)

    def cloneSelectedKeys(self):
        #TODO: command
        selectedKeys = self.widget.getKeySelection()
        cloned = []
        for key in selectedKeys:
            clonedKey = self.delegate.callMethod('view', 'cloneKey', key)
            if clonedKey:
                cloned.append(clonedKey)

        for clonedKey in cloned:
            keyItem = self.widget.addKey(clonedKey, False)
            keyItem.fitIntoNextEmptySpan()

    def onKeyRemoving(self, key):
        if self.delegate.callMethod('view', 'removeKey', key) != False:
            self.refreshPreview()
            return True

    def onMarkerRemoving(self, marker):
        if self.delegate.callMethod('view', 'removeMarker', marker) != False:
            return True

    def onClipLengthChanging(self, t1):
        if self.delegate.callMethod('view', 'setTargetClipLength',
                                    t1) != False:
            self.refreshPreview()
            return True

    def onTimelineKeyChanged(self, key, pos, length):
        self.delegate.callMethod('view', 'updateTimelineKey', key, pos, length)
        self.refreshPreview()

    def onTimelineKeyCurveValueChanged(self, key, value):
        self.delegate.callMethod('view', 'updateTimelineKeyCurveValue', key,
                                 value)
        self.refreshPreview()

    def onTimelineKeyTweenModeChanged(self, key, mode):
        self.delegate.callMethod('view', 'updateTimelineKeyTweenMode', key,
                                 mode)
        self.refreshPreview()

    def onTimelineKeyBezierPointChanged(self, key, bpx0, bpy0, bpx1, bpy1):
        self.delegate.callMethod('view', 'updateTimelineKeyBezierPoint', key,
                                 bpx0, bpy0, bpx1, bpy1)
        self.refreshPreview()

    def onTimelineMarkerChanged(self, marker, pos):
        self.delegate.callMethod('view', 'updateTimelineMarker', marker, pos)

    def toggleTrackActive(self, track):
        #TODO: command
        # self.module.doCommand( 'scene_editor/toggle_entity_visibility', target = node )
        self.delegate.callMethod('view', 'toggleTrackActive', track)
        self.refreshPreview()
        self.refreshPreview()

    def renameTrack(self, track, name):
        self.delegate.callMethod('view', 'renameTrack', track, name)

    def renameClip(self, clip, name):
        self.delegate.callMethod('view', 'renameClip', clip, name)

    def createClipTreeNode(self, nodeTypeName):
        if not self.targetClip: return None
        contextNode = self.widget.treeClipTree.getFirstSelection()
        cmd = self.doCommand('scene_editor/animator_add_clip_tree_node',
                             context_node=contextNode,
                             parent_tree=self.targetClip,
                             node_type=nodeTypeName)
        node = cmd.getResult()
        if node:
            self.widget.addClipTreeNode(node, True)
        return node

    def listClipTreeNodeTypes(self, typeId, context, option):
        contextNode = self.widget.treeClipTree.getFirstSelection()
        parentTree = self.targetClip
        if not contextNode:
            contextNode = parentTree.getTreeRoot(parentTree)
        res = _MOCK_EDIT.requestAvailAnimatorClipTreeNodeTypes(contextNode)
        entries = []
        for n in list(res.values()):
            entry = (n, n, 'AnimatorClipTreeNode', 'animator_clip_tree/' + n)
            entries.append(entry)
        return entries

    def retargetTrack(self, entity):
        for track in self.widget.treeTracks.getSelection():
            cmd = self.doCommand('scene_editor/animator_retarget_track',
                                 target_track=track,
                                 target_entity=entity,
                                 animator=self.targetAnimator)
            self.widget.treeTracks.refreshNodeContent(track)
        self.delegate.callMethod('view', 'clearPreviewState')
        self.delegate.callMethod('view', 'markClipDirty')
        self.refreshPreview()

    def selectAnimatorEntity(self, com):
        entity = com._entity
        if not entity: return
        self.changeSelection(entity)
        self.findTargetAnimator()

    def openTargetContextMenu(self):
        menu = QtWidgets.QMenu("Animator Target Context")
        itemAddKey = menu.addAction('Relocate Targets')
        itemAddKey.triggered.connect(self.onRelocateTargets)
        menu.exec_(QtGui.QCursor.pos())

    def onRelocateTargets(self):
        if not self.targetAnimator: return
        self.delegate.callMethod('view', 'relocateTargets')

    def onTool(self, tool):
        name = tool.name
        if name == 'find_animator':
            requestSearchView(context='scene',
                              type=_MOCK.Animator,
                              on_selection=self.selectAnimatorEntity)

        elif name == 'change_animator':
            target0 = self.targetAnimator
            target1 = self.findTargetAnimator()
            if (not target0) and (not target1):
                alertMessage('No Animator',
                             'No Animator found in selected entity scope',
                             'question')

        elif name == 'save_data':
            self.saveAnimatorData()

        elif name == 'extra':
            self.openTargetContextMenu()

        elif name == 'add_clip':
            if self.checkTargetAnimator():
                self.addClip()

        elif name == 'add_clip_tree':
            if self.checkTargetAnimator():
                self.addClipTree()

        elif name == 'add_clip_group':
            if self.checkTargetAnimator():
                self.addClipGroup()

        elif name == 'remove_clip':
            if self.checkTargetAnimator():
                self.removeClipNode()

        elif name == 'clone_clip':
            if self.checkTargetAnimator():
                self.cloneClipNode()

        elif name == 'add_track_group':
            group = self.delegate.callMethod('view', 'addTrackGroup')
            if group:
                self.widget.addTrack(group, True)

        elif name == 'remove_track':
            for track in self.widget.treeTracks.getSelection():
                self.delegate.callMethod('view', 'removeTrack', track)
                self.widget.removeTrack(track)
            self.refreshPreview()

        elif name == 'fold_tracks':
            self.widget.treeTracks.foldAllItems()

        elif name == 'unfold_tracks':
            self.widget.treeTracks.expandAllItems()

        elif name == 'locate_target':
            for track in self.widget.treeTracks.getSelection():
                sceneGraphEditor = self.getModule('scenegraph_editor')
                if sceneGraphEditor:
                    targetEntity = self.delegate.callMethod(
                        'view', 'findTrackEntity', track)
                    if targetEntity:
                        sceneGraphEditor.selectEntity(targetEntity,
                                                      focus_tree=True)
                #pass
                return

        elif name == 'retarget':
            requestSearchView(
                info='retarget animator track to...',
                context='scene',
                type='entity',
                multiple_selection=False,
                on_selection=self.retargetTrack,
            )

        elif name == 'add_clip_tree_node':
            requestSearchView(info='adding AnimatorClipTree node...',
                              context='clip_tree_node',
                              type=None,
                              multiple_selection=False,
                              on_selection=self.createClipTreeNode,
                              on_search=self.listClipTreeNodeTypes)

        elif name == 'remove_clip_tree_node':
            for node in self.widget.treeClipTree.getSelection():
                if node.isVirtual(node): continue
                self.doCommand('scene_editor/animator_remove_clip_tree_node',
                               target_node=node)
            self.widget.rebuildClipTree()
            self.refreshPreview()

        #preview
        elif name == 'goto_start':
            self.gotoStart()
        elif name == 'goto_end':
            self.gotoEnd()
        elif name == 'play':
            if tool.getValue():
                self.startPreview()
            else:
                self.stopPreview(False)
        elif name == 'stop':
            self.stopPreview(True)
        elif name == 'play_tree':
            if tool.getValue():
                self.startPreview()
            else:
                self.stopPreview(False)
        elif name == 'stop_tree':
            self.stopPreview(True)
        elif name == 'toggle_repeat':
            self.delegate.callMethod('view', 'togglePreviewRepeat',
                                     tool.getValue())

    def getActiveSceneView(self):
        return self.getModule('scene_view')

    #preview
    def togglePreview(self):
        if self.previewing:
            self.stopPreview()
        else:
            self.startPreview()

    def restartPreview(self):
        self.stopPreview(True)
        self.startPreview()

    def resetPreview(self):
        self.stopPreview(True)

    def startPreview(self):
        # self.saveAnimatorData() #WHY??????
        if self.delegate.callMethod('view', 'startPreview', self.previewTime):
            self.widget.setCursorMovable(False)
            self.previewing = True
            self.findTool('animator_play/play').setValue(True)
            self.findTool('animator_clip_tree/play_tree').setValue(True)
            self.previewTimer.start()
            self.getApp().setMinimalMainLoopBudget()

    def stopPreview(self, rewind=False):
        if self.previewing:
            self.delegate.callMethod('view', 'stopPreview')
            self.getApp().resetMainLoopBudget()
            self.widget.setCursorMovable(True)
            self.previewing = False
            self.findTool('animator_play/play').setValue(False)
            self.findTool('animator_clip_tree/play_tree').setValue(False)
            self.previewTimer.stop()
            signals.emit('entity.modified', None, '')
        if rewind:
            self.gotoStart()

    def onPreviewTimer(self):
        playing, currentTime = self.delegate.callMethod(
            'view', 'doPreviewStep')
        self.previewTime = currentTime
        self.getActiveSceneView().forceUpdate()
        self.widget.setCursorPos(self.previewTime)
        if not playing:
            self.stopPreview()

    def gotoStart(self):
        if self.previewing:
            self.delegate.callMethod('view', 'applyTime', 0)
        else:
            self.widget.setCursorPos(0, True)

    def gotoEnd(self):
        if self.previewing:
            self.delegate.callMethod('view', 'applyTime', 10)
        else:
            self.widget.setCursorPos(10, True)

    def applyTime(self, t, syncCursor=False):
        self.previewTime = self.delegate.callMethod('view', 'applyTime', t)
        # self.getActiveSceneView().scheduleUpdate()
        self.getActiveSceneView().forceUpdate()
        # signals.emit( 'entity.modified',  None , '' )
        if syncCursor:
            self.widget.setCursorPos(t)

    def saveAnimatorData(self):
        if not self.targetAnimator:
            return
        self.delegate.callMethod('view', 'saveData')

    def preSceneSave(self):
        if self.targetAnimator:
            self.delegate.callMethod('view', 'restoreEntityState')

    def postSceneSave(self):
        if self.targetAnimator:
            self.refreshPreview()

    def onSceneClose(self, scene):
        self.setTargetAnimator(None)

    def onPreviewSpeedChange(self, index):
        label, throttle = PREVIEW_SPEED_OPTIONS[index]
        self.delegate.callMethod('view', 'setPreviewThrottle', throttle)

    def refreshPreview(self):
        self.applyTime(self.previewTime)
        self.applyTime(self.previewTime)

    def refreshTimeline(self):
        self.widget.rebuildTimeline()

    def refreshClipList(self):
        self.widget.rebuildClipList()

    def refreshAll(self):
        self.widget.rebuild()
Esempio n. 6
0
class SceneGraphEditor( SceneEditorModule ):
	def __init__(self):
		super( SceneGraphEditor, self ).__init__()
		self.sceneDirty = False
		self.activeSceneNode  = None
		self.refreshScheduled = False
		self.previewing       = False
		self.workspaceState   = None
		
	def getName( self ):
		return 'scenegraph_editor'

	def getDependency( self ):
		return [ 'scene_editor', 'mock' ]

	def onLoad( self ):
		#UI
		self.windowTitle = 'Scenegraph'
		self.container = self.requestDockWindow( 'SceneGraphEditor',
			title     = 'Scenegraph',
			size      = (200,200),
			minSize   = (200,200),
			dock      = 'left'
			)

		#Components
		self.treeFilter = self.container.addWidget(
			GenericTreeFilter(
				self.container
			),
			expanding = False
		)
		self.tree = self.container.addWidget( 
				SceneGraphTreeWidget( 
					self.container,
					sorting  = True,
					editable = True,
					multiple_selection = True,
					drag_mode = 'internal'
				)
			)
		self.treeFilter.setTargetTree( self.tree )
		self.tree.module = self
		self.tool = self.addToolBar( 'scene_graph', self.container.addToolBar() )
		self.delegate = MOAILuaDelegate( self )
		self.delegate.load( getModulePath( 'SceneGraphEditor.lua' ) )

		self.entityCreatorMenu=self.addMenu(
			'main/scene/entity_create',
			{ 'label':'Create Entity' }
			)

		self.componentCreatorMenu=self.addMenu(
			'main/scene/component_create',
			{ 'label':'Create Component' }
			)


		#menu
		self.addMenuItem(
			'main/file/open_scene', 
			dict( label = 'Open Scene', shortcut = 'ctrl+shift+o' )
			)

		self.addMenuItem( 'main/file/close_scene', 
			dict( label = 'Close Scene', shortcut = 'Ctrl+W' )
			)
		self.addMenuItem( 'main/scene/save_scene',
			dict( label = 'Save', shortcut = 'Ctrl+S' )
			)
		self.addMenuItem( 'main/scene/locate_scene_asset',
			dict( label = 'Locate Scene Asset' )
			)

		self.addMenu( 'main/scene/----' )
		
		self.addMenu( 'component_context', dict( label = 'Selected Component' ) )
		self.addMenuItem( 'component_context/remove_component', 
			dict( label = 'Remove' )
			)

		self.addMenuItem( 'component_context/----' )
		
		self.addMenuItem( 'component_context/copy_component', 
			dict( label = 'Copy' )
			)
		self.addMenuItem( 'component_context/paste_component', 
			dict( label = 'Paste Component Here' )
			)
		self.addMenuItem( 'component_context/----' )
		
		self.addMenuItem( 'component_context/move_component_up', 
			dict( label = 'Move Up' )
			)

		self.addMenuItem( 'component_context/move_component_down', 
			dict( label = 'Move Down' )
			)
		

		self.addMenu( 'main/entity', dict( label = 'Entity' ) )
		self.addMenuItem( 'main/entity/add_empty_entity',    dict( label = 'Create Empty', shortcut = 'ctrl+alt+N' ) )
		self.addMenuItem( 'main/entity/add_entity',          dict( label = 'Create',       shortcut = 'ctrl+shift+N' ) )
		self.addMenuItem( 'main/entity/----' )
		self.addMenuItem( 'main/entity/group_entity',        dict( label = 'Group Entites',    shortcut = 'ctrl+G' ) )
		self.addMenuItem( 'main/entity/create_group',        dict( label = 'Create Empty Group',    shortcut = 'ctrl+shift+G' ) )
		self.addMenuItem( 'main/entity/----' )
		self.addMenuItem( 'main/entity/load_prefab',         dict( label = 'Load Prefab', shortcut = 'ctrl+alt+shift+N' ) )
		self.addMenuItem( 'main/entity/load_prefab_in_container', dict( label = 'Load Prefab In Container', shortcut = 'ctrl+shift+=' ) )
		self.addMenuItem( 'main/entity/----' )
		self.addMenuItem( 'main/entity/remove_entity',       dict( label = 'Remove'  ) )
		self.addMenuItem( 'main/entity/clone_entity',        dict( label = 'Clone',  shortcut = 'ctrl+d' ) )
		self.addMenuItem( 'main/entity/----' )
		self.addMenuItem( 'main/entity/add_component',       dict( label = 'Add Component', shortcut = 'ctrl+alt+=' ) )
		self.addMenuItem( 'main/entity/assign_layer',        dict( label = 'Assign Layer', shortcut = 'ctrl+alt+L' ) )
		self.addMenuItem( 'main/entity/toggle_visibility',   dict( label = 'Toggle Visibility', shortcut = 'ctrl+/' ) )
		self.addMenuItem( 'main/entity/freeze_entity_pivot', dict( label = 'Freeze Pivot' ) )

		self.addMenuItem( 'main/entity/----' )
		self.addMenuItem( 'main/find/find_entity', dict( label = 'Find In Scene', shortcut = 'ctrl+f' ) )
		self.addMenuItem( 'main/find/find_entity_in_group', dict( label = 'Find In Group', shortcut = 'ctrl+shift+f' ) )
		self.addMenuItem( 'main/find/find_entity_group', dict( label = 'Find Group', shortcut = 'ctrl+alt+f' ) )

		#Toolbars
		self.addTool( 'scene_graph/select_scene',    label ='Select Scene', icon = 'settings' )
		self.addTool( 'scene_graph/----'  )
		self.addTool( 'scene_graph/create_group',    label ='+ Group', icon = 'add_folder' )
		self.addTool( 'scene_graph/----'  )
		self.addTool( 'scene_graph/make_proto',    label = 'Convert To Proto', icon = 'proto_make' )
		self.addTool( 'scene_graph/create_proto_instance',    label = 'Create Proto Instance', icon = 'proto_instantiate' )
		self.addTool( 'scene_graph/create_proto_container',    label = 'Create Proto Container', icon = 'proto_container' )
		self.addTool( 'scene_graph/----'  )
		self.addTool( 'scene_graph/fold_all',    label = 'F' )
		self.addTool( 'scene_graph/unfold_all',  label = 'U' )
		self.addTool( 'scene_graph/refresh_tree',  label = 'R' )
		# self.addTool( 'scene_graph/load_prefab', label = '+ P' )
		# self.addTool( 'scene_graph/save_prefab', label = '>>P' )

		self.addTool( 'scene/refresh', label = 'refresh', icon='refresh' )

		#SIGNALS
		signals.connect( 'moai.clean',        self.onMoaiClean        )

		signals.connect( 'scene.clear',       self.onSceneClear      )
		signals.connect( 'scene.change',      self.onSceneChange     )

		signals.connect( 'selection.changed', self.onSelectionChanged )
		signals.connect( 'selection.hint',    self.onSelectionHint    )

		signals.connect( 'preview.start',     self.onPreviewStart     )
		signals.connect( 'preview.stop' ,     self.onPreviewStop      )

		# signals.connect( 'animator.start',     self.onAnimatorStart     )
		# signals.connect( 'animator.stop' ,     self.onAnimatorStop      )

		signals.connect( 'entity.added',      self.onEntityAdded      )
		signals.connect( 'entity.removed',    self.onEntityRemoved    )
		signals.connect( 'entity.renamed',    self.onEntityRenamed    )
		signals.connect( 'entity.modified',    self.onEntityModified    )
		signals.connect( 'entity.visible_changed',    self.onEntityVisibleChanged )
		signals.connect( 'entity.pickable_changed',   self.onEntityPickableChanged )


		signals.connect( 'prefab.unlink',     self.onPrefabUnlink    )
		signals.connect( 'prefab.relink',     self.onPrefabRelink    )
		signals.connect( 'proto.unlink',      self.onPrefabUnlink    )
		signals.connect( 'proto.relink',      self.onPrefabRelink    )

		signals.connect( 'app.ready', self.postAppReady )


		signals.connect( 'component.added',   self.onComponentAdded   )
		signals.connect( 'component.removed', self.onComponentRemoved )

		signals.connect( 'project.presave',   self.preProjectSave )

		registerSearchEnumerator( sceneObjectSearchEnumerator )
		registerSearchEnumerator( entityNameSearchEnumerator )
		registerSearchEnumerator( componentNameSearchEnumerator )
		registerSearchEnumerator( layerNameSearchEnumerator )

	def onStart( self ):
		self.refreshCreatorMenu()

	def postAppReady( self ):
		self.openPreviousScene()

	def openPreviousScene( self ):
		previousScene = self.getConfig( 'previous_scene', None )
		if previousScene:
			node = self.getAssetLibrary().getAssetNode( previousScene )
			if node:
				node.edit()

	def onStop( self ):
		if self.activeSceneNode:
			self.setConfig( 'previous_scene', self.activeSceneNode.getNodePath() )
		else:
			self.setConfig( 'previous_scene', False )

	def onSetFocus( self ):
		self.container.show()
		self.container.raise_()
		self.container.setFocus()

	def getActiveScene( self ):
		return self.delegate.safeCallMethod( 'editor', 'getScene' )

	def getActiveSceneRootGroup( self ):
		scene = self.delegate.safeCallMethod( 'editor', 'getScene' )
		if scene:
			return scene.rootGroup
		else:
			return None

	def openScene( self, node, protoNode = None ):
		if self.activeSceneNode == node:			
			if self.getModule('scene_view'):
				self.getModule('scene_view').setFocus()

			if protoNode:
				self.delegate.safeCallMethod( 'editor', 'locateProto', protoNode.getPath() )
				if self.getModule('scene_view'):
					self.getModule('scene_view').focusSelection()
				
		else:
			if not self.closeScene(): return
			if self.getModule('scene_view'):
				self.getModule('scene_view').makeCanvasCurrent()
			self.activeSceneNode = node
			signals.emitNow( 'scene.pre_open', node )
			scene = self.delegate.safeCallMethod( 'editor', 'openScene', node.getPath() )
			if not scene:
				#todo: raise something
				alertMessage( 'error', 
					'%s\n\nfailed to open scene, see console for detailed information.' % node.getPath() )
				return False
			signals.emitNow( 'scene.open', self.activeSceneNode, scene )
			self.setFocus()
			self.editingProtoNode = protoNode		
			self.loadWorkspaceState( False )
			self.delegate.safeCallMethod( 'editor', 'postOpenScene' )

		
	def closeScene( self ):
		if not self.activeSceneNode: return True
		if self.sceneDirty:
			res = requestConfirm( 'scene modified!', 'save scene before close?' )
			if res == True:   #save
				self.saveScene()
			elif res == None: #cancel
				return
			elif res == False: #no save
				pass

		self.markSceneDirty( False )
		self.tree.clear()
		self.getApp().clearCommandStack( 'scene_editor' )
		self.getSelectionManager().removeSelection( self.getActiveScene() )
		signals.emitNow( 'scene.close', self.activeSceneNode )
		self.delegate.safeCallMethod( 'editor', 'closeScene' )		
		self.activeSceneNode = None
		return True

	def onSceneClear( self ):
		# self.tree.clear()
		pass

	def markSceneDirty( self, dirty = True ):
		if not self.previewing:
			self.sceneDirty = dirty

	def saveWorkspaceState( self ):
		self.retainWorkspaceState()
		treeFoldState      = self.workspaceState['tree_state']
		containerFoldState = self.workspaceState['container_state']
		entityLockState    = self.workspaceState['entity_lock_state']
		self.activeSceneNode.setMetaData( 'tree_state', treeFoldState )
		self.activeSceneNode.setMetaData( 'container_state', containerFoldState )
		self.activeSceneNode.setMetaData( 'entity_lock_state', entityLockState )

	def loadWorkspaceState( self, restoreState = True ):
		treeFoldState      = self.activeSceneNode.getMetaData( 'tree_state', None )		
		containerFoldState = self.activeSceneNode.getMetaData( 'container_state', None )		
		entityLockState    = self.activeSceneNode.getMetaData( 'entity_lock_state', None )	
		self.workspaceState = {
			'tree_state'        : treeFoldState,
			'container_state'   : containerFoldState,
			'entity_lock_state' : entityLockState
		}		
		if restoreState: self.restoreWorkspaceState()

	def retainWorkspaceState( self ):
		#tree node foldstate
		treeFoldState =  self.tree.saveFoldState()
		#save introspector foldstate
		introspectorFoldState = self.delegate.safeCallMethod( 'editor', 'saveIntrospectorFoldState' )
		entityLockState = self.delegate.safeCallMethod( 'editor', 'saveEntityLockState' )

		self.workspaceState = {
			'tree_state'        : treeFoldState,
			'container_state'   : introspectorFoldState,
			'entity_lock_state' : entityLockState
		}

	def restoreWorkspaceState( self ):
		if not self.workspaceState: return
		treeState = self.workspaceState.get( 'tree_state', None )
		if treeState:
			self.tree.loadFoldState( treeState )	
		
		containerState = self.workspaceState.get( 'container_state', None )
		if containerState:
			self.delegate.safeCallMethod( 'editor', 'loadIntrospectorFoldState', containerState )
		
		lockState = self.workspaceState.get( 'entity_lock_state', None )
		if lockState:
			self.delegate.safeCallMethod( 'editor', 'loadEntityLockState', lockState )


	def onSceneChange( self ):
		self.tree.hide()
		self.tree.rebuild()
		self.restoreWorkspaceState()
		self.tree.refreshAllContent()
		self.tree.verticalScrollBar().setValue( 0 )
		self.tree.show()
		if self.editingProtoNode:
			self.delegate.safeCallMethod( 'editor', 'locateProto', self.editingProtoNode.getPath() )
			self.editingProtoNode = None
			if self.getModule('scene_view'):
					self.getModule('scene_view').focusSelection()
		
	def saveScene( self ):
		if not self.activeSceneNode: return
		self.markSceneDirty( False )
		signals.emitNow( 'scene.save' )
		self.delegate.safeCallMethod( 'editor', 'saveScene', self.activeSceneNode.getAbsFilePath() )
		signals.emitNow( 'scene.saved' )
		self.saveWorkspaceState()

	def refreshScene( self ):
		if not self.activeSceneNode: return
		if self.previewing: return
		self.refreshScheduled = False
		node = self.activeSceneNode
		self.retainWorkspaceState()
		if self.delegate.safeCallMethod( 'editor', 'refreshScene' ):
			self.restoreWorkspaceState()
		self.refreshCreatorMenu()

	def scheduleRefreshScene( self ):
		if not self.activeSceneNode: return
		self.refreshScheduled = True

	def refreshCreatorMenu( self ):
		def addEntityMenuItem( name ):
			if name == '----': 
				self.entityCreatorMenu.addChild( '----' )
				return
			self.entityCreatorMenu.addChild({
					'name'     : 'create_entity_'+name,
					'label'    : name,
					'command'  : 'scene_editor/create_entity',
					'command_args' : dict( name = name )
				})

		def addComponentMenuItem( name ):
			if name == '----': 
				self.componentCreatorMenu.addChild( '----' )
				return
			self.componentCreatorMenu.addChild({
					'name'     : 'create_component_'+name,
					'label'    : name,
					'command'  : 'scene_editor/create_component',
					'command_args' : dict( name = name )
				})

		self.entityCreatorMenu.clear()
		self.componentCreatorMenu.clear()

		registry = _MOCK.getEntityRegistry()
		#entity
		keys = sorted( registry.keys() )
		addEntityMenuItem( 'Entity' )
		addEntityMenuItem( '----' )
		for entityName in sorted( registry.keys() ):
			if entityName!='Entity': addEntityMenuItem( entityName )

		#component
		registry = _MOCK.getComponentRegistry()
		for comName in sorted( registry.keys() ):
			addComponentMenuItem( comName )

	def needUpdate( self ):
		return True
		
	def onUpdate( self ):
		if self.refreshScheduled:
			self.refreshScene()

	def preProjectSave( self, prj ):
		if self.activeSceneNode:
			_MOCK.game.previewingScene = self.activeSceneNode.getNodePath()

	def onMoaiClean( self ):
		self.tree.clear()

	def onTool( self, tool ):
		name = tool.name
		
		if name == 'fold_all':
			self.tree.foldAllItems()

		elif name == 'unfold_all':
			self.tree.expandAllItems()

		elif name == 'refresh_tree':
			self.tree.rebuild()

		elif name == 'refresh':
			self.scheduleRefreshScene()

		elif name == 'make_proto':
			self.makeProto()

		elif name == 'create_proto_instance':
			requestSearchView( 
				info    = 'select a proto to instantiate',
				context = 'asset',
				type    = 'proto',
				on_selection = 
					lambda obj: 
						self.doCommand( 'scene_editor/create_proto_instance', proto = obj.getNodePath() )
				)

		elif name == 'create_proto_container':
			requestSearchView( 
				info    = 'select a proto to create contained instance',
				context = 'asset',
				type    = 'proto',
				on_selection = 
					lambda obj: 
						self.doCommand( 'scene_editor/create_proto_container', proto = obj.getNodePath() )
				)

		elif name == 'create_group':
			self.doCommand( 'scene_editor/entity_group_create' )

		elif name == 'group_entity':
			self.doCommand( 'scene_editor/group_entities' )
		
		elif name == 'select_scene':
			self.doCommand( 'scene_editor/select_scene' )
			

	def onMenu( self, menu ):
		name = menu.name
		if name == 'close_scene':
			if self.previewing:
				alertMessage( 'Warning', 'Stop previewing before closing scene' )
				return
			self.closeScene()

		elif name == 'open_scene':
			if self.previewing:
				alertMessage( 'Warning', 'Stop previewing before opening scene' )
				return
			requestSearchView( 
				info    = 'select scene to open',
				context = 'asset',
				type    = 'scene',
				on_selection = self.openScene
				)
			
		elif name == 'save_scene':
			if self.previewing:
				alertMessage( 'Warning', 'Stop previewing before saving' )
				return
			self.saveScene()

		elif name == 'locate_scene_asset':
			if self.activeSceneNode:
				assetBrowser = self.getModule( 'asset_browser' )
				if assetBrowser:
					assetBrowser.selectAsset( self.activeSceneNode )

		elif name == 'add_entity':
			requestSearchView( 
				info    = 'select entity type to create',
				context = 'entity_creation',
				on_selection = lambda obj: 
					self.doCommand( 'scene_editor/create_entity', name = obj )
				)

		elif name == 'add_component':
			requestSearchView( 
				info    = 'select component type to create',
				context = 'component_creation',
				on_selection = lambda obj: 
					self.doCommand( 'scene_editor/create_component', name = obj )
				)

		elif name == 'add_empty_entity':
			self.doCommand( 'scene_editor/create_entity', name = 'Entity' )

		elif name == 'load_prefab':
			requestSearchView( 
				info    = 'select a perfab node to instantiate',
				context = 'asset',
				type    = 'prefab',
				on_selection = 
					lambda obj: 
						self.doCommand( 'scene_editor/create_prefab_entity', prefab = obj.getNodePath() )
				)

		elif name == 'load_prefab_in_container':
			requestSearchView( 
				info    = 'select a perfab node to instantiate( PefabContainer )',
				context = 'asset',
				type    = 'prefab',
				on_selection = 
					lambda obj: 
						self.doCommand( 'scene_editor/create_prefab_container', prefab = obj.getNodePath() )
				)

		elif name == 'remove_entity':
			self.doCommand( 'scene_editor/remove_entity' )

		elif name == 'clone_entity':
			self.doCommand( 'scene_editor/clone_entity' )

		elif name == 'find_entity':
			requestSearchView( 
				info    = 'search for entity in current scene',
				context = 'scene',
				type    = 'entity',
				on_selection = lambda x: self.selectEntity( x, focus_tree = True ) ,
				on_test      = self.selectEntity
				)

		elif name == 'find_entity_in_group':
			requestSearchView( 
				info    = 'search for entity in current entity group',
				context = 'scene',
				type    = 'entity_in_group',
				on_selection = lambda x: self.selectEntity( x, focus_tree = True ) ,
				on_test      = self.selectEntity
				)

		elif name == 'find_entity_group':
			requestSearchView( 
				info    = 'search for group in current scene',
				context = 'scene',
				type    = 'group',
				on_selection = lambda x: self.selectEntity( x, focus_tree = True ) ,
				on_test      = self.selectEntity
				)

		elif name == 'create_group':
			self.doCommand( 'scene_editor/entity_group_create' )

		elif name == 'remove_component':
			context = menu.getContext()
			if context:
				self.doCommand( 'scene_editor/remove_component', target = context )

		elif name == 'copy_component':
			context = menu.getContext()
			if context:
				self.doCommand( 'scene_editor/copy_component', target = context )

		elif name == 'assign_layer':
			if not self.tree.getSelection(): return
			requestSearchView( 
				info    = 'select layer to assign',
				context = 'scene_layer',
				type    = _MOCK.Entity,
				on_selection = self.assignEntityLayer
				)

		elif name == 'toggle_visibility':
			self.doCommand( 'scene_editor/toggle_entity_visibility' )

		elif name == 'freeze_entity_pivot':
			self.doCommand( 'scene_editor/freeze_entity_pivot' )


	def onSelectionChanged( self, selection, key ):
		if key != 'scene': return
		if self.tree.syncSelection:
			self.tree.blockSignals( True )
			self.tree.selectNode( None )
			for e in selection:
				self.tree.selectNode( e, add = True)
			self.tree.blockSignals( False )

	def selectEntity( self, target, **option ):
		if option.get( 'focus_tree', False ):
			self.tree.setFocus()
		self.changeSelection( target )

	##----------------------------------------------------------------##
	def renameEntity( self, target, name ):
		#TODO:command pattern
		target.setName( target, name )
		signals.emit( 'entity.modified', target )

	def addEntityNode( self, entity ):
		self.tree.addNode( entity, expanded = False )
		self.tree.setNodeExpanded( entity, False )

	def removeEntityNode( self, entity ):
		self.tree.removeNode( entity )

	def assignEntityLayer( self, layerName ):
		#TODO:command pattern
		if not layerName: return
		self.doCommand( 'scene_editor/assign_layer', target = layerName )

	def onSelectionHint( self, selection ):
		if selection._entity:
			self.changeSelection( selection._entity )			
		else:
			self.changeSelection( selection )

	def onPreviewStart( self ):
		if not self.activeSceneNode: return
		self.retainWorkspaceState()
		self.delegate.safeCallMethod( 'editor', 'retainScene' )
		self.delegate.safeCallMethod( 'editor', 'startScenePreview' )
		self.previewing = True

	def onPreviewStop( self ):
		if not self.activeSceneNode: return
		self.changeSelection( None )
		self.tree.clear()
		self.delegate.safeCallMethod( 'editor', 'stopScenePreview' )
		self.previewing = False
		if self.delegate.safeCallMethod( 'editor', 'restoreScene' ):
			self.restoreWorkspaceState()

	def onAnimatorStart( self ):
		self.retainWorkspaceState()
		self.delegate.safeCallMethod( 'editor', 'retainScene' )

	def onAnimatorStop( self ):
		self.tree.clear()
		self.delegate.safeCallMethod( 'editor', 'clearScene' )
		if self.delegate.safeCallMethod( 'editor', 'restoreScene' ):
			self.restoreWorkspaceState()

	##----------------------------------------------------------------##
	def updateEntityPriority( self ):
		if not self.activeSceneNode: return
		self.markSceneDirty()

	def onEntityRenamed( self, entity, newname ):
		self.tree.refreshNodeContent( entity )
		self.markSceneDirty()

	def onEntityVisibleChanged( self, entity ):
		self.tree.refreshNodeContent( entity )

	def onEntityPickableChanged( self, entity ):
		self.tree.refreshNodeContent( entity )

	def onEntityAdded( self, entity, context = None ):
		if context == 'new':
			self.setFocus()
			pnode = entity.parent
			if pnode:
				self.tree.setNodeExpanded( pnode, True )
			self.tree.setFocus()
			self.tree.editNode( entity )
			self.tree.selectNode( entity )
		signals.emit( 'scene.update' )
		self.markSceneDirty()

	def onEntityRemoved( self, entity ):
		signals.emit( 'scene.update' )
		self.markSceneDirty()

	def onEntityModified( self, entity, context = None ):
		self.markSceneDirty()

	##----------------------------------------------------------------##
	def onComponentAdded( self, com, entity ):
		signals.emit( 'scene.update' )
		self.markSceneDirty()


	def onComponentRemoved( self, com, entity ):
		signals.emit( 'scene.update' )
		self.markSceneDirty()


	##----------------------------------------------------------------##
	def onPrefabUnlink( self, entity ):
		self.tree.refreshNodeContent( entity, updateChildren = True )

	def onPrefabRelink( self, entity ):
		self.tree.refreshNodeContent( entity, updateChildren = True )

	def createPrefab( self, targetPrefab ):
		selection = self.getSelection()
		if not selection: return
		if len( selection ) > 1:
			return alertMessage( 'multiple entities cannot be converted into prefab' )
		target = selection[0]
		self.doCommand( 'scene_editor/create_prefab', 
			entity = target, 
			prefab = targetPrefab.getNodePath(),
			file   = targetPrefab.getAbsFilePath()
		)

	def makeProto( self ):
		selection = self.getSelection()
		if not selection: return
		if len( selection ) > 1:
			return alertMessage( 'multiple entities cannot be converted into Proto' )
		target = selection[0]
		if not target: return
		if requestConfirm( 'convert proto', 'Convert this Entity into Proto?' ):
			self.doCommand( 'scene_editor/make_proto', 
				entity = target
			)
			self.tree.refreshNodeContent( target )

	def createProtoInstance( self ):
		pass


	##----------------------------------------------------------------##
	def onCopyEntity( self ):
		entityGroupData = self.delegate.callMethod( 'editor', 'makeSceneSelectionCopyData' )
		if not entityGroupData: return False
		clip = QtGui.QApplication.clipboard()
		mime = QtCore.QMimeData()
		text = ''
		for s in self.getSelection():
			if text == '':
				text = text + s.name
			else:
				text = text + '\n' + s.name
		mime.setText( text )
		mime.setData( GII_MIME_ENTITY_DATA, entityGroupData.encode('utf-8') )
		clip.setMimeData( mime )
		return True

	def onPasteEntity( self ):
		clip = QtGui.QApplication.clipboard()
		mime = clip.mimeData()
		if mime.hasFormat( GII_MIME_ENTITY_DATA ):
			data = mime.data( GII_MIME_ENTITY_DATA )
			self.doCommand( 'scene_editor/paste_entity',
				data = str(data).decode('utf-8')
			)

	##----------------------------------------------------------------##
	def onCopyComponent( self ):
		entityGroupData = self.delegate.callMethod( 'editor', 'makeEntityCopyData' )
		if not entityGroupData: return False
		clip = QtGui.QApplication.clipboard()
		mime = QtCore.QMimeData()
		text = ''
		for s in self.getSelection():
			if text == '':
				text = text + s.name
			else:
				text = text + '\n' + s.name
		mime.setText( text )
		mime.setData( GII_MIME_ENTITY_DATA, str(entityGroupData) )
		clip.setMimeData( mime )
		return True

	def onPasteComponent( self ):
		clip = QtGui.QApplication.clipboard()
		mime = clip.mimeData()
		if mime.hasFormat( GII_MIME_ENTITY_DATA ):
			data = mime.data( GII_MIME_ENTITY_DATA )
			self.doCommand( 'scene_editor/paste_entity',
				data = str(data)
			)