Share My Creation MakeBxL - create a layout file from text or from an SQLite table (B4X) (Tool) (Source included)

I wanted a quick way to generate a layout file (add the views and their names and events) to then fine-tune it with the Designer - MakeBxL does that, either from
- a list of names (for the views) that you add in its TextArea, or
- from an SQLite database table
Some additional options are available - see the screenshots below.

All basic views for B4A, B4I, and B4J are included in the project. To extract custom views from layout files, use the 'Extract custom view' RadioButton and then click the 'Select file' button to select the layout file, after which you can pick one from a list of views in that file. See post 11 for a how-to if you want/need to do that manually.

Hints:
- To make your own specific version of a view (with different properties like e.g. colours, text, ...) make a layout that contains it and then extract it as a custom view.
- After extracting custom views, you may want to give the extracted files more significant names. E.g., when extracting a Button, the produced files may have names like 'bjl.button1.hdr.json' and 'bjl.button1.json'. If you rename them, only replace the 'button1' part and make it identical for both files, e.g. 'bjl.BigRedButton.hdr.json' and 'bjl.BigRedButton.json'.

Screenshots and project attached, enjoy!

CHANGES:
- 2024-02-07 (v1.03):
* Added custom view extraction from layout files
* Corrected bug in 'CustomViews' directory processing when file names weren't all lowercase

- 2024-02-06 (v1.02):
* Added tests to avoid exceptions if definition files are missing
* Added custom views processing (in other words, 'Bring Your own Views'); see post 11 for a how-to
* Updated project attached

- 2024-02-05 (v1.01):
* B4I (.bil) processing added (thank you for the json file, @mcqueccu)
* A check was added for duplicate view names
* Updated project attached

- 2024-02-09 (v1.04):
* Enhanced custom view extraction as per @Mashiane's suggestions/request in post 13
* Custom view extraction now has an '<All>' option to extract all views from the selected layout file (so either select one view, or get all of them)
* Custom view extraction now makes sure each view has a distinct name (across the complete collection of standard views and custom views)
* The 'Restart' button now refreshes the lists of available views, no need to exit and restart the entire program
* Added column 'JSON' to the TableView, which shows the view's JSON as a TreeView (based on JsonTree: https://www.b4x.com/android/forum/t...ith-json-parsing-updated-as-23-4-2022.140068/)
* Used ComboBoxes instead of ChoiceBoxes for improved performance
* Bug fixes

- 2024-02-10 (v1.05):
* Bug fixes (thank you for pointing out the ChoiceBox/ComboBox issue, @Mariano Ismael Castro )

Start:

Start.png


SQLite-based:

SQLite1.png
SQLite2.png


SQLite3.png
SQLite4.png


SQLite9.png


Text-based:

Text1.png
Text2.png


Text3.png
Text4.png


Extraction:

Extract1.png
Extract2.png
 

Attachments

  • SQLite2.png
    SQLite2.png
    31.8 KB · Views: 390
  • Text1.png
    Text1.png
    13.2 KB · Views: 357
  • Text2.png
    Text2.png
    32.6 KB · Views: 363
  • Start.png
    Start.png
    15.6 KB · Views: 239
  • MakeBxL.zip
    79.3 KB · Views: 185
Last edited:

walt61

Active Member
Licensed User
Longtime User
EDIT: this can now be handled by the program itself (as of v1.03).

How to add custom views (as of v1.02)

1. In the IDE, create a layout with the custom view.

2. Run BalConverter on the layout to produce the JSON file - for the sake of this post, let's call it 'layout.json'. (Any name will do)

3. Create two text files in subdirectory CustomViews of your DirApp directory. For example, for a bjl CustomListView combination these would be:
bjl.CustomListView.json
bjl.CustomListView.hdr.json
The filenames are case-insensitive. Upon completion, 'CustomListView' will appear in MakeBxL's 'type' ChoiceBoxes.

