Przeglądaj źródła

gui.TabBar builder

leonsal 8 lat temu
rodzic
commit
48f952c850
3 zmienionych plików z 131 dodań i 29 usunięć
  1. 45 18
      gui/builder.go
  2. 56 0
      gui/builder_panel.go
  3. 30 11
      gui/tabbar.go

+ 45 - 18
gui/builder.go

@@ -67,6 +67,7 @@ const (
 	TypeWindow      = "window"
 	TypeWindow      = "window"
 	TypeChart       = "chart"
 	TypeChart       = "chart"
 	TypeTable       = "table"
 	TypeTable       = "table"
+	TypeTabBar      = "tabbar"
 	TypeHBoxLayout  = "hbox"
 	TypeHBoxLayout  = "hbox"
 	TypeVBoxLayout  = "vbox"
 	TypeVBoxLayout  = "vbox"
 	TypeGridLayout  = "grid"
 	TypeGridLayout  = "grid"
@@ -87,6 +88,7 @@ const (
 	AttribCols           = "cols"          // int GridLayout
 	AttribCols           = "cols"          // int GridLayout
 	AttribColSpan        = "colspan"       // int GridLayout
 	AttribColSpan        = "colspan"       // int GridLayout
 	AttribColumns        = "columns"       // []map[string]interface{} Table
 	AttribColumns        = "columns"       // []map[string]interface{} Table
+	AttribContent        = "content"       // map[string]interface{} Table
 	AttribCountStepx     = "countstepx"    // float32
 	AttribCountStepx     = "countstepx"    // float32
 	AttribEdge           = "edge"          // int
 	AttribEdge           = "edge"          // int
 	AttribEnabled        = "enabled"       // bool
 	AttribEnabled        = "enabled"       // bool
@@ -121,6 +123,7 @@ const (
 	AttribPanel0         = "panel0"        // map[string]interface{}
 	AttribPanel0         = "panel0"        // map[string]interface{}
 	AttribPanel1         = "panel1"        // map[string]interface{}
 	AttribPanel1         = "panel1"        // map[string]interface{}
 	AttribParentInternal = "parent_"       // string (internal attribute)
 	AttribParentInternal = "parent_"       // string (internal attribute)
+	AttribPinned         = "pinned"        // bool
 	AttribPlaceHolder    = "placeholder"   // string
 	AttribPlaceHolder    = "placeholder"   // string
 	AttribPosition       = "position"      // []float32
 	AttribPosition       = "position"      // []float32
 	AttribRangeAuto      = "rangeauto"     // bool
 	AttribRangeAuto      = "rangeauto"     // bool
@@ -147,19 +150,19 @@ const (
 )
 )
 
 
 const (
 const (
-	aPOS         = 1 << iota                                  // attribute position
-	aSIZE        = 1 << iota                                  // attribute size
-	aNAME        = 1 << iota                                  // attribute name
-	aMARGINS     = 1 << iota                                  // attribute margins widths
-	aBORDERS     = 1 << iota                                  // attribute borders widths
-	aBORDERCOLOR = 1 << iota                                  // attribute border color
-	aPADDINGS    = 1 << iota                                  // attribute paddings widths
-	aCOLOR       = 1 << iota                                  // attribute panel bgcolor
-	aENABLED     = 1 << iota                                  // attribute enabled for events
-	aRENDER      = 1 << iota                                  // attribute renderable
-	aVISIBLE     = 1 << iota                                  // attribute visible
-	asPANEL      = 0xFF                                       // attribute set for panels
-	asWIDGET     = aPOS | aNAME | aSIZE | aENABLED | aVISIBLE // attribute set for widgets
+	aPOS         = 1 << iota                                             // attribute position
+	aSIZE        = 1 << iota                                             // attribute size
+	aNAME        = 1 << iota                                             // attribute name
+	aMARGINS     = 1 << iota                                             // attribute margins widths
+	aBORDERS     = 1 << iota                                             // attribute borders widths
+	aBORDERCOLOR = 1 << iota                                             // attribute border color
+	aPADDINGS    = 1 << iota                                             // attribute paddings widths
+	aCOLOR       = 1 << iota                                             // attribute panel bgcolor
+	aENABLED     = 1 << iota                                             // attribute enabled for events
+	aRENDER      = 1 << iota                                             // attribute renderable
+	aVISIBLE     = 1 << iota                                             // attribute visible
+	asPANEL      = 0xFF                                                  // attribute set for panels
+	asWIDGET     = aPOS | aNAME | aMARGINS | aSIZE | aENABLED | aVISIBLE // attribute set for widgets
 )
 )
 
 
 // maps align name with align parameter
 // maps align name with align parameter
@@ -232,6 +235,7 @@ func NewBuilder() *Builder {
 		TypeWindow:      buildWindow,
 		TypeWindow:      buildWindow,
 		TypeChart:       buildChart,
 		TypeChart:       buildChart,
 		TypeTable:       buildTable,
 		TypeTable:       buildTable,
+		TypeTabBar:      buildTabBar,
 	}
 	}
 	// Sets map of layout type name to layout function
 	// Sets map of layout type name to layout function
 	b.layouts = map[string]IBuilderLayout{
 	b.layouts = map[string]IBuilderLayout{
@@ -255,6 +259,7 @@ func NewBuilder() *Builder {
 		AttribCols:          AttribCheckInt,
 		AttribCols:          AttribCheckInt,
 		AttribColSpan:       AttribCheckInt,
 		AttribColSpan:       AttribCheckInt,
 		AttribColumns:       AttribCheckListMap,
 		AttribColumns:       AttribCheckListMap,
+		AttribContent:       AttribCheckMap,
 		AttribCountStepx:    AttribCheckFloat,
 		AttribCountStepx:    AttribCheckFloat,
 		AttribEdge:          AttribCheckEdge,
 		AttribEdge:          AttribCheckEdge,
 		AttribEnabled:       AttribCheckBool,
 		AttribEnabled:       AttribCheckBool,
@@ -287,6 +292,7 @@ func NewBuilder() *Builder {
 		AttribPaddings:      AttribCheckBorderSizes,
 		AttribPaddings:      AttribCheckBorderSizes,
 		AttribPanel0:        AttribCheckMap,
 		AttribPanel0:        AttribCheckMap,
 		AttribPanel1:        AttribCheckMap,
 		AttribPanel1:        AttribCheckMap,
+		AttribPinned:        AttribCheckBool,
 		AttribPlaceHolder:   AttribCheckString,
 		AttribPlaceHolder:   AttribCheckString,
 		AttribPosition:      AttribCheckPosition,
 		AttribPosition:      AttribCheckPosition,
 		AttribRangeAuto:     AttribCheckBool,
 		AttribRangeAuto:     AttribCheckBool,
@@ -360,6 +366,9 @@ func (b *Builder) ParseString(desc string) error {
 
 
 		case map[interface{}]interface{}:
 		case map[interface{}]interface{}:
 			ms := make(map[string]interface{})
 			ms := make(map[string]interface{})
+			if par != nil {
+				ms[AttribParentInternal] = par
+			}
 			for k, v := range vt {
 			for k, v := range vt {
 				// Checks key
 				// Checks key
 				ks, ok := k.(string)
 				ks, ok := k.(string)
@@ -377,7 +386,7 @@ func (b *Builder) ParseString(desc string) error {
 					return nil, err
 					return nil, err
 				}
 				}
 				ms[ks] = vi
 				ms[ks] = vi
-				// If has panel has parent or is a single top level panel, checks attributes
+				// If has parent or is a single top level panel, checks attributes
 				if par != nil || single {
 				if par != nil || single {
 					// Get attribute check function
 					// Get attribute check function
 					acf, ok := b.attribs[ks]
 					acf, ok := b.attribs[ks]
@@ -391,9 +400,6 @@ func (b *Builder) ParseString(desc string) error {
 					}
 					}
 				}
 				}
 			}
 			}
-			if par != nil {
-				ms[AttribParentInternal] = par
-			}
 			return ms, nil
 			return ms, nil
 
 
 		default:
 		default:
@@ -1122,7 +1128,28 @@ func (b *Builder) parseFloats(am map[string]interface{}, fname string, min, max
 // err creates and returns an error for the current object, field name and with the specified message
 // err creates and returns an error for the current object, field name and with the specified message
 func (b *Builder) err(am map[string]interface{}, fname, msg string) error {
 func (b *Builder) err(am map[string]interface{}, fname, msg string) error {
 
 
-	return fmt.Errorf("Error in object:%s field:%s -> %s", am[AttribName], fname, msg)
+	// Get path of objects till the error
+	names := []string{}
+	var name string
+	for {
+		if v := am[AttribName]; v != nil {
+			name = v.(string)
+		} else {
+			name = "?"
+		}
+		names = append(names, name)
+		var par interface{}
+		if par = am[AttribParentInternal]; par == nil {
+			break
+		}
+		am = par.(map[string]interface{})
+	}
+	path := []string{}
+	for i := len(names) - 1; i >= 0; i-- {
+		path = append(path, names[i])
+	}
+
+	return fmt.Errorf("Error in object:%s field:%s -> %s", strings.Join(path, "/"), fname, msg)
 }
 }
 
 
 // debugPrint prints the internal attribute map of the builder for debugging.
 // debugPrint prints the internal attribute map of the builder for debugging.

+ 56 - 0
gui/builder_panel.go

@@ -800,3 +800,59 @@ func buildTable(b *Builder, am map[string]interface{}) (IPanel, error) {
 
 
 	return table, nil
 	return table, nil
 }
 }
+
+// buildTabBar builds a gui object of type: TabBare
+func buildTabBar(b *Builder, am map[string]interface{}) (IPanel, error) {
+
+	// Creates TabBar and set common attributes
+	tabbar := NewTabBar(0, 0)
+	err := b.setAttribs(am, tabbar, asPANEL)
+	if err != nil {
+		return nil, err
+	}
+	v := am[AttribItems]
+
+	// For each tab
+	if v != nil {
+		items := v.([]map[string]interface{})
+		for _, item := range items {
+			// Creates Tab
+			text := ""
+			if v := item[AttribText]; v != nil {
+				text = v.(string)
+			}
+			tab := tabbar.AddTab(text)
+			// Sets optional icon
+			if v := item[AttribIcon]; v != nil {
+				tab.SetIcon(v.(string))
+			}
+			// Sets optional image
+			if v := item[AttribImageFile]; v != nil {
+				// If path is not absolute join with user supplied image base path
+				imagefile := v.(string)
+				if !filepath.IsAbs(imagefile) {
+					imagefile = filepath.Join(b.imgpath, imagefile)
+				}
+				err := tab.SetImage(imagefile)
+				if err != nil {
+					return nil, err
+				}
+			}
+			// Sets content panel
+			if v := item[AttribContent]; v != nil {
+				am := v.(map[string]interface{})
+				content, err := b.build(am, nil)
+				if err != nil {
+					return nil, err
+				}
+				tab.SetContent(content)
+			}
+			// Sets pinned state
+			if v := item[AttribPinned]; v != nil {
+				tab.SetPinned(v.(bool))
+			}
+		}
+	}
+
+	return tabbar, nil
+}

+ 30 - 11
gui/tabbar.go

@@ -133,7 +133,6 @@ func (tb *TabBar) InsertTab(text string, pos int) *Tab {
 	copy(tb.tabs[pos+1:], tb.tabs[pos:])
 	copy(tb.tabs[pos+1:], tb.tabs[pos:])
 	tb.tabs[pos] = tab
 	tb.tabs[pos] = tab
 	tb.Add(&tab.header)
 	tb.Add(&tab.header)
-	tb.Add(&tab.content)
 
 
 	tb.update()
 	tb.update()
 	tb.recalc()
 	tb.recalc()
@@ -152,7 +151,9 @@ func (tb *TabBar) RemoveTab(pos int) error {
 	// Remove tab from TabBar panel
 	// Remove tab from TabBar panel
 	tab := tb.tabs[pos]
 	tab := tb.tabs[pos]
 	tb.Remove(&tab.header)
 	tb.Remove(&tab.header)
-	tb.Remove(&tab.content)
+	if tab.content != nil {
+		tb.Remove(tab.content)
+	}
 
 
 	// Remove tab from tabbar array
 	// Remove tab from tabbar array
 	copy(tb.tabs[pos:], tb.tabs[pos+1:])
 	copy(tb.tabs[pos:], tb.tabs[pos+1:])
@@ -353,10 +354,13 @@ func (tb *TabBar) recalc() {
 		tab.recalc(tabWidth)
 		tab.recalc(tabWidth)
 		tab.header.SetPosition(headerx, 0)
 		tab.header.SetPosition(headerx, 0)
 		// Sets size and position of the Tab content panel
 		// Sets size and position of the Tab content panel
-		contenty := tab.header.Height() + tb.styles.SepHeight
-		tab.content.SetWidth(tb.ContentWidth())
-		tab.content.SetHeight(tb.ContentHeight() - contenty)
-		tab.content.SetPosition(0, contenty)
+		if tab.content != nil {
+			cpan := tab.content.GetPanel()
+			contenty := tab.header.Height() + tb.styles.SepHeight
+			cpan.SetWidth(tb.ContentWidth())
+			cpan.SetHeight(tb.ContentHeight() - contenty)
+			cpan.SetPosition(0, contenty)
+		}
 		headerx += tab.header.Width()
 		headerx += tab.header.Width()
 		// If Tab can be shown set its header visible
 		// If Tab can be shown set its header visible
 		if i < count {
 		if i < count {
@@ -406,7 +410,7 @@ type Tab struct {
 	icon       *Label     // Tab optional user icon
 	icon       *Label     // Tab optional user icon
 	image      *Image     // Tab optional user image
 	image      *Image     // Tab optional user image
 	bottom     Panel      // Panel to cover the bottom edge of the Tab
 	bottom     Panel      // Panel to cover the bottom edge of the Tab
-	content    Panel      // User content panel
+	content    IPanel     // User content panel
 	cursorOver bool
 	cursorOver bool
 	selected   bool
 	selected   bool
 	pinned     bool
 	pinned     bool
@@ -429,7 +433,6 @@ func newTab(text string, tb *TabBar, styles *TabStyles) *Tab {
 	tab.bottom.SetBounded(false)
 	tab.bottom.SetBounded(false)
 	tab.bottom.SetColor4(&tab.styles.Selected.BgColor)
 	tab.bottom.SetColor4(&tab.styles.Selected.BgColor)
 	tab.header.Add(&tab.bottom)
 	tab.header.Add(&tab.bottom)
-	tab.content.Initialize(0, 0)
 
 
 	// Subscribe to header panel events
 	// Subscribe to header panel events
 	tab.header.Subscribe(OnCursorEnter, tab.onCursor)
 	tab.header.Subscribe(OnCursorEnter, tab.onCursor)
@@ -573,17 +576,33 @@ func (tab *Tab) Header() *Panel {
 	return &tab.header
 	return &tab.header
 }
 }
 
 
+// SetContent sets or replaces this tab content panel.
+func (tab *Tab) SetContent(ipan IPanel) {
+
+	// Remove previous content if any
+	if tab.content != nil {
+		tab.tb.Remove(tab.content)
+	}
+	tab.content = ipan
+	if ipan != nil {
+		tab.tb.Add(tab.content)
+	}
+	tab.tb.recalc()
+}
+
 // Content returns a pointer to the specified Tab content panel
 // Content returns a pointer to the specified Tab content panel
-func (tab *Tab) Content() *Panel {
+func (tab *Tab) Content() IPanel {
 
 
-	return &tab.content
+	return tab.content
 }
 }
 
 
 // setSelected sets this Tab selected state
 // setSelected sets this Tab selected state
 func (tab *Tab) setSelected(selected bool) {
 func (tab *Tab) setSelected(selected bool) {
 
 
 	tab.selected = selected
 	tab.selected = selected
-	tab.content.SetVisible(selected)
+	if tab.content != nil {
+		tab.content.GetPanel().SetVisible(selected)
+	}
 	tab.bottom.SetVisible(selected)
 	tab.bottom.SetVisible(selected)
 	tab.update()
 	tab.update()
 	tab.setBottomPanel()
 	tab.setBottomPanel()