Fan

 

Fwt

Overview

Fan Widget Toolkit or FWT provides a toolkit for building both desktop and HTML5 browser based applications:

  • Widgets are reusable UI components such as buttons, text fields, dialogs, etc
  • Graphics for 2D rendering
  • Eventing for user input: keyboard, mouse, and focus eventing
  • UI layout

The fwt defines the basic low level infrastructure for applications. Flux is built on top of the fwt to provide a more advanced application framework for desktop apps.

Widgets

The fwt::Widget class is the root of the widget class hierarchy. Widgets represent UI components such as buttons or text fields.

Widget Tree

Widgets are structured as a tree. Typically the root of a visible widget tree is a fwt::Window on the screen. Any widget is a potential container for other widgets - although typically only Panes contain children. The following methods are used to work with the widget tree:

A widget may only be mounted under one parent. If you attempt to add a widget to multiple parents an exception is thrown.

Panes

Widgets come in two flavors: panes and controls. Panes are widgets which are designed to be containers for other widgets. Panes are responsible for laying out their children. Widgets which don't subclass from Pane are most often leaf widgets which provide some control such as a button or text field.

Custom Widgets

Most often you will use the predefined widgets in the toolkit. However you can create your own widgets too. Typically you will subclass fwt::Pane to create a new container widget or fwt::Canvas for a new control. Panes are responsible for deciding how to layout their children. Controls will typically define custom painting and eventing.

Painting

Canvas widgets may override the onPaint method to provide custom painting. Painting is done via the gfx::Graphics API:

  • draw geometries
  • fill geometries
  • draw text
  • draw images
  • coordinate system transformations
  • clipping

A Graphics instance maintains state for how it renders:

  • gfx::Pen defines how geometries are drawn
  • gfx::Brush defines how geometries and text are drawn and filled
  • gfx::Font defines how text is rendered
  • gfx::Image models an image - typically loaded from a png, gif, or jpeg file
  • current clipping region
  • current transform to apply to the coordinate system

You can use the push and pop methods to create a stack of Graphics instances and their associated state. A typical pattern is:

g.push
try
{
  g.translate(...)
  ...
}
finally
{
  g.pop
}

The following is a simple widget which paints itself as a red box with a blue outline:

using gfx
using fwt
class RedBox : Canvas
{
  override Void onPaint(Graphics g)
  {
    w := size.w
    h := size.h
    g.brush = Color.red
    g.fillRect(0, 0, w, h)
    g.brush = Color.blue
    g.drawRect(0, 0, w-1, h-1)
  }

  Void main()
  {
    Window { InsetPane { content = RedBox() }, }.open
  }
}

Layout

Every widget plays a role in how the UI is laid out. Leaf widgets define a preferred size by overriding the prefSize method. The prefSize method takes a gfx::Hints which contains an optional width and height constraint.

Panes which contain children implement a layout strategy by overriding the onLayout method. This callback is used to set the bounds of all the children widgets. Often panes will also override prefSize to compute the containers preferred size from the children.

Eventing

All widgets support a set of eventing callbacks which by convention start with the "on" prefix. Widget events are declared as fields of type fwt::EventListeners which maintain a list of callback functions. Event callbacks take a single Event argument. Refer to the fandoc of each event to see how the Event fields are used.

The following illustrates a simple text field with some event handlers:

class EventTest
{
  Void modifyCallback(Event event) { echo(event) }

  Void main()
  {
    text := Text
    {
      onFocus.add |Event e| { echo(e) }
      onAction.add |,| { echo("onAction!") }
      onModify.add(&modifyCallback)
    }

    Window { GridPane { text, }, }.open
  }
}

The example illustrates creating callbacks using both closures and the curry operator. The onFocus event handler is defined as a closure with an Event argument. The onAction event handler is also a closure, but with no arguments (remember that you can use functions which take fewer arguments). The onModify event handler shows how you might use the curry operator to define a callback function.

Commands

A common technique in user interfaces to separate the UI elements from the command logic. For example you might have both a menu item and a toolbar button for a "Save" command. The fwt::Command class is used to manage this design pattern.

Commands are responsible for the text, icon, accelerator, and how a command is executed. Commands may optionally handle undo/redo. Often the visual elements of a command are stored in a localization props file. For example to create a localized "Save" command:

// locale/en.props
save.name=Save
save.icon=fan:/sys/pod/icons/x16/save.png
save.accelerator=Ctrl+S

// create Command instance
save := Command.makeLocale(Pod.find("flux"), "save") |,| { echo("save!") }

You can create UI widgets from commands:

menu.addCommand(save)
toolBar.addCommand(save)

Widgets which are mapped to a command are said to be registered. Registration occurs automatically when setting a widget's command field. If you create your own custom widgets with command support you should follow the pattern used by Button and MenuItem. Once a widget is registered with a command, it tracks the command's state. For example enabling or disabling the command will automatically enable/disable as its registered widgets. For toggle commands its widgets automatically track the command's select state.