TableLayout updates

scene2d.ui has been using TableLayout for a long time. TableLayout sizes and positions actors using a logical table, similar to HTML tables. The resulting layout does not (usually) use pixel coordinates, so it automatically adapts to different resolutions. It can also scale positions, sizes, padding, etc based on the screen density. It is an extremely convenient way to position UI widgets. If you are manually doing the math to calculate widget positions, TableLayout is highly suggested. Once you learn the API, you can use it for libgdx, Android, Swing, and TWL.

Beyond just layout using a table, one of the big ideas in TableLayout was a DSL (domain specific language) for describing UI widget hierarchies. Writing layouts in code is flat. It is difficult to see the hierarchy in complex layouts that have a lot of nesting. Describing layouts in XML is a huge pain, and JSON isn’t much better. The TableLayout DSL put a minimal amount of cruft around the important bits. In the beginning it only allowed layout, using the half dozen or so TableLayout constraints. Features were added to reduce the amount of Java code by allowing more to be described in the DSL. Eventually it could do object creation, set field and bean properties, and more. The DSL syntax was still relatively simple, but the extra features certainly didn’t help new users get started.

Unfortunately, it turns out that the usefulness of the DSL is limited. Very often with a complex UI, portions of it are dynamic. Eg, sections A, B, or C are optionally shown based on some state, or you have a table or other container that has items added by code. The DSL can describe the main structure and then code can fill in the rest, but this ends up being awkward. When a large portion of the UI is built by code, the DSL no longer makes sense for the minimal remaining structure. At this point you are back to the Java API and probably would have saved time if you started there.

As TableLayout got used for a few big apps, the Java API has started to look very similar to the DSL. It is still flat, but specifying constraints is quite concise by using a builder pattern. Constraints can be specified for all cells, all cells in a column, all cells in a row, or for an individual cell. This greatly reduces repeating yourself. Here’s a quick example:

Table table = new Table();
table.pad(10).defaults().spaceBottom(10);
table.row().fill().expandX();
table.add(button).fill(false);
table.add(buttonMulti);
table.add(imgButton);
table.add(imgToggleButton);
table.row();
table.add(checkBox);
table.add(slider).width(100).fillX().colspan(3).left();

With the recent scene2d updates, I thought it was time for a TableLayout refuctoring. The DSL has been removed, along with a TON of support code, leaving only the Java API. It’s a little sad because it was a lot of work and very powerful — it even had an editor for the DSL, with syntax highlight and realtime rendering of the layout. Ultimately though, I came to the conclusion the DSL isn’t the right way to go. Implementing the DSL positively affected the Java API in many ways, so not all is lost.

A few other TableLayout changes have been made. All the int values have been changed to float. Also, it no longer parses strings for constraints. Instead, there is a Value interface, which can be implemented to compute a value however you like. This is a lot more flexible and avoids allocation. Setting the logical table size is gone, it was rarely needed and confused people. The scaling property is gone, it is replaced with the flexibility offered by Value.

These changes only affect the libgdx scene2d-new branch. If you use TableLayout, this is your heads up about the changes! The branch will likely be merged into trunk in the next few days.

Edit: The TableLayout documentation is now up to date. It has been completely rewritten.

