BresenhamLine used the dodgy SwapXY... if your code uses it, you should change SwapXY(x,y) to Set(y,x).

#Rem
Copyright (c) 2011 Steve Revill and Shane Woolcock
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#End

Import mojo
Import diddy.framework
Import diddy.assert
Import diddy.vector2d
Import diddy.externfunctions
Import diddy.constants

#If TARGET<>"html5" Then
	Function GetBrowserName:String()
		Return ""
	End
	Function GetBrowserVersion:String()
		Return ""
	End
	Function GetBrowserOS:String()
		Return ""
	End
	#If TARGET<>"flash" Then
		Function GetCurrentURL:String()
			Return ""
		End
	#End
#End

#If LANG <> "java" Then
	Function BuildString:String(arr:Int[], offset:Int, length:Int)
		If offset<0 Or length<=0 Or offset+length > arr.Length Then Return ""
		Local rv:String = String.FromChar(arr[offset])
		For Local i:Int = offset+1 Until offset+length
			rv += String.FromChar(arr[i])
		Next
		Return rv
	End
#End

#If TARGET="xna" Or TARGET="psm" Then
	Private
	Global seekMusicCalled:Bool = False
	Public
	Function SeekMusic:Int(timeMillis:Int)
		If Not seekMusicCalled Then
			seekMusicCalled = True
			Print "Warning: SeekMusic is not implemented in XNA and PSM!"
		End
		Return 1
	End
#End

Function FlushKeys:Void()
	ResetInput()
End

Function GetUpdateRate:Int()
	Return UpdateRate()
End

Function LaunchBrowser(address:String, openNewWindow:Bool = True)
	Local windowName:String = "_self"
	If openNewWindow
		windowName = "_blank"
	End
	LaunchNativeBrowser(address, windowName)
End

Function SetGraphics:Void(w:Int, h:Int)
	SetNativeGraphicsSize(w, h)
	DEVICE_WIDTH = w
	DEVICE_HEIGHT = h
	SCREEN_HEIGHT = h
	SCREEN_WIDTH = w
	SCREEN_WIDTH2 = SCREEN_WIDTH / 2
	SCREEN_HEIGHT2 = SCREEN_HEIGHT / 2
End

Function ExitApp:Void()
	#If TARGET="win8"
		Print "Cant exit a Win8 application"
	#Else
		EndApp()
	#End
End

Function GetDayOfMonth:Int()
	 Local date:=GetDate()
	 Local day:=date[2]
	 Return day
End

Function GetDayOfWeek:Int()
	Print "GetDayOfWeek is not supported returning -1"
	Print "GetDayOfWeek will be removed in future versions!!!"
	Return -1
End

Function GetMonth:Int()
	Local date:=GetDate()
	Local month:=date[1]
	Return month
End

Function GetYear:Int()
	Local date:=GetDate()
	Local year:=date[0]
	Return year
End

Function GetHours:Int()
	Local date:=GetDate()
	Local hour:=date[3]
	Return hour
End

Function GetMinutes:Int()
	Local date:=GetDate()
	Local min:=date[4]
	Return min
End

Function GetSeconds:Int()
	Local date:=GetDate()
	Local sec:=date[5]
	Return sec
End

Function GetMilliSeconds:Int()
	Local date:=GetDate()
	Local msec:=date[6]
	Return msec
End

Function RectsOverlap:Int(x0:Float, y0:Float, w0:Float, h0:Float, x2:Float, y2:Float, w2:Float, h2:Float)
	If x0 > (x2 + w2) Or (x0 + w0) < x2 Then Return False
	If y0 > (y2 + h2) Or (y0 + h0) < y2 Then Return False
	Return True
End

Function DrawRectOutline:Void(x:Int, y:Int, w:Int, h:Int)
	w -= 1
	h -= 1
	DrawLine(x, y, x + w, y)
	DrawLine(x + w, y, x + w, y + h)
	DrawLine(x + w, y + h, x, y + h)
	DrawLine(x, y + h, x, y)
End

Function CircleOverlap:Bool(x1:Float, y1:Float, r1:Float, x2:Float, y2:Float, r2:Float)
	Local dx:Float = x1 - x2
	Local dy:Float = y1 - y2
	Local r:Float = r1 + r2
	If dx * dx + dy * dy <= r * r Then ' collided
		Return True
	End
	Return False
End

Function CircleRectsOverlap:Bool(x1:Float, y1:Float, w1:Float, h1:Float, cx:Float, cy:Float, r:Float)
	Local testX:Float = cx
	Local testY:Float = cy
	If testX < x1 Then testX = x1
	If testX > (x1 + w1) Then testX = (x1 + w1)
	If testY < y1 Then testY = y1
	If testY > (y1 + h1) Then testY = (y1 + h1)
	Return ( (cx - testX) * (cx - testX) + (cy - testY) * (cy - testY)) < r * r
End

Function LoadBitmap:Image(path$, flags%=0)
	Local pointer:Image = LoadImage(path, 1, flags)

	AssertNotNull(pointer, "Error loading bitmap "+path)

   	Return pointer
End

Function LoadAnimBitmap:Image(path$, w%, h%, count%, tmpImage:Image=Null)
	'tmpImage = loadBitmap(path) <-- This creates another image, decided to just copy the code here
	tmpImage = LoadImage(path)

	AssertNotNull(tmpImage, "Error loading bitmap "+path)

	Local pointer:Image = tmpImage.GrabImage( 0, 0, w, h, count, Image.MidHandle)

   	Return pointer
End

Function LoadSoundSample:Sound(path$)
	Local pointer:Sound = LoadSound(path)
	AssertNotNull(pointer, "Error loading sound "+path)
	Return pointer
End

Function FormatNumeric:String(value:Float)
	Local i:Int,s:String,ns:String,k:Int
	Local os:String
	s=String(value)
	os=s
	Local pos:Int=s.Length()
	If s.Find(".")>0 pos=s.Find(".") Else os=""
	For i=pos To 1 Step -1
		If k>2 ns+="." k=0
		k+=1
		ns=ns+Mid(s,i,1)
	Next
	s=""
	For i= ns.Length() To 1 Step -1
		s+=Mid(ns,i,1)
	Next
	If os<>"" s=s+","+os[pos+1..]
	Return s
End

Function Left$( str$,n:Int )
	If n>str.Length() n=str.Length()
	Return str[..n]
End

Function Right$( str$,n:Int )
	If n>str.Length() n=str.Length()
	Return str[str.Length()-n..]
End

Function LSet$( str$,n:Int,char:String=" " )
	Local rep:String
	For Local i:Int=1 To n
		rep=rep+char
	Next
	str=str+rep
	Return str[..n]
End

Function RSet$( str$,n:Int,char:String=" " )
	Local rep:String
	For Local i:Int=1 To n
		rep=rep+char
	Next
	str=rep+str
	Return str[str.Length()-n..]
End

Function Mid$( str$,pos:Int,size:Int=-1 )
	If pos>str.Length() Return ""
	pos-=1
	If( size<0 ) Return str[pos..]
	If pos<0 size=size+pos pos=0
	If pos+size>str.Length() size=str.Length()-pos
	Return str[pos..pos+size]
End

Function StripDir$( path$ )
	Local i:=path.FindLast( "/" )
	If i<>-1 Return path[i+1..]
	Return path
End

Function StripExt$( path$ )
	Local i:=path.FindLast( "." )
	If i<>-1 And path.Find( "/",i+1 )=-1 Return path[..i]
	Return path
End

Function StripAll$( path$ )
	Return StripDir( StripExt( path ) )
End

