class CommonObjectEditor( ObjectEditor ): #a generic property grid def initWidget( self, container, objectContainer ): self.grid = PropertyEditor(container) self.grid.propertyChanged.connect( self.onPropertyChanged ) return self.grid def setTarget( self, target ): self.target = target self.grid.setTarget( target ) def refresh( self ): self.grid.refreshAll() def unload( self ): self.grid.clear() self.target = None def onPropertyChanged( self, obj, id, value ): pass
class CommonObjectEditor(ObjectEditor): #a generic property grid def initWidget(self, container, objectContainer): self.grid = PropertyEditor(container) self.grid.propertyChanged.connect(self.onPropertyChanged) return self.grid def setTarget(self, target): self.target = target self.grid.setTarget(target) def refresh(self): self.grid.refreshAll() def unload(self): self.grid.clear() self.target = None def onPropertyChanged(self, obj, id, value): pass
class SerializableAssetPreviewer(AssetPreviewer): def createWidget(self,container): self.scroll = scroll = QtGui.QScrollArea( container ) scroll.verticalScrollBar().setStyleSheet('width:4px') scroll.setWidgetResizable( True ) self.editor = PropertyEditor( scroll ) self.editor.setReadonly() scroll.setWidget( self.editor ) return self.scroll def accept(self, assetNode): return assetNode.getManager().getMetaType() in [ 'serializable' ] def onStart(self, selection): data = _MOCK.loadAsset( selection.getPath() ) if data: asset, luaAssetNode = data self.editor.setTarget( asset ) else: self.editor.setTarget( None ) def onStop(self): self.editor.setTarget( None )
class SQScriptEditorWidget(QtGui.QWidget): def __init__(self, *args, **kwargs): super(SQScriptEditorWidget, self).__init__(*args, **kwargs) self.owner = None self.targetRoutine = None self.targetNode = None self.currentNodeEditor = None self.initData() self.initUI() def initData(self): self.routineEditors = {} def initUI(self): self.setObjectName("SQScriptEditorWidget") self.ui = SQScriptEditorForm() self.ui.setupUi(self) self.listRoutine = addWidgetWithLayout(RoutineListWidget(self.ui.containerRoutine)) self.listRoutine.owner = self self.toolbarMain = wrapToolBar( "main", addWidgetWithLayout(QtGui.QToolBar(self.ui.containerToolbar)), owner=self ) self.toolbarMain.addTools( [ dict(name="save", label="Save", icon="save"), dict(name="locate", label="Locate", icon="search-2"), "----", dict(name="add_routine", label="Add Routine", icon="add"), dict(name="del_routine", label="Remove Routine", icon="remove"), ] ) self.treeRoutineNode = addWidgetWithLayout(RoutineNodeTreeWidget(self.ui.containerContent)) self.treeRoutineNode.owner = self self.scrollProperty = scroll = addWidgetWithLayout(QtGui.QScrollArea(self.ui.containerProperty)) scroll.verticalScrollBar().setStyleSheet("width:4px") scroll.setWidgetResizable(True) self.propertyEditor = PropertyEditor(scroll) scroll.setWidget(self.propertyEditor) self.propertyEditor.propertyChanged.connect(self.onPropertyChanged) # setup shortcuts # self.addShortcut( self.treeRoutineNode, 'Tab', self.promptAddNode ) self.addShortcut(self.treeRoutineNode, "Return", self.focusNodeEditor) self.addShortcut(self, "Ctrl+Return", self.promptAddNode) self.addShortcut(self, "Escape", self.focusContentTree) # self.addShortcut( self, 'Ctrl+Return', self.focusContentTree ) # self.addShortcut( self, 'Ctrl+1', self.focusContentTree ) self.nodeEditorContainer = self.ui.containerEditor editorContainerLayout = QtGui.QVBoxLayout(self.nodeEditorContainer) editorContainerLayout.setSpacing(0) editorContainerLayout.setMargin(0) def addShortcut(self, contextWindow, keySeq, target, *args, **option): contextWindow = contextWindow or self shortcutContext = Qt.WidgetWithChildrenShortcut action = QtGui.QAction(contextWindow) action.setShortcut(QtGui.QKeySequence(keySeq)) action.setShortcutContext(shortcutContext) contextWindow.addAction(action) if isinstance(target, str): # command def onAction(): self.doCommand(target, **option) action.triggered.connect(onAction) else: # callable def onAction(): target(*args, **option) action.triggered.connect(onAction) return action def setTargetRoutine(self, routine): self.targetRoutine = routine self.propertyEditor.setTarget(self.targetRoutine) self.treeRoutineNode.rebuild() def getTargetRoutine(self): return self.targetRoutine def setTargetNode(self, node): self.targetNode = node self.propertyEditor.setTarget(node) # apply node editor clasName = node.getClassName(node) self.nodeEditorContainer.hide() if self.currentNodeEditor: self.currentNodeEditor.onUnload(self.currentNodeEditor.getTargetNode()) self.nodeEditorContainer.layout().takeAt(0) self.currentNodeEditor.setParent(None) pushSQNodeEditorToCache(self.currentNodeEditor) self.currentNodeEditor = None editor = requestSQNodeEditor(clasName) if editor: self.currentNodeEditor = editor editor.setParent(self.nodeEditorContainer) self.nodeEditorContainer.layout().addWidget(editor) editor.parentEditor = self editor.setTargetNode(node) editor.onLoad(node) editor.onRefresh(node) self.nodeEditorContainer.show() def getTargetNode(self): return self.targetNode def rebuild(self): self.listRoutine.rebuild() self.treeRoutineNode.rebuild() script = self.getTargetScript() firstRoutine = script.getRoutines(script)[1] # lua if firstRoutine: self.listRoutine.selectNode(firstRoutine) def getRoutineEditor(self, routine): return self.routineEditors.get(routine, None) def getTargetScript(self): return self.owner.getTargetScript() def getRoutines(self): targetScript = self.getTargetScript() if not targetScript: return [] else: routines = targetScript.routines return [routine for routine in routines.values()] def getRoutineName(self, routine): return routine.getName() # TODO def addRoutine(self): script = self.getTargetScript() newRoutine = script.addRoutine(script) # lua self.listRoutine.addNode(newRoutine) self.listRoutine.editNode(newRoutine) self.listRoutine.selectNode(newRoutine) def delRoutine(self): script = self.getTargetScript() for routine in self.listRoutine.getSelection(): script.removeRoutine(script, routine) # lua self.listRoutine.removeNode(routine) def renameRoutine(self, routine, name): routine.setName(routine, name) def promptAddNode(self): requestSearchView( info="adding SQScript node...", context="sq_script_editor", type=None, multiple_selection=False, on_selection=self.createNode, on_search=self.listNodeTypes, ) def cloneNode(self): pass def getContextNode(self): context = self.treeRoutineNode.getFirstSelection() if not context: context = self.targetRoutine.getRootNode(self.targetRoutine) return context def createNode(self, nodeTypeName): contextNode = self.getContextNode() node = _MOCK_EDIT.createSQNode(nodeTypeName, contextNode, self.targetRoutine) if node: self.treeRoutineNode.rebuild() self.treeRoutineNode.selectNode(node) def listNodeTypes(self, typeId, context, option): contextNode = self.getContextNode() res = _MOCK_EDIT.requestAvailSQNodeTypes(contextNode) entries = [] for n in res.values(): entry = (n, n, "SQ Node", "sq_script/" + n) entries.append(entry) return entries def onRoutineSelectionChanged(self): for routine in self.listRoutine.getSelection(): self.setTargetRoutine(routine) break # self.listRoutine.removeNode( routine) def onNodeSelectionChanged(self): for node in self.treeRoutineNode.getSelection(): self.setTargetNode(node) break # self.listRoutine.removeNode( routine) def onNodeTreeDeletePressed(self): selection = self.treeRoutineNode.getSelection() for node in selection: if node.isBuiltin(node): continue parent = node.getParent(node) if parent: parent.removeChild(parent, node) # lua self.treeRoutineNode.removeNode(node) def onPropertyChanged(self, obj, fid, value): if isMockInstance(obj, "SQNode"): self.treeRoutineNode.refreshNodeContent(obj) if self.currentNodeEditor: self.currentNodeEditor.onRefresh(obj) elif isMockInstance(obj, "SQRoutine"): pass def focusContentTree(self): self.treeRoutineNode.setFocus() def focusNodeEditor(self): if self.currentNodeEditor: self.currentNodeEditor.setFocus() def onTool(self, tool): name = tool.getName() if name == "add_routine": self.addRoutine() elif name == "del_routine": self.delRoutine() elif name == "save": self.owner.saveAsset() elif name == "locate": self.owner.locateAsset()
class EffectEditor(SceneEditorModule): def __init__(self): super(EffectEditor, self).__init__() self.editingAsset = None self.editConfig = None self.previewing = False self.refreshFlag = -1 self.scriptModifyFlag = -1 self.refreshingScript = False def getName(self): return 'effect_editor' def getDependency(self): return ['qt', 'mock'] def onLoad(self): self.windowTitle = 'Effect System Editor' self.container = self.requestDocumentWindow( 'MockEffectEditor', title='Effect Editor', size=(500, 300), minSize=(500, 300), # allowDock = False ) self.tool = self.addToolBar('effect_editor', self.container.addToolBar()) self.addTool('effect_editor/save', label='Save', icon='save') self.addTool('effect_editor/----') self.addTool('effect_editor/remove_node', icon='remove') self.addTool('effect_editor/clone_node', icon='clone') self.addTool('effect_editor/add_system', label='+System') self.addTool('effect_editor/add_child', label='+Child') self.addTool('effect_editor/----') self.addTool('effect_editor/add_move', label='+Move') self.addTool('effect_editor/----') self.addTool('effect_editor/move_up', icon='arrow-up') self.addTool('effect_editor/move_down', icon='arrow-down') self.addTool('effect_editor/----') self.addTool('effect_editor/toggle_preview', icon='play', type='check') self.window = window = self.container.addWidgetFromFile( _getModulePath('EffectEditor.ui')) self.canvas = addWidgetWithLayout( MOAIEditCanvas(window.containerPreview)) window.setFocusProxy(self.canvas) self.tree = addWidgetWithLayout( EffectNodeTreeWidget(window.containerTree)) self.tree.module = self propLayout = QtGui.QVBoxLayout() window.containerEditor.setLayout(propLayout) propLayout.setSpacing(2) propLayout.setMargin(0) self.nodePropEditor = PropertyEditor(window.containerEditor) self.paramPropEditor = PropertyEditor(window.containerEditor) propLayout.addWidget(self.nodePropEditor) propLayout.addWidget(self.paramPropEditor) self.paramPropEditor.setVisible(False) window.containerScript.setVisible(False) self.codebox = codebox = addWidgetWithLayout( CodeEditor(window.containerScript)) settingData = jsonHelper.tryLoadJSON( self.getApp().findDataFile('script_settings.json')) # if settingData: # codebox.applySetting( settingData ) self.editingTarget = None #ShortCuts self.addShortcut(self.container, '+', self.addSystem) self.addShortcut(self.container, '=', self.promptAddChild) self.addShortcut(self.container, '-', self.removeNode) # self.addShortcut( self.container, ']', self.moveNodeUp ) # self.addShortcut( self.container, '[', self.moveNodeDown ) self.addShortcut(self.container, 'ctrl+D', self.cloneNode) self.addShortcut(self.container, 'f5', self.togglePreview) self.addShortcut(self.container, 'f4', self.restartPreview) #Signals self.nodePropEditor.propertyChanged.connect(self.onNodePropertyChanged) self.paramPropEditor.propertyChanged.connect( self.onParamPropertyChanged) self.codebox.textChanged.connect(self.onScriptChanged) def onStart(self): self.canvas.loadScript(_getModulePath('EffectEditor.lua')) def onSetFocus(self): self.container.show() self.container.raise_() self.container.activateWindow() self.container.setFocus() def openAsset(self, node): self.setFocus() if self.editingAsset == node: return self.editConfig = self.canvas.safeCallMethod('editor', 'open', node.getNodePath()) self.editingAsset = node self.container.setDocumentName(node.getNodePath()) self.tree.rebuild() self.selectEditTarget(None) self.checkScriptTimer = self.container.startTimer(3, self.checkScript) self.checkRefershTimer = self.container.startTimer( 10, self.checkRefresh) def saveAsset(self): if not self.editingAsset: return self.canvas.safeCallMethod('editor', 'save', self.editingAsset.getAbsFilePath()) def closeAsset(self): self.checkScriptTimer.stop() self.checkRefershTimer.stop() def getEditingConfig(self): return self.editConfig def selectEditTarget(self, node): self.editingTarget = node self.nodePropEditor.setTarget(node) #check tool button state # isSystem = isMockInstance( node, 'EffectNodeParticleSystem' ) if isMockInstance(node, 'EffectNodeParticleState'): self.window.containerScript.setVisible(True) self.paramPropEditor.setVisible(True) self.updateScript() elif isMockInstance(node, 'EffectScript'): self.window.containerScript.setVisible(True) self.paramPropEditor.setVisible(False) self.paramPropEditor.setTarget(None) self.updateScript() else: self.window.containerScript.setVisible(False) self.paramPropEditor.setVisible(False) self.paramPropEditor.setTarget(None) self.canvas.callMethod('editor', 'selectEditTarget') def renameNode(self, node, name): node['name'] = name if node == self.editingTarget: self.nodePropEditor.refreshField('name') def postCreateNode(self, node): self.tree.addNode(node) self.tree.selectNode(node) self.tree.editNode(node) self.markNodeDirty(node) def listParticleSystemChildTypes(self, typeId, context, option): res = self.canvas.callMethod('editor', 'requestAvailSubNodeTypes', self.tree.getFirstSelection()) entries = [] for n in res.values(): entry = (n, n, 'FX Node', 'effect/' + n) entries.append(entry) return entries def addChildNode(self, childType): node = self.canvas.callMethod('editor', 'addChildNode', self.editingTarget, childType) self.postCreateNode(node) def removeNode(self): if self.editingTarget: self.markNodeDirty(self.editingTarget) self.canvas.callMethod('editor', 'removeNode', self.editingTarget) self.tree.removeNode(self.editingTarget) def promptAddChild(self): requestSearchView(context='effect_editor', type=None, multiple_selection=False, on_selection=self.addChildNode, on_search=self.listParticleSystemChildTypes) def cloneNode(self): if self.editingTarget: node = self.canvas.callMethod('editor', 'cloneNode', self.editingTarget) self.postCreateNode(node) def addSystem(self): sys = self.canvas.callMethod('editor', 'addSystem') self.postCreateNode(sys) def addMove(self): sys = self.canvas.callMethod('editor', 'addMove') self.postCreateNode(sys) def updateScript(self): self.refreshingScript = True stateNode = self.editingTarget self.codebox.setPlainText(stateNode.script or '', 'text/x-lua') self.updateParamProxy() self.refreshingScript = False #TODO: param def updateParamProxy(self): if isMockInstance(self.editingTarget, 'EffectNodeParticleState'): stateNode = self.editingTarget self.paramProxy = stateNode.buildParamProxy(stateNode) self.paramPropEditor.setTarget(self.paramProxy) def onScriptChanged(self): if not self.editingTarget: return if self.refreshingScript: return src = self.codebox.toPlainText() stateNode = self.editingTarget stateNode.script = src self.scriptModifyFlag = 1 def togglePreview(self): self.previewing = not self.previewing if self.previewing: self.canvas.callMethod('editor', 'startPreview') else: self.canvas.callMethod('editor', 'stopPreview') self.checkTool('effect_editor/toggle_preview', self.previewing) def restartPreview(self): if self.previewing: self.togglePreview() self.togglePreview() def onTool(self, tool): name = tool.name if name == 'save': self.saveAsset() elif name == 'add_system': self.addSystem() elif name == 'add_move': self.addMove() elif name == 'add_child': self.promptAddChild() elif name == 'remove_node': self.removeNode() elif name == 'clone_node': self.cloneNode() elif name == 'toggle_preview': self.togglePreview() def onNodePropertyChanged(self, node, id, value): if id == 'name': self.tree.refreshNodeContent(node) else: self.markNodeDirty(self.editingTarget) def onParamPropertyChanged(self, node, id, value): self.markNodeDirty(self.editingTarget) def markNodeDirty(self, node): self.canvas.callMethod('editor', 'markDirty', node) self.refreshFlag = 1 def checkScript(self): if self.scriptModifyFlag == 0: self.updateParamProxy() self.markNodeDirty(self.editingTarget) if self.scriptModifyFlag >= 0: self.scriptModifyFlag -= 1 def checkRefresh(self): if self.refreshFlag > 0: self.canvas.callMethod('editor', 'refreshPreview') self.refreshFlag = 0
class SQScriptEditorWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): super(SQScriptEditorWidget, self).__init__(*args, **kwargs) self.owner = None self.targetRoutine = None self.targetNode = None self.currentNodeEditor = None self.initData() self.initUI() def initData(self): self.routineEditors = {} def initUI(self): self.setObjectName('SQScriptEditorWidget') self.ui = SQScriptEditorForm() self.ui.setupUi(self) self.listRoutine = addWidgetWithLayout( RoutineListWidget(self.ui.containerRoutine)) self.listRoutine.owner = self self.toolbarMain = wrapToolBar( 'main', addWidgetWithLayout(QtWidgets.QToolBar(self.ui.containerToolbar)), owner=self) self.toolbarMain.addTools([ dict(name='save', label='Save', icon='save'), dict(name='locate', label='Locate', icon='search'), '----', dict(name='add_routine', label='Add Routine', icon='add'), dict(name='del_routine', label='Remove Routine', icon='remove'), ]) self.treeRoutineNode = addWidgetWithLayout( RoutineNodeTreeWidget(self.ui.containerContent)) self.treeRoutineNode.owner = self self.scrollProperty = scroll = addWidgetWithLayout( QtWidgets.QScrollArea(self.ui.containerProperty)) scroll.verticalScrollBar().setStyleSheet('width:4px') scroll.setWidgetResizable(True) self.propertyEditor = PropertyEditor(scroll) scroll.setWidget(self.propertyEditor) self.propertyEditor.propertyChanged.connect(self.onPropertyChanged) #setup shortcuts # self.addShortcut( self.treeRoutineNode, 'Tab', self.promptAddNode ) self.addShortcut(self.treeRoutineNode, 'Return', self.focusNodeEditor) self.addShortcut(self, 'Ctrl+Return', self.promptAddNode) self.addShortcut(self, 'Escape', self.focusContentTree) # self.addShortcut( self, 'Ctrl+Return', self.focusContentTree ) # self.addShortcut( self, 'Ctrl+1', self.focusContentTree ) self.nodeEditorContainer = self.ui.containerEditor editorContainerLayout = QtWidgets.QVBoxLayout(self.nodeEditorContainer) editorContainerLayout.setSpacing(0) editorContainerLayout.setContentsMargins(0, 0, 0, 0) def addShortcut(self, contextWindow, keySeq, target, *args, **option): contextWindow = contextWindow or self shortcutContext = Qt.WidgetWithChildrenShortcut action = QtWidgets.QAction(contextWindow) action.setShortcut(QtGui.QKeySequence(keySeq)) action.setShortcutContext(shortcutContext) contextWindow.addAction(action) if isinstance(target, str): #command def onAction(): self.doCommand(target, **option) action.triggered.connect(onAction) else: #callable def onAction(): target(*args, **option) action.triggered.connect(onAction) return action def setTargetRoutine(self, routine): self.targetRoutine = routine self.propertyEditor.setTarget(self.targetRoutine) self.treeRoutineNode.rebuild() def getTargetRoutine(self): return self.targetRoutine def setTargetNode(self, node): self.targetNode = node self.propertyEditor.setTarget(node) #apply node editor clasName = node.getClassName(node) self.nodeEditorContainer.hide() if self.currentNodeEditor: self.currentNodeEditor.onUnload( self.currentNodeEditor.getTargetNode()) self.nodeEditorContainer.layout().takeAt(0) self.currentNodeEditor.setParent(None) pushSQNodeEditorToCache(self.currentNodeEditor) self.currentNodeEditor = None editor = requestSQNodeEditor(clasName) if editor: self.currentNodeEditor = editor editor.setParent(self.nodeEditorContainer) self.nodeEditorContainer.layout().addWidget(editor) editor.parentEditor = self editor.setTargetNode(node) editor.onLoad(node) editor.onRefresh(node) self.nodeEditorContainer.show() def getTargetNode(self): return self.targetNode def rebuild(self): self.listRoutine.rebuild() self.treeRoutineNode.rebuild() script = self.getTargetScript() firstRoutine = script.getRoutines(script)[1] #lua if firstRoutine: self.listRoutine.selectNode(firstRoutine) def getRoutineEditor(self, routine): return self.routineEditors.get(routine, None) def getTargetScript(self): return self.owner.getTargetScript() def getRoutines(self): targetScript = self.getTargetScript() if not targetScript: return [] else: routines = targetScript.routines return [routine for routine in list(routines.values())] def getRoutineName(self, routine): return routine.getName() #TODO def addRoutine(self): script = self.getTargetScript() newRoutine = script.addRoutine(script) #lua self.listRoutine.addNode(newRoutine) self.listRoutine.editNode(newRoutine) self.listRoutine.selectNode(newRoutine) def delRoutine(self): script = self.getTargetScript() for routine in self.listRoutine.getSelection(): script.removeRoutine(script, routine) #lua self.listRoutine.removeNode(routine) def renameRoutine(self, routine, name): routine.setName(routine, name) def promptAddNode(self): requestSearchView(info='adding SQScript node...', context='sq_script_editor', type=None, multiple_selection=False, on_selection=self.createNode, on_search=self.listNodeTypes) def cloneNode(self): pass def getContextNode(self): context = self.treeRoutineNode.getFirstSelection() if not context: context = self.targetRoutine.getRootNode(self.targetRoutine) return context def createNode(self, nodeTypeName): contextNode = self.getContextNode() node = _MOCK_EDIT.createSQNode(nodeTypeName, contextNode, self.targetRoutine) if node: self.treeRoutineNode.rebuild() self.treeRoutineNode.selectNode(node) def listNodeTypes(self, typeId, context, option): contextNode = self.getContextNode() res = _MOCK_EDIT.requestAvailSQNodeTypes(contextNode) entries = [] for n in list(res.values()): entry = (n, n, 'SQ Node', 'sq_script/' + n) entries.append(entry) return entries def onRoutineSelectionChanged(self): for routine in self.listRoutine.getSelection(): self.setTargetRoutine(routine) break # self.listRoutine.removeNode( routine) def onNodeSelectionChanged(self): for node in self.treeRoutineNode.getSelection(): self.setTargetNode(node) break # self.listRoutine.removeNode( routine) def onNodeTreeDeletePressed(self): selection = self.treeRoutineNode.getSelection() for node in selection: if node.isBuiltin(node): continue parent = node.getParent(node) if parent: parent.removeChild(parent, node) #lua self.treeRoutineNode.removeNode(node) def onPropertyChanged(self, obj, fid, value): if isMockInstance(obj, 'SQNode'): self.treeRoutineNode.refreshNodeContent(obj) if self.currentNodeEditor: self.currentNodeEditor.onRefresh(obj) elif isMockInstance(obj, 'SQRoutine'): pass def focusContentTree(self): self.treeRoutineNode.setFocus() def focusNodeEditor(self): if self.currentNodeEditor: self.currentNodeEditor.setFocus() def onTool(self, tool): name = tool.getName() if name == 'add_routine': self.addRoutine() elif name == 'del_routine': self.delRoutine() elif name == 'save': self.owner.saveAsset() elif name == 'locate': self.owner.locateAsset()
class SerializableEditorInstance(object): def __init__(self, id): self.id = id self.targetNode = None self.targetAsset = None self.container = None self.body = None self.dataDirty = False def createWidget(self, container): self.container = container self.container.setCallbackOnClose(self.onClose) self.toolbar = self.container.addToolBar() self.toolbar.setIconSize(QtCore.QSize(16, 16)) self.actionSave = self.toolbar.addAction(getIcon('save'), 'Save') self.actionLocate = self.toolbar.addAction(getIcon('search-2'), 'Locate') self.actionSave.setEnabled(False) self.actionSave.triggered.connect(self.onActionSave) self.actionLocate.triggered.connect(self.onActionLocate) self.window = window = self.container.addWidgetFromFile( _getModulePath('SerializableEditor.ui')) self.scroll = scroll = addWidgetWithLayout( QtGui.QScrollArea(window.containerProperty), window.containerProperty) scroll.verticalScrollBar().setStyleSheet('width:4px') scroll.setWidgetResizable(True) self.propertyEditor = PropertyEditor(scroll) scroll.setWidget(self.propertyEditor) self.propertyEditor.propertyChanged.connect(self.onPropertyChanged) def setTarget(self, targetNode): self.targetNode = targetNode data = _MOCK.loadAsset(targetNode.getPath()) if data: asset, luaAssetNode = data self.targetAsset = asset self.propertyEditor.setTarget(asset) else: self.targetAsset = None self.propertyEditor.setTarget(None) def refresh(self): self.propertyEditor.refreshAll() def hasTarget(self, targetNode): return self.targetNode == targetNode def resetData(self): if self.targetAsset and self.targetNode: path = self.targetNode.getAbsFilePath() _MOCK.deserializeFromFile(self.targetAsset, path) self.actionSave.setEnabled(False) self.dataDirty = False def saveData(self): if self.targetAsset: path = self.targetNode.getAbsFilePath() _MOCK.serializeToFile(self.targetAsset, path) self.actionSave.setEnabled(False) self.dataDirty = False def onActionSave(self): self.saveData() def onActionLocate(self): if self.targetNode: browser = app.getModule('asset_browser') if browser: browser.locateAsset(self.targetNode) def onPropertyChanged(self, id, value): self.dataDirty = True self.actionSave.setEnabled(True) def onClose(self): if self.dataDirty: res = requestConfirm('data modified!', 'save scene before close?') if res == None: #cancel return False elif res == True: #save self.onActionSave() elif res == False: #no save self.resetData() self.parentModule.removeInstance(self) return True
class EntityEditor( ObjectEditor, SceneObjectEditorMixin ): #a generic property grid def initWidget( self, container, objectContainer ): self.header = EntityHeader( container ) self.grid = PropertyEditor( self.header ) self.header.layout().addWidget( self.grid ) self.grid.setContext( 'scene_editor' ) self.grid.propertyChanged.connect( self.onPropertyChanged ) self.header.buttonEdit .clicked .connect ( self.onEditProto ) self.header.buttonGoto .clicked .connect ( self.onGotoProto ) self.header.buttonUnlink .clicked .connect ( self.onUnlinkProto ) self.initFieldContextMenu( self.grid ) self.initFoldState() self.initAnimatorButton() return self.header def setTarget( self, target ): if not target.components: return introspector = self.getIntrospector() self.target = target self.grid.setTarget( target ) if isMockInstance( target, 'Entity' ): if target['__proto_history']: self.container.setProperty( 'proto', True ) else: self.container.setProperty( 'proto', False ) self.container.repolish() #setup prefab tool protoState = target['PROTO_INSTANCE_STATE'] if protoState: self.header.containerPrefab.show() protoPath = getProtoPath( target ) self.header.labelPrefabPath.setText( protoPath ) else: self.header.containerPrefab.hide() #add component editors for com in target.getSortedComponentList( target ).values(): if com.FLAG_INTERNAL: continue editor = introspector.addObjectEditor( com, context_menu = 'component_context', editor_class = ComponentEditor ) container = editor.getContainer() self.buttonAddComponent = buttonAddComponent = QtGui.QToolButton() buttonAddComponent.setObjectName( 'ButtonIntrospectorAddComponent' ) buttonAddComponent.setText( 'Add Component ...' ) buttonAddComponent.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed ) buttonAddComponent.clicked.connect( self.onButtonAddComponent ) introspector.addWidget( self.buttonAddComponent ) self.restoreFoldState() self.updateAnimatorButton() def onButtonAddComponent( self ): requestSearchView( info = 'select component type to create', context = 'component_creation', on_selection = lambda obj: app.doCommand( 'scene_editor/create_component', name = obj ) ) def onPropertyChanged( self, obj, id, value ): if _MOCK.markProtoInstanceOverrided( obj, id ): self.grid.refershFieldState( id ) if id == 'name': signals.emit( 'entity.renamed', obj, value ) elif id == 'layer': signals.emit( 'entity.renamed', obj, value ) elif id == 'visible': signals.emit( 'entity.visible_changed', obj ) signals.emit( 'entity.modified', obj, 'introspector' ) def onPropertyReset( self, obj, id ): self.grid.refershFieldState( id ) if id == 'name': signals.emit( 'entity.renamed', obj, obj.getName( obj ) ) elif id == 'layer': signals.emit( 'entity.renamed', obj, obj.getName( obj ) ) elif id == 'visible': signals.emit( 'entity.visible_changed', obj ) signals.emit( 'entity.modified', obj, 'introspector' ) def onGotoProto( self ): assetBrowser = app.getModule( 'asset_browser' ) if assetBrowser: assetBrowser.locateAsset( getProtoPath(self.target) ) def onEditProto( self ): path = getProtoPath( self.target ) assetNode = app.getAssetLibrary().getAssetNode( path ) if assetNode: assetNode.edit() def onUnlinkProto( self ): app.doCommand( 'scene_editor/unlink_proto', entity = self.target ) def onUnlinkPrefab( self ): app.doCommand( 'scene_editor/unlink_prefab', entity = self.target ) self.header.containerPrefab.hide() def onPushPrefab( self ): app.doCommand( 'scene_editor/push_prefab', entity = self.target ) def onPullPrefab( self ): app.doCommand( 'scene_editor/pull_prefab', entity = self.target ) def refresh( self ): self.grid.refreshAll() def unload( self ): self.target = None self.grid.clear()
class AnimatorWidget( QtGui.QWidget, AnimatorWidgetUI ): """docstring for AnimatorWidget""" def __init__( self, *args, **kwargs ): super(AnimatorWidget, self).__init__( *args, **kwargs ) self.setupUi( self ) self.treeTracks = AnimatorTrackTree( parent = self ) self.timeline = AnimatorTimelineWidget( parent = self ) self.treeClips = AnimatorClipListTree( parent = self ) self.propertyEditor = PropertyEditor( self ) self.propertyEditor.propertyChanged.connect( self.onPropertyChanged ) self.propertyEditor.objectChanged.connect( self.onPropertyTargetChanged ) # self.treeTracks.setRowHeight( _TRACK_SIZE ) self.treeTracks.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.treeTracks.verticalScrollBar().setStyleSheet('width:4px') self.treeTracks.setHorizontalScrollBarPolicy( Qt.ScrollBarAlwaysOff ) self.toolbarTarget = QtGui.QToolBar() self.toolbarClips = QtGui.QToolBar() self.toolbarPlay = QtGui.QToolBar() self.toolbarTrack = QtGui.QToolBar() self.toolbarEdit = self.timeline.toolbarEdit self.timeline.toolbuttonCurveModeLinear .setIcon( getIcon( 'curve_mode_linear' ) ) self.timeline.toolbuttonCurveModeConstant .setIcon( getIcon( 'curve_mode_constant' ) ) self.timeline.toolbuttonCurveModeBezier .setIcon( getIcon( 'curve_mode_bezier' ) ) self.timeline.toolbuttonCurveModeBezierS .setIcon( getIcon( 'curve_mode_bezier_s' ) ) self.timeline.toolbuttonAddMarker .setIcon( getIcon( 'marker' ) ) self.timeline.toolbuttonAddKey .setIcon( getIcon( 'add' ) ) self.timeline.toolbuttonRemoveKey .setIcon( getIcon( 'remove' ) ) self.timeline.toolbuttonCloneKey .setIcon( getIcon( 'clone' ) ) treeLayout = QtGui.QVBoxLayout(self.containerTree) treeLayout.setSpacing( 0 ) treeLayout.setMargin( 0 ) treeLayout.addWidget( self.treeTracks ) rightLayout = QtGui.QVBoxLayout(self.containerRight) rightLayout.setSpacing( 0 ) rightLayout.setMargin( 0 ) rightLayout.addWidget( self.timeline ) treeClipsLayout = QtGui.QVBoxLayout(self.containerClips) treeClipsLayout.setSpacing( 0 ) treeClipsLayout.setMargin( 0 ) treeClipsLayout.addWidget( self.toolbarTarget ) treeClipsLayout.addWidget( self.treeClips ) treeClipsLayout.addWidget( self.toolbarClips ) self.treeClips.setHeaderHidden( True ) self.treeClips.verticalScrollBar().setStyleSheet('width:4px') propLayout = QtGui.QVBoxLayout(self.containerProperty) propLayout.setSpacing( 0 ) propLayout.setMargin( 0 ) propLayout.addWidget( self.propertyEditor ) # headerHeight = self.treeTracks.header().height() playToolLayout = QtGui.QVBoxLayout(self.containerPlayTool) playToolLayout.setSpacing( 0 ) playToolLayout.setMargin( 0 ) playToolLayout.addWidget( self.toolbarPlay ) playToolLayout.addStretch( ) trackToolLayout = QtGui.QVBoxLayout(self.containerTrackTool) trackToolLayout.setSpacing( 0 ) trackToolLayout.setMargin( 0 ) trackToolLayout.addWidget( self.toolbarTrack ) bottomToolHeight = 20 self.containerTrackTool.setFixedHeight( bottomToolHeight ) self.toolbarClips.setFixedHeight( bottomToolHeight ) self.toolbarTrack.setFixedHeight( bottomToolHeight ) topToolHeight = self.timeline.getRulerHeight() self.containerPlayTool.setFixedHeight( topToolHeight ) self.toolbarPlay.setFixedHeight( topToolHeight ) self.toolbarClips.setFixedHeight( topToolHeight ) self.treeTracks.header().hide() self.treeTracks.setObjectName( 'AnimatorTrackTree' ) self.treeClips.setObjectName( 'AnimatorClipListTree' ) self.toolbarPlay.setObjectName( 'TimelineToolBarPlay') self.toolbarTrack.setObjectName( 'TimelineToolBarTrack') #signals self.treeTracks.verticalScrollBar().valueChanged.connect( self.onTrackTreeScroll ) self.timeline.cursorPosChanged.connect( self.onCursorPosChanged ) self.timeline.trackView.scrollYChanged.connect( self.onTrackViewScrollDragged ) self.treeTracks.layoutChanged.connect( self.updateTrackLayout ) self.cursorMovable = True self.updatingScroll = False def setOwner( self, owner ): self.owner = owner self.treeTracks.parentView = self self.treeClips.parentView = self self.timeline.parentView = self self.treeTracks.owner = owner self.treeClips.owner = owner self.timeline.owner = owner #signals self.timeline.markerChanged.connect( self.onMarkerChanged ) self.timeline.keyChanged.connect( self.onKeyChanged ) self.timeline.keyCurveValueChanged.connect( self.onKeyCurveValueChanged ) self.timeline.keyBezierPointChanged.connect( self.onKeyBezierPointChanged ) self.timeline.keyTweenModeChanged.connect( self.onKeyTweenModeChanged ) def rebuild( self ): self.treeTracks.rebuild() self.treeClips.rebuild() self.timeline.rebuild() self.setTrackViewScrollRange( 0 ) def rebuildTimeline( self ): self.timeline.rebuild() self.treeTracks.rebuild() def rebuildClipList( self ): self.treeClips.rebuild() def updateTrackLayout( self ): self.timeline.updateTrackLayout() def createClip( self ): pass def addClip( self, clip, focus = False ): self.treeClips.addNode( clip ) if focus: self.treeClips.selectNode( clip ) self.treeClips.editNode( clip ) def addKey( self, key, focus = False ): self.addTrack( key.parent ) self.timeline.addKey( key ) if focus: #TODO: select key pass def addTrack( self, track, focus = False ): self.treeTracks.addNode( track ) self.timeline.addTrack( track ) if focus: self.treeTracks.editNode( track ) self.timeline.setTrackSelection( [track] ) def addMarker( self, marker, focus = False ): self.timeline.addMarker( marker ) if focus: #TODO: select marker pass def selectTrack( self, trackNode ): self.treeTracks.selectNode( trackNode ) def removeClip( self, clip ): self.treeClips.removeNode( clip ) def removeTrack( self, track ): self.treeTracks.removeNode( track ) self.timeline.removeTrack( track ) def removeKey( self, key ): self.timeline.removeKey( key ) def setPropertyTarget( self, target ): self.propertyEditor.setTarget( target ) def isTrackVisible( self, trackNode ): return self.treeTracks.isNodeVisible( trackNode ) def getTrackPos( self, trackNode ): rect = self.treeTracks.getNodeVisualRect( trackNode ) scrollY = self.treeTracks.verticalScrollBar().value() pos = rect.y() + 3 + scrollY return pos def onTrackViewScrollDragged( self, y ): if self.updatingScroll: return self.updatingScroll = True self.treeTracks.verticalScrollBar().setValue( -y ) self.updatingScroll = False def setTrackViewScrollRange( self, maxRange ): self.timeline.setTrackViewScrollRange( maxRange ) def onTrackTreeScroll( self, v ): self.timeline.setTrackViewScroll( -v ) def onTrackFolded( self, track, folded ): track._folded = folded self.timeline.updateTrackLayout() self.timeline.clearSelection() def onMarkerChanged( self, marker, pos ): self.propertyEditor.refreshFor( marker ) self.owner.onTimelineMarkerChanged( marker, pos ) def onKeyChanged( self, key, pos, length ): self.propertyEditor.refreshFor( key ) self.owner.onTimelineKeyChanged( key, pos, length ) def onKeyCurveValueChanged( self, key, value ): self.owner.onTimelineKeyCurveValueChanged( key, value ) def onKeyBezierPointChanged( self, key, bpx0, bpy0, bpx1, bpy1 ): self.owner.onTimelineKeyBezierPointChanged( key, bpx0, bpy0, bpx1, bpy1 ) def onKeyTweenModeChanged( self, key, mode ): if mode == TWEEN_MODE_LINEAR: mode = 0 elif mode == TWEEN_MODE_CONSTANT: mode = 1 elif mode == TWEEN_MODE_BEZIER: mode = 2 else: mode = 0 self.owner.onTimelineKeyTweenModeChanged( key, mode ) def onKeyRemoving( self, key ): return self.owner.onKeyRemoving( key ) def onPropertyChanged( self, obj, fid, value ): pass # if isMockInstance( obj, 'AnimatorKey' ): # if fid == 'pos' or fid == 'length': # self.timeline.refreshKey( obj ) # elif isMockInstance( obj, 'AnimatorClipMarker' ): # if fid == 'name' or fid =='pos': # self.timeline.refreshMarker( obj ) # self.owner.onObjectEdited( obj ) def onPropertyTargetChanged( self, obj ): if isMockInstance( obj, 'AnimatorKey' ): self.timeline.refreshKey( obj ) elif isMockInstance( obj, 'AnimatorClipMarker' ): self.timeline.refreshMarker( obj ) self.owner.onObjectEdited( obj ) def setEnabled( self, enabled ): super( AnimatorWidget, self ).setEnabled( enabled ) self.timeline.setEnabled( enabled ) def startPreview( self ): # self.timeline.setCursorDraggable( False ) pass def stopPreview( self ): # self.timeline.setCursorDraggable( True ) pass def setCursorMovable( self, movable ): self.cursorMovable = movable self.timeline.setCursorDraggable( movable ) def onCursorPosChanged( self, pos ): if self.cursorMovable: self.owner.applyTime( pos ) def setCursorPos( self, pos, focus = False ): self.timeline.setCursorPos( pos, focus ) def getCursorPos( self ): return self.timeline.getCursorPos() def onTrackSelectioChanged( self ): selection = self.treeTracks.getSelection() self.timeline.setTrackSelection( selection ) if selection: track = selection[0] else: track = None self.owner.setCurrentTrack( track ) def onClipSelectioChanged( self ): selection = self.treeClips.getSelection() if selection: clip = selection[0] else: clip = None if isMockInstance( clip, 'AnimatorClip' ): self.owner.setTargetClip( clip ) else: #TODO pass def getTrackSelection( self ): return self.timeline.getTrackSelection() def getClipSelection( self ): return self.treeClips.getSelection() def getKeySelection( self ): return self.timeline.getSelection() def getCurrentClipGroup( self ): selection = self.treeClips.getSelection() if selection: node = selection[ 0 ] while node: if isMockInstance( node, 'AnimatorClipGroup' ): return node node = node.parentGroup return None
class SerializableEditorInstance( object ): def __init__(self, id): self.id = id self.targetNode = None self.targetAsset = None self.container = None self.body = None self.dataDirty = False def createWidget( self, container ): self.container = container self.container.setCallbackOnClose( self.onClose ) self.toolbar = self.container.addToolBar() self.toolbar.setIconSize( QtCore.QSize( 16, 16 ) ) self.actionSave = self.toolbar.addAction( getIcon( 'save' ), 'Save' ) self.actionLocate = self.toolbar.addAction( getIcon( 'search-2' ), 'Locate' ) self.actionSave.setEnabled( False ) self.actionSave.triggered.connect( self.onActionSave ) self.actionLocate.triggered.connect( self.onActionLocate ) self.window = window = self.container.addWidgetFromFile( _getModulePath('SerializableEditor.ui') ) self.scroll = scroll = addWidgetWithLayout( QtGui.QScrollArea( window.containerProperty ), window.containerProperty ) scroll.verticalScrollBar().setStyleSheet('width:4px') scroll.setWidgetResizable( True ) self.propertyEditor = PropertyEditor( scroll ) scroll.setWidget( self.propertyEditor ) self.propertyEditor.propertyChanged.connect( self.onPropertyChanged ) def setTarget(self, targetNode): self.targetNode = targetNode data = _MOCK.loadAsset( targetNode.getPath() ) if data: asset, luaAssetNode = data self.targetAsset = asset self.propertyEditor.setTarget( asset ) else: self.targetAsset = None self.propertyEditor.setTarget( None ) def refresh( self ): self.propertyEditor.refreshAll() def hasTarget( self, targetNode ): return self.targetNode == targetNode def resetData( self ): if self.targetAsset and self.targetNode: path = self.targetNode.getAbsFilePath() _MOCK.deserializeFromFile( self.targetAsset, path ) self.actionSave.setEnabled( False ) self.dataDirty = False def saveData( self ): if self.targetAsset: path = self.targetNode.getAbsFilePath() _MOCK.serializeToFile( self.targetAsset, path ) self.actionSave.setEnabled( False ) self.dataDirty = False def onActionSave( self ): self.saveData() def onActionLocate( self ): if self.targetNode: browser = app.getModule( 'asset_browser' ) if browser: browser.locateAsset( self.targetNode ) def onPropertyChanged( self, id, value ): self.dataDirty = True self.actionSave.setEnabled( True ) def onClose( self ): if self.dataDirty: res = requestConfirm( 'data modified!', 'save scene before close?' ) if res == None: #cancel return False elif res == True: #save self.onActionSave() elif res == False: #no save self.resetData() self.parentModule.removeInstance( self ) return True