B4J=true
Group=Default Group
ModulesStructureVersion=1
Type=Class
Version=4.7
@EndOfDesignText@
'xLimitBar CustomView cross platform b4xlib.
'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.
'Version 1.0
'Author: Klaus CHRISTL (klaus)
'
'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: 0, 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.

Sub Class_Globals
	Private xui As XUI
	Private mCallback As Object					' calling module
	Private mEventName As String				' event name
	Public mBase As B4XView
	Private mParent As B4XView
	'two paths for the cursor shape and the background
	Private CursorPaths(2), BackgroundPath As B4XPath
	
	Private mLeft, mTop, mWidth, mHeight, mRadius As Double

	Private ltbPanelFront As B4XView		' the background panel
	Private cvsPanelBack As B4XCanvas		' the background canvas
	Private cvsPanelFront As B4XCanvas	' the foreground canvas
	Private rectPanelFront As B4XRect		' a rectangle for the foreground canvas
	
	Private mBackgroundColor As Int			' color for the background
	Private mBackLineColor As Int				' color for the background line
	Private mFrontLineColor As Int			' color for the foreground line
	Private mMargin As Double						' left and right margins for the line
	Private x0, y0, x1, y1, y2 As Double	' 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						' value of the limits
	Private PositionPixels(2) As Double	' left and right positions in pixels
	Private PosIndex As Int
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 = xui.Color_Blue
	mBackLineColor = xui.Color_Black
	mFrontLineColor = xui.Color_RGB(51, 181, 229)
	mRadius = 10dip
	mMargin = 15dip
	mMaxValue = 100
	mLimit(0) = 0
	mLimit(1) = mMaxValue
End Sub

Public Sub DesignerCreateView(Base As Object, Lbl As Label, Props As Map)
	' we use the Base panel as the background panel
	mBase = Base
	
	' we memorize the Base Width and Height properties
	mLeft = mBase.Left
	mTop = mBase.Top
	mWidth = mBase.Width
	mHeight = mBase.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 = DipToCurrent(Props.Get("Radius"))
	mBackgroundColor = xui.PaintOrColorToColor(Props.Get("BackgroundColor"))
	mBackLineColor = xui.PaintOrColorToColor(Props.Get("BackLineColor"))
	mFrontLineColor = xui.PaintOrColorToColor(Props.Get("FrontLineColor"))
	
	#If B4A
		InitClass		' initializes the common parts for Designer and code
	#End If
End Sub

Public Sub Base_Resize (Width As Double, Height As Double)
	mWidth = Width
	mHeight = Height
	
	If ltbPanelFront.IsInitialized = False Then
		InitClass		' initializes the common parts for Designer and code
	Else
		mBase.Width = mWidth
		mBase.Height = mHeight
		
		rectPanelFront.Width = mWidth
		rectPanelFront.Height = mHeight
		
		ltbPanelFront.Width = mWidth
		ltbPanelFront.Height = mHeight
		
		cvsPanelBack.Resize(mWidth, mHeight)
		cvsPanelFront.Resize(mWidth, mHeight)
		
 		InitCursors
		DrawBackGround
		DrawCursors
	End If
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 xLimitBar
'Height min = 30, Height min = 60
'BackgroundColor = background color of the xLimitBar
'Radius = corner radius of the xLimitBar
Public Sub AddToParent(Parent As Object, Left As Int, Top As Int, Width As Int, Height As Int, BackgroundColor As Int, Radius As Int)
	mLeft = Left
	mTop = Top
	mWidth = Width
	mHeight = Max(Height, 30dip)					' limits the height to min 30 pixels
	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
	mParent = Parent
	
	' initialize the mBase panel and add it onto the parent view
	mBase = xui.CreatePanel("")
	mParent.AddView(mBase, Left, Top, Width, Height)
	
	InitClass		' initializes the common parts for Designer and code
End Sub

Private Sub InitClass
	' initialize the background canvas and draw the background line
	cvsPanelBack.Initialize(mBase)
	
	' initialize the foreground panel and canvas
	ltbPanelFront = xui.CreatePanel("ltbPanelFront")
	mBase.AddView(ltbPanelFront, 0, 0, mWidth, mHeight)
	cvsPanelFront.Initialize(ltbPanelFront)
	
	' initialize the foreground panel rectangle used to erase ltbPanelFront
	rectPanelFront.Initialize(0, 0, ltbPanelFront.Width, ltbPanelFront.Height)

	' 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
	' set the background color and the radius for the background panel
	cvsPanelBack.ClearRect(rectPanelFront)	'needed to have the round corners when the width is decreased
	BackgroundPath.InitializeRoundedRect(rectPanelFront, mRadius)
	cvsPanelBack.ClipPath(BackgroundPath)
	cvsPanelBack.DrawRect(rectPanelFront, mBackgroundColor, True, 1dip)
	
	'draw the background line
	cvsPanelBack.DrawLine(x0, y0, x1, y0, mBackLineColor, 2dip)
	cvsPanelBack.RemoveClip
	cvsPanelBack.Invalidate
