~eliasnaur/gio

ref: 82fff0178bed gio/widget/material/slider.go -rw-r--r-- 2.7 KiB
82fff017Elias Naur gpu: [compute] generalize sizedBuffer to cover vertex buffers a month 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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// SPDX-License-Identifier: Unlicense OR MIT

package material

import (
	"image"
	"image/color"

	"gioui.org/f32"
	"gioui.org/internal/f32color"
	"gioui.org/layout"
	"gioui.org/op"
	"gioui.org/op/clip"
	"gioui.org/op/paint"
	"gioui.org/unit"
	"gioui.org/widget"
)

// Slider is for selecting a value in a range.
func Slider(th *Theme, float *widget.Float, min, max float32) SliderStyle {
	return SliderStyle{
		Min:        min,
		Max:        max,
		Color:      th.Palette.ContrastBg,
		Float:      float,
		FingerSize: th.FingerSize,
	}
}

type SliderStyle struct {
	Min, Max float32
	Color    color.NRGBA
	Float    *widget.Float

	FingerSize unit.Value
}

func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions {
	thumbRadius := gtx.Px(unit.Dp(6))
	trackWidth := gtx.Px(unit.Dp(2))

	axis := s.Float.Axis
	// Keep a minimum length so that the track is always visible.
	minLength := thumbRadius + 3*thumbRadius + thumbRadius
	// Try to expand to finger size, but only if the constraints
	// allow for it.
	touchSizePx := min(gtx.Px(s.FingerSize), axis.Convert(gtx.Constraints.Max).Y)
	sizeMain := max(axis.Convert(gtx.Constraints.Min).X, minLength)
	sizeCross := max(2*thumbRadius, touchSizePx)
	size := axis.Convert(image.Pt(sizeMain, sizeCross))

	st := op.Save(gtx.Ops)
	o := axis.Convert(image.Pt(thumbRadius, 0))
	op.Offset(layout.FPt(o)).Add(gtx.Ops)
	gtx.Constraints.Min = axis.Convert(image.Pt(sizeMain-2*thumbRadius, sizeCross))
	s.Float.Layout(gtx, thumbRadius, s.Min, s.Max)
	gtx.Constraints.Min = gtx.Constraints.Min.Add(axis.Convert(image.Pt(0, sizeCross)))
	thumbPos := thumbRadius + int(s.Float.Pos())
	st.Load()

	color := s.Color
	if gtx.Queue == nil {
		color = f32color.Disabled(color)
	}

	// Draw track before thumb.
	st = op.Save(gtx.Ops)
	track := image.Rectangle{
		Min: axis.Convert(image.Pt(thumbRadius, sizeCross/2-trackWidth/2)),
		Max: axis.Convert(image.Pt(thumbPos, sizeCross/2+trackWidth/2)),
	}
	clip.Rect(track).Add(gtx.Ops)
	paint.Fill(gtx.Ops, color)
	st.Load()

	// Draw track after thumb.
	st = op.Save(gtx.Ops)
	track = image.Rectangle{
		Min: axis.Convert(image.Pt(thumbPos, axis.Convert(track.Min).Y)),
		Max: axis.Convert(image.Pt(sizeMain-thumbRadius, axis.Convert(track.Max).Y)),
	}
	clip.Rect(track).Add(gtx.Ops)
	paint.Fill(gtx.Ops, f32color.MulAlpha(color, 96))
	st.Load()

	// Draw thumb.
	pt := axis.Convert(image.Pt(thumbPos, sizeCross/2))
	paint.FillShape(gtx.Ops, color,
		clip.Circle{
			Center: f32.Point{X: float32(pt.X), Y: float32(pt.Y)},
			Radius: float32(thumbRadius),
		}.Op(gtx.Ops))

	return layout.Dimensions{Size: size}
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}