For convenience of specifying widgets hierarchy in Lisp code, the let-ui macro is introduced.
(let-ui ui-description &body body) ui-description ::= widget widget ::= (class properties child*) properties ::= {:prop-name prop-value}* child ::= widget properties child ::= (:expr expr) properties
:var
for specifying the variable name to which the object will be bound
:prop-name
is :var
This macro creates widgets and evaluates the body. Widgets that have :var
specified are bound to lexical variables with specified names.
ui-description specifies the hierarchy of widgets in a window. It can specify either the entire top-level window or other kind of widgets. ui-description is a mini-language for specifying widgets. let-ui creates specified widgets, lexically binds specified variables to widgets and evaluates the body. The body my refer to these widgets.
widget is the specification of a single widget. It may specify some properties (slots of objects) and their values (the expressions to be evaluated), a variable name that will be bound to the widget (the :var
property whose prop-value must be a symbol) and widget's children.
class specifies the class of the widget (e.g., label, button, gtk-window). :prop-name may be any slot of the class. If :var property is specified, then corresponding variable is accessible in body and its value is the widget on which it is specified as :var.
Container widgets may specify their children along with their child properties. Child properties specify how children are used in widget. They are specific to the type of the container:
:expand
, :fill
. See box-pack-start for information.
:resize
, :shrink
. See paned-pack-1 for information.
:left
, :right
, :top
, :bottom
, :x-options
, :y-options
, x-padding
, y-padding
. Of these, :left
, :right
, :top
and :bottom
are mandatory. See table-attach for information.
An example:
(let-ui (gtk-window :title "Hello" :position :center :var w (v-box (label :label "Hello, world!") (button :label "gtk-ok" :use-stock t) :expand nil)) (widget-show w))
produces this output:
More complex example from demo of cl-gtk2-gtk-glext:
(let-ui (v-paned :var v (:expr (opengl-window-drawing-area window)) :resize t :shrink nil (v-box (h-paned (scrolled-window :hscrollbar-policy :automatic :vscrollbar-policy :automatic (:expr (opengl-window-expose-fn-text-view window))) :resize t :shrink nil (scrolled-window :hscrollbar-policy :automatic :vscrollbar-policy :automatic (:expr (opengl-window-resize-fn-text-view window))) :resize t :shrink nil) (h-box (button :label "Update functions" :var update-fns-button) :expand nil (button :label "Redraw" :var redraw-button) :expand nil) :expand nil) :resize t :shrink nil) (container-add window v) (connect-signal update-fns-button "clicked" (lambda (b) (declare (ignore b)) (update-fns window))) (connect-signal redraw-button "clicked" (lambda (b) (declare (ignore b)) (widget-queue-draw (opengl-window-drawing-area window)))) (let ((area (opengl-window-drawing-area window))) (setf (gl-drawing-area-on-expose area) (lambda (w e) (declare (ignore w e)) (opengl-interactive-on-expose window)) (gl-drawing-area-on-resize area) (lambda (widget w h) (declare (ignore widget)) (opengl-interactive-on-resize window w h)))))
produces this output:
In this example, not top-level window, but a widget is created and then added to already existing window. This UI also uses some already created widgets: (:expr (opengl-window-resize-fn-text-view window))
.