diff options
| author | Sam Anthony <sam@samanthony.xyz> | 2026-02-11 17:42:51 -0500 |
|---|---|---|
| committer | Sam Anthony <sam@samanthony.xyz> | 2026-02-11 17:42:51 -0500 |
| commit | c8610ea4164403c418c3fc13aee13685aeff447f (patch) | |
| tree | 06e0d4b2012b791fd6bec059d6cde0fd22a3d5e1 | |
| parent | ebc5d96f0614ab3b4f2073eadf22fbe554b0ec8f (diff) | |
| download | gui-c8610ea4164403c418c3fc13aee13685aeff447f.zip | |
add border layout
| -rw-r--r-- | layout/border.go | 234 | ||||
| -rw-r--r-- | layout/geo.go | 97 | ||||
| -rw-r--r-- | layout/geo_test.go | 98 | ||||
| -rw-r--r-- | layout/region.go | 45 | ||||
| -rw-r--r-- | layout/resize.go | 35 | ||||
| -rw-r--r-- | layout/resize_test.go | 58 | ||||
| -rw-r--r-- | layout/rows.go | 6 | ||||
| -rw-r--r-- | test/border/main.go | 95 | ||||
| -rw-r--r-- | test/region/main.go | 8 | ||||
| -rw-r--r-- | test/rows/main.go | 2 |
10 files changed, 555 insertions, 123 deletions
diff --git a/layout/border.go b/layout/border.go new file mode 100644 index 0000000..c60e602 --- /dev/null +++ b/layout/border.go @@ -0,0 +1,234 @@ +package layout + +import ( + "fmt" + "image" + "image/color" + "image/draw" + + "github.com/faiface/gui" +) + +// NewBorder creates a layout with a margin, border, and padding drawn around itself. +func NewBorder(env gui.Env, opts ...BorderOption) gui.Env { + o := evalBorderOptions(opts...) + + events := make(chan gui.Event) // to child + draws := make(chan func(draw.Image) image.Rectangle) // from child + + go func(events chan<- gui.Event, draws <-chan func(draw.Image) image.Rectangle) { + defer close(env.Draw()) + defer close(events) + + redraw := func(area image.Rectangle) { + env.Draw() <- drawBorder(o) + fmt.Println("area, content:", area, borderContentArea(area, o)) + events <- gui.Resize{borderContentArea(area, o)} // translate and forward to child + } + + // Forward first resize event to child and draw border + event := (<-env.Events()).(gui.Resize) // first event guaranteed to be Resize + area := event.Rectangle + go redraw(area) + + for { + select { + case event := <-env.Events(): // event from parent + switch event := event.(type) { + case gui.Resize: + area = event.Rectangle + go redraw(area) + default: + go func() { events <- event }() // forward to child + } + case f, ok := <-draws: // draw call from child + if !ok { + return + } + env.Draw() <- drawSubImage(f, borderContentArea(area, o)) + } + } + }(events, draws) + + return NewRegion(borderEnv{events, draws}, color.Transparent, Full()) +} + +// BorderContentArea returns the drawable area inside the margin, +// border, and padding of a border layout, given the overall area +// of the layout and the options. +func borderContentArea(area image.Rectangle, o borderOptions) image.Rectangle { + top := o.margin.top + o.border.top + o.padding.top + right := o.margin.right + o.border.right + o.padding.right + bottom := o.margin.bottom + o.border.bottom + o.padding.bottom + left := o.margin.left + o.border.left + o.padding.left + return Inset(top, right, bottom, left)(area) +} + +func drawBorder(o borderOptions) func(draw.Image) image.Rectangle { + return func(img draw.Image) image.Rectangle { + r := Inset(o.margin.top, o.margin.right, o.margin.bottom, o.margin.left)(img.Bounds()) + mask := image.NewAlpha(image.Rect(0, 0, r.Dx(), r.Dy())) + draw.Draw(mask, mask.Bounds(), image.Opaque, image.ZP, draw.Src) // mask border + draw.Draw(mask, Inset(o.border.top, o.border.right, o.border.bottom, o.border.left)(mask.Bounds()), image.Transparent, image.ZP, draw.Src) // unmask inside border + draw.DrawMask(img, r, &image.Uniform{o.Color}, image.ZP, mask, image.ZP, draw.Over) + fmt.Println("border:", r) + return r + } +} + +// BorderOption is a functional option for the NewBorder constructor. +type BorderOption func(o *borderOptions) + +type borderOptions struct { + margin, border, padding sides + color.Color +} + +type sides struct{ top, right, bottom, left int } + +// Margin option sets the margin size, in pixels, on all sides. +func Margin(px int) BorderOption { + if px < 0 { + panic(fmt.Sprintf("margin %d < 0", px)) + } + return func(o *borderOptions) { o.margin = sides{px, px, px, px} } +} + +// MarginTop option sets the top margin size, in pixels. +func MarginTop(px int) BorderOption { + if px < 0 { + panic(fmt.Sprintf("margin %d < 0", px)) + } + return func(o *borderOptions) { o.margin.top = px } +} + +// MarginRight option sets the right margin size, in pixels. +func MarginRight(px int) BorderOption { + if px < 0 { + panic(fmt.Sprintf("margin %d < 0", px)) + } + return func(o *borderOptions) { o.margin.right = px } +} + +// MarginBottom option sets the bottom margin size, in pixels. +func MarginBottom(px int) BorderOption { + if px < 0 { + panic(fmt.Sprintf("margin %d < 0", px)) + } + return func(o *borderOptions) { o.margin.bottom = px } +} + +// MarginLeft option sets the left margin size, in pixels. +func MarginLeft(px int) BorderOption { + if px < 0 { + panic(fmt.Sprintf("margin %d < 0", px)) + } + return func(o *borderOptions) { o.margin.left = px } +} + +// Border option sets the border thickness (in pixels) and color on all sides. +func Border(thick int, c color.Color) BorderOption { + if thick < 0 { + panic(fmt.Sprintf("border thickness %d < 0", thick)) + } + return func(o *borderOptions) { + o.border = sides{thick, thick, thick, thick} + o.Color = c + } +} + +// BorderColor sets the color of the border. +func BorderColor(c color.Color) BorderOption { + return func(o *borderOptions) { o.Color = c } +} + +// BorderTop sets the top border thickness, in pixels. +func BorderTop(thick int) BorderOption { + if thick < 0 { + panic(fmt.Sprintf("border thickness %d < 0", thick)) + } + return func(o *borderOptions) { o.border.top = thick } +} + +// BorderRight sets the right border thickness, in pixels. +func BorderRight(thick int) BorderOption { + if thick < 0 { + panic(fmt.Sprintf("border thickness %d < 0", thick)) + } + return func(o *borderOptions) { o.border.right = thick } +} + +// BorderBottom sets the bottom border thickness, in pixels. +func BorderBottom(thick int) BorderOption { + if thick < 0 { + panic(fmt.Sprintf("border thickness %d < 0", thick)) + } + return func(o *borderOptions) { o.border.bottom = thick } +} + +// BorderLeft sets the left border thickness, in pixels. +func BorderLeft(thick int) BorderOption { + if thick < 0 { + panic(fmt.Sprintf("border thickness %d < 0", thick)) + } + return func(o *borderOptions) { o.border.left = thick } +} + +// Padding option sets the padding size, in pixels, on all sides. +func Padding(px int) BorderOption { + if px < 0 { + panic(fmt.Sprintf("padding %d < 0", px)) + } + return func(o *borderOptions) { o.padding = sides{px, px, px, px} } +} + +// PaddingTop option sets the top padding size, in pixels. +func PaddingTop(px int) BorderOption { + if px < 0 { + panic(fmt.Sprintf("padding %d < 0", px)) + } + return func(o *borderOptions) { o.padding.top = px } +} + +// PaddingRight option sets the right padding size, in pixels. +func PaddingRight(px int) BorderOption { + if px < 0 { + panic(fmt.Sprintf("padding %d < 0", px)) + } + return func(o *borderOptions) { o.padding.right = px } +} + +// PaddingBottom option sets the bottom padding size, in pixels. +func PaddingBottom(px int) BorderOption { + if px < 0 { + panic(fmt.Sprintf("padding %d < 0", px)) + } + return func(o *borderOptions) { o.padding.bottom = px } +} + +// PaddingLeft option sets the left padding size, in pixels. +func PaddingLeft(px int) BorderOption { + if px < 0 { + panic(fmt.Sprintf("padding %d < 0", px)) + } + return func(o *borderOptions) { o.padding.left = px } +} + +func evalBorderOptions(opts ...BorderOption) borderOptions { + o := borderOptions{} + for _, opt := range opts { + opt(&o) + } + return o +} + +type borderEnv struct { + events <-chan gui.Event + draw chan<- func(draw.Image) image.Rectangle +} + +// Events implements the Env interface. +func (b borderEnv) Events() <-chan gui.Event { return b.events } + +// Draw implements the Env interface. +func (b borderEnv) Draw() chan<- func(draw.Image) image.Rectangle { return b.draw } diff --git a/layout/geo.go b/layout/geo.go new file mode 100644 index 0000000..6f84049 --- /dev/null +++ b/layout/geo.go @@ -0,0 +1,97 @@ +package layout + +import ( + "fmt" + "image" +) + +// ResizeFunc is a function that computes the area of a layout when it receives a Resize event. +// It takes the Resize's Rectangle and returns the area that the layout should cover. +type ResizeFunc func(image.Rectangle) image.Rectangle + +// Full resizes a layout to consume all of its parent's area. +func Full() ResizeFunc { + return func(r image.Rectangle) image.Rectangle { return r } +} + +// Quad1 resizes a layout to consume the top-right quadrant of its parent. +func Quad1() ResizeFunc { + return func(r image.Rectangle) image.Rectangle { + mid := midpoint(r) + return image.Rect(mid.X, r.Min.Y, r.Max.X, mid.Y) + } +} + +// Quad2 resizes a layout to consume the top-left quadrant of its parent. +func Quad2() ResizeFunc { + return func(r image.Rectangle) image.Rectangle { + mid := midpoint(r) + return image.Rectangle{r.Min, mid} + } +} + +// Quad3 resizes a layout to consume the bottom-left quadrant of its parent. +func Quad3() ResizeFunc { + return func(r image.Rectangle) image.Rectangle { + mid := midpoint(r) + return image.Rect(r.Min.X, mid.Y, mid.X, r.Max.Y) + } +} + +// Quad4 resizes a layout to consume the bottom-right quadrant of its parent. +func Quad4() ResizeFunc { + return func(r image.Rectangle) image.Rectangle { + mid := midpoint(r) + return image.Rectangle{mid, r.Max} + } +} + +// Inset resizes a layout to be inset some number of pixels from the edges of its parent. +func Inset(top, right, bottom, left int) ResizeFunc { + if top < 0 { + panic(fmt.Sprintf("inset %d < 0", top)) + } else if right < 0 { + panic(fmt.Sprintf("inset %d < 0", right)) + } else if bottom < 0 { + panic(fmt.Sprintf("inset %d < 0", bottom)) + } else if left < 0 { + panic(fmt.Sprintf("inset %d < 0", left)) + } + return func(r image.Rectangle) image.Rectangle { + if r.Dx() < left+right { + r.Min.X = (r.Min.X + r.Max.X) / 2 + r.Max.X = r.Min.X + } else { + r.Min.X += left + r.Max.X -= right + } + if r.Dy() < top+bottom { + r.Min.Y = (r.Min.Y + r.Max.Y) / 2 + r.Max.Y = r.Min.Y + } else { + r.Min.Y += top + r.Max.Y -= bottom + } + return r + } +} + +// InsetAll resizes as layout to be inset px pixels on all sides from the edges of its parent. +func InsetAll(px int) ResizeFunc { return Inset(px, px, px, px) } + +// InsetTop resizes a layout to be inset px pixels from the top edge of its parent. +func InsetTop(px int) ResizeFunc { return Inset(px, 0, 0, 0) } + +// InsetRight resizes a layout to be inset px pixels from the top edge of its parent. +func InsetRight(px int) ResizeFunc { return Inset(0, px, 0, 0) } + +// InsetBottom resizes a layout to be inset px pixels from the top edge of its parent. +func InsetBottom(px int) ResizeFunc { return Inset(0, 0, px, 0) } + +// InsetLeft resizes a layout to be inset px pixels from the top edge of its parent. +func InsetLeft(px int) ResizeFunc { return Inset(0, 0, 0, px) } + +// midpoint returns the point in the middle of a rectangle. +func midpoint(r image.Rectangle) image.Point { + return r.Min.Add(r.Max).Div(2) +} diff --git a/layout/geo_test.go b/layout/geo_test.go new file mode 100644 index 0000000..7dfc864 --- /dev/null +++ b/layout/geo_test.go @@ -0,0 +1,98 @@ +package layout_test + +import ( + "image" + "testing" + + "github.com/faiface/gui/layout" +) + +func TestFull(t *testing.T) { + t.Parallel() + parent := image.Rect(111, 222, 333, 444) + want := parent + testResize(t, layout.Full(), parent, want) +} + +func TestQuad1(t *testing.T) { + t.Parallel() + parent := image.Rect(111, 222, 333, 444) + want := image.Rect(222, 222, 333, 333) + testResize(t, layout.Quad1(), parent, want) +} + +func TestQuad2(t *testing.T) { + t.Parallel() + parent := image.Rect(111, 222, 333, 444) + want := image.Rect(111, 222, 222, 333) + testResize(t, layout.Quad2(), parent, want) +} + +func TestQuad3(t *testing.T) { + t.Parallel() + parent := image.Rect(111, 222, 333, 444) + want := image.Rect(111, 333, 222, 444) + testResize(t, layout.Quad3(), parent, want) +} + +func TestQuad4(t *testing.T) { + t.Parallel() + parent := image.Rect(111, 222, 333, 444) + want := image.Rect(222, 333, 333, 444) + testResize(t, layout.Quad4(), parent, want) +} + +func TestInset(t *testing.T) { + t.Parallel() + parent := image.Rect(111, 222, 333, 444) + resize := layout.Inset(1, 2, 3, 4) + want := image.Rect(115, 223, 331, 441) + testResize(t, resize, parent, want) +} + +func TestInsetAll(t *testing.T) { + t.Parallel() + parent := image.Rect(111, 222, 333, 444) + resize := layout.InsetAll(5) + want := parent.Inset(5) + testResize(t, resize, parent, want) +} + +func TestInsetTop(t *testing.T) { + t.Parallel() + parent := image.Rect(111, 222, 333, 444) + resize := layout.InsetTop(2) + want := image.Rect(111, 224, 333, 444) + testResize(t, resize, parent, want) +} + +func TestInsetRight(t *testing.T) { + t.Parallel() + parent := image.Rect(111, 222, 333, 444) + resize := layout.InsetRight(3) + want := image.Rect(111, 222, 330, 444) + testResize(t, resize, parent, want) +} + +func TestInsetBottom(t *testing.T) { + t.Parallel() + parent := image.Rect(111, 222, 333, 444) + resize := layout.InsetBottom(4) + want := image.Rect(111, 222, 333, 440) + testResize(t, resize, parent, want) +} + +func TestInsetLeft(t *testing.T) { + t.Parallel() + parent := image.Rect(111, 222, 333, 444) + resize := layout.InsetLeft(1) + want := image.Rect(112, 222, 333, 444) + testResize(t, resize, parent, want) +} + +func testResize(t *testing.T, f layout.ResizeFunc, r, want image.Rectangle) { + r1 := f(r) + if r1 != want { + t.Errorf("resize(%v) = %v; want %v", r, r1, want) + } +} diff --git a/layout/region.go b/layout/region.go index 1e4d4b1..08fa48d 100644 --- a/layout/region.go +++ b/layout/region.go @@ -17,45 +17,46 @@ type Region struct { // 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. // It returns the child Env. -func NewRegion(env gui.Env, clr color.Color, 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 +func NewRegion(env gui.Env, clr color.Color, resize ResizeFunc) gui.Env { + events := make(chan gui.Event) // to child + draws := 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} + go func(events chan<- gui.Event, draws <-chan func(draw.Image) image.Rectangle) { + defer close(env.Draw()) + defer close(events) - // Draw background - redrawBg := func(area image.Rectangle) func(draw.Image) image.Rectangle { - return drawSubImage(drawBackground(clr), area) + redraw := func(area, childArea image.Rectangle) { + env.Draw() <- drawSubImage(drawBackground(clr), area) + events <- gui.Resize{childArea} } - env.Draw() <- redrawBg(area) + + // Draw background and forward first resize event to child + event := (<-env.Events()).(gui.Resize) // first event guaranteed to be Resize + area := event.Rectangle + childArea := resize(area) + go redraw(area, childArea) for { select { case event := <-env.Events(): // event from parent switch event := event.(type) { case gui.Resize: - env.Draw() <- redrawBg(area) - area = resize(event.Rectangle) - events <- gui.Resize{area} // forward to child + area = event.Rectangle + childArea = resize(area) + go redraw(area, childArea) default: - events <- event + go func() { events <- event }() // forward to child } - case f, ok := <-drw: // draw call from child + case f, ok := <-draws: // draw call from child if !ok { - close(events) - close(env.Draw()) return } - env.Draw() <- drawSubImage(f, area) + env.Draw() <- drawSubImage(f, childArea) } } - }(events, drw) + }(events, draws) - return Region{events, drw} + return Region{events, draws} } // Events implements the Env interface. diff --git a/layout/resize.go b/layout/resize.go deleted file mode 100644 index 1d3d6f1..0000000 --- a/layout/resize.go +++ /dev/null @@ -1,35 +0,0 @@ -package layout - -import "image" - -// ResizeAll resizes a layout to consume all of its parent's area. -func ResizeAll(r image.Rectangle) image.Rectangle { return r } - -// ResizeQuad1 resizes a layout to consume the top-right quadrant of its parent. -func ResizeQuad1(r image.Rectangle) image.Rectangle { - mid := midpoint(r) - return image.Rect(mid.X, r.Min.Y, r.Max.X, mid.Y) -} - -// ResizeQuad2 resizes a layout to consume the top-left quadrant of its parent. -func ResizeQuad2(r image.Rectangle) image.Rectangle { - mid := midpoint(r) - return image.Rectangle{r.Min, mid} -} - -// ResizeQuad3 resizes a layout to consume the bottom-left quadrant of its parent. -func ResizeQuad3(r image.Rectangle) image.Rectangle { - mid := midpoint(r) - return image.Rect(r.Min.X, mid.Y, mid.X, r.Max.Y) -} - -// ResizeQuad4 resizes a layout to consume the bottom-right quadrant of its parent. -func ResizeQuad4(r image.Rectangle) image.Rectangle { - mid := midpoint(r) - return image.Rectangle{mid, r.Max} -} - -// midpoint returns the point in the middle of a rectangle. -func midpoint(r image.Rectangle) image.Point { - return r.Min.Add(r.Max).Div(2) -} diff --git a/layout/resize_test.go b/layout/resize_test.go deleted file mode 100644 index 5be7a41..0000000 --- a/layout/resize_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package layout_test - -import ( - "image" - "testing" - - "github.com/faiface/gui/layout" -) - -func TestResizeAll(t *testing.T) { - t.Parallel() - parent := image.Rect(111, 222, 333, 444) - child := layout.ResizeAll(parent) - want := parent - if child != want { - t.Errorf("got %v; want %v", child, want) - } -} - -func TestResizeQuad1(t *testing.T) { - t.Parallel() - parent := image.Rect(111, 222, 333, 444) - child := layout.ResizeQuad1(parent) - want := image.Rect(222, 222, 333, 333) - if child != want { - t.Errorf("got %v; want %v", child, want) - } -} - -func TestResizeQuad2(t *testing.T) { - t.Parallel() - parent := image.Rect(111, 222, 333, 444) - child := layout.ResizeQuad2(parent) - want := image.Rect(111, 222, 222, 333) - if child != want { - t.Errorf("got %v; want %v", child, want) - } -} - -func TestResizeQuad3(t *testing.T) { - t.Parallel() - parent := image.Rect(111, 222, 333, 444) - child := layout.ResizeQuad3(parent) - want := image.Rect(111, 333, 222, 444) - if child != want { - t.Errorf("got %v; want %v", child, want) - } -} - -func TestResizeQuad4(t *testing.T) { - t.Parallel() - parent := image.Rect(111, 222, 333, 444) - child := layout.ResizeQuad4(parent) - want := image.Rect(222, 333, 333, 444) - if child != want { - t.Errorf("got %v; want %v", child, want) - } -} diff --git a/layout/rows.go b/layout/rows.go index 603eddc..cfb85c9 100644 --- a/layout/rows.go +++ b/layout/rows.go @@ -39,7 +39,7 @@ func NewRows(env gui.Env, nrows uint) []gui.Env { event := (<-env.Events()).(gui.Resize) // first event guaranteed to be Resize area := event.Rectangle rowHeights := make([]uint, nrows) // initially zero until draw call received - resize(area, rowHeights) // send first Resize to children + go resize(area, rowHeights) // send first Resize to children // Multiplex rows' draw channels. Tag draw functions with row index. draws := make(chan taggedDrawCall) @@ -56,9 +56,9 @@ func NewRows(env gui.Env, nrows uint) []gui.Env { switch event := event.(type) { case gui.Resize: area = event.Rectangle - resize(area, rowHeights) + go resize(area, rowHeights) default: - multicast(event, eventss) // forward event to all rows + go multicast(event, eventss) // forward event to all rows } case drw := <-draws: // draw call from a row rh := rowHeight(area, drw.f) diff --git a/test/border/main.go b/test/border/main.go new file mode 100644 index 0000000..315216c --- /dev/null +++ b/test/border/main.go @@ -0,0 +1,95 @@ +package main + +import ( + "image" + "image/color" + "image/draw" + "time" + + "github.com/faiface/gui" + "github.com/faiface/gui/layout" + "github.com/faiface/gui/win" + "github.com/faiface/mainthread" +) + +const ( + margin = 10 + border = 2 + padding = 15 +) + +var ( + bgClr = gui.HexToColor("#999999") // background color + brdrClr = color.RGBA{0xFF, 0x00, 0xFF, 0xFF} +) + +func main() { + mainthread.Run(run) +} + +func run() { + w, err := win.New(win.Title("Grid Layout Test"), win.Resizable()) + if err != nil { + panic(err) + } + + mux, env := gui.NewMux(w) + + // Background + bg := layout.NewRegion(mux.MakeEnv(), bgClr, layout.Full()) + + // Margin, border, and padding + border := layout.NewBorder(bg, layout.Margin(margin), layout.Border(border, brdrClr), layout.Padding(padding)) + + //region := layout.NewRegion(border, color.White, layout.Full()) + //go func() { for range region.Events() {} }() + + // Region in top-right quadrant + region := layout.NewRegion(border, color.Transparent, layout.Quad1()) + go blinker(region) + + for event := range env.Events() { + switch event.(type) { + case win.WiClose: + close(env.Draw()) + return + } + } +} + +// Blinker is a widget that blinks three times when it is clicked. +func blinker(env gui.Env) { + redraw := func(visible bool) func(draw.Image) image.Rectangle { + return func(img draw.Image) image.Rectangle { + if visible { + draw.Draw(img, img.Bounds(), image.White, image.ZP, draw.Src) + } else { + draw.Draw(img, img.Bounds(), image.Black, image.ZP, draw.Src) + } + return img.Bounds() + } + } + + area := (<-env.Events()).(gui.Resize).Rectangle // first event guaranteed to be Resize + env.Draw() <- redraw(true) + + for event := range env.Events() { + switch event := event.(type) { + case gui.Resize: + area = event.Rectangle + env.Draw() <- redraw(true) + case win.MoDown: + if event.Point.In(area) { + go func() { + for i := 0; i < 3; i++ { + env.Draw() <- redraw(false) + time.Sleep(time.Second / 6) + env.Draw() <- redraw(true) + time.Sleep(time.Second / 6) + } + }() + } + } + } + close(env.Draw()) +} diff --git a/test/region/main.go b/test/region/main.go index ef7f9ac..0ea358c 100644 --- a/test/region/main.go +++ b/test/region/main.go @@ -26,11 +26,11 @@ func run() { mux, env := gui.NewMux(w) - // Background region - bg := layout.NewRegion(mux.MakeEnv(), bgclr, layout.ResizeAll) + // Background + bg := layout.NewRegion(mux.MakeEnv(), bgclr, layout.Full()) - // Region on top of background, in bottom-right quadrant - region := layout.NewRegion(bg, color.Transparent, layout.ResizeQuad4) + // Region in bottom-right quadrant + region := layout.NewRegion(bg, color.Transparent, layout.Quad4()) go blinker(region) for event := range env.Events() { diff --git a/test/rows/main.go b/test/rows/main.go index 29b7344..0b78893 100644 --- a/test/rows/main.go +++ b/test/rows/main.go @@ -30,7 +30,7 @@ func run() { } mux, env := gui.NewMux(w) - bg := layout.NewRegion(mux.MakeEnv(), bgclr, layout.ResizeAll) + bg := layout.NewRegion(mux.MakeEnv(), bgclr, layout.Full()) rows := layout.NewRows(bg, nrows) for i, row := range rows { go colorBlock(row, image.Pt(rowWidth, rowHeight), color.RGBA{uint8(i * 256 / 4), 0x20, 0x20, 0xFF}) |