Function Round%(flot#)
	Return Floor(flot+0.5)
End

'summary: returns an angle between two points
Function CalcAngle:Float(x1:Float, y1:Float, x2:Float, y2:Float)
	Local dx:Float = x2 - x1
	Local dy:Float = y2 - y1
	Return (ATan2(dy, dx) + 360) Mod 360
End

'summary: Calculate distance between two points - overload using x,y
Function CalcDistance:Float(x1:Float, y1:Float, x2:Float, y2:Float)
	Local dx:Float = x2 - x1
	Local dy:Float = y2 - y1
	Return Sqrt(dx * dx + dy * dy)
End

Function PointInSpot:Int(x1:Float, y1:Float, x2:Float, y2:Float, radius:Float)
	Local dx:Float = x2 - x1
	Local dy:Float = y2 - y1
	Return dx * dx + dy * dy <= radius * radius
End

Function AnyInputPressed:Bool()
	For Local i:Int = 0 To 511
		If KeyHit(i) Then Return True
	Next
	Return False
End

Function FormatNumber:String(number:Float, decimal:Int=4, comma:Int=0, padleft:Int=0 )
	Assert(decimal > -1 And comma > -1 And padleft > -1, "Negative numbers not allowed in FormatNumber()")

	Local str:String = number
	Local dl:Int = str.Find(".")
	If decimal = 0 Then decimal = -1
	str = str[..dl+decimal+1]

	If comma
		While dl>comma
			str = str[..dl-comma] + "," + str[dl-comma..]
			dl -= comma
		Wend
	End

	If padleft
		Local paddedLength:Int = padleft+decimal+1
		If paddedLength < str.Length Then str = "Error"
		str = RSet(str,paddedLength)
	End
	Return str
End

Function IsWhitespace:Bool(str:String)
	Return str = "~t" Or str = "~n" Or str = "~r" Or str = " "
End

Function IsWhitespace:Bool(val:Int)
	Return val = ASC_TAB Or val = ASC_LF Or val = ASC_CR Or val = ASC_SPACE
End

Function Interpolate:Float(type:Int, startValue:Float, endValue:Float, alpha:Float)
	Local range:Float = endValue-startValue
	Local rv:Float = 0
	Select type
		Case INTERPOLATION_LINEAR
			rv = startValue + range*alpha

		Case INTERPOLATION_INVERSE_LINEAR
			rv = startValue + range - range*alpha

		Case INTERPOLATION_HALF_SINE
			rv = startValue + range * Sinr(alpha*PI)

		Case INTERPOLATION_HALF_COSINE
			rv = startValue + range * Cosr(alpha*PI)
	End
	' clip to start/end
	If startValue < endValue And rv < startValue Or startValue > endValue And rv > startValue Then
		rv = startValue
	Elseif startValue < endValue And rv > endValue Or startValue > endValue And rv < endValue Then
		rv = endValue
	End
	Return rv
End

' arghhhh monkey needs enums!!!
Function InterpolationFromString:Int(interp:String)
	If interp = "" Or interp = "none" Then Return INTERPOLATION_NONE
	If interp = "linear" Then Return INTERPOLATION_LINEAR
	If interp = "inverselinear" Then Return INTERPOLATION_INVERSE_LINEAR
	If interp = "halfsine" Then Return INTERPOLATION_HALF_SINE
	If interp = "halfcosine" Then Return INTERPOLATION_HALF_COSINE
End

' colour conversions (hsl is range 0-1, return is RGB as a single int)
' Monkey conversion of http://www.geekymonkey.com/Programming/CSharp/RGB2HSL_HSL2RGB.htm
Function HSLtoRGB:Int(hue:Float, saturation:Float, luminance:Float, rgbArray:Int[] = [])
	Local r:Float = luminance, g:Float = luminance, b:Float = luminance
	Local v:Float = 0
	If luminance <= 0.5 Then
		v = luminance * (1.0 + saturation)
	Else
		v = luminance + saturation - luminance * saturation
	End
	If v > 0 Then
		Local m:Float = luminance + luminance - v
		Local sv:Float = (v - m) / v
		hue *= 6
		Local sextant:Int = Int(hue)
		Local fract:Float = hue - sextant
		Local vsf:Float = v * sv * fract
		Local mid1:Float = m + vsf
		Local mid2:Float = v - vsf

		Select sextant
			Case 0
				r = v
				g = mid1
				b = m

			Case 1
				r = mid2
				g = v
				b = m

			Case 2
				r = m
				g = v
				b = mid1

			Case 3
				r = m
				g = mid2
				b = v

			Case 4
				r = mid1
				g = m
				b = v

			Case 5
				r = v
				g = m
				b = mid2
		End
	End
	If rgbArray.Length = 3 Then
		rgbArray[0] = Int(r*255)
		rgbArray[1] = Int(g*255)
		rgbArray[2] = Int(b*255)
	End
	Return $ff000000 | (Int(r*255) Shl 16) | (Int(g*255) Shl 8) | (Int(b*255) Shl 0)
End

' colour conversions (rgb is 0-255, return is a float array, reusing the hslvals array if it was big enough)
' Monkey conversion of http://www.geekymonkey.com/Programming/CSharp/RGB2HSL_HSL2RGB.htm
Function RGBtoHSL:Float[](red:Int, green:Int, blue:Int, hslvals:Float[] = [])
	If hslvals.Length <> 3 Then hslvals = New Float[3]
	Local r:Float = red/255.0, g:Float = green/255.0, b:Float = blue/255.0
	hslvals[0] = 0
	hslvals[1] = 0
	hslvals[2] = 0

	' calculate luminance
	Local v:Float = Max(Max(r,g),b)
	Local m:Float = Min(Min(r,g),b)
	hslvals[2] = (m + v) / 2.0
	' die if it's black
	If hslvals[2] <= 0 Then Return hslvals

	' precalculate saturation
	Local vm:Float = v - m
	hslvals[1] = vm
	' die if it's grey
	If hslvals[1] <= 0 Then Return hslvals

	' finish saturation
	If hslvals[2] <= 0.5 Then
		hslvals[1] /= v + m
	Else
		hslvals[1] /= 2 - v - m
	End

	Local r2:Float = (v - r) / vm
	Local g2:Float = (v - g) / vm
	Local b2:Float = (v - b) / vm
	If r = v Then
		If g = m Then hslvals[0] = 5 + b2 Else hslvals[0] = 1 - g2
	Elseif g = v Then
		If b = m Then hslvals[0] = 1 + r2 Else hslvals[0] = 3 - b2
	Else
		If r = m Then hslvals[0] = 3 + g2 Else hslvals[0] = 5 - r2
	End
	hslvals[0] /= 6.0

	Return hslvals
End

Function DecToHex:String(dec:Int)
	Local rv:String = ""
	If dec <= 0 Then Return "0"
	While dec > 0
		If dec Mod 16 < 10 Then
			rv += dec Mod 16
		Else
			rv += String.FromChar(ASC_LOWER_A+(dec Mod 16)-10)
		End
		dec = dec / 16
	End
	Return rv
End

Function HexToDec:Int(hx:String)
	Local rv:Int = 0
	Local lookup:String = "0123456789abcdef"
	hx = hx.ToLower()
	For Local i:Int = 0 Until hx.Length()
		rv *= 16
		Local idx:Int = lookup.Find(hx[i..i+1])
		If idx < 0 Then Error("Error parsing Hex string!")
		rv += idx
	Next
	Return rv
End

Function DrawLineThick(x1:Int, y1:Int, x2:Int, y2:Int, thinkness:Int = 2)
	Local steep:Bool = Abs(y2 - y1) > Abs(x2 - x1)
	Local swapped:Bool = False

	If steep
		Local tmp:Int = x1
		x1 = y1
		y1 = tmp

		tmp = x2
		x2 = y2
		y2 = tmp
	End

	If x1 > x2
		Local t:Float = x1
		x1 = x2
		x2 = t
		t = y1
		y1 = y2
		y2 = t
		swapped = True
	End

	Local deltax:Float = x2 - x1
	Local deltay:Float = Abs(y2 - y1)
	Local error:Float = deltax / 2
	Local ystep:Float
	Local y:Float = y1

	If y1 < y2 Then
		ystep = 1
	Else
		ystep = -1
	End
	Local offset:Int = thinkness / 2
	For Local x:Int = x1 Until x2
		If steep
			DrawRect(y - offset, x - offset, thinkness, thinkness)
		Else
			DrawRect(x - offset, y - offset, thinkness, thinkness)
		End

		error -= deltay
		If error < 0
			y += ystep
			error += deltax
		End
	Next
End

Function BresenhamLine:Vector2D[](startPos:Vector2D, endPos:Vector2D)
	Local points:Stack<Vector2D> = New Stack<Vector2D>
	Local steep:Bool = Abs(endPos.y - startPos.y) > Abs(endPos.x - startPos.x)
	Local swapped:Bool = False

	If steep
		startPos.Set(startPos.y, startPos.x)
		endPos.Set(endPos.y, endPos.x)
	End

	If startPos.x > endPos.x
		Local t:Float = startPos.x
		startPos.x = endPos.x
		endPos.x = t
		t = startPos.y
		startPos.y = endPos.y
		endPos.y = t
		swapped = True
	End

	Local deltax:Float = endPos.x - startPos.x
	Local deltay:Float = Abs(endPos.y - startPos.y)
	Local error:Float = deltax / 2
	Local ystep:Float
	Local y:Float = startPos.y

	If startPos.y < endPos.y Then
		ystep = 1
	Else
		ystep = -1
	End

	For Local x:Int = startPos.x Until endPos.x
		If steep
			points.Push(New Vector2D(y, x))
		Else
			points.Push(New Vector2D(x, y))
		End

		error -= deltay
		If error < 0
			y += ystep
			error += deltax
		End
	Next
	Local arr:Vector2D[] = points.ToArray()
	If swapped
		Arrays < Vector2D >.Reverse(arr)
	End
	Return arr
End

Private
Global screenshotPixels:Int[] ' this is globally cached for performance
Public
' summary: Takes a screenshot of a certain rectangle on the screen.  Defaults to the entire screen.
Function CreateScreenshot:Image(x%=0, y%=0, width%=0, height%=0)
	' if no width passed in, assume the whole width
	If width <= 0 Then
		width = DeviceWidth()
		x = 0
	End

	' if no height passed in, assume the whole height
	If height <= 0 Then
		height = DeviceHeight()
		y = 0
	End

	' check that the rectangle is entirely within the screen bounds
	If x < 0 Or y < 0 Or x + width > DeviceWidth() Or y + height > DeviceHeight() Then Return Null

	' create an image
	Local image:Image = CreateImage(width, height)

	' read the screen
	If screenshotPixels.Length <> width*height Then screenshotPixels = New Int[width*height]
	ReadPixels(screenshotPixels, x, y, width, height)
	image.WritePixels(screenshotPixels, 0, 0, width, height)

	Return image
End

'summary: Returns a random int in the range low (inclusive) to high (exclusive).
Function Rand:Int (low:Int, high:Int)
	Local v:Float = Rnd(low, high)
	if (v < 0) Then v -= 1.0
	Local vi:Int = Int(v)
	if vi = (low - 1) Then vi = Min (-1, high)
	Return vi
End

'summary: Converts Mask Pixel Color to Transparent Pixel
Function PixelArrayMask:Void(pixels:Int[], maskRed:Int = 0, maskGreen:Int = 0, maskBlue:Int = 0)
	For Local i:Int = 0 Until pixels.Length
		Local argb:Int = pixels[i]
		Local a:Int = (argb Shr 24) & $ff
		Local r:Int = (argb Shr 16) & $ff
		Local g:Int = (argb Shr 8) & $ff
		Local b:Int = argb & $ff

		If a = 255 And r = maskRed And g = maskGreen And b = maskBlue
			a = 0
			argb = (a Shl 24) | (r Shl 16) | (g Shl 8) | b
			pixels[i] = argb
		End
	Next
End

Function Lerp:Float(startValue:Float, endValue:Float, progress:Float)
	Return startValue + (endValue-startValue) * progress
End

Function InterpolateWithEase:Float(startValue:Float, endValue:Float, progress:Float, ease:Int)
	If progress <= 0 Then Return startValue
	If progress >= 1 Then Return endValue
	Select ease
		Case EASE_IN_DOUBLE
			Return Lerp(endValue, startValue, (1-progress)*(1-progress)*(1-progress)*(1-progress))
		Case EASE_IN
			Return Lerp(endValue, startValue, (1-progress)*(1-progress))
		Case EASE_IN_HALF
			Return Lerp(endValue, startValue, Pow(1-progress, 1.5))
		Case EASE_OUT
			Return Lerp(startValue, endValue, progress * progress)
		Case EASE_OUT_HALF
			Return Lerp(startValue, endValue, Pow(progress, 1.5))
		Case EASE_OUT_DOUBLE
			Return Lerp(startValue, endValue, progress*progress*progress*progress)
		Case EASE_IN_OUT
			Return startValue + (-2*(progress*progress*progress) + 3*(progress*progress)) * (endValue - startValue)
		Default
			Return Lerp(startValue, endValue, progress);
	End
End

' summary:
' CastUtil is a utility class to allow casting of primitives to Null in the case that the variable type is unknown.
' Assuming Hello is a class, and T is a generic in the current scope...
' [code]
' Local foo:T = <something>
' Local bar:Hello = CastUtil<Hello>.Cast(foo) ' returns Null if foo is primitive
' Local baz:Hello = Hello(foo) ' error if foo is primitive
' [/code]
Class CastUtil<T>
Private
	Global NIL:T

Public
	Function Cast:T(value:Int)
		Return NIL
	End

	Function Cast:T(value:Float)
		Return NIL
	End

	Function Cast:T(value:String)
		Return NIL
	End

	Function Cast:T(value:Bool)
		Return NIL
	End

	Function Cast:T(value:Object)
		'Return T(value) FIXME: this is no longer working for some reason
		Return NIL
	End

	Function IsPrimitive:Bool(value:T)
		'Return Cast(value) = Null ' FIXME
		Return False
	End
End

#Rem
Copyright (c) 2011 Steve Revill and Shane Woolcock
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#End

Import mojo
Import diddy.framework
Import diddy.assert
Import diddy.vector2d
Import diddy.externfunctions
Import diddy.constants

#If TARGET<>"html5" Then
	Function GetBrowserName:String()
		Return ""
	End
	Function GetBrowserVersion:String()
		Return ""
	End
	Function GetBrowserOS:String()
		Return ""
	End
	#If TARGET<>"flash" Then
		Function GetCurrentURL:String()
			Return ""
		End
	#End
#End

#If LANG <> "java" Then
	Function BuildString:String(arr:Int[], offset:Int, length:Int)
		If offset<0 Or length<=0 Or offset+length > arr.Length Then Return ""
		Local rv:String = String.FromChar(arr[offset])
		For Local i:Int = offset+1 Until offset+length
			rv += String.FromChar(arr[i])
		Next
		Return rv
	End
#End

#If TARGET="xna" Or TARGET="psm" Then
	Private
	Global seekMusicCalled:Bool = False
	Public
	Function SeekMusic:Int(timeMillis:Int)
		If Not seekMusicCalled Then
			seekMusicCalled = True
			Print "Warning: SeekMusic is not implemented in XNA and PSM!"
		End
		Return 1
	End
#End

Function FlushKeys:Void()
	ResetInput()
End

Function GetUpdateRate:Int()
	Return UpdateRate()
End

Function LaunchBrowser(address:String, openNewWindow:Bool = True)
	Local windowName:String = "_self"
	If openNewWindow
		windowName = "_blank"
	End
	LaunchNativeBrowser(address, windowName)
End

Function SetGraphics:Void(w:Int, h:Int)
	SetNativeGraphicsSize(w, h)
	DEVICE_WIDTH = w
	DEVICE_HEIGHT = h
	SCREEN_HEIGHT = h
	SCREEN_WIDTH = w
	SCREEN_WIDTH2 = SCREEN_WIDTH / 2
	SCREEN_HEIGHT2 = SCREEN_HEIGHT / 2
End

Function ExitApp:Void()
	#If TARGET="win8"
		Print "Cant exit a Win8 application"
	#Else
		EndApp()
	#End
End

Function GetDayOfMonth:Int()
	 Local date:=GetDate()
	 Local day:=date[2]
	 Return day
End

Function GetDayOfWeek:Int()
	Print "GetDayOfWeek is not supported returning -1"
	Print "GetDayOfWeek will be removed in future versions!!!"
	Return -1
End

Function GetMonth:Int()
	Local date:=GetDate()
	Local month:=date[1]
	Return month
End

Function GetYear:Int()
	Local date:=GetDate()
	Local year:=date[0]
	Return year
End

Function GetHours:Int()
	Local date:=GetDate()
	Local hour:=date[3]
	Return hour
End

Function GetMinutes:Int()
	Local date:=GetDate()
	Local min:=date[4]
	Return min
End

Function GetSeconds:Int()
	Local date:=GetDate()
	Local sec:=date[5]
	Return sec
End

Function GetMilliSeconds:Int()
	Local date:=GetDate()
	Local msec:=date[6]
	Return msec
End

Function RectsOverlap:Int(x0:Float, y0:Float, w0:Float, h0:Float, x2:Float, y2:Float, w2:Float, h2:Float)
	If x0 > (x2 + w2) Or (x0 + w0) < x2 Then Return False
	If y0 > (y2 + h2) Or (y0 + h0) < y2 Then Return False
	Return True
End

Function DrawRectOutline:Void(x:Int, y:Int, w:Int, h:Int)
	w -= 1
	h -= 1
	DrawLine(x, y, x + w, y)
	DrawLine(x + w, y, x + w, y + h)
	DrawLine(x + w, y + h, x, y + h)
	DrawLine(x, y + h, x, y)
End

Function CircleOverlap:Bool(x1:Float, y1:Float, r1:Float, x2:Float, y2:Float, r2:Float)
	Local dx:Float = x1 - x2
	Local dy:Float = y1 - y2
	Local r:Float = r1 + r2
	If dx * dx + dy * dy <= r * r Then ' collided
		Return True
	End
	Return False
End

Function CircleRectsOverlap:Bool(x1:Float, y1:Float, w1:Float, h1:Float, cx:Float, cy:Float, r:Float)
	Local testX:Float = cx
	Local testY:Float = cy
	If testX < x1 Then testX = x1
	If testX > (x1 + w1) Then testX = (x1 + w1)
	If testY < y1 Then testY = y1
	If testY > (y1 + h1) Then testY = (y1 + h1)
	Return ( (cx - testX) * (cx - testX) + (cy - testY) * (cy - testY)) < r * r
End

Function LoadBitmap:Image(path$, flags%=0)
	Local pointer:Image = LoadImage(path, 1, flags)

	AssertNotNull(pointer, "Error loading bitmap "+path)

   	Return pointer
End

Function LoadAnimBitmap:Image(path$, w%, h%, count%, tmpImage:Image=Null)
	'tmpImage = loadBitmap(path) <-- This creates another image, decided to just copy the code here
	tmpImage = LoadImage(path)

	AssertNotNull(tmpImage, "Error loading bitmap "+path)

	Local pointer:Image = tmpImage.GrabImage( 0, 0, w, h, count, Image.MidHandle)

   	Return pointer
End

Function LoadSoundSample:Sound(path$)
	Local pointer:Sound = LoadSound(path)
	AssertNotNull(pointer, "Error loading sound "+path)
	Return pointer
End

Function FormatNumeric:String(value:Float)
	Local i:Int,s:String,ns:String,k:Int
	Local os:String
	s=String(value)
	os=s
	Local pos:Int=s.Length()
	If s.Find(".")>0 pos=s.Find(".") Else os=""
	For i=pos To 1 Step -1
		If k>2 ns+="." k=0
		k+=1
		ns=ns+Mid(s,i,1)
	Next
	s=""
	For i= ns.Length() To 1 Step -1
		s+=Mid(ns,i,1)
	Next
	If os<>"" s=s+","+os[pos+1..]
	Return s
End

Function Left$( str$,n:Int )
	If n>str.Length() n=str.Length()
	Return str[..n]
End

Function Right$( str$,n:Int )
	If n>str.Length() n=str.Length()
	Return str[str.Length()-n..]
End

Function LSet$( str$,n:Int,char:String=" " )
	Local rep:String
	For Local i:Int=1 To n
		rep=rep+char
	Next
	str=str+rep
	Return str[..n]
End

Function RSet$( str$,n:Int,char:String=" " )
	Local rep:String
	For Local i:Int=1 To n
		rep=rep+char
	Next
	str=rep+str
	Return str[str.Length()-n..]
End

Function Mid$( str$,pos:Int,size:Int=-1 )
	If pos>str.Length() Return ""
	pos-=1
	If( size<0 ) Return str[pos..]
	If pos<0 size=size+pos pos=0
	If pos+size>str.Length() size=str.Length()-pos
	Return str[pos..pos+size]
End

Function StripDir$( path$ )
	Local i:=path.FindLast( "/" )
	If i<>-1 Return path[i+1..]
	Return path
End

Function StripExt$( path$ )
	Local i:=path.FindLast( "." )
	If i<>-1 And path.Find( "/",i+1 )=-1 Return path[..i]
	Return path
End

Function StripAll$( path$ )
	Return StripDir( StripExt( path ) )
End

Function Round%(flot#)
	Return Floor(flot+0.5)
End

'summary: returns an angle between two points
Function CalcAngle:Float(x1:Float, y1:Float, x2:Float, y2:Float)
	Local dx:Float = x2 - x1
	Local dy:Float = y2 - y1
	Return (ATan2(dy, dx) + 360) Mod 360
End

'summary: Calculate distance between two points - overload using x,y
Function CalcDistance:Float(x1:Float, y1:Float, x2:Float, y2:Float)
	Local dx:Float = x2 - x1
	Local dy:Float = y2 - y1
	Return Sqrt(dx * dx + dy * dy)
End

Function PointInSpot:Int(x1:Float, y1:Float, x2:Float, y2:Float, radius:Float)
	Local dx:Float = x2 - x1
	Local dy:Float = y2 - y1
	Return dx * dx + dy * dy <= radius * radius
End

Function AnyInputPressed:Bool()
	For Local i:Int = 0 To 511
		If KeyHit(i) Then Return True
	Next
	Return False
End

Function FormatNumber:String(number:Float, decimal:Int=4, comma:Int=0, padleft:Int=0 )
	Assert(decimal > -1 And comma > -1 And padleft > -1, "Negative numbers not allowed in FormatNumber()")

	Local str:String = number
	Local dl:Int = str.Find(".")
	If decimal = 0 Then decimal = -1
	str = str[..dl+decimal+1]

	If comma
		While dl>comma
			str = str[..dl-comma] + "," + str[dl-comma..]
			dl -= comma
		Wend
	End

	If padleft
		Local paddedLength:Int = padleft+decimal+1
		If paddedLength < str.Length Then str = "Error"
		str = RSet(str,paddedLength)
	End
	Return str
End

Function IsWhitespace:Bool(str:String)
	Return str = "~t" Or str = "~n" Or str = "~r" Or str = " "
End

Function IsWhitespace:Bool(val:Int)
	Return val = ASC_TAB Or val = ASC_LF Or val = ASC_CR Or val = ASC_SPACE
End

Function Interpolate:Float(type:Int, startValue:Float, endValue:Float, alpha:Float)
	Local range:Float = endValue-startValue
	Local rv:Float = 0
	Select type
		Case INTERPOLATION_LINEAR
			rv = startValue + range*alpha

		Case INTERPOLATION_INVERSE_LINEAR
			rv = startValue + range - range*alpha

		Case INTERPOLATION_HALF_SINE
			rv = startValue + range * Sinr(alpha*PI)

		Case INTERPOLATION_HALF_COSINE
			rv = startValue + range * Cosr(alpha*PI)
	End
	' clip to start/end
	If startValue < endValue And rv < startValue Or startValue > endValue And rv > startValue Then
		rv = startValue
	Elseif startValue < endValue And rv > endValue Or startValue > endValue And rv < endValue Then
		rv = endValue
	End
	Return rv
End

' arghhhh monkey needs enums!!!
Function InterpolationFromString:Int(interp:String)
	If interp = "" Or interp = "none" Then Return INTERPOLATION_NONE
	If interp = "linear" Then Return INTERPOLATION_LINEAR
	If interp = "inverselinear" Then Return INTERPOLATION_INVERSE_LINEAR
	If interp = "halfsine" Then Return INTERPOLATION_HALF_SINE
	If interp = "halfcosine" Then Return INTERPOLATION_HALF_COSINE
End

' colour conversions (hsl is range 0-1, return is RGB as a single int)
' Monkey conversion of http://www.geekymonkey.com/Programming/CSharp/RGB2HSL_HSL2RGB.htm
Function HSLtoRGB:Int(hue:Float, saturation:Float, luminance:Float, rgbArray:Int[] = [])
	Local r:Float = luminance, g:Float = luminance, b:Float = luminance
	Local v:Float = 0
	If luminance <= 0.5 Then
		v = luminance * (1.0 + saturation)
	Else
		v = luminance + saturation - luminance * saturation
	End
	If v > 0 Then
		Local m:Float = luminance + luminance - v
		Local sv:Float = (v - m) / v
		hue *= 6
		Local sextant:Int = Int(hue)
		Local fract:Float = hue - sextant
		Local vsf:Float = v * sv * fract
		Local mid1:Float = m + vsf
		Local mid2:Float = v - vsf

		Select sextant
			Case 0
				r = v
				g = mid1
				b = m

			Case 1
				r = mid2
				g = v
				b = m

			Case 2
				r = m
				g = v
				b = mid1

			Case 3
				r = m
				g = mid2
				b = v

			Case 4
				r = mid1
				g = m
				b = v

			Case 5
				r = v
				g = m
				b = mid2
		End
	End
	If rgbArray.Length = 3 Then
		rgbArray[0] = Int(r*255)
		rgbArray[1] = Int(g*255)
		rgbArray[2] = Int(b*255)
	End
	Return $ff000000 | (Int(r*255) Shl 16) | (Int(g*255) Shl 8) | (Int(b*255) Shl 0)
End

' colour conversions (rgb is 0-255, return is a float array, reusing the hslvals array if it was big enough)
' Monkey conversion of http://www.geekymonkey.com/Programming/CSharp/RGB2HSL_HSL2RGB.htm
Function RGBtoHSL:Float[](red:Int, green:Int, blue:Int, hslvals:Float[] = [])
	If hslvals.Length <> 3 Then hslvals = New Float[3]
	Local r:Float = red/255.0, g:Float = green/255.0, b:Float = blue/255.0
	hslvals[0] = 0
	hslvals[1] = 0
	hslvals[2] = 0

	' calculate luminance
	Local v:Float = Max(Max(r,g),b)
	Local m:Float = Min(Min(r,g),b)
	hslvals[2] = (m + v) / 2.0
	' die if it's black
	If hslvals[2] <= 0 Then Return hslvals

	' precalculate saturation
	Local vm:Float = v - m
	hslvals[1] = vm
	' die if it's grey
	If hslvals[1] <= 0 Then Return hslvals

	' finish saturation
	If hslvals[2] <= 0.5 Then
		hslvals[1] /= v + m
	Else
		hslvals[1] /= 2 - v - m
	End

	Local r2:Float = (v - r) / vm
	Local g2:Float = (v - g) / vm
	Local b2:Float = (v - b) / vm
	If r = v Then
		If g = m Then hslvals[0] = 5 + b2 Else hslvals[0] = 1 - g2
	Elseif g = v Then
		If b = m Then hslvals[0] = 1 + r2 Else hslvals[0] = 3 - b2
	Else
		If r = m Then hslvals[0] = 3 + g2 Else hslvals[0] = 5 - r2
	End
	hslvals[0] /= 6.0

	Return hslvals
End

Function DecToHex:String(dec:Int)
	Local rv:String = ""
	If dec <= 0 Then Return "0"
	While dec > 0
		If dec Mod 16 < 10 Then
			rv += dec Mod 16
		Else
			rv += String.FromChar(ASC_LOWER_A+(dec Mod 16)-10)
		End
		dec = dec / 16
	End
	Return rv
End

Function HexToDec:Int(hx:String)
	Local rv:Int = 0
	Local lookup:String = "0123456789abcdef"
	hx = hx.ToLower()
	For Local i:Int = 0 Until hx.Length()
		rv *= 16
		Local idx:Int = lookup.Find(hx[i..i+1])
		If idx < 0 Then Error("Error parsing Hex string!")
		rv += idx
	Next
	Return rv
End

Function DrawLineThick(x1:Int, y1:Int, x2:Int, y2:Int, thinkness:Int = 2)
	Local steep:Bool = Abs(y2 - y1) > Abs(x2 - x1)
	Local swapped:Bool = False

	If steep
		Local tmp:Int = x1
		x1 = y1
		y1 = tmp

		tmp = x2
		x2 = y2
		y2 = tmp
	End

	If x1 > x2
		Local t:Float = x1
		x1 = x2
		x2 = t
		t = y1
		y1 = y2
		y2 = t
		swapped = True
	End

	Local deltax:Float = x2 - x1
	Local deltay:Float = Abs(y2 - y1)
	Local error:Float = deltax / 2
	Local ystep:Float
	Local y:Float = y1

	If y1 < y2 Then
		ystep = 1
	Else
		ystep = -1
	End
	Local offset:Int = thinkness / 2
	For Local x:Int = x1 Until x2
		If steep
			DrawRect(y - offset, x - offset, thinkness, thinkness)
		Else
			DrawRect(x - offset, y - offset, thinkness, thinkness)
		End

		error -= deltay
		If error < 0
			y += ystep
			error += deltax
		End
	Next
End

Function BresenhamLine:Vector2D[](startPos:Vector2D, endPos:Vector2D)
	Local points:Stack<Vector2D> = New Stack<Vector2D>
	Local steep:Bool = Abs(endPos.y - startPos.y) > Abs(endPos.x - startPos.x)
	Local swapped:Bool = False

	If steep
		startPos.SwapXY(startPos.x, startPos.y)
		endPos.SwapXY(endPos.x, endPos.y)
	End

	If startPos.x > endPos.x
		Local t:Float = startPos.x
		startPos.x = endPos.x
		endPos.x = t
		t = startPos.y
		startPos.y = endPos.y
		endPos.y = t
		swapped = True
	End

	Local deltax:Float = endPos.x - startPos.x
	Local deltay:Float = Abs(endPos.y - startPos.y)
	Local error:Float = deltax / 2
	Local ystep:Float
	Local y:Float = startPos.y

	If startPos.y < endPos.y Then
		ystep = 1
	Else
		ystep = -1
	End

	For Local x:Int = startPos.x Until endPos.x
		If steep
			points.Push(New Vector2D(y, x))
		Else
			points.Push(New Vector2D(x, y))
		End

		error -= deltay
		If error < 0
			y += ystep
			error += deltax
		End
	Next
	Local arr:Vector2D[] = points.ToArray()
	If swapped
		Arrays < Vector2D >.Reverse(arr)
	End
	Return arr
End

Private
Global screenshotPixels:Int[] ' this is globally cached for performance
Public
' summary: Takes a screenshot of a certain rectangle on the screen.  Defaults to the entire screen.
Function CreateScreenshot:Image(x%=0, y%=0, width%=0, height%=0)
	' if no width passed in, assume the whole width
	If width <= 0 Then
		width = DeviceWidth()
		x = 0
	End

	' if no height passed in, assume the whole height
	If height <= 0 Then
		height = DeviceHeight()
		y = 0
	End

	' check that the rectangle is entirely within the screen bounds
	If x < 0 Or y < 0 Or x + width > DeviceWidth() Or y + height > DeviceHeight() Then Return Null

	' create an image
	Local image:Image = CreateImage(width, height)

	' read the screen
	If screenshotPixels.Length <> width*height Then screenshotPixels = New Int[width*height]
	ReadPixels(screenshotPixels, x, y, width, height)
	image.WritePixels(screenshotPixels, 0, 0, width, height)

	Return image
End

'summary: Returns a random int in the range low (inclusive) to high (exclusive).
Function Rand:Int (low:Int, high:Int)
	Local v:Float = Rnd(low, high)
	if (v < 0) Then v -= 1.0
	Local vi:Int = Int(v)
	if vi = (low - 1) Then vi = Min (-1, high)
	Return vi
End

'summary: Converts Mask Pixel Color to Transparent Pixel
Function PixelArrayMask:Void(pixels:Int[], maskRed:Int = 0, maskGreen:Int = 0, maskBlue:Int = 0)
	For Local i:Int = 0 Until pixels.Length
		Local argb:Int = pixels[i]
		Local a:Int = (argb Shr 24) & $ff
		Local r:Int = (argb Shr 16) & $ff
		Local g:Int = (argb Shr 8) & $ff
		Local b:Int = argb & $ff

		If a = 255 And r = maskRed And g = maskGreen And b = maskBlue
			a = 0
			argb = (a Shl 24) | (r Shl 16) | (g Shl 8) | b
			pixels[i] = argb
		End
	Next
End

Function Lerp:Float(startValue:Float, endValue:Float, progress:Float)
	Return startValue + (endValue-startValue) * progress
End

Function InterpolateWithEase:Float(startValue:Float, endValue:Float, progress:Float, ease:Int)
	If progress <= 0 Then Return startValue
	If progress >= 1 Then Return endValue
	Select ease
		Case EASE_IN_DOUBLE
			Return Lerp(endValue, startValue, (1-progress)*(1-progress)*(1-progress)*(1-progress))
		Case EASE_IN
			Return Lerp(endValue, startValue, (1-progress)*(1-progress))
		Case EASE_IN_HALF
			Return Lerp(endValue, startValue, Pow(1-progress, 1.5))
		Case EASE_OUT
			Return Lerp(startValue, endValue, progress * progress)
		Case EASE_OUT_HALF
			Return Lerp(startValue, endValue, Pow(progress, 1.5))
		Case EASE_OUT_DOUBLE
			Return Lerp(startValue, endValue, progress*progress*progress*progress)
		Case EASE_IN_OUT
			Return startValue + (-2*(progress*progress*progress) + 3*(progress*progress)) * (endValue - startValue)
		Default
			Return Lerp(startValue, endValue, progress);
	End
End

' summary:
' CastUtil is a utility class to allow casting of primitives to Null in the case that the variable type is unknown.
' Assuming Hello is a class, and T is a generic in the current scope...
' [code]
' Local foo:T = <something>
' Local bar:Hello = CastUtil<Hello>.Cast(foo) ' returns Null if foo is primitive
' Local baz:Hello = Hello(foo) ' error if foo is primitive
' [/code]
Class CastUtil<T>
Private
	Global NIL:T

Public
	Function Cast:T(value:Int)
		Return NIL
	End

	Function Cast:T(value:Float)
		Return NIL
	End

	Function Cast:T(value:String)
		Return NIL
	End

	Function Cast:T(value:Bool)
		Return NIL
	End

	Function Cast:T(value:Object)
		'Return T(value) FIXME: this is no longer working for some reason
		Return NIL
	End

	Function IsPrimitive:Bool(value:T)
		'Return Cast(value) = Null ' FIXME
		Return False
	End
End


Added Disconnect method for signals

Added Disconnect method for signals

Strict

Import reflection
Import system.signals.flxsignal

Class FlxSignals

Private
	Field _signals:IntMap<FlxSignal>

	Field _methodSlots:List<FlxMethodSlot>

	Field _functionSlots:List<FlxFunctionSlot>

Public
	Method New()
		_signals = New IntMap<FlxSignal>()
		_methodSlots = New List<FlxMethodSlot>()
		_functionSlots = New List<FlxFunctionSlot>()
	End Method

	Method Connect:Void(signalID:Int, listener:FlxSignalListener)
		_GetSignal(signalID).RegisterListener(listener)
	End Method

	Method Connect:Void(signalID:Int, listener:FlxSignalListener, instant:Bool)
		_GetSignal(signalID).RegisterListener(listener, instant)
	End Method

	Method Connect:Void(signalID:Int, listener:FlxSignalListener, instant:Bool, priority:Int)
		_GetSignal(signalID).RegisterListener(listener, instant, priority)
	End Method

	Method Connect:Void(signalID:Int, methodInfo:MethodInfo, context:Object)
		Connect(signalID, _GetMethodSlot(methodInfo, context))
	End Method

	Method Connect:Void(signalID:Int, methodInfo:MethodInfo, context:Object, instant:Bool)
		Connect(signalID, _GetMethodSlot(methodInfo, context), instant)
	End Method

	Method Connect:Void(signalID:Int, methodInfo:MethodInfo, context:Object, instant:Bool, priority:Int)
		Connect(signalID, _GetMethodSlot(methodInfo, context), instant, priority)
	End Method

	Method Connect:Void(signalID:Int, functionInfo:FunctionInfo)
		Connect(signalID, _GetFunctionSlot(functionInfo))
	End Method

	Method Connect:Void(signalID:Int, functionInfo:FunctionInfo, instant:Bool)
		Connect(signalID, _GetFunctionSlot(functionInfo), instant)
	End Method

	Method Connect:Void(signalID:Int, functionInfo:FunctionInfo, instant:Bool, priority:Int)
		Connect(signalID, _GetFunctionSlot(functionInfo), instant, priority)
	End Method

	Method ConnectM:Void(signalID:Int, methodName:String, context:Object)
		Connect(signalID, _GetMethodSlot(_GetMethodInfo(methodName, context), context))
	End Method

	Method ConnectM:Void(signalID:Int, methodName:String, context:Object, instant:Bool)
		Connect(signalID, _GetMethodSlot(_GetMethodInfo(methodName, context), context), instant)
	End Method

	Method ConnectM:Void(signalID:Int, methodName:String, context:Object, instant:Bool, priority:Int)
		Connect(signalID, _GetMethodSlot(_GetMethodInfo(methodName, context), context), instant, priority)
	End Method

	Method ConnectF:Void(signalID:Int, functionName:String)
		Connect(signalID, _GetFunctionSlot(GetFunction(functionName,[])))
	End Method

	Method ConnectF:Void(signalID:Int, functionName:String, instant:Bool)
		Connect(signalID, _GetFunctionSlot(GetFunction(functionName,[])), instant)
	End Method

	Method ConnectF:Void(signalID:Int, functionName:String, instant:Bool, priority:Int)
		Connect(signalID, _GetFunctionSlot(GetFunction(functionName,[])), instant, priority)
	End Method

	Method Disconnect:Void(signalID:Int, listener:FlxSignalListener)
		Local s:FlxSignal = _signals.Get(signalID)
		If (s <> Null) s.RemoveListener(listener)
	End Method

	Method Disconnect:Void(signalID:Int, methodInfo:MethodInfo, context:Object)
		Disconnect(signalID, _GetMethodSlot(methodInfo, context))
	End Method

	Method Disconnect:Void(signalID:Int, functionInfo:FunctionInfo)
		Disconnect(signalID, _GetFunctionSlot(functionInfo))
	End Method

	Method DisconnectM:Void(signalID:Int, methodName:String, context:Object)
		Disconnect(signalID, _GetMethodSlot(_GetMethodInfo(methodName, context), context))
	End Method

	Method DisconnectF:Void(signalID:Int, functionName:String)
		Disconnect(signalID, _GetFunctionSlot(GetFunction(functionName,[])))
	End Method

	Method Emit:Void(signalID:Int, data:Object = Null)
		_GetSignal(signalID).Emit(data)
	End Method

	Method Emit:Void(signalIDs:Int[], data:Object = Null)
		For Local id:Int = EachIn signalIDs
			_GetSignal(id).Emit(data)
		Next
	End Method

	Method EmitAll:Void(data:Object)
		For Local signal:FlxSignal = EachIn _signals.Values()
			signal.Emit(data)
		Next
	End Method

Private
	Method _GetSignal:FlxSignal(signalID:Int)
		Local s:FlxSignal = _signals.Get(signalID)

		If (s = Null) Then
			s = New FlxSignal(signalID)
			_signals.Set(signalID, s)
		End If

		Return s
	End Method

	Method _GetMethodInfo:MethodInfo(methodName:String, context:Object)
		Local classInfo:ClassInfo = GetClass(context)

		If (classInfo <> Null) Then
			Return classInfo.GetMethod(methodName,[])
		End If

		Return Null
	End Method

	Method _GetMethodSlot:FlxMethodSlot(methodInfo:MethodInfo, context:Object)
		If (methodInfo = Null) Return Null

		Local node:list.Node<FlxMethodSlot> = _methodSlots.FirstNode()

		While (node <> Null)
			If (node.Value()._method = methodInfo And node.Value()._context = context) Then
				Return node.Value()
			End If

			node = node.NextNode()
		Wend

		Return _methodSlots.AddLast(New FlxMethodSlot(context, methodInfo)).Value()
	End Method

	Method _GetFunctionSlot:FlxFunctionSlot(functionInfo:FunctionInfo)
		If (functionInfo = Null) Return Null

		Local node:list.Node<FlxFunctionSlot> = _functionSlots.FirstNode()

		While (node <> Null)
			If (node.Value()._function = functionInfo) Then
				Return node.Value()
			End If

			node = node.NextNode()
		Wend

		Return _functionSlots.AddLast(New FlxFunctionSlot(functionInfo)).Value()
	End Method

End Class

Private

Class FlxMethodSlot Implements FlxSignalListener

Private
	Field _context:Object

	Field _method:MethodInfo

Public
	Method New(context:Object, methodInfo:MethodInfo)
		_context = context
		_method = methodInfo
	End Method

	Method OnSignalEmitted:Void(signal:FlxSignal, data:Object)
		_method.Invoke(_context,[])
	End Method

End Class

Class FlxFunctionSlot Implements FlxSignalListener

Private
	Field _function:FunctionInfo

Public
	Method New(functionInfo:FunctionInfo)
		_function = functionInfo
	End Method

	Method OnSignalEmitted:Void(signal:FlxSignal, data:Object)
		_function.Invoke([])
	End Method

End Class

Strict

Import reflection
Import system.signals.flxsignal

Class FlxSignals

Private
	Field _signals:IntMap<FlxSignal>

	Field _methodSlots:List<FlxMethodSlot>

	Field _functionSlots:List<FlxFunctionSlot>

Public
	Method New()
		_signals = New IntMap<FlxSignal>()
		_methodSlots = New List<FlxMethodSlot>()
		_functionSlots = New List<FlxFunctionSlot>()
	End Method

	Method Connect:Void(signalID:Int, listener:FlxSignalListener)
		_GetSignal(signalID).RegisterListener(listener)
	End Method

	Method Connect:Void(signalID:Int, listener:FlxSignalListener, instant:Bool)
		_GetSignal(signalID).RegisterListener(listener, instant)
	End Method

	Method Connect:Void(signalID:Int, listener:FlxSignalListener, instant:Bool, priority:Int)
		_GetSignal(signalID).RegisterListener(listener, instant, priority)
	End Method

	Method Connect:Void(signalID:Int, methodInfo:MethodInfo, context:Object)
		Connect(signalID, _GetMethodSlot(methodInfo, context))
	End Method

	Method Connect:Void(signalID:Int, methodInfo:MethodInfo, context:Object, instant:Bool)
		Connect(signalID, _GetMethodSlot(methodInfo, context), instant)
	End Method

	Method Connect:Void(signalID:Int, methodInfo:MethodInfo, context:Object, instant:Bool, priority:Int)
		Connect(signalID, _GetMethodSlot(methodInfo, context), instant, priority)
	End Method

	Method Connect:Void(signalID:Int, functionInfo:FunctionInfo)
		Connect(signalID, _GetFunctionSlot(functionInfo))
	End Method

	Method Connect:Void(signalID:Int, functionInfo:FunctionInfo, instant:Bool)
		Connect(signalID, _GetFunctionSlot(functionInfo), instant)
	End Method

	Method Connect:Void(signalID:Int, functionInfo:FunctionInfo, instant:Bool, priority:Int)
		Connect(signalID, _GetFunctionSlot(functionInfo), instant, priority)
	End Method

	Method ConnectM:Void(signalID:Int, methodName:String, context:Object)
		Connect(signalID, _GetMethodSlot(_GetMethodInfo(methodName, context), context))
	End Method

	Method ConnectM:Void(signalID:Int, methodName:String, context:Object, instant:Bool)
		Connect(signalID, _GetMethodSlot(_GetMethodInfo(methodName, context), context), instant)
	End Method

	Method ConnectM:Void(signalID:Int, methodName:String, context:Object, instant:Bool, priority:Int)
		Connect(signalID, _GetMethodSlot(_GetMethodInfo(methodName, context), context), instant, priority)
	End Method

	Method ConnectF:Void(signalID:Int, functionName:String)
		Connect(signalID, _GetFunctionSlot(GetFunction(functionName,[])))
	End Method

	Method ConnectF:Void(signalID:Int, functionName:String, instant:Bool)
		Connect(signalID, _GetFunctionSlot(GetFunction(functionName,[])), instant)
	End Method

	Method ConnectF:Void(signalID:Int, functionName:String, instant:Bool, priority:Int)
		Connect(signalID, _GetFunctionSlot(GetFunction(functionName,[])), instant, priority)
	End Method

	Method Emit:Void(signalID:Int, data:Object = Null)
		_GetSignal(signalID).Emit(data)
	End Method

	Method Emit:Void(signalIDs:Int[], data:Object = Null)
		For Local id:Int = EachIn signalIDs
			_GetSignal(id).Emit(data)
		Next
	End Method

	Method EmitAll:Void(data:Object)
		For Local signal:FlxSignal = EachIn _signals.Values()
			signal.Emit(data)
		Next
	End Method

Private
	Method _GetSignal:FlxSignal(signalID:Int)
		Local s:FlxSignal = _signals.Get(signalID)

		If (s = Null) Then
			s = New FlxSignal()
			_signals.Set(signalID, s)
		End If

		Return s
	End Method

	Method _GetMethodInfo:MethodInfo(methodName:String, context:Object)
		Local classInfo:ClassInfo = GetClass(context)

		If (classInfo <> Null) Then
			Return classInfo.GetMethod(methodName,[])
		End If

		Return Null
	End Method

	Method _GetMethodSlot:FlxMethodSlot(methodInfo:MethodInfo, context:Object)
		If (methodInfo = Null) Return Null

		Local node:list.Node<FlxMethodSlot> = _methodSlots.FirstNode()

		While (node <> Null)
			If (node.Value()._method = methodInfo And node.Value()._context = context) Then
				Return node.Value()
			End If

			node = node.NextNode()
		Wend

		Return _methodSlots.AddLast(New FlxMethodSlot(context, methodInfo)).Value()
	End Method

	Method _GetFunctionSlot:FlxFunctionSlot(functionInfo:FunctionInfo)
		If (functionInfo = Null) Return Null

		Local node:list.Node<FlxFunctionSlot> = _functionSlots.FirstNode()

		While (node <> Null)
			If (node.Value()._function = functionInfo) Then
				Return node.Value()
			End If

			node = node.NextNode()
		Wend

		Return _functionSlots.AddLast(New FlxFunctionSlot(functionInfo)).Value()
	End Method

End Class

Private

Class FlxMethodSlot Implements FlxSignalListener

Private
	Field _context:Object

	Field _method:MethodInfo

Public
	Method New(context:Object, methodInfo:MethodInfo)
		_context = context
		_method = methodInfo
	End Method

	Method OnSignalEmitted:Void(signal:FlxSignal, data:Object)
		_method.Invoke(_context,[])
	End Method

End Class

Class FlxFunctionSlot Implements FlxSignalListener

Private
	Field _function:FunctionInfo

Public
	Method New(functionInfo:FunctionInfo)
		_function = functionInfo
	End Method

	Method OnSignalEmitted:Void(signal:FlxSignal, data:Object)
		_function.Invoke([])
	End Method

End Class


optional arguments: remove spaces before & after "="

Strict

Private

Import bono
Import mojo.graphics

Public

Class Sprite Extends BaseDisplayObject Implements Updateable, Renderable, Rotateable, Timelineable
    Private

    Field currentFrame:Int
    Field frameCount:Int
    Field frameSize:Vector2D
    Field frameTimer:Int
    Field image:Image
    Field renderPos:Vector2D = New Vector2D()
    Field imageName:String
    Field baseRotation:Int
    Field _scale:Vector2D = New Vector2D(1, 1)
    Field lastScale:Vector2D = New Vector2D(1, 1)
    Global cacheImage:StringMap<Image> = New StringMap<Image>()
    Global cacheSize:StringMap<Vector2D> = New StringMap<Vector2D>()
    Field rotation:Float
    Field timelineFactory:TimelineFactory

    Public

    Field frameSpeed:Int
    Field loopAnimation:Bool

    Method New(imageName:String, pos:Vector2D=Null)
        Self.imageName = imageName

        LoadImage()
    End

    Method New(imageName:String, frameSize:Vector2D, frameCount:Int, frameSpeed:Int, pos:Vector2D=Null)
        Self.imageName = imageName
        Self.frameSize = frameSize
        Self.frameCount = frameCount
        Self.frameSpeed = frameSpeed

        LoadImage()
    End

    Method New(imageName:String, image:Image, forcedSize:Vector2D=Null, baseRotation:Int=0)
        Self.imageName = imageName
        Self.image = image
        Self.baseRotation = baseRotation

        If forcedSize
            SetSize(forcedSize)
        Else
            SetSize(New Vector2D(image.Width(), image.Height()))
        End
    End

    Method GetTimeline:TimelineFactory()
        If Not timelineFactory Then timelineFactory = New TimelineFactory(Self)
        Return timelineFactory
    End

    Method SetRotation:Void(angel:Float)
        rotation = angel
        While rotation > 360
            rotation -= 360
        End
        While rotation < 0
            rotation += 360
        End
    End

    Method GetRotation:Float()
        Return rotation
    End

    Method Copy:Sprite()
        Local tmp:Sprite = New Sprite(imageName, image, Null, baseRotation)
        BaseDisplayObject.Copy(Self, tmp)

        tmp.frameSpeed = frameSpeed
        tmp.loopAnimation = loopAnimation
        tmp.rotation = rotation
        tmp.scale = scale.Copy()

        Return tmp
    End

    Method GrabSprite:Sprite(name:String, src:Vector2D, size:Vector2D, rotation:Int=0)
        Local img:Image = image.GrabImage(
            src.x, src.y,
            size.x, size.y,
            1,
            Image.MidHandle)

        Local forcedSize:Vector2D
        Select rotation
        Case 90, 270, -90, -270
            forcedSize = New Vector2D(size.y, size.x)
        Case 0, 180, -180
            ' nothing to do here
        Default
            Throw New InvalidArgumentException(
                "Unable to handle given rotation '" + String(rotation) + "'")
        End

        Return New Sprite(name, img, forcedSize, rotation)
    End

    Method OnRender:Void()
        GetSize().Div(lastScale).Mul(_scale)
        lastScale.Set(_scale)

        renderPos.Set(GetSize()).Div(2)
        renderPos.Add(GetPosition())
        Align.Align(renderPos, Self, GetAlignment())

        GetColor().Activate()
        DrawImage(
            image,
            renderPos.x, renderPos.y,
            baseRotation + rotation,
            _scale.x, _scale.y,
            currentFrame)
        GetColor().Deactivate()
    End

    Method OnUpdate:Void(deltaTimer:DeltaTimer)
        If timelineFactory Then timelineFactory.GetTimeline().OnUpdate(deltaTimer)

        If frameCount <= 0 Then Return
        If animationIsDone Then Return

        If frameTimer < frameSpeed
            frameTimer += deltaTimer.frameTime
            Return
        End

        If (currentFrame + 1) = frameCount
            If loopAnimation
                currentFrame = 1
            End
        Else
            currentFrame += 1
        End
        frameTimer = 0
    End

    Method Restart:Void()
        currentFrame = 0
    End

    Method animationIsDone:Bool() Property
        If loopAnimation Then Return False
        Return (currentFrame = frameCount)
    End

    Method scale:Vector2D() Property
        Return _scale
    End

    Method scale:Void(newScale:Vector2D) Property
        _scale = newScale
    End

    Method filepath:String() Property
        Return imageName
    End

    Method DrawImageRect:Void(pos:Vector2D, rectPos:Vector2D, rectSize:Vector2D)
        DrawImageRect(pos.x, pos.y, rectPos.x, rectPos.y, rectSize.x, rectSize.y)
    End

    Method DrawImageRect:Void(x:Float, y:Float, srcX:Float, srcY:Float, srcWidth:Float, srcHeight:Float)
        ' borrow renderPos (mainly used in OnRender) here to avoid a new
        ' instance of Vector2D
        renderPos.Set(GetSize()).Div(2)

        x += renderPos.x
        y += renderPos.y
        graphics.DrawImageRect(image, x, y, srcX, srcY, srcWidth, srcHeight, rotation, _scale.x, _scale.y, currentFrame)
    End

    Private

    Method CacheSet:Void(name:String, image:Image, size:Vector2D)
        cacheImage.Set(name, image)
        cacheSize.Set(name, size.Copy())
    End

    Method CacheGetSize:Vector2D(name:String)
        Return cacheSize.Get(name).Copy()
    End

    Method CacheGetImage:Image(name:String)
        Return cacheImage.Get(name)
    End

    Method LoadImage:Void()
        ' Try the cache first ...
        image = CacheGetImage(imageName)
        If image
            SetSize(CacheGetSize(imageName))
        End

        ' ... but handle misses aswell
        If Not image
            If frameSize
                image = graphics.LoadImage(imageName, frameSize.x, frameSize.y, frameCount, Image.MidHandle)
                FailIfImageNotLoaded()
                SetSize(frameSize.Copy())
            Else
                image = graphics.LoadImage(imageName, 1, Image.MidHandle)
                FailIfImageNotLoaded()
                SetSize(New Vector2D(image.Width(), image.Height()))
            End
            CacheSet(imageName, image, GetSize())
        End

        GetSize().Mul(scale)
    End

    Method FailIfImageNotLoaded:Void()
        If Not image Then Throw New RuntimeException(
            "Unable to load image file: " + imageName)
    End
End

Strict

Private

Import bono
Import mojo.graphics

Public

Class Sprite Extends BaseDisplayObject Implements Updateable, Renderable, Rotateable, Timelineable
    Private

    Field currentFrame:Int
    Field frameCount:Int
    Field frameSize:Vector2D
    Field frameTimer:Int
    Field image:Image
    Field renderPos:Vector2D = New Vector2D()
    Field imageName:String
    Field baseRotation:Int
    Field _scale:Vector2D = New Vector2D(1, 1)
    Field lastScale:Vector2D = New Vector2D(1, 1)
    Global cacheImage:StringMap<Image> = New StringMap<Image>()
    Global cacheSize:StringMap<Vector2D> = New StringMap<Vector2D>()
    Field rotation:Float
    Field timelineFactory:TimelineFactory

    Public

    Field frameSpeed:Int
    Field loopAnimation:Bool

    Method New(imageName:String, pos:Vector2D=Null)
        Self.imageName = imageName

        LoadImage()
    End

    Method New(imageName:String, frameSize:Vector2D, frameCount:Int, frameSpeed:Int, pos:Vector2D=Null)
        Self.imageName = imageName
        Self.frameSize = frameSize
        Self.frameCount = frameCount
        Self.frameSpeed = frameSpeed

        LoadImage()
    End

    Method New(imageName:String, image:Image, forcedSize:Vector2D = Null, baseRotation:Int = 0)
        Self.imageName = imageName
        Self.image = image
        Self.baseRotation = baseRotation

        If forcedSize
            SetSize(forcedSize)
        Else
            SetSize(New Vector2D(image.Width(), image.Height()))
        End
    End

    Method GetTimeline:TimelineFactory()
        If Not timelineFactory Then timelineFactory = New TimelineFactory(Self)
        Return timelineFactory
    End

    Method SetRotation:Void(angel:Float)
        rotation = angel
        While rotation > 360
            rotation -= 360
        End
        While rotation < 0
            rotation += 360
        End
    End

    Method GetRotation:Float()
        Return rotation
    End

    Method Copy:Sprite()
        Local tmp:Sprite = New Sprite(imageName, image, Null, baseRotation)
        BaseDisplayObject.Copy(Self, tmp)

        tmp.frameSpeed = frameSpeed
        tmp.loopAnimation = loopAnimation
        tmp.rotation = rotation
        tmp.scale = scale.Copy()

        Return tmp
    End

    Method GrabSprite:Sprite(name:String, src:Vector2D, size:Vector2D, rotation:Int = 0)
        Local img:Image = image.GrabImage(
            src.x, src.y,
            size.x, size.y,
            1,
            Image.MidHandle)

        Local forcedSize:Vector2D
        Select rotation
        Case 90, 270, -90, -270
            forcedSize = New Vector2D(size.y, size.x)
        Case 0, 180, -180
            ' nothing to do here
        Default
            Throw New InvalidArgumentException(
                "Unable to handle given rotation '" + String(rotation) + "'")
        End

        Return New Sprite(name, img, forcedSize, rotation)
    End

    Method OnRender:Void()
        GetSize().Div(lastScale).Mul(_scale)
        lastScale.Set(_scale)

        renderPos.Set(GetSize()).Div(2)
        renderPos.Add(GetPosition())
        Align.Align(renderPos, Self, GetAlignment())

        GetColor().Activate()
        DrawImage(
            image,
            renderPos.x, renderPos.y,
            baseRotation + rotation,
            _scale.x, _scale.y,
            currentFrame)
        GetColor().Deactivate()
    End

    Method OnUpdate:Void(deltaTimer:DeltaTimer)
        If timelineFactory Then timelineFactory.GetTimeline().OnUpdate(deltaTimer)

        If frameCount <= 0 Then Return
        If animationIsDone Then Return

        If frameTimer < frameSpeed
            frameTimer += deltaTimer.frameTime
            Return
        End

        If (currentFrame + 1) = frameCount
            If loopAnimation
                currentFrame = 1
            End
        Else
            currentFrame += 1
        End
        frameTimer = 0
    End

    Method Restart:Void()
        currentFrame = 0
    End

    Method animationIsDone:Bool() Property
        If loopAnimation Then Return False
        Return (currentFrame = frameCount)
    End

    Method scale:Vector2D() Property
        Return _scale
    End

    Method scale:Void(newScale:Vector2D) Property
        _scale = newScale
    End

    Method filepath:String() Property
        Return imageName
    End

    Method DrawImageRect:Void(pos:Vector2D, rectPos:Vector2D, rectSize:Vector2D)
        DrawImageRect(pos.x, pos.y, rectPos.x, rectPos.y, rectSize.x, rectSize.y)
    End

    Method DrawImageRect:Void(x:Float, y:Float, srcX:Float, srcY:Float, srcWidth:Float, srcHeight:Float)
        ' borrow renderPos (mainly used in OnRender) here to avoid a new
        ' instance of Vector2D
        renderPos.Set(GetSize()).Div(2)

        x += renderPos.x
        y += renderPos.y
        graphics.DrawImageRect(image, x, y, srcX, srcY, srcWidth, srcHeight, rotation, _scale.x, _scale.y, currentFrame)
    End

    Private

    Method CacheSet:Void(name:String, image:Image, size:Vector2D)
        cacheImage.Set(name, image)
        cacheSize.Set(name, size.Copy())
    End

    Method CacheGetSize:Vector2D(name:String)
        Return cacheSize.Get(name).Copy()
    End

    Method CacheGetImage:Image(name:String)
        Return cacheImage.Get(name)
    End

    Method LoadImage:Void()
        ' Try the cache first ...
        image = CacheGetImage(imageName)
        If image
            SetSize(CacheGetSize(imageName))
        End

        ' ... but handle misses aswell
        If Not image
            If frameSize
                image = graphics.LoadImage(imageName, frameSize.x, frameSize.y, frameCount, Image.MidHandle)
                FailIfImageNotLoaded()
                SetSize(frameSize.Copy())
            Else
                image = graphics.LoadImage(imageName, 1, Image.MidHandle)
                FailIfImageNotLoaded()
                SetSize(New Vector2D(image.Width(), image.Height()))
            End
            CacheSet(imageName, image, GetSize())
        End

        GetSize().Mul(scale)
    End

    Method FailIfImageNotLoaded:Void()
        If Not image Then Throw New RuntimeException(
            "Unable to load image file: " + imageName)
    End
End


Router example fixed

Router example fixed

Strict

Import mojo.graphics
Import bono

Class PlainScene Extends Partial
    Method OnRender:Void()
        Cls(0, 255, 0)
        DrawText("PLAIN", 0, 0)
    End

    Method OnTouchDown:Void(touch:TouchEvent)
        Router(director.handler).Goto("advanced")
    End
End

Class AdvancedScene Extends Partial Implements RouterEvents
    Method OnRender:Void()
        Cls(255, 0, 0)
        DrawText("ADVANCED", 0, 0)
    End

    Method OnTouchDown:Void(touch:TouchEvent)
        Router(director.handler).Goto("plain")
    End

    Method OnEnter:Void()
        Print("scene enter")
    End

    Method OnLeave:Void()
        Print("scene leave")
    End
End

Function Main:Int()
    Local router:Router = New Router()
    router.Add("plain", New PlainScene())
    router.Add("advanced", New AdvancedScene())
    router.Goto("plain")

    Local director:Director = New Director(640, 480)
    director.inputController.trackTouch = True
    director.inputController.trackKeys = True
    director.Run(router)

    Return 0
End

Strict

Import mojo.graphics
Import bono

Class PlainScene Extends Partial
    Method OnRender:Void()
        Cls(0, 255, 0)
        DrawText("PLAIN", 0, 0)
    End

    Method OnTouchDown:Void(touch:TouchEvent)
        Router(director.handler).Goto("advanced")
    End
End

Class AdvancedScene Extends Partial Implements RouterEvents
    Method OnRender:Void()
        Cls(255, 0, 0)
        DrawText("ADVANCED", 0, 0)
    End

    Method OnTouchDown:Void(touch:TouchEvent)
        Router(director.handler).Goto("plain")
    End

    Method OnEnter:Void()
        Print("scene enter")
    End

    Method OnLeave:Void()
        Print("scene leave")
    End
End

Function Main:Int()
    Local router:Router = New Router()
    router.Add("plain", New PlainScene())
    router.Add("advanced", New AdvancedScene())
    router.Goto("plain")

    Local director:Director = New Director(640, 480)
    director.Run(router)

    Return 0
End


Testing new functionality.

Testing new functionality.

Strict

Import mojo
Import diddy

Function Main:Int()
	game = new MyGame()
	Return 0
End Function

Global guiScreen:GUIScreen
Global xmlParser:XMLParser = New XMLParser
Global guiSkin:XMLDocument

Class MyGame extends DiddyApp
	Method OnCreate:Int()
		Super.OnCreate()

		game.images.Load("continue.png",,False)
		game.images.Load("continueMO.png",,False)
		game.images.Load("newgame.png",,False)
		game.images.Load("newgameMO.png",,False)
		game.images.Load("options.png",,False)
		game.images.Load("optionsMO.png",,False)

		' enable this and UseVirtualResolution to test the GUI under virtual res
		'SetScreenSize(1024, 768)

		Font.LoadFonts(xmlParser.ParseString(LoadString("fonts.xml")))
		guiSkin = xmlParser.ParseString(LoadString("defaultguiskin.xml"))

		drawFPSOn = True

		guiScreen = new GUIScreen
		guiScreen.PreStart()
		return 0
	End
End

Class GUIScreen Extends Screen
	Field mygui:MyGUI = New MyGUI

	Method New()
		name = "Game"
	End

	Method Start:Void()
		game.screenFade.Start(50, false)
	End

	Method Render:Void()
		Cls
		mygui.Draw()
		SetColor(255, 255, 255)
		DrawText("slider value="+mygui.slider.Value, 0, 20)
		DrawText("radio value="+mygui.rg.SelectedValue, 0, 40)
	End

	Method Update:Void()
		mygui.Update()
		If KeyHit(KEY_ESCAPE)
			game.screenFade.Start(50, true)
			game.nextScreen = game.exitScreen
		End
	End
End

Class MyGUI Extends GUI
	Field window1:Window
	Field button1:Button
	Field button2:Button
	Field button3:Button
	Field checkbox:Checkbox

	Field window2:Window
	Field rg:RadioGroup
	Field slider:Slider
	Field radio1:RadioButton
	Field radio2:RadioButton
	Field radio3:RadioButton
	Field radio4:RadioButton
	Field radio5:RadioButton

	Field window3:Window
	Field imageButton1:Button
	Field imageButton2:Button
	Field imageButton3:Button

	Field testPanel:Panel

	Method New()
		' by default the GUI will always ignore virtual resolution and display using 1:1 with the device resolution
		'UseVirtualResolution = True
		Self.LayoutEnabled = True
		' Note: LoadSkin (should) work at any point of the GUI lifecycle
		LoadSkin(guiSkin)

		window1 = New Window(Self.Desktop)
		window1.ShowMaximize = True
		window1.SetBounds(50,70,200,200)
		window1.Title = "GridLayout Demo"
		window1.ContentPane.LayoutManager = New GridLayout(0,2)

		button1 = New Button(window1.ContentPane)
		button1.Text = "Button 1"
		button1.LayoutData = New GridData(1,2)
		button2 = New Button(window1.ContentPane)
		button2.Text = "Button 2"
		button3 = New Button(window1.ContentPane)
		button3.Text = "Button 3"

		window2 = New Window(Self.Desktop)
		window2.ShowMinimize = True
		window2.Title = "Form Components Example"
		window2.SetBounds(300,200,230,200)

		radio1 = New RadioButton(window2.ContentPane)
		radio1.Text = "Lorum"
		radio1.SetBounds(10,10,100,15)

		radio2 = New RadioButton(window2.ContentPane)
		radio2.Text = "Ipsum"
		radio2.SetBounds(10,30,100,15)

		radio3 = New RadioButton(window2.ContentPane)
		radio3.Text = "Dolor"
		radio3.SetBounds(10,50,100,15)

		radio4 = New RadioButton(window2.ContentPane)
		radio4.Text = "Sit"
		radio4.SetBounds(10,70,100,15)

		radio5 = New RadioButton(window2.ContentPane)
		radio5.Text = "Amet"
		radio5.SetBounds(10,90,100,15)

		rg = New RadioGroup
		rg.AddButton(radio1, "L")
		rg.AddButton(radio2, "I")
		rg.AddButton(radio3, "D")
		rg.AddButton(radio4, "S")
		rg.AddButton(radio5, "A")
		rg.SelectedValue = "I"

		slider = New Slider(window2.ContentPane)
		slider.SetBounds(10,110,200,15)
		slider.ShowButtons = True

		checkbox = New Checkbox(window2.ContentPane)
		checkbox.Text = "Does diddy rock?"
		checkbox.SetBounds(10,130,150,15)

		'window3 = New Window(Self.Desktop)
		'window3.ShowShade = True
		'window3.ShowClose = False
		'window3.Title = "Image Button Demo"
		'window3.SetBounds(350,50,260,200)

		'window3.ContentPane.LayoutManager = New GridLayout(0,1)'FlowLayout(FlowLayout.FLOW_VERTICAL)
		' test panel not using a window
		testPanel = New Panel(Self.Desktop)
		Local gl:GridLayout = New GridLayout(0,1)
		testPanel.LayoutManager = gl
		gl.rowHeightTypes[0] = GridLayout.FILLTYPE_PREFERRED
		gl.rowHeightTypes[1] = GridLayout.FILLTYPE_PREFERRED
		gl.rowHeightTypes[2] = GridLayout.FILLTYPE_PREFERRED
		gl.colWidthTypes[0] = GridLayout.FILLTYPE_PREFERRED

		imageButton1 = New Button(testPanel, game.images.Find("continue"), game.images.Find("continueMO"))
		imageButton2 = New Button(testPanel, game.images.Find("newgame"), game.images.Find("newgameMO"))
		imageButton3 = New Button(testPanel, game.images.Find("options"), game.images.Find("optionsMO"))

		testPanel.Pack()
		testPanel.SetLocation((Self.Desktop.Width-testPanel.Width)/2,Self.Desktop.Height-testPanel.Height)

		' Layout manager is disabled by default (to stop nasty recursion spam while building up the gui); this line enables it.
		' From here on, any changes to the gui structure that affect the layout will cause it to fire.
		Self.LayoutEnabled = True
	End

	Method ActionPerformed:Void(source:Component, action:String)
		If source = slider And action = ACTION_VALUE_CHANGED Then
			Print "slider="+slider.Value
		ElseIf source = button1 And action = ACTION_CLICKED Then
			Print("pressed button1!")
			slider.Value = 10
		ElseIf source = button2 And action = ACTION_CLICKED Then
			Print("pressed button2!")
			slider.Value = 20
		ElseIf source = button3 And action = ACTION_CLICKED Then
			Print("pressed button3!")
			slider.Value = 30
		ElseIf source = imageButton1 And action = ACTION_CLICKED Then
			Print("Pressed continue!")
			slider.Value = 40
		ElseIf source = imageButton2 And action = ACTION_CLICKED Then
			Print("Pressed new game!")
			slider.Value = 50
		ElseIf source = imageButton3 And action = ACTION_CLICKED Then
			Print("Pressed options!")
			slider.Value = 60
		ElseIf source = checkbox And action = ACTION_CLICKED Then
			If checkbox.Selected Then
				Print("pressed checkbox! selected=true")
			Else
				Print("pressed checkbox! selected=false")
			End
		ElseIf RadioButton(source) <> Null Then
			Print("pressed radiobutton! value="+rg.SelectedValue)
		End
	End
End

Strict

Import mojo
Import diddy

Function Main:Int()
	game = new MyGame()
	Return 0
End Function

Global guiScreen:GUIScreen

Class MyGame extends DiddyApp
	Method OnCreate:Int()
		Super.OnCreate()

		game.images.Load("continue.png",,False)
		game.images.Load("continueMO.png",,False)
		game.images.Load("newgame.png",,False)
		game.images.Load("newgameMO.png",,False)
		game.images.Load("options.png",,False)
		game.images.Load("optionsMO.png",,False)

		' enable this and UseVirtualResolution to test the GUI under virtual res
		'SetScreenSize(1024, 768)

		Local parser:XMLParser = New XMLParser
		Font.LoadFonts(parser.ParseString(LoadString("fonts.xml")))
		drawFPSOn = True

		guiScreen = new GUIScreen
		guiScreen.PreStart()
		return 0
	End
End

Class GUIScreen Extends Screen
	Field mygui:MyGUI = New MyGUI

	Method New()
		name = "Game"
	End

	Method Start:Void()
		game.screenFade.Start(50, false)
	End

	Method Render:Void()
		Cls
		mygui.Draw()
		SetColor(255, 255, 255)
		DrawText("slider value="+mygui.slider.Value, 0, 20)
		DrawText("radio value="+mygui.rg.SelectedValue, 0, 40)
	End

	Method Update:Void()
		mygui.Update()
		If KeyHit(KEY_ESCAPE)
			game.screenFade.Start(50, true)
			game.nextScreen = game.exitScreen
		End
	End
End

Class MyGUI Extends GUI
	Field window1:Window
	Field button1:Button
	Field button2:Button
	Field button3:Button
	Field checkbox:Checkbox

	Field window2:Window
	Field rg:RadioGroup
	Field slider:Slider
	Field radio1:RadioButton
	Field radio2:RadioButton
	Field radio3:RadioButton
	Field radio4:RadioButton
	Field radio5:RadioButton

	Field window3:Window
	Field imageButton1:Button
	Field imageButton2:Button
	Field imageButton3:Button

	Method New()
		' by default the GUI will always ignore virtual resolution and display using 1:1 with the device resolution
		'UseVirtualResolution = True

		Local parser:XMLParser = New XMLParser
		Local guiskin:XMLDocument = parser.ParseString(LoadString("defaultguiskin.xml"))

		' Note: LoadSkin (should) work at any point of the GUI lifecycle
		LoadSkin(guiskin)

		window1 = New Window(Desktop)
		window1.SetBounds(50,70,200,200)
		window1.Title = "GridLayout Demo"
		window1.ContentPane.LayoutManager = New GridLayout(0,2)

		button1 = New Button(window1.ContentPane)
		button1.Text = "Button 1"
		button1.LayoutData = New GridData(1,2)
		button2 = New Button(window1.ContentPane)
		button2.Text = "Button 2"
		button3 = New Button(window1.ContentPane)
		button3.Text = "Button 3"

		window2 = New Window(Desktop)
		window2.Title = "Form Components Example"
		window2.SetBounds(300,200,230,200)

		radio1 = New RadioButton(window2.ContentPane)
		radio1.Text = "Lorum"
		radio1.SetBounds(10,10,100,15)

		radio2 = New RadioButton(window2.ContentPane)
		radio2.Text = "Ipsum"
		radio2.SetBounds(10,30,100,15)

		radio3 = New RadioButton(window2.ContentPane)
		radio3.Text = "Dolor"
		radio3.SetBounds(10,50,100,15)

		radio4 = New RadioButton(window2.ContentPane)
		radio4.Text = "Sit"
		radio4.SetBounds(10,70,100,15)

		radio5 = New RadioButton(window2.ContentPane)
		radio5.Text = "Amet"
		radio5.SetBounds(10,90,100,15)

		rg = New RadioGroup
		rg.AddButton(radio1, "L")
		rg.AddButton(radio2, "I")
		rg.AddButton(radio3, "D")
		rg.AddButton(radio4, "S")
		rg.AddButton(radio5, "A")
		rg.SelectedValue = "I"

		slider = New Slider(window2.ContentPane)
		slider.SetBounds(10,110,200,15)
		slider.ShowButtons = True

		checkbox = New Checkbox(window2.ContentPane)
		checkbox.Text = "Does diddy rock?"
		checkbox.SetBounds(10,130,150,15)

		window3 = New Window(Desktop)
		window3.Title = "Image Button Demo"
		window3.SetBounds(350,50,260,200)

		imageButton1 = New Button(window3.ContentPane, game.images.Find("continue"), game.images.Find("continueMO"))
		imageButton1.SetLocation(20,20)

		imageButton2 = New Button(window3.ContentPane, game.images.Find("newgame"), game.images.Find("newgameMO"))
		imageButton2.SetLocation(20,imageButton1.Y+imageButton1.Height)

		imageButton3 = New Button(window3.ContentPane, game.images.Find("options"), game.images.Find("optionsMO"))
		imageButton3.SetLocation(20,imageButton2.Y+imageButton2.Height)
	End

	Method ActionPerformed:Void(source:Component, action:String)
		If source = slider And action = ACTION_VALUE_CHANGED Then
			Print "slider="+slider.Value
		ElseIf source = button1 And action = ACTION_CLICKED Then
			Print("pressed button1!")
		ElseIf source = button2 And action = ACTION_CLICKED Then
			Print("pressed button2!")
		ElseIf source = button3 And action = ACTION_CLICKED Then
			Print("pressed button3!")
		ElseIf source = imageButton1 And action = ACTION_CLICKED Then
			Print("Pressed continue!")
		ElseIf source = imageButton2 And action = ACTION_CLICKED Then
			Print("Pressed new game!")
		ElseIf source = imageButton3 And action = ACTION_CLICKED Then
			Print("Pressed options!")
		ElseIf source = checkbox And action = ACTION_CLICKED Then
			If checkbox.Selected Then
				Print("pressed checkbox! selected=true")
			Else
				Print("pressed checkbox! selected=false")
			End
		ElseIf RadioButton(source) <> Null Then
			Print("pressed radiobutton! value="+rg.SelectedValue)
		End
	End
End


Framework started

Framework started

'
' Module diddy.diddy
'

Import functions
Import framework