﻿B4J=true
Group=Default Group
ModulesStructureVersion=1
Type=Class
Version=6
@EndOfDesignText@
'ImageSlider v1.12
#DesignerProperty: Key: AnimationDuration, DisplayName: Animation Duration (ms), FieldType: Int, DefaultValue: 500
#DesignerProperty: Key: CacheSize, DisplayName: Image Cache Size, FieldType: Int, DefaultValue: 5
#DesignerProperty: Key: AnimationType, DisplayName: Animation Type, FieldType: String, DefaultValue: Horizontal, List: Vertical|Horizontal|Fade
#DesignerProperty: Key: ShowIndicators, DisplayName: Show Indicators, FieldType: Boolean, DefaultValue: True
#Event: GetImage (Index As Int) As ResumableSub
Sub Class_Globals
	Private mEventName As String 'ignore
	Private mCallBack As Object 'ignore
	Private mBase As B4XView
	Private xui As XUI
	Private CurrentPanel, NextPanel As B4XView
	Private panels As List
	Private CurrentIndex As Int = -1
	Private CachedImages As List
	Private AnimationDuration As Int
	Private CacheSize As Int
	Type ImageSliderImage (bmp As B4XBitmap, index As Int)
	Private TaskIndex As Int
	Private mNumberOfImages As Int
	Private AnimationType As String
	Public WindowBase As B4XView
	Private MousePressedX As Float
	Private ShowIndicators As Boolean
	Private IndicatorsPanel As B4XView
	Private IndicatorsCVS As B4XCanvas
	Public ImageScale As Float = 1
End Sub

Public Sub Initialize (Callback As Object, EventName As String)
	mEventName = EventName
	mCallBack = Callback
	CachedImages.Initialize
	#if B4i
	ImageScale = GetDeviceLayoutValues.NonnormalizedScale
	#End If
End Sub

Public Sub DesignerCreateView (Base As Object, Lbl As Label, Props As Map)
	mBase = Base
	WindowBase = xui.CreatePanel("WindowBase")
	mBase.AddView(WindowBase, 0, 0, 0, 0)
	AnimationDuration = Props.Get("AnimationDuration")
	CacheSize = Props.Get("CacheSize")
	AnimationType = Props.Get("AnimationType")
  	CurrentPanel = xui.CreatePanel("pnl")
	NextPanel = xui.CreatePanel("pnl")
	ShowIndicators = Props.GetDefault("ShowIndicators", True)
	panels = Array(CurrentPanel, NextPanel)
	WindowBase.AddView(CurrentPanel, 0, 0, 0, 0)
	WindowBase.AddView(NextPanel, 0, 0, 0, 0)
	Dim iv1, iv2 As ImageView
	iv1.Initialize("")
	iv2.Initialize("")
	CurrentPanel.AddView(iv1, 0, 0, 0, 0)
	NextPanel.AddView(iv2, 0, 0, 0, 0)
	If ShowIndicators Then
		IndicatorsPanel = xui.CreatePanel("")
		WindowBase.AddView(IndicatorsPanel, 0, 0, 2dip, 2dip)
		IndicatorsCVS.Initialize(IndicatorsPanel)
	End If
	Base_Resize(mBase.Width, mBase.Height)
End Sub


Private Sub Base_Resize (Width As Double, Height As Double)
	WindowBase.SetLayoutAnimated(0, 0, 0, Width, Height)
	For Each p As B4XView In panels
		p.SetLayoutAnimated(0, 0, 0, Width, Height)
		p.GetView(0).SetLayoutAnimated(0, 0, 0, Width, Height)
	Next
	CachedImages.Clear 'clear the images cache as the sizes are no longer correct
	If ShowIndicators Then
		IndicatorsPanel.SetLayoutAnimated(0, 0, 0, WindowBase.Width, 50dip)
		IndicatorsCVS.Resize(IndicatorsPanel.Width, IndicatorsPanel.Height)
		DrawIndicators
	End If
End Sub

Private Sub DrawIndicators
	If ShowIndicators = False Then Return
	IndicatorsCVS.ClearRect(IndicatorsCVS.TargetRect)
	Dim clr As Int
	For i = 0 To mNumberOfImages - 1
		If CurrentIndex = i Then clr = 0xFFC80000 Else clr = 0xFF7A7A7A
		IndicatorsCVS.DrawCircle(IndicatorsCVS.TargetRect.CenterX + (-(mNumberOfImages - 1) / 2 + i) * 30dip, 25dip, 3dip, clr, True, 0)
	Next
	IndicatorsCVS.Invalidate
End Sub

Public Sub ShowStartImage (bmp As B4XBitmap)
	NextPanel.GetView(0).SetBitmap(bmp)
	NextPanel.GetView(0).SetLayoutAnimated(0, WindowBase.Width / 2 - bmp.Width / 2, _
		WindowBase.Height / 2 - bmp.Height / 2, bmp.Width, bmp.Height)
	NextPanel.Visible = True
