ref: 2883e0082c123a335ccfc8756dcc2e2857f8db8c
parent: 29ad10125ebbee01ea914955a33c0be26ee1ae20
author: Philip Silva <philip.silva@protonmail.com>
date: Sun Jun 6 07:44:51 EDT 2021
Copy grid.go from duit
--- a/browser/browser.go
+++ b/browser/browser.go
@@ -853,7 +853,7 @@
Kids: duit.NewKids(finalUis...),
}
} else {
- return &duit.Grid{
+ return &Grid{
Columns: len(es),
Padding: duit.NSpace(len(es), duit.SpaceXY(0, 3)),
Halign: halign,
@@ -875,7 +875,7 @@
uis = append(uis, e)
}
- return &duit.Grid{
+ return &Grid{
Columns: 1,
Padding: duit.NSpace(1, duit.SpaceXY(0, 3)),
Halign: []duit.Halign{duit.HalignLeft},
@@ -976,7 +976,7 @@
}
return NewElement(
- &duit.Grid{
+ &Grid{
Columns: numCols,
Padding: duit.NSpace(numCols, duit.SpaceXY(0, 3)),
Halign: halign,
@@ -1214,7 +1214,7 @@
return
}
traverseTree(r+1, v.UI, f)
- case *duit.Grid:
+ case *Grid:
for _, kid := range v.Kids {
traverseTree(r+1, kid.UI, f)
}
@@ -1268,8 +1268,8 @@
}
fmt.Printf("Element\n")
printTree(r+1, v.UI)
- case *duit.Grid:
- fmt.Printf("duit.Grid %vx%v\n", len(v.Kids)/v.Columns, v.Columns)
+ case *Grid:
+ fmt.Printf("Grid %vx%v\n", len(v.Kids)/v.Columns, v.Columns)
for _, kid := range v.Kids {
printTree(r+1, kid.UI)
}
--- a/browser/browser_test.go
+++ b/browser/browser_test.go
@@ -95,7 +95,7 @@
t.Fatalf("%+v", b)
}
} else {
- if g := v.UI.(*duit.Grid); g.Columns != 1 || len(g.Kids) != 3 {
+ if g := v.UI.(*Grid); g.Columns != 1 || len(g.Kids) != 3 {
t.Fatalf("%+v", g)
}
}
--- a/browser/experimental.go
+++ b/browser/experimental.go
@@ -66,7 +66,7 @@
return false
case *Element:
return false
- case *duit.Grid:
+ case *Grid:
return false
case *duit.Image:
return true
--- /dev/null
+++ b/browser/grid.go
@@ -1,0 +1,206 @@
+package browser
+
+// Original code from github.com/mjl-/duit
+//
+// Copyright 2018 Mechiel Lukkien mechiel@ueber.net
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import (
+ "fmt"
+ "image"
+
+ "9fans.net/go/draw"
+ "github.com/mjl-/duit"
+)
+
+// 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.
+ 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.
+ Background *draw.Image `json:"-"` // Background color.
+
+ widths []int
+ heights []int
+ size image.Point
+}
+
+var _ duit.UI = &Grid{}
+
+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) {
+ return
+ }
+
+ 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))
+ }
+ if ui.Halign != nil && len(ui.Halign) != ui.Columns {
+ panic(fmt.Sprintf("len(halign) = %d, should be ui.Columns = %d", len(ui.Halign), ui.Columns))
+ }
+ if ui.Padding != nil && len(ui.Padding) != ui.Columns {
+ panic(fmt.Sprintf("len(padding) = %d, should be ui.Columns = %d", len(ui.Padding), ui.Columns))
+ }
+ if len(ui.Kids)%ui.Columns != 0 {
+ panic(fmt.Sprintf("len(kids) = %d, should be multiple of ui.Columns = %d", len(ui.Kids), ui.Columns))
+ }
+
+ scaledWidth := dui.Scale(ui.Width)
+ if scaledWidth > 0 && scaledWidth < sizeAvail.X {
+ ui.size.X = scaledWidth
+ }
+
+ 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)
+ }
+ }
+ 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-width-space.Dx(), sizeAvail.Y-space.Dy()), true)
+ newDx = maximum(newDx, k.R.Dx()+space.Dx())
+ }
+ ui.widths[col] = newDx
+ width += ui.widths[col]
+ }
+ if scaledWidth < 0 && width < sizeAvail.X {
+ leftover := sizeAvail.X - width
+ given := 0
+ for i := range ui.widths {
+ x[i] += given
+ var dx int
+ if i == len(ui.widths)-1 {
+ dx = leftover - given
+ } else {
+ dx = leftover / len(ui.widths)
+ }
+ ui.widths[i] += dx
+ given += dx
+ }
+ }
+
+ // now determine row heights
+ ui.heights = make([]int, (len(ui.Kids)+ui.Columns-1)/ui.Columns)
+ height := 0 // total height so far
+ y := make([]int, len(ui.heights)) // including padding
+ y[0] = 0
+ for i := 0; i < len(ui.Kids); i += ui.Columns {
+ row := i / ui.Columns
+ if row > 0 {
+ y[row] = y[row-1] + ui.heights[row-1]
+ }
+ rowDy := 0
+ for col := 0; col < ui.Columns; col++ {
+ space := spaces[col]
+ k := ui.Kids[i+col]
+ k.UI.Layout(dui, k, image.Pt(ui.widths[col]-space.Dx(), sizeAvail.Y-y[row]-space.Dy()), true)
+ offset := image.Pt(x[col], y[row]).Add(space.Topleft())
+ k.R = k.R.Add(offset) // aligned in top left, fixed for halign/valign later on
+ rowDy = maximum(rowDy, k.R.Dy()+space.Dy())
+ }
+ ui.heights[row] = rowDy
+ height += ui.heights[row]
+ }
+
+ // now shift the kids for right valign/halign
+ for i, k := range ui.Kids {
+ row := i / ui.Columns
+ col := i % ui.Columns
+ space := spaces[col]
+
+ valign := duit.ValignTop
+ halign := duit.HalignLeft
+ if ui.Valign != nil {
+ valign = ui.Valign[col]
+ }
+ if ui.Halign != nil {
+ halign = ui.Halign[col]
+ }
+ cellSize := image.Pt(ui.widths[col], ui.heights[row]).Sub(space.Size())
+ spaceX := 0
+ switch halign {
+ case duit.HalignLeft:
+ case duit.HalignMiddle:
+ spaceX = (cellSize.X - k.R.Dx()) / 2
+ case duit.HalignRight:
+ spaceX = cellSize.X - k.R.Dx()
+ }
+ spaceY := 0
+ switch valign {
+ case duit.ValignTop:
+ case duit.ValignMiddle:
+ spaceY = (cellSize.Y - k.R.Dy()) / 2
+ case duit.ValignBottom:
+ spaceY = cellSize.Y - k.R.Dy()
+ }
+ k.R = k.R.Add(image.Pt(spaceX, spaceY))
+ }
+
+ ui.size = image.Pt(width, height)
+ if ui.Width < 0 && ui.size.X < sizeAvail.X {
+ ui.size.X = sizeAvail.X
+ }
+ self.R = rect(ui.size)
+}
+
+func (ui *Grid) Draw(dui *duit.DUI, self *duit.Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool) {
+ duit.KidsDraw(dui, self, ui.Kids, ui.size, ui.Background, img, orig, m, force)
+}
+
+func (ui *Grid) Mouse(dui *duit.DUI, self *duit.Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r duit.Result) {
+ return duit.KidsMouse(dui, self, ui.Kids, m, origM, orig)
+}
+
+func (ui *Grid) Key(dui *duit.DUI, self *duit.Kid, k rune, m draw.Mouse, orig image.Point) (r duit.Result) {
+ return duit.KidsKey(dui, self, ui.Kids, k, m, orig)
+}
+
+func (ui *Grid) FirstFocus(dui *duit.DUI, self *duit.Kid) *image.Point {
+ return duit.KidsFirstFocus(dui, self, ui.Kids)
+}
+
+func (ui *Grid) Focus(dui *duit.DUI, self *duit.Kid, o duit.UI) *image.Point {
+ return duit.KidsFocus(dui, self, ui.Kids, o)
+}
+
+func (ui *Grid) Mark(self *duit.Kid, o duit.UI, forLayout bool) (marked bool) {
+ return duit.KidsMark(self, ui.Kids, o, forLayout)
+}
+
+func (ui *Grid) Print(self *duit.Kid, indent int) {
+ duit.PrintUI(fmt.Sprintf("Grid columns=%d padding=%v", ui.Columns, ui.Padding), self, indent)
+ duit.KidsPrint(ui.Kids, indent+1)
+}