ref: 5d0400cb4e2503228f1225cc2e1f6f9904a92da4
parent: d7a54dfa83c869f442cd919898f75ca475ce1f7d
author: Philip Silva <philip.silva@protonmail.com>
date: Sat Aug 28 02:47:11 EDT 2021
Prepare grid with col and row spans
--- a/browser/browser.go
+++ b/browser/browser.go
@@ -939,12 +939,20 @@
}
uis := make([]duit.UI, 0, len(es))
+ colSpans := make([]int, 0, len(es))
+ rowSpans := make([]int, 0, len(es))
+
for _, e := range es {uis = append(uis, e)
+ colSpans = append(colSpans, 1)
+ rowSpans = append(rowSpans, 1)
}
return &duitx.Grid{Columns: 1,
+ Rows: len(uis),
+ ColSpans: colSpans,
+ RowSpans: rowSpans,
Padding: duit.NSpace(1, duit.SpaceXY(0, 3)),
Halign: []duit.Halign{duit.HalignLeft}, Valign: []duit.Valign{duit.ValignTop},@@ -1029,10 +1037,16 @@
}
}
+ colSpans := make([]int, 0, len(uis))
+ rowSpans := make([]int, 0, len(uis))
halign := make([]duit.Halign, 0, len(uis))
valign := make([]duit.Valign, 0, len(uis))
- for i := 0; i < numCols; i++ {+ for j := 0; j < numCols; j++ {+ for i := 0; i < len(t.rows); i++ {+ colSpans = append(colSpans, 1)
+ rowSpans = append(rowSpans, 1)
+ }
halign = append(halign, duit.HalignLeft)
valign = append(valign, duit.ValignTop)
}
@@ -1040,6 +1054,9 @@
return NewElement(
&duitx.Grid{Columns: numCols,
+ Rows: len(t.rows),
+ ColSpans: colSpans,
+ RowSpans: rowSpans,
Padding: duit.NSpace(numCols, duit.SpaceXY(0, 3)),
Halign: halign,
Valign: valign,
--- a/browser/duitx/grid.go
+++ b/browser/duitx/grid.go
@@ -26,25 +26,90 @@
"9fans.net/go/draw"
"github.com/mjl-/duit"
+ "github.com/psilva261/opossum/logger"
)
// Grid lays out other duit.UIs in a table-like grid.
type Grid struct {Kids []*duit.Kid // Holds UIs in the grid, per row.
- Columns int // Number of clumns.
+ Columns int // Number of columns.
+ Rows int // Number of rows.
+ RowSpans []int
+ ColSpans []int
Valign []duit.Valign // Vertical alignment per column.
Halign []duit.Halign // Horizontal alignment per column.
Padding []duit.Space // Padding in lowDPI pixels per column.
- Width int // -1 means full width, 0 means automatic width, >0 means exactly that many lowDPI pixels.
+ Width int // -1 means full width, 0 means automatic width, >0 means exactly that many lowDPI pixels.
Background *draw.Image `json:"-"` // Background color.
widths []int
heights []int
+ pos [][]int
size image.Point
}
var _ duit.UI = &Grid{}+func (ui *Grid) initPos() {+ log.Printf("grid: %+v", ui)+ var i, j int
+ // make ui.pos and init with (-1)
+ ui.pos = make([][]int, ui.Rows)
+ for i := 0; i < ui.Rows; i++ {+ ui.pos[i] = make([]int, ui.Columns)
+ for j := 0; j < ui.Columns; j++ {+ ui.pos[i][j] = -1
+ }
+ }
+ inc := func() {+ j +=1
+ if j >= ui.Columns {+ j = 0
+ i += 1
+ }
+ }
+
+ for l := range ui.Kids {+ij_iter:
+ if ll := ui.pos[i][j]; ll >= 0 {+ inc()
+ goto ij_iter
+ }
+ for jj := j; jj < j+ui.RowSpans[l]; jj++ {+ ui.pos[i][jj] = l
+ }
+ for ii := i; ii < i+ui.ColSpans[l]; ii++ {+ ui.pos[ii][j] = l
+ }
+ inc()
+ }
+}
+
+func (ui *Grid) maxWidths(dui *duit.DUI, sizeAvail image.Point) (maxW []int, width int, x []int) {+ x = make([]int, ui.Columns)
+ maxW = make([]int, ui.Columns)
+ spaces := ui.spaces(dui)
+ for j := 0; j < ui.Columns; j++ {+ space := spaces[j]
+ newDx := 0
+ if j > 0 {+ x[j] = x[j-1] + maxW[j-1]
+ }
+ for i := 0; i < ui.Rows; i++ {+ l := ui.pos[i][j]
+ k := ui.Kids[l]
+ k.UI.Layout(dui, k, image.Pt(sizeAvail.X-space.Dx(), sizeAvail.Y-space.Dy()), true)
+ newDx = maximum(
+ newDx,
+ (k.R.Dx()+space.Dx()) / ui.ColSpans[l],
+ )
+ }
+ maxW[j] = newDx
+ width += newDx
+ }
+ return
+}
+
func (ui *Grid) Layout(dui *duit.DUI, self *duit.Kid, sizeAvail image.Point, force bool) {debugLayout(dui, self)
if duit.KidsLayout(dui, self, ui.Kids, force) {@@ -51,6 +116,10 @@
return
}
+ if ui.pos == nil {+ ui.initPos()
+ }
+
if ui.Valign != nil && len(ui.Valign) != ui.Columns { panic(fmt.Sprintf("len(valign) = %d, should be ui.Columns = %d", len(ui.Valign), ui.Columns))}
@@ -70,32 +139,13 @@
}
ui.widths = make([]int, ui.Columns) // widths include padding
- spaces := make([]duit.Space, ui.Columns)
- if ui.Padding != nil {- for i, pad := range ui.Padding {- spaces[i] = dui.ScaleSpace(pad)
- }
- }
+ spaces := ui.spaces(dui)
width := 0 // total width so far
x := make([]int, len(ui.widths)) // x offsets per column
x[0] = 0
// first determine the column widths
- for col := 0; col < ui.Columns; col++ {- if col > 0 {- x[col] = x[col-1] + ui.widths[col-1]
- }
- ui.widths[col] = 0
- newDx := 0
- space := spaces[col]
- for i := col; i < len(ui.Kids); i += ui.Columns {- k := ui.Kids[i]
- k.UI.Layout(dui, k, image.Pt(sizeAvail.X-space.Dx(), sizeAvail.Y-space.Dy()), true)
- newDx = maximum(newDx, k.R.Dx()+space.Dx())
- }
- ui.widths[col] = newDx
- width += ui.widths[col]
- }
+ ui.widths, width, x = ui.maxWidths(dui, sizeAvail)
// Reduce used widths if too large
if width > sizeAvail.X {@@ -185,6 +235,16 @@
ui.size.X = sizeAvail.X
}
self.R = rect(ui.size)
+}
+
+func (ui *Grid) spaces(dui *duit.DUI) (s []duit.Space) {+ s = make([]duit.Space, ui.Columns)
+ if ui.Padding != nil {+ for i, pad := range ui.Padding {+ s[i] = dui.ScaleSpace(pad)
+ }
+ }
+ return
}
func (ui *Grid) Draw(dui *duit.DUI, self *duit.Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool) {--- /dev/null
+++ b/browser/duitx/grid_test.go
@@ -1,0 +1,45 @@
+package duitx
+
+import (
+ "testing"
+
+ "github.com/mjl-/duit"
+)
+
+func TestInitPos(t *testing.T) {+ g := &Grid{+ Kids: make([]*duit.Kid, 2*2),
+ Columns: 2,
+ Rows: 2,
+ RowSpans: []int{1, 1, 1, 1},+ ColSpans: []int{1, 1, 1, 1},+ }
+ g.initPos()
+ if len(g.pos) != 2 || len(g.pos[0]) != 2 || len(g.pos[1]) != 2 || g.pos[0][0] != 0 || g.pos[0][1] != 1 || g.pos[1][0] != 2 || g.pos[1][1] != 3 {+ t.Fatalf("%+v", g.pos)+ }
+
+ g = &Grid{+ Kids: make([]*duit.Kid, 1*2),
+ Columns: 2,
+ Rows: 2,
+ RowSpans: []int{1, 1},+ ColSpans: []int{2, 2},+ }
+ g.initPos()
+ if len(g.pos) != 2 || len(g.pos[0]) != 2 || len(g.pos[1]) != 2 || g.pos[0][0] != 0 || g.pos[0][1] != 1 || g.pos[1][0] != 0 || g.pos[1][1] != 1 {+ t.Fatalf("..%+v", g.pos)+ }
+
+ g = &Grid{+ Kids: make([]*duit.Kid, 2*1),
+ Columns: 2,
+ Rows: 2,
+ RowSpans: []int{2, 2},+ ColSpans: []int{1, 1},+ }
+ g.initPos()
+ if len(g.pos) != 2 || len(g.pos[0]) != 2 || len(g.pos[1]) != 2 || g.pos[0][0] != 0 || g.pos[0][1] != 0 || g.pos[1][0] != 1 || g.pos[1][1] != 1 {+ t.Fatalf("%+v", g.pos)+ }
+}
--
⑨