standard spinner gadget

BlitzMax Forums/BlitzMax GUI Programming/standard spinner gadget

allows for negative and floating point

windows only.... needs to be modified quite a bit for the mac

SuperStrict 

'-----------------------------------------------------------------------------------------------------
' Example program
'-----------------------------------------------------------------------------------------------------

Local Window:TGadget=CreateWindow("My Window",0,0,240,240,Null,WINDOW_TITLEBAR)


' default spinner (0 to 10 step 1) with trackbar
CreateSpinner(15,15,65,30,Window,SLIDER_TRACKBAR)

' spinner (-10 to 10 step .1)
Local spinner:TSpinner = CreateSpinner(15,65,65,20,Window)
SetSpinnerRange spinner,-10,10
SetSpinnerPrecision spinner,.1
SetSpinnerValue spinner,-5

' % spinner (0 to 1 step .01)
Local spinner2:TSpinner = CreateSpinner(15,100,65,20,Window)
SetSpinnerRange spinner2,0,1
SetSpinnerPrecision spinner2,.01
SetSpinnerValue spinner2,.5


While WaitEvent()
	Local event:TEvent = CurrentEvent

	Print event.ToString()
	Select event.id
		Case EVENT_GADGETACTION
			Print "GadgetText: " + GadgetText(TGadget(event.source)) + "~tEventExtra: " + String(event.extra)
		
		Case EVENT_WINDOWCLOSE
			End
	End Select
Wend



'-----------------------------------------------------------------------------------------------------
' TSpinner Gadget
' by dmaz
'-----------------------------------------------------------------------------------------------------

Function CreateSpinner:TSpinner( x:Int, y:Int, w:Int, h:Int, group:TGadget, style:Int=0 )
	Return New TSpinner.Create(x,y,w,h,group,style)
End Function

Function SetSpinnerRange( spinner:TSpinner, low:Double, high:Double )
	spinner.SetSpinnerRange low,high
End Function

Function SetSpinnerPrecision( spinner:TSpinner, precision:Double )
	spinner.SetSpinnerPrecision precision
End Function

Function SetSpinnerValue( spinner:TSpinner, value:Double )
	spinner.SetSpinnerValue value
End Function



