瀏覽代碼

Squashed 'src/ted2go/' changes from 8d1358d9..358f7111

358f7111 Merge branch 'dev'
f1a4b3cc #87 (Remembering open folders in project tree even if they are closed - but children are opened).
2931e268 Update modules dialog - now stores targets state.
3ff3652e Added x64 logo and tweaked android product.
1f4262dd #86. Rebuild modules dialog now stores its checkboxes.
3f69425e Fix for crashes because of incorrect params-hint detection.
9d4c378c Fixes for switching to fullscreen mode from maximized state.
55a10919 Updates in menu items - Edit and Goto.
39f22c77 Updates in text editing, including new shortcuts.
a33ecee9 Updates in fullscreen mode.
89265a36 Change Fullscreen mode to Borderless Fullscreen (#85)
91f160c8 Added patrons; removed incorrect globals; added 'join the community' into Help menu; added 'close all tabs' in right click menu on tabs.
5d0126ae Added feature "Remove word before cursor" on windows/linux by Ctrl+Backspace.
ae63a504 Fixed #84. (opened incorrect tab if filename casing is incorrect)
36d619cb Fixed #83. (crashes on start when toolbar is hidden)
1791535a Fixed #82. (Strange bug in Rightclick Menu.)
17cf135b Merge branch 'dev'
b166ba7b Bump version.
b2c81127 Merge branch 'dev'
0b2c4eb4 Don't add 'Override' for interface members.
87531c64 Improvements in Source code tree (expanded state fixes).
aa7e490d Added fading for about dialog (to avoid dialog 'blending' with bananas showcase at the first run).
d1f5abe3 Search in docs improvements - try to be more accurately by F1.
99d025b1 Said goodbye to "optimization" for completion list - it ate our results!
81d012f6 Fixed #81. (if you use 'save' to change filetype, the editor thinks it's still the old type.)
b191d482 Fullscreen editor - added status bar and dirty-state-changed detection.
c9099f37 Added comment/uncomment to editor rightclick menu.
8102fd48 Fixed #79 by renaming png files. (Not all themes elements are changed by switching theme.)
478cb847 Updated.
ba64fee4 Fixed issue with non-existant module in module.json "depends" array.
6aded373 Added patrons to special thanks section (a few were already there).
5f8ca9e8 Save/load Verbose mode into prefs.
9ff2d560 Add Verbose CheckButton (#76)
d1de31ac Fixed #70 - sorting in docs tab.
8404ef44 Now uses SetConfig to set default theme.
2fb67b4b Changed AppInstance creation.
7c68d646 Hotkeys for Zoom in, out, default (#75)
ea1abb47 #73 Fix for fullscreen mode.
ffc15221 Added ability to change docs while in fullscreen mode.
140d3fbb Added "Fullscreen editor" mode in which we have editor view only (temporarily closing all other views).
2712cba8 Fix for json viewer.
7d6b50fe Json viewer - added ability to jump to values by clicking on Source tree view nodes.
8bc34b94 Enabled monkey2's highlighter for .json files.
906bf520 Don't reset syntax errors on document save.
0dce9252 Added fulscreen mode: menu Window -- Fullscreen mode (F11).
516b3f67 Fixed #67 - Can’t read the last item in completion list.
d580064a Attemp to pass event from hint to editor.
967c8d6b Close params hint by mouse click.
a79a6007 Merge branch 'params_hint' into dev
6a43bbe3 Done with hint for parameters. Added option into Preferences to enable / disable this hint.
784d8159 Almost done params hint.
036958b9 Added support for multiple module dirs via MX2_MODULE_DIRS env var.
a339f42d Removed unused imports.
322b93d3 (wip) Params hint.
b15b143d (wip) Params hint.
2f508071 Fixed file renaming (case-insensitive file system on Windows).
88155f33 Updates in docs selection.
81bcf8f9 #70. Fixed search-by-namespace in docs.
54b6e16a Updated mojo3d's template up to v1.1.08.
226dc456 Theme update.
905d60a6 MacOS Improvements (#69)
627b8754 Closed #68. Added - closing tabs by pressing middle mouse button.
d8dcce3d Some updates for "first app launch" - moved Source tab into left panel, changed bananas image sizes to fit into window.
2e8c8df0 Updated themes.
d2d55b5c Fixed Docs tree - open docs by second F1, improved node filtering.
c9c7b7d3 Fixed incorrect selection in tree views.
d5bfcbf6 Added '#Reflect' keyword.
552176d8 Improvement in parsing.
fbde4be9 Merge branch 'dev' of https://github.com/engor/Ted2Go into dev
467e2dc4 Removed unused imports.
d52150fb Project tree - added Cut / Copy / Paste actions on files and foldes.
b3e167db Fixed "Close tabs to the right" behaviour.
ddf08f96 Fixed #62.
6990910e Project tree - added confirm to replace items when drag-n-drop.
bd6df470 Added ability to drop files / folders from desktop explorer directly into specified folder inside of project tree. Added ability to copy dragged items by holding Ctrl key.
e7e16f94 Done with drag-n-drop inside of Project tree.
8de195b1 (wip) project tree
b0b11eb4 (wip) draggable project tree.
2174a913 Extract draggable tabs logic into own class to reuse for other cases.

git-subtree-dir: src/ted2go
git-subtree-split: 358f7111d41d5b4788d864cb1cf7d54711bfe316
Mark Sibly 7 年之前
父節點
當前提交
1b419253cf
共有 72 個文件被更改,包括 3173 次插入1007 次删除
  1. 2 1
      .gitignore
  2. 352 148
      MainWindow.monkey2
  3. 1 1
      Plugin.monkey2
  4. 3 0
      Prefs.monkey2
  5. 15 11
      Ted2.monkey2
  6. 94 0
      Tree.monkey2
  7. 67 16
      action/BuildActions.monkey2
  8. 106 1
      action/EditActions.monkey2
  9. 1 1
      action/FileActions.monkey2
  10. 36 32
      action/HelpActions.monkey2
  11. 3 3
      action/ViewActions.monkey2
  12. 76 0
      action/WindowActions.monkey2
  13. 1 1
      assets/aboutTed2Go.html
  14. 5 6
      assets/newfiles/Simple_Mojo3d_App.monkey2
  15. 0 0
      assets/themes/hollow_assets/hollow_checkbox_icons.png
  16. 0 0
      assets/themes/hollow_assets/hollow_dialog_skin.png
  17. 0 0
      assets/themes/hollow_assets/hollow_progressbar_icons.png
  18. 0 0
      assets/themes/hollow_assets/hollow_tabclose_icons.png
  19. 0 0
      assets/themes/hollow_assets/hollow_treeview_icons.png
  20. 0 0
      assets/themes/prime_assets/prime_checkbox_icons.png
  21. 0 0
      assets/themes/prime_assets/prime_dialog_skin.png
  22. 0 0
      assets/themes/prime_assets/prime_progressbar_icons.png
  23. 0 0
      assets/themes/prime_assets/prime_tabclose_icons.png
  24. 0 0
      assets/themes/prime_assets/prime_treeview_icons.png
  25. 0 0
      assets/themes/smooth_assets/smooth_button_skin.png
  26. 0 0
      assets/themes/smooth_assets/smooth_checkbox_icons.png
  27. 0 0
      assets/themes/smooth_assets/smooth_dialog_skin.png
  28. 0 0
      assets/themes/smooth_assets/smooth_progressbar_icons.png
  29. 二進制
      assets/themes/smooth_assets/smooth_tabbutton_locked_skin.png
  30. 0 0
      assets/themes/smooth_assets/smooth_tabbutton_selected_skin.png
  31. 0 0
      assets/themes/smooth_assets/smooth_tabbutton_skin.png
  32. 0 0
      assets/themes/smooth_assets/smooth_tabclose_icons.png
  33. 0 0
      assets/themes/smooth_assets/smooth_treeview_icons.png
  34. 8 3
      assets/themes/ted2-default.json
  35. 14 7
      assets/themes/theme-hollow.json
  36. 11 6
      assets/themes/theme-prime-base.json
  37. 14 9
      assets/themes/theme-smooth.json
  38. 1 1
      assets/themes/theme-warm.json
  39. 42 0
      dialog/DialogExt.monkey2
  40. 1 1
      dialog/GenerateClassDialog.monkey2
  41. 7 1
      dialog/PrefsDialog.monkey2
  42. 47 54
      dialog/UpdateModulesDialog.monkey2
  43. 18 12
      document/BananasDocument.monkey2
  44. 441 49
      document/CodeDocument.monkey2
  45. 54 21
      document/DocumentManager.monkey2
  46. 59 4
      document/JsonDocument.monkey2
  47. 28 22
      document/Ted2Document.monkey2
  48. 1 5
      eventfilter/Monkey2KeyEventFilter.monkey2
  49. 二進制
      logo/resource_x64.o
  50. 28 22
      parser/CodeItem.monkey2
  51. 132 46
      parser/Monkey2Parser.monkey2
  52. 11 3
      parser/Parser.monkey2
  53. 3 1
      product/BuildProduct.monkey2
  54. 50 40
      product/ModuleManager.monkey2
  55. 14 2
      product/Mx2ccEnv.monkey2
  56. 2 2
      syntax/Monkey2Highlighter.monkey2
  57. 11 0
      testing/ParserTests.monkey2
  58. 86 0
      testing/pixelPerfect.json
  59. 5 4
      utils/JsonUtils.monkey2
  60. 117 1
      utils/Utils.monkey2
  61. 33 33
      view/AutocompleteView.monkey2
  62. 131 35
      view/CodeTextView.monkey2
  63. 9 7
      view/CodeTreeView.monkey2
  64. 160 0
      view/DraggableViewListener.monkey2
  65. 198 99
      view/HelpTreeView.monkey2
  66. 12 2
      view/ListViewExt.monkey2
  67. 256 27
      view/ProjectBrowserView.monkey2
  68. 179 70
      view/ProjectView.monkey2
  69. 83 179
      view/TabViewExt.monkey2
  70. 31 7
      view/Ted2CodeTextView.monkey2
  71. 1 1
      view/ToolBarViewExt.monkey2
  72. 113 10
      view/TreeViewExt.monkey2

+ 2 - 1
.gitignore

@@ -2,4 +2,5 @@
 *.bak
 *.buildv*
 *.products/
-*.app
+*.app
+*.DS_*

+ 352 - 148
MainWindow.monkey2

@@ -45,13 +45,18 @@ Class MainWindowInstance Extends Window
 		_docsManager.CurrentDocumentChanged+=Lambda()
 			
 			UpdateKeyView()
-			CodeDocument.HideAutocomplete()
+			CodeDocument.HideAllPopups()
 			
 			Local doc:=Cast<CodeTextView>( _docsManager.CurrentTextView )
 			Local mode:=doc ? doc.OverwriteMode Else False
 			OverwriteTextMode=mode
 			
 			_findReplaceView.CodeView=Cast<CodeTextView>( _docsManager.CurrentTextView )
+			
+			If _fullscreenState=FullscreenState.Editor
+				SwapFullscreenEditor( False,1 )
+			Endif
+			
 		End
 		
 		_docsManager.DocumentDoubleClicked+=Lambda( doc:Ted2Document )
@@ -241,6 +246,7 @@ Class MainWindowInstance Extends Window
 		_tabMenu.AddAction( _fileActions.close )
 		_tabMenu.AddAction( _fileActions.closeOthers )
 		_tabMenu.AddAction( _fileActions.closeToRight )
+		_tabMenu.AddAction( _fileActions.closeAll )
 		_tabMenu.AddSeparator()
 		_tabMenu.AddAction( _fileActions.save )
 		_tabMenu.AddAction( _fileActions.saveAs )
@@ -312,8 +318,30 @@ Class MainWindowInstance Extends Window
 		_editMenu.AddSeparator()
 		_editMenu.AddAction( _editActions.selectAll )
 		_editMenu.AddSeparator()
+		' Edit -- Text
+		Local subText:=New MenuExt( "Text" )
+		subText.AddAction( _editActions.textDeleteWordForward )
+		subText.AddAction( _editActions.textDeleteWordBackward )
+		subText.AddAction( _editActions.textDeleteLine )
+		subText.AddAction( _editActions.textDeleteToEnd )
+		subText.AddAction( _editActions.textDeleteToBegin )
+		_editMenu.AddSubMenu( subText )
+		' Edit -- Comment
+		Local subComment:=New MenuExt( "Comment" )
+		subComment.AddAction( _viewActions.comment )
+		subComment.AddAction( _viewActions.uncomment )
+		_editMenu.AddSubMenu( subComment )
+		' Edit -- Convert case
+		Local subCase:=New MenuExt( "Convert case" )
+		subCase.AddAction( _editActions.textUppercase )
+		subCase.AddAction( _editActions.textLowercase )
+		subCase.AddAction( _editActions.textSwapCase )
+		_editMenu.AddSubMenu( subCase )
+		'
+		_editMenu.AddSeparator()
 		_editMenu.AddAction( _editActions.wordWrap )
 		
+		
 		'Find menu
 		'
 		_findMenu=New MenuExt( "Find" )
@@ -324,17 +352,14 @@ Class MainWindowInstance Extends Window
 		_findMenu.AddSeparator()
 		_findMenu.AddAction( _findActions.findInFiles )
 		
-		'View menu
+		'Goto menu
 		'
-		_viewMenu=New MenuExt( "View" )
-		_viewMenu.AddAction( _viewActions.gotoLine )
-		_viewMenu.AddAction( _viewActions.gotoDeclaration )
-		_viewMenu.AddSeparator()
-		_viewMenu.AddAction( _viewActions.comment )
-		_viewMenu.AddAction( _viewActions.uncomment )
-		_viewMenu.AddSeparator()
-		_viewMenu.AddAction( _viewActions.goBack )
-		_viewMenu.AddAction( _viewActions.goForward )
+		_gotoMenu=New MenuExt( "Goto" )
+		_gotoMenu.AddAction( _viewActions.gotoLine )
+		_gotoMenu.AddAction( _viewActions.gotoDeclaration )
+		_gotoMenu.AddSeparator()
+		_gotoMenu.AddAction( _viewActions.goBack )
+		_gotoMenu.AddAction( _viewActions.goForward )
 		
 		'Build menu
 		'
@@ -366,15 +391,19 @@ Class MainWindowInstance Extends Window
 		
 		'Window menu
 		'
+		Local windowActions:=New WindowActions( _docsManager )
 		_windowMenu=New MenuExt( "Window" )
-		_windowMenu.AddAction( _docsManager.nextDocument )
-		_windowMenu.AddAction( _docsManager.prevDocument )
+		_windowMenu.AddAction( windowActions.nextTab )
+		_windowMenu.AddAction( windowActions.prevTab )
 		_windowMenu.AddSeparator()
-		
-		_themesMenu=CreateThemesMenu( "Themes" )
-		
-		AddZoomActions( _windowMenu )
+		_windowMenu.AddAction( windowActions.fullscreenWindow )
+		_windowMenu.AddAction( windowActions.fullscreenEditor )
 		_windowMenu.AddSeparator()
+		_windowMenu.AddAction( windowActions.zoomIn )
+		_windowMenu.AddAction( windowActions.zoomOut )
+		_windowMenu.AddAction( windowActions.zoomDefault )
+		_windowMenu.AddSeparator()
+		_themesMenu=CreateThemesMenu( "Themes" )
 		_windowMenu.AddSubMenu( _themesMenu )
 		
 		
@@ -395,6 +424,7 @@ Class MainWindowInstance Extends Window
 		_helpMenu.AddAction( _helpActions.aboutTed2go )
 		_helpMenu.AddSeparator()
 		_helpMenu.AddAction( _helpActions.makeBetter )
+		_helpMenu.AddAction( _helpActions.joinCommunity )
 		
 		'Menu bar
 		'
@@ -402,7 +432,7 @@ Class MainWindowInstance Extends Window
 		_menuBar.AddMenu( _fileMenu )
 		_menuBar.AddMenu( _editMenu )
 		_menuBar.AddMenu( _findMenu )
-		_menuBar.AddMenu( _viewMenu )
+		_menuBar.AddMenu( _gotoMenu )
 		_menuBar.AddMenu( _buildMenu )
 		_menuBar.AddMenu( _windowMenu )
 		_menuBar.AddMenu( _helpMenu )
@@ -425,8 +455,10 @@ Class MainWindowInstance Extends Window
 		
 		ArrangeElements()
 		
+		'_helpTree.QuickHelp( "" )
+		
 		ContentView=_contentView
-
+		
 		OnCreatePlugins() 'init plugins before loadstate, to register doctypes before open last opened files
 		
 		LoadState( jobj )
@@ -592,6 +624,7 @@ Class MainWindowInstance Extends Window
 	Method Terminate()
 		
 		_isTerminating=True
+		
 		SaveState()
 		_enableSaving=False
 		OnForceStop() ' kill build process if started
@@ -665,6 +698,96 @@ Class MainWindowInstance Extends Window
 		_modsDir=RealPath( "modules/" )
 	End
 	
+	Method SwapFullscreenWindow()
+		
+		If _fullscreenState=FullscreenState.Editor
+			SwapFullscreenEditor()
+			Return
+		Endif
+		
+		If Not _fullscreen
+			_storedSize=Frame
+			_storedMaximized=Maximized
+		Endif
+		
+		_fullscreen=Not _fullscreen
+		_fullscreenState=_fullscreen ? FullscreenState.Window Else FullscreenState.None
+		
+		UpdateFullscreenMode()
+		
+	End
+	
+	' customState: -1 - make windowed, 1 - make fullscreen
+	'
+	Method SwapFullscreenEditor( justStarted:Bool=False,customState:Int=0 )
+		
+		If Not justStarted And _docsManager.CurrentDocument=Null
+			Alert( "There is no editor to be fullscreened!","Fullscreen" )
+			Return
+		Endif
+		
+		If Not _fullscreen
+			_storedSize=Frame
+			_storedMaximized=Maximized
+		Endif
+		
+		' restore
+		If _fullscreenHelper.storedContentView<>Null
+			Local view:=_fullscreenHelper.editorContainer.ContentView
+			view.Layout="fill"
+			_fullscreenHelper.editorContainer.ContentView=Null
+			_fullscreenHelper.statusContainer.ContentView=Null
+			_statusBarContainer.ContentView=_statusBar
+			ContentView=_fullscreenHelper.storedContentView
+			_docsTabView.SetTabView( _fullscreenHelper.storedTabIndex,view )
+			_docsTabView.EnsureVisibleCurrentTab()
+			_docsManager.UpdateCurrentTabLabel()
+			_docsManager.CurrentDocument?.DirtyChanged-=_fullscreenHelper.UpdateTitle
+			_fullscreenHelper.storedContentView=Null
+		Endif
+		
+		' stay in fullscreen
+		If _fullscreenPrevState=FullscreenState.Window 
+			_fullscreenState=FullscreenState.Window 
+			_fullscreenPrevState=FullscreenState.None 
+			Return
+		Endif
+		
+		_fullscreenPrevState=_fullscreenState
+		
+		Local state:=Not _fullscreen
+		
+		If customState<>0 Then state=(customState > 0)
+		If _fullscreenState<>FullscreenState.Window Then _fullscreen=state
+		
+		_fullscreenState=_fullscreen ? FullscreenState.Editor Else FullscreenState.None
+		
+		UpdateFullscreenMode()
+		
+		If _fullscreen
+			_fullscreenHelper.storedContentView=ContentView
+			_fullscreenHelper.storedTabIndex=_docsTabView.CurrentIndex
+			_docsTabView.SetTabView( _fullscreenHelper.storedTabIndex,Null )
+			Local view:=_docsManager.CurrentView
+			view.Layout="fill-y"
+			view.Gravity=New Vec2f( .5,0 )
+			Local sz:=New Vec2i( Int(App.DesktopSize.x*.7),100000 )
+			view.MaxSize=sz
+			view.MinSize=sz
+			_fullscreenHelper.editorContainer.ContentView=view
+			_fullscreenHelper.titleLabel.Text=_docsManager.CurrentDocumentLabel
+			_docsManager.CurrentDocument?.DirtyChanged+=_fullscreenHelper.UpdateTitle
+			' status bar
+			_statusBarContainer.ContentView=Null
+			_fullscreenHelper.statusContainer.ContentView=_statusBar
+			'
+			ContentView=_fullscreenHelper.editorContainer
+			
+			_docsManager.CurrentTextView?.MakeKeyView()
+			
+		Endif
+	End
+	
 	Method StoreConsoleVisibility()
 	
 		'If Prefs.SiblyMode return
@@ -853,99 +976,115 @@ Class MainWindowInstance Extends Window
 		
 		Local tab:=_tabsWrap.tabs["Build"]
 		tab.Activate()
-		If vis tab.ParentDock.Visible=True
+		If vis tab.CurrentHolder.Visible=True
 	End
 	
 	Method ShowOutputConsole( vis:Bool=True )
 		
 		Local tab:=_tabsWrap.tabs["Output"]
 		tab.Activate()
-		If vis tab.ParentDock.Visible=True
+		If vis tab.CurrentHolder.Visible=True
 	End
 	
-	Method ShowHelpView()
+	Method ShowDocsView( expandTree:Bool=False )
 		
 		Local tab:=_tabsWrap.tabs["Docs"]
 		tab.Activate()
-		tab.ParentDock.Visible=True
+		tab.CurrentHolder.Visible=True
+		
+		If expandTree
+			_helpTree.Visible=False
+			_helpSwitcher.Clicked()
+		Endif
 	End
 	
 	Method ShowFindResults()
 		
 		Local tab:=_tabsWrap.tabs["Find"]
 		tab.Activate()
-		tab.ParentDock.Visible=True
+		tab.CurrentHolder.Visible=True
 	End
 	
-	Method ShowFindInDocs()
+	Method RebuildDocs()
 		
-		Local doc:=Cast<CodeDocumentView>( _docsManager.CurrentTextView )
-		If Not doc Return
-		
-		Local ident:=doc.WordAtCursor
-		Print "ident: "+ident
-		_helpTree.QuickHelp( ident )
-		_helpTree.Visible=False
-		_helpSwitcher.Clicked()
-		_tabsWrap.tabs["Docs"].Activate()
+		_buildActions.rebuildHelp.Trigger()
 	End
 	
-	Method ShowQuickHelp()
+	Method ShowHelp( url:String="",searchMode:Bool=False )
+		
+		' direct jump
+		If url
+			_helpView.Navigate( url )
+			_helpView.Scroll=New Vec2i( 0,0 )
+			ShowDocsView()
+			Return
+		Endif
 		
 		Local doc:=Cast<CodeDocumentView>( _docsManager.CurrentTextView )
 		If Not doc Return
 		
+		' don't check with parser, just find in docs tree
+		If searchMode
+			Local ident:=doc.WordAtCursor
+			_helpTree.QuickHelp( ident )
+			ShowDocsView( True )
+			Return
+		Endif
+		
 		Local ident:=doc.FullIdentAtCursor
 		
 		If Not ident Return
 		
 		Local parser:=ParsersManager.Get( doc.FileType )
 		Local item:=parser.ItemAtScope( ident,doc.FilePath,doc.LineNumAtCursor )
+		
 		If item
-			Local s:=item.Namespac
-			If s
-				Local i:=s.Find( "." )
-				If i<>-1 Then s=s.Slice( 0,i )
-			Endif
-			Local ident2:="",parentIdent:=""
-			ident=s+":"+item.Namespac+"."
-			If item.Parent
-				If item.Parent.IsLikeClass
-					parentIdent=item.Parent.Ident
-					ident2=s+":"+parentIdent+"."+item.Ident
-				Endif
-				ident+=item.Parent.Ident+"."
-			Endif
-			ident+=item.Ident
 			
-			If ident=_helpIdent
-				If item.IsModuleMember
-					Local url:=_helpTree.PageUrl( ident )
-					If GetFileType( url )<>FileType.File Then url=_helpTree.PageUrl( ident2 )
+			ident=item.Ident
+			
+			Local pathTemplate:=Prefs.MonkeyRootPath+"docs/modules/{mod-name}/module/{path-to-ident}.html"
+			Local modName:=item.ModuleName
+			
+			Local pathToIdent:=(item.Namespac+"."+item.Scope).Replace( ".","-" )
+			Local path:=pathTemplate.Replace( "{mod-name}",modName ).Replace( "{path-to-ident}",pathToIdent )
+			
+			Global __prevPath:=""
+			
+			If path=__prevPath
+				
+				If modName ' show docs for modules members
+					
+					_helpTree.QuickHelp( ident )
+					
+					_helpView.Navigate( path )
+					_helpView.Scroll=New Vec2i( 0,0 )
+					
+					_helpTree.Selected=_helpTree.FindByText( ident )
+					
+					ShowDocsView( True )
+					
+				Else ' or jump to non modules members
 					
-					If GetFileType( url )<>FileType.File
-						Local ext:=ExtractExt( url )
-						Repeat
-							Local i:=url.FindLast( "-" )
-							If i=-1
-								url=""
-								Exit
-							Endif
-							url=url.Slice( 0,i )+ext
-						Forever
-					Endif
-					If url ShowHelp( url )
-				Else
 					GotoCodePosition( item.FilePath,item.ScopeStartPos )
+					
 				Endif
 			Else
+				
+				Local parentIdent:=""
+				If item.Parent
+					If item.Parent.IsLikeClass
+						parentIdent=item.Parent.Ident
+					Endif
+				Endif
+				
 				Local nmspace:=item.Namespac
 				If parentIdent Then nmspace+="."+parentIdent
 				Local ext:=item.IsExtension ? "(ext) " Else ""
 				ShowStatusBarText( ext+"("+item.KindStr+") "+item.Text+"    |  "+nmspace+"  |  "+StripDir( item.FilePath )+"  |  line "+(item.ScopeStartPos.x+1) )
+			
 			Endif
 			
-			_helpIdent=ident
+			__prevPath=path
 			
 		ElseIf KeywordsManager.Get( doc.FileType ).Contains( ident )
 			
@@ -953,19 +1092,12 @@ Class MainWindowInstance Extends Window
 		
 		Else
 			
-			ShowFindInDocs()
+			ShowHelp( "",True ) ' try to search ident
 			
 		Endif
 		
 	End
 	
-	Method ShowHelp( url:String )
-		
-		ShowHelpView()
-		_helpView.Navigate( url )
-		_helpView.Scroll=New Vec2i( 0,0 )
-	End
-	
 	Method ShowEditorMenu( tv:TextView )
 		
 		If Not tv Then tv=_docsManager.CurrentTextView
@@ -978,24 +1110,31 @@ Class MainWindowInstance Extends Window
 			_editorMenu.AddAction( _editActions.cut )
 			_editorMenu.AddAction( _editActions.copy )
 			_editorMenu.AddAction( _editActions.paste )
+			_editorMenu.AddSeparator()
+			_editorMenu.AddAction( _viewActions.comment )
+			_editorMenu.AddAction( _viewActions.uncomment )
 		Endif
 		
 		_editorMenu.Open()
 	End
 	
 	Method UpdateHelpTree()
-		_helpTree.Update()
+		
+		_helpTree.Update( True )
 	End
 	
 	Method ShowBananasShowcase()
+		
 		OpenDocument( Prefs.MonkeyRootPath+"bananas/ted2go-showcase/all.bananas" )
 	End
 	
 	Method ReadError( path:String )
+		
 		Alert( "I/O Error reading file '"+path+"'" )
 	End
 	
 	Method WriteError( path:String )
+		
 		Alert( "I/O Error writing file '"+path+"'" )
 	End
 
@@ -1012,6 +1151,31 @@ Class MainWindowInstance Extends Window
 		Endif
 	End
 	
+	Method UpdateFullscreenMode()
+		
+		If _fullscreen
+			
+			Local bounds:SDL_Rect
+			SDL_GetDisplayBounds( SDL_GetWindowDisplayIndex(Window.SDLWindow),Varptr bounds )
+			
+			If _storedMaximized Then Restore()
+			
+			SDL_SetWindowSize( Window.SDLWindow,bounds.w,bounds.h )
+			SDL_SetWindowPosition( Window.SDLWindow,bounds.x,bounds.y )
+			
+			' Frame=... doesn't work here
+		Else
+			
+			SDL_SetWindowSize( Window.SDLWindow,_storedSize.Width,_storedSize.Height )
+			SDL_SetWindowPosition( Window.SDLWindow,_storedSize.Left,_storedSize.Top )
+			
+			If _storedMaximized Then Maximize()
+			
+		End
+		
+		SendWindowEvent( New WindowEvent( EventType.WindowResized,Self ) )
+	End
+	
 	Method GotoCodePosition( docPath:String,pos:Vec2i,lenToSelect:Int=0 )
 		
 		Local doc:=Cast<CodeDocument>( _docsManager.OpenDocument( docPath,True ) )
@@ -1053,12 +1217,16 @@ Class MainWindowInstance Extends Window
 	End
 	
 	Method SaveState()
-	
+		
 		If Not _enableSaving Return
-
+		
 		Local jobj:=New JsonObject
 		
-		jobj["windowRect"]=ToJson( Frame )
+		Local state:=_fullscreenState
+		If state=FullscreenState.None Then _storedSize=Frame
+		
+		jobj["windowRect"]=ToJson( _storedSize )
+		jobj["windowState"]=New JsonNumber( Int(state) )
 		
 		SaveTabsState( jobj )
 		
@@ -1120,13 +1288,11 @@ Class MainWindowInstance Extends Window
 
 	Private
 	
-	Field _inited:=False
-	Field _helpIdent:String
-	
 	Method OnRender( canvas:Canvas ) Override
 		
-		If Not _inited
-			_inited=True
+		Global __inited:=False
+		If Not __inited
+			__inited=True
 			OnInit()
 		Endif
 		
@@ -1150,11 +1316,14 @@ Class MainWindowInstance Extends Window
 	
 	Method OnFileDropped( path:String )
 		
-		If FileExists( path )
-			_docsManager.OpenDocument( path,True )
-		Else
-			_projectView.OpenProject( path )
-		Endif
+		New Fiber( Lambda()
+			
+			Local ok:=_projectView.OnFileDropped( path )
+			If Not ok And FileExists( path ) 'file
+				_docsManager.OpenDocument( path,True )
+			Endif
+			
+		End )
 	End
 	
 	Method OnAppClose()
@@ -1248,7 +1417,7 @@ Class MainWindowInstance Extends Window
 				mentionStr+=message.fromUser+" in "
 				mentionStr+=container.name
 				
-				Local dock:=_tabsWrap.tabs["Chat"].ParentDock '_tabsWrap.docks["bottom"]
+				Local dock:=_tabsWrap.tabs["Chat"].CurrentHolder '_tabsWrap.docks["bottom"]
 				ShowHint( mentionStr, New Vec2i( 0, -GetStyle( "Hint" ).Font.Height*4 ), dock, 20000 )
 				
 			Endif
@@ -1308,7 +1477,7 @@ Class MainWindowInstance Extends Window
 		InitTabs()
 		
 		_contentView.RemoveView( _toolBar )
-		_contentView.RemoveView( _statusBar )
+		_contentView.RemoveView( _statusBarContainer )
 		_contentView.RemoveView( _findReplaceView )
 		
 		_tabsWrap.DetachFromParent()
@@ -1318,7 +1487,11 @@ Class MainWindowInstance Extends Window
 			_contentView.AddView( _toolBar,"top" )
 		Endif
 		
-		_contentView.AddView( _statusBar,"bottom" )
+		If Not _statusBarContainer
+			_statusBarContainer=New DockingView
+			_statusBarContainer.ContentView=_statusBar
+		Endif
+		_contentView.AddView( _statusBarContainer,"bottom" )
 		
 		_tabsWrap.AttachToParent( _contentView )
 		
@@ -1328,23 +1501,22 @@ Class MainWindowInstance Extends Window
 		
 		_contentView.ContentView=_docsTabView
 		
-		
 	End
 	
 	Method LoadTabsState( jobj:JsonObject )
 		
 		Global places:=New StringMap<StringStack>
 		' defaults
-		Local s:=""
-		places["left"]=New StringStack
-		s="Project,Source,Debug,Help"
+		Local s:="Source"
+		places["left"]=New StringStack( s.Split( "," ) )
+		s="Project,Debug"
 		places["right"]=New StringStack( s.Split( "," ) )
 		s="Build,Output,Docs,Find,Chat"
 		places["bottom"]=New StringStack( s.Split( "," ) )
 		
 		Global actives:=New StringMap<String>
 		' defaults
-		actives["left"]="Project"
+		actives["left"]="Source"
 		actives["right"]="Project"
 		actives["bottom"]="Docs"
 		
@@ -1409,7 +1581,7 @@ Class MainWindowInstance Extends Window
 		
 		For Local edge:=Eachin edges
 			Local dock:=_tabsWrap.docks[edge]
-			jj[edge+"Tabs"]=JsonArray.Create( dock.TabsNames )
+			jj[edge+"Tabs"]=JsonArray.FromStrings( dock.TabsNames )
 			jj[edge+"Active"]=New JsonString( dock.ActiveName )
 			jj[edge+"Visible"]=New JsonBool( dock.Visible )
 			jj[edge+"Size"]=New JsonString( _tabsWrap.GetDockSize( dock ) )
@@ -1417,7 +1589,7 @@ Class MainWindowInstance Extends Window
 	End
 	
 	Method LoadState( jobj:JsonObject )
-	
+		
 		LoadTabsState( jobj )
 		
 		If jobj.Contains( "docsTab" )
@@ -1448,8 +1620,8 @@ Class MainWindowInstance Extends Window
 		If jobj.Contains( "theme" ) ThemeName=jobj.GetString( "theme" )
 		
 		If jobj.Contains( "themeScale" )
-			_themeScale=jobj.GetNumber( "themeScale" )
-			App.Theme.Scale=New Vec2f( _themeScale,_themeScale )
+			Local sc:=jobj.GetNumber( "themeScale" )
+			App.Theme.Scale=New Vec2f( sc )
 		Endif
 		
 		If jobj.Contains( "mx2ccDir" )
@@ -1469,9 +1641,17 @@ Class MainWindowInstance Extends Window
 			UpdateRecentFilesMenu()
 			UpdateRecentProjectsMenu()
 			UpdateCloseProjectMenu()
-
+			
 			DeleteTmps()
 			
+			' enter fullscreen mode
+			Local state:=Json_GetInt( jobj.Data,"windowState",0 )
+			If state=1
+				SwapFullscreenWindow()
+			Elseif state=2
+				SwapFullscreenEditor( True )
+			Endif
+			
 		End
 	End
 	
@@ -1486,6 +1666,11 @@ Class MainWindowInstance Extends Window
 			Select event.Key
 			Case Key.Escape
 				
+				If _fullscreenState=FullscreenState.Editor
+					SwapFullscreenEditor()
+					Return
+				Endif
+					
 				' hide find / replace panel
 				If HideFindPanel()
 					Return
@@ -1579,7 +1764,7 @@ Class MainWindowInstance Extends Window
 	Field _fileMenu:MenuExt
 	Field _editMenu:MenuExt
 	Field _findMenu:MenuExt
-	Field _viewMenu:MenuExt
+	Field _gotoMenu:MenuExt
 	Field _buildMenu:MenuExt
 	Field _windowMenu:MenuExt
 	Field _helpMenu:MenuExt
@@ -1588,7 +1773,6 @@ Class MainWindowInstance Extends Window
 	Field _themesMenu:MenuExt
 	
 	Field _theme:="default"
-	Field _themeScale:=1.0
 	
 	Field _contentView:DockingView
 	
@@ -1599,6 +1783,7 @@ Class MainWindowInstance Extends Window
 	Field _recentProjectsMenu:MenuExt
 	Field _closeProjectMenu:MenuExt
 	Field _statusBar:StatusBarView
+	Field _statusBarContainer:DockingView
 	Field _ovdMode:=False
 	Field _storedConsoleVisible:Bool
 	Field _consoleVisibleCounter:=0
@@ -1608,6 +1793,11 @@ Class MainWindowInstance Extends Window
 	Field _findReplaceView:FindReplaceView
 	Field _tabsWrap:=New DraggableTabs
 	
+	Field _fullscreen:Bool
+	Field _fullscreenState:=FullscreenState.None,_fullscreenPrevState:=FullscreenState.None
+	Field _fullscreenHelper:= New FullscreenHelper
+	Field _storedSize:Recti,_storedMaximized:Bool
+	
 	Method ToJson:JsonValue( rect:Recti )
 		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 ) ) )
 	End
@@ -1692,53 +1882,26 @@ Class MainWindowInstance Extends Window
 		Next
 	End
 	
-	Method AddZoomActions( menu:MenuExt )
-		
-		menu.AddAction( "Zoom in" ).Triggered=Lambda()
-			If _themeScale>=4 Return
-			
-			_themeScale+=.125
-
-			App.Theme.Scale=New Vec2f( _themeScale,_themeScale )
-		End
-		
-		menu.AddAction( "Zoom out" ).Triggered=Lambda()
-			If _themeScale<=.5 Return
-			
-			_themeScale-=.125
-
-			App.Theme.Scale=New Vec2f( _themeScale,_themeScale )
-		End
-		
-		menu.AddAction( "Reset zoom" ).Triggered=Lambda()
-		
-			_themeScale=1
-			
-			App.Theme.Scale=New Vec2f( _themeScale,_themeScale )
-		End
-	End
-
 	Method ThemeScaleMouseFilter( event:MouseEvent )
-	
+		
 		If event.Eaten Return
-			
+		
 		If event.Type=EventType.MouseWheel And event.Modifiers & Modifier.Menu
 			
+			Local sc:=App.Theme.Scale.x
 			If event.Wheel.y>0
-				If _themeScale<4 _themeScale+=0.125
+				If sc<4 sc+=0.125
 			Else
-				If _themeScale>.5 _themeScale-=0.125
+				If sc>.5 sc-=0.125
 			Endif
-				
-			App.Theme.Scale=New Vec2f( _themeScale,_themeScale )
-
+			
+			App.Theme.Scale=New Vec2f( sc )
+			
 			event.Eat()
-				
+			
 		Else If event.Type=EventType.MouseDown And event.Button=MouseButton.Middle And event.Modifiers & Modifier.Menu
 			
-			_themeScale=1
-
-			App.Theme.Scale=New Vec2f( _themeScale,_themeScale )
+			App.Theme.Scale=New Vec2f( 1 )
 			
 			event.Eat()
 		Endif
@@ -1760,15 +1923,16 @@ Class MainWindowInstance Extends Window
 				If value=ThemeName Return
 				
 				ThemeName=value
+				Local sc:=App.Theme.Scale.x
 				
-				App.Theme.Load( _theme,New Vec2f( _themeScale ) )
+				App.Theme.Load( _theme,New Vec2f( sc ) )
 				SaveState()
 			End
 		Next
 		
 		Return menu
 	End
-		
+	
 	Method OnAppIdle()
 		
 		_docsManager.Update()
@@ -1778,9 +1942,11 @@ Class MainWindowInstance Extends Window
 		_buildActions.Update()
 		
 		_forceStop.Enabled=_buildConsole.Running Or _outputConsole.Running
-	
-		_saveItem.SetIcon( _fileActions.save.Enabled ? 1 Else 0 )
-		_saveAllItem.SetIcon( _fileActions.saveAll.Enabled ? 1 Else 0 )
+		
+		If _saveItem ' when toolbar is visible
+			_saveItem.SetIcon( _fileActions.save.Enabled ? 1 Else 0 )
+			_saveAllItem.SetIcon( _fileActions.saveAll.Enabled ? 1 Else 0 )
+		Endif
 		
 		App.Idle+=OnAppIdle
 		
@@ -1791,6 +1957,44 @@ End
 
 Private
 
+Enum FullscreenState
+	None=0
+	Window=1
+	Editor=2
+End
+
+
+Class FullscreenHelper
+	
+	Field state:FullscreenState
+	Field frame:Recti
+	Field storedContentView:View
+	Field storedTabIndex:Int
+	Field editorContainer:DockingView
+	Field statusContainer:DockingView
+	Field titleLabel:Label
+	
+	Method New()
+		
+		editorContainer=New DockingView
+		
+		titleLabel=New Label
+		titleLabel.Gravity=New Vec2f( .5,0 )
+		titleLabel.Layout="float"
+		editorContainer.AddView( titleLabel,"top" )
+		
+		statusContainer=New DockingView
+		editorContainer.AddView( statusContainer,"bottom" )
+	End
+	
+	Method UpdateTitle()
+		
+		titleLabel.Text=MainWindow.DocsManager.CurrentDocumentLabel
+	End
+	
+End
+
+
 Class DraggableTabs
 	
 	Const Edges:=New String[]( "left","right","bottom" )
@@ -1801,7 +2005,7 @@ Class DraggableTabs
 	
 	Method New()
 		
-		sizes["left"]="300"
+		sizes["left"]="250"
 		sizes["right"]="300"
 		sizes["bottom"]="250"
 		

+ 1 - 1
Plugin.monkey2

@@ -53,7 +53,7 @@ Class PluginDependsOnFileType Extends Plugin Implements IDependsOnFileType
 	End
 	
 	Method New()
-		_types = New String[]("*")
+		_types=New String[]( "*" )
 	End
 	
 	Method GetFileTypes:String[]() Virtual

+ 3 - 0
Prefs.monkey2

@@ -38,6 +38,7 @@ Class PrefsInstance
 	Field EditorAutoIndent:=True
 	Field EditorAutoPairs:=True
 	Field EditorSurroundSelection:=True
+	Field EditorShowParamsHint:=True
 	'
 	Field SourceSortByType:=True
 	Field SourceShowInherited:=False
@@ -106,6 +107,7 @@ Class PrefsInstance
 			EditorAutoIndent=Json_GetBool( j2,"autoIndent",EditorAutoIndent )
 			EditorAutoPairs=Json_GetBool( j2,"autoPairs",EditorAutoPairs )
 			EditorSurroundSelection=Json_GetBool( j2,"surroundSelection",EditorSurroundSelection )
+			EditorShowParamsHint=Json_GetBool( j2,"showParamsHint",EditorShowParamsHint )
 			
 		Endif
 		
@@ -165,6 +167,7 @@ Class PrefsInstance
 		j["autoIndent"]=New JsonBool( EditorAutoIndent )
 		j["autoPairs"]=New JsonBool( EditorAutoPairs )
 		j["surroundSelection"]=New JsonBool( EditorSurroundSelection )
+		j["showParamsHint"]=New JsonBool( EditorShowParamsHint )
 		
 		j=New JsonObject
 		json["source"]=j

+ 15 - 11
Ted2.monkey2

@@ -7,7 +7,11 @@
 '
 'windres resource.rc resource.o
 
+#If __ARCH__="x86"
 #Import "logo/resource.o"
+#Elseif __ARCH__="x64"
+#Import "logo/resource_x64.o"
+#Endif
 
 #Endif
 
@@ -19,6 +23,7 @@
 #Import "<mojo>"
 #Import "<mojox>"
 #Import "<tinyxml2>"
+#Import "<sdl2>"
 
 #Import "action/FileActions"
 #Import "action/EditActions"
@@ -26,6 +31,7 @@
 #Import "action/HelpActions"
 #Import "action/FindActions"
 #Import "action/ViewActions"
+#Import "action/WindowActions"
 
 #Import "dialog/FindDialog"
 #Import "dialog/PrefsDialog"
@@ -35,7 +41,6 @@
 #Import "dialog/FindInFilesDialog"
 #Import "dialog/UpdateModulesDialog"
 #Import "dialog/GenerateClassDialog"
-#Import "dialog/LiveTemplateDialog"
 
 #Import "document/DocumentManager"
 #Import "document/Ted2Document"
@@ -84,7 +89,6 @@
 #Import "view/AutocompleteView"
 #Import "view/TreeViewExt"
 #Import "view/CodeTreeView"
-'#Import "view/FileBrowserExt"
 #Import "view/CodeGutterView"
 #Import "view/ToolBarViewExt"
 #Import "view/HintView"
@@ -109,14 +113,15 @@
 #Import "view/FindReplaceView"
 #Import "view/ViewExtensions"
 #Import "view/DockingViewExt"
+#Import "view/DraggableViewListener"
 
+#Import "Tree"
 #Import "Tuple"
 #Import "Plugin"
 #Import "ThemeImages"
 #Import "Prefs"
 #Import "ProcessReader"
 #Import "LiveTemplates"
-#Import "DraggableTabs"
 #Import "MainWindow"
 
 
@@ -126,11 +131,11 @@ Using std..
 Using mojo..
 Using mojox..
 Using tinyxml2..
-
+Using sdl2..
 
 Const MONKEY2_DOMAIN:="http://monkeycoder.co.nz"
 
-Global AppTitle:="Ted2Go v2.7"
+Global AppTitle:="Ted2Go v2.8"
 
 
 Function Main()
@@ -159,18 +164,17 @@ Function Main()
 	
 	'initial theme
 	'
-	If Not jobj.Contains( "theme" ) jobj["theme"]=New JsonString( "theme-prime-blue" )
+	If Not jobj.Contains( "theme" ) jobj["theme"]=New JsonString( "theme-warm" )
 
 	If Not jobj.Contains( "themeScale" ) jobj["themeScale"]=New JsonNumber( 1 )
 	
-	Local config:=New StringMap<String>
+	SetConfig( "MOJO_INITIAL_THEME",jobj.GetString( "theme" ) )
 	
-	config["initialTheme"]=jobj.GetString( "theme" )
-	config["initialThemeScale"]=jobj.GetNumber( "themeScale" )
+	SetConfig( "MOJO_INITIAL_THEME_SCALE",jobj.GetString( "themeScale" ) )
 	
 	'start the app!
 	'
-	New AppInstance( config )
+	New AppInstance
 	
 	'initial window state
 	'
@@ -181,7 +185,7 @@ Function Main()
 	If jobj.Contains( "windowRect" ) 
 		rect=ToRecti( jobj["windowRect"] )
 	Else
-		Local w:=Min( 1380,App.DesktopSize.x-40 )
+		Local w:=Min( 1480,App.DesktopSize.x-40 )
 		Local h:=Min( 970,App.DesktopSize.y-64 )
 		rect=New Recti( 0,0,w,h )
 		flags|=WindowFlags.Center

+ 94 - 0
Tree.monkey2

@@ -0,0 +1,94 @@
+
+Namespace ted2go
+
+
+Class Tree
+	
+	Class Node
+		
+		Field Text:String
+		Field UserData:Variant
+		
+		Property Children:Stack<Node>()
+			Return _children
+		End
+		
+		Property NumChildren:Int()
+			Return Children?.Length
+		End
+		
+		Property Parent:Node()
+			Return _parent
+		Setter( value:Node )
+			If _parent Then _parent-=Self
+			_parent=value
+			If _parent Then _parent+=Self
+		End
+		
+		Property ParentsHierarchy:Stack<Node>()
+			
+			Local result:=New Stack<Node>
+			Local p:=_parent
+			While p
+				result.Insert( 0,p )
+				p=p.Parent
+			Wend
+			Return result
+		End
+		
+		Method New( text:String,parent:Node=Null,userData:Variant=Null )
+			
+			Text=text
+			Parent=parent
+			UserData=userData
+		End
+		
+		Method GetUserData<T>:T()
+			
+			Return UserData ? Cast<T>( UserData ) Else Null
+		End
+		
+		Operator +=( child:Node )
+			
+			If Not _children Then _children=New Stack<Node>
+			_children.Add( child )
+		End
+		
+		Operator -=( child:Node )
+			
+			If Not _children Return
+			_children.Remove( child )
+		End
+		
+		Method Clear()
+			
+			_children?.Clear()
+		End
+		
+		
+		Private
+		
+		Field _parent:Node
+		Field _children:Stack<Node>
+		
+	End
+	
+	Method New()
+		
+		_root=New Node( "" )
+	End
+	
+	Property RootNode:Node()
+		Return _root
+	End
+	
+	Method Clear()
+	
+		_root.Clear()
+	End
+	
+	Private
+	
+	Field _root:Node
+	
+End

+ 67 - 16
action/BuildActions.monkey2

@@ -26,7 +26,11 @@ End
 
 Interface IModuleBuilder
 	
-	Method BuildModules:Bool( clean:Bool,modules:String="",configs:String="debug release" )
+	' cleanState: 
+	' -1: don't clean
+	' 0: use previous
+	' 1: clean
+	Method BuildModules:Bool( modules:String="",configs:String="",cleanState:Int=0 )
 	
 End
 
@@ -149,6 +153,9 @@ Class BuildActions Implements IModuleBuilder
 		_iosTarget=New CheckButton( "iOS",,group )
 		_iosTarget.Layout="fill-x"
 		
+		_verboseMode=New CheckButton( "Verbose")
+		_verboseMode.Layout="fill-x"
+		
 		targetMenu=New MenuExt( "Build target" )
 		targetMenu.AddView( _debugConfig )
 		targetMenu.AddView( _releaseConfig )
@@ -159,6 +166,8 @@ Class BuildActions Implements IModuleBuilder
 		targetMenu.AddView( _iosTarget )
 		targetMenu.AddSeparator()
 		targetMenu.AddAction( buildSettings )
+		targetMenu.AddSeparator()
+		targetMenu.AddView( _verboseMode )
 		
 		'check valid targets...WIP...
 		
@@ -204,6 +213,11 @@ Class BuildActions Implements IModuleBuilder
 		Return _locked
 	End
 	
+	Property Verbosed:Bool()
+	
+		Return _verboseMode.Checked
+	End
+	
 	Method LockBuildFile()
 		
 		Local doc:=Cast<CodeDocument>( _docs.CurrentDocument )
@@ -217,6 +231,8 @@ Class BuildActions Implements IModuleBuilder
 		jobj["buildConfig"]=New JsonString( _buildConfig )
 		
 		jobj["buildTarget"]=New JsonString( _buildTarget )
+		
+		jobj["buildVerbose"]=New JsonBool( _verboseMode.Checked )
 	End
 		
 	Method LoadState( jobj:JsonObject )
@@ -239,12 +255,12 @@ Class BuildActions Implements IModuleBuilder
 		Endif
 		
 		If jobj.Contains( "buildTarget" )
-					
+			
 			local target:=jobj["buildTarget"].ToString()
-
-			If _validTargets.Contains( target )
 			
-				 _buildTarget=target
+			If _validTargets.Contains( target )
+				
+				_buildTarget=target
 				
 				Select _buildTarget
 				Case "desktop"
@@ -261,6 +277,10 @@ Class BuildActions Implements IModuleBuilder
 			
 		Endif
 		
+		If jobj.Contains( "buildVerbose" )
+			_verboseMode.Checked=jobj.GetBool( "buildVerbose" )
+		Endif
+		
 	End
 	
 	Method Update()
@@ -279,27 +299,48 @@ Class BuildActions Implements IModuleBuilder
 		rebuildHelp.Enabled=idle
 		moduleManager.Enabled=idle
 	End
-
-	Method BuildModules:Bool( clean:Bool,modules:String="",configs:String="debug release" )
 	
-		Local dialog:=New UpdateModulesDialog( _validTargets,modules,configs,clean )
+	Method BuildModules:Bool( modules:String="",configs:String="",cleanState:Int=0 )
+		
+		If Not modules Then modules=_storedModules
+		
+		If Not configs
+			configs=_storedConfigs
+			If Not configs Then configs="debug release"
+		Endif
+		
+		Local clean:Bool
+		If cleanState=0
+			clean=_storedClean
+		Else
+			clean=(cleanState=1)
+		Endif
+		
+		Local selTargets:=(_storedTargets ?Else "desktop")
+		
+		Local dialog:=New UpdateModulesDialog( _validTargets,selTargets,modules,configs,clean )
 		dialog.Title="Update / Rebuild modules"
 		
 		Local ok:=dialog.ShowModal()
 		If Not ok Return False
 		
-		Local result:=True
+		Local result:Bool
 		
 		Local targets:=dialog.SelectedTargets
 		modules=dialog.SelectedModules
-		
-		clean=dialog.NeedClean
 		configs=dialog.SelectedConfigs
+		clean=dialog.NeedClean
+		
+		' store
+		_storedTargets=targets.Join( " " )
+		_storedModules=modules
+		_storedConfigs=configs
+		_storedClean=clean
 		
 		Local time:=Millisecs()
 		
 		For Local target:=Eachin targets
-			result=BuildModules( clean,target,modules,configs )
+			result=BuildModules( target,modules,configs,clean )
 			If result=False Exit
 		Next
 		
@@ -318,7 +359,7 @@ Class BuildActions Implements IModuleBuilder
 	
 	Method GotoError( err:BuildError )
 	
-		Local doc:=Cast<CodeDocument>( _docs.OpenDocument( err.path,True ) )
+		Local doc:=Cast<CodeDocument>( _docs.OpenDocument( GetCaseSensitivePath( err.path ),True ) )
 		If Not doc Return
 	
 		Local tv := doc.CodeView
@@ -349,10 +390,15 @@ Class BuildActions Implements IModuleBuilder
 	Field _emscriptenTarget:CheckButton
 	Field _androidTarget:CheckButton
 	Field _iosTarget:CheckButton
+	Field _verboseMode:CheckButton
 	
 	Field _validTargets:StringStack
 	Field _timing:Long
 	
+	Field _storedModules:String
+	Field _storedConfigs:String
+	Field _storedTargets:String
+	Field _storedClean:Bool
 	
 	Method BuildDoc:CodeDocument()
 		
@@ -434,7 +480,7 @@ Class BuildActions Implements IModuleBuilder
 						Local msg:=stdout.Slice( i+12 )
 						
 						Local err:=New BuildError( path,line,msg )
-						Local doc:=Cast<CodeDocument>( _docs.OpenDocument( path,False ) )
+						Local doc:=Cast<CodeDocument>( _docs.OpenDocument( GetCaseSensitivePath( path ),False ) )
 						
 						If doc
 							doc.AddError( err )
@@ -477,7 +523,7 @@ Class BuildActions Implements IModuleBuilder
 		Return _console.ExitCode=0
 	End
 
-	Method BuildModules:Bool( clean:Bool,target:String,modules:String,configs:String="debug release" )
+	Method BuildModules:Bool( target:String,modules:String,configs:String,clean:Bool )
 		
 		PreBuildModules()
 		
@@ -490,6 +536,7 @@ Class BuildActions Implements IModuleBuilder
 			
 			Local cmd:=MainWindow.Mx2ccPath+" makemods -target="+target
 			If clean cmd+=" -clean"
+			If Verbosed cmd+=" -verbose"
 			cmd+=" -config="+cfg
 			If modules Then cmd+=" "+modules
 			
@@ -523,6 +570,7 @@ Class BuildActions Implements IModuleBuilder
 		If run Then action="build"
 
 		Local cmd:=MainWindow.Mx2ccPath+" makeapp -"+action+" "+opts
+		If Verbosed cmd+=" -verbose"
 		cmd+=" -config="+config
 		cmd+=" -target="+target
 		cmd+=" ~q"+buildDoc.Path+"~q"
@@ -623,6 +671,8 @@ Class BuildActions Implements IModuleBuilder
 		
 		_locked=doc
 		SetLockedState( _locked,True )
+		
+		
 	End
 	
 	Method SetLockedState( doc:CodeDocument,locked:Bool )
@@ -630,6 +680,7 @@ Class BuildActions Implements IModuleBuilder
 		doc.State=locked ? "+" Else ""
 		Local tab:=_docs.FindTab( doc.View )
 		If tab Then tab.SetLockedState( locked )
+		_docs.CurrentDocumentChanged()
 	End
 	
 	Method OnBuildFileSettings()
@@ -644,7 +695,7 @@ Class BuildActions Implements IModuleBuilder
 		
 		If _console.Running Return
 	
-		BuildModules( False )
+		BuildModules()
 	End
 	
 	Method OnModuleManager()

+ 106 - 1
action/EditActions.monkey2

@@ -11,7 +11,15 @@ Class EditActions
 	Field paste:Action
 	Field selectAll:Action
 	Field wordWrap:Action
-	
+	' Edit -- Text
+	Field textDeleteWordForward:Action
+	Field textDeleteWordBackward:Action
+	Field textDeleteLine:Action
+	Field textDeleteToEnd:Action
+	Field textDeleteToBegin:Action
+	Field textLowercase:Action
+	Field textUppercase:Action
+	Field textSwapCase:Action
 	
 	Method New( docs:DocumentManager )
 	
@@ -57,6 +65,58 @@ Class EditActions
 		wordWrap.HotKey=Key.Z
 		wordWrap.HotKeyModifiers=Modifier.Alt
 		
+		textDeleteLine=New Action( "Delete line" )
+		textDeleteLine.Triggered=OnDeleteLine
+		#If __TARGET__="macos"
+		textDeleteLine.HotKey=Key.K
+		textDeleteLine.HotKeyModifiers=Modifier.Control|Modifier.Shift
+		#Else
+		textDeleteLine.HotKey=Key.E
+		textDeleteLine.HotKeyModifiers=Modifier.Control
+		#Endif
+		
+		textDeleteWordForward=New Action( "Delete word forward" )
+		textDeleteWordForward.Triggered=OnDeleteWordForward
+		textDeleteWordForward.HotKey=Key.KeyDelete
+		textDeleteWordForward.HotKeyModifiers=Modifier.Control
+		
+		textDeleteWordBackward=New Action( "Delete word backward" )
+		textDeleteWordBackward.Triggered=OnDeleteWordBackward
+		textDeleteWordBackward.HotKey=Key.Backspace
+		textDeleteWordBackward.HotKeyModifiers=Modifier.Control
+		
+		textDeleteToBegin=New Action( "Delete to beginning" )
+		textDeleteToBegin.Triggered=OnDeleteToBegin
+		textDeleteToBegin.HotKey=Key.Backspace
+		#If __TARGET__="macos"
+		textDeleteToBegin.HotKeyModifiers=Modifier.Menu
+		#Else
+		textDeleteToBegin.HotKeyModifiers=Modifier.Menu|Modifier.Shift
+		#Endif
+		
+		textDeleteToEnd=New Action( "Delete to end" )
+		textDeleteToEnd.Triggered=OnDeleteToEnd
+		#If __TARGET__="macos"
+		textDeleteToEnd.HotKey=Key.K
+		textDeleteToEnd.HotKeyModifiers=Modifier.Control
+		#Else
+		textDeleteToEnd.HotKey=Key.KeyDelete
+		textDeleteToEnd.HotKeyModifiers=Modifier.Control|Modifier.Shift
+		#Endif
+		
+		textLowercase=New Action( "lowercace" )
+		textLowercase.Triggered=OnLowercase
+		textLowercase.HotKey=Key.L
+		textLowercase.HotKeyModifiers=Modifier.Control|Modifier.Shift
+		
+		textUppercase=New Action( "UPPERCASE" )
+		textUppercase.Triggered=OnUppercase
+		textUppercase.HotKey=Key.U
+		textUppercase.HotKeyModifiers=Modifier.Control|Modifier.Shift
+		
+		textSwapCase=New Action( "Swap case" )
+		textSwapCase.Triggered=OnSwapCase
+		
 	End
 	
 	Method Update()
@@ -75,6 +135,51 @@ Class EditActions
 	
 	Field _docs:DocumentManager
 	
+	Property CurrentCodeDocument:CodeTextView()
+		
+		Return Cast<CodeTextView>( App.KeyView )
+	End
+	
+	Method OnDeleteLine()
+		
+		CurrentCodeDocument?.DeleteLineAtCursor()
+	End
+	
+	Method OnDeleteWordForward()
+		
+		CurrentCodeDocument?.DeleteWordForward()
+	End
+	
+	Method OnDeleteWordBackward()
+		
+		CurrentCodeDocument?.DeleteWordBackward()
+	End
+	
+	Method OnDeleteToBegin()
+		
+		CurrentCodeDocument?.DeleteToBegin()
+	End
+	
+	Method OnDeleteToEnd()
+	
+		CurrentCodeDocument?.DeleteToEnd()
+	End
+	
+	Method OnLowercase()
+	
+		CurrentCodeDocument?.LowercaseSelection()
+	End
+	
+	Method OnUppercase()
+	
+		CurrentCodeDocument?.UppercaseSelection()
+	End
+	
+	Method OnSwapCase()
+		
+		CurrentCodeDocument?.SwapCaseSelection()
+	End
+	
 	Method OnUndo()
 
 		Local tv:=Cast<TextView>( App.KeyView )

+ 1 - 1
action/FileActions.monkey2

@@ -144,7 +144,7 @@ Class FileActions
 		Local name:=StripDir( doc.Path )
 		Local path:=MainWindow.RequestFile( "Save As",name,True )
 		If Not path Return Null
-				
+		
 		If Not ExtractExt( path ) path+=ExtractExt( doc.Path )
 		
 		Return _docs.RenameDocument( doc,path )

+ 36 - 32
action/HelpActions.monkey2

@@ -13,8 +13,9 @@ Class HelpActions
 	Field makeBetter:Action
 	Field mx2homepage:Action
 	Field bananas:Action
+	Field joinCommunity:Action
+	
 	
-
 	Method New()
 	
 		quickHelp=New Action( "Quick help" )
@@ -22,7 +23,7 @@ Class HelpActions
 		quickHelp.HotKey=Key.F1
 		
 		onlineHelp=New Action( "Online help" )
-		onlineHelp.Triggered=lambda()
+		onlineHelp.Triggered=Lambda()
 		
 			OpenUrl( MONKEY2_DOMAIN+"/monkey2-docs/" )
 		End
@@ -38,58 +39,44 @@ Class HelpActions
 		
 			GotoUploadModulesPage()
 		End
-
+		
 		about=New Action( "About monkey2" )
 		about.Triggered=Lambda()
 		
-			Local htmlView:=New HtmlView
-			htmlView.Go( MainWindow.AboutPagePath )
-	
-			Local dialog:=New Dialog( "About monkey2" )
-			dialog.ContentView=htmlView
-
-			dialog.MinSize=New Vec2i( 640,600 )
-
-			dialog.AddAction( "Okay!" ).Triggered=dialog.Close
-			
-			dialog.Open()
+			OnAboutDialog( "About monkey2",MainWindow.AboutPagePath )
 		End
-
+		
 		aboutTed2go=New Action( "About ted2go" )
 		aboutTed2go.Triggered=Lambda()
 		
-			Local htmlView:=New HtmlView
-			htmlView.Go( "asset::ted2/aboutTed2Go.html" )
-	
-			Local dialog:=New Dialog( "About ted2go" )
-			dialog.ContentView=htmlView
-
-			dialog.MinSize=New Vec2i( 640,600 )
-
-			dialog.AddAction( "Okay!" ).Triggered=dialog.Close
-			
-			dialog.Open()
+			OnAboutDialog( "About ted2go","asset::ted2/aboutTed2Go.html" )
 		End
 		
-		makeBetter=New Action( "Make this app better! (paypal)" )
+		makeBetter=New Action( "Make this app better! (PayPal)" )
 		makeBetter.Triggered=Lambda()
 		
 			OpenUrl( "https://paypal.me/engor/10" )
 		End
 		
 		mx2homepage=New Action( "Monkey2 homepage" )
-		mx2homepage.Triggered=lambda()
+		mx2homepage.Triggered=Lambda()
 		
 			OpenUrl( MONKEY2_DOMAIN )
 		End
 		
 		bananas=New Action( "Bananas showcase" )
-		bananas.Triggered=lambda()
-		
+		bananas.Triggered=Lambda()
+			
 			MainWindow.ShowBananasShowcase()
 		End
+		
+		joinCommunity=New Action( "Join the community (Discord)" )
+		joinCommunity.Triggered=Lambda()
+		
+			OpenUrl( "https://discord.gg/A2C6AMM" )
+		End
+		
 	End
-
 	
 	Private
 	
@@ -97,7 +84,24 @@ Class HelpActions
 	
 	Method OnQuickHelp()
 	
-		MainWindow.ShowQuickHelp()
+		MainWindow.ShowHelp()
+	End
+	
+	Method OnAboutDialog( title:String,url:String,okButton:String="Okay!" )
+	
+		Local htmlView:=New HtmlView
+		htmlView.Go( url )
+	
+		Local dialog:=New DialogExt( title,htmlView )
+	
+		dialog.MinSize=New Vec2i( 640,600 )
+	
+		dialog.AddAction( okButton ).Triggered=dialog.Hide
+	
+		dialog.FadeEnabled=True ' faded
+	
+		dialog.Show()
+	
 	End
 	
 End

+ 3 - 3
action/ViewActions.monkey2

@@ -15,12 +15,12 @@ Class ViewActions
 		
 		_docs=docs
 		
-		goBack=New Action( "Go back" )
+		goBack=New Action( "Jump back" )
 		goBack.Triggered=OnGoBack
 		goBack.HotKey=Key.Left
 		goBack.HotKeyModifiers=Modifier.Alt|Modifier.Menu
 		
-		goForward=New Action( "Go forward" )
+		goForward=New Action( "Jump forward" )
 		goForward.Triggered=OnGoForward
 		goForward.HotKey=Key.Right
 		goForward.HotKeyModifiers=Modifier.Alt|Modifier.Menu
@@ -48,7 +48,7 @@ Class ViewActions
 		gotoLine.HotKey=Key.G
 		gotoLine.HotKeyModifiers=Modifier.Menu
 		
-		gotoDeclaration=New Action( "Goto declaration" )
+		gotoDeclaration=New Action( "Goto definition" )
 		gotoDeclaration.Triggered=OnGotoDeclaration
 		gotoDeclaration.HotKey=Key.F12
 	End

+ 76 - 0
action/WindowActions.monkey2

@@ -0,0 +1,76 @@
+
+Namespace ted2go
+
+
+Class WindowActions
+
+	Field nextTab:Action
+	Field prevTab:Action
+	Field zoomIn:Action
+	Field zoomOut:Action
+	Field zoomDefault:Action
+	Field themes:Action
+	Field fullscreenWindow:Action
+	Field fullscreenEditor:Action
+	
+	Method New( docs:DocumentManager )
+		
+		nextTab=docs.nextDocument
+		prevTab=docs.prevDocument
+		
+		fullscreenWindow=New Action( "Fullscreen window" )
+#If __TARGET__="macos"
+		fullscreenWindow.HotKey=Key.F
+		fullscreenWindow.HotKeyModifiers=Modifier.Menu|Modifier.Control
+#Else
+		fullscreenWindow.HotKey=Key.F11
+#Endif
+		fullscreenWindow.Triggered=Lambda()
+			MainWindow.SwapFullscreenWindow()
+		End
+		
+		fullscreenEditor=New Action( "Fullscreen editor" )
+#If __TARGET__="macos"
+		fullscreenEditor.HotKey=Key.F
+		fullscreenEditor.HotKeyModifiers=Modifier.Menu|Modifier.Control|Modifier.Shift
+#Else
+		fullscreenEditor.HotKey=Key.F11
+		fullscreenEditor.HotKeyModifiers=Modifier.Shift
+#Endif
+		fullscreenEditor.Triggered=Lambda()
+			MainWindow.SwapFullscreenEditor()
+		End
+		
+		zoomIn=New Action( "Zoom in" )
+		zoomIn.HotKey=Key.KeypadPlus
+		zoomIn.HotKeyModifiers=Modifier.Control
+		zoomIn.Triggered=Lambda()
+		
+			Local sc:=App.Theme.Scale.x
+			If sc>=4 Return
+			sc+=.125
+			App.Theme.Scale=New Vec2f( sc )
+		End
+		
+		zoomOut=New Action( "Zoom out" )
+		zoomOut.HotKey=Key.KeypadMinus
+		zoomOut.HotKeyModifiers=Modifier.Control
+		zoomOut.Triggered=Lambda()
+		
+			Local sc:=App.Theme.Scale.x
+			If sc<=.5 Return
+			sc-=.125
+			App.Theme.Scale=New Vec2f( sc )
+		End
+		
+		zoomDefault=New Action( "Reset zoom" )
+		zoomDefault.HotKey=Key.Keypad0
+		zoomDefault.HotKeyModifiers=Modifier.Control
+		zoomDefault.Triggered=Lambda()
+		
+			App.Theme.Scale=New Vec2f( 1 )
+		End
+		
+	End
+	
+End

+ 1 - 1
assets/aboutTed2Go.html

@@ -124,7 +124,7 @@ ToolBar icons were taken from <a href="https://icons8.com/icon/new-icons/win8">i
 
 <h3>Special thanks</h3>
 
-<p>Matthew Bowen, Mark Mcvittie, Simon Armstrong, Rudy van Etten, Hezkore, Sal Gunduz, Peter Scheutz, Matthieu Chemin, David Maziarka, Leonardo Teixeira, Jesus Perez, Mark Sibly, Philipp Moeller, Lee Wade.</p>
+<p>Rajasekaran Senthil Kumaran, abakobo, Peter Rigby, Dmitry Fadeev, James Boyd, Sam Fisher, Matthew Bowen, Mark Mcvittie, Simon Armstrong, Rudy van Etten, Hezkore, Sal Gunduz, Peter Scheutz, Matthieu Chemin, David Maziarka, Leonardo Teixeira, Jesus Perez, Mark Sibly, Philipp Moeller, Lee Wade.</p>
 
 </body>
 

+ 5 - 6
assets/newfiles/Simple_Mojo3d_App.monkey2

@@ -1,13 +1,9 @@
-Namespace myapp
+Namespace myapp3d
 
 #Import "<std>"
 #Import "<mojo>"
 #Import "<mojo3d>"
 
-#Import "assets/"
-
-#Import "util"
-
 Using std..
 Using mojo..
 Using mojo3d..
@@ -42,6 +38,7 @@ Class MyWindow Extends Window
 		_camera.Near=.1
 		_camera.Far=100
 		_camera.Move( 0,10,-10 )
+		_camera.AddComponent<FlyBehaviour>()
 		
 		'create light
 		'
@@ -61,11 +58,13 @@ Class MyWindow Extends Window
 	
 		RequestRender()
 		
+		If Keyboard.KeyHit( Key.Escape ) App.Terminate()
+		
 		If Keyboard.KeyHit( Key.Space ) _donut.Visible=Not _donut.Visible
 		
 		_donut.Rotate( .2,.4,.6 )
 		
-		util.Fly( _camera,Self )
+		_scene.Update()
 		
 		_scene.Render( canvas,_camera )
 		

+ 0 - 0
assets/themes/hollow_assets/checkbox_icons.png → assets/themes/hollow_assets/hollow_checkbox_icons.png


+ 0 - 0
assets/themes/hollow_assets/dialog_skin.png → assets/themes/hollow_assets/hollow_dialog_skin.png


+ 0 - 0
assets/themes/hollow_assets/progressbar_icons.png → assets/themes/hollow_assets/hollow_progressbar_icons.png


+ 0 - 0
assets/themes/hollow_assets/tabclose_icons.png → assets/themes/hollow_assets/hollow_tabclose_icons.png


+ 0 - 0
assets/themes/hollow_assets/treeview_icons.png → assets/themes/hollow_assets/hollow_treeview_icons.png


+ 0 - 0
assets/themes/prime_assets/checkbox_icons.png → assets/themes/prime_assets/prime_checkbox_icons.png


+ 0 - 0
assets/themes/prime_assets/dialog_skin.png → assets/themes/prime_assets/prime_dialog_skin.png


+ 0 - 0
assets/themes/prime_assets/progressbar_icons.png → assets/themes/prime_assets/prime_progressbar_icons.png


+ 0 - 0
assets/themes/prime_assets/tabclose_icons.png → assets/themes/prime_assets/prime_tabclose_icons.png


+ 0 - 0
assets/themes/prime_assets/treeview_icons.png → assets/themes/prime_assets/prime_treeview_icons.png


+ 0 - 0
assets/themes/smooth_assets/button_skin.png → assets/themes/smooth_assets/smooth_button_skin.png


+ 0 - 0
assets/themes/smooth_assets/checkbox_icons.png → assets/themes/smooth_assets/smooth_checkbox_icons.png


+ 0 - 0
assets/themes/smooth_assets/dialog_skin.png → assets/themes/smooth_assets/smooth_dialog_skin.png


+ 0 - 0
assets/themes/smooth_assets/progressbar_icons.png → assets/themes/smooth_assets/smooth_progressbar_icons.png


二進制
assets/themes/smooth_assets/smooth_tabbutton_locked_skin.png


+ 0 - 0
assets/themes/smooth_assets/tabbutton_selected_skin.png → assets/themes/smooth_assets/smooth_tabbutton_selected_skin.png


+ 0 - 0
assets/themes/smooth_assets/tabbutton_skin.png → assets/themes/smooth_assets/smooth_tabbutton_skin.png


+ 0 - 0
assets/themes/smooth_assets/tabclose_icons.png → assets/themes/smooth_assets/smooth_tabclose_icons.png


+ 0 - 0
assets/themes/smooth_assets/treeview_icons.png → assets/themes/smooth_assets/smooth_treeview_icons.png


+ 8 - 3
assets/themes/ted2-default.json

@@ -11,7 +11,9 @@
 		"statusbar-active": "#CA5100",
 		"menu-shortcut":"text-background",
 		"codemap-background": "transparent",
-		"codemap-selection": "#48000000"		
+		"codemap-selection": "#48000000",
+		"params-hint-common": "textview-color1",
+		"params-hint-selected": "textview-color4"
 	},
 
 	"fonts":{
@@ -21,8 +23,7 @@
 	},
 	
 	"styles":{
-				
-
+		
 		"GutterView":{
 			"extends":"TextView",
 			"textColor":"text-disabled",
@@ -47,6 +48,10 @@
 			"backgroundColor":"panel"
 		},
 
+		"ParamsHint":{
+			"extends":"Hint"
+		},
+
 		"ToolBarExt":{
 			"extends":"ToolBar",
 			"padding":[ 0 ],

+ 14 - 7
assets/themes/theme-hollow.json

@@ -23,6 +23,8 @@
 		"brighter": "#665C54",
 		"brightest": "#7C6F64",
 
+		"separator": "#2A2828",
+
 		"text-default": "#CECECE",
 		"text-highlight": "#FFFFFF",
 		"text-disabled": "#6F6F6F",
@@ -130,7 +132,7 @@
 		},
 
 		"ProgressBar":{
-			"icons":"hollow_assets/progressbar_icons.png"
+			"icons":"hollow_assets/hollow_progressbar_icons.png"
 		},
 
 		"StatusBar":{
@@ -232,7 +234,7 @@
 		},
 		
 		"CheckBox":{
-			"icons":"hollow_assets/checkbox_icons.png",
+			"icons":"hollow_assets/hollow_checkbox_icons.png",
 			"iconColor":"textview-color7",
 			"margin":[0,0,0,0]
 		},
@@ -302,7 +304,7 @@
 		"Menu":{
 			"extends":"DockingView",
 			"padding":[ 0 ],
-			"skin":"hollow_assets/dialog_skin.png",
+			"skin":"hollow_assets/hollow_dialog_skin.png",
 			"skinColor":"dark"
 		},
 		
@@ -334,7 +336,7 @@
 		
 		"MenuSeparator":{
 			"padding":[ 0,0,0,1 ],
-			"backgroundColor":"dark",
+			"backgroundColor":"separator",
 			"border":[ 8,8,7,7 ]
 		},
 
@@ -370,9 +372,14 @@
 			}
 		},
 		
