package main import ( "image" "image/color" "gioui.org/f32" "gioui.org/gesture" "gioui.org/io/pointer" "gioui.org/layout" "gioui.org/op" "gioui.org/op/paint" "gioui.org/text" "gioui.org/unit" ) var ( black = color.RGBA{A: 0xff, R: 0, G: 0, B: 0} white = color.RGBA{A: 0xff, R: 0xff, G: 0xff, B: 0xff} gray = color.RGBA{A: 0xff, R: 0xf0, G: 0xf0, B: 0xf0} darkgray = color.RGBA{A: 0xff, R: 0xa0, G: 0xa0, B: 0xa0} ) type Overlay struct { Size unit.Value Text string Click gesture.Click Color color.RGBA Background color.RGBA Alignment text.Alignment } func (b *Overlay) Layout(gtx *layout.Context, family text.Family) { ins := layout.UniformInset(unit.Dp(1)) ins.Layout(gtx, func() { st := layout.Stack{} c2 := st.Rigid(gtx, func() { l := text.Label{ Size: b.Size, Text: b.Text, Alignment: b.Alignment, } ins := layout.UniformInset(unit.Dp(4)) l.Material.Record(gtx.Ops) paint.ColorOp{Color: b.Color}.Add(gtx.Ops) l.Material.Stop() ins.Layout(gtx, func() { l.Layout(gtx, family) }) pointer.RectAreaOp{image.Rect(0, 0, gtx.Dimensions.Size.X, gtx.Dimensions.Size.Y)}.Add(gtx.Ops) }) c1 := st.Expand(gtx, func() { layoutRRect(b.Background, gtx) }) st.Layout(gtx, c1, c2) }) } type SelButton struct { Button SelColor color.RGBA Selected bool } type Button struct { Size unit.Value Label string Click gesture.Click Color color.RGBA Background color.RGBA Alignment text.Alignment clicked bool } func layoutRRect(col color.RGBA, gtx *layout.Context) { r := float32(gtx.Config.Px(unit.Dp(4))) sz := image.Point{X: gtx.Constraints.Width.Min, Y: gtx.Constraints.Height.Min} w, h := float32(sz.X), float32(sz.Y) rrect(gtx.Ops, w, h, r, r, r, r) paint.ColorOp{Color: col}.Add(gtx.Ops) paint.PaintOp{Rect: f32.Rectangle{Max: f32.Point{X: w, Y: h}}}.Add(gtx.Ops) gtx.Dimensions = layout.Dimensions{Size: sz} } // https://pomax.github.io/bezierinfo/#circles_cubic. func rrect(ops *op.Ops, width, height, se, sw, nw, ne float32) { w, h := float32(width), float32(height) const c = 0.55228475 // 4*(sqrt(2)-1)/3 var b paint.Path b.Begin(ops) b.Move(f32.Point{X: w, Y: h - se}) b.Cube(f32.Point{X: 0, Y: se * c}, f32.Point{X: -se + se*c, Y: se}, f32.Point{X: -se, Y: se}) // SE b.Line(f32.Point{X: sw - w + se, Y: 0}) b.Cube(f32.Point{X: -sw * c, Y: 0}, f32.Point{X: -sw, Y: -sw + sw*c}, f32.Point{X: -sw, Y: -sw}) // SW b.Line(f32.Point{X: 0, Y: nw - h + sw}) b.Cube(f32.Point{X: 0, Y: -nw * c}, f32.Point{X: nw - nw*c, Y: -nw}, f32.Point{X: nw, Y: -nw}) // NW b.Line(f32.Point{X: w - ne - nw, Y: 0}) b.Cube(f32.Point{X: ne * c, Y: 0}, f32.Point{X: ne, Y: ne - ne*c}, f32.Point{X: ne, Y: ne}) // NE b.End() } func (b *Button) Layout(gtx *layout.Context, family text.Family) { b.clicked = false for _, ev := range b.Click.Events(gtx) { if ev.Type == gesture.TypeClick { b.clicked = true } } ins := layout.UniformInset(unit.Dp(1)) ins.Layout(gtx, func() { st := layout.Stack{} c2 := st.Rigid(gtx, func() { l := text.Label{ Size: b.Size, Text: b.Label, Alignment: b.Alignment, } ins := layout.UniformInset(unit.Dp(4)) //paint.ColorOp{Color: b.Color}.Add(ops) ins.Layout(gtx, func() { l.Layout(gtx, family) }) pointer.RectAreaOp{image.Rect(0, 0, gtx.Dimensions.Size.X, gtx.Dimensions.Size.Y)}.Add(gtx.Ops) b.Click.Add(gtx.Ops) }) c1 := st.Expand(gtx, func() { layoutRRect(b.Background, gtx) }) st.Layout(gtx, c1, c2) }) } func (b *Button) Clicked() bool { return b.clicked } func (b *SelButton) Clicked() bool { if b.clicked { b.Selected = !b.Selected b.SelColor, b.Background = b.Background, b.SelColor return true } else { return false } }