Browse Source

tweaks to mojo in prep. for mojox.

Mark Sibly 9 years ago
parent
commit
ee94b4bcc9

+ 205 - 91
modules/mojo/app/app.monkey2

@@ -1,9 +1,10 @@
 
 
+#Import "native/async.cpp"
+
 Namespace mojo.app
 Namespace mojo.app
 
 
-#Import "native/async.cpp"
-#Import "assets/Roboto-Regular.ttf@/mojo"
-#Import "assets/RobotoMono-Regular.ttf@/mojo"
+'#Import "assets/Roboto-Regular.ttf@/mojo"
+'#Import "assets/RobotoMono-Regular.ttf@/mojo"
 
 
 #rem monkeydoc The global AppInstance instance.
 #rem monkeydoc The global AppInstance instance.
 #end
 #end
@@ -40,15 +41,31 @@ Class AppInstance
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
 	#end
 	#end
 	Field NextIdle:Void()	
 	Field NextIdle:Void()	
+
+	#rem monkeydoc @hidden
+	#end
+	Field ThemeChanged:Void()
+	
+	#rem monkeydoc Invoked when app is activated.
+	#end
+	Field Activated:Void()
+	
+	#rem monkeydoc Invoked when app is deactivated.
+	#end
+	Field Deactivated:Void()
 	
 	
 	#rem monkeydoc Key event filter.
 	#rem monkeydoc Key event filter.
 	
 	
+	To prevent the event from being sent to a view, a filter can eat the event using [[Event.Eat]].
+	
 	Functions should check if the event has already been 'eaten' by checking the event's [[Event.Eaten]] property before processing the event.
 	Functions should check if the event has already been 'eaten' by checking the event's [[Event.Eaten]] property before processing the event.
 	
 	
 	#end
 	#end
 	Field KeyEventFilter:Void( event:KeyEvent )
 	Field KeyEventFilter:Void( event:KeyEvent )
 
 
 	#rem monkeydoc MouseEvent filter.
 	#rem monkeydoc MouseEvent filter.
+	
+	To prevent the event from being sent to a view, a filter can eat the event using [[Event.Eat]].
 
 
 	Functions should check if the event has already been 'eaten' by checking the event's [[Event.Eaten]] property before processing the event.
 	Functions should check if the event has already been 'eaten' by checking the event's [[Event.Eaten]] property before processing the event.
 	
 	
@@ -67,8 +84,6 @@ Class AppInstance
 		
 		
 		SDL_Init( SDL_INIT_EVERYTHING & ~SDL_INIT_AUDIO )
 		SDL_Init( SDL_INIT_EVERYTHING & ~SDL_INIT_AUDIO )
 		
 		
-		_sdlThread=SDL_ThreadID()
-		
 		Keyboard.Init()
 		Keyboard.Init()
 		
 		
 		Mouse.Init()
 		Mouse.Init()
@@ -83,40 +98,38 @@ Class AppInstance
 		SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE,Int( GetConfig( "GL_depth_buffer_enabled",0 ) ) )
 		SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE,Int( GetConfig( "GL_depth_buffer_enabled",0 ) ) )
 		SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE,Int( GetConfig( "GL_stencil_buffer_enabled",0 ) ) )
 		SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE,Int( GetConfig( "GL_stencil_buffer_enabled",0 ) ) )
 
 
-		_dummyWindow=New Window( "<hidden>",Self )
-		
+		'create dummy window/context
+		Local _sdlWindow:=SDL_CreateWindow( "<dummy>",0,0,0,0,SDL_WINDOW_HIDDEN|SDL_WINDOW_OPENGL )
+		Assert( _sdlWindow,"FATAL ERROR: SDL_CreateWindow failed" )
+
+		Local _sdlGLContext:=SDL_GL_CreateContext( _sdlWindow )
+		Assert( _sdlGLContext,"FATAL ERROR: SDL_GL_CreateContext failed" )
+		SDL_GL_MakeCurrent( _sdlWindow,_sdlGLContext )	
+
 #Endif
 #Endif
-		_defaultFont=Font.Open( DefaultFontName,16 )
+		_defaultFont=Font.Open( "asset::fonts/DejaVuSans.ttf",16 )
 		
 		
-		_defaultMonoFont=Font.Open( DefaultMonoFontName,16 )
-
-		Local style:=Style.GetStyle( "" )
-		style.DefaultFont=_defaultFont
-		style.DefaultColor=Color.White
+		_theme=Theme.Load( GetConfig( "initialTheme","asset::themes/default.json" ) )
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
-	#end
-	Property DefaultFontName:String()
-		Return "asset::mojo/Roboto-Regular.ttf"
-	End
-	
-	#rem monkeydoc @hidden
-	#end
-	Property DefaultMonoFontName:String()
-		Return "asset::mojo/RobotoMono-Regular.ttf"
-	End
-	
-	#rem monkeydoc @hidden
+	#rem monkeydoc Fallback font.
 	#end
 	#end
 	Property DefaultFont:Font()
 	Property DefaultFont:Font()
+	
 		Return _defaultFont
 		Return _defaultFont
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc The current theme.
 	#end
 	#end
-	Property DefaultMonoFont:Font()
-		Return _defaultMonoFont
+	Property Theme:Theme()
+	
+		Return _theme
+		
+	Setter( theme:Theme )
+	
+		_theme=theme
+		
+		ThemeChanged()
 	End
 	End
 	
 	
 	#rem monkeydoc True if clipboard text is empty.
 	#rem monkeydoc True if clipboard text is empty.
@@ -159,16 +172,15 @@ Class AppInstance
 	#end
 	#end
 	Property KeyView:View()
 	Property KeyView:View()
 	
 	
-		Local window:=ActiveWindow
-		If window Return window.KeyView
+		If IsActive( _keyView ) Return _keyView
 		
 		
-		Return Null
+		If _modalView Return _modalView
+		
+		Return _activeWindow
 		
 		
 	Setter( keyView:View )
 	Setter( keyView:View )
-
-		Local window:=ActiveWindow
-		If window window.KeyView=keyView
-
+	
+		_keyView=keyView
 	End
 	End
 	
 	
 	#rem monkeydoc The current mouse view.
 	#rem monkeydoc The current mouse view.
@@ -208,15 +220,40 @@ Class AppInstance
 #Endif
 #Endif
 
 
 	End
 	End
+	
+	#rem monkeydoc True if app is active.
+	
+	An app is active if any of its windows has system input focus.
+	
+	If Active is true, then [[ActiveWindow]] will always be non-null.
+	
+	If Active is false, then [[ActiveWindow]] will always be null.
+	
+	#end
+	Property Active:Bool()
+	
+		Return _active
+	End
 
 
-	#rem monkeydoc The current active window.
+	#rem monkeydoc The currently active window.
+	
+	The active window is the window that has system input focus.
+	
+	If ActiveWindow is non-null, then [[Active]] will always be true.
 	
 	
-	The active window is the window that has input focus.
+	If ActiveWindow is null, then [[Active]] will always be false.
 	
 	
 	#end
 	#end
 	Property ActiveWindow:Window()
 	Property ActiveWindow:Window()
+
+		#rem	
+		If Not _activeWindow
+			Local windows:=Window.VisibleWindows()
+			If windows _activeWindow=windows[0]
+		Endif
+		#end
 	
 	
-		Return Window.VisibleWindows()[0]
+		Return _activeWindow
 	End
 	End
 	
 	
 	#rem monkeydoc Approximate frames per second rendering rate.
 	#rem monkeydoc Approximate frames per second rendering rate.
@@ -246,6 +283,23 @@ Class AppInstance
 		Return _mouseLocation
 		Return _mouseLocation
 	End
 	End
 	
 	
+	Property ModalView:View()
+	
+		Return _modalView
+	End
+	
+	#rem monkeydoc @hidden
+	#end
+	Method WaitIdle()
+		Local future:=New Future<Bool>
+		
+		Idle+=Lambda()
+			future.Set( True )
+		End
+		
+		future.Get()
+	End
+	
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
 	#end
 	#end
 	Method GetConfig:String( name:String,defValue:String )
 	Method GetConfig:String( name:String,defValue:String )
@@ -273,14 +327,21 @@ Class AppInstance
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
 	#end
 	#end
 	Method BeginModal( view:View )
 	Method BeginModal( view:View )
+	
 		_modalStack.Push( _modalView )
 		_modalStack.Push( _modalView )
+		
 		_modalView=view
 		_modalView=view
+		
+		RequestRender()
 	End
 	End
 	
 	
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
 	#end
 	#end
 	Method EndModal()
 	Method EndModal()
+	
 		_modalView=_modalStack.Pop()
 		_modalView=_modalStack.Pop()
+		
+		RequestRender()
 	End
 	End
 	
 	
 	#rem monkeydoc Terminate the app.
 	#rem monkeydoc Terminate the app.
@@ -293,7 +354,7 @@ Class AppInstance
 	#rem monkeydoc Request that the app render itself.
 	#rem monkeydoc Request that the app render itself.
 	#end
 	#end
 	Method RequestRender()
 	Method RequestRender()
-
+	
 		_requestRender=True
 		_requestRender=True
 	End
 	End
 
 
@@ -309,17 +370,57 @@ Class AppInstance
 	
 	
 		UpdateEvents()
 		UpdateEvents()
 		
 		
-		If Not _requestRender Return
+		UpdateWindows()
+	End
+	
+	#rem @hiddden
+	#end
+	Method IsActive:Bool( view:View )
+	
+		Return view And view.Active And (Not _modalView Or view.IsChildOf( _modalView ))
+	End
+	
+	#rem @hiddden
+	#end
+	Method ActiveViewAtMouseLocation:View()
+	
+		If Not _window Return Null
+		
+		Local view:=_window.FindViewAtWindowPoint( _mouseLocation )
+		If IsActive( view ) Return view
 		
 		
+		Return Null
+	End
+
+	#rem @hidden
+	#end	
+	Method UpdateWindows()
+	
+		Local render:=_requestRender
 		_requestRender=False
 		_requestRender=False
 		
 		
-		UpdateFPS()
-			
+		If render UpdateFPS()
+		
 		For Local window:=Eachin Window.VisibleWindows()
 		For Local window:=Eachin Window.VisibleWindows()
-			window.Update()
-			window.Render()
-		Next
-			
+			window.UpdateWindow( render )
+		End
+
+		If _mouseView And Not IsActive( _mouseView )
+			SendMouseEvent( EventType.MouseUp,_mouseView )
+			_mouseView=Null
+		Endif
+		
+		If _hoverView And Not IsActive( _hoverView )
+			SendMouseEvent( EventType.MouseLeave,_hoverView )
+			_hoverView=Null
+		Endif
+		
+		If Not _hoverView
+			_hoverView=ActiveViewAtMouseLocation()
+			If _mouseView And _hoverView<>_mouseView _hoverView=Null
+			If _hoverView SendMouseEvent( EventType.MouseEnter,_hoverView )
+		Endif
+		
 	End
 	End
 	
 	
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
@@ -355,24 +456,23 @@ Class AppInstance
 
 
 	Private
 	Private
 	
 	
