From 3a216b96b6a7c80275a2516e7de82d9b2ffc96df Mon Sep 17 00:00:00 2001 From: Clement Benard Date: Thu, 4 Jul 2019 16:28:51 +0200 Subject: added layout basics --- examples/layout/button.go | 64 +++++++++++++++++++++++ examples/layout/main.go | 128 ++++++++++++++++++++++++++++++++++++++++++++++ examples/layout/theme.go | 19 +++++++ examples/layout/utils.go | 104 +++++++++++++++++++++++++++++++++++++ 4 files changed, 315 insertions(+) create mode 100644 examples/layout/button.go create mode 100644 examples/layout/main.go create mode 100644 examples/layout/theme.go create mode 100644 examples/layout/utils.go (limited to 'examples') diff --git a/examples/layout/button.go b/examples/layout/button.go new file mode 100644 index 0000000..6c907e3 --- /dev/null +++ b/examples/layout/button.go @@ -0,0 +1,64 @@ +package main + +import ( + "image" + "image/color" + "image/draw" + "log" + + "github.com/faiface/gui" + "github.com/faiface/gui/win" +) + +func Button(env gui.Env, theme *Theme, text string, action func()) { + textImg := MakeTextImage(text, theme.Face, theme.Text) + + redraw := func(r image.Rectangle, over, pressed bool) func(draw.Image) image.Rectangle { + return func(drw draw.Image) image.Rectangle { + var clr color.Color + if pressed { + clr = theme.ButtonDown + } else if over { + clr = theme.ButtonOver + } else { + clr = theme.ButtonUp + } + draw.Draw(drw, r, &image.Uniform{clr}, image.ZP, draw.Src) + DrawCentered(drw, r, textImg, draw.Over) + return r + } + } + + var ( + r image.Rectangle + over bool + pressed bool + ) + + for e := range env.Events() { + switch e := e.(type) { + case gui.Resize: + r = e.Rectangle + log.Print("button ", e) + env.Draw() <- redraw(r, over, pressed) + + case win.MoDown: + newPressed := e.Point.In(r) + if newPressed != pressed { + pressed = newPressed + env.Draw() <- redraw(r, over, pressed) + } + + case win.MoUp: + if pressed { + if e.Point.In(r) { + action() + } + pressed = false + env.Draw() <- redraw(r, over, pressed) + } + } + } + + close(env.Draw()) +} diff --git a/examples/layout/main.go b/examples/layout/main.go new file mode 100644 index 0000000..47364a9 --- /dev/null +++ b/examples/layout/main.go @@ -0,0 +1,128 @@ +package main + +import ( + "image" + "image/draw" + "log" + "time" + + "github.com/faiface/gui" + "github.com/faiface/gui/fixedgrid" + "github.com/faiface/gui/win" + "github.com/faiface/mainthread" + "golang.org/x/image/colornames" + "golang.org/x/image/font/gofont/goregular" +) + +func Blinker(env gui.Env, closed bool) { + defer func() { + if recover() != nil { + log.Print("recovered blinker") + } + }() + + var r image.Rectangle + var visible bool = true + // redraw takes a bool and produces a draw command + redraw := func() func(draw.Image) image.Rectangle { + return func(drw draw.Image) image.Rectangle { + if visible { + draw.Draw(drw, r, image.White, image.ZP, draw.Src) + } else { + draw.Draw(drw, r, &image.Uniform{colornames.Firebrick}, image.ZP, draw.Src) + } + return r + } + } + + // first we draw a white rectangle + env.Draw() <- redraw() + go func() { + for event := range env.Events() { + switch event := event.(type) { + case win.MoDown: + if event.Point.In(r) { + go func() { + for i := 0; i < 3; i++ { + visible = false + env.Draw() <- redraw() + time.Sleep(time.Second / 3) + visible = true + env.Draw() <- redraw() + time.Sleep(time.Second / 3) + } + }() + } + case gui.Resize: + log.Print(event) + r = event.Rectangle + env.Draw() <- redraw() + } + } + }() + + if closed { + time.Sleep(time.Second * 1) + close(env.Draw()) + } +} + +func run() { + face, err := TTFToFace(goregular.TTF, 18) + if err != nil { + panic(err) + } + theme := &Theme{ + Face: face, + Background: colornames.White, + Empty: colornames.Darkgrey, + Text: colornames.Black, + Highlight: colornames.Blueviolet, + ButtonUp: colornames.Lightgrey, + ButtonDown: colornames.Grey, + } + w, err := win.New(win.Title("gui test"), + win.Resizable(), + ) + if err != nil { + panic(err) + } + mux, env := gui.NewMux(w) + gr := fixedgrid.New(mux.MakeEnv(), + fixedgrid.Rows(5), + fixedgrid.Columns(2), + fixedgrid.Gap(10), + ) + log.Print(gr) + go Blinker(gr.GetEnv("0;0"), false) + go Blinker(gr.GetEnv("0;1"), true) + go Blinker(gr.GetEnv("1;1"), false) + go Blinker(gr.GetEnv("0;2"), false) + go Blinker(gr.GetEnv("0;3"), false) + go Blinker(gr.GetEnv("0;4"), false) + sgr := fixedgrid.New(gr.GetEnv("1;0"), + fixedgrid.Columns(3), + fixedgrid.Gap(4), + fixedgrid.Background(colornames.Darkgrey), + ) + go Button(sgr.GetEnv("0;0"), theme, "Hey", func() { + log.Print("hey") + }) + go Button(sgr.GetEnv("1;0"), theme, "Ho", func() { + log.Print("ho") + }) + go Button(sgr.GetEnv("2;0"), theme, "Hu", func() { + log.Print("hu") + }) + // we use the master env now, w is used by the mux + for event := range env.Events() { + switch event.(type) { + case win.WiClose: + close(env.Draw()) + } + } +} + +func main() { + mainthread.Run(run) +} diff --git a/examples/layout/theme.go b/examples/layout/theme.go new file mode 100644 index 0000000..e37c0c0 --- /dev/null +++ b/examples/layout/theme.go @@ -0,0 +1,19 @@ +package main + +import ( + "image/color" + + "golang.org/x/image/font" +) + +type Theme struct { + Face font.Face + + Background color.Color + Empty color.Color + Text color.Color + Highlight color.Color + ButtonUp color.Color + ButtonOver color.Color + ButtonDown color.Color +} diff --git a/examples/layout/utils.go b/examples/layout/utils.go new file mode 100644 index 0000000..e799988 --- /dev/null +++ b/examples/layout/utils.go @@ -0,0 +1,104 @@ +package main + +import ( + "image" + "image/color" + "image/draw" + "sync" + + "github.com/golang/freetype/truetype" + + "golang.org/x/image/font" + "golang.org/x/image/math/fixed" +) + +type concurrentFace struct { + mu sync.Mutex + face font.Face +} + +func (cf *concurrentFace) Close() error { + cf.mu.Lock() + defer cf.mu.Unlock() + return cf.face.Close() +} + +func (cf *concurrentFace) Glyph(dot fixed.Point26_6, r rune) (dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) { + cf.mu.Lock() + defer cf.mu.Unlock() + return cf.face.Glyph(dot, r) +} + +func (cf *concurrentFace) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) { + cf.mu.Lock() + defer cf.mu.Unlock() + return cf.face.GlyphBounds(r) +} + +func (cf *concurrentFace) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) { + cf.mu.Lock() + defer cf.mu.Unlock() + return cf.face.GlyphAdvance(r) +} + +func (cf *concurrentFace) Kern(r0, r1 rune) fixed.Int26_6 { + cf.mu.Lock() + defer cf.mu.Unlock() + return cf.face.Kern(r0, r1) +} + +func (cf *concurrentFace) Metrics() font.Metrics { + cf.mu.Lock() + defer cf.mu.Unlock() + return cf.face.Metrics() +} + +func TTFToFace(ttf []byte, size float64) (font.Face, error) { + font, err := truetype.Parse(ttf) + if err != nil { + return nil, err + } + return &concurrentFace{face: truetype.NewFace(font, &truetype.Options{ + Size: size, + })}, nil +} + +func MakeTextImage(text string, face font.Face, clr color.Color) image.Image { + drawer := &font.Drawer{ + Src: &image.Uniform{clr}, + Face: face, + Dot: fixed.P(0, 0), + } + b26_6, _ := drawer.BoundString(text) + bounds := image.Rect( + b26_6.Min.X.Floor(), + b26_6.Min.Y.Floor(), + b26_6.Max.X.Ceil(), + b26_6.Max.Y.Ceil(), + ) + drawer.Dst = image.NewRGBA(bounds) + drawer.DrawString(text) + return drawer.Dst +} + +func DrawCentered(dst draw.Image, r image.Rectangle, src image.Image, op draw.Op) { + if src == nil { + return + } + bounds := src.Bounds() + center := bounds.Min.Add(bounds.Max).Div(2) + target := r.Min.Add(r.Max).Div(2) + delta := target.Sub(center) + draw.Draw(dst, bounds.Add(delta).Intersect(r), src, bounds.Min, op) +} + +func DrawLeftCentered(dst draw.Image, r image.Rectangle, src image.Image, op draw.Op) { + if src == nil { + return + } + bounds := src.Bounds() + leftCenter := image.Pt(bounds.Min.X, (bounds.Min.Y+bounds.Max.Y)/2) + target := image.Pt(r.Min.X, (r.Min.Y+r.Max.Y)/2) + delta := target.Sub(leftCenter) + draw.Draw(dst, bounds.Add(delta).Intersect(r), src, bounds.Min, op) +} -- cgit v1.2.3 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 --- examples/layout/layout | Bin 0 -> 5570192 bytes examples/layout/main.go | 122 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 94 insertions(+), 28 deletions(-) create mode 100755 examples/layout/layout (limited to 'examples') diff --git a/examples/layout/layout b/examples/layout/layout new file mode 100755 index 0000000..050fbdf Binary files /dev/null and b/examples/layout/layout differ diff --git a/examples/layout/main.go b/examples/layout/main.go index 47364a9..20d82c2 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -7,7 +7,7 @@ import ( "time" "github.com/faiface/gui" - "github.com/faiface/gui/fixedgrid" + "github.com/faiface/gui/layout" "github.com/faiface/gui/win" "github.com/faiface/mainthread" "golang.org/x/image/colornames" @@ -81,39 +81,105 @@ func run() { ButtonUp: colornames.Lightgrey, ButtonDown: colornames.Grey, } - w, err := win.New(win.Title("gui test"), - win.Resizable(), - ) + w, err := win.New(win.Title("gui test")) // win.Resizable(), + if err != nil { panic(err) } mux, env := gui.NewMux(w) - gr := fixedgrid.New(mux.MakeEnv(), - fixedgrid.Rows(5), - fixedgrid.Columns(2), - fixedgrid.Gap(10), + var ( + top gui.Env + left, right gui.Env + bottomLeft, bottom, bottomRight gui.Env + ) + layout.NewGrid( + mux.MakeEnv(), + [][]*gui.Env{ + {&top}, + {&left, &right}, + {&bottomLeft, &bottom, &bottomRight}, + }, + layout.GridGap(10), + layout.GridBackground(colornames.Sandybrown), + layout.GridSplitY(func(els int, width int) []int { + ret := make([]int, els) + total := 0 + for i := 0; i < els; i++ { + if i == els-1 { + ret[i] = width - total + } else { + v := (width - total) / 2 + ret[i] = v + total += v + } + } + return ret + }), + ) + go Blinker(right, false) + go Blinker(left, false) + go Blinker(bottomRight, false) + + var ( + b1, b2, b3, b4, b5, b6 gui.Env ) - log.Print(gr) - go Blinker(gr.GetEnv("0;0"), false) - go Blinker(gr.GetEnv("0;1"), true) - go Blinker(gr.GetEnv("1;1"), false) - go Blinker(gr.GetEnv("0;2"), false) - go Blinker(gr.GetEnv("0;3"), false) - go Blinker(gr.GetEnv("0;4"), false) - sgr := fixedgrid.New(gr.GetEnv("1;0"), - fixedgrid.Columns(3), - fixedgrid.Gap(4), - fixedgrid.Background(colornames.Darkgrey), + layout.NewBox( + top, + []*gui.Env{ + &b1, &b2, &b3, + }, + layout.BoxGap(10), + layout.BoxBackground(colornames.Lightblue), ) - go Button(sgr.GetEnv("0;0"), theme, "Hey", func() { - log.Print("hey") - }) - go Button(sgr.GetEnv("1;0"), theme, "Ho", func() { - log.Print("ho") - }) - go Button(sgr.GetEnv("2;0"), theme, "Hu", func() { - log.Print("hu") - }) + go Blinker(b1, false) + go Blinker(b2, false) + layout.NewBox( + b3, + []*gui.Env{ + &b4, &b5, &b6, + }, + layout.BoxVertical, + layout.BoxBackground(colornames.Pink), + layout.BoxGap(4), + layout.BoxSplit(func(els int, width int) []int { + ret := make([]int, els) + total := 0 + for i := 0; i < els; i++ { + if i == els-1 { + ret[i] = width - total + } else { + v := (width - total) / 2 + ret[i] = v + total += v + } + } + return ret + }), + ) + go Blinker(b4, false) + go Blinker(b5, false) + go Blinker(b6, false) + + var ( + btn1, btn2, btn3 gui.Env + ) + layout.NewGrid( + bottom, + [][]*gui.Env{ + {&btn1, &btn2, &btn3}, + }, + layout.GridGap(4), + layout.GridBackground(colornames.Darkgrey), + ) + btn := func(env gui.Env, name string) { + Button(env, theme, name, func() { + log.Print(name) + }) + } + go btn(btn1, "Hey") + go btn(btn2, "Ho") + go btn(btn3, "Hu") + // we use the master env now, w is used by the mux for event := range env.Events() { switch event.(type) { -- 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 --- examples/layout/layout | Bin 5570192 -> 0 bytes examples/layout/main.go | 27 +++++++++++---------------- 2 files changed, 11 insertions(+), 16 deletions(-) delete mode 100755 examples/layout/layout (limited to 'examples') diff --git a/examples/layout/layout b/examples/layout/layout deleted file mode 100755 index 050fbdf..0000000 Binary files a/examples/layout/layout and /dev/null differ diff --git a/examples/layout/main.go b/examples/layout/main.go index 20d82c2..f7023a2 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -14,7 +14,7 @@ import ( "golang.org/x/image/font/gofont/goregular" ) -func Blinker(env gui.Env, closed bool) { +func Blinker(env gui.Env) { defer func() { if recover() != nil { log.Print("recovered blinker") @@ -23,7 +23,7 @@ func Blinker(env gui.Env, closed bool) { var r image.Rectangle var visible bool = true - // redraw takes a bool and produces a draw command + redraw := func() func(draw.Image) image.Rectangle { return func(drw draw.Image) image.Rectangle { if visible { @@ -37,7 +37,7 @@ func Blinker(env gui.Env, closed bool) { // first we draw a white rectangle env.Draw() <- redraw() - go func() { + func() { for event := range env.Events() { switch event := event.(type) { case win.MoDown: @@ -60,11 +60,6 @@ func Blinker(env gui.Env, closed bool) { } } }() - - if closed { - time.Sleep(time.Second * 1) - close(env.Draw()) - } } func run() { @@ -116,9 +111,9 @@ func run() { return ret }), ) - go Blinker(right, false) - go Blinker(left, false) - go Blinker(bottomRight, false) + go Blinker(right) + go Blinker(left) + go Blinker(bottomRight) var ( b1, b2, b3, b4, b5, b6 gui.Env @@ -131,8 +126,8 @@ func run() { layout.BoxGap(10), layout.BoxBackground(colornames.Lightblue), ) - go Blinker(b1, false) - go Blinker(b2, false) + go Blinker(b1) + go Blinker(b2) layout.NewBox( b3, []*gui.Env{ @@ -156,9 +151,9 @@ func run() { return ret }), ) - go Blinker(b4, false) - go Blinker(b5, false) - go Blinker(b6, false) + go Blinker(b4) + go Blinker(b5) + go Blinker(b6) var ( btn1, btn2, btn3 gui.Env -- cgit v1.2.3 From 24286694a5ba80cc3f54a224b62ac11c773b4985 Mon Sep 17 00:00:00 2001 From: Clement Benard Date: Tue, 9 Jul 2019 17:30:30 +0200 Subject: Documenting, bug fixing and refactoring to be more in line with the project. --- examples/layout/main.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/layout/main.go b/examples/layout/main.go index f7023a2..7e40ea4 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -128,7 +128,7 @@ func run() { ) go Blinker(b1) go Blinker(b2) - layout.NewBox( + box := layout.NewBox( b3, []*gui.Env{ &b4, &b5, &b6, @@ -151,6 +151,13 @@ func run() { return ret }), ) + log.Print(box) + // go func() { + // for v := range box.Events() { + // log.Print("box: ", v) + // } + // }() + go Blinker(b4) go Blinker(b5) go Blinker(b6) -- 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 --- examples/layout/layout | Bin 0 -> 5571064 bytes examples/layout/main.go | 146 +++++++++++++++--------------------------------- 2 files changed, 46 insertions(+), 100 deletions(-) create mode 100755 examples/layout/layout (limited to 'examples') diff --git a/examples/layout/layout b/examples/layout/layout new file mode 100755 index 0000000..08d9e00 Binary files /dev/null and b/examples/layout/layout differ diff --git a/examples/layout/main.go b/examples/layout/main.go index 7e40ea4..3a2b7be 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -1,10 +1,7 @@ package main import ( - "image" - "image/draw" "log" - "time" "github.com/faiface/gui" "github.com/faiface/gui/layout" @@ -14,54 +11,6 @@ import ( "golang.org/x/image/font/gofont/goregular" ) -func Blinker(env gui.Env) { - defer func() { - if recover() != nil { - log.Print("recovered blinker") - } - }() - - var r image.Rectangle - var visible bool = true - - redraw := func() func(draw.Image) image.Rectangle { - return func(drw draw.Image) image.Rectangle { - if visible { - draw.Draw(drw, r, image.White, image.ZP, draw.Src) - } else { - draw.Draw(drw, r, &image.Uniform{colornames.Firebrick}, image.ZP, draw.Src) - } - return r - } - } - - // first we draw a white rectangle - env.Draw() <- redraw() - func() { - for event := range env.Events() { - switch event := event.(type) { - case win.MoDown: - if event.Point.In(r) { - go func() { - for i := 0; i < 3; i++ { - visible = false - env.Draw() <- redraw() - time.Sleep(time.Second / 3) - visible = true - env.Draw() <- redraw() - time.Sleep(time.Second / 3) - } - }() - } - case gui.Resize: - log.Print(event) - r = event.Rectangle - env.Draw() <- redraw() - } - } - }() -} - func run() { face, err := TTFToFace(goregular.TTF, 18) if err != nil { @@ -77,39 +26,41 @@ func run() { ButtonDown: colornames.Grey, } w, err := win.New(win.Title("gui test")) // win.Resizable(), - if err != nil { panic(err) } + mux, env := gui.NewMux(w) var ( top gui.Env left, right gui.Env bottomLeft, bottom, bottomRight gui.Env ) - layout.NewGrid( + layout.NewMux( mux.MakeEnv(), - [][]*gui.Env{ - {&top}, - {&left, &right}, - {&bottomLeft, &bottom, &bottomRight}, - }, - layout.GridGap(10), - layout.GridBackground(colornames.Sandybrown), - layout.GridSplitY(func(els int, width int) []int { - ret := make([]int, els) - total := 0 - for i := 0; i < els; i++ { - if i == els-1 { - ret[i] = width - total - } else { - v := (width - total) / 2 - ret[i] = v - total += v + layout.NewGrid( + [][]*gui.Env{ + {&top}, + {&left, &right}, + {&bottomLeft, &bottom, &bottomRight}, + }, + layout.GridGap(10), + layout.GridBackground(colornames.Sandybrown), + layout.GridSplitY(func(els int, width int) []int { + ret := make([]int, els) + total := 0 + for i := 0; i < els; i++ { + if i == els-1 { + ret[i] = width - total + } else { + v := (width - total) / 2 + ret[i] = v + total += v + } } - } - return ret - }), + return ret + }), + ), ) go Blinker(right) go Blinker(left) @@ -118,18 +69,18 @@ func run() { var ( b1, b2, b3, b4, b5, b6 gui.Env ) - layout.NewBox( - top, - []*gui.Env{ - &b1, &b2, &b3, - }, - layout.BoxGap(10), - layout.BoxBackground(colornames.Lightblue), + layout.NewMux(top, + layout.NewBox( + []*gui.Env{ + &b1, &b2, &b3, + }, + layout.BoxGap(10), + layout.BoxBackground(colornames.Lightblue), + ), ) go Blinker(b1) go Blinker(b2) box := layout.NewBox( - b3, []*gui.Env{ &b4, &b5, &b6, }, @@ -139,24 +90,17 @@ func run() { layout.BoxSplit(func(els int, width int) []int { ret := make([]int, els) total := 0 - for i := 0; i < els; i++ { - if i == els-1 { - ret[i] = width - total - } else { - v := (width - total) / 2 - ret[i] = v - total += v - } + for i := 0; i < els-1; i++ { + v := (width - total) / 2 + ret[i] = v + total += v } + ret[els-1] = width - total return ret }), ) + layout.NewMux(b3, box) log.Print(box) - // go func() { - // for v := range box.Events() { - // log.Print("box: ", v) - // } - // }() go Blinker(b4) go Blinker(b5) @@ -165,13 +109,15 @@ func run() { var ( btn1, btn2, btn3 gui.Env ) - layout.NewGrid( + layout.NewMux( bottom, - [][]*gui.Env{ - {&btn1, &btn2, &btn3}, - }, - layout.GridGap(4), - layout.GridBackground(colornames.Darkgrey), + layout.NewGrid( + [][]*gui.Env{ + {&btn1, &btn2, &btn3}, + }, + layout.GridGap(4), + layout.GridBackground(colornames.Darkgrey), + ), ) btn := func(env gui.Env, name string) { Button(env, theme, name, func() { -- cgit v1.2.3 From 1b03644d1e0e1be27cdd22732f893d03c0e8421d Mon Sep 17 00:00:00 2001 From: Clement Benard Date: Fri, 12 Jul 2019 17:32:57 +0200 Subject: Somehow added the wrong file, fix that --- examples/layout/blinker.go | 60 +++++++++++++++++++++++++++++++++++++++++++++ examples/layout/layout | Bin 5571064 -> 0 bytes 2 files changed, 60 insertions(+) create mode 100644 examples/layout/blinker.go delete mode 100755 examples/layout/layout (limited to 'examples') diff --git a/examples/layout/blinker.go b/examples/layout/blinker.go new file mode 100644 index 0000000..76dbd95 --- /dev/null +++ b/examples/layout/blinker.go @@ -0,0 +1,60 @@ +package main + +import ( + "image" + "image/draw" + "log" + "time" + + "github.com/faiface/gui" + "github.com/faiface/gui/win" + "golang.org/x/image/colornames" +) + +func Blinker(env gui.Env) { + defer func() { + if recover() != nil { + log.Print("recovered blinker") + } + }() + + var r image.Rectangle + var visible bool = true + + redraw := func() func(draw.Image) image.Rectangle { + return func(drw draw.Image) image.Rectangle { + if visible { + draw.Draw(drw, r, image.White, image.ZP, draw.Src) + } else { + draw.Draw(drw, r, &image.Uniform{colornames.Firebrick}, image.ZP, draw.Src) + } + return r + } + } + + // first we draw a white rectangle + env.Draw() <- redraw() + func() { + for event := range env.Events() { + switch event := event.(type) { + case win.MoDown: + if event.Point.In(r) { + go func() { + for i := 0; i < 3; i++ { + visible = false + env.Draw() <- redraw() + time.Sleep(time.Second / 3) + visible = true + env.Draw() <- redraw() + time.Sleep(time.Second / 3) + } + }() + } + case gui.Resize: + log.Print(event) + r = event.Rectangle + env.Draw() <- redraw() + } + } + }() +} diff --git a/examples/layout/layout b/examples/layout/layout deleted file mode 100755 index 08d9e00..0000000 Binary files a/examples/layout/layout and /dev/null differ -- 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 --- examples/layout/blinker.go | 1 - examples/layout/button.go | 2 -- examples/layout/main.go | 90 +++++++++++++++++++++++++++------------------- 3 files changed, 54 insertions(+), 39 deletions(-) (limited to 'examples') diff --git a/examples/layout/blinker.go b/examples/layout/blinker.go index 76dbd95..b096a73 100644 --- a/examples/layout/blinker.go +++ b/examples/layout/blinker.go @@ -51,7 +51,6 @@ func Blinker(env gui.Env) { }() } case gui.Resize: - log.Print(event) r = event.Rectangle env.Draw() <- redraw() } diff --git a/examples/layout/button.go b/examples/layout/button.go index 6c907e3..0693e06 100644 --- a/examples/layout/button.go +++ b/examples/layout/button.go @@ -4,7 +4,6 @@ import ( "image" "image/color" "image/draw" - "log" "github.com/faiface/gui" "github.com/faiface/gui/win" @@ -39,7 +38,6 @@ func Button(env gui.Env, theme *Theme, text string, action func()) { switch e := e.(type) { case gui.Resize: r = e.Rectangle - log.Print("button ", e) env.Draw() <- redraw(r, over, pressed) case win.MoDown: diff --git a/examples/layout/main.go b/examples/layout/main.go index 3a2b7be..c0055ee 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -1,7 +1,10 @@ package main import ( + "image" + "image/draw" "log" + "time" "github.com/faiface/gui" "github.com/faiface/gui/layout" @@ -31,6 +34,20 @@ func run() { } mux, env := gui.NewMux(w) + + go func() { + // Hack for non-reparenting window managers (I think) + e := mux.MakeEnv() + for { + time.Sleep(time.Second / 5) + e.Draw() <- func(drw draw.Image) image.Rectangle { + r := image.Rect(0, 0, 10, 10) + draw.Draw(drw, r, image.Transparent, image.ZP, draw.Over) + return r + } + } + }() + var ( top gui.Env left, right gui.Env @@ -38,15 +55,15 @@ func run() { ) layout.NewMux( mux.MakeEnv(), - layout.NewGrid( - [][]*gui.Env{ - {&top}, - {&left, &right}, - {&bottomLeft, &bottom, &bottomRight}, - }, - layout.GridGap(10), - layout.GridBackground(colornames.Sandybrown), - layout.GridSplitY(func(els int, width int) []int { + []*gui.Env{ + &top, + &left, &right, + &bottomLeft, &bottom, &bottomRight}, + layout.Grid{ + Rows: []int{1, 2, 3}, + Gap: 10, + Background: colornames.Sandybrown, + SplitY: func(els int, width int) []int { ret := make([]int, els) total := 0 for i := 0; i < els; i++ { @@ -59,8 +76,8 @@ func run() { } } return ret - }), - ), + }, + }, ) go Blinker(right) go Blinker(left) @@ -70,24 +87,21 @@ func run() { b1, b2, b3, b4, b5, b6 gui.Env ) layout.NewMux(top, - layout.NewBox( - []*gui.Env{ - &b1, &b2, &b3, - }, - layout.BoxGap(10), - layout.BoxBackground(colornames.Lightblue), - ), + []*gui.Env{&b1, &b2, &b3}, + layout.Box{ + Length: 3, + Gap: 10, + Background: colornames.Lightblue, + }, ) go Blinker(b1) go Blinker(b2) - box := layout.NewBox( - []*gui.Env{ - &b4, &b5, &b6, - }, - layout.BoxVertical, - layout.BoxBackground(colornames.Pink), - layout.BoxGap(4), - layout.BoxSplit(func(els int, width int) []int { + box := layout.Box{ + Length: 4, + Vertical: true, + Gap: 4, + Background: colornames.Pink, + Split: func(els int, width int) []int { ret := make([]int, els) total := 0 for i := 0; i < els-1; i++ { @@ -97,10 +111,15 @@ func run() { } ret[els-1] = width - total return ret - }), + }, + } + + layout.NewMux(b3, + []*gui.Env{ + &b4, &b5, &b6, + }, + box, ) - layout.NewMux(b3, box) - log.Print(box) go Blinker(b4) go Blinker(b5) @@ -111,13 +130,12 @@ func run() { ) layout.NewMux( bottom, - layout.NewGrid( - [][]*gui.Env{ - {&btn1, &btn2, &btn3}, - }, - layout.GridGap(4), - layout.GridBackground(colornames.Darkgrey), - ), + []*gui.Env{&btn1, &btn2, &btn3}, + layout.Grid{ + Rows: []int{2, 1}, + Background: colornames.Darkgrey, + Gap: 4, + }, ) btn := func(env gui.Env, name string) { Button(env, theme, name, func() { -- cgit v1.2.3 From 8b70878ccc7fe324f3647e56503a37f3780f9d41 Mon Sep 17 00:00:00 2001 From: Clement Benard Date: Mon, 15 Jul 2019 16:19:19 +0200 Subject: now working --- examples/layout/blinker.go | 7 ++----- examples/layout/layout | Bin 0 -> 5564792 bytes examples/layout/main.go | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) create mode 100755 examples/layout/layout (limited to 'examples') diff --git a/examples/layout/blinker.go b/examples/layout/blinker.go index b096a73..8c380c3 100644 --- a/examples/layout/blinker.go +++ b/examples/layout/blinker.go @@ -40,11 +40,8 @@ func Blinker(env gui.Env) { case win.MoDown: if event.Point.In(r) { go func() { - for i := 0; i < 3; i++ { - visible = false - env.Draw() <- redraw() - time.Sleep(time.Second / 3) - visible = true + for i := 0; i < 6; i++ { + visible = !visible env.Draw() <- redraw() time.Sleep(time.Second / 3) } diff --git a/examples/layout/layout b/examples/layout/layout new file mode 100755 index 0000000..0d51021 Binary files /dev/null and b/examples/layout/layout differ diff --git a/examples/layout/main.go b/examples/layout/main.go index c0055ee..c672e63 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -97,7 +97,7 @@ func run() { go Blinker(b1) go Blinker(b2) box := layout.Box{ - Length: 4, + Length: 3, Vertical: true, Gap: 4, Background: colornames.Pink, -- 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 --- examples/layout/blinker.go | 37 +++++++++++----- examples/layout/button.go | 7 +++ examples/layout/card.go | 24 +++++++++++ examples/layout/label.go | 35 +++++++++++++++ examples/layout/layout | Bin 5564792 -> 5614432 bytes examples/layout/main.go | 103 +++++++++++++++++++++++++++------------------ 6 files changed, 155 insertions(+), 51 deletions(-) create mode 100644 examples/layout/card.go create mode 100644 examples/layout/label.go (limited to 'examples') diff --git a/examples/layout/blinker.go b/examples/layout/blinker.go index 8c380c3..65dce43 100644 --- a/examples/layout/blinker.go +++ b/examples/layout/blinker.go @@ -2,13 +2,15 @@ package main import ( "image" + "image/color" "image/draw" "log" + "math/rand" + "sync" "time" "github.com/faiface/gui" "github.com/faiface/gui/win" - "golang.org/x/image/colornames" ) func Blinker(env gui.Env) { @@ -17,23 +19,33 @@ func Blinker(env gui.Env) { log.Print("recovered blinker") } }() - - var r image.Rectangle - var visible bool = true - - redraw := func() func(draw.Image) image.Rectangle { + buf := make([]byte, 3) + rand.Read(buf) + defaultColor := image.NewUniform(color.RGBA{buf[0], buf[1], buf[2], 255}) + rand.Read(buf) + blinkColor := image.NewUniform(color.RGBA{buf[0], buf[1], buf[2], 255}) + redraw := func(r image.Rectangle, visible bool) func(draw.Image) image.Rectangle { return func(drw draw.Image) image.Rectangle { + if r == image.ZR { + return r + } if visible { - draw.Draw(drw, r, image.White, image.ZP, draw.Src) + draw.Draw(drw, r, defaultColor, image.ZP, draw.Src) } else { - draw.Draw(drw, r, &image.Uniform{colornames.Firebrick}, image.ZP, draw.Src) + draw.Draw(drw, r, blinkColor, image.ZP, draw.Src) } return r } } + var mu sync.Mutex + var ( + r image.Rectangle + visible bool = true + ) + // first we draw a white rectangle - env.Draw() <- redraw() + // env.Draw() <- redraw(b) func() { for event := range env.Events() { switch event := event.(type) { @@ -41,15 +53,18 @@ func Blinker(env gui.Env) { if event.Point.In(r) { go func() { for i := 0; i < 6; i++ { + mu.Lock() visible = !visible - env.Draw() <- redraw() + env.Draw() <- redraw(r, visible) + mu.Unlock() + time.Sleep(time.Second / 3) } }() } case gui.Resize: r = event.Rectangle - env.Draw() <- redraw() + env.Draw() <- redraw(r, visible) } } }() diff --git a/examples/layout/button.go b/examples/layout/button.go index 0693e06..cf13c3d 100644 --- a/examples/layout/button.go +++ b/examples/layout/button.go @@ -40,6 +40,13 @@ func Button(env gui.Env, theme *Theme, text string, action func()) { r = e.Rectangle env.Draw() <- redraw(r, over, pressed) + case win.MoMove: + nover := e.Point.In(r) + if nover != over { + over = nover + env.Draw() <- redraw(r, over, pressed) + } + case win.MoDown: newPressed := e.Point.In(r) if newPressed != pressed { diff --git a/examples/layout/card.go b/examples/layout/card.go new file mode 100644 index 0000000..501e4e3 --- /dev/null +++ b/examples/layout/card.go @@ -0,0 +1,24 @@ +package main + +import ( + "github.com/faiface/gui" + "github.com/faiface/gui/layout" + "golang.org/x/image/colornames" +) + +func Card(env gui.Env, theme *Theme, title, content string) { + box := layout.Grid{ + Rows: []int{1, 1}, + // Flip: true, + // Gap: 4, + Background: colornames.Pink, + } + fields := makeEnvPtr(2) + layout.NewMux(env, + fields, + box, + ) + go Label(*fields[0], theme, title, colornames.Lightgray) + go Label(*fields[1], theme, content, colornames.Slategray) + // go Blinker(*fields[1]) +} diff --git a/examples/layout/label.go b/examples/layout/label.go new file mode 100644 index 0000000..f46f25f --- /dev/null +++ b/examples/layout/label.go @@ -0,0 +1,35 @@ +package main + +import ( + "image" + "image/color" + "image/draw" + + "github.com/faiface/gui" +) + +func Label(env gui.Env, theme *Theme, text string, colr color.Color) { + textImg := MakeTextImage(text, theme.Face, theme.Text) + + redraw := func(r image.Rectangle) func(draw.Image) image.Rectangle { + return func(drw draw.Image) image.Rectangle { + draw.Draw(drw, r, &image.Uniform{colr}, image.ZP, draw.Src) + DrawLeftCentered(drw, r.Add(image.Pt(5, 0)), textImg, draw.Over) + return r + } + } + + var ( + r image.Rectangle + ) + + for e := range env.Events() { + switch e := e.(type) { + case gui.Resize: + r = e.Rectangle + env.Draw() <- redraw(r) + } + } + + close(env.Draw()) +} diff --git a/examples/layout/layout b/examples/layout/layout index 0d51021..e7e9c5b 100755 Binary files a/examples/layout/layout and b/examples/layout/layout differ diff --git a/examples/layout/main.go b/examples/layout/main.go index c672e63..83a170d 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -1,9 +1,11 @@ package main import ( + "fmt" "image" "image/draw" "log" + "os" "time" "github.com/faiface/gui" @@ -14,6 +16,14 @@ import ( "golang.org/x/image/font/gofont/goregular" ) +func makeEnvPtr(n int) []*gui.Env { + elsp := make([]*gui.Env, n) + for i := 0; i < len(elsp); i++ { + elsp[i] = new(gui.Env) + } + return elsp +} + func run() { face, err := TTFToFace(goregular.TTF, 18) if err != nil { @@ -26,7 +36,8 @@ func run() { Text: colornames.Black, Highlight: colornames.Blueviolet, ButtonUp: colornames.Lightgrey, - ButtonDown: colornames.Grey, + ButtonOver: colornames.Grey, + ButtonDown: colornames.Dimgrey, } w, err := win.New(win.Title("gui test")) // win.Resizable(), if err != nil { @@ -39,7 +50,7 @@ func run() { // Hack for non-reparenting window managers (I think) e := mux.MakeEnv() for { - time.Sleep(time.Second / 5) + time.Sleep(time.Second / 10) e.Draw() <- func(drw draw.Image) image.Rectangle { r := image.Rect(0, 0, 10, 10) draw.Draw(drw, r, image.Transparent, image.ZP, draw.Over) @@ -60,21 +71,21 @@ func run() { &left, &right, &bottomLeft, &bottom, &bottomRight}, layout.Grid{ - Rows: []int{1, 2, 3}, - Gap: 10, - Background: colornames.Sandybrown, - SplitY: func(els int, width int) []int { + Rows: []int{1, 2, 3}, + Gap: 10, + Margin: -6, + Border: 1, + // Flip: true, + BorderColor: image.White, + Background: colornames.Sandybrown, + SplitRows: func(els int, width int) []int { ret := make([]int, els) total := 0 - for i := 0; i < els; i++ { - if i == els-1 { - ret[i] = width - total - } else { - v := (width - total) / 2 - ret[i] = v - total += v - } + for i := 0; i < els-1; i++ { + ret[i] = (width - total) / 2 + total += ret[i] } + ret[els-1] = width - total return ret }, }, @@ -83,22 +94,36 @@ func run() { go Blinker(left) go Blinker(bottomRight) - var ( - b1, b2, b3, b4, b5, b6 gui.Env - ) + subGrid := makeEnvPtr(3) layout.NewMux(top, - []*gui.Env{&b1, &b2, &b3}, - layout.Box{ - Length: 3, + subGrid, + layout.Grid{ + Rows: []int{len(subGrid)}, Gap: 10, Background: colornames.Lightblue, }, ) - go Blinker(b1) - go Blinker(b2) - box := layout.Box{ - Length: 3, - Vertical: true, + + elsp := makeEnvPtr(100) + scrl := &layout.Scroller{ + Background: colornames.Red, + Length: len(elsp), + Gap: 2, + ChildHeight: 80, + } + layout.NewMux(*subGrid[0], + elsp, + scrl, + ) + for i, el := range elsp { + // go Blinker(*el) + go Card(*el, theme, "hello", fmt.Sprintf("I'm card #%d", i)) + } + + go Blinker(*subGrid[1]) + box := layout.Grid{ + Rows: []int{3}, + Flip: true, Gap: 4, Background: colornames.Pink, Split: func(els int, width int) []int { @@ -113,28 +138,25 @@ func run() { return ret }, } - - layout.NewMux(b3, - []*gui.Env{ - &b4, &b5, &b6, - }, + blinkers := makeEnvPtr(3) + layout.NewMux(*subGrid[2], + blinkers, box, ) - go Blinker(b4) - go Blinker(b5) - go Blinker(b6) + go Blinker(*blinkers[0]) + go Blinker(*blinkers[1]) + go Blinker(*blinkers[2]) - var ( - btn1, btn2, btn3 gui.Env - ) + btns := makeEnvPtr(3) layout.NewMux( bottom, - []*gui.Env{&btn1, &btn2, &btn3}, + btns, layout.Grid{ Rows: []int{2, 1}, Background: colornames.Darkgrey, Gap: 4, + Flip: true, }, ) btn := func(env gui.Env, name string) { @@ -142,15 +164,16 @@ func run() { log.Print(name) }) } - go btn(btn1, "Hey") - go btn(btn2, "Ho") - go btn(btn3, "Hu") + go btn(*btns[0], "Hey") + go btn(*btns[1], "Ho") + go btn(*btns[2], "Hu") // we use the master env now, w is used by the mux for event := range env.Events() { switch event.(type) { case win.WiClose: close(env.Draw()) + os.Exit(0) } } } -- cgit v1.2.3