July 20th, 2010

Pixel complete

In an indirect response to my earlier post, David Grace writes:

All this talk about not being able to create something that looks good in JavaFX is hot air. JavaFX has the functionality to do so, you just have to know how. What JavaFX needs is for the preview controls and layouts to be finished, controls such as a table implemented, and the Prism renderer implemented. When this is done it will be easy to write any application that could be written in Swing quicker, looking much better and with far greater performance. Personally i would of rathered investment in Swing instead, but Sun/Oracle have invested in JavaFX and in many ways its already far better than Swing, except for missing components.

Modern programming languages provide abstraction layers and higher level concepts to shield the programmers from the low level drudgery of writing assembly code. In much the same way modern UI toolkits provide component libraries, image composition, transformations, animations and many other tools that make it simpler to translate the intended design into a living and breathing reality. But eventually, it’s pixels. All the way down.

Just as the vast majority of the programming languages are Turing complete, the vast majority of UI toolkits are what i call pixel complete. If the specific toolkit exposes the ability to control every single pixel in the window (with, say, paintComponent in Swing, onDraw in Android, paintControl in SWT or updateDisplayList in Flex just to name a few), there are no limits to what can be put on the screen. Modulo support for translucent and shaped windows, you can take any design and turn it into reality. Indeed, if you know how to do it, you can do anything. But that’s not the point.

How about this – instead of asking what people can do with JavaFX, ask what people are actually doing with it.

July 14th, 2010

JavaFX is a train wreck

It’s been three years since JavaFX was announced to the world, and it’s time to see how far has it gone with capturing the minds of the target audience. From the very beginning, JavaFX was positioned to be a prime environment to create compelling user interfaces (count how many times the word “rich” is used in the first sentence):

JavaFX provides a unified development and deployment model for building rich client applications that integrate rich immersive media such as audio and video, graphics, rich text and web services. JavaFX allows creative developers to program in a visual context thus helping them to bring their ideas to life quicker and better.

In addition, following in the footsteps of Apple, Adobe and Microsoft that have all realized the importance of bringing professional designers as equal partners in the process of creating new wave of user-facing products, JavaFX has placed significant effort into making the collaboration between developers and designers easy:

JavaFX allows designers and developers to simply and swiftly combine graphics and media assets to unleash their creative potential with significantly reduced effort. Using the JavaFX Production Suite, a suite of tools and plugins for Adobe Photoshop and Adobe Illustrator, designers seamlessly create and export graphics from their existing tools into the JavaFX format. The plugins allow One-click conversion and provide a preview enabling designers to make any necessary modifications prior to conversion. Also included is the JavaFX Media Factory, enabling designers to use Scalable Vector Graphics (SVG) editors such as Inkscape with JavaFX as well.

In this world, a designer continues to use the tools that he is fluent with (Photoshop and Illustrator), and a developer continues to use the tools that he is fluent with (code editor). And while the final product contains the work of both sides, they can continue working in parallel, refining and tweaking the UI and the business logic as they go. In fact, one of the earliest demos shown at JavaOne showed a designer exporting a layered background to be used in a UI and a developer importing the visual assets to be used in the application. After the developer had added a few listeners, the designer changed the visuals, which were then re-imported into the application without any change in the application code.

And that was one of the main promises to the companies considering the choice of a UI toolkit for their next big application. That  there’s this large pool of professional creative talent, and you can tap into it without forcing them to abandon the familiar set of tools. In addition, you don’t need to fear that the developers will cut corners and miss all the fine visual details when they implement the UI mocks – the visuals are imported from the design tools, untouched by the developers that toil away at the business logic.

Judging by how well this promise has translated into reality, JavaFX is a train wreck.

No matter what your opinion on Microsoft, you cannot deny that they have mastered the fine art of promoting their UI toolkits. When WPF was announced a few years ago (slightly before JavaFX), Microsoft forged agreements with a number of third-party companies that have created visually rich and aesthetically pleasing business applications that focused mainly on showcasing the full graphic capabilities of the UI toolkit. Companies such as thirteen23 and Infragistics have created WPF applications to browse Netflix, Amazon, Flickr, Twitter and many more.

