Seite 1 von 1

KnobControl (ehem. ControllerGadget)

Verfasst: 18.03.2012 18:12
von Mr.L
Die Möglichkeiten des CanvasGadget sind ja praktisch unendlich... (Kann-was-Gadget :lol: )
Hier habe ich mal einen Gadget Typen entwickelt den ich "ControllerGadget"
nenne.
Er verhält sich wie ein Drehregler, - also mit linker Maustaste draufklicken,
gedrückt halten und den Regler nach links oder rechts drehen.

Minimal- und Maximalwert sowie Minimal- und Maximalwinkel lassen sich einstellen.
Wird der Flagwert #ControllerGadget_Infinite übergeben, dann besitzt das Gadget
keinen "Anschlag", d.h. es lässt sich unendlich nach links oder rechts drehen.


- Name geändert: "KnobControl" gefällt mir besser als ControllerGadget (Danke
RSBasic, für den Hinweis)
- Flag "#KnobControl_LinearPointer" hinzugefügt. (zeichnet einen linearen Zeiger)
- Flag "#KnobControl_Smooth" hinzugefügt. (stufenloses Drehen)
- Farbwert "ColorBorder" hinzugefügt. (Randfarbe des Drehreglers)
- Procedure "KnobControl_SetColor" hinzugefügt. (eigene Farben definieren)
- Darstellung der Drehregler geändert.


Code: Alles auswählen

; Knob-Control
; ----------------
; March 2012  Mr.L
;
; left-click on a controller and hold the button down 
; turn the 'KnobControl' left or right

EnableExplicit

Structure KnobControlData
	Canvas.i
	
	Radius.w	
	MinAngle.i
	MaxAngle.i
	MinValue.i
	MaxValue.i
 	State.i
	Value.i
	Angle.i
	LastAngle.i
	Steps.i
	Flags.i
	HasFocus.b
	
	ColorBackGround.i	
	ColorForeGround.i
	ColorBorder.i
	ColorShadow.i
	ColorHighLight.i
EndStructure

Enumeration
	#KnobControl_Background
	#KnobControl_Foreground
	#KnobControl_Border
	#KnobControl_Highlight
	#KnobControl_Shadow
EndEnumeration

#KnobControl_Ticks			= 1		; draw ticks around the control
#KnobControl_LinearPointer	= 2		; draw a linear pointer instead of a circle
#KnobControl_Infinite		= 4		; infinite turning to left or right
#KnobControl_Smooth			= 8		; enable smooth movement


Declare KnobControl(Gadget , x,y,Radius , MinValue=0 , MaxValue=100 , Steps=360 , MinAngle=0 , MaxAngle=360 , Flags=0)
Declare KnobControl_GetValue(Gadget)
Declare KnobControl_SetValue(Gadget , Value)
Declare KnobControl_SetColor(Gadget , ColorType , Color)
Declare KnobControl_Event(Gadget , Event)
Declare KnobControl_Free(Gadget)