-Nate

  • mingming-killer

    Hi~~Nate. Glad to see you update TableLayout.

    The DSL whether it is like this:

    “w:100% h:100%

    * align:left

    [OptBtnBack]
    w:15% h:15%
    colspan:2


    [OptLabelMusic]
    w:15% h:15%
    paddingTop:10%
    paddingLeft:25%

    I have write a simple 2D game framework base on libgdx, which I think is more convenient to use.
    It’s can deploy Game Scene by JSON UI file, like layout xml of android and support string reference(mulit-language). The JSON UI file like this:

    {
    “namespace”: “com.badlogic.gdx.scenes.scene2d.ui.”,

    “actors”: [
    "label_music",
    {
    "class": "Label",
    "text": "Lang",
    "name": "OptLabelMusic"
    },

    "label_mix",
    {
    "class": "Label",
    "text": "Music",
    "name": "OptLabelMix"
    },

    "label_grid",
    {
    "class": "Label",
    "text": "Test",
    "name": "OptLabelGrid"
    },

    "toggle_music",
    {
    "class": "com.gaforce.killer7.ui.ToggleButton",
    "name": "OptToggleMusic"
    },

    "toggle_mix",
    {
    "class": "com.gaforce.killer7.ui.ToggleButton",
    "name": "OptToggleMix"
    },

    "toggle_grid",
    {
    "class": "com.gaforce.killer7.ui.ToggleButton",
    "name": "OptToggleGrid"
    },

    "btn_back",
    {
    "class": "com.gaforce.killer7.ui.ImageButton",
    "style": "image-back",
    "scaling": "fit",
    "align": 6,
    "name": "OptBtnBack"
    }
    ],

    “layout”: ”
    w:100% h:100%

    * align:left

    [OptBtnBack]
    w:15% h:15%
    colspan:2


    [OptLabelMusic]
    w:15% h:15%
    paddingTop:10%
    paddingLeft:25%

    [OptToggleMusic]
    w:30% h:15%
    paddingTop:10%
    paddingLeft:5%
    paddingRight:25%


    [OptLabelMix]
    w:15% h:15%
    paddingTop:5%
    paddingLeft:25%

    [OptToggleMix]
    w:30% h:15%
    paddingTop:5%
    paddingLeft:5%
    paddingRight:25%


    [OptLabelGrid]
    w:15% h:15%
    paddingTop:5%
    paddingLeft:25%

    [OptToggleGrid]
    w:30% h:15%
    paddingTop:5%
    paddingLeft:5%
    paddingRight:25%


    }

    It not only can use your said DSL editor, but also can use JSON online editor: http://www.jsoneditoronline.org/ (In fact I often use there powerful tools ^_^).

    I hope I can give you some reference. If you feel this idea is not bad, I hope you can merge it to libgdx ^_^. (The mainly class is com.gaforce.killer7.ui.SerializerFactory and com.gaforce.killer7.resource.StringValues).

    Here is my project: git clone git@bitbucket.org:mingming_killer/my-gdx.git

  • Nate

    Interesting stuff! The reason I removed the DSL from TableLayout was because I felt the loss of flexibility versus using code isn’t worth it. Also, the Java API has evolved to the point where it is similar to the DSL in verbosity.

    The JSON you posted looks like it creates widgets in the first portion, and then does TableLayout in the second. Prior to the removal of the DSL, you could use TableLayout for widget creation. Eg:

    [label_mix:Label] w:15% h:15% (text:Music)

    This creates a widget named label_mix that is of class Label and sets the bean property (or field) text to Music. Widgets of any class can be created and configured this way. There is no need to specify the widgets separately using JSON, you can do it all in TableLayout. You can also extend Toolkit to have special properties and other behavior. Eg, you could enable this syntax which would create a named label:

    [label_mix:"Music"] w:15% h:15%

    Or an unnamed label:

    “Music” w:15% h:15%

    You can have special properties, eg this could hook the property named “bg” to look up an image and set the background:

    [name:com.some.WidgetClass] size:100,200 (bg:someImageName)

    If you are interested in this, you can use the SVN history of TableLayout to make use of the code before the DSL was removed.

  • mingming

    Nate, thanks for your suggestion of DSL function. Your example is amazing. I had not yet realized that TableLayout have this way to use ^_^ . But I recommend keep the implementing of DSL. Because use layout file to deploy UI is quit convenient(like android xml layout). I think use code to layout is pain. And in fact as game UI is rarely use dynamic layout. And there is no cost to leave old code.

    Though I can use SVN history of TableLayout to use DSL, it’s more inconvenient. Maybe there have other people like layout file. Or could you find another way of file layout implementing ^_^ ??

  • Nate

    I also think the DSL is pretty cool, but ultimately I feel that the library will see more usage without it. The docs are simpler, so users can pick it up much easier. Also the code is smaller and simpler. I feel this way about all layout DSLs, not just TableLayout. Specifying a layout in a DSL is a clean and convenient way to describe the layout, but it is a lot less powerful when you need code to manipulate the layout. I think you would agree, once you have a large layout in the DSL and you have to port it all to Java code because you need the extra flexibility afforded there.

    You’re right that using a version from SVN history isn’t very good. I have made a branch called “v1″ that contains TableLayout before the DSL was removed:
    https://code.google.com/p/table-layout/source/browse/branches/v1

    I have also preserved the V1 documentation, so you can have an idea of how the DSL works:
    https://code.google.com/p/table-layout/wiki/V1Documentation

  • mingming

    I think maybe I can leave DSL implement out of libgdx, just like my simple custom framework. I will try to extends TableLayout to do it. It’s than a feasible way to keep DSL implement ?

    Because I want to use new version of libgdx, the new feature is good. But I really want to use file layout too ^_^ .

    Or maybe you can make TableLayout more easily to extends ^_^ .

    As for why I still use this version because I was work for some new game UI widget now. When it’s done, I will update the new libgdx version. Oh ~~ It’s look there is a great change ╮(╯▽╰)╭ .

  • Nate

    Probably you will need to have your own table class based on the old TableLayout with the DSL.

  • Jimmi Prajapati

    I agree with Nate

    Jimmi

    http://codebeautify.org