コード例 #1
0
 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()
コード例 #2
0
class TestEnvironment(Scenario):
    """Draw some test grid and stuff."""
    def __init__(self):
        # initialise ODE
        world = OdeWorld()
        #world.setGravity(0.0, 0.0, -9.81)
        world.setGravity(0.0, 0.0, 0.0)
        
        self.grid = DirectGrid(2000, 20, parent=render)
        self.grid.setZ(-0.001)
        setSky("bluesky")

        # lights
        sunlight = DirectionalLight("sun")
        sunlight.setColor(Vec4(1.0, 0.9, 0.8, 1))
        sunnp = render.attachNewNode(sunlight)
        sunnp.setP(-60)
        render.setLight(sunnp)

        alight = AmbientLight("alight")
        alight.setColor(Vec4(0.6, 0.6, 0.8, 1))
        alnp = render.attachNewNode(alight)
        render.setLight(alnp)

        #render.setShaderAuto(True)

        ## initialise physics engine
        #base.enableParticles()

        # load our plane(s)
        base.player = Aeroplane("griffin", world=world)
        base.player_camera = views.PlaneCamera(base.player)
        self.control = controls.PlaneFlight()

        # load some others
        #pirate1 = Aeroplane("griffin")
        #pirate1.node.setPosHpr(-15, -20, 12, -10, -10, 20)

        #pirate2 = Aeroplane("griffin")
        #pirate2.node.setPosHpr(18, -30, 6, 5, -5, -5)

        # set default camera
        base.player.hud = gui.HUD(base.player, base.camera)
        base.player.hud.update()
        self.control.activate()

    def start(self):
        pass
コード例 #3
0
    def makePerspective(parent):
        v = Viewport('persp', parent)
        v.camPos = Point3(-19, -19, 19)
        v.camLookAt = Point3(0, 0, 0)

        v.grid = DirectGrid(parent=render)
        collPlane = CollisionNode('PerspGridCol')
        collPlane.addSolid(CollisionPlane(Plane(0, 0, 1, 0)))
        #oldBitmask = collPlane.getIntoCollideMask()
        #collPlane.setIntoCollideMask(BitMask32.bit(21)|oldBitmask)
        collPlane.setIntoCollideMask(BitMask32.bit(21))
        v.collPlane = NodePath(collPlane)
        v.collPlane.reparentTo(v.grid)

        collPlane2 = CollisionNode('PerspGridCol2')
        collPlane2.addSolid(CollisionPlane(Plane(0, 0, -1, 0)))
        #oldBitmask = collPlane2.getIntoCollideMask()
        #collPlane2.setIntoCollideMask(BitMask32.bit(21)|oldBitmask)
        collPlane2.setIntoCollideMask(BitMask32.bit(21))
        v.collPlane2 = NodePath(collPlane2)
        v.collPlane2.reparentTo(v.grid)

        #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_perspViewGridBack")
        LE_showInOneCam(v.grid, 'persp')
        return v
コード例 #4
0
 def makeOrthographic(parent, name, campos):
     v = Viewport(name, parent)
     v.lens = OrthographicLens()
     v.lens.setFilmSize(30)
     v.camPos = campos
     v.camLookAt = Point3(0, 0, 0)
     v.grid = DirectGrid(parent=render)
     if name == 'left':
         v.grid.setHpr(0, 0, 90)
         collPlane = CollisionNode('LeftGridCol')
         collPlane.addSolid(CollisionPlane(Plane(1, 0, 0, 0)))
         collPlane.setIntoCollideMask(BitMask32.bit(21))
         v.collPlane = NodePath(collPlane)
         v.collPlane.wrtReparentTo(v.grid)
         #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_leftViewGridBack")
         LE_showInOneCam(v.grid, name)
     elif name == 'front':
         v.grid.setHpr(90, 0, 90)
         collPlane = CollisionNode('FrontGridCol')
         collPlane.addSolid(CollisionPlane(Plane(0, -1, 0, 0)))
         collPlane.setIntoCollideMask(BitMask32.bit(21))
         v.collPlane = NodePath(collPlane)
         v.collPlane.wrtReparentTo(v.grid)
         #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_frontViewGridBack")
         LE_showInOneCam(v.grid, name)
     else:
         collPlane = CollisionNode('TopGridCol')
         collPlane.addSolid(CollisionPlane(Plane(0, 0, 1, 0)))
         collPlane.setIntoCollideMask(BitMask32.bit(21))
         v.collPlane = NodePath(collPlane)
         v.collPlane.reparentTo(v.grid)
         #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_topViewGridBack")
         LE_showInOneCam(v.grid, name)
     return v
