Type=Class
Version=6.5
ModulesStructureVersion=1
B4A=true
@EndOfDesignText@
'Custom View class LimitBar

'Events declaration
#Event: ValuesChanged(LimitLeft As Int, LimitRight As Int)
#RaisesSynchronousEvents: ValuesChanged

'Designer property declarations
#DesignerProperty: Key: Max, DisplayName: Max, FieldType: Int, DefaultValue: 100, Description: Sets the max value.
#DesignerProperty: Key: LimitLeft, DisplayName: Left limit, FieldType: Int, DefaultValue: 10, Description: Sets the left limit value.
#DesignerProperty: Key: LimitRight, DisplayName: Right limit, FieldType: Int, DefaultValue: 100, Description: Sets the right limit value.
#DesignerProperty: Key: Radius, DisplayName: Radius, FieldType: Int, DefaultValue: 5, Description: Sets the corner radius.
#DesignerProperty: Key: BackgroundColor, DisplayName: BackgroundColor, FieldType: Color, DefaultValue: 0xFF0000FF, Description: Sets the background color.
#DesignerProperty: Key: BackLineColor, DisplayName: BackLineColor, FieldType: Color, DefaultValue: 0xFFFF0000, Description: Sets the back line color.
#DesignerProperty: Key: FrontLineColor, DisplayName: FrontLineColor, FieldType: Color, DefaultValue: 0xFF33B5E5, Description: Sets the front line color.

'LimitBar CustomView class.
'This CustomView allows the user to set two limits with two cursors.
'The Min value is 0 and the Max value is 100.
'The Max value can be changed by the programmer.
Sub Class_Globals
	Private mCallback As Object				' calling module
	Private mEventName As String			' event name
	Private mWidth, mHeight, mRadius As Int

	Private ltbPanelBack As Panel			' the background panel
	Private ltbPanelFront As Panel		' the foreground panel
	Private cvsPanelBack As Canvas		' the background canvas
	Private cvsPanelFront As Canvas		' the foreground canvas
	Private rectPanelFront As Rect		' a rectangle for the foreground canvas
	
	Private mBackgroundColor As Int		' color for the background
	Private cdwBackground As ColorDrawable	' background drawable, only for B4A
	Private mBackLineColor As Int			' color for the background line
	Private mFrontLineColor As Int		' color for the foreground line
	Private mMargin As Int						' left and right margins for the line
	Private x0, y0, x1, y1, y2 As Int	' backline and cursor coordinates
	Private mMaxValue As Int					' value of the Max property
	Private mScale As Double					' scale between position value and pixels
	Private mLimit(2) As Int					' values of the limits
	Private PositionPixels(2) As Int	' left and right positions in pixels
	Private Paths(2) As Path					' two paths for the cursor shape
	Private PosIndex As Int						' current index of the cursor position
																		' 0 = left  1 = right  cursor
End Sub

'Initializes the object.
'Callback = name of the calling module
'EventName = event name
'Example if added in the code: 
'<code>ltbTest.Initialize(Me, "ltbTest")</code>
Public Sub Initialize(Callback As Object, EventName As String)
	mCallback = Callback
	mEventName = EventName

	' initialize default values
	mBackgroundColor = Colors.Blue
	mBackLineColor = Colors.Black
	mFrontLineColor = Colors.RGB(51, 181, 229)
	mMargin = 15dip	
	mMaxValue = 100
	mLimit(0) = 0
	mLimit(1) = mMaxValue
End Sub

Public Sub DesignerCreateView(Base As Panel, Lbl As Label, Props As Map)
	' we use the Base panel as the background panel
	ltbPanelBack = Base
	
	' we memorize the Base Width and Height properties
	mWidth = Base.Width
	mHeight = Base.Height
	
	' we memorize the custom properties
	mMaxValue = Props.Get("Max")
	mLimit(0) = Props.Get("LimitLeft")
	mLimit(0) = Max(0, mLimit(0))					' we check the min value, not less than 0
	
	mLimit(1) = Props.Get("LimitRight")
	mLimit(1) = Min(mMaxValue, mLimit(1))	' we check the max value, not higher than Max
	
	mRadius = Props.Get("Radius")
	mBackgroundColor = Props.Get("BackgroundColor")
	mBackLineColor = Props.Get("BackLineColor")
	mFrontLineColor = Props.Get("FrontLineColor")
	
	InitClass		' initializes the common parts for Designer and code
End Sub

