B4J Question ABMaterial Canvas How-To.

techknight

Well-Known Member
Licensed User
Longtime User
Is there an AB material for dummies out there? I saw the examples website and it shows all the controls and features it has along with code, but its not really telling me on how everything works, or more importantly how to use anything. I just dont get it...

For example, something as easy as changing the background color of one of the cells to see where it shows up in the page? Nope no idea.

What about adding a scaled background image to the web page? Nope, not a clue....

any help would be appreciated.
 

Harris

Expert
Licensed User
Longtime User
"Maybe" us so called experts could put something together. We could use an open framework where we all could contribute to get a base Table of Contents laid down and then each contribute a section.
This is a big task since the scope is broad. The fundamentals of a "page" are relatively simple, but everything else can get confusing for the newbie.
However, once over the initial hump - it is all easy and the best thing for web apps.

For the moment, use the on-line demo as AB explains each topic - and what you need to know to start.

Thanks
 
Upvote 0

techknight

Well-Known Member
Licensed User
Longtime User
Thats what I have been using is the online demo, but I find it vague as there is not enough detail explaining every little tiny part, parameter, function, etc. I mean it needs to be written for the newbie newbie.
 
Upvote 0

techknight

Well-Known Member
Licensed User
Longtime User
Thats a nice resource, considering thats how I learned B4X to begin with . ;-)

But I noticed it isnt up to date, as I see an ABM.ABMColorToHex which isn't listed in there. I am slowly starting to figure everything out, but its things as simple as trying to change a Label's font properties like bold, italics, even point size. I know there is H1, H2, H3, etc. But if I make the text "FlowText" then it gets way smaller than my liking and I cant make it bold or anything.

You know, the little things.

I cant blame the author because programmers usually don't make good documentation/manual writers. I know as I fall into that category. LOL.
 
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
Most of the formatting is done by Themes in ABMaterial (this is like the CSS). Some things cannot be changed (like for example the font size you mention). This is because it uses the Google Material Design Guidelines and they specify the sizes.

A lot can be overruled by using the formatting {} tags in ABM. Almost all "text" properties in ABM can use these special formatting tags:

