sceneEditor.py 75 KB

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