-	Field _sdlThread:SDL_threadID
-	
 	Field _config:StringMap<String>
 	Field _config:StringMap<String>
 	
 	
-	Field _dummyWindow:Window
-
 	Field _defaultFont:Font
 	Field _defaultFont:Font
-	Field _defaultMonoFont:Font
-		
-	Field _requestRender:Bool
+	Field _theme:Theme
+
+	Field _active:Bool
+	Field _activeWindow:Window
 	
 	
+	Field _keyView:View
 	Field _hoverView:View
 	Field _hoverView:View
 	Field _mouseView:View
 	Field _mouseView:View
 	
 	
+	Field _requestRender:Bool
 	Field _fps:Float
 	Field _fps:Float
 	Field _fpsFrames:Int
 	Field _fpsFrames:Int
 	Field _fpsMillis:Int
 	Field _fpsMillis:Int
-	
+
 	Field _window:Window
 	Field _window:Window
 	Field _key:Key
 	Field _key:Key
 	Field _rawKey:Key
 	Field _rawKey:Key
@@ -381,6 +481,7 @@ Class AppInstance
 	Field _mouseButton:MouseButton
 	Field _mouseButton:MouseButton
 	Field _mouseLocation:Vec2i
 	Field _mouseLocation:Vec2i
 	Field _mouseWheel:Vec2i
 	Field _mouseWheel:Vec2i
+	Field _mouseClicks:Int=0
 	
 	
 	Field _modalView:View
 	Field _modalView:View
 	Field _modalStack:=New Stack<View>
 	Field _modalStack:=New Stack<View>
@@ -424,16 +525,11 @@ Class AppInstance
 		NextIdle=Null
 		NextIdle=Null
 		idle()
 		idle()
 		
 		
-		For Local window:=Eachin Window.VisibleWindows()
-'			window.Update()
-		Next
-
 	End
 	End
 	
 	
 	Method SendKeyEvent( type:EventType )
 	Method SendKeyEvent( type:EventType )
 	
 	
 		Local view:=KeyView
 		Local view:=KeyView
-		If view And Not view.ReallyEnabled view=Null
 		
 		
 		Local event:=New KeyEvent( type,view,_key,_rawKey,_modifiers,_keyChar )
 		Local event:=New KeyEvent( type,view,_key,_rawKey,_modifiers,_keyChar )
 		
 		
@@ -441,28 +537,43 @@ Class AppInstance
 		
 		
 		If event.Eaten Return
 		If event.Eaten Return
 		
 		
-		If _modalView And Not view.IsChildOf( _modalView ) Return
-		
-		If view 
-			view.SendKeyEvent( event )
-		Else If ActiveWindow
-			ActiveWindow.SendKeyEvent( event )
-		Endif
+		If view view.SendKeyEvent( event )
 	End
 	End
 	
 	
 	Method SendMouseEvent( type:EventType,view:View )
 	Method SendMouseEvent( type:EventType,view:View )
 	
 	
 		Local location:=view.TransformWindowPointToView( _mouseLocation )
 		Local location:=view.TransformWindowPointToView( _mouseLocation )
 		
 		
-		Local event:=New MouseEvent( type,view,location,_mouseButton,_mouseWheel,_modifiers )
+		Local event:=New MouseEvent( type,view,location,_mouseButton,_mouseWheel,_modifiers,_mouseClicks )
 		
 		
 		MouseEventFilter( event )
 		MouseEventFilter( event )
 		
 		
 		If event.Eaten Return
 		If event.Eaten Return
 		
 		
-		If _modalView And Not view.IsChildOf( _modalView ) Return
-		
 		view.SendMouseEvent( event )
 		view.SendMouseEvent( event )
+		
+		If event.Eaten Return
+		
+		Select type
+		Case EventType.MouseDown
+		
+			Select _mouseButton
+			Case MouseButton.Left
+			
+				SendMouseEvent( EventType.MouseClick,view )
+				
+				If _mouseClicks And Not (_mouseClicks & 1)
+				
+					SendMouseEvent( EventType.MouseDoubleClick,view )
+					
+				End
+			
+			Case MouseButton.Right
+
+				SendMouseEvent( EventType.MouseRightClick,view )
+			End
+		End
+		
 	End
 	End
 	
 	
 	Method SendWindowEvent( type:EventType )
 	Method SendWindowEvent( type:EventType )
@@ -535,7 +646,8 @@ Class AppInstance
 			
 			
 			If Not _mouseView
 			If Not _mouseView
 			
 			
-				Local view:=_window.FindViewAtWindowPoint( _mouseLocation )
+				Local view:=ActiveViewAtMouseLocation()
+
 				If view
 				If view
 '#If __HOSTOS__<>"linux"
 '#If __HOSTOS__<>"linux"
 					SDL_CaptureMouse( SDL_TRUE )
 					SDL_CaptureMouse( SDL_TRUE )
@@ -544,7 +656,14 @@ Class AppInstance
 				Endif
 				Endif
 			Endif
 			Endif
 				
 				
-			If _mouseView SendMouseEvent( EventType.MouseDown,_mouseView )
+			If _mouseView 
+			
+				_mouseClicks=mevent->clicks
+				
+				SendMouseEvent( EventType.MouseDown,_mouseView )
+				
+				_mouseClicks=0
+			Endif
 		
 		
 		Case SDL_MOUSEBUTTONUP
 		Case SDL_MOUSEBUTTONUP
 		
 		
@@ -576,8 +695,7 @@ Class AppInstance
 			
 			
 			_mouseLocation=New Vec2i( mevent->x,mevent->y )
 			_mouseLocation=New Vec2i( mevent->x,mevent->y )
 			
 			
-			Local view:=_window.FindViewAtWindowPoint( _mouseLocation )
-
+			Local view:=ActiveViewAtMouseLocation()
 			If _mouseView And view<>_mouseView view=Null
 			If _mouseView And view<>_mouseView view=Null
 			
 			
 			If view<>_hoverView
 			If view<>_hoverView
@@ -639,12 +757,24 @@ Class AppInstance
 			
 			
 			Case SDL_WINDOWEVENT_FOCUS_GAINED
 			Case SDL_WINDOWEVENT_FOCUS_GAINED
 			
 			
+				Local active:=_active
+				_activeWindow=_window
+				_active=True
+				
 				SendWindowEvent( EventType.WindowGainedFocus )
 				SendWindowEvent( EventType.WindowGainedFocus )
+				
+				If active<>_active Activated()
 			
 			
 			Case SDL_WINDOWEVENT_FOCUS_LOST
 			Case SDL_WINDOWEVENT_FOCUS_LOST
 			
 			
+				Local active:=_active
+				_activeWindow=Null
+				_active=False
+			
 				SendWindowEvent( EventType.WindowLostFocus )
 				SendWindowEvent( EventType.WindowLostFocus )
 				
 				
+				If active<>_active Deactivated()
+				
 			Case SDL_WINDOWEVENT_LEAVE
 			Case SDL_WINDOWEVENT_LEAVE
 			
 			
 				If _hoverView
 				If _hoverView
@@ -680,13 +810,6 @@ Class AppInstance
 	
 	
 	Method EventFilter:Int( userData:Void Ptr,event:SDL_Event Ptr )
 	Method EventFilter:Int( userData:Void Ptr,event:SDL_Event Ptr )
 	
 	
-		#rem
-		If SDL_ThreadID()<>_sdlThread 
-			Print "Yikes! EventFilter running in non-main thread..."
-			Return 1
-		Endif
-		#end
-			
 		Select event[0].type
 		Select event[0].type
 		Case SDL_WINDOWEVENT
 		Case SDL_WINDOWEVENT
 
 
@@ -707,16 +830,7 @@ Class AppInstance
 			
 			
 				SendWindowEvent( EventType.WindowResized )
 				SendWindowEvent( EventType.WindowResized )
 				
 				
-				If _requestRender
-				
-					_requestRender=False
-					
-					For Local window:=Eachin Window.VisibleWindows()
-						window.Update()
-						window.Render()
-					Next
-					
-				Endif
+				UpdateWindows()
 			
 			
 				Return 0
 				Return 0
 
 

BIN
modules/mojo/app/assets/DejaVuSansMono.ttf


BIN
modules/mojo/app/assets/Inconsolata-g.ttf


BIN
modules/mojo/app/assets/Roboto-Regular.ttf


BIN
modules/mojo/app/assets/RobotoMono-Regular.ttf


BIN
modules/mojo/app/assets/checkmark_icons.png


+ 0 - 327
modules/mojo/app/assets/htmlview_master_css.css

