widget/material: remove padding from Slider

Remove padding from the sides of the Slider to align them with
other components.

However, since sliders still need to be used with fingers try to
enforce a minimum finger height, if there is sufficient room.
The sides don't need similar treatment since after grabbing it's
possible to move the finger beyond the touch area, without losing
interaction.

To not enforce finger size, the theme can be adjusted:

    theme.FingerSize = unit.Px(0)

Signed-off-by: Egon Elbre <egonelbre@gmail.com>
This commit is contained in:
Egon Elbre
2020-12-12 13:21:06 +02:00
committed by Elias Naur
parent 8e7066ecd7
commit 296303210f
2 changed files with 36 additions and 18 deletions
+30 -18
View File
@@ -19,10 +19,11 @@ import (
// Slider is for selecting a value in a range. // Slider is for selecting a value in a range.
func Slider(th *Theme, float *widget.Float, min, max float32) SliderStyle { func Slider(th *Theme, float *widget.Float, min, max float32) SliderStyle {
return SliderStyle{ return SliderStyle{
Min: min, Min: min,
Max: max, Max: max,
Color: th.Palette.ContrastBg, Color: th.Palette.ContrastBg,
Float: float, Float: float,
FingerSize: th.FingerSize,
} }
} }
@@ -30,28 +31,39 @@ type SliderStyle struct {
Min, Max float32 Min, Max float32
Color color.NRGBA Color color.NRGBA
Float *widget.Float Float *widget.Float
FingerSize unit.Value
} }
func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions { func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions {
thumbRadiusInt := gtx.Px(unit.Dp(6)) thumbRadiusInt := gtx.Px(unit.Dp(6))
trackWidth := float32(gtx.Px(unit.Dp(2))) trackWidth := float32(gtx.Px(unit.Dp(2)))
thumbRadius := float32(thumbRadiusInt) thumbRadius := float32(thumbRadiusInt)
halfWidthInt := 2 * thumbRadiusInt
halfWidth := float32(halfWidthInt)
size := gtx.Constraints.Min size := gtx.Constraints.Min
// Keep a minimum length so that the track is always visible. // Keep a minimum length so that the track is always visible.
minLength := halfWidthInt + 3*thumbRadiusInt + halfWidthInt minLength := thumbRadiusInt + 3*thumbRadiusInt + thumbRadiusInt
if size.X < minLength { if size.X < minLength {
size.X = minLength size.X = minLength
} }
size.Y = 2 * halfWidthInt size.Y = 2 * thumbRadiusInt
// Try to expand to finger size, but only if the constraints
// allow for it.
touchSizePx := gtx.Px(s.FingerSize)
if touchSizePx > gtx.Constraints.Max.Y {
touchSizePx = gtx.Constraints.Max.Y
}
if size.Y < touchSizePx {
size.Y = 2 * (touchSizePx / 2)
}
st := op.Push(gtx.Ops) st := op.Push(gtx.Ops)
op.Offset(f32.Pt(halfWidth, 0)).Add(gtx.Ops) op.Offset(f32.Pt(thumbRadius, 0)).Add(gtx.Ops)
gtx.Constraints.Min = image.Pt(size.X-2*halfWidthInt, size.Y) gtx.Constraints.Min = image.Pt(size.X-2*thumbRadiusInt, size.Y)
s.Float.Layout(gtx, halfWidthInt, s.Min, s.Max) s.Float.Layout(gtx, thumbRadiusInt, s.Min, s.Max)
thumbPos := halfWidth + s.Float.Pos() gtx.Constraints.Min.Y = size.Y
thumbPos := thumbRadius + s.Float.Pos()
st.Pop() st.Pop()
color := s.Color color := s.Color
@@ -63,12 +75,12 @@ func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions {
st = op.Push(gtx.Ops) st = op.Push(gtx.Ops)
track := f32.Rectangle{ track := f32.Rectangle{
Min: f32.Point{ Min: f32.Point{
X: halfWidth, X: thumbRadius,
Y: halfWidth - trackWidth/2, Y: float32(size.Y/2) - trackWidth/2,
}, },
Max: f32.Point{ Max: f32.Point{
X: thumbPos, X: thumbPos,
Y: halfWidth + trackWidth/2, Y: float32(size.Y/2) + trackWidth/2,
}, },
} }
clip.RRect{Rect: track}.Add(gtx.Ops) clip.RRect{Rect: track}.Add(gtx.Ops)
@@ -79,7 +91,7 @@ func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions {
// Draw track after thumb. // Draw track after thumb.
st = op.Push(gtx.Ops) st = op.Push(gtx.Ops)
track.Min.X = thumbPos track.Min.X = thumbPos
track.Max.X = float32(size.X) - halfWidth track.Max.X = float32(size.X) - thumbRadius
clip.RRect{Rect: track}.Add(gtx.Ops) clip.RRect{Rect: track}.Add(gtx.Ops)
paint.ColorOp{Color: f32color.MulAlpha(color, 96)}.Add(gtx.Ops) paint.ColorOp{Color: f32color.MulAlpha(color, 96)}.Add(gtx.Ops)
paint.PaintOp{}.Add(gtx.Ops) paint.PaintOp{}.Add(gtx.Ops)
@@ -90,11 +102,11 @@ func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions {
thumb := f32.Rectangle{ thumb := f32.Rectangle{
Min: f32.Point{ Min: f32.Point{
X: thumbPos - thumbRadius, X: thumbPos - thumbRadius,
Y: halfWidth - thumbRadius, Y: float32(size.Y/2) - thumbRadius,
}, },
Max: f32.Point{ Max: f32.Point{
X: thumbPos + thumbRadius, X: thumbPos + thumbRadius,
Y: halfWidth + thumbRadius, Y: float32(size.Y/2) + thumbRadius,
}, },
} }
rr := thumbRadius rr := thumbRadius
+6
View File
@@ -40,6 +40,9 @@ type Theme struct {
RadioChecked *widget.Icon RadioChecked *widget.Icon
RadioUnchecked *widget.Icon RadioUnchecked *widget.Icon
} }
// FingerSize is the minimum touch target size.
FingerSize unit.Value
} }
func NewTheme(fontCollection []text.FontFace) *Theme { func NewTheme(fontCollection []text.FontFace) *Theme {
@@ -59,6 +62,9 @@ func NewTheme(fontCollection []text.FontFace) *Theme {
t.Icon.RadioChecked = mustIcon(widget.NewIcon(icons.ToggleRadioButtonChecked)) t.Icon.RadioChecked = mustIcon(widget.NewIcon(icons.ToggleRadioButtonChecked))
t.Icon.RadioUnchecked = mustIcon(widget.NewIcon(icons.ToggleRadioButtonUnchecked)) t.Icon.RadioUnchecked = mustIcon(widget.NewIcon(icons.ToggleRadioButtonUnchecked))
// 38dp is on the lower end of possible finger size.
t.FingerSize = unit.Dp(38)
return t return t
} }