#lang scribble/manual @(require scribble/eval (for-label racket)) @title{GUIML} This is a DSL for describing GUIs. It is inspired by SXML notation and the HTMLPrag library. "GUIML" is a thin wrapper around Racket's standard GUI library that allows a window and all its initial contents to be specified in a single expression, instead of having to specify each child widget's parent by name. Here is a simple GUI: @racketblock[ (define g (guiml (frame% (|@| (label "Foobar") (width 640) (height 150)) (vertical-panel% (|@|) (message% (|@| (label "Hello, world!"))) (editor-canvas% 'ecanvas (|@|)) (button% (|@| (label "Close") (style '(border)) (callback (lambda ignored-args (sendmsg g show #f))))))))) ] @scheme[g] is actually of a subclass of @scheme[frame%]. The subclass is generated on the fly, and allows all the widgets in the tree to be tagged with an optional identifier, which can be used to retrieve a widget from the tree even if it's not bound to a variable. Usage: @defform[ #:literals (guiml |@|) (guiml (class% [id] (|@| (class-parameter val) ...) (child-class% [child-id] (|@| ...) [grandchildren] ...) [more-children] ...))] The @scheme[|@|] subform contains all the arguments required by that object's @scheme[new] operator, except the @scheme[parent], which is added automatically. This subform is required even if it's empty. Within the context of the above @scheme[guiml] form, this: @racketblock[ (button% (|@| (label "Close") (style '(border)) (callback (λ ignored-args (sendmsg g show #f))))) ] is equivalent to this: @racketblock[ (new button% (parent the-vertical-panel-above-this-in-the-tree) (label "Close") (style '(border)) (callback (λ ignored-args (sendmsg g show #f)))) ] The @scheme[|@|] subform is followed by all the object's children. To give an object in the tree a name, you put the identifier in front of the @scheme[|@|] subform: @racketblock[ (guiml frame% ... (editor-canvas% 'ecanvas (|@|))) ] The identifier can be of any type, and by default will be compared with @scheme[eq?] Then the same object can be retrieved from the tree using @scheme[get-widget-by-id]: @racketblock[ (get-widget-by-id g 'ecanvas) ] You can specify a comparator if you used an identifier that can't be compared with @scheme[eq?]: @racketblock[ (get-widget-by-id g "ecanvas" string=?) ] You can also retrieve all the objects of a given class from the tree: @racketblock[ (get-widgets-by-type g button%) ] Each object in the tree has its own semaphore, which can be obtained like this: @racketblock[ (send g get-semaphore) ] The following syntax is provided for backward compatibility: @racketblock[ (sendmsg g show #t) ] In older versions of GUIML, the GUI objects were wrapped in a bundle of structs and lists, and that was how they were tagged with identifiers and arranged in a tree that could be traversed. The @scheme[sendmsg] form allowed you to somewhat still be able to treat this structure like a class.