Apple’s obsession with design has not gone unnoticed with the designer community. Not a week passes by without yet another round of beautifully designed applications for Mac, iPad or iPhone. People obsess over the placement and color of each pixel, and spend untold hours refining and polishing every single element that is displayed on the screen. Applications are judged on the appearance as much as they are judged on the functionality – if not more.

What has happened with JavaFX in the meantime? Nada. I am yet to see a single significant JavaFX application that looks good. And while developers obsess over semantics of sequences and null pointer exceptions, designers just don’t care. The “rich” part of JavaFX-powered RIAs is just not happening. Jim Weaver had an interesting idea when he required all teams participating in the JavaFX RIA exemplar challenge to have one developer and one designer. After a few weeks the rules were changed to no longer require the participation of a designer. Nine months after the competition has been announced, no news on the participants or the winner.

If the simplest explanation is also the correct one, then i would assume that the competition has failed to attract any significant number of professional designers. Extrapolating that, publishing screenshots of the existing entries (presumably designed by the developers) would not sit well with what this competition meant to achieve – showing the world that JavaFX is a viable and strong alternative for companies that want to create rich business applications. Depending on your personal opinion, the last statement may have never been true.

June 11th, 2010

Immovable. Unshaken.

Bear with me for a moment. There’s this guy sitting in a bar. He doesn’t have any money to pay for the drinks, and nobody wants to invite him to join their table. Thinking about what he can do, he sees a bunch of guys from Mongolia sitting around a table full of food and alcohol. Strolling over, he asks them: “Do you want to hear a story about a fight between a russian warrior and a mongol warrior”? Half ignoring him, they say “whatever, go ahead”.

“And so the story goes that a russian warrior and a mongol warrior met for a fight. The mongol struck the russian, and the russian sunk into the ground up to his ankles”. The mongols are starting to pay some interest, and give the guy a small drink. After finishing the drink the guy continues. “The mongol strikes the russian one more time, and the russian sinks into the ground up to his knees”. The mongols give him some food and more to drink. “He strikes him the third time, and the russian sinks into the ground up to his chest”.

Now the mongols are really happy, giving him some steak to eat and more to drink. The guy starts getting drunk and relaxed, and continues the story. “Now it’s time for the russian. He strikes him once, but the mongol stands. Immovable, unshaken”. The mongols keep on giving him more food and alcohol. “The russian strikes once more, but the mongol stands. Immovable, unshaken”. They give him all their food, captivated by the story. The guy keeps on drinking. “The russian strikes the third time, but the mongol stands. Immovable, unshaken”. The mongols are ecstatic, unable to contain their joy. The guy is done with eating and drinking, and leans back to rest. The mongols are urging him to continue the story and keep on asking him what’s next. The guy says: “What’s next? The mongol stands. Immovable, unshaken. With only his ears above the ground”. (*)

Which brings me to Swing. The last 18 months have seen little change in the direction of the core Swing library – maintenance and bug fixing. With every passing milestone of JDK 7, more and more Swing features have been removed from the feature list. Swing application framework, SwingX painters and new components all fell to the side. And while there have been a number of bug fixes in the last few months, the only public API enhancements in core Swing are shaped / translucent windows (an API that has been promoted from 6u10+ to be public) and JLayer (an almost direct port of JXLayer).

In the meantime, we’re not going to see any of:

  • Components such as date picker, month view, task panes, split buttons.
  • A modern (HTML 5 / CSS 3) browser component.
  • Form / grid oriented layout managers.
  • Binding.
  • Video playback / recording.
  • Docking / windowing.
  • API enhancements to the table component.

Given how much is going on with JavaFX, this is not really surprising. This just confirms what i said before. Core Swing is in feature freeze, immovable, unshaken. It is a solid foundation, and lends itself quite easily to external third-party enhancements. But as far as the core feature set – it’s not going anywhere. A couple of random observations.

