소스 검색

gui builder...

leonsal 8 년 전
부모
커밋
61319114e7
2개의 변경된 파일213개의 추가작업 그리고 86개의 파일을 삭제
  1. 196 86
      gui/builder.go
  2. 17 0
      gui/label.go

+ 196 - 86
gui/builder.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"io/ioutil"
 	"os"
+	"path/filepath"
 	"sort"
 	"strconv"
 	"strings"
@@ -18,8 +19,8 @@ import (
 
 // Builder builds GUI objects from a declarative description in YAML format
 type Builder struct {
-	desc   map[string]*panelDesc
-	panels []IPanel // first level panels
+	desc    map[string]*panelDesc // parsed descriptions
+	imgpath string                // base path for image panels files
 }
 
 type panelStyle struct {
@@ -39,28 +40,33 @@ type panelStyles struct {
 }
 
 type panelDesc struct {
-	Type        string
-	Name        string
-	Posx        float32
-	Posy        float32
-	Width       float32
-	Height      float32
-	Margins     string
-	Borders     string
-	BorderColor string
-	Paddings    string
-	Color       string
-	Enabled     bool
-	Visible     bool
-	Renderable  bool
-	Children    []*panelDesc
-	Layout      layoutAttr
-	Styles      *panelStyles
-	Text        string
-	FontSize    *float32
-	FontDPI     *float32
-	PlaceHolder string
-	MaxLength   *uint
+	Type         string   // Gui object type: Panel, Label, Edit, etc ...
+	Name         string   // Optional name for identification
+	Position     string   // Optional position as: x y | x,y
+	Width        float32  // Optional width (default = 0)
+	Height       float32  // Optional height (default = 0)
+	AspectWidth  *float32 // Optional aspectwidth (default = nil)
+	AspectHeight *float32 // Optional aspectwidth (default = nil)
+	Margins      string   // Optional margins as 1 or 4 float values
+	Borders      string   // Optional borders as 1 or 4 float values
+	BorderColor  string   // Optional border color as name or 3 or 4 float values
+	Paddings     string   // Optional paddings as 1 or 4 float values
+	Color        string   // Optional color as 1 or 4 float values
+	Enabled      bool
+	Visible      bool
+	Renderable   bool
+	Imagefile    string // Optional image filepath for ImagePanel
+	Children     []*panelDesc
+	Layout       layoutAttr
+	Styles       *panelStyles
+	Text         string
+	BgColor      string
+	FontColor    string // Optional
+	FontSize     *float32
+	FontDPI      *float32
+	LineSpacing  *float32
+	PlaceHolder  string
+	MaxLength    *uint
 }
 
 type layoutAttr struct {
@@ -68,14 +74,15 @@ type layoutAttr struct {
 }
 
 const (
-	descTypePanel    = "Panel"
-	descTypeLabel    = "Label"
-	descTypeEdit     = "Edit"
-	fieldMargins     = "margins"
-	fieldBorders     = "borders"
-	fieldBorderColor = "bordercolor"
-	fieldPaddings    = "paddings"
-	fieldColor       = "color"
+	descTypePanel      = "Panel"
+	descTypeImagePanel = "ImagePanel"
+	descTypeLabel      = "Label"
+	descTypeEdit       = "Edit"
+	fieldMargins       = "margins"
+	fieldBorders       = "borders"
+	fieldBorderColor   = "bordercolor"
+	fieldPaddings      = "paddings"
+	fieldColor         = "color"
 )
 
 //
@@ -83,9 +90,7 @@ const (
 //
 func NewBuilder() *Builder {
 
-	b := new(Builder)
-
-	return b
+	return new(Builder)
 }
 
 //
@@ -170,117 +175,222 @@ func (b *Builder) Build(name string) (IPanel, error) {
 	if !ok {
 		return nil, fmt.Errorf("Object name:%s not found", name)
 	}
-	return b.build(pd, name, nil)
+	return b.build(pd, nil)
+}
+
+// Sets the path for image panels relative image files
+func (b *Builder) SetImagepath(path string) {
+
+	b.imgpath = path
 }
 
 //
-// build builds gui objects from the specified description and its children recursively
+// build builds the gui object from the specified description.
+// All its children are also built recursively
+// Returns the built object or an error
 //
-func (b *Builder) build(pd *panelDesc, pname string, parent *Panel) (IPanel, error) {
+func (b *Builder) build(pd *panelDesc, iparent IPanel) (IPanel, error) {
 
 	fmt.Printf("\n%+v\n\n", pd)
 	var err error
 	var pan IPanel
 	switch pd.Type {
 	case descTypePanel:
-		pan, err = b.buildPanel(pd, pname)
+		pan, err = b.buildPanel(pd)
+	case descTypeImagePanel:
+		pan, err = b.buildImagePanel(pd)
 	case descTypeLabel:
-		pan, err = b.buildLabel(pd, pname)
+		pan, err = b.buildLabel(pd)
 	case descTypeEdit:
-		pan, err = b.buildEdit(pd, pname)
+		pan, err = b.buildEdit(pd)
 	default:
 		err = fmt.Errorf("Invalid panel type:%s", pd.Type)
 	}
 	if err != nil {
 		return nil, err
 	}
-	if parent != nil {
-		parent.Add(pan)
+	if iparent != nil {
+		iparent.GetPanel().Add(pan)
 	}
 	return pan, nil
 }
 
-func (b *Builder) buildPanel(pd *panelDesc, pname string) (IPanel, error) {
+// buildPanel builds a gui object of type: "Panel"
+func (b *Builder) buildPanel(pd *panelDesc) (IPanel, error) {
 
-	log.Error("buildPanel:[%s]", pd.Borders)
+	// Builds panel and set common attributes
 	pan := NewPanel(pd.Width, pd.Height)
-	pan.SetPosition(pd.Posx, pd.Posy)
-
-	// Set margin sizes
-	bs, err := b.parseBorderSizes(pname, fieldMargins, pd.Margins)
+	err := b.setCommon(pd, pan)
 	if err != nil {
 		return nil, err
 	}
-	if bs != nil {
-		pan.SetMarginsFrom(bs)
+
+	// Builds panel children recursively
+	for i := 0; i < len(pd.Children); i++ {
+		child, err := b.build(pd.Children[i], pan)
+		if err != nil {
+			return nil, err
+		}
+		pan.Add(child)
 	}
+	return pan, nil
+}
+
+// buildImagePanel builds a gui object of type: "ImagePanel"
+func (b *Builder) buildImagePanel(pd *panelDesc) (IPanel, error) {
 
-	// Set border sizes
-	bs, err = b.parseBorderSizes(pname, fieldBorders, pd.Borders)
+	// Imagefile must be supplied
+	if pd.Imagefile == "" {
+		return nil, b.err(pd.Name, "Imagefile", "Imagefile must be supplied")
+	}
+
+	// If path is not absolute join with user supplied image base path
+	path := pd.Imagefile
+	if !filepath.IsAbs(path) {
+		path = filepath.Join(b.imgpath, path)
+	}
+
+	// Builds panel and set common attributes
+	panel, err := NewImage(path)
 	if err != nil {
 		return nil, err
 	}
-	if bs != nil {
-		pan.SetBordersFrom(bs)
+	err = b.setCommon(pd, panel)
+	if err != nil {
+		return nil, err
+	}
+
+	// AspectWidth and AspectHeight attributes
+	if pd.AspectWidth != nil {
+		panel.SetContentAspectWidth(*pd.AspectWidth)
+	}
+	if pd.AspectHeight != nil {
+		panel.SetContentAspectHeight(*pd.AspectHeight)
+	}
+
+	// Builds panel children recursively
+	for i := 0; i < len(pd.Children); i++ {
+		child, err := b.build(pd.Children[i], panel)
+		if err != nil {
+			return nil, err
+		}
+		panel.Add(child)
 	}
+	return panel, nil
+}
+
+func (b *Builder) buildLabel(pd *panelDesc) (IPanel, error) {
 
-	// Set border color
-	c, err := b.parseColor(pname, fieldBorderColor, pd.BorderColor)
+	// Builds panel and set common attributes
+	label := NewLabel(pd.Text)
+	err := b.setCommon(pd, label)
 	if err != nil {
 		return nil, err
 	}
-	if c != nil {
-		pan.SetBordersColor4(c)
-	}
 
-	// Set paddings sizes
-	bs, err = b.parseBorderSizes(pname, fieldPaddings, pd.Paddings)
+	// Set optional background color
+	c, err := b.parseColor(pd.Name, "bgcolor", pd.BgColor)
 	if err != nil {
 		return nil, err
 	}
-	if bs != nil {
-		pan.SetPaddingsFrom(bs)
+	if c != nil {
+		label.SetBgColor4(c)
 	}
 
-	// Set color
-	c, err = b.parseColor(pname, fieldColor, pd.Color)
+	// Set optional font color
+	c, err = b.parseColor(pd.Name, "fontcolor", pd.FontColor)
 	if err != nil {
 		return nil, err
 	}
 	if c != nil {
-		pan.SetColor4(c)
+		label.SetColor4(c)
 	}
 
-	// Children
-	for i := 0; i < len(pd.Children); i++ {
-		child, err := b.build(pd.Children[i], pname, pan)
-		if err != nil {
-			return nil, err
-		}
-		pan.Add(child)
+	// Sets optional font size
+	if pd.FontSize != nil {
+		label.SetFontSize(float64(*pd.FontSize))
 	}
 
-	return pan, nil
-}
-
-func (b *Builder) buildLabel(pd *panelDesc, name string) (IPanel, error) {
+	// Sets optional font dpi
+	if pd.FontDPI != nil {
+		label.SetFontDPI(float64(*pd.FontDPI))
+	}
 
-	label := NewLabel(pd.Text)
-	label.SetPosition(pd.Posx, pd.Posy)
-	log.Error("label pos:%v", label.Position())
+	// Sets optional line spacing
+	if pd.LineSpacing != nil {
+		label.SetLineSpacing(float64(*pd.LineSpacing))
+	}
 
 	return label, nil
 }
 
-func (b *Builder) buildEdit(pa *panelDesc, name string) (IPanel, error) {
+func (b *Builder) buildEdit(pa *panelDesc) (IPanel, error) {
 
 	return nil, nil
 }
 
-//
+// setCommon sets the common attributes in the description to the specified panel
+func (b *Builder) setCommon(pd *panelDesc, ipan IPanel) error {
+
+	// Set optional position
+	panel := ipan.GetPanel()
+	if pd.Position != "" {
+		va, err := b.parseFloats(pd.Name, "position", pd.Position, 2, 2)
+		if va == nil || err != nil {
+			return err
+		}
+		panel.SetPosition(va[0], va[1])
+	}
+
+	// Set optional margin sizes
+	bs, err := b.parseBorderSizes(pd.Name, fieldMargins, pd.Margins)
+	if err != nil {
+		return err
+	}
+	if bs != nil {
+		panel.SetMarginsFrom(bs)
+	}
+
+	// Set optional border sizes
+	bs, err = b.parseBorderSizes(pd.Name, fieldBorders, pd.Borders)
+	if err != nil {
+		return err
+	}
+	if bs != nil {
+		panel.SetBordersFrom(bs)
+	}
+
+	// Set optional border color
+	c, err := b.parseColor(pd.Name, fieldBorderColor, pd.BorderColor)
+	if err != nil {
+		return err
+	}
+	if c != nil {
+		panel.SetBordersColor4(c)
+	}
+
+	// Set optional paddings sizes
+	bs, err = b.parseBorderSizes(pd.Name, fieldPaddings, pd.Paddings)
+	if err != nil {
+		return err
+	}
+	if bs != nil {
+		panel.SetPaddingsFrom(bs)
+	}
+
+	// Set optional color
+	c, err = b.parseColor(pd.Name, fieldColor, pd.Color)
+	if err != nil {
+		return err
+	}
+	if c != nil {
+		panel.SetColor4(c)
+	}
+	return nil
+}
+
 // parseBorderSizes parses a string field which can contain one float value or
 // float values. In the first case all borders has the same width
-//
 func (b *Builder) parseBorderSizes(pname, fname, field string) (*BorderSizes, error) {
 
 	va, err := b.parseFloats(pname, fname, field, 1, 4)
@@ -340,7 +450,7 @@ func (b *Builder) parseFloats(pname, fname, field string, min, max int) ([]float
 	// Separate individual fields
 	var parts []string
 	if strings.Index(field, ",") < 0 {
-		parts = strings.Split(field, " ")
+		parts = strings.Fields(field)
 	} else {
 		parts = strings.Split(field, ",")
 	}
@@ -351,7 +461,7 @@ func (b *Builder) parseFloats(pname, fname, field string, min, max int) ([]float
 	// Parse each field value and appends to slice
 	var values []float32
 	for i := 0; i < len(parts); i++ {
-		val, err := strconv.ParseFloat(parts[i], 32)
+		val, err := strconv.ParseFloat(strings.Trim(parts[i], " "), 32)
 		if err != nil {
 			return nil, fmt.Errorf("Error parsing float32 field:[%s]: %s", field, err)
 		}

+ 17 - 0
gui/label.go

@@ -162,6 +162,23 @@ func (l *Label) FontSize() float64 {
 	return l.fontSize
 }
 
+// SetFontDPI sets the font dots per inch
+func (l *Label) SetFontDPI(dpi float64) *Label {
+
+	l.fontDPI = dpi
+	l.SetText(l.currentText)
+	return l
+}
+
+// SetLineSpacing sets the spacing between lines.
+// The default value is 1.0
+func (l *Label) SetLineSpacing(spacing float64) *Label {
+
+	l.lineSpacing = spacing
+	l.SetText(l.currentText)
+	return l
+}
+
 // setTextCaret sets the label text and draws a caret at the
 // specified line and column.
 // It is normally used by the Edit widget.