B4A Library [Class] Screen HotSpots

stevel05

Expert
Licensed User
HotSpots Class and CustomView

Having done some work on the hotspot module in the last few days, it struck me that there might be an easier way to get the hotspots aligned with images by using the designer and this is the result.

The class provides the same functionality as the code module, you can use it all manually and except for the initialization requiring two subroutines, there is very little difference. Why does the initialization required two subroutines, because it is sharing the code with a CustomView, which has a strict signature for the initialization subroutine, but we need to pass additional information so we need to do it in a second subroutine.

Manual Creation

To set up and use the HotSpots manually wih the class we need to declare the Class:
B4X:
Dim HotSpot As HotSpotClass
Then Initialize it:
B4X:
Hotspot.Initialize(Me,"HotSpot")   'Requires the calling Module, and an EventName.
Then setup,
B4X:
HotSpot.SetUp(Activity,0,0,50%x,100%y)
Which passes the activity (or Panel if preferred) and the size of the panel that the HotSpot class should create and add to the passed Activity or Panel.
Then we can add some hotspots:
B4X:
HotSpot.AddHotSpot(10Dip,10Dip,60Dip,70Dip,"Tag1")
HotSpot.AddHotSpot(100Dip,10Dip,160Dip,70Dip,"Tag2")
HotSpot.AddHotSpot(200Dip,10Dip,260Dip,70Dip,"Tag3")
We need to create a Touch sub for the EventName we passed in initialize:
B4X:
Sub HotSpot_Touch(Param() As Object)
We use a Param() array to pass parameters to the touch sub as we use CallSub which only supports passing two separate parameters, and we need three. So we bundle them into an array and then unpack them in the called subroutine as:
B4X:
Dim Action As Int = Param(0)
Dim X As Float = Param(1)
Dim Y As Float = Param(2)
Then we can add the code to process the touch and check if any of the HotSpots are being touched (See the example Main Activity).
B4X:
#Project Attributes 
#Activity Attributes 
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
End Sub
Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.

   Dim HSPnl As Panel
   Dim Canv As Canvas
   Dim HotSpot As HotSpotClass

End Sub

Sub Activity_Create(FirstTime As Boolean)
   'Do not forget to load the layout file created with the visual designer. For example:
   'Activity.LoadLayout("Layout1")

   HotSpot.Initialize(Me,"HotSpot")
   HotSpot.SetUp(Activity,0,0,50%x,100%y)
   
   'We can get the panel that the Hotspots are monitored on 
   'perhaps To add a Canvas and draw to, or to change parameters.
   HSPnl = HotSpot.GetPanel
   HSPnl.Color=Colors.White
   
   Canv.Initialize(HSPnl)
   
   Log(HotSpot.AddHotSpot(10Dip,10Dip,60Dip,70Dip,"Tag1"))
   Log(HotSpot.AddHotSpot(100Dip,10Dip,160Dip,70Dip,"Tag2"))
   Log(HotSpot.AddHotSpot(200Dip,10Dip,260Dip,70Dip,"Tag3"))
   Log(HotSpot.AddHotCircle(20Dip,100Dip,80Dip,"Tag4"))
   Log(HotSpot.AddHotSpot(10Dip,10Dip,260Dip,70Dip,"Tag5"))
   Canv.DrawCircle(60Dip,140Dip,40Dip,Colors.Blue,True,1Dip)

   Activity.Invalidate
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub
Sub HotSpot_Touch (Param() As Object)
   Dim Action As Int = Param(0)
   Dim X As Float = Param(1)
   Dim Y As Float = Param(2)
   'Use This Version for FindHotSpot,FindHotSpotFirst and FindHotSpotLast
   '   If Action = Activity.ACTION_DOWN Then
   '      Dim HS As HotSpotType = HotSpot.FindHotSpot(X,Y)
   '      'If HotSpot is not found an uninitialized HotSpotType is returned.
   '      If HS.IsInitialized Then 
   '         Log("X "&X&" Y "&Y&" "&HS.Tag)
   '         'Edit the SLHotSpot, because we can
   '         If HS.Tag = "Tag3" Then HotSpot.EditHotSpot(HS.ID,10,200,70,270,"Ha Moved...")
   '      End If
   '   End If
   
   'Use this version for FindHotSpotAll
   If Action = Activity.ACTION_DOWN Then
      Dim ResultsList As List
      ResultsList=HotSpot.FindHotSpotAll(X,Y)
      For Each HS As HotSpotType In ResultsList
         'If HotSpot is not found an uninitialized HotSpotType is returned.
         If HS.IsInitialized Then 
            Log("X "&X&" Y "&Y&" "&HS.Tag)
            'Edit the HotSpot, because we can
            If HS.Tag = "Tag3" Then 
                              HotSpot.EditHotSpot(HS.ID,10Dip,200Dip,70Dip,270Dip,"Ha Moved...")
               HotSpot.ChangeType(HS.ID,"C")
            End If
         End If
      Next
   End If
End Sub
Designer Creation

