leonsal 8 лет назад
Родитель
Сommit
a63ac016fb
3 измененных файлов с 703 добавлено и 666 удалено
  1. 74 664
      gui/builder.go
  2. 627 0
      gui/builder_panel.go
  3. 2 2
      gui/vboxlayout.go

+ 74 - 664
gui/builder.go

@@ -1,13 +1,13 @@
 // Copyright 2016 The G3N Authors. All rights reserved.
 // Copyright 2016 The G3N Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 // license that can be found in the LICENSE file.
+
 package gui
 package gui
 
 
 import (
 import (
 	"fmt"
 	"fmt"
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
-	"path/filepath"
 	"sort"
 	"sort"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
@@ -21,10 +21,10 @@ import (
 // Builder builds GUI objects from a declarative description in YAML format
 // Builder builds GUI objects from a declarative description in YAML format
 type Builder struct {
 type Builder struct {
 	am       map[string]interface{}     // parsed map with gui object atttributes
 	am       map[string]interface{}     // parsed map with gui object atttributes
-	imgpath  string                     // base path for image panels files
 	builders map[string]BuilderFunc     // map of builder functions by type
 	builders map[string]BuilderFunc     // map of builder functions by type
 	attribs  map[string]AttribCheckFunc // map of attribute name with check functions
 	attribs  map[string]AttribCheckFunc // map of attribute name with check functions
 	layouts  map[string]IBuilderLayout  // map of layout type to layout builder
 	layouts  map[string]IBuilderLayout  // map of layout type to layout builder
+	imgpath  string                     // base path for image panels files
 }
 }
 
 
 // IBuilderLayout is the interface for all layout builders
 // IBuilderLayout is the interface for all layout builders
@@ -36,6 +36,9 @@ type IBuilderLayout interface {
 // BuilderFunc is type for functions which build a gui object from an attribute map
 // BuilderFunc is type for functions which build a gui object from an attribute map
 type BuilderFunc func(*Builder, map[string]interface{}) (IPanel, error)
 type BuilderFunc func(*Builder, map[string]interface{}) (IPanel, error)
 
 
+// IgnoreSuffix specified the suffix of ignored keys
+const IgnoreSuffix = "_"
+
 // Panel and layout types
 // Panel and layout types
 const (
 const (
 	TypePanel       = "panel"
 	TypePanel       = "panel"
@@ -171,6 +174,7 @@ var mapResizable = map[string]Resizable{
 	"all":    ResizeAll,
 	"all":    ResizeAll,
 }
 }
 
 
+// AttribCheckFunc is the type for all attribute check functions
 type AttribCheckFunc func(b *Builder, am map[string]interface{}, fname string) error
 type AttribCheckFunc func(b *Builder, am map[string]interface{}, fname string) error
 
 
 // NewBuilder creates and returns a pointer to a new gui Builder object
 // NewBuilder creates and returns a pointer to a new gui Builder object
@@ -284,7 +288,6 @@ func (b *Builder) ParseString(desc string) error {
 			break
 			break
 		}
 		}
 	}
 	}
-	log.Error("single:%v", single)
 
 
 	// Internal function which converts map[interface{}]interface{} to
 	// Internal function which converts map[interface{}]interface{} to
 	// map[string]interface{} recursively and lower case of all map keys.
 	// map[string]interface{} recursively and lower case of all map keys.
@@ -315,6 +318,10 @@ func (b *Builder) ParseString(desc string) error {
 					return nil, fmt.Errorf("Keys must be strings")
 					return nil, fmt.Errorf("Keys must be strings")
 				}
 				}
 				ks = strings.ToLower(ks)
 				ks = strings.ToLower(ks)
+				// Ignores keys suffixed by IgnoreSuffix
+				if strings.HasSuffix(ks, IgnoreSuffix) {
+					continue
+				}
 				// Checks value
 				// Checks value
 				vi, err := visitor(v, ms)
 				vi, err := visitor(v, ms)
 				if err != nil {
 				if err != nil {
@@ -389,11 +396,13 @@ func (b *Builder) ParseFile(filepath string) error {
 func (b *Builder) Names() []string {
 func (b *Builder) Names() []string {
 
 
 	var objs []string
 	var objs []string
+	// Single object
 	if b.am[AttribType] != nil {
 	if b.am[AttribType] != nil {
 		objs = append(objs, "")
 		objs = append(objs, "")
 		return objs
 		return objs
 	}
 	}
-	for name, _ := range b.am {
+	// Multiple objects
+	for name := range b.am {
 		objs = append(objs, name)
 		objs = append(objs, name)
 	}
 	}
 	sort.Strings(objs)
 	sort.Strings(objs)
@@ -419,7 +428,7 @@ func (b *Builder) Build(name string) (IPanel, error) {
 	return b.build(am.(map[string]interface{}), nil)
 	return b.build(am.(map[string]interface{}), nil)
 }
 }
 
 
-// Sets the path for image panels relative image files
+// SetImagePath Sets the path for image panels relative image files
 func (b *Builder) SetImagepath(path string) {
 func (b *Builder) SetImagepath(path string) {
 
 
 	b.imgpath = path
 	b.imgpath = path
@@ -460,620 +469,77 @@ func (b *Builder) build(am map[string]interface{}, iparent IPanel) (IPanel, erro
 	return pan, nil
 	return pan, nil
 }
 }
 
 
-// buildPanel builds an object of type Panel
-func buildPanel(b *Builder, am map[string]interface{}) (IPanel, error) {
-
-	pan := NewPanel(0, 0)
-	err := b.setAttribs(am, pan, asPANEL)
-	if err != nil {
-		return nil, err
-	}
-
-	// Builds children recursively
-	if am[AttribItems] != nil {
-		items := am[AttribItems].([]map[string]interface{})
-		for i := 0; i < len(items); i++ {
-			item := items[i]
-			child, err := b.build(item, pan)
-			if err != nil {
-				return nil, err
-			}
-			pan.Add(child)
-		}
-	}
-	return pan, nil
-}
-
-// buildImagePanel builds a gui object of type ImagePanel
-func buildImagePanel(b *Builder, am map[string]interface{}) (IPanel, error) {
-
-	// Checks imagefile attribute
-	if am[AttribImageFile] == nil {
-		return nil, b.err(am, AttribImageFile, "Must be supplied")
-	}
-
-	// If path is not absolute join with user supplied image base path
-	imagefile := am[AttribImageFile].(string)
-	if !filepath.IsAbs(imagefile) {
-		imagefile = filepath.Join(b.imgpath, imagefile)
-	}
-
-	// Builds panel and set common attributes
-	panel, err := NewImage(imagefile)
-	if err != nil {
-		return nil, err
-	}
-	err = b.setAttribs(am, panel, asPANEL)
-	if err != nil {
-		return nil, err
-	}
-
-	// Sets optional AspectWidth attribute
-	if aw := am[AttribAspectWidth]; aw != nil {
-		panel.SetContentAspectWidth(aw.(float32))
-	}
-
-	// Sets optional AspectHeight attribute
-	if ah := am[AttribAspectHeight]; ah != nil {
-		panel.SetContentAspectHeight(ah.(float32))
-	}
-
-	// Builds children recursively
-	if am[AttribItems] != nil {
-		items := am[AttribItems].([]map[string]interface{})
-		for i := 0; i < len(items); i++ {
-			item := items[i]
-			child, err := b.build(item, panel)
-			if err != nil {
-				return nil, err
-			}
-			panel.Add(child)
-		}
-	}
-	return panel, nil
-}
-
-// buildLabel builds a gui object of type Label
-func buildLabel(b *Builder, am map[string]interface{}) (IPanel, error) {
-
-	var label *Label
-	if am[AttribIcon] != nil {
-		label = NewLabel(am[AttribIcon].(string), true)
-	} else if am[AttribText] != nil {
-		label = NewLabel(am[AttribText].(string))
-	} else {
-		label = NewLabel("")
-	}
-
-	// Sets common attributes
-	err := b.setAttribs(am, label, asPANEL)
-	if err != nil {
-		return nil, err
-	}
-
-	// Set optional background color
-	if bgc := am[AttribBgColor]; bgc != nil {
-		label.SetBgColor4(bgc.(*math32.Color4))
-	}
-
-	// Set optional font color
-	if fc := am[AttribFontColor]; fc != nil {
-		label.SetColor4(fc.(*math32.Color4))
-	}
-
-	// Sets optional font size
-	if fs := am[AttribFontSize]; fs != nil {
-		label.SetFontSize(float64(fs.(float32)))
-	}
-
-	// Sets optional font dpi
-	if fdpi := am[AttribFontDPI]; fdpi != nil {
-		label.SetFontDPI(float64(fdpi.(float32)))
-	}
-
-	// Sets optional line spacing
-	if ls := am[AttribLineSpacing]; ls != nil {
-		label.SetLineSpacing(float64(ls.(float32)))
-	}
-
-	return label, nil
-}
-
-// buildImageLabel builds a gui object of type: ImageLabel
-func buildImageLabel(b *Builder, am map[string]interface{}) (IPanel, error) {
-
-	// Builds image label and set common attributes
-	var text string
-	if am[AttribText] != nil {
-		text = am[AttribText].(string)
-	}
-	imglabel := NewImageLabel(text)
-	err := b.setAttribs(am, imglabel, asPANEL)
-	if err != nil {
-		return nil, err
-	}
-
-	// Sets optional icon(s)
-	if icon := am[AttribIcon]; icon != nil {
-		imglabel.SetIcon(icon.(string))
-	}
-
-	// Sets optional image from file
-	// If path is not absolute join with user supplied image base path
-	if imgf := am[AttribImageFile]; imgf != nil {
-		path := imgf.(string)
-		if !filepath.IsAbs(path) {
-			path = filepath.Join(b.imgpath, path)
-		}
-		err := imglabel.SetImageFromFile(path)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	return imglabel, nil
-}
-
-// buildButton builds a gui object of type: Button
-func buildButton(b *Builder, am map[string]interface{}) (IPanel, error) {
-
-	// Builds button and set commont attributes
-	var text string
-	if am[AttribText] != nil {
-		text = am[AttribText].(string)
-	}
-	button := NewButton(text)
-	err := b.setAttribs(am, button, asWIDGET)
-	if err != nil {
-		return nil, err
-	}
-
-	// Sets optional icon(s)
-	if icon := am[AttribIcon]; icon != nil {
-		button.SetIcon(icon.(string))
-	}
-
-	// Sets optional image from file
-	// If path is not absolute join with user supplied image base path
-	if imgf := am[AttribImageFile]; imgf != nil {
-		path := imgf.(string)
-		if !filepath.IsAbs(path) {
-			path = filepath.Join(b.imgpath, path)
-		}
-		err := button.SetImage(path)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	return button, nil
-}
-
-// buildEdit builds a gui object of type: "Edit"
-func buildEdit(b *Builder, am map[string]interface{}) (IPanel, error) {
-
-	// Builds button and set attributes
-	var width float32
-	var placeholder string
-	if aw := am[AttribWidth]; aw != nil {
-		width = aw.(float32)
-	}
-	if ph := am[AttribPlaceHolder]; ph != nil {
-		placeholder = ph.(string)
-	}
-	edit := NewEdit(int(width), placeholder)
-	err := b.setAttribs(am, edit, asWIDGET)
-	if err != nil {
-		return nil, err
-	}
-	return edit, nil
-}
-
-// buildCheckBox builds a gui object of type: CheckBox
-func buildCheckBox(b *Builder, am map[string]interface{}) (IPanel, error) {
-
-	// Builds check box and set commont attributes
-	var text string
-	if am[AttribText] != nil {
-		text = am[AttribText].(string)
-	}
-	cb := NewCheckBox(text)
-	err := b.setAttribs(am, cb, asWIDGET)
-	if err != nil {
-		return nil, err
-	}
-
-	// Sets optional checked value
-	if checked := am[AttribChecked]; checked != nil {
-		cb.SetValue(checked.(bool))
-	}
-	return cb, nil
-}
-
-// buildRadioButton builds a gui object of type: RadioButton
-func buildRadioButton(b *Builder, am map[string]interface{}) (IPanel, error) {
-
-	// Builds check box and set commont attributes
-	var text string
-	if am[AttribText] != nil {
-		text = am[AttribText].(string)
-	}
-	rb := NewRadioButton(text)
-	err := b.setAttribs(am, rb, asWIDGET)
-	if err != nil {
-		return nil, err
-	}
-
-	// Sets optional radio button group
-	if gr := am[AttribGroup]; gr != nil {
-		rb.SetGroup(gr.(string))
-	}
-
-	// Sets optional checked value
-	if checked := am[AttribChecked]; checked != nil {
-		rb.SetValue(checked.(bool))
-	}
-	return rb, nil
-}
-
-// buildVList builds a gui object of type: VList
-func buildVList(b *Builder, am map[string]interface{}) (IPanel, error) {
-
-	// Builds list and set commont attributes
-	list := NewVList(0, 0)
-	err := b.setAttribs(am, list, asWIDGET)
-	if err != nil {
-		return nil, err
-	}
-
-	// Builds children
-	if am[AttribItems] != nil {
-		items := am[AttribItems].([]map[string]interface{})
-		for i := 0; i < len(items); i++ {
-			item := items[i]
-			child, err := b.build(item, list)
-			if err != nil {
-				return nil, err
-			}
-			list.Add(child)
-		}
-	}
-	return list, nil
-}
-
-// buildHList builds a gui object of type: VList
-func buildHList(b *Builder, am map[string]interface{}) (IPanel, error) {
-
-	// Builds list and set commont attributes
-	list := NewHList(0, 0)
-	err := b.setAttribs(am, list, asWIDGET)
-	if err != nil {
-		return nil, err
-	}
-
-	// Builds children
-	if am[AttribItems] != nil {
-		items := am[AttribItems].([]map[string]interface{})
-		for i := 0; i < len(items); i++ {
-			item := items[i]
-			child, err := b.build(item, list)
-			if err != nil {
-				return nil, err
-			}
-			list.Add(child)
-		}
-	}
-	return list, nil
-}
-
-// buildDropDown builds a gui object of type: DropDown
-func buildDropDown(b *Builder, am map[string]interface{}) (IPanel, error) {
-
-	// If image label attribute defined use it, otherwise
-	// uses default value.
-	var imglabel *ImageLabel
-	if iv := am[AttribImageLabel]; iv != nil {
-		imgl := iv.(map[string]interface{})
-		imgl[AttribType] = TypeImageLabel
-		ipan, err := b.build(imgl, nil)
-		if err != nil {
-			return nil, err
-		}
-		imglabel = ipan.(*ImageLabel)
-	} else {
-		imglabel = NewImageLabel("")
-	}
-
-	// Builds drop down and set common attributes
-	dd := NewDropDown(0, imglabel)
-	err := b.setAttribs(am, dd, asWIDGET)
-	if err != nil {
-		return nil, err
-	}
-
-	// Builds children
-	if am[AttribItems] != nil {
-		items := am[AttribItems].([]map[string]interface{})
-		for i := 0; i < len(items); i++ {
-			item := items[i]
-			child, err := b.build(item, dd)
-			if err != nil {
-				return nil, err
-			}
-			dd.Add(child.(*ImageLabel))
-		}
-	}
-	return dd, nil
-}
-
-// buildMenu builds a gui object of type: Menu or MenuBar from the
-// specified panel descriptor.
-func buildMenu(b *Builder, am map[string]interface{}) (IPanel, error) {
+// setAttribs sets common attributes from the description to the specified panel
+// The attributes which are set can be specified by the specified bitmask.
+func (b *Builder) setAttribs(am map[string]interface{}, ipan IPanel, attr uint) error {
 
 
-	// Builds menu bar or menu
-	var menu *Menu
-	if am[AttribType].(string) == TypeMenuBar {
-		menu = NewMenuBar()
-	} else {
-		menu = NewMenu()
+	panel := ipan.GetPanel()
+	// Set optional position
+	if attr&aPOS != 0 && am[AttribPosition] != nil {
+		va := am[AttribPosition].([]float32)
+		panel.SetPosition(va[0], va[1])
 	}
 	}
 
 
-	// Only sets attribs for top level menus
-	if pi := am[AttribParent_]; pi != nil {
-		par := pi.(map[string]interface{})
-		ptype := ""
-		if ti := par[AttribType]; ti != nil {
-			ptype = ti.(string)
-		}
-		if ptype != TypeMenu && ptype != TypeMenuBar {
-			err := b.setAttribs(am, menu, asWIDGET)
-			if err != nil {
-				return nil, err
-			}
-		}
+	// Set optional panel width
+	if attr&aSIZE != 0 && am[AttribWidth] != nil {
+		panel.SetWidth(am[AttribWidth].(float32))
+		log.Error("set width:%v", am[AttribWidth])
 	}
 	}
 
 
-	// Builds and adds menu items
-	if am[AttribItems] != nil {
-		items := am[AttribItems].([]map[string]interface{})
-		for i := 0; i < len(items); i++ {
-			// Get the item optional type and text
-			item := items[i]
-			itype := ""
-			itext := ""
-			if iv := item[AttribType]; iv != nil {
-				itype = iv.(string)
-			}
-			if iv := item[AttribText]; iv != nil {
-				itext = iv.(string)
-			}
-			// Item is another menu
-			if itype == TypeMenu {
-				subm, err := buildMenu(b, item)
-				if err != nil {
-					return nil, err
-				}
-				menu.AddMenu(itext, subm.(*Menu))
-				continue
-			}
-			// Item is a separator
-			if itext == TypeSeparator {
-				menu.AddSeparator()
-				continue
-			}
-			// Item must be a menu option
-			mi := menu.AddOption(itext)
-			// Set item optional icon(s)
-			if icon := item[AttribIcon]; icon != nil {
-				mi.SetIcon(icon.(string))
-			}
-			// Sets optional menu item shortcut
-			if sci := item[AttribShortcut]; sci != nil {
-				sc := sci.([]int)
-				mi.SetShortcut(window.ModifierKey(sc[0]), window.Key(sc[1]))
-			}
-		}
+	// Sets optional panel height
+	if attr&aSIZE != 0 && am[AttribHeight] != nil {
+		panel.SetHeight(am[AttribHeight].(float32))
 	}
 	}
-	return menu, nil
-}
-
-// buildSlider builds a gui object of type: HSlider or VSlider
-func buildSlider(b *Builder, am map[string]interface{}) (IPanel, error) {
 
 
-	// Builds horizontal or vertical slider
-	var slider *Slider
-	if am[AttribType].(string) == TypeHSlider {
-		slider = NewHSlider(0, 0)
-	} else {
-		slider = NewVSlider(0, 0)
+	// Set optional margin sizes
+	if attr&aMARGINS != 0 && am[AttribMargins] != nil {
+		panel.SetMarginsFrom(am[AttribMargins].(*BorderSizes))
 	}
 	}
 
 
-	// Sets common attributes
-	err := b.setAttribs(am, slider, asWIDGET)
-	if err != nil {
-		return nil, err
+	// Set optional border sizes
+	if attr&aBORDERS != 0 && am[AttribBorders] != nil {
+		panel.SetBordersFrom(am[AttribBorders].(*BorderSizes))
 	}
 	}
 
 
-	// Sets optional text
-	if itext := am[AttribText]; itext != nil {
-		slider.SetText(itext.(string))
-	}
-	// Sets optional scale factor
-	if isf := am[AttribScaleFactor]; isf != nil {
-		slider.SetScaleFactor(isf.(float32))
-	}
-	// Sets optional value
-	if iv := am[AttribValue]; iv != nil {
-		slider.SetValue(iv.(float32))
+	// Set optional border color
+	if attr&aBORDERCOLOR != 0 && am[AttribBorderColor] != nil {
+		panel.SetBordersColor4(am[AttribBorderColor].(*math32.Color4))
 	}
 	}
-	return slider, nil
-}
 
 
-// buildSplitter builds a gui object of type: HSplitterr or VSplitter
-func buildSplitter(b *Builder, am map[string]interface{}) (IPanel, error) {
-
-	// Builds horizontal or vertical splitter
-	var splitter *Splitter
-	if am[AttribType].(string) == TypeHSplitter {
-		splitter = NewHSplitter(0, 0)
-	} else {
-		splitter = NewVSplitter(0, 0)
+	// Set optional paddings sizes
+	if attr&aPADDINGS != 0 && am[AttribPaddings] != nil {
+		panel.SetPaddingsFrom(am[AttribPaddings].(*BorderSizes))
 	}
 	}
 
 
-	// Sets common attributes
-	err := b.setAttribs(am, splitter, asWIDGET)
-	if err != nil {
-		return nil, err
+	// Set optional panel color
+	if attr&aCOLOR != 0 && am[AttribColor] != nil {
+		panel.SetColor4(am[AttribColor].(*math32.Color4))
 	}
 	}
 
 
-	// Sets optional split value
-	if v := am[AttribSplit]; v != nil {
-		splitter.SetSplit(v.(float32))
+	if attr&aNAME != 0 && am[AttribName] != nil {
+		panel.SetName(am[AttribName].(string))
 	}
 	}
 
 
-	// Internal function to set each of the splitter's panel attributes and items
-	setpan := func(attrib string, pan *Panel) error {
-
-		// Get internal panel attributes
-		ipattribs := am[attrib]
-		if ipattribs == nil {
-			return nil
-		}
-		pattr := ipattribs.(map[string]interface{})
-		// Set panel attributes
-		err := b.setAttribs(pattr, pan, asPANEL)
-		if err != nil {
-			return nil
-		}
-		// Builds panel children
-		if pattr[AttribItems] != nil {
-			items := pattr[AttribItems].([]map[string]interface{})
-			for i := 0; i < len(items); i++ {
-				item := items[i]
-				child, err := b.build(item, pan)
-				if err != nil {
-					return err
-				}
-				pan.Add(child)
-			}
-		}
-		return nil
+	if attr&aVISIBLE != 0 && am[AttribVisible] != nil {
+		panel.SetVisible(am[AttribVisible].(bool))
 	}
 	}
 
 
-	// Set optional splitter panel's attributes
-	err = setpan(AttribPanel0, &splitter.P0)
-	if err != nil {
-		return nil, err
+	if attr&aENABLED != 0 && am[AttribEnabled] != nil {
+		panel.SetEnabled(am[AttribEnabled].(bool))
 	}
 	}
-	err = setpan(AttribPanel1, &splitter.P1)
-	if err != nil {
-		return nil, err
+	if attr&aRENDER != 0 && am[AttribRender] != nil {
+		panel.SetRenderable(am[AttribRender].(bool))
 	}
 	}
 
 
-	return splitter, nil
-}
-
-// buildTree builds a gui object of type: Tree
-func buildTree(b *Builder, am map[string]interface{}) (IPanel, error) {
-
-	// Builds tree and sets its common attributes
-	tree := NewTree(0, 0)
-	err := b.setAttribs(am, tree, asWIDGET)
+	// Sets optional layout (must pass IPanel not *Panel)
+	err := b.setLayout(am, ipan)
 	if err != nil {
 	if err != nil {
-		return nil, err
-	}
-
-	// Internal function to build tree nodes recursively
-	var buildItems func(am map[string]interface{}, pnode *TreeNode) error
-	buildItems = func(am map[string]interface{}, pnode *TreeNode) error {
-
-		v := am[AttribItems]
-		if v == nil {
-			return nil
-		}
-		items := v.([]map[string]interface{})
-
-		for i := 0; i < len(items); i++ {
-			// Get the item type
-			item := items[i]
-			itype := ""
-			if v := item[AttribType]; v != nil {
-				itype = v.(string)
-			}
-			itext := ""
-			if v := item[AttribText]; v != nil {
-				itext = v.(string)
-			}
-
-			// Item is a tree node
-			if itype == "" || itype == TypeTreeNode {
-				var node *TreeNode
-				if pnode == nil {
-					node = tree.AddNode(itext)
-				} else {
-					node = pnode.AddNode(itext)
-				}
-				err := buildItems(item, node)
-				if err != nil {
-					return err
-				}
-				continue
-			}
-			// Other controls
-			ipan, err := b.build(item, nil)
-			if err != nil {
-				return err
-			}
-			if pnode == nil {
-				tree.Add(ipan)
-			} else {
-				pnode.Add(ipan)
-			}
-		}
 		return nil
 		return nil
 	}
 	}
 
 
-	// Build nodes
-	err = buildItems(am, nil)
-	if err != nil {
-		return nil, err
-	}
-	return tree, nil
-}
-
-// buildWindow builds a gui object of type: Window
-func buildWindow(b *Builder, am map[string]interface{}) (IPanel, error) {
-
-	// Builds window and sets its common attributes
-	win := NewWindow(0, 0)
-	err := b.setAttribs(am, win, asWIDGET)
-	if err != nil {
-		return nil, err
-	}
-
-	// Sets optional title
-	if title := am[AttribTitle]; title != nil {
-		win.SetTitle(title.(string))
-	}
-
-	// Set optional resizable borders
-	if resiz := am[AttribResizable]; resiz != nil {
-		win.SetResizable(resiz.(Resizable))
-	}
-
-	// Builds window children
-	if v := am[AttribItems]; v != nil {
-		items := v.([]map[string]interface{})
-		for i := 0; i < len(items); i++ {
-			item := items[i]
-			child, err := b.build(item, win)
-			if err != nil {
-				return nil, err
-			}
-			win.Add(child)
-		}
-	}
-	return win, nil
+	// Sets optional layout params
+	err = b.setLayoutParams(am, panel)
+	return err
 }
 }
 
 
 // setLayout sets the optional layout of the specified panel
 // setLayout sets the optional layout of the specified panel
@@ -1105,6 +571,7 @@ func (b *Builder) setLayout(am map[string]interface{}, ipan IPanel) error {
 	return nil
 	return nil
 }
 }
 
 
+// setLayoutParams sets the optional layout params of the specified panel and its attributes
 func (b *Builder) setLayoutParams(am map[string]interface{}, ipan IPanel) error {
 func (b *Builder) setLayoutParams(am map[string]interface{}, ipan IPanel) error {
 
 
 	// Get layout params attributes
 	// Get layout params attributes
@@ -1137,6 +604,7 @@ func (b *Builder) setLayoutParams(am map[string]interface{}, ipan IPanel) error
 	return nil
 	return nil
 }
 }
 
 
+// AttribCheckResizable checks and converts attribute with list of window resizable borders
 func AttribCheckResizable(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckResizable(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	// If attribute not found, ignore
 	// If attribute not found, ignore
@@ -1165,6 +633,7 @@ func AttribCheckResizable(b *Builder, am map[string]interface{}, fname string) e
 	return nil
 	return nil
 }
 }
 
 
+// AttributeCheckEdge checks and converts attribute with name of layout edge
 func AttribCheckEdge(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckEdge(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	v := am[fname]
 	v := am[fname]
@@ -1183,6 +652,7 @@ func AttribCheckEdge(b *Builder, am map[string]interface{}, fname string) error
 	return nil
 	return nil
 }
 }
 
 
+// AttributeCheckLayout checks and converts layout attribute
 func AttribCheckLayout(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckLayout(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	v := am[fname]
 	v := am[fname]
@@ -1204,6 +674,7 @@ func AttribCheckLayout(b *Builder, am map[string]interface{}, fname string) erro
 	return nil
 	return nil
 }
 }
 
 
+// AttributeCheckAlignt checks and converts layout align* attribute
 func AttribCheckAlign(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckAlign(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	v := am[fname]
 	v := am[fname]
@@ -1227,6 +698,7 @@ func AttribCheckAlign(b *Builder, am map[string]interface{}, fname string) error
 	return nil
 	return nil
 }
 }
 
 
+// AttributeCheckMenuShortcut checks and converts attribute describing menu shortcut key
 func AttribCheckMenuShortcut(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckMenuShortcut(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	v := am[fname]
 	v := am[fname]
@@ -1273,6 +745,7 @@ func AttribCheckMenuShortcut(b *Builder, am map[string]interface{}, fname string
 	return nil
 	return nil
 }
 }
 
 
+// AttributeCheckListMap checks and converts attribute to []map[string]interface{}
 func AttribCheckListMap(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckListMap(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	v := am[fname]
 	v := am[fname]
@@ -1296,6 +769,7 @@ func AttribCheckListMap(b *Builder, am map[string]interface{}, fname string) err
 	return nil
 	return nil
 }
 }
 
 
+// AttributeCheckMap checks and converts attribute to map[string]interface{}
 func AttribCheckMap(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckMap(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	v := am[fname]
 	v := am[fname]
@@ -1310,6 +784,7 @@ func AttribCheckMap(b *Builder, am map[string]interface{}, fname string) error {
 	return nil
 	return nil
 }
 }
 
 
+// AttribCheckIcons checks and converts attribute with a list of icon names or codepoints
 func AttribCheckIcons(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckIcons(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	v := am[fname]
 	v := am[fname]
@@ -1341,6 +816,7 @@ func AttribCheckIcons(b *Builder, am map[string]interface{}, fname string) error
 	return nil
 	return nil
 }
 }
 
 
+// AttribCheckColor checks and converts attribute with color name or color component values
 func AttribCheckColor(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckColor(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	// Checks if field is nil
 	// Checks if field is nil
@@ -1394,6 +870,7 @@ func AttribCheckColor(b *Builder, am map[string]interface{}, fname string) error
 	return nil
 	return nil
 }
 }
 
 
+// AttribCheckBorderSizes checks and convert attribute with border sizes
 func AttribCheckBorderSizes(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckBorderSizes(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	va, err := b.parseFloats(am, fname, 1, 4)
 	va, err := b.parseFloats(am, fname, 1, 4)
@@ -1411,6 +888,7 @@ func AttribCheckBorderSizes(b *Builder, am map[string]interface{}, fname string)
 	return nil
 	return nil
 }
 }
 
 
+// AttribCheckPosition checks and convert attribute with x and y position
 func AttribCheckPosition(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckPosition(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	v := am[fname]
 	v := am[fname]
@@ -1425,6 +903,7 @@ func AttribCheckPosition(b *Builder, am map[string]interface{}, fname string) er
 	return nil
 	return nil
 }
 }
 
 
+// AttribCheckStringLower checks and convert string attribute to lower case
 func AttribCheckStringLower(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckStringLower(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	err := AttribCheckString(b, am, fname)
 	err := AttribCheckString(b, am, fname)
@@ -1437,6 +916,7 @@ func AttribCheckStringLower(b *Builder, am map[string]interface{}, fname string)
 	return nil
 	return nil
 }
 }
 
 
+// AttribCheckFloat checks and convert attribute to float32
 func AttribCheckFloat(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckFloat(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	v := am[fname]
 	v := am[fname]
@@ -1456,6 +936,7 @@ func AttribCheckFloat(b *Builder, am map[string]interface{}, fname string) error
 	return nil
 	return nil
 }
 }
 
 
+// AttribCheckInt checks and convert attribute to int
 func AttribCheckInt(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckInt(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	v := am[fname]
 	v := am[fname]
@@ -1470,6 +951,7 @@ func AttribCheckInt(b *Builder, am map[string]interface{}, fname string) error {
 	return nil
 	return nil
 }
 }
 
 
+// AttribCheckString checks and convert attribute to string
 func AttribCheckString(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckString(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	v := am[fname]
 	v := am[fname]
@@ -1484,6 +966,7 @@ func AttribCheckString(b *Builder, am map[string]interface{}, fname string) erro
 	return nil
 	return nil
 }
 }
 
 
+// AttribCheckBool checks and convert attribute to bool
 func AttribCheckBool(b *Builder, am map[string]interface{}, fname string) error {
 func AttribCheckBool(b *Builder, am map[string]interface{}, fname string) error {
 
 
 	v := am[fname]
 	v := am[fname]
@@ -1498,79 +981,6 @@ func AttribCheckBool(b *Builder, am map[string]interface{}, fname string) error
 	return nil
 	return nil
 }
 }
 
 
-// setAttribs sets common attributes from the description to the specified panel
-// The attributes which are set can be specified by the specified bitmask.
-func (b *Builder) setAttribs(am map[string]interface{}, ipan IPanel, attr uint) error {
-
-	panel := ipan.GetPanel()
-	// Set optional position
-	if attr&aPOS != 0 && am[AttribPosition] != nil {
-		va := am[AttribPosition].([]float32)
-		panel.SetPosition(va[0], va[1])
-	}
-
-	// Set optional panel width
-	if attr&aSIZE != 0 && am[AttribWidth] != nil {
-		panel.SetWidth(am[AttribWidth].(float32))
-		log.Error("set width:%v", am[AttribWidth])
-	}
-
-	// Sets optional panel height
-	if attr&aSIZE != 0 && am[AttribHeight] != nil {
-		panel.SetHeight(am[AttribHeight].(float32))
-	}
-
-	// Set optional margin sizes
-	if attr&aMARGINS != 0 && am[AttribMargins] != nil {
-		panel.SetMarginsFrom(am[AttribMargins].(*BorderSizes))
-	}
-
-	// Set optional border sizes
-	if attr&aBORDERS != 0 && am[AttribBorders] != nil {
-		panel.SetBordersFrom(am[AttribBorders].(*BorderSizes))
-	}
-
-	// Set optional border color
-	if attr&aBORDERCOLOR != 0 && am[AttribBorderColor] != nil {
-		panel.SetBordersColor4(am[AttribBorderColor].(*math32.Color4))
-	}
-
-	// Set optional paddings sizes
-	if attr&aPADDINGS != 0 && am[AttribPaddings] != nil {
-		panel.SetPaddingsFrom(am[AttribPaddings].(*BorderSizes))
-	}
-
-	// Set optional panel color
-	if attr&aCOLOR != 0 && am[AttribColor] != nil {
-		panel.SetColor4(am[AttribColor].(*math32.Color4))
-	}
-
-	if attr&aNAME != 0 && am[AttribName] != nil {
-		panel.SetName(am[AttribName].(string))
-	}
-
-	if attr&aVISIBLE != 0 && am[AttribVisible] != nil {
-		panel.SetVisible(am[AttribVisible].(bool))
-	}
-
-	if attr&aENABLED != 0 && am[AttribEnabled] != nil {
-		panel.SetEnabled(am[AttribEnabled].(bool))
-	}
-	if attr&aRENDER != 0 && am[AttribRender] != nil {
-		panel.SetRenderable(am[AttribRender].(bool))
-	}
-
-	// Sets optional layout (must pass IPanel not *Panel)
-	err := b.setLayout(am, ipan)
-	if err != nil {
-		return nil
-	}
-
-	// Sets optional layout params
-	err = b.setLayoutParams(am, panel)
-	return err
-}
-
 // parseFloats parses a string with a list of floats with the specified size
 // parseFloats parses a string with a list of floats with the specified size
 // and returns a slice. The specified size is 0 any number of floats is allowed.
 // and returns a slice. The specified size is 0 any number of floats is allowed.
 // The individual values can be separated by spaces or commas
 // The individual values can be separated by spaces or commas

+ 627 - 0
gui/builder_panel.go

@@ -0,0 +1,627 @@
+// Copyright 2016 The G3N Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+package gui
+
+import (
+	"path/filepath"
+
+	"github.com/g3n/engine/math32"
+	"github.com/g3n/engine/window"
+)
+
+// buildPanel builds an object of type Panel
+func buildPanel(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	pan := NewPanel(0, 0)
+	err := b.setAttribs(am, pan, asPANEL)
+	if err != nil {
+		return nil, err
+	}
+
+	// Builds children recursively
+	if am[AttribItems] != nil {
+		items := am[AttribItems].([]map[string]interface{})
+		for i := 0; i < len(items); i++ {
+			item := items[i]
+			child, err := b.build(item, pan)
+			if err != nil {
+				return nil, err
+			}
+			pan.Add(child)
+		}
+	}
+	return pan, nil
+}
+
+// buildImagePanel builds a gui object of type ImagePanel
+func buildImagePanel(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	// Checks imagefile attribute
+	if am[AttribImageFile] == nil {
+		return nil, b.err(am, AttribImageFile, "Must be supplied")
+	}
+
+	// If path is not absolute join with user supplied image base path
+	imagefile := am[AttribImageFile].(string)
+	if !filepath.IsAbs(imagefile) {
+		imagefile = filepath.Join(b.imgpath, imagefile)
+	}
+
+	// Builds panel and set common attributes
+	panel, err := NewImage(imagefile)
+	if err != nil {
+		return nil, err
+	}
+	err = b.setAttribs(am, panel, asPANEL)
+	if err != nil {
+		return nil, err
+	}
+
+	// Sets optional AspectWidth attribute
+	if aw := am[AttribAspectWidth]; aw != nil {
+		panel.SetContentAspectWidth(aw.(float32))
+	}
+
+	// Sets optional AspectHeight attribute
+	if ah := am[AttribAspectHeight]; ah != nil {
+		panel.SetContentAspectHeight(ah.(float32))
+	}
+
+	// Builds children recursively
+	if am[AttribItems] != nil {
+		items := am[AttribItems].([]map[string]interface{})
+		for i := 0; i < len(items); i++ {
+			item := items[i]
+			child, err := b.build(item, panel)
+			if err != nil {
+				return nil, err
+			}
+			panel.Add(child)
+		}
+	}
+	return panel, nil
+}
+
+// buildLabel builds a gui object of type Label
+func buildLabel(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	var label *Label
+	if am[AttribIcon] != nil {
+		label = NewLabel(am[AttribIcon].(string), true)
+	} else if am[AttribText] != nil {
+		label = NewLabel(am[AttribText].(string))
+	} else {
+		label = NewLabel("")
+	}
+
+	// Sets common attributes
+	err := b.setAttribs(am, label, asPANEL)
+	if err != nil {
+		return nil, err
+	}
+
+	// Set optional background color
+	if bgc := am[AttribBgColor]; bgc != nil {
+		label.SetBgColor4(bgc.(*math32.Color4))
+	}
+
+	// Set optional font color
+	if fc := am[AttribFontColor]; fc != nil {
+		label.SetColor4(fc.(*math32.Color4))
+	}
+
+	// Sets optional font size
+	if fs := am[AttribFontSize]; fs != nil {
+		label.SetFontSize(float64(fs.(float32)))
+	}
+
+	// Sets optional font dpi
+	if fdpi := am[AttribFontDPI]; fdpi != nil {
+		label.SetFontDPI(float64(fdpi.(float32)))
+	}
+
+	// Sets optional line spacing
+	if ls := am[AttribLineSpacing]; ls != nil {
+		label.SetLineSpacing(float64(ls.(float32)))
+	}
+
+	return label, nil
+}
+
+// buildImageLabel builds a gui object of type: ImageLabel
+func buildImageLabel(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	// Builds image label and set common attributes
+	var text string
+	if am[AttribText] != nil {
+		text = am[AttribText].(string)
+	}
+	imglabel := NewImageLabel(text)
+	err := b.setAttribs(am, imglabel, asPANEL)
+	if err != nil {
+		return nil, err
+	}
+
+	// Sets optional icon(s)
+	if icon := am[AttribIcon]; icon != nil {
+		imglabel.SetIcon(icon.(string))
+	}
+
+	// Sets optional image from file
+	// If path is not absolute join with user supplied image base path
+	if imgf := am[AttribImageFile]; imgf != nil {
+		path := imgf.(string)
+		if !filepath.IsAbs(path) {
+			path = filepath.Join(b.imgpath, path)
+		}
+		err := imglabel.SetImageFromFile(path)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return imglabel, nil
+}
+
+// buildButton builds a gui object of type: Button
+func buildButton(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	// Builds button and set commont attributes
+	var text string
+	if am[AttribText] != nil {
+		text = am[AttribText].(string)
+	}
+	button := NewButton(text)
+	err := b.setAttribs(am, button, asWIDGET)
+	if err != nil {
+		return nil, err
+	}
+
+	// Sets optional icon(s)
+	if icon := am[AttribIcon]; icon != nil {
+		button.SetIcon(icon.(string))
+	}
+
+	// Sets optional image from file
+	// If path is not absolute join with user supplied image base path
+	if imgf := am[AttribImageFile]; imgf != nil {
+		path := imgf.(string)
+		if !filepath.IsAbs(path) {
+			path = filepath.Join(b.imgpath, path)
+		}
+		err := button.SetImage(path)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return button, nil
+}
+
+// buildEdit builds a gui object of type: "Edit"
+func buildEdit(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	// Builds button and set attributes
+	var width float32
+	var placeholder string
+	if aw := am[AttribWidth]; aw != nil {
+		width = aw.(float32)
+	}
+	if ph := am[AttribPlaceHolder]; ph != nil {
+		placeholder = ph.(string)
+	}
+	edit := NewEdit(int(width), placeholder)
+	err := b.setAttribs(am, edit, asWIDGET)
+	if err != nil {
+		return nil, err
+	}
+	return edit, nil
+}
+
+// buildCheckBox builds a gui object of type: CheckBox
+func buildCheckBox(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	// Builds check box and set commont attributes
+	var text string
+	if am[AttribText] != nil {
+		text = am[AttribText].(string)
+	}
+	cb := NewCheckBox(text)
+	err := b.setAttribs(am, cb, asWIDGET)
+	if err != nil {
+		return nil, err
+	}
+
+	// Sets optional checked value
+	if checked := am[AttribChecked]; checked != nil {
+		cb.SetValue(checked.(bool))
+	}
+	return cb, nil
+}
+
+// buildRadioButton builds a gui object of type: RadioButton
+func buildRadioButton(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	// Builds check box and set commont attributes
+	var text string
+	if am[AttribText] != nil {
+		text = am[AttribText].(string)
+	}
+	rb := NewRadioButton(text)
+	err := b.setAttribs(am, rb, asWIDGET)
+	if err != nil {
+		return nil, err
+	}
+
+	// Sets optional radio button group
+	if gr := am[AttribGroup]; gr != nil {
+		rb.SetGroup(gr.(string))
+	}
+
+	// Sets optional checked value
+	if checked := am[AttribChecked]; checked != nil {
+		rb.SetValue(checked.(bool))
+	}
+	return rb, nil
+}
+
+// buildVList builds a gui object of type: VList
+func buildVList(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	// Builds list and set commont attributes
+	list := NewVList(0, 0)
+	err := b.setAttribs(am, list, asWIDGET)
+	if err != nil {
+		return nil, err
+	}
+
+	// Builds children
+	if am[AttribItems] != nil {
+		items := am[AttribItems].([]map[string]interface{})
+		for i := 0; i < len(items); i++ {
+			item := items[i]
+			child, err := b.build(item, list)
+			if err != nil {
+				return nil, err
+			}
+			list.Add(child)
+		}
+	}
+	return list, nil
+}
+
+// buildHList builds a gui object of type: VList
+func buildHList(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	// Builds list and set commont attributes
+	list := NewHList(0, 0)
+	err := b.setAttribs(am, list, asWIDGET)
+	if err != nil {
+		return nil, err
+	}
+
+	// Builds children
+	if am[AttribItems] != nil {
+		items := am[AttribItems].([]map[string]interface{})
+		for i := 0; i < len(items); i++ {
+			item := items[i]
+			child, err := b.build(item, list)
+			if err != nil {
+				return nil, err
+			}
+			list.Add(child)
+		}
+	}
+	return list, nil
+}
+
+// buildDropDown builds a gui object of type: DropDown
+func buildDropDown(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	// If image label attribute defined use it, otherwise
+	// uses default value.
+	var imglabel *ImageLabel
+	if iv := am[AttribImageLabel]; iv != nil {
+		imgl := iv.(map[string]interface{})
+		imgl[AttribType] = TypeImageLabel
+		ipan, err := b.build(imgl, nil)
+		if err != nil {
+			return nil, err
+		}
+		imglabel = ipan.(*ImageLabel)
+	} else {
+		imglabel = NewImageLabel("")
+	}
+
+	// Builds drop down and set common attributes
+	dd := NewDropDown(0, imglabel)
+	err := b.setAttribs(am, dd, asWIDGET)
+	if err != nil {
+		return nil, err
+	}
+
+	// Builds children
+	if am[AttribItems] != nil {
+		items := am[AttribItems].([]map[string]interface{})
+		for i := 0; i < len(items); i++ {
+			item := items[i]
+			child, err := b.build(item, dd)
+			if err != nil {
+				return nil, err
+			}
+			dd.Add(child.(*ImageLabel))
+		}
+	}
+	return dd, nil
+}
+
+// buildMenu builds a gui object of type: Menu or MenuBar from the
+// specified panel descriptor.
+func buildMenu(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	// Builds menu bar or menu
+	var menu *Menu
+	if am[AttribType].(string) == TypeMenuBar {
+		menu = NewMenuBar()
+	} else {
+		menu = NewMenu()
+	}
+
+	// Only sets attribs for top level menus
+	if pi := am[AttribParent_]; pi != nil {
+		par := pi.(map[string]interface{})
+		ptype := ""
+		if ti := par[AttribType]; ti != nil {
+			ptype = ti.(string)
+		}
+		if ptype != TypeMenu && ptype != TypeMenuBar {
+			err := b.setAttribs(am, menu, asWIDGET)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	// Builds and adds menu items
+	if am[AttribItems] != nil {
+		items := am[AttribItems].([]map[string]interface{})
+		for i := 0; i < len(items); i++ {
+			// Get the item optional type and text
+			item := items[i]
+			itype := ""
+			itext := ""
+			if iv := item[AttribType]; iv != nil {
+				itype = iv.(string)
+			}
+			if iv := item[AttribText]; iv != nil {
+				itext = iv.(string)
+			}
+			// Item is another menu
+			if itype == TypeMenu {
+				subm, err := buildMenu(b, item)
+				if err != nil {
+					return nil, err
+				}
+				menu.AddMenu(itext, subm.(*Menu))
+				continue
+			}
+			// Item is a separator
+			if itext == TypeSeparator {
+				menu.AddSeparator()
+				continue
+			}
+			// Item must be a menu option
+			mi := menu.AddOption(itext)
+			// Set item optional icon(s)
+			if icon := item[AttribIcon]; icon != nil {
+				mi.SetIcon(icon.(string))
+			}
+			// Sets optional menu item shortcut
+			if sci := item[AttribShortcut]; sci != nil {
+				sc := sci.([]int)
+				mi.SetShortcut(window.ModifierKey(sc[0]), window.Key(sc[1]))
+			}
+		}
+	}
+	return menu, nil
+}
+
+// buildSlider builds a gui object of type: HSlider or VSlider
+func buildSlider(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	// Builds horizontal or vertical slider
+	var slider *Slider
+	if am[AttribType].(string) == TypeHSlider {
+		slider = NewHSlider(0, 0)
+	} else {
+		slider = NewVSlider(0, 0)
+	}
+
+	// Sets common attributes
+	err := b.setAttribs(am, slider, asWIDGET)
+	if err != nil {
+		return nil, err
+	}
+
+	// Sets optional text
+	if itext := am[AttribText]; itext != nil {
+		slider.SetText(itext.(string))
+	}
+	// Sets optional scale factor
+	if isf := am[AttribScaleFactor]; isf != nil {
+		slider.SetScaleFactor(isf.(float32))
+	}
+	// Sets optional value
+	if iv := am[AttribValue]; iv != nil {
+		slider.SetValue(iv.(float32))
+	}
+	return slider, nil
+}
+
+// buildSplitter builds a gui object of type: HSplitterr or VSplitter
+func buildSplitter(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	// Builds horizontal or vertical splitter
+	var splitter *Splitter
+	if am[AttribType].(string) == TypeHSplitter {
+		splitter = NewHSplitter(0, 0)
+	} else {
+		splitter = NewVSplitter(0, 0)
+	}
+
+	// Sets common attributes
+	err := b.setAttribs(am, splitter, asWIDGET)
+	if err != nil {
+		return nil, err
+	}
+
+	// Sets optional split value
+	if v := am[AttribSplit]; v != nil {
+		splitter.SetSplit(v.(float32))
+	}
+
+	// Internal function to set each of the splitter's panel attributes and items
+	setpan := func(attrib string, pan *Panel) error {
+
+		// Get internal panel attributes
+		ipattribs := am[attrib]
+		if ipattribs == nil {
+			return nil
+		}
+		pattr := ipattribs.(map[string]interface{})
+		// Set panel attributes
+		err := b.setAttribs(pattr, pan, asPANEL)
+		if err != nil {
+			return nil
+		}
+		// Builds panel children
+		if pattr[AttribItems] != nil {
+			items := pattr[AttribItems].([]map[string]interface{})
+			for i := 0; i < len(items); i++ {
+				item := items[i]
+				child, err := b.build(item, pan)
+				if err != nil {
+					return err
+				}
+				pan.Add(child)
+			}
+		}
+		return nil
+	}
+
+	// Set optional splitter panel's attributes
+	err = setpan(AttribPanel0, &splitter.P0)
+	if err != nil {
+		return nil, err
+	}
+	err = setpan(AttribPanel1, &splitter.P1)
+	if err != nil {
+		return nil, err
+	}
+
+	return splitter, nil
+}
+
+// buildTree builds a gui object of type: Tree
+func buildTree(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	// Builds tree and sets its common attributes
+	tree := NewTree(0, 0)
+	err := b.setAttribs(am, tree, asWIDGET)
+	if err != nil {
+		return nil, err
+	}
+
+	// Internal function to build tree nodes recursively
+	var buildItems func(am map[string]interface{}, pnode *TreeNode) error
+	buildItems = func(am map[string]interface{}, pnode *TreeNode) error {
+
+		v := am[AttribItems]
+		if v == nil {
+			return nil
+		}
+		items := v.([]map[string]interface{})
+
+		for i := 0; i < len(items); i++ {
+			// Get the item type
+			item := items[i]
+			itype := ""
+			if v := item[AttribType]; v != nil {
+				itype = v.(string)
+			}
+			itext := ""
+			if v := item[AttribText]; v != nil {
+				itext = v.(string)
+			}
+
+			// Item is a tree node
+			if itype == "" || itype == TypeTreeNode {
+				var node *TreeNode
+				if pnode == nil {
+					node = tree.AddNode(itext)
+				} else {
+					node = pnode.AddNode(itext)
+				}
+				err := buildItems(item, node)
+				if err != nil {
+					return err
+				}
+				continue
+			}
+			// Other controls
+			ipan, err := b.build(item, nil)
+			if err != nil {
+				return err
+			}
+			if pnode == nil {
+				tree.Add(ipan)
+			} else {
+				pnode.Add(ipan)
+			}
+		}
+		return nil
+	}
+
+	// Build nodes
+	err = buildItems(am, nil)
+	if err != nil {
+		return nil, err
+	}
+	return tree, nil
+}
+
+// buildWindow builds a gui object of type: Window
+func buildWindow(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	// Builds window and sets its common attributes
+	win := NewWindow(0, 0)
+	err := b.setAttribs(am, win, asWIDGET)
+	if err != nil {
+		return nil, err
+	}
+
+	// Sets optional title
+	if title := am[AttribTitle]; title != nil {
+		win.SetTitle(title.(string))
+	}
+
+	// Set optional resizable borders
+	if resiz := am[AttribResizable]; resiz != nil {
+		win.SetResizable(resiz.(Resizable))
+	}
+
+	// Builds window children
+	if v := am[AttribItems]; v != nil {
+		items := v.([]map[string]interface{})
+		for i := 0; i < len(items); i++ {
+			item := items[i]
+			child, err := b.build(item, win)
+			if err != nil {
+				return nil, err
+			}
+			win.Add(child)
+		}
+	}
+	return win, nil
+}

+ 2 - 2
gui/vboxlayout.go

@@ -208,7 +208,7 @@ func (bl *VBoxLayout) Recalc(ipan IPanel) {
 		// Calculates initial y position which depends
 		// Calculates initial y position which depends
 		// on the current horizontal alignment.
 		// on the current horizontal alignment.
 		switch bl.alignV {
 		switch bl.alignV {
-		case AlignTop:
+		case AlignNone, AlignTop:
 			posY = 0
 			posY = 0
 		case AlignCenter:
 		case AlignCenter:
 			posY = (parent.ContentHeight() - theight) / 2
 			posY = (parent.ContentHeight() - theight) / 2
@@ -239,7 +239,7 @@ func (bl *VBoxLayout) Recalc(ipan IPanel) {
 		}
 		}
 		cwidth := pan.Width()
 		cwidth := pan.Width()
 		switch params.AlignH {
 		switch params.AlignH {
-		case AlignLeft:
+		case AlignNone, AlignLeft:
 			posX = 0
 			posX = 0
 		case AlignCenter:
 		case AlignCenter:
 			posX = (width - cwidth) / 2
 			posX = (width - cwidth) / 2