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)
+ }
+}