+		"TabButtonLocked":{
+			"extends":"TabButton",
+			"borderColor":"#F26522"
+		},
+		
 		"TabClose":{
 			"margin":[32,0,0,0 ],
-			"icons":"hollow_assets/tabclose_icons.png",
+			"icons":"hollow_assets/hollow_tabclose_icons.png",
 			"iconColor":"text-disabled",
 			"states":{
 				"hover":{
@@ -399,7 +406,7 @@
 		
 		"TreeView":{
 			"backgroundColor":"darker",
-			"icons":"hollow_assets/treeview_icons.png",
+			"icons":"hollow_assets/hollow_treeview_icons.png",
 			"iconColor":"text-background"
 		},
 		
@@ -454,7 +461,7 @@
 		},
 		
 		"Dialog":{
-			"skin":"hollow_assets/dialog_skin.png",
+			"skin":"hollow_assets/hollow_dialog_skin.png",
 			"skinColor":"bright"
 		},
 		

+ 11 - 6
assets/themes/theme-prime-base.json

@@ -142,7 +142,7 @@
 
 		"ProgressBar":{
 			"iconColor":"accent",
-			"icons":"prime_assets/progressbar_icons.png"
+			"icons":"prime_assets/prime_progressbar_icons.png"
 		},
 
 		"StatusBar":{
@@ -222,7 +222,7 @@
 		},
 		
 		"CheckBox":{
-			"icons":"prime_assets/checkbox_icons.png",
+			"icons":"prime_assets/prime_checkbox_icons.png",
 			"iconColor":"accent",
 			"margin":[0,0,0,0]
 		},
@@ -292,7 +292,7 @@
 		"Menu":{
 			"extends":"DockingView",
 			"padding":[ 0 ],
-			"skin":"prime_assets/dialog_skin.png",
+			"skin":"prime_assets/prime_dialog_skin.png",
 			"skinColor":"darkest"
 		},
 		
@@ -358,10 +358,15 @@
 				}
 			}
 		},
