コード例 #1
0
ファイル: app.py プロジェクト: vheuken/panda3d-editor
class App( p3d.wx.App ):
    
    """Base editor class."""
    
    def OnInit( self ):
        self.gizmo = False
        self._xformTask = None
        
        # Bind publisher events
        pub.subscribe( self.OnUpdate, 'Update' )
        
        # Build main frame, start Panda and replace the wx event loop with
        # Panda's.
        self.frame = ui.MainFrame( None, size=(800, 600) )
        ShowBase( self.frame.pnlViewport )
        self.ReplaceEventLoop()
        self.frame.Show()
        wx.CallAfter( self.FinishInit )
        
        return True
    
    def FinishInit( self ):
        base.FinishInit()
        
        # Create project manager
        self.project = Project( self )
        base.project = self.project
        self.frame.SetProjectPath( self.frame.cfg.Read( 'projDirPath' ) )
        
        # Create grid
        self.SetupGrid()
        
        # Create frame rate meter
        self.frameRate = p3d.FrameRate()
        
        # Create shading mode keys
        dsp = p3d.DisplayShading()
        dsp.accept( '4', dsp.Wireframe )
        dsp.accept( '5', dsp.Shade )
        dsp.accept( '6', dsp.Texture )
        
        # Set up gizmos
        self.SetupGizmoManager()
        
        # Bind mouse events
        self.accept( 'mouse1', self.OnMouse1Down )
        self.accept( 'shift-mouse1', self.OnMouse1Down, [True] )
        self.accept( 'control-mouse1', self.OnMouse1Down )
        self.accept( 'mouse2', self.OnMouse2Down )
        self.accept( 'mouse1-up', self.OnMouse1Up )
        self.accept( 'mouse2-up', self.OnMouse2Up )
        
        # Create selection manager
        self.selection = Selection(
            camera=base.edCamera, 
            root2d=base.edRender2d, 
            win=base.win, 
            mouseWatcherNode=base.edMouseWatcherNode 
        )
        base.selection = self.selection
        
        # Create our managers.
        self.assetMgr = AssetManager()
        self.dDropMgr = DragDropManager()
        self.actnMgr = actions.Manager()
        
        # Bind events
        self.accept( 'z', self.Undo )
        self.accept( 'shift-z', self.Redo )
        self.accept( 'f', self.FrameSelection )
        self.accept( 'del', lambda fn: cmds.Remove( fn() ), [self.selection.Get] )
        self.accept( 'backspace', lambda fn: cmds.Remove( fn() ), [self.selection.Get] )
        self.accept( 'control-d', lambda fn: cmds.Duplicate( fn() ), [self.selection.Get] )
        self.accept( 'control-g', lambda fn: cmds.Group( fn() ), [self.selection.Get] )
        self.accept( 'control-s', self.frame.OnFileSave, [None] )
        self.accept( 'arrow_up', lambda fn: cmds.Select( fn() ), [self.selection.SelectParent] )
        self.accept( 'arrow_down', lambda fn: cmds.Select( fn() ), [self.selection.SelectChild] )
        self.accept( 'arrow_left', lambda fn: cmds.Select( fn() ), [self.selection.SelectPrev] )
        self.accept( 'arrow_right', lambda fn: cmds.Select( fn() ), [self.selection.SelectNext] )
        self.accept( 'projectFilesModified', self.OnProjectFilesModified )
        
        # Create a "game"
        self.game = editor.Base()
        self.game.OnInit()
        
        # Start with a new scene
        self.CreateScene()
        self.doc.OnRefresh()
        
        return True
    
    def SetupGrid( self ):
        """Create the grid and set up its appearance."""
        self.grid = DirectGrid( 
            gridSize=20.0,
            gridSpacing=1.0,
            planeColor=(0.5, 0.5, 0.5, 0.0),
            parent=base.edRender
        )
        self.grid.snapMarker.hide()
        self.grid.centerLines.setColor( (0, 0, 0, 0) )
        self.grid.centerLines.setThickness( 2 )
        self.grid.majorLines.setColor( (0.25, 0.25, 0.25, 0) )
        self.grid.majorLines.setThickness( 1 )
        self.grid.minorLines.setColor( (0.5, 0.5, 0.5, 0) )
        self.grid.updateGrid()
    
    def SetupGizmoManager( self ):
        """Create gizmo manager."""
        gizmoMgrRootNp = base.edRender.attachNewNode( 'gizmoManager' )
        kwargs = {
            'camera':base.edCamera, 
            'rootNp':gizmoMgrRootNp, 
            'win':base.win, 
            'mouseWatcherNode':base.edMouseWatcherNode
        }
        self.gizmoMgr = gizmos.Manager( **kwargs )
        self.gizmoMgr.AddGizmo( gizmos.Translation( 'pos', **kwargs ) )
        self.gizmoMgr.AddGizmo( gizmos.Rotation( 'rot', **kwargs ) )
        self.gizmoMgr.AddGizmo( gizmos.Scale( 'scl', **kwargs ) )
        
        # Bind gizmo manager events
        self.accept( 'q', self.SetActiveGizmo, [None] )
        self.accept( 'w', self.SetActiveGizmo, ['pos'] )
        self.accept( 'e', self.SetActiveGizmo, ['rot'] )
        self.accept( 'r', self.SetActiveGizmo, ['scl'] )
        self.accept( 'space', self.ToggleGizmoLocal )
        self.accept( '+', self.gizmoMgr.SetSize, [2] )
        self.accept( '-', self.gizmoMgr.SetSize, [0.5] )
        
    def SetActiveGizmo( self, name ):
        self.gizmoMgr.SetActiveGizmo( name )
        self.frame.OnUpdateXform( None )
        
    def SetGizmoLocal( self, val ):
        self.gizmoMgr.SetLocal( val )
        self.frame.OnUpdateXform( None )
        
    def ToggleGizmoLocal( self ):
        self.gizmoMgr.ToggleLocal()
        self.frame.OnUpdateXform( None )
        
    def OnMouse1Down( self, shift=False ):
        """
        Handle mouse button 1 down event. Start the drag select operation if
        a gizmo is not being used and the alt key is not down, otherwise start 
        the transform operation.
        """
        if ( not self.gizmoMgr.IsDragging() and 
             p3d.MOUSE_ALT not in base.edCamera.mouse.modifiers ):
            self.selection.StartDragSelect( shift )
        elif self.gizmoMgr.IsDragging():
            self.StartTransform()
            
    def OnMouse2Down( self ):
        """
        Handle mouse button 2 down event. Start the transform operation if a
        gizmo is being used.
        """
        if self.gizmoMgr.IsDragging():
            self.StartTransform()
                    
    def OnMouse1Up( self ):
        """
        Handle mouse button 1 up event. Stop the drag select operation if the
        marquee is running, otherwise stop the transform operation if a gizmo
        is being used.
        """
        if self.selection.marquee.IsRunning():
            cmds.Select( self.selection.StopDragSelect() )
        elif self.gizmoMgr.IsDragging() or self.gizmo:
            self.StopTransform()
            
    def OnMouse2Up( self ):
        """
        Handle mouse button 2 up event. Stop the transform operation if a 
        gizmo is being used.
        """
        if self.gizmoMgr.IsDragging() or self.gizmo:
            self.StopTransform()
            
    def StartTransform( self ):
        """
        Start the transfrom operation by adding a task to constantly send a
        selection modified message while transfoming.
        """
        self.gizmo = True
        self._xformTask = taskMgr.add( self.doc.OnSelectionModified, 
                                       'SelectionModified' )
            
    def StopTransform( self ):
        """
        Stop the transfrom operation by removing the selection modified 
        message task. Also create a transform action and push it onto the undo 
        queue.
        """
        # Remove the transform task
        if self._xformTask in taskMgr.getAllTasks():
            taskMgr.remove( self._xformTask )
            self._xformTask = None
            
        actGizmo = self.gizmoMgr.GetActiveGizmo()
        actns = []
        for i, np in enumerate( actGizmo.attachedNps ):
            actns.append( actions.Transform( np, np.getTransform(), actGizmo.initNpXforms[i] ) )
        actn = actions.Composite( actns )
        self.actnMgr.Push( actn )
        self.gizmo = False
        
        # Make sure to mark the NodePath as dirty in case it is a child of a
        # model root.
        wrpr = base.game.nodeMgr.Wrap( np )
        wrpr.SetModified( True )
        
        # Call OnModified next frame. Not sure why but if we call it straight
        # away it causes a small jitter when xforming...
        taskMgr.doMethodLater( 0, self.doc.OnModified, 'dragDrop', 
                               [actGizmo.attachedNps] )
        
    def FrameSelection( self ):
        """
        Call frame selection on the camera if there are some node paths in the 
        selection.
        """
        nps = self.selection.GetNodePaths()
        if nps:
            base.edCamera.Frame( nps )
        else:
            base.edCamera.Frame( [base.scene.rootNp] )
            
    def OnUpdate( self, msg ):
        """
        Subscribed to the update selection message. Make sure that the
        selected nodes are attached to the managed gizmos, then refresh the
        active one.
        """
        nps = self.selection.GetNodePaths()
        self.gizmoMgr.AttachNodePaths( nps )
        self.gizmoMgr.RefreshActiveGizmo()
        self.selection.Update()
                    
    def CreateScene( self, filePath=None, newDoc=True ):
        """
        Create an empty scene and set its root node to the picker's root node.
        """
        # Reset undo queue if creating a new document
        if newDoc:
            self.actnMgr.Reset()
        
        # Close the current scene if there is one
        self.selection.Clear()
        if hasattr( self, 'scene' ):
            self.scene.Close()
            
        # Create a new scene
        self.scene = editor.Scene()
        self.scene.rootNp.reparentTo( base.edRender )
        
        # Set the selection and picker root node to the scene's root node
        self.selection.rootNp = self.scene.rootNp
        self.selection.picker.rootNp = self.scene.rootNp
        self.selection.marquee.rootNp = self.scene.rootNp
        
        # Create the document wrapper if creating a new document
        if newDoc:
            self.doc = ui.Document( filePath, self.scene )
        
    def AddComponent( self, typeStr, *args, **kwargs ):
        wrprCls = base.game.nodeMgr.GetWrapperByName( typeStr )
        wrpr = wrprCls.Create( *args, **kwargs )
        wrpr.SetDefaultValues()
        wrpr.SetParent( wrpr.GetDefaultParent() )
        
        # Bit of a hack. Sometimes a wrapper can create multiple components 
        # when Create is called. Make sure to set default values on all the 
        # components that were created.
        if hasattr( wrpr, 'extraNps' ):
            for np in wrpr.extraNps:
                eWrpr = base.game.nodeMgr.Wrap( np )
                eWrpr.SetDefaultValues()
        cmds.Add( [wrpr.data] )
        
        return wrpr
        
    def OnProjectFilesModified( self, filePaths ):
        self.assetMgr.OnAssetModified( filePaths )
        self.game.pluginMgr.OnProjectFilesModified( filePaths )
        
    def Undo( self ):
        self.actnMgr.Undo()
        self.doc.OnModified()
        
    def Redo( self ):
        self.actnMgr.Redo()
        self.doc.OnModified()
        
    def Group( self ):
        nps = self.selection.GetNodePaths()
        if nps:
            cmds.Group( nps )
        
    def Ungroup( self ):
        nps = self.selection.GetNodePaths()
        if nps:
            cmds.Ungroup( nps )
        
    def Parent( self ):
        pass
        
    def Unparent( self ):
        pass