mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-05 01:15:35 +00:00
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>
This commit is contained in:
+16
-7
@@ -14,6 +14,7 @@ import (
|
|||||||
// Float is for selecting a value in a range.
|
// Float is for selecting a value in a range.
|
||||||
type Float struct {
|
type Float struct {
|
||||||
Value float32
|
Value float32
|
||||||
|
Axis layout.Axis
|
||||||
|
|
||||||
drag gesture.Drag
|
drag gesture.Drag
|
||||||
pos float32 // position normalized to [0, 1]
|
pos float32 // position normalized to [0, 1]
|
||||||
@@ -24,13 +25,15 @@ type Float struct {
|
|||||||
// Dragging returns whether the value is being interacted with.
|
// Dragging returns whether the value is being interacted with.
|
||||||
func (f *Float) Dragging() bool { return f.drag.Dragging() }
|
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 {
|
func (f *Float) Layout(gtx layout.Context, pointerMargin int, min, max float32) layout.Dimensions {
|
||||||
size := gtx.Constraints.Min
|
size := gtx.Constraints.Min
|
||||||
f.length = float32(size.X)
|
f.length = float32(f.Axis.Convert(size).X)
|
||||||
|
|
||||||
var de *pointer.Event
|
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 {
|
if e.Type == pointer.Press || e.Type == pointer.Drag {
|
||||||
de = &e
|
de = &e
|
||||||
}
|
}
|
||||||
@@ -38,7 +41,11 @@ func (f *Float) Layout(gtx layout.Context, pointerMargin int, min, max float32)
|
|||||||
|
|
||||||
value := f.Value
|
value := f.Value
|
||||||
if de != nil {
|
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
|
value = min + (max-min)*f.pos
|
||||||
} else if min != max {
|
} else if min != max {
|
||||||
f.pos = value/(max-min) - min
|
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()
|
defer op.Save(gtx.Ops).Load()
|
||||||
rect := image.Rectangle{Max: size}
|
margin := f.Axis.Convert(image.Pt(pointerMargin, 0))
|
||||||
rect.Min.X -= pointerMargin
|
rect := image.Rectangle{
|
||||||
rect.Max.X += pointerMargin
|
Min: margin.Mul(-1),
|
||||||
|
Max: size.Add(margin),
|
||||||
|
}
|
||||||
pointer.Rect(rect).Add(gtx.Ops)
|
pointer.Rect(rect).Add(gtx.Ops)
|
||||||
f.drag.Add(gtx.Ops)
|
f.drag.Add(gtx.Ops)
|
||||||
|
|
||||||
|
|||||||
+46
-56
@@ -6,7 +6,6 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
"gioui.org/f32"
|
|
||||||
"gioui.org/internal/f32color"
|
"gioui.org/internal/f32color"
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/op"
|
"gioui.org/op"
|
||||||
@@ -36,34 +35,26 @@ type SliderStyle struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions {
|
func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions {
|
||||||
thumbRadiusInt := gtx.Px(unit.Dp(6))
|
thumbRadius := gtx.Px(unit.Dp(6))
|
||||||
trackWidth := float32(gtx.Px(unit.Dp(2)))
|
trackWidth := gtx.Px(unit.Dp(2))
|
||||||
thumbRadius := float32(thumbRadiusInt)
|
|
||||||
|
|
||||||
size := gtx.Constraints.Min
|
axis := s.Float.Axis
|
||||||
// Keep a minimum length so that the track is always visible.
|
// Keep a minimum length so that the track is always visible.
|
||||||
minLength := thumbRadiusInt + 3*thumbRadiusInt + thumbRadiusInt
|
minLength := thumbRadius + 3*thumbRadius + thumbRadius
|
||||||
if size.X < minLength {
|
|
||||||
size.X = minLength
|
|
||||||
}
|
|
||||||
size.Y = 2 * thumbRadiusInt
|
|
||||||
|
|
||||||
// Try to expand to finger size, but only if the constraints
|
// Try to expand to finger size, but only if the constraints
|
||||||
// allow for it.
|
// allow for it.
|
||||||
touchSizePx := gtx.Px(s.FingerSize)
|
touchSizePx := min(gtx.Px(s.FingerSize), axis.Convert(gtx.Constraints.Max).Y)
|
||||||
if touchSizePx > gtx.Constraints.Max.Y {
|
sizeMain := max(axis.Convert(gtx.Constraints.Min).X, minLength)
|
||||||
touchSizePx = gtx.Constraints.Max.Y
|
sizeCross := max(2*thumbRadius, touchSizePx)
|
||||||
}
|
size := axis.Convert(image.Pt(sizeMain, sizeCross))
|
||||||
if size.Y < touchSizePx {
|
|
||||||
size.Y = 2 * (touchSizePx / 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
st := op.Save(gtx.Ops)
|
st := op.Save(gtx.Ops)
|
||||||
op.Offset(f32.Pt(thumbRadius, 0)).Add(gtx.Ops)
|
o := axis.Convert(image.Pt(thumbRadius, 0))
|
||||||
gtx.Constraints.Min = image.Pt(size.X-2*thumbRadiusInt, size.Y)
|
op.Offset(layout.FPt(o)).Add(gtx.Ops)
|
||||||
s.Float.Layout(gtx, thumbRadiusInt, s.Min, s.Max)
|
gtx.Constraints.Min = axis.Convert(image.Pt(sizeMain-2*thumbRadius, sizeCross))
|
||||||
gtx.Constraints.Min.Y = size.Y
|
s.Float.Layout(gtx, thumbRadius, s.Min, s.Max)
|
||||||
thumbPos := thumbRadius + s.Float.Pos()
|
gtx.Constraints.Min = gtx.Constraints.Min.Add(axis.Convert(image.Pt(0, sizeCross)))
|
||||||
|
thumbPos := thumbRadius + int(s.Float.Pos())
|
||||||
st.Load()
|
st.Load()
|
||||||
|
|
||||||
color := s.Color
|
color := s.Color
|
||||||
@@ -73,50 +64,49 @@ func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions {
|
|||||||
|
|
||||||
// Draw track before thumb.
|
// Draw track before thumb.
|
||||||
st = op.Save(gtx.Ops)
|
st = op.Save(gtx.Ops)
|
||||||
track := f32.Rectangle{
|
track := image.Rectangle{
|
||||||
Min: f32.Point{
|
Min: axis.Convert(image.Pt(thumbRadius, sizeCross/2-trackWidth/2)),
|
||||||
X: thumbRadius,
|
Max: axis.Convert(image.Pt(thumbPos, sizeCross/2+trackWidth/2)),
|
||||||
Y: float32(size.Y/2) - trackWidth/2,
|
|
||||||
},
|
|
||||||
Max: f32.Point{
|
|
||||||
X: thumbPos,
|
|
||||||
Y: float32(size.Y/2) + trackWidth/2,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
clip.RRect{Rect: track}.Add(gtx.Ops)
|
clip.Rect(track).Add(gtx.Ops)
|
||||||
paint.ColorOp{Color: color}.Add(gtx.Ops)
|
paint.Fill(gtx.Ops, color)
|
||||||
paint.PaintOp{}.Add(gtx.Ops)
|
|
||||||
st.Load()
|
st.Load()
|
||||||
|
|
||||||
// Draw track after thumb.
|
// Draw track after thumb.
|
||||||
st = op.Save(gtx.Ops)
|
st = op.Save(gtx.Ops)
|
||||||
track.Min.X = thumbPos
|
track = image.Rectangle{
|
||||||
track.Max.X = float32(size.X) - thumbRadius
|
Min: axis.Convert(image.Pt(thumbPos, axis.Convert(track.Min).Y)),
|
||||||
clip.RRect{Rect: track}.Add(gtx.Ops)
|
Max: axis.Convert(image.Pt(sizeMain-thumbRadius, axis.Convert(track.Max).Y)),
|
||||||
paint.ColorOp{Color: f32color.MulAlpha(color, 96)}.Add(gtx.Ops)
|
}
|
||||||
paint.PaintOp{}.Add(gtx.Ops)
|
clip.Rect(track).Add(gtx.Ops)
|
||||||
|
paint.Fill(gtx.Ops, f32color.MulAlpha(color, 96))
|
||||||
st.Load()
|
st.Load()
|
||||||
|
|
||||||
// Draw thumb.
|
// Draw thumb.
|
||||||
st = op.Save(gtx.Ops)
|
st = op.Save(gtx.Ops)
|
||||||
thumb := f32.Rectangle{
|
pt := axis.Convert(image.Pt(thumbPos, sizeCross/2))
|
||||||
Min: f32.Point{
|
rpt := image.Pt(thumbRadius, thumbRadius)
|
||||||
X: thumbPos - thumbRadius,
|
thumb := image.Rectangle{
|
||||||
Y: float32(size.Y/2) - thumbRadius,
|
Min: pt.Sub(rpt),
|
||||||
},
|
Max: pt.Add(rpt),
|
||||||
Max: f32.Point{
|
|
||||||
X: thumbPos + thumbRadius,
|
|
||||||
Y: float32(size.Y/2) + thumbRadius,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
rr := thumbRadius
|
clip.UniformRRect(layout.FRect(thumb), float32(thumbRadius)).Add(gtx.Ops)
|
||||||
clip.RRect{
|
paint.Fill(gtx.Ops, color)
|
||||||
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)
|
|
||||||
st.Load()
|
st.Load()
|
||||||
|
|
||||||
return layout.Dimensions{Size: size}
|
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
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user