Previous: Gtk+ Flags, Up: Gtk Reference


6.8 Gtk+ Embedded UI Mini-language

For convenience of specifying widgets hierarchy in Lisp code, the let-ui macro is introduced.

— Macro: let-ui
     (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
class
Name of class of a widget
:prop-name
Name of class's slot or a :var for specifying the variable name to which the object will be bound
prop-value
A Lisp expression that will be evaluated to obtain the initarg for slot of a class; or a symbol if :prop-name is :var
expr
An expression that will be evaluated to obtain the widget

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:

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:

let-ui.png

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:

let-ui-glext.png

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)).