Browse Source

More mojo tweaks.

Mark Sibly 9 năm trước cách đây
mục cha
commit
34a9c91b6c

+ 404 - 0
modules/mojo/app/theme.monkey2

@@ -0,0 +1,404 @@
+
+Namespace mojo.app
+
+Class Theme
+
+	Property Path:String()
+
+		Return _themePath
+	End
+	
+	Property DefaultStyle:Style()
+	
+		Return _defaultStyle
+	End
+	
+	#rem monkeydoc Gets a color from the theme.
+	
+	If no color named `name` is found, [[Color.Grey]] is returned.
+	
+	#end
+	Method GetColor:Color( name:String )
+	
+		If _colors.Contains( name ) Return _colors[name]
+		
+		Return Color.Grey
+	End
+	
+	#rem monkeydoc Gets a font from the theme.
+	
+	If no font named `name` is found, [[App.DefaultFont]] is returned.
+
+	#end
+	Method GetFont:Font( name:String )
+	
+		Local font:=_fonts[name]
+		If font Return font
+		
+		Return App.DefaultFont
+	End
+	
+	#rem monkeydoc Gets a style from the theme.
+	
+	If no style named `name` is found, the [[DefaultStyle]] for the theme is returned.
+	
+	#end
+	Method GetStyle:Style( name:String )
+	
+		Local style:=_styles[name]
+		If style Return style
+		
+		Return _defaultStyle
+	End
+	
+	#rem monkeydoc Loads a font from a file.
+	
+	If `file` is an absolute path, this method is effectively the same as calling [[Font.Load]].
+	
+	If `file` is not an absolute path, the font is searched for in the following locations:
+	
+	* The theme's directory.
+	
+	* The asset::fonts/ directory.
+	
+	#end
+	Method LoadFont:Font( file:String,size:Int )
+	
+		Local font:Font
+		
+		If ExtractRootDir( file )
+			font=Font.Open( file,size )
+		Else
+			font=Font.Open( _themeDir+file,size )
+			If Not font 
+				font=Font.Open( "asset::fonts/"+file,size )
+			Endif
+		Endif
+		
+		If Not font Return App.DefaultFont
+		
+		Return font
+	End
+	
+	#rem monkeydoc Loads an array of icon images from a file.
+	
+	Loads an array of icons from an image file.
+	
+	The icons should be square, and laid out in a horizontal 'strip' within the image file.
+	
+	The width and height of each image is taken from the height of the image file.
+	
+	The number of icons loaded is the width of the image file divided by its height.
+	
+	If `file` is not an absolute path, the file is searched for in the following locations:
+	
+	* The theme's directory.
+	
+	* The asset::images/ directory.
+	
+	#end
+	Method LoadIcons:Image[]( file:String )
+	
+		Local atlas:Image
+		
+		If ExtractRootDir( file )
+			atlas=Image.Load( file )
+		Else
+			atlas=Image.Load( _themeDir+file )
+			If Not atlas
+				atlas=Image.Load( "asset::images/"+file )
+			Endif
+		Endif
+
+		If Not atlas Return Null
+		
+		Local size:=atlas.Height
+		
+		Local n:=atlas.Width/size
+		
+		Local icons:=New Image[n]
+		
+		For Local i:=0 Until n
+			icons[i]=New Image( atlas,New Recti( i*size,0,i*size+size,atlas.Height ) )
+		Next
+		
+		Return icons
+	End
+	
+	#rem monkeydoc Loads a skin from a file.
+	
+	If `file` is an absolute path, this method is effectively the same as calling [[Skin.Load]].
+	
+	If `file` is not an absolute path, the skin is searched for in the following locations:
+	
+	* The theme directory.
+	
+	* The asset::images/ directory.
+	
+	#end
+	Method LoadSkin:Skin( file:String )
+	
+		Local skin:Skin
+
+		If ExtractRootDir( file )
+			skin=Skin.Load( file )
+		Else
+			skin=Skin.Load( _themeDir+file )
+			If Not skin skin=Skin.Load( "asset::images/"+file )
+		Endif
+		
+		Return skin
+	End
+
+	#rem monkeydoc Loads a theme from a file.
+	
+	#end
+	Function Load:Theme( path:String )
+	
+		Local jobj:=JsonObject.Load( path )
+		If Not jobj 
+			Print "Failed to load theme:"+path
+			return New Theme
+		Endif
+		
+		Return New Theme( path,jobj )
+	End
+
+	Private
+	
+	Const _jdefault:=New JsonString( "default" )
+
+	Field _themePath:String
+	Field _themeDir:String
+	
+	Field _defaultStyle:Style
+	
+	Field _colors:=New StringMap<Color>
+	Field _fonts:=New StringMap<Font>
+	Field _styles:=New StringMap<Style>
+	
+	Field _jcolors:StringMap<JsonValue>
+	Field _jfonts:StringMap<JsonValue>
+	Field _jstyles:StringMap<JsonValue>
+	
+	Method New()
+		_themePath=""
+		_themeDir=""
+		_defaultStyle=New Style
+		_defaultStyle.Font=App.DefaultFont
+	End
+	
+	Method New( path:String,jobj:JsonObject )
+		Self.New()
+	
+		_themePath=path
+		_themeDir=ExtractDir( _themePath )
+	
+		_jcolors=jobj["colors"].ToObject()
+		_jfonts=jobj["fonts"].ToObject()
+		_jstyles=jobj["styles"].ToObject()
+		
+		_defaultStyle=LoadStyle( _jdefault )
+		
+		For Local it:=Eachin _jcolors
+			LoadColor( New JsonString( it.Key ) )
+		Next
+		
+		For Local it:=Eachin _jfonts
+			LoadFont( New JsonString( it.Key ) )
+		Next
+		
+		For Local it:=Eachin _jstyles
+			LoadStyle( New JsonString( it.Key ) )
+		Next
+		
+		_jcolors=Null
+		_jfonts=Null
+		_jstyles=Null
+	End
+	
+	Method ToRect:Recti( jrect:JsonValue )
+	
+		Local arr:=jrect.ToArray()
+		
+		Local l:=0,t:=0,r:=0,b:=0
+		
+		Select arr.Length
+		Case 1
+			l=arr[0].ToNumber() ; r=l
+			t=arr[0].ToNumber() ; b=t
+		Case 2
+			l=arr[0].ToNumber() ; r=l
+			t=arr[1].ToNumber() ; b=t
+		Case 4
+			l=arr[0].ToNumber()
+			t=arr[1].ToNumber()
+			r=arr[2].ToNumber()
+			b=arr[3].ToNumber()
+		End
+		
+		Return New Recti( -l,-t,r,b )
+	End
+	
+	Method LoadColor:Color( jcolor:JsonValue )
+	
+		Local jarr:=Cast<JsonArray>( jcolor )
+		If jarr
+		
+			Local r:=0.0,g:=0.0,b:=0.0,a:=1.0
+
+			Select jarr.Length
+			Case 1
+				r=jarr[0].ToNumber()
+				g=jarr[0].ToNumber()
+				b=jarr[0].ToNumber()
+			Case 3
+				r=jarr[0].ToNumber()
+				g=jarr[1].ToNumber()
+				b=jarr[2].ToNumber()
+			Case 4
+				r=jarr[0].ToNumber()
+				g=jarr[1].ToNumber()
+				b=jarr[2].ToNumber()
+				a=jarr[3].ToNumber()
+			Default
+				Return Color.Magenta
+			End
+			
+			Return New Color( r,g,b,a )
+		Endif
+		
+		Local str:=jcolor.ToString()
+		
+		If str.StartsWith( "#" )
+		
+			Local a:=1.0,r:=0.0,g:=0.0,b:=0.0
+		
+			If str.Length=4			'#RGB
+				r=StringToULong( str.Slice( 1,2 ),16 )/15.0
+				g=StringToULong( str.Slice( 2,3 ),16 )/15.0
+				b=StringToULong( str.Slice( 3,4 ),16 )/15.0
+			Else If str.Length=5	'#ARGB
+				a=StringToULong( str.Slice( 1,2 ),16 )/15.0
+				r=StringToULong( str.Slice( 2,3 ),16 )/15.0
+				g=StringToULong( str.Slice( 3,4 ),16 )/15.0
+				b=StringToULong( str.Slice( 4,5 ),16 )/15.0
+			Else If str.Length=7	'#RRGGBB
+				r=StringToULong( str.Slice( 1,3 ),16 )/255.0
+				g=StringToULong( str.Slice( 3,5 ),16 )/255.0
+				b=StringToULong( str.Slice( 5,7 ),16 )/255.0
+			Else If str.Length=9	'#AARRGGBB
+				a=StringToULong( str.Slice( 1,3 ),16 )/255.0
+				r=StringToULong( str.Slice( 3,5 ),16 )/255.0
+				g=StringToULong( str.Slice( 5,7 ),16 )/255.0
+				b=StringToULong( str.Slice( 7,9 ),16 )/255.0
+			Else
+				Return Color.Magenta
+			Endif
+			
+			Return New Color( r,g,b,a )
+			
+		Endif
+		
+		If _colors.Contains( str ) Return _colors[str]
+		
+		jcolor=_jcolors[str]
+		If Not jcolor Return Color.Magenta
+		
+		Local color:=LoadColor( jcolor )
+		
+		_colors[str]=color
+		
+		Return color
+	End
+	
+	Method LoadFont:Font( name:JsonValue )
+	
+		Local str:=name.ToString()
+	
+		If _fonts.Contains( str ) Return _fonts[str]
+		
+		Local jfont:=_jfonts[str]
+		If Not jfont Return App.DefaultFont
+		
+		Local fname:=jfont.ToString()
+		
+		Local fsize:=0
+		Local i:=fname.Find( "," )
+		If i<>-1
+			fsize=Int( fname.Slice( i+1 ) )
+			fname=fname.Slice( 0,i )
+		Endif
+
+		Local font:=LoadFont( fname,fsize )
+
+		_fonts[str]=font
+		
+		Return font
+	End
+	
+	Method SetStyle( style:Style,jstyle:StringMap<JsonValue> )
+	
+		If jstyle.Contains( "backgroundColor" ) style.BackgroundColor=LoadColor( jstyle["backgroundColor"] )
+		If jstyle.Contains( "borderColor" ) style.BorderColor=LoadColor( jstyle["borderColor"] )
+		If jstyle.Contains( "textColor" ) style.TextColor=LoadColor( jstyle["textColor"] )
+		If jstyle.Contains( "iconColor" ) style.IconColor=LoadColor( jstyle["iconColor"] )
+		If jstyle.Contains( "skinColor" ) style.SkinColor=LoadColor( jstyle["skinColor"] )
+		
+		If jstyle.Contains( "padding" ) style.Padding=ToRect( jstyle["padding"] )
+		If jstyle.Contains( "border" ) style.Border=ToRect( jstyle["border"] )
+		If jstyle.Contains( "margin" ) style.Margin=ToRect( jstyle["margin"] )
+		
+		If jstyle.Contains( "icons" ) style.Icons=LoadIcons( jstyle["icons"].ToString() )
+		If jstyle.Contains( "skin" ) style.Skin=LoadSkin( jstyle["skin"].ToString() )
+
+		If jstyle.Contains( "font" ) style.Font=LoadFont( jstyle["font"] )
+	End
+	
+	Method LoadStyle:Style( name:JsonValue )
+	
+		Local str:=name.ToString()
+		
+		If _styles.Contains( str ) Return _styles[str]
+		
+		Local jobj:=_jstyles[str]
+		If Not jobj Return _defaultStyle
+		
+		Local jstyle:=jobj.ToObject()
+		
+		Local pstyle:Style
+		
+		If jstyle.Contains( "extends" )
+			pstyle=LoadStyle( jstyle["extends"] )
+		Else
+			pstyle=_defaultStyle
+		Endif
+		
+		Local style:=New Style( pstyle )
+		
+		SetStyle( style,jstyle )
+		
+		For Local it:=Eachin style.States
+
+			SetStyle( it.Value,jstyle )
+		Next
+		
+		If jstyle.Contains( "states" )
+		
+			local jstates:=jstyle["states"].ToObject()
+			
+			For Local it:=Eachin jstates
+			
+				Local state:=style.AddState( it.Key )
+
+				SetStyle( state,it.Value.ToObject() )
+			Next
+		
+		Endif
+
+		_styles[str]=style
+		
+		Return style
+	End
+	
+End

