When developing a graphics user interface based application, it is convinient to assemble it from simple and elastic components, such as buttons, text areas, draggable icons, canvases, menus, windows and so on. The common name for these components is “widget”. SLAYER is shipped with its own framework for creating and using widgets.
In order to use the widget framework, one shall
(use-modules (widgets base))
. It creates and exports the main widget
under the symbol *stage*
, and sets the appropriate display and resize
procedures, as well as handlers for mouse1 and mouse2 press and release events
and mousemove event.
It also contains a definition of a <widget>
class, which is the base
class for all widgets. Here's a simplified definition of <widget>
class
(in fact, all event handler slots are initialized to noop, and their init
keywords correspond strictly to their names):
(define-class <widget> () (parent #:init-value #f #:init-keyword #:parent) (children #:init-value '() #:init-keyword #:children) ;; event handlers (initialized to noop) left-mouse-down left-mouse-up right-mouse-down right-mouse-up mouse-over mouse-out drag update! activate deactivate resize (x #:init-value 0 #:init-keyword #:x) (y #:init-value 0 #:init-keyword #:y) (w #:init-value 0 #:init-keyword #:w) (h #:init-value 0 #:init-keyword #:h))
As you can see, the widget structure is hierarchical: all widgets (except
*stage*
) have their parent, and some can have their children.
The biggest part of the definition consists of some event handlers, which
are called in certain situations (like clicking, dragging and so on).
Furthermore, all widgets have rectangular shape, and the rectangle should be
big enough to fit all of the widget's children (otherwise they can become
unreachable).
In order to use the widget framework, it is enough to load the desired
widget modules and add their instances to *stage*
using the
(add-child! /instance-of-a-widget/ #;to *stage*)
. The simplest program
that uses widgets – a draggable rectangle – could look like this:
(use-modules (slayer) (slayer image) (widgets base) (widgets sprite) (oop goops)) (keydn 'esc quit) (define-method (dragger (w <widget>)) (lambda (x y xrel yrel) (slot-set! w 'x (+ (slot-ref w 'x) xrel)) (slot-set! w 'y (+ (slot-ref w 'y) yrel)))) (let* ((rect (rectangle #;w 50 #;h 50 #;color #xcc33dd)) (img (make-image rect #;x 50 #;y 50))) (slot-set! img 'drag (dragger img)) (add-child! img #;to *stage*))
There are a few widgets already bundled with slayer, among which there is <text-area> widget (which still requires some work) and <3d-view> widget.
Check the slayer.scm demo to see how to use them.
Note also, that although the direct layer described in the previous chapter is rather stable and will only be extended rather than modified, the widget layer is more likely to change.