B4J Tutorial [ABMaterial] New in 3.50: Drag and Drop about anything

It may have been a bit silent the last few weeks around ABMaterial, but behind the scenes I have been working practically around the clock on maybe the biggest new feature since Chipmunk was introduced: Drag & Drop!

In 3.50, it will be possible to drag ABMContainers (and hence about anything in it) from one cell to another.

Let's watch a video demonstration first:


Pretty cool hè! :)

How it works:
I explain the basics here, the DragDrop demo project included in the ABMaterial 3.50 download will show all tricks shown in the demo video.

1. Page_ParseEvent() gets a little bit of extra code to sync the moves made in the browser with our server
B4X:
...
If SubExists(Me, eventName) Then
     Params.Remove("eventname")
     Params.Remove("eventparams")
     ' BEGIN NEW DRAGDROP
     If eventName = "page_dropped" Then
       page.ProcessDroppedEvent(Params)       
     End If
     ' END NEW DRAGDROP
     Select Case Params.Size
     ...

2. Next we define a 'DRAG' group:
B4X:
' name, minimum height of a cell
page.DragDropCreateGroup("DRAG", 150)

3. We add cells to this 'DRAG' group we want to drag & drop between. The last 'null' parameter can be any ABMComponent you want to use a title of the cell (e.g. the COLUMN X ABMLabel in the demo).
B4X:
page.DragDropAddZone("DRAG", "DRAGCELL1", page.Cell(3,1),null)
page.DragDropAddZone("DRAG", "DRAGCELL2", page.Cell(3,2),null)
page.DragDropAddZone("DRAG", "DRAGCELL3", page.Cell(3,3),null)

4. We add our draggable ABMContainers to the cells. Note: they MUST be added with AddArrayComponent!

Here we also enable them to be draggable with cont.EnableDragDropZone(). There is also a shortcut method to enable/disable all 'Zones/Cells' in a group with cont.EnableDragDropAllZonesFromGroup() in one go.
B4X:
page.Cell(3,1).AddArrayComponent(CreateCard("1", True, True, True, "I may be dragged everywhere", "../images/list1.jpg"), "Cards")
...

Sub CreateCard(ID As String, AllowInCell1 As Boolean, AllowInCell2 As Boolean, AllowInCell3 As Boolean, Title As String, image As String) As ABMContainer
  Dim cont As ABMContainer
  cont.Initialize(page, ID, "")
  cont.AddRows(1,True,"").AddCells12(1, "")
  cont.BuildGrid

  cont.IsTextSelectable = False
   
  If AllowInCell1 Then
    ' can be dragged to zone 1 of 'DRAG'
    cont.EnableDragDropZone("DRAG","DRAGCELL1",True)
  End If
  If AllowInCell2 Then
    ' can be dragged to zone 2 of 'DRAG'
    cont.EnableDragDropZone("DRAG","DRAGCELL2",True)
  End If
  If AllowInCell3 Then
    ' can be dragged to zone 3 of 'DRAG'
    cont.EnableDragDropZone("DRAG","DRAGCELL3",True)
  End If
  cont.EnableDragDropZone("DRAG","DRAGCELL4",True) ' for the sidebar
     
  Dim card As ABMCard
  card.InitializeAsCard(page, "card", "MY CARD", Title, ABM.CARD_SMALL, "")
  card.Image = image
  card.AddAction("Press me")
   
  ' add the card to the page
  cont.Cell(1,1).AddComponent(card)
  Return cont
End Sub

5. There are three events you will receive (all on Page level):
B4X:
Sub Page_DragStart(component As String, source As String)
  Log("Drag start: " & component)
End Sub

Sub Page_DragCancelled(component As String, source As String)
  Log("Drag cancelled: " & component)
End Sub

' there are four parameters: component, source , target, before
Sub Page_Dropped(Params As Map)
  Log("Dropped: " & Params.Get("component"))
End Sub

And this is basically it! Very simple without having to write any HTML, CSS, PHP or Javascript ;)