@@ -1,327 +0,0 @@
-html {
-    display: block;
-    height:100%;
-    width:100%;
-	position: relative;
-}
-
-head {
-    display: none
-}
-
-meta {
-    display: none
-}
-
-title {
-    display: none
-}
-
-link {
-    display: none
-}
-
-style {
-    display: none
-}
-
-script {
-    display: none
-}
-
-body {
-	display:block; 
-	margin:8px; 
-    height:100%;
-    width:100%;
-}
-
-p {
-	display:block; 
-	margin-top:1em; 
-	margin-bottom:1em;
-}
-
-b, strong {
-	display:inline; 
-	font-weight:bold;
-}
-
-i, em {
-	display:inline; 
-	font-style:italic;
-}
-
-center 
-{
-	text-align:center;
-	display:block;
-}
-
-a:link
-{
-	text-decoration: underline;
-	color: #00f;
-	cursor: pointer;
-}
-
-h1, h2, h3, h4, h5, h6, div {
-	display:block;
-}
-
-h1 {
-	font-weight:bold; 
-	margin-top:0.67em; 
-	margin-bottom:0.67em; 
-	font-size: 2em;
-}
-
-h2 {
-	font-weight:bold; 
-	margin-top:0.83em; 
-	margin-bottom:0.83em; 
-	font-size: 1.5em;
-}
-
-h3 {
-	font-weight:bold; 
-	margin-top:1em; 
-	margin-bottom:1em; 
-	font-size:1.17em;
-}
-
-h4 {
-	font-weight:bold; 
-	margin-top:1.33em; 
-	margin-bottom:1.33em
-}
-
-h5 {
-	font-weight:bold; 
-	margin-top:1.67em; 
-	margin-bottom:1.67em;
-	font-size:.83em;
-}
-
-h6 {
-	font-weight:bold; 
-	margin-top:2.33em; 
-	margin-bottom:2.33em;
-	font-size:.67em;
-} 
-
-br {
-	display:inline-block;
-}
-
-br[clear="all"]
-{
-	clear:both;
-}
-
-br[clear="left"]
-{
-	clear:left;
-}
-
-br[clear="right"]
-{
-	clear:right;
-}
-
-span {
-	display:inline
-}
-
-img {
-	display: inline-block;
-}
-
-img[align="right"]
-{
-	float: right;
-}
-
-img[align="left"]
-{
-	float: left;
-}
-
-hr {
-    display: block;
-    margin-top: 0.5em;
-    margin-bottom: 0.5em;
-    margin-left: auto;
-    margin-right: auto;
-    border-style: inset;
-    border-width: 1px
-}
-
-
-/***************** TABLES ********************/
-
-table {
-    display: table;
-    border-style: solid;
-    border-collapse: separate;
-    border-spacing: 2px;
-    border-top-color:gray;
-    border-left-color:gray;
-    border-bottom-color:black;
-    border-right-color:black;
-}
-
-tbody, tfoot, thead {
-	display:table-row-group;
-	vertical-align:middle;
-}
-
-tr {
-    display: table-row;
-    vertical-align: inherit;
-    border-color: inherit;
-}
-
-td, th {
-    display: table-cell;
-    vertical-align: inherit;
-    border-width:1px;
-    padding:1px;
-}
-
-th {
-	font-weight: bold;
-}
-
-table[border] {
-    border-style:solid;
-}
-
-table[border|=0] {
-    border-style:none;
-}
-
-table[border] td, table[border] th {
-    border-style:solid;
-    border-top-color:black;
-    border-left-color:black;
-    border-bottom-color:gray;
-    border-right-color:gray;
-}
-
-table[border|=0] td, table[border|=0] th {
-    border-style:none;
-}
-
-caption {
-	display: table-caption;
-}
-
-td[nowrap], th[nowrap] {
-	white-space:nowrap;
-}
-
-tt, code, kbd, samp {
-    font-family: monospace
-}
-
-pre, xmp, plaintext, listing {
-    display: block;
-    font-family: monospace;
-    white-space: pre;
-    margin: 1em 0
-}
-
-/***************** LISTS ********************/
-
-ul, menu, dir {
-    display: block;
-    list-style-type: disc;
-    margin-top: 1em;
-    margin-bottom: 1em;
-    margin-left: 0;
-    margin-right: 0;
-    padding-left: 40px
-}
-
-ol {
-    display: block;
-    list-style-type: decimal;
-    margin-top: 1em;
-    margin-bottom: 1em;
-    margin-left: 0;
-    margin-right: 0;
-    padding-left: 40px
-}
-
-li {
-    display: list-item;
-}
-
-ul ul, ol ul {
-    list-style-type: circle;
-}
-
-ol ol ul, ol ul ul, ul ol ul, ul ul ul {
-    list-style-type: square;
-}
-
-dd {
-    display: block;
-    margin-left: 40px;
-}
-
-dl {
-    display: block;
-    margin-top: 1em;
-    margin-bottom: 1em;
-    margin-left: 0;
-    margin-right: 0;
-}
-
-dt {
-    display: block;
-}
-
-ol ul, ul ol, ul ul, ol ol {
-    margin-top: 0;
-    margin-bottom: 0
-}
-
-blockquote {
-	display: block;
-	margin-top: 1em;
-	margin-bottom: 1em;
-	margin-left: 40px;
-	margin-left: 40px;
-}
-
-/*********** FORM ELEMENTS ************/
-
-form {
-	display: block;
-	margin-top: 0em;
-}
-
-option {
-	display: none;
-}
-
-input, textarea, keygen, select, button, isindex {
-	margin: 0em;
-	color: initial;
-	line-height: normal;
-	text-transform: none;
-	text-indent: 0;
-	text-shadow: none;
-	display: inline-block;
-}
-input[type="hidden"] {
-	display: none;
-}
-
-
-article, aside, footer, header, hgroup, nav, section 
-{
-	display: block;
-}

BIN
modules/mojo/app/assets/monkey_font.png


BIN
modules/mojo/app/assets/treenode_collapsed.png


BIN
modules/mojo/app/assets/treenode_expanded.png


+ 23 - 4
modules/mojo/app/event.monkey2

@@ -10,6 +10,9 @@ Namespace mojo.app
 | KeyUp				| Key up event.
 | KeyUp				| Key up event.
 | KeyChar			| Key char event.
 | KeyChar			| Key char event.
 | MouseDown			| Mouse button down event.
 | MouseDown			| Mouse button down event.
+| MouseClick		| Mouse left click event.
+| MouseRightClick	| Mouse right click event.
+| MouseDoubleClick	| Mouse double left click event.
 | MouseUp			| Mouse button up event.
 | MouseUp			| Mouse button up event.
 | MouseMove			| Mouse movement event.
 | MouseMove			| Mouse movement event.
 | MouseWheel		| Mouse wheel event.
 | MouseWheel		| Mouse wheel event.
@@ -30,6 +33,9 @@ Enum EventType
 	KeyChar,
 	KeyChar,
 	
 	
 	MouseDown,
 	MouseDown,
+	MouseClick,
+	MouseRightClick,
+	MouseDoubleClick,
 	MouseUp,
 	MouseUp,
 	MouseMove,
 	MouseMove,
 	MouseWheel,
 	MouseWheel,
@@ -42,7 +48,7 @@ Enum EventType
 	WindowGainedFocus,
 	WindowGainedFocus,
 	WindowLostFocus,
 	WindowLostFocus,
 	
 	
-	Eaten=$80000000
+	Eaten=$40000000
 End
 End
 
 
 #rem monkeydoc The Event class.
 #rem monkeydoc The Event class.
@@ -145,15 +151,16 @@ Class MouseEvent Extends Event
 
 
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
 	#end
 	#end
-	Method New( type:EventType,view:View,location:Vec2i,button:MouseButton,wheel:Vec2i,modifiers:Modifier )
+	Method New( type:EventType,view:View,location:Vec2i,button:MouseButton,wheel:Vec2i,modifiers:Modifier,clicks:Int )
 		Super.New( type,view )
 		Super.New( type,view )
 		_location=location
 		_location=location
 		_button=button
 		_button=button
 		_wheel=wheel
 		_wheel=wheel
 		_modifiers=modifiers
 		_modifiers=modifiers
+		_clicks=clicks
 	End
 	End
 	
 	
-	#rem monkeydoc Mouse location.
+	#rem monkeydoc Mouse location in View.
 	#end
 	#end
 	Property Location:Vec2i()
 	Property Location:Vec2i()
 		Return _location
 		Return _location
@@ -177,13 +184,25 @@ Class MouseEvent Extends Event
 		Return _modifiers
 		Return _modifiers
 	End
 	End
 	
 	
+	#rem monkeydoc Number of mouse clicks.
+	#end
+	Property Clicks:Int()
+		Return _clicks
+	End
+	
+	Method TransformToView:MouseEvent( view:View )
+		If view=View Return self
+		Local location:=view.TransformPointFromView( _location,_view )
+		Return New MouseEvent( Type,View,location,_button,_wheel,_modifiers,_clicks )
+	End
+	
 	Private
 	Private
 	
 	
 	Field _location:Vec2i
 	Field _location:Vec2i
 	Field _button:MouseButton
 	Field _button:MouseButton
 	Field _wheel:Vec2i
 	Field _wheel:Vec2i
 	Field _modifiers:Modifier
 	Field _modifiers:Modifier
-	
+	Field _clicks:Int
 End
 End
 
 
 #rem monkeydoc The WindowEvent class.
 #rem monkeydoc The WindowEvent class.

+ 156 - 89
modules/mojo/app/style.monkey2

@@ -6,46 +6,37 @@ Namespace mojo.app
 Class Style
 Class Style
 
 
 	Method New()
 	Method New()
-		Init( "",Null,False )
 	End
 	End
 	
 	
 	Method New( style:Style )
 	Method New( style:Style )
-		Init( "",style,True )
+		Init( style )
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
-	#end
-	Method New( name:String )
-		Init( name,Null,False )
-	End
-	
-	#rem monkeydoc @hidden
-	#end
-	Method New( name:String,style:Style )
-		Init( name,style,True )
+	Method Copy:Style()
+		Return New Style( Self )
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
-	#end
-	Method AddState:Style( state:String,srcState:String="" )
-	
-		Local style:=New Style
-		
-		style.Init( "",GetState( srcState ),False )
-		
-		_states[state]=style
+	Method GetState:Style( name:String )
+		Local state:=_states[name]
+		If Not state Return Self
 		
 		
-		Return style
+		Return state
+	End
+
+	Method AddState:Style( name:String )
+		Local state:=_states[name]
+		If state Return state
+
+		state=New Style( Self )
+		_states[name]=state
+
+		Return state
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc Name of the style.
 	#end
 	#end
-	Method GetState:Style( state:String )
-	
-		Local style:=_states[state]
-		If style Return style
-		
-		Return Self
+	Property Name:String()
+		Return _name
 	End
 	End
 
 
 	#rem monkeydoc Background color.
 	#rem monkeydoc Background color.
@@ -104,35 +95,50 @@ Class Style
 		_margin=margin
 		_margin=margin
 	End
 	End
 	
 	
-	#rem monkeydoc Default canvas color.
+	#rem monkeydoc Color to use when drawing text.
 	#end
 	#end
-	Property DefaultColor:Color()
-		Return _color
+	Property TextColor:Color()
+		Return _textColor
 	Setter( color:Color )
 	Setter( color:Color )
-		_color=color
+		_textColor=color
 	End
 	End
-
-	#rem monkeydoc Default canvas font.
-	#end	
+	
+	#rem monkeydoc Color to use when drawing icons.
+	#end
+	Property IconColor:Color()
+		Return _iconColor
+	Setter( color:Color )
+		_iconColor=color
+	End
+	
+	#rem monkeydoc Font to use when drawing text.
+	
+	Deprecated! Just use [[Font]] instead...
+	
+	#end
 	Property DefaultFont:Font()
 	Property DefaultFont:Font()
 		Return _font
 		Return _font
 	Setter( font:Font )
 	Setter( font:Font )
 		_font=font
 		_font=font
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc Font to use when drawing text.
 	#end
 	#end
-	Method SetImage( name:String,image:Image )
-		_images[name]=image
+	Property Font:Font()
+		Return _font
+	Setter( font:Font )
+		_font=font
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc Custom icons.
 	#end
 	#end
-	Method GetImage:Image( name:String )
-		Return _images[name]
+	Property Icons:Image[]()
+		Return _icons
+	Setter( icons:Image[] )
+		_icons=icons
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc Total style bounds.
 	#end
 	#end
 	Property Bounds:Recti()
 	Property Bounds:Recti()
 		Local bounds:=Padding
 		Local bounds:=Padding
