github.com/gop9/olt@v0.0.0-20200202132135-d956aad50b08/gio/widget/material/button.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 package material 4 5 import ( 6 "image" 7 "image/color" 8 9 "github.com/gop9/olt/gio/f32" 10 "github.com/gop9/olt/gio/io/pointer" 11 "github.com/gop9/olt/gio/layout" 12 "github.com/gop9/olt/gio/op" 13 "github.com/gop9/olt/gio/op/clip" 14 "github.com/gop9/olt/gio/op/paint" 15 "github.com/gop9/olt/gio/text" 16 "github.com/gop9/olt/gio/unit" 17 "github.com/gop9/olt/gio/widget" 18 ) 19 20 type Button struct { 21 Text string 22 // Color is the text color. 23 Color color.RGBA 24 Font text.Font 25 Background color.RGBA 26 CornerRadius unit.Value 27 shaper *text.Shaper 28 } 29 30 type IconButton struct { 31 Background color.RGBA 32 Color color.RGBA 33 Icon *Icon 34 Size unit.Value 35 Padding unit.Value 36 } 37 38 func (t *Theme) Button(txt string) Button { 39 return Button{ 40 Text: txt, 41 Color: rgb(0xffffff), 42 Background: t.Color.Primary, 43 Font: text.Font{ 44 Size: t.TextSize.Scale(14.0 / 16.0), 45 }, 46 shaper: t.Shaper, 47 } 48 } 49 50 func (t *Theme) IconButton(icon *Icon) IconButton { 51 return IconButton{ 52 Background: t.Color.Primary, 53 Color: t.Color.InvText, 54 Icon: icon, 55 Size: unit.Dp(56), 56 Padding: unit.Dp(16), 57 } 58 } 59 60 func (b Button) Layout(gtx *layout.Context, button *widget.Button) { 61 col := b.Color 62 bgcol := b.Background 63 hmin := gtx.Constraints.Width.Min 64 vmin := gtx.Constraints.Height.Min 65 layout.Stack{Alignment: layout.Center}.Layout(gtx, 66 layout.Expanded(func() { 67 rr := float32(gtx.Px(unit.Dp(4))) 68 clip.Rect{ 69 Rect: f32.Rectangle{Max: f32.Point{ 70 X: float32(gtx.Constraints.Width.Min), 71 Y: float32(gtx.Constraints.Height.Min), 72 }}, 73 NE: rr, NW: rr, SE: rr, SW: rr, 74 }.Op(gtx.Ops).Add(gtx.Ops) 75 fill(gtx, bgcol) 76 for _, c := range button.History() { 77 drawInk(gtx, c) 78 } 79 }), 80 layout.Stacked(func() { 81 gtx.Constraints.Width.Min = hmin 82 gtx.Constraints.Height.Min = vmin 83 layout.Align(layout.Center).Layout(gtx, func() { 84 layout.Inset{Top: unit.Dp(10), Bottom: unit.Dp(10), Left: unit.Dp(12), Right: unit.Dp(12)}.Layout(gtx, func() { 85 paint.ColorOp{Color: col}.Add(gtx.Ops) 86 widget.Label{}.Layout(gtx, b.shaper, b.Font, b.Text) 87 }) 88 }) 89 pointer.Rect(image.Rectangle{Max: gtx.Dimensions.Size}).Add(gtx.Ops) 90 button.Layout(gtx) 91 }), 92 ) 93 } 94 95 func (b IconButton) Layout(gtx *layout.Context, button *widget.Button) { 96 layout.Stack{}.Layout(gtx, 97 layout.Expanded(func() { 98 size := float32(gtx.Constraints.Width.Min) 99 rr := float32(size) * .5 100 clip.Rect{ 101 Rect: f32.Rectangle{Max: f32.Point{X: size, Y: size}}, 102 NE: rr, NW: rr, SE: rr, SW: rr, 103 }.Op(gtx.Ops).Add(gtx.Ops) 104 fill(gtx, b.Background) 105 for _, c := range button.History() { 106 drawInk(gtx, c) 107 } 108 }), 109 layout.Stacked(func() { 110 layout.UniformInset(b.Padding).Layout(gtx, func() { 111 size := gtx.Px(b.Size) - 2*gtx.Px(b.Padding) 112 if b.Icon != nil { 113 b.Icon.Color = b.Color 114 b.Icon.Layout(gtx, unit.Px(float32(size))) 115 } 116 gtx.Dimensions = layout.Dimensions{ 117 Size: image.Point{X: size, Y: size}, 118 } 119 }) 120 pointer.Ellipse(image.Rectangle{Max: gtx.Dimensions.Size}).Add(gtx.Ops) 121 button.Layout(gtx) 122 }), 123 ) 124 } 125 126 func toPointF(p image.Point) f32.Point { 127 return f32.Point{X: float32(p.X), Y: float32(p.Y)} 128 } 129 130 func toRectF(r image.Rectangle) f32.Rectangle { 131 return f32.Rectangle{ 132 Min: toPointF(r.Min), 133 Max: toPointF(r.Max), 134 } 135 } 136 137 func drawInk(gtx *layout.Context, c widget.Click) { 138 d := gtx.Now().Sub(c.Time) 139 t := float32(d.Seconds()) 140 const duration = 0.5 141 if t > duration { 142 return 143 } 144 t = t / duration 145 var stack op.StackOp 146 stack.Push(gtx.Ops) 147 size := float32(gtx.Px(unit.Dp(700))) * t 148 rr := size * .5 149 col := byte(0xaa * (1 - t*t)) 150 ink := paint.ColorOp{Color: color.RGBA{A: col, R: col, G: col, B: col}} 151 ink.Add(gtx.Ops) 152 op.TransformOp{}.Offset(c.Position).Offset(f32.Point{ 153 X: -rr, 154 Y: -rr, 155 }).Add(gtx.Ops) 156 clip.Rect{ 157 Rect: f32.Rectangle{Max: f32.Point{ 158 X: float32(size), 159 Y: float32(size), 160 }}, 161 NE: rr, NW: rr, SE: rr, SW: rr, 162 }.Op(gtx.Ops).Add(gtx.Ops) 163 paint.PaintOp{Rect: f32.Rectangle{Max: f32.Point{X: float32(size), Y: float32(size)}}}.Add(gtx.Ops) 164 stack.Pop() 165 op.InvalidateOp{}.Add(gtx.Ops) 166 }