B4X:
{B} and {/B} Bold
{I} and {/I} Italic
{U} and {/U} Underlined
{SUB} and {/SUB} Subscript
{SUP} and {/SUP} Superscript
{BR} Line Break
{NBSP} Non breakable space
{AL}{AT}{/AL} Hyperlink e.g. {AL}http://alwaysbusyscorner.com{AT}Alwaysbusy's Corner{/AL}
{CODE}{/CODE}: creates a simple code box (no syntax highlighting). {CODE} tags do not play well with ABM.SIZE_PARAGRAPH!
{ST:xxxx}{/ST}: Very powerful tag where you can use about any style code. Caution: this is a heavy tag, as it writes inline styling span tags. It is always faster to use the default ABMaterial themes, but in some cases this can come in handy to make a special formatting. Good knowledge of styling is required.
{WBR} tags allows one to have content side-by-side then wrap when the browser window shrinks.
{C:#ff0000} and {/C} color in RGB format
{IC:#ff0000}3d_rotation{/IC} will insert a red 3d_rotation icon in the text

Some example usages can be found in the Demo source code.
 
Upvote 0

techknight

Well-Known Member
Licensed User
Longtime User
to know where the cell is:
page.ShowGridInfo
in sub BuildPage()

Ah see that answers my question.

But, now I have a new one! Is it possible to put more than 1 control/object in a cell? For example I want 2 lables, center aligned but need them top and bottom from one another. For the sake of argument, I attempted this, but it put them side-by-side which I didn't want. Almost need a <br> in between somehow.

Sure I could put each label in top/bottom cells, but then the margins? I need the two labels super close to one another, but only on top/bottom. I dont want a large gap.
 
Upvote 0

Cableguy

Expert
Licensed User
Longtime User
then you need to set the cells padding so that it auto "wraps" the tables putting them one on top of the other, or add 2 containers to the cell and put each table in its own container
 
Upvote 0

techknight

Well-Known Member
Licensed User
Longtime User
Basically, I am trying to do THIS: (screenshot below) I understand it might not look "exactly" the same, but I need to get it close. This is a basketball app, but I am trying to make a baseball app. But you get the idea.

But its proving highly difficult without the "drag and drop" WYSIWYG stuff. Also, it needs to scale and fit the browser window no matter the size, and whether is drug around.

Same type of way I scale this to multiple devices: (I posted this so you get an idea what I am attempting to do.
 
Last edited:
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
Also, it needs to scale and fit the browser window no matter the size
That is something ABM will definitely NOT do! ABMaterial is a responsive framework, and responsive frameworks do not scale, they reorganize stuff to improve the users experience, depending on the device (phone, tablet or desktop). That is the whole purpose of ABM and the 12-grid system.

I think you may be better of using an ABMCanvas and 'draw' everything on it.
 
Upvote 0

techknight

Well-Known Member
Licensed User
Longtime User
Alright, then I can probably work around that limitation.

But what about Buttons? like command buttons. I noticed you have small, medium, large, but is it possible to change the width/height of these buttons? Like the image above, make them more square, or more elongated?

Sorry if my desires or questions are coming off offensive in any way, I mean no disrespect.

I was hoping this framework would work out, and it still may, but I have almost zero knowledge of HTML, CSS, and some knowledge of PHP/MySQL. Maybe I am treading uncharted territory by making an "app like" interface run in the browser, but control hardware on the other end.
 
Last edited:
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
Sorry if my desires or questions are coming off offensive in any way
Not at all! It is just that the 'Material' in ABMaterial is not by accident. It is because it (tries) to follow the Google Material Design Guidelines (see https://material.io/guidelines/components/buttons.html# for example) as close as possible. Which does also mean indeed buttons look a certain way (width, height, font, corner radius, etc).

In your case I really think you should look into ABMCanvas (http://prd.one-two.com:51042/demo/CompCanvasPage/abmaterial-canvas.html). It does scale depending of the browsers window size + you could use ABMCanvasObjects to create all you buttons etc (maybe even use some of the graphics you already have in your native apps?).

Here is for example someone who used the canvas to create his solar panel web app https://www.b4x.com/android/forum/threads/solar-eclipse.83324/#content with all kind of cool animations, pushable objects etc.

We (at my dayjob) use ABM all the time to control hardware (in our case barcode scanners). It is one of the main reasons I wrote ABM to create a UI for all platforms using a browser, and use the power of B4J to do all the IoT stuff.

I do know at first ABM may be overwhelming, but given some time, I'm sure you will be able to build what you have in mind! And zero knowledge of all the html/css/php stuff is not an issue. In theory, that is exactly the amount you should need to build ABM WebApps :)
 
Upvote 0

techknight

Well-Known Member
Licensed User
Longtime User
Luckily I know enough PHP to get myself into trouble, and I mostly use it on the back-end of things such as maintaning activation data, logins, etc. But the last time I took a class in PHP Was in 2004. Now PHP has two different syntaxes. Procedural which is the one I am used to, and object oriented which looking at that code and how it works makes my head spin. Kinda like .NET did from VB6.

But I digress. As far as a canvas control, that may work fine. I have to look into it and see, but my worry is the amount of math needed for it to work as I have a very weak math background, so it may be mathematically above my head. I remember looking into OpenGL years ago and soon as I saw some example code, I ran away... Fast...

But what I am looking to do is basically take the device out of the loop. I want to have scorekeeping done in the browser, while its electronically connected to the static LED scoreboard, or a video board. I have already filed a patent on that idea a couple years back and currently hold the provisional. Hopefully its something that goes viral in the scoring industry.

I have been doing App controlled scoreboards (with B4A) and built a company on it since roughly early 2012. It works great and people love it, however its incredibly device specific. Certain tablets work and a bunch of them dont. Why? Bluetooth hardware performance. the early Samsung devices had good bluetooth hardware that didnt stutter, and maintain connection. That all changed with the Tab A line. its pure crap now. And the cheap tablets wont maintain the connection, and it skips around and gets worse if the WiFi is on. Never used to do that. Plus this all relies on Bluetooth 2.0 Class 1 SPP technology, which is fading away slowly as more and more long range high power bluetooth devices become EOL. And where does this put iOS? well basically unsupported as it never had bluetooth SPP out of the gate. Our packets are too fast and too long to be compatible with Bluetooth BLE, especially with 100mS clocks, thats 100mS per packet. turned alot of customers away as they are "Apple Only" which drives me nuts, but oh well.

This is why I need to move onto this idea. Currently I am going to test it on the Raspberry Pi, but in its final phases it will be on proprietary hardware which will be integrated into the scoreboard driver PCB.
 
Last edited:
Upvote 0

aidymp

Well-Known Member
Licensed User
Longtime User
I don't know if I have asked this before, but a 1 page demo, with some of the core functions, and lots and lots of comments! would be great!!

The Sample app is HUGE! and covers everything! and the template app is a bit smaller than HUGE but does nothing!

So for me, a couple of demos, with a few controls, would help us mortals get the idea of how its working! ideally one that has a login area, and can update or display database content would be great! ;)

Thanks

Aidy
 
Upvote 0

techknight

Well-Known Member
Licensed User
Longtime User
Well his code contains the ABMFeedback which is just that. a database, with a login. At least thats what it looked like when I saw it. However, I think you may have to donate to get it.

I will say this, after looking at it and playing with it, the code is pretty complicated. After staring at it, and trying to follow it, I am slowly starting to understand the layout and how everything works.

the programs, even blank programs are "huge" because it has to run an HTTP server, and then generate the CSS/HTML code for each page fetch, and its the BASIC code that runs to generate all of that.

if ABMaterial was its own compiler/product line then alot of that would be "hidden" in the compiler
 
Last edited:
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
However, I think you may have to donate to get it.
No, everything is available for everyone.

@techknight I have been playing a bit with how you could build your Score Board app.

It is a 'very' quick test, but it should show it could be possible with an ABMCanvas.

http://prd.one-two.com:59999/sports

Things that do work/don't work yet:
1. the special 'number' Font is not loaded on the first run (known browser limitation, but there are solution out there that I could implement in ABM)
2. No correct live resize scalling. Works if you resize the browser + F5. But in your case, your 'screens' are a fixed size so no live resize needed anyway I think.
3. You can use the start/stop click button and the HOME score plus/min. Values should change.

How it works:
I 'cleaned-up' your picture so the changeable text from HOME, the timer and the Start/Stop button was removed

appimage.jpg


I created from you picture a 'click map' picture. So every time one clicks on the 'real picture' the x,y position is send to the server and performed on the 'click map' picture. That way we know very fast on which button the user clicked:

appimageclick.png


Every 'button' got its own unique color. Check out the below myCanvas_CanvasUp() method to see how it is used.

Relevant source code (if you're interested I'll forsee some time this week to make a real project you can then download).

B4X:
Sub Class_Globals 

   ' your own variables   
   Dim MyClickPic(0,0) As Int
   Dim HomeScore As Int
   Dim GameTimer As Timer   
   Dim GameStart As Long
End Sub

B4X:
public Sub BuildTheme()
   ' start with the base theme defined in ABMShared
   theme.Initialize("pagetheme")
   theme.AddABMTheme(ABMShared.MyTheme)
 
   theme.Page.BackColor = ABM.COLOR_BLACK
 
   ' a cell theme to center
   theme.AddCellTheme("blackcenter")
   theme.Cell("blackcenter").BackColor = ABM.COLOR_BLACK
   theme.Cell("blackcenter").VerticalAlign = True
   theme.Cell("blackcenter").Align = ABM.CELL_ALIGN_CENTER
End Sub

public Sub BuildPage()
   ' initialize the theme
   BuildTheme
 
   ' initialize this page using our theme
   page.InitializeWithTheme(Name, "/ws/" & ABMShared.AppName & "/" & Name, False, ABMShared.SessionMaxInactiveIntervalSeconds, theme)
   page.ShowLoader=True
   page.PageHTMLName = "index.html"
   page.PageTitle = "Template"
   page.PageDescription = "Template"
   page.PageKeywords = ""
   page.PageSiteMapPriority = ""
   page.PageSiteMapFrequency = ABM.SITEMAP_FREQ_YEARLY
 
   page.AddExtraCSSFile("custom/scoreboard.css") ' <------------- see below

   page.AddCanvasImage("background", "../images/appimage.png")  '<----- we have to preload images we are going to use in an ABMCanvas
       
   ' create the page grid, we only need 1 row with one cell
   page.AddRowsM(1,False,0,0, "").AddCellsOSMP(1,0,0,0,12,12,12,0,0,0,0,"blackcenter")
   page.BuildGrid 'IMPORTANT once you loaded the complete grid AND before you start adding components
   
End Sub

Source code for custom/scoreboard.css
B4X:
@font-face {
  font-family: "SFDigitalReadout";
  src: url("../../font/scoreboard/SFDigitalReadout-Heavy.ttf") format("truetype");
}
And the font I used can be downloaded here: http://gorgeousapps.com/SFDigitalReadout-Heavy.ttf
Put the font in the folder /font/scoreboard/

B4X:
public Sub ConnectPage()
   ' see below for the native Java code function loadPixelsFromImage
   Dim NativeMe As JavaObject = Me
   MyClickPic = NativeMe.RunMethod("loadPixelsFromImage", Array(File.Combine(File.DirApp, "appimageclick.png")))
 
   ' we create our canvas
   Dim myCanvas As ABMCanvas
   myCanvas.Initialize(page, "myCanvas", ABM.COLOR_BLACK, "", 1280, 800, True)
   page.Cell(1,1).AddComponent(myCanvas)
 
   ' set the fixed height 1px from the bottom to make it 'full window'
   page.Row(1).SetFixedHeightFromBottom(1,False)
 
   ' add the background from our loaded image in BuildPage() AddCanvasImage
   Dim bg As ABMCanvasObject
   bg.InitializeAsRectangle(page, "bg",0,0,1024,569,False)
   bg.drawImage("background", 0,0)
   myCanvas.AddObject(bg)
 
    ' the 'labels' that we need on the canvas
   Dim HomeLabel As ABMCanvasObject
   ' the +(225/2) etc is to determine the center position
   HomeLabel.InitializeAsRectangle(page, "HomeLabel", 15+(225/2),200+(100/2), 225, 100, False)
   DrawLabel(HomeLabel, "SFDigitalReadout", 130, "#ADFF2F", "00")
   myCanvas.AddObject(HomeLabel)
 
   Dim TimerLabel As ABMCanvasObject
   TimerLabel.InitializeAsRectangle(page, "TimerLabel", 440+(400/2),90+(90/2), 400, 90, False)
   DrawLabel(TimerLabel, "SFDigitalReadout", 130, "#ADFF2F", "00:00:00")
   myCanvas.AddObject(TimerLabel)
 
   Dim StartStopLabel As ABMCanvasObject
   StartStopLabel.InitializeAsRectangle(page, "StartStopLabel", 450+(380/2),200+(70/2), 390, 70, False)
   DrawLabel(StartStopLabel, "arial", 40, "#000000", "Start Clock")
   myCanvas.AddObject(StartStopLabel)
 
   ' important
   myCanvas.Refresh
 
   ' refresh the page
   page.Refresh
 
   ' Tell the browser we finished loading
   page.FinishedLoading
   ' restoring the navigation bar position
   page.RestoreNavigationBarPosition   
End Sub
#end region

' helper method to draw the ABMCanvasObject
Sub DrawLabel(LabelObject As ABMCanvasObject, Font As String, Size As Int, Color As String, Text As String)
   LabelObject.Clear
   LabelObject.font(Font, Size)
   LabelObject.textBaseline(ABM.CANVAS_TEXTBASELINE_MIDDLE)
   LabelObject.textAlign(ABM.CANVAS_TEXTALIGN_CENTER)
   LabelObject.fillStyleColor(Color)
   LabelObject.fillText(Text, 0, 0)
End Sub

' Here we map the real clicked position with the position on our 'Click map'
Sub myCanvas_CanvasUp(x As Int, y As Int)
   Dim myCanvas As ABMCanvas = page.Component("myCanvas")
   Log(x & " " & y & ":" & MyClickPic(x,y))
   Select Case MyClickPic(x,y)
       Case -65281
           Log("home up")
           HomeScore = HomeScore + 1
           Dim HomeScoreStr As String = HomeScore
           If HomeScoreStr.Length = 1 Then HomeScoreStr = "0" & HomeScoreStr
           Dim HomeLabel As ABMCanvasObject = myCanvas.GetObject("HomeLabel")
           DrawLabel(HomeLabel, "SFDigitalReadout", 130, "#ADFF2F", HomeScoreStr)               
           HomeLabel.Refresh
       Case -1.6776961E7
           Log("home down")
           HomeScore = HomeScore - 1
           Dim HomeScoreStr As String = HomeScore
           If HomeScoreStr.Length = 1 Then HomeScoreStr = "0" & HomeScoreStr
           Dim HomeLabel As ABMCanvasObject = myCanvas.GetObject("HomeLabel")
           DrawLabel(HomeLabel, "SFDigitalReadout", 130, "#ADFF2F", HomeScoreStr)
           HomeLabel.Refresh
       Case -16711681
           Dim StartStopLabel As ABMCanvasObject = myCanvas.GetObject("StartStopLabel")
           If GameStart > 0 Then
               GameTimer.Enabled = False
               GameStart = 0           
               DrawLabel(StartStopLabel, "arial", 40, "#000000", "Start Clock")
           Else
               GameTimer.Initialize("GameTimer", 1000)
               GameTimer.Enabled = True
               GameStart = DateTime.Now
               DrawLabel(StartStopLabel, "arial", 40, "#000000", "Stop Clock")
           End If
           StartStopLabel.Refresh
   End Select
   myCanvas.Refresh
End Sub

Sub GameTimer_Tick
   Dim GameNow As Long  = DateTime.Now
   Dim GameTime As String
   Dim p As Period = DateUtils.PeriodBetween(GameStart, GameNow)
 
   If p.Hours > 9 Then
       GameTime = p.Hours & ":"
   Else
       GameTime = "0" & p.Hours & ":"
   End If
   If p.Minutes > 9 Then
       GameTime = GameTime & p.Minutes & ":"
   Else
       GameTime = GameTime & "0" & p.minutes & ":"
   End If
   If p.Seconds > 9 Then
       GameTime = GameTime & p.seconds
   Else
       GameTime = GameTime & "0" & p.seconds
   End If
 
   Dim myCanvas As ABMCanvas = page.Component("myCanvas")
   Dim TimerLabel As ABMCanvasObject = myCanvas.GetObject("TimerLabel")
   DrawLabel(TimerLabel, "SFDigitalReadout", 130, "#ADFF2F", GameTime)
   TimerLabel.Refresh
   myCanvas.Refresh
End Sub

Here we need some inline java to load our 'MyClickPic' because B4J does not have such a method for NON-UI apps (I think).
B4X:
#if java
   import java.awt.Color;
   import java.awt.image.BufferedImage;
   import java.io.File;
   import java.io.IOException;
   import javax.imageio.ImageIO;
 
   public static int[][] loadPixelsFromImage(String filePath) throws IOException {
       File file = new File(filePath);
        BufferedImage image = ImageIO.read(file);
        int[][] colors = new int[image.getWidth()][image.getHeight()];

        for (int x = 0; x < image.getWidth(); x++) {
            for (int y = 0; y < image.getHeight(); y++) {
                colors[x][y] = image.getRGB(x, y);
            }
        }
        return colors;
    }
#End If
 
Last edited:
Upvote 0

techknight

Well-Known Member
Licensed User
Longtime User
ok this helps me out a ton. I can pretty much pick it up from here. The only thing that isnt really clicking in my head is the "click picture" with all the different colors. I dont see how its playing in the code?

I Still need to create a session lock to prevent others from controlling it while someone is using it, and I also need to do something with possibly adding a settings menu. But the icons at the top of my image, are actually part of an android app. The power LED goes Red or Green based on if there is an active connection to the scoreboard.
 
Last edited:
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
The only thing that isnt really clicking in my head is the "click picture" with all the different colors. I dont see how its playing in the code?
This is the key, so I'll elaborate a bit

1. User clicks on position {x = 100, y = 100}
2. {x = 100, y = 100} is send to the server
3. we check what color in the 'click picture' is under {x = 100, y = 100}

IF it is black, then nothing has to be done
IF it is a color, depending on what color, we know on what button the user has clicked

I've outlined this method a long time ago for another programming language on my blog, but it still may be an intersting read: https://alwaysbusycorner.com/2011/09/22/detecting-pixel-precise-clicktouch-in-irregular-shapes/

InitializeAsRectangle
An ABMCanvasObject can be compared (somewhat) with a panel in B4A. But it can be initialized as a Rectangle, or as a Circle shape. This 'shape' is only important for collision detection of drag/drop. So in most cases, InitializeAsRectangle will do the trick.
 
Upvote 0
Top