180 lines
2.9 KiB
Go
180 lines
2.9 KiB
Go
package ui
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"fyne.io/fyne/v2"
|
|
)
|
|
|
|
type Debouncer struct {
|
|
mu sync.Mutex
|
|
timer *time.Timer
|
|
duration time.Duration
|
|
callback func()
|
|
}
|
|
|
|
func NewDebouncer(duration time.Duration, callback func()) *Debouncer {
|
|
return &Debouncer{
|
|
duration: duration,
|
|
callback: callback,
|
|
}
|
|
}
|
|
|
|
func (d *Debouncer) Trigger() {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
|
|
if d.timer != nil {
|
|
d.timer.Stop()
|
|
}
|
|
|
|
d.timer = time.AfterFunc(d.duration, func() {
|
|
fyne.Do(d.callback)
|
|
})
|
|
}
|
|
|
|
type Throttler struct {
|
|
mu sync.Mutex
|
|
lastCall time.Time
|
|
interval time.Duration
|
|
callback func()
|
|
}
|
|
|
|
func NewThrottler(interval time.Duration, callback func()) *Throttler {
|
|
return &Throttler{
|
|
interval: interval,
|
|
callback: callback,
|
|
}
|
|
}
|
|
|
|
func (t *Throttler) Trigger() {
|
|
t.mu.Lock()
|
|
defer t.mu.Unlock()
|
|
|
|
now := time.Now()
|
|
if now.Sub(t.lastCall) >= t.interval {
|
|
t.lastCall = now
|
|
fyne.Do(t.callback)
|
|
}
|
|
}
|
|
|
|
type LazyLoader struct {
|
|
mu sync.Mutex
|
|
loaded bool
|
|
loading bool
|
|
callback func()
|
|
}
|
|
|
|
func NewLazyLoader(callback func()) *LazyLoader {
|
|
return &LazyLoader{
|
|
callback: callback,
|
|
}
|
|
}
|
|
|
|
func (l *LazyLoader) Load() {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
if l.loaded || l.loading {
|
|
return
|
|
}
|
|
|
|
l.loading = true
|
|
go func() {
|
|
l.callback()
|
|
l.mu.Lock()
|
|
l.loaded = true
|
|
l.loading = false
|
|
l.mu.Unlock()
|
|
}()
|
|
}
|
|
|
|
type VirtualList struct {
|
|
items []interface{}
|
|
renderer func(item interface{}) fyne.CanvasObject
|
|
visible int
|
|
start int
|
|
end int
|
|
}
|
|
|
|
func NewVirtualList(items []interface{}, renderer func(item interface{}) fyne.CanvasObject, visible int) *VirtualList {
|
|
return &VirtualList{
|
|
items: items,
|
|
renderer: renderer,
|
|
visible: visible,
|
|
end: visible,
|
|
}
|
|
}
|
|
|
|
func (vl *VirtualList) GetVisibleItems() []fyne.CanvasObject {
|
|
if vl.start >= len(vl.items) {
|
|
return []fyne.CanvasObject{}
|
|
}
|
|
|
|
if vl.end > len(vl.items) {
|
|
vl.end = len(vl.items)
|
|
}
|
|
|
|
var result []fyne.CanvasObject
|
|
for i := vl.start; i < vl.end; i++ {
|
|
result = append(result, vl.renderer(vl.items[i]))
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (vl *VirtualList) ScrollTo(index int) {
|
|
if index < 0 {
|
|
index = 0
|
|
}
|
|
if index >= len(vl.items) {
|
|
index = len(vl.items) - 1
|
|
}
|
|
|
|
vl.start = index
|
|
vl.end = index + vl.visible
|
|
if vl.end > len(vl.items) {
|
|
vl.end = len(vl.items)
|
|
vl.start = vl.end - vl.visible
|
|
if vl.start < 0 {
|
|
vl.start = 0
|
|
}
|
|
}
|
|
}
|
|
|
|
type MemoryPool struct {
|
|
mu sync.Mutex
|
|
items []interface{}
|
|
new func() interface{}
|
|
reset func(interface{})
|
|
}
|
|
|
|
func NewMemoryPool(new func() interface{}, reset func(interface{})) *MemoryPool {
|
|
return &MemoryPool{
|
|
new: new,
|
|
reset: reset,
|
|
}
|
|
}
|
|
|
|
func (mp *MemoryPool) Get() interface{} {
|
|
mp.mu.Lock()
|
|
defer mp.mu.Unlock()
|
|
|
|
if len(mp.items) > 0 {
|
|
item := mp.items[len(mp.items)-1]
|
|
mp.items = mp.items[:len(mp.items)-1]
|
|
mp.reset(item)
|
|
return item
|
|
}
|
|
|
|
return mp.new()
|
|
}
|
|
|
|
func (mp *MemoryPool) Put(item interface{}) {
|
|
mp.mu.Lock()
|
|
defer mp.mu.Unlock()
|
|
|
|
mp.items = append(mp.items, item)
|
|
}
|