################################################################# # collisionWindow.py # Written by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004 ################################################################# # Import Tkinter, Pmw, and the floater code from this directory tree. from direct.tkwidgets.AppShell import * from direct.showbase.TkGlobal import * from tkSimpleDialog import askfloat import string import math import types from direct.task import Task FRAMES = 0 SECONDS = 1 class AnimPanel(AppShell): ################################################################# # This class will generate a animation panel for an actor # which user assigned. Inside this panel, instead of using actorInterval # or just simply calling the play function in Actor, we create a task to # set animation frame by frame using setPose. ################################################################# # Override class variables appname = 'Anim Panel' frameWidth = 575 frameHeight = 250 usecommandarea = 0 usestatusarea = 0 index = 0 dragMode = False rateList= ['1/24.0', '0.1', '0.5', '1.0', '2.0', '5.0' , '10.0'] def __init__(self, aNode = None, parent = None, **kw): INITOPT = Pmw.INITOPT self.id = 'AnimPanel '+ aNode.getName() self.appname = self.id optiondefs = ( ('title', self.appname, None), ('actor', aNode, None), ('animList', [], None), ) self.defineoptions(kw, optiondefs) self.frameHeight = 300 self.id = 'AnimPanel '+ aNode.getName() self.nodeName = aNode.getName() # Initialize the superclass AppShell.__init__(self) # Execute option callbacks self.initialiseoptions(AnimPanel) self.currTime = 0.0 # Initialize the start time self.animName = None self.parent.resizable(False,False) ## Disable the ability to resize for this Window. def createInterface(self): # Handle to the toplevels interior interior = self.interior() menuBar = self.menuBar menuBar.addmenu('Anim', 'Anim Panel Operations') # Reset all actor controls menuBar.addmenuitem('File', 'command', 'Load Animation', label = 'Load Animation', command = self.loadAnimation) menuBar.addmenuitem('Anim', 'command', 'Set actor controls to t = 0.0', label = 'Jump all to zero', command = self.resetAllToZero) menuBar.addmenuitem('Anim', 'command', 'Set Actor controls to end time', label = 'Jump all to end time', command = self.resetAllToEnd) menuBar.addmenuitem('Anim', 'separator') menuBar.addmenuitem('Anim', 'command', 'Play Current Animation', label = 'Play', command = self.play) menuBar.addmenuitem('Anim', 'command', 'Stop Current Animation', label = 'stop', command = self.stop) # Create a frame to hold all the actor controls actorFrame = Frame(interior) name_label = Label(actorFrame, text= self.nodeName,font=('MSSansSerif', 16), relief = SUNKEN, borderwidth=3) name_label.place(x=5,y=5,anchor=NW) Label(actorFrame, text= "Animation:", font=('MSSansSerif', 12)).place(x=140,y=5,anchor=NW) Label(actorFrame, text= "Play Rate:", font=('MSSansSerif', 12)).place(x=140,y=35,anchor=NW) self['animList'] = self['actor'].getAnimNames() self.AnimEntry = self.createcomponent( 'AnimationMenu', (), None, Pmw.ComboBox, (actorFrame,), labelpos = W, entry_width = 20, selectioncommand = self.setAnimation, scrolledlist_items = self['animList']) self.AnimEntry.place(x=240,y=10,anchor=NW) self.playRateEntry = self.createcomponent( 'playRateMenu', (), None, Pmw.ComboBox, (actorFrame,), labelpos = W, entry_width = 20, selectioncommand = self.setPlayRate, scrolledlist_items = self.rateList) self.playRateEntry.place(x=240,y=40,anchor=NW) self.playRateEntry.selectitem('1.0') ### Loop checkbox Label(actorFrame, text= "Loop:", font=('MSSansSerif', 12)).place(x=420,y=05,anchor=NW) self.loopVar = IntVar() self.loopVar.set(0) self.loopButton = self.createcomponent( 'loopButton', (), None, Checkbutton, (actorFrame,), variable = self.loopVar) self.loopButton.place(x=470,y=7,anchor=NW) ### Display Frames/Seconds Label(actorFrame, text= "Frame/Second:", font=('MSSansSerif', 11)).place(x=5,y=75,anchor=NW) self.unitsVar = IntVar() self.unitsVar.set(FRAMES) self.displayButton = self.createcomponent( 'displayButton', (), None, Checkbutton, (actorFrame,), command = self.updateDisplay, variable = self.unitsVar) self.displayButton.place(x=120,y=77,anchor=NW) ## scale control frameFrame = Frame(actorFrame, relief = SUNKEN, bd = 1) self.minLabel = self.createcomponent( 'minLabel', (), 'sLabel', Label, (frameFrame,), text = 0) self.minLabel.pack(side = LEFT) self.frameControl = self.createcomponent( 'scale', (), None, Scale, (frameFrame,), from_ = 0, to = 24, resolution = 1.0, command = self.goTo, length = 500, orient = HORIZONTAL, showvalue = 1) self.frameControl.pack(side = LEFT, expand = 1) self.frameControl.bind('', self.onPress) self.frameControl.bind('', self.onRelease) self.maxLabel = self.createcomponent( 'maxLabel', (), 'sLabel', Label, (frameFrame,), text = 24) self.maxLabel.pack(side = LEFT) frameFrame.pack(side = LEFT, expand = 1, fill = X) ## button contorl ButtomFrame = Frame(actorFrame, relief = SUNKEN, bd = 1,borderwidth=5) self.toStartButton = self.createcomponent( 'toStart', (), None, Button, (ButtomFrame,), text = '<<', width = 8, command = self.resetAllToZero) self.toStartButton.pack(side = LEFT, expand = 1, fill = X) self.playButton = self.createcomponent( 'playButton', (), None, Button, (ButtomFrame,), text = 'Play', width = 8, command = self.play) self.playButton.pack(side = LEFT, expand = 1, fill = X) self.stopButton = self.createcomponent( 'stopButton', (), None, Button, (ButtomFrame,), text = 'Stop', width = 8, state=DISABLED, command = self.stop) self.stopButton.pack(side = LEFT, expand = 1, fill = X) self.toEndButton = self.createcomponent( 'toEnd', (), None, Button, (ButtomFrame,), text = '>>', width = 8, command = self.resetAllToEnd) self.toEndButton.pack(side = LEFT, expand = 1, fill = X) ButtomFrame.place(anchor=NW,x=5,y=165) self.removeButton = self.createcomponent( 'Remove Animation', (), None, Button, (actorFrame,), text = 'Remove This Animation', width = 20, command = self.removeAnim) self.removeButton.place(anchor=NW,x=5,y=220) self.loadButton = self.createcomponent( 'Load Animation', (), None, Button, (actorFrame,), text = 'Load New Animation', width = 20, command = self.loadAnimation) self.loadButton.place(anchor=NW,x=180,y=220) # Now pack the actor frame actorFrame.pack(expand = 1, fill = BOTH) def updateList(self): ################################################################# # updateList(self) # This function will update the list of animations that the Actor # currently has into the combo box widget. ################################################################# self.ignore('DataH_loadFinish'+self.nodeName) del self.loaderWindow self['animList'] = self['actor'].getAnimNames() animL = self['actor'].getAnimNames() self.AnimEntry.setlist(animL) def removeAnim(self): ################################################################# # removeAnim(self) # This function will stop the animation and get the name of animation # which user wish to remove from the panel. Then, it will send out # a message to dataHolder to remove the target animation. # And in the same time, it will start waiting a return message to # make sure that target animation has been removed. ################################################################# name = self.AnimEntry.get() if taskMgr.hasTaskNamed(self.id + '_UpdateTask'): self.stop() self.accept('DataH_removeAnimFinish'+self.nodeName,self.afterRemove) messenger.send('AW_removeAnim',[self['actor'],name]) return def afterRemove(self): ################################################################# # afterRemove(self) # This function will be called once panel has received the return # message from dataHolder. This function will call setList to # reset the list of Animations ################################################################# self.ignore('DataH_removeAnimFinish'+self.nodeName) self['animList'] = self['actor'].getAnimNames() animL = self['actor'].getAnimNames() self.AnimEntry.setlist(animL) print '-----',animL return def loadAnimation(self): ################################################################# # loadAnimation(self) # This function will open a dialog window to require user to input # the animation he wants to load in for this actor. ################################################################# self.loaderWindow = LoadAnimPanel(aNode=self['actor']) self.accept('DataH_loadFinish'+self.nodeName,self.updateList) return def play(self): ################################################################# # play(self) # This function will be called when user click on the "play" button. # First, this function will initialize all parameter that the actual # play task need to run and add the play task into the taskMgr. ################################################################# self.animName = self.AnimEntry.get() if self.animName in self['animList']: animName = self.AnimEntry.get() self.playButton.config(state=DISABLED) self.lastT = globalClock.getFrameTime() taskMgr.add(self.playTask, self.id + '_UpdateTask') self.stopButton.config(state=NORMAL) else: print '----Illegal Animaion name!!', self.animName return def playTask(self, task): ################################################################# # playTask(self, task) # This task will record time by each frame # In fact it is just a clock keeper. # If the current frame time over the max long of the animation, # it will reset the timer. # Anyway, this function will call gotoT by each frame. ################################################################# fLoop = self.loopVar.get() currT = globalClock.getFrameTime() deltaT = currT - self.lastT self.lastT = currT if self.dragMode: return Task.cont self.currTime = self.currTime + deltaT if (self.currTime > self.maxSeconds): if fLoop: self.currTime = self.currTime%self.duration self.gotoT(self.currTime) else: self.currTime = 0.0 self.gotoT(0.0) self.playButton.config(state=NORMAL) self.stopButton.config(state=DISABLED) return Task.done else: self.gotoT(self.currTime) return Task.cont def stop(self): ################################################################# # stop(self) # This function will remove the play task from taskMgr when user # click on the "Stop" button ################################################################# taskMgr.remove(self.id + '_UpdateTask') self.playButton.config(state=NORMAL) self.stopButton.config(state=DISABLED) return def setAnimation(self, animation): ################################################################# # setAnimation(self, animation) # This function will be called each time when user change # the current animation. Most important thing this function do is # to recalculate all variables to fit the selected animation ################################################################# self.animName = self.AnimEntry.get() playRate = '%0.1f' % self['actor'].getPlayRate(self.animName) if playRate not in self.rateList: def strCmp(a, b): return cmp(eval(a), eval(b)) self.rateList.append(playRate) self.rateList.sort(strCmp) self.playRateEntry.reset(self.rateList) self.playRateEntry.selectitem(playRate) self.currTime = 0.0 self.frameControl.set(0) self.updateDisplay() return def setPlayRate(self,rate): ################################################################# # setPlayRate(self, rate) # This function will be called each time when user changes the current play rate. ################################################################# self.animName = self.AnimEntry.get() if self.animName in self['animList']: self['actor'].setPlayRate(eval(rate), self.animName) self.updateDisplay() return def updateDisplay(self): ################################################################# # updateDisplay(self) # This function will be called whenever something has been changed # on the panel. In here we will re-new all widgets on the panel to # correct value. ################################################################# self.fps = self['actor'].getFrameRate(self.animName) self.duration = self['actor'].getDuration(self.animName) self.maxFrame = self['actor'].getNumFrames(self.animName) - 1 self.maxSeconds = self.duration if self.unitsVar.get() == FRAMES: fromFrame = 0 toFrame = self.maxFrame self.minLabel['text'] = fromFrame self.maxLabel['text'] = toFrame self.frameControl.configure(from_ = fromFrame, to = toFrame, resolution = 1.0) else: self.minLabel['text'] = '0.0' self.maxLabel['text'] = "%.2f" % self.duration self.frameControl.configure(from_ = 0.0, to = self.duration, resolution = 0.01) def gotoT(self,time): ################################################################# # gotoT(self, time) # calculate the right parameter which will be send to set Frame # Control slider, which is the real place we play the animation. ################################################################# if self.unitsVar.get() == FRAMES: self.frameControl.set(time * self.fps) else: self.frameControl.set(time) return def goTo(self,frame): ################################################################# # goto(self, frame) # Call back function for the frame control slider. # This function will set the animation by the value on the slider. # # This function is the real function we "play" the animation. # ################################################################# if self.animName in self['animList']: # Convert scale value to float frame = string.atof(frame) # Now convert t to seconds for offset calculations if self.unitsVar.get() == FRAMES: frame = frame / self.fps if self.dragMode: # If user is clicking on the slider and is draging the bar, reset the global timer. self.currTime = frame self['actor'].pose(self.animName, min(self.maxFrame, int(frame * self.fps))) return def onRelease(self,frame): ################################################################# # onRelease(self, frame) # disable the dragMode when user releases the bar on the slider. ################################################################# self.dragMode = False return def onPress(self,frame): ################################################################# # onPress(self, frame) # enable the dragMode when user press the bar on the slider. ################################################################# self.dragMode = True return def resetAllToZero(self): ################################################################# # resetAllToZero(self) # reset the global timer to zero and also move the slider to zero. # This will also reset the actor to the zero frame of current animation ################################################################# self.currTime = 0.0 self.gotoT(0) return def resetAllToEnd(self): ################################################################# # resetAllToEnd(self) # set the global timer to the end of current animation and # also move the slider to the end. ################################################################# self.currTime = self.maxSeconds self.gotoT(self.duration) return def onDestroy(self, event): if taskMgr.hasTaskNamed(self.id + '_UpdateTask'): taskMgr.remove(self.id + '_UpdateTask') self.ignore('DataH_loadFinish') messenger.send('AW_close',[self.nodeName]) ''' If you have open any thing, please rewrite here! ''' pass class LoadAnimPanel(AppShell): ################################################################# # LoadAnimPanel(AppShell) # This class will open a dialog to ask user to input names and # file paths of animations ################################################################# # Override class variables appname = 'Load Animation' frameWidth = 575 frameHeight = 200 usecommandarea = 0 usestatusarea = 0 index = 0 ## Anim name : File Path def __init__(self, aNode = None, parent = None, **kw): INITOPT = Pmw.INITOPT self.id = 'Load Animation '+ aNode.getName() self.appname = self.id self.animDic = {} self.animList = [] optiondefs = ( ('title', self.appname, None), ) self.defineoptions(kw, optiondefs) self.frameHeight = 300 self.nodeName = aNode.getName() self.Actor = aNode # Initialize the superclass AppShell.__init__(self) # Execute option callbacks self.initialiseoptions(LoadAnimPanel) def createInterface(self): self.menuBar.destroy() interior = self.interior() mainFrame = Frame(interior) self.inputZone = Pmw.Group(mainFrame, tag_text='File Setting') self.inputZone.pack(fill='both',expand=1) settingFrame = self.inputZone.interior() Label(settingFrame,text='Anim Name').place(anchor=NW,x=60,y=5) Label(settingFrame,text='File Path').place(anchor=NW,x=205,y=5) self.AnimName_1 = self.createcomponent( 'Anim Name List', (), None, Pmw.ComboBox, (settingFrame,),label_text='Anim :', labelpos = W, entry_width = 10, selectioncommand = self.selectAnim, scrolledlist_items = self.animList) self.AnimFile_1 = Pmw.EntryField(settingFrame,value='') self.AnimFile_1.component('entry').config(width=20) self.AnimName_1.place(anchor=NW,x=10,y=25) self.AnimFile_1.place(anchor=NW,x=140,y=25) self.Browse_1 = self.createcomponent( 'File Browser1', (), None, Button, (mainFrame,), text = 'Browse...', command = self.Browse_1) self.Browse_1.place(anchor=NW,x=270,y=38) self.addIntoButton = self.createcomponent( 'Load Add', (), None, Button, (mainFrame,), text = 'Add to Load', command = self.addIntoList) self.addIntoButton.place(anchor=NW,x=345,y=38) att_label = Label(mainFrame, font=('MSSansSerif', 10), text= "Attention! Animations won't be loaded in before you press the 'OK' button below!") att_label.place(anchor=NW,x=10,y=80) self.button_ok = Button(mainFrame, text="OK", command=self.ok_press,width=10) self.button_ok.pack(fill=BOTH,expand=0,side=RIGHT) mainFrame.pack(expand = 1, fill = BOTH) def onDestroy(self, event): messenger.send('AWL_close',[self.nodeName]) ''' If you have open any thing, please rewrite here! ''' pass def selectAnim(self,name): ################################################################# # selectAnim(self, name) # This function will be called if user select an animation on the list. ################################################################# if name in self.animDic: self.AnimFile_1.setvalue = self.animDic[name] return def Browse_1(self): ################################################################# # Browse_1(self) # when the browse button pused, this function will be called. # Do nothing but open a file dialog for user to set the path to target file # Then, set the path back to the entry on the panel. ################################################################# AnimFilename = askopenfilename( defaultextension = '.egg', filetypes = (('Egg Files', '*.egg'), ('Bam Files', '*.bam'), ('All files', '*')), initialdir = '.', title = 'File Path for Anim 1', parent = self.parent) if AnimFilename: self.AnimFile_1.setvalue(AnimFilename) return def addIntoList(self): ################################################################# # addIntoList(self) # This function will be called each time when user click on the # "Add to Load" button. This function will read the current data # on the panel into a dictionary. then reset the list of the animation # name list on this panel.(not the one in the animation panel...) # # This function won't load any animation.... # ################################################################# name = self.AnimName_1.get() self.animDic[name] = Filename.fromOsSpecific(self.AnimFile_1.getvalue()).getFullpath() if name in self.animList: pass else: self.animList.append(name) self.AnimName_1.setlist(self.animList) print self.animDic return def ok_press(self): ################################################################# # ok_press(Self) # This functiion will be called when user click on the "OK" # button. This function will send a message along with the animation # file we wish to load for this actor. # Then, it will close the panel itself. ################################################################# messenger.send('AW_AnimationLoad',[self.Actor,self.animDic]) #print self.animDic self.quit() return