-
Notifications
You must be signed in to change notification settings - Fork 31
/
callbacks.go
155 lines (133 loc) · 3.55 KB
/
callbacks.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Copyright 2019-2022 Graham Clark. All rights reserved. Use of this source code is governed by the MIT license
// that can be found in the LICENSE file.
package gowid
import (
"sync"
)
//======================================================================
type ClickCB struct{}
type DoubleClickCB struct{}
type KeyPressCB struct{}
type SubWidgetCB struct{}
type SubWidgetsCB struct{}
type DimensionsCB struct{}
type FocusCB struct{}
type VAlignCB struct{}
type HAlignCB struct{}
type HeightCB struct{}
type WidthCB struct{}
// ICallback represents any object that can provide a way to be compared to others,
// and that can be called with an arbitrary number of arguments returning no result.
// The comparison is expected to be used by having the callback object provide a name
// to identify the callback operation e.g. "buttonclicked", so that it can later
// be removed.
type ICallback interface {
IIdentity
Call(args ...interface{})
}
type CallbackFunction func(args ...interface{})
type CallbackID struct {
Name interface{}
}
// Callback is a simple implementation of ICallback.
type Callback struct {
Name interface{}
CallbackFunction
}
func (f CallbackFunction) Call(args ...interface{}) {
f(args...)
}
func (f CallbackID) ID() interface{} {
return f.Name
}
func (f Callback) ID() interface{} {
return f.Name
}
type Callbacks struct {
sync.Mutex
callbacks map[interface{}][]ICallback
}
type ICallbacks interface {
RunCallbacks(name interface{}, args ...interface{})
AddCallback(name interface{}, cb ICallback)
RemoveCallback(name interface{}, cb IIdentity) bool
HaveCallbacks(interface{}) bool
}
func NewCallbacks() *Callbacks {
cb := &Callbacks{}
cb.callbacks = make(map[interface{}][]ICallback)
var _ ICallbacks = cb
return cb
}
func (f *Callbacks) HaveCallbacks(t interface{}) bool {
return f != nil && f.callbacks != nil && len(f.callbacks[t]) > 0
}
// CopyOfCallbacks is used when callbacks are run - they are copied
// so that any callers modifying the callbacks themselves can do so
// safely with the modifications taking effect after all callbacks
// are run. Can be called with a nil receiver if the widget's callback
// object has not been initialized and e.g. RunWidgetCallbacks is called.
func (c *Callbacks) CopyOfCallbacks(name interface{}) ([]ICallback, bool) {
if c != nil {
c.Lock()
defer c.Unlock()
cbs, ok := c.callbacks[name]
if ok {
cbscopy := make([]ICallback, len(cbs))
copy(cbscopy, cbs)
return cbscopy, true
}
}
return []ICallback{}, false
}
func (c *Callbacks) RunCallbacks(name interface{}, args ...interface{}) {
if cbs, ok := c.CopyOfCallbacks(name); ok {
for _, cb := range cbs {
if cb != nil {
cb.Call(args...)
}
}
}
}
func (c *Callbacks) AddCallback(name interface{}, cb ICallback) {
c.Lock()
defer c.Unlock()
cbs := c.callbacks[name]
cbs = append(cbs, cb)
c.callbacks[name] = cbs
}
func (c *Callbacks) RemoveCallback(name interface{}, cb IIdentity) bool {
if c == nil {
return false
}
c.Lock()
defer c.Unlock()
cbs, ok := c.callbacks[name]
if ok {
idxs := make([]int, 0)
ok = false
for i, cb2 := range cbs {
if cb.ID() == cb2.ID() {
// Append backwards for easier deletion later
idxs = append([]int{i}, idxs...)
}
}
if len(idxs) > 0 {
ok = true
for _, j := range idxs {
cbs = append(cbs[:j], cbs[j+1:]...)
}
if len(cbs) == 0 {
delete(c.callbacks, name)
} else {
c.callbacks[name] = cbs
}
}
}
return ok
}
//======================================================================
// Local Variables:
// mode: Go
// fill-column: 110
// End: