mainwindow.monkey2 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476
  1. Namespace ted2
  2. #Import "assets/about.html@/ted2"
  3. #Import "assets/scripts.json@/ted2"
  4. #Import "assets/newfiles/Simple_Console_App.monkey2@/ted2/newfiles"
  5. #Import "assets/newfiles/Simple_Mojo_App.monkey2@/ted2/newfiles"
  6. #Import "assets/newfiles/Letterboxed_Mojo_App.monkey2@/ted2/newfiles"
  7. Global MainWindow:MainWindowInstance
  8. Class MainWindowInstance Extends Window
  9. Field _debugging:String
  10. 'paths
  11. Field _tmp:String
  12. Field _mx2cc:String
  13. 'actions
  14. Field _fileNew:Action
  15. Field _fileOpen:Action
  16. Field _fileClose:Action
  17. Field _fileCloseOthers:Action
  18. Field _fileCloseAll:Action
  19. Field _fileSave:Action
  20. Field _fileSaveAs:Action
  21. Field _fileSaveAll:Action
  22. Field _fileNextFile:Action
  23. Field _filePrevFile:Action
  24. Field _fileOpenProject:Action
  25. Field _fileQuit:Action
  26. Field _editUndo:Action
  27. Field _editRedo:Action
  28. Field _editCut:Action
  29. Field _editCopy:Action
  30. Field _editPaste:Action
  31. Field _editSelectAll:Action
  32. Field _editFind:Action
  33. Field _buildDebug:Action
  34. Field _buildRelease:Action
  35. Field _buildForceStop:Action
  36. Field _buildLockFile:Action
  37. Field _buildNextError:Action
  38. Field _helpOnlineHelp:Action
  39. Field _helpOfflineHelp:Action
  40. Field _helpAbout:Action
  41. Field _findNext:Action
  42. Field _findPrevious:Action
  43. Field _findReplace:Action
  44. Field _findReplaceAll:Action
  45. Field _escape:Action
  46. 'menus
  47. Field _menuBar:MenuBar
  48. Field _newFiles:Menu
  49. Field _recentFiles:Menu
  50. Field _closeProject:Menu
  51. Field _scripts:Menu
  52. Field _fileMenu:Menu
  53. Field _tabMenu:Menu
  54. Field _editMenu:Menu
  55. Field _viewMenu:Menu
  56. Field _buildMenu:Menu
  57. Field _helpMenu:Menu
  58. Field _recent:=New Stack<String>
  59. Field _projects:=New Stack<String>
  60. 'dialogs
  61. Field _findDialog:FindDialog
  62. 'browsers
  63. Field _browser:TabView
  64. Field _projectView:ProjectView
  65. Field _debugView:DebugView
  66. Field _helpView:HelpView
  67. Field _console:Console
  68. 'documents
  69. Field _docTabber:TabView
  70. Field _currentDoc:Ted2Document
  71. Field _currentTextView:TextView
  72. Field _openDocs:=New Stack<Ted2Document>
  73. Field _lockedDoc:Ted2Document
  74. 'main docking view
  75. Field _docker:DockingView
  76. Field _errors:=New List<Mx2Error>
  77. Method OnFileNew()
  78. OpenDocument( "" )
  79. End
  80. Method OnFileOpen()
  81. Local path:=RequestFile( "Open file...","",False )
  82. If Not path Return
  83. OpenDocument( path,True )
  84. SaveState()
  85. End
  86. Method OnFileClose()
  87. If Not _currentDoc Return
  88. If _currentDoc.Dirty
  89. Local buttons:=New String[]( "Save","Discard Changes","Cancel" )
  90. Select TextDialog.Run( "Close","File '"+_currentDoc.Path+"' has been modified.",buttons )
  91. Case 0
  92. If Not SaveDocument( _currentDoc ) Return
  93. Case 2
  94. Return
  95. End
  96. Endif
  97. CloseDocument( _currentDoc )
  98. SaveState()
  99. End
  100. Method OnFileCloseOthers()
  101. Local docs:=_openDocs.Slice( 0 )
  102. For Local doc:=Eachin docs
  103. If doc<>_currentDoc CloseDocument( doc )
  104. Next
  105. End
  106. Method OnFileCloseAll()
  107. Local close:=New Stack<Ted2Document>
  108. For Local doc:=Eachin _openDocs
  109. If doc.Dirty
  110. MakeCurrent( doc )
  111. Local buttons:=New String[]( "Save","Discard Changes","Cancel" )
  112. Select TextDialog.Run( "Close All","File '"+doc.Path+"' has been modified.",buttons )
  113. Case 0
  114. If Not SaveDocument( doc ) Return
  115. Case 2
  116. Return
  117. End
  118. Endif
  119. close.Add( doc )
  120. Next
  121. For Local doc:=Eachin close
  122. CloseDocument( doc )
  123. Next
  124. SaveState()
  125. End
  126. Method OnFileSave()
  127. If Not _currentDoc Return
  128. SaveDocument( _currentDoc )
  129. End
  130. Method OnFileSaveAs()
  131. If Not _currentDoc Return
  132. Local path:=RequestFile( "Save As","",True )
  133. If Not path Return
  134. RenameDocument( _currentDoc,path )
  135. SaveDocument( _currentDoc )
  136. End
  137. Method OnFileSaveAll()
  138. For Local doc:=Eachin _openDocs
  139. SaveDocument( doc )
  140. Next
  141. End
  142. Method OnFileNextFile()
  143. If _docTabber.Count<2 Return
  144. Local i:=_docTabber.CurrentIndex+1
  145. If i=_docTabber.Count i=0
  146. Local doc:=FindDocument( _docTabber.TabView( i ) )
  147. If Not doc Return
  148. MakeCurrent( doc )
  149. End
  150. Method OnFilePrevFile()
  151. If _docTabber.Count<2 Return
  152. Local i:=_docTabber.CurrentIndex-1
  153. If i=-1 i=_docTabber.Count-1
  154. Local doc:=FindDocument( _docTabber.TabView( i ) )
  155. If Not doc Return
  156. MakeCurrent( doc )
  157. End
  158. Method OnFileOpenProject()
  159. Local dir:=RequestDir( "Select Project Directory...","" )
  160. If Not dir Return
  161. If Not _projectView.OpenProject( dir ) Return
  162. _projects.Push( dir )
  163. UpdateCloseProjectMenu()
  164. End
  165. Method OnFileQuit()
  166. For Local doc:=Eachin _openDocs
  167. If doc.Dirty
  168. MakeCurrent( doc )
  169. Local buttons:=New String[]( "Save","Discard Changes","Cancel" )
  170. Select TextDialog.Run( "Quit","File '"+doc.Path+"' has been modified.",buttons )
  171. Case 0
  172. If Not SaveDocument( doc ) Return
  173. Case 2
  174. Return
  175. End
  176. Endif
  177. Next
  178. SaveState()
  179. _console.Terminate()
  180. App.Terminate()
  181. End
  182. Method OnEditUndo()
  183. Local textView:=Cast<TextView>( App.KeyView )
  184. If textView textView.Undo()
  185. End
  186. Method OnEditRedo()
  187. Local textView:=Cast<TextView>( App.KeyView )
  188. If textView textView.Redo()
  189. End
  190. Method OnEditCut()
  191. Local textView:=Cast<TextView>( App.KeyView )
  192. If textView textView.Cut()
  193. End
  194. Method OnEditCopy()
  195. Local textView:=Cast<TextView>( App.KeyView )
  196. If textView textView.Copy()
  197. End
  198. Method OnEditPaste()
  199. Local textView:=Cast<TextView>( App.KeyView )
  200. If textView textView.Paste()
  201. End
  202. Method OnEditSelectAll()
  203. Local textView:=Cast<TextView>( App.KeyView )
  204. If textView textView.SelectAll()
  205. End
  206. Method OnEditFind()
  207. _findDialog.Open()
  208. End
  209. Method OnBuildDebug()
  210. Build( "debug" )
  211. End
  212. Method OnBuildRelease()
  213. Build( "release" )
  214. End
  215. Method OnBuildForceStop()
  216. _console.Terminate()
  217. End
  218. Method OnBuildLockFile()
  219. LockDoc( _currentDoc )
  220. End
  221. Method OnBuildNextError()
  222. While Not _errors.Empty And _errors.First.removed
  223. _errors.RemoveFirst()
  224. Wend
  225. If _errors.Empty Return
  226. _errors.AddLast( _errors.RemoveFirst() )
  227. GotoError( _errors.First )
  228. End
  229. Method OnHelpOnlineHelp()
  230. App.Idle+=Lambda()
  231. mojo.requesters.OpenUrl( "http://monkeycoder.co.nz/modules-reference/" )
  232. End
  233. End
  234. Method OnHelpOfflineHelp()
  235. App.Idle+=Lambda()
  236. mojo.requesters.OpenUrl( "file://"+CurrentDir()+"docs/index.html" )
  237. End
  238. End
  239. Method OnHelpAbout()
  240. Local htmlView:=New HtmlView
  241. htmlView.Go( "asset::ted2/about.html" )
  242. Local dialog:=New Dialog( "About Monkey2" )
  243. dialog.ContentView=htmlView
  244. dialog.MinSize=New Vec2i( 640,600 )
  245. dialog.MaxSize=Rect.Size
  246. dialog.AddAction( "Okay!" ).Triggered=Lambda()
  247. dialog.Close()
  248. End
  249. dialog.Open()
  250. End
  251. Method OnFindNext()
  252. If Not _currentTextView Return
  253. Local text:=_findDialog.FindText
  254. If Not text Return
  255. Local tvtext:=_currentTextView.Text
  256. Local cursor:=Max( _currentTextView.Anchor,_currentTextView.Cursor )
  257. If Not _findDialog.CaseSensitive
  258. tvtext=tvtext.ToLower()
  259. text=text.ToLower()
  260. Endif
  261. Local i:=tvtext.Find( text,cursor )
  262. If i=-1
  263. i=tvtext.Find( text )
  264. If i=-1 Return
  265. Endif
  266. _currentTextView.SelectText( i,i+text.Length )
  267. End
  268. Method OnFindPrevious()
  269. If Not _currentTextView Return
  270. Local text:=_findDialog.FindText
  271. If Not text Return
  272. Local tvtext:=_currentTextView.Text
  273. Local cursor:=Min( _currentTextView.Anchor,_currentTextView.Cursor )
  274. If Not _findDialog.CaseSensitive
  275. tvtext=tvtext.ToLower()
  276. text=text.ToLower()
  277. Endif
  278. Local i:=tvtext.Find( text )
  279. If i=-1 Return
  280. If i>=cursor
  281. i=tvtext.FindLast( text )
  282. Else
  283. Repeat
  284. Local n:=tvtext.Find( text,i+text.Length )
  285. If n>=cursor Exit
  286. i=n
  287. Forever
  288. End
  289. _currentTextView.SelectText( i,i+text.Length )
  290. End
  291. Method OnFindReplace()
  292. If Not _currentTextView Return
  293. Local text:=_findDialog.FindText
  294. If Not text Return
  295. Local min:=Min( _currentTextView.Anchor,_currentTextView.Cursor )
  296. Local max:=Max( _currentTextView.Anchor,_currentTextView.Cursor )
  297. Local tvtext:=_currentTextView.Text.Slice( min,max )
  298. If Not _findDialog.CaseSensitive
  299. tvtext=tvtext.ToLower()
  300. text=text.ToLower()
  301. Endif
  302. If tvtext<>text Return
  303. _currentTextView.ReplaceText( _findDialog.ReplaceText )
  304. OnFindNext()
  305. End
  306. Method OnFindReplaceAll()
  307. If Not _currentTextView Return
  308. Local text:=_findDialog.FindText
  309. If Not text Return
  310. Local rtext:=_findDialog.ReplaceText
  311. Local tvtext:=_currentTextView.Text
  312. If Not _findDialog.CaseSensitive
  313. tvtext=tvtext.ToLower()
  314. text=text.ToLower()
  315. Endif
  316. Local anchor:=_currentTextView.Anchor
  317. Local cursor:=_currentTextView.Cursor
  318. Local i:=0,t:=0
  319. Repeat
  320. Local i:=tvtext.Find( text,i )
  321. If i=-1 Exit
  322. _currentTextView.SelectText( i+t,i+text.Length+t )
  323. _currentTextView.ReplaceText( rtext )
  324. t+=rtext.Length-text.Length
  325. i+=text.Length
  326. Forever
  327. _currentTextView.SelectText( anchor,cursor )
  328. End
  329. Method OnEscape()
  330. If _findDialog.Visible
  331. _findDialog.Close()
  332. UpdateKeyView()
  333. Return
  334. Endif
  335. _console.Visible=Not _console.Visible
  336. End
  337. Method InitPaths()
  338. _tmp=RealPath( "tmp/" )
  339. #If __HOSTOS__="macos"
  340. _mx2cc="bin/mx2cc_macos"
  341. #Else If __HOSTOS__="windows"
  342. _mx2cc="bin/mx2cc_windows.exe"
  343. #Else
  344. _mx2cc="bin/mx2cc_linux"
  345. #Endif
  346. CreateDir( _tmp )
  347. End
  348. Method InitActions()
  349. _fileNew=New Action( "New" )
  350. _fileNew.HotKey=Key.N
  351. _fileNew.HotKeyModifiers=Modifier.Control
  352. _fileNew.Triggered=OnFileNew
  353. _fileOpen=New Action( "Open" )
  354. _fileOpen.HotKey=Key.O
  355. _fileOpen.HotKeyModifiers=Modifier.Control
  356. _fileOpen.Triggered=OnFileOpen
  357. _fileClose=New Action( "Close" )
  358. _fileClose.HotKey=Key.F4
  359. _fileClose.HotKeyModifiers=Modifier.Control
  360. _fileClose.Triggered=OnFileClose
  361. _fileCloseOthers=New Action( "Close Others" )
  362. _fileCloseOthers.Triggered=OnFileCloseOthers
  363. _fileCloseAll=New Action( "Close All" )
  364. _fileCloseAll.Triggered=OnFileCloseAll
  365. _fileSave=New Action( "Save" )
  366. _fileSave.HotKey=Key.S
  367. _fileSave.HotKeyModifiers=Modifier.Control
  368. _fileSave.Triggered=OnFileSave
  369. _fileSaveAs=New Action( "Save As" )
  370. _fileSaveAs.Triggered=OnFileSaveAs
  371. _fileSaveAll=New Action( "Save All" )
  372. _fileSaveAll.Triggered=OnFileSaveAll
  373. _fileNextFile=New Action( "Next File" )
  374. _fileNextFile.Triggered=OnFileNextFile
  375. _fileNextFile.HotKey=Key.Tab
  376. _fileNextFile.HotKeyModifiers=Modifier.Control
  377. _filePrevFile=New Action( "Previous File" )
  378. _filePrevFile.Triggered=OnFilePrevFile
  379. _filePrevFile.HotKey=Key.Tab
  380. _filePrevFile.HotKeyModifiers=Modifier.Control|Modifier.Shift
  381. _fileOpenProject=New Action( "Open project" )
  382. _fileOpenProject.Triggered=OnFileOpenProject
  383. _fileQuit=New Action( "Quit" )
  384. _fileQuit.Triggered=OnFileQuit
  385. _editUndo=New Action( "Undo" )
  386. _editUndo.HotKey=Key.Z
  387. _editUndo.HotKeyModifiers=Modifier.Control
  388. _editUndo.Triggered=OnEditUndo
  389. _editRedo=New Action( "Redo" )
  390. _editRedo.HotKey=Key.Y
  391. _editRedo.HotKeyModifiers=Modifier.Control
  392. _editRedo.Triggered=OnEditRedo
  393. _editCut=New Action( "Cut" )
  394. ' _editCut.HotKey=Key.X
  395. ' _editCut.HotKeyModifiers=Modifier.Control
  396. _editCut.Triggered=OnEditCut
  397. _editCopy=New Action( "Copy" )
  398. ' _editCopy.HotKey=Key.C
  399. ' _editCopy.HotKeyModifiers=Modifier.Control
  400. _editCopy.Triggered=OnEditCopy
  401. _editPaste=New Action( "Paste" )
  402. ' _editPaste.HotKey=Key.V
  403. ' _editPaste.HotKeyModifiers=Modifier.Control
  404. _editPaste.Triggered=OnEditPaste
  405. _editSelectAll=New Action( "Select All" )
  406. ' _editSelectAll.HotKey=Key.A
  407. ' _editSelectAll.HotKeyModifiers=Modifier.Control
  408. _editSelectAll.Triggered=OnEditSelectAll
  409. _editFind=New Action( "Find" )
  410. _editFind.HotKey=Key.F
  411. _editFind.HotKeyModifiers=Modifier.Control
  412. _editFind.Triggered=OnEditFind
  413. _findNext=New Action( "Find Next" )
  414. _findNext.HotKey=Key.F3
  415. _findNext.Triggered=OnFindNext
  416. _findPrevious=New Action( "Find Previous" )
  417. _findPrevious.HotKey=Key.F3
  418. _findPrevious.HotKeyModifiers=Modifier.Shift
  419. _findPrevious.Triggered=OnFindPrevious
  420. _findReplace=New Action( "Replace" )
  421. _findReplace.Triggered=OnFindReplace
  422. _findReplaceAll=New Action( "Replace All" )
  423. _findReplaceAll.Triggered=OnFindReplaceAll
  424. _buildDebug=New Action( "Debug" )
  425. _buildDebug.HotKey=Key.F5
  426. _buildDebug.Triggered=OnBuildDebug
  427. _buildRelease=New Action( "Release" )
  428. _buildRelease.HotKey=Key.F6
  429. _buildRelease.Triggered=OnBuildRelease
  430. _buildForceStop=New Action( "Force Stop" )
  431. _buildForceStop.HotKey=Key.F5
  432. _buildForceStop.HotKeyModifiers=Modifier.Shift
  433. _buildForceStop.Triggered=OnBuildForceStop
  434. _buildLockFile=New Action( "Lock Build File" )
  435. _buildLockFile.HotKey=Key.L
  436. _buildLockFile.HotKeyModifiers=Modifier.Control
  437. _buildLockFile.Triggered=OnBuildLockFile
  438. _buildNextError=New Action( "Next Error" )
  439. _buildNextError.HotKey=Key.F4
  440. _buildNextError.Triggered=OnBuildNextError
  441. _helpOnlineHelp=New Action( "Online Help" )
  442. _helpOnlineHelp.Triggered=OnHelpOnlineHelp
  443. _helpOfflineHelp=New Action( "Offline Help" )
  444. _helpOfflineHelp.Triggered=OnHelpOfflineHelp
  445. _helpAbout=New Action( "About Monkey2" )
  446. _helpAbout.Triggered=OnHelpAbout
  447. _escape=New Action( "" )
  448. _escape.HotKey=Key.Escape
  449. _escape.Triggered=OnEscape
  450. End
  451. Method InitMenus()
  452. _newFiles=New Menu( "New..." )
  453. Local p:=AssetsDir()+"ted2/newfiles/"
  454. For Local f:=Eachin LoadDir( p )
  455. Local src:=stringio.LoadString( p+f )
  456. _newFiles.AddAction( StripExt( f.Replace( "_"," " ) ) ).Triggered=Lambda()
  457. Local doc:=Cast<Mx2Document>( OpenDocument( "" ) )
  458. If doc
  459. doc.TextDocument.Text=src
  460. doc.Save()
  461. Endif
  462. End
  463. Next
  464. _scripts=New Menu( "Scripts..." )
  465. Local obj:=JsonObject.Load( "asset::ted2/scripts.json" )
  466. If obj
  467. For Local obj2:=Eachin obj["scripts"].ToArray()
  468. Local name:=obj2.ToObject()["name"].ToString()
  469. Local script:=obj2.ToObject()["script"].ToString()
  470. Local action:=_scripts.AddAction( name )
  471. action.Triggered=Lambda()
  472. RunScript( script )
  473. End
  474. Next
  475. Endif
  476. _recentFiles=New Menu( "Recent Files..." )
  477. _closeProject=New Menu( "Close Project..." )
  478. _fileMenu=New Menu( "File" )
  479. _fileMenu.AddAction( _fileNew )
  480. _fileMenu.AddSubMenu( _newFiles )
  481. _fileMenu.AddAction( _fileOpen )
  482. _fileMenu.AddSubMenu( _recentFiles )
  483. _fileMenu.AddSeparator()
  484. _fileMenu.AddAction( _fileClose )
  485. _fileMenu.AddAction( _fileCloseOthers )
  486. _fileMenu.AddAction( _fileCloseAll )
  487. _fileMenu.AddSeparator()
  488. _fileMenu.AddAction( _fileSave )
  489. _fileMenu.AddAction( _fileSaveAs )
  490. _fileMenu.AddAction( _fileSaveAll )
  491. _fileMenu.AddSeparator()
  492. _fileMenu.AddAction( _fileNextFile )
  493. _fileMenu.AddAction( _filePrevFile )
  494. _fileMenu.AddSeparator()
  495. _fileMenu.AddAction( _fileOpenProject )
  496. _fileMenu.AddSubMenu( _closeProject )
  497. _fileMenu.AddSeparator()
  498. _fileMenu.AddAction( _fileQuit )
  499. _tabMenu=New Menu
  500. _tabMenu.AddAction( _fileClose )
  501. _tabMenu.AddAction( _fileCloseOthers )
  502. _tabMenu.AddSeparator()
  503. _tabMenu.AddAction( _fileSave )
  504. _tabMenu.AddAction( _fileSaveAs )
  505. _tabMenu.AddSeparator()
  506. _tabMenu.AddAction( _buildLockFile )
  507. _editMenu=New Menu( "Edit" )
  508. _editMenu.AddAction( _editUndo )
  509. _editMenu.AddAction( _editRedo )
  510. _editMenu.AddSeparator()
  511. _editMenu.AddAction( _editCut )
  512. _editMenu.AddAction( _editCopy )
  513. _editMenu.AddAction( _editPaste )
  514. _editMenu.AddSeparator()
  515. _editMenu.AddAction( _editSelectAll )
  516. _editMenu.AddSeparator()
  517. _editMenu.AddAction( _editFind )
  518. _editMenu.AddAction( _findNext )
  519. _editMenu.AddAction( _findPrevious )
  520. _editMenu.AddAction( _findReplace )
  521. _editMenu.AddAction( _findReplaceAll )
  522. _buildMenu=New Menu( "Build" )
  523. _buildMenu.AddAction( _buildDebug )
  524. _buildMenu.AddAction( _buildRelease )
  525. _buildMenu.AddSeparator()
  526. _buildMenu.AddAction( _buildNextError )
  527. _buildMenu.AddSeparator()
  528. _buildMenu.AddAction( _buildLockFile )
  529. _buildMenu.AddSeparator()
  530. _buildMenu.AddSubMenu( _scripts )
  531. _buildMenu.AddSeparator()
  532. _buildMenu.AddAction( _buildForceStop )
  533. _helpMenu=New Menu( "Help" )
  534. _helpMenu.AddAction( _helpOnlineHelp )
  535. _helpMenu.AddAction( _helpOfflineHelp )
  536. _helpMenu.AddAction( _helpAbout )
  537. _menuBar=New MenuBar
  538. _menuBar.AddMenu( _fileMenu )
  539. _menuBar.AddMenu( _editMenu )
  540. _menuBar.AddMenu( _buildMenu )
  541. _menuBar.AddMenu( _helpMenu )
  542. End
  543. Method InitViews()
  544. _findDialog=New FindDialog
  545. _projectView=New ProjectView
  546. _debugView=New DebugView
  547. _helpView=New HelpView
  548. _browser=New TabView( TabViewFlags.DraggableTabs )'|TabViewFlags.ClosableTabs )
  549. _browser.AddTab( "Project",_projectView )
  550. _browser.AddTab( "Debug",_debugView )
  551. ' _browser.AddTab( "Help",_helpView )
  552. _browser.CurrentView=_projectView
  553. _console=New Console
  554. _console.ReadOnly=True
  555. _docTabber=New TabView( TabViewFlags.DraggableTabs|TabViewFlags.ClosableTabs )
  556. _docTabber.CurrentChanged=Lambda()
  557. MakeCurrent( FindDocument( _docTabber.CurrentView ) )
  558. End
  559. _docTabber.RightClicked=Lambda()
  560. _tabMenu.Open()
  561. End
  562. _docTabber.CloseClicked=Lambda( index:Int )
  563. CloseDocument( FindDocument( _docTabber.TabView( index ) ) )
  564. End
  565. _docker=New DockingView
  566. _docker.ContentView=_docTabber
  567. _docker.AddView( _menuBar,"top",0 )
  568. _docker.AddView( _browser,"right",250 )
  569. _docker.AddView( _console,"bottom",200 )
  570. End
  571. Method New( title:String,rect:Recti,flags:WindowFlags )
  572. Super.New( title,rect,flags )
  573. MainWindow=Self
  574. ClearColor=App.Theme.GetColor( "windowClearColor" )
  575. SwapInterval=1
  576. InitPaths()
  577. InitActions()
  578. InitMenus()
  579. InitViews()
  580. LoadState()
  581. DeleteTmps()
  582. UpdateRecentFilesMenu()
  583. UpdateCloseProjectMenu()
  584. If Not _projects.Length
  585. Local dir:=CurrentDir()
  586. If _projectView.OpenProject( dir ) _projects.Push( dir )
  587. Endif
  588. App.Idle+=AppIdle
  589. ContentView=_docker
  590. Update( False )
  591. Print "Here!"
  592. ' If Not _docTabber.Count OnHelpAbout()
  593. End
  594. Method OnWindowEvent( event:WindowEvent ) Override
  595. Select event.Type
  596. Case EventType.WindowClose
  597. _fileQuit.Trigger()
  598. Default
  599. Super.OnWindowEvent( event )
  600. End
  601. End
  602. Method ToRecti:Recti( value:JsonValue )
  603. Local json:=value.ToArray()
  604. Return New Recti( json[0].ToNumber(),json[1].ToNumber(),json[2].ToNumber(),json[3].ToNumber() )
  605. End
  606. Method UpdateCloseProjectMenu()
  607. _closeProject.Clear()
  608. For Local dir:=Eachin _projects
  609. _closeProject.AddAction( dir ).Triggered=Lambda()
  610. _projectView.CloseProject( dir )
  611. _projects.Remove( dir )
  612. UpdateCloseProjectMenu()
  613. End
  614. Next
  615. End
  616. Method UpdateRecentFilesMenu()
  617. _recentFiles.Clear()
  618. For Local path:=Eachin _recent
  619. _recentFiles.AddAction( path ).Triggered=Lambda()
  620. OpenDocument( path )
  621. End
  622. Next
  623. End
  624. Method LoadState()
  625. Local obj:=JsonObject.Load( "bin/ted2.state.json" )
  626. If Not obj Return
  627. If obj.Contains( "openDocuments" )
  628. For Local doc:=Eachin obj["openDocuments"].ToArray()
  629. Local path:=doc.ToString()
  630. If GetFileType( path )<>FileType.File Continue
  631. OpenDocument( doc.ToString() )
  632. Next
  633. Endif
  634. If obj.Contains( "recentFiles" )
  635. _recent.Clear()
  636. For Local file:=Eachin obj["recentFiles"].ToArray()
  637. Local path:=file.ToString()
  638. If GetFileType( path )<>FileType.File Continue
  639. _recent.Push( path )
  640. Next
  641. End
  642. If obj.Contains( "openProjects" )
  643. _projects.Clear()
  644. For Local proj:=Eachin obj["openProjects"].ToArray()
  645. Local dir:=proj.ToString()
  646. If Not _projectView.OpenProject( dir ) Continue
  647. _projects.Push( dir )
  648. Next
  649. Endif
  650. If obj.Contains( "windowRect" )
  651. Frame=ToRecti( obj["windowRect"] )
  652. Endif
  653. If obj.Contains( "consoleSize" )
  654. _docker.SetViewSize( _console,obj["consoleSize"].ToNumber() )
  655. Endif
  656. If obj.Contains( "browserSize" )
  657. _docker.SetViewSize( _browser,obj["browserSize"].ToNumber() )
  658. Endif
  659. If obj.Contains( "helpTreeSize" )
  660. _helpView.SetViewSize( _helpView.HelpTree,obj["helpTreeSize"].ToNumber() )
  661. Endif
  662. If obj.Contains( "lockedDocument" )
  663. Local doc:=OpenDocument( obj["lockedDocument"].ToString() )
  664. If doc LockDoc( doc )
  665. Endif
  666. End
  667. Method ToJson:JsonValue( rect:Recti )
  668. Return New JsonArray( New JsonValue[]( New JsonNumber( rect.min.x ),New JsonNumber( rect.min.y ),New JsonNumber( rect.max.x ),New JsonNumber( rect.max.y ) ) )
  669. End
  670. Method SaveState()
  671. Local obj:=New JsonObject
  672. Local docs:=New JsonArray
  673. For Local doc:=Eachin _openDocs
  674. docs.Add( New JsonString( doc.Path ) )
  675. Next
  676. obj["openDocuments"]=docs
  677. Local recent:=New JsonArray
  678. For Local path:=Eachin _recent
  679. recent.Add( New JsonString( path ) )
  680. End
  681. obj["recentFiles"]=recent
  682. Local projects:=New JsonArray
  683. For Local dir:=Eachin _projects
  684. projects.Add( New JsonString( dir ) )
  685. Next
  686. obj["openProjects"]=projects
  687. obj["windowRect"]=ToJson( Frame )
  688. obj["consoleSize"]=New JsonNumber( _docker.GetViewSize( _console ) )
  689. obj["browserSize"]=New JsonNumber( _docker.GetViewSize( _browser ) )
  690. obj["helpTreeSize"]=New JsonNumber( _helpView.GetViewSize( _helpView.HelpTree ) )
  691. If _lockedDoc obj["lockedDocument"]=New JsonString( _lockedDoc.Path )
  692. SaveString( obj.ToJson(),"bin/ted2.state.json" )
  693. End
  694. Method Notify( text:String,title:String="Ted2" )
  695. Local buttons:=New String[]( "Okay" )
  696. TextDialog.Run( title,text,buttons )
  697. End
  698. Method Confirm:Bool( text:String,title:String="Ted2" )
  699. Local buttons:=New String[]( "Okay","Cancel" )
  700. Return TextDialog.Run( title,text,buttons )=0
  701. End
  702. Method DeleteTmps()
  703. For Local i:=1 Until 10
  704. Local path:=RealPath( _tmp+"untitled"+i+".monkey2" )
  705. If GetFileType( path )=FileType.File
  706. If Not FindDocument( path ) DeleteFile( path )
  707. Endif
  708. Next
  709. End
  710. Method AllocTmpPath:String()
  711. For Local i:=1 Until 10
  712. Local path:=_tmp+"untitled"+i+".monkey2"
  713. If GetFileType( path )=FileType.None Return path
  714. Next
  715. Return ""
  716. End
  717. Method IsTmpPath:Bool( path:String )
  718. Return path.StartsWith( _tmp )
  719. End
  720. Method BuildDoc:Ted2Document()
  721. If _lockedDoc Return _lockedDoc
  722. Return _currentDoc
  723. End
  724. Method LockDoc( doc:Ted2Document )
  725. If _lockedDoc And _lockedDoc=doc
  726. _lockedDoc=Null
  727. UpdateTabLabel( doc )
  728. Return
  729. Endif
  730. If doc And Not Cast<TextView>( doc.View ) doc=Null
  731. Local old:=_lockedDoc
  732. _lockedDoc=doc
  733. If _lockedDoc=old Return
  734. UpdateTabLabel( old )
  735. UpdateTabLabel( _lockedDoc )
  736. End
  737. Method UpdateKeyView()
  738. If Not _currentDoc Return
  739. _currentDoc.View.MakeKeyView()
  740. End
  741. Method MakeCurrent( doc:Ted2Document )
  742. If doc=_currentDoc Return
  743. If doc And _docTabber.CurrentView<>doc.View
  744. _docTabber.CurrentView=doc.View
  745. Endif
  746. _currentDoc=doc
  747. _currentTextView=Null
  748. If doc _currentTextView=Cast<TextView>( doc.View )
  749. App.Idle+=Lambda()
  750. If _currentDoc
  751. Title="Ted2 - "+_currentDoc.Path
  752. Else
  753. Title="Ted2"
  754. Endif
  755. End
  756. UpdateKeyView()
  757. Update( False )
  758. End
  759. Method FindDocument:Ted2Document( path:String )
  760. For Local doc:=Eachin _openDocs
  761. If doc.Path=path Return doc
  762. Next
  763. Return Null
  764. End
  765. Method FindDocument:Ted2Document( view:View )
  766. For Local doc:=Eachin _openDocs
  767. If doc.View=view Return doc
  768. Next
  769. Return Null
  770. End
  771. Method ReadError( path:String )
  772. Notify( "I/O Error reading file '"+path+"'" )
  773. End
  774. Method WriteError( path:String )
  775. Notify( "I/O Error writing file '"+path+"'" )
  776. End
  777. Method DocumentTabLabel:String( doc:Ted2Document )
  778. Local label:=StripDir( doc.Path )
  779. If ExtractExt( doc.Path ).ToLower()=".monkey2" label=StripExt( label )
  780. If IsTmpPath( doc.Path ) label="<"+label+">"
  781. If doc=_lockedDoc label="+"+label
  782. If doc.Dirty label+="*"
  783. Return label
  784. End
  785. Method UpdateTabLabel( doc:Ted2Document )
  786. If doc _docTabber.SetTabLabel( doc.View,DocumentTabLabel( doc ) )
  787. End
  788. Method OpenDocument:Ted2Document( path:String,addRecent:Bool=False,makeCurrent:Bool=True )
  789. Local doc:Ted2Document
  790. If path
  791. path=RealPath( path )
  792. Local ext:=ExtractExt( path ).ToLower()
  793. Select ext
  794. Case ".monkey2"
  795. Case ".png",".jpg",".bmp"
  796. Case ".h",".hpp",".hxx",".c",".cpp",".cxx",".m",".mm",".s",".asm"
  797. Case ".html",".md",".json",".xml"
  798. Case ".sh",".bat"
  799. Case ".glsl"
  800. Case ".txt"
  801. Default
  802. Notify( "Unrecognized file type extension for file '"+path+"'" )
  803. Return Null
  804. End
  805. doc=FindDocument( path )
  806. If doc
  807. If makeCurrent MakeCurrent( doc )
  808. Return doc
  809. Endif
  810. Select ext
  811. Case ".monkey2"
  812. doc=New Mx2Document( path )
  813. Case ".png",".jpg"
  814. doc=New ImgDocument( path )
  815. Default
  816. doc=New TxtDocument( path )
  817. End
  818. Else
  819. path=AllocTmpPath()
  820. If Not path
  821. Notify( "Can't create temporary file" )
  822. Return Null
  823. Endif
  824. SaveString( "",path )
  825. doc=New Mx2Document( path )
  826. Endif
  827. If GetFileType( path )<>FileType.File Or Not doc.Load()
  828. ReadError( path )
  829. Return Null
  830. End
  831. doc.DirtyChanged=Lambda()
  832. UpdateTabLabel( doc )
  833. End
  834. _docTabber.AddTab( DocumentTabLabel( doc ),doc.View )
  835. _openDocs.Add( doc )
  836. If addRecent
  837. _recent.Remove( path )
  838. _recent.Insert( 0,path )
  839. If _recent.Length>20 _recent.Resize( 20 )
  840. UpdateRecentFilesMenu()
  841. Endif
  842. If makeCurrent MakeCurrent( doc )
  843. Return doc
  844. End
  845. Method RenameDocument( doc:Ted2Document,path:String )
  846. doc.Rename( path )
  847. UpdateTabLabel( doc )
  848. End
  849. Method SaveDocument:Bool( doc:Ted2Document )
  850. If IsTmpPath( doc.Path )
  851. Local path:=RequestFile( "Save As","",True )
  852. If Not path Return False
  853. RenameDocument( doc,path )
  854. Endif
  855. If doc.Save() Return True
  856. WriteError( doc.Path )
  857. Return False
  858. End
  859. Method CloseDocument( doc:Ted2Document )
  860. Local index:=_docTabber.TabIndex( doc.View )
  861. _docTabber.RemoveTab( doc.View )
  862. _openDocs.Remove( doc )
  863. doc.Close()
  864. If IsTmpPath( doc.Path ) DeleteFile( doc.Path )
  865. If doc=_lockedDoc _lockedDoc=Null
  866. If doc<>_currentDoc Return
  867. If Not _docTabber.Count
  868. MakeCurrent( Null )
  869. Return
  870. Endif
  871. If index=_docTabber.Count index-=1
  872. MakeCurrent( FindDocument( _docTabber.TabView( index ) ) )
  873. End
  874. Method GotoError( err:Mx2Error )
  875. Local doc:=Cast<Mx2Document>( OpenDocument( err.path ) )
  876. If Not doc Return
  877. Local tv:=Cast<TextView>( doc.View )
  878. If Not tv Return
  879. Local sol:=tv.Document.StartOfLine( err.line )
  880. tv.SelectText( sol,sol )
  881. Return
  882. End
  883. Method Build( config:String )
  884. If _console.Running Return
  885. Local buildDoc:=Cast<Mx2Document>( BuildDoc() )
  886. If Not buildDoc Return
  887. For Local doc:=Eachin _openDocs
  888. Local mx2Doc:=Cast<Mx2Document>( doc )
  889. If mx2Doc mx2Doc.Errors.Clear()
  890. Next
  891. For Local doc:=Eachin _openDocs
  892. If doc.Save() Continue
  893. WriteError( doc.Path )
  894. Return
  895. Next
  896. _console.Clear()
  897. Local cmd:=_mx2cc+" makeapp -apptype=gui -build -config="+config+" ~q"+buildDoc.Path+"~q"
  898. If Not _console.Start( cmd )
  899. Notify( "Failed to start process: '"+cmd+"'" )
  900. Return
  901. Endif
  902. Local appFile:String
  903. Local dialog:=New TextDialog( "Ted2","Building "+buildDoc.Path+"..." )
  904. dialog.AddAction( "Cancel" ).Triggered=_console.Terminate
  905. dialog.Open()
  906. _errors.Clear()
  907. Repeat
  908. Local stdout:=_console.ReadStdout()
  909. If Not stdout Exit
  910. If stdout.StartsWith( "Application built:" )
  911. appFile=stdout.Slice( stdout.Find( ":" )+1 ).Trim()
  912. Else
  913. Local i:=stdout.Find( "] : Error : " )
  914. If i<>-1
  915. Local j:=stdout.Find( " [" )
  916. If j<>-1
  917. Local path:=stdout.Slice( 0,j )
  918. Local line:=Int( stdout.Slice( j+2,i ) )-1
  919. Local msg:=stdout.Slice( i+12 )
  920. Local err:=New Mx2Error( path,line,msg )
  921. Local doc:=Cast<Mx2Document>( OpenDocument( path,False,False ) )
  922. If doc
  923. doc.Errors.Add( err )
  924. If _errors.Empty GotoError( err )
  925. _errors.Add( err )
  926. Endif
  927. Endif
  928. Endif
  929. Endif
  930. _console.Write( stdout )
  931. Forever
  932. dialog.Close()
  933. If Not appFile Return
  934. cmd=appFile
  935. If Not _console.Start( cmd )
  936. Notify( "Failed to start process: '"+cmd+"'" )
  937. Return
  938. Endif
  939. _console.Clear()
  940. Local tab:=_browser.CurrentView
  941. If config="debug"
  942. _console.Write( "Debugging app:"+appFile+"~n" )
  943. _browser.CurrentView=_debugView
  944. _debugView.DebugBegin()
  945. Else
  946. _console.Write( "Running app:"+appFile+"~n" )
  947. Endif
  948. Repeat
  949. Local stdout:=_console.ReadStdout()
  950. If Not stdout Exit
  951. If config="debug" And stdout="{{!DEBUG!}}~n"
  952. _debugView.DebugStop()
  953. Continue
  954. End
  955. _console.Write( stdout )
  956. Forever
  957. If config="debug"
  958. _debugView.DebugEnd()
  959. Endif
  960. For Local doc:=Eachin _openDocs
  961. Local mx2Doc:=Cast<Mx2Document>( doc )
  962. If mx2Doc mx2Doc.DebugLine=-1
  963. Next
  964. _browser.CurrentView=tab
  965. _console.Write( "Done.~n" )
  966. End
  967. Method RunScript( script:String )
  968. If _console.Running Return
  969. For Local doc:=Eachin _openDocs
  970. If doc.Save() Continue
  971. WriteError( doc.Path )
  972. Return
  973. Next
  974. _console.Clear()
  975. Local cmd:=script
  976. #If __HOSTOS__="windows"
  977. cmd=script+".bat"
  978. #Else If __HOSTOS__="macos"
  979. cmd="/bin/bash -l "+script+".sh"
  980. #Else
  981. cmd="/bin/bash -l -c "+script+".sh"
  982. #Endif
  983. Local cd:=CurrentDir()
  984. ChangeDir( "scripts" )
  985. Local r:=_console.Start( cmd )
  986. ChangeDir( cd )
  987. If Not r
  988. Notify( "Failed to start process: '"+cmd+"'" )
  989. Return
  990. Endif
  991. Repeat
  992. Local stdout:=_console.ReadStdout()
  993. If Not stdout Exit
  994. _console.Write( stdout )
  995. Forever
  996. _console.Write( "Done.~n" )
  997. End
  998. Method RequestDir:String( title:String,dir:String )
  999. Local future:=New Future<String>
  1000. App.Idle+=Lambda()
  1001. future.Set( mojo.requesters.RequestDir( title,dir ) )
  1002. End
  1003. Return future.Get()
  1004. End
  1005. Method RequestFile:String( title:String,filters:String,save:Bool,path:String="" )
  1006. Local future:=New Future<String>
  1007. App.Idle+=Lambda()
  1008. future.Set( mojo.requesters.RequestFile( title,filters,save,path ) )
  1009. End
  1010. Return future.Get()
  1011. End
  1012. Method UpdateActions()
  1013. Local keyView:=Cast<TextView>( App.KeyView )
  1014. Local dirtyDocs:Bool
  1015. For Local doc:=Eachin _openDocs
  1016. If doc.Dirty dirtyDocs=True
  1017. Next
  1018. While Not _errors.Empty And _errors.First.removed
  1019. _errors.RemoveFirst()
  1020. Wend
  1021. _fileClose.Enabled=_currentDoc<>Null
  1022. _fileCloseOthers.Enabled=_openDocs.Length>1
  1023. _fileCloseAll.Enabled=_openDocs.Length<>0
  1024. _fileSave.Enabled=_currentDoc<>Null And _currentDoc.Dirty
  1025. _fileSaveAs.Enabled=_currentDoc<>Null
  1026. _fileSaveAll.Enabled=dirtyDocs
  1027. _fileNextFile.Enabled=_docTabber.Count>1
  1028. _filePrevFile.Enabled=_docTabber.Count>1
  1029. _editUndo.Enabled=keyView And keyView.CanUndo
  1030. _editRedo.Enabled=keyView And keyView.CanRedo
  1031. _editCut.Enabled=keyView And keyView.CanCut
  1032. _editCopy.Enabled=keyView And keyView.CanCopy
  1033. _editPaste.Enabled=keyView And keyView.CanPaste
  1034. _editSelectAll.Enabled=keyView<>Null
  1035. _buildDebug.Enabled=BuildDoc()<>Null And Not _console.Running
  1036. _buildRelease.Enabled=BuildDoc()<>Null And Not _console.Running
  1037. _buildLockFile.Enabled=_currentDoc<>Null
  1038. _buildForceStop.Enabled=_console.Running
  1039. _buildNextError.Enabled=Not _errors.Empty
  1040. _scripts.Enabled=Not _console.Running
  1041. End
  1042. Method AppIdle()
  1043. UpdateActions()
  1044. ' App.RequestRender()
  1045. App.Idle+=AppIdle
  1046. GCCollect() 'thrash that GC!
  1047. End
  1048. End