Since Oracle acquisition, the bug fixing pace has definitely picked up. There’s a bunch of bugs being fixed in both Swing and Java2D. On the other hand, JavaFX has Prism, a new rendering pipeline for mobile, desktop and TV stacks. While Swing / Java2D has been the foundation of JavaFX desktop profile before, and we enjoyed incidental performance improvements and bug fixes as the result, it’s not going to last for very long. New composites, hardware acceleration, new graphic primitives are unlikely to be ported and maintained in two different pipelines. And i would imagine that internally Prism also has quite a few different backends, each one optimized for the specific graphics hardware – meaning more work in the foreseeable future outside the existing Java2D backends.

NetBeans is an interesting beast. A solid foundation for writing modular boring business applications, it has not seen any of its features ported to core Swing. We’re talking about docking, windowing, sliding palettes, layouts, application framework and more. If the crossover has not happened until now, how likely is it that it will happen in the future? Speculating widely, recently rumored cuts in european / asian offices may jeopardize the future of NetBeans – which, to the best of my knowledge, is mainly developed in Prague. And don’t forget that Oracle has its own JDeveloper IDE. The only hope for NetBeans would be if they position themselves as the platform for JavaFX development. Given Eclipse’s dominance presence outside the internal bubble, how long will it be before the internal investment in NetBeans is reconsidered in this profit-oriented environment?

And what’s up with an embeddable browser component? Seriously, everybody is doing it. WebKit must be exposed in a gazillion other UI toolkits by now. Big companies are doing it. Small companies are doing it. It’s been what? Two, three years? If this is still going on internally, and you’re thinking to somehow monetize your investment, you can forget about it. Open source it now, and let people help you. You’re not really thinking that this port is going to be so unique that companies will be lining up to pay top dollar to license it.

(*) Russian readers not familiar with the joke can find the original here (number 48). This is not really politically correct, but i’m sure that every folklore has its own version.

May 22nd, 2010

Onyx reloaded

Exactly a year ago I’ve introduced project Onyx – animation blueprints for Swing using the Trident animation library. Onyx is a small application that loads album information for the specific artist from the Internet and displays it as a scrollable gallery. Here is how Onyx looked a year ago:

And here is how Onyx looks now:

Along with running on Java 6 (with Java 7 weekly binaries for Mac nowhere in sight), Onyx also has received a slight visual facelift for the main window. First, let’s see the code for disposing a window by fading it out:

public static void fadeOutAndDispose(final Window window,
      int fadeOutDuration) {
   Timeline dispose = new Timeline(window);

   try {
      Class clazz = Class.forName("com.sun.awt.AWTUtilities");
      final Method opacityMethod = clazz.getDeclaredMethod(
            "setWindowOpacity", Window.class, float.class);

      dispose.addPropertyToInterpolate(Timeline. property(
            "opacity").from(1.0f).to(0.0f).setWith(
            new PropertySetter() {
               @Override
               public void set(Object obj, String fieldName,
                     Float value) {
                  try {
                     opacityMethod.invoke(null, obj, value);
                  } catch (Exception exc) {
                     exc.printStackTrace();
                  }
               }
            }));
      dispose.addCallback(new UIThreadTimelineCallbackAdapter() {
         @Override
         public void onTimelineStateChanged(TimelineState oldState,
               TimelineState newState, float durationFraction,
               float timelinePosition) {
            if (newState == TimelineState.DONE) {
               window.dispose();
            }
         }
      });
      dispose.setDuration(fadeOutDuration);
      dispose.play();
   } catch (Exception exc) {
      exc.printStackTrace();
   }
}

With Java 7, you can simply do this:

dispose.addPropertyToInterpolate("opacity", 1.0f, 0.0f);

and let Trident call Window.setOpacity method at every timeline pulse. In Java 6 (starting with 6u10), the AWTUtilities.setWindowOpacity needs to be called on every pulse explicitly.

And here is the code for painting the main content window. First, we store the current clip and enable anti-aliasing:

@Override
protected void paintComponent(Graphics g) {
   Graphics2D g2d = (Graphics2D) g.create();
   Shape clip = g2d.getClip();

   g2d.setStroke(new BasicStroke(1.0f));
   g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
         RenderingHints.VALUE_ANTIALIAS_ON);

