aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--layout/mux.go170
1 files changed, 72 insertions, 98 deletions
diff --git a/layout/mux.go b/layout/mux.go
index 9d8eb0c..cab7cfa 100644
--- a/layout/mux.go
+++ b/layout/mux.go
@@ -4,8 +4,8 @@ import (
"image"
"image/draw"
"log"
- "sync"
+ "git.samanthony.xyz/share"
"github.com/faiface/gui"
)
@@ -14,14 +14,14 @@ import (
// events apart from gui.Resize, and their draw functions get redirected to the root Env.
//
// All gui.Resize events are instead modified according to the underlying Layout.
-// The master Env gets the original gui.Resize events.
type Mux struct {
- mu sync.Mutex
- lastResize gui.Event
- eventsIns []chan<- gui.Event
- draw chan<- func(draw.Image) image.Rectangle
+ // Sending any value to Kill will terminate the Mux.
+ Kill chan<- any
- layout Layout
+ bounds share.Val[image.Rectangle]
+ draw chan<- func(draw.Image) image.Rectangle
+ eventsIns share.ConstSlice[chan<- gui.Event]
+ layout Layout
}
// Layout returns the underlying Layout of the Mux.
@@ -29,70 +29,77 @@ 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 an underlying Layout
-// for modifying the gui.Resize events sent to the childs.
-func NewMux(parent gui.Env, children []*gui.Env, l Layout) (mux *Mux, master gui.Env) {
- parent = l.Intercept(parent)
- drawChan := make(chan func(draw.Image) image.Rectangle)
- mux = &Mux{
- layout: l,
- draw: drawChan,
- }
- master, masterIn := mux.makeEnv(true)
- events := make(chan gui.Event)
- go func() {
- for d := range drawChan {
- parent.Draw() <- d
- }
- close(parent.Draw())
- }()
+func NewMux(parent gui.Env, children []*gui.Env, layout Layout) Mux {
+ parent = layout.Intercept(parent)
- go func() {
- for e := range parent.Events() {
- events <- e
+ kill := make(chan any)
+ bounds := share.NewVal[image.Rectangle]()
+ drawChan := make(chan func(draw.Image) image.Rectangle)
+ eventsIns := func() share.ConstSlice[chan<- gui.Event] { // create child Env's
+ evIns := make([]chan<- gui.Event, len(children))
+ for i, child := range children {
+ *child, evIns[i] = makeEnv(drawChan)
}
+ return share.NewConstSlice(evIns)
}()
+ mux := Mux{
+ kill,
+ bounds,
+ drawChan,
+ eventsIns,
+ layout,
+ }
go func() {
- for e := range events {
- // master gets a copy of all events to the Mux
- masterIn <- e
- mux.mu.Lock()
- if resize, ok := e.(gui.Resize); ok {
- mux.lastResize = resize
- rect := resize.Rectangle
- lay := mux.layout.Lay(rect)
- if len(lay) < len(children) {
- log.Printf("Lay of %T is not large enough (%d) for %d childs, skipping\n", l, len(lay), len(children))
- mux.mu.Unlock()
- continue
- }
-
- // Send appropriate resize Events to childs
- for i, eventsIn := range mux.eventsIns {
- resize.Rectangle = lay[i]
- eventsIn <- resize
- }
+ defer close(parent.Draw())
+ defer close(kill)
+ defer bounds.Close()
+ defer close(drawChan)
+ defer func() {
+ for eventsIn := range eventsIns.Elems() {
+ close(eventsIn)
+ }
+ eventsIns.Close()
+ }()
- } else {
- for _, eventsIn := range mux.eventsIns {
- eventsIn <- e
+ for {
+ select {
+ case <-kill:
+ return
+ case d := <-drawChan:
+ parent.Draw() <- d
+ case e := <-parent.Events():
+ if resize, ok := e.(gui.Resize); ok {
+ bounds.Set <- resize.Rectangle
+ mux.resizeChildren()
+ } else {
+ for eventsIn := range eventsIns.Elems() {
+ eventsIn <- e
+ }
}
}
- mux.mu.Unlock()
}
- mux.mu.Lock()
- for _, eventsIn := range mux.eventsIns {
- close(eventsIn)
- }
- mux.mu.Unlock()
}()
- for _, child := range children {
- *child, _ = mux.makeEnv(false)
+ // First event of a new Env must be Resize.
+ mux.resizeChildren()
+
+ return mux
+}
+
+func (mux *Mux) resizeChildren() {
+ rect := mux.bounds.Get()
+ lay := mux.layout.Lay(rect)
+ i := 0
+ for eventsIn := range mux.eventsIns.Elems() {
+ if i > len(lay) {
+ log.Printf("Lay of %T is not large enough (%d) for the number of children, skipping\n",
+ mux.layout, len(lay))
+ break
+ }
+ eventsIn <- gui.Resize{lay[i]}
+ i++
}
- return
}
type muxEnv struct {
@@ -103,22 +110,10 @@ type muxEnv struct {
func (m *muxEnv) Events() <-chan gui.Event { return m.events }
func (m *muxEnv) Draw() chan<- func(draw.Image) image.Rectangle { return m.draw }
-// We do not store master env
-func (mux *Mux) makeEnv(master bool) (env gui.Env, eventsIn chan<- gui.Event) {
+func makeEnv(muxDraw chan<- func(draw.Image) image.Rectangle) (env gui.Env, eventsIn chan<- gui.Event) {
eventsOut, eventsIn := gui.MakeEventsChan()
- drawChan := make(chan func(draw.Image) image.Rectangle)
- env = &muxEnv{eventsOut, drawChan}
-
- if !master {
- mux.mu.Lock()
- mux.eventsIns = append(mux.eventsIns, eventsIn)
- // make sure to always send a resize event to a new Env if we got the size already
- // that means it missed the resize event by the root Env
- if mux.lastResize != nil {
- eventsIn <- mux.lastResize
- }
- mux.mu.Unlock()
- }
+ envDraw := make(chan func(draw.Image) image.Rectangle)
+ env = &muxEnv{eventsOut, envDraw}
go func() {
func() {
@@ -137,35 +132,14 @@ func (mux *Mux) makeEnv(master bool) (env gui.Env, eventsIn chan<- gui.Event) {
// commands, correctly draining the Env until it closes itself.
defer func() {
if recover() != nil {
- for range drawChan {
+ for range envDraw {
}
}
}()
- for d := range drawChan {
- mux.draw <- d // !
+ for d := range envDraw {
+ muxDraw <- d // !
}
}()
- if master {
- mux.mu.Lock()
- for _, eventsIn := range mux.eventsIns {
- close(eventsIn)
- }
- mux.eventsIns = nil
- close(mux.draw)
- mux.mu.Unlock()
- } else {
- mux.mu.Lock()
- i := -1
- for i = range mux.eventsIns {
- if mux.eventsIns[i] == eventsIn {
- break
- }
- }
- if i != -1 {
- mux.eventsIns = append(mux.eventsIns[:i], mux.eventsIns[i+1:]...)
- }
- mux.mu.Unlock()
- }
}()
return env, eventsIn