diff --git a/direct/src/cluster/ClusterClient.py b/direct/src/cluster/ClusterClient.py index 9721541a68..532da0b55f 100644 --- a/direct/src/cluster/ClusterClient.py +++ b/direct/src/cluster/ClusterClient.py @@ -1,14 +1,10 @@ """ClusterClient: Master for mutlipiping or PC clusters. """ from PandaModules import * -from TaskManagerGlobal import * -from ShowBaseGlobal import * -import Task -import DirectNotifyGlobal -import Datagram -import DirectObject from ClusterMsgs import * -import time +import DirectNotifyGlobal +import DirectObject +import Task class ClusterConfigItem: def __init__(self, serverFunction, serverName, port): @@ -79,10 +75,12 @@ class DisplayConnection: # the following should only be called by a synchronized cluster manger def getSwapReady(self): - datagram = self.msgHandler.blockingRead(self.qcr) - (type,dgi) = self.msgHandler.readHeader(datagram) - if type != CLUSTER_SWAP_READY: - self.notify.warning( ('was expecting SWAP_READY, got %d' % type) ) + while 1: + (datagram, dgi,type) = self.msgHandler.blockingRead(self.qcr) + if type == CLUSTER_SWAP_READY: + break + else: + self.notify.warning('was expecting SWAP_READY, got %d' % type) # the following should only be called by a synchronized cluster manger def sendSwapNow(self): @@ -97,6 +95,13 @@ class DisplayConnection: datagram = self.msgHandler.makeCommandStringDatagram(commandString) self.cw.send(datagram, self.tcpConn) + def sendExit(self): + ClusterManager.notify.debug( + "display connect send exit, packet %d" % + self.msgHandler.packetNumber) + datagram = self.msgHandler.makeExitDatagram() + self.cw.send(datagram, self.tcpConn) + class ClusterManager(DirectObject.DirectObject): notify = DirectNotifyGlobal.directNotify.newCategory("ClusterClient") MGR_NUM = 1000000 @@ -127,9 +132,7 @@ class ClusterManager(DirectObject.DirectObject): server.sendMoveCam(xyz,hpr) def startMoveCamTask(self): - task = Task.Task(self.moveCameraTask,49) - taskMgr.add(task, "moveCamTask") - return None + taskMgr.add(self.moveCameraTask, "moveCamTask", 49) def moveCameraTask(self,task): self.moveCamera( @@ -142,7 +145,15 @@ class ClusterManager(DirectObject.DirectObject): for server in self.serverList: server.sendCommandString(commandString) # Execute locally - exec( commandString, globals() ) + exec( commandString, globals()) + + def exit(self): + # Execute remotely + for server in self.serverList: + server.sendExit() + # Execute locally + import sys + sys.exit() class ClusterManagerSync(ClusterManager): @@ -154,8 +165,7 @@ class ClusterManagerSync(ClusterManager): self.startSwapCoordinatorTask() def startSwapCoordinatorTask(self): - task = Task.Task(self.swapCoordinator,51) - taskMgr.add(task, "clientSwapCoordinator") + taskMgr.add(self.swapCoordinator, "clientSwapCoordinator", 51) return None def swapCoordinator(self,task): diff --git a/direct/src/cluster/ClusterConfig.py b/direct/src/cluster/ClusterConfig.py index 8be19e6e0a..306a40e3ae 100644 --- a/direct/src/cluster/ClusterConfig.py +++ b/direct/src/cluster/ClusterConfig.py @@ -23,7 +23,7 @@ ClientConfigs = { {'pos' : Vec3(0), 'hpr' : Vec3(60,0,0)} ], - 'cavetest' : [{'pos' : Vec3(-0.105, -0.020, 5.000), + 'cavetest-old' : [{'pos' : Vec3(-0.105, -0.020, 5.000), 'hpr' : Vec3(51.213, 0.000, 0.000), 'focal length' : 0.809, 'film size' : (1.000, 0.831), @@ -48,7 +48,7 @@ ClientConfigs = { 'film offset' : (0.000, 0.173), }, ], - 'cavetest-all' : [{'pos' : Vec3(-0.105, -0.020, 5.000), + 'cavetest' : [{'pos' : Vec3(-0.105, -0.020, 5.000), 'hpr' : Vec3(51.213, 0.000, 0.000), 'focal length' : 0.809, 'film size' : (1.000, 0.831), @@ -100,7 +100,7 @@ def createClusterManager(): displayConfigs = [] configList = ClientConfigs[clusterConfig] numConfigs = len(configList) - for i in range(numConfigs): + for i in range(1,numConfigs): configData = configList[i] serverConfigName = 'display%d' % i serverString = base.config.GetString(serverConfigName, '') diff --git a/direct/src/cluster/ClusterMsgs.py b/direct/src/cluster/ClusterMsgs.py index 34ba60f2e0..30231c4851 100644 --- a/direct/src/cluster/ClusterMsgs.py +++ b/direct/src/cluster/ClusterMsgs.py @@ -7,70 +7,77 @@ # recieved are handled outside of here, after the header (message type # and number) are read here. +from PandaModules import * +import Datagram +import time + #these are the types of messages that are currently supported. -CLUSTER_NOTHING = -1 +CLUSTER_NONE = 0 CLUSTER_CAM_OFFSET = 1 CLUSTER_CAM_FRUSTUM = 2 -CLUSTER_POS_UPDATE = 3 +CLUSTER_CAM_MOVEMENT = 3 CLUSTER_SWAP_READY = 4 CLUSTER_SWAP_NOW = 5 CLUSTER_COMMAND_STRING = 6 +CLUSTER_EXIT = 100 #Port number for cluster rendering CLUSTER_PORT = 1970 -from ShowBaseGlobal import * -from PandaModules import * -from TaskManagerGlobal import * -import Task -import DirectNotifyGlobal -import Datagram -import time - class MsgHandler: """MsgHandler: wrapper for PC clusters/multi-piping networking""" def __init__(self,packetStart, notify): - #packetStart can be used to distinguish which MsgHandler sends a - #given packet. + # packetStart can be used to distinguish which MsgHandler sends a + # given packet. self.packetNumber = packetStart self.notify = notify def nonBlockingRead(self,qcr): - availGetVal = qcr.dataAvailable() - if availGetVal: + """ + Return a datagram iterator and type if data is available on the + queued connection reader + """ + if qcr.dataAvailable(): datagram = NetDatagram() - readRetVal = qcr.getData(datagram) - if readRetVal: - dgi = DatagramIterator(datagram) - number = dgi.getUint32() - type = dgi.getUint8() - self.notify.debug( ("Packet %d type %d recieved" % (number,type)) ) + if qcr.getData(datagram): + (dgi, type) = self.readHeader(datagram) else: + dgi = None + type = CLUSTER_NONE self.notify.warning("getData returned false") else: - type = CLUSTER_NOTHING dgi = None - return (type,dgi) - - def readHeader(self,datagram): - dgi = DatagramIterator(datagram) - number = dgi.getUint32() - type = dgi.getUint8() - self.notify.debug( ("Packet %d type %d recieved" % (number,type)) ) - return (type,dgi) + type = CLUSTER_NONE + # Note, return datagram to keep a handle on the data + return (datagram, dgi,type) def blockingRead(self,qcr): + """ + Block until data is available on the queued connection reader. + Returns a datagram iterator and type + """ while not qcr.dataAvailable(): # The following may not be necessary. # I just wanted some # time given to the operating system while # busy waiting. time.sleep(0.002) + # Data is available, create a datagram iterator datagram = NetDatagram() - readRetVal = qcr.getData(datagram) - if not readRetVal: + if qcr.getData(datagram): + (dgi, type) = self.readHeader(datagram) + else: + (dgi, type) = (None, CLUSTER_NONE) self.notify.warning("getData returned false") - return datagram + # Note, return datagram to keep a handle on the data + return (datagram, dgi, type) + + def readHeader(self,datagram): + dgi = DatagramIterator(datagram) + number = dgi.getUint32() + type = dgi.getUint8() + self.notify.debug("Packet %d type %d recieved" % (number,type)) + return (dgi,type) def makeCamOffsetDatagram(self,xyz,hpr): datagram = Datagram.Datagram() @@ -85,14 +92,6 @@ class MsgHandler: datagram.addFloat32(hpr[2]) return datagram - def makeCommandStringDatagram(self, commandString): - datagram = Datagram.Datagram() - datagram.addUint32(self.packetNumber) - self.packetNumber = self.packetNumber + 1 - datagram.addUint8(CLUSTER_COMMAND_STRING) - datagram.addString(commandString) - return datagram - def makeCamFrustumDatagram(self,focalLength, filmSize, filmOffset): datagram = Datagram.Datagram() datagram.addUint32(self.packetNumber) @@ -109,7 +108,7 @@ class MsgHandler: datagram = Datagram.Datagram() datagram.addUint32(self.packetNumber) self.packetNumber = self.packetNumber + 1 - datagram.addUint8(CLUSTER_POS_UPDATE) + datagram.addUint8(CLUSTER_CAM_MOVEMENT) datagram.addFloat32(xyz[0]) datagram.addFloat32(xyz[1]) datagram.addFloat32(xyz[2]) @@ -118,6 +117,14 @@ class MsgHandler: datagram.addFloat32(hpr[2]) return datagram + def makeCommandStringDatagram(self, commandString): + datagram = Datagram.Datagram() + datagram.addUint32(self.packetNumber) + self.packetNumber = self.packetNumber + 1 + datagram.addUint8(CLUSTER_COMMAND_STRING) + datagram.addString(commandString) + return datagram + def makeSwapNowDatagram(self): datagram = Datagram.Datagram() datagram.addUint32(self.packetNumber) @@ -131,6 +138,13 @@ class MsgHandler: self.packetNumber = self.packetNumber + 1 datagram.addUint8(CLUSTER_SWAP_READY) return datagram + + def makeExitDatagram(self): + datagram = Datagram.Datagram() + datagram.addUint32(self.packetNumber) + self.packetNumber = self.packetNumber + 1 + datagram.addUint8(CLUSTER_EXIT) + return datagram diff --git a/direct/src/cluster/ClusterServer.py b/direct/src/cluster/ClusterServer.py index e892bfef77..cfee4c8258 100644 --- a/direct/src/cluster/ClusterServer.py +++ b/direct/src/cluster/ClusterServer.py @@ -1,18 +1,11 @@ """ServerRepository module: contains the ServerRepository class""" -from ShowBaseGlobal import * -from ClusterMsgs import * -import DirectObject -import Datagram -#import DatagramIterator -#import NetDatagram -import __builtin__ -import time from PandaModules import * -from TaskManagerGlobal import * +from ClusterMsgs import * from MsgTypes import * -import Task import DirectNotifyGlobal +import DirectObject +import Task # Cam offset handling is a little sloppy. The problem is that there is a # single arc used for both movement of the camera, and the offset of the @@ -76,32 +69,32 @@ class ClusterServer(DirectObject.DirectObject): # Run this task just after the listener poll task and dataloop taskMgr.add(self.readerPollTask, "serverReaderPollTask", -39) - def readerPollTask(self): - while self.qcr.dataAvailable(): - datagram = NetDatagram() - readRetVal = self.qcr.getData(datagram) - if readRetVal: - self.handleDatagram(datagram) + def readerPollTask(self, state): + # Process all available datagrams + while 1: + (datagram, dgi,type) = self.msgHandler.nonBlockingRead(self.qcr) + if type is CLUSTER_NONE: + break else: - self.notify.warning("getData returned false") + handleDatagram(dgi, type) return Task.cont - def handleDatagram(self, datagram): - (type, dgi) = self.msgHandler.nonBlockingRead(self.qcr) - if type==CLUSTER_CAM_OFFSET: + def handleDatagram(self, dgi, type): + if type == CLUSTER_NONE: + pass + elif type == CLUSTER_EXIT: + import sys + sys.exit() + elif type == CLUSTER_CAM_OFFSET: self.handleCamOffset(dgi) - elif type==CLUSTER_CAM_FRUSTUM: + elif type == CLUSTER_CAM_FRUSTUM: self.handleCamFrustum(dgi) - elif type==CLUSTER_POS_UPDATE: + elif type == CLUSTER_CAM_MOVEMENT: self.handleCamMovement(dgi) - elif type==CLUSTER_SWAP_READY: - pass - elif type==CLUSTER_SWAP_NOW: - pass - elif type==CLUSTER_COMMAND_STRING: + elif type == CLUSTER_COMMAND_STRING: self.handleCommandString(dgi) else: - self.notify.warning("recieved unknown packet") + self.notify.warning("Recieved unknown packet type:" % type) return type def handleCamOffset(self,dgi): @@ -147,7 +140,7 @@ class ClusterServer(DirectObject.DirectObject): def handleCommandString(self, dgi): command = dgi.getString() - exec( command, globals() ) + exec( command, globals()) class ClusterServerSync(ClusterServer): @@ -163,11 +156,10 @@ class ClusterServerSync(ClusterServer): pass elif self.qcr.isConnectionOk(self.lastConnection): # Process datagrams till you get a postion update - type = CLUSTER_NOTHING - while type != CLUSTER_POS_UPDATE: - datagram = self.msgHandler.blockingRead(self.qcr) - (type,dgi) = self.msgHandler.readHeader(datagram) - if type == CLUSTER_POS_UPDATE: + type = CLUSTER_NONE + while type != CLUSTER_CAM_MOVEMENT: + (datagram,dgi,type) = self.msgHandler.blockingRead(self.qcr) + if type == CLUSTER_CAM_MOVEMENT: # Move camera self.handleCamMovement(dgi) # Set flag for swap coordinator @@ -194,13 +186,14 @@ class ClusterServerSync(ClusterServer): if self.posRecieved: self.posRecieved = 0 self.sendSwapReady() - datagram = self.msgHandler.blockingRead(self.qcr) - (type,dgi) = self.msgHandler.readHeader(datagram) - if type == CLUSTER_SWAP_NOW: - self.notify.debug('swapping') - base.win.swap() - else: - self.notify.warning("did not get expected swap now") + while 1: + (datagram,dgi,type) = self.msgHandler.blockingRead(self.qcr) + if type == CLUSTER_SWAP_NOW: + self.notify.debug('swapping') + base.win.swap() + break + else: + self.handleDatagram(dgi,type) return Task.cont diff --git a/direct/src/directtools/DirectCameraControl.py b/direct/src/directtools/DirectCameraControl.py index c5db3d7ec5..5b4feb8b82 100644 --- a/direct/src/directtools/DirectCameraControl.py +++ b/direct/src/directtools/DirectCameraControl.py @@ -260,11 +260,23 @@ class DirectCameraControl(PandaObject): angle = getCrankAngle(state.coaCenter) deltaAngle = angle - state.lastAngle state.lastAngle = angle + if deltaAngle != 0.0: + print deltaAngle + print 'cam Manip before' + print self.camManipRef.getMat() if base.config.GetBool('temp-hpr-fix',0): self.camManipRef.setHpr(self.camManipRef, 0, 0, deltaAngle) else: self.camManipRef.setHpr(self.camManipRef, 0, 0, -deltaAngle) + print 'cam Manip after' + print self.camManipRef.getMat() + print 'direct camera before' + print direct.camera.getMat() direct.camera.setMat(self.camManipRef, wrtMat) + print 'direct camera after' + print direct.camera.getMat() + print + print return Task.cont def lockCOA(self): @@ -352,6 +364,8 @@ class DirectCameraControl(PandaObject): # ref = base.cam ref = direct.drList.getCurrentDr().cam self.coaMarker.setPos(ref, self.coa) + pos = self.coaMarker.getPos() + self.coaMarker.setPosHprScale(pos, Vec3(0), Vec3(1)) # Resize it self.updateCoaMarkerSize(coaDist) # Record marker pos in render space diff --git a/direct/src/directtools/DirectManipulation.py b/direct/src/directtools/DirectManipulation.py index 2c6499c50f..f08562f056 100644 --- a/direct/src/directtools/DirectManipulation.py +++ b/direct/src/directtools/DirectManipulation.py @@ -98,7 +98,7 @@ class DirectManipulationControl(PandaObject): self.hitPt.assign(hitPt) self.hitPtDist = hitPtDist # Find the node path from the node found above - nodePath = render.findPathDownTo(node) + nodePath = render.findAllPathsTo(node)[0] # Select it direct.select(nodePath, direct.fShift) else: @@ -223,7 +223,7 @@ class DirectManipulationControl(PandaObject): self.objectHandles.transferObjectHandlesScale() self.fScaling = 0 # Alt key switches to a scaling mode - if direct.fAlt: + if direct.fControl: self.fScaling = 1 self.scale3D(state) # Otherwise, manip mode depends on where you started diff --git a/direct/src/directtools/DirectSelection.py b/direct/src/directtools/DirectSelection.py index d91fd3c677..80b0a8603b 100644 --- a/direct/src/directtools/DirectSelection.py +++ b/direct/src/directtools/DirectSelection.py @@ -22,7 +22,7 @@ class DirectNodePath(NodePath): # and its center of action (COA) self.mCoa2Dnp = Mat4() self.mCoa2Dnp.assign(Mat4.identMat()) - # self.mCoa2Dnp.setRow(3, Vec4(center[0], center[1], center[2], 1)) + self.mCoa2Dnp.setRow(3, Vec4(center[0], center[1], center[2], 1)) # Transform from nodePath to widget self.mDnp2Widget = Mat4() self.mDnp2Widget.assign(Mat4.identMat()) @@ -127,18 +127,7 @@ class SelectedNodePaths(PandaObject): """ dnp = self.selectedDict.get(id, None) if dnp: - # Found item in selected Dictionary, is it still valid? - if dnp.verifyConnectivity(): - # Yes - return dnp - else: - # Not valid anymore, try to repair - if dnp.repairConnectivity(render): - # Fixed, return node path - return dnp - else: - del(self.selectedDict[id]) - return None + return dnp else: # Not in selected dictionary return None @@ -152,18 +141,8 @@ class SelectedNodePaths(PandaObject): """ dnp = self.deselectedDict.get(id, None) if dnp: - # Found item in deselected Dictionary, is it still valid? - if dnp.verifyConnectivity(): - # Yes - return dnp - else: - # Not valid anymore, try to repair - if dnp.repairConnectivity(render): - # Fixed, return node path - return dnp - else: - del(self.deselectedDict[id]) - return None + # Yes + return dnp else: # Not in deselected dictionary return None @@ -344,10 +323,11 @@ class DirectBoundingBox: def getBounds(self): # Get a node path's bounds - nodeBounds = self.nodePath.node().getBound() + nodeBounds = BoundingSphere() + nodeBounds.extendBy(self.nodePath.node().getInternalBound()) for child in self.nodePath.getChildrenAsList(): - nodeBounds.extendBy(child.arc().getBound()) - return nodeBounds.makeCopy() + nodeBounds.extendBy(child.getBounds()) + return nodeBounds.makeCopy() def show(self): self.lines.reparentTo(self.nodePath) @@ -428,11 +408,11 @@ class SelectionRay: for i in range(0,self.numEntries): entry = self.cq.getEntry(i) node = entry.getIntoNode() - nodePath = render.findPathDownTo(node) + nodePath = render.findAllPathsTo(node)[0] # Don't pick hidden nodes - if node.isHidden(): - pass - elif fIgnoreCamera and (direct.camera in nodePath.getAncestry()): + #if node.isHidden(): + #pass + if fIgnoreCamera and (direct.camera in nodePath.getAncestry()): # This avoids things parented to a camera. Good idea? pass # Can pick unpickable, use the first visible node @@ -520,10 +500,11 @@ class SelectionRay: entry = self.cq.getEntry(i) node = entry.getIntoNode() # Don't pick hidden nodes - if node.isHidden(): - pass + # MRM: Doesn't work in new panda for GeomNodes + #if node.isHidden(): + #pass # Can pick unpickable, use the first visible node - elif fIntersectUnpickable: + if fIntersectUnpickable: self.cqIndex = i break # Is it a named node?, If so, see if it has a name diff --git a/direct/src/showbase/qpShowBase.py b/direct/src/showbase/qpShowBase.py index b2ce01653e..faadf39c1a 100644 --- a/direct/src/showbase/qpShowBase.py +++ b/direct/src/showbase/qpShowBase.py @@ -96,12 +96,7 @@ class ShowBase: self.camList = [] self.camNode = None self.camLens = None - - # base.camera is a little different; rather than referring to - # base.cameraList[0], it is instead the parent node of all - # cameras in base.cameraList. That way, multiple cameras can - # easily be dragged around by moving the one node. - self.camera = self.render.attachNewNode('camera') + self.camera = None self.cameraList = [] self.groupList = [] self.camera2d = self.render2d.attachNewNode('camera2d') @@ -383,8 +378,8 @@ class ShowBase: def getCameras(self, chanConfig): - """getCameras(self, chanConfig) - + """ + getCameras(self, chanConfig) Extracts the camera(s) out of the ChanConfig record, parents them all to base.camera, and adds them to base.cameraList. """ @@ -393,7 +388,7 @@ class ShowBase: # be more than one display region/camera node beneath each # one. for i in range(chanConfig.getNumGroups()): - camera = self.camera.attachNewNode(chanConfig.getGroupNode(i)) + camera = self.render.attachNewNode(chanConfig.getGroupNode(i)) cam = camera.find('**/+Camera') lens = cam.node().getLens() @@ -409,19 +404,18 @@ class ShowBase: for i in range(chanConfig.getNumDrs()): self.groupList.append(chanConfig.getGroupMembership(i)) - # Set the default camera + # Set the default camera and cam + if self.camera == None: + self.camera = self.cameraList[0] if self.cam == None: self.cam = self.camList[0] - # If you need to get a handle to the camera node itself, # use self.camNode. self.camNode = self.cam.node() - # If you need to adjust camera parameters, like fov or # near/far clipping planes, use self.camLens. self.camLens = self.camNode.getLens() - def getAlt(self): return base.mouseWatcherNode.getModifierButtons().isDown( KeyboardButton.alt()) @@ -576,12 +570,13 @@ class ShowBase: self.backfaceCullingOn() def backfaceCullingOn(self): - self.render.setTwoSided(self.wireframeEnabled) + if not self.backfaceCullingEnabled: + self.render.setTwoSided(0) self.backfaceCullingEnabled = 1 def backfaceCullingOff(self): - if not self.wireframeEnabled: - self.render.setTwoSided(0) + if self.backfaceCullingEnabled: + self.render.setTwoSided(1) self.backfaceCullingEnabled = 0 def toggleTexture(self): diff --git a/direct/src/task/Task.py b/direct/src/task/Task.py index 4a3d80a032..bc4f5aed5f 100644 --- a/direct/src/task/Task.py +++ b/direct/src/task/Task.py @@ -5,6 +5,7 @@ from MessengerGlobal import * import time import fnmatch import string +import signal # MRM: Need to make internal task variables like time, name, index # more unique (less likely to have name clashes) @@ -230,6 +231,8 @@ class TaskManager: TaskManager.notify = directNotify.newCategory("TaskManager") self.taskTimerVerbose = 0 self.extendedExceptions = 0 + self.fKeyboardInterrupt = 0 + self.interruptCount = 0 self.pStatsTasks = 0 self.resumeFunc = None self.fVerbose = 0 @@ -241,6 +244,14 @@ class TaskManager: self.fVerbose = value messenger.send('TaskManager-setVerbose', sentArgs = [value]) + def keyboardInterruptHandler(self, signalNumber, stackFrame): + self.fKeyboardInterrupt = 1 + self.interruptCount += 1 + if self.interruptCount == 2: + # The user must really want to interrupt this process + # Next time around use the default interrupt handler + signal.signal(signal.SIGINT, signal.default_int_handler) + def add(self, funcOrTask, name, priority = 0): """ Add a new task to the taskMgr. @@ -370,6 +381,12 @@ class TaskManager: if TaskManager.notify.getDebug(): TaskManager.notify.debug('step') self.currentTime, self.currentFrame = self.__getTimeFrame() + # Replace keyboard interrupt handler during task list processing + # so we catch the keyboard interrupt but don't handle it until + # after task list processing is complete. + self.fKeyboardInterrupt = 0 + self.interruptCount = 0 + signal.signal(signal.SIGINT, self.keyboardInterruptHandler) for task in self.taskList: task.setCurrentTimeFrame(self.currentTime, self.currentFrame) @@ -410,6 +427,10 @@ class TaskManager: self.__removeTask(task) else: raise StandardError, "Task named %s did not return cont, exit, or done" % task.name + # Restore default interrupt handler + signal.signal(signal.SIGINT, signal.default_int_handler) + if self.fKeyboardInterrupt: + raise KeyboardInterrupt return len(self.taskList) def run(self): diff --git a/direct/src/tkpanels/DirectSessionPanel.py b/direct/src/tkpanels/DirectSessionPanel.py index 9f2baf114a..7962762b76 100644 --- a/direct/src/tkpanels/DirectSessionPanel.py +++ b/direct/src/tkpanels/DirectSessionPanel.py @@ -695,7 +695,7 @@ class DirectSessionPanel(AppShell): dictName = name else: # Generate a unique name for the dict - dictName = name + '-' + `nodePath.id().this` + dictName = name + '-' + `nodePath.id()` if not dict.has_key(dictName): # Update combo box to include new item names.append(dictName) diff --git a/direct/src/tkpanels/MopathRecorder.py b/direct/src/tkpanels/MopathRecorder.py index 1228d04633..17556b5f43 100644 --- a/direct/src/tkpanels/MopathRecorder.py +++ b/direct/src/tkpanels/MopathRecorder.py @@ -292,8 +292,7 @@ class MopathRecorder(AppShell, PandaObject): resolution = 0.01, command = self.playbackGoTo, side = TOP) widget.component('hull')['relief'] = RIDGE # Kill playback task if drag slider - widget.component('scale').bind( - '', lambda e = None, s = self: s.stopPlayback()) + widget['preCallback'] = self.stopPlayback # Jam duration entry into entry scale self.createLabeledEntry(widget.labelFrame, 'Resample', 'Path Duration', 'Set total curve duration', @@ -371,7 +370,7 @@ class MopathRecorder(AppShell, PandaObject): 'Number of samples in resampled curve', resolution = 1, min = 2, max = 1000, command = self.setNumSamples) widget.component('hull')['relief'] = RIDGE - widget['preCallback'] = widget['postCallback'] = self.sampleCurve + widget['postCallback'] = self.sampleCurve frame = Frame(resampleFrame) self.createButton( @@ -785,7 +784,9 @@ class MopathRecorder(AppShell, PandaObject): def extractPointSetFromCurveCollection(self): # Use curve to compute new point set # Record maxT + print 'before', self.maxT self.maxT = self.curveCollection.getMaxT() + print 'after', self.maxT # Determine num samples # Limit point set to 1000 points and samples per second to 30 samplesPerSegment = min(30.0, 1000.0/self.curveCollection.getMaxT()) @@ -1232,7 +1233,7 @@ class MopathRecorder(AppShell, PandaObject): dictName = name else: # Generate a unique name for the dict - dictName = name + '-' + `nodePath.id().this` + dictName = name + '-' + `nodePath.id()` if not dict.has_key(dictName): # Update combo box to include new item names.append(dictName) @@ -1248,7 +1249,6 @@ class MopathRecorder(AppShell, PandaObject): def playbackGoTo(self, time): if self.curveCollection == None: return - print time self.playbackTime = CLAMP(time, 0.0, self.maxT) if self.curveCollection != None: pos = Point3(0) diff --git a/direct/src/tkpanels/Placer.py b/direct/src/tkpanels/Placer.py index d3f0d54633..892bf41100 100644 --- a/direct/src/tkpanels/Placer.py +++ b/direct/src/tkpanels/Placer.py @@ -493,7 +493,7 @@ class Placer(AppShell): dictName = name else: # Generate a unique name for the dict - dictName = name + '-' + `nodePath.id().this` + dictName = name + '-' + `nodePath.id()` if not dict.has_key(dictName): # Update combo box to include new item names.append(dictName) diff --git a/direct/src/tkwidgets/Slider.py b/direct/src/tkwidgets/Slider.py index 8a6875df18..e3ca05d140 100644 --- a/direct/src/tkwidgets/Slider.py +++ b/direct/src/tkwidgets/Slider.py @@ -374,6 +374,8 @@ class SliderWidget(Pmw.MegaWidget): if fInside: self._fPressInside = 1 self._fUpdate = 1 + if self['preCallback']: + apply(self['preCallback'], self['callbackData']) self._updateValue(event) else: self._fPressInside = 0 @@ -385,11 +387,16 @@ class SliderWidget(Pmw.MegaWidget): event.y_root - self._widget.winfo_rooty()) if canvasY > 0: self._fUpdate = 1 + if self['preCallback']: + apply(self['preCallback'], self['callbackData']) self._unpostOnNextRelease() elif self._fUpdate: self._updateValue(event) def _widgetBtnRelease(self, event): + # Do post callback if any + if self._fUpdate and self['postCallback']: + apply(self['postCallback'], self['callbackData']) if (self._fUnpost or (not (self._firstPress or self._fPressInside))): self._unpostSlider()