Files
prevara/iconbutton.go
2025-11-30 16:45:22 +00:00

130 lines
3.2 KiB
Go

package gel
import (
"image"
l "github.com/p9c/p9/pkg/gel/gio/layout"
"github.com/p9c/p9/pkg/gel/gio/op/clip"
"github.com/p9c/p9/pkg/gel/gio/unit"
"golang.org/x/exp/shiny/materialdesign/icons"
"github.com/p9c/p9/pkg/gel/f32color"
)
type IconButton struct {
*Window
background string
// Color is the icon color.
color string
icon *Icon
// Size is the icon size.
size unit.Sp
inset *Inset
button *Clickable
corners int
}
// IconButton creates an icon with a circular *optional non-round corners* background and an icon placed in the centre
func (w *Window) IconButton(button *Clickable) *IconButton {
return &IconButton{
Window: w,
background: "Primary",
color: "DocBg",
size: w.TextSize,
inset: w.Inset(0.33, nil),
button: button,
icon: w.Icon().Src(&icons.AlertError),
}
}
// Corners sets the corners that will be circular
func (b *IconButton) Corners(corners int) *IconButton {
b.corners = corners
return b
}
// Background sets the color of the circular background
func (b *IconButton) Background(color string) *IconButton {
b.background = color
return b
}
// Color sets the color of the icon
func (b *IconButton) Color(color string) *IconButton {
b.color = color
return b
}
// Icon sets the icon to display
func (b *IconButton) Icon(ic *Icon) *IconButton {
b.icon = ic
return b
}
// Scale changes the size of the icon as a ratio of the base font size
func (b *IconButton) Scale(scale float32) *IconButton {
b.size = unit.Sp(float32(b.Theme.TextSize) * scale * 0.72)
return b
}
// ButtonInset sets the size of inset that goes in between the button background
// and the icon
func (b *IconButton) ButtonInset(inset float32) *IconButton {
b.inset = b.Inset(inset, b.button.Fn)
return b
}
// SetClick sets the function to run on click
func (b *IconButton) SetClick(fn func()) *IconButton {
b.button.SetClick(fn)
return b
}
// SetPress sets the function to run on press
func (b *IconButton) SetPress(fn func()) *IconButton {
b.button.SetPress(fn)
return b
}
// SetCancel sets the function to run on cancel (click but release outside)
func (b *IconButton) SetCancel(fn func()) *IconButton {
b.button.SetCancel(fn)
return b
}
// Fn renders the icon button
func (b *IconButton) Fn(gtx l.Context) l.Dimensions {
return b.Stack().Expanded(
func(gtx l.Context) l.Dimensions {
sizex, sizey := gtx.Constraints.Min.X, gtx.Constraints.Min.Y
rr := (sizex + sizey) / 4
defer clip.RRect{
Rect: image.Rectangle{Max: image.Point{X: sizex, Y: sizey}},
NE: ifDirInt(rr, b.corners&NE),
NW: ifDirInt(rr, b.corners&NW),
SE: ifDirInt(rr, b.corners&SE),
SW: ifDirInt(rr, b.corners&SW),
}.Push(gtx.Ops).Pop()
background := b.Theme.Colors.GetNRGBAFromName(b.background)
if !gtx.Source.Enabled() {
background = f32color.MulAlpha(background, 150)
}
var dims l.Dimensions
if b.background != "" {
dims = Fill(gtx, background)
}
for _, c := range b.button.History() {
drawInk(gtx, c)
}
return dims
},
).Stacked(
b.inset.Embed(b.icon.Fn).Fn,
).Expanded(
func(gtx l.Context) l.Dimensions {
defer clip.Ellipse(image.Rectangle{Max: gtx.Constraints.Min}).Push(gtx.Ops).Pop()
return b.button.Fn(gtx)
},
).Fn(gtx)
}