diff --git a/direct/src/directutil/DirectCameraControl.py b/direct/src/directutil/DirectCameraControl.py index 9c02b7440b..d89f8ca050 100644 --- a/direct/src/directutil/DirectCameraControl.py +++ b/direct/src/directutil/DirectCameraControl.py @@ -1,6 +1,7 @@ from PandaObject import * CAM_MOVE_DURATION = 1.0 +Y_AXIS = Vec3(0,1,0) class DirectCameraControl(PandaObject): def __init__(self, direct): @@ -34,7 +35,8 @@ class DirectCameraControl(PandaObject): # If shift key is pressed, just perform horiz and vert pan: self.spawnHPPan() else: - # Otherwise, check for a hit point based on current mouse position + # Otherwise, check for a hit point based on + # current mouse position # And then spawn task to determine mouse mode numEntries = self.direct.iRay.pickGeom( render,chan.mouseX,chan.mouseY) @@ -348,6 +350,43 @@ class DirectCameraControl(PandaObject): 0.0) return Task.cont + def fitOnWidget(self): + # Fit the node on the screen + + # stop any ongoing tasks + taskMgr.removeTasksNamed('manipulateCamera') + + # How big is the node? + nodeScale = self.direct.widget.getScale(render) + maxScale = max(nodeScale[0],nodeScale[1],nodeScale[2]) + maxDim = min(self.chan.nearWidth, self.chan.nearHeight) + + # At what distance does the object fill 30% of the screen? + # Assuming radius of 1 on widget + camY = self.chan.near * (2.0 * maxScale)/(0.3 * maxDim) + + # What is the vector through the center of the screen? + centerVec = Y_AXIS * camY + + # Where is the node relative to the viewpoint + vWidget2Camera = self.direct.widget.getPos(self.camera) + + # How far do you move the camera to be this distance from the node? + deltaMove = vWidget2Camera - centerVec + + # Move a target there + self.relNodePath.setPos(self.camera, deltaMove) + + parent = self.camera.getParent() + self.camera.wrtReparentTo(self.relNodePath) + fitTask = self.camera.lerpPos(Point3(0,0,0), + CAM_MOVE_DURATION, + blendType = 'easeInOut', + task = 'manipulateCamera') + # Upon death, reparent Cam to parent + fitTask.parent = parent + fitTask.uponDeath = self.reparentCam + def enableMouseFly(self): self.enableMouseInteraction() self.enableHotKeys() diff --git a/direct/src/directutil/DirectSession.py b/direct/src/directutil/DirectSession.py index 23ea1fbf76..524cc9141d 100644 --- a/direct/src/directutil/DirectSession.py +++ b/direct/src/directutil/DirectSession.py @@ -73,7 +73,10 @@ class DirectSession(PandaObject): # Adjust widgets size self.widget.setScale(dnp.getRadius()) - + # This is the additional scaling factor used to grow and + # shrink the widget + self.widget.setScalingFactor(1.0) + # Spawn task to have object handles follow the selected object taskMgr.removeTasksNamed('followSelectedNodePath') t = Task.Task(self.followSelectedNodePathTask) diff --git a/direct/src/showbase/FSM.py b/direct/src/showbase/FSM.py index 4d23eff5db..1481d6425b 100644 --- a/direct/src/showbase/FSM.py +++ b/direct/src/showbase/FSM.py @@ -97,6 +97,8 @@ class FSM(DirectObject): """__exitCurrent(self) Exit the current state""" FSM.notify.info("exiting %s" % self.__currentState.getName()) + messenger.send(self.getName() + '_' + + self.__currentState.getName() + '_exited') self.__currentState.exit() self.__currentState = None @@ -106,6 +108,8 @@ class FSM(DirectObject): if (aState in self.__states): self.__currentState = aState aState.enter() + messenger.send(self.getName() + '_' + + aState.getName() + '_entered') FSM.notify.info("entering %s" % aState.getName()) else: FSM.notify.error("enter: no such state") diff --git a/direct/src/showbase/State.py b/direct/src/showbase/State.py index 9e42054f4e..1439c9ccf9 100644 --- a/direct/src/showbase/State.py +++ b/direct/src/showbase/State.py @@ -16,6 +16,7 @@ class State(DirectObject): self.setEnterFunc(enterFunc) self.setExitFunc(exitFunc) self.setTransitions(transitions) + self.setDefaultPosition([]) self.__FSMList = None @@ -53,6 +54,14 @@ class State(DirectObject): """setTransitions(self, string[])""" self.__transitions = stateTransitions + def getDefaultPosition(self): + """getDefaultPosition(self)""" + return(self.__defaultPosition) + + def setDefaultPosition(self, defaultPosition): + """setDefaultPosition(self, x, y)""" + self.__defaultPosition = defaultPosition + # support for HFSMs diff --git a/direct/src/tkpanels/FSMInspector.py b/direct/src/tkpanels/FSMInspector.py index 5276d572c1..674f188316 100644 --- a/direct/src/tkpanels/FSMInspector.py +++ b/direct/src/tkpanels/FSMInspector.py @@ -1,3 +1,4 @@ +from PandaObject import * from Tkinter import * from tkSimpleDialog import askstring import Pmw @@ -6,23 +7,27 @@ import operator DELTA = (5.0 / 360.) * 2.0 * math.pi -class FSMInspector(Pmw.MegaToplevel): +class FSMInspector(Pmw.MegaToplevel, PandaObject): def __init__(self, parent = None, **kw): + # Initialize instance variables + self.states = [] self.stateInspectorDict = {} #define the megawidget options INITOPT = Pmw.INITOPT optiondefs = ( ('title', 'FSM Viewer', None), - ('currentFSM', (), None), + ('FSM', (), None), ('gridSize', '0.25i', self._setGridSize), ) self.defineoptions(kw, optiondefs) # Initialize the toplevel widget Pmw.MegaToplevel.__init__(self, parent) - + + self.fsm = self['FSM'] + # Create the components oldInterior = Pmw.MegaToplevel.interior(self) # The Menu Bar @@ -138,8 +143,8 @@ class FSMInspector(Pmw.MegaToplevel): for key in self.stateInspectorDict.keys(): si = self.stateInspectorDict[key] state = si.state - if state.transitionArray: - for name in state.transitionArray: + if state.getTransitions(): + for name in state.getTransitions(): self.connectStates(si, self.getStateInspector(name)) def connectStates(self, fromState, toState): @@ -199,29 +204,39 @@ class FSMInspector(Pmw.MegaToplevel): self._top = self._canvas.yview()[0] def createStateInspectors(self): - fsm = self['currentFSM'] - # Number of rows/cols needed to fit inspectors in a grid - dim = int(math.ceil(math.sqrt(len(fsm)))) + fsm = self.fsm + self.states = fsm.getStates() + # Number of rows/cols needed to fit inspectors in a grid + dim = int(math.ceil(math.sqrt(len(self.states)))) # Separation between nodes spacing = 2.5 * self._canvas.canvasx('0.375i') count = 0 - for state in self['currentFSM']: + for state in self.states: si = self.addState(state) - if state.defaultPosition: - si.setPos(state.defaultPosition[0], state.defaultPosition[1]) + if state.getDefaultPosition(): + si.setPos(state.getDefaultPosition()[0], + state.getDefaultPosition()[1]) else: row = int(math.floor(count / dim)) col = count % dim si.setPos(col * spacing, row * spacing + 0.5 * (0, spacing)[col % 2]) + # Add hooks + self.accept(fsm.getName() + '_' + si.getName() + '_entered', + si.enteredState) + self.accept(fsm.getName() + '_' + si.getName() + '_exited', + si.exitedState) count = count + 1 self.drawConnections() + if fsm.getCurrentState(): + self.enteredState(fsm.getCurrentState().getName()) def getStateInspector(self, name): return self.stateInspectorDict.get(name, None) def addState(self, state): - si = self.stateInspectorDict[state.name] = StateInspector(self, state) + si = self.stateInspectorDict[state.getName()] = ( + StateInspector(self, state)) return si def enteredState(self, stateName): @@ -263,12 +278,12 @@ class FSMInspector(Pmw.MegaToplevel): si = dict[key] center = si.center() print "'%s' : (%.3f, %.3f)," % \ - (si.state.name, center[0], center[1]) + (si.state.getName(), center[0], center[1]) for key in keys[-1:]: si = dict[key] center = si.center() print "'%s' : (%.3f, %.3f)," % \ - (si.state.name, center[0], center[1]) + (si.state.getName(), center[0], center[1]) print '}' def toggleBalloon(self): @@ -287,8 +302,9 @@ class StateInspector(Pmw.MegaArchetype): self.state = state # Create a unique tag which you can use to move a marker and # and its corresponding text around together - self.tag = state.name - + self.tag = state.getName() + self.fsm = inspector.fsm + # Pointers to the inspector's components self.scrolledCanvas = inspector.component('scrolledCanvas') self._canvas = self.scrolledCanvas.component('canvas') @@ -313,11 +329,11 @@ class StateInspector(Pmw.MegaArchetype): (self.y + half), fill = 'CornflowerBlue', tags = (self.tag,'markers')) - self.text = self._canvas.create_text(0, 0, text = state.name, + self.text = self._canvas.create_text(0, 0, text = state.getName(), justify = CENTER, tags = (self.tag,'labels')) # Is this state contain a sub machine? - if state.fsmArray: + if state.hasChildren(): # reduce half by sqrt of 2.0 half = half * 0.707106 self.rect = self._canvas.create_rectangle((- half), (- half), @@ -327,11 +343,11 @@ class StateInspector(Pmw.MegaArchetype): # The Popup State Menu self._popupMenu = Menu(self._canvas, tearoff = 0) - self._popupMenu.add_command(label = 'Request transistion to ' + - state.name, + self._popupMenu.add_command(label = 'Request transition to ' + + state.getName(), command = self.transitionTo) - if state.fsmArray: - self._popupMenu.add_command(label = 'Inspect ' + state.name + + if state.hasChildren(): + self._popupMenu.add_command(label = 'Inspect ' + state.getName() + ' submachine', command = self.inspectSubMachine) @@ -356,7 +372,7 @@ class StateInspector(Pmw.MegaArchetype): c = self.center() self._canvas.coords(self.marker, c[0] - half, c[1] - half, c[0] + half, c[1] + half) - if self.state.fsmArray: + if self.state.hasChildren(): half = self.radius * 0.707106 self._canvas.coords(self.rect, c[0] - half, c[1] - half, c[0] + half, c[1] + half) @@ -389,6 +405,9 @@ class StateInspector(Pmw.MegaArchetype): c = self._canvas.coords(self.marker) return (c[0] + c[2])/2.0, (c[1] + c[3])/2.0 + def getName(self): + return self.tag + # Event Handlers def mouseEnter(self, event): self._canvas.itemconfig(self.marker, width = 2) @@ -416,7 +435,7 @@ class StateInspector(Pmw.MegaArchetype): event.widget.winfo_pointery()) def transitionTo(self): - print 'transition to ' + self.tag + self.fsm.request(self.getName()) def inspectSubMachine(self): print 'inspect ' + self.tag + ' subMachine' @@ -441,7 +460,7 @@ class dummyFSM: self.stateCollection = stateCollection if layout: for state in self.stateCollection: - pos = layout.get(state.name, None) + pos = layout.get(state.getName(), None) if pos: state.defaultPosition= pos def __getitem__(self, item): @@ -465,5 +484,19 @@ if __name__ == '__main__': 'state-4' : (335.67, 143.86), 'state-5' : (239.76, 143.86), 'state-6' : (23.98, 71.93)}) - fsmi = FSMInspector(title = 'My Little Viewer', currentFSM = fsm) + fsmi = FSMInspector(title = 'My Little Viewer', FSM = fsm) mainloop() +""" +def enterState(): + print 'enterState' +def exitState(): + print 'exitState' +fsm = FSM.FSM('stopLight', + [ State.State('red', enterState, exitState, ['green']), + State.State('yellow', enterState, exitState, ['red']), + State.State('green', enterState, exitState, ['yellow']) ], + 'red', + 'red') +inspector = FSMInspector(FSM = fsm) +""" +