+
+		"TabButtonLocked":{
+			"extends":"TabButton",
+			"borderColor":"textview-color4"
+		},
 		
 		"TabClose":{
 			"margin":[32,0,0,0 ],
-			"icons":"prime_assets/tabclose_icons.png",
+			"icons":"prime_assets/prime_tabclose_icons.png",
 			"iconColor":"text-disabled",
 			"states":{
 				"hover":{
@@ -388,7 +393,7 @@
 		
 		"TreeView":{
 			"backgroundColor":"dark",
-			"icons":"prime_assets/treeview_icons.png",
+			"icons":"prime_assets/prime_treeview_icons.png",
 			"iconColor":"#8fff"
 		},
 		
@@ -444,7 +449,7 @@
 		},
 		
 		"Dialog":{
-			"skin":"prime_assets/dialog_skin.png",
+			"skin":"prime_assets/prime_dialog_skin.png",
 			"skinColor":"bright"
 		},
 		

+ 14 - 9
assets/themes/theme-smooth.json

@@ -49,7 +49,7 @@
 
 		"Hint":{
 			"textColor":"text-highlight",
-			"skin":"smooth_assets/button_skin.png",
+			"skin":"smooth_assets/smooth_button_skin.png",
 			"skinColor":"#9EBEFF"
 		},
 
@@ -79,14 +79,14 @@
 		},
 
 		"ProgressBar":{
-			"icons":"smooth_assets/progressbar_icons.png"
+			"icons":"smooth_assets/smooth_progressbar_icons.png"
 		},
 
 		"Button":{
 			"font":"small",
 			"extends":"Label",
 			"padding":[4,2],
-			"skin":"smooth_assets/button_skin.png",
+			"skin":"smooth_assets/smooth_button_skin.png",
 			"skinColor":"panel",
 
 			"states":{
@@ -103,7 +103,7 @@
 		},
 
 		"Dialog":{
-			"skin":"smooth_assets/dialog_skin.png",
+			"skin":"smooth_assets/smooth_dialog_skin.png",
 			"skinColor":"panel"
 		},
 
@@ -115,7 +115,7 @@
         "TreeView":{
             "borderColor":"border",
             "backgroundColor":"content",
-            "icons":"smooth_assets/treeview_icons.png",
+            "icons":"smooth_assets/smooth_treeview_icons.png",
             "iconColor":"#9DA5B4"
         },
 
@@ -140,7 +140,7 @@
 		},
 
 		"CheckBox":{
-			"icons":"smooth_assets/checkbox_icons.png",
+			"icons":"smooth_assets/smooth_checkbox_icons.png",
 			"margin":[8,0,0,0]
 		},
 
@@ -197,7 +197,7 @@
             "margin":[0,0,-1,0],
 			"padding":[16,5,16,7],
 			"backgroundColor":"#0000",
-			"skin":"smooth_assets/tabbutton_skin.png",
+			"skin":"smooth_assets/smooth_tabbutton_skin.png",
 			"textColor":"text-background",
 			"states":{
 				"hover":{
@@ -205,7 +205,7 @@
 				"active":{
 				},
 				"selected":{
-                    "skin":"smooth_assets/tabbutton_selected_skin.png",
+                    "skin":"smooth_assets/smooth_tabbutton_selected_skin.png",
                     "padding":[16,5,16,9],
 					"border":[0],
 					"borderColor":"#507FDF",
@@ -214,9 +214,14 @@
 			}
 		},
 
+		"TabButtonLocked":{
+			"extends":"TabButton",
+			"skin":"smooth_assets/smooth_tabbutton_locked_skin.png"
+		},
+
 		"TabClose":{
 			"margin":[4,0,0,0],
-			"icons":"smooth_assets/tabclose_icons.png",
+			"icons":"smooth_assets/smooth_tabclose_icons.png",
 			"iconColor":"#373737",
 			"states":{
 				"hover":{

+ 1 - 1
assets/themes/theme-warm.json

@@ -54,7 +54,7 @@
 
 		"TabClose":{
 			"margin":[8,8,8,8 ],
-			"icons":"prime_assets/tabclose_icons.png",
+			"icons":"prime_assets/prime_tabclose_icons.png",
 			"iconColor":"text-disabled",
 			"states":{
 				"hover":{

+ 42 - 0
dialog/DialogExt.monkey2

@@ -7,14 +7,30 @@ Class DialogExt Extends Dialog
 	Field OnShow:Void()
 	Field OnHide:Void()
 	
+	Method New()
+		Super.New()
+	End
+	
+	Method New( title:String,contentView:View=Null )
+		Super.New( title,contentView )
+	End
+	
 	Property IsOpened:Bool()
 		Return _opened
 	End
 	
+	Property FadeEnabled:Bool()
+		Return _fadeEnabled
+	Setter( value:Bool )
+		_fadeEnabled=value
+	End
+	
 	Method Show()
 		
 		If _opened Return
 		_opened = True
+		
+		TryAddFade()
 		Open()
 		OnShow()
 	End
@@ -24,6 +40,8 @@ Class DialogExt Extends Dialog
 		If _opened Return False
 		
 		_opened = True
+		
+		TryAddFade()
 		Open()
 		OnShow()
 		
@@ -45,6 +63,13 @@ Class DialogExt Extends Dialog
 		If Not _opened Return
 		
 		_opened = False
+		
+		If _fadeView
+			Local wnd:=App.ActiveWindow
+			wnd.RemoveChildView( _fadeView )
+			_fadeView=Null
+		Endif
+		
 		Close()
 		OnHide()
 		
@@ -59,5 +84,22 @@ Class DialogExt Extends Dialog
 	
 	Field _opened:Bool
 	Field _wait:Future<Bool>
+	Field _fadeEnabled:Bool
+	Field _fadeView:View
+	
+	Method TryAddFade()
+		
+		If Not _fadeEnabled Return
+		
+		Local wnd:=App.ActiveWindow
+		_fadeView=New Label
+		_fadeView.Layout="float"
+		_fadeView.Gravity=New Vec2f
+		_fadeView.MinSize=wnd.Frame.Size
+		Local st:=_fadeView.Style.Copy()
+		st.BackgroundColor=New Color( 0,0,0,0.33 )
+		_fadeView.Style=st
+		wnd.AddChildView( _fadeView )
+	End
 	
 End

+ 1 - 1
dialog/GenerateClassDialog.monkey2

@@ -16,7 +16,7 @@ Class GenerateClassDialog Extends DialogExt
 		
 		Local dock:=New DockingView
 		
-		_codeView=New Ted2CodeTextView
+		_codeView=New Ted2CodeTextView( Ted2Document.Empty )
 		_codeView.FileType=".monkey2"
 		_codeView.MinSize=New Vec2i( 200,200 )
 		dock.AddView( _codeView,"bottom" )

+ 7 - 1
dialog/PrefsDialog.monkey2

@@ -79,6 +79,7 @@ Class PrefsDialog Extends DialogExt
 	Field _editorAutoIndent:CheckButton
 	Field _editorAutoPairs:CheckButton
 	Field _editorSurround:CheckButton
+	Field _editorShowParamsHint:CheckButton
 	
 	Field _mainToolBarVisible:CheckButton
 	Field _mainProjectIcons:CheckButton
@@ -123,6 +124,7 @@ Class PrefsDialog Extends DialogExt
 		Prefs.EditorAutoIndent=_editorAutoIndent.Checked
 		Prefs.EditorAutoPairs=_editorAutoPairs.Checked
 		Prefs.EditorSurroundSelection=_editorSurround.Checked
+		Prefs.EditorShowParamsHint=_editorShowParamsHint.Checked
 		
 		Prefs.MainToolBarVisible=_mainToolBarVisible.Checked
 		Prefs.MainProjectIcons=_mainProjectIcons.Checked
@@ -229,6 +231,9 @@ Class PrefsDialog Extends DialogExt
 		_editorSurround=New CheckButton( "Surround selected text with ~q~q, (), []" )
 		_editorSurround.Checked=Prefs.EditorSurroundSelection
 		
+		_editorShowParamsHint=New CheckButton( "Show parameters hint" )
+		_editorShowParamsHint.Checked=Prefs.EditorShowParamsHint
+		
 		Local path:=Prefs.EditorFontPath
 		If Not path Then path=_defaultFont
 		_editorFontPath=New TextFieldExt( "" )
@@ -281,6 +286,7 @@ Class PrefsDialog Extends DialogExt
 		docker.AddView( _editorAutoIndent,"top" )
 		docker.AddView( _editorAutoPairs,"top" )
 		docker.AddView( _editorSurround,"top" )
+		docker.AddView( _editorShowParamsHint,"top" )
 		docker.AddView( New Label( " " ),"top" )
 		
 		Return docker
@@ -414,7 +420,7 @@ Class PrefsDialog Extends DialogExt
 		Local docker1:=New DockingView
 		docker1.AddView( treeDock,"left","170",True)
 		
-		_codeView=New Ted2CodeTextView
+		_codeView=New Ted2CodeTextView( Ted2Document.Empty )
 		_codeView.ShowWhiteSpaces=True
 		_codeView.Document.TextChanged+=Lambda()
 			

+ 47 - 54
dialog/UpdateModulesDialog.monkey2

@@ -1,9 +1,9 @@
-Namespace ted2go
 
+Namespace ted2go
 
 Class UpdateModulesDialog Extends DialogExt
 	
-	Method New( targets:StringStack,selectedModules:String,configs:String,clean:Bool )
+	Method New( targets:StringStack,selectedTargets:String,selectedModules:String,configs:String,clean:Bool )
 		
 		_modsNames.Clear()
 		GetModulesNames( _modsNames )
@@ -53,13 +53,15 @@ Class UpdateModulesDialog Extends DialogExt
 		dock.AddView( table,"top" )
 		dock.AddView( New Label( " " ),"top" )
 		
+		Local selTargets:=New StringStack( selectedTargets.Split( " " ) )
+		
 		dock.AddView( New Label( "Targets:" ),"top" )
 		Local targetDock:=New DockingView
 		For Local t:=Eachin targets
 			Local chb:=New CheckButton( t )
 			targetDock.AddView( chb,"left" )
 			_targetsViews.Add( chb )
-			chb.Checked=(t="desktop")
+			chb.Checked=selTargets.Contains( t )
 		Next
 		dock.AddView( targetDock,"top" )
 		dock.AddView( New Label( " " ),"top" )
@@ -171,11 +173,17 @@ Class UpdateModulesDialog Extends DialogExt
 	This sorts modules into dependancy order.
 	
 	#end
-	Function EnumModules( out:StringStack,cur:String,deps:StringMap<StringStack> )
-		If out.Contains( cur ) Return
+	Function EnumModules( out:StringStack,cur:String,src:String,deps:StringMap<StringStack> )
 		
+		If Not deps.Contains( cur )
+'			Print "Can't find module dependancy '"+cur+"' - check module.json file for '"+src+"'"
+			Return
+		End
+		
+		If out.Contains( cur ) Return
+
 		For Local dep:=Eachin deps[cur]
-			EnumModules( out,dep,deps )
+			EnumModules( out,dep,cur,deps )
 		Next
 		
 		out.Push( cur )
@@ -183,43 +191,46 @@ Class UpdateModulesDialog Extends DialogExt
 	
 	Function EnumModules:String[]()
 	
+		LoadEnv()
+		
 		Local mods:=New StringMap<StringStack>
 		
-		Local modsPath:=MainWindow.ModsPath
+		For Local moddir:=Eachin ModuleDirs
 	
-		For Local f:=Eachin LoadDir( modsPath )
-		
-			Local dir:=modsPath+f+"/"
-			If GetFileType( dir )<>FileType.Directory Continue
-			
-			Local str:=LoadString( dir+"module.json" )
-			If Not str Continue
-			
-			Local obj:=JsonObject.Parse( str )
-			If Not obj 
-				Print "Error parsing json:"+dir+"module.json"
-				Continue
-			Endif
-			
-			Local name:=obj["module"].ToString()
-			If name<>f Continue
-			
-			Local deps:=New StringStack
-			If name<>"monkey" deps.Push( "monkey" )
+			For Local f:=Eachin LoadDir( moddir )
 			
-			Local jdeps:=obj["depends"]
-			If jdeps
-				For Local dep:=Eachin jdeps.ToArray()
-					deps.Push( dep.ToString() )
-				Next
-			Endif
-			
-			mods[name]=deps
+				Local dir:=moddir+f+"/"
+				If GetFileType( dir )<>FileType.Directory Continue
+				
+				Local str:=LoadString( dir+"module.json" )
+				If Not str Continue
+				
+				Local obj:=JsonObject.Parse( str )
+				If Not obj 
+					Print "Error parsing json:"+dir+"module.json"
+					Continue
+				Endif
+				
+				Local name:=obj["module"].ToString()
+				If name<>f Continue
+				
+				Local deps:=New StringStack
+				If name<>"monkey" deps.Push( "monkey" )
+				
+				Local jdeps:=obj["depends"]
+				If jdeps
+					For Local dep:=Eachin jdeps.ToArray()
+						deps.Push( dep.ToString() )
+					Next
+				Endif
+				
+				mods[name]=deps
+			Next
 		Next
-		
+				
 		Local out:=New StringStack
 		For Local cur:=Eachin mods.Keys
-			EnumModules( out,cur,mods )
+			EnumModules( out,cur,"",mods )
 		Next
 		
 		Return out.ToArray()
@@ -230,22 +241,4 @@ Class UpdateModulesDialog Extends DialogExt
 		out.AddAll( EnumModules() )
 	End
 
-#rem	
-	Function GetModulesNames( out:StringStack )
-	
-		Local modsPath:=MainWindow.ModsPath
-	
-		Local dd:=LoadDir( modsPath )
-	
-		For Local d:=Eachin dd
-			If GetFileType( modsPath+d ) = FileType.Directory
-				Local file:=modsPath + d + "/module.json"
-				If GetFileType( file ) = FileType.File
-					out.Add( d )
-				Endif
-			Endif
-		Next
-	End
-#end
-	
 End

+ 18 - 12
document/BananasDocument.monkey2

@@ -21,8 +21,11 @@ Class BananasDocument Extends Ted2Document
 		_table.Gravity=New Vec2f( 0.5,0 )
 		scrollView.ContentView=_table
 		
-		_filterPanel=New ToolBar
-		scrollView.AddView( _filterPanel,"bottom" )
+		_filterPanel=New ToolBarExt
+		Local sbox:=New ScrollViewTabs( _filterPanel )
+		sbox.ScrollBarsVisible=False
+		
+		scrollView.AddView( sbox,"bottom" )
 		
 		Local lab:=New Label( "Bananas Showcase" )
 		lab.Style=App.Theme.GetStyle( "BananasTitle" )
@@ -31,6 +34,9 @@ Class BananasDocument Extends Ted2Document
 		scrollView.AddView( lab,"top" )
 		
 		_list=New ListView
+		Local st:=_list.Style.Copy()
+		st.Padding=New Recti( -6,-6,6,6 )
+		_list.Style=st
 		_list.ItemDoubleClicked+=Lambda( item:ListView.Item )
 			
 			OpenItem( FindItem( item.Text ) )
@@ -64,8 +70,8 @@ Class BananasDocument Extends Ted2Document
 	Private
 	
 	Const EMPTY_TAG:="#"
-	Const MAX_WIDTH:=300
-	Const MAX_HEIGHT:=200
+	Const MAX_WIDTH:=256
+	Const MAX_HEIGHT:=196
 	Field _list:ListView
 	Field _table:TableView
 	Field _view:View
@@ -75,7 +81,7 @@ Class BananasDocument Extends Ted2Document
 	Field _tags:=New StringStack
 	Field _filterTags:=New StringStack
 	Field _filterViews:=New Stack<ToolButtonExt>
-	Field _filterPanel:ToolBar
+	Field _filterPanel:ToolBarExt
 	
 	Struct Item
 		
@@ -353,13 +359,13 @@ Class BananasDocument Extends Ted2Document
 		If item.author Then dock.AddView( New Label( item.author ),"top" )
 		
 		' version and modified
-		Local vers:=item.version
-		If vers Then vers="v"+vers
-		If item.modified
-			If vers Then vers+=" at "
-			vers+=item.modified
-		Endif
-		If vers Then dock.AddView( New Label( vers ),"top" )
+'		Local vers:=item.version
+'		If vers Then vers="v"+vers
+'		If item.modified
+'			If vers Then vers+=" at "
+'			vers+=item.modified
+'		Endif
+'		If vers Then dock.AddView( New Label( vers ),"top" )
 		
 		'tags
 		If item.tags Then dock.AddView( New Label( item.tags ),"top" )

+ 441 - 49
document/CodeDocument.monkey2

@@ -32,16 +32,13 @@ Class CodeDocumentView Extends Ted2CodeTextView
 	
 	
 	Method New( doc:CodeDocument )
-	
+		
+		Super.New( doc )
+		
 		_doc=doc
 		
 		ContentView.Style.Border=New Recti( -4,-4,4,4 )
 		
-		'very important to set FileType for init
-		'formatter, highlighter and keywords
-		FileType=doc.FileExtension
-		FilePath=doc.Path
-		
 		'AutoComplete
 		If Not AutoComplete Then AutoComplete=New AutocompleteDialog
 		AutoComplete.OnChoosen+=Lambda( result:AutocompleteResult )
@@ -117,12 +114,14 @@ Class CodeDocumentView Extends Ted2CodeTextView
 		_doc.ArrangeElements()
 	End
 	
-
+	
 	Protected
 	
 	Method OnThemeChanged() Override
 		
-		_doc.HideAutocomplete()
+		_doc.HideAllPopups()
+		
+		Super.OnThemeChanged()
 	End
 	
 	Method OnRenderContent( canvas:Canvas ) Override
@@ -177,6 +176,7 @@ Class CodeDocumentView Extends Ted2CodeTextView
 		Local alt:=(event.Modifiers & Modifier.Alt)
 		Local ctrl:=(event.Modifiers & Modifier.Control)
 		Local shift:=(event.Modifiers & Modifier.Shift)
+		Local menu:=(event.Modifiers & Modifier.Menu)
 		
 		'ctrl+space - show autocomplete list
 		Select event.Type
@@ -185,7 +185,19 @@ Class CodeDocumentView Extends Ted2CodeTextView
 			Local key:=FixNumpadKeys( event )
 			
 			Select key
-			
+				
+'				#If __TARGET__="macos"
+'				Case Key.K
+'					If ctrl 
+'						If shift
+'							DeleteLineAtCursor()
+'						Else
+'							DeleteToEnd()
+'						Endif
+'						Return
+'					Endif
+'				#Endif
+				
 				Case Key.Space
 					If ctrl
 						Return
@@ -207,17 +219,27 @@ Class CodeDocumentView Extends Ted2CodeTextView
 						
 					Else
 						
-						#If __TARGET__="macos"
-						If ctrl
-							DeleteLineAtCursor()
-						Endif
-						#Endif
+'						#If __TARGET__="macos"
+'						If menu
+'							DeleteToBegin()
+'						Elseif ctrl
+'							DeleteWordBeforeCursor()
+'						Endif
+'						#Else
+'						If ctrl
+'							If shift
+'								DeleteToBegin()
+'							Else
+'								DeleteWordBeforeCursor()
+'							Endif
+'						Endif
+'						#Endif
 						
 					Endif
 				
-				Case Key.F11
-				
-					ShowJsonDialog()
+				'Case Key.F11
+				'
+				'	ShowJsonDialog()
 					
 					
 				#If __TARGET__="windows"
@@ -261,7 +283,13 @@ Class CodeDocumentView Extends Ted2CodeTextView
 				Case Key.KeyDelete
 			
 					If shift 'shift+del - cut selected
-						If CanCopy Then OnCut()
+						If ctrl
+'							DeleteToEnd()
+						Elseif CanCopy
+							OnCut()
+						Endif
+'					Else If ctrl 'ctrl w/o shift
+'						DeleteWordAfterCursor()
 					Else
 						If Anchor = Cursor
 							Local len:=Text.Length
@@ -745,16 +773,6 @@ Class CodeDocumentView Extends Ted2CodeTextView
 		Return False
 	End
 	
-	Method DeleteLineAtCursor()
-		
-		Local line:=Document.FindLine( Cursor )
-		Local pos:=Cursor
-		SelectText( Document.StartOfLine( line ),Document.EndOfLine( line )+1 )
-		ReplaceText( "" )
-		pos=Min( pos,Document.EndOfLine( line ) )
-		SelectText( pos,pos )
-	End
-	
 End
 
 
@@ -763,7 +781,14 @@ Class CodeDocument Extends Ted2Document
 	Method New( path:String )
 		
 		Super.New( path )
-	
+		
+		' if file type was changed
+		Renamed+=Lambda( newPath:String,oldPath:String )
+			
+			InitParser()
+			ResetErrors()
+		End
+		
 		_view=New DockingView
 		
 		' Editor
@@ -797,11 +822,14 @@ Class CodeDocument Extends Ted2Document
 		End
 		
 		_doc.TextChanged+=Lambda()
+		
 			Dirty=True
 			OnTextChanged()
 			_codeView.TextChanged()
 		End
 		
+		_codeView.CursorMoved+=OnCursorChanged
+		
 		' bar + editor
 		_content=New DockingView
 		_content.ContentView=_codeView
@@ -817,9 +845,9 @@ Class CodeDocument Extends Ted2Document
 		End
 		
 		' update 
-		Monkey2Parser.OnDoneParseModules+=Lambda( deltaMs:Int )
-			UpdateCodeTree()
-		End
+'		Monkey2Parser.OnDoneParseModules+=Lambda( deltaMs:Int )
+'			UpdateCodeTree()
+'		End
 		
 		ArrangeElements()
 	End
@@ -899,13 +927,15 @@ Class CodeDocument Extends Ted2Document
 		
 		If FileExtension <> ".monkey2" Return ident
 		
-		If ident <> text And item And item.IsLikeFunc 'not a keyword
+		If ident<>text And item And item.IsLikeFunc 'not a keyword
 			
 			Local i:=textLine.Find( "Method " ) 'to simplify overriding - insert full text
 			If i <> -1 And i < cursorPosInLine
 				Local i2:=textLine.Find( "(" ) 'is inside of params?
 				If i2 = -1 Or i2 > cursorPosInLine
-					Return text.StartsWith( "New(" ) ? text Else text+" Override"
+					Local ovr:=Not text.StartsWith( "New(" )
+					If ovr And item.Parent And item.Parent.Kind=CodeItemKind.Interface_ Then ovr=False
+					Return ovr ? text+" Override" Else text
 				Endif
 			Endif
 			
@@ -1008,6 +1038,7 @@ Class CodeDocument Extends Ted2Document
 	End
 	
 	Property HasErrors:Bool()
+		
 		Return Not _errors.Empty
 	End
 	
@@ -1106,6 +1137,8 @@ Class CodeDocument Extends Ted2Document
 		
 		If ident = "" Then ident=_codeView.IdentBeforeCursor()
 		
+		Print "ident: "+ident
+		
 		'show
 		Local lineNum:=TextDocument.FindLine( _codeView.Cursor )
 		Local lineStr:=TextDocument.GetLine( lineNum )
@@ -1145,7 +1178,14 @@ Class CodeDocument Extends Ted2Document
 	End
 	
 	Function HideAutocomplete()
-		If AutoComplete AutoComplete.Hide()
+	
+		AutoComplete?.Hide()
+	End
+	
+	Function HideAllPopups()
+	
+		AutoComplete?.Hide()
+		ParamsHint?.Hide()
 	End
 	
 	Method GoBack()
@@ -1296,9 +1336,9 @@ Class CodeDocument Extends Ted2Document
 		Local text:=stringio.LoadString( Path )
 		
 		_doc.Text=text
+		Dirty=False
 		
-		_parser=ParsersManager.Get( FileExtension )
-		_parsingEnabled=Not ParsersManager.IsFake( _parser )
+		InitParser()
 		
 		ParsingDoc() 'start parsing right after loading, not by timer
 		
@@ -1313,7 +1353,7 @@ Class CodeDocument Extends Ted2Document
 	
 	Method OnSave:Bool() Override
 	
-		ResetErrors()
+		'ResetErrors()
 		
 		Local text:=_doc.Text
 		
@@ -1343,7 +1383,7 @@ Class CodeDocument Extends Ted2Document
 	
 	Method OnUpdateCurrentScope()
 		
-		Local scope:=_parser.GetScope( Path,_codeView.LineNumAtCursor+1 )
+		Local scope:=_parser.GetNearestScope( Path,_codeView.LineNumAtCursor+1,True )
 		If scope
 			_treeView.SelectByScope( scope )
 		Endif
@@ -1355,8 +1395,14 @@ Class CodeDocument Extends Ted2Document
 		OnUpdateCurrentScope()
 	End
 	
-	Field _timeTextChanged:=0
+	Method InitParser()
+		
+		_parser=ParsersManager.Get( FileExtension )
+		_parsingEnabled=Not ParsersManager.IsFake( _parser )
+	End
+	
 	Field _timeDocParsed:=0
+	Field _timeTextChanged:=0
 	Method ParsingOnTextChanged()
 		
 		If Not _parsingEnabled Return
@@ -1385,15 +1431,18 @@ Class CodeDocument Extends Ted2Document
 		_parsing=True
 		
 		New Fiber( Lambda()
-		
-			Local tmp:=MainWindow.AllocTmpPath( "_mx2cc_parse_",".monkey2" )
-			Local file:=StripDir( Path )
 			
-			SaveString( _doc.Text,tmp )
+			Local dirty:=Dirty
+			
+			Local filePath:=Path
+			If dirty
+				filePath=MainWindow.AllocTmpPath( "_mx2cc_parse_",".monkey2" )
+				SaveString( _doc.Text,filePath )
+			Endif
 			
-			ParsingFile( tmp )
+			ParsingFile( filePath )
 		
-			DeleteFile( tmp )
+			If dirty Then DeleteFile( filePath )
 			
 			_parsing=False
 			
@@ -1409,7 +1458,7 @@ Class CodeDocument Extends Ted2Document
 		
 		ResetErrors()
 		
-		Local errors:=_parser.ParseFile( Path,pathOnDisk,False )
+		Local errors:=_parser.ParseFile( Path,pathOnDisk,"" )
 		
 		If MainWindow.IsTerminating Return
 		
@@ -1456,6 +1505,207 @@ Class CodeDocument Extends Ted2Document
 		
 	End
 	
+	Method OnCursorChanged()
+		
+		' try to show hint for method parameters
+		
+		If Not Prefs.EditorShowParamsHint Return
+		
+		Global _storedPos:=-1,_storedIdent:=""
+		Global opts:=New ParserRequestOptions
+		Global results:=New Stack<CodeItem>
+		
+		'If _codeView.CanCopy Print "can copy, exit" ; Return ' has selection
+		
+		Local line:=_codeView.LineTextAtCursor
+		Local pos:=_codeView.PosInLineAtCursor
+		Local lower:=line.Trim().ToLower()
+		Local skip:=lower.StartsWith( "function " ) Or lower.StartsWith( "method " ) Or 
+						lower.StartsWith( "operator " ) Or lower.StartsWith( "property " )
+		If Not skip
+			Local i1:=line.Find( "(" )
+			skip=(i1<0 Or i1>=pos)
+		Endif
+		If skip
+			ParamsHint?.Hide()
+			_storedPos=-1
+			Return
+		Endif
+		
+		Local brackets:=0,quotes:=0
+		Local part:ParamsPart
+		Local parts:=New Stack<ParamsPart>
+		
+		For Local i:=0 Until pos
+			Local c:=line[i]
+			Select c
+				Case Chars.OPENED_ROUND_BRACKET
+					
+					If quotes Mod 2 <> 0 Continue
+					
+					brackets+=1
+					' skip spaces
+					Local j:=i-1
+					While j>=0 And line[j]<=32
+						j-=1
+					Wend
+					j+=1
+					Local pair:=GetIndentBeforePos_Mx2( line,j,True )
+					Local ident:=pair.Item1
+					'Print "ident: "+ident'+", paramIndex: "+paramIndex+", isNew: "+isNew
+					If ident
+						part=New ParamsPart
+						parts.Add( part )
+						part.ident=ident
+						part.ranges=New Stack<Vec2i>
+						part.ranges.Add( New Vec2i( i,0 ) )
+						
+						' check for 'New' keyword
+						j=pair.Item2-1 'where ident starts
+						While j>=0 And line[j]<=32
+							j-=1
+						Wend
+						'j+=1
+						Local s:=""
+						While j>=0 And IsAlpha( line[j] )
+							s=String.FromChar( line[j] )+s
+							j-=1
+						Wend
+						part.isNew=(s.ToLower()="new")
+					Endif
+					
+				Case Chars.CLOSED_ROUND_BRACKET
+					
+					If quotes Mod 2 <> 0 Continue
+					
+					brackets-=1
+					If brackets>0 And brackets<parts.Length
+						part=parts[brackets-1]
+						Local r:=part.current
+						r.y=i
+						part.current=r
+					Endif
+					
+				Case Chars.DOUBLE_QUOTE
+					
+					quotes+=1
+					
+				Case Chars.SINGLE_QUOTE 'comment char
+					
+					If quotes Mod 2 = 0
+						Exit
+					Endif
+					
+				Case Chars.COMMA
+					
+					If quotes Mod 2 = 0 And part<>Null
+						Local r:=part.current
+						r.y=i
+						part.current=r
+						r=New Vec2i( i+1,0 )
+						part.ranges.Add( r )
+						part.index+=1
+					Endif
+					
+			End
+		Next
+		
+		If brackets<=0 Or 	' outside of brackets
+			part=Null 		' found brackets w/o idents - in expressions
+			
+			ParamsHint?.Hide()
+			_storedPos=-1
+			Return
+		Endif
+		
+'		Local i:=brackets-1
+'		While part And _codeView.Keywords.Contains( part.ident )
+'			i-=1
+'			If i>=0
+'				Print "part: "+part.ident+", "+i
+'				part=parts[i]
+'			Else
+'				Return 'exit
+'			Endif
+'		Wend
+		
+		'If ident<>_storedIdent 'Or bracketPos<>_storedPos
+			
+			Local ident:=part.ident
+			Local paramIndex:=part.index
+			Local isNew:=part.isNew
+			
+			_storedIdent=ident
+			'_storedPos=bracketPos
+			
+			opts.ident=ident
+			opts.filePath=Path
+			opts.docLineNum=_codeView.LineNumAtCursor
+			opts.docLineStr=line
+			opts.docPosInLine=pos
+			opts.results=results
+			
+			results.Clear()
+			
+			If isNew
+				
+				Local item:=_parser.GetItem( ident )
+				If item Then _parser.GetConstructors( item,results )
+				
+			Else
+				
+				_parser.GetItemsForAutocomplete( opts )
+				
+				Local parts:=ident.Split( "." )
+				Local last:=parts[parts.Length-1]
+				
+				Local it:=results.All()
+				While Not it.AtEnd
+					If it.Current.Ident<>last
+						it.Erase()
+					Else
+						it.Bump()
+					Endif
+				Wend
+			Endif
+			
+			If results.Empty
+				ParamsHint?.Hide()
+				_storedPos=-1
+				Return
+			Endif
+			
+			If Not ParamsHint Then ParamsHint=New ParamsHintView
+			
+			Local startPos:=_codeView.StartOfLineAtCursor+part.ranges[0].x
+			Local r:=_codeView.CharRect( startPos )
+			Local location:=r.min-_codeView.Scroll
+			location.x+=80*App.Theme.Scale.x
+			
+			ParamsHint.Show( results,location,_codeView )
+			
+		'Else
+		'	Print "the same"
+		'Endif
+		
+		ParamsHint?.SetIndex( paramIndex )
+	End
+	
+	Class ParamsPart
+		
+		Field ident:String
+		Field ranges:=New Stack<Vec2i>
+		Field index:Int
+		Field isNew:Bool
+		
+		Property current:Vec2i()
+			Return ranges[index]
+		Setter( value:Vec2i )
+			ranges[index]=value
+		End
+	End
+	
+	
 	Method OnFindSelection()
 		MainWindow.OnFind()
 	End
@@ -1511,11 +1761,11 @@ Class CodeDocumentType Extends Ted2DocumentType
 	End
 	
 	Method OnCreateDocument:Ted2Document( path:String ) Override
-
+		
 		Return New CodeDocument( path )
 	End
 	
-		
+	
 	Private
 	
 	Global _instance:=New CodeDocumentType
@@ -1748,3 +1998,145 @@ Function ScaledVal:Int( val:Int )
 	
 	Return val*App.Theme.Scale.x
 End
+
+
+Global ParamsHint:ParamsHintView
+
+Class ParamsHintView Extends TextView
+
+	Method New()
+		
+		Style=GetStyle( "ParamsHint" )
+		ReadOnly=True
+		Visible=False
+		Layout="float"
+		Gravity=New Vec2f( 0,1 )
+		
+		MainWindow.AddChildView( Self )
+		
+		OnThemeChanged()
+	End
+	
+	Method Show( items:Stack<CodeItem>,location:Vec2i,sender:CodeTextView )
+		
+		Hide()
+		
+		_items=items
+		_sender=sender
+		
+		Local s:=""
+		For Local i:=Eachin _items
+			If s Then s+="~n"
+			Local params:=i.Params
+			If Not params Then s+="<no params>" ; Continue
+			For Local j:=0 Until params.Length
+				If j>0 Then s+=", "
+				s+=params[j].ToString()
+			Next
+		Next
+		Text=s ' use it for TextView.OnMeasure
+		
+		Visible=True
+		
+		Local window:=sender.Window
+		
+		location=sender.TransformPointToView( location,window )
+		'Local dy:=New Vec2i( 0,-10 )
+		
+		' fit into window area
+'		Local size:=MeasureLayoutSize()
+'		Local dx:=location.x+size.x-window.Bounds.Right
+'		If dx>0
+'			location=location-New Vec2i( dx,0 )
+'		Endif
+'		If location.y+size.y+dy.y>window.Bounds.Bottom
+'			location=location-New Vec2i( 0,size.y )
+'			'dy=-dy
+'		Endif
+		Offset=location'+dy
+		
+	End
+	
+	Method Hide()
+		
+		Visible=False
+	End
+	
+	Method SetIndex( index:Int )
+		
+		_paramIndex=index
+	End
+	
+	Private
+	
+	Field _items:Stack<CodeItem>
+	Field _paramIndex:Int
+	Field _color1:Color,_color2:Color
+	Field _sender:CodeTextView
+	
+	Method OnRenderContent( canvas:Canvas ) Override
+		
+		Local stored:=canvas.Color
+		
+		Local x:Float,y:Float,s:=""
+		Local font:=RenderStyle.Font
+		For Local item:=Eachin _items
+			
+			Local params:=item.Params
+			If Not params
+				s="<no params>"
+				canvas.Color=(_paramIndex=0) ? _color2 Else _color1
+				canvas.DrawText( s,x,y )
+			Else
+				For Local i:=0 Until params.Length
+					
+					If i>0
+						canvas.Color=_color1
+						canvas.DrawText( ", ",x,y )
+						x+=font.TextWidth( ", " )
+					Endif
+					
+					s=params[i].ToString()
+					canvas.Color=(i=_paramIndex) ? _color2 Else _color1
+					canvas.DrawText( s,x,y )
+					x+=font.TextWidth( s )
+				Next
+				
+			Endif
+			
+			y+=font.Height
+			x=0
+		Next
+		
+		canvas.Color=stored
+	End
+	
+	Method OnThemeChanged() Override
+		
+		_color1=App.Theme.GetColor( "params-hint-common" )
+		_color2=App.Theme.GetColor( "params-hint-selected" )
+	End
+	
+	Method OnContentMouseEvent( event:MouseEvent ) Override
+		
+		If event.Type=EventType.MouseDown
+			
+'			Print App.MouseLocation
+'			Local me:=New MouseEvent( event.Type,_sender,App.MouseLocation,event.Button,event.Wheel,event.Modifiers,event.Clicks )
+'			CodeTextView_Bridge.OnContentMouseEvent( _sender,me )
+			
+			Hide()
+		Endif
+		
+	End
+	
+End
+
+'Class CodeTextView_Bridge Extends CodeTextView Final
+'	
+'	Function OnContentMouseEvent( view:CodeTextView,event:MouseEvent )
+'		
+'		view.OnContentMouseEvent( event )
+'	End
+'	
+'End

+ 54 - 21
document/DocumentManager.monkey2

@@ -87,10 +87,46 @@ Class DocumentManager
 	End
 	
 	Property OpenDocuments:Ted2Document[]()
-	
+		
 		Return _openDocs.ToArray()
 	End
 	
+	Property CurrentDocumentLabel:String()
+		
+		Return DocumentLabel( CurrentDocument )
+	End
+	
+	Method DocumentLabel:String( doc:Ted2Document )
+		
+		If Not doc Return ""
+		
+		Local label:=StripDir( doc.Path )
+	
+		If ExtractExt( doc.Path ).ToLower()=".monkey2"  label=StripExt( label )
+	
+		label=doc.State+label
+	
+		If doc.Dirty label+="*"
+	
+		Return label
+	End
+	
+	Method UpdateCurrentTabLabel()
+		
+		Local doc:=CurrentDocument
+		If doc _tabView.SetTabText( doc.View,DocumentLabel( doc ) )
+	End
+	
+	Method IsDocumentOpened:Bool( path:String )
+		
+		For Local i:=Eachin _openDocs
+			
+			If i.Path=path Return True
+		Next
+		
+		Return False
+	End
+	
 	Method OpenDocument:Ted2Document( path:String,makeCurrent:Bool=False,openByHand:Bool=True )
 	
 		path=RealPath( path )
@@ -110,10 +146,17 @@ Class DocumentManager
 		If Not doc.Load() Return Null
 
 		InitDoc( doc )
-	
-		_openDocs.Add( doc )
+		
 		Local addAtBegin:=(openByHand And Prefs.MainPlaceDocsAtBegin)
-		Local tab:=_tabView.AddTab( TabText( doc ),doc.View,False,addAtBegin )
+		
+		If addAtBegin
+			_openDocs.Insert( 0,doc )
+		Else
+			_openDocs.Add( doc )
+		Endif
+		
+		Local tab:=_tabView.AddTab( DocumentLabel( doc ),doc.View,False,addAtBegin )
+		
 		tab.DoubleClicked+=Lambda()
 			DocumentDoubleClicked( doc )
 		End
@@ -148,12 +191,14 @@ Class DocumentManager
 			Endif
 			
 			Local newDoc:=newType.CreateDocument( newPath )
-			If Not newDoc.Load() Return Null
+			If Not newDoc.Load()
+				Return Null
+			Endif
 			
 			InitDoc( newDoc )
 			
 			_openDocs[i]=newDoc
-			_tabView.SetTabText( i,TabText( newDoc ) )
+			_tabView.SetTabText( i,DocumentLabel( newDoc ) )
 			_tabView.SetTabView( i,newDoc.View )
 			
 			doc.Close()
@@ -163,7 +208,7 @@ Class DocumentManager
 			DocumentAdded( newDoc )
 			
 			If doc=_currentDoc CurrentDocument=newDoc
-
+			
 			Return newDoc
 		Next
 		
@@ -246,6 +291,7 @@ Class DocumentManager
 	End
 
 	Method Update()
+		
 		nextDocument.Enabled=_openDocs.Length>1
 		prevDocument.Enabled=_openDocs.Length>1
 	End
@@ -301,22 +347,9 @@ Class DocumentManager
 		Endif
 	End
 	
-	Method TabText:String( doc:Ted2Document )
-	
-		Local label:=StripDir( doc.Path )
-		
-		If ExtractExt( doc.Path ).ToLower()=".monkey2"  label=StripExt( label )
-		
-		label=doc.State+label
-		
-		If doc.Dirty label+="*"
-		
-		Return label
-	End
-	
 	Method UpdateTabLabel( doc:Ted2Document )
 	
-		If doc _tabView.SetTabText( doc.View,TabText( doc ) )
+		If doc _tabView.SetTabText( doc.View,DocumentLabel( doc ) )
 	End
 	
 	Method UpdateWindowTitle( doc:Ted2Document )

+ 59 - 4
document/JsonDocument.monkey2

@@ -7,12 +7,30 @@ Class JsonDocument Extends Ted2Document
 	Method New( path:String )
 		Super.New( path )
 		
-		_doc=New TextDocument
+		_view=New JsonDocumentView( Self )
 		
-		_view=New TextView( _doc )
+		_doc=_view.Document
 		
 		_browser=New JsonTreeView
-
+		
+		_browser.NodeClicked+=Lambda( node:TreeView.Node )
+			
+			Local i:=FindInText( node,-1 )
+			
+			If i=-1 Return
+			
+			Local from:=Min( _view.Cursor,_view.Anchor )
+			
+			If i=from
+				i=FindInText( node,from )
+				If i=-1 Return
+			Endif
+			
+			Local name:=node.Text.Slice( 0,node.Text.Find( ":" ) )
+			_view.SelectText( i,i+name.Length+2 ) '2 for quotes
+			_view.MakeCentered()
+		End
+		
 		_doc.TextChanged+=Lambda()
 		
 			_browser.Value=JsonValue.Parse( _doc.Text )
@@ -59,11 +77,38 @@ Class JsonDocument Extends Ted2Document
 	
 	Field _doc:TextDocument
 	
-	Field _view:TextView
+	Field _view:JsonDocumentView
 	
 	Field _browser:JsonTreeView
+	
+	Method FindInText:Int( node:TreeView.Node,fromIndex:Int )
+		
+		Local nodes:=New Stack<TreeView.Node>
+		While node And node.Text.Contains( ":" )
+			If node.Text.Contains( ":[" )
+				' skip array indexing nodes
+				nodes.Erase( 0 )
+			Endif
+			nodes.Insert( 0,node )
+			node=node.Parent
+		Wend
+		
+		Local index:=fromIndex
+		For Local n:=Eachin nodes
+			Local s:=n.Text
+			Local i:=s.Find( ":" )
+			Local name:="~q"+s.Slice( 0,i )+"~q"
+			i=_view.Text.Find( name,index+1 )
+			If i=-1 Return -1
+			index=i
+		Next
+		
+		Return index
+	End
+	
 End
 
+
 Class JsonDocumentType Extends Ted2DocumentType
 
 	Protected
@@ -84,3 +129,13 @@ Class JsonDocumentType Extends Ted2DocumentType
 	Global _instance:=New JsonDocumentType
 	
 End
+
+
+Class JsonDocumentView Extends Ted2CodeTextView
+	
+	Method New( doc:Ted2Document )
+		
+		Super.New( doc )
+	End
+	
+End

+ 28 - 22
document/Ted2Document.monkey2

@@ -3,18 +3,22 @@ Namespace ted2go
 
 
 Class Ted2Document
-
+	
+	Const Empty:=New Ted2Document("")
+	
 	Field DirtyChanged:Void()
 	
 	Field StateChanged:Void()
 
 	Field Closed:Void()
+	
+	Field Renamed:Void( newPath:String,oldPath:String )
 
 	Method New( path:String )
 	
 		_path=path
 		_fileExt=ExtractExt( _path )
-				
+		
 		_modTime=GetFileTime( _path )
 	End
 	
@@ -23,7 +27,7 @@ Class Ted2Document
 		Return _path
 	End
 	
-	Property FileExtension:String()'file extension
+	Property FileExtension:String()
 		
 		Return _fileExt
 	End
@@ -106,11 +110,17 @@ Class Ted2Document
 		Return True
 	End
 
-	'DON'T USE YET!	
 	Method Rename( path:String )
+		
+		If path=_path Return
+		
+		Local old:=_path
 		_path=path
+		_fileExt=ExtractExt( _path )
 		
 		Dirty=True
+		
+		Renamed( path,old )
 	End
 	
 	Method Close()
@@ -173,11 +183,11 @@ Class Ted2DocumentType Extends Plugin
 		ext=ext.ToLower()
 
 		Local types:=Plugin.PluginsOfType<Ted2DocumentType>()
-		Local defaultType:Ted2DocumentType = Null
+		Local defaultType:Ted2DocumentType=Null
 		
 		For Local type:=Eachin types
 		
-			For Local ext2:=Eachin type.Extensions	'Array.Contains() would be nice!
+			For Local ext2:=Eachin type.Extensions
 			
 				If ext=ext2 Return type
 				If ext2 = ".*" Then defaultType = type
@@ -185,9 +195,7 @@ Class Ted2DocumentType Extends Plugin
 			
 		Next
 		
-		If defaultType <> Null Return defaultType 'use it if there is no registered extension
-		
-		Return Null
+		Return defaultType 'use it if there is no registered extension
 	End
 	
 	Method CreateDocument:Ted2Document( path:String )
@@ -204,25 +212,23 @@ Class Ted2DocumentType Extends Plugin
 	
 	Property Extensions:String[]()
 	
-		Return _exts
+		Return _exts.ToArray()
 	
 	Setter( exts:String[] )
 	
-		_exts=exts
+		_exts.Clear()
+		_exts.AddAll( exts )
 	End
 	
 	Method AddExtensions( exts:String[] )
-		If _exts = Null
-			_exts=exts
-			Return
-		Endif
-		' check  for duplicates here?
-		Local arr:=New String[_exts.Length+exts.Length]
-		_exts.CopyTo( arr,0,0,_exts.Length )
-		exts.CopyTo( arr,0,_exts.Length,exts.Length )
-		_exts=arr
-	End
 		
+		For Local ext:=Eachin exts
+			If Not _exts.Contains( ext )
+				_exts.Add( ext )
+			Endif
+		Next
+	End
+	
 	Method OnCreateDocument:Ted2Document( path:String ) Virtual
 	
 		Return Null	'should return hex editor!
@@ -230,7 +236,7 @@ Class Ted2DocumentType Extends Plugin
 
 	Private
 	
-	Field _exts:String[]
+	Field _exts:=New StringStack
 	
 	
 End

+ 1 - 5
eventfilter/Monkey2KeyEventFilter.monkey2

@@ -23,11 +23,7 @@ Class Monkey2KeyEventFilter Extends TextViewKeyEventFilter
 				
 				Case Key.F1
 					
-					If ctrl
-						MainWindow.ShowFindInDocs()
-					Else
-						MainWindow.ShowQuickHelp()
-					Endif
+					MainWindow.ShowHelp( "",ctrl )
 					event.Eat()
 					
 				Case Key.F2

二進制
logo/resource_x64.o


+ 28 - 22
parser/CodeItem.monkey2

@@ -35,6 +35,7 @@ End
 Class CodeItem
 	
 	Field nspace:NSpace
+	Field isAlias:=False
 	
 	Method New( ident:String )
 		_ident=ident
@@ -124,6 +125,11 @@ Class CodeItem
 		
 	End
 	
+	Property NumChildren:Int()
+		
+		Return _children?.Length
+	End
+	
 	Property Children:Stack<CodeItem>()
 		Return _children
 	Setter( value:Stack<CodeItem> )
@@ -145,19 +151,13 @@ Class CodeItem
 		_namespace=value
 	End
 	
-	Property IsModuleMember:Bool()
+	Property ModuleName:String()
 		
-		If _isModuleMember=-1
-			Local p:=_parent
-			While p<>Null
-				_isModuleMember=p._isModuleMember
-				If _isModuleMember<>-1 Exit
-				p=p._parent
-			Wend
-		Endif
-		Return _isModuleMember=1 ? True Else False
-	Setter( value:Bool )
-		_isModuleMember=value ? 1 Else 0
+		Local s:=_modName
+		If Not s Then s=_parent?.ModuleName
+		Return s
+	Setter( value:String )
+		_modName=value
 	End
 	
 	Property FilePath:String()
@@ -200,13 +200,13 @@ Class CodeItem
 		item.Parent=Self
 	End
 	
-	Property SuperTypes:List<CodeType>()
+	Property SuperTypes:Stack<CodeType>()
 		Return _superTypes
-	Setter( value:List<CodeType> )
+	Setter( value:Stack<CodeType> )
 		_superTypes=value
 	End
 	
-	Property SuperTypesStr:List<String>()
+	Property SuperTypesStr:Stack<String>()
 		Return _superTypesStr
 	End
 	
@@ -232,14 +232,20 @@ Class CodeItem
 		_isExtension=value
 	End
 	
+	Property IsIfaceMember:Bool()
+		Return _isIfaceMember
+	Setter( value:Bool )
+		_isIfaceMember=value
+	End
+	
 	Method AddSuperType( type:CodeType )
-		If Not _superTypes Then _superTypes=New List<CodeType>
-		_superTypes.AddLast( type )
+		If Not _superTypes Then _superTypes=New Stack<CodeType>
+		_superTypes.Add( type )
 	End
 	
 	Method AddSuperTypeStr( type:String )
-		If Not _superTypesStr Then _superTypesStr=New List<String>
-		_superTypesStr.AddLast( type )
+		If Not _superTypesStr Then _superTypesStr=New Stack<String>
+		_superTypesStr.Add( type )
 	End
 	
 	Method FindParent:CodeItem( parentIdent:String )
@@ -309,12 +315,12 @@ Class CodeItem
 	Field _namespace:String
 	Field _filePath:String
 	Field _scopeStartPos:Vec2i=New Vec2i,_scopeEndPos:Vec2i=New Vec2i
-	Field _superTypes:List<CodeType>,_superTypesStr:List<String>
+	Field _superTypes:Stack<CodeType>,_superTypesStr:Stack<String>
 	Field _params:CodeParam[]
 	Field _paramsStr:String
-	Field _isModuleMember:=-1
 	Field _isExtension:Bool
-	
+	Field _isIfaceMember:Bool
+	Field _modName:String
 	
 	Private
 	

+ 132 - 46
parser/Monkey2Parser.monkey2

@@ -90,11 +90,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Return True
 	End
 	
-	Method ParseFile:String( filePath:String,pathOnDisk:String,isModule:Bool )
-		
-		If Not isModule
-			isModule=filePath.StartsWith( _modsPath )
-		Endif
+	Method ParseFile:String( filePath:String,pathOnDisk:String,moduleName:String )
 		
 		' is file modified?
 		Local time:=GetFileTime( pathOnDisk )
@@ -111,7 +107,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Endif
 		
 		' start parsing process
-		Local str:=StartParsing( pathOnDisk,isModule )
+		Local str:=StartParsing( pathOnDisk )
 		
 		If Not str Return "#" 'special kind of error
 		
@@ -138,7 +134,6 @@ Class Monkey2Parser Extends CodeParserPlugin
 		
 		Local nspace:= jobj.Contains( "namespace" ) ? jobj["namespace"].ToString() Else ""
 		
-		
 		If jobj.Contains( "members" )
 			Local items:=New Stack<CodeItem>
 			Local members:=jobj["members"].ToArray()
@@ -147,7 +142,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 			Items.AddAll( items )
 			
 			For Local i:=Eachin items
-				i.IsModuleMember=isModule
+				i.ModuleName=moduleName
 				NSpace.AddItem( nspace,i )
 			Next
 			'Print "file parsed: "+filePath+", items.count: "+items.Count()
@@ -169,7 +164,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 				Endif
 				file=folder+file
 				'Print "parse import: "+file+"  mod: "+Int(isModule)
-				ParseFile( file,file,isModule )
+				ParseFile( file,file,moduleName )
 			Next
 		Endif
 		
@@ -221,7 +216,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 			arr=endPos.Split( ":" )
 			item.ScopeEndPos=New Vec2i( Int(arr[0])-1,Int(arr[1]) )
 			item.Namespac=namespac
-			
+			item.IsIfaceMember=(flags & Flags.DECL_IFACEMEMBER <> 0)
 			'Print "parser. add item: "+item.Scope+" "+kind
 			
 			If kind="class" Or kind="struct" Or kind="interface" Or kind="enum"
@@ -254,6 +249,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 				' alias
 				If kind = "alias"
 					_aliases.Add( ident,item )
+					item.isAlias=True
 				End
 				
 			Endif
@@ -263,6 +259,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 				Local supIdent:=sup["ident"]
 				If supIdent Then item.AddSuperTypeStr( supIdent.ToString() )
 			Endif
+			
 			If jobj.Contains( "ifaceTypes" )
 				Local ifaces:=jobj["ifaceTypes"].ToArray()
 				For Local ifaceType:=Eachin ifaces
@@ -272,7 +269,6 @@ Class Monkey2Parser Extends CodeParserPlugin
 				Next
 			Endif
 			
-			
 			If parent
 				item.SetParent( parent )
 				If parent.IsExtension
@@ -318,7 +314,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Next
 		
 		If result
-			' try to check is we inside of method/ property / etc
+			' try to check - are we inside of method/ property / etc
 			Repeat
 				Local i:=GetInnerScope( result,docLine )
 				If i = Null Exit
@@ -343,6 +339,50 @@ Class Monkey2Parser Extends CodeParserPlugin
 		
 	End
 	
+	Method GetNearestScope:CodeItem( docPath:String,docLine:Int,above:Bool )
+	
+		Local items:=ItemsMap[docPath]
+	
+		If Not items Return Null
+	
+		' all classes / structs
+		Local fakeItem:=New CodeItem( "fake" )
+		fakeItem.Children=items
+'		For Local i:=Eachin items
+'			If docLine > i.ScopeStartPos.x And docLine < i.ScopeEndPos.x
+'				result=i
+'				Exit
+'			Endif
+'		Next
+		Local dir:=above ? -1 Else 1
+		Local result:=GetInnerScope( fakeItem,docLine )
+		
+		If result
+			' try to check - are we inside of method/ property / etc
+			Repeat
+				Local i:=GetInnerScope( result,docLine,dir )
+				If i = Null Exit
+				result=i
+			Forever
+	
+		Else
+			' try to find in extension members
+			For Local list:=Eachin ExtraItemsMap.Values
+				For Local i:=Eachin list
+					If i.FilePath<>docPath Continue
+					If docLine > i.ScopeStartPos.x And docLine < i.ScopeEndPos.x
+						result=i
+						Exit
+					Endif
+				Next
+				If result Exit
+			Next
+		End
+	
+		Return result
+	
+	End
+	
 	Method ItemAtScope:CodeItem( ident:String,filePath:String,docLine:Int )
 		
 		Local opts:=New ParserRequestOptions
@@ -351,7 +391,10 @@ Class Monkey2Parser Extends CodeParserPlugin
 		opts.filePath=filePath
 		opts.docLineNum=docLine
 		opts.usingsFilter=_lastUsingsFilter
+		opts.intelliIdent=False
+		
 		GetItemsInternal( opts,1 )
+		
 		Return (Not opts.results.Empty) ? opts.results[0] Else Null
 	End
 	
@@ -363,6 +406,9 @@ Class Monkey2Parser Extends CodeParserPlugin
 		For Local i:=Eachin Items
 			If i.Ident=ident Return i
 		Next
+		For Local i:=Eachin _aliases.Values
+			If i.Ident=ident Return i
+		Next
 		Return Null
 	End
 	
@@ -371,6 +417,33 @@ Class Monkey2Parser Extends CodeParserPlugin
 		GetItemsInternal( options )
 	End
 	
+	Method GetConstructors( item:CodeItem,target:Stack<CodeItem> )
+		
+		If item.isAlias
+			Local type:=item.Type?.ident
+			item=Self[type]
+			If Not item Return
+		Endif
+		
+		If Not item.IsLikeClass Print "not a class" ; Return
+		
+		If item.Children
+			For Local i:=Eachin item.Children
+		
+				If i.Ident.ToLower()="new"
+					target+=i
+				Endif
+			Next
+		Endif
+		
+'		If _superTypes
+'			For Local i:=Eachin _superTypes
+'		
+'			Next
+'		Endif
+		
+	End
+	
 	
 	Private
 	
@@ -395,6 +468,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Local docLineStr:=options.docLineStr
 		Local target:=options.results
 		Local usingsFilter:=options.usingsFilter
+		Local intelliIdent:=options.intelliIdent
 		
 		_lastUsingsFilter=usingsFilter
 		
@@ -442,7 +516,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 					
 					For Local i:=Eachin items
 						'Print "item at scope: "+i.Text
-						If Not CheckIdent( i.Ident,firstIdent,onlyOne )
+						If Not CheckIdent( i.Ident,firstIdent,onlyOne,intelliIdent )
 							'Print "cont1: "+i.Ident
 							Continue
 						Endif
@@ -513,7 +587,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 					Endif
 					
 					'Print "global 1: "+i.Scope
-					If Not CheckIdent( i.Ident,firstIdent,onlyOne )
+					If Not CheckIdent( i.Ident,firstIdent,onlyOne,intelliIdent )
 						'Print "skip 2 "+i.Ident
 						Continue
 					Endif
@@ -678,7 +752,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 						' skip constructors
 						If Not (isSelf Or isSuper) And i.Kind=CodeItemKind.Method_ And i.Ident="New" Continue
 						
-						If Not CheckIdent( i.Ident,identPart,last )
+						If Not CheckIdent( i.Ident,identPart,last,intelliIdent )
 							'Print "continue 1: "+i.Ident
 							Continue
 						Endif
@@ -767,7 +841,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Endif
 	End
 	
-	Method StartParsing:String( pathOnDisk:String,isModule:Bool )
+	Method StartParsing:String( pathOnDisk:String )
 		
 		If Not _enabled Return ""
 		
@@ -793,12 +867,12 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Next
 		
 		For Local d:=Eachin dirs
-			If GetFileType( _modsPath+d ) = FileType.Directory
+			If GetFileType( _modsPath+d )=FileType.Directory
 				Local file:=_modsPath + d + "/" + d + ".monkey2"
 				'Print "module: "+file
-				If GetFileType( file ) = FileType.File
+				If GetFileType( file )=FileType.File
 					OnParseModule( file )
-					ParseFile( file,file,True )
+					ParseFile( file,file,d )
 				Endif
 			Endif
 		Next
@@ -991,15 +1065,44 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Return type
 	End
 	
-	Method GetInnerScope:CodeItem( parent:CodeItem,docLine:Int )
+	Method GetInnerScope:CodeItem( parent:CodeItem,docLine:Int,dir:Int=0 )
 		
 		Local items:=parent.Children
-		If items = Null Return Null
+		If items=Null Return Null
+		
+		Local result:CodeItem=Null
+		Local storedPos:=dir>0 ? 999999999 Else -1
 		For Local i:=Eachin items
-			If docLine > i.ScopeStartPos.x And docLine < i.ScopeEndPos.x Return i
+			
+			If i.Kind=CodeItemKind.Param_ Continue
+			
+			Local i1:=i.ScopeStartPos.x
+			Local i2:=i.ScopeEndPos.x
+			
+			'inside
+			If docLine>i1 And docLine<=i2
+				result=i
+				Exit
+			Endif
+			
+			If dir=-1 ' above
+				
+				If docLine>i2 And i2>storedPos
+					result=i
+					storedPos=i2
+				Endif
+				
+			Elseif dir=1 ' below
+				
+				If docLine<i1 And i1<storedPos
+					result=i
+					storedPos=i1
+				Endif
+				
+			End
+			
 		Next
-		Return Null
-		
+		Return result
 	End
 	
 	Function CheckUsingsFilter:Bool( nspace:String,usingsFilter:StringStack )
@@ -1143,12 +1246,12 @@ Class Monkey2Parser Extends CodeParserPlugin
 		
 	End
 	
-	Method CheckIdent:Bool( ident1:String,ident2:String,startsOnly:Bool,smartStarts:Bool=True )
+	Method CheckIdent:Bool( ident1:String,ident2:String,startsOnly:Bool,intelliIdent:Bool=True )
 	
-		If ident2 = "" Return True
+		If ident2="" Return True
 		
 		If startsOnly
-			Return smartStarts ? CheckStartsWith( ident1,ident2 ) Else ident1.StartsWith( ident2 )
+			Return intelliIdent ? CheckStartsWith( ident1,ident2 ) Else ident1.StartsWith( ident2 )
 		Else
 			Return ident1 = ident2
 		Endif
@@ -1213,25 +1316,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 	
 	Method IsPosInsideOfQuotes:Bool( text:String,pos:Int )
 	
-		Local i:=0
-		Local n:=text.Length
-		if pos = 0 Return False
-		Local quoteCounter:=0
-		While i < n
-			Local c:=text[i]
-			If i = pos
-				If quoteCounter Mod 2 = 0 'not inside of string
-					Return False
-				Else 'inside
-					Return True
-				Endif 
-			Endif
-			If c = Chars.DOUBLE_QUOTE
-				quoteCounter+=1
-			Endif
-			i+=1
-		Wend
-		Return (quoteCounter Mod 2 <> 0)
+		Return IsPosInsideOfQuotes_Mx2( text,pos )
 	End
 	
 	Method RemovePrevious( path:String )
@@ -1258,6 +1343,7 @@ Struct Chars
 	Const SINGLE_QUOTE:="'"[0] '39
 	Const DOUBLE_QUOTE:="~q"[0] '34
 	Const COMMA:=","[0] '44
+	Const SEMICOLON:=";"[0]
 	Const DOT:="."[0] '46
 	Const EQUALS:="="[0] '61
 	Const LESS_BRACKET:="<"[0] '60

+ 11 - 3
parser/Parser.monkey2

@@ -3,13 +3,15 @@ Namespace ted2go
 
 
 Interface ICodeParser
-
+	
+	Method GetConstructors( item:CodeItem,target:Stack<CodeItem> )
 	Method RefineRawType( item:CodeItem )
-	Method ParseFile:String( filePath:String,pathOnDisk:String,isModule:Bool )
+	Method ParseFile:String( filePath:String,pathOnDisk:String,moduleName:String )
 	'Method ParseJson( json:String,filePath:String )
 	Method IsPosInsideOfQuotes:Bool( text:String,pos:Int )
 	Method CanShowAutocomplete:Bool( line:String,posInLine:Int )
 	Method GetScope:CodeItem( docPath:String,docLine:Int )
+	Method GetNearestScope:CodeItem( docPath:String,docLine:Int,above:Bool )
 	Method ItemAtScope:CodeItem( ident:String,filePath:String,docLine:Int )
 	
 	Method GetItemsForAutocomplete( options:ParserRequestOptions )
@@ -73,6 +75,7 @@ Class ParserRequestOptions Final
 	Field usingsFilter:Stack<String>
 	Field docLineStr:String
 	Field docPosInLine:Int
+	Field intelliIdent:=True
 	
 End
 
@@ -97,7 +100,9 @@ Class FakeParser Implements ICodeParser
 		Return _extraItemsMap
 	End
 	
-	Method ParseFile:String( filePath:String,pathOnDisk:String,isModule:Bool )
+	Method GetConstructors( item:CodeItem,target:Stack<CodeItem> )
+	End
+	Method ParseFile:String( filePath:String,pathOnDisk:String,moduleName:String )
 		'do nothing
 		Return Null
 	End
@@ -110,6 +115,9 @@ Class FakeParser Implements ICodeParser
 	Method GetScope:CodeItem( docPath:String,docLine:Int )
 		Return Null
 	End
+	Method GetNearestScope:CodeItem( docPath:String,docLine:Int,above:Bool )
+		Return Null
+	End
 	Method ItemAtScope:CodeItem( ident:String,filePath:String,docLine:Int )
 		Return Null
 	End

+ 3 - 1
product/BuildProduct.monkey2

@@ -384,6 +384,8 @@ Class MacosProduct Extends DesktopProduct
 		plist+="<!DOCTYPE plist PUBLIC ~q-//Apple Computer//DTD PLIST 1.0//EN~q ~qhttp://www.apple.com/DTDs/PropertyList-1.0.dtd~q>~n"
 		plist+="<plist version=~q1.0~q>~n"
 		plist+="<dict>~n"
+		plist+="~t<key>CFBundleName</key>~n"
+		plist+="~t<string>"+AppName+"</string>~n"
 		plist+="~t<key>CFBundleExecutable</key>~n"
 		plist+="~t<string>"+AppName+"</string>~n"
 		plist+="~t<key>CFBundleIconFile</key>~n"
@@ -476,7 +478,7 @@ Class AndroidProduct Extends BuildProduct
 	Method New( srcPath:String )
 		Super.New( srcPath,"android" )
 		
-		AddExts( New String[]( ".xml",".java",".gradle" ) )
+		AddExts( New String[]( ".xml",".java",".gradle",".name" ) )
 		
 		AddVar( "Package Name","com.monkey2.monkey2game" )
 		AddVar( "Activity Name","Monkey2Game" )

+ 50 - 40
product/ModuleManager.monkey2

@@ -5,6 +5,7 @@ Namespace ted2go
 Private
 
 Class Module
+	Field dir:String
 	Field name:String
 	Field about:String
 	Field author:String
@@ -146,7 +147,8 @@ Class ModuleManager Extends Dialog
 		
 		For Local module:=Eachin _procmods
 		
-			Local src:="modules/"+module.name
+'			Local src:="modules/"+module.name
+			Local src:=module.dir+module.name
 			Local dst:=backupDir+module.name
 			
 			Select GetFileType( src )
@@ -169,7 +171,8 @@ Class ModuleManager Extends Dialog
 		For Local module:=Eachin _procmods
 		
 			Local src:=backupDir+module.name
-			Local dst:="modules/"+module.name
+'			Local dst:="modules/"+module.name
+			Local dst:=module.dir+module.name
 			
 			Select GetFileType( src )
 			Case FileType.Directory
@@ -236,12 +239,14 @@ Class ModuleManager Extends Dialog
 			Local zip:=module.name+"-v"+module.new_version+".zip"
 			Local dst:=downloadDir+zip
 			
-			If Not DeleteDir( "modules/"+module.name,True )
+'			If Not DeleteDir( "modules/"+module.name,True )
+			If Not DeleteDir( module.dir+module.name,True )
 				Alert( "Error deleting module directory '"+module.name+"'" )
 				Return False
 			End
 		
-			If Not ExtractZip( dst,"modules",module.name+"/" )
+'			If Not ExtractZip( dst,"modules",module.name+"/" )
+			If Not ExtractZip( dst,module.dir,module.name+"/" )
 				Alert( "Error extracting zip to '"+dst+"'" )
 				Return False
 			Endif
@@ -356,7 +361,7 @@ Class ModuleManager Extends Dialog
 		Endif
 		
 		
-		App.EndModal()		
+		App.EndModal()
 		
 		_progress.Close()
 		
@@ -483,6 +488,7 @@ Class ModuleManager Extends Dialog
 				Endif
 			Else
 				module=New Module
+				module.dir=ModuleDirs[0]
 				module.version=version
 				module.new_version=version
 				module.status="Uninstalled"
@@ -502,44 +508,48 @@ Class ModuleManager Extends Dialog
 	End
 	
 	Method EnumLocalModules()
-	
-		For Local f:=Eachin LoadDir( "modules" )
 		
-			Local dir:="modules/"+f+"/"
-			If GetFileType( dir )<>FileType.Directory Continue
-			
-			Local str:=LoadString( dir+"module.json" )
-			If Not str Continue
-			
-			Local obj:=JsonObject.Parse( str )
-			If Not obj Continue
-			
-			Local jname:=obj["module"]
-			If Not jname Or Not Cast<JsonString>( jname ) Continue
-			
-			Local jabout:=obj["about"]
-			If Not jabout Or Not Cast<JsonString>( jabout ) Continue
-			
-			Local jauthor:=obj["author"]
-			If Not jauthor Or Not Cast<JsonString>( jauthor ) Continue
-			
-			Local jversion:=obj["version"]
-			If Not jversion Or Not Cast<JsonString>( jversion ) Continue
-			
-			Local name:=jname.ToString()
-			Local about:=jabout.ToString()
-			Local author:=jauthor.ToString()
-			Local version:=jversion.ToString()
+		For Local moddir:=Eachin ModuleDirs
+	
+			For Local f:=Eachin LoadDir( moddir )
 			
-			Local module:=New Module
-			module.name=name
-			module.about=about
-			module.author=author
-			module.version=version
-			module.status="Local"
+				Local dir:=moddir+f+"/"
+				If GetFileType( dir )<>FileType.Directory Continue
+				
+				Local str:=LoadString( dir+"module.json" )
+				If Not str Continue
+				
+				Local obj:=JsonObject.Parse( str )
+				If Not obj Continue
+				
+				Local jname:=obj["module"]
+				If Not jname Or Not Cast<JsonString>( jname ) Continue
+				
+				Local jabout:=obj["about"]
+				If Not jabout Or Not Cast<JsonString>( jabout ) Continue
+				
+				Local jauthor:=obj["author"]
+				If Not jauthor Or Not Cast<JsonString>( jauthor ) Continue
+				
+				Local jversion:=obj["version"]
+				If Not jversion Or Not Cast<JsonString>( jversion ) Continue
+				
+				Local name:=jname.ToString()
+				Local about:=jabout.ToString()
+				Local author:=jauthor.ToString()
+				Local version:=jversion.ToString()
+				
+				Local module:=New Module
+				module.dir=moddir
+				module.name=name
+				module.about=about
+				module.author=author
+				module.version=version
+				module.status="Local"
+				
+				_modules[name]=module
 			
-			_modules[name]=module
-		
+			Next
 		Next
 	End
 

+ 14 - 2
product/Mx2ccEnv.monkey2

@@ -1,6 +1,7 @@
 
 Namespace ted2go
 
+Global ModuleDirs:String[]
 
 Function GetEnv:String( name:String )
 
@@ -51,6 +52,8 @@ Function ReplaceEnv:String( str:String,lineid:Int )
 	Return str
 End
 
+Public
+
 Function LoadEnv()
 
 	Local path:="bin/env_"+HostOS+".txt"
@@ -79,10 +82,19 @@ Function LoadEnv()
 		
 		SetEnv( name,value )
 	Next
+	
+	Local moddirs:=New StringStack
+	moddirs.Add( CurrentDir()+"modules/" )
+	For Local moddir:=Eachin GetEnv( "MX2_MODULE_DIRS" ).Split( ";" )
+		moddir=moddir.Replace( "\","/" )
+		If GetFileType( moddir )<>FileType.Directory Continue
+		moddir=RealPath( moddir )
+		If Not moddir.EndsWith( "/" ) moddir+="/"
+		If Not moddirs.Contains( moddir ) moddirs.Add( moddir )
+	Next
+	ModuleDirs=moddirs.ToArray()
 End
 
-Public
-
 Function EnumValidTargets:StringStack( console:ConsoleExt )
 
 	LoadEnv()

+ 2 - 2
syntax/Monkey2Highlighter.monkey2

@@ -15,7 +15,7 @@ Class Monkey2Highlighter Extends HighlighterPlugin
 	
 	Method New()
 		Super.New()
-		_types=New String[](".monkey2")
+		_types=New String[]( ".monkey2",".json" )
 		_hl=New Highlighter
 		_hl.Painter=HL
 	End
@@ -121,7 +121,7 @@ Class Monkey2Highlighter Extends HighlighterPlugin
 				If preproc And istart=sol
 				
 					Select id.ToLower()
-					Case "rem"				
+					Case "rem"
 						cnest+=1
 					Case "end"
 						cnest=Max( cnest-1,-1 )

+ 11 - 0
testing/ParserTests.monkey2

@@ -43,6 +43,17 @@ Interface ITest
 	
 End
 
+Class c123 Implements ITest
+	
+	Method abs()
+	End
+End
+
+Class c456 Extends c123
+	
+'	Method abs()' Override
+'	End
+End
 
 '0000000000000000000000000000000
 '0000000000000000000000000000000

+ 86 - 0
testing/pixelPerfect.json

@@ -0,0 +1,86 @@
+{
+	"Object2D":{
+		"Class":"game3d.GameObject",
+		"Components":[{
+			"Animation":"WalkRight",
+			"Class":"game3d.SpriteAnim",
+			"Enabled":true,
+			"Frame":0,
+			"FrameOffset":0,
+			"FrameRate":20,
+			"Name":"SpriteAnim",
+			"animationPath":"asset::blob.json",
+			"border":0,
+			"cellHeight":16,
+			"cellWidth":16,
+			"defaultAnimation":"WalkRight",
+			"flags":0,
+			"padding":0,
+			"path":"asset::blob.png"
+		},{
+			"Class":"game3d.SinePosition",
+			"Enabled":true,
+			"Name":"SinePosition",
+			"period":0.5,
+			"x":16,
+			"y":16,
+			"z":0
+		}],
+		"Name":"Object2D",
+		"Parent":"",
+		"Position":[0,0,0],
+		"Rotation":[-0,-0,0],
+		"Scale":[16,16,1],
+		"Visible":true,
+		"timeOffset":0
+	},
+	"camera":{
+		"Class":"game3d.GameObject",
+		"Components":[{
+			"AmbientLight":[1,1,1,1],
+			"Class":"game3d.CameraComponent",
+			"ClearColor":[0.30000001192092896,0.30000001192092896,0.30000001192092896,1],
+			"Enabled":true,
+			"EnvColor":[0,0,0,1],
+			"FOV":45,
+			"Far":1000,
+			"FogColor":[0,0,0,0],
+			"Name":"CameraComponent",
+			"Near":0.10000000149011612
+		}],
+		"Name":"camera",
+		"Parent":"",
+		"Position":[0,0,-217.27922058105469],
+		"Rotation":[-0,-0,0],
+		"Scale":[1,1,1],
+		"Visible":true,
+		"timeOffset":0
+	},
+	"checkerboard":{
+		"Class":"game3d.GameObject",
+		"Components":[{
+			"Animation":"",
+			"Class":"game3d.SpriteAnim",
+			"Enabled":true,
+			"Frame":0,
+			"FrameOffset":0,
+			"FrameRate":15,
+			"Name":"SpriteAnim",
+			"animationPath":"",
+			"border":0,
+			"cellHeight":180,
+			"cellWidth":320,
+			"defaultAnimation":"",
+			"flags":0,
+			"padding":0,
+			"path":"asset::checkerboard.png"
+		}],
+		"Name":"checkerboard",
+		"Parent":"",
+		"Position":[0,0,217.27922058105469],
+		"Rotation":[-0,-0,0],
+		"Scale":[640,360,1],
+		"Visible":true,
+		"timeOffset":0
+	}
+}

+ 5 - 4
utils/JsonUtils.monkey2

@@ -40,23 +40,24 @@ End
 
 Function Json_GetBool:Bool( json:Map<String,JsonValue>,key:String,def:Bool )
 	
-	Return json[key] ? json[key].ToBool() Else def
+	Return json.Contains( key ) ? json[key].ToBool() Else def
 End
 
 Function Json_GetString:String( json:Map<String,JsonValue>,key:String,def:String )
 	
-	Return json[key] ? json[key].ToString() Else def
+	Return json.Contains( key ) ? json[key].ToString() Else def
 End
 
 Function Json_GetInt:Int( json:Map<String,JsonValue>,key:String,def:Int )
 	
-	Return json[key] ? Int(json[key].ToNumber()) Else def
+	Return json.Contains( key ) ? Int(json[key].ToNumber()) Else def
 End
 
 
+
 Class JsonArray Extension
 	
-	Function Create:JsonArray( values:String[] )
+	Function FromStrings:JsonArray( values:String[] )
 		
 		Local jvals:=New JsonValue[values.Length]
 		For Local i:=0 Until values.Length

+ 117 - 1
utils/Utils.monkey2

@@ -2,13 +2,40 @@
 Namespace ted2go
 
 
-Function IsLowercacedFirstChar:Bool(s:String)
+Function SwapCase:String( s:String )
+	
+	Local result:="",ss:String,lower:String
+	For Local i:=0 Until s.Length
+		ss=s.Slice( i,i+1 )
+		lower=ss.ToLower()
+		result+=(ss=lower) ? ss.ToUpper() Else lower
+	Next
+	Return result
+End
+
+Function IsLowercacedFirstChar:Bool( s:String )
 	
 	If Not s Return False
 	Local s1:=s.Slice( 0,1 )
 	Return s1 = s1.ToLower()
 End
 
+Function GetCaseSensitivePath:String( path:String )
+
+#If __HOSTOS__="windows"
+	Local dir:=ExtractDir( path )
+	Local items:=LoadDir( dir )
+	If items
+		Local lower:=StripDir( path ).ToLower()
+		For Local i:=Eachin items
+			If i.ToLower()=lower Return dir+i
+		Next
+	Endif
+	Return path
+#Else
+	Return path
+#Endif
+End
 
 Class Utils
 	
@@ -263,6 +290,11 @@ Class Stack<T> Extension
 		Self.Remove( item )
 	End
 	
+	Operator+=( items:T[] )
+	
+		Self.AddAll( items )
+	End
+	
 End
 
 
@@ -282,3 +314,87 @@ Struct Recti Extension
 		Self.Size=size
 	End
 End
+
+
+Function TypeName<T>:String( obj:T ) Where T Extends Object
+	
+	Return obj ? String.FromCString( obj.typeName() ) Else Null
+End
+
+Function FindViewInHierarchy<T>:T( view:View ) Where T Extends View
+	
+	While view
+		Local r:=Cast<T>( view )
+		If r Return r
+		view=view.Parent
+	Wend
+	Return Null
+End
+
+Function StripEnding:String( text:String,ends:String )
+	
+	Return text.EndsWith( ends ) ? text.Slice( 0,text.Length-ends.Length ) Else text
+End
+
+Function StripStarting:String( text:String,starts:String )
+	
+	Return text.StartsWith( starts ) ? text.Slice( starts.Length ) Else text
+End
+
+#Rem monkeydocs Return ident and position in line where ident starts
+#End
+Function GetIndentBeforePos_Mx2:Tuple2<String,Int>( line:String,pos:Int,withDots:Bool )
+	
+	Local n:=pos-1
+	
+	While n >= 0
+	
+		Local more:=(line[n]=Chars.MORE_BRACKET)
+	
+		If line[n] = Chars.DOT Or more ' . | ?. | ->
+			If Not withDots Exit
+			If more
+				If n>0 And line[n-1]<>"-"[0] Exit
+				n-=1 ' skip '-'
+			Else
+				If n>0 And line[n-1]="?"[0] Then n-=1 ' skip '?'
+			Endif
+		ElseIf Not (IsIdent( line[n] ) Or line[n] = Chars.GRID) ' #
+			Exit
+		Endif
+	
+		n-=1
+	Wend
+	n+=1
+	
+	Local s:=""
+	Local starts:=-1
+	If n < pos
+		starts=n
+		s=line.Slice( n,pos ).Replace( "?.","." ).Replace( "->","." )
+	Endif
+	Return New Tuple2<String,Int>( s,starts )
+End
+
+Function IsPosInsideOfQuotes_Mx2:Bool( text:String,pos:Int )
+
+	Local i:=0
+	Local n:=text.Length
+	If pos=0 Return False
+	Local quoteCounter:=0
+	While i < n
+		Local c:=text[i]
+		If i = pos
+			If quoteCounter Mod 2 = 0 'not inside of string
+				Return False
+			Else 'inside
+				Return True
+			Endif 
+		Endif
+		If c = Chars.DOUBLE_QUOTE
+			quoteCounter+=1
+		Endif
+		i+=1
+	Wend
+	Return (quoteCounter Mod 2 <> 0)
+End

+ 33 - 33
view/AutocompleteView.monkey2

@@ -158,7 +158,7 @@ Class AutocompleteDialog Extends NoTitleDialog
 		' using lowerCase for keywords
 		Local lastIdent:=(dotPos > 0) ? ident.Slice( dotPos+1 ) Else ident
 		Local lastIdentLower:=lastIdent.ToLower()
-				
+		
 		_view.word=lastIdentLower
 		
 		Local starts:=(_fullIdent And ident.StartsWith( _fullIdent ))
@@ -175,37 +175,37 @@ Class AutocompleteDialog Extends NoTitleDialog
 		'if typed ident starts with previous
 		'need to simple filter items
 		
-		If IsOpened And starts And Not ident.EndsWith(".")
-			
-			Local items:=_view.Items
-			For Local i:=Eachin items
-				
-				If parser.CheckStartsWith( i.Text,lastIdentLower )
-					result.Add( i )
-				Endif
-				
-			Next
-			
-			' some "copy/paste" code
-			_fullIdent=ident
-			_lastIdentPart=lastIdentLower
-			If IsOpened Then Hide() 'hide to re-layout on open
-			
-			'nothing to show
-			If result.Empty
-				Return
-			Endif
-			
-			CodeItemsSorter.SortByIdent( result,lastIdent )
-			
-			_view.Reset()'reset selIndex
-			_view.SetItems( result )
-			
-			Super.Show()
-			
-			_disableUsingsFilter=filter
-			Return
-		End
+'		If IsOpened And starts And Not ident.EndsWith(".")
+'			
+'			Local items:=_view.Items
+'			For Local i:=Eachin items
+'				
+'				If parser.CheckStartsWith( i.Text,lastIdentLower )
+'					result.Add( i )
+'				Endif
+'				
+'			Next
+'			
+'			' some "copy/paste" code
+'			_fullIdent=ident
+'			_lastIdentPart=lastIdentLower
+'			If IsOpened Then Hide() 'hide to re-layout on open
+'			
+'			'nothing to show
+'			If result.Empty
+'				Return
+'			Endif
+'			
+'			CodeItemsSorter.SortByIdent( result,lastIdent )
+'			
+'			_view.Reset()'reset selIndex
+'			_view.SetItems( result )
+'			
+'			Super.Show()
+'			
+'			_disableUsingsFilter=filter
+'			Return
+'		End
 		
 		
 		_fullIdent=ident
@@ -514,7 +514,7 @@ Class AutocompleteDialog Extends NoTitleDialog
 		Next
 		'preprocessor
 		'need to load it like keywords
-		Local s:="#If ,#Rem,#End,#Endif,#Else,#Else If ,#Import ,monkeydoc,__TARGET__,__MOBILE_TARGET__,__DESKTOP_TARGET__,__HOSTOS__"
+		Local s:="#If ,#Rem,#End,#Endif,#Else,#Else If ,#Import ,monkeydoc,__TARGET__,__MOBILE_TARGET__,__DESKTOP_TARGET__,__HOSTOS__,__ARCH__,#Reflect "
 		Local arr:=s.Split( "," )
 		For Local i:=Eachin arr
 			list.Add( New ListViewItem( i ) )

+ 131 - 35
view/CodeTextView.monkey2

@@ -12,6 +12,7 @@ Class CodeTextView Extends TextView
 	Field TextChanged:Void()
 	
 	Method New()
+		
 		Super.New()
 		
 		CursorBlinkRate=2.5
@@ -59,6 +60,116 @@ Class CodeTextView Extends TextView
 		UpdateThemeColors()
 	End
 	
+	Method DeleteLineAtCursor()
+	
+		Local line:=Document.FindLine( Cursor )
+		Local pos:=Cursor
+		SelectText( Document.StartOfLine( line ),Document.EndOfLine( line )+1 )
+		ReplaceText( "" )
+		pos=Min( pos,Document.EndOfLine( line ) )
+		SelectText( pos,pos )
+	End
+	
+	Method DeleteWordBackward()
+	
+		If CanCopy ' try to delete selected area
+			ReplaceText( "" )
+			Return
+		Endif
+	
+		Local line:=Document.FindLine( Cursor )
+		Local found:Word=Null
+		For Local word:=Eachin WordIterator.ForLine( Self,line )
+			If Cursor>word.index And Cursor<=word.index+word.length
+				found=word
+				Exit
+			Endif
+		Next
+		If found
+			SelectText( found.index,Cursor )
+			ReplaceText( "" )
+		Endif
+	End
+	
+	Method DeleteWordForward()
+	
+		If CanCopy ' try to delete selected area
+			ReplaceText( "" )
+			Return
+		Endif
+	
+		Local line:=Document.FindLine( Cursor )
+		Local found:Word=Null
+		For Local word:=Eachin WordIterator.ForLine( Self,line )
+			If Cursor>=word.index And Cursor<word.index+word.length
+				found=word
+				Exit
+			Endif
+		Next
+		If found
+			SelectText( Cursor,found.index+found.length )
+			ReplaceText( "" )
+		Endif
+	End
+	
+	Method DeleteToEnd()
+	
+		Local i1:=Min( Anchor,Cursor )
+		Local i2:=Max( Anchor,Cursor )
+	
+		SelectText( i1,Document.EndOfLine( Document.FindLine( i2 ) ) )
+		ReplaceText( "" )
+	End
+	
+	Method DeleteToBegin()
+	
+		Local i1:=Min( Anchor,Cursor )
+		Local i2:=Max( Anchor,Cursor )
+	
+		SelectText( Document.StartOfLine( Document.FindLine( i1 ) ),i2 )
+		ReplaceText( "" )
+	End
+	
+	Method LowercaseSelection()
+	
+		Local txt:=SelectedText
+		If txt
+			Local a:=Anchor,c:=Cursor
+			ReplaceText( txt.ToLower() )
+			SelectText( a,c )
+		Endif
+	End
+	
+	Method UppercaseSelection()
+	
+		Local txt:=SelectedText
+		If txt
+			Local a:=Anchor,c:=Cursor
+			ReplaceText( txt.ToUpper() )
+			SelectText( a,c )
+		Endif
+	End
+	
+	Method SwapCaseSelection()
+	
+		Local txt:=SelectedText
+		If txt
+			Local a:=Anchor,c:=Cursor
+			ReplaceText( SwapCase( txt ) )
+			SelectText( a,c )
+		Endif
+	End
+	
+	Property SelectedText:String()
+		
+		If Not CanCopy Return ""
+		
+		Local i1:=Min( Anchor,Cursor )
+		Local i2:=Max( Anchor,Cursor )
+		
+		Return Text.Slice( i1,i2 )
+	End
+	
 	Property IsCursorAtTheEndOfLine:Bool()
 		
 		Local line:=Document.FindLine( Cursor )
@@ -92,36 +203,8 @@ Class CodeTextView Extends TextView
 	
 	Method IdentBeforeCursor:String( withDots:Bool=True )
 		
-		Local text:=Text
-		Local cur:=Cursor
-		Local n:=Cursor-1
-		Local start:=Document.StartOfLine( Document.FindLine( Cursor ) )
-		
-		While n >= start
-			
-			Local more:=(text[n]=Chars.MORE_BRACKET)
-			
-			If text[n] = Chars.DOT Or more ' . | ?. | ->
-				If Not withDots Exit
-				If more
-					If n>0 And text[n-1]<>"-"[0] Exit
-					n-=1 ' skip '-'
-				Else
-					If n>0 And text[n-1]="?"[0] Then n-=1 ' skip '?'
-				Endif
-			ElseIf Not (IsIdent( text[n] ) Or text[n] = Chars.GRID) ' #
-				Exit
-			Endif
-			
-			n-=1
-		Wend
-		n+=1
-		
-		Local s:=""
-		If n < cur
-			s=text.Slice( n,cur ).Replace( "?.","." ).Replace( "->","." )
-		Endif
-		Return s
+		Local pair:=GetIndentBeforePos_Mx2( LineTextAtCursor,PosInLineAtCursor,withDots )
+		Return pair.Item1
 	End
 	
 	Property WordAtCursor:String()
@@ -247,6 +330,10 @@ Class CodeTextView Extends TextView
 		Return Anchor-Document.StartOfLine( LineNumAtAnchor )
 	End
 	
+	Property StartOfLineAtCursor:Int()
+		Return Document.StartOfLine( LineNumAtCursor )
+	End
+	
 	Property CursorPos:Vec2i()
 		Return New Vec2i( LineNumAtCursor,PosInLineAtCursor )
 	End
@@ -354,7 +441,18 @@ Class CodeTextView Extends TextView
 						Local cur:=CharAtPoint( event.Location )
 						SelectText( cur,cur )
 					Else
-						Local r:=CursorRect | CharRect( Anchor )
+						Local i1:=Min( Cursor,Anchor )
+						Local i2:=Max( Cursor,Anchor )
+						Local l1:=Document.FindLine( i1 )
+						Local l2:=Document.FindLine( i2 )
+						Local r:Recti=Null
+						For Local line:=l1 To l2
+							If r=Null
+								r=LineRect( line )
+							Else
+								r|=LineRect( line )
+							Endif
+						Next
 						If Not r.Contains( event.Location )
 							Local cur:=CharAtPoint( event.Location )
 							SelectText( cur,cur )
@@ -413,9 +511,6 @@ Class CodeTextView Extends TextView
 		Return _line
 	End
 	
-	
-	Protected
-	
 	Method OnCut( wholeLine:Bool=False )
 	
 		If wholeLine
@@ -573,11 +668,12 @@ Class CodeTextView Extends TextView
 	Method OnThemeChanged() Override
 		
 		Super.OnThemeChanged()
+		
 		UpdateThemeColors()
 	End
 	
 	Method UpdateThemeColors() Virtual
-	
+		
 		_whitespacesColor=App.Theme.GetColor( "textview-whitespaces" )
 		_extraSelColor=App.Theme.GetColor( "textview-extra-selection" )
 	End

+ 9 - 7
view/CodeTreeView.monkey2

@@ -44,19 +44,20 @@ Class CodeTreeView Extends TreeViewExt
 		If expandIfOnlyOneItem And RootNode.NumChildren=1
 			RootNode.Children[0].Expanded=True
 		Endif
+		
 	End
 	
 	Method SelectByScope( scope:CodeItem )
-	
+		
 		Local node:=FindNode( RootNode,scope )
 		If Not node Return
 		
-		If scope.IsLikeClass
-			node.Expanded=True
-			NodeExpanded( node )
-			Return
-		Endif
+		node.Expanded=True
+		TreeViewExpander.ExpandParents( node )
 		
+		MeasureLayoutSize()
+		
+		Selected=Null
 		Selected=node
 	End
 	
@@ -173,13 +174,14 @@ End
 Class CodeTreeNode Extends TreeView.Node
 
 	Method New( item:CodeItem,node:TreeView.Node )
+		
 		Super.New( item.Text,node )
 		_code=item
 		Icon=CodeItemIcons.GetIcon( item )
-		
 	End
 	
 	Property CodeItem:CodeItem()
+		
 		Return _code
 	End
 	

+ 160 - 0
view/DraggableViewListener.monkey2

@@ -0,0 +1,160 @@
+
+Namespace ted2go
+
+
+Interface IDraggableItem<THolder>
+	
+	Property Detachable:Bool()
+	
+	Property PossibleHolders:THolder[]()
+	Setter( value:THolder[] )
+	
+	Property CurrentHolder:THolder()
+	
+End
+
+Interface IDraggableHolder
+	
+	Method Attach( item:Object,eventLocation:Vec2i )
+	Method Detach:View( item:Object )
+	
+	Method OnDragStarted() 	' highlight holder here (if needed)
+	Method OnDragEnded() 	' reset highlighting
+	
+End
+
+#Rem Call order: Detach -> OnDragStarted -> Attach -> OnDragEnded
+
+#End
+Class DraggableViewListener<TItem,THolder>
+	
+	Method GetItem:TItem( eventView:View,eventLocation:Vec2i ) Abstract
+	Method GetHolder:THolder( view:View ) Abstract
+	
+	Method New()
+		
+		_window=Window.AllWindows()[0]
+		
+		App.MouseEventFilter+=OnMouseEvent
+	End
+	
+	Property DragThreshold:Float()
+		Return _threshold
+	Setter( value:Float )
+		_threshold=value
+	End
+	
+	
+	Private
+	
+	Field _threshold:=10.0
+	Field _item:TItem
+	Field _view:View
+	Field _pressedPos:Vec2i
+	Field _detached:Bool
+	Field _window:Window
+	
+	Method OnMouseEvent( event:MouseEvent )
+	
+		Select event.Type
+			
+			Case EventType.MouseDown
+				
+				_item=GetItem( event.View,event.Location )
+				If Not _item Return
+				
+				If Not _item.Detachable
+					_item=Null
+					Return
+				Endif
+				
+				_pressedPos=Mouse.Location
+				
+			
+			Case EventType.MouseMove
+			
+				If Not _item Return
+				
+				If _detached
+					Local r:=_view.Frame
+					Local sz:=r.Size
+					r.TopLeft=Mouse.Location+New Vec2i( 0,-10 )
+					r.BottomRight=r.TopLeft+sz
+					_view.Frame=r
+					App.RequestRender()
+					Return
+				Endif
+				
+				Local dy:Float=Abs(Mouse.Y-_pressedPos.y)
+				
+				If dy>=_threshold*App.Theme.Scale.y
+					Detach()
+				Endif
+				
+			
+			Case EventType.MouseUp
+				
+				If Not _detached 
+					_item=Null
+					Return
+				Endif
+				
+				_window.RemoveChildView( _view )
+				
+				Local holder:=GetHolder( App.ActiveViewAtMouseLocation() )
+				
+				If Not CanAttach( _item,holder ) Then holder=_item.CurrentHolder
+				
+				holder.Attach( _item,event.Location )
+				
+				_item.CurrentHolder.OnDragEnded()
+				If _item.PossibleHolders
+					For Local i:=Eachin _item.PossibleHolders
+						If i=_item.CurrentHolder Continue
+						i.OnDragEnded()
+					Next
+				Endif
+				
+				_item=Null
+				_detached=False
+				
+				event.Eat()
+				
+		End
+	
+	End
+	
+	Method Detach()
+		
+		_detached=True
+		
+		Local holder:=GetHolder( _item.View )
+		_view=holder.Detach( _item )
+		
+		_window.AddChildView( _view )
+		
+		_item.CurrentHolder.OnDragStarted()
+		
+		If Not _item.PossibleHolders Return
+		
+		For Local i:=Eachin _item.PossibleHolders
+			If i=_item.CurrentHolder Continue
+			i.OnDragStarted()
+		Next
+		
+	End
+	
+	Function CanAttach:Bool( item:TItem,holder:THolder )
+		
+		If Not holder Return False
+		If Not item.PossibleHolders Return False
+		
+		For Local i:=Eachin item.PossibleHolders
+			
+			If i=holder Return True
+		Next
+		
+		Return False
+	End
+	
+End

+ 198 - 99
view/HelpTreeView.monkey2

@@ -35,9 +35,9 @@ Class HelpTreeView Extends TreeViewExt
 	Field PageClicked:Void( page:String )
 	
 	Method New( htmlView:HtmlView )
-	
-		htmlView.AnchorClicked=Lambda( url:String )
 		
+		htmlView.AnchorClicked=Lambda( url:String )
+			
 			'dodgy work around for mx2 docs!
 			'
 			If url.StartsWith( "javascript:void('" ) And url.EndsWith( "')" )
@@ -50,7 +50,7 @@ Class HelpTreeView Extends TreeViewExt
 		End
 		
 		PageClicked+=Lambda( page:String )
-		
+			
 			Local url:=PageUrl( page )
 			If Not url Return
 			
@@ -58,15 +58,16 @@ Class HelpTreeView Extends TreeViewExt
 		End
 		
 		Init()
+		
 	End
 	
 	Property FindField:TextFieldExt()
-	
+		
 		Return _textField
 	End
 	
 	Method QuickHelp( text:String )
-	
+		
 		If text<>_textField.Text
 			_textField.Text=text
 		Else
@@ -76,153 +77,245 @@ Class HelpTreeView Extends TreeViewExt
 	End
 	
 	Method PageUrl:String( page:String )
-
-		'old doc system		
+		
+		'old doc system
 		'Return RealPath( "modules/"+page.Replace( ":","/docs/__PAGES__/" ).Replace( ".","-" )+".html" )
 		
 		'new doc system
 		Return RealPath( "docs/"+page )
 	End
 	
-	Method Update()
+	Function CreateNodes( obj:JsonObject,parent:Tree.Node,indexer:StringMap<Tree.Node> )
+		
+		Local text:=obj["text"].ToString()
+		Local page:=""
+		
+		If obj.Contains( "data" )
+			Local data:=obj["data"].ToObject()
+			page=data["page"].ToString()
+		Endif
+		
+		Local node:=New Tree.Node( text,parent,page )
+		indexer[page.ToLower()]=node
+		
+		If obj.Contains( "children" )
+			For Local child:=Eachin obj["children"].ToArray()
+				CreateNodes( Cast<JsonObject>( child ),node,indexer )
+			Next
+		Endif
+		
+	End
+	
+	Function FindChild:Node( node:TreeView.Node,text:String )
+		
+		For Local n:=Eachin node.Children
+			If n.Text=text Return Cast<Node>( n )
+		Next
+		Return Null
+	End
 	
-		RootNode.RemoveAllChildren()
-
+	Method InsertNode:Node( node:Tree.Node )
+		
+		Local parent:=RootNode
+		Local items:=node.ParentsHierarchy
+		items.Add( node )
+		
+		Local last:Node
+		Local len:=items.Length
+		For Local i:=1 Until len ' start from 1 to skip root node
+			Local item:=items[i]
+			Local text:=item.Text
+			If i+1<len And items[i+1].Text=text Continue ' skip nested mogo>mojo>... etc
+			last=FindChild( parent,text )
+			If Not last
+				last=New Node( text,parent,item.GetUserData<String>() )
+			Endif
+			parent=last
+		Next
+		Return last
+	End
+	
+	Method Update( applyFilter:Bool=False )
+		
+		_index.Clear()
+		_index2.Clear()
+		_tree.Clear()
+		
 		For Local modname:=Eachin EnumModules()
-
-			'old doc system		
+			
+			'old doc system
 			'Local index:="modules/"+modname+"/docs/__PAGES__/index.js"
-
+			
 			'new doc system
 			Local index:="docs/modules/"+modname+"/module/index.js"
-		
+			
 			Local obj:=JsonObject.Load( index )
 			If Not obj Continue
 			
-			New Node( obj,RootNode,Self )
+			CreateNodes( obj,_tree.RootNode,_index )
 		Next
 		
-		NodeClicked+=Lambda( tnode:TreeView.Node )
+		FillTree()
 		
-			Local node:=Cast<Node>( tnode )
-			If Not node Or Not node.Page Return
-			
-			PageClicked( node.Page )
-		End
+		If applyFilter Then Update( _textField.Text )
+	End
+	
+	Method RequestFocus()
 		
+		_textField.MakeKeyView()
 	End
-
+	
+	
 	Private
 	
 	Class Node Extends TreeView.Node
 	
-		Method New( page:String,parent:TreeView.Node,tree:HelpTreeView )
-			Super.New( page,parent )
-			
-			_page=page
-		End
-	
-		Method New( obj:JsonObject,parent:TreeView.Node,tree:HelpTreeView )
-			Super.New( "",parent )
-		
-			Text=obj["text"].ToString()
+		Method New( text:String,parent:TreeView.Node,page:String )
 			
-			If obj.Contains( "data" )
-
-				Local data:=obj["data"].ToObject()
-
-				Local page:=data["page"].ToString()
-				
-				tree._index[page.ToLower()]=Self
-				
-				_page=page
-			Endif
+			Super.New( text,parent )
 			
-			If obj.Contains( "children" )
-				For Local child:=Eachin obj["children"].ToArray()
-					New Node( Cast<JsonObject>( child ),Self,tree )
-				Next
-			Endif
-
+			_page=page
 		End
 		
 		Property Page:String()
 			Return _page
 		End
 		
-		Property Url:String()
-			Return _url
-		End
-		
 		Private
 		
 		Field _page:String
 		
-		Field _url:String
+	End
+	
+	Method FillTree()
+	
+		RootNode.RemoveAllChildren()
+		
+		FillNode( RootNode,_tree.RootNode.Children )
+		
+		Sort()
+	End
+	
+	Method FillNode( node:TreeView.Node,items:Stack<Tree.Node> )
+		
+		If Not items Return
+		
+		For Local item:=Eachin items
+			
+			Local page:=item.GetUserData<String>()
+			
+			' hack for the-same-nested 
+			If item.NumChildren=1
+				Local child:=item.Children[0]
+				If child.Text=item.Text.Replace( "-","." )
+					item=child
+				Endif
+			Endif
+			
+			Local n:=New Node( item.Text,node,page )
+			_index2[page.ToLower()]=n
+			
+			If item.NumChildren
+				FillNode( n,item.Children )
+			Endif
+		Next
+		
 	End
 	
 	Method Update( text:String )
-
+		
 		RootNode.CollapseAll()
-			
+		
+		text=StripEnding( text,"." )
+		
 		text=text.ToLower()
-			
+		
+		Local parts:=text.Split( "." )
+		Local text2:=text.Replace( ".","-" )
+		
+		If _tree.RootNode.NumChildren=0
+			New Node( "Click here to rebuild docs!",RootNode,"$$rebuild$$" )
+			Return
+		Endif
+		
 		_matches.Clear()
+		
+		For Local it:=Eachin _index2
 			
-		Local selected:=New Map<Node,Bool>
+			'Local node:=it.Value
+			Local n:=it.Value
 			
-		For Local it:=Eachin _index
+			'Local n:=InsertNode( node )
 			
-			If Not it.Key.Contains( text ) Continue
-				
-			Local node:=it.Value
-				
-			_matches.Push( node )
-				
-			node.Selected=True
+			'If Not text Continue
+			
+			If Not text2 Or Not it.Key.Contains( text2 )
+				n.Selected=False
+				Continue
+			Endif
+			
+			n.Selected=GetSelectionState( n,parts )
+			
+			If n.Selected
 				
-			selected[node]=True
+				_matches.Push( n )
 				
-			While node
-				node.Expanded=True
-				node=Cast<Node>( node.Parent )
-			Wend
-
-		Next
-						
-		For Local node:=Eachin _selected.Keys
+				Local n2:=n.Parent
+				While n2
+					n2.Expanded=True
+					n2=n2.Parent
+				Wend
+			Endif
 			
-			If Not selected.Contains( node ) node.Selected=False
-
 		Next
-			
-		_selected=selected
-			
+		
 		RootNode.Expanded=True
-			
+		
+		MainWindow.UpdateWindow( False )
+		
 		_matchid=0
-			
+		
 		If _matches.Length
 			
 			PageClicked( _matches[0].Page )
-			
+			Selected=_matches[0]
 		Endif
+		
+	End
 	
+	Method GetSelectionState:Bool( node:TreeView.Node,parts:String[] )
+		
+		Local last:=parts.Length-1
+		Local i:=last
+		Repeat
+			Local part:=parts[i]
+			Local txt:=node.Text.ToLower()
+			If txt.Contains( part )
+				i-=1
+				If i<0 Exit 'true
+			Else
+				If i=last Return False
+			Endif
+			node=node.Parent
+			If Not node Return False
+		Forever
+		
+		Return True
 	End
 	
 	Method NextHelp()
-	
-		If Not _matches Return
-	
-		_matchid+=1
-		If _matchid>=_matches.Length _matchid=0
 		
-		If _matchid<_matches.Length PageClicked( _matches[_matchid].Page )
+		If _matches.Empty Return
+		
+		_matchid=(_matchid+1) Mod _matches.Length
+		
+		PageClicked( _matches[_matchid].Page )
+		Selected=_matches[_matchid]
 	End
 	
 	Method Init()
-
-		_textField=New TextFieldExt
+		
+		_textField=New TextFieldExt( "" )
 		_textField.Style=GetStyle( "HelpTextField" )
 		
 		_textField.Entered=Lambda()
@@ -245,22 +338,28 @@ Class HelpTreeView Extends TreeViewExt
 		RootNodeVisible=False
 		RootNode.Expanded=True
 		
-		_textField.Activated+=_textField.MakeKeyView
+		NodeClicked+=Lambda( tnode:TreeView.Node )
 		
-		Activated+=MainWindow.ShowHelpView
+			Local node:=Cast<Node>( tnode )
+			Local page:=node?.Page
+			If Not page Return
+			
+			If page="$$rebuild$$"
+				MainWindow.RebuildDocs()
+				Return
+			Endif
+			
+			PageClicked( page )
+		End
 		
 		Update()
-				
 	End
 	
 	Field _textField:TextFieldExt
-	
 	Field _matchid:Int
-		
 	Field _matches:=New Stack<Node>
-	
-	Field _selected:=New Map<Node,Bool>
-	
-	Field _index:=New Map<String,Node>
+	Field _index:=New Map<String,Tree.Node>
+	Field _index2:=New Map<String,Node>
+	Field _tree:=New Tree
 	
 End

+ 12 - 2
view/ListViewExt.monkey2

@@ -216,9 +216,10 @@ Class ListViewExt Extends ScrollableView
 			Local d:=(firstVisLine-_selIndex)*_lineH
 			Scroll-=New Vec2i( 0,d )
 		Elseif _selIndex >= lastVisLine
-			Local d:=(lastVisLine-_selIndex)*_lineH
+			Local d:=(lastVisLine-_selIndex)*_lineH - _dh
 			Scroll-=New Vec2i( 0,d )
 		Endif
+		
 	End
 
 	Method OnRender( canvas:Canvas ) Override
@@ -258,6 +259,14 @@ Class ListViewExt Extends ScrollableView
 		_width=w
 		
 		Local h:=_items.Length*_lineH
+		
+		_dh=0
+		Local maxH:=Min( _visibleCount*_lineH,MaxSize.y )
+		If h>maxH 'has scroll
+			_dh=20*App.Theme.Scale.y '+20 for scrollbar
+			h+=_dh
+		Endif
+		
 		_height=h
 		
 		Return New Vec2i( w,h )
@@ -276,7 +285,7 @@ Class ListViewExt Extends ScrollableView
 		Endif
 		If sx Then h+=_lineH
 		
-		Return New Vec2i( w,h ) '+20 for scrollbar
+		Return New Vec2i( w,h )
 	End
 	
 	Method OnContentMouseEvent( event:MouseEvent ) Override
@@ -326,5 +335,6 @@ Class ListViewExt Extends ScrollableView
 	Field _selColor:Color,_hoverColor:Color
 	Field _width:Int,_height:Int
 	Field _moveCyclic:Bool
+	Field _dh:Float
 	
 End

+ 256 - 27
view/ProjectBrowserView.monkey2

@@ -2,7 +2,7 @@
 Namespace ted2go
 
 
-Class ProjectBrowserView Extends TreeViewExt
+Class ProjectBrowserView Extends TreeViewExt Implements IDraggableHolder
 	
 	Field RequestedDelete:Void( node:Node )
 	Field FileClicked:Void( node:Node )
@@ -15,7 +15,7 @@ Class ProjectBrowserView Extends TreeViewExt
 		
 		Style=GetStyle( "FileBrowser" )
 		
-		_rootNode=New Node( Null )
+		_rootNode=NewNode( Null )
 		RootNode=_rootNode
 		RootNode.Expanded=True
 		RootNodeVisible=False
@@ -34,11 +34,141 @@ Class ProjectBrowserView Extends TreeViewExt
 		
 		UpdateFileTypeIcons()
 		
+		If Not _listener Then _listener=New DraggableProjTreeListener
+	End
+	
+	Method Attach( item:Object,eventLocation:Vec2i )
+		
+		New Fiber( Lambda()
+			
+			Local node:=Cast<Node>( item )
+			Local node2:=FindNodeAtPoint( eventLocation )
+			If Not node2 Return
+			
+			Local destNode:=Cast<Node>( node2 )
+			
+			Local srcIsFolder:=GetFileType( node.Path )=FileType.Directory
+			Local destIsFolder:=GetFileType( destNode.Path )=FileType.Directory
+			
+			If Not destIsFolder
+				node2=node2.Parent ' grab destination folder
+				destNode=Cast<Node>( node2 )
+				destIsFolder=True
+			Endif
+			
+			If srcIsFolder
+				If node2=node Or node.Parent=node2 Return
+				' deny to move into child folder
+				Local n:=node2.Parent
+				While n
+					If n=node Return
+					n=n.Parent
+				Wend
+			Else
+				If node.Parent=node2 Return
+			Endif
+			
+			Local src:=node.Path
+			Local dest:=destNode.Path
+			
+			If Not dest.EndsWith( "/" ) Then dest+="/"
+			Local name:=StripDir( src )
+			dest+=name
+			
+			If Not CheckOverwritingConfirm( dest,name,srcIsFolder ) Return
+			
+			Local ok:=False
+			Local move:=(Keyboard.Modifiers & Modifier.Control)=0
+			
+			If srcIsFolder
+				ok=CopyDir( src,dest )
+				If ok And move Then DeleteDir( src,True )
+			Else
+				ok=CopyFile( src,dest )
+				If ok And move Then DeleteFile( src )
+			Endif
+			If ok
+				If move Then node.Remove()
+				
+				OnDraggedInto( destNode,name )
+			Else
+				Alert( "Can't move into "+ExtractDir( dest ) )
+			Endif
+			
+		End )
+		
+	End
+	
+	Method Detach:View( item:Object )
+		
+		' don't remove
+		Local node:=Cast<Node>( item )
+		
+		_draggingText=node.Text
+		If Not _draggableView
+			_draggableView=New Button( "",node.Icon )
+			_draggableView.Layout="float"
+		Else
+			_draggableView.Icon=node.Icon
+		Endif
+		
+		MakeKeyView() 'wonna catch Ctrl-key
+		
+		Return _draggableView
+	End
+	
+	Method OnDragStarted()
+		
+		_draggingState=True
+	End
+	
+	Method OnDragEnded()
+		
+		_draggingState=False
+	End
+	
+	Method OnFileDropped:Bool( path:String )
+		
+		Local point:=TransformWindowPointToView( Mouse.Location )
+		Local node:=Cast<Node>( FindNodeAtPoint( point ) )
+		If Not node Return False
+		
+		If GetFileType( node.Path )=FileType.File
+			node=Cast<Node>( node.Parent )
+		Endif
+		
+		Local dest:=node.Path
+		If Not dest.EndsWith( "/" ) Then dest+="/"
+		Local name:=StripDir( path )
+		dest+=name
+		
+		Local isFolder:=GetFileType( path )=FileType.Directory
+		
+		If Not CheckOverwritingConfirm( dest,name,isFolder ) Return True ' don't copied but return true
+		
+		Local ok:=False
+		If isFolder
+			ok=CopyDir( path,dest )
+		Else
+			ok=CopyFile( path,dest )
+		Endif
+		If ok
+			OnDraggedInto( node,name )
+		Else
+			Alert( "Can't copy into "+ExtractDir( dest ) )
+		Endif
+		
+		Return True
+	End
+	
+	Method NewNode:Node( parent:Node )
+		
+		Return New Node( parent,Self )
 	End
 	
 	Method AddProject( dir:String )
 		
-		Local node:=New Node( _rootNode )
+		Local node:=NewNode( _rootNode )
 		Local s:=StripDir( dir )+" ("+dir+")"
 		node.Text=s
 		node._path=dir
@@ -85,30 +215,62 @@ Class ProjectBrowserView Extends TreeViewExt
 	Method Refresh( node:Node )
 	
 		UpdateNode( node,True )
+		ApplyFilter( node )
+		Selected=node
 	End
 	
 	Method Refresh( tnode:TreeView.Node )
 		
 		Local node:=Cast<Node>( tnode )
-		If node then UpdateNode( node,True )
+		If node Then Refresh( node )
 	End
 	
 	
 	Protected
 	
-	Class Node Extends TreeView.Node
+	Class Node Extends TreeView.Node Implements IDraggableItem<ProjectBrowserView>
 	
-		Method New( parent:Node )
+		Method New( parent:Node,view:ProjectBrowserView )
+			
 			Super.New( "",parent )
+			_view=view
+			_curHolder=view
 		End
 	
 		Property Path:String()
 			Return _path
 		End
 		
+		Property Detachable:Bool()
+			Return GetNodeDeepLevel( Self )>1
+		End
+		
+		Property PossibleHolders:ProjectBrowserView[]()
+			Return _holders
+		Setter( value:ProjectBrowserView[] )
+			_holders=value
+		End
+		
+		Property CurrentHolder:ProjectBrowserView()
+			Return _curHolder
+		End
+		
+		Property View:View()
+		
+			Return _view
+		
+		Setter( view:View )
+		
+			_view=view
+		End
+		
 		Private
 	
 		Field _path:String
+		Field _holders:ProjectBrowserView[]
+		Field _curHolder:ProjectBrowserView
+		Field _view:View
+		
 	End
 	
 	Method GetFileTypeIcon:Image( path:String ) Virtual
@@ -144,6 +306,15 @@ Class ProjectBrowserView Extends TreeViewExt
 		Endif
 		
 		Super.OnKeyEvent( event )
+		
+		UpdateDraggingState()
+	End
+	
+	Method OnContentMouseEvent( event:MouseEvent ) Override
+		
+		Super.OnContentMouseEvent( event )
+		
+		UpdateDraggingState()
 	End
 	
 	
@@ -158,6 +329,48 @@ Class ProjectBrowserView Extends TreeViewExt
 	Field _dirIcon:Image
 	Field _fileIcon:Image
 	
+	Field _draggableView:Button
+	Field _draggingState:Bool
+	Field _draggingText:String
+	
+	Global _listener:DraggableProjTreeListener
+	
+	Method CheckOverwritingConfirm:Bool( destPath:String,name:String,isFolder:Bool )
+		
+		' confirm overwriting
+		Local confirm:=""
+		If isFolder And DirectoryExists( destPath )
+			confirm="Destination folder already contains '"+name+"' subfolder.~nDo you want to merge files replacing with moved ones?"
+		Elseif FileExists( destPath )
+			confirm="Destination folder already contains '"+name+"'.~nDo you want to replace existing file with moved one?"
+		Endif
+		
+		If confirm
+			Return RequestOkay( confirm,"" )
+		Endif
+		
+		Return True
+	End
+	
+	Method OnDraggedInto( node:Node,name:String )
+		
+		Local path:=node.Text+"\"+name
+		
+		node.Expanded=True
+		_expander.Store( node )
+		Local par:=IsProjectNode( node ) ? node Else node.Parent
+		OnNodeExpanded( par ) 'update parent folder
+		
+		SelectByPathEnds( path )
+		
+	End
+	
+	Method UpdateDraggingState()
+		
+		If _draggingState
+			_draggableView.Text=(Keyboard.Modifiers & Modifier.Control = 0) ? _draggingText Else _draggingText+" (copy)"
+		Endif
+	End
 	
 	Method FindProjectNode:Node( node:TreeView.Node )
 		
@@ -248,14 +461,14 @@ Class ProjectBrowserView Extends TreeViewExt
 		'Print "update node: "+path
 		If Not path.EndsWith( "/" ) path+="/"
 		Local dir:=filesystem.LoadDir( path )
-	
+		
 		Local dirs:=New Stack<String>
 		Local files:=New Stack<String>
-	
+		
 		For Local f:=Eachin dir
-	
+			
 			Local fpath:=path+f
-	
+			
 			Select GetFileType( fpath )
 			Case FileType.Directory
 				dirs.Add( f )
@@ -263,42 +476,42 @@ Class ProjectBrowserView Extends TreeViewExt
 				files.Add( f )
 			End
 		Next
-	
+		
 		dirs.Sort()
 		files.Sort()
-	
+		
 		Local i:=0,children:=node.Children
-	
+		
 		While i<dir.Length
-	
+			
 			Local f:=""
 			If i<dirs.Length f=dirs[i] Else f=files[i-dirs.Length]
-	
+			
 			Local child:Node
-	
+			
 			If i<children.Length
 				child=Cast<Node>( children[i] )
 				child.RemoveAllChildren()
 			Else
-				child=New Node( node )
+				child=NewNode( node )
 			Endif
-	
+			
 			Local fpath:=path+f
-	
+			
 			child.Text=f
 			child._path=fpath
-	
+			
 			Local icon:Image
 			If Prefs.MainProjectIcons 'Only load icon if settings say so
 				icon=GetFileTypeIcon( fpath )
 			Endif
-	
+			
 			If i<dirs.Length
 				If Not icon And Prefs.MainProjectIcons Then icon=_dirIcon
 				child.Icon=icon
-	
+				
 				_expander.Restore( child )
-	
+				
 				If child.Expanded Or recurse
 					UpdateNode( child,child.Expanded )
 				Endif
@@ -307,12 +520,12 @@ Class ProjectBrowserView Extends TreeViewExt
 				child.Icon=icon
 				child.RemoveAllChildren()
 			Endif
-	
+			
 			i+=1
 		Wend
-	
+		
 		node.RemoveChildren( i )
-	
+		
 	End
 	
 	Method OnNodeClicked( tnode:TreeView.Node )
@@ -324,7 +537,7 @@ Class ProjectBrowserView Extends TreeViewExt
 	End
 	
 	Method OnNodeRightClicked( tnode:TreeView.Node )
-	
+		
 		Local node:=Cast<Node>( tnode )
 		If Not node Return
 		
@@ -445,3 +658,19 @@ Class TextFilter
 	Field _type:=CheckType.Equals
 	
 End
+
+Class DraggableProjTreeListener Extends DraggableViewListener<ProjectBrowserView.Node,ProjectBrowserView>
+	
+	Method GetItem:ProjectBrowserView.Node( eventView:View,eventLocation:Vec2i ) Override
+		
+		Local projTree:=FindViewInHierarchy<ProjectBrowserView>( eventView )
+		
+		Return Cast<ProjectBrowserView.Node>( projTree?.FindNodeAtPoint( eventLocation ) )
+	End
+	
+	Method GetHolder:ProjectBrowserView( view:View ) Override
+	
+		Return Cast<ProjectBrowserView>( view )
+	End
+	
+End

+ 179 - 70
view/ProjectView.monkey2

@@ -56,6 +56,19 @@ Class ProjectView Extends ScrollView
 		Return ""
 	End
 	
+	Method OnFileDropped:Bool( path:String )
+		
+		Local ok:=_projBrowser.OnFileDropped( path )
+		If Not ok
+			Local isFolder:=GetFileType( path )=FileType.Directory
+			If isFolder
+				ok=True
+				OpenProject( path )
+			Endif
+		Endif
+		Return ok
+	End
+	
 	Method OpenProject:Bool( dir:String )
 	
 		dir=StripSlashes( dir )
@@ -145,6 +158,64 @@ Class ProjectView Extends ScrollView
 	Field _builder:IModuleBuilder
 	Field _projBrowser:ProjectBrowserView
 	
+	Field _cutPath:String,_copyPath:String
+	
+	Method OnCut( path:String )
+		
+		_copyPath=""
+		_cutPath=path
+	End
+	
+	Method OnCopy( path:String )
+		
+		_cutPath=""
+		_copyPath=path
+	End
+	
+	Method OnPaste:Bool( path:String )
+		
+		Local ok:=True
+		
+		If Not path.EndsWith( "/" ) Then path+="/"
+		
+		Local cut:=(_cutPath<>"")
+		Local srcPath:=cut ? _cutPath Else _copyPath
+		
+		Local isFolder:=(GetFileType( srcPath )=FileType.Directory)
+		
+		If isFolder And path.StartsWith( srcPath )
+			
+			Alert( "Can't paste into the same or nested folder!","Paste element" )
+			Return False
+		Endif
+		
+		Local name:=StripDir( srcPath )
+		
+		Local dest:=path+name
+		Local exists:=(GetFileType( dest )<>FileType.None)
+		
+		If exists
+			Local s:=RequestString( "New name:","Element already exists",name )
+			If Not s Or s=name Return False
+			name=s
+			dest=path+name
+		Endif
+		
+		If isFolder
+			ok=CopyDir( srcPath,dest )
+			If ok And cut Then DeleteDir( srcPath,True )
+		Else
+			ok=CopyFile( srcPath,dest )
+			If ok And cut Then DeleteFile( srcPath )
+		Endif
+		
+		If Not ok Then Alert( "Can't copy~n"+srcPath+"~ninto~n"+dest,"Paste element" )
+		
+		_cutPath=""
+		
+		Return ok
+	End
+	
 	Method DeleteItem( browser:ProjectBrowserView,path:String,node:TreeView.Node )
 		
 		Local nodeToRefresh:=Cast<ProjectBrowserView.Node>( node.Parent )
@@ -285,187 +356,225 @@ Class ProjectView Extends ScrollView
 		
 			Local menu:=New MenuExt
 			Local path:=node.Path
-		
+			Local pasteAction:Action
+			Local isFolder:=False
+			
 			Select GetFileType( path )
 			Case FileType.Directory
-		
+				
+				isFolder=True
+				
 				menu.AddAction( "Find..." ).Triggered=Lambda()
-		
+					
 					RequestedFindInFolder( path )
 				End
-		
+				
 				menu.AddSeparator()
-		
+				
 				menu.AddAction( "New class..." ).Triggered=Lambda()
-		
+					
 					Local d:=New GenerateClassDialog( path )
 					d.Generated+=Lambda( filePath:String,fileContent:String )
-		
+						
 						If CreateFileInternal( filePath,fileContent )
-		
+							
 							MainWindow.OpenDocument( filePath )
 							browser.Refresh( node )
 						Endif
 					End
 					d.ShowModal()
 				End
-		
+				
 				menu.AddSeparator()
-		
+				
 				menu.AddAction( "New file" ).Triggered=Lambda()
-		
+					
 					Local file:=RequestString( "New file name:" )
 					If Not file Return
-		
+					
 					Local tpath:=path+"/"+file
-		
+					
 					CreateFileInternal( tpath )
-		
+					
 					browser.Refresh( node )
 				End
-		
+				
 				menu.AddAction( "New folder" ).Triggered=Lambda()
-		
+					
 					Local dir:=RequestString( "New folder name:" )
 					If Not dir Return
-		
+					
 					Local tpath:=path+"/"+dir
-		
+					
 					If GetFileType( tpath )<>FileType.None
 						Alert( "A file or directory already exists at '"+tpath+"'" )
 						Return
 					End
-		
+					
 					If Not CreateDir( tpath )
 						Alert( "Failed to create folder '"+dir+"'" )
 						Return
 					Endif
-		
+					
 					browser.Refresh( node )
 				End
-		
+				
 				menu.AddAction( "Delete" ).Triggered=Lambda()
-		
+					
 					DeleteItem( browser,path,node )
 				End
-		
+				
 				menu.AddSeparator()
-		
+				
 				If browser.IsProjectNode( node ) ' root node
-		
+					
 					menu.AddAction( "Close project" ).Triggered=Lambda()
-		
+						
 						CloseProject( path )
 					End
-		
+					
 					menu.AddAction( "Clean (delete .buildv)" ).Triggered=Lambda()
-		
+						
 						If Not RequestOkay( "Really delete all '.buildv' folders?" ) Return
-		
+						
 						Local changes:=CleanProject( path )
 						If changes Then browser.Refresh( node )
 					End
 				Else
-		
+					
 					menu.AddAction( "Open as a project" ).Triggered=Lambda()
-		
+					
 						OpenProject( path )
 					End
 				Endif
-		
+				
 				' update / rebuild module
 				path=path.Replace( "\","/" )
 				Local name := path.Slice( path.FindLast( "/")+1 )
 				Local file:=path+"/module.json"
-		
+				
 				If path.Contains( "/modules/") And GetFileType( file )=FileType.File
-		
+					
 					menu.AddSeparator()
-		
+					
 					menu.AddAction( "Update / Rebuild "+name ).Triggered=Lambda()
-		
-						_builder.BuildModules( True,name )
+						
+						_builder.BuildModules( name )
 					End
-		
+					
 				Endif
-		
+				
 				' update all modules
 				Local path2:=MainWindow.ModsPath
 				If path2.EndsWith( "/" ) Then path2=path2.Slice( 0,path2.Length-1 )
-		
+				
 				If path = path2
-		
+					
 					menu.AddSeparator()
-		
+					
 					menu.AddAction( "Update / Rebuild modules" ).Triggered=Lambda()
-		
-						_builder.BuildModules( False )
+						
+						_builder.BuildModules()
 					End
-		
+					
 				Endif
-		
+				
 				' bananas showcase
 				If IsBananasShowcaseAvailable()
 					path2=Prefs.MonkeyRootPath+"bananas"
 					If path = path2
-		
+						
 						menu.AddSeparator()
-		
+						
 						menu.AddAction( "Open bananas showcase" ).Triggered=Lambda()
-		
+							
 							MainWindow.ShowBananasShowcase()
 						End
-		
+						
 					Endif
 				Endif
-		
+				
 				menu.AddSeparator()
-		
+				
 				menu.AddAction( "Open on Desktop" ).Triggered=Lambda()
-		
+					
 					requesters.OpenUrl( path )
 				End
-		
-		
+			
+			
 			Case FileType.File
-		
+				
 				menu.AddAction( "Open on Desktop" ).Triggered=Lambda()
-		
+					
 					requesters.OpenUrl( path )
 				End
-		
+				
 				menu.AddSeparator()
-		
+				
 				menu.AddAction( "Rename" ).Triggered=Lambda()
-		
+					
 					Local oldName:=StripDir( path )
 					Local name:=RequestString( "Enter new name:","Ranaming '"+oldName+"'",oldName )
 					If Not name Or name=oldName Return
-		
+					
 					Local newPath:=ExtractDir( path )+name
+					
+					If FileExists( newPath )
+						Alert( "File already exists! Path: '"+newPath+"'" )
+						Return
+					Endif
+					
 					If CopyFile( path,newPath )
-		
+						
 						DeleteFile( path )
-		
+						
 						browser.Refresh( node.Parent )
 						Return
 					Endif
-		
+					
 					Alert( "Failed to rename file: '"+path+"'" )
 				End
-		
+				
 				menu.AddSeparator()
-		
+				
 				menu.AddAction( "Delete" ).Triggered=Lambda()
-		
+					
 					DeleteItem( browser,path,node )
 				End
-		
+			
 			Default
-		
+				
 				Return
 			End
-		
+			
+			' cut / copy / paste
+			menu.AddSeparator()
+			
+			menu.AddAction( "Cut" ).Triggered=Lambda()
+			
+				OnCut( path )
+			End
+			
+			menu.AddAction( "Copy" ).Triggered=Lambda()
+			
+				OnCopy( path )
+			End
+			
+			pasteAction=menu.AddAction( "Paste" )
+			pasteAction.Triggered=Lambda()
+				
+				New Fiber( Lambda()
+					
+					Local ok:=OnPaste( path )
+					If ok
+						Local n:=browser.IsProjectNode( node ) ? node Else node.Parent
+						browser.Refresh( n )
+					Endif
+				End )
+				
+			End
+			pasteAction.Enabled=(_cutPath Or _copyPath) And isFolder
+			
 			menu.Open()
 		End
 		

+ 83 - 179
view/TabViewExt.monkey2

@@ -20,7 +20,8 @@ Class ScrollViewTabs Extends ScrollView
 		
 			Scroll-=delta
 		
-			If scroll<>Scroll event.Eat()
+			'If scroll<>Scroll event.Eat()
+			event.Eat()
 			Return
 		End
 		
@@ -34,7 +35,7 @@ End
 ' full copy of mojox.TabView
 ' can't extend it, all I need is private there
 '
-Class TabViewExt Extends DockingView
+Class TabViewExt Extends DockingView Implements IDraggableHolder
 
 	#rem monkeydoc Invoked when the current tab changes.
 	#end
@@ -107,10 +108,60 @@ Class TabViewExt Extends DockingView
 	Function CreateDraggableTab:TabButtonExt( text:String,view:View,possibleParents:TabViewExt[],icon:Image=Null,closable:Bool=False )
 		
 		Local tab:=New TabButtonExt( text,icon,view,closable,Null )
-		tab.PossibleParentDocks=possibleParents
+		tab.PossibleHolders=possibleParents
 		Return tab
 	End
 	
+	Method Attach( item:Object,eventLocation:Vec2i )
+		
+		Local tab:=Cast<TabButtonExt>( item )
+		AddTab( tab )
+		MakeCurrent( tab,True )
+		
+		_vis=True
+		_curIndex=CurrentIndex-1 '-1 for [+] tab
+	End
+	
+	Method Detach:View( item:Object )
+		
+		Local tab:=Cast<TabButtonExt>( item )
+		RemoveTab( tab )
+		tab.Selected=True
+		Return tab
+	End
+	
+	Method OnDragStarted()
+		
+		_dragDropMode=True
+		_curIndex=CurrentIndex
+		_vis=Visible
+		Visible=True
+		If Not _placeHolderTab
+			Local v:=New Label ("[Drop tab here]")
+			v.Style=GetStyle( "TabsDropArea","Label" )
+			v.Layout="fill"
+			v.Gravity=New Vec2f( .5,.5 )
+			_placeHolderTab=AddTab( "[+]",v,True )
+			_placeHolderContent=v
+		Else
+			AddTab( _placeHolderTab,True )
+		Endif
+	End
+	
+	Method OnDragEnded()
+		
+		If Not _dragDropMode Return
+		
+		_dragDropMode=False
+		
+		RemoveTab( _placeHolderTab )
+		_placeHolderTab=Null
+'		
+		Visible=(_vis And NumTabs>0)
+		
+		If _curIndex>=0 Then CurrentIndex=_curIndex
+	End
+	
 	#rem monkeydoc Tab view flags.
 	#end
 	Property Flags:TabViewFlags()
@@ -347,8 +398,9 @@ Class TabViewExt Extends DockingView
 	End
 	
 	Method SetTabText( view:View,text:String )
-	
-		SetTabText( TabIndex( view ),text )
+		
+		Local index:=TabIndex( view )
+		If index>=0 Then SetTabText( index,text )
 	End
 	
 	#rem monkeydoc Sets a tab's icon.
@@ -378,38 +430,6 @@ Class TabViewExt Extends DockingView
 		Next
 	End
 	
-	Method ShowDragPlaceHolder()
-		
-		_dragDropMode=True
-		_curIndex=CurrentIndex
-		_vis=Visible
-		Visible=True
-		If Not _placeHolderTab
-			Local v:=New Label ("[Drop tab here]")
-			v.Style=GetStyle( "TabsDropArea","Label" )
-			v.Layout="fill"
-			v.Gravity=New Vec2f( .5,.5 )
-			_placeHolderTab=AddTab( "[+]",v,True )
-			_placeHolderContent=v
-		Else
-			AddTab( _placeHolderTab,True )
-		Endif
-	End
-	
-	Method HideDragPlaceHolder()
-		
-		If Not _dragDropMode Return
-		
-		_dragDropMode=False
-		
-		RemoveTab( _placeHolderTab )
-		_placeHolderTab=Null
-'		
-		Visible=(_vis And NumTabs>0)
-		
-		If _curIndex>=0 Then CurrentIndex=_curIndex
-	End
-	
 	
 	Protected
 	
@@ -516,7 +536,7 @@ Class TabViewExt Extends DockingView
 End
 
 
-Class TabButtonExt Extends TabButton
+Class TabButtonExt Extends TabButton Implements IDraggableItem<TabViewExt>
 	
 	Field ActiveChanged:Void()
 	
@@ -524,17 +544,18 @@ Class TabButtonExt Extends TabButton
 		
 		Super.New( text,icon,view,closable )
 		_parentDock=parentDock
+		_closable=closable
 	End
 	
 	Property Detachable:Bool()
-		Return PossibleParentDocks<>Null
+		Return PossibleHolders<>Null
 	End
 	
-	Property ParentDock:TabViewExt()
+	Property CurrentHolder:TabViewExt()
 		Return _parentDock
 	End
 	
-	Property PossibleParentDocks:TabViewExt[]()
+	Property PossibleHolders:TabViewExt[]()
 		Return _possibleParentDocks
 	Setter( value:TabViewExt[] )
 		_possibleParentDocks=value
@@ -542,22 +563,7 @@ Class TabButtonExt Extends TabButton
 	
 	Method Activate()
 		
-		Local dock:=ParentDock
-		If dock Then dock.MakeCurrent( Text )
-	End
-	
-	Method TryDropTo( tabDock:TabViewExt )
-		
-		If Not CanDropTo( tabDock )
-			tabDock=_parentDock
-		Endif
-		
-		_parentDock.Visible=(_parentDock.NumTabs>0)
-		_parentDock=tabDock
-		tabDock.AddTab( Self )
-		tabDock.Visible=True
-		
-		Activate()
+		CurrentHolder?.MakeCurrent( Text )
 	End
 	
 	Property IsActive:Bool()
@@ -581,25 +587,26 @@ Class TabButtonExt Extends TabButton
 		Style=GetStyle( _locked ? "TabButtonLocked" Else "TabButton" )
 	End
 	
+	Method OnMouseEvent( event:MouseEvent ) Override
+		
+		If _closable And 
+			event.Type=EventType.MouseUp And 
+			event.Button=MouseButton.Middle
+			
+			CloseClicked()
+			event.Eat()
+			Return
+		Endif
+		
+		Super.OnMouseEvent( event )
+	End
+	
 	
 	Private
 	
 	Field _possibleParentDocks:TabViewExt[]
 	Field _locked:Bool
-	
-	Method CanDropTo:Bool( tabDock:TabViewExt )
-	
-		If Not tabDock Print "if 1" ; Return False
-		If Not _possibleParentDocks Print "if 1" ; Return False
-	
-		For Local d:=Eachin _possibleParentDocks
-	
-			If d=tabDock Return True
-		Next
-		Print "false"
-		Return False
-	End
-	
+	Field _closable:Bool
 End
 
 
@@ -623,119 +630,16 @@ Class TabButtonExt_Bridge Extends TabButtonExt Abstract
 End
 
 
-Class DraggableTabsListener
+Class DraggableTabsListener Extends DraggableViewListener<TabButtonExt,TabViewExt>
 	
-	Method New()
+	Method GetItem:TabButtonExt( eventView:View,eventLocation:Vec2i ) Override
 		
-		App.MouseEventFilter+=OnMouseEvent
+		Return Cast<TabButtonExt>( eventView )
 	End
 	
-	Private
-	
-	Global _label:Label
-	Global _tab:TabButtonExt
-	Global _pressedPos:Vec2i
-	Global _detached:Bool
-	
-	Function OnMouseEvent( event:MouseEvent )
-	
-		Select event.Type
-			
-			Case EventType.MouseDown
-				
-				_tab=Cast<TabButtonExt>( event.View )
-				If Not _tab Return
-				
-				If Not _tab.Detachable
-					_tab=Null
-					Return
-				Endif
-				
-				_pressedPos=Mouse.Location
-				
-			
-			Case EventType.MouseMove
-			
-				If Not _tab Return
-				
-				If _detached
-					Local r:=_tab.Frame
-					Local sz:=r.Size
-					r.TopLeft=Mouse.Location+New Vec2i( 0,-10 )
-					r.BottomRight=r.TopLeft+sz
-					_tab.Frame=r
-					App.RequestRender()
-					Return
-				Endif
-				
-				Local dy:Float=Abs(Mouse.Y-_pressedPos.y)
-				If dy>10.0*App.Theme.Scale.y
-					Detach()
-				Endif
-				
-				
-			Case EventType.MouseUp
-				
-				If Not _detached 
-					_tab=Null
-					Return
-				Endif
-				
-				MainWindow.RemoveChildView( _tab )
-				
-				Local dock:TabViewExt=Null
-				Local v:=App.ActiveViewAtMouseLocation()
-				While v
-					Local d:=Cast<TabViewExt>( v )
-					If d
-						dock=d
-						Exit
-					Endif
-					v=v.Parent
-				Wend
-				
-				If _tab.PossibleParentDocks
-					For Local d:=Eachin _tab.PossibleParentDocks
-						d.HideDragPlaceHolder()
-					Next
-				Endif
-				
-				_tab.TryDropTo( dock )
-				
-				_tab=Null
-				_detached=False
-			
-		End
-	
-	End
-	
-	Function Detach()
-		
-		_detached=True
-		
-'		If Not _label
-'			_label=New Label
-'			_label.Layout="float"
-'			_label.MaxSize=New Vec2i( 40,100 )
-'			MainWindow.AddChildView( _label )
-'		Endif
-'		_label.Text=_tab.Text
-'		_label.Visible=True
-		'Local size:=_label.MeasureLayoutSize()
-		'_label.Frame=New Recti( Mouse.Location,Mouse.Location+size)
-		
-		_tab.ParentDock.RemoveTab( _tab )
-		MainWindow.AddChildView( _tab )
-		_tab.Selected=True
-		
-		If Not _tab.PossibleParentDocks Return
-		
-		For Local d:=Eachin _tab.PossibleParentDocks
-			d.ShowDragPlaceHolder()
-		Next
+	Method GetHolder:TabViewExt( view:View ) Override
 		
+		Return FindViewInHierarchy<TabViewExt>( view )
 	End
 	
-	
 End
-	

+ 31 - 7
view/Ted2CodeTextView.monkey2

@@ -3,15 +3,31 @@ Namespace ted2go
 
 
 Class Ted2CodeTextView Extends CodeTextView
-
+	
+	Method New( doc:Ted2Document )
+		
+		_document=doc
+		
+		AdjustFileType()
+		
+		_document.Renamed+=Lambda( newPath:String,oldPath:String )
+			
+			AdjustFileType()
+		End
+	End
+	
 	Property FileType:String() 'where else we can store this type?
-		return _type
+		
+		Return _type
+		
 	Setter( value:String )
+		
+		If value=_type Return
 		_type=value
-		Keywords = KeywordsManager.Get(_type)
-		Highlighter = HighlightersManager.Get(_type)
-		Formatter = FormattersManager.Get(_type)
-		Document.TextHighlighter = Highlighter.Painter
+		Keywords=KeywordsManager.Get(_type)
+		Highlighter=HighlightersManager.Get(_type)
+		Formatter=FormattersManager.Get(_type)
+		Document.TextHighlighter=Highlighter.Painter
 	End
 	
 	Property FilePath:String()
@@ -31,6 +47,14 @@ Class Ted2CodeTextView Extends CodeTextView
 	
 	Protected
 	
+	Field _document:Ted2Document
+	
+	Method AdjustFileType()
+		
+		FileType=_document.FileExtension
+		FilePath=_document.Path
+	End
+	
 	Method OnKeyEvent( event:KeyEvent ) Override
 	
 		TextViewKeyEventFilter.FilterKeyEvent( event,Self,FileType )
@@ -40,7 +64,7 @@ Class Ted2CodeTextView Extends CodeTextView
 		Endif
 		
 	End
-
+	
 	Private
 	
 	Field _type:String

+ 1 - 1
view/ToolBarViewExt.monkey2

@@ -21,7 +21,7 @@ Class ToolBarExt Extends ToolBar
 	End
 	
 	Method AddIconicButton:MultiIconToolButton( icons:Image[],trigger:Void(),hint:String=Null )
-	
+		
 		Local act:=New Action( Null )
 		act.Triggered=trigger
 		Local b:=New MultiIconToolButton( act,icons,hint )

+ 113 - 10
view/TreeViewExt.monkey2

@@ -15,7 +15,7 @@ Class TreeViewExt Extends TreeView
 		
 		Super.New()
 		
-		Super.NodeClicked+=Lambda( node:Node )
+		NodeClicked2+=Lambda( node:Node )
 			
 			If _singleClickExpanding
 				If TrySwitchExpandingState( node ) Return
@@ -41,6 +41,8 @@ Class TreeViewExt Extends TreeView
 		
 		Super.NodeExpanded+=Lambda( node:Node )
 			
+			_expandStateChanged=True
+			
 			_expander.Store( node )
 			OnSelect( node )
 			NodeExpanded( node )
@@ -48,6 +50,8 @@ Class TreeViewExt Extends TreeView
 		
 		Super.NodeCollapsed+=Lambda( node:Node )
 			
+			_expandStateChanged=True
+			
 			_expander.Store( node )
 			OnSelect( node )
 			NodeCollapsed( node )
@@ -62,9 +66,10 @@ Class TreeViewExt Extends TreeView
 		
 	Setter( value:TreeView.Node )
 		
-		If _sel=value Return
-		_sel=value
-		SelectedChanged( _sel )
+		If _sel<>value
+			_sel=value
+			SelectedChanged( _sel )
+		Endif
 		
 		EnsureVisible( _sel )
 		
@@ -91,6 +96,15 @@ Class TreeViewExt Extends TreeView
 		_expander.LoadState( jobj,jkey )
 	End
 	
+	Method FindByText:TreeView.Node( text:String,recursive:Bool=False )
+	
+		Return FindSubNode( RootNode,
+						recursive,
+						Lambda:Bool( n:TreeView.Node )
+							Return n.Text=text
+						End )
+	End
+	
 	Method FindSubNode:TreeView.Node( text:String,whereNode:TreeView.Node,recursive:Bool=False )
 		
 		Return FindSubNode( whereNode,
@@ -132,6 +146,22 @@ Class TreeViewExt Extends TreeView
 		If n Then Selected=n
 	End
 	
+	Method SelectByPathEnds( pathEnding:String )
+	
+		Local n:=FindSubNode( RootNode,
+						True,
+						Lambda:Bool( n:TreeView.Node )
+							Return GetNodePath( n ).EndsWith( pathEnding )
+						End )
+	
+		If n Then Selected=n
+	End
+	
+	Method Sort()
+	
+		SortNode( RootNode )
+	End
+	
 	
 	Protected
 	
@@ -165,19 +195,39 @@ Class TreeViewExt Extends TreeView
 				' make scroll little faster
 				Scroll-=New Vec2i( 0,RenderStyle.Font.Height*event.Wheel.Y*2 )
 				Return
-		
+			
+			Case EventType.MouseClick
+				
+				_expandStateChanged=False
+				
+				
+			Case EventType.MouseUp
+				
+				If event.Button=MouseButton.Left
+					
+					Local p:=TransformWindowPointToView( Mouse.Location )
+					Local node:=FindNodeAtPoint( p )
+					If node And Not _expandStateChanged Then NodeClicked2( node )
+				Endif
 		End
 		
 		Super.OnContentMouseEvent( event )
 		
 	End
 	
+'	Method PrintExpanded()
+'		
+'		_expander.PrintExpanded()
+'	End
 	
 	Private
 	
 	Field _sel:TreeView.Node
 	Field _selColor:Color
 	Field _singleClickExpanding:Bool
+	Field _expandStateChanged:Bool
+	
+	Field NodeClicked2:Void( node:Node )
 	
 	Method TrySwitchExpandingState:Bool( node:TreeView.Node )
 		
@@ -202,15 +252,15 @@ Class TreeViewExt Extends TreeView
 	End
 	
 	Method EnsureVisible( node:TreeView.Node )
-		
+	
 		If Not node Return
-		
+	
 		Local n:=node.Parent
 		While n
 			n.Expanded=True
 			n=n.Parent
 		Wend
-		
+	
 		' scroll Y only 
 		Local sx:=Scroll.x
 		Local scroll:=Scroll
@@ -219,17 +269,53 @@ Class TreeViewExt Extends TreeView
 		Scroll=scroll
 	End
 	
+	Method SortNode( node:TreeView.Node )
+		
+		If node.Children.Length=0 Return
+		
+		Local children:=New Stack<TreeView.Node>
+		children+=node.Children
+		
+		children.Sort( Lambda:Int( lhs:TreeView.Node,rhs:TreeView.Node )
+			
+			Return lhs.Text<=>rhs.Text
+		End )
+		
+		node.RemoveAllChildren()
+		
+		For Local n:=Eachin children
+			node.AddChild( n )
+			
+			SortNode( n )
+		Next
+	End
+	
 End
 
 
 Class TreeViewExpander
 	
+	Function ExpandParents( node:TreeView.Node )
+		
+		Local p:=node.Parent
+		While p<>Null
+			p.Expanded=True
+			p=p.Parent
+		Wend
+	End
+	
 	Method Store( node:TreeView.Node,recurse:Bool=False )
 	
 		Local key:=GetNodePath( node )
 	
 		If node.Expanded
 			_expands[key]=True
+			' grab all parents states
+			Local p:=node.Parent
+			While p<>Null
+				If p.Expanded Then _expands[GetNodePath( p )]=True
+				p=p.Parent
+			Wend
 		Else
 			_expands.Remove( key )
 		Endif
@@ -245,7 +331,7 @@ Class TreeViewExpander
 	
 		Local key:=GetNodePath( node )
 		
-		node.Expanded = _expands.Contains( key ) ? True Else False
+		node.Expanded=_expands.Contains( key )
 		
 		If Not recurse Return
 		
@@ -277,7 +363,14 @@ Class TreeViewExpander
 		Next
 	End
 	
-	Private
+	Method PrintExpanded()
+		
+		For Local key:=Eachin _expands.Keys
+			If _expands[key] Print "expanded: "+key
+		Next
+	End
+	
+	Protected
 	
 	Field _expands:=New StringMap<Bool>
 	
@@ -319,3 +412,13 @@ Function GetNodePath:String( node:TreeView.Node )
 	Wend
 	Return s
 End
+
+Function GetNodeDeepLevel:Int( node:TreeView.Node )
+	
+	Local level:=-1
+	While node
+		level+=1
+		node=node.Parent
+	Wend
+	Return level
+End