HaxeUI v1.3 Released!

Howdy!

Ive finally managed to get round to releasing haxeui v1.3 to haxelib. I cant believe its been 5 months since the 1.2.3 release! Time really does fly.

This release is a general release and although a massive amount of things have changed there isnt that much to go over (compared to previous releases at least). There are some big changes but alot of this release is refinement and bug fixing.

Breaking Changes

So there have been a number of breaking changes this release. Almost all of them revolve around issues identified where references to components were being brought in unnecessarily (which iI’ll go over in a little more detail later).

Dialog shortcuts moved

Prior to this release, you could show a custom dialog or a message box quite simply with one of these calls:

  • Toolkit.messageBox(...)
  • Toolkit.dialog(...)
  • Screen.instance.messageBox(...)
  • Screen.instance.dialog(...)

The problem with these calls being in such a fundamental part of haxeui is that if you werent using dialogs at all (which would certainly be quite common) then you were pulling in all the code and components for Dialog anyway.

These calls have now been moved to a Dialogs helper class (package: haxe.ui.containers.dialogs), eg:

Dialogs.messageBox(...)

The function signature is exactly the same, and by moving it to a separate, non “core” class it makes usage of dialogs (and therefore inclusion of its dependencies) much more explicit.

Note that “normal” custom dialog usage remains the same:

var myDialog = new MyDialog();
myDialog.show();

Toolkit.componentFromString

in a similar vein prior to this release it was possible to create a component from a string at runtime using Toolkit.componentFromString. To be honest, I seriously doubt this function is ever used to any great degree (though I do know of at least one project that does use it). Much like the dialog issue above this also brought in a number of dependencies unnecessarily - not a huge amount, but enough to warrant it to be refactored out. This call has now moved to haxe.ui.RuntimeComponentBuilder.fromString.

Another (non breaking) change is that components built at compile time can now use a differently named set of macros (these are really just aliases to make things simpler):

  • haxe.ui.ComponentBuilder.fromString(...)
  • haxe.ui.ComponentBuilder.fromFile(...)
  • haxe.ui.ComponentBuilder.build(...)

The previous macros are still available, but these are shorter, neater and “fit” with the new RuntimeComponentBuilder

Component aliasing removed

One of the major things that was identified in this release was how the haxeui component macros were bringing in a reference to every component when it scanned the class path and build up a “component class map”! I’ll get into the details a little more later, but suffice to say that you used to be able to define an alias for a component for use with xml in your module.xml:

<module>
    <components>
        <class name="foo.bar.MyComponent" alias="myfoo" />
    </componens>
</module>

This would mean you could use “mycomponent” or “myfoo” in your xml. This is no longer an option. The way that tags are resolved to classes has changed now, and aliasing is no longer simple or feasible. If you really want to use “myfoo” you could always just create a new class: class MyFoo extends MyComponent

haxeui-html5 no longer supports native components

The haxeui-html5 backed used to be able to use native components (where they were available - eg buttons, sliders, scrollers, etc). This functionality has been stripped now and a new backend has this functionality haxeui-html5-native - the reasoning for this is pretty much the same as all the above - this feature (rarely used i suspect) was bringing references to components and other bits of code that simply were not relevant for 99% of use cases. If you want a browser native UI, then you can use haxeui-html5-native as a drop in replacement that will allow this.

Thats it, as far as I remember, for the breaking changes. I really hope these wont cause too much friction upgrading but they were really quite important to get haxeui file sizes nice and trim, dependencies at a minimum and build speed as fast as possible.

Now thats out the way, some of the more interesting changes!

Removal of hscript!

HaxeUI always had a dependency on hscript. It used this for various things, but mainly it was for allowing code to run at runtime (usually inside <script> tags, but also for event handlers in xml and other things). This not only added a layer of complexity it also caused various DCE and runtime related problems (or potential problems at least).

This dependency has now been totally removed. If you use code in your xml files, or handlers, etc then, at compile time that “script” code is injected into your class (if you are using a custom xml component) or into you function (if you are using haxeui expression macros), this has a bunch of benefits and side effects.

The most obvious is that you will get compile time errors if your code doesnt make sense. Previously this would have been a runtime error.

Performance is better. This, to me, wasnt a big issue but its nice to have anyway. Since now your script code will be real haxe code it will have the same performance as the underlying haxe target you are using (it wont need to pass through an interpreter etc).

You can do “crazy” things now since your script code will essentially be injected into your class, eg:

<vbox>
    <script>
        private override function onReady() {
            super.onReady();
            trace("Im ready!");
        }
    </script>
</vbox>

Here the onReady function will be injected into the class as an override for a haxeui core function. If the “old” hscript method was being use this simply wouldnt be possible without some (overly complex) layer to call the appropriate script function when haxeui calls “onReady”.

Its probably worth noting that i 100% do not advocate things like this - its very ugly in my opinion and completely breaks separation of UI and logic. But its there, and ready to be abused should your wish to :smiley:

