gioui.org@v0.6.1-0.20240506124620-7a9ce51988ce/widget/material/slider.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 package material 4 5 import ( 6 "image" 7 "image/color" 8 9 "gioui.org/internal/f32color" 10 "gioui.org/layout" 11 "gioui.org/op" 12 "gioui.org/op/clip" 13 "gioui.org/op/paint" 14 "gioui.org/unit" 15 "gioui.org/widget" 16 ) 17 18 // Slider is for selecting a value in a range. 19 func Slider(th *Theme, float *widget.Float) SliderStyle { 20 return SliderStyle{ 21 Color: th.Palette.ContrastBg, 22 Float: float, 23 FingerSize: th.FingerSize, 24 } 25 } 26 27 type SliderStyle struct { 28 Axis layout.Axis 29 Color color.NRGBA 30 Float *widget.Float 31 32 FingerSize unit.Dp 33 } 34 35 func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions { 36 const thumbRadius unit.Dp = 6 37 tr := gtx.Dp(thumbRadius) 38 trackWidth := gtx.Dp(2) 39 40 axis := s.Axis 41 // Keep a minimum length so that the track is always visible. 42 minLength := tr + 3*tr + tr 43 // Try to expand to finger size, but only if the constraints 44 // allow for it. 45 touchSizePx := min(gtx.Dp(s.FingerSize), axis.Convert(gtx.Constraints.Max).Y) 46 sizeMain := max(axis.Convert(gtx.Constraints.Min).X, minLength) 47 sizeCross := max(2*tr, touchSizePx) 48 size := axis.Convert(image.Pt(sizeMain, sizeCross)) 49 50 o := axis.Convert(image.Pt(tr, 0)) 51 trans := op.Offset(o).Push(gtx.Ops) 52 gtx.Constraints.Min = axis.Convert(image.Pt(sizeMain-2*tr, sizeCross)) 53 dims := s.Float.Layout(gtx, axis, thumbRadius) 54 gtx.Constraints.Min = gtx.Constraints.Min.Add(axis.Convert(image.Pt(0, sizeCross))) 55 thumbPos := tr + int(s.Float.Value*float32(axis.Convert(dims.Size).X)) 56 trans.Pop() 57 58 color := s.Color 59 if !gtx.Enabled() { 60 color = f32color.Disabled(color) 61 } 62 63 rect := func(minx, miny, maxx, maxy int) image.Rectangle { 64 r := image.Rect(minx, miny, maxx, maxy) 65 if axis == layout.Vertical { 66 r.Max.X, r.Min.X = sizeMain-r.Min.X, sizeMain-r.Max.X 67 } 68 r.Min = axis.Convert(r.Min) 69 r.Max = axis.Convert(r.Max) 70 return r 71 } 72 73 // Draw track before thumb. 74 track := rect( 75 tr, sizeCross/2-trackWidth/2, 76 thumbPos, sizeCross/2+trackWidth/2, 77 ) 78 paint.FillShape(gtx.Ops, color, clip.Rect(track).Op()) 79 80 // Draw track after thumb. 81 track = rect( 82 thumbPos, axis.Convert(track.Min).Y, 83 sizeMain-tr, axis.Convert(track.Max).Y, 84 ) 85 paint.FillShape(gtx.Ops, f32color.MulAlpha(color, 96), clip.Rect(track).Op()) 86 87 // Draw thumb. 88 pt := image.Pt(thumbPos, sizeCross/2) 89 thumb := rect( 90 pt.X-tr, pt.Y-tr, 91 pt.X+tr, pt.Y+tr, 92 ) 93 paint.FillShape(gtx.Ops, color, clip.Ellipse(thumb).Op(gtx.Ops)) 94 95 return layout.Dimensions{Size: size} 96 } 97 98 func max(a, b int) int { 99 if a > b { 100 return a 101 } 102 return b 103 } 104 105 func min(a, b int) int { 106 if a < b { 107 return a 108 } 109 return b 110 }