-
Notifications
You must be signed in to change notification settings - Fork 2
Overview
From programmer's (user's) point of view GUI FTW! is divided to two parts: compile-time and runtime. At compile time you create functions that will create your GUI at runtime. There's no windows, widgets or any other state initialized at that point. You create two type of functions: GUI creators and style sheets.
GUI structure (don't confuse it with GUI state which is something different) is your tree of widgets, so by it you define where your widgets are put. For example if you want a window with two panels in it each one having one button and one text field you would write:
[window
[panel [text-field]
[button]]
[panel [text-field]
[button]]](Where window, panel, etc. are yours frameworks classes for
windows and panels.)
On contrary, style sheets tell how element looks and how it
behaves. So, in style sheet you'll define all object properties and
event handlers. Style sheets are composed of individual styles. A
style is a list of pairs: key and value. Keys corresponds 1:1 to
JavaBean properties (all those setXxx(v) methods). So, if you have
setText(String text) method in some class, you'd write :text "Some text" in style.
Each object in GUI structure have its private style which comes right after it's class, so earlier example becomes:
[window [:title "My Window"]
[panel [] [text-field]
[button]]
[panel [] [text-field]
[button]]]Notice that if some widget have children you have to pass empty style explicitly.
There are few special properties and those begin with asterisk
(*). Two are defined by GUI FTW itself:
-
*id-- identificator of an object. Label (preferably of keyword type) that belongs to that object and no other. -
*groups-- list of groups identificators that this object belongs to.
There are others like *cons or *lay that are implemented in
frontends and will be discused later.
Once object has an id or belongs to some group, it can be styled by style sheets. Style sheets are list of styles with additional information: to which identificators they're revelant. To accomodate that style sheet definition looks like this:
(stylesheet [:window :buttons] [:color "red"]
[:panels :menu] [:background-color "blue"])This style sheet will have [:color "red"] style for :window and
:buttons and [:background-color "blue"] style for :panels and
:menu. Meaning of identificators (whether it's individual id or
group) in style sheet is not important. Groups and individual ids can
be mixed freely.
Events are like other properties but instead to setters they correspond to event listeners. You are not constrained to standard event listeners. You can create and use any custom listeners that follows that pattern.
Name of the event "property" maps 1:1 to *Listener class and method
to implement. It's composed of this two as follows: first name of the
class (without "Listener" part) a + sign and name of the method. All
names can be in lispy-notation instead of CamelCase and they will be
translated to canonic Java form (CamelCase everywhere).
Example: You want to hook into "mouse clicked" event in
Swing. Corresponding method lives in
java.awt.event.MouseListener. You import this class and add property
:mouse+mouse-clicked to the object. Notice that you have "mouse" two
times. It's so common that GUI FTW! have shortcut for this. You can
write :mouse++clicked instead.
Value for event "property" is a function that takes two arguments: GUI state and event object.
Full mouse clicked event will look like this:
:mouse++clicked (fn [gui event] ...)GUI FTW! is as abstract as possible at it's core. Which means that no
functionality specific to Swing in SWT is in core. These
functionalities are squized to minimum and they reside in so-called
frontends. You usually won't invoke guiftw.tree/parse-gui which is
core GUI structure parser. You'd rather invoke one of the frontends
which are very thin wrappers around parse-gui macro.
Swing frontend resides in
guiftw.swing
namespace and one macro that you should be interested in is
swing. It feeds parse-gui macro with Swing-specific functionality.
Analogous to Swing, for SWT there's
guiftw.swt
namespace and swt macro. Remember that GUI FTW! doesn't come with
SWT jars. You have to add them manually to your project.
parse-gui, (so also swt and swing) macro will generate function
to create your GUI at runtime. Both frontends take one argument: GUI
structure and return function that will create that GUI structure for
you.
With swing you declare your GUI creator fn like this:
(def window
(swing [JFrame [:title "This is a window!"
:visible true]
[JButton [:text "There's a button here"]]]))After that window is a function that takes variable number of
arguments, all are optional (you can ommit them at will, no need for
nilling them):
- GUI state (see next section),
- parent element for elements in this tree,
- any number of stylesheets.
If you don't pass GUI state, it'll be created for you. If you pass parent explicitly element at root of GUI structure will be added to parent as a child. Then you can pass any number of stylesheets which gives you flexibility to mix them at runtime.
GUI creator will instantiate all objects defined in GUI structure and return GUI state. GUI state is a map wrapped in an atom. This map contains those predefined keys:
-
:ids-- a map with objects indentified by their:*idproperty, -
:groups-- a map with lists of objects grouped by:*groupproperty, -
:root-- top-level object in GUI tree (usually the window).
So, if you marked some object with :my-button id, you can refer to
it like this:
(-> @gui-state :ids :my-button)You can put any number of custom keys in GUI state. They will be
preserved. Say you have a window GUI creator fn and you want to put
some custom variables in state. Initializing such a window will look
like this:
(window (atom {:my-agent (agent 123)
:my-atom (atom 456)}))Notice that GUI state is always passed to event handlers. So in simple programs you probably won't care about returned value. It's also important to stress the fact that you can decide when different parts of your GUI share state. It's a matter of passing same GUI state to creators. When mixing this with passing parent explicitly they can be part of same window but have different GUI states.