BIN
modules/mojo/assets/fonts/DejaVuSans.ttf


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


+ 22 - 0
modules/mojo/assets/themes/default.json

@@ -0,0 +1,22 @@
+{
+	"colors":{
+	
+		"windowClearColor":"#888"
+	},
+	
+	"fonts":{
+	
+		"normal":"DejaVuSans,16"
+	},
+	
+	"styles":{
+	
+		"default":{
+		
+			"font":"normal"
+		},
+		
+		"Window":{
+		}
+	}
+}

+ 102 - 0
modules/mojo/input/gamecontroller.monkey2

@@ -0,0 +1,102 @@
+
+Namespace mojo.input
+
+#rem monkeydoc @hidden
+#end
+Enum GameControllerButton	'uses SDL values
+	A=0
+	B=1
+	X=2
+	Y=3
+	Back=4
+	Guide=5
+	Start=6
+	LeftStick=7
+	RightStick=8
+	LeftShoulder=9
+	RightShoulder=10
+	DpadUp=11
+	DpadDown=12
+	DpadLeft=13
+	DpadRight=14
+End
+
+#rem monkeydoc @hidden
+#end
+Enum GameControllerAxis		'uses SDL values
+	LeftX=0
+	LeftY=1
+	RightX=2
+	RightY=3
+	LeftTrigger=4
+	RightTrigger=5
+End
+
+#rem monkeydoc @hidden
+#end
+Class GameController Extends InputDevice
+
+	Method New( axisDevice:InputDevice,buttonDevice:InputDevice,_pointerDevice:InputDevice )
+		_axisDevice=axisDevice
+		_buttonDevice=buttonDevice
+		_pointerDevice=pointerDevice
+		For Local i:=0 Until _axisMap.Length
+			_axisMap[i]=i
+		Next
+		For Local i:=0 Until _buttonMap.Length
+			_buttonMap[i]=i
+		Next
+		For Local i:=0 Until _pointerMap.Length
+			_pointerMap[i]=i
+		Next
+	End
+	
+	Method GetAxis:Float( axis:GameControllerAxis ) Override
+		If _axisDevice Return _axisDevice.GetAxis( _axisMap[axis] )
+		Return 0
+	End
+	
+	Method GetButton:Bool( button:GameControllerButton ) Override
+		If _buttonDevice Return _buttonDevice.GetButton( _buttonMap[button] )
+		Return False
+	End
+	
+	Method GetPointer:Vec2i( pointer:Int ) Override
+		If _pointerDevice Return _pointerDevice.GetPointer( _pointerMap[pointer] )
+	End
+	
+	Method MapAxis( axis:GameControllerAxis,deviceAxis:Int )
+		_axisMap[axis]=deviceAxis
+	End
+	
+	Method MapButton( button:GameControllerButton,deviceButton:Int )
+		_buttonMap[button]=deviceButton
+	End
+	
+	Method MapPointer( pointer:Int,devicePointer:Int )
+		_pointerMap[pointer]=devicePointer
+	End
+	
+	Function WASD:GameController()
+		If Not _wasd
+			_wasd=New GameController( Null,Keyboard )
+			_wasd.MapButton( GameControllerButton.DpadLeft,Key.A )
+			_wasd.MapButton( GameControllerButton.DpadRight,Key.D )
+			_wasd.MapButton( GameControllerButton.DpadUp,Key.W )
+			_wasd.MapButton( GameControllerButton.DpadDown,Key.S )
+		Endif
+		Return _wasd
+	End
+	
+	Private
+	
+	Global _wasd:GameController
+	
+	Field _axisDevice:InputDevice
+	Field _buttonDevice:InputDevice
+	Field _pointerDevice:InputDevice
+	Field _axisMap:=New Int[6]
+	Field _buttonMap:=New Int[16]
+	Field _pointerMap:=New Int[10]
+	
+End