4. Look for 'ControlsHeaders' in layout.json, and copy the relevant block to the bjl.CustomListView.hdr.json file. It will look like:
B4X:
{
    "JavaType": ".CustomViewWrapper",
    "DesignerType": "CustomView",
    "Name": "CustomListView1"
}

5. Replace the view's name with '$MAKEBXL_CHILD_NAME$' (this is case-sensitive) so that the file now looks like:
B4X:
{
    "JavaType": ".CustomViewWrapper",
    "DesignerType": "CustomView",
    "Name": "$MAKEBXL_CHILD_NAME$"
}

6. Look for 'Kids' in layout.json, and copy the relevant block to the bjl.CustomListView.json file. That block will look like (I've only left the relevant lines here):
B4X:
            "0": {
...
                "variant0": {
                    "top": 100,
                    "left": 100,
                    "hanchor": 0,
                    "width": 100,
                    "vanchor": 0,
                    "height": 100
                },
...
                "eventName": "CustomListView1",
...
                "name": "CustomListView1",
...
                "font": {
                    "fontName": "DEFAULT",
                    "csType": "Dbasic.Designer.FontGrid",
                    "fontSize": {
                        "ValueType": 7,
                        "Value": 15
                    },
                    "bold": false,
                    "type": "B4IFontWrapper",
                    "italic": false
                }
            }

7. Replace the following values with these strings (again, case-sensitive):
- view number: $MAKEBXL_CHILD_NUM$
- view name: $MAKEBXL_CHILD_NAME$
- event name: $MAKEBXL_CHILD_NAME$
- font (or typeface) name: $MAKEBXL_FONTNAME$
- font (or typeface) size: $MAKEBXL_FONTSIZE$
- left, top, width, height: $MAKEBXL_LEFT$, $MAKEBXL_TOP$, $MAKEBXL_WIDTH$, $MAKEBXL_HEIGHT$
It will look like:
B4X:
            "$MAKEBXL_CHILD_NUM$": {
...
                "variant0": {
                    "top": $MAKEBXL_TOP$,
                    "left": $MAKEBXL_LEFT$,
                    "hanchor": 0,
                    "width": $MAKEBXL_WIDTH$,
                    "vanchor": 0,
                    "height": $MAKEBXL_HEIGHT$
                },
...
                "eventName": "$MAKEBXL_CHILD_NAME$",
...
                "name": "$MAKEBXL_CHILD_NAME$",
...
                "font": {
                    "fontName": "$MAKEBXL_FONTNAME$",
                    "csType": "Dbasic.Designer.FontGrid",
                    "fontSize": {
                        "ValueType": 7,
                        "Value": $MAKEBXL_FONTSIZE$
                    },
                    "bold": false,
                    "type": "B4IFontWrapper",
                    "italic": false
                }
            }

8. That's it. Restart MakeBxL and it will pick the new view(s) up from the CustomViews directory
 
Last edited:

Mashiane

Expert
Licensed User
Longtime User
Thank you so much.....

So I had a look at this and its amazing tool you have here. Thank you so much.

So Im playing around, here are some observations, if you dont mind. I mostly use custom views, so I will be a little biased towards that.

I like this...

1707333790633.png


The tricky part though is that on the created output and header files, everything is a "customview". A look at the generated json file with BalConvertor, I learned that the "child" > shortType key has the custom view name.

1707333962470.png


So, the I thought about having the shortType added where it exists..., so that we have the following "CustomView.[ActualCustomViewName]"

1707334704648.png


This is a tweak to SelectLayout.., by moving the "Dim Data..." up so that we can execute the FindKidCustomType call, so we can get the actual custom view name.

B4X:
'extract the data, so that if its a custom type, we get the 'shortType', i.e. real custom view type
    Dim Data As Map = layoutMap.Get("Data")
    Try
        lstViews.Initialize
        Dim LayoutHeader As Map = layoutMap.Get("LayoutHeader")
        Dim ControlsHeaders As List = LayoutHeader.Get("ControlsHeaders")
        For Each colControlsHeaders As Map In ControlsHeaders
            Dim Name As String = colControlsHeaders.Get("Name")
            If (Name = "Main") Or (Name = "Activity") Then Continue
            Dim DesignerType As String = colControlsHeaders.Get("DesignerType")
            'find the kid based on the control header name
            Dim theKidX As Map = FindKidCustomType(ext, Name, Data)
            'get the shortType i.e. the actual custom view name
            Dim sshortType As String = theKidX.GetDefault("shortType","")
            'if this is blank, use the usual addition
            If sshortType = "" Then
                lstViews.Add(Name & " (" & DesignerType & ")")
            Else
                'this has a short name, add the name
                lstViews.Add(Name & " (" & DesignerType & "." & sshortType &  ")")
            End If  
        Next
    Catch
        fx.Msgbox(MainForm, LastException, "Couldn't parse the layout file")
        Return
    End Try

A new method added to just return the kid

B4X:
'we need to find the custom type of the kid
'findKid replaces the original map
Private Sub FindKidCustomType(ext As String, selectedName As String, parent As Map) As Map
    Dim kids As Map = parent.Get(":kids")
    If kids.IsInitialized = False Then Return kids ' Parent doesn't have kids

    For Each kidKey As String In kids.Keys
        Dim onekid As Map = kids.Get(kidKey)
        If onekid.Get("name") = selectedName Then ' Got it
            Return onekid
        End If
        ' Kids can have grandkids etc
        Dim nextKid As Map = FindKidCustomType(ext, selectedName, onekid)
        If nextKid.IsInitialized And nextKid.Size > 0 Then Return nextKid
    Next

    ' This should not happen
    Dim noKid As Map
    Return noKid

End Sub

PS: Im not really sure whether the shortType can ever be blank, so I just worked on assumptions.. ;)