'Adds the LimitBar to the Parent object
'Parent = parent view, the Activity or a Panel
'Left, Right, Width, Height = position and dimensions properties of the LimitBar
'Color = background color of the LimitBar
'Radius = corner radius of the LimitBar
Public Sub AddToParent(Parent As Activity, Left As Int, Top As Int, Width As Int, Height As Int, BackgroundColor As Int, Radius As Int)
	mWidth = Width
	mHeight = Max(Height, 30dip)				' limits the height to min 30dip
	mHeight = Min(Height, 60dip)					' limits the height to max 60 pixels
	mRadius = Min(Radius, Height / 2)		' limits the max radius to half the height
	mBackgroundColor = BackgroundColor
	
	' initialize the background panel ltbPanelBack and add it onto the parent view
	ltbPanelBack.Initialize("")
	Parent.AddView(ltbPanelBack, Left, Top, Width, Height)
	
	InitClass		' initializes the common parts for Designer and code
End Sub

Private Sub InitClass
	' initialize and set the ColorDrawable for the background panel
	cdwBackground.Initialize(mBackgroundColor, mRadius)
	ltbPanelBack.Background = cdwBackground

	' initialize the foreground panel and add it onto the background panel
	ltbPanelFront.Initialize("ltbPanelFront")
	ltbPanelBack.AddView(ltbPanelFront, 0, 0, ltbPanelBack.Width, ltbPanelBack.Height)
	
	' initialize the foreground panel rectangle used to erase ltbPanelFront
	rectPanelFront.Initialize(0, 0, ltbPanelFront.Width, ltbPanelFront.Height)
	ltbPanelFront.BringToFront
	
	' initialize the background canvas and draw the background line
	cvsPanelBack.Initialize(ltbPanelBack)
	
	' initialize the foreground canvas
	cvsPanelFront.Initialize(ltbPanelFront)
	
	' set the limit max value, which calculates also the scale limit values <> pixels
	setMax(mMaxValue)

	DrawBackGround
End Sub

Private Sub InitCursors
	x0 = mMargin
	x1 = mWidth - mMargin
	mScale = (x1 - x0) / mMaxValue
	PositionPixels(0) = mLimit(0) * mScale + x0
	PositionPixels(1) = mLimit(1) * mScale + x0

	y0 = 0.2 * mHeight
	y1 = y0 + 8dip + 0.05 * mHeight
	y2 = 0.9 * mHeight
End Sub

Private Sub DrawBackGround
	ltbPanelBack.Background = cdwBackground
	cvsPanelBack.Initialize(ltbPanelBack)
	cvsPanelBack.DrawLine(x0, y0, x1, y0, mBackLineColor, 2dip)
	ltbPanelBack.Invalidate
End Sub

Private Sub DrawCursors
	' draw a transparent rectangle to erase the foreground panel
	cvsPanelFront.DrawRect(rectPanelFront, Colors.Transparent, True, 1)
	
	' define the left cursor path according to its current position
	Paths(0).Initialize(PositionPixels(0), y0)
	Paths(0).LineTo(PositionPixels(0), y2)
	Paths(0).LineTo(PositionPixels(0) - 12dip, y2)
	Paths(0).LineTo(PositionPixels(0) - 12dip, y1)
	Paths(0).LineTo(PositionPixels(0), y0)
	
	' define the right cursor path according to its current position
	Paths(1).Initialize(PositionPixels(1), y0)
	Paths(1).LineTo(PositionPixels(1), y2)
	Paths(1).LineTo(PositionPixels(1) + 12dip, y2)
	Paths(1).LineTo(PositionPixels(1) + 12dip, y1)
	Paths(1).LineTo(PositionPixels(1), y0)
	
	' draw the two cursors and the front line
	cvsPanelFront.DrawPath(Paths(0), mFrontLineColor, True, 1)
	cvsPanelFront.DrawPath(Paths(1), mFrontLineColor, True, 1)
	cvsPanelFront.DrawLine(PositionPixels(0), y0, PositionPixels(1), y0, mFrontLineColor, 3dip)

	ltbPanelFront.Invalidate
End Sub

