diff --git a/widget/float.go b/widget/float.go index 3c59a26a..8d9c9145 100644 --- a/widget/float.go +++ b/widget/float.go @@ -14,6 +14,7 @@ import ( // Float is for selecting a value in a range. type Float struct { Value float32 + Axis layout.Axis drag gesture.Drag pos float32 // position normalized to [0, 1] @@ -24,13 +25,15 @@ type Float struct { // Dragging returns whether the value is being interacted with. func (f *Float) Dragging() bool { return f.drag.Dragging() } -// Layout processes events. +// Layout updates the value according to drag events along the f's main axis. +// +// The range of f is set by the minimum constraints main axis value. func (f *Float) Layout(gtx layout.Context, pointerMargin int, min, max float32) layout.Dimensions { size := gtx.Constraints.Min - f.length = float32(size.X) + f.length = float32(f.Axis.Convert(size).X) var de *pointer.Event - for _, e := range f.drag.Events(gtx.Metric, gtx, gesture.Horizontal) { + for _, e := range f.drag.Events(gtx.Metric, gtx, gesture.Axis(f.Axis)) { if e.Type == pointer.Press || e.Type == pointer.Drag { de = &e } @@ -38,7 +41,11 @@ func (f *Float) Layout(gtx layout.Context, pointerMargin int, min, max float32) value := f.Value if de != nil { - f.pos = de.Position.X / f.length + xy := de.Position.X + if f.Axis == layout.Vertical { + xy = de.Position.Y + } + f.pos = xy / f.length value = min + (max-min)*f.pos } else if min != max { f.pos = value/(max-min) - min @@ -53,9 +60,11 @@ func (f *Float) Layout(gtx layout.Context, pointerMargin int, min, max float32) } defer op.Save(gtx.Ops).Load() - rect := image.Rectangle{Max: size} - rect.Min.X -= pointerMargin - rect.Max.X += pointerMargin + margin := f.Axis.Convert(image.Pt(pointerMargin, 0)) + rect := image.Rectangle{ + Min: margin.Mul(-1), + Max: size.Add(margin), + } pointer.Rect(rect).Add(gtx.Ops) f.drag.Add(gtx.Ops) diff --git a/widget/material/slider.go b/widget/material/slider.go index 1ce95ffa..6617fbca 100644 --- a/widget/material/slider.go +++ b/widget/material/slider.go @@ -6,7 +6,6 @@ import ( "image" "image/color" - "gioui.org/f32" "gioui.org/internal/f32color" "gioui.org/layout" "gioui.org/op" @@ -36,34 +35,26 @@ type SliderStyle struct { } func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions { - thumbRadiusInt := gtx.Px(unit.Dp(6)) - trackWidth := float32(gtx.Px(unit.Dp(2))) - thumbRadius := float32(thumbRadiusInt) + thumbRadius := gtx.Px(unit.Dp(6)) + trackWidth := gtx.Px(unit.Dp(2)) - size := gtx.Constraints.Min + axis := s.Float.Axis // Keep a minimum length so that the track is always visible. - minLength := thumbRadiusInt + 3*thumbRadiusInt + thumbRadiusInt - if size.X < minLength { - size.X = minLength - } - size.Y = 2 * thumbRadiusInt - + minLength := thumbRadius + 3*thumbRadius + thumbRadius // 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) - } + 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) - op.Offset(f32.Pt(thumbRadius, 0)).Add(gtx.Ops) - gtx.Constraints.Min = image.Pt(size.X-2*thumbRadiusInt, size.Y) - s.Float.Layout(gtx, thumbRadiusInt, s.Min, s.Max) - gtx.Constraints.Min.Y = size.Y - thumbPos := thumbRadius + s.Float.Pos() + 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 @@ -73,50 +64,49 @@ func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions { // Draw track before thumb. st = op.Save(gtx.Ops) - track := f32.Rectangle{ - Min: f32.Point{ - X: thumbRadius, - Y: float32(size.Y/2) - trackWidth/2, - }, - Max: f32.Point{ - X: thumbPos, - Y: float32(size.Y/2) + trackWidth/2, - }, + track := image.Rectangle{ + Min: axis.Convert(image.Pt(thumbRadius, sizeCross/2-trackWidth/2)), + Max: axis.Convert(image.Pt(thumbPos, sizeCross/2+trackWidth/2)), } - clip.RRect{Rect: track}.Add(gtx.Ops) - paint.ColorOp{Color: color}.Add(gtx.Ops) - paint.PaintOp{}.Add(gtx.Ops) + clip.Rect(track).Add(gtx.Ops) + paint.Fill(gtx.Ops, color) st.Load() // Draw track after thumb. st = op.Save(gtx.Ops) - track.Min.X = thumbPos - track.Max.X = float32(size.X) - thumbRadius - clip.RRect{Rect: track}.Add(gtx.Ops) - paint.ColorOp{Color: f32color.MulAlpha(color, 96)}.Add(gtx.Ops) - paint.PaintOp{}.Add(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) - thumb := f32.Rectangle{ - Min: f32.Point{ - X: thumbPos - thumbRadius, - Y: float32(size.Y/2) - thumbRadius, - }, - Max: f32.Point{ - X: thumbPos + thumbRadius, - Y: float32(size.Y/2) + thumbRadius, - }, + pt := axis.Convert(image.Pt(thumbPos, sizeCross/2)) + rpt := image.Pt(thumbRadius, thumbRadius) + thumb := image.Rectangle{ + Min: pt.Sub(rpt), + Max: pt.Add(rpt), } - rr := thumbRadius - clip.RRect{ - Rect: thumb, - NE: rr, NW: rr, SE: rr, SW: rr, - }.Add(gtx.Ops) - paint.ColorOp{Color: color}.Add(gtx.Ops) - paint.PaintOp{}.Add(gtx.Ops) + 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 +}