slider.go raw

   1  package gel
   2  
   3  import (
   4  	"image"
   5  	"image/color"
   6  	
   7  	"github.com/p9c/gio/f32"
   8  	l "github.com/p9c/gio/layout"
   9  	"github.com/p9c/gio/op"
  10  	"github.com/p9c/gio/op/clip"
  11  	"github.com/p9c/gio/op/paint"
  12  	"github.com/p9c/gio/unit"
  13  	
  14  	"github.com/p9c/gel/f32color"
  15  )
  16  
  17  type Slider struct {
  18  	*Window
  19  	min, max float32
  20  	color    color.NRGBA
  21  	float    *Float
  22  }
  23  
  24  // Slider is for selecting a value in a range.
  25  func (w *Window) Slider() *Slider {
  26  	return &Slider{
  27  		Window: w,
  28  		color:  w.Colors.GetNRGBAFromName("Primary"),
  29  	}
  30  }
  31  
  32  // Min sets the value at the left hand side
  33  func (s *Slider) Min(min float32) *Slider {
  34  	s.min = min
  35  	return s
  36  }
  37  
  38  // Max sets the value at the right hand side
  39  func (s *Slider) Max(max float32) *Slider {
  40  	s.max = max
  41  	return s
  42  }
  43  
  44  // Color sets the color to draw the slider in
  45  func (s *Slider) Color(color string) *Slider {
  46  	s.color = s.Theme.Colors.GetNRGBAFromName(color)
  47  	return s
  48  }
  49  
  50  // Float sets the initial value
  51  func (s *Slider) Float(f *Float) *Slider {
  52  	s.float = f
  53  	return s
  54  }
  55  
  56  // Fn renders the slider
  57  func (s *Slider) Fn(gtx l.Context) l.Dimensions {
  58  	thumbRadiusInt := gtx.Px(unit.Dp(6))
  59  	trackWidth := float32(gtx.Px(unit.Dp(2)))
  60  	thumbRadius := float32(thumbRadiusInt)
  61  	halfWidthInt := 2 * thumbRadiusInt
  62  	halfWidth := float32(halfWidthInt)
  63  	
  64  	size := gtx.Constraints.Min
  65  	// Keep a minimum length so that the track is always visible.
  66  	minLength := halfWidthInt + 3*thumbRadiusInt + halfWidthInt
  67  	if size.X < minLength {
  68  		size.X = minLength
  69  	}
  70  	size.Y = 2 * halfWidthInt
  71  	
  72  	st := op.Save(gtx.Ops)
  73  	op.Offset(f32.Pt(halfWidth, 0)).Add(gtx.Ops)
  74  	gtx.Constraints.Min = image.Pt(size.X-2*halfWidthInt, size.Y)
  75  	s.float.Fn(gtx, halfWidthInt, s.min, s.max)
  76  	thumbPos := halfWidth + s.float.Pos()
  77  	st.Load()
  78  	
  79  	col := s.color
  80  	if gtx.Queue == nil {
  81  		col = f32color.MulAlpha(col, 150)
  82  	}
  83  	
  84  	// Draw track before thumb.
  85  	st = op.Save(gtx.Ops)
  86  	track := f32.Rectangle{
  87  		Min: f32.Point{
  88  			X: halfWidth,
  89  			Y: halfWidth - trackWidth/2,
  90  		},
  91  		Max: f32.Point{
  92  			X: thumbPos,
  93  			Y: halfWidth + trackWidth/2,
  94  		},
  95  	}
  96  	clip.RRect{Rect: track}.Add(gtx.Ops)
  97  	paint.ColorOp{Color: col}.Add(gtx.Ops)
  98  	paint.PaintOp{}.Add(gtx.Ops)
  99  	st.Load()
 100  	
 101  	// Draw track after thumb.
 102  	st = op.Save(gtx.Ops)
 103  	track.Min.X = thumbPos
 104  	track.Max.X = float32(size.X) - halfWidth
 105  	clip.RRect{Rect: track}.Add(gtx.Ops)
 106  	paint.ColorOp{Color: f32color.MulAlpha(col, 96)}.Add(gtx.Ops)
 107  	paint.PaintOp{}.Add(gtx.Ops)
 108  	st.Load()
 109  	
 110  	// Draw thumb.
 111  	st = op.Save(gtx.Ops)
 112  	thumb := f32.Rectangle{
 113  		Min: f32.Point{
 114  			X: thumbPos - thumbRadius,
 115  			Y: halfWidth - thumbRadius,
 116  		},
 117  		Max: f32.Point{
 118  			X: thumbPos + thumbRadius,
 119  			Y: halfWidth + thumbRadius,
 120  		},
 121  	}
 122  	rr := thumbRadius
 123  	clip.RRect{
 124  		Rect: thumb,
 125  		NE:   rr, NW: rr, SE: rr, SW: rr,
 126  	}.Add(gtx.Ops)
 127  	paint.ColorOp{Color: col}.Add(gtx.Ops)
 128  	paint.PaintOp{}.Add(gtx.Ops)
 129  	st.Load()
 130  	
 131  	return l.Dimensions{Size: size}
 132  }
 133