~eliasnaur/gio

gio/widget/float.go -rw-r--r-- 1.7 KiB View raw
6c30c638Elias Naur app,app/internal: [Android] replace Window.Do with ViewEvent 11 hours 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
85
86
87
88
// SPDX-License-Identifier: Unlicense OR MIT

package widget

import (
	"image"

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

// 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
}

// Layout processes events.
func (f *Float) Layout(gtx layout.Context, pointerMargin int, min, max float32) layout.Dimensions {
	size := gtx.Constraints.Min
	f.length = float32(size.X)

	var de *pointer.Event
	for _, e := range f.drag.Events(gtx.Metric, gtx, gesture.Horizontal) {
		if e.Type == pointer.Press || e.Type == pointer.Drag {
			de = &e
		}
	}

	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
	}

	defer op.Push(gtx.Ops).Pop()
	rect := image.Rectangle{Max: size}
	rect.Min.X -= pointerMargin
	rect.Max.X += pointerMargin
	pointer.Rect(rect).Add(gtx.Ops)
	f.drag.Add(gtx.Ops)

	return layout.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
}