diff options
| author | Clement Benard <contact@clementbenard.com> | 2019-07-12 17:23:28 +0200 |
|---|---|---|
| committer | Clement Benard <contact@clementbenard.com> | 2019-07-12 17:23:28 +0200 |
| commit | 0cc6367a881ab7dba48ace7b111e0eb1151c10bb (patch) | |
| tree | eabadd10783b857271f12797f1a505efec85630c /layout | |
| parent | 009f865bc5484e54f09d2173b2b3dbbf3838d391 (diff) | |
| download | gui-0cc6367a881ab7dba48ace7b111e0eb1151c10bb.zip | |
Better separation between Layout and Mux
Diffstat (limited to 'layout')
| -rw-r--r-- | layout/box.go | 13 | ||||
| -rw-r--r-- | layout/grid.go | 21 | ||||
| -rw-r--r-- | layout/layout.go | 9 | ||||
| -rw-r--r-- | layout/mux.go | 43 | ||||
| -rw-r--r-- | layout/split.go | 9 |
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 |