Wednesday, June 11, 2008

So the original intention was to create a Dashboard style widget UI using Swing.

In nine fairly simple steps we've gone from a blue square:

...to a nice looking widget that hopefully looks at home on the modern Desktop:

The only shortcut I took was not to pull out the maths book and write my own transform filter.

I'm very pleased with the result, it was a lot easier than I thought it would be. Hopefully this exercise proves (again) that Swing can be more than just a boring, gray, toolkit suitable for boring, gray, form-filling applications. The new transparency features especially allow vibrant, modern looking UI's that are relatively simple and quick to create.

So that's really it for the UI.

A few non-UI remarks...

Java widgets have a number of benefits over other widgets systems:- No framework or widget manager needed- Platform independent- Installed from a web-page- The extensive JDK library available as standard- Sandboxed and secure automatically- Familiar language with powerful UI toolkit- Customizable, fast, accelerated painting (try that in Javascript)

There are still a few non-UI things to do before making this code truly useful: preferences and desktop startup spring immediately to mind.

Performance is also an issue. On my machine the two widgets take about 20 MB of RAM each and 0 CPU cycles when just sitting there. 20MB is considerably more than a simple Widget in Apple's Dashboard for example.However, in modern machines with RAMs of 1GB+ as standard, and depending who you're asking, maybe this is an increasingly unimportant issue. Especially if the widget is useful.

Feel free to use the Source Code. Don't forget you'll need the filters classes from JHLabs.

With the widget specific code pushed into a base class, these two examples just needed code to gather some information and paint themselves: About 100 lines each.

ClockWidget Code:These examples are just a taste of what's possible, rather than meant be really useful as working widgets - e.g. the weather widget is hard coded to San Francisco and could do with some better graphics.They also illustrate one real advantage over traditional Javascript widgets in the use of the familiar libraries which are shipped as part of the base JDK. The weather reads an Yahoo XML feed and the clock uses a date formatter, both easily done in Java with no external libraries to download, license, ship, or understand.

Source code and summary next.

*I managed to fix the earlier OSX rendering problems by explicitly clearing the graphics before each frame. The widgets will now run on OSX with no additional downloads (Java 1.5).

Wednesday, June 4, 2008

To prove that its possible to produce, fairly easily, and faithful interpretation of a UI it's important to get the little touches right.

When I added the close button I mentioned that the close action has a nice swoosh animation as the widget is removed but conveniently didn't implement it.

So I took a shot, and it actually it wasn't too bad.

There's already the basis for it:- The code that is used in the flipping animation snaps an image of a component and transforms it.- The marvelous Filter library from JHLabs provides various image distortion filters, or if you want to use no libraries and are good at matrix maths then roll your own BufferedImageOp )

I factored out the general component animation from the flipping animation code to create a simple framework that can visually filter a component over time - just supply the distortion or adjustment.

Using the Image Processing Editor I tried out different filters with different setting. It looks like Dashboard is using a Pinch filter to distort the widget away to nothingness.

The distortion code is quite small: use a pinch filter and gradually adjust the pinch amount and radius over time (once per timerTick()). The same image is painted every few milliseconds, and using this filter it displays the animation.Oh, and the widget should fade over time too, so gradually reduce the alpha:

Tuesday, June 3, 2008

Widgets can be moved around by clicking almost anywhere their surface and dragging.OSX provides this by default when the window decoration is turned off. On Windows a mouse listener has to be attached directly to the widget, and some simple repositioning code added.

With this, and some other tidying up, a demo of progress up till now is possible.

Remember you'll need the Java 6 update 10 for this to work properly. Anything less certainly won't do the transparency and will look poor.

OSX will run it but, as there's no Java 6 update 10 to try, you'll see bad transparency rendering issues (still worth a look though). I still hope the transparency can be fixed without using an additional external library. Also the font alignment is frustratingly different on different platforms, making the 'Done' and 'i' text buttons look poor on OSX, but this will be fixed [at the cost of writing more code].

Monday, June 2, 2008

When the info button is pressed the widget should flip over to reveal the back.Using a flippable component to hold a blue front and green back, and hooking it up to the info button gives a very nice flipping transition, but with horrifying artifacts on OSX:

Also, on Windows the corners of the widget aren't transparent as expected:

After a little struggling I found that on Windows JPanels were causing the corner painting problem. Although marked as non-opaque their backgrounds were still being cleared to white every repaint! Turning off double buffering by passing false in the JPanel constructor fixed this:

Sunday, June 1, 2008

Widgets have an info button which when pressed flips the widget over to the back so the user can edit their preferences.

It has a number of visual states:- usually invisible- when cursor is over the widget the 'i' fades in.- when the cursor is over the button a background appears

Changing the state of the button's ButtonModel as the mouse cursor moves over various code is simple. The painting code looks at the model to decide what to paint.Fading is more tricky, especially as the TimingFramework isn't integrated into the JDK.So I just used a straight forward Swing Timer that varies the alpha value of the button 'i'. When the state changes the timer is kicked off, and for every timer beat the painting transparency is slightly altered until it's either completely transparent or completely opaque.It would have been better to use a curve rather than the liner adjustment.