@@ -142,6 +148,83 @@ Class Style
 		bounds+=Margin
 		bounds+=Margin
 		Return bounds
 		Return bounds
 	End
 	End
+
+	#rem monkeydoc Measure text.
+	#end
+	Method MeasureText:Vec2i( text:String )
+	
+		If Not text Return New Vec2i( 0,0 )
+		
+		If text.Contains( "~n" )
+
+			Local lines:=text.Split( "~n" ),w:=0
+
+			For Local line:=Eachin lines
+				w=Max( w,Int( _font.TextWidth( line ) ) )
+			Next
+			Return New Vec2i( w,_font.Height * lines.Length )
+		Else
+			Return New Vec2i( _font.TextWidth( text ),_font.Height )
+		Endif
+	End
+	
+	Method DrawText( canvas:Canvas,text:String,x:Int,y:Int,handlex:Float=0,handley:Float=0 )
+
+		Local font:=canvas.Font
+		Local color:=canvas.Color
+		
+		canvas.Font=_font
+		canvas.Color=_textColor
+		
+		canvas.DrawText( text,x,y,handlex,handley )
+		
+		canvas.Font=font
+		canvas.Color=color
+	End
+	
+	Method DrawText( canvas:Canvas,text:String,rect:Recti,gravity:Vec2f )
+	
+		If Not text Return
+	
+		Local size:=MeasureText( text )
+		
+		Local x:=rect.Left + (rect.Width-size.x) * gravity.x
+		Local y:=rect.Top + (rect.Height-size.y) * gravity.y
+		
+		Local font:=canvas.Font
+		Local color:=canvas.Color
+		
+		canvas.Font=_font
+		canvas.Color=_textColor
+		
+		If text.Contains( "~n" )
+		
+			Local lines:=text.Split( "~n" )
+			
+			For Local line:=Eachin lines
+			
+				If line canvas.DrawText( line,x + (size.x-_font.TextWidth( line )) * gravity.x,y )
+				y+=_font.Height
+			Next
+		
+		Else If text<>"~n"
+		
+			canvas.DrawText( text,x,y )
+		Endif
+		
+		canvas.Font=font
+		canvas.Color=color
+	End
+	
+	Method DrawIcon( canvas:Canvas,icon:Image,x:Int,y:Int )
+	
+		Local color:=canvas.Color
+		canvas.Color=_iconColor
+		
+		canvas.DrawImage( icon,x,y )
+		
+		canvas.Color=color
+	End
 	
 	
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
 	#end
 	#end
@@ -185,31 +268,21 @@ Class Style
 		Endif
 		Endif
 		
 		
 		canvas.Font=_font
 		canvas.Font=_font
-		canvas.Color=_color
-		
+		canvas.Color=Color.White
 	End
 	End
 	
 	
+	'***** INTERNAL *****
+
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
 	#end
 	#end
-	Function GetStyle:Style( name:String )
-	
-		Local style:=_styles[name]
-		If style Return style
-		
-		Local i:=name.Find( ":" )
-		If i<>-1 Return GetStyle( name.Slice( 0,i ) )
-		
-		If Not _defaultStyle _defaultStyle=New Style
-		Return _defaultStyle
+	Property States:StringMap<Style>()
+		If Not _states _states=New StringMap<Style>
+		Return _states
 	End
 	End
-
-	Private
-	
-	Global _defaultStyle:Style
-	Global _styles:=New StringMap<Style>
 	
 	
-	Field _states:=New StringMap<Style>
+	Private
 	
 	
+	Field _name:String
 	Field _bgcolor:Color=Color.None
 	Field _bgcolor:Color=Color.None
 	Field _padding:Recti
 	Field _padding:Recti
 	Field _skin:Skin
 	Field _skin:Skin
@@ -217,35 +290,29 @@ Class Style
 	Field _border:Recti
 	Field _border:Recti
 	Field _bdcolor:Color=Color.None
 	Field _bdcolor:Color=Color.None
 	Field _margin:Recti
 	Field _margin:Recti
-	Field _color:Color
+	Field _textColor:Color=Color.Black
+	Field _iconColor:Color=Color.White
+	Field _icons:Image[]
 	Field _font:Font
 	Field _font:Font
-	Field _images:=New StringMap<Image>
-	
-	Method Init( name:String,style:Style,copyStates:Bool )
-	
-		If Not style style=_defaultStyle
-		
-		If style
-			_bgcolor=style._bgcolor
-			_padding=style._padding
-			_skin=style._skin
-			_skcolor=style._skcolor
-			_border=style._border
-			_bdcolor=style._bdcolor
-			_margin=style._margin
-			_color=style._color
-			_font=style._font
-			_images=style._images.Copy()
-			
-			If copyStates
-				For Local it:=Eachin style._states
-					_states[it.Key]=New Style( it.Value )
-				Next
-			Endif
-		Endif
-		
-		If name
-			_styles[name]=Self
+	Field _states:=New StringMap<Style>
+
+	Method Init( style:Style )
+		If Not style Return
+		_bgcolor=style._bgcolor
+		_padding=style._padding
+		_skin=style._skin
+		_skcolor=style._skcolor
+		_border=style._border
+		_bdcolor=style._bdcolor
+		_margin=style._margin
+		_textColor=style._textColor
+		_iconColor=style._iconColor
+		_icons=style._icons.Slice( 0 )
+		_font=style._font
+		If style._states
+			For Local it:=Eachin style._states
+				_states[it.Key]=New Style( it.Value )
+			Next
 		Endif
 		Endif
 	End
 	End
 	
 	

+ 277 - 153
modules/mojo/app/view.monkey2

@@ -5,15 +5,30 @@ Namespace mojo.app
 #end
 #end
 Class View
 Class View
 
 
-	Method New()
+	#rem monkeydoc Invoked when a view becomes visble and active.
+	#end
+	Field Activated:Void()
 	
 	
-		_style=New Style
+	#rem monkeydoc Invoked when a view becomes is not longer visble or active.
+	#end
+	Field Deactivated:Void()
+
+	Method New()
+		
+		If Not _themeSeq
+			_themeSeq=1
+			App.ThemeChanged+=Lambda()
+				_themeSeq+=1
+				If _themeSeq<0 _themeSeq=1
+			End
+		Endif
+		
+		_style=New Style( App.Theme.DefaultStyle )
+		
+		InvalidateStyle()
 	End
 	End
 
 
-	#rem monkeydoc @hidden View visible flag.
-	
-	Use [[ReallyVisible]] to test if the view is really visible.
-	
+	#rem monkeydoc View visibility state.
 	#end
 	#end
 	Property Visible:Bool()
 	Property Visible:Bool()
 	
 	
@@ -23,26 +38,17 @@ Class View
 		If visible=_visible Return
 		If visible=_visible Return
 	
 	
 		_visible=visible
 		_visible=visible
-	End
-
-	#rem monkeydoc @hidden View visibility state.
-	
-	True if the view's visibility flag is set AND all its parent visibility flags up to the root window are also set.
-	
-	#end
-	Property ReallyVisible:Bool()
-	
-		Return _visible And (Not _parent Or _parent.ReallyVisible)
+		
+		RequestRender()
+		
+		UpdateActive()
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden View enabled flag.
-	
-	Use [[ReallyEnabled]] to test if the view is really enabled.
-	
+	#rem monkeydoc View enabled state.
 	#end
 	#end
 	Property Enabled:Bool()
 	Property Enabled:Bool()
 	
 	
-		Return _enabled
+		Return _enabled And (Not _parent Or _parent.Enabled)
 	
 	
 	Setter( enabled:Bool )
 	Setter( enabled:Bool )
 		If enabled=_enabled Return
 		If enabled=_enabled Return
@@ -50,16 +56,42 @@ Class View
 		_enabled=enabled
 		_enabled=enabled
 		
 		
 		InvalidateStyle()
 		InvalidateStyle()
+		
+		UpdateActive()
 	End
 	End
 
 
-	#rem monkeydoc @hidden View enabled state.
+	#rem monkeydoc View active state.
+	
+	A view is active it is visible, enabled, attached to a window and all its parents are also active.
 	
 	
-	True if the view's enabled flag is set AND all its parent enabled flags are set AND [[ReallyVisible]] is also true. 
+	Events are only sent to active windows.
 	
 	
+	#end	
+	Property Active:Bool()
+	
+		Return _active
+	End
+	
+	#rem monkeydoc Whether the view accepts key events.
+	#end
+	Property AcceptsKeyEvents:Bool()
+	
+		Return _acceptsKeyEvents
+	
+	Setter( acceptsKeyEvents:Bool )
+	
+		_acceptsKeyEvents=acceptsKeyEvents
+	End
+	
+	#rem monkeydoc Whether the view accepts mouse events.
 	#end
 	#end
-	Property ReallyEnabled:Bool()
+	Property AcceptsMouseEvents:Bool()
 	
 	
-		Return _enabled And _visible And (Not _parent Or _parent.ReallyEnabled)
+		Return _acceptsMouseEvents
+	
+	Setter( acceptsMouseEvents:Bool )
+	
+		_acceptsMouseEvents=acceptsMouseEvents
 	End
 	End
 	
 	
 	#rem monkeydoc View style.
 	#rem monkeydoc View style.
@@ -76,7 +108,7 @@ Class View
 		InvalidateStyle()
 		InvalidateStyle()
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc View style state.
 	#end
 	#end
 	Property StyleState:String()
 	Property StyleState:String()
 	
 	
@@ -90,7 +122,10 @@ Class View
 		InvalidateStyle()
 		InvalidateStyle()
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc View render style.
+	
+	This is the style used to render the view, and is dependant on [[Style]] and [[StyleState]].
+	
 	#end
 	#end
 	Property RenderStyle:Style()
 	Property RenderStyle:Style()
 	
 	
@@ -105,11 +140,14 @@ Class View
 	
 	
 	| Layout mode		| Description
 	| Layout mode		| Description
 	|:------------------|:-----------
 	|:------------------|:-----------
-	| "resize"			| View is resized to fit its layout frame.
+	| "fill"			| View is resized to fit its layout frame.
+	| "float"			| View floats within its layout frame according to the view [[Gravity]].
+	| "fill-x"			| View is resized on the x axis and floats on the y axis.
+	| "fill-y"			| View is resized on the y axis and floats on the x axs.
 	| "stretch"			| View is stretched to fit its layout frame.
 	| "stretch"			| View is stretched to fit its layout frame.
 	| "letterbox"		| View is uniformly stretched on both axii and centered within its layout frame.
 	| "letterbox"		| View is uniformly stretched on both axii and centered within its layout frame.