Next, we compute the outer and inner contours of the panel (the inner contour will be painted with slightly brighter colors as shown in the screenshot above):

   int radius = 16;

   Shape contour = new RoundRectangle2D.Double(0, 0, getWidth() - 1,
         getHeight() - 1, radius, radius);
   Shape innerContour = new RoundRectangle2D.Double(1, 1, getWidth() - 3,
         getHeight() - 3, radius - 1, radius - 1);

When the main window is first shown and disposed, a special timeline is played to make the window appear and disappear smoothly. The timeline interpolates the alpha field between 0.0 and 0.9. The main panel has two parts – the bright blue header and the black content. While the content is painted based on the current value of alpha, the header uses less translucency:

   g2d.setComposite(AlphaComposite.SrcOver.derive(1.0f - (float) Math.pow(
         1.0f - alpha, 3.0)));

To paint the header, we first update the current clip to make sure that the painting is only done in the header section. Next, we fill the contour, draw the inner contour and draw the outer contour – all based on the specific colors required by the target design:

   // top part
   g2d.clipRect(0, 0, getWidth(), TITLE_HEIGHT);
   g2d.setPaint(new LinearGradientPaint(0, 0, 0, TITLE_HEIGHT,
         new float[] { 0.0f, 0.49999f, 0.5f, 1.0f }, new Color[] {
               new Color(119, 152, 251), new Color(80, 127, 250),
               new Color(48, 109, 250), new Color(10, 97, 250) }));
   g2d.fill(contour);
   g2d.setPaint(new GradientPaint(0, 0, new Color(151, 179, 253), 0,
         TITLE_HEIGHT, new Color(19, 92, 233)));
   g2d.draw(innerContour);
   g2d.setColor(new Color(11, 61, 200));
   g2d.draw(contour);

Now we restore the clip:

   g2d.setClip(clip);

If we have an artist name to display, we position it in the middle of the title area (using font ascent for proper baseline alignment) and paint the string twice to create a lighting effect:

   if (this.searchString != null) {
      g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
            RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
      g2d.setFont(UIManager.getFont("Label.font").deriveFont(14.0f)
            .deriveFont(Font.BOLD));
      int fa = g2d.getFontMetrics().getAscent();
      int x = (getWidth() - g2d.getFontMetrics().stringWidth(
            this.searchString)) / 2;
      int y = (TITLE_HEIGHT + fa) / 2;
      g2d.setColor(new Color(31, 60, 114));
      g2d.drawString(this.searchString, x, y + 1);
      g2d.setColor(new Color(255, 255, 255));
      g2d.drawString(this.searchString, x, y);
   }

The main content area is painted in the same way as the header. We update the clip, fill the contour, draw the inner contour and draw the outer contour:

   // bottom part
   g2d.setComposite(AlphaComposite.SrcOver.derive(this.alpha));
   g2d.clipRect(0, TITLE_HEIGHT, getWidth(), getHeight() - TITLE_HEIGHT
         + 1);

   g2d.setColor(new Color(0, 0, 0));
   g2d.fill(contour);
   g2d.setPaint(new GradientPaint(0, TITLE_HEIGHT, new Color(57, 56, 57),
         0, getHeight() - TITLE_HEIGHT, new Color(50, 48, 50)));
   g2d.draw(innerContour);
   g2d.setPaint(new GradientPaint(0, TITLE_HEIGHT, new Color(13, 11, 15),
         0, getHeight() - TITLE_HEIGHT, new Color(15, 8, 13)));
   g2d.draw(contour);

Finally, we draw a single line separator between the title and main content areas:

   // separator
   g2d.setClip(clip);
   g2d.setColor(new Color(12, 11, 12));
   g2d.drawLine(1, TITLE_HEIGHT, getWidth() - 2, TITLE_HEIGHT);

   g2d.dispose();
}

To see the latest Onyx in action, click on the button below to launch the WebStart demo. Use the mouse wheel to scroll between the albums. Click a specific album to show a larger cover and the track list.

If you cannot run the demo, here is a short video of Onyx in action: