Files
gio-patched/widget/material/slider.go
T
pierre 85c0a7d803 widget/material: added support for Vertical axis to Slider
Adding an axis to the Float widget, allows positioning the Slider one not only horizontally but also vertically.
Also update the fill ops while there.

Signed-off-by: pierre <pierre.curto@gmail.com>
2021-01-14 17:42:58 +01:00

113 lines
2.7 KiB
Go

// SPDX-License-Identifier: Unlicense OR MIT
package material
import (
"image"
"image/color"
"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.
st = op.Save(gtx.Ops)
pt := axis.Convert(image.Pt(thumbPos, sizeCross/2))
rpt := image.Pt(thumbRadius, thumbRadius)
thumb := image.Rectangle{
Min: pt.Sub(rpt),
Max: pt.Add(rpt),
}
clip.UniformRRect(layout.FRect(thumb), float32(thumbRadius)).Add(gtx.Ops)
paint.Fill(gtx.Ops, color)
st.Load()
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
}