Kawa graphics

With Kawa you can easily write compact programs for graphical interfaces, using nested expressions that match the structure of the display. This makes GUI programs easy to read, write, and maintain. Also, the programs are toolkit-independent, so the same program can use Swing, SWT, or execute in a Web Server. So it is just as easy to write an interactive Web Application as a normal application. The library can be used from different programming languages (it is written in pure Java), but the examples below will use the Scheme language.

This is an early prototype, little more than a proof-of-concept, so not a lot of functionality has been implemented.

Hello world!

Let's start with everybody's favorite application:
(require 'gui)
(run-application
 (Window title: "Hello World!"
	 content: (Label "Hello world!")))

The first line is boiler-plate to make the GUI functions available. The third and fourth lines create a new Window object, with the given title, which is shown in the window's title-bar. The content is a text Label containing a single string. The second line invokes the run-application command, passing it the newly-constructed Window as an argument. This makes the window visible and active.

If you put this program in a file named HelloWorld.scm, you can run it from a console by typing this command:

java kawa.repl HelloWorld.scm

You should see a window pop up looking like [[[image]]].

If you prefer to use the SWT toolkit, you can instead do:

java kawa.repl display:toolkit=swt HelloWorld.scm
(You also need to make sure Java can find the SWT packages and libraries.) The display:toolkit parameter allows you to specify the preferred toolkit, in this case using swt rather than the default swing.

You can also run the same program in a web server. See [[link coming soon]] for details and examples.

Event handling

Here is a more interesting example. It displays a counter, which is incremented each time you click on a button.

(require 'gui)
(define n 0)
(define count-label (Label "Hello! This is a click counter."))
(define (handle-click event)
  (set! n (+ n 1))
  (set! count-label:text
	(if (= n 1)
	    "You have clicked once."
	    (format #f "You have clicked ~d times."
		    n))))

(run-application
 (Window title: "Hello counter!"
	 content:
	 (Column
	  count-label
	  (Button text: "click here"
		  foreground: 'red
		  action: handle-click))))

We first define the variable n, which counts the number of times the button has been clicked. The count-label is a Label that will be updated to show the number of clicks. The handle-click is an event handler: It is a function that will get called each time the button is clicked; we'll cover what it does later. Then as before we create a Window, and pass it to run-application.

The Window we create is a little more complicated this time: The content of the window is a Column, which is a container of parts that are displayed in a vertical stack. Above is the previously-defined count-label, and below it is a Button. The button shows a text in a foreground color, but the most important property is the action, which is bound to the previously-defined handle-click function. When the button is clicked, the implementation calls the procedure bound to the action property, which is handle-click.

The handle-click procedure takes one parameter named event (providing information about the event) - which is ignored. When it gets called, it first increments n, and then it updates the text property of the code-label.

Models descriptors

The functions Button, Label, and Column return fresh model descriptor ((is better terminology needed?)) objects. People talk about model (application data) vs view (a displayed component instance). These descriptors have aspects of both: A descriptor is model because it isn't tied to a specific display, window, or area of the screen. The same descriptor can displayed on multiple displays and multiple times on the same display. Hence a descriptor doesn't have a parent - just like list doesn't have a parent.

To illustate, let's modify the previous example so the count-label is displayed twice, once above and once below the button:

... unchanged except for following ...
(run-application
 (Window title: "Hello counter!"
	 content:
	 (Column
	  count-label
	  (Button text: "click here"
		  foreground: 'red
		  action: handle-click)
	  count-label)))

When the button is clicked, the action updates the count-label's text property - which causes the text to be updated in both places in the window.

Properties

A descriptor object has a number of named properties. A property is normally implemented as a private field which you access with coventional get and set methods; however, in Kawa you normally name the properties directly, without the get and set prefixes.

Usually you initialize them using the colon notation shown above when the object is created:

(Constructor name1: value1 name1: value1 ...)

This creates a new instance of Constructor, initializing the property named name1 to value1, and so on.

You can modify a property of an existing object in various ways, but the easiest may be using this syntax:

(set! object:name value)

This sets the property with the given name of the given object to the new value.

This change will propagate to other objects that depend on the object, which will often update the display. (The current prototype implementation does not propagate all the updates it should.)

Styles

Currently, only some ad-hoc style propertioes can be associated with a descriptor object, such the background color of a button. The plan is that a style will be a updatable collection of name-value bindings, and you will be able to assocate a style with a descriptor. The style is not used directly by the descriptor, but it is used when the descripctor is used as the model for a toolkit-specific view.