Documentation
¶
Overview ¶
Package wml loads window layouts from XML files at run time, similar to QML or XAML. A layout describes windows and controls of package wui; this package parses it, validates it against a schema and builds the real controls.
<wml version="1">
<Window Name="main" Title="Login" InnerSize="400,300">
<Label Text="User" Bounds="10,14,60,18"/>
<EditLine Name="user" Bounds="80,10,300,22"/>
<Button Name="ok" Text="Login" Bounds="300,260,90,26" OnClick="doLogin"/>
</Window>
</wml>
The work happens in three steps:
- Parse reads the XML into a Document. It enforces size limits, rejects DOCTYPEs and namespaces, and tracks line and column of every element and attribute. Parse also validates, so a Document is always valid. This step needs no Windows API and is safe to call from any goroutine.
- Document.Build creates the wui controls, applies the properties in a fixed, schema-defined order, binds event handlers by name and fills a struct with the controls you want to use. Build must be called on the GUI thread, like every other wui call. It is only available on Windows.
- You call Show on the window.
A minimal program:
type form struct {
Window *wui.Window `wml:"main"`
User *wui.EditLine `wml:"user"`
}
func main() {
doc, err := wml.ParseFile("login.xml")
if err != nil { log.Fatal(err) }
var f form
_, err = doc.Build(&f, wml.Handlers{
"doLogin": func() { println(f.User.Text()) },
})
if err != nil { log.Fatal(err) }
f.Window.Show()
}
XML contains data only. It never contains code: events refer to Go functions by name, and every handler is type checked against the event it is bound to.
Index ¶
Constants ¶
const CurrentVersion = 1
CurrentVersion is the WML format version written by Marshal and the only version understood by this package.
Variables ¶
var DefaultLimits = Limits{MaxBytes: 4 << 20, MaxDepth: 64, MaxNodes: 10000}
DefaultLimits are used when no WithLimits option is given.
Functions ¶
Types ¶
type Attr ¶
type Attr struct {
Name string
Value string
Line int // position of the attribute name, 0 if unknown
Col int
}
Attr is one attribute of an element.
type Document ¶
type Document struct {
File string // file name used in error messages, may be empty
Version int // format version, always CurrentVersion after Parse
Windows []*Node // the <Window> elements in file order
Warnings []*Error // only filled when parsing with Lenient()
}
Document is a parsed and validated WML file. A Document is immutable once it was returned by Parse: it can be shared between goroutines and built any number of times.
func NewDocument ¶
NewDocument creates a Document for programmatic construction. Call Validate before building it.
func Parse ¶
func Parse(r io.Reader, opts ...ParseOption) (*Document, error)
Parse reads, checks and validates a WML document. It never panics on bad input. Problems are returned as an *Error or an ErrorList.
func ParseFS ¶
ParseFS parses the file name in fsys, for example an embed.FS. The name must be a valid io/fs path, so it cannot escape the file system.
func ParseFile ¶
func ParseFile(path string, opts ...ParseOption) (*Document, error)
ParseFile parses the file at path. The path is used as the file name in error messages.
type Error ¶
type Error struct {
File string // file name given with WithFileName/ParseFile, may be empty
Line int // 1-based, 0 if unknown
Col int // 1-based byte column, 0 if unknown
Msg string
}
Error is a problem found in a WML document. It always carries the position of the offending element or attribute so that messages look like
login.xml:12:9: unknown property "Txet" on Button; did you mean "Text"?
type ErrorList ¶
type ErrorList []*Error
ErrorList is returned by Parse, Validate and Build when more than one problem was found. All problems are reported at once, not just the first.
type Kind ¶
type Kind int
Kind is the value kind of a property.
const ( KindString Kind = iota KindBool KindInt KindFloat KindColor KindEnum KindInts KindList KindFloats )
Property kinds. How each one is written in XML:
KindString any text KindBool true | false KindInt a whole number, e.g. 25 KindFloat a decimal number, e.g. 0.5 KindColor #RRGGBB or #RGB KindEnum one of a fixed list of names, case-insensitive KindInts comma separated whole numbers, e.g. Bounds="10,10,100,25" KindList not an attribute: repeated child elements, e.g. <Item> KindFloats comma separated decimal numbers, e.g. MinMax="0,1.5"
type Limits ¶
type Limits struct {
MaxBytes int // size of the whole file, default 4 MiB
MaxDepth int // element nesting depth, default 64
MaxNodes int // number of elements, default 10000
}
Limits bound the size of a document so that hostile or broken input cannot use unbounded memory or time. A zero field means "use the default".
type Node ¶
type Node struct {
Type string
Attrs []Attr
Children []*Node
Text string // trimmed character data, only used by list items
Line int // position of the element's '<', 0 if unknown
Col int
}
Node is one element of a WML document. The element name is the control type ("Window", "Button", ...), attributes are properties and events, children are nested controls, Font and list items.
type ParseOption ¶
type ParseOption func(*parseConfig)
ParseOption changes how a document is parsed.
func Lenient ¶
func Lenient() ParseOption
Lenient turns unknown properties into warnings (Document.Warnings) instead of errors. Everything else is still checked strictly.
func WithFileName ¶
func WithFileName(name string) ParseOption
WithFileName sets the file name that is shown in error messages.
func WithLimits ¶
func WithLimits(l Limits) ParseOption
WithLimits replaces the default limits. Zero fields keep their default.
type PropSpec ¶
type PropSpec struct {
Name string
Kind Kind
Setter string // method name on the wui type, default "Set"+Name
Alt string // method name to try if Setter does not exist
Enum []string // KindEnum: the names, the index is the numeric value
N int // KindInts: how many numbers
Min, Max int64 // KindInt and KindInts: inclusive range
FMin, FMax float64 // KindFloat: inclusive range
NonNegTail int // KindInts: the last NonNegTail numbers must be >= 0
Elem string // KindList: the child element name
Covers []string // properties that this one sets as well, they conflict
}
PropSpec describes one property of a control type.