So the output without having to overwrite whatever is on the folder becomes..

1707336925176.png



Here is the update, I suffixed it with "_Mashy" so that there is no confusion with your original

Let me continue exploring...


Update: I see now. I am using an existing layout that has user defined names. I could just use custom layouts without changing the original IDE given name. Cool.

Actually, this is now even better...

1707337761076.png


So i created a couple of files... and added them to the project.

1707338308704.png


and whalla... this thing works beautifully!!! Wow. Im mind blown right now.

1707338366914.png



NB: The attached project does not ask you which custom view to process, it processes everything on the file.
 

Attachments

  • MakeBxL_Mashy.zip
    79.4 KB · Views: 116
Last edited:

walt61

Active Member
Licensed User
Longtime User
Thank you so much.....

So I had a look at this and its amazing tool you have here. Thank you so much.

So Im playing around, here are some observations, if you dont mind. I mostly use custom views, so I will be a little biased towards that.

...

Thanks for your tests, suggestions, and ground work @Mashiane , I'll implement that (and some more stuff I thought of) in the next version!
 

walt61

Active Member
Licensed User
Longtime User
Let me push my luck. ;)

Feature Request: Functionality for parent child relationship definition here, so that some components can be inside one another

Alas, that's one I'm going to give a pass. The objective was to be able to quickly (without having to select them from a menu and then changing the name etc in the Designer) put a bunch of elements into a layout, and then polish the layout in the Designer. As you did with the 'shortType' parameter, I had to make some assumptions based on what I found in the JSON generated from the layout files. Also, making the program more complicated would - in my opinion - increase the odds for errors (when Erel changes things to internal structures).
 

Magma

Expert
Licensed User
Longtime User
Great Work walt61 !

Also Mashiane, cool ideas !

* Until today didn't find the time to run it... but today (v1.03) tried to run it (b4j v10, jdk11) and freezing (debug and release)

Tested in OpenJDK11... or other needed ?
 

Magma

Expert
Licensed User
Longtime User
- OpenJDK 14.0
That's a difference... for now keeping openjdk 11 - because of projects... but i will try it for sure - later (thought was that)

but... then check at Images posted using Fonts... (and yes i am having a lot ~4000)

so removing this line... get fast into :)
'ChoiceBoxFont.Items.AddAll(fx.GetAllFontFamilies)
 
Top