示例#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))
示例#2
0
class DeployManager(SceneEditorModule):
    def __init__(self):
        super(DeployManager, self).__init__()

    def getName(self):
        return 'deploy_manager'

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

    def onLoad(self):
        self.configPath = self.getProject().getConfigPath(_DEPLOY_CONFIG_FILE)
        #UI
        self.container = self.requestDocumentWindow('DeployManager',
                                                    title='Deployment Manager',
                                                    allowDock=False,
                                                    minSize=(300, 300),
                                                    maxSize=(300, 300))

        #Components
        self.window = self.container.addWidgetFromFile(
            _getModulePath('DeployManager.ui'))

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

        #scene tree
        layout = QtGui.QVBoxLayout()
        self.window.containerSceneTree.setLayout(layout)
        layout.setSpacing(0)
        layout.setMargin(0)

        self.treeScene = DeploySceneTree(self.window.containerSceneTree,
                                         editable=True,
                                         sorting=False,
                                         multiple_selection=False)
        self.treeScene.manager = self
        layout.addWidget(self.treeScene)

        sceneToolbar = QtGui.QToolBar(self.window.containerSceneTree)
        layout.addWidget(sceneToolbar)
        self.sceneTool = self.addToolBar('deploy_scene', sceneToolbar)
        self.addTool('deploy_scene/add_scene', label='add', icon='add')
        self.addTool('deploy_scene/remove_scene',
                     label='remove',
                     icon='remove')
        self.addTool('deploy_scene/move_up_scene', label='up', icon='arrow-up')
        self.addTool('deploy_scene/move_down_scene',
                     label='down',
                     icon='arrow-down')
        self.addTool('deploy_scene/----')
        self.addTool('deploy_scene/edit_scene',
                     label='change target scene',
                     icon='pencil')
        self.addTool('deploy_scene/----')
        self.addTool('deploy_scene/set_entry_scene',
                     label='set as entry',
                     icon='flag')

        #deploy target tree
        layout = QtGui.QVBoxLayout()
        self.window.containerTargetTree.setLayout(layout)
        layout.setSpacing(0)
        layout.setMargin(0)

        self.treeTarget = DeployTargetTree(self.window.containerTargetTree,
                                           editable=True,
                                           multiple_selection=False)
        self.treeTarget.manager = self
        layout.addWidget(self.treeTarget)

        targetToolbar = QtGui.QToolBar(self.window.containerTargetTree)
        layout.addWidget(targetToolbar)
        self.targetTool = self.addToolBar('deploy_target', targetToolbar)
        self.addTool('deploy_target/add_target', label='+')
        self.addTool('deploy_target/remove_target', label='-')

        #target property
        self.propertyTarget = addWidgetWithLayout(
            PropertyEditor(self.window.containerTargetProp))

        #menu
        self.addMenuItem('main/file/----')
        self.addMenuItem('main/file/deploy_manager',
                         dict(label='Deploy Manager', shortcut='F11'))

        self.addMenuItem('main/file/deploy_build',
                         dict(label='Deploy Build', shortcut='Ctrl+F11'))

        # self.container.show()
        self.window.buttonOK.clicked.connect(self.onButtonOK)

        #other
        registerSearchEnumerator(deployTargetSearchEnumerator)

        signals.connect('project.pre_deploy', self.preDeploy)
        signals.connect('project.deploy', self.onDeploy)
        signals.connect('project.post_deploy', self.postDeploy)

    def onStart(self):
        #load config
        self.loadConfig()
        #fill trees
        self.treeTarget.rebuild()
        self.treeScene.rebuild()

    def onStop(self):
        self.saveConfig()

    def loadConfig(self):
        self.delegate.safeCall('loadDeployManagerConfig', self.configPath)

    def saveConfig(self):
        self.delegate.safeCall('saveDeployManagerConfig', self.configPath)

    def getDeployTargetTypes(self):
        registry = self.delegate.safeCall('getDeployTargetTypeRegistry')
        return [name for name in registry.keys()]

    def getDeployTargets(self):
        targets = self.delegate.safeCallMethod('config', 'getTargets')
        return [obj for obj in targets.values()]

    def addDeployTarget(self, targetType):
        target = self.delegate.safeCallMethod('config', 'addDeployTarget',
                                              targetType)
        self.treeTarget.addNode(target)
        self.treeTarget.editNode(target)

    def changeDeployScene(self, targetScene):
        for sceneEntry in self.treeScene.getSelection():
            self.delegate.safeCallMethod('config', 'changeTargetScene',
                                         sceneEntry, targetScene.getPath())
            self.treeScene.refreshNode(sceneEntry)
            return

    def renameDeployTarget(self, target, name):
        target.name = name  #avoid duplicated name

    def addDeployScene(self, sceneNode):
        if not sceneNode: return
        entry = self.delegate.safeCallMethod('config', 'addDeployScene',
                                             sceneNode.getNodePath())
        self.treeScene.addNode(entry)
        self.treeScene.editNode(entry)

    def renameDeployScene(self, entry, alias):
        entry.alias = alias  #TODO: avoid duplicated name

    def getDeployScenes(self):
        scenes = self.delegate.safeCallMethod('config', 'getScenes')
        return [obj for obj in scenes.values()]

    def updateGameConfig(self):
        self.delegate.safeCallMethod('config', 'updateGameConfig')

    def preDeploy(self, context):
        self.updateGameConfig()

    def onDeploy(self, context):
        pass

    def postDeploy(self, context):
        pass

    def onTool(self, tool):
        name = tool.name
        if name == 'add_target':
            requestSearchView(info='select deploy target type',
                              context='deploy_target_type',
                              on_selection=self.addDeployTarget)

        elif name == 'remove_target':
            for target in self.treeTarget.getSelection():
                self.treeTarget.removeNode(target)
                self.delegate.safeCallMethod('config', 'removeDeployTarget',
                                             target)

        elif name == 'add_scene':
            requestSearchView(info='select scene to deploy',
                              context='asset',
                              type='scene',
                              on_selection=self.addDeployScene)

        elif name == 'edit_scene':
            requestSearchView(info='select new target scene ',
                              context='asset',
                              type='scene',
                              on_selection=self.changeDeployScene)

        elif name == 'remove_scene':
            for entry in self.treeScene.getSelection():
                self.delegate.safeCallMethod('config', 'removeDeployScene',
                                             entry)
                self.treeScene.removeNode(entry)
            self.treeScene.refreshAllContent()

        elif name == 'set_entry_scene':
            for entry in self.treeScene.getSelection():
                self.delegate.safeCallMethod('config', 'setEntryScene', entry)
                break
            self.treeScene.refreshAllContent()

        elif name == 'move_up_scene':
            for target in self.treeScene.getSelection():
                self.delegate.safeCallMethod('config', 'moveSceneUp', target)
                self.treeScene.rebuild()
                self.treeScene.selectNode(target)
                break

        elif name == 'move_down_scene':
            for target in self.treeScene.getSelection():
                self.delegate.safeCallMethod('config', 'moveSceneDown', target)
                self.treeScene.rebuild()
                self.treeScene.selectNode(target)
                break

    def onMenu(self, node):
        name = node.name
        if name == 'deploy_manager':
            self.onSetFocus()

        elif name == 'deploy_build':
            app.getProject().deploy()

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

    def onButtonOK(self):
        self.saveConfig()
        self.container.hide()
