From 5fde17eafa11bf397bbf1f18864b8ee26d9a701d Mon Sep 17 00:00:00 2001 From: Sam Anthony Date: Mon, 9 Feb 2026 21:01:34 -0500 Subject: add region layout --- layout/doc.go | 15 +++++++++++++ layout/region.go | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ layout/subimage.go | 17 +++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 layout/doc.go create mode 100644 layout/region.go create mode 100644 layout/subimage.go (limited to 'layout') diff --git a/layout/doc.go b/layout/doc.go new file mode 100644 index 0000000..bae4673 --- /dev/null +++ b/layout/doc.go @@ -0,0 +1,15 @@ +/* +Package layout provides means of partitioning screen space. + +A layout exists in a parent Env, and has one or more child Envs. It +acts as a multiplexer for the children. The parent Env may be a window, +another layout, or whatever... Several layers of layouts can be composed. + +A layout allocates screen area to its children by intercepting Resize +events from the parent Env. Upon reception by the layout, a Resize event +is transformed for each child, and forwarded to them. + +Draw calls from the children are intercepted and translated onto their +respective areas before being forwarded to the parent Env. +*/ +package layout diff --git a/layout/region.go b/layout/region.go new file mode 100644 index 0000000..1e92455 --- /dev/null +++ b/layout/region.go @@ -0,0 +1,63 @@ +package layout + +import ( + "image" + "image/draw" + + "github.com/faiface/gui" +) + +// Region is a layout with a single child Env that occupies a sub-area of its parent. +type Region struct { + events <-chan gui.Event + draw chan<- func(draw.Image) image.Rectangle +} + +// NewRegion creates a region layout that occupies part of the parent env's area, as determined by the resize function. +// Resize takes the area of the parent and returns the area of the region. +func NewRegion(env gui.Env, resize func(image.Rectangle) image.Rectangle) gui.Env { + events := make(chan gui.Event) // to child + drw := make(chan func(draw.Image) image.Rectangle) // from child + + go func(events chan<- gui.Event, drw <-chan func(draw.Image) image.Rectangle) { + // Forward first resize event to child + event := <-env.Events() + area := resize(event.(gui.Resize).Rectangle) // first event guaranteed to be Resize + events <- gui.Resize{area} + + for { + select { + case event := <-env.Events(): + switch event := event.(type) { + case gui.Resize: + area = resize(event.Rectangle) + events <- gui.Resize{area} + default: + events <- event + } + case f, ok := <-drw: + if !ok { + close(events) + close(env.Draw()) + return + } + env.Draw() <- drawRegion(f, area) + } + } + }(events, drw) + + return Region{events, drw} +} + +// Translate a draw call to the given area. +func drawRegion(f func(draw.Image) image.Rectangle, area image.Rectangle) func(draw.Image) image.Rectangle { + return func(img draw.Image) image.Rectangle { + return f(subimage(img, area)) + } +} + +// Events implements the Env interface. +func (r Region) Events() <-chan gui.Event { return r.events } + +// Draw implements the Env interface. +func (r Region) Draw() chan<- func(draw.Image) image.Rectangle { return r.draw } diff --git a/layout/subimage.go b/layout/subimage.go new file mode 100644 index 0000000..ecbe931 --- /dev/null +++ b/layout/subimage.go @@ -0,0 +1,17 @@ +package layout + +import ( + "image" + "image/draw" +) + +type subimager interface { + SubImage(image.Rectangle) image.Image +} + +// Subimage returns an image representing the portion of the image m visible through r. +// The returned value shares pixels with the original. +// Panics if the concrete image type does not have a SubImage() method. +func subimage(m draw.Image, r image.Rectangle) draw.Image { + return m.(subimager).SubImage(r).(draw.Image) +} -- cgit v1.2.3