소스 검색

gui builder dev...

leonsal 8 년 전
부모
커밋
7dab4d12a4
2개의 변경된 파일224개의 추가작업 그리고 132개의 파일을 삭제
  1. 36 36
      gui/builder.go
  2. 188 96
      gui/gridlayout.go

+ 36 - 36
gui/builder.go

@@ -910,36 +910,36 @@ func (b *Builder) setLayoutParams(dp *descPanel, ipan IPanel) error {
 
 	// GridLayout parameters
 	if playout.Type == descTypeGridLayout {
-		// Creates layout parameter
-		params := GridLayoutParams{
-			Row:     0,
-			Col:     0,
-			ColSpan: 0,
-			AlignH:  AlignCenter,
-			AlignV:  AlignCenter,
-		}
-		// Sets row parameter
-		params.Row = dlp.Row
-		params.Col = dlp.Col
-		params.ColSpan = dlp.ColSpan
-		// Sets optional alignh parameter
-		if dlp.AlignH != "" {
-			align, ok := mapAlignName[dlp.AlignH]
-			if !ok {
-				return b.err("alignh", "Invalid align name:"+dlp.AlignH)
-			}
-			params.AlignH = align
-		}
-		// Sets optional alignv parameter
-		if dlp.AlignV != "" {
-			align, ok := mapAlignName[dlp.AlignV]
-			if !ok {
-				return b.err("alignv", "Invalid align name:"+dlp.AlignV)
-			}
-			params.AlignV = align
-		}
-		panel.SetLayoutParams(&params)
-		log.Error("set grid parameters:%v", params)
+		//		// Creates layout parameter
+		//		params := GridLayoutParams{
+		//			Row:     0,
+		//			Col:     0,
+		//			ColSpan: 0,
+		//			AlignH:  AlignCenter,
+		//			AlignV:  AlignCenter,
+		//		}
+		//		// Sets row parameter
+		//		params.Row = dlp.Row
+		//		params.Col = dlp.Col
+		//		params.ColSpan = dlp.ColSpan
+		//		// Sets optional alignh parameter
+		//		if dlp.AlignH != "" {
+		//			align, ok := mapAlignName[dlp.AlignH]
+		//			if !ok {
+		//				return b.err("alignh", "Invalid align name:"+dlp.AlignH)
+		//			}
+		//			params.AlignH = align
+		//		}
+		//		// Sets optional alignv parameter
+		//		if dlp.AlignV != "" {
+		//			align, ok := mapAlignName[dlp.AlignV]
+		//			if !ok {
+		//				return b.err("alignv", "Invalid align name:"+dlp.AlignV)
+		//			}
+		//			params.AlignV = align
+		//		}
+		//		panel.SetLayoutParams(&params)
+		//		log.Error("set grid parameters:%v", params)
 		return nil
 	}
 
@@ -991,12 +991,12 @@ func (b *Builder) setLayout(dp *descPanel, ipan IPanel) error {
 	}
 
 	// Grid layout
-	if dl.Type == descTypeGridLayout {
-		log.Error("set grid layout")
-		grl := NewGridLayout()
-		panel.SetLayout(grl)
-		return nil
-	}
+	//	if dl.Type == descTypeGridLayout {
+	//		log.Error("set grid layout")
+	//		grl := NewGridLayout()
+	//		panel.SetLayout(grl)
+	//		return nil
+	//	}
 
 	return b.err("layout", "Invalid layout type:"+dl.Type)
 }

+ 188 - 96
gui/gridlayout.go

@@ -1,135 +1,227 @@
 // 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
 
+// GridLayout is a panel layout which arranges its children in a rectangular grid.
+// It is necessary to set the number of columns of the grid when the layout is created.
+// The panel's child elements are positioned in the grid cells accordingly to the
+// order they were added to the panel.
+// The height of each row is determined by the height of the heightest child in the row.
+// The width of each column is determined by the width of the widest child in the column
 type GridLayout struct {
-	columns int
+	columns []colInfo
+	alignh  Align   // global cell horizontal alignment
+	alignv  Align   // global cell vertical alignment
+	spaceh  float32 // space between rows
+	specev  float32 // space between columns
 }
 
+// GridLayoutParams describes layout parameter for an specific child
 type GridLayoutParams struct {
-	Row     int   // grid layout row number from 0
-	Col     int   // grid layout column number from 0
-	ColSpan int   // number of additional columns to ocuppy to the right
-	AlignH  Align // vertical alignment
-	AlignV  Align // horizontal alignment
+	ColSpan int   // Number of additional columns to ocuppy to the right
+	AlignH  Align // Vertical alignment
+	AlignV  Align // Horizontal alignment
+}
+
+// colInfo keeps information about each grid column
+type colInfo struct {
+	width  float32 // column width
+	alignh *Align  // optional column horizontal alignment
+	alignv *Align  // optional column vertical alignment
 }
 
 // NewGridLayout creates and returns a pointer of a new grid layout