Private Sub ltbPanelFront_Touch (Action As Int, X As Float, Y As Float)
	' check if the cursor is outsides the limits
	X = Max(x0, X)
	X = Min(x1, X)
	
	' select the Action type
	Select Action
	Case 0  				'DOWN
		If X < Abs(PositionPixels(0) + PositionPixels(1)) / 2 Then
			' if X is closer to the left cursor we choose it
			PosIndex = 0
		Else
			' otherwise we choose the right cursor
			PosIndex = 1
		End If
		mLimit(PosIndex) = Floor((X - x0) / mScale + .5)
		PositionPixels(PosIndex) = X
		DrawCursors
	Case 2				' MOVE
		mLimit(PosIndex) = Floor((X - x0) / mScale + .5)
		PositionPixels(PosIndex) = X
		DrawCursors
	Case 1				' UP
		' when Action is UP (mouse released) check if mLimit(0) > mLimit(1)
		' if yes we invert the limit values and redraw the cursors
		If mLimit(0) > mLimit(1) Then
			Private val As Int
			val = mLimit(0)
			mLimit(0) = mLimit(1)
			mLimit(1) = val
			PositionPixels(0) = mLimit(0) * mScale + x0
			PositionPixels(1) = mLimit(1) * mScale + x0
			DrawCursors
		End If
	End Select
	
	' if a callback routine exists in the calling module we call it
	If SubExists(mCallback, mEventName & "_ValuesChanged") Then
		CallSub3(mCallback, mEventName & "_ValuesChanged", mLimit(0), mLimit(1))
	End If
End Sub

'gets or sets the max value
Public Sub setMax(MaxValue As Int)
	mMaxValue = MaxValue
	InitCursors	
	DrawCursors
End Sub

Public Sub getMax As Int
	Return mMaxValue
End Sub

'gets or sets the left limit
Public Sub setLimitLeft(Pos As Int)
	' if Pos is lower than 0 set cLimitLeft to 0
	mLimit(0) = Max(0, Pos)
	InitCursors
	DrawCursors
End Sub

Public Sub getLimitLeft As Int
	Return mLimit(0)
End Sub

'gets or sets the right limit
Public Sub setLimitRight(Pos As Int)
	' if Pos is higher than mMaxValue set mLimit(1) to mMaxValue
	mLimit(1) = Min(mMaxValue, Pos)
	InitCursors
	DrawCursors
End Sub

Public Sub getLimitRight As Int
	Return mLimit(1)
End Sub

'gets or sets the Left property
Public Sub setLeft(Left As Int)
	ltbPanelBack.Left = Left
End Sub

Public Sub getLeft As Int
	Return ltbPanelBack.Left
End Sub

'gets or sets the Top property
Public Sub setTop(Top As Int)
	ltbPanelBack.Top = Top
End Sub

Public Sub getTop As Int
	Return ltbPanelBack.Top
End Sub

'gets or sets the Width property
Public Sub setWidth(Width As Int)
	mWidth = Width
	ltbPanelBack.Width = mWidth
	ltbPanelFront.Width = mWidth
	cvsPanelBack.Initialize(ltbPanelBack)
	cvsPanelFront.Initialize(ltbPanelFront)
	
	' initialize the foreground panel rectangle used to erase ltbPanelFront
	rectPanelFront.Initialize(0, 0, ltbPanelFront.Width, ltbPanelFront.Height)

	InitCursors
	DrawBackGround
	DrawCursors
End Sub

Public Sub getWidth As Int
	Return ltbPanelBack.Width
End Sub

'gets or sets the Height property
Public Sub setHeight(Height As Int)
	mHeight = Max(Height, 30dip)
	ltbPanelBack.Height = mHeight
	ltbPanelFront.Height = mHeight
	cvsPanelBack.Initialize(ltbPanelBack)
	cvsPanelFront.Initialize(ltbPanelFront)

	' initialize the foreground panel rectangle used to erase ltbPanelFront
	rectPanelFront.Initialize(0, 0, mWidth, mHeight)
	
	InitCursors
	DrawBackGround
	DrawCursors
End Sub

Public Sub getHeight As Int
	Return ltbPanelBack.Height
End Sub

'gets or sets the Visible property
Public Sub setVisible(IsVisible As Boolean)
	ltbPanelBack.Visible = IsVisible
End Sub

Public Sub getVisible As Boolean
	Return ltbPanelBack.Visible
End Sub

'gets or sets the back line color
Public Sub setBackLineColor(BackLineColor As Int)
	mBackLineColor = BackLineColor
	If ltbPanelBack.IsInitialized Then
		DrawBackGround
	End If
End Sub

Public Sub getBackLineColor As Int
	Return mBackLineColor
End Sub

'gets or sets the front line color
Public Sub setFrontLineColor(FrontLineColor As Int)
	mFrontLineColor = FrontLineColor
	If ltbPanelBack.IsInitialized Then
		DrawCursors
	End If
End Sub

Public Sub getFrontineColor As Int
	Return mFrontLineColor
End Sub

