zntg/ui/button.go

236 lines
5.1 KiB
Go

package ui
import (
"image/color"
"opslag.de/schobers/geom"
)
type Button struct {
ControlBase
DisabledColor color.Color
HoverColor color.Color
Icon string // optional: icon to display in front of the text.
IconHeight float32 // overrides the height of the icon (overrides auto-scaling when text is provided).
Text string
Type ButtonType
clicked ControlClickedEvents
}
type ButtonType int
const (
ButtonTypeContained ButtonType = iota
ButtonTypeIcon
ButtonTypeOutlined
ButtonTypeText
)
func BuildButton(text string, fn func(b *Button)) *Button { return BuildIconButton("", text, fn) }
func BuildIconButton(icon, text string, fn func(b *Button)) *Button {
var b = &Button{Text: text, Icon: icon}
if fn != nil {
fn(b)
}
return b
}
func (b *Button) desiredSize(ctx Context) geom.PointF32 {
var pad = b.ActualTextPadding(ctx)
var font = b.ActualFont(ctx)
var w, h float32 = 0, font.Height()
icon, iconW, iconH := b.icon(ctx)
if len(b.Text) == 0 {
if icon != nil && iconH > 0 {
w = pad.Left + iconW + pad.Right
h = iconH
}
} else {
w += pad.Left + font.WidthOf(b.Text) + pad.Right
if icon != nil && iconH > 0 {
if b.IconHeight == 0 {
iconW = iconW * h / iconH
// iconH = h
}
w += iconW + pad.Right
}
}
if w == 0 {
return geom.ZeroPtF32
}
return geom.PtF32(w, pad.Top+h+pad.Bottom)
}
func (b *Button) icon(ctx Context) (Texture, float32, float32) {
if b.Icon == "" {
return nil, 0, 0
}
icon := ctx.Textures().Texture(b.Icon)
iconW, iconH := float32(icon.Width()), float32(icon.Height())
if b.IconHeight != 0 {
iconW = b.IconHeight * iconW / iconH
iconH = b.IconHeight
}
return icon, iconW, iconH
}
func (b *Button) ButtonClicked() ControlClickedEventHandler { return &b.clicked }
func (b *Button) DesiredSize(ctx Context, _ geom.PointF32) geom.PointF32 {
return b.desiredSize(ctx)
}
func (b *Button) Handle(ctx Context, e Event) bool {
result := b.ControlBase.HandleNotify(ctx, e, b)
if b.over {
if b.Disabled {
return true
}
ctx.Renderer().SetMouseCursor(MouseCursorPointer)
}
return result
}
func (b *Button) Notify(ctx Context, state interface{}) bool {
switch state.(type) {
case ControlClickedArgs:
if !b.Disabled {
if b.clicked.Notify(ctx, state) {
return true
}
}
}
return b.ControlBase.Notify(ctx, state)
}
func (b *Button) disabledColor(p *Palette) color.Color {
if b.DisabledColor != nil {
return b.DisabledColor
}
return p.Disabled
}
func (b *Button) fillColor(p *Palette) color.Color {
if b.Type == ButtonTypeIcon {
return nil
}
if b.Disabled {
if b.Background != nil {
return b.disabledColor(p)
}
switch b.Type {
case ButtonTypeContained:
return b.disabledColor(p)
default:
return nil
}
}
if b.Background != nil {
if b.over && b.HoverColor != nil {
return b.HoverColor
}
return b.Background
}
if b.over {
if b.HoverColor != nil {
return b.HoverColor
}
switch b.Type {
case ButtonTypeContained:
return p.PrimaryLight
default:
return p.PrimaryHighlight
}
}
switch b.Type {
case ButtonTypeContained:
return p.Primary
}
return nil
}
func (b *Button) fontColor(c color.Color) color.Color {
if b.Font.Color == nil {
return c
}
return b.Font.Color
}
func (b *Button) textColor(p *Palette) color.Color {
if b.Disabled {
if b.Background != nil {
return p.TextOnDisabled
}
switch b.Type {
case ButtonTypeContained:
return p.TextOnDisabled
}
return b.disabledColor(p)
}
switch b.Type {
case ButtonTypeContained:
return b.fontColor(p.TextOnPrimary)
case ButtonTypeIcon:
if b.over {
if b.HoverColor != nil {
return b.HoverColor
}
return b.fontColor(p.Primary)
}
return b.fontColor(p.Text)
default:
return b.fontColor(p.Primary)
}
}
func (b *Button) Render(ctx Context) {
var style = ctx.Style()
var palette = style.Palette
textColor := b.textColor(palette)
fillColor := b.fillColor(palette)
if fillColor != nil {
ctx.Renderer().FillRectangle(b.bounds, fillColor)
}
size := b.desiredSize(ctx)
bounds := b.bounds
deltaX, deltaY := bounds.Dx()-size.X, bounds.Dy()-size.Y
bounds.Min.X += .5 * deltaX
bounds.Min.Y += .5 * deltaY
pad := b.ActualTextPadding(ctx)
bounds = pad.InsetRect(bounds)
boundsH := bounds.Dy()
pos := bounds.Min
icon, iconW, iconH := b.icon(ctx)
var iconOffsetY float32
if icon != nil && iconH > 0 {
if b.Text != "" {
if b.IconHeight == 0 {
iconH = boundsH
scaled, _ := ctx.Textures().ScaledHeight(icon, iconH) // try to pre-scale scaled
if scaled != nil { // let the renderer scale
icon = scaled
}
_, iconW = ScaleToHeight(SizeOfTexture(icon).ToF32(), iconH)
}
iconOffsetY = .5 * (boundsH - iconH)
}
ctx.Renderer().DrawTextureOptions(icon, geom.RectRelF32(pos.X, pos.Y+iconOffsetY, iconW, iconH), DrawOptions{Tint: textColor})
pos.X += iconW + pad.Right
}
if len(b.Text) != 0 {
font := b.ActualFont(ctx)
ctx.Renderer().Text(font, geom.PtF32(pos.X, pos.Y+.5*(boundsH-font.Height())), textColor, b.Text)
}
if b.Type == ButtonTypeOutlined {
b.RenderOutlineDefault(ctx, textColor)
}
}