-	| "float"			| View floats within its layout frame according to the view [[Gravity]].
-	
+	| "letterbox-int"	| View is uniformly stretched on both axii and centered within its layout frame. Scale factors are integrized.
+
 	#end
 	#end
 	Property Layout:String()
 	Property Layout:String()
 
 
@@ -125,7 +163,7 @@ Class View
 	
 	
 	The 'frame' the view is contained in.
 	The 'frame' the view is contained in.
 	
 	
-	Note that the frame rect is in 'parent space' coordinates, and is usually set by the parent view when layout occurs.
+	Note that the frame rect is in parent space coordinates, and is usually set by the parent view when layout occurs.
 	
 	
 	#end	
 	#end	
 	Property Frame:Recti()
 	Property Frame:Recti()
@@ -133,7 +171,6 @@ Class View
 		Return _frame
 		Return _frame
 	
 	
 	Setter( frame:Recti )
 	Setter( frame:Recti )
-		If frame=_frame Return
 	
 	
 		_frame=frame
 		_frame=frame
 	End
 	End
@@ -172,8 +209,6 @@ Class View
 	Setter( minSize:Vec2i )
 	Setter( minSize:Vec2i )
 	
 	
 		_minSize=minSize
 		_minSize=minSize
-		
-		InvalidateStyle()
 	End
 	End
 	
 	
 	#rem monkeydoc Maximum view size.
 	#rem monkeydoc Maximum view size.
@@ -185,8 +220,6 @@ Class View
 	Setter( maxSize:Vec2i )
 	Setter( maxSize:Vec2i )
 	
 	
 		_maxSize=maxSize
 		_maxSize=maxSize
-		
-		InvalidateStyle()
 	End
 	End
 	
 	
 	#rem monkeydoc View content rect.
 	#rem monkeydoc View content rect.
@@ -269,37 +302,71 @@ Class View
 		Return _rmatrix
 		Return _rmatrix
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc The parent view of this view.
 	#end
 	#end
 	Property Parent:View()
 	Property Parent:View()
 	
 	
 		Return _parent
 		Return _parent
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc The Window this view is attached to, if any.
+	#end
+	Property Window:Window()
+	
+		Return _window
+	End
+	
+	#rem monkeydoc Gets a style.
+	
+	This is a convenience method equivalent to App.Theme.GetStyle( name ).
+	
+	#end
+	Method GetStyle:Style( name:String )
+	
+		Return App.Theme.GetStyle( name )
+	End
+	
+	#rem monkeydoc Adds a child view to this view.
+	
+	AddChildView is normally used internally by 'layout' views. However you can also add a child view to any view
+	directly by calling this method.
+	
+	If you use this method to add a child view to a view, it is your responsiblity to also manage the child view's frame using
+	the [[Frame]] property.
+
 	#end
 	#end
-	Method AddChild( view:View )
+	Method AddChildView( view:View )
 	
 	
 		If Not view Return
 		If Not view Return
 		
 		
-		Assert( Not view._parent )
-		
+		Assert( Not view._parent,"View already has a parent" )
+
+		Assert( Not Cast<Window>( view ),"Windows cannot be child views" )
+	
+		view._parent=Self
+		view.SetWindow( _window )
 		_children.Add( view )
 		_children.Add( view )
 		
 		
-		view._parent=Self
+		RequestRender()
+		
+		view.UpdateActive()
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc Removes a child view from this view.
 	#end
 	#end
-	Method RemoveChild( view:View )
+	Method RemoveChildView( view:View )
 	
 	
 		If Not view Return
 		If Not view Return
 		
 		
-		Assert( view._parent=Self )
-		
+		Assert( view._parent=Self,"View is not a child view" )
+
+		view._parent=Null
+		view.SetWindow( Null )
 		_children.Remove( view )
 		_children.Remove( view )
 		
 		
-		view._parent=Null
+		RequestRender()
+		
+		view.UpdateActive()
 	End
 	End
 	
 	
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
@@ -342,7 +409,7 @@ Class View
 	
 	
 	#rem monkeydoc Transforms a point from another view.
 	#rem monkeydoc Transforms a point from another view.
 	
 	
-	Transforms `point` in coordinates local to 'view' to coodinates local to this view.
+	Transforms `point` in coordinates local to 'view' to coordinates local to this view.
 	
 	
 	@param point The point to transform.
 	@param point The point to transform.
 	
 	
@@ -388,7 +455,14 @@ Class View
 		Return New Recti( TransformPointFromView( rect.min,view ),TransformPointFromView( rect.max,view ) )
 		Return New Recti( TransformPointFromView( rect.min,view ),TransformPointFromView( rect.max,view ) )
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc Transforms a point in window coordinates to view coordinates.
+
+	Transforms `point` in window coordinates to coordinates local to this view.
+	
+	@param point The point to transform.
+	
+	@return The transformed point.
+	
 	#end
 	#end
 	Method TransformWindowPointToView:Vec2i( point:Vec2i )
 	Method TransformWindowPointToView:Vec2i( point:Vec2i )
 	
 	
@@ -397,73 +471,54 @@ Class View
 		Return New Vec2i( Round( t.x ),Round( t.y ) )
 		Return New Vec2i( Round( t.x ),Round( t.y ) )
 	End
 	End
 	
 	
-	
-	#rem monkeydoc Makes this view the 'key' view.
+	#rem monkeydoc Makes this view the key view.
 	
 	
 	The key view is the view that receives keyboard events.
 	The key view is the view that receives keyboard events.
 	
 	
 	#end
 	#end
 	Method MakeKeyView()
 	Method MakeKeyView()
-	
-		If Not ReallyEnabled Return
-	
-		OnMakeKeyView()
-	End
-	
-	#rem monkeydoc @hidden
-	#end
-	Method SendMouseEvent( event:MouseEvent )
-	
-		If Not ReallyEnabled
-			Select event.Type
-			Case EventType.MouseUp,EventType.MouseLeave
-				OnMouseEvent( event )
-			End
-			Return
-		Endif
-	
-		OnMouseEvent( event )
+
+		Local oldKeyView:=App.KeyView
+		If oldKeyView=Self Return
 		
 		
-		If event.Eaten Return
-	
-		Select event.Type
-		Case EventType.MouseWheel
-			Local view:=_parent
-			While view
-				view.OnMouseEvent( event )
-				If event.Eaten Return
-				view=view._parent
-			Wend
-		End
+		If Not Active Return
 		
 		
+		App.KeyView=Self
+		
+		If oldKeyView oldKeyView.OnKeyViewChanged( oldKeyView,Self )
+		
+		OnKeyViewChanged( oldKeyView,Self )
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc Sends a key event to the view.
 	#end
 	#end
 	Method SendKeyEvent( event:KeyEvent )
 	Method SendKeyEvent( event:KeyEvent )
 	
 	
-		If Not ReallyEnabled Return
-	
-		OnKeyEvent( event )
-	End
-	
-	#rem monkeydoc @hidden
-	#end
-	Property Container:View() Virtual
-	
-		Return Self
+		If _acceptsKeyEvents
+		
+			OnKeyEvent( event )
+			
+			If event.Eaten Return
+		Endif
+		
+		If _parent _parent.SendKeyEvent( event )
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc Sends a mouse event to the view.
 	#end
 	#end
-	Method FindWindow:Window() Virtual
+	Method SendMouseEvent( event:MouseEvent )
 	
 	
-		If _parent Return _parent.FindWindow()
+		If _acceptsMouseEvents
+
+			OnMouseEvent( event.TransformToView( Self ) )
+			
+			If event.Eaten Return
+		Endif
 		
 		
-		Return Null
+		If _parent _parent.SendMouseEvent( event )
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc Checks if the view is a child of another view.
 	#end
 	#end
 	Method IsChildOf:Bool( view:View )
 	Method IsChildOf:Bool( view:View )
 		
 		
@@ -474,46 +529,70 @@ Class View
 		Return False
 		Return False
 	End
 	End
 	
 	
+	#rem monkeydoc @hidden
+	#end
+	Method RequestRender()
+	
+		App.RequestRender()
+	End
+
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
 	#end
 	#end
 	Method InvalidateStyle()
 	Method InvalidateStyle()
 	
 	
-		_dirty|=Dirty.Style
+		_styleSeq=-1
+		
+		App.RequestRender()
 	End
 	End
 	
 	
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
 	#end
 	#end
 	Method ValidateStyle()
 	Method ValidateStyle()
 	
 	
-		If Not (_dirty & Dirty.Style) Return
+		If _styleSeq=_themeSeq Return
+		
+		If _styleSeq<>-1
 		
 		
+			Local name:=_style.Name
+			If name
+				Local style:=App.Theme.GetStyle( name )
+				If style _style=style
+			Endif
+
+		Endif
+	
 		_rstyle=_style
 		_rstyle=_style
 		
 		
-		If Not ReallyEnabled 
-			_rstyle=_style.GetState( "disabled" )
-		Else If _styleState
+		If Enabled
 			_rstyle=_style.GetState( _styleState )
 			_rstyle=_style.GetState( _styleState )
+		Else
+			_rstyle=_style.GetState( "disabled" )
 		Endif
 		Endif
 		
 		
 		_styleBounds=_rstyle.Bounds
 		_styleBounds=_rstyle.Bounds
-
-		_dirty&=~Dirty.Style
+		
+		_styleSeq=_themeSeq
 				
 				
 		OnValidateStyle()
 		OnValidateStyle()
 	End
 	End
 	
 	
+	Method MeasureLayoutSize:Vec2i()
+	
+		Measure()
+		
+		Return _layoutSize
+	End
+	
 	Protected
 	Protected
 	
 	
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
 	#end
 	#end
 	Method Measure()
 	Method Measure()
-	
-		If Not _visible Return
+
+'		If Not _visible Return
 		
 		
 		For Local view:=Eachin _children
 		For Local view:=Eachin _children
-		
 			view.Measure()
 			view.Measure()
-
 		Next
 		Next
 		
 		
 		ValidateStyle()
 		ValidateStyle()
@@ -560,6 +639,15 @@ Class View
 			
 			
 			_matrix=_matrix.Translate( 0,(_frame.Height-_bounds.Height)*_gravity.y )
 			_matrix=_matrix.Translate( 0,(_frame.Height-_bounds.Height)*_gravity.y )
 			
 			
+		Case "fill-y"
+		
+			_rect.max.y=_frame.Height-_styleBounds.Height
+			
+			_bounds.min.y=_rect.min.y+_styleBounds.min.y
+			_bounds.max.y=_rect.max.y+_styleBounds.max.y
+			
+			_matrix=_matrix.Translate( (_frame.Width-_bounds.Width)*_gravity.x,0 )
+			
 		Case "float"
 		Case "float"
 		
 		
 			_matrix=_matrix.Translate( (_frame.Width-_bounds.Width)*_gravity.x,(_frame.Height-_bounds.Height)*_gravity.y )
 			_matrix=_matrix.Translate( (_frame.Width-_bounds.Width)*_gravity.x,(_frame.Height-_bounds.Height)*_gravity.y )
