A tiny UI macro for injecting ui items declared in a xml file into a haxe class. Inspired by stablexui. Use with OpenFL
Branch: master
Clone or download



A tiny UI macro for injecting ui items declared in a xml file into a haxe class



  1. Tiny. Only one @:build macro file
  2. Cross platform
  3. Very simple: Only translate UI declared in xml into haxe code. Not use Reflect
  4. Transparent accessing code-from-ui & ui-from-code
  5. Very powerful - see example
  6. Very stable
  • because its so simple (only translate xml view into simple haxe code)
  • tinyui is used in several games (web, ios, android) that are played by millions users at http://sandinh.com


haxelib install tinyui


  1. The macro building class src/UI18All.hx

    //all things in-scope is accessible in xml, include static extension methods
    using com.sandinh.ui.BitmapTools;
    using com.sandinh.TipTools;
    using layout.LayoutUtils;
    class UI18All extends Sprite {
        public function new() {
            //initUI is generated by TinyUI
            initUI(10, 20);
        //those method is called from xml
        function simpleMethod(msg: String){
            //myFmt, uiMode, UI_m2 is generated by TinyUI
            trace(msg + this.myFmt.bold);
            this.uiMode = UI_m2;
        function myMethod(i1: Int, msg: String){ }
        function complexMethod(i1: Int, tf: TextFormat, i2: Int){ }
        function methodCreateSprite(): Sprite {
            return new Sprite();
  2. UI is declared in an xml file ui/18-all.xml

    <UI function="foo:Int, baz:Int"
        x="foo + baz"
        simpleMethod="'message 1'">
        <!--You declare UI in a xml file, then `inject` into a haxe class by macro meta:
            The injected class is call the `building class` or `view class`.
            Object of this class is called `view object` -->
        <!--`code` in xml can interact with code in .hx and vise versa
            TinyUI is JUST a macro tool translating xml into haxe code!-->
        <!--See the generated code at http://tinyui.sandinh.com -->
        <!--Use case 0. customize the arguments of initUI method.
            Sometime you need customize the UI by passing argument to initUI method.
                all expression (value of xml attribute) in the UI xml file is just plain haxe code,
                that code can reference to the arguments of initUI method.
            Syntax: set the optional attribute `function` of the root node in UI file (see above) -->
        <!--Use case 1. Create local var in initUI method.
            Use to Declare a temp value that can be referenced later in this UI xml file
                + node name in format: `var.` + <ClassName>
                + Must have 'var' attribute -->
        <var.TextFormat var="tmpFmt" bold="true"/>
        <!--Use case 2: Create a field in view class.
            Similar to local var above.
            But you need access this field in haxe code (in view class or in other class)
                + node name in format: `var.` + <class-name>
                + Must have 'var.field' attribute -->
        <var.TextFormat var.field="myFmt" bold="false"/>
        <!--Use case 3: Set properties or call methods of an object (maybe view object or other object)
            a. (for simple prop/method)
            + use attributes of the node correspond to the object
                see attr `x`, `simpleMethod` of root node -->
            + or attributes of 'this' child node of the node correspond to the object:-->
        <this y="3" simpleMethod="'message 2'" myMethod="1, 'msg1'"/>
            b. (for complex prop/method)
            + node name in format: `this.` + <prop/method name>-->
        <this.myFmt color="0xFF0000" align="CENTER" />
        <!--    note: attribute names is not important, only the order of attributes is -->
        <this.myMethod i="2" msg="'msg2'" />
        <!--    note: you can use child node of `method call node` for complex arguments -->
        <this.complexMethod i1="1">
            <TextFormat size="22" align="RIGHT" />
            <this i2="2" />
        <!--    note:
                + you can access prop/method of every object, not only the view object.
                + you can access static extension method using the same syntax-->
        <var.Bitmap var="myBmp" x="5">
            <!--`src` is the extension method that bring to scope by:
                `using com.sandinh.ui.BitmapTools;` -->
            <this src="'img/sd.jpg'" />
        <!--    note: you can access nested prop/method -->
        <Shape graphics.lineStyle="2, 0xFF0000">
            <this.graphics.drawCircle x="10" y="10" radius="5" />
        <!--Use case 4: Declare view items (the display object need to be added to view object)
            + node name is the class name of the view item
             (need be imported in the .hx building class, or the full fqdn class name - include package path)
            + you can use attribute `var` / `var.field` to declare variable for this view item. see usecase 1, 2 -->
        <TextField var.field="myTxt" x="100" defaultTextFormat="tmpFmt" text="'my text'">
            <!--see usecase 3.b-->
                <TextFormat font="'Tahoma'" size="13" />
                <this beginIndex="3" endIndex="5" />
            <!--see usecase 3.a-->
            <this appendText="' appended'" />
        <!--Use case 5: Nested view items-->
        <Sprite var="mySpr" x="200">
            <TextField text="'nested text'"/>
        <!--Use case 6: new expression.
            Sometime you need an expression that return the object instead of let tinyui create one.
            Syntax: use attribute `new` with value is the haxe expression -->
        <var.Int var="padding" new="3+4" />
        <Sprite new="methodCreateSprite()" x="padding">
            <Bitmap new="myBmp" />
        <!--Use case 7: Modes.
            The UI view can have several modes with different look.
                1. add a direct child node named `case`-->
            <!--2. each mode is a child node.
                Name of mode node is used to generate a static var for the view class:
                `public static inline var UI_<name>: Int = <auto-inc-value-start-at-0>`
                Here is: `public static inline var UI_m1: Int = 0`-->
            <!--You can set the mode for a view object `someView` by:
                `someView.uiMode = SomeView.UI_<the-mode-name>` -->
            <!--if a mode has `default="true"` then at the end of initUI method,
                tinyui will place a statement:
                `this.uiMode = UI_<the-mode-name>` -->
            <m1 default="true">
                <!--You customize the view in a mode by
                    + customize view object instance: -->
                <this y="100" />
                <!--+ or customize view items:
                    Syntax: node name <var-name> -->
                <myTxt y="20">
                    <this.setTextFormat fmt="tmpFmt" beginIndex="6" />
                <!--you can customize multiple view item in one xml node:
                    + node name is: `in`
                    + must have attribute `var` with value is comma-separated-var-names. -->
                <in var="myTxt,mySpr" mouseEnabled="false" />
                <this y="200" />
                <myTxt y="40" setTextFormat="myFmt, 6" />
                <in var="myTxt,mySpr" mouseEnabled="true" />
        <!--Use case 8: Styles
                1. add a direct child node named `class`-->
        <!--    you can import a style file into this view by set `import` attribute for `class` node-->
        <class import="ui/styles.xml">
            <!--2. each style has a name specified by the name of the style xml node-->
            <fmt2 selectable="false">
                <this.defaultTextFormat color="0x00ff00" bold="true" />
            <!--A style can extends other styles.
                    here, style fmt1 is imported from 'ui/styles.xml'.
                TinyUI can auto-resolve conflict.
                    here, fmt3.defaultTextFormat will be taken from fmt1 (not from fmt2)-->
            <fmt3 extends="fmt1,fmt2" />
        <!--    3. set style for view item (or other object) by add `class` attribute -->
        <TextField class="fmt1" text="'Text 1'" />
        <TextField text="'Text 2'">
            <this class="fmt2"/>
        <!--backgroundColor will be override here with a warning when compile -->
        <TextField class="fmt3" text="'Text 3'" backgroundColor="0x0000FF" />
        <!--Use case 9: for loop-->
        <for i="1...4">
            <TextField y="i * 25">
                <this.defaultTextFormat color="0xFF0000" />
                <this text="'some text'" />
        <!--Use case 10+: Layout, tooltip, and other.
            TinyUI is very powerful and extensible. With the core feature here
            , we can solve other usecases like below: -->
        <!--a. Tooltip using openfl-tooltip haxelib.
            Note: `tooltip` is an extension method from com.sandinh.TipTools class -->
        <TextField text="'the target'" border="true" borderColor="0xFF0000"
                      tooltip="'An floating tooltip'"/>
        <!--b. Layout using advanced-layout haxelib-->
        <Bitmap var="bmp1" src="'img/sd.jpg'" />
        <!--Note: `alignRight`, `alignBottom`, `rightOf`, `below`, `alignWith` methods
            is extension method from layout.LayoutUtils class -->
        <Bitmap bitmapData="bmp1.bitmapData"
                alignRight="" alignBottom="15" />
        <TextField var="txt1" defaultTextFormat="tmpFmt" text="'TinyUI &amp; Layout!'"
                   width="200" height="33"
                   rightOf="bmp1, padding" />
        <TextField defaultTextFormat="tmpFmt" text="'Hi Layout2!'" width="200"
                      below="txt1" alignWith="txt1,LEFT" />
        <!--TinyUI is stable & be used in several games (web, ios, android)
                that are played by millions users at http://sandinh.com
            See the generated code of this UI and other examples at http://tinyui.sandinh.com for more detail-->
  3. you can also define a class by ONLY the xml file. see file example/ui-src/com/sandinh/XmlOnlyView.xml

  4. (optional) save generated code

    <haxeflag name="--macro" value="TinyUI.init('ui-codegen')"/>
  5. you can use the generated code (bypass the whole tinyui macro building) by set tinyui-use-gen-code flag:

    <!--uncomment to bypass TinyUI.build & using the generated code-->
    <haxeflag name="-D tinyui-use-gen-code"/>
  6. see example


see CHANGES.md


This software is licensed under the MIT license.

Copyright 2015 Sân Đình (http://sandinh.com)