Wednesday, May 2, 2007

Visual Form File format

XAML this, XAML that, blah, blah, blah. I get so sick of hearing about how great XAML is, as if this were the most mind altering, earth shaking technology to hit the streets in years. Bah Humbug!

We've had something like this for years in the VCF! And the predecessor to XAML dates back even further than that, to Delphi's form files, NeXT's NIB files, and so on. So, I thought I'd post what the format for a Visual Form File (VFF) looks like, in Backus-Naur format:


component-decl ::= "object" component-id component-properties
*(component-decl) [component-delegates] "end"
component-id ::= component-name component-class ["," component-classid]

component-name ::= id
id ::= ALPHA *(ALPHA | DIGIT | '_' )
component-class ::= ALPHA *(ALPHA | DIGIT | '_' | "::" )
component-classid ::= ''' 1*(ALPHA | DIGIT | '-' ) '''

component-properties ::= 1*component-property
component-property ::= property-name '=' property-value
property-name ::= id | property-object-name | property-collection-name
property-object-name ::= id '.' property-name
property-collection-name ::= id '[' property-collection-key ']'
property-collection-key ::= property-number | property-string
property-value ::= property-string | property-number |
property-component-ref | property-enum |
property-enum-mask | property-binary | property-bool


property-string ::= ''' *(ALPHA | DIGIT | 'any printable unicode char' ) '''
property-number ::= 1*DIGIT ['.' 1*(DIGIT) ]
property-component-ref ::= ('@' component-name) | "null"
property-enum ::= id
property-enum-mask ::= '[' property-enum *[',' property-enum] ']'
property-binary ::= '{' binary-data '}'
binary-data ::= 1*(binary-byte)
binary-byte ::= (DIGIT | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' )
(DIGIT | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' )
property-bool ::= "true" | "false"

component-delegates ::= "delegates" *(component-delegate-decl) "end"
component-delegate-decl ::= delegate-name '=' delegate-array
delegate-name ::= id
delegate-array ::= '[' 1*(event-handler-ref) ']'
event-handler-ref ::= component-instance '@' component-callback-method
component-instance ::= id
component-callback-method ::= component-classname "::" component-methodname
component-classname ::= id
component-methodname ::= id


A simple example:

object window1 : VCF::Window
top = 500
left = 500
width = 400
height = 300
end

Note that the class name must be a fully qualified C++ class name, including the namespace the class belongs to.

A more complex example might look like this:

object Form1 : Window, 'ED88C0A1-26AB-11d4-B539-00C04F0196DA'
alignment = AlignNone
anchor = 0
bottom = 555.00000
color.blue = 0.78431
color.green = 0.81569
color.red = 0.83137
height = 537.00000
left = 234.00000
name = 'Form1'
top = 70.00000
visible = true
width = 565.00000

object label1 : VCF::Label, 'ED88C09F-26AB-11d4-B539-00C04F0196DA'
anchor = [AnchorLeft,AnchorRight]
bottom = 100.00000
caption = 'This is a label!'
color.blue = 0.50000
color.green = 1.00000
color.red = 0.00000
height = 45.00000
left = 20.00000
name = 'label1'
textAlignment = taTextLeft
top = 55.00000
verticalAlignment = tvaTextCenter
visible = true
width = 300.00000
wordWrap = false

delegates
end
end

delegates
end

end

This is what we use to load up components dynamically at runtime. So a form can be stored in format, and then loaded at runtime, dynamically no less (!), like so:


Window* window = Frame::createWindow( classid(VisualFormFilesWindow) );


So no one thinks we're using some new fangled version of C++, "classid" is simply a macro that gets the VCF Class instance from a given C++ class type.

When you call Frame::createWindow(), you get a new instance of your window class (called VisualFormFilesWindow), with all the controls and components as you've defined them in your VFF file! Voila!

There's more information on the VFF format here:
Visual Form File format

Something to note - in the latest version, we now support collection properties that can be specified via the RTTI macros, and can also be modified via the VFF format, for example:

object myObj : MyObjectWithItems
items[0] = 10
items[1] = 123
end

1 comment:

Oleksiy Gorelov said...

I think it would be much helpfull if there was an GUI designer. Like Interface Builder for example.