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

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  package material
     4  
     5  import (
     6  	"image"
     7  	"image/color"
     8  
     9  	"gioui.org/internal/f32color"
    10  	"gioui.org/layout"
    11  	"gioui.org/op/clip"
    12  	"gioui.org/op/paint"
    13  	"gioui.org/unit"
    14  )
    15  
    16  type ProgressBarStyle struct {
    17  	Color      color.NRGBA
    18  	Height     unit.Dp
    19  	Radius     unit.Dp
    20  	TrackColor color.NRGBA
    21  	Progress   float32
    22  }
    23  
    24  func ProgressBar(th *Theme, progress float32) ProgressBarStyle {
    25  	return ProgressBarStyle{
    26  		Progress:   progress,
    27  		Height:     unit.Dp(4),
    28  		Radius:     unit.Dp(2),
    29  		Color:      th.Palette.ContrastBg,
    30  		TrackColor: f32color.MulAlpha(th.Palette.Fg, 0x88),
    31  	}
    32  }
    33  
    34  func (p ProgressBarStyle) Layout(gtx layout.Context) layout.Dimensions {
    35  	shader := func(width int, color color.NRGBA) layout.Dimensions {
    36  		d := image.Point{X: width, Y: gtx.Dp(p.Height)}
    37  		rr := gtx.Dp(p.Radius)
    38  
    39  		defer clip.UniformRRect(image.Rectangle{Max: image.Pt(width, d.Y)}, rr).Push(gtx.Ops).Pop()
    40  		paint.ColorOp{Color: color}.Add(gtx.Ops)
    41  		paint.PaintOp{}.Add(gtx.Ops)
    42  
    43  		return layout.Dimensions{Size: d}
    44  	}
    45  
    46  	progressBarWidth := gtx.Constraints.Max.X
    47  	return layout.Stack{Alignment: layout.W}.Layout(gtx,
    48  		layout.Stacked(func(gtx layout.Context) layout.Dimensions {
    49  			return shader(progressBarWidth, p.TrackColor)
    50  		}),
    51  		layout.Stacked(func(gtx layout.Context) layout.Dimensions {
    52  			fillWidth := int(float32(progressBarWidth) * clamp1(p.Progress))
    53  			fillColor := p.Color
    54  			if !gtx.Enabled() {
    55  				fillColor = f32color.Disabled(fillColor)
    56  			}
    57  			if fillWidth < int(p.Radius*2) {
    58  				fillWidth = int(p.Radius * 2)
    59  			}
    60  			return shader(fillWidth, fillColor)
    61  		}),
    62  	)
    63  }
    64  
    65  // clamp1 limits v to range [0..1].
    66  func clamp1(v float32) float32 {
    67  	if v >= 1 {
    68  		return 1
    69  	} else if v <= 0 {
    70  		return 0
    71  	} else {
    72  		return v
    73  	}
    74  }