109 lines
2.2 KiB
Go
109 lines
2.2 KiB
Go
// SPDX-License-Identifier: Unlicense OR MIT
|
|
|
|
package gel
|
|
|
|
import (
|
|
"image"
|
|
|
|
"github.com/p9c/p9/pkg/gel/gio/gesture"
|
|
"github.com/p9c/p9/pkg/gel/gio/io/pointer"
|
|
l "github.com/p9c/p9/pkg/gel/gio/layout"
|
|
"github.com/p9c/p9/pkg/gel/gio/op/clip"
|
|
)
|
|
|
|
// Float is for selecting a value in a range.
|
|
type Float struct {
|
|
value float32
|
|
drag gesture.Drag
|
|
pos float32 // position normalized to [0, 1]
|
|
length float32
|
|
changed bool
|
|
changeHook func(float32)
|
|
}
|
|
|
|
func (th *Theme) Float() *Float {
|
|
return &Float{changeHook: func(float32) {}}
|
|
}
|
|
|
|
func (f *Float) SetValue(value float32) *Float {
|
|
f.value = value
|
|
return f
|
|
}
|
|
func (f *Float) Value() float32 {
|
|
return f.value
|
|
}
|
|
|
|
func (f *Float) SetHook(fn func(fl float32)) *Float {
|
|
f.changeHook = fn
|
|
return f
|
|
}
|
|
|
|
// Fn processes events.
|
|
func (f *Float) Fn(gtx l.Context, pointerMargin int, min, max float32) l.Dimensions {
|
|
size := gtx.Constraints.Min
|
|
f.length = float32(size.X)
|
|
var de *pointer.Event
|
|
for {
|
|
ev, ok := f.drag.Update(gtx.Metric, gtx.Source, gesture.Horizontal)
|
|
if !ok {
|
|
break
|
|
}
|
|
if ev.Kind == pointer.Press || ev.Kind == pointer.Drag {
|
|
de = &ev
|
|
}
|
|
if ev.Kind == pointer.Release {
|
|
f.changeHook(f.value)
|
|
}
|
|
}
|
|
value := f.value
|
|
if de != nil {
|
|
f.pos = de.Position.X / f.length
|
|
value = min + (max-min)*f.pos
|
|
} else if min != max {
|
|
f.pos = value/(max-min) - min
|
|
}
|
|
// Unconditionally call setValue in case min, max, or value changed.
|
|
f.setValue(value, min, max)
|
|
|
|
if f.pos < 0 {
|
|
f.pos = 0
|
|
} else if f.pos > 1 {
|
|
f.pos = 1
|
|
}
|
|
|
|
rect := image.Rectangle{Max: size}
|
|
rect.Min.X -= pointerMargin
|
|
rect.Max.X += pointerMargin
|
|
defer clip.Rect(rect).Push(gtx.Ops).Pop()
|
|
f.drag.Add(gtx.Ops)
|
|
|
|
return l.Dimensions{Size: size}
|
|
}
|
|
|
|
func (f *Float) setValue(value, min, max float32) {
|
|
if min > max {
|
|
min, max = max, min
|
|
}
|
|
if value < min {
|
|
value = min
|
|
} else if value > max {
|
|
value = max
|
|
}
|
|
if f.value != value {
|
|
f.value = value
|
|
f.changed = true
|
|
}
|
|
}
|
|
|
|
// Pos reports the selected position.
|
|
func (f *Float) Pos() float32 {
|
|
return f.pos * f.length
|
|
}
|
|
|
|
// Changed reports whether the value has changed since the last call to Changed.
|
|
func (f *Float) Changed() bool {
|
|
changed := f.changed
|
|
f.changed = false
|
|
return changed
|
|
}
|