I'm finishing up ABMaterial 3.50, ABMonitor and ABTreeTableView now and early next week I think I may be able to release it to the donators.

Cheers,

Alain
 

Cableguy

Expert
Licensed User
Longtime User
I just love the new features!
Question, what happens if a cell contains more than one container, and both are dragable? That both move or just the one selected? Are they dragable also within the same cell?
 
Last edited:

Cableguy

Expert
Licensed User
Longtime User
Yes. In the demo each 'COLUMN' is one cell. e.g. in COLUMN 1, it contains three ABMcontainers in one cell. All are draggable, so you can drag/drop (re-order) ABMContainers within the same cell.
Very very nice!

I have one last question... Will there be some "remember my last placement" mechanism?
Like, the user rearranges the page as he feels like, can we save the layout?
 

alwaysbusy

Expert
Licensed User
Longtime User
No, at least not automatically. You will have to keep track of this yourself (as you get the page_dropped event, you get from where it came, where it was dropped and in case it was dropped 'before' another component in the cell, also that component. )

There are other methods you can also use (like I use in de log in the demo that can be helpful like page.GetAllDragDropComponentsFromGroupZone("DRAG", "DRAGCELL1") which gives a list of all the components currently in the given cell. You can use this to save it in a database or so.)

B4X:
' just to get some nice names
   Dim m As Map
   m.Initialize
   m.Put("r3c1", "COLUMN 1")
   m.Put("r3c2", "COLUMN 2")
   m.Put("r3c3", "COLUMN 3")
 
   If m.Get(Params.Get("source")) <> Null Then ' is it one of the 'basic' cards?
     If Params.Get("before") = "" Then
       Log("'" & Params.Get("component") & "' moved from " & m.Get(Params.Get("source")) & " to " & m.Get(Params.Get("target")))
     Else
       Log("'" & Params.Get("component") & "' moved from " & m.Get(Params.Get("source")) & " to " & m.Get(Params.Get("target")) & " before component " & Params.Get("before"))
     End If
   
     Log("Current position of the Cards (note the order too):")
   
     ' for each dropzone in our group, lets show what is in them now
     For i = 1 To 3
       Log("COLUMN " & i & ":")
       Dim col As List = page.GetAllDragDropComponentsFromGroupZone("DRAG", "DRAGCELL" & i)
       For j = 0 To col.Size - 1
         Dim comp As ABMComponent = col.Get(j)
         Log("  " & comp.ID)       
       Next
     Next
   
     ' you can keep getting your components just like always
     ' A new property container.BelongsToDropZone will give you in which zone the container is currently
     Dim card1 As ABMContainer = page.Component("Cards1")
     Log("Card1 is now in " & card1.BelongsToDropZone)
     Log("------------------------------------------------------------")
   Else ' it is a more complex card, so lets check out the black box situation
     Log("'" & Params.Get("component") & "' moved from " & Params.Get("source") & " to " & Params.Get("target"))
   
     Log("Current position of the black boxes (note the order too):")
     Dim k As Int = 0
     ' for each of our complex containers
     For cardCounter = 6 To 9
       ' get them
       Dim card As ABMContainer = page.Component("Cards" & cardCounter)
       Log("Cards" & cardCounter & ":")     
       ' for each dropzone in our sub group, lets show what is in them now
       For i = 1 To 3
         Log("  COLUMN " & i & ":")
         Dim col As List =  page.GetAllDragDropComponentsFromGroupZone("DRAGSUB", "DRAGSUBCELL" & (i + k))
         For j = 0 To col.Size - 1
           Dim comp As ABMComponent = col.Get(j)
           Log("  " & comp.ID)         
         Next
       Next
       ' lets see if we can get sub container 6
       Dim blackbox As ABMContainer = card.Component("subcont6")
       If blackbox <> Null Then
         Log("Sub container 6 is now in " & blackbox.BelongsToDropZone)
       End If
       k = k + 3
     Next 
     Log("------------------------------------------------------------")
   End If
 
Top