-func NewGridLayout() *GridLayout {
+func NewGridLayout(ncols int) *GridLayout {
 
-	g := new(GridLayout)
-	return g
+	if ncols <= 0 {
+		panic("Invalid number of columns")
+	}
+	gl := new(GridLayout)
+	gl.columns = make([]colInfo, ncols)
+	return gl
 }
 
+// SetAlignV sets the vertical alignment for all the grid cells
+// The alignment of an individual cell can be set by settings its layout parameters.
+func (g *GridLayout) SetAlignV(align Align) {
+
+	g.alignv = align
+}
+
+// SetAlignH sets the horizontal alignment for all the grid cells
+// The alignment of an individual cell can be set by settings its layout parameters.
+func (g *GridLayout) SetAlignH(align Align) {
+
+	g.alignh = align
+}
+
+// SetColAlignV sets the vertical alignment for all the cells of
+// the specified column. The function panics if the supplied column is invalid
+func (g *GridLayout) SetColAlignV(col int, align Align) {
+
+	if col < 0 || col >= len(g.columns) {
+		panic("Invalid column")
+	}
+	if g.columns[col].alignv == nil {
+		g.columns[col].alignv = new(Align)
+	}
+	*g.columns[col].alignv = align
+}
+
+// SetColAlignH sets the horizontal alignment for all the cells of
+// the specified column. The function panics if the supplied column is invalid.
+func (g *GridLayout) SetColAlignH(col int, align Align) {
+
+	if col < 0 || col >= len(g.columns) {
+		panic("Invalid column")
+	}
+	if g.columns[col].alignh == nil {
+		g.columns[col].alignh = new(Align)
+	}
+	*g.columns[col].alignh = align
+}
+
+// Recalc sets the position and sizes of all of the panel's children.
+// It is normally called by the parent panel when its size changes or
+// a child is added or removed.
 func (g *GridLayout) Recalc(ipan IPanel) {
 
-	type element struct {
+	type cell struct {
 		panel  *Panel
 		params *GridLayoutParams
 	}
-	rows := 0
-	cols := 0
-	items := []element{}
 
+	type row struct {
+		cells  []*cell
+		height float32
+	}
+
+	// Builds array of child rows
 	pan := ipan.GetPanel()
-	for _, obj := range pan.Children() {
-		// Get child panel
-		child := obj.(IPanel).GetPanel()
-		// Ignore if not visible
+	var irow int
+	var icol int
+	rows := []row{}
+	for _, node := range pan.Children() {
+		// Ignore invisible child
+		child := node.(IPanel).GetPanel()
 		if !child.Visible() {
 			continue
 		}
-		// Ignore if no layout params
-		if child.layoutParams == nil {
-			continue
+		// Checks child layout params, if supplied
+		ip := child.layoutParams
+		var params *GridLayoutParams
+		var ok bool
+		if ip != nil {
+			params, ok = child.layoutParams.(*GridLayoutParams)
+			if !ok {
+				panic("layoutParams is not GridLayoutParams")
+			}
 		}
-		// Checks layout params
-		params, ok := child.layoutParams.(*GridLayoutParams)
-		if !ok {
-			panic("layoutParams is not GridLayoutParams")
+		// If first column, creates row and appends to rows
+		if icol == 0 {
+			var r row
+			r.cells = make([]*cell, len(g.columns))
+			rows = append(rows, r)
 		}
-		if params.Row >= rows {
-			rows = params.Row + 1
+		// Set current child panel to current cells
+		rows[irow].cells[icol] = &cell{child, params}
+		// Checks child panel colspan layout params
+		coljump := 1
+		if params != nil && params.ColSpan > 0 {
+			coljump += params.ColSpan
 		}
-		if params.Col >= cols {
-			cols = params.Col + 1
+		// Updates next cell column and row
+		icol += coljump
+		if icol >= len(g.columns) {
+			irow++
+			icol = 0
 		}
-		items = append(items, element{child, params})
-	}
-	// Check limits
-	if rows > 100 {
-		panic("Element row outsize limits")
-	}
-	if cols > 100 {
-		panic("Element column outsize limits")
 	}
 
-	// Determine row and column maximum sizes
-	colSizes := make([]int, cols)
-	rowSizes := make([]int, rows)
-	for _, el := range items {
-		width := el.panel.Width()
-		height := el.panel.Height()
-		if int(width) > colSizes[el.params.Col] {
-			colSizes[el.params.Col] = int(width)
-		}
-		if int(height) > rowSizes[el.params.Row] {
-			rowSizes[el.params.Row] = int(height)
-		}
+	// Resets columns widths
+	for i := 0; i < len(g.columns); i++ {
+		g.columns[i].width = 0
 	}
 
-	// Determine row and column starting positions
-	colStart := make([]int, cols)
-	rowStart := make([]int, rows)
-	for i := 1; i < len(colSizes); i++ {
-		colStart[i] = colStart[i-1] + colSizes[i-1]
-	}
-	for i := 1; i < len(rowSizes); i++ {
-		rowStart[i] = rowStart[i-1] + rowSizes[i-1]
+	// Sets the height of each row to the height of the heightest child
+	// Sets the width of each column to the width of the widest column
+	for i := 0; i < len(rows); i++ {
+		r := &rows[i]
+		r.height = 0
+		for ci, cell := range r.cells {
+			if cell == nil {
+				continue
+			}
+			if cell.panel.Height() > r.height {
+				r.height = cell.panel.Height()
+			}
+			if cell.panel.Width() > g.columns[ci].width {
+				g.columns[ci].width = cell.panel.Width()
+			}
+		}
 	}
 
-	// Position the elements
-	for _, el := range items {
-		row := el.params.Row
-		col := el.params.Col
-		cellHeight := rowSizes[row]
-		// Current cell width
-		cellWidth := 0
-		for c := 0; c <= el.params.ColSpan; c++ {
-			pos := col + c
-			if pos >= len(colSizes) {
-				break
+	// Position each child panel in the parent panel
+	var celly float32
+	for _, r := range rows {
+		var cellx float32
+		for ci, cell := range r.cells {
+			if cell == nil {
+				continue
+			}
+			colWidth := g.columns[ci].width
+			colspan := 0
+			// Default grid cell alignment
+			alignv := g.alignv
+			alignh := g.alignh
+			// If column has aligment:
+			if g.columns[ci].alignv != nil {
+				alignv = *g.columns[ci].alignv
+			}
+			if g.columns[ci].alignh != nil {
+				alignh = *g.columns[ci].alignh
+			}
+			// If cell has layout parameters:
+			if cell.params != nil {
+				alignv = cell.params.AlignV
+				alignv = cell.params.AlignH
+				colspan = cell.params.ColSpan
+			}
+			// Determines child panel horizontal position
+			px := cellx
+			switch alignh {
+			case AlignNone:
+			case AlignLeft:
+			case AlignRight:
+				px += float32(colWidth) - cell.panel.Width()
+			case AlignCenter:
+				px += (float32(colWidth) - cell.panel.Width()) / 2
+			default:
+				panic("Invalid horizontal alignment")
+			}
+			// Determines child panel vertical position
+			py := celly
+			switch alignv {
+			case AlignNone:
+			case AlignTop:
+			case AlignBottom:
+				py += r.height - cell.panel.Height()
+			case AlignCenter:
+				py += (r.height - cell.panel.Height()) / 2
+			default:
+				panic("Invalid vertical alignment")
+			}
+			// Sets child panel position
+			cell.panel.SetPosition(px, py)
+			// Advances to next row cell considering colspan
+			for i := ci; i < ci+colspan+1; i++ {
+				if i >= len(g.columns) {
+					break
+				}
+				cellx += g.columns[i].width
 			}
-			cellWidth += colSizes[pos]
-		}
-		rstart := float32(rowStart[row])
-		cstart := float32(colStart[col])
-		// Horizontal alignment
-		var dx float32 = 0
-		switch el.params.AlignH {
-		case AlignNone:
-		case AlignLeft:
-		case AlignRight:
-			dx = float32(cellWidth) - el.panel.width
-		case AlignCenter:
-			dx = (float32(cellWidth) - el.panel.width) / 2
-		default:
-			panic("Invalid horizontal alignment")
-		}
-		// Vertical alignment
-		var dy float32 = 0
-		switch el.params.AlignV {
-		case AlignNone:
-		case AlignTop:
-		case AlignBottom:
-			dy = float32(cellHeight) - el.panel.height
-		case AlignCenter:
-			dy = (float32(cellHeight) - el.panel.height) / 2
-		default:
-			panic("Invalid vertical alignment")
 		}
-		el.panel.SetPosition(cstart+dx, rstart+dy)
+		celly += r.height
 	}
 }