@@ -654,61 +742,46 @@ Class View
 		Next
 		Next
 		
 		
 		canvas.EndRender()
 		canvas.EndRender()
-		
 	End
 	End
-	
+
 	Protected
 	Protected
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc Called during layout if [[Style]] or [[StyleState]] have changed.
+
+	Views can use this method to cache [[RenderStyle]] properties if necessary.
+		
 	#end
 	#end
 	Method OnValidateStyle() Virtual
 	Method OnValidateStyle() Virtual
-	
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc Called during layout to measure the view.
+	
+	Overriding methods should return their preferred content size.
+	
 	#end
 	#end
 	Method OnMeasure:Vec2i() Virtual
 	Method OnMeasure:Vec2i() Virtual
-	
 		Return New Vec2i( 0,0 )
 		Return New Vec2i( 0,0 )
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
-	#end
-	Method OnMeasure2:Vec2i( size:Vec2i ) Virtual
+	#rem monkeydoc Called during layout when the view needs to update its child views.
 	
 	
-		Return New Vec2i( 0,0 )
-	End
+	Overriding methods should set the [[Frame]] property of any child views they are resposible for.
 	
 	
-	#rem monkeydoc @hidden
 	#end
 	#end
 	Method OnLayout() Virtual
 	Method OnLayout() Virtual
-	
-		For Local view:=Eachin _children
-			view.Frame=Rect
-		Next
-
 	End
 	End
 	
 	
-	#rem monkeydoc Render this view.
-	
-	Called when the view should render itself.
-	
+	#rem monkeydoc Called when the view needs to render itself.
 	#end
 	#end
 	Method OnRender( canvas:Canvas ) Virtual
 	Method OnRender( canvas:Canvas ) Virtual
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
-	#end
-	Method OnRenderBounds( canvas:Canvas ) Virtual
-	End
-	
-	#rem monkeydoc @hidden
-	#end
-	Method OnMakeKeyView() Virtual
+	#rem monkeydoc Called when the key view changes.
 	
 	
-		Local window:=FindWindow()
-		If window window.KeyView=Self
+	This method is invoked on both the old key view and new key view when the key view changes.
 	
 	
+	#end
+	Method OnKeyViewChanged( oldKeyView:View,newKeyView:View ) Virtual
 	End
 	End
 	
 	
 	#rem monkeydoc Keyboard event handler.
 	#rem monkeydoc Keyboard event handler.
@@ -727,53 +800,105 @@ Class View
 	Method OnMouseEvent( event:MouseEvent ) Virtual
 	Method OnMouseEvent( event:MouseEvent ) Virtual
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc The last size returned by OnMeasure.
 	#end
 	#end
 	Property MeasuredSize:Vec2i()
 	Property MeasuredSize:Vec2i()
 	
 	
 		Return _measuredSize
 		Return _measuredSize
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc MeasuredSize plus the current [[RenderStyle]] bounds size.
+	
+	Use this instead of MeasuredSize when calculating layout size for child views.
+	
 	#end
 	#end
 	Property LayoutSize:Vec2i()
 	Property LayoutSize:Vec2i()
 	
 	
 		Return _layoutSize
 		Return _layoutSize
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
+	#rem monkeydoc The current [[RenderStyle]] bounds rect.
 	#end
 	#end
 	Property StyleBounds:Recti()
 	Property StyleBounds:Recti()
 	
 	
 		Return _styleBounds
 		Return _styleBounds
 	End
 	End
 	
 	
+	'***** INTERNAL *****
+	
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
+	
+	For height-dependant-on-width views - clean me up!
+	
+	#end
+	Method OnMeasure2:Vec2i( size:Vec2i ) Virtual
+		Return New Vec2i( 0,0 )
+	End
+	
+	#rem monkeydoc @hidden
+	
+	For height-dependant-on-width views - clean me up!
+	
 	#end
 	#end
 	Method Measure2:Vec2i( size:Vec2i )
 	Method Measure2:Vec2i( size:Vec2i )
 		size=OnMeasure2( size-_styleBounds.Size )
 		size=OnMeasure2( size-_styleBounds.Size )
 		If size.x And size.y _layoutSize=size+_styleBounds.Size
 		If size.x And size.y _layoutSize=size+_styleBounds.Size
 		Return _layoutSize
 		Return _layoutSize
 	End
 	End
+
+	#rem monkeydoc @hidden
+	#end
+	Method SetWindow( window:Window )
 	
 	
-	Private
+		_window=window
+		
+		For Local view:=Eachin _children
+			view.SetWindow( window )
+		Next
+	End
 	
 	
-	Enum Dirty
-		Style=1
-		All=1
+	#rem monkeydoc @hidden
+	#end
+	Method UpdateActive()
+	
+		'Note: views are activated top-down, deactivated bottom-up.
+		'	
+		Local active:=_visible And _enabled And _window And (Not _parent Or _parent._active )
+		
+		Local changed:=active<>_active
+		
+		If changed
+			_active=active
+			If Not _active Deactivated()
+		Endif
+		
+		For Local child:=Eachin _children
+			child.UpdateActive()
+		Next
+		
+		If changed And _active Activated()
 	End
 	End
 	
 	
-	Field _dirty:Dirty=Dirty.All
-
+	Private
+	
+	Global _themeSeq:Int
+	
+	Field _styleSeq:Int=-1
+	
 	Field _parent:View
 	Field _parent:View
+	Field _window:Window
 	Field _children:=New Stack<View>
 	Field _children:=New Stack<View>
 	
 	
 	Field _visible:Bool=True
 	Field _visible:Bool=True
 	Field _enabled:Bool=True
 	Field _enabled:Bool=True
+	Field _active:Bool=False
+	Field _acceptsKeyEvents:Bool=True
+	Field _acceptsMouseEvents:Bool=True
+	
 	Field _style:Style
 	Field _style:Style
 	Field _styleState:String
 	Field _styleState:String
-
-	Field _layout:String
+	
+	Field _layout:String="fill"
 	Field _gravity:=New Vec2f( .5,.5 )
 	Field _gravity:=New Vec2f( .5,.5 )
 	Field _offset:=New Vec2i( 0,0 )
 	Field _offset:=New Vec2i( 0,0 )
 
 
@@ -782,13 +907,13 @@ Class View
 	
 	
 	Field _frame:Recti
 	Field _frame:Recti
 	
 	
-	'After Measuring...
+	'After measuring...
 	Field _rstyle:Style
 	Field _rstyle:Style
 	Field _styleBounds:Recti
 	Field _styleBounds:Recti
 	Field _measuredSize:Vec2i
 	Field _measuredSize:Vec2i
 	Field _layoutSize:Vec2i
 	Field _layoutSize:Vec2i
 	
 	
-	'After layout
+	'After layout..
 	Field _rect:Recti
 	Field _rect:Recti
 	Field _bounds:Recti
 	Field _bounds:Recti
 	Field _matrix:AffineMat3f
 	Field _matrix:AffineMat3f
@@ -796,5 +921,4 @@ Class View
 	Field _rbounds:Recti
 	Field _rbounds:Recti
 	Field _rclip:Recti
 	Field _rclip:Recti
 	Field _clip:Recti
 	Field _clip:Recti
-	
 End
 End

+ 97 - 101
modules/mojo/app/window.monkey2

@@ -107,83 +107,29 @@ Class Window Extends View
 	
 	
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
-	#End
-	Method Update()
-
-#If __TARGET__="emscripten"
-
-		'ugly...fixme.
-		Local w:Int,h:Int,fs:Int
-		emscripten_get_canvas_size( Varptr w,Varptr h,Varptr fs )
-		If w<>Frame.Width Or h<>Frame.Height
-			Frame=New Recti( 0,0,w,h )
-		Endif
-	
-#Else
-		'ugly...fixme.
-		If MinSize<>_minSize
-			SDL_SetWindowMinimumSize( _sdlWindow,MinSize.x,MinSize.y )
-			_minSize=GetMinSize()
-			MinSize=_minSize
-		Endif
-		
-		If MaxSize<>_maxSize 
-			SDL_SetWindowMaximumSize( _sdlWindow,MaxSize.x,MaxSize.y )
-			_maxSize=GetMaxSize()
-			MaxSize=_maxSize
-		Endif
-		
-		If Frame<>_frame
-			SDL_SetWindowPosition( _sdlWindow,Frame.X,Frame.Y )
-			SDL_SetWindowSize( _sdlWindow,Frame.Width,Frame.Height )
-			_frame=GetFrame()
-			Frame=_frame
-			_weirdHack=True
-		Endif
-		
-#Endif
-		Measure()
-		
-		UpdateLayout()
-	End
+	Property ContentView:View()
 	
 	
-	#rem monkeydoc @hidden
-	#end
-	Method Render()
+		Return _contentView
 	
 	
-		SDL_GL_MakeCurrent( _sdlWindow,_sdlGLContext )	
-		SDL_GL_SetSwapInterval( _swapInterval )
+	Setter( contentView:View )
 	
 	
-#If __TARGET__="desktop" And __HOSTOS__="windows"
-		If _weirdHack
-			_weirdHack=False
-			SDL_GL_SwapWindow( _sdlWindow )
-		Endif
-#Endif
+		If _contentView RemoveChildView( _contentView )
 		
 		
-		Local bounds:=New Recti( 0,0,Frame.Size )
+		_contentView=contentView
 		
 		
-		_canvas.Resize( bounds.Size )
+		If _contentView AddChildView( _contentView )
 		
 		
-		_canvas.BeginRender( bounds,New AffineMat3f )
-		
-		If _clearEnabled _canvas.Clear( _clearColor )
-		
-		Render( _canvas )
-		
-		_canvas.EndRender()
-		
-		SDL_GL_SwapWindow( _sdlWindow )
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
-	#end
-	Method FindWindow:Window() Override
+	Method UpdateWindow( render:Bool )
 	
 	
-		Return Self
+		LayoutWindow()
+		
+		If render RenderWindow()
 	End
 	End
 	
 	
+	'***** INTERNAL *****
+
 	#rem monkeydoc The internal SDL_Window used by this window.
 	#rem monkeydoc The internal SDL_Window used by this window.
 	#end
 	#end
 	Property SDLWindow:SDL_Window Ptr()
 	Property SDLWindow:SDL_Window Ptr()
@@ -218,8 +164,6 @@ Class Window Extends View
 		Return _windowsByID[id]
 		Return _windowsByID[id]
 	End
 	End
 
 