示例#3
0
class DeployManager( SceneEditorModule ):
	def __init__(self):
		super( DeployManager, self ).__init__()

	def getName( self ):
		return 'deploy_manager'

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

	def onLoad( self ):
		self.configPath = self.getProject().getConfigPath( _DEPLOY_CONFIG_FILE )
		#UI
		self.container = self.requestDocumentWindow( 'DeployManager',
			title     = 'Deployment Manager',
			allowDock = False,
			minSize   = ( 300, 300 ),
			maxSize   = ( 300, 300 )
			)

		#Components
		self.window = self.container.addWidgetFromFile( _getModulePath('DeployManager.ui') )

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

		#scene tree
		layout = QtGui.QVBoxLayout()
		self.window.containerSceneTree.setLayout( layout )
		layout.setSpacing( 0 )
		layout.setMargin( 0 )

		self.treeScene = DeploySceneTree( 
			self.window.containerSceneTree,
			editable = True,
			sorting  = False,
			multiple_selection = False
			)
		self.treeScene.manager = self
		layout.addWidget( self.treeScene )

		sceneToolbar = QtGui.QToolBar( self.window.containerSceneTree )
		layout.addWidget( sceneToolbar )
		self.sceneTool = self.addToolBar( 'deploy_scene', sceneToolbar )
		self.addTool( 'deploy_scene/add_scene',         label = 'add'     ,icon = 'add'    )
		self.addTool( 'deploy_scene/remove_scene',      label = 'remove'  ,icon = 'remove' )
		self.addTool( 'deploy_scene/move_up_scene',     label = 'up'      ,icon = 'arrow-up'     )
		self.addTool( 'deploy_scene/move_down_scene',   label = 'down'    ,icon = 'arrow-down'   )
		self.addTool( 'deploy_scene/----' )
		self.addTool( 'deploy_scene/edit_scene',   label = 'change target scene' ,icon = 'pencil'   )
		self.addTool( 'deploy_scene/----' )
		self.addTool( 'deploy_scene/set_entry_scene',   label = 'set as entry' ,icon = 'flag'   )

		#deploy target tree
		layout = QtGui.QVBoxLayout()
		self.window.containerTargetTree.setLayout( layout )
		layout.setSpacing( 0 )		
		layout.setMargin( 0 )

		self.treeTarget = DeployTargetTree( 
			self.window.containerTargetTree,
			editable = True,
			multiple_selection = False
			)
		self.treeTarget.manager = self
		layout.addWidget( self.treeTarget )

		targetToolbar = QtGui.QToolBar( self.window.containerTargetTree )
		layout.addWidget( targetToolbar )
		self.targetTool = self.addToolBar( 'deploy_target', targetToolbar )
		self.addTool( 'deploy_target/add_target',    label = '+' )
		self.addTool( 'deploy_target/remove_target', label = '-' )

		#target property
		self.propertyTarget = addWidgetWithLayout(
			PropertyEditor( self.window.containerTargetProp )
		)

		#menu
		self.addMenuItem( 'main/file/----' )
		self.addMenuItem( 'main/file/deploy_manager', 
			dict( label = 'Deploy Manager', shortcut = 'F11' )
			)

		self.addMenuItem( 'main/file/deploy_build', 
			dict( label = 'Deploy Build', shortcut = 'Ctrl+F11' )
			)
		
		
		# self.container.show()
		self.window.buttonOK.clicked.connect( self.onButtonOK )

		#other
		registerSearchEnumerator( deployTargetSearchEnumerator )

		signals.connect( 'project.pre_deploy', self.preDeploy )
		signals.connect( 'project.deploy', self.onDeploy )
		signals.connect( 'project.post_deploy', self.postDeploy )


	def onStart( self ):
		#load config
		self.loadConfig()
		#fill trees
		self.treeTarget.rebuild()
		self.treeScene.rebuild()

	def onStop( self ):
		self.saveConfig()

	def loadConfig( self ):
		self.delegate.safeCall( 'loadDeployManagerConfig', self.configPath )

	def saveConfig( self ):
		self.delegate.safeCall( 'saveDeployManagerConfig', self.configPath )		

	def getDeployTargetTypes( self ):
		registry = self.delegate.safeCall( 'getDeployTargetTypeRegistry' )
		return [ name for name in registry.keys() ]

	def getDeployTargets( self ):
		targets =  self.delegate.safeCallMethod( 'config', 'getTargets' )
		return [ obj for obj in targets.values() ]

	def addDeployTarget( self, targetType ):
		target = self.delegate.safeCallMethod( 'config', 'addDeployTarget', targetType )
		self.treeTarget.addNode( target )
		self.treeTarget.editNode( target )

	def changeDeployScene( self, targetScene ):
		for sceneEntry in self.treeScene.getSelection():
			self.delegate.safeCallMethod( 'config', 'changeTargetScene', sceneEntry, targetScene.getPath() )
			self.treeScene.refreshNode( sceneEntry )
			return

	def renameDeployTarget( self, target, name ):
		target.name = name #avoid duplicated name

	def addDeployScene( self, sceneNode ):
		if not sceneNode: return
		entry = self.delegate.safeCallMethod( 'config', 'addDeployScene', sceneNode.getNodePath() )
		self.treeScene.addNode( entry )
		self.treeScene.editNode( entry )

	def renameDeployScene( self, entry, alias ):
		entry.alias = alias #TODO: avoid duplicated name

	def getDeployScenes( self ):
		scenes =  self.delegate.safeCallMethod( 'config', 'getScenes' )
		return [ obj for obj in scenes.values() ]

	def updateGameConfig( self ):
		self.delegate.safeCallMethod( 'config', 'updateGameConfig' )

	def preDeploy( self, context ):
		self.updateGameConfig()

	def onDeploy( self, context ):
		pass

	def postDeploy( self, context ):
		pass

	def onTool( self, tool ):
		name = tool.name
		if name == 'add_target':
			requestSearchView( 
				info    = 'select deploy target type',
				context = 'deploy_target_type',
				on_selection = self.addDeployTarget
				)

		elif name == 'remove_target':
			for target in self.treeTarget.getSelection():
				self.treeTarget.removeNode( target )
				self.delegate.safeCallMethod( 'config', 'removeDeployTarget', target )

		elif name == 'add_scene':
			requestSearchView( 
				info    = 'select scene to deploy',
				context = 'asset',
				type    = 'scene',
				on_selection = self.addDeployScene
				)

		elif name == 'edit_scene':
			requestSearchView( 
				info    = 'select new target scene ',
				context = 'asset',
				type    = 'scene',
				on_selection = self.changeDeployScene
				)

		elif name == 'remove_scene':
			for entry in self.treeScene.getSelection():	
				self.delegate.safeCallMethod( 'config', 'removeDeployScene', entry )
				self.treeScene.removeNode( entry )
			self.treeScene.refreshAllContent()

		elif name == 'set_entry_scene':
			for entry in self.treeScene.getSelection():
				self.delegate.safeCallMethod( 'config', 'setEntryScene', entry )
				break
			self.treeScene.refreshAllContent()

		elif name == 'move_up_scene':
			for target in self.treeScene.getSelection():
				self.delegate.safeCallMethod( 'config', 'moveSceneUp', target )
				self.treeScene.rebuild()
				self.treeScene.selectNode( target )
				break

		elif name == 'move_down_scene':
			for target in self.treeScene.getSelection():
				self.delegate.safeCallMethod( 'config', 'moveSceneDown', target )
				self.treeScene.rebuild()
				self.treeScene.selectNode( target )
				break

	def onMenu( self, node ):
		name = node.name
		if name == 'deploy_manager' :
			self.onSetFocus()

		elif name == 'deploy_build':
			app.getProject().deploy()

	def onSetFocus( self ):
		self.container.show()
		self.container.raise_()
	
	def onButtonOK( self ):
		self.saveConfig()
		self.container.hide()
示例#4
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)
			)