End Sub

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

	cvsPanelFront.Invalidate
End Sub

Private Sub ltbPanelFront_Touch (Action As Int, X As Double, Y As Double)
	' check if the cursor is outsides the limits
	Private xx As Double
	xx = X
	xx = Max(x0, xx)
	xx = Min(x1, xx)
	
	' select the Action type
	Select Action
		Case ltbPanelFront.TOUCH_ACTION_DOWN
			If xx < 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((xx - x0) / mScale + .5)
			PositionPixels(PosIndex) = xx
			DrawCursors
		Case ltbPanelFront.TOUCH_ACTION_MOVE
			If xui.SubExists(mCallback, mEventName & "_ValuesChanged", 2) Then
				CallSub3(mCallback, mEventName & "_ValuesChanged", mLimit(0), mLimit(1))
			End If
			
			mLimit(PosIndex) = Floor((xx - x0) / mScale + .5)
			PositionPixels(PosIndex) = xx
			DrawCursors
		Case ltbPanelFront.TOUCH_ACTION_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

			'call the ValuesChanged routine if it exists
			If xui.SubExists(mCallback, mEventName & "_ValuesChanged", 2) Then
				CallSub3(mCallback, mEventName & "_ValuesChanged", mLimit(0), mLimit(1))
			End If
	End Select
End Sub

'gets or sets the max value
Public Sub setMax(MaxValue As Int)
	mMaxValue = MaxValue
	InitCursors
	If ltbPanelFront.IsInitialized Then
		DrawCursors
	End If
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
	If ltbPanelFront.IsInitialized Then
		DrawCursors
	End If
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 mLimitRight to mMaxValue
	mLimit(1) = Min(mMaxValue, Pos)
	InitCursors
	If ltbPanelFront.IsInitialized Then
		DrawCursors
	End If
End Sub

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

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

Public Sub getLeft As Int
	Return mLeft
End Sub

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

Public Sub getTop As Int
	Return mTop
End Sub

'gets or sets the Width property
Public Sub setWidth(Width As Int)
	mWidth = Width
	
	' set the new widths
	mBase.Width = mWidth
	ltbPanelFront.Width = mWidth
	
	' resize the two Canvases
	cvsPanelBack.Resize(mWidth, mHeight)
	cvsPanelFront.Resize(mWidth, mHeight)
	
	' adjust the width of rectPanelFront
	rectPanelFront.Width = mWidth
	
	If ltbPanelFront.IsInitialized Then 
		InitCursors
		DrawBackGround
		DrawCursors
	End If
End Sub

Public Sub getWidth As Int
	Return mWidth
End Sub

'gets or sets the Height property
Public Sub setHeight(Height As Int)
	mHeight = Max(Height, 30dip)
	
	' set the new heights
	mBase.Height = mHeight
	ltbPanelFront.Height = mHeight
	
	' resize the two Canvases
	cvsPanelBack.Resize(mWidth, mHeight)
	cvsPanelFront.Resize(mWidth, mHeight)
	
	' adjust the height of rectPanelFront
	rectPanelFront.Height = mHeight
	
	If ltbPanelFront.IsInitialized Then
		InitCursors
		DrawBackGround
		DrawCursors
	End If
End Sub

Public Sub getHeight As Int
	Return mHeight
End Sub

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

Public Sub getVisible As Boolean
	Return mBase.Visible
End Sub

'gets or sets the background color
Public Sub setBackgroundColor(BackgroundColor As Int)
	mBackgroundColor = BackgroundColor
	If ltbPanelFront.IsInitialized Then
		DrawBackGround
	End If
End Sub

Public Sub getBackgroundColor As Int
	Return mBackgroundColor
End Sub

'gets or sets the back line color
Public Sub setBackLineColor(BackLineColor As Int)
	mBackLineColor = BackLineColor
	If ltbPanelFront.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 ltbPanelFront.IsInitialized Then
		DrawCursors	
	End If
End Sub

Public Sub getFrontLineColor As Int
	Return mFrontLineColor
End Sub
