~whereswaldon/sprig

ref: v0.0.16 sprig/widget/polyclick.go -rw-r--r-- 2.0 KiB
fbfe7d32Chris Waldon fix: use concrete ds.ReplyData as target of reply methods and focus 5 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package widget

import (
	"image"
	"time"

	"gioui.org/gesture"
	"gioui.org/io/pointer"
	"gioui.org/layout"
	"gioui.org/op"
	"gioui.org/widget"
)

// Polyclick can detect and report a variety of gesture interactions
// within a single pointer input area.
type Polyclick struct {
	Pass bool
	gesture.Click
	clicks                     []widget.Click
	pressed, longPressReported bool
	pressStart                 time.Time
	currentTime                time.Time
}

func (p *Polyclick) update(gtx layout.Context) {
	p.currentTime = gtx.Now
	for _, event := range p.Click.Events(gtx) {
		switch event.Type {
		case gesture.TypeCancel:
			p.processCancel(event, gtx)
		case gesture.TypePress:
			p.processPress(event, gtx)
		case gesture.TypeClick:
			p.processClick(event, gtx)
		default:
			continue
		}
	}
}

func (p *Polyclick) processCancel(event gesture.ClickEvent, gtx layout.Context) {
	p.pressed = false
	p.longPressReported = false
}
func (p *Polyclick) processPress(event gesture.ClickEvent, gtx layout.Context) {
	p.pressed = true
	p.pressStart = gtx.Now
}
func (p *Polyclick) processClick(event gesture.ClickEvent, gtx layout.Context) {
	p.pressed = false
	if !p.longPressReported {
		p.clicks = append(p.clicks, widget.Click{
			Modifiers: event.Modifiers,
			NumClicks: event.NumClicks,
		})
	}
	p.longPressReported = false
}

func (p *Polyclick) Clicks() (out []widget.Click) {
	out, p.clicks = p.clicks, p.clicks[:0]
	return
}

func (p *Polyclick) LongPressed() bool {
	elapsed := p.currentTime.Sub(p.pressStart)
	if !p.longPressReported && p.pressed && elapsed > time.Millisecond*250 {
		p.longPressReported = true
		return true
	}
	return false
}

func (p *Polyclick) Layout(gtx layout.Context) layout.Dimensions {
	p.update(gtx)
	defer op.Save(gtx.Ops).Load()
	pointer.PassOp{Pass: p.Pass}.Add(gtx.Ops)
	pointer.Rect(image.Rectangle{Max: gtx.Constraints.Min}).Add(gtx.Ops)
	p.Click.Add(gtx.Ops)
	if p.pressed {
		op.InvalidateOp{}.Add(gtx.Ops)
	}
	return layout.Dimensions{Size: gtx.Constraints.Min}
}