""" DIRECT Session Main panel """ # Import Tkinter, Pmw, and the dial code from PandaObject import * from AppShell import * from Tkinter import * import string import Pmw import Dial import Floater import EntryScale import VectorWidgets import SceneGraphExplorer """ Possible to add: messenger.clear? popup panels taskMgr page """ class DirectSessionPanel(AppShell): # Override class variables here appname = 'Direct Session Panel' frameWidth = 550 frameHeight = 502 usecommandarea = 1 usestatusarea = 0 def __init__(self, parent = None, **kw): INITOPT = Pmw.INITOPT optiondefs = ( ('title', self.appname, None), ) self.defineoptions(kw, optiondefs) # Call superclass initialization function AppShell.__init__(self, parent) # Active light if len(direct.lights) > 0: name = direct.lights[0].getName() self.lightMenu.selectitem(name) self.selectLightNamed(name) else: self.activeLight = None # Active display region self.drMenu.selectitem('Display Region 0') self.selectDisplayRegionNamed('Display Region 0') # Make sure we've got valid initial values self.updateInfo() self.initialiseoptions(DirectSessionPanel) def appInit(self): # Initialize state # Dictionary keeping track of all node paths selected so far self.nodePathDict = {} self.nodePathDict['widget'] = direct.widget self.nodePathNames = ['widget'] # Dictionary keeping track of all jb node paths selected so far self.jbNodePathDict = {} self.jbNodePathDict['none'] = 'No Node Path' self.jbNodePathDict['widget'] = direct.widget self.jbNodePathDict['camera'] = direct.camera self.jbNodePathNames = ['camera', 'selected', 'none'] # Set up event hooks self.actionEvents = [('undo', self.undoHook), ('pushUndo', self.pushUndoHook), ('undoListEmpty', self.undoListEmptyHook), ('redo', self.redoHook), ('pushRedo', self.pushRedoHook), ('redoListEmpty', self.redoListEmptyHook), ('selectedNodePath', self.selectedNodePathHook), ('DirectLights_addLight', self.addLight), ] for event, method in self.actionEvents: self.accept(event, method) def createInterface(self): # The interior of the toplevel panel interior = self.interior() # Add placer commands to menubar self.menuBar.addmenu('DIRECT', 'Direct Session Panel Operations') self.directEnabled = BooleanVar() self.directEnabled.set(direct.isEnabled()) self.menuBar.addmenuitem('DIRECT', 'checkbutton', 'DIRECT Enabled', label = 'Enable', variable = self.directEnabled, command = self.toggleDirect) self.directGridEnabled = BooleanVar() self.directGridEnabled.set(direct.grid.isEnabled()) self.menuBar.addmenuitem('DIRECT', 'checkbutton', 'DIRECT Grid Enabled', label = 'Enable Grid', variable = self.directGridEnabled, command = self.toggleDirectGrid) # Get a handle to the menu frame menuFrame = self.menuFrame # Widget to select node paths (and display list of selected node paths) self.nodePathMenu = Pmw.ComboBox( menuFrame, labelpos = W, label_text = 'DIRECT Select:', entry_width = 20, selectioncommand = self.selectNodePathNamed, scrolledlist_items = self.nodePathNames) self.nodePathMenu.selectitem('widget') self.nodePathMenuEntry = ( self.nodePathMenu.component('entryfield_entry')) self.nodePathMenuBG = ( self.nodePathMenuEntry.configure('background')[3]) self.nodePathMenu.pack(side = LEFT, fill = X, expand = 1) self.bind(self.nodePathMenu, 'Select node path to manipulate') self.undoButton = Button(menuFrame, text = 'Undo', command = direct.undo) if direct.undoList: self.undoButton['state'] = 'normal' else: self.undoButton['state'] = 'disabled' self.undoButton.pack(side = LEFT, expand = 0) self.bind(self.undoButton, 'Undo last operation') self.redoButton = Button(menuFrame, text = 'Redo', command = direct.redo) if direct.redoList: self.redoButton['state'] = 'normal' else: self.redoButton['state'] = 'disabled' self.redoButton.pack(side = LEFT, expand = 0) self.bind(self.redoButton, 'Redo last operation') # The master frame for the dials mainFrame = Frame(interior) # Scene Graph Explorer sgeFrame = Frame(mainFrame) self.sgeUpdate = Button(sgeFrame, text = 'Update Explorer') self.sgeUpdate.pack(fill = X, expand = 0) self.SGE = SceneGraphExplorer.SceneGraphExplorer( sgeFrame, nodePath = render, scrolledCanvas_hull_width = 200, scrolledCanvas_hull_height = 400) self.SGE.pack(fill = BOTH, expand = 0) self.sgeUpdate['command'] = self.SGE.update sgeFrame.pack(side = LEFT, fill = 'both', expand = 0) # Create the notebook pages notebook = Pmw.NoteBook(mainFrame) notebook.pack(fill = BOTH, expand = 1) envPage = notebook.add('Environment') lightsPage = notebook.add('Lights') gridPage = notebook.add('Grid') devicePage = notebook.add('Devices') scenePage = notebook.add('Scene') # Put this here so it isn't called right away notebook['raisecommand'] = self.updateInfo ## Environment page ## # Backgroud color bkgrdFrame = Frame(envPage, borderwidth = 2, relief = 'sunken') Label(bkgrdFrame, text = 'Background', font=('MSSansSerif', 14, 'bold')).pack(expand = 0) self.backgroundColor = VectorWidgets.ColorEntry( bkgrdFrame, text = 'Background Color') self.backgroundColor['command'] = self.setBackgroundColor self.backgroundColor.pack(fill = X, expand = 0) self.bind(self.backgroundColor, 'Set background color') bkgrdFrame.pack(fill = BOTH, expand = 0) drFrame = Frame(envPage, borderwidth = 2, relief = 'sunken') Label(drFrame, text = 'Display Region', font=('MSSansSerif', 14, 'bold')).pack(expand = 0) nameList = map(lambda x: 'Display Region ' + `x`, range(len(direct.drList))) self.drMenu = Pmw.ComboBox( drFrame, labelpos = W, label_text = 'Display Region:', entry_width = 20, selectioncommand = self.selectDisplayRegionNamed, scrolledlist_items = nameList) self.drMenu.pack(fill = X, expand = 0) self.bind(self.drMenu, 'Select display region to configure') self.nearPlane = Floater.Floater( drFrame, text = 'Near Plane', min = 0.01) self.nearPlane['command'] = self.setNear self.nearPlane.pack(fill = X, expand = 0) self.bind(self.nearPlane, 'Set near plane distance') self.farPlane = Floater.Floater( drFrame, text = 'Far Plane', min = 0.01) self.farPlane['command'] = self.setFar self.farPlane.pack(fill = X, expand = 0) self.bind(self.farPlane, 'Set far plane distance') fovFrame = Frame(drFrame) fovFloaterFrame = Frame(fovFrame) self.hFov = EntryScale.EntryScale( fovFloaterFrame, text = 'Horizontal FOV', min = 0.01, max = 170.0) self.hFov['command'] = self.setHFov self.hFov.pack(fill = X, expand = 0) self.bind(self.hFov, 'Set horizontal field of view') self.vFov = EntryScale.EntryScale( fovFloaterFrame, text = 'Vertical FOV', min = 0.01, max = 170.0) self.vFov['command'] = self.setVFov self.vFov.pack(fill = X, expand = 0) self.bind(self.vFov, 'Set vertical field of view') fovFloaterFrame.pack(side = LEFT, fill = X, expand = 1) frame = Frame(fovFrame) self.lockedFov = BooleanVar() self.lockedFov.set(1) self.lockedFovButton = Checkbutton( frame, text = 'Locked', anchor = 'w', justify = LEFT, variable = self.lockedFov) self.lockedFovButton.pack(fill = X, expand = 0) self.resetFovButton = Button( frame, text = 'Reset', command = self.resetFov) self.resetFovButton.pack(fill = X, expand = 0) frame.pack(side = LEFT, fill = X, expand = 0) fovFrame.pack(fill = X, expand = 1) drFrame.pack(fill = BOTH, expand = 0) ## Render Style ## toggleFrame = Frame(envPage, borderwidth = 2, relief = 'sunken') Label(toggleFrame, text = 'Toggle Render Style', font=('MSSansSerif', 14, 'bold')).pack(expand = 0) self.toggleBackfaceButton = Button( toggleFrame, text = 'Backface', command = base.toggleBackface) self.toggleBackfaceButton.pack(side = LEFT, fill = X, expand = 1) self.toggleLightsButton = Button( toggleFrame, text = 'Lights', command = direct.lights.toggle) self.toggleLightsButton.pack(side = LEFT, fill = X, expand = 1) self.toggleTextureButton = Button( toggleFrame, text = 'Texture', command = base.toggleTexture) self.toggleTextureButton.pack(side = LEFT, fill = X, expand = 1) self.toggleWireframeButton = Button( toggleFrame, text = 'Wireframe', command = base.toggleWireframe) self.toggleWireframeButton.pack(fill = X, expand = 1) toggleFrame.pack(side = LEFT, fill = X, expand = 1) ## Lights page ## # Lights # lightFrame = Frame(lightsPage, borderwidth = 2, relief = 'sunken') self.lightsButton = Menubutton(lightFrame, text = 'Lights', font=('MSSansSerif', 14, 'bold'), activebackground = '#909090') lightsMenu = Menu(self.lightsButton) lightsMenu.add_command(label = 'Add Ambient Light', command = self.addAmbient) lightsMenu.add_command(label = 'Add Directional Light', command = self.addDirectional) lightsMenu.add_command(label = 'Add Point Light', command = self.addPoint) lightsMenu.add_command(label = 'Add Spotlight', command = self.addSpot) self.lightsButton.pack(expand = 0) self.lightsButton['menu'] = lightsMenu # Notebook pages for light specific controls self.lightNotebook = Pmw.NoteBook(lightFrame, tabpos = None, borderwidth = 0) ambientPage = self.lightNotebook.add('Ambient') directionalPage = self.lightNotebook.add('Directional') pointPage = self.lightNotebook.add('Point') spotPage = self.lightNotebook.add('Spot') # Put this here so it isn't called right away self.lightNotebook['raisecommand'] = self.updateLightInfo # Main light switch mainSwitchFrame = Frame(lightFrame) Label(mainSwitchFrame, text = 'Lighting:').pack(side = LEFT, expand = 0) self.enableLights = BooleanVar() self.enableLightsButton = Checkbutton( mainSwitchFrame, text = 'Enabled/Disabled', variable = self.enableLights, command = self.toggleLights) self.enableLightsButton.pack(side = LEFT, fill = X, expand = 0) mainSwitchFrame.pack(fill = X, expand = 0) # Widget to select a light to configure nameList = direct.lights.nameList lightMenuFrame = Frame(lightFrame) self.lightMenu = Pmw.ComboBox( lightMenuFrame, labelpos = W, label_text = 'Light:', entry_width = 20, selectioncommand = self.selectLightNamed, scrolledlist_items = nameList) self.lightMenu.pack(side = LEFT, fill = X, expand = 0) self.bind(self.lightMenu, 'Select light to configure') self.lightActive = BooleanVar() self.lightActiveButton = Checkbutton( lightMenuFrame, text = 'On/Off', variable = self.lightActive, command = self.toggleActiveLight) self.lightActiveButton.pack(side = LEFT, fill = X, expand = 0) # Pack light menu lightMenuFrame.pack(fill = X, expand = 0, padx = 2) self.lightColor = VectorWidgets.ColorEntry( lightFrame, text = 'Light Color') self.lightColor['command'] = self.setLightColor self.lightColor.pack(fill = X, expand = 0, padx = 4) self.bind(self.lightColor, 'Set active light color') # Directional light controls self.dSpecularColor = VectorWidgets.ColorEntry( directionalPage, text = 'Specular Color') self.dSpecularColor['command'] = self.setSpecularColor self.dSpecularColor.pack(fill = X, expand = 0) self.bind(self.dSpecularColor, 'Set directional light specular color') # Point light controls self.pSpecularColor = VectorWidgets.ColorEntry( pointPage, text = 'Specular Color') self.pSpecularColor['command'] = self.setSpecularColor self.pSpecularColor.pack(fill = X, expand = 0) self.bind(self.pSpecularColor, 'Set point light specular color') self.pConstantAttenuation = EntryScale.EntryScale( pointPage, text = 'Constant Attenuation', min = 0.0, max = 1.0, initialValue = 1.0) self.pConstantAttenuation['command'] = self.setConstantAttenuation self.pConstantAttenuation.pack(fill = X, expand = 0) self.bind(self.pConstantAttenuation, 'Set point light constant attenuation') self.pLinearAttenuation = EntryScale.EntryScale( pointPage, text = 'Linear Attenuation', min = 0.0, max = 1.0, initialValue = 0.0) self.pLinearAttenuation['command'] = self.setLinearAttenuation self.pLinearAttenuation.pack(fill = X, expand = 0) self.bind(self.pLinearAttenuation, 'Set point light linear attenuation') self.pQuadraticAttenuation = EntryScale.EntryScale( pointPage, text = 'Quadratic Attenuation', min = 0.0, max = 1.0, initialValue = 0.0) self.pQuadraticAttenuation['command'] = self.setQuadraticAttenuation self.pQuadraticAttenuation.pack(fill = X, expand = 0) self.bind(self.pQuadraticAttenuation, 'Set point light quadratic attenuation') # Spot light controls self.sSpecularColor = VectorWidgets.ColorEntry( spotPage, text = 'Specular Color') self.sSpecularColor['command'] = self.setSpecularColor self.sSpecularColor.pack(fill = X, expand = 0) self.bind(self.sSpecularColor, 'Set spot light specular color') self.sConstantAttenuation = EntryScale.EntryScale( spotPage, text = 'Constant Attenuation', min = 0.0, max = 1.0, initialValue = 1.0) self.sConstantAttenuation['command'] = self.setConstantAttenuation self.sConstantAttenuation.pack(fill = X, expand = 0) self.bind(self.sConstantAttenuation, 'Set spot light constant attenuation') self.sLinearAttenuation = EntryScale.EntryScale( spotPage, text = 'Linear Attenuation', min = 0.0, max = 1.0, initialValue = 0.0) self.sLinearAttenuation['command'] = self.setLinearAttenuation self.sLinearAttenuation.pack(fill = X, expand = 0) self.bind(self.sLinearAttenuation, 'Set spot light linear attenuation') self.sQuadraticAttenuation = EntryScale.EntryScale( spotPage, text = 'Quadratic Attenuation', min = 0.0, max = 1.0, initialValue = 0.0) self.sQuadraticAttenuation['command'] = self.setQuadraticAttenuation self.sQuadraticAttenuation.pack(fill = X, expand = 0) self.bind(self.sQuadraticAttenuation, 'Set spot light quadratic attenuation') self.sExponent = EntryScale.EntryScale( spotPage, text = 'Exponent', min = 0.0, max = 1.0, initialValue = 0.0) self.sExponent['command'] = self.setExponent self.sExponent.pack(fill = X, expand = 0) self.bind(self.sExponent, 'Set spot light exponent') # MRM: Add frustum controls self.lightNotebook.setnaturalsize() self.lightNotebook.pack(expand = 1, fill = BOTH) lightFrame.pack(expand = 1, fill = BOTH) ## GRID PAGE ## Label(gridPage, text = 'Grid', font=('MSSansSerif', 14, 'bold')).pack(expand = 0) self.enableGrid = BooleanVar() self.enableGridButton = Checkbutton( gridPage, text = 'Enabled/Disabled', anchor = 'w', justify = LEFT, variable = self.enableGrid, command = self.toggleGrid) self.enableGridButton.pack(fill = X, expand = 0) self.xyzSnap = BooleanVar() self.xyzSnapButton = Checkbutton( gridPage, text = 'XYZ Snap', anchor = 'w', justify = LEFT, variable = self.xyzSnap, command = self.toggleXyzSnap) self.xyzSnapButton.pack(fill = X, expand = 0) self.hprSnap = BooleanVar() self.hprSnapButton = Checkbutton( gridPage, text = 'HPR Snap', anchor = 'w', justify = LEFT, variable = self.hprSnap, command = self.toggleHprSnap) self.hprSnapButton.pack(fill = X, expand = 0) self.gridSpacing = Floater.Floater( gridPage, text = 'Grid Spacing', min = 0.1, initialValue = direct.grid.getGridSpacing()) self.gridSpacing['command'] = direct.grid.setGridSpacing self.gridSpacing.pack(fill = X, expand = 0) self.gridSize = Floater.Floater( gridPage, text = 'Grid Size', min = 1.0, initialValue = direct.grid.getGridSize()) self.gridSize['command'] = direct.grid.setGridSize self.gridSize.pack(fill = X, expand = 0) self.gridSnapAngle = Dial.Dial( gridPage, text = 'Snap Angle', min = 0.0, max = 360.0, numTicks = 12, fRollover = 0, initialValue = direct.grid.getSnapAngle()) self.gridSnapAngle['command'] = direct.grid.setSnapAngle self.gridSnapAngle.pack(fill = X, expand = 0) ## DEVICE PAGE ## Label(devicePage, text = 'DEVICES', font=('MSSansSerif', 14, 'bold')).pack(expand = 0) if direct.joybox != None: joyboxFrame = Frame(devicePage, borderwidth = 2, relief = 'sunken') Label(joyboxFrame, text = 'Joybox', font=('MSSansSerif', 14, 'bold')).pack(expand = 0) self.enableJoybox = BooleanVar() self.enableJoybox.set(1) self.enableJoyboxButton = Checkbutton( joyboxFrame, text = 'Enabled/Disabled', anchor = 'w', justify = LEFT, variable = self.enableJoybox, command = self.toggleJoybox) self.enableJoyboxButton.pack(fill = X, expand = 0) joyboxFrame.pack(fill = X, expand = 0) self.jbModeMenu = Pmw.ComboBox( joyboxFrame, labelpos = W, label_text = 'Joybox Mode:', label_width = 16, entry_width = 20, selectioncommand = self.selectJBModeNamed, scrolledlist_items = ['Joe Mode', 'Drive Mode', 'Orbit Mode', 'Look At Mode', 'Look Around Mode', 'Walkthru Mode', 'Demo Mode', 'HPRXYZ Mode']) self.jbModeMenu.selectitem('Joe Mode') self.jbModeMenu.pack(fill = X, expand = 1) self.jbNodePathMenu = Pmw.ComboBox( joyboxFrame, labelpos = W, label_text = 'Joybox Node Path:', label_width = 16, entry_width = 20, selectioncommand = self.selectJBNodePathNamed, scrolledlist_items = self.jbNodePathNames) self.jbNodePathMenu.selectitem('camera') self.jbNodePathMenuEntry = ( self.jbNodePathMenu.component('entryfield_entry')) self.jbNodePathMenuBG = ( self.jbNodePathMenuEntry.configure('background')[3]) self.jbNodePathMenu.pack(fill = X, expand = 1) self.bind(self.jbNodePathMenu, 'Select node path to manipulate using the joybox') self.jbXyzSF = EntryScale.EntryScale( joyboxFrame, text = 'XYZ Scale Factor', initialValue = 1.0, hull_relief = RIDGE, hull_borderwidth = 2, min = 1.0, max = 100.0) self.jbXyzSF['command'] = ( lambda v: direct.joybox.setXyzMultiplier(v)) self.jbXyzSF.pack(fill = X, expand = 0) self.bind(self.jbXyzSF, 'Set joybox XYZ speed multiplier') self.jbHprSF = EntryScale.EntryScale( joyboxFrame, text = 'HPR Scale Factor', initialValue = 1.0, hull_relief = RIDGE, hull_borderwidth = 2, min = 1.0, max = 100.0) self.jbHprSF['command'] = ( lambda v: direct.joybox.setHprMultiplier(v)) self.jbHprSF.pack(fill = X, expand = 0) self.bind(self.jbHprSF, 'Set joybox HPR speed multiplier') notebook.setnaturalsize() mainFrame.pack(fill = 'both', expand = 1) # Create some buttons in the bottom tray self.createButtons() # Clean up things when you destroy the panel interior.bind('', self.onDestroy) def createButtons(self): # Grid: enable/disable, xyz/hpr snap, snap to plane # Render mode: wireframe, lights, texture self.buttonAdd('Toggle Widget Viz', helpMessage='Toggle Object Handles Visability', statusMessage='Toggle Object Handles Visability', command=direct.toggleWidgetVis) self.buttonAdd( 'Toggle Widget Mode', helpMessage='Toggle Widget Move/COA Mode', statusMessage='Toggle Widget Move/COA Mode', command=direct.manipulationControl.toggleObjectHandlesMode) # Make all buttons as wide as widest self.alignbuttons() def toggleDirect(self): if self.directEnabled.get(): direct.enable() else: direct.disable() def toggleDirectGrid(self): if self.directGridEnabled.get(): direct.grid.enable() else: direct.grid.disable() def selectedNodePathHook(self, nodePath): # Make sure node path is in nodePathDict # MRM: Do we need to truncate list? if isinstance(nodePath, NodePath): self.addNodePath(nodePath) def selectNodePathNamed(self, name): # See if node path has already been selected nodePath = self.nodePathDict.get(name, None) # If not, see if listbox evals into a node path if (nodePath == None): # See if this evaluates into a node path try: nodePath = eval(name) if isinstance(nodePath, NodePath): self.addNodePath(nodePath) else: # Good eval but not a node path, give up nodePath = None except: # Bogus eval nodePath = None # Clear bogus entry from listbox listbox = self.nodePathMenu.component('scrolledlist') listbox.setlist(self.nodePathNames) # Did we finally get something? if (nodePath != None): # Yes, select it! direct.select(nodePath) def addNodePath(self, nodePath): self.addNodePathToDict(nodePath, self.nodePathNames, self.nodePathMenu, self.nodePathDict) def selectJBModeNamed(self, name): if name == 'Joe Mode': direct.joybox.joeMode() elif name == 'Drive Mode': direct.joybox.driveMode() elif name == 'Orbit Mode': direct.joybox.orbitMode() elif name == 'Look At Mode': direct.joybox.lookAtMode() elif name == 'Look Around Mode': direct.joybox.lookAroundMode() elif name == 'Walkthru Mode': direct.joybox.walkthruMode() elif name == 'Demo Mode': direct.joybox.demoMode() elif name == 'HPRXYZ Mode': direct.joybox.hprXyzMode() def selectJBNodePathNamed(self, name): if name == 'selected': nodePath = direct.selected.last # Add Combo box entry for this selected object self.addJBNodePath(nodePath) else: # See if node path has already been selected nodePath = self.jbNodePathDict.get(name, None) if (nodePath == None): # If not, see if listbox evals into a node path try: nodePath = eval(name) if isinstance(nodePath, NodePath): self.addJBNodePath(nodePath) else: # Good eval but not a node path, give up nodePath = None except: # Bogus eval nodePath = None # Clear bogus entry from listbox listbox = self.jbNodePathMenu.component('scrolledlist') listbox.setlist(self.jbNodePathNames) # Did we finally get something? if (nodePath != None): # Yes, select it! if (nodePath == 'No Node Path'): direct.joybox.setNodePath(None) else: direct.joybox.setNodePath(nodePath) def addJBNodePath(self, nodePath): self.addNodePathToDict(nodePath, self.jbNodePathNames, self.jbNodePathMenu, self.jbNodePathDict) def addNodePathToDict(self, nodePath, names, menu, dict): if not nodePath: return # Get node path's name name = nodePath.getName() if name in ['parent', 'render', 'camera']: dictName = name else: # Generate a unique name for the dict dictName = name + '-' + `nodePath.id().this` if not dict.has_key(dictName): # Update combo box to include new item names.append(dictName) listbox = menu.component('scrolledlist') listbox.setlist(names) # Add new item to dictionary dict[dictName] = nodePath menu.selectitem(dictName) ## ENVIRONMENT CONTROLS ## # Background # def setBackgroundColor(self, color): base.win.getGsg().setColorClearValue( VBase4(color[0]/255.0, color[1]/255.0, color[2]/255.0, 1.0)) def selectDisplayRegionNamed(self, name): if (string.find(name, 'Display Region ') >= 0): drIndex = string.atoi(name[-1:]) self.activeDisplayRegion = direct.drList[drIndex] else: self.activeDisplayRegion = None # Make sure info is current self.updateDisplayRegionInfo() def setNear(self, near): dr = self.activeDisplayRegion if dr: dr.camNode.setNear(near) def setFar(self, far): dr = self.activeDisplayRegion if dr: dr.camNode.setFar(far) def setHFov(self, hFov): dr = self.activeDisplayRegion if dr: if self.lockedFov.get(): sf = hFov/dr.camNode.getHfov() vFov = min(dr.camNode.getVfov() * sf, 170.0) dr.camNode.setFov(hFov, vFov) # Update scale self.vFov.set(vFov, 0) else: # Just set horizontal dr.camNode.setHfov(hFov) def setVFov(self, vFov): dr = self.activeDisplayRegion if dr: if self.lockedFov.get(): sf = vFov/dr.camNode.getVfov() hFov = min(dr.camNode.getHfov() * sf, 170.0) dr.camNode.setFov(hFov, vFov) # Update scale self.hFov.set(hFov, 0) else: # Just set horizontal dr.camNode.setVfov(vFov) def resetFov(self): dr = self.activeDisplayRegion if dr: dr.camNode.setFov(45.0, 33.75) self.hFov.set(45.0, 0) self.vFov.set(33.75, 0) # Lights # def selectLightNamed(self, name): self.activeLight = None for light in direct.lights: if name == light.getName(): self.activeLight = light break if self.activeLight == None: self.activeLight = direct.lights.create(name) if self.activeLight: if isinstance(self.activeLight, AmbientLight): self.lightNotebook.selectpage('Ambient') elif isinstance(self.activeLight, DirectionalLight): self.lightNotebook.selectpage('Directional') elif isinstance(self.activeLight, PointLight): self.lightNotebook.selectpage('Point') elif isinstance(self.activeLight, Spotlight): self.lightNotebook.selectpage('Spot') else: # Restore valid data listbox = self.lightMenu.component('scrolledlist') listbox.setlist(direct.lights.nameList) if len(direct.lights) > 0: self.lightMenu.selectitem(direct.lights[0].getName()) # Make sure info is current self.updateLightInfo() def addAmbient(self): direct.lights.create('ambient') def addDirectional(self): direct.lights.create('directional') def addPoint(self): direct.lights.create('point') def addSpot(self): direct.lights.create('spot') def addLight(self, light): # Make list reflect current list of lights listbox = self.lightMenu.component('scrolledlist') listbox.setlist(direct.lights.nameList) # Select the newly added light self.lightMenu.selectitem(light.getName()) # And show corresponding page self.selectLightNamed(light.getName()) def toggleLights(self): if self.enableLights.get(): direct.lights.allOn() else: direct.lights.allOff() def toggleActiveLight(self): if self.activeLight: if self.lightActive.get(): direct.lights.setOn(self.activeLight) else: direct.lights.setOff(self.activeLight) def setLightColor(self, color): if self.activeLight: self.activeLight.setColor(Vec4(color[0]/255.0, color[1]/255.0, color[2]/255.0, color[3]/255.0)) def setSpecularColor(self, color): if self.activeLight: self.activeLight.setSpecular(Vec4(color[0]/255.0, color[1]/255.0, color[2]/255.0, color[3]/255.0)) def setConstantAttenuation(self, value): if self.activeLight: self.activeLight.setConstantAttenuation(value) def setLinearAttenuation(self, value): if self.activeLight: self.activeLight.setLinearAttenuation(value) def setQuadraticAttenuation(self, value): if self.activeLight: self.activeLight.setQuadraticAttenuation(value) def setExponent(self, value): if self.activeLight: self.activeLight.setExponent(value) ## GRID CONTROLS ## def toggleGrid(self): if self.enableGrid.get(): direct.grid.enable() else: direct.grid.disable() def toggleXyzSnap(self): direct.grid.setXyzSnap(self.xyzSnap.get()) def toggleHprSnap(self): direct.grid.setHprSnap(self.hprSnap.get()) ## DEVICE CONTROLS def toggleJoybox(self): if self.enableJoybox.get(): direct.joybox.enable() else: direct.joybox.disable() ## UPDATE INFO ## def updateInfo(self, page = 'Environment'): if page == 'Environment': self.updateEnvironmentInfo() elif page == 'Lights': self.updateLightInfo() elif page == 'Grid': self.updateGridInfo() def updateEnvironmentInfo(self): bkgrdColor = base.win.getGsg().getColorClearValue() * 255.0 self.backgroundColor.set([bkgrdColor[0], bkgrdColor[1], bkgrdColor[2], bkgrdColor[3]], 0) self.updateDisplayRegionInfo() def updateDisplayRegionInfo(self): if self.activeDisplayRegion: self.nearPlane.set(self.activeDisplayRegion.near, 0) self.farPlane.set(self.activeDisplayRegion.far, 0) self.hFov.set(self.activeDisplayRegion.fovH, 0) self.vFov.set(self.activeDisplayRegion.fovV, 0) def updateLightInfo(self, page = None): # Set main lighting button self.enableLights.set( base.initialState.hasAttribute(LightTransition.getClassType())) # Set light specific info if self.activeLight: l = self.activeLight self.lightActive.set(direct.lights.la.isOn(l)) lightColor = l.getColor() * 255.0 self.lightColor.set([lightColor[0], lightColor[1], lightColor[2], lightColor[3]], 0) if isinstance(l, DirectionalLight): specularColor = l.getSpecular() * 255.0 self.dSpecularColor.set([specularColor[0], specularColor[1], specularColor[2], specularColor[3]], 0) elif isinstance(l, PointLight): specularColor = l.getSpecular() * 255.0 self.pSpecularColor.set([specularColor[0], specularColor[1], specularColor[2], specularColor[3]], 0) constantAtten = l.getConstantAttenuation() self.pConstantAttenuation.set(constantAtten, 0) linearAtten = l.getLinearAttenuation() self.pLinearAttenuation.set(linearAtten, 0) quadraticAtten = l.getQuadraticAttenuation() self.pQuadraticAttenuation.set(quadraticAtten, 0) elif isinstance(l, Spotlight): specularColor = l.getSpecular() * 255.0 self.sSpecularColor.set([specularColor[0], specularColor[1], specularColor[2], specularColor[3]], 0) constantAtten = l.getConstantAttenuation() self.sConstantAttenuation.set(constantAtten, 0) linearAtten = l.getLinearAttenuation() self.sLinearAttenuation.set(linearAtten, 0) quadraticAtten = l.getQuadraticAttenuation() self.sQuadraticAttenuation.set(quadraticAtten, 0) def updateGridInfo(self): self.enableGrid.set(direct.grid.isEnabled()) self.xyzSnap.set(direct.grid.getXyzSnap()) self.hprSnap.set(direct.grid.getHprSnap()) self.gridSpacing.set(direct.grid.getGridSpacing(), 0) self.gridSize.set(direct.grid.getGridSize(), 0) self.gridSnapAngle.set(direct.grid.getSnapAngle(), 0) # UNDO/REDO def pushUndo(self, fResetRedo = 1): direct.pushUndo([self['nodePath']]) def undoHook(self): pass def pushUndoHook(self): # Make sure button is reactivated self.undoButton.configure(state = 'normal') def undoListEmptyHook(self): # Make sure button is deactivated self.undoButton.configure(state = 'disabled') def pushRedo(self): direct.pushRedo([self['nodePath']]) def redoHook(self): pass def pushRedoHook(self): # Make sure button is reactivated self.redoButton.configure(state = 'normal') def redoListEmptyHook(self): # Make sure button is deactivated self.redoButton.configure(state = 'disabled') def onDestroy(self, event): # Remove hooks for event, method in self.actionEvents: self.ignore(event)