End Sub

Private Sub ShowImage (bmp As B4XBitmap, MovingToNext As Boolean)
	NextPanel.GetView(0).SetBitmap(bmp)
	NextPanel.GetView(0).SetLayoutAnimated(0, WindowBase.Width / 2 - bmp.Width / 2 / ImageScale, _
		WindowBase.Height / 2 - bmp.Height / 2 / ImageScale, bmp.Width / ImageScale, bmp.Height / ImageScale)
	NextPanel.Visible = True
	Select AnimationType
		Case "Vertical"
			Dim top As Int
			If MovingToNext Then top = -NextPanel.Height Else top = NextPanel.Height
			NextPanel.SetLayoutAnimated(0, 0, top, NextPanel.Width, NextPanel.Height)
			NextPanel.SetLayoutAnimated(AnimationDuration, 0, 0, NextPanel.Width, NextPanel.Height)
			CurrentPanel.SetLayoutAnimated(AnimationDuration, 0, -top, CurrentPanel.Width, CurrentPanel.Height)
		Case "Horizontal"
			Dim left As Int
			If MovingToNext Then left = NextPanel.Width Else left = -NextPanel.Width
			NextPanel.SetLayoutAnimated(0, left, 0, NextPanel.Width, NextPanel.Height)
			NextPanel.SetLayoutAnimated(AnimationDuration, 0, 0, NextPanel.Width, NextPanel.Height)
			CurrentPanel.SetLayoutAnimated(AnimationDuration, -left, 0, CurrentPanel.Width, CurrentPanel.Height)
		Case "Fade"
			NextPanel.Visible = False
			NextPanel.SetLayoutAnimated(0, left, 0, NextPanel.Width, NextPanel.Height)
			NextPanel.SetVisibleAnimated(AnimationDuration, True)
			CurrentPanel.SetVisibleAnimated(AnimationDuration, False)			
	End Select
	Dim p As B4XView = CurrentPanel
	CurrentPanel = NextPanel
	NextPanel = p
	DrawIndicators
End Sub

Public Sub NextImage
	TaskIndex = TaskIndex + 1
	Dim MyTask As Int = TaskIndex
	CurrentIndex = (CurrentIndex + 1) Mod mNumberOfImages
	Wait For (GetImage(CurrentIndex)) Complete (Result As ImageSliderImage)
	If MyTask <> TaskIndex Or Result.IsInitialized = False Then Return
	ShowImage(Result.bmp, True)
	Sleep(0)
	If CurrentIndex < mNumberOfImages -1 Then GetImage(CurrentIndex + 1)
End Sub

Public Sub PrevImage
	TaskIndex = TaskIndex + 1
	Dim MyTask As Int = TaskIndex
	CurrentIndex = (CurrentIndex - 1 + mNumberOfImages) Mod mNumberOfImages
	Wait For (GetImage(CurrentIndex)) Complete (Result As ImageSliderImage)
	If MyTask <> TaskIndex Or Result.IsInitialized = False Then Return
	ShowImage(Result.bmp, False)
	Sleep(0)
	If CurrentIndex > 0 Then GetImage(CurrentIndex - 1)
End Sub

Private Sub GetImage(index As Int) As ResumableSub
	For Each ii As ImageSliderImage In CachedImages
		If ii.index = index Then
			CachedImages.RemoveAt(CachedImages.IndexOf(ii))
			CachedImages.Add(ii)
			Return ii
		End If
	Next
	Dim rs As ResumableSub = CallSub2(mCallBack, mEventName & "_GetImage", index)
	Dim ii As ImageSliderImage
	If rs.IsInitialized = False Then Return ii
	Wait For (rs) Complete (bmp As B4XBitmap)
	ii.Initialize
	ii.bmp = bmp
'	Log($"${bmp.Width}, ${bmp.Height} "$)
	ii.index = index
	CachedImages.Add(ii)
	Do While CachedImages.Size > CacheSize
		CachedImages.RemoveAt(0)
	Loop
	Return ii
End Sub

Private Sub WindowBase_Touch (Action As Int, X As Float, Y As Float)
	If Action = WindowBase.TOUCH_ACTION_DOWN Then
		MousePressedX = X
	Else If Action = WindowBase.TOUCH_ACTION_UP Then
		If X > MousePressedX + 50dip Then
			PrevImage
		Else if X < MousePressedX - 50dip Then
			NextImage
		Else
			CallSub2(mCallBack,  mEventName & "_Click",CurrentIndex)
		End If
	End If
End Sub

Public Sub getNumberOfImages As Int
	Return mNumberOfImages
End Sub

Public Sub setNumberOfImages (i As Int)
	mNumberOfImages = i
	DrawIndicators
End Sub

Public Sub ClearCache
	CachedImages.Clear
End Sub


