From ce5646492362c45de276450e6288041cca63b379 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Mon, 8 Jun 2020 23:47:40 +0200 Subject: [PATCH] widget,gesture: fade out cancelled inkwells While here, adjust inkwell sizes to match gtx.Constraints.Min. Signed-off-by: Elias Naur --- gesture/gesture.go | 4 ++++ widget/bool.go | 5 ++++- widget/button.go | 20 +++++++++++++++----- widget/material/button.go | 38 ++++++++++++++++++++++++++++---------- widget/material/switch.go | 4 +++- 5 files changed, 54 insertions(+), 17 deletions(-) diff --git a/gesture/gesture.go b/gesture/gesture.go index 13774419..c6a0599f 100644 --- a/gesture/gesture.go +++ b/gesture/gesture.go @@ -147,6 +147,8 @@ func (c *Click) Events(q event.Queue) []ClickEvent { } c.clickedAt = e.Time events = append(events, ClickEvent{Type: TypeClick, Position: e.Position, Source: e.Source, Modifiers: e.Modifiers, NumClicks: c.clicks}) + } else { + events = append(events, ClickEvent{Type: TypeCancel}) } case pointer.Cancel: wasPressed := c.state == StatePressed @@ -304,6 +306,8 @@ func (ct ClickType) String() string { return "TypePress" case TypeClick: return "TypeClick" + case TypeCancel: + return "TypeCancel" default: panic("invalid ClickType") } diff --git a/widget/bool.go b/widget/bool.go index f2f0cc6d..9b37dda3 100644 --- a/widget/bool.go +++ b/widget/bool.go @@ -2,6 +2,7 @@ package widget import ( "image" + "time" "gioui.org/gesture" "gioui.org/io/pointer" @@ -31,8 +32,10 @@ func (b *Bool) Layout(gtx layout.Context) layout.Dimensions { for _, e := range b.gesture.Events(gtx) { switch e.Type { case gesture.TypeClick: + now := gtx.Now() b.Last = Press{ - Time: gtx.Now(), + Start: now, + End: now.Add(time.Second), Position: e.Position, } b.Value = !b.Value diff --git a/widget/button.go b/widget/button.go index 2d739ea4..08591a4f 100644 --- a/widget/button.go +++ b/widget/button.go @@ -33,8 +33,13 @@ type Click struct { // Press represents a past pointer press. type Press struct { + // Position of the press. Position f32.Point - Time time.Time + // Start is when the press began. + Start time.Time + // End is when the press was ended by a release or cancel. + // A zero End means it hasn't ended yet. + End time.Time } // Clicked reports whether there are pending clicks as would be @@ -73,7 +78,7 @@ func (b *Clickable) Layout(gtx layout.Context) layout.Dimensions { stack.Pop() for len(b.history) > 0 { c := b.history[0] - if gtx.Now().Sub(c.Time) < 1*time.Second { + if c.End.IsZero() || gtx.Now().Sub(c.Start) < 1*time.Second { break } n := copy(b.history, b.history[1:]) @@ -91,17 +96,22 @@ func (b *Clickable) update(gtx layout.Context) { for _, e := range b.click.Events(gtx) { switch e.Type { - case gesture.TypeCancel: - b.history = nil case gesture.TypeClick: b.clicks = append(b.clicks, Click{ Modifiers: e.Modifiers, NumClicks: e.NumClicks, }) + fallthrough + case gesture.TypeCancel: + for i := range b.history { + if b.history[i].End.IsZero() { + b.history[i].End = gtx.Now() + } + } case gesture.TypePress: b.history = append(b.history, Press{ Position: e.Position, - Time: gtx.Now(), + Start: gtx.Now(), }) } } diff --git a/widget/material/button.go b/widget/material/button.go index b1598a85..33daf45c 100644 --- a/widget/material/button.go +++ b/widget/material/button.go @@ -5,6 +5,7 @@ package material import ( "image" "image/color" + "math" "gioui.org/f32" "gioui.org/io/pointer" @@ -190,20 +191,37 @@ func (b IconButtonStyle) Layout(gtx layout.Context) layout.Dimensions { func drawInk(gtx layout.Context, c widget.Press) { now := gtx.Now() - age := now.Sub(c.Time) + age := now.Sub(c.Start) t := float32(age.Seconds()) - const duration = 0.5 - if t > duration { - // Too old. - return - } + const duration = 0.4 t = t / duration + if t > 1.0 { + if c.Start.IsZero() || !c.End.IsZero() { + // Too old. + return + } + t = 1.0 + } defer op.Push(gtx.Ops).Pop() - size := float32(gtx.Px(unit.Dp(700))) * t - rr := size * .5 - col := byte(0xcc * t * t) - ink := paint.ColorOp{Color: color.RGBA{A: col, R: col, G: col, B: col}} + t2 := t + if t2 > 1.0 { + t2 = 2.0 - t2 + } + bezierBlend := t2 * t2 * (3.0 - 2.0*t2) + size := float32(gtx.Constraints.Min.X) + if h := float32(gtx.Constraints.Min.Y); h > size { + size = h + } + // Cover the entire constraints min rectangle. + size *= 2 * float32(math.Sqrt(2)) + // Animate. + size *= bezierBlend + alpha := 0.7 * bezierBlend + const col = 0.8 + ba, bc := byte(alpha*0xff), byte(alpha*col*0xff) + ink := paint.ColorOp{Color: color.RGBA{A: ba, R: bc, G: bc, B: bc}} ink.Add(gtx.Ops) + rr := size * .5 op.TransformOp{}.Offset(c.Position).Offset(f32.Point{ X: -rr, Y: -rr, diff --git a/widget/material/switch.go b/widget/material/switch.go index bc71e6a8..45b38fe4 100644 --- a/widget/material/switch.go +++ b/widget/material/switch.go @@ -91,6 +91,8 @@ func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions { }, NE: rr, NW: rr, SE: rr, SW: rr, }.Op(gtx.Ops).Add(gtx.Ops) + dims := image.Point{X: trackWidth, Y: thumbSize} + gtx.Constraints.Min = dims drawInk(gtx, s.Switch.Last) stack.Pop() @@ -108,7 +110,7 @@ func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions { s.Switch.Layout(gtx) stack.Pop() - return layout.Dimensions{Size: image.Point{X: trackWidth, Y: thumbSize}} + return layout.Dimensions{Size: dims} } func drawDisc(ops *op.Ops, sz float32, col color.RGBA) {