コード例 #5
0
ファイル: app.py プロジェクト: FelixBucket/panda3d-editor
 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()
コード例 #6
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
コード例 #7
0
    def __init__(self, parent):
        self.parent = parent
        self.elementHandler = None

        color = (
            (0.8, 0.8, 0.8, 1), # Normal
            (0.9, 0.9, 1, 1), # Click
            (0.8, 0.8, 1, 1), # Hover
            (0.5, 0.5, 0.5, 1)) # Disabled
        # respect menu bar

        self.canvasScale = 1080 # min(base.getSize()[0], base.getSize()[1])

        # we default to a 1920x1080 FHD screen
        self.canvasLeft = -1920/2
        self.canvasRight = 1920/2
        self.canvasTop = 1080/2
        self.canvasBottom = -1080/2

        self.visualEditor = DirectScrolledFrame(
            frameColor=(0.25, 0.25, 0.25, 1),
            canvasSize=(self.canvasLeft, self.canvasRight, self.canvasBottom, self.canvasTop),
            scrollBarWidth=20,

            # vertical scrollbar
            verticalScroll_value=0.5,
            verticalScroll_thumb_relief=DGG.FLAT,
            verticalScroll_incButton_relief=DGG.FLAT,
            verticalScroll_decButton_relief=DGG.FLAT,
            verticalScroll_thumb_frameColor=color,
            verticalScroll_incButton_frameColor=color,
            verticalScroll_decButton_frameColor=color,

            # horizontal scrollbar
            horizontalScroll_value=0.5,
            horizontalScroll_thumb_relief=DGG.FLAT,
            horizontalScroll_incButton_relief=DGG.FLAT,
            horizontalScroll_decButton_relief=DGG.FLAT,
            horizontalScroll_thumb_frameColor=color,
            horizontalScroll_incButton_frameColor=color,
            horizontalScroll_decButton_frameColor=color,
            )

        self.scaleParent = DirectFrame(
            scale=(1,1,1)
            )

        # store which base parent should be used for the elements
        self.currentVisEditorParent = base.aspect2d
        self.visEditorInAspect2D = True

        # Layouting
        self.sizer = DirectAutoSizer(
            updateOnWindowResize=False,
            parent=parent,
            child=self.visualEditor,
            )

        # zoom scale
        self.minScale = DEFAULT_MIN_SCALE
        self.maxScale = DEFAULT_MAX_SCALE
        self.zoomInMultiplyer = 1.1
        self.zoomOutMultiplyer = 0.9

        # This frame will be the base parent for the added GUI elements
        self.elementHolder = DirectFrame(
            #frameColor=(0.25, 0.25, 0.25, 1),
            scale=LVecBase3f(self.canvasScale/2,1,self.canvasScale/2),
            parent=self.scaleParent
            )
        self.elementHolder.bind(DGG.B1RELEASE, base.messenger.send, ["mouse3"])
        # Ensure the holder frame will be streched to fill the parent
        self.scaleParentSizer = DirectAutoSizer(
            parent=self.visualEditor.canvas,
            child=self.scaleParent,
            parentGetSizeFunction=self.visualEditor.cget,
            parentGetSizeExtraArgs=["canvasSize"],
            )

        self.elementHolderSizer = DirectAutoSizer(
            parent=self.scaleParent,
            child=self.elementHolder
            )

        # The designers grid
        self.grid = DirectGrid(gridSize=50.0, gridSpacing=0.05,parent=self.elementHolder)
        self.grid.setP(90)
        self.grid.snapMarker.hide()
        self.snapToGrid = not self.grid.isHidden()

        self.canvasTopCenter = self.elementHolder.attachNewNode("canvasTopCenter")
        self.canvasBottomCenter = self.elementHolder.attachNewNode("canvasBottomCenter")
        self.canvasLeftCenter = self.elementHolder.attachNewNode("canvasLeftCenter")
        self.canvasRightCenter = self.elementHolder.attachNewNode("canvasRightCenter")

        self.canvasTopLeft = self.elementHolder.attachNewNode("canvasTopLeft")
        self.canvasTopRight = self.elementHolder.attachNewNode("canvasTopRight")
        self.canvasBottomLeft = self.elementHolder.attachNewNode("canvasBottomLeft")
        self.canvasBottomRight = self.elementHolder.attachNewNode("canvasBottomRight")

        # default to Aspect2D
        self.setVisualEditorParent(False)

        base.taskMgr.add(self.watchCanvasProps, "watch-canvas-properties", sort=50, priority=0)
