aboutsummaryrefslogtreecommitdiffstats
path: root/layout
diff options
context:
space:
mode:
authorClement Benard <contact@clementbenard.com>2019-07-12 17:23:28 +0200
committerClement Benard <contact@clementbenard.com>2019-07-12 17:23:28 +0200
commit0cc6367a881ab7dba48ace7b111e0eb1151c10bb (patch)
treeeabadd10783b857271f12797f1a505efec85630c /layout
parent009f865bc5484e54f09d2173b2b3dbbf3838d391 (diff)
downloadgui-0cc6367a881ab7dba48ace7b111e0eb1151c10bb.zip
Better separation between Layout and Mux
Diffstat (limited to 'layout')
-rw-r--r--layout/box.go13
-rw-r--r--layout/grid.go21
-rw-r--r--layout/layout.go9
-rw-r--r--layout/mux.go43
-rw-r--r--layout/split.go9
5 files changed, 68 insertions, 27 deletions
diff --git a/layout/box.go b/layout/box.go
index 01a1143..13c7b2b 100644
--- a/layout/box.go
+++ b/layout/box.go
@@ -19,7 +19,7 @@ type box struct {
// NewBox creates a familiar flexbox-like list layout.
// It can be horizontal or vertical.
-func NewBox(env gui.Env, contents []*gui.Env, options ...func(*box)) gui.Env {
+func NewBox(contents []*gui.Env, options ...func(*box)) Layout {
ret := &box{
Background: image.Black,
Contents: contents,
@@ -28,12 +28,7 @@ func NewBox(env gui.Env, contents []*gui.Env, options ...func(*box)) gui.Env {
for _, f := range options {
f(ret)
}
-
- mux, env := NewMux(env, ret)
- for _, item := range contents {
- *item = mux.MakeEnv()
- }
- return env
+ return ret
}
// BoxVertical changes the otherwise horizontal Box to be vertical.
@@ -67,6 +62,10 @@ 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)
diff --git a/layout/grid.go b/layout/grid.go
index 9c79343..c90821a 100644
--- a/layout/grid.go
+++ b/layout/grid.go
@@ -18,7 +18,7 @@ type grid struct {
// NewGrid creates a familiar flexbox-like grid layout.
// Each row can be a different length.
-func NewGrid(env gui.Env, contents [][]*gui.Env, options ...func(*grid)) gui.Env {
+func NewGrid(contents [][]*gui.Env, options ...func(*grid)) Layout {
ret := &grid{
Background: image.Black,
Gap: 0,
@@ -29,15 +29,7 @@ func NewGrid(env gui.Env, contents [][]*gui.Env, options ...func(*grid)) gui.Env
for _, f := range options {
f(ret)
}
-
- mux, env := NewMux(env, ret)
- for _, row := range contents {
- for _, item := range row {
- *item = mux.MakeEnv()
- }
- }
-
- return env
+ return ret
}
// GridBackground changes the background of the grid to a uniform color.
@@ -73,6 +65,15 @@ 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...)
+ }
+ return ret
+}
+
func (g *grid) Lay(bounds image.Rectangle) []image.Rectangle {
gap := g.Gap
ret := make([]image.Rectangle, 0)
diff --git a/layout/layout.go b/layout/layout.go
index 987ee24..dfacca1 100644
--- a/layout/layout.go
+++ b/layout/layout.go
@@ -3,17 +3,22 @@ package layout
import (
"image"
"image/draw"
+
+ "github.com/faiface/gui"
)
// Layout represents any graphical layout
//
-// A Layout needs to be able to redraw itself with the Redraw method.
-// Redraw() only draws the background or frame of the Layout, not the childs.
+// 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.
+// The order must be the same as Items.
+//
+// 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 208664c..6c7ddaa 100644
--- a/layout/mux.go
+++ b/layout/mux.go
@@ -1,6 +1,7 @@
package layout
import (
+ "fmt"
"image"
"image/draw"
"sync"
@@ -24,9 +25,15 @@ type Mux struct {
layout Layout
}
+// Layout returns the underlying Layout of the Mux.
+func (mux *Mux) Layout() Layout {
+ return mux.layout
+}
+
// NewMux should only be used internally by Layouts.
-// It has mostly the same behaviour as gui.Mux, except for its use of and underlying Layout
-// for modifying the gui.Resize events. to the childs.
+// 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) {
drawChan := make(chan func(draw.Image) image.Rectangle)
mux = &Mux{
@@ -34,7 +41,7 @@ func NewMux(env gui.Env, l Layout) (mux *Mux, master gui.Env) {
draw: drawChan,
}
master, masterIn := mux.makeEnv(true)
- events := make(chan gui.Event, 0)
+ events := make(chan gui.Event)
mux.evIn = events
go func() {
for d := range drawChan {
@@ -85,12 +92,36 @@ func NewMux(env gui.Env, l Layout) (mux *Mux, master gui.Env) {
}
mux.mu.Unlock()
}()
+
+ err := mux.FillLayout()
+ if err != nil {
+ panic(err)
+ }
return
}
-func (mux *Mux) MakeEnv() gui.Env {
- env, _ := mux.makeEnv(false)
- return env
+// 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
+ }
+ *en, _ = mux.makeEnv(false)
+ }
+ if nilptrs > 0 {
+ return fmt.Errorf("Mux: %d already filled and %d nil pointers", filleditems, nilptrs)
+ }
+ return nil
}
type muxEnv struct {
diff --git a/layout/split.go b/layout/split.go
index 4bf00a7..fb6d36e 100644
--- a/layout/split.go
+++ b/layout/split.go
@@ -1,13 +1,18 @@
package layout
+import "fmt"
+
// SplitFunc represents a way to split a space among a number of elements.
-// The space of the returned slice must be equal to the number of elements.
+// The length of the returned slice must be equal to the number of elements.
// The sum of all elements of the returned slice must be eqal to the space.
type SplitFunc func(elements int, space int) []int
-// EvenSplit implements SplitFunc to split a space (almost) evenly among the elements.
+// EvenSplit is a SplitFunc used to split a space (almost) evenly among the elements.
// It is almost evenly because width may not be divisible by elements.
func EvenSplit(elements int, width int) []int {
+ if elements <= 0 {
+ panic(fmt.Errorf("EvenSplit: elements must be greater than 0"))
+ }
ret := make([]int, 0, elements)
for elements > 0 {
v := width / elements