aboutsummaryrefslogtreecommitdiffstats
path: root/layout
diff options
context:
space:
mode:
authorClement Benard <contact@clementbenard.com>2019-07-15 15:44:34 +0200
committerClement Benard <contact@clementbenard.com>2019-07-15 15:44:34 +0200
commit736e35bd9b0c8f4f9649557e4b7a3085b4bdbe63 (patch)
tree53c854ae5142a879a1a0076e804f210db5cb7b85 /layout
parent1b03644d1e0e1be27cdd22732f893d03c0e8421d (diff)
downloadgui-736e35bd9b0c8f4f9649557e4b7a3085b4bdbe63.zip
Easier and more idiomatic Layout initializing
Diffstat (limited to 'layout')
-rw-r--r--layout/box.go93
-rw-r--r--layout/doc.go10
-rw-r--r--layout/grid.go98
-rw-r--r--layout/layout.go5
-rw-r--r--layout/mux.go41
5 files changed, 79 insertions, 168 deletions
diff --git a/layout/box.go b/layout/box.go
index 13c7b2b..24f0c0d 100644
--- a/layout/box.go
+++ b/layout/box.go
@@ -4,84 +4,53 @@ import (
"image"
"image/color"
"image/draw"
-
- "github.com/faiface/gui"
)
-type box struct {
- Contents []*gui.Env
+type Box struct {
+ // Number of child elements
+ Length int
+ // Background changes the background of the Box to a uniform color.
Background color.Color
- Split SplitFunc
- Gap int
-
- vertical bool
-}
-
-// NewBox creates a familiar flexbox-like list layout.
-// It can be horizontal or vertical.
-func NewBox(contents []*gui.Env, options ...func(*box)) Layout {
- ret := &box{
- Background: image.Black,
- Contents: contents,
- Split: EvenSplit,
- }
- for _, f := range options {
- f(ret)
- }
- return ret
-}
+ // Split changes the way the space is divided among the elements.
+ Split SplitFunc
+ // Gap changes the Box gap.
+ // The gap is identical everywhere (top, left, bottom, right).
+ Gap int
-// BoxVertical changes the otherwise horizontal Box to be vertical.
-func BoxVertical(b *box) {
- b.vertical = true
+ // Vertical changes the otherwise horizontal Box to be vertical.
+ Vertical bool
}
-// BoxBackground changes the background of the box to a uniform color.
-func BoxBackground(c color.Color) func(*box) {
- return func(grid *box) {
- grid.Background = c
+func (b Box) Redraw(drw draw.Image, bounds image.Rectangle) {
+ col := b.Background
+ if col == nil {
+ col = image.Black
}
-}
-// BoxSplit changes the way the space is divided among the elements.
-func BoxSplit(split SplitFunc) func(*box) {
- return func(grid *box) {
- grid.Split = split
- }
+ draw.Draw(drw, bounds, image.NewUniform(col), image.ZP, draw.Src)
}
-// BoxGap changes the box gap.
-// The gap is identical everywhere (top, left, bottom, right).
-func BoxGap(gap int) func(*box) {
- return func(grid *box) {
- grid.Gap = gap
+func (b Box) Lay(bounds image.Rectangle) []image.Rectangle {
+ items := b.Length
+ gap := b.Gap
+ split := b.Split
+ if split == nil {
+ split = EvenSplit
}
-}
-
-func (g *box) Redraw(drw draw.Image, bounds image.Rectangle) {
- draw.Draw(drw, bounds, image.NewUniform(g.Background), image.ZP, draw.Src)
-}
-
-func (g *box) Items() []*gui.Env {
- return g.Contents
-}
-
-func (g *box) Lay(bounds image.Rectangle) []image.Rectangle {
- items := len(g.Contents)
ret := make([]image.Rectangle, 0, items)
- if g.vertical {
- spl := g.Split(items, bounds.Dy()-(g.Gap*(items+1)))
- Y := bounds.Min.Y + g.Gap
+ if b.Vertical {
+ spl := split(items, bounds.Dy()-(gap*(items+1)))
+ Y := bounds.Min.Y + gap
for _, item := range spl {
- ret = append(ret, image.Rect(bounds.Min.X+g.Gap, Y, bounds.Max.X-g.Gap, Y+item))
- Y += item + g.Gap
+ ret = append(ret, image.Rect(bounds.Min.X+gap, Y, bounds.Max.X-gap, Y+item))
+ Y += item + gap
}
} else {
- spl := g.Split(items, bounds.Dx()-(g.Gap*(items+1)))
- X := bounds.Min.X + g.Gap
+ spl := split(items, bounds.Dx()-(gap*(items+1)))
+ X := bounds.Min.X + gap
for _, item := range spl {
- ret = append(ret, image.Rect(X, bounds.Min.Y+g.Gap, X+item, bounds.Max.Y-g.Gap))
- X += item + g.Gap
+ ret = append(ret, image.Rect(X, bounds.Min.Y+gap, X+item, bounds.Max.Y-gap))
+ X += item + gap
}
}
return ret
diff --git a/layout/doc.go b/layout/doc.go
new file mode 100644
index 0000000..8305d43
--- /dev/null
+++ b/layout/doc.go
@@ -0,0 +1,10 @@
+/*
+Package layout provides a Layout system for faiface/gui.
+
+The core of the package is the Layout interface, everything else is just
+implementation.
+
+The Layouts represent a Layout, and the Mux makes them usable.
+The Mux basically acts as a sort of driver.
+*/
+package layout
diff --git a/layout/grid.go b/layout/grid.go
index c90821a..f3cced6 100644
--- a/layout/grid.go
+++ b/layout/grid.go
@@ -4,92 +4,50 @@ import (
"image"
"image/color"
"image/draw"
-
- "github.com/faiface/gui"
)
-type grid struct {
- Contents [][]*gui.Env
+type Grid struct {
+ // Rows represents the number of childs of each row.
+ Rows []int
+ // Background represents the background of the grid as a uniform color.
Background color.Color
- Gap int
- SplitX SplitFunc
- SplitY SplitFunc
-}
-
-// NewGrid creates a familiar flexbox-like grid layout.
-// Each row can be a different length.
-func NewGrid(contents [][]*gui.Env, options ...func(*grid)) Layout {
- ret := &grid{
- Background: image.Black,
- Gap: 0,
- Contents: contents,
- SplitX: EvenSplit,
- SplitY: EvenSplit,
- }
- for _, f := range options {
- f(ret)
- }
- return ret
-}
-
-// GridBackground changes the background of the grid to a uniform color.
-func GridBackground(c color.Color) func(*grid) {
- return func(grid *grid) {
- grid.Background = c
- }
-}
-
-// GridGap changes the grid gap.
-// The gap is identical everywhere (top, left, bottom, right).
-func GridGap(g int) func(*grid) {
- return func(grid *grid) {
- grid.Gap = g
- }
+ // Gap represents the grid gap, equal on all sides.
+ Gap int
+ // SplitX represents the way the space is divided among the columns in each row.
+ SplitX SplitFunc
+ // SplitY represents the way the space is divided among the rows.
+ SplitY SplitFunc
}
-// GridSplitX changes the way the space is divided among the columns in each row.
-func GridSplitX(split SplitFunc) func(*grid) {
- return func(grid *grid) {
- grid.SplitX = split
+func (g Grid) Redraw(drw draw.Image, bounds image.Rectangle) {
+ col := g.Background
+ if col == nil {
+ col = image.Black
}
+ draw.Draw(drw, bounds, image.NewUniform(col), image.ZP, draw.Src)
}
-// GridSplitY changes the way the space is divided among the rows.
-func GridSplitY(split SplitFunc) func(*grid) {
- return func(grid *grid) {
- grid.SplitY = split
+func (g Grid) Lay(bounds image.Rectangle) []image.Rectangle {
+ gap := g.Gap
+ rows := g.Rows
+ splitX := g.SplitX
+ if splitX == nil {
+ splitX = EvenSplit
}
-}
-
-func (g *grid) Redraw(drw draw.Image, bounds image.Rectangle) {
- draw.Draw(drw, bounds, image.NewUniform(g.Background), image.ZP, draw.Src)
-}
-
-func (g *grid) Items() []*gui.Env {
- // 32 should be more than enough for most grids
- ret := make([]*gui.Env, 0, 32)
- for _, row := range g.Contents {
- ret = append(ret, row...)
+ splitY := g.SplitY
+ if splitY == nil {
+ splitY = EvenSplit
}
- return ret
-}
-func (g *grid) Lay(bounds image.Rectangle) []image.Rectangle {
- gap := g.Gap
ret := make([]image.Rectangle, 0)
- rows := len(g.Contents)
-
- rowsH := g.SplitY(rows, bounds.Dy()-(g.Gap*(rows+1)))
-
+ rowsH := splitY(len(rows), bounds.Dy()-(gap*(len(rows)+1)))
X := gap + bounds.Min.X
Y := gap + bounds.Min.Y
- for y, row := range g.Contents {
- cols := len(row)
+ for y, cols := range rows {
h := rowsH[y]
- colsW := g.SplitX(cols, bounds.Dx()-(g.Gap*(cols+1)))
+ colsW := splitX(cols, bounds.Dx()-(gap*(cols+1)))
X = gap + bounds.Min.X
- for x := range row {
- w := colsW[x]
+ for _, w := range colsW {
ret = append(ret, image.Rect(X, Y, X+w, Y+h))
X += gap + w
}
diff --git a/layout/layout.go b/layout/layout.go
index dfacca1..8b8e039 100644
--- a/layout/layout.go
+++ b/layout/layout.go
@@ -3,14 +3,10 @@ package layout
import (
"image"
"image/draw"
-
- "github.com/faiface/gui"
)
// Layout represents any graphical layout
//
-// Items returns the Layout's childs in whatever order.
-//
// Lay represents the way to divide space among your childs.
// It takes a parameter of how much space is available,
// and returns where exactly to put its childs.
@@ -18,7 +14,6 @@ import (
//
// Redraw only draws the background or frame of the Layout, not the childs.
type Layout interface {
- Items() []*gui.Env
Lay(image.Rectangle) []image.Rectangle
Redraw(draw.Image, image.Rectangle)
}
diff --git a/layout/mux.go b/layout/mux.go
index 6c7ddaa..2789878 100644
--- a/layout/mux.go
+++ b/layout/mux.go
@@ -1,9 +1,9 @@
package layout
import (
- "fmt"
"image"
"image/draw"
+ "log"
"sync"
"github.com/faiface/gui"
@@ -33,8 +33,7 @@ func (mux *Mux) Layout() Layout {
// NewMux should only be used internally by Layouts.
// It has mostly the same behaviour as gui.Mux, except for its use of an underlying Layout
// for modifying the gui.Resize events sent to the childs.
-// Also, you cannot make Envs manually, you must use FillLayout.
-func NewMux(env gui.Env, l Layout) (mux *Mux, master gui.Env) {
+func NewMux(env gui.Env, envs []*gui.Env, l Layout) (mux *Mux, master gui.Env) {
drawChan := make(chan func(draw.Image) image.Rectangle)
mux = &Mux{
layout: l,
@@ -63,6 +62,12 @@ func NewMux(env gui.Env, l Layout) (mux *Mux, master gui.Env) {
mux.mu.Lock()
if resize, ok := e.(gui.Resize); ok {
mux.lastResize = resize
+ lay := mux.layout.Lay(rect)
+ if len(lay) != len(mux.eventsIns) {
+ log.Printf("Lay of %T has %d elements while mux has %d, skipping\n", l, len(lay), len(envs))
+ mux.mu.Unlock()
+ continue
+ }
rect := resize.Rectangle
@@ -73,7 +78,6 @@ func NewMux(env gui.Env, l Layout) (mux *Mux, master gui.Env) {
}
// Send appropriate resize Events to childs
- lay := mux.layout.Lay(rect)
for i, eventsIn := range mux.eventsIns {
resize.Rectangle = lay[i]
eventsIn <- resize
@@ -93,35 +97,10 @@ func NewMux(env gui.Env, l Layout) (mux *Mux, master gui.Env) {
mux.mu.Unlock()
}()
- err := mux.FillLayout()
- if err != nil {
- panic(err)
- }
- return
-}
-
-// FillLayout uses the mux to fill the Layout's Envs with suitable Envs.
-// It's called automatically on NewMux, but you can call it again to fill
-// the Envs that became nil, to change a child in the Layout.
-func (mux *Mux) FillLayout() error {
- nilptrs := 0
- filleditems := 0
- // err
- for _, en := range mux.layout.Items() {
- if en == nil {
- nilptrs += 1
- continue
- }
- if *en != nil {
- filleditems += 1
- continue
- }
+ for _, en := range envs {
*en, _ = mux.makeEnv(false)
}
- if nilptrs > 0 {
- return fmt.Errorf("Mux: %d already filled and %d nil pointers", filleditems, nilptrs)
- }
- return nil
+ return
}
type muxEnv struct {