All in all the hscript removal was super essential. It had wormed its way into so many subsystems (language binding, component binding, even parts of the module resolution phase in the macros!) - All of these systems now work much better, much simpler and a whole bunch of code was deleted because of it. I can only hold my hand up a plead total laziness for letting it get into so many parts of haxeui!

ComponentClassMap populated on demand

Another massive oversight on my part was how haxeui was resolving xml node names → component classes. Previously it would scan the entire class path looking for Component derived classes and add them to a class map ready for lookup. This, upon reflection, was just such a dumb idea.

The biggest issue with it is that it used getType / getModule. I had no idea, but using these functions in a macro actually created a reference to that component. So this meant that every single component that was discovered by the macros (ie, all of them) had a reference created and was brought into the the final output. Needless to say, this was a little crazy!

Another issue with this method was that if you never used the xml / markup part of haxeui, well, you were still scanning the classpath, still building up a map of all components that would, essentially, never be used. So your build time would be longer for no reason what-so-ever.

Both of these issues have now been rectified. When haxeui builds a component from xml / markup and wants to find a classname based on a node name it then scans the classpath looking for matches (unless its already found one previously in which case it will just use that one). This has a number of improvements, namely the things mentioned above. References are not brought in for no reason, the entire class path isnt scanned (just until it finds a match the first time) and if you arent using xml at all, then you dont scan the class path at all, ever.

This drastically improves build time and final output size. For example, previously a simple “1 button” application brought in a reference to every component and container (:man_facepalming:), would take about 4 seconds to build a JS output and would weigh in at a whopping 1.8mb.

With this new “on demand” lookup system (and some of the other enhancements above), the same app takes about 1.3 seconds to build, has a file size of around 650kb (130ish zipped) and has a totally sensible set of dependencies.

image

im almost sure there is some more fat to trim, but this is a pretty important step and fixes an absolutely huge oversight on my part regarding creating a reference to every component (:man_facepalming: - it deserves another facepalm!)

As part of this ive create a tool to track down dependencies that has been pretty invaluable: Dependency Analyzer

New Component - SideBar

Its been there for a while, but there is a new component in haxeui: SideBar as you gather this allows you slide in content from top / bottom / left / right and can optionally “sqaush” / “shift” the content beneath it.

Click here to see it in action http://haxeui.org/shared/sidebar5.gif (its a huge gif so cant be rendered into the page)

Usage is prtty simple, its basically the same as dialogs from an API perspective:

var sidebar = new MySideBar();
sidebar.method = "squeeze"; // default is "float"
sidebar.position = "bottom"; // default is "left"
sidebar.show();

You can build the sidebar with xml if you want, or plain code, any way that you build any other component.

DataSource filtering and sorting

DataSources can now be filtered and sorted. This has been on my todo list for quite a while and has finally made its way into core. Filtering can be achieved with:

myDataSource.filter(function(index, item) {
    return index % 2 == 0; // this example will filter out any odd items
});

The type of item will be whatever the type of the datasource is, ie, if its DataSource<Int> then item will be Int.

Sorting works pretty similar - the big difference is that there is a helper function to perform an alpha-numeric sort, some examples:

myDataSource.sort(SortDirection.DECENDING);
myDataSource.sort("someField", SortDirection.DECENDING);
myDataSource.sortCustom(function(item1, item2) {
    return 0;
});

For both filtering and sorting, if the data sources are attached to something like a TableView or ListView then the order / items will reflect the sorted / filtered data source contents.

filter-1

Also, for TableView specifically, sorting can be linked up very easily be doing something similar in the table header:

<header width="100%">
    <column width="32" id="colX" sortable="true" sortField="imageIndex" />
    <column width="32" id="colA" sortable="true" />
    <column id="colB" width="180" text="Progress" sortable="true" />
    <column width="100%" id="colC" text="Status" sortable="true" />
</header>

datasource_sorting

(obviously thats using xml, but the same applies to using it from code).

New Slider properties

Sliders (both vertical and horizontal) get some snazzy new properties:

  • center this is where the “center” of the slider is calculate at
  • step this will what increments the slider value will go up by
  • minorTicks this will define how often to draw small “tick” lines
  • majorTicks this will define how often to draw larger “tick” lines

new-sliders-default

New Backend: haxeui-raylib

HaxeUI has yet another backend. This time using the pretty amazing RayLib. This started off by spending a little bit of time writing externs for raylib (GitHub - haxeui/raylib-haxe: RayLib extern bindings for Haxe) for no particular reason. Then, to test them, i thought about playing with a backend - i had no intention of making it official. Very very quickly it all came together and once it had full text input (modeled after haxeui-kha) I decided it should become a full, official backend! Theres not much in the way of instructions at the moment, but its pretty simple, and pretty much like every other haxeui backend. haxelib run haxeui-core create raylib in a blank directory will create a skeleton project.

haxeui-raylib

Notable Mentions

As usual, this “wall of text” has gotten away from me, and im running the risk of rambling on and on. This has been another really big release, and long overdue, an untold amount of bug fixes and enhancements. And great feed back from a bunch of project authors.

One i would like to highlight is “kLabs” 100% native TODO app that uses haxeui-hxwidgets and coconut.ui (coconut.haxeui)

recording-2021-08-14-01

This has been an extremely interesting app to watch evolve since its using a 100% native backend and a coconut.ui which, although i dont know that much about it, i know its pretty damned cool. So seeing it play well with a native UI has been great. Its also been a good source of bugs (and fixes) for hxWidgets and haxeui-hxwidgets

Some other very small additions that come to mind are

  • full list of html colours can be used in styles, etc (thanks Joe!)
  • when using “file://something.png” in image resources, paths relative to the executable work - tiny change but essential
  • ability to omit the root node when importing xml from an external file via the omitRoot property on <import> - another small but useful change

So I think thats it for now. Ill try and not a) leave the next update so long b) not ramble so much in the release details :slight_smile:

Cheers,
Ian

8 Likes

Great work as usual !

A few comments

it’s Dialogs.messageBox(…) on the most recent haxe ui core :wink:

I’ve tried this exact code and I have

haxeui-core/haxe/ui/macros/ComponentMacros.hx:278: c0
haxeui-core/haxe/ui/macros/ComponentMacros.hx:278: c0
src/Main.hx:32: characters 39-46 : Expected }

1 Like

Ah, nice catch.

Hmmm, ill have to check it out… it was working at some point and i dont remember explicitly stopping it from working. Its probably good to fix it though as it might be hiding a deeper problem, another nice catch… thanks!

Cheers,
Ian

Hi @ianharrigan
Is it available via haxelib ? It seems I can’t get it

I mean, I see the version but I can’t update it

 2021-08-15 12:01:43 1.3.0 : 1.3 release

EDIT:
Ok, remove e reinstall did the job

@ianharrigan
I get a

Type not found : haxe.ui.binding.BindingManager

Did you change something for that library ?
I just removed the import (not using it atm) and it works, but I had no problem with building before

and could it be related to the fact that now it’s not showing theme.icon ?

Yeah, binding manager is gone now, it used to be hscript based so got rid of it. Now its macro based so if you are using xml, it will write the code for you, if you arent using xml, well, you can just write the code… I may reintroduce something similar (for consistently) but honestly, im not sure how useful it would be.

Can you show me your usage of theme.icon?

Cool :slight_smile:

Nothing special, just like this

<image id="back" height="20" width="20" resource="${theme.icon('arrow-left')}" verticalAlign="center"/>
1 Like

Ah, nice catch… i didnt actually test that… should be an easy fix. Ill check it out during lunch.

Thanks!

1 Like

@ianharrigan
Just a note about the MEssageBox

maybe it would be useful to include a “YESNO” type too

                case MessageBoxType.TYPE_YESNO:
                    buttons = DialogButton.YES | DialogButton.NO;

It’s like a question, but without a cancel button :grin:

1 Like

That should work now… nice find :slight_smile:

Added MessageBoxType.TYPE_YESNO

Cheers,
Ian

Yup :+1: it works now

1 Like

@ianharrigan
Out of curiosity, did you test it with the latest haxe (4.2.3) ?

The actions test up to 4.2.2, but its just a compile, not a “test”… why is something wrong?

Not while compiling but at runtime.
It’s probably an openfl/neko issue but I did not dig that much

The syncValidation returned too many times during validation. This may be an infinite loop. Try to avoid doing anything that calls invalidate() during validation.

by the way, I’m still not able to use OpenFL/HL due to some dll issue

Can you repro (minimally) and open an issue please?

This is because i dont think you have HL installed correctly, you might need to rebuild it manually or download it prebuilt from somewhere… I think i had to drop ssl.hdll, or some other hdll - probably best to ask in openfl / GH?

Cheers,
Ian

Yep. I did some test and it seems to be a problem (at least) with Frame component

Yes I know, there something involving Lime too
I need ti spend some time on this just for the sake of it :grin:

EDIT
While adding an issue I’ve found this SyncValidation loop when using min-height · Issue #382 · haxeui/haxeui-core · GitHub
so I just had a look to the section and in fact it turned out to be an issue related to the height=“auto” setting of the frame
Removing it, the runtime error went away :slight_smile:
I’ll update that issue adding my sample

You can also check the “old” shared project on github.
I’ve noticed that, every else “height=auto” are acting weirdly, setting in fact the component height to 0 (or maybe just not rendering it).
You can check the main-view.xml in the shared project, playing a bit with the height settings there

:exploding_head: haxeui-raylib–an unexpected and amazing surprise! Will definitely experiment with this. Thanks and keep up the good work!