gioui.org@v0.6.1-0.20240506124620-7a9ce51988ce/widget/float.go (about)

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  package widget
     4  
     5  import (
     6  	"image"
     7  
     8  	"gioui.org/gesture"
     9  	"gioui.org/io/pointer"
    10  	"gioui.org/layout"
    11  	"gioui.org/op/clip"
    12  	"gioui.org/unit"
    13  )
    14  
    15  // Float is for selecting a value in a range.
    16  type Float struct {
    17  	// Value is the value of the Float, in the [0; 1] range.
    18  	Value float32
    19  
    20  	drag   gesture.Drag
    21  	axis   layout.Axis
    22  	length float32
    23  }
    24  
    25  // Dragging returns whether the value is being interacted with.
    26  func (f *Float) Dragging() bool { return f.drag.Dragging() }
    27  
    28  func (f *Float) Layout(gtx layout.Context, axis layout.Axis, pointerMargin unit.Dp) layout.Dimensions {
    29  	f.Update(gtx)
    30  	size := gtx.Constraints.Min
    31  	f.length = float32(axis.Convert(size).X)
    32  	f.axis = axis
    33  
    34  	margin := axis.Convert(image.Pt(gtx.Dp(pointerMargin), 0))
    35  	rect := image.Rectangle{
    36  		Min: margin.Mul(-1),
    37  		Max: size.Add(margin),
    38  	}
    39  	defer clip.Rect(rect).Push(gtx.Ops).Pop()
    40  	f.drag.Add(gtx.Ops)
    41  
    42  	return layout.Dimensions{Size: size}
    43  }
    44  
    45  // Update the Value according to drag events along the f's main axis.
    46  // The return value reports whether the value was changed.
    47  //
    48  // The range of f is set by the minimum constraints main axis value.
    49  func (f *Float) Update(gtx layout.Context) bool {
    50  	changed := false
    51  	for {
    52  		e, ok := f.drag.Update(gtx.Metric, gtx.Source, gesture.Axis(f.axis))
    53  		if !ok {
    54  			break
    55  		}
    56  		if f.length > 0 && (e.Kind == pointer.Press || e.Kind == pointer.Drag) {
    57  			pos := e.Position.X
    58  			if f.axis == layout.Vertical {
    59  				pos = f.length - e.Position.Y
    60  			}
    61  			f.Value = pos / f.length
    62  			if f.Value < 0 {
    63  				f.Value = 0
    64  			} else if f.Value > 1 {
    65  				f.Value = 1
    66  			}
    67  			changed = true
    68  		}
    69  	}
    70  	return changed
    71  }