
For the inaugural entry on the new series, i’ve chosen to go with the design of AdFlavor.net. It has great choice of color schemes, subtle use of multiple textures that bleed across different areas, consistent use of colors for links and headers, good use of white space and restrained lighting effects.
It’s my great pleasure today to announce the availability of release candidates of the following projects:
Substance 6.0 main features include:
- Support for multi-state animations
- New look for text-based components
- Custom component states
Click on the button below to launch a signed WebStart application that shows the available Substance features.

Trident 1.2 is a stabilization release and has a few new APIs.
You’re more than welcome to download the release candidates for Trident, Substance and relevant plugins. If you see any exceptions, visual artifacts or anything else that shouldn’t be there – don’t assume that i know about it. Drop me a line on project forums or mailing lists. The final releases for the libraries are scheduled on April 14.
From “Engineer Thinking” by Matt Legend Gemmell:
If you’ve exposed underling complexity or unnecessary choice in your software because you see those things as inevitable, it’s because your job isn’t finished. If you’re going to write GUI software for other people to use, do it properly, and treat those people like human beings instead of software engineers. If you want to expose complexity to the user and wash your hands of it, write command-line tools – or utilities that are used exclusively by other machine processes.
You can’t have it both ways. Writing GUI software is for people who strive for excellence not only in the “software” part but in the “GUI” part too.
The Trident animation library was born in February 2009 out of the internal animation layer used in Substance look-and-feel over the last three years. A year after, it is nearing its third official release which focuses mainly on stabilizing the API and ironing out the existing bugs.
The major milestone for this release is moving Substance 6.0 to use Trident – along with validating the library performance and flexibility to support a wide variety of UI animations. Trident 1.2 has also added a few new APIs to address a few common application requirements.
Custom property accessors
The default mechanism to retrieve and update the interpolated field is to use reflection to look up and call the matching published getter and setter. Application code that does not wish to expose these methods should use the following APIs:
-
TimelinePropertyBuilder.getWith(PropertyGetter)
– new in 1.2
-
TimelinePropertyBuilder.setWith(PropertySetter)
-
TimelinePropertyBuilder.accessWith(PropertyAccessor)
– new in 1.2
Where the relevant interfaces are defined in the TimelinePropertyBuilder
class as follows:
If the timeline property builder is configured with a custom property setter / accessor, the set()
will be called at every timeline pulse passing the object, the name of the field and the new value to set on the field. If the timeline property builder is configured with a custom property getter / accessor, the get()
will be called when the current value of the field is needed. For example, when the builder is configured with fromCurrent()
, the get()
will be called to get the current field value when the timeline starts playing.
The following sample shows usage of a custom property setter:
public class CustomSetter {
private float value;
public static void main(String[] args) {
final CustomSetter helloWorld = new CustomSetter();
Timeline timeline = new Timeline(helloWorld);
PropertySetter propertySetter = new PropertySetter() {
@Override
public void set(Object obj, String fieldName, Float value) {
SimpleDateFormat sdf = new SimpleDateFormat("ss.SSS");
float oldValue = helloWorld.value;
System.out.println(sdf.format(new Date()) + " : " + oldValue
+ " -> " + value);
helloWorld.value = value;
}
};
timeline.addPropertyToInterpolate(Timeline. property("value")
.from(0.0f).to(1.0f).setWith(propertySetter));
timeline.play();
try {
Thread.sleep(3000);
} catch (Exception exc) {
}
}
}
Here, the CustomSetter
class does not wish to expose the value
field via a public setter. Instead, a custom property setter is provided to be called on every timeline pulse. Note that while this sample code does update the matching object field, it is not a strict requirement. Your custom property setter can do anything it wants in the set
implementation – update a key-value map, update multiple fields or even ignore some of the values altogether.
The following sample shows usage of a custom property accessor backed up by a key-value map:
public class CustomAccessor {
private Map values = new HashMap();
public static void main(String[] args) {
final CustomAccessor helloWorld = new CustomAccessor();
Timeline timeline = new Timeline(helloWorld);
PropertyAccessor propertyAccessor = new PropertyAccessor() {
@Override
public Float get(Object obj, String fieldName) {
return helloWorld.values.get("value");
}
@Override
public void set(Object obj, String fieldName, Float value) {
SimpleDateFormat sdf = new SimpleDateFormat("ss.SSS");
float oldValue = helloWorld.values.get("value");
System.out.println(sdf.format(new Date()) + " : " + oldValue
+ " -> " + value);
helloWorld.values.put("value", value);
}
};
helloWorld.values.put("value", 50f);
timeline.addPropertyToInterpolate(Timeline. property("value")
.fromCurrent().to(100.0f).accessWith(propertyAccessor));
timeline.setDuration(300);
timeline.play();
try {
Thread.sleep(1000);
} catch (Exception exc) {
}
}
}
Note that both examples assume that the setter / accessor is used only for one specific field (“value”). You can use the same getter / setter / accessor implementation to access multiple fields – using the fieldName
parameter passed to the get()
and set()
methods.
Stopping a timeline
In some cases you will want to stop a running timeline. There are three different APIs that you can use, each with its own semantics:
-
Timeline.abort()
. The timeline transitions to the idle state. No application callbacks or field interpolations are done.
-
Timeline.end()
– new in 1.2. The timeline transitions to the done state, with the timeline position set to 0.0 or 1.0 – based on the direction of the timeline. After application callbacks and field interpolations are done on the done state, the timeline transitions to the idle state. Application callbacks and field interpolations are done on this state as well.
-
Timeline.cancel()
. The timeline transitions to the cancelled state, preserving its current timeline position. After application callbacks and field interpolations are done on the cancelled state, the timeline transitions to the idle state. Application callbacks and field interpolations are done on this state as well.
In addition, there is a method to indicate that a looping timeline should stop once it reaches the end of the loop. For example, suppose that you have a pulsating animation of system tray icon to indicate unread messages. Once the message is read, this animation is canceled in the application code. However, immediate cancellation of the pulsating animation may result in jarring visuals, especially if it is done at the “peak” of the pulsation cycle. Calling Timeline.cancelAtCycleBreak()
method will indicate that the looping animation should stop once it reaches the end of the loop.