-	'***** INTERNAL *****
-	
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
 	#end
 	#end
 	Method SendWindowEvent( event:WindowEvent )
 	Method SendWindowEvent( event:WindowEvent )
@@ -234,32 +178,6 @@ Class Window Extends View
 		OnWindowEvent( event )
 		OnWindowEvent( event )
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
-	#end
-	Property KeyView:View()
-	
-		Return _keyView
-		
-	Setter( keyView:View )
-	
-		_keyView=keyView
-	End
-	
-	#rem monkeydoc @hidden
-	
-	Dummy default window.
-	
-	#end
-	Method New( title:String,app:AppInstance )
-	
-		_sdlWindow=SDL_CreateWindow( title,0,0,0,0,SDL_WINDOW_HIDDEN|SDL_WINDOW_OPENGL )
-		Assert( _sdlWindow,"FATAL ERROR: SDL_CreateWindow failed" )
-
-		_sdlGLContext=SDL_GL_CreateContext( _sdlWindow )
-		Assert( _sdlGLContext,"FATAL ERROR: SDL_GL_CreateContext failed" )
-		SDL_GL_MakeCurrent( _sdlWindow,_sdlGLContext )	
-	End
-	
 	Protected
 	Protected
 	
 	
 	#rem monkeydoc Window event handler.
 	#rem monkeydoc Window event handler.
@@ -288,14 +206,20 @@ Class Window Extends View
 		
 		
 	End
 	End
 	
 	
+	Protected
+	
+	Method OnLayout() Override
+	
+		If _contentView _contentView.Frame=Rect
+	End
+	
 	Private
 	Private
 	
 	
 	Field _sdlWindow:SDL_Window Ptr
 	Field _sdlWindow:SDL_Window Ptr
 	Field _sdlGLContext:SDL_GLContext
 	Field _sdlGLContext:SDL_GLContext
-
+	
 	Field _flags:WindowFlags
 	Field _flags:WindowFlags
 	Field _fullscreen:=False
 	Field _fullscreen:=False
-
 	Field _swapInterval:=1
 	Field _swapInterval:=1
 	
 	
 	Field _canvas:Canvas
 	Field _canvas:Canvas
@@ -303,8 +227,8 @@ Class Window Extends View
 	Field _clearColor:=Color.Grey
 	Field _clearColor:=Color.Grey
 	Field _clearEnabled:=True
 	Field _clearEnabled:=True
 	
 	
-	Field _keyView:View
-	
+	Field _contentView:View
+
 	Field _minSize:Vec2i
 	Field _minSize:Vec2i
 	Field _maxSize:Vec2i
 	Field _maxSize:Vec2i
 	Field _frame:Recti
 	Field _frame:Recti
@@ -335,9 +259,75 @@ Class Window Extends View
 		Return New Recti( x,y,x+w,y+h )
 		Return New Recti( x,y,x+w,y+h )
 	End
 	End
 	
 	
-	Method Init( title:String,rect:Recti,flags:WindowFlags )
+	Method LayoutWindow()
+	
+#If __TARGET__="emscripten"
+
+		'ugly...fixme.
+		Local w:Int,h:Int,fs:Int
+		emscripten_get_canvas_size( Varptr w,Varptr h,Varptr fs )
+		If w<>Frame.Width Or h<>Frame.Height
+			Frame=New Recti( 0,0,w,h )
+		Endif
+	
+#Else
+		'ugly...fixme.
+		If MinSize<>_minSize
+			SDL_SetWindowMinimumSize( _sdlWindow,MinSize.x,MinSize.y )
+			_minSize=GetMinSize()
+			MinSize=_minSize
+		Endif
+		
+		If MaxSize<>_maxSize 
+			SDL_SetWindowMaximumSize( _sdlWindow,MaxSize.x,MaxSize.y )
+			_maxSize=GetMaxSize()
+			MaxSize=_maxSize
+		Endif
+		
+		If Frame<>_frame
+			SDL_SetWindowPosition( _sdlWindow,Frame.X,Frame.Y )
+			SDL_SetWindowSize( _sdlWindow,Frame.Width,Frame.Height )
+			_frame=GetFrame()
+			Frame=_frame
+			_weirdHack=True
+		Endif
+		
+#Endif
+		Measure()
+		
+		UpdateLayout()
+	End
 	
 	
-		Layout="fill"
+	#rem monkeydoc @hidden
+	#end
+	Method RenderWindow()
+	
+		SDL_GL_MakeCurrent( _sdlWindow,_sdlGLContext )	
+		SDL_GL_SetSwapInterval( _swapInterval )
+	
+#If __TARGET__="desktop" And __HOSTOS__="windows"
+		If _weirdHack
+			_weirdHack=False
+			SDL_GL_SwapWindow( _sdlWindow )
+		Endif
+#Endif
+		
+		Local bounds:=New Recti( 0,0,Frame.Size )
+		
+		_canvas.Resize( bounds.Size )
+		
+		_canvas.BeginRender( bounds,New AffineMat3f )
+		
+		If _clearEnabled _canvas.Clear( _clearColor )
+		
+		Render( _canvas )
+		
+		_canvas.EndRender()
+		
+		SDL_GL_SwapWindow( _sdlWindow )
+	End
+	
+	Method Init( title:String,rect:Recti,flags:WindowFlags )
 	
 	
 		Local x:=(flags & WindowFlags.CenterX) ? SDL_WINDOWPOS_CENTERED Else rect.X
 		Local x:=(flags & WindowFlags.CenterX) ? SDL_WINDOWPOS_CENTERED Else rect.X
 		Local y:=(flags & WindowFlags.CenterY) ? SDL_WINDOWPOS_CENTERED Else rect.Y
 		Local y:=(flags & WindowFlags.CenterY) ? SDL_WINDOWPOS_CENTERED Else rect.Y
@@ -374,6 +364,12 @@ Class Window Extends View
 		
 		
 		_canvas=New Canvas( _frame.Width,_frame.Height )
 		_canvas=New Canvas( _frame.Width,_frame.Height )
 		
 		
-		Update()
+		_clearColor=App.Theme.GetColor( "windowClearColor" )
+		
+		SetWindow( Self )
+		
+		UpdateActive()
+
+		LayoutWindow()
 	End
 	End
 End
 End

+ 2 - 9
modules/mojo/docs/module.md

@@ -1,5 +1,5 @@
 
 
-# The mojo module
+# The mojo module.
 
 
 The mojo module provides a simple cross platform application framework for writing games and other graphical apps.
 The mojo module provides a simple cross platform application framework for writing games and other graphical apps.
 
 
@@ -9,25 +9,19 @@ The mojo module provides a simple cross platform application framework for writi
 To initialize mojo, you need to do at least 3 things:
 To initialize mojo, you need to do at least 3 things:
 
 
 * Create an [[app.AppInstance]] using 'New AppInstance'. This will automatically initialize the [[app.App]] global variable.
 * Create an [[app.AppInstance]] using 'New AppInstance'. This will automatically initialize the [[app.App]] global variable.
-
-* Create a [[app.Window]]. You will generally create a subclass of window you have defined yourself, eg: 'New MyWindow'.
-
+* Create an [[app.Window]]. You will generally create a subclass of window you have defined yourself, eg: 'New MyWindow'.
 * Start the app using App.Run().
 * Start the app using App.Run().
 
 
 This can all be done inside Main().
 This can all be done inside Main().
 
 
-
 Once the app is running, mojo runs a simple event loop that looks like this:
 Once the app is running, mojo runs a simple event loop that looks like this:
 
 
 * Get OS events and dispatch corresponding mojo events if necessary.
 * Get OS events and dispatch corresponding mojo events if necessary.
-
 * Once there are no OS events left to process, any custom [[app.AppInstance.Idle]] handlers are called.
 * Once there are no OS events left to process, any custom [[app.AppInstance.Idle]] handlers are called.
-
 * If the application has called [[app.AppInstance.RequestRender]], then the app is rendered.
 * If the application has called [[app.AppInstance.RequestRender]], then the app is rendered.
 
 
 The app will continue executing the event loop until [[app.AppInstance.Terminate]] is called.
 The app will continue executing the event loop until [[app.AppInstance.Terminate]] is called.
 
 
-
 ## Subclassing Window
 ## Subclassing Window
 
 
 Subclassing the app Window class is easy - just extend the [[app.Window]] class.
 Subclassing the app Window class is easy - just extend the [[app.Window]] class.
@@ -38,7 +32,6 @@ The OnRender method is called when the app needs to be rendered, and is passed a
 
 
 In addition, you may also want to override the [[app.Window.OnWindowEvent]] method to handle window close, resize etc events.
 In addition, you may also want to override the [[app.Window.OnWindowEvent]] method to handle window close, resize etc events.
 
 
-
 ## Handling user input
 ## Handling user input
 
 
 There are 2 main ways to handle user input, via the [[app.View.OnKeyEvent]] and [[app.View.OnMouseEvent]] event handlers or using the
 There are 2 main ways to handle user input, via the [[app.View.OnKeyEvent]] and [[app.View.OnMouseEvent]] event handlers or using the

+ 8 - 12
modules/mojo/graphics/canvas.monkey2

@@ -1,9 +1,6 @@
 
 
 Namespace mojo.graphics
 Namespace mojo.graphics
 
 
-#Import "assets/shader_env.glsl@/mojo"
-#Import "assets/RobotoMono-Regular.ttf@/mojo"
-
 #rem monkeydoc @hidden
 #rem monkeydoc @hidden
 #end	
 #end	
 Class DrawOp
 Class DrawOp
@@ -20,17 +17,11 @@ Canvas objects are used to perform rendering to either a mojo [[app.View]] or an
 To draw to a canvas, use one of the 'Draw' methods. Drawing is affected by a number of draw states, including:
 To draw to a canvas, use one of the 'Draw' methods. Drawing is affected by a number of draw states, including:
 
 
 * [[Color]] - the current drawing color. This is combined with the current alpha to produce the final rendering color and alpha values.
 * [[Color]] - the current drawing color. This is combined with the current alpha to produce the final rendering color and alpha values.
-
 * [[Alpha]] - the current drawing alpha level.
 * [[Alpha]] - the current drawing alpha level.
-
 * [[Matrix]] - the current drawing matrix. All drawing coordinates are multiplied by this matrix before rendering.
 * [[Matrix]] - the current drawing matrix. All drawing coordinates are multiplied by this matrix before rendering.
-
 * [[BlendMode]] - the blending mode for drawing, eg: opaque, alpha, additive, multiply.
 * [[BlendMode]] - the blending mode for drawing, eg: opaque, alpha, additive, multiply.
-
 * [[Viewport]] - the current viewport. All drawing coordinates are relative to the top-left of the viewport.
 * [[Viewport]] - the current viewport. All drawing coordinates are relative to the top-left of the viewport.
