Reintroducing GUI FTW & Progress Report

Lublin, 2011-05-16

I meant this post to be a simple translation of this but some things changed that are worth mentioning.

GUI FTW is a declarative GUI library. It’s kind of little internal DSL for GUI’s. You’ll stop manually creating boring repetitive code like:

(doto (JFrame.)
  (.setA "A")
  (.setB "B")
  (.addXxxListener (reify ...))
  ...)

Instead all the boilerplate will be generated by GUI FTW and you’ll never need to look at code like that again.

The before-mentioned concepts borrowed from the Web include:

  1. a GUI structure tree (say, like HTML but in Clojure),
    [JFrame [*id :main-window]
      [JButton [*id :super-button]]]
  2. Cascade Style Sheets (say, like CSS but in Clojure),
    [:main-window] [:title "Window FTW!", :visible true]
    [:super-button] [:text "Make something happen!"]
  3. hooking functions into events (say, like JavaScript but in Clojure).
    [:super-button] [:action++performed (fn [state event] ...)]

The bad parts would be using XML and JavaScript literally ;) . Actually, the CSS part look and works like original CSS. It just doesn’t have those fancy selectors yet.

SWT FTW!

[1] Well, for toolkits that follow the same pattern that SWT and Swing do.

[2] Notice that swt is just a wrapper around parse-gui and swt-create.

GUI FTW works with both Swing and SWT because all of the toolkit-specific are strictly separated from the core. Neither Swing nor SWT stuff are hard-coded and GUI FTW needs only one function to be implemented to support another toolkit. [1] And those functions can be as simple as swt-create. [2]

Reusability

What’s created with GUI FTW is always reusable: you’ll get a function to instantiate your GUI as many times as you want to. Also, style sheets are list of function-like objects that apply some properties to objects. You can mix different GUI’s with different style sheets at runtime freely. This paragraph is here in case of thought that everything is written using macros flew across someone’s mind ;) . Actually, I’ve tried to minimize use of macros and most of the times you’ll end up holding a function in your hand which is a win for run-time reusability.

More?

I’ve setup a wiki on GitHub and even wrote a tutorial for GUI FTW. Here’s a couple of links you’d likely be interested in:

What’s New?

Since the original announcement in Polish I’ve added couple of things, most important runtime state handling, support for custom “special properties” and for custom “adders(Swing only).

State in Sane Manner

After creating a widget you’ll get a map wrapped with atom which I call “GUI state”. It contains data about identifiers, groups, and root of the widget tree. Any other additional data can be added by user. Every event handler fn will get that state as first argument. You can query state like this:

(-> @state :ids :asdf)    ;; get object with id :asdf
(-> @state :groups :qwer) ;; get list of objects in group :qwer
(-> @state :root)         ;; get root, usually the window

When creating widgets you either pass state explicitly or a new one is created for you. You can also decide which parts of window share state and which doesn’t.

For more info check out last part of Overview on wiki.

Custom “Adders”

I knew that the day will come that I get hit by some Swing or SWT -specific quirk. So I got an issue :) (Thanks to the Reporter, by the way).

Everything is sweet and honey in Swing when you can use method add to add object to its parent. But there are some cases when Swing implementers broke that pattern, most notably the JTabbedPane when you have to use addTab method. So now (only in Swing, SWT has different “parenting” scheme) you can set :*adder property to change default behavior. Adder is just a function that takes 4 arguments [parent parent-style child child-style] and does whatever is needed. For JTabbedPane it would be:

(fn [parent parent-style child child-style]
  (.addTab parent (-> child-style :specials :*tab-title) child))

There’s also a case of JScrollPane where the setViewportView method should be used. When you want to have scroll controls on JTextArea, you have to wrap a JScrollPane around it. So it sounds like putting text area into scroll pane. So for this scenario we’d write:

[JScrollPane [:*adder (fn [parent _ child _]
                        (.setViewportView parent child))]
 [JTextArea]]

instead of

[JScrollPane [:viewport-view (JTextArea.)]]

which breaks flow of the tree (and you can’t use other goodness of GUI FTW for the text area object like styles or grouping).

There’s a fancy example using those two.

Why Bother the Programmer?

[3] Good luck with that, I live on 10th floor :P.

If you look at my TODO list you will see that I plan to put those quirks in special style sheet in guiftw.swing. I also consider using this style sheet by default in Swing. If you know any other cases that should be included, please let me know, either by creating an issue, mailing me or throwing a brick at my window. [3]