Fuse, UI Oriented Resource Injection

I spend a lot of time designing and creating graphical user interfaces. Hence, the bulk of my work is not to design object oriented architectures or think of complicated algorithms. Instead, I mostly tweak values: colors, opacities, gradients, rendering hints and so forth. Creating nice mockups in an image manipulation program is unfortunately not enough and I have to adapt the design to Java SE limitations, my liking and colleagues suggestions. As you can imagine, tuning a value for the umpteenth time in the day to rerun the application and check the result can become somewhat tedious. Unfortunately, this is exactly what I have been doing lately for an internal project at Sun. When the project started I knew I would soon beg for mercy or eat my keyboard out of despair if I didn't find something to ease my pain.

This is why I created Fuse a small library designed to change GUI resources easily. It has other advantages like the ability to reload values at runtime and decoupling the resource loading code from the GUI. (To sound smart and wise I say it's a resource injection library; but one day I'll have the same gray hair as Chet and I'll naturally look smart and wise even though I'll still be a fool – like Chet :) Anyway, Sun let me open source the project which will become a sub-project of SwingLabs as soon as I get the approval from java.net.

“Ye gods! Cut to the chase and show us some code!”, are you probably yelling behind your screen by now. Before delving into this matter, I'd like to warn you the API is far from being finalized yet. The names are likely to change. (hitherto I was using the notion of “themes” and “theme resources” instead of the current broader definition) One last thing: you might hate the apparent trickery introduced by the use of Fuse. You will need two things: a Java class and a plain text file. The first step is to identify the resource you want to inject in your instances:

The call to inject() will browse the annotated fields from instance t and give them a value found in a properties file called /resource/classic_theme.uitheme (this will change, but this is how it works in the project from wich Fuse is born). As you can see, there is some black magic at work here since Fuse will assign a value to the private fields. Many might despise that, I think it's ok. You can also perform the injection in the component's constructor if you need the values right away. Now, here is the content of the properties file:

Depending on the type of each resource, Fuse will invoke a specific TypeLoader which role is to create the appropriate value from the plain text. Each value is identified by the field name prefixed by the class name. The library ships with many type loaders: boolean, byte, character, color, composite (and alpha composite), double, file, float, font, gradient paint, image icon, image (and buffered image), insets, int, long, rendering hints, short, string, stroke (and basic stroke) and URL. You can also easily create your own type loaders.

The good thing with these type loaders is they allow you to define values in an easier way. For instance you can define a font with the format Face-Style-Size but if Face is a TrueType font file, Fuse will load it for you. Another example is the rendering hints: if you want to use the value VALUE_ANTIALIASING_ON for the key KEY_ANTIALIASING, you can write one of the following:

Fuse will try to be smart and infer hints names (for instance a key “antialiasing” is actually KEY_ANTIALIASING, and its value “on” must be VALUE_ANTIALIASING_ON). Very often in a UI design you will reuse the same values over and over and Fuse makes this easy by allowing references:

A key surrounded by curly braces is interpreted as a reference. The library will detect circular references (for instance if Common.darkColor was defined by {MyComponent.shadowColor}) and will warn you about them. Speaking of which, every type loading can raise a TypeLoadingException which tells exactly which property is wrong and why. (and you don't have to catch this exception, but you can)

Another nicety is the ability for a single type loader to inject a value into different types of a same class hierarchy. Take these declarations for instance:

Both these values will be injected by ImageTypeLoader. Finally, you can reinject the values any time you want, and this is why I first named the ResourceInjecter a Theme, by calling inject(). This really saves quite some time when you just want to adjust a value without having to create some annoying GUI for debug purpose only.

I have many ideas for Fuse. For instance, it'd be nice if it let you define the naming pattern of your properties files. (so that they don't have to be /resource/*.uitheme) I also would like to introduce an optionnal component hive that would keep track of every component in which you injected resource. The hive would then be able to reinject values at runtime without you having to go through your instances.

No matter what, you will see this library in my future demos :)

As a bonus, here is an example of a real component I created for the aforementionned project:

2 Responses to “Fuse, UI Oriented Resource Injection”

Great write-up, I’m a big believer in commenting on blogs to help the blog writers know that they’ve added something worthwhile to the world extensive web! (supply roblox-cheats.com). Anyway, in my language, there aren’t much good source like this.