In it's most basic form we can recreate the above with the designer by adding a CustomView to the designer and select HotSpotClass in the Customview field, the Customview object should be the size of the panel we want to monitor the touches on and save it as a layout, then use Activity LoadLayout in the Module in the usual way.

Then add the Dim to Globals, either from the designer or manually, we don't then need to initialize, or run the setup subroutine, this is taken care of by the designer and code in the Class.

We can then add our hotspots as in the example above.



Using a Second Layout File

In addition to this, we can use a second layoutfile to define our HotSpots. To do this, the second layout must contain a panel called panel1. On this panel we put:
  • Panels to represent HotSpots and
  • Labels to represent HotCircles.
If we give the panels and labels an alpha of 0, we will be able to see the panel behind and just an outline of the additional Panels and Labels.

If we add an image to the background of panel1 it makes aligning the HotSpots quite straightforward with just the outline of the panels and labels visible. We can also elect to display the image on the panel automatically, or we would need to display a relevant background separately and ensure that it is behind the Base Panel and that the base panel color is set to transparent.



We can get access to the Base panel by calling the HotSpot.GetPanel subroutine. It is then possible to add views or a Canvas to the panel to draw on or display other things or set it's size or color etc.

To get the HotSpots to generate, we can either add the name of the second layout file to the Tag of the CustomView Object in the first layout file (see image above), or we can call the subroutine:
B4X:
HotSpot.PopulateFromLayout(FileName As String, Copy As Boolean) As Int
Filename is the name of the second LayoutFile, and copy determines if the background from panel1 in the second layout file should be copied to the Base Panel and therefore displayed. We can also add the word 'copy' to the Tag of Panel1 in the second layout file to achieve the copy of it's background automatically.



B4X:
#Activity Attributes 

Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.

End Sub

Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.

   Dim HSPnl As Panel
   Dim Canv As Canvas
   Dim HotSpot As HotSpotClass

End Sub

Sub Activity_Create(FirstTime As Boolean)
   'Do not forget to load the layout file created with the visual designer. For example:
   'Activity.LoadLayout("Layout1")
   
   Activity.LoadLayout("1")
   
   Activity.Invalidate
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub
Sub HotSpot_Touch (Param() As Object)
   Dim Action As Int = Param(0)
   Dim X As Float = Param(1)
   Dim Y As Float = Param(2)
   'Use This Version for FindHotSpot,FindHotSpotFirst and FindHotSpotLast
   '   If Action = Activity.ACTION_DOWN Then
   '      Dim HS As HotSpotType = HotSpot.FindHotSpot(X,Y)
   '      'If HotSpot is not found an uninitialized HotSpotType is returned.
   '      If HS.IsInitialized Then 
   '         Log("X "&X&" Y "&Y&" "&HS.Tag)
   '         'Edit the HotSpot, because we can
   '         If HS.Tag = "Tag3" Then HotSpot.EditHotSpot(HS.ID,10,200,70,270,"Ha Moved...")
   '      End If
   '   End If
   
   'Use this version for FindSLHotSpotAll
   If Action = Activity.ACTION_DOWN Then
      Dim ResultsList As List
      ResultsList=HotSpot.FindHotSpotAll(X,Y)
      For Each HS As HotSpotType In ResultsList
         'If SLHotSpot is not found an uninitialized SLHotSpotType is returned.
         If HS.IsInitialized Then 
            Log("X "&X&" Y "&Y&" "&HS.Tag)
            'Edit the SLHotSpot, because we can
            If HS.Tag = "Tag3" Then 
               HotSpot.EditHotSpot(HS.ID,10Dip,200Dip,70Dip,270Dip,"Ha Moved...")
               HotSpot.ChangeType(HS.ID,"C")
            End If
            Return True
         End If
      Next
   End If
   
End Sub
I hope you find this useful.

Dependencies:

Reflection Library - Andrew Graham

V1 HotSpotClass attached to this post.
V1.1 added polygons - see post #4
- fixed bugs and omissions with find routines.
- added initcomplete call back for customview.
- draw the hotspots for visibility.
 

Attachments

Last edited:

stevel05

Expert
Licensed User
You give us the tools, we'll try to find something different to do with them. :)

Sent using Tapatalk 2
 
Last edited:

stevel05

Expert
Licensed User
This is definitely a case of 1 step back, 3 steps forward. The step back is that I can't currently incorporate the latest addition into the visual interface that the custom view allows. This may change as the custom view matures.

The step forward is that the hotspots now incorporate polygons. I came across a great piece of code here. I've no real idea why it works, but it does. It's released under The Code Project Open License (CPOL) for which it seems pretty much anything goes.

So what else is new? I have incorporated draw functions so that you can easily see where the hot spot are going to be, and tidied up and fixed some bugs/omissions with the find routines.

And for customview users I've added a InitComplete callback as the set up uses a callsubdelayed, you can never be sure when the routine has finished and some things may fail inexplicably and not on other occasions. So changes / modifications to the hotspots should be carried out starting from this sub, but only for setups using customview .

Class version 1.1 can be found attached to the original post.
 
Last edited:
Top