Type TSpinner Extends TProxyGadget
	Field panel	:TGadget
	Field textField:TGadget
	Field stepper	:TGadget
	Field trackbar	:TGadget
	Field range	:Double
	Field value	:Double = 0.0
	Field low		:Double = 0.0
	Field high	:Double = 10.0
	Field precision:Double = 1.0
	
	Method New()
		AddHook EmitEventHook,MyEventHook,Self
	End Method
	
	Method Create:TSpinner( x:Int, y:Int, w:Int, h:Int, group:TGadget, style:Int=0 )
		panel = CreatePanel(x,y,w,h,group,PANEL_BORDER)
		If style & SLIDER_TRACKBAR
			stepper = CreateSlider(w-h+14,0,h-18,h-14,panel,SLIDER_STEPPER)
			textField = CreateTextField(-2,-2,w-h+18,h-10,panel)
			trackbar = CreateSlider(-2,h-12,w+1,10,panel,SLIDER_HORIZONTAL|SLIDER_TRACKBAR)
		Else
			stepper = CreateSlider(w-h+4,0,h-8,h-4,panel,SLIDER_STEPPER)
			textField = CreateTextField(-2,-2,w-h+8,h,panel)
		EndIf
		SetGadgetFilter textField,NumFilter
		SetProxy textField
		
		SetSpinnerRange low,high
		SetSpinnerPrecision precision
		SetSpinnerValue low
		
		Return Self
	End Method

	Method Free()
		RemoveHook EmitEventHook,MyEventHook,Self
		'textField is freed in super
		If trackbar Then FreeGadget trackbar
		FreeGadget stepper
		FreeGadget panel
		Super.Free
	End Method

	Method SetSpinnerRange( low:Double, high:Double )
		Self.low = low
		Self.high = high
		range = Round((high-low)/precision)
		SetSpinnerValue low
		SetSliderRange stepper,0,range
		SetSliderValue stepper,0
		If trackbar
			SetSliderRange trackbar,0,range
			SetSliderValue trackbar,0
		EndIf
	End Method
	
	Method SetSpinnerPrecision( precision:Double )
		Self.precision = precision
		range = Round((high-low)/precision)
		SetSliderRange stepper,0,range
		If trackbar Then SetSliderRange trackbar,0,range
	End Method

	Method SetSpinnerValue:Int( value:Double )
		Self.value = Min(Max(low,value),high)
		SetSliderValue stepper,Round((Self.value-low)/precision)
		If trackbar Then SetSliderValue trackbar,Round((Self.value-low)/precision)
		SetGadgetText Self,PrettyFloat(Self.value)
		If value < low Or value > high Then Return False Else Return True
	End Method

	Method GetSpinnerValue:String()
		Return PrettyFloat(value)
	End Method


	'------------------------------------------------------------------------------------------------
	
	Function MyEventHook:Object( id:Int, data:Object, context:Object )
		If TSpinner(context) Then data=TSpinner(context).MyEvents(TEvent(data))
		Return data
	End Function
		
	Method MyEvents:TEvent( event:TEvent )
		If event
			Select event.id
				Case EVENT_GADGETACTION
					If event.source = stepper Or event.source = trackbar
						ActivateGadget TGadget(event.source)
						If low+(event.data/precision) <> value
							SetSpinnerValue low+(event.data*precision)
							EmitEvent CreateEvent(EVENT_GADGETACTION,Self,0,0,0,0,GetSpinnerValue())
						EndIf
						event = Null
					EndIf
	
				Case EVENT_GADGETLOSTFOCUS
					If event.source = Self
						If GadgetText(Self).ToDouble() <> value
							SetSpinnerValue GadgetText(Self).ToDouble()
							EmitEvent CreateEvent(EVENT_GADGETACTION,Self,0,0,0,0,GetSpinnerValue())
						EndIf
					EndIf
				
			End Select
		EndIf
		Return event
	End Method


	'------------------------------------------------------------------------------------------------

	Function NumFilter:Int(event:TEvent, context:Object)
		If event.ID = EVENT_KEYCHAR
			If event.data = KEY_BACKSPACE Then Return True
			If event.data = 47 Then Return False
			If event.data < 45 Or event.data > 57 Then Return False
		EndIf
		
		Return True
	End Function

	Function PrettyFloat:String( value:Double )	'by grable
		Extern "C"
			Function modf:Double( value:Double, intpart:Double Var)
			Function snprintf_i:Int( buf:Byte Ptr, szbuf:Int, fmtstr$z, val:Int) = "snprintf"
			Function snprintf_f:Int( buf:Byte Ptr, szbuf:Int, fmtstr$z, val:Double) = "snprintf"	
		EndExtern
		Local i:Double
		Local buf:Byte[32]
		Local l:Int
		' check for whole number
		If modf( value, i) = 0.0 Then 
			l = snprintf_i( buf, SizeOf(buf), "%d", i)
			Return String.FromBytes( buf, l)
		Else
			' eliminate ending zeros except the one after "."
			l = snprintf_f( buf, SizeOf(buf), "%f", value)
			While (l > 0) And (buf[l-1] = Asc("0")) And (buf[l-2] <> Asc("."))
				l :- 1
			Wend
			' terminate it, just in case
			buf[l+1] = 0
			Return String.FromBytes( buf, l)
		EndIf
	EndFunction
	
	Function Round:Double(x:Double)
		Return Int(x + (Sgn(x) * 0.5))
	End Function
	
End Type




Excellent ! i Really need this ! Thanks :)

I get

Unhandled Exception : Attempt to access field or method of a null object.


when changing the value in debug mode although it seems OK in release mode.
Error is listed against
Select event.id
in the tspinner myevents method.

my fault.... I was working with debug off.... I will fix.
[edit] first post fixed for debug.

This code has fundamental problems because you are comparing double floats, and there will always be some inaccuracy.