-
 * [[Scissor]] - the current scissor rect. All rendering is clipped to the union of the viewport and the scissor rect.
 * [[Scissor]] - the current scissor rect. All rendering is clipped to the union of the viewport and the scissor rect.
-
 * [[Font]] - The current font to use when drawing text with [[DrawText]].
 * [[Font]] - The current font to use when drawing text with [[DrawText]].
 
 
 Drawing does not occur immediately. Drawing commands are 'buffered' to reduce the overhead of sending lots of draw calls to the lower level graphics API. You can force all drawing commands in the buffer to actually render using [[Flush]].
 Drawing does not occur immediately. Drawing commands are 'buffered' to reduce the overhead of sending lots of draw calls to the lower level graphics API. You can force all drawing commands in the buffer to actually render using [[Flush]].
@@ -631,6 +622,11 @@ Class Canvas
 		AddVertex( rect.min.x,rect.max.y,s0,t1 )
 		AddVertex( rect.min.x,rect.max.y,s0,t1 )
 	End
 	End
 	
 	
+	Method DrawRect( x:Float,y:Float,width:Float,height:Float,srcImage:Image,srcX:Int,srcY:Int )
+
+		DrawRect( New Rectf( x,y,x+width,y+height ),srcImage,New Recti( srcX,srcY,srcX+width,srcY+height ) )
+	End
+	
 	Method DrawRect( x:Float,y:Float,width:Float,height:Float,srcImage:Image,srcX:Int,srcY:Int,srcWidth:Int,srcHeight:Int )
 	Method DrawRect( x:Float,y:Float,width:Float,height:Float,srcImage:Image,srcX:Int,srcY:Int,srcWidth:Int,srcHeight:Int )
 
 
 		DrawRect( New Rectf( x,y,x+width,y+height ),srcImage,New Recti( srcX,srcY,srcX+srcWidth,srcY+srcHeight ) )
 		DrawRect( New Rectf( x,y,x+width,y+height ),srcImage,New Recti( srcX,srcY,srcX+srcWidth,srcY+srcHeight ) )
@@ -843,8 +839,8 @@ Class Canvas
 		_matrix=matrix
 		_matrix=matrix
 	End
 	End
 
 
-	Method DrawImage( image:Image,tv:Vec2f,rz:Float,scale:Vec2f )
-		DrawImage( image,tv.x,tv.y,rz,scale.x,scale.y )
+	Method DrawImage( image:Image,translation:Vec2f,rz:Float,scale:Vec2f )
+		DrawImage( image,translation.x,translation.y,rz,scale.x,scale.y )
 	End
 	End
 	
 	
 	#rem monkeydoc Draws text.
 	#rem monkeydoc Draws text.
@@ -975,7 +971,7 @@ Class Canvas
 			Local env:=stringio.LoadString( "asset::mojo/shader_env.glsl" )
 			Local env:=stringio.LoadString( "asset::mojo/shader_env.glsl" )
 			_ambientEnv=New ShaderEnv( "#define RENDERPASS_AMBIENT~n"+env )
 			_ambientEnv=New ShaderEnv( "#define RENDERPASS_AMBIENT~n"+env )
 '			_ambientEnv=New ShaderEnv( "#define RENDERPASS_NORMAL~n"+env )
 '			_ambientEnv=New ShaderEnv( "#define RENDERPASS_NORMAL~n"+env )
-			_defaultFont=Font.Load( "asset::mojo/RobotoMono-Regular.ttf",16 )
+			_defaultFont=Font.Load( "font::DejaVuSans.ttf",16 )
 			_nullShader=Shader.GetShader( "null" )
 			_nullShader=Shader.GetShader( "null" )
 		Endif
 		Endif
 
 

+ 9 - 11
modules/mojo/graphics/shader.monkey2

@@ -1,11 +1,6 @@
 
 
 Namespace mojo.graphics
 Namespace mojo.graphics
 
 
-#Import "assets/shader_sprite.glsl@/mojo"
-#Import "assets/shader_phong.glsl@/mojo"
-#Import "assets/shader_font.glsl@/mojo"
-#Import "assets/shader_null.glsl@/mojo"
-
 Private
 Private
 
 
 Function BindUniforms( uniforms:Uniform[],params:ParamBuffer,filter:Bool )
 Function BindUniforms( uniforms:Uniform[],params:ParamBuffer,filter:Bool )
@@ -25,13 +20,16 @@ Function BindUniforms( uniforms:Uniform[],params:ParamBuffer,filter:Bool )
 			Local tex:=p.texture
 			Local tex:=p.texture
 			DebugAssert( tex,"Can't bind shader texture uniform '"+u.name+"' - no texture!" )
 			DebugAssert( tex,"Can't bind shader texture uniform '"+u.name+"' - no texture!" )
 			glActiveTexture( GL_TEXTURE0+u.texunit )
 			glActiveTexture( GL_TEXTURE0+u.texunit )
-			glBindTexture( GL_TEXTURE_2D,tex.GLTexture )
-			If (tex.Flags & TextureFlags.Filter) And filter
-				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR )
-			Else
-				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST )
+			Local gltex:=tex.GLTexture
+			If gltex
+				glBindTexture( GL_TEXTURE_2D,tex.GLTexture )
+				If (tex.Flags & TextureFlags.Filter) And filter
+					glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR )
+				Else
+					glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST )
+				Endif
+				glUniform1i( u.location,u.texunit )
 			Endif
 			Endif
-			glUniform1i( u.location,u.texunit )
 		Default
 		Default
 			Assert( False,"Unsupported uniform type for param:"+u.name )
 			Assert( False,"Unsupported uniform type for param:"+u.name )
 		End
 		End

+ 2 - 1
modules/mojo/graphics/texture.monkey2

@@ -153,7 +153,8 @@ Class Texture
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
 	#end	
 	#end	
 	Property GLTexture:GLuint()
 	Property GLTexture:GLuint()
-		DebugAssert( Not _discarded,"texture has been discarded" )
+		If _discarded Return 0
+'		DebugAssert( Not _discarded,"texture has been discarded" )
 	
 	
 		If _texSeq=glGraphicsSeq And Not _texDirty And Not _mipsDirty Return _glTexture
 		If _texSeq=glGraphicsSeq And Not _texDirty And Not _mipsDirty Return _glTexture
 		
 		

+ 3 - 0
modules/mojo/module.json

@@ -1,5 +1,8 @@
 {
 {
 	"module":"mojo",
 	"module":"mojo",
+	"about":"Monkey2 app framework",
+	"author":"Mark Sibly",
 	"version":"1.0.0",
 	"version":"1.0.0",
+	"support":"http://monkey2.monkey-x.com",
 	"depends":["freetype","emscripten","std","sdl2","gles20","openal"]
 	"depends":["freetype","emscripten","std","sdl2","gles20","openal"]
 }
 }

+ 23 - 0
modules/mojo/mojo.monkey2

@@ -1,6 +1,8 @@
 
 
 Namespace mojo
 Namespace mojo
 
 
+#Import "assets/"
+
 #Import "<emscripten>"
 #Import "<emscripten>"
 #Import "<std>"
 #Import "<std>"
 #Import "<sdl2>"
 #Import "<sdl2>"
@@ -11,6 +13,9 @@ Namespace mojo
 #Import "app/event"
 #Import "app/event"
 #Import "app/skin"
 #Import "app/skin"
 #Import "app/style"
 #Import "app/style"
+#Import "app/theme"
+#import "app/jsonify"
+
 #Import "app/view"
 #Import "app/view"
 #Import "app/window"
 #Import "app/window"
 #Import "app/glwindow"
 #Import "app/glwindow"
@@ -47,4 +52,22 @@ Using mojo..
 Private
 Private
 
 
 Function Main()
 Function Main()
+
+	Stream.OpenFuncs["font"]=Lambda:Stream( proto:String,path:String,mode:String )
+	
+		Return Stream.Open( "asset::fonts/"+path,mode )
+	End
+		
+	Stream.OpenFuncs["image"]=Lambda:Stream( proto:String,path:String,mode:String )
+	
+		Return Stream.Open( "asset::images/"+path,mode )
+	End
+
+	Stream.OpenFuncs["theme"]=Lambda:Stream( proto:String,path:String,mode:String )
+	
+		If Not App Or Not App.Theme Or Not App.Theme.Path Return Null
+
+		Return Stream.Open( ExtractDir( App.Theme.Path )+path,mode )
+	End
+	
 End
 End

+ 6 - 0
modules/mojo/process/native/process.cpp

@@ -34,6 +34,8 @@ struct semaphore{
 #include <windows.h>
 #include <windows.h>
 #include <tlhelp32.h>
 #include <tlhelp32.h>
 
 
+extern "C" WINBASEAPI WINBOOL WINAPI CancelIoEx( HANDLE hFile,LPOVERLAPPED lpOverlapped );
+
 #else
 #else
 
 
 #include <sys/ioctl.h>
 #include <sys/ioctl.h>
@@ -451,7 +453,11 @@ void bbProcess::terminate(){
 	if( !_rep ) return;
 	if( !_rep ) return;
 
 
 #if _WIN32
 #if _WIN32
+
 	TerminateProcessGroup( _rep->proc,-1 );
 	TerminateProcessGroup( _rep->proc,-1 );
+	
+	CancelIoEx( _rep->out,0 );
+
 #else
 #else
 	killpg( _rep->proc,SIGTERM );
 	killpg( _rep->proc,SIGTERM );
 #endif
 #endif

+ 2 - 2
modules/mojo/process/process.monkey2

@@ -1,9 +1,9 @@
 
 
-Namespace mojo.process
-
 #Import "native/process.h"
 #Import "native/process.h"
 #Import "native/process.cpp"
 #Import "native/process.cpp"
 
 
+Namespace mojo.process
+
 Extern
 Extern
 
 
 Class Process="bbProcess"
 Class Process="bbProcess"

+ 4 - 1
modules/mojo/requesters/native/requesters.cpp

@@ -192,7 +192,10 @@ bbString bbRequesters::RequestDir( bbString title,bbString dir ){
 
 
 void bbRequesters::OpenUrl( bbString url ){
 void bbRequesters::OpenUrl( bbString url ){
 
 
-	ShellExecute( HWND_DESKTOP,"open",url.c_str(),0,0,SW_SHOWNORMAL );
+	CoInitializeEx( NULL,COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE );
+	
+	ShellExecute( HWND_DESKTOP,0,url.c_str(),0,0,SW_SHOWNORMAL );
+//	ShellExecute( HWND_DESKTOP,"open",url.c_str(),0,0,SW_SHOWNORMAL );
 }
 }
 
 
 #elif __linux
 #elif __linux