-
Notifications
You must be signed in to change notification settings - Fork 17
/
clickfilter.go
119 lines (99 loc) · 2.47 KB
/
clickfilter.go
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package mousefilter
import (
"image"
"time"
"github.com/jmigpin/editor/v2/util/uiutil/event"
)
// produce click/doubleclick/tripleclick events
type ClickFilter struct {
m map[event.MouseButton]*MultipleClick
emitEvFn func(interface{}, image.Point)
}
func NewClickFilter(emitEvFn func(interface{}, image.Point)) *ClickFilter {
return &ClickFilter{
m: map[event.MouseButton]*MultipleClick{},
emitEvFn: emitEvFn,
}
}
func (clickf *ClickFilter) Filter(ev interface{}) {
switch t := ev.(type) {
case *event.MouseDown:
clickf.down(t)
case *event.MouseUp:
clickf.up(t)
case *event.MouseMove:
clickf.move(t)
}
}
func (clickf *ClickFilter) down(ev *event.MouseDown) {
// initialize on demand
mc, ok := clickf.m[ev.Button]
if !ok {
mc = &MultipleClick{}
clickf.m[ev.Button] = mc
}
mc.prevDownPoint = mc.downPoint
mc.downPoint = ev.Point
}
func (clickf *ClickFilter) up(ev *event.MouseUp) {
mc, ok := clickf.m[ev.Button]
if !ok {
return
}
// update time
upTime0 := mc.upTime
mc.upTime = time.Now()
// must be clicked within a margin
if DetectMove(mc.downPoint, ev.Point) {
mc.action = MClickActionSingle // reset action
return
}
// if it takes too much time, it gets back to single click
d := mc.upTime.Sub(upTime0)
if d > 400*time.Millisecond {
mc.action = MClickActionSingle
} else {
if DetectMove(mc.prevDownPoint, ev.Point) {
mc.action = MClickActionSingle // reset action
} else {
// single, double, triple
mc.action = (mc.action + 1) % 3
}
}
// always run a click
ev2 := &event.MouseClick{ev.Point, ev.Button, ev.Buttons, ev.Mods}
clickf.emitEv(ev2, ev.Point)
switch mc.action {
case MClickActionDouble:
ev2 := &event.MouseDoubleClick{ev.Point, ev.Button, ev.Buttons, ev.Mods}
clickf.emitEv(ev2, ev.Point)
case MClickActionTriple:
ev2 := &event.MouseTripleClick{ev.Point, ev.Button, ev.Buttons, ev.Mods}
clickf.emitEv(ev2, ev.Point)
}
}
func (clickf *ClickFilter) move(ev *event.MouseMove) {
for b, mc := range clickf.m {
// clear if moved outside move detection margins
if DetectMove(mc.downPoint, ev.Point) {
delete(clickf.m, b)
}
}
}
//----------
func (clickf *ClickFilter) emitEv(ev interface{}, p image.Point) {
clickf.emitEvFn(ev, p)
}
//----------
type MultipleClick struct {
upTime time.Time
downPoint image.Point
prevDownPoint image.Point
action MClickAction
}
type MClickAction int
const (
MClickActionSingle MClickAction = iota
MClickActionDouble
MClickActionTriple
)