[bmx] Spinner Proxygadget by JoshK [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:42

Previous topic - Next topic

BlitzBot

Title : Spinner Proxygadget
Author : JoshK
Posted : 1+ years ago

Description : Advanced number editor with an optional trackbar.  The gadget can edit integers and floats with any range of values, including negative numbers.  No floating point errors will occur.

Code :
Code: blitzmax
SuperStrict

Import MaxGui.Drivers
Import brl.retro


Local window:TGadget

window=CreateWindow("Spinner Example",40,40,320,240)

Local spinner:TSpinner
Local label:TGadget
Local x:Int=2,y:Int=2

label=CreateLabel("Float spinner:",x,y,200,18,window)
SetGadgetLayout label,1,0,1,0
y:+18
spinner=CreateSpinner(x,y,50,20,window)
SetSpinnerRange(spinner,0.11,1.2,2)
SetSpinnerValue(spinner,0.1)

SetGadgetLayout spinner,1,1,1,0
y:+22

label=CreateLabel("Integer spinner with trackbar:",x,y,200,18,window)
SetGadgetLayout label,1,0,1,0
y:+18
spinner=CreateSpinner(x,y,300,20,window,SPINNER_TRACKBAR)
SetSpinnerRange(spinner,-2,2,0)
SetGadgetLayout spinner,1,1,1,0
y:+22


While True
	WaitEvent 
	Print CurrentEvent.ToString()
	Select EventID()
		Case EVENT_WINDOWCLOSE
			End
	End Select
Wend


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

Const SPINNER_TRACKBAR:Int=1

Type TSpinner Extends TProxygadget
	
	Const SliderWidth:Int=12
	Const Div:Int=52
	
	Field panel:TGadget
	Field textfield:TGadget
	Field slider:TGadget
	Field trackbar:TGadget
	Field value:Int
	Field range:Int[2]
	Field accuracy:Int=1
	Field floatitemmultiplier:Double=10

	Method SetTextColor(r:Int,g:Int,b:Int)
		Local gadget:TGadget
		Super.SetTextColor(r,g,b)
		textfield.SetTextColor(r,g,b)
		slider.SetTextColor(r,g,b)
		If trackbar trackbar.SetTextColor(r,g,b)
	EndMethod
	
	Method SetColor(r:Int,g:Int,b:Int)
		Local gadget:TGadget
		Super.SetColor(r,g,b)
		textfield.SetColor(r,g,b)
		slider.SetColor(r,g,b)
		If trackbar trackbar.SetColor(r,g,b)
	EndMethod
	
	Method SetRange_(minimum:Double,maximum:Double,accuracy:Int=1)
		Self.accuracy=accuracy
		floatitemmultiplier=10.0^Double(accuracy)
		range[0]=Round(minimum*floatitemmultiplier)
		range[1]=Round(maximum*floatitemmultiplier)-range[0]
		SetSliderRange slider,1,range[1]+1
		If trackbar
			SetSliderRange trackbar,1,range[1]+1
		EndIf
		SetValue_(value)
	EndMethod

	Method SetValue_(f:Double)
		Local i:Int
		i=Round(f*floatitemmultiplier)
		i=Max(i,range[0])
		i=Min(i,range[0]+range[1])
		'Notify i+", "+range[0]+", "+range[1]
		SetGadgetText textfield,FloatToString(i/floatitemmultiplier,accuracy)
		SetSliderValue slider,range[1]-(i-range[0])
		If trackbar SetSliderValue trackbar,i-range[0]+1
		value=i
	EndMethod
		
	Method Cleanup()
		RemoveHook(EmitEventHook,EventHook,Self)
		Super.Cleanup()
	EndMethod
	
	Function Create:TSpinner(x:Int,y:Int,width:Int,height:Int,group:TGadget,flags:Int=0)
		Local spinner:TSpinner
		Local w:Int
		
		spinner=New TSpinner
				
		spinner.panel=CreatePanel(x,y,width,height,group)
		spinner.setproxy(spinner.panel)
		
		w=spinner.panel.ClientWidth()
		If (SPINNER_TRACKBAR & flags)
			w=div
			If w>spinner.panel.ClientWidth() w=spinner.panel.ClientWidth()
		EndIf
		
		spinner.textfield=CreateTextField(0,0,w-SliderWidth,spinner.panel.ClientHeight(),spinner.panel)
		If (SPINNER_TRACKBAR & flags)
			SetGadgetLayout spinner.textfield,1,0,1,1
		Else
			SetGadgetLayout spinner.textfield,1,1,1,1
		EndIf
		
		spinner.slider=CreateSlider(w-SliderWidth,0,SliderWidth,spinner.panel.ClientHeight(),spinner.panel,SLIDER_VERTICAL)		
		If (SPINNER_TRACKBAR & flags)
			SetGadgetLayout spinner.slider,1,0,1,1
		Else
			SetGadgetLayout spinner.slider,0,1,1,1
		EndIf
		AddHook(EmitEventHook,EventHook,spinner)
		
		If (SPINNER_TRACKBAR & flags)
			spinner.trackbar=CreateSlider(w,0,spinner.panel.ClientWidth()-w,spinner.panel.ClientHeight(),spinner.panel,SLIDER_TRACKBAR|SLIDER_HORIZONTAL)
			SetGadgetLayout spinner.trackbar,1,1,1,1
		EndIf
		
		spinner.SetRange_(0,1)
		Return spinner
	EndFunction

	Function EventHook:Object(id:Int,data:Object,context:Object)
		Local event:TEvent
		Local spinner:TSpinner
		Local i:Int
		
		event=TEvent(data)
		If event
			spinner=TSpinner(context)
			If spinner
				Select event.id
				Case EVENT_GADGETLOSTFOCUS
					If event.source=spinner.textfield
						Local old:Double=SpinnerValue(spinner)
						spinner.SetValue_(Double(GadgetText(spinner.textfield)))
						If old<>SpinnerValue(spinner)
							EmitEvent CreateEvent(EVENT_GADGETACTION,spinner)
						EndIf
						Return Null
					EndIf				
				Case EVENT_GADGETACTION
					Select event.source
					Case spinner.trackbar
						If spinner.trackbar
							i=(SliderValue(spinner.trackbar)+spinner.range[0]-1)
							spinner.SetValue_(i/spinner.floatitemmultiplier)
							EmitEvent CreateEvent(EVENT_GADGETACTION,spinner)
						EndIf
					Case spinner.textfield
						Return Null
					Case spinner.slider
						i=spinner.range[1]-(SliderValue(spinner.slider)-spinner.range[0])
						spinner.SetValue_(Double(i)/spinner.floatitemmultiplier)
						EmitEvent CreateEvent(EVENT_GADGETACTION,spinner)
						Return Null
					EndSelect
				EndSelect
			EndIf
		EndIf
		Return data
	EndFunction
	
	Function Round:Int(val:Double)
		Local dec#
		dec#=val-Floor(val)
		If dec<0.5 Return Floor(val) Else Return Ceil(val)
	EndFunction	
	
	Function FloatToString:String(value:Float,places:Int=3)
		Local sign:Int=Sgn(value)
		value=Abs(value)
		Local i:Int=Round(value*10^places)
		Local ipart:Int=Int(i/10^places)
		Local dpart:Int=i-ipart*10^places
		Local si$=ipart
		Local di$
		If dpart>0
			di=dpart
			While di.length<places
				di="0"+di
			Wend
			di="."+di
		EndIf
		While Right(di,1)="0"
			di=Left(di,di.length-1)
		Wend
		If places
			If di="" di=".0"
		EndIf
		If sign=-1 si="-"+si
		Return si+di
	EndFunction	
	
EndType

Rem
bbdoc:
EndRem
Function CreateSpinner:TSpinner(x:Int,y:Int,width:Int,height:Int,group:TGadget,flags:Int=0)
	Return TSpinner.Create(x,y,width,height,group,flags)
EndFunction

Rem
bbdoc:
EndRem
Function SetSpinnerRange(spinner:TSpinner,minimum:Double,maximum:Double,accuracy:Int=1)
	spinner.SetRange_(minimum,maximum,accuracy)
EndFunction

Rem
bbdoc:
EndRem
Function SetSpinnerValue(spinner:TSpinner,value:Double)
	spinner.SetValue_(value)
EndFunction

Rem
bbdoc:
EndRem
Function SpinnerValue:Double(spinner:TSpinner)
	Return spinner.value/spinner.floatitemmultiplier
EndFunction


Comments :


JoshK(Posted 1+ years ago)

 Updated with some bug fixes and improvements.


JoshK(Posted 1+ years ago)

 Updated to fix bug when strange ranges are used.