コード例 #8
0
class CanvasPanel():
    def __init__(self, parent):
        self.parent = parent
        self.elementHandler = None

        color = (
            (0.8, 0.8, 0.8, 1), # Normal
            (0.9, 0.9, 1, 1), # Click
            (0.8, 0.8, 1, 1), # Hover
            (0.5, 0.5, 0.5, 1)) # Disabled
        # respect menu bar

        self.canvasScale = 1080 # min(base.getSize()[0], base.getSize()[1])

        # we default to a 1920x1080 FHD screen
        self.canvasLeft = -1920/2
        self.canvasRight = 1920/2
        self.canvasTop = 1080/2
        self.canvasBottom = -1080/2

        self.visualEditor = DirectScrolledFrame(
            frameColor=(0.25, 0.25, 0.25, 1),
            canvasSize=(self.canvasLeft, self.canvasRight, self.canvasBottom, self.canvasTop),
            scrollBarWidth=20,

            # vertical scrollbar
            verticalScroll_value=0.5,
            verticalScroll_thumb_relief=DGG.FLAT,
            verticalScroll_incButton_relief=DGG.FLAT,
            verticalScroll_decButton_relief=DGG.FLAT,
            verticalScroll_thumb_frameColor=color,
            verticalScroll_incButton_frameColor=color,
            verticalScroll_decButton_frameColor=color,

            # horizontal scrollbar
            horizontalScroll_value=0.5,
            horizontalScroll_thumb_relief=DGG.FLAT,
            horizontalScroll_incButton_relief=DGG.FLAT,
            horizontalScroll_decButton_relief=DGG.FLAT,
            horizontalScroll_thumb_frameColor=color,
            horizontalScroll_incButton_frameColor=color,
            horizontalScroll_decButton_frameColor=color,
            )

        self.scaleParent = DirectFrame(
            scale=(1,1,1)
            )

        # store which base parent should be used for the elements
        self.currentVisEditorParent = base.aspect2d
        self.visEditorInAspect2D = True

        # Layouting
        self.sizer = DirectAutoSizer(
            updateOnWindowResize=False,
            parent=parent,
            child=self.visualEditor,
            )

        # zoom scale
        self.minScale = DEFAULT_MIN_SCALE
        self.maxScale = DEFAULT_MAX_SCALE
        self.zoomInMultiplyer = 1.1
        self.zoomOutMultiplyer = 0.9

        # This frame will be the base parent for the added GUI elements
        self.elementHolder = DirectFrame(
            #frameColor=(0.25, 0.25, 0.25, 1),
            scale=LVecBase3f(self.canvasScale/2,1,self.canvasScale/2),
            parent=self.scaleParent
            )
        self.elementHolder.bind(DGG.B1RELEASE, base.messenger.send, ["mouse3"])
        # Ensure the holder frame will be streched to fill the parent
        self.scaleParentSizer = DirectAutoSizer(
            parent=self.visualEditor.canvas,
            child=self.scaleParent,
            parentGetSizeFunction=self.visualEditor.cget,
            parentGetSizeExtraArgs=["canvasSize"],
            )

        self.elementHolderSizer = DirectAutoSizer(
            parent=self.scaleParent,
            child=self.elementHolder
            )

        # The designers grid
        self.grid = DirectGrid(gridSize=50.0, gridSpacing=0.05,parent=self.elementHolder)
        self.grid.setP(90)
        self.grid.snapMarker.hide()
        self.snapToGrid = not self.grid.isHidden()

        self.canvasTopCenter = self.elementHolder.attachNewNode("canvasTopCenter")
        self.canvasBottomCenter = self.elementHolder.attachNewNode("canvasBottomCenter")
        self.canvasLeftCenter = self.elementHolder.attachNewNode("canvasLeftCenter")
        self.canvasRightCenter = self.elementHolder.attachNewNode("canvasRightCenter")

        self.canvasTopLeft = self.elementHolder.attachNewNode("canvasTopLeft")
        self.canvasTopRight = self.elementHolder.attachNewNode("canvasTopRight")
        self.canvasBottomLeft = self.elementHolder.attachNewNode("canvasBottomLeft")
        self.canvasBottomRight = self.elementHolder.attachNewNode("canvasBottomRight")

        # default to Aspect2D
        self.setVisualEditorParent(False)

        base.taskMgr.add(self.watchCanvasProps, "watch-canvas-properties", sort=50, priority=0)

    def getEditorCanvasSize(self):
        cs = self.elementHolder["frameSize"]

        if self.currentVisEditorParent == base.pixel2d:
            cs = self.visualEditor["canvasSize"]

        return cs

    def getEditorRootCanvas(self):
        return self.elementHolder

    def watchCanvasProps(self, task):
        """Watch for all properties that can be changed on the canvas and won't
        directly propagate down to the actual background, which is the element
        holder."""

        self.sizer.refresh()

        sizeChanged = False
        cs = self.getEditorCanvasSize()
        if self.canvasLeft != cs[0]:
            sizeChanged = True
        elif self.canvasRight != cs[1]:
            sizeChanged = True
        elif self.canvasBottom != cs[2]:
            sizeChanged = True
        elif self.canvasTop != cs[3]:
            sizeChanged = True

        if sizeChanged:
            width = cs[1] - cs[0]
            height = cs[3] - cs[2]

            self.canvasScale = min(width, height)

            if self.currentVisEditorParent == base.pixel2d:
                if width > height:
                    self.canvasScale *= self.visualEditor.getScale()[2]
                else:
                    self.canvasScale *= self.visualEditor.getScale()[0]
            else:
                if width > height:
                    self.canvasScale *= self.elementHolder.getScale()[2]
                else:
                    self.canvasScale *= self.elementHolder.getScale()[0]

            #TODO: the scale probably needs to be calculated dependent on the users screen size
            self.elementHolder["scale"]= LVecBase3f(self.canvasScale/2,1,self.canvasScale/2),

            self.elementHolderSizer.refresh()
            self.scaleParentSizer.refresh()
            self.setCanvasPlacers()

        if self.visualEditor["frameColor"] != self.elementHolder["frameColor"]:
            fc = self.visualEditor["frameColor"]
            self.elementHolder["frameColor"] = fc
            self.elementHolderSizer["frameColor"] = fc
            self.scaleParentSizer["frameColor"] = fc
            self.scaleParent["frameColor"] = fc
        self.visualEditor

        return task.cont

    def setCanvasPlacers(self):
        cs = self.getEditorCanvasSize()
        self.canvasLeft = cs[0]
        self.canvasRight = cs[1]
        self.canvasBottom = cs[2]
        self.canvasTop = cs[3]

        # Put the nodes in their places
        self.canvasTopCenter.setPos(0, 0, self.canvasTop)
        self.canvasBottomCenter.setPos(0, 0, self.canvasBottom)
        self.canvasLeftCenter.setPos(self.canvasLeft, 0, 0)
        self.canvasRightCenter.setPos(self.canvasRight, 0, 0)

        self.canvasTopLeft.setPos(self.canvasLeft, 0, self.canvasTop)
        self.canvasTopRight.setPos(self.canvasRight, 0, self.canvasTop)
        self.canvasBottomLeft.setPos(self.canvasLeft, 0, self.canvasBottom)
        self.canvasBottomRight.setPos(self.canvasRight, 0, self.canvasBottom)

    def getEditorPlacer(self, placerName):
        placerName = placerName.lower()
        placerName = placerName.replace("a2d", "canvas")
        if placerName == "canvasTopCenter".lower():
            return self.canvasTopCenter
        elif placerName == "canvasBottomCenter".lower():
            return self.canvasBottomCenter
        elif placerName == "canvasLeftCenter".lower():
            return self.canvasLeftCenter
        elif placerName == "canvasRightCenter".lower():
            return self.canvasRightCenter
        elif placerName == "canvasTopLeft".lower():
            return self.canvasTopLeft
        elif placerName == "canvasTopRight".lower():
            return self.canvasTopRight
        elif placerName == "canvasBottomLeft".lower():
            return self.canvasBottomLeft
        elif placerName == "canvasBottomRight".lower():
            return self.canvasBottomRight

    def setElementHandler(self, elementHandler):
        self.elementHandler = elementHandler

    def setVisualEditorCanvasSize(self, newCanvasSize):
        self.visualEditor["canvasSize"] = newCanvasSize
        self.elementHolderSizer.refresh()
        self.scaleParentSizer.refresh()
        self.setCanvasPlacers()

    def setVisualEditorParent(self, toPixel2D):
        if toPixel2D:
            # change to pixel2d
            # we default to a 1920x1080 FHD screen
            self.canvasLeft = 0
            self.canvasRight = 1920
            self.canvasBottom = -1080
            self.canvasTop = 0

            self.setVisualEditorCanvasSize((self.canvasLeft, self.canvasRight, self.canvasBottom, self.canvasTop))
            self.currentVisEditorParent = base.pixel2d

            # Speed up the setGridSpacing call by setting the size to 1
            self.grid.setGridSize(1)
            self.grid.setGridSpacing(0.05 * (self.canvasScale / 2))
            self.grid.setGridSize(1920*4)
            self.visEditorInAspect2D = False
            if self.elementHandler is not None:
                self.elementHandler.setEditorParentType(self.visEditorInAspect2D)
                self.elementHandler.setEditorCenter((self.visualEditor.getWidth()/2, 0, -self.visualEditor.getHeight()/2))
        else:
            # change to aspect2d
            # we default to a 1920x1080 FHD screen
            self.canvasLeft = -1920/2
            self.canvasRight = 1920/2
            self.canvasTop = 1080/2
            self.canvasBottom = -1080/2

            self.scaleParent.setScale(1, 1, 1)

            self.setVisualEditorCanvasSize((self.canvasLeft, self.canvasRight, self.canvasBottom, self.canvasTop))
            self.currentVisEditorParent = base.aspect2d

            # Speed up the setGridSpacing call by setting the size to 1
            self.grid.setGridSize(1)
            self.grid.setGridSpacing(0.05)
            self.grid.setGridSize(50)
            self.visEditorInAspect2D = True
            if self.elementHandler is not None:
                self.elementHandler.setEditorParentType(self.visEditorInAspect2D)
                self.elementHandler.setEditorCenter((0, 0, 0))

        # reset the zoom value
        self.resetZoom()

        self.setCanvasPlacers()

    def toggleVisualEditorParent(self):
        if self.currentVisEditorParent == base.aspect2d:
            self.setVisualEditorParent(True)
        elif self.currentVisEditorParent != base.aspect2d:
            self.setVisualEditorParent(False)

    def resizeFrame(self):
        self.sizer.refresh()

    def toggleGrid(self, enable):
        if enable:
            self.grid.show()
            self.snapToGrid = True
        else:
            self.grid.hide()
            self.snapToGrid = False

    def resetZoom(self):
        self.visualEditor["verticalScroll_range"] = (0, 1)
        self.visualEditor["horizontalScroll_range"] = (0, 1)
        if self.currentVisEditorParent != base.aspect2d:
            # we are in pixel2d
            self.getEditorRootCanvas().setScale(1,1,1)
            self.visualEditor.verticalScroll["value"] = 0
            self.visualEditor.horizontalScroll["value"] = 0

            posParentScaleX = DGH.getRealWidth(self.parent)
            self.minScale = DEFAULT_MIN_SCALE
            self.maxScale = DEFAULT_MAX_SCALE
            base.messenger.send("setZoomValeMinMax", [self.minScale, self.maxScale])
            base.messenger.send("setZoomValue", [1])
        else:
            # we are in aspect2d
            self.getEditorRootCanvas().setScale(self.canvasScale/2,1,self.canvasScale/2)
            self.visualEditor.verticalScroll["value"] = 0.5
            self.visualEditor.horizontalScroll["value"] = 0.5

            posParentScaleX = DGH.getRealWidth(self.parent)
            self.minScale = posParentScaleX * DEFAULT_MIN_SCALE
            self.maxScale = posParentScaleX * DEFAULT_MAX_SCALE
            base.messenger.send("setZoomValeMinMax", [self.minScale, self.maxScale])
            base.messenger.send("setZoomValue", [self.canvasScale/2])

    def setZoom(self, zoomValue):
        z = zoomValue
        s = self.getEditorRootCanvas().getScale()

        self.getEditorRootCanvas().setScale(z, s[1], z)

        # update scroll bars
        vr = self.visualEditor["verticalScroll_range"]
        vv = self.visualEditor.verticalScroll["value"]
        hr = self.visualEditor["horizontalScroll_range"]
        hv = self.visualEditor.horizontalScroll["value"]

        vw = vr[1] - vr[0]
        hw = hr[1] - hr[0]

        curPosVer = vv / vw * 100
        curPosHor = hv / hw * 100

        self.visualEditor["verticalScroll_range"] = (vr[0]*(z/s[0]), vr[1]*(z/s[2]))
        self.visualEditor["horizontalScroll_range"] = (hr[0]*(z/s[0]), hr[1]*(z/s[2]))

        vr = self.visualEditor["verticalScroll_range"]
        hr = self.visualEditor["horizontalScroll_range"]

        self.visualEditor.verticalScroll["value"] = (vr[1] - vr[0]) / 100 * curPosVer
        self.visualEditor.horizontalScroll["value"] = (hr[1] - hr[0]) / 100 * curPosHor

        self.elementHolderSizer.refresh()


    def zoom(self, direction):
        z = 1
        s = self.getEditorRootCanvas().getScale()
        if direction < 0 and self.getEditorRootCanvas().getScale()[0] > self.minScale:
            z = self.zoomOutMultiplyer
        elif direction > 0 and self.getEditorRootCanvas().getScale()[0] < self.maxScale:
            z = self.zoomInMultiplyer

        self.getEditorRootCanvas().setScale(s[0]*z, s[1], s[2]*z)

        base.messenger.send("setZoomValue", [self.getEditorRootCanvas().getScale()[0]])
        #print(self.getEditorRootCanvas().getScale())

        # update scroll bars
        vr = self.visualEditor["verticalScroll_range"]
        vv = self.visualEditor.verticalScroll["value"]
        hr = self.visualEditor["horizontalScroll_range"]
        hv = self.visualEditor.horizontalScroll["value"]

        vw = vr[1] - vr[0]
        hw = hr[1] - hr[0]

        curPosVer = vv / vw * 100
        curPosHor = hv / hw * 100

        self.visualEditor["verticalScroll_range"] = (vr[0]*z, vr[1]*z)
        self.visualEditor["horizontalScroll_range"] = (hr[0]*z, hr[1]*z)

        vr = self.visualEditor["verticalScroll_range"]
        hr = self.visualEditor["horizontalScroll_range"]

        self.visualEditor.verticalScroll["value"] = (vr[1] - vr[0]) / 100 * curPosVer
        self.visualEditor.horizontalScroll["value"] = (hr[1] - hr[0]) / 100 * curPosHor

        self.elementHolderSizer.refresh()

    def dragEditorFrame(self, dragEnabled):
        taskMgr.remove("dragEditorFrameTask")
        mwn = base.mouseWatcherNode
        if dragEnabled:
            t = taskMgr.add(self.dragEditorFrameTask, "dragEditorFrameTask")
            t.vMouse2render2d = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1])

    def dragEditorFrameTask(self, t):
        mwn = base.mouseWatcherNode
        if mwn.hasMouse():
            vMouse2render2d = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1])
            moveVec = t.vMouse2render2d - vMouse2render2d
            t.vMouse2render2d = vMouse2render2d
            newValue = self.visualEditor["verticalScroll_value"] - moveVec.getZ()
            if newValue <= 1 and newValue >= 0:
                self.visualEditor["verticalScroll_value"] = newValue
            elif newValue > 1:
                self.visualEditor["verticalScroll_value"] = 1
            elif newValue < 0:
                self.visualEditor["verticalScroll_value"] = 0

            newValue = self.visualEditor["horizontalScroll_value"] + moveVec.getX()
            if newValue <= 1 and newValue >= 0:
                self.visualEditor["horizontalScroll_value"] = newValue
            elif newValue > 1:
                self.visualEditor["horizontalScroll_value"] = 1
            elif newValue < 0:
                self.visualEditor["horizontalScroll_value"] = 0

        return t.cont