From 1223e277009005337243ca991cb54dd75bf723a7 Mon Sep 17 00:00:00 2001 From: Clement Benard Date: Tue, 9 Jul 2019 10:59:38 +0200 Subject: Layout system remaking --- layout/grid.go | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 layout/grid.go (limited to 'layout/grid.go') diff --git a/layout/grid.go b/layout/grid.go new file mode 100644 index 0000000..55111cb --- /dev/null +++ b/layout/grid.go @@ -0,0 +1,92 @@ +package layout + +import ( + "image" + "image/color" + "image/draw" + + "github.com/faiface/gui" +) + +// Grid represents a simple grid layout. +// Do not edit properties directly, use the constructor instead. +type Grid struct { + Contents [][]*gui.Env + Background color.Color + Gap int + SplitX func(int, int) []int + SplitY func(int, int) []int +} + +func NewGrid(env gui.Env, contents [][]*gui.Env, options ...func(*Grid)) { + ret := &Grid{ + Background: image.Black, + Gap: 0, + Contents: contents, + SplitX: evenSplit, + SplitY: evenSplit, + } + for _, f := range options { + f(ret) + } + + mux := NewMux(env, ret) + for _, row := range contents { + for _, item := range row { + *item, _ = mux.makeEnv(false) + } + } +} + +func GridBackground(c color.Color) func(*Grid) { + return func(grid *Grid) { + grid.Background = c + } +} + +func GridGap(g int) func(*Grid) { + return func(grid *Grid) { + grid.Gap = g + } +} + +func GridSplitX(split func(int, int) []int) func(*Grid) { + return func(grid *Grid) { + grid.SplitX = split + } +} + +func GridSplitY(split func(int, int) []int) func(*Grid) { + return func(grid *Grid) { + grid.SplitY = split + } +} + +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) Lay(bounds image.Rectangle) []image.Rectangle { + gap := g.Gap + ret := make([]image.Rectangle, 0) + rows := len(g.Contents) + + rowsH := g.SplitY(rows, bounds.Dy()-(g.Gap*(rows+1))) + + X := gap + bounds.Min.X + Y := gap + bounds.Min.Y + for y, row := range g.Contents { + cols := len(row) + h := rowsH[y] + colsW := g.SplitX(cols, bounds.Dx()-(g.Gap*(cols+1))) + X = gap + bounds.Min.X + for x := range row { + w := colsW[x] + ret = append(ret, image.Rect(X, Y, X+w, Y+h)) + X += gap + w + } + Y += gap + h + } + + return ret +} -- cgit v1.2.3 From 1415586e633ee33194442f131a5a691f889c8ee5 Mon Sep 17 00:00:00 2001 From: Clement Benard Date: Tue, 9 Jul 2019 15:31:32 +0200 Subject: better Mux and Env handling in layout --- layout/grid.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'layout/grid.go') diff --git a/layout/grid.go b/layout/grid.go index 55111cb..1831794 100644 --- a/layout/grid.go +++ b/layout/grid.go @@ -18,7 +18,7 @@ type Grid struct { SplitY func(int, int) []int } -func NewGrid(env gui.Env, contents [][]*gui.Env, options ...func(*Grid)) { +func NewGrid(env gui.Env, contents [][]*gui.Env, options ...func(*Grid)) gui.Env { ret := &Grid{ Background: image.Black, Gap: 0, @@ -30,12 +30,14 @@ func NewGrid(env gui.Env, contents [][]*gui.Env, options ...func(*Grid)) { f(ret) } - mux := NewMux(env, ret) + mux, env := NewMux(env, ret) for _, row := range contents { for _, item := range row { - *item, _ = mux.makeEnv(false) + *item = mux.MakeEnv() } } + + return env } func GridBackground(c color.Color) func(*Grid) { -- cgit v1.2.3 From 009f865bc5484e54f09d2173b2b3dbbf3838d391 Mon Sep 17 00:00:00 2001 From: Clement Benard Date: Thu, 11 Jul 2019 10:50:37 +0200 Subject: Added SplitFunc type, documented everything exported --- layout/grid.go | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) (limited to 'layout/grid.go') diff --git a/layout/grid.go b/layout/grid.go index 1831794..9c79343 100644 --- a/layout/grid.go +++ b/layout/grid.go @@ -8,23 +8,23 @@ import ( "github.com/faiface/gui" ) -// Grid represents a simple grid layout. -// Do not edit properties directly, use the constructor instead. -type Grid struct { +type grid struct { Contents [][]*gui.Env Background color.Color Gap int - SplitX func(int, int) []int - SplitY func(int, int) []int + SplitX SplitFunc + SplitY SplitFunc } -func NewGrid(env gui.Env, contents [][]*gui.Env, options ...func(*Grid)) gui.Env { - ret := &Grid{ +// 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 { + ret := &grid{ Background: image.Black, Gap: 0, Contents: contents, - SplitX: evenSplit, - SplitY: evenSplit, + SplitX: EvenSplit, + SplitY: EvenSplit, } for _, f := range options { f(ret) @@ -40,35 +40,40 @@ func NewGrid(env gui.Env, contents [][]*gui.Env, options ...func(*Grid)) gui.Env return env } -func GridBackground(c color.Color) func(*Grid) { - return func(grid *Grid) { +// GridBackground changes the background of the grid to a uniform color. +func GridBackground(c color.Color) func(*grid) { + return func(grid *grid) { grid.Background = c } } -func GridGap(g int) func(*Grid) { - return func(grid *Grid) { +// GridGap changes the grid gap. +// The gap is identical everywhere (top, left, bottom, right). +func GridGap(g int) func(*grid) { + return func(grid *grid) { grid.Gap = g } } -func GridSplitX(split func(int, int) []int) func(*Grid) { - return func(grid *Grid) { +// GridSplitX changes the way the space is divided among the columns in each row. +func GridSplitX(split SplitFunc) func(*grid) { + return func(grid *grid) { grid.SplitX = split } } -func GridSplitY(split func(int, int) []int) func(*Grid) { - return func(grid *Grid) { +// GridSplitY changes the way the space is divided among the rows. +func GridSplitY(split SplitFunc) func(*grid) { + return func(grid *grid) { grid.SplitY = split } } -func (g *Grid) Redraw(drw draw.Image, bounds image.Rectangle) { +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) Lay(bounds image.Rectangle) []image.Rectangle { +func (g *grid) Lay(bounds image.Rectangle) []image.Rectangle { gap := g.Gap ret := make([]image.Rectangle, 0) rows := len(g.Contents) -- cgit v1.2.3 From 0cc6367a881ab7dba48ace7b111e0eb1151c10bb Mon Sep 17 00:00:00 2001 From: Clement Benard Date: Fri, 12 Jul 2019 17:23:28 +0200 Subject: Better separation between Layout and Mux --- layout/grid.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'layout/grid.go') 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) -- cgit v1.2.3 From 736e35bd9b0c8f4f9649557e4b7a3085b4bdbe63 Mon Sep 17 00:00:00 2001 From: Clement Benard Date: Mon, 15 Jul 2019 15:44:34 +0200 Subject: Easier and more idiomatic Layout initializing --- layout/grid.go | 98 +++++++++++++++++----------------------------------------- 1 file changed, 28 insertions(+), 70 deletions(-) (limited to 'layout/grid.go') diff --git a/layout/grid.go b/layout/grid.go index c90821a..f3cced6 100644 --- a/layout/grid.go +++ b/layout/grid.go @@ -4,92 +4,50 @@ import ( "image" "image/color" "image/draw" - - "github.com/faiface/gui" ) -type grid struct { - Contents [][]*gui.Env +type Grid struct { + // Rows represents the number of childs of each row. + Rows []int + // Background represents the background of the grid as a uniform color. Background color.Color - Gap int - SplitX SplitFunc - SplitY SplitFunc -} - -// NewGrid creates a familiar flexbox-like grid layout. -// Each row can be a different length. -func NewGrid(contents [][]*gui.Env, options ...func(*grid)) Layout { - ret := &grid{ - Background: image.Black, - Gap: 0, - Contents: contents, - SplitX: EvenSplit, - SplitY: EvenSplit, - } - for _, f := range options { - f(ret) - } - return ret -} - -// GridBackground changes the background of the grid to a uniform color. -func GridBackground(c color.Color) func(*grid) { - return func(grid *grid) { - grid.Background = c - } -} - -// GridGap changes the grid gap. -// The gap is identical everywhere (top, left, bottom, right). -func GridGap(g int) func(*grid) { - return func(grid *grid) { - grid.Gap = g - } + // Gap represents the grid gap, equal on all sides. + Gap int + // SplitX represents the way the space is divided among the columns in each row. + SplitX SplitFunc + // SplitY represents the way the space is divided among the rows. + SplitY SplitFunc } -// GridSplitX changes the way the space is divided among the columns in each row. -func GridSplitX(split SplitFunc) func(*grid) { - return func(grid *grid) { - grid.SplitX = split +func (g Grid) Redraw(drw draw.Image, bounds image.Rectangle) { + col := g.Background + if col == nil { + col = image.Black } + draw.Draw(drw, bounds, image.NewUniform(col), image.ZP, draw.Src) } -// GridSplitY changes the way the space is divided among the rows. -func GridSplitY(split SplitFunc) func(*grid) { - return func(grid *grid) { - grid.SplitY = split +func (g Grid) Lay(bounds image.Rectangle) []image.Rectangle { + gap := g.Gap + rows := g.Rows + splitX := g.SplitX + if splitX == nil { + splitX = EvenSplit } -} - -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...) + splitY := g.SplitY + if splitY == nil { + splitY = EvenSplit } - return ret -} -func (g *grid) Lay(bounds image.Rectangle) []image.Rectangle { - gap := g.Gap ret := make([]image.Rectangle, 0) - rows := len(g.Contents) - - rowsH := g.SplitY(rows, bounds.Dy()-(g.Gap*(rows+1))) - + rowsH := splitY(len(rows), bounds.Dy()-(gap*(len(rows)+1))) X := gap + bounds.Min.X Y := gap + bounds.Min.Y - for y, row := range g.Contents { - cols := len(row) + for y, cols := range rows { h := rowsH[y] - colsW := g.SplitX(cols, bounds.Dx()-(g.Gap*(cols+1))) + colsW := splitX(cols, bounds.Dx()-(gap*(cols+1))) X = gap + bounds.Min.X - for x := range row { - w := colsW[x] + for _, w := range colsW { ret = append(ret, image.Rect(X, Y, X+w, Y+h)) X += gap + w } -- cgit v1.2.3 From 8d183ef96a57e3a2f42c0cb4ec0ab4c256e0d47e Mon Sep 17 00:00:00 2001 From: Clement Benard Date: Wed, 7 Aug 2019 16:02:33 +0200 Subject: Made the layout package actually usable --- layout/grid.go | 95 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 19 deletions(-) (limited to 'layout/grid.go') diff --git a/layout/grid.go b/layout/grid.go index f3cced6..3ff8112 100644 --- a/layout/grid.go +++ b/layout/grid.go @@ -4,8 +4,15 @@ import ( "image" "image/color" "image/draw" + "log" + + "github.com/faiface/gui" ) +var _ Layout = Grid{} + +// Grid represents a grid with rows and columns in each row. +// Each row can be a different length. type Grid struct { // Rows represents the number of childs of each row. Rows []int @@ -13,42 +20,92 @@ type Grid struct { Background color.Color // Gap represents the grid gap, equal on all sides. Gap int - // SplitX represents the way the space is divided among the columns in each row. - SplitX SplitFunc - // SplitY represents the way the space is divided among the rows. - SplitY SplitFunc + // Split represents the way the space is divided among the columns in each row. + Split SplitFunc + // SplitRows represents the way the space is divided among the rows. + SplitRows SplitFunc + + Margin int + Border int + BorderColor color.Color + + // Flip represents the orientation of the grid. + // When false, rows are spread in the Y axis and columns in the X axis. + // When true, rows are spread in the X axis and columns in the Y axis. + Flip bool } -func (g Grid) Redraw(drw draw.Image, bounds image.Rectangle) { +func (g Grid) redraw(drw draw.Image, bounds image.Rectangle) { col := g.Background if col == nil { - col = image.Black + col = color.Black + } + if g.Border > 0 { + bcol := g.BorderColor + if bcol == nil { + bcol = color.Black + } + draw.Draw(drw, bounds, image.NewUniform(bcol), image.ZP, draw.Src) } - draw.Draw(drw, bounds, image.NewUniform(col), image.ZP, draw.Src) + draw.Draw(drw, bounds.Inset(g.Border), image.NewUniform(col), image.ZP, draw.Src) +} + +func (g Grid) Intercept(env gui.Env) gui.Env { + return RedrawIntercepter{g.redraw}.Intercept(env) } func (g Grid) Lay(bounds image.Rectangle) []image.Rectangle { gap := g.Gap rows := g.Rows - splitX := g.SplitX - if splitX == nil { - splitX = EvenSplit + splitMain := g.Split + if splitMain == nil { + splitMain = EvenSplit + } + splitSec := g.SplitRows + if splitSec == nil { + splitSec = EvenSplit } - splitY := g.SplitY - if splitY == nil { - splitY = EvenSplit + margin := g.Margin + flip := g.Flip + if margin+gap < 0 { + log.Println("Grid goes out of bounds") + } + if margin+gap < g.Border { + log.Println("Grid border will not be shown properly") } ret := make([]image.Rectangle, 0) - rowsH := splitY(len(rows), bounds.Dy()-(gap*(len(rows)+1))) - X := gap + bounds.Min.X - Y := gap + bounds.Min.Y + + // Sorry it's not very understandable + var H, W int + var mX, mY int + if flip { + H = bounds.Dx() + W = bounds.Dy() + mX = bounds.Min.Y + mY = bounds.Min.X + } else { + H = bounds.Dy() + W = bounds.Dx() + mX = bounds.Min.X + mY = bounds.Min.Y + } + rowsH := splitSec(len(rows), H-(gap*(len(rows)+1))-margin*2) + var X int + var Y int + Y = gap + mY + margin for y, cols := range rows { h := rowsH[y] - colsW := splitX(cols, bounds.Dx()-(gap*(cols+1))) - X = gap + bounds.Min.X + colsW := splitMain(cols, W-(gap*(cols+1))-margin*2) + X = gap + mX + margin for _, w := range colsW { - ret = append(ret, image.Rect(X, Y, X+w, Y+h)) + var r image.Rectangle + if flip { + r = image.Rect(Y, X, Y+h, X+w) + } else { + r = image.Rect(X, Y, X+w, Y+h) + } + ret = append(ret, r) X += gap + w } Y += gap + h -- cgit v1.2.3