sceneEditor.py 75 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709
  1. import sys
  2. try: import _tkinter
  3. except: sys.exit("Please install python module 'Tkinter'")
  4. import direct
  5. from direct.directbase.DirectStart import*
  6. from direct.showbase.TkGlobal import *
  7. from direct.showbase.TkGlobal import spawnTkLoop, Toplevel
  8. from tkFileDialog import *
  9. from direct.directtools.DirectGlobals import *
  10. from direct.tkwidgets.AppShell import*
  11. from SideWindow import*
  12. from duplicateWindow import*
  13. from lightingPanel import *
  14. from seMopathRecorder import *
  15. from seSession import *
  16. from quad import *
  17. from sePlacer import *
  18. from seFileSaver import *
  19. from propertyWindow import *
  20. import seParticlePanel
  21. from collisionWindow import *
  22. from direct.gui.DirectGui import *
  23. from MetadataPanel import *
  24. from seBlendAnimPanel import *
  25. from controllerWindow import *
  26. from AlignTool import *
  27. import os
  28. import string
  29. from direct.tkwidgets import Dial
  30. from direct.tkwidgets import Floater
  31. from direct.tkwidgets import Slider
  32. from direct.actor import Actor
  33. import seAnimPanel
  34. from direct.task import Task
  35. import math
  36. #################################################################
  37. # All scene and windows object will be stored in here.
  38. # So, any event which will or need to change contents
  39. # should be wirtten in here or imported into here!
  40. #################################################################
  41. from dataHolder import* ## Use this thing to Save/load data.
  42. AllScene = dataHolder()
  43. class myLevelEditor(AppShell):
  44. ## overridden the basic app info ##
  45. appname = 'Scene Editor - New Scene'
  46. appversion = '1.0'
  47. copyright = ('Copyright 2004 E.T.C. Carnegie Mellon U.' +
  48. ' All Rights Reserved')
  49. contactname = 'Jesse Schell, Shalin Shodhan & YiHong Lin'
  50. contactphone = '(412) 268-5791'
  51. contactemail = '[email protected]'
  52. frameWidth = 1024
  53. frameHeight = 80
  54. frameIniPosX = 0
  55. frameIniPosY = 0
  56. usecommandarea = 0
  57. usestatusarea = 0
  58. padx = 5
  59. pady = 5
  60. sideWindowCount = 0
  61. ## Basic World default setting (For side window)
  62. worldColor = [0,0,0,0]
  63. lightEnable = 1
  64. ParticleEnable = 1
  65. basedriveEnable = 0
  66. collision = 1
  67. backface = 0
  68. texture = 1
  69. wireframe = 0
  70. grid = 0
  71. widgetVis = 0
  72. enableAutoCamera = 1
  73. enableControl = False
  74. controlType = 'Keyboard'
  75. keyboardMapDict = {}
  76. keyboardSpeedDict = {}
  77. Scene=None
  78. isSelect = False
  79. nodeSelected = None
  80. undoDic = {}
  81. redoDic = {}
  82. animPanel = {}
  83. animBlendPanel = {}
  84. propertyWindow = {}
  85. CurrentFileName=None #Holds the current scene file name
  86. CurrentDirName=None # Holds the current file name without extension which is the path where file's data gets saved
  87. Dirty=0 # Keeps track of whether there are any modifications that should be saved
  88. def __init__(self, parent = None, **kw):
  89. base.setBackgroundColor(0,0,0)
  90. self.parent = parent
  91. ## Check TkTool is activated! ##
  92. self.wantTK = config.GetBool('want-tk', 0)
  93. if self.wantTK:
  94. pass
  95. else:
  96. taskMgr.remove('tkloop')
  97. spawnTkLoop()
  98. ## Set up window frame
  99. INITOPT = Pmw.INITOPT
  100. optiondefs = (
  101. ('title', self.appname, None),
  102. )
  103. self.defineoptions(kw, optiondefs)
  104. AppShell.__init__(self, parent)
  105. self.parent.geometry('%dx%d+%d+%d' % (self.frameWidth, self.frameHeight,self.frameIniPosX,self.frameIniPosY))
  106. ###### Put th directLabel on the screen to show the selected object Data
  107. self.posLabel = DirectLabel(
  108. relief = None,
  109. pos = (-1.3, 0, 0.90),
  110. text = "Position : X: 00.00 Y: 00.00 Z: 00.00",
  111. color = Vec4(1, 1, 1, 1),
  112. text_scale = 0.05,
  113. text_align = TextNode.ALeft
  114. )
  115. self.hprLabel = DirectLabel(
  116. relief = None,
  117. pos = (-1.3 , 0, 0.80),
  118. text = "Orientation: H: 00.00 P: 00.00 R: 00.00",
  119. color = Vec4(1, 1, 1, 1),
  120. text_scale = 0.05,
  121. text_align = TextNode.ALeft
  122. )
  123. self.scaleLabel = DirectLabel(
  124. relief = None,
  125. pos = (-1.3, 0, 0.70),
  126. text = "Scale : X: 00.00 Y: 00.00 Z: 00.00",
  127. color = Vec4(1, 1, 1, 1),
  128. text_scale = 0.05,
  129. text_align = TextNode.ALeft
  130. )
  131. self.initialiseoptions(myLevelEditor)
  132. self.parent.resizable(False,False) ## Disable the ability to resize for this Window.
  133. ######### Set the event handler ##########
  134. self.dataFlowEvents = [
  135. ## Event from Side Window
  136. ['SW_lightToggle',self.lightToggle],
  137. ['SW_collisionToggle',AllScene.toggleCollisionVisable],
  138. ['SW_particleToggle',self.toggleParticleVisable],
  139. ['SW_close',self.sideWindowClose],
  140. ## From Duplication Window
  141. ['DW_duplicating',self.duplicationObj],
  142. ## From Animation Panel
  143. ['AW_AnimationLoad',self.animationLoader],
  144. ['AW_removeAnim',self.animationRemove],
  145. ['AW_close',self.animPanelClose],
  146. ## From Blending Animation Window
  147. ['BAW_saveBlendAnim',self.animBlendPanelSave],
  148. ['BAW_removeBlendAnim',self.animBlendPanelRemove],
  149. ['BAW_renameBlendAnim',self.animBlendPanelRename],
  150. ['BAW_close',self.animBlendPanelClose],
  151. ## From Lighting Panel
  152. ['LP_selectLight', self.lightSelect],
  153. ['LP_addLight',self.addLight],
  154. ['LP_rename',self.lightRename],
  155. ['LP_removeLight',self.removeLight],
  156. ['LP_close',self.lightingPanelClose],
  157. ## From MotionPath Panel
  158. ['mPath_bindPathToNode',AllScene.bindCurveToNode],
  159. ['mPath_requestCurveList', self.requestCurveList],
  160. ['mPath_close', self.mopathClosed],
  161. ## From Property Window
  162. ['PW_removeCurveFromNode', AllScene.removeCurveFromNode],
  163. ['PW_removeAnimFromNode', AllScene.removeAnimation],
  164. ['PW_toggleLight', AllScene.toggleLightNode],
  165. ['PW_close', self.closePropertyWindow],
  166. ## From collisionWindow
  167. ['CW_addCollisionObj', AllScene.addCollisionObject],
  168. ## From AlignWindow
  169. ['ALW_close', self.closeAlignPanel],
  170. ['ALW_align', self.alignObject],
  171. ## From controllerWindow
  172. ['ControlW_close', self.closeInputPanel],
  173. ['ControlW_require', self.requestObjFromControlW],
  174. ['ControlW_controlSetting', self.setControlSet],
  175. ['ControlW_controlEnable', self.startControl],
  176. ['ControlW_controlDisable', self.stopControl],
  177. ['ControlW_saveSetting', AllScene.saveControlSetting],
  178. ## From Placer
  179. ['Placer_close', self.closePlacerPanel],
  180. ## From Particle Panel
  181. ['ParticlePanle_close', self.closeParticlePanel],
  182. ## From SEditor object which is a altered DirectSession
  183. ['SEditor-ToggleWidgetVis',self.toggleWidgetVis],
  184. ['SEditor-ToggleBackface',self.toggleBackface],
  185. ['SEditor-ToggleTexture',self.toggleTexture],
  186. ['SEditor-ToggleWireframe',self.toggleWireframe],
  187. ['ParticlePanel_Added_Effect',self.addParticleEffect],
  188. ['f11',self.loadFromBam],
  189. ['f12',self.saveAsBam],
  190. ]
  191. #################################
  192. ### Collision detection
  193. #################################
  194. self.cTrav = CollisionTraverser()
  195. base.cTrav = self.cTrav
  196. for event in self.dataFlowEvents:
  197. self.accept(event[0], event[1], extraArgs = event[2:])
  198. self.actionEvents = [
  199. # Scene graph explorer functions
  200. ['SGE_changeName', self.changeName],
  201. ['SGE_Properties', self.openPropertyPanel],
  202. ['SGE_Duplicate', self.duplicate],
  203. ['SGE_Remove', self.remove],
  204. ['SGE_Add Dummy', self.addDummyNode],
  205. ['SGE_Add Collision Object', self.addCollisionObj],
  206. ['SGE_Metadata', self.openMetadataPanel],
  207. ['SGE_Set as Reparent Target', self.setAsReparentTarget],
  208. ['SGE_Reparent to Target', self.reparentToNode],
  209. ['SGE_Animation Panel', self.openAnimPanel],
  210. ['SGE_Blend Animation Panel', self.openBlendAnimPanel],
  211. ['SGE_MoPath Panel', self.openMoPathPanel],
  212. ['SGE_Align Tool', self.openAlignPanel],
  213. ['SGE_Flash', self.flash],
  214. ['SGE_madeSelection', self.selectNode],
  215. ['select',self.selectNode],
  216. ['deselect', self.deSelectNode],
  217. ['se_selectedNodePath',self.selectFromScene],
  218. ['se_deselectedAll',self.deselectFromScene],
  219. ]
  220. ''' All messages starting with "SGE_" are generated in seSceneGraphExplorer'''
  221. for event in self.actionEvents:
  222. self.accept(event[0], event[1], extraArgs = event[2:])
  223. camera.toggleVis()
  224. self.selectNode(base.camera) ## Initially, we select camera as the first node...
  225. def appInit(self):
  226. #################################################################
  227. # appInit(self)
  228. # Initialize the application.
  229. # This function will be called when you call AppShell's constructor
  230. #################################################################
  231. ### Create SceneEditor Ver. DirectSession
  232. self.seSession = SeSession()
  233. self.seSession.enable()
  234. SEditor.camera.setPos(0,-50,10)
  235. self.placer=None
  236. self.MopathPanel = None
  237. self.alignPanelDict = {}
  238. #self.quadview=QuadView()
  239. self.lightingPanel = None
  240. self.controllerPanel = None
  241. self.particlePanel = None
  242. ### Create Side Window
  243. self.sideWindow = sideWindow(worldColor = self.worldColor,
  244. lightEnable = self.lightEnable,
  245. ParticleEnable = self.ParticleEnable,
  246. basedriveEnable = self.basedriveEnable,
  247. collision = self.collision,
  248. backface = self.backface,
  249. texture = self.texture,
  250. wireframe = self.wireframe,
  251. grid = self.grid,
  252. widgetVis = self.widgetVis,
  253. enableAutoCamera = self.enableAutoCamera)
  254. self.sideWindowCount = 1
  255. self.sideWindow.selectPage()
  256. messenger.send('SGE_Update Explorer',[render]) ## Update the Scene Graph
  257. pass
  258. def getPhotoImage(self,name):
  259. modpath = ConfigVariableSearchPath("model-path")
  260. path = modpath.findFile(Filename(name))
  261. return PhotoImage(file=path.toOsSpecific())
  262. def createInterface(self):
  263. # The interior of the toplevel panel
  264. interior = self.interior()
  265. #######################################################
  266. ### Creating the Buttons in the window frame
  267. #######################################################
  268. buttonFrame = Frame(interior)
  269. self.image=[]
  270. self.image.append(self.getPhotoImage('models/icons/new.gif'))#0
  271. self.image.append(self.getPhotoImage('models/icons/open.gif'))#1
  272. self.image.append(self.getPhotoImage('models/icons/save.gif'))#2
  273. self.image.append(self.getPhotoImage('models/icons/model.gif'))#3
  274. self.image.append(self.getPhotoImage('models/icons/actor.gif'))#4
  275. self.image.append(self.getPhotoImage('models/icons/placer.gif'))#5
  276. self.image.append(self.getPhotoImage('models/icons/mopath.gif'))#6
  277. self.image.append(self.getPhotoImage('models/icons/lights.gif'))#7
  278. self.image.append(self.getPhotoImage('models/icons/particles.gif'))#8
  279. self.image.append(self.getPhotoImage('models/icons/control.gif'))
  280. self.image.append(self.getPhotoImage('models/icons/help.gif'))#9
  281. self.image.append(self.getPhotoImage('models/icons/blank.gif'))
  282. self.image.append(self.getPhotoImage('models/icons/blank.gif'))
  283. self.image.append(self.getPhotoImage('models/icons/blank.gif'))
  284. self.image.append(self.getPhotoImage('models/icons/blank.gif'))
  285. self.image.append(self.getPhotoImage('models/icons/blank.gif'))
  286. self.image.append(self.getPhotoImage('models/icons/blank.gif'))
  287. self.image.append(self.getPhotoImage('models/icons/blank.gif'))
  288. self.image.append(self.getPhotoImage('models/icons/blank.gif'))
  289. self.image.append(self.getPhotoImage('models/icons/blank.gif'))
  290. self.image.append(self.getPhotoImage('models/icons/blank.gif'))
  291. self.image.append(self.getPhotoImage('models/icons/blank.gif'))
  292. self.image.append(self.getPhotoImage('models/icons/blank.gif'))
  293. i = 0
  294. for element in self.image:
  295. i += 1
  296. button = Button(buttonFrame, image = element, command=lambda n=i : self.buttonPushed(n))
  297. button.pack(fill=X, side = LEFT)
  298. buttonFrame.pack(fill=X, side=LEFT,expand=True)
  299. def buttonPushed(self, buttonIndex):
  300. #################################################################
  301. # buttonPushed(self, buttonNum)
  302. # This function will handle all button events from top level window
  303. # Take the button index as a reference to sence which button has been pushed.
  304. #################################################################
  305. ####
  306. #### Change here to process the button event further.
  307. ####
  308. if buttonIndex==1: # New Scene
  309. self.newScene()
  310. return
  311. elif buttonIndex==2: # Open Scene
  312. self.openScene()
  313. return
  314. elif buttonIndex==3: # Save Scene
  315. self.saveScene()
  316. return
  317. elif buttonIndex==4: # Load Model
  318. self.loadModel()
  319. return
  320. elif buttonIndex==5: # Load Actor
  321. self.loadActor()
  322. return
  323. elif buttonIndex==6: # Open Placer
  324. self.openPlacerPanel()
  325. return
  326. elif buttonIndex==7: # Open Mopath Panel
  327. self.openMoPathPanel()
  328. return
  329. elif buttonIndex==8: # Open Lighting Panel
  330. self.openLightingPanel()
  331. return
  332. elif buttonIndex==9: # Open Particle Panel
  333. self.openParticlePanel()
  334. return
  335. elif buttonIndex==10:
  336. self.openInputPanel()
  337. return
  338. elif buttonIndex==11: # Help
  339. self.showAbout()
  340. return
  341. elif buttonIndex==12:
  342. print "You haven't defined the function for this Button, Number %d."%buttonIndex
  343. return
  344. elif buttonIndex==13:
  345. print "You haven't defined the function for this Button, Number %d."%buttonIndex
  346. return
  347. elif buttonIndex==14:
  348. print "You haven't defined the function for this Button, Number %d."%buttonIndex
  349. return
  350. elif buttonIndex==15:
  351. print "You haven't defined the function for this Button, Number %d."%buttonIndex
  352. return
  353. elif buttonIndex==16:
  354. print "Your scene will be eliminated within five seconds, Save your world!!!, Number %d."%buttonIndex
  355. return
  356. elif buttonIndex==17:
  357. print "You haven't defined the function for this Button, Number %d."%buttonIndex
  358. return
  359. elif buttonIndex==18:
  360. print "You haven't defined the function for this Button, Number %d."%buttonIndex
  361. return
  362. elif buttonIndex==19:
  363. print "You haven't defined the function for this Button, Number %d."%buttonIndex
  364. return
  365. elif buttonIndex==20:
  366. print "You haven't defined the function for this Button, Number %d."%buttonIndex
  367. return
  368. return
  369. def createMenuBar(self):
  370. # Creates default menus. Can be overridden or simply augmented
  371. # Using button Add below
  372. self.menuBar.addmenuitem('Help', 'command',
  373. 'Get information on application',
  374. label='About...', command=self.showAbout)
  375. ## Creat stuff inside the "File"
  376. self.menuBar.addmenuitem('File', 'command', 'Creat New Scene',
  377. label='New Scene',
  378. command=self.newScene)
  379. self.menuBar.addmenuitem('File', 'command', 'Open a Scene',
  380. label='Open Scene',
  381. command=self.openScene)
  382. self.menuBar.addmenuitem('File', 'command', 'Save a Scene',
  383. label='Save Scene',
  384. command=self.saveScene)
  385. self.menuBar.addmenuitem('File', 'command', 'Save Scene as...',
  386. label='Save as...',
  387. command=self.saveAsScene)
  388. self.menuBar.addmenuitem('File', 'separator')
  389. self.menuBar.addmenuitem('File', 'command', 'Load Model',
  390. label='Load Model',
  391. command=self.loadModel)
  392. self.menuBar.addmenuitem('File', 'command', 'Load Actor',
  393. label='Load Actor',
  394. command=self.loadActor)
  395. self.menuBar.addmenuitem('File', 'separator')
  396. self.menuBar.addmenuitem('File', 'command', 'Import a Scene',
  397. label='Import...',
  398. command=self.importScene)
  399. self.menuBar.addmenuitem('File', 'separator')
  400. self.menuBar.addmenuitem('File', 'command', 'Quit this application',
  401. label='Exit',
  402. command=self.quit)
  403. ## Creat "Edit" on the menu and its stuff
  404. self.menuBar.addmenu('Edit', 'Editting tools')
  405. self.menuBar.addmenuitem('Edit', 'command', 'Un-do',
  406. label='Undo...',
  407. command=self.unDo)
  408. self.menuBar.addmenuitem('Edit', 'command', 'Re-do',
  409. label='Redo...',
  410. command=self.reDo)
  411. self.menuBar.addmenuitem('Edit', 'separator')
  412. self.menuBar.addmenuitem('Edit', 'command', 'Deselect nodepath',
  413. label='Deselect',
  414. command=self.deSelectNode)
  415. self.menuBar.addmenuitem('Edit', 'separator')
  416. self.menuBar.addmenuitem('Edit', 'command', 'Add a Dummy',
  417. label='Add Dummy',
  418. command=self.addDummy)
  419. self.menuBar.addmenuitem('Edit', 'command', 'Duplicate nodepath',
  420. label='Duplicate',
  421. command=self.duplicateNode)
  422. self.menuBar.addmenuitem('Edit', 'command', 'Remove the nodepath',
  423. label='Remove',
  424. command=self.removeNode)
  425. self.menuBar.addmenuitem('Edit', 'command', 'Show the object properties',
  426. label='Object Properties',
  427. command=self.showObjProp)
  428. self.menuBar.addmenuitem('Edit', 'separator')
  429. self.menuBar.addmenuitem('Edit', 'command', 'Show the Camera setting',
  430. label='Camera Setting',
  431. command=self.showCameraSetting)
  432. self.menuBar.addmenuitem('Edit', 'command', 'Render setting',
  433. label='Render Setting',
  434. command=self.showRenderSetting)
  435. ## Creat "Panel" on the menu and its stuff
  436. self.menuBar.addmenu('Panel', 'Panel tools')
  437. self.menuBar.addmenuitem('Panel', 'command', 'Open Side Window',
  438. label='Side Window',
  439. command=self.openSideWindow)
  440. self.menuBar.addmenuitem('Panel', 'command', 'Placer Panel',
  441. label='Placer Panel',
  442. command=self.openPlacerPanel)
  443. self.menuBar.addmenuitem('Panel', 'command', 'Animation Panel',
  444. label='Animation Panel',
  445. command=self.openAnimationPanel)
  446. self.menuBar.addmenuitem('Panel', 'command', 'Motion Path Panel',
  447. label='Mopath Panel',
  448. command=self.openMopathPanel)
  449. self.menuBar.addmenuitem('Panel', 'command', 'Lighting Panel',
  450. label='Lighting Panel',
  451. command=self.openLightingPanel)
  452. self.menuBar.addmenuitem('Panel', 'command', 'Particle Panel',
  453. label='Particle Panel',
  454. command=self.openParticlePanel)
  455. self.menuBar.addmenuitem('Panel', 'separator')
  456. self.menuBar.addmenuitem('Panel', 'command', 'Input control Panel',
  457. label='Input device panel',
  458. command=self.openInputPanel)
  459. self.menuBar.pack(fill=X, side = LEFT)
  460. ## get "Menu" items in order to control the entry status
  461. self.menuFile = self.menuBar.component('File-menu')
  462. self.menuEdit = self.menuBar.component('Edit-menu')
  463. self.menuPanel = self.menuBar.component('Panel-menu')
  464. ## Disable entries when user doesn't select anything
  465. if not self.isSelect:
  466. self.menuEdit.entryconfig('Deselect', state=DISABLED)
  467. self.menuEdit.entryconfig('Add Dummy', state=DISABLED)
  468. self.menuEdit.entryconfig('Duplicate', state=DISABLED)
  469. self.menuEdit.entryconfig('Remove', state=DISABLED)
  470. self.menuEdit.entryconfig('Object Properties', state=DISABLED)
  471. self.menuPanel.entryconfig('Animation Panel', state=DISABLED)
  472. self.menuPanel.entryconfig('Side Window', state=DISABLED)
  473. def onDestroy(self, event):
  474. #################################################################
  475. # If you have open any thing, please rewrite here!
  476. #################################################################
  477. if taskMgr.hasTaskNamed('seMonitorSelectedNode'):
  478. taskMgr.remove('seMonitorSelectedNode')
  479. pass
  480. def closeAllSubWindows(self):
  481. #################################################################
  482. # closeAllSubWindows(self)
  483. # except side window. this function will close all sub window if there is any.
  484. #################################################################
  485. if self.lightingPanel != None:
  486. self.lightingPanel.quit()
  487. if self.placer != None:
  488. self.placer.quit()
  489. if self.MopathPanel != None:
  490. self.MopathPanel.quit()
  491. if self.particlePanel != None:
  492. self.particlePanel.quit()
  493. if self.controllerPanel != None:
  494. self.controllerPanel.quit()
  495. list = self.animPanel.keys()
  496. for index in list:
  497. self.animPanel[index].quit()
  498. list = self.animBlendPanel.keys()
  499. for index in list:
  500. self.animBlendPanel[index].quit()
  501. list = self.propertyWindow.keys()
  502. for index in list:
  503. self.propertyWindow[index].quit()
  504. list = self.alignPanelDict.keys()
  505. for index in list:
  506. self.alignPanelDict[index].quit()
  507. self.animPanel.clear()
  508. self.animBlendPanel.clear()
  509. self.propertyWindow.clear()
  510. self.alignPanelDict.clear()
  511. return
  512. ## Processing message events
  513. def makeDirty(self):
  514. self.Dirty=1
  515. def removeLight(self, lightNode):
  516. #################################################################
  517. # removeLight(self, lightNode)
  518. # This function will be called when user try to remove the light from lightingPanel
  519. # (by sending out the message)
  520. # So, in here we will call dataHolder(AllScene) to remove the light
  521. # and return a list contains the newest data of lights in he scene.
  522. # Then, this function will reset the lighting list in the lightingPanel
  523. #################################################################
  524. list = AllScene.removeObj(lightNode)
  525. if self.lightingPanel != None:
  526. self.lightingPanel.updateList(list)
  527. return
  528. def lightRename(self,oName, nName):
  529. #################################################################
  530. # lightRename(self,oName, nName)
  531. # This function will be called when user try to rename the light from lightingPanel
  532. # (by sending out the message)
  533. # So, in here we will call dataHolder(AllScene) to rename the light
  534. # and return a list contains the newest data of lights in he scene.
  535. # Then, this function will reset the lighting list in the lightingPanel
  536. #################################################################
  537. list, lightNode = AllScene.rename(oName, nName)
  538. if self.lightingPanel != None:
  539. self.lightingPanel.updateList(list,lightNode)
  540. return
  541. def lightSelect(self,lightName):
  542. #################################################################
  543. # lightSelect(self,lightName)
  544. # This function will be called when user try to select the light from lightingPanel
  545. # (by sending out the message)
  546. # So, in here we will call dataHolder(AllScene) to get the target light node
  547. # Then, this function will put this light node back into lighting
  548. # panel and update the data on the panel.
  549. #################################################################
  550. lightNode = AllScene.getLightNode(lightName)
  551. if self.lightingPanel != None:
  552. self.lightingPanel.updateDisplay(lightNode)
  553. return
  554. def addLight(self, type):
  555. #################################################################
  556. # addLight(self, type)
  557. # This function will be called when user try to add a light from lightingPanel
  558. # (by sending out the message)
  559. # So, in here we will call dataHolder(AllScene) to create a default light node
  560. # by the type that user assigned.
  561. # Then, this function will put this light node back into lighting
  562. # panel with the newest lighting list and update the data on the panel.
  563. #################################################################
  564. list, lightNode = AllScene.createLight(type = type)
  565. if self.lightingPanel != None:
  566. self.lightingPanel.updateList(list,lightNode)
  567. self.makeDirty()
  568. return
  569. def lightingPanelClose(self):
  570. #################################################################
  571. # lightingPanelClose(self)
  572. # This function will be called when user try to close the lighting panel
  573. # This function will re-config the state of the lighting panel button on the top screen
  574. # And it will set the self.lightingPanel to None
  575. #################################################################
  576. self.menuPanel.entryconfig('Lighting Panel', state=NORMAL)
  577. self.lightingPanel = None
  578. return
  579. def openPropertyPanel(self, nodePath = None):
  580. #################################################################
  581. # openPropertyPanel(self, nodePath = None)
  582. # This function will be called when user try to open a property window
  583. # for one specific node in the scene.
  584. # Here we will call dataHolder to get the basic properties
  585. # we would like to let user to see and cange.
  586. # And then we pass those information into propertyWindow
  587. #################################################################
  588. type, info = AllScene.getInfoOfThisNode(nodePath)
  589. name = nodePath.getName()
  590. if not self.propertyWindow.has_key(name):
  591. self.propertyWindow[name] = propertyWindow(nodePath, type,info )
  592. pass
  593. def closePropertyWindow(self, name):
  594. if self.propertyWindow.has_key(name):
  595. del self.propertyWindow[name]
  596. return
  597. def openMetadataPanel(self,nodePath=None):
  598. print nodePath
  599. self.MetadataPanel=MetadataPanel(nodePath)
  600. pass
  601. def duplicate(self, nodePath = None):
  602. #################################################################
  603. # duplicate(self, nodePath = None)
  604. # This function will be called when user try to open the duplication window
  605. #################################################################
  606. print '----Duplication!!'
  607. if nodePath != None:
  608. self.duplicateWindow = duplicateWindow(nodePath = nodePath)
  609. pass
  610. def remove(self, nodePath = None):
  611. #################################################################
  612. # remove(self, nodePath = None)
  613. # This function will be called when user try to delete a node from scene
  614. #
  615. # For safty issue,
  616. # we will do deselect first then remove the certain node.
  617. #
  618. #################################################################
  619. if nodePath==None:
  620. if self.nodeSelected == None:
  621. return
  622. nodePath = self.nodeSelected
  623. self.deSelectNode()
  624. if AllScene.isLight(nodePath.getName()):
  625. self.removeLight(nodePath)
  626. else:
  627. AllScene.removeObj(nodePath)
  628. pass
  629. def addDummyNode(self, nodepath = None):
  630. #################################################################
  631. # addDummyNode(self, nodepath = None)
  632. # This function will be called when user try to create a dummy node into scene
  633. #
  634. # Here we will call dataHolder to create a dummy node
  635. # and reparent it to the nodePath that user has assigned.
  636. #
  637. #################################################################
  638. AllScene.addDummyNode(nodepath)
  639. self.makeDirty()
  640. pass
  641. def addCollisionObj(self, nodepath = None):
  642. #################################################################
  643. # addCollisionObj(self, nodepath = None)
  644. # This function will be called when user try to create a collision object into the scene
  645. #
  646. # Here we will call collisionWindow to ask user what kind of collision objects they want to have.
  647. # Then, send the information and generated collision object to dataHolder to finish the whole process
  648. # and reparent it to the nodePath that user has assigned.
  649. #
  650. #################################################################
  651. self.collisionWindow = collisionWindow(nodepath)
  652. pass
  653. def setAsReparentTarget(self, nodepath = None):
  654. #################################################################
  655. # setAsReparentTarget(self, nodepath = None)
  656. # This function will be called when user select a nodePaht
  657. # and want to reparent other node under it. (Drom side window pop-up nemu)
  658. #################################################################
  659. SEditor.setActiveParent(nodepath)
  660. return
  661. def reparentToNode(self, nodepath = None):
  662. #################################################################
  663. # reparentToNode(self, nodepath = None)
  664. # This function will be call when user try to reparent a node to
  665. # that node he selected as a reparent target before.
  666. #
  667. # The whole reparent process is handled by seSession,
  668. # which is tunned from DirectSession
  669. #
  670. #################################################################
  671. SEditor.reparent(nodepath, fWrt = 1)
  672. return
  673. def openPlacerPanel(self, nodePath = None):
  674. #################################################################
  675. # openPlacerPanel(self, nodePath = None)
  676. # This function will be call when user try to open a placer panel.
  677. # This call will only success if there is no other placer panel been activated
  678. #################################################################
  679. if(self.placer==None):
  680. self.placer = Placer()
  681. self.menuPanel.entryconfig('Placer Panel', state=DISABLED)
  682. return
  683. def closePlacerPanel(self):
  684. #################################################################
  685. # closePlacerPanel(self)
  686. # This function will be called when user close the placer panel.
  687. # Here we will reset the self.placer back to None.
  688. # (You can think this is just like a reference count)
  689. #################################################################
  690. self.placer = None
  691. self.menuPanel.entryconfig('Placer Panel', state=NORMAL)
  692. return
  693. def openAnimPanel(self, nodePath = None):
  694. #################################################################
  695. # openAnimPanel(self, nodePath = None)
  696. # This function will be called when user tries to open an Animation Panel
  697. # This will generated a panel and put it
  698. # into a dictionary using the actor's name as an index.
  699. # So, if there already has an animation panel for the target actor,
  700. # it won't allow user to open another one.
  701. #################################################################
  702. name = nodePath.getName()
  703. if AllScene.isActor(name):
  704. if self.animPanel.has_key(name):
  705. print '---- You already have an animation panel for this Actor!'
  706. return
  707. else:
  708. Actor = AllScene.getActor(name)
  709. self.animPanel[name] = seAnimPanel.AnimPanel(aNode=Actor)
  710. pass
  711. def openMoPathPanel(self, nodepath = None):
  712. #################################################################
  713. # openMoPathPanel(self, nodepath = None)
  714. # This function will open a Motion Path Recorder for you.
  715. #################################################################
  716. if self.MopathPanel == None:
  717. self.MopathPanel = MopathRecorder()
  718. pass
  719. def mopathClosed(self):
  720. self.MopathPanel = None
  721. return
  722. def changeName(self, nodePath, nName):
  723. #################################################################
  724. # changeName(self, nodePath, nName)
  725. # This function will be called when user tries to change the name of the node
  726. #################################################################
  727. oName = nodePath.getName() # I need this line in order to check the obj name in the control panel.
  728. AllScene.rename(nodePath,nName)
  729. # reset the list in the controller panel if it has been opened.
  730. if (self.controllerPanel) != None:
  731. list = AllScene.getAllObjNameAsList()
  732. self.controllerPanel.resetNameList(list = list, name = oName, nodePath = nodePath)
  733. return
  734. # Take care things under File menu
  735. def newScene(self):
  736. #################################################################
  737. # newScene(self)
  738. # This function will clear whole stuff in the scene
  739. # and will reset the application title to "New Scene"
  740. #################################################################
  741. self.closeAllSubWindows() ## Close all sub window
  742. if(self.CurrentFileName):
  743. currentF=Filename(self.CurrentFileName)
  744. self.CurrentFileName=None
  745. AllScene.resetAll()
  746. currentModName=currentF.getBasenameWoExtension()
  747. # Let us actually remove the scene from sys modules... this is done because every scene is loaded as a module
  748. # And if we reload a scene python wont reload since its already in sys.modules... and hence we delete it
  749. # If there is ever a garbage colleciton bug..this might be a point to look at
  750. if sys.modules.has_key(currentModName):
  751. del sys.modules[currentModName]
  752. print sys.getrefcount(AllScene.theScene)
  753. del AllScene.theScene
  754. else:
  755. AllScene.resetAll()
  756. self.parent.title('Scene Editor - New Scene')
  757. pass
  758. def openScene(self):
  759. #################################################################
  760. # openScene(self)
  761. #################################################################
  762. # In the future try and provide merging of two scenes
  763. if(self.CurrentFileName or self.Dirty):
  764. saveScene = tkMessageBox._show("Load scene","Save the current scene?",icon = tkMessageBox.QUESTION,type = tkMessageBox.YESNOCANCEL)
  765. if (saveScene == "yes"):
  766. self.saveScene()
  767. elif (saveScene == "cancel"):
  768. return
  769. self.closeAllSubWindows() ## Close all sub window
  770. if(self.CurrentFileName):
  771. currentF=Filename(self.CurrentFileName)
  772. AllScene.resetAll()
  773. currentModName=currentF.getBasenameWoExtension()
  774. # Let us actually remove the scene from sys modules... this is done because every scene is loaded as a module
  775. # And if we reload a scene python wont reload since its already in sys.modules... and hence we delete it
  776. # If there is ever a garbage colleciton bug..this might be a point to look at
  777. if sys.modules.has_key(currentModName):
  778. del sys.modules[currentModName]
  779. print sys.getrefcount(AllScene.theScene)
  780. del AllScene.theScene
  781. else:
  782. AllScene.resetAll()
  783. self.CurrentFileName = AllScene.loadScene()
  784. if(self.CurrentFileName==None):
  785. return
  786. thefile=Filename(self.CurrentFileName)
  787. thedir=thefile.getFullpathWoExtension()
  788. print "SCENE EDITOR::" + thedir
  789. self.CurrentDirName=thedir
  790. if self.CurrentFileName != None:
  791. self.parent.title('Scene Editor - '+ Filename.fromOsSpecific(self.CurrentFileName).getBasenameWoExtension())
  792. if self.lightingPanel !=None:
  793. lightList=AllScene.getList()
  794. self.lightingPanel.updateList(lightList)
  795. messenger.send('SGE_Update Explorer',[render])
  796. # Close the side window in order to reset all world settings to fit the scene we have loaded.
  797. self.sideWindow.quit()
  798. # Try to re-open the side window again
  799. while self.sideWindow == None:
  800. wColor = base.getBackgroundColor()
  801. self.worldColor[0] = wColor.getX()
  802. self.worldColor[1] = wColor.getY()
  803. self.worldColor[2] = wColor.getZ()
  804. self.worldColor[3] = wColor.getW()
  805. self.lightEnable = 1
  806. self.ParticleEnable = 1
  807. self.collision = 1
  808. self.openSideWindow()
  809. def saveScene(self):
  810. #################################################################
  811. # saveScene(self)
  812. # If this is an open file call saveAsScene
  813. # or else instantiate FileSaver from seFileSaver.py and pass it the filename
  814. # If this filename exists in sys.modules you cannot use it
  815. #################################################################
  816. if(self.CurrentFileName):
  817. f=FileSaver()
  818. f.SaveFile(AllScene,self.CurrentFileName,self.CurrentDirName,1)
  819. self.Dirty=0
  820. else:
  821. self.saveAsScene()
  822. pass
  823. def saveAsBam(self):
  824. fileName = tkFileDialog.asksaveasfilename(filetypes = [("BAM",".bam")],title = "Save Scenegraph as Bam file")
  825. theScene=render.find("**/Scene")
  826. if not theScene is None:
  827. theScene.writeBamFile(fileName)
  828. else:
  829. render.writeBamFile(fileName+".bad")
  830. print " Scenegraph saved as :" +str(fileName)
  831. def loadFromBam(self):
  832. fileName = tkFileDialog.askopenfilename(filetypes = [("BAM",".bam")],title = "Load Scenegraph from Bam file")
  833. if not fileName is None:
  834. d=path(fileName)
  835. scene=loader.loadModel(d.relpath())
  836. scene.reparentTo(render)
  837. def saveAsScene(self):
  838. #################################################################
  839. # saveAsScene(self)
  840. # Ask for filename using a file save dialog
  841. # If this filename exists in sys.modules you cannot use it
  842. # Instantiate FileSaver from seFileSaver.py and pass it the filename
  843. #################################################################
  844. fileName = tkFileDialog.asksaveasfilename(filetypes = [("PY","py")],title = "Save Scene")
  845. if(not fileName):
  846. return
  847. fCheck=Filename(fileName)
  848. #print fCheck.getBasenameWoExtension()
  849. ###############################################################################
  850. # !!!!! See if a module exists by this name... if it does you cannot use this filename !!!!!
  851. ###############################################################################
  852. if(sys.modules.has_key(fCheck.getBasenameWoExtension())):
  853. tkMessageBox.showwarning(
  854. "Save file",
  855. "Cannot save with this name because there is a system module with the same name. Please resave as something else."
  856. )
  857. return
  858. self.CurrentDirName=fileName
  859. fileName=fileName+".py"
  860. f=FileSaver()
  861. self.CurrentFileName=fileName
  862. f.SaveFile(AllScene,fileName,self.CurrentDirName,0)
  863. self.Dirty=0
  864. self.parent.title('Scene Editor - '+ Filename.fromOsSpecific(self.CurrentFileName).getBasenameWoExtension())
  865. pass
  866. def loadModel(self):
  867. #################################################################
  868. # loadModel(self)
  869. # This function will be called when user tries to load a model into the scene.
  870. # Here we will pop-up a dialog to ask user which model file should be loaded in.
  871. # Then, pass the path to dataHolder to load the model in.
  872. #################################################################
  873. modelFilename = askopenfilename(
  874. defaultextension = '.egg',
  875. filetypes = (('Egg Files', '*.egg'),
  876. ('Bam Files', '*.bam'),
  877. ('All files', '*')),
  878. initialdir = '.',
  879. title = 'Load New Model',
  880. parent = self.parent)
  881. if modelFilename:
  882. self.makeDirty()
  883. if not AllScene.loadModel(modelFilename, Filename.fromOsSpecific(modelFilename)):
  884. print '----Error! No Such Model File!'
  885. pass
  886. def loadActor(self):
  887. #################################################################
  888. # loadActor(self)
  889. # This function will be called when user tries to load an Actor into the scene.
  890. # Here we will pop-up a dialog to ask user which Actor file should be loaded in.
  891. # Then, pass the path to dataHolder to load the Actor in.
  892. #################################################################
  893. ActorFilename = askopenfilename(
  894. defaultextension = '.egg',
  895. filetypes = (('Egg Files', '*.egg'),
  896. ('Bam Files', '*.bam'),
  897. ('All files', '*')),
  898. initialdir = '.',
  899. title = 'Load New Actor',
  900. parent = self.parent)
  901. if ActorFilename:
  902. self.makeDirty()
  903. if not AllScene.loadActor(ActorFilename, Filename.fromOsSpecific(ActorFilename)):
  904. print '----Error! No Such Model File!'
  905. pass
  906. def importScene(self):
  907. self.makeDirty()
  908. print '----God bless you Please Import!'
  909. pass
  910. ## Take care those things under Edit nemu
  911. def unDo(self):
  912. pass
  913. def reDo(self):
  914. pass
  915. def deSelectNode(self, nodePath=None):
  916. #################################################################
  917. # deSelectNode(self, nodePath=None)
  918. # This function will deselect the node which we have selected currently.
  919. # This will also remove the monitor task which monitor selected object's
  920. # position, orientation and scale each frame.
  921. #################################################################
  922. if nodePath != None:
  923. self.seSession.deselect(nodePath)
  924. if self.isSelect:
  925. self.isSelect = False
  926. #if self.nodeSelected != None:
  927. # self.nodeSelected.hideBounds()
  928. self.nodeSelected =None
  929. self.menuEdit.entryconfig('Deselect', state=DISABLED)
  930. self.menuEdit.entryconfig('Add Dummy', state=DISABLED)
  931. self.menuEdit.entryconfig('Duplicate', state=DISABLED)
  932. self.menuEdit.entryconfig('Remove', state=DISABLED)
  933. self.menuEdit.entryconfig('Object Properties', state=DISABLED)
  934. if self.sideWindowCount==1:
  935. self.sideWindow.SGE.deSelectTree()
  936. if taskMgr.hasTaskNamed('seMonitorSelectedNode'):
  937. taskMgr.remove('seMonitorSelectedNode')
  938. return
  939. pass
  940. def addDummy(self):
  941. #################################################################
  942. # addDummy(self)
  943. # This function will do nothing but call other function
  944. # to add a dummy into the scene.
  945. #
  946. # Ok... this is really redundancy...
  947. #
  948. #################################################################
  949. self.addDummyNode(self.nodeSelected)
  950. pass
  951. def duplicateNode(self):
  952. #################################################################
  953. # duplicateNode(self)
  954. # This function will do nothing but call other function
  955. # to open the duplication window.
  956. #
  957. # Ok... this is really redundancy...
  958. #
  959. #################################################################
  960. if self.nodeSelected!=None:
  961. self.duplicate(self.nodeSelected)
  962. pass
  963. def removeNode(self):
  964. #################################################################
  965. # removeNode(self)
  966. # This function will do nothing but call other function
  967. # to remove the current selected node..
  968. #
  969. # Ok... this is really redundancy...
  970. #
  971. ################################################################
  972. self.remove(self.nodeSelected)
  973. pass
  974. def showObjProp(self):
  975. ################################################################
  976. # showObjProp(self)
  977. # This function will do nothing but call other function
  978. # to open the property window of current selected node..
  979. #
  980. # Ok... this is really redundancy...
  981. #
  982. ################################################################
  983. self.openPropertyPanel(self.nodeSelected)
  984. pass
  985. def showCameraSetting(self):
  986. ################################################################
  987. # showCameraSetting(self)
  988. # This function will do nothing but call other function
  989. # to open the property window of camera..
  990. #
  991. # Ok... this is really redundancy...
  992. #
  993. ################################################################
  994. self.openPropertyPanel(camera)
  995. pass
  996. def showRenderSetting(self):
  997. '''Currently, no idea what gonna pop-out here...'''
  998. pass
  999. ## Take care those thins under Edit nemu
  1000. def openSideWindow(self):
  1001. ################################################################
  1002. # openSideWindow(self)
  1003. # This function will open the side window and set the reference number
  1004. # so that we can make sure there won't have two or more side windows in the same time.
  1005. ################################################################
  1006. if self.sideWindowCount==0:
  1007. self.sideWindow = sideWindow(worldColor = self.worldColor,
  1008. lightEnable = self.lightEnable,
  1009. ParticleEnable = self.ParticleEnable,
  1010. basedriveEnable = self.basedriveEnable,
  1011. collision = self.collision,
  1012. backface = self.backface,
  1013. texture = self.texture,
  1014. wireframe = self.wireframe,
  1015. grid = self.grid,
  1016. widgetVis = self.widgetVis,
  1017. enableAutoCamera = self.enableAutoCamera)
  1018. self.sideWindowCount = 1
  1019. self.menuPanel.entryconfig('Side Window', state=DISABLED)
  1020. return
  1021. def openAnimationPanel(self):
  1022. ################################################################
  1023. # openAnimationPanel(self)
  1024. # This function will do nothing but call other function
  1025. # to open the animation window for selected node(if it is an Actor)..
  1026. #
  1027. # Ok... this is really redundancy...
  1028. #
  1029. ################################################################
  1030. if AllScene.isActor(self.nodeSelected):
  1031. self.openAnimPanel(self.nodeSelected)
  1032. pass
  1033. def openMopathPanel(self):
  1034. ################################################################
  1035. # openMopathPanel(self)
  1036. # This function will create a Motion Path Recorder
  1037. ################################################################
  1038. MopathPanel = MopathRecorder()
  1039. pass
  1040. def toggleParticleVisable(self, visable):
  1041. ################################################################
  1042. # toggleParticleVisable(self, visable)
  1043. # This function will be called each time user has toggled
  1044. # the check box of Particle visibility in the side window.
  1045. # The reason we keep track this is because
  1046. # we have to know we should show/hide the model on the new-created particle
  1047. ################################################################
  1048. self.ParticleEnable = visable
  1049. AllScene.toggleParticleVisable(visable)
  1050. return
  1051. def openLightingPanel(self):
  1052. ################################################################
  1053. # openLightingPanel(self)
  1054. # open the lighting panel here.
  1055. # If there is already exist a lighting panel, then do nothing
  1056. ################################################################
  1057. if self.lightingPanel==None:
  1058. self.lightingPanel = lightingPanel(AllScene.getLightList())
  1059. self.menuPanel.entryconfig('Lighting Panel', state=DISABLED)
  1060. return
  1061. def addParticleEffect(self,effect_name,effect,node):
  1062. AllScene.particleDict[effect_name]=effect
  1063. AllScene.particleNodes[effect_name]=node
  1064. if not self.ParticleEnable:
  1065. AllScene.particleNodes[effect_name].setTransparency(True)
  1066. AllScene.particleNodes[effect_name].setAlphaScale(0)
  1067. AllScene.particleNodes[effect_name].setBin("fixed",1)
  1068. return
  1069. def openParticlePanel(self):
  1070. if self.particlePanel != None:
  1071. ## There already has a Particle panel!
  1072. return
  1073. if(len(AllScene.particleDict)==0):
  1074. self.particlePanel=seParticlePanel.ParticlePanel()
  1075. else:
  1076. for effect in AllScene.particleDict:
  1077. theeffect=AllScene.particleDict[effect]
  1078. self.particlePanel=seParticlePanel.ParticlePanel(particleEffect=theeffect,effectsDict=AllScene.particleDict)
  1079. pass
  1080. def closeParticlePanel(self):
  1081. self.particlePanel = None
  1082. return
  1083. def openInputPanel(self):
  1084. if self.controllerPanel==None:
  1085. list = AllScene.getAllObjNameAsList()
  1086. type, dataList = AllScene.getControlSetting()
  1087. self.controllerPanel = controllerWindow(listOfObj = list, controlType = type, dataList = dataList)
  1088. pass
  1089. def closeInputPanel(self):
  1090. self.controllerPanel = None
  1091. return
  1092. def requestObjFromControlW(self, name):
  1093. ################################################################
  1094. # requestObjFromControlW(self, name)
  1095. # Call back function
  1096. # Each time when user selects a node from Control Panel,
  1097. # this function will be called.
  1098. # This function will get the actual nodePath from dataHolder and then
  1099. # set it back into controller panel
  1100. ################################################################
  1101. node = AllScene.getObjFromSceneByName(name)
  1102. if (self.controllerPanel) != None and (node!=None):
  1103. self.controllerPanel.setNodePathIn(node)
  1104. return
  1105. def setControlSet(self, controlType, dataList):
  1106. if controlType == 'Keyboard':
  1107. self.controlTarget = dataList[0]
  1108. self.keyboardMapDict.clear()
  1109. self.keyboardMapDict = dataList[1].copy()
  1110. self.keyboardSpeedDict.clear()
  1111. self.keyboardSpeedDict = dataList[2].copy()
  1112. return
  1113. def startControl(self, controlType, dataList):
  1114. if not self.enableControl:
  1115. self.enableControl = True
  1116. else:
  1117. # Stop the current control setting first
  1118. # Also this will make sure we won't catch wrong keyboard message
  1119. self.stopControl(controlType)
  1120. self.enableControl = True
  1121. self.setControlSet(controlType, dataList)
  1122. self.lastContorlTimer = globalClock.getFrameTime()
  1123. if controlType == 'Keyboard':
  1124. self.controlType = 'Keyboard'
  1125. self.keyControlEventDict = {}
  1126. self.transNodeKeyboard = self.controlTarget.attachNewNode('transformNode')
  1127. self.transNodeKeyboard.hide()
  1128. for index in self.keyboardMapDict:
  1129. self.keyControlEventDict[index] = 0
  1130. self.accept(self.keyboardMapDict[index], lambda a = index:self.keyboardPushed(a))
  1131. self.accept(self.keyboardMapDict[index]+'-up', lambda a = index:self.keyboardReleased(a))
  1132. return
  1133. def stopControl(self, controlType):
  1134. if not self.enableControl:
  1135. return
  1136. if controlType == 'Keyboard':
  1137. self.enableControl = False
  1138. for index in self.keyboardMapDict:
  1139. self.ignore(self.keyboardMapDict[index])
  1140. self.ignore(self.keyboardMapDict[index]+'-up')
  1141. taskMgr.remove("KeyboardControlTask")
  1142. self.transNodeKeyboard.removeNode()
  1143. return
  1144. def keyboardPushed(self, key):
  1145. self.keyControlEventDict[key] = 1
  1146. if not taskMgr.hasTaskNamed("KeyboardControlTask"):
  1147. self.keyboardLastTimer = globalClock.getFrameTime()
  1148. taskMgr.add(self.keyboardControlTask, "KeyboardControlTask")
  1149. return
  1150. def keyboardReleased(self, key):
  1151. self.keyControlEventDict[key] = 0
  1152. for index in self.keyControlEventDict:
  1153. if self.keyControlEventDict[index] == 1:
  1154. return
  1155. if taskMgr.hasTaskNamed("KeyboardControlTask"):
  1156. taskMgr.remove("KeyboardControlTask")
  1157. return
  1158. def keyboardControlTask(self, task):
  1159. newTimer = globalClock.getFrameTime()
  1160. delta = newTimer - self.keyboardLastTimer
  1161. self.keyboardLastTimer = newTimer
  1162. pos = self.controlTarget.getPos()
  1163. hpr = self.controlTarget.getHpr()
  1164. scale = self.controlTarget.getScale()
  1165. self.transNodeKeyboard.setPosHpr((self.keyControlEventDict['KeyRight']*self.keyboardSpeedDict['SpeedRight']-self.keyControlEventDict['KeyLeft']*self.keyboardSpeedDict['SpeedLeft'])*delta,
  1166. (self.keyControlEventDict['KeyForward']*self.keyboardSpeedDict['SpeedForward']-self.keyControlEventDict['KeyBackward']*self.keyboardSpeedDict['SpeedBackward'])*delta,
  1167. (self.keyControlEventDict['KeyUp']*self.keyboardSpeedDict['SpeedUp']-self.keyControlEventDict['KeyDown']*self.keyboardSpeedDict['SpeedDown'])*delta,
  1168. (self.keyControlEventDict['KeyTurnLeft']*self.keyboardSpeedDict['SpeedTurnLeft']-self.keyControlEventDict['KeyTurnRight']*self.keyboardSpeedDict['SpeedTurnRight'])*delta,
  1169. (self.keyControlEventDict['KeyTurnUp']*self.keyboardSpeedDict['SpeedTurnUp']-self.keyControlEventDict['KeyTurnDown']*self.keyboardSpeedDict['SpeedTurnDown'])*delta,
  1170. (self.keyControlEventDict['KeyRollLeft']*self.keyboardSpeedDict['SpeedRollLeft']-self.keyControlEventDict['KeyRollRight']*self.keyboardSpeedDict['SpeedRollRight'])*delta)
  1171. newPos = self.transNodeKeyboard.getPos(self.controlTarget.getParent())
  1172. newHpr = self.transNodeKeyboard.getHpr(self.controlTarget.getParent())
  1173. overAllScale = self.keyControlEventDict['KeyScaleUp']*self.keyboardSpeedDict['SpeedScaleUp']-self.keyControlEventDict['KeyScaleDown']*self.keyboardSpeedDict['SpeedScaleDown']
  1174. newScale = Point3(scale.getX() + (overAllScale + self.keyControlEventDict['KeyScaleXUp']*self.keyboardSpeedDict['SpeedScaleXUp'] - self.keyControlEventDict['KeyScaleXDown']*self.keyboardSpeedDict['SpeedScaleXDown'])*delta,
  1175. scale.getY() + (overAllScale + self.keyControlEventDict['KeyScaleYUp']*self.keyboardSpeedDict['SpeedScaleYUp'] - self.keyControlEventDict['KeyScaleYDown']*self.keyboardSpeedDict['SpeedScaleYDown'])*delta,
  1176. scale.getZ() + (overAllScale + self.keyControlEventDict['KeyScaleZUp']*self.keyboardSpeedDict['SpeedScaleZUp'] - self.keyControlEventDict['KeyScaleZDown']*self.keyboardSpeedDict['SpeedScaleZDown'])*delta
  1177. )
  1178. self.controlTarget.setPos(newPos.getX(), newPos.getY() , newPos.getZ())
  1179. self.controlTarget.setHpr(newHpr.getX(), newHpr.getY() , newHpr.getZ())
  1180. self.controlTarget.setScale(newScale.getX(),newScale.getY(),newScale.getZ())
  1181. self.transNodeKeyboard.setPosHpr(0,0,0,0,0,0)
  1182. return Task.cont
  1183. ## Misc
  1184. ##### This one get the event from SGE (Scene Graph Explorer) and Picking
  1185. def selectNode(self, nodePath=None, callBack = True):
  1186. ################################################################
  1187. # selectNode(self, nodePath=None, callBack = True)
  1188. # This will be called when user try to select nodes from the
  1189. # side window.
  1190. # It will also call seSession to select this node in order to keep data's consistency
  1191. ################################################################
  1192. if nodePath==None:
  1193. self.isSelect = False
  1194. self.nodeSelected =None
  1195. if taskMgr.hasTaskNamed('seMonitorSelectedNode'):
  1196. taskMgr.remove('seMonitorSelectedNode')
  1197. return
  1198. else:
  1199. self.isSelect = True
  1200. #if self.nodeSelected != None:
  1201. # self.nodeSelected.hideBounds()
  1202. self.nodeSelected = nodePath
  1203. #self.nodeSelected.showBounds()
  1204. self.menuEdit.entryconfig('Deselect', state=NORMAL)
  1205. self.menuEdit.entryconfig('Add Dummy', state=NORMAL)
  1206. self.menuEdit.entryconfig('Duplicate', state=NORMAL)
  1207. self.menuEdit.entryconfig('Remove', state=NORMAL)
  1208. self.menuEdit.entryconfig('Object Properties', state=NORMAL)
  1209. if callBack:
  1210. self.seSession.select(nodePath,fResetAncestry=1)
  1211. messenger.send('SGE_Update Explorer',[render])
  1212. if not taskMgr.hasTaskNamed('seMonitorSelectedNode'):
  1213. self.oPos = self.nodeSelected.getPos()
  1214. self.oHpr = self.nodeSelected.getHpr()
  1215. self.oScale = self.nodeSelected.getScale()
  1216. taskMgr.add(self.monitorSelectedNodeTask, 'seMonitorSelectedNode')
  1217. return
  1218. pass
  1219. def selectFromScene(self, nodePath=None, callBack=True):
  1220. ################################################################
  1221. # selectFromScene(self, nodePath=None, callBack = True)
  1222. # This will be called when user try to select nodes from the
  1223. # scene. (By picking)
  1224. # Actually this will be called by seSession
  1225. # The reason we make two selections is we don't want they call each other and never stop...
  1226. ################################################################
  1227. if nodePath==None:
  1228. self.isSelect = False
  1229. self.nodeSelected =None
  1230. if taskMgr.hasTaskNamed('seMonitorSelectedNode'):
  1231. taskMgr.remove('seMonitorSelectedNode')
  1232. return
  1233. else:
  1234. self.isSelect = True
  1235. #if self.nodeSelected != None:
  1236. # self.nodeSelected.hideBounds()
  1237. self.nodeSelected = nodePath
  1238. #self.nodeSelected.showBounds()
  1239. self.menuEdit.entryconfig('Deselect', state=NORMAL)
  1240. self.menuEdit.entryconfig('Add Dummy', state=NORMAL)
  1241. self.menuEdit.entryconfig('Duplicate', state=NORMAL)
  1242. self.menuEdit.entryconfig('Remove', state=NORMAL)
  1243. self.menuEdit.entryconfig('Object Properties', state=NORMAL)
  1244. self.sideWindow.SGE.selectNodePath(nodePath,callBack)
  1245. messenger.send('SGE_Update Explorer',[render])
  1246. if not taskMgr.hasTaskNamed('seMonitorSelectedNode'):
  1247. self.oPos = self.nodeSelected.getPos()
  1248. self.oHpr = self.nodeSelected.getHpr()
  1249. self.oScale = self.nodeSelected.getScale()
  1250. taskMgr.add(self.monitorSelectedNodeTask, 'seMonitorSelectedNode')
  1251. return
  1252. pass
  1253. def monitorSelectedNodeTask(self, task):
  1254. ################################################################
  1255. # monitorSelectedNodeTask(self, task)
  1256. # This is a function which will keep tracking
  1257. # the position, orientation and scale data of selected node and update the display on the screen.
  1258. # Alos, it will send out message to sychronize the data in the placer and property window.
  1259. ################################################################
  1260. if self.nodeSelected != None:
  1261. pos = self.nodeSelected.getPos()
  1262. hpr = self.nodeSelected.getHpr()
  1263. scale = self.nodeSelected.getScale()
  1264. if ((self.oPos != pos )or(self.oScale != scale)or(self.oHpr != hpr)):
  1265. messenger.send('forPorpertyWindow'+self.nodeSelected.getName(),[pos, hpr, scale])
  1266. messenger.send('placerUpdate')
  1267. self.oPos = pos
  1268. self.oScale = scale
  1269. self.oHpr = hpr
  1270. self.posLabel['text'] = "Position : X: %2.2f Y: %2.2f Z: %2.2f"%(pos.getX(), pos.getY(),pos.getZ())
  1271. self.hprLabel['text'] = "Orientation: H: %2.2f P: %2.2f R: %2.2f"%(hpr.getX(), hpr.getY(),hpr.getZ())
  1272. self.scaleLabel['text'] = "Scale : X: %2.2f Y: %2.2f Z: %2.2f"%(scale.getX(), scale.getY(),scale.getZ())
  1273. return Task.cont
  1274. def deselectFromScene(self):
  1275. ################################################################
  1276. # deselectFromScene(self)
  1277. # This function will do nothing but call other function
  1278. # to delete selected node...
  1279. #
  1280. # Ok... this is really redundancy...
  1281. #
  1282. ################################################################
  1283. self.deSelectNode(self.nodeSelected)
  1284. messenger.send('SGE_Update Explorer',[render])
  1285. ##### Take care the even quest from Side Window
  1286. def lightToggle(self):
  1287. ################################################################
  1288. # lightToggle(self)
  1289. # This function will do nothing but call other function
  1290. # to toggle the light...
  1291. ################################################################
  1292. self.makeDirty()
  1293. AllScene.toggleLight()
  1294. return
  1295. def sideWindowClose(self,worldColor,lightEnable,ParticleEnable, basedriveEnable,collision,
  1296. backface, texture, wireframe, grid, widgetVis, enableAutoCamera):
  1297. ################################################################
  1298. # sideWindowClose(self,worldColor,lightEnable,ParticleEnable, basedriveEnable,collision,
  1299. # backface, texture, wireframe, grid, widgetVis, enableAutoCamera):
  1300. # This function will be called when user close the side window.
  1301. # Here we will restore all parameters about world setting back in the sceneEditor.
  1302. # So, when next time people recall the side window, it will still keep the same world setting.
  1303. ################################################################
  1304. if self.sideWindowCount==1:
  1305. self.worldColor = worldColor
  1306. self.lightEnable = lightEnable
  1307. self.ParticleEnable = ParticleEnable
  1308. self.basedriveEnable = basedriveEnable
  1309. self.collision = collision
  1310. self.backface = backface
  1311. self.texture = texture
  1312. self.wireframe = wireframe
  1313. self.grid = grid
  1314. self.enableAutoCamera = enableAutoCamera
  1315. self.widgetVis = widgetVis
  1316. self.sideWindowCount=0
  1317. self.sideWindow = None
  1318. self.menuPanel.entryconfig('Side Window', state=NORMAL)
  1319. return
  1320. ## Process message from Duplication Window
  1321. def duplicationObj(self, nodePath, pos, hpr, scale, num):
  1322. ################################################################
  1323. # duplicationObj(self, nodePath, pos, hpr, scale, num)
  1324. # This function will do nothing but call other function
  1325. # to duplicate selected node...
  1326. #
  1327. # Ok... this is really redundancy...
  1328. #
  1329. ################################################################
  1330. AllScene.duplicateObj(nodePath, pos, hpr, scale, num)
  1331. return
  1332. ## Process message from Animation Panel
  1333. def animationLoader(self, nodePath, Dic):
  1334. name = nodePath.getName()
  1335. AllScene.loadAnimation(name, Dic)
  1336. return
  1337. def animationRemove(self, nodePath, name):
  1338. AllScene.removeAnimation(nodePath.getName(),name)
  1339. return
  1340. def animPanelClose(self, name):
  1341. if self.animPanel.has_key(name):
  1342. del self.animPanel[name]
  1343. return
  1344. ### Blend Animation Panel
  1345. def openBlendAnimPanel(self, nodePath=None):
  1346. ################################################################
  1347. # openBlendAnimPanel(self, nodePath=None)
  1348. # This function will get the user defined blending animation data from dataHolder.
  1349. # And then open a blendAnimPanel by passing those data in.
  1350. ################################################################
  1351. name = nodePath.getName()
  1352. if AllScene.isActor(name):
  1353. if self.animBlendPanel.has_key(name):
  1354. print '---- You already have an Blend Animation Panel for this Actor!'
  1355. return
  1356. else:
  1357. Actor = AllScene.getActor(name)
  1358. Dict = AllScene.getBlendAnimAsDict(name)
  1359. self.animBlendPanel[name] = BlendAnimPanel(aNode=Actor, blendDict=Dict)
  1360. pass
  1361. return
  1362. def animBlendPanelSave(self, actorName, blendName, animNameA, animNameB, effect):
  1363. ################################################################
  1364. # animBlendPanelSave(self, actorName, blendName, animNameA, animNameB, effect)
  1365. # This function will call dataHolder to save the blended animation.
  1366. # Then, it will reset the newest blended animation list back to animBlendPanel
  1367. ################################################################
  1368. dict = AllScene.saveBlendAnim(actorName, blendName, animNameA, animNameB, effect)
  1369. self.animBlendPanel[actorName].setBlendAnimList(dict)
  1370. return
  1371. def animBlendPanelRemove(self, actorName, blendName):
  1372. ################################################################
  1373. # animBlendPanelRemove(self, actorName, blendName)
  1374. # This function will call dataHolder to remove the blended animation.
  1375. # Then, it will reset the newest blended animation list back to animBlendPanel
  1376. ################################################################
  1377. dict = AllScene.removeBlendAnim(actorName, blendName)
  1378. self.animBlendPanel[actorName].setBlendAnimList(dict, True)
  1379. return
  1380. def animBlendPanelRename(self, actorName, nName, oName, animNameA, animNameB, effect):
  1381. ################################################################
  1382. # animBlendPanelRename(self, actorName, nName, oName, animNameA, animNameB, effect)
  1383. # This function will call dataHolder to rename the blended animation.
  1384. # Then, it will reset the newest blended animation list back to animBlendPanel
  1385. ################################################################
  1386. dict = AllScene.renameBlendAnim(actorName, nName, oName, animNameA, animNameB, effect)
  1387. self.animBlendPanel[actorName].setBlendAnimList(dict)
  1388. return
  1389. def animBlendPanelClose(self, name):
  1390. ################################################################
  1391. # animBlendPanelClose(self, name)
  1392. # This function will be called when Blend panel has been closed.
  1393. # Here we will reset the reference dictionary so it can be open again.
  1394. ################################################################
  1395. if self.animBlendPanel.has_key(name):
  1396. del self.animBlendPanel[name]
  1397. return
  1398. ## Process message from SEditor object
  1399. def toggleWidgetVis(self):
  1400. ################################################################
  1401. # toggleWidgetVis(self)
  1402. # This function will be called when user use the hot-key to change the
  1403. # world setting. (From seSession)
  1404. # In this function we will restore the change and let side window know
  1405. # the hot-key ahs been pushed.
  1406. ################################################################
  1407. if self.sideWindow != None:
  1408. self.sideWindow.toggleWidgetVisFromMainW()
  1409. else:
  1410. self.widgetVis = (self.widgetVis+1)%2
  1411. def toggleBackface(self):
  1412. ################################################################
  1413. # toggleBackface(self)
  1414. # This function will be called when user use the hot-key to change the
  1415. # world setting. (From seSession)
  1416. # In this function we will restore the change and let side window know
  1417. # the hot-key ahs been pushed.
  1418. ################################################################
  1419. if self.sideWindow != None:
  1420. self.sideWindow.toggleBackfaceFromMainW()
  1421. else:
  1422. self.backface = (self.backface+1)%2
  1423. def toggleTexture(self):
  1424. ################################################################
  1425. # toggleTexture(self)
  1426. # This function will be called when user use the hot-key to change the
  1427. # world setting. (From seSession)
  1428. # In this function we will restore the change and let side window know
  1429. # the hot-key ahs been pushed.
  1430. ################################################################
  1431. if self.sideWindow != None:
  1432. self.sideWindow.toggleTextureFromMainW()
  1433. else:
  1434. self.texture = (self.texture+1)%2
  1435. def toggleWireframe(self):
  1436. ################################################################
  1437. # toggleWireframe(self)
  1438. # This function will be called when user use the hot-key to change the
  1439. # world setting. (From seSession)
  1440. # In this function we will restore the change and let side window know
  1441. # the hot-key ahs been pushed.
  1442. ################################################################
  1443. if self.sideWindow != None:
  1444. self.sideWindow.toggleWireframeFromMainW()
  1445. else:
  1446. self.wireframe = (self.wireframe+1)%2
  1447. def openAlignPanel(self, nodePath=None):
  1448. name = nodePath.getName()
  1449. if not self.alignPanelDict.has_key(name):
  1450. list = AllScene.getAllObjNameAsList()
  1451. if name in list:
  1452. list.remove(name)
  1453. else:
  1454. return
  1455. self.alignPanelDict[name] = AlignTool(nodePath = nodePath, list = list)
  1456. return
  1457. def closeAlignPanel(self, name=None):
  1458. if self.alignPanelDict.has_key(name):
  1459. del self.alignPanelDict[name]
  1460. def alignObject(self, nodePath, name, list):
  1461. target = AllScene.getObjFromSceneByName(name)
  1462. pos = target.getPos()
  1463. hpr = target.getHpr()
  1464. scale = target.getScale()
  1465. if list[0]: # Align X
  1466. nodePath.setX(pos.getX())
  1467. if list[1]: # Align Y
  1468. nodePath.setY(pos.getY())
  1469. if list[2]: # Align Z
  1470. nodePath.setZ(pos.getZ())
  1471. if list[3]: # Align H
  1472. nodePath.setH(hpr.getX())
  1473. if list[4]: # Align P
  1474. nodePath.setP(hpr.getY())
  1475. if list[5]: # Align R
  1476. nodePath.setR(hpr.getZ())
  1477. if list[6]: # Scale X
  1478. nodePath.setSx(scale.getX())
  1479. if list[7]: # Scale Y
  1480. nodePath.setSy(scale.getY())
  1481. if list[8]: # Scale Z
  1482. nodePath.setSz(scale.getZ())
  1483. return
  1484. ### Event from Motion Path Panel
  1485. def requestCurveList(self, nodePath,name):
  1486. curveList = AllScene.getCurveList(nodePath)
  1487. messenger.send('curveListFor'+name, [curveList])
  1488. ## Steal from DirectSession...
  1489. def flash(self, nodePath = 'None Given'):
  1490. """ Highlight an object by setting it red for a few seconds """
  1491. # Clean up any existing task
  1492. taskMgr.remove('flashNodePath')
  1493. # Spawn new task if appropriate
  1494. if nodePath == 'None Given':
  1495. # If nothing specified, try selected node path
  1496. nodePath = self.selected.last
  1497. if nodePath:
  1498. if nodePath.hasColor():
  1499. doneColor = nodePath.getColor()
  1500. flashColor = VBase4(1) - doneColor
  1501. flashColor.setW(1)
  1502. else:
  1503. doneColor = None
  1504. flashColor = VBase4(1,0,0,1)
  1505. # Temporarily set node path color
  1506. nodePath.setColor(flashColor)
  1507. # Clean up color in a few seconds
  1508. t = taskMgr.doMethodLater(1.5,
  1509. # This is just a dummy task
  1510. self.flashDummy,
  1511. 'flashNodePath')
  1512. t.nodePath = nodePath
  1513. t.doneColor = doneColor
  1514. # This really does all the work
  1515. t.uponDeath = self.flashDone
  1516. def flashDummy(self, state):
  1517. # Real work is done in upon death function
  1518. return Task.done
  1519. def flashDone(self,state):
  1520. # Return node Path to original state
  1521. if state.nodePath.isEmpty():
  1522. # Node path doesn't exist anymore, bail
  1523. return
  1524. if state.doneColor:
  1525. state.nodePath.setColor(state.doneColor)
  1526. else:
  1527. state.nodePath.clearColor()
  1528. editor = myLevelEditor(parent = tkroot)
  1529. run()