Procedure __KnobControl_Redraw__(*KnobControl.KnobControlData)
	
	; all the drawing stuff
	
	Protected a,s,x,y,minAngle,maxAngle
	
	If *KnobControl
		
		StartDrawing(CanvasOutput(*KnobControl\Canvas))
		
		With *KnobControl
			
			Box(0,0,OutputWidth(),OutputHeight() , \ColorBackGround)
			
			; draw the 'clock-face'
			
			Circle(\Radius , \Radius , \Radius - 1 , \ColorBorder)
			
			DrawingMode(#PB_2DDrawing_Gradient)
			If \HasFocus
				GradientColor(0.0 , \ColorHighLight)
			Else
				GradientColor(0.0 , \ColorForeGround)				
			EndIf
			GradientColor(1.0 , \ColorShadow)
			CircularGradient(\Radius * 0.65 , \Radius * 0.65 , \Radius * 3)
			Circle(\Radius , \Radius , \Radius - 3)
			
			DrawingMode(#PB_2DDrawing_Default)
			
			If \Flags & #KnobControl_Ticks
				
				; draw the 'ticks'
				
				If \MinAngle Or \MaxAngle
					minAngle = \MinAngle + 90
					maxAngle = \MaxAngle + 90
				Else
					minAngle = 0
					maxAngle = 360
				EndIf
				
				If (maxAngle - minAngle) And \Steps 
					a = minAngle
					s = (maxAngle - minAngle) / \Steps	
					
					Repeat
						x = \Radius - Cos(Radian(a)) * (\Radius * 0.85)
						y = \Radius - Sin(Radian(a)) * (\Radius * 0.85)
						
						Circle(x,y,1,\ColorShadow)
						
						a + s
					Until a > maxAngle Or a > (minAngle + 360)
					
				EndIf
				
			EndIf
			
			; draw the 'clockhand'
			
			x	= \Radius - Cos(Radian(\State + 90)) * (\Radius * 0.65)
			y	= \Radius - Sin(Radian(\State + 90)) * (\Radius * 0.65)
			
			If \Flags & #KnobControl_LinearPointer
				LineXY(\Radius   , \Radius   , x     , y		, \ColorShadow)
				LineXY(\Radius+1 , \Radius   , x + 1 , y		, \ColorShadow)
				LineXY(\Radius   , \Radius+1 , x     , y + 1	, \ColorShadow)
				LineXY(\Radius+1 , \Radius+1 , x + 1 , y + 1	, \ColorShadow)
				Circle(\Radius , \Radius , 3 , \ColorShadow)
				Circle(\Radius , \Radius , 1 , \ColorBackGround)
			Else				
				Circle(x,y,3,\ColorShadow)
				Circle(x,y,1,\ColorForeGround)
			EndIf			
			
		EndWith	
		
		StopDrawing()
		
	EndIf
	
EndProcedure

Procedure __KnobControl_Update__(*KnobControl.KnobControlData , lockAngle = #False)
	
	; Update angle and value
	
	Protected angle.d , stepSize
	
	If *KnobControl
		
		With *KnobControl
			
			If \Flags & #KnobControl_Infinite = 0				
				; clamp angle
				If \Angle < \MinAngle
					\Angle = \MinAngle
				ElseIf	\Angle > \MaxAngle
					\Angle = \MaxAngle
				EndIf			
			EndIf
			
			If \Steps
				angle 		= (\MaxAngle - \MinAngle)			
				stepSize	= angle / \Steps				
				
				If angle And stepSize
					; convert angle to value
					If lockAngle Or (\Flags & #KnobControl_Smooth) = #False
						\State = Round(\Angle / (stepSize * 1.0) , #PB_Round_Nearest) * stepSize
					Else
						\State = \Angle
					EndIf
					\Value = (\State - \MinAngle) * ((\MaxValue - \MinValue) / angle) + \MinValue
				Else
					If lockAngle Or (\Flags & #KnobControl_Smooth) = #False
						\State = Round(\Angle / (\Steps * 1.0) , #PB_Round_Nearest) * \Steps
					Else
						\State = \Angle
					EndIf
					\Value = \State
				EndIf				
			EndIf
			
			If \MinValue Or \MaxValue
				; keep value inside range
				If \Value > \MaxValue
					\Value = Mod(\Value , \MaxValue)
				EndIf
				If \Value < \MinValue
					\Value = Mod(\Value , \MaxValue) + \MaxValue
				EndIf				
			EndIf
			
		EndWith
		
		__KnobControl_Redraw__(*KnobControl)
		
	EndIf
	
EndProcedure

Procedure __KnobControl_Get__(Gadget)	
	
	; Return the KnobControlData of the 'Gadget' 
	
	If IsGadget(Gadget) = 0 Or GadgetType(Gadget) <> #PB_GadgetType_Canvas
		ProcedureReturn #Null
	EndIf	
	
	ProcedureReturn GetGadgetData(Gadget)
	
EndProcedure

Procedure KnobControl(Gadget , x,y,Radius , MinValue=0 , MaxValue=100 , Steps=360 , MinAngle=0 , MaxAngle=360 , Flags=0)
	
	; Create a new KnobControl and return its handle
	
	Protected *KnobControl.KnobControlData
	
	*KnobControl = __KnobControl_Get__(Gadget)
	
	If *KnobControl
		
		; if a control with this ID already exists - delete it
		
 		KnobControl_Free(Gadget)
		
	EndIf	
	
	If MaxAngle < MinAngle
		Swap MinAngle , MaxAngle
	EndIf
	
	If MaxValue < MinValue
		Swap MinValue , MaxValue
	EndIf
	
	If Gadget = #PB_Any
		Gadget = CanvasGadget(#PB_Any , x,y,Radius * 2,Radius * 2 , #PB_Canvas_Keyboard)
	Else
		CanvasGadget(Gadget , x,y,Radius * 2,Radius * 2 , #PB_Canvas_Keyboard)
	EndIf
	
	If IsGadget(Gadget)
		
		*KnobControl = AllocateMemory(SizeOf(KnobControlData))
		
		If *KnobControl
			
			With *KnobControl
				
				\Canvas					= Gadget
				\MinAngle				= MinAngle
				\MaxAngle				= MaxAngle
				\MinValue				= MinValue
				\MaxValue				= MaxValue
				\Angle					= MinAngle
; 				\State					= MinValue			
				\Radius					= Radius
				\Flags					= Flags			
				\Steps					= Steps
				
				If \Steps < 1
					\Steps				= 1
				EndIf
				
				CompilerIf #PB_Compiler_OS = #PB_OS_Windows
					\ColorBackGround	= GetSysColor_(#COLOR_3DFACE)
					\ColorForeGround	= GetSysColor_(#COLOR_3DLIGHT)
					\ColorHighLight		= GetSysColor_(#COLOR_3DHIGHLIGHT)
					\ColorBorder		= GetSysColor_(#COLOR_3DSHADOW)
					\ColorShadow		= GetSysColor_(#COLOR_3DDKSHADOW)
				CompilerElse
					\ColorBackGround	= $F2F1F0
					\ColorForeGround	= $C8D0D4
					\ColorHighLight		= $FFFFFF
					\ColorBorder		= $808080
					\ColorShadow		= $404040
				CompilerEndIf
				
			EndWith
			
			SetGadgetData(Gadget , *KnobControl)			
			
			__KnobControl_Update__(*KnobControl)
			
		Else
			
			FreeGadget(Gadget)
			Gadget = 0
			
		EndIf
		
	EndIf	
	
	ProcedureReturn Gadget
	
EndProcedure

Procedure KnobControl_GetValue(Gadget)
	
	; Return the Value of the 'Gadget'
	
	Protected *KnobControl.KnobControlData
	Protected value
	
	*KnobControl = __KnobControl_Get__(Gadget)
	
	If *KnobControl
		
		value = *KnobControl\Value
		
	EndIf
	
	ProcedureReturn value
	
EndProcedure

Procedure KnobControl_SetValue(Gadget , Value)
	
	; Set the Value of the 'Gadget'
	; (convert value to angle)
	
	Protected *KnobControl.KnobControlData
	Protected angle.d
	
	*KnobControl = __KnobControl_Get__(Gadget)
	
	If *KnobControl
		
		With *KnobControl
			
			angle = (\MaxAngle - \MinAngle)
			
			If angle And (\MaxValue - \MinValue)
				*KnobControl\Angle = (Value - \MinValue) / ((\MaxValue - \MinValue) / angle) + \MinAngle
			Else
				*KnobControl\Angle = Value
			EndIf
			
		EndWith
		
		__KnobControl_Update__(*KnobControl)
		
	EndIf
	
EndProcedure

Procedure KnobControl_SetColor(Gadget , ColorType , Color)
	
	; Set the Color (RGB) of the specified "ColorType"
	
	Protected *KnobControl.KnobControlData
	
	*KnobControl = __KnobControl_Get__(Gadget)
	
	If *KnobControl
		
		With *KnobControl
		
			Select ColorType
					
				Case #KnobControl_Background	:	\ColorBackGround	= Color
					
				Case #KnobControl_Foreground	:	\ColorForeGround	= Color
					
				Case #KnobControl_Border		:	\ColorBorder		= Color
					
				Case #KnobControl_Highlight		:	\ColorHighLight		= Color
					
				Case #KnobControl_Shadow		:	\ColorShadow		= Color
					
			EndSelect
			
		EndWith
		
		__KnobControl_Redraw__(*KnobControl)
		
	EndIf
	
EndProcedure

Procedure KnobControl_Event(Gadget , Event)
	
	; KnobControl event handling
	; Return #True if 'Event' is valid
	
	Protected *KnobControl.KnobControlData
	Protected s,mx,my,angle,angleDif,redraw
	Protected result = #False
	
	*KnobControl = __KnobControl_Get__(Gadget)
	
	If *KnobControl
		
		With *KnobControl		
			
			mx		= GetGadgetAttribute(\Canvas , #PB_Canvas_MouseX)
			my		= GetGadgetAttribute(\Canvas , #PB_Canvas_MouseY)
			
			If Event = #PB_EventType_Focus
				
				\HasFocus = #True
				
				result = #True
				
			ElseIf Event = #PB_EventType_LostFocus
				
				\HasFocus = #False
				
				__KnobControl_Update__(*KnobControl , #True)
				
			ElseIf Event = #PB_EventType_LeftButtonUp
				
				__KnobControl_Update__(*KnobControl , #True)
				
			EndIf
			
			If \HasFocus
				
				If Event = #PB_EventType_LeftButtonDown
					
					\LastAngle		= Degree(ATan2(\Radius - mx , \Radius - my))
					
					result			= #True
					
				ElseIf Event = #PB_EventType_MouseMove
					
					If GetGadgetAttribute(\Canvas , #PB_Canvas_Buttons) = #PB_Canvas_LeftButton
						
						angle		= Degree(ATan2(\Radius - mx , \Radius - my))						
						angleDif	= Mod(angle - \LastAngle , 360)

						If angleDif > 180
							angleDif - 360
						ElseIf angleDif < -180
							angleDif + 360
						EndIf
						
						\Angle + angleDif
						\LastAngle =  angle
						
						result = #True
					
					EndIf
					
				ElseIf Event = #PB_EventType_MouseWheel
					
					angleDif = (\MaxAngle - \MinAngle)
					
					If angleDif	And \Steps			
						\Angle + GetGadgetAttribute(\Canvas , #PB_Canvas_WheelDelta)	* (angleDif / \Steps)
					Else
						\Angle + GetGadgetAttribute(\Canvas , #PB_Canvas_WheelDelta)	* \Steps
					EndIf
					
					result = #True	
					
				EndIf
				
			EndIf
			
		EndWith
		
		If result
			
			__KnobControl_Update__(*KnobControl)
			
		EndIf
		
		ProcedureReturn result
		
	EndIf
	
EndProcedure

Procedure KnobControl_Free(Gadget)
	
	; free the CanvasGadget and the allocated memory
	
	Protected *KnobControl.KnobControlData
	
	*KnobControl = __KnobControl_Get__(Gadget)
	
	If *KnobControl
		
		FreeGadget(*KnobControl\Canvas)
		FreeMemory(*KnobControl)		
		
	EndIf
	
EndProcedure


; - Knob-Control - Test -

Define event,current

OpenWindow(0,0,0,320,220,"KnobControl" , #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
StringGadget(0,60,190,200,20,"")

; Default Controller
KnobControl(1, 10,10,20)

; Speedometer ; Range 0 to 255 ; Stepsize 10 ; Anglge -90 to +90
KnobControl(2,100,10,35, 0,255, 10 , -90, 90 , #KnobControl_Ticks | #KnobControl_LinearPointer | #KnobControl_Smooth)

; Controller ; Range -1000 to +1000 ; Stepsize 20 ; Angle -90 to +810 (= 2.5 Rounds)
KnobControl(3,220,10,45, -1000,1000, 20,-90,810 , #KnobControl_Ticks)

; Clock with custom colors
KnobControl(4, 30,80,40, 1,12, 11, 30,360 , #KnobControl_Ticks|#KnobControl_Infinite | #KnobControl_LinearPointer | #KnobControl_Smooth)
KnobControl_SetColor(4 , #KnobControl_Foreground , RGB(100,180,110))
KnobControl_SetColor(4 , #KnobControl_Border , RGB(255,255,255))
KnobControl_SetColor(4 , #KnobControl_Highlight , RGB(100,225,0))
KnobControl_SetColor(4 , #KnobControl_Shadow , RGB(255,255,255))

; Infinte controller ; Stepsize 1
KnobControl(5, 150,110,25, 0,0,1,0,0,#KnobControl_Infinite)

AddWindowTimer(0,0,1000)

Repeat
	
	event = WaitWindowEvent()
	
	If event = #PB_Event_Gadget
		Select EventGadget()
			Case 1,2,3,4,5
				If KnobControl_Event(EventGadget() , EventType())
					current = EventGadget()
					SetGadgetText(0 , "KnobControl " + Str(current) + "  Value:" + Str(KnobControl_GetValue(current)))
				EndIf
			Case 0
				If EventType() = #PB_EventType_Focus
					SetGadgetText(0 , "")
				ElseIf EventType() = #PB_EventType_Change
					KnobControl_SetValue(current , Val(GetGadgetText(0)))
				EndIf
		EndSelect
	ElseIf event = #PB_Event_Timer
 		KnobControl_SetValue(4 , KnobControl_GetValue(4) + 1)
	EndIf
	
Until event = #PB_Event_CloseWindow

KnobControl_Free(1)
KnobControl_Free(2)
KnobControl_Free(3)
KnobControl_Free(4)
KnobControl_Free(5)
[/size]

Re: ControllerGadget

Verfasst: 18.03.2012 18:25
von STARGÅTE
Cool :allright:

mir gefällt vorallem, dass man mehrer Runden drehen kann, halt wie in "echt".
Ich habe zwar aktuell keinen Einsatz dafür, aber es kann hier und da das Spin-Gadget ersetzen

Es bietet eine schöne alternative zu meinem AngleGadget.

Re: ControllerGadget

Verfasst: 18.03.2012 18:47
von ts-soft
:allright:
Gefällt mir auch das GAUGE-Control :wink:

Re: ControllerGadget

Verfasst: 18.03.2012 18:56
von RSBasic
Gefällt mir auch. Schaut gut aus. :allright:

Re: ControllerGadget

Verfasst: 18.03.2012 19:41
von Nino
Gefällt mir auch, aber der Name sollte besser geändert werden (wie ts-soft schon angedeutet hat).

Re: ControllerGadget

Verfasst: 18.03.2012 21:03
von Mr.L
So wie ich das sehe, ist das Gauge-Control eine runde Anzeige,
wo hingegen mein ControllerGadget ein interaktiver Regler ist (und auch eine Anzeige).
Aber hauptsache es gefällt :D

Re: ControllerGadget

Verfasst: 18.03.2012 21:21
von Nino
Mr.L hat geschrieben:So wie ich das sehe, ist das Gauge-Control eine runde Anzeige,
"Gauge-Control" halte auch ich hier nicht für passend.
Mr.L hat geschrieben:wo hingegen mein ControllerGadget ein interaktiver Regler ist (und auch eine Anzeige).
Ich würde es als "Drehregler" bezeichnen (keine Ahnung, wie das auf Englisch heißt).

Grüße, Nino

Re: ControllerGadget

Verfasst: 18.03.2012 21:25
von RSBasic
Ich denke einfach mal Knob Control? Wie z.B.: http://www.codeproject.com/Articles/256 ... ms-and-GDI

Re: ControllerGadget

Verfasst: 18.03.2012 21:35
von ts-soft
Genau, Knop ist der richtige Begriff, bin ich nicht drauf gekommen.

Re: ControllerGadget

Verfasst: 19.03.2012 10:43
von Mr.L
STARGÅTE hat geschrieben:Es bietet eine schöne alternative zu meinem AngleGadget.
Dein AngleGadget kannte ich noch garnicht, es ist aber schon Interessant, wieviele Ähnlichkeiten zwischen unseren Programmen bestehen.