zntg/ui/button.go
Sander Schobers ff51378aff Added button types.
Go image can be reconstructed from ui.Image/allg5.Bitmap.
Changed allg5.Scale from interface to struct.
2019-03-13 19:49:00 +01:00

161 lines
3.3 KiB
Go

package ui
import (
"image/color"
"github.com/nfnt/resize"
"opslag.de/schobers/geom"
)
type Button struct {
ControlBase
Type ButtonType
Text string
Icon Image
scale float32
icon Image
}
type ButtonType int
const (
ButtonTypeContained ButtonType = iota
ButtonTypeIcon
ButtonTypeOutlined
ButtonTypeText
)
func BuildButton(text string, fn func(b *Button)) *Button { return BuildIconButton(nil, text, fn) }
func BuildIconButton(i Image, text string, fn func(b *Button)) *Button {
var b = &Button{Text: text, Icon: i}
if fn != nil {
fn(b)
}
return b
}
func (b *Button) desiredSize(ctx Context) geom.PointF32 {
var pad = ctx.Style().Dimensions.TextPadding
var font = ctx.Renderer().Font(b.FontName(ctx))
var w, h float32 = 0, font.Height()
if len(b.Text) != 0 {
w += font.WidthOf(b.Text) + pad
}
if b.Icon != nil && b.Icon.Height() > 0 {
w += b.Icon.Width()*h/b.Icon.Height() + pad
}
if w == 0 {
return geom.ZeroPtF32
}
return geom.PtF32(pad+w, pad+h+pad)
}
func (b *Button) DesiredSize(ctx Context) geom.PointF32 {
return b.desiredSize(ctx)
}
func (b *Button) Handle(ctx Context, e Event) {
b.ControlBase.Handle(ctx, e)
if b.over {
ctx.Renderer().SetMouseCursor(MouseCursorPointer)
}
}
func (b *Button) fillColor(p *Palette) color.Color {
if b.Background != nil {
return b.Background
}
if b.over {
switch b.Type {
case ButtonTypeContained:
return p.PrimaryHighlight
case ButtonTypeIcon:
default:
return p.PrimaryLight
}
}
switch b.Type {
case ButtonTypeContained:
return p.Primary
case ButtonTypeIcon:
default:
}
return nil
}
func (b *Button) scaledIcon(ctx Context, height float32) Image {
scale := height / b.Icon.Height()
if scale == 1 {
b.scale = 1
return b.Icon
}
if b.icon == nil || b.scale != scale {
if b.icon != nil {
b.icon.Destroy()
b.icon = nil
}
im := resize.Resize(uint(b.Icon.Width()*scale), 0, b.Icon.Image(), resize.Bilinear)
icon, err := ctx.Renderer().CreateImage(im)
if err != nil {
return nil
}
b.icon = icon
b.scale = scale
}
return b.icon
}
func (b *Button) textColor(p *Palette) color.Color {
if b.Font.Color != nil {
return b.Font.Color
}
switch b.Type {
case ButtonTypeContained:
return p.TextOnPrimary
case ButtonTypeIcon:
if b.over {
return p.Primary
}
return p.Text
default:
return 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
var pad = style.Dimensions.TextPadding
bounds = bounds.Inset(pad)
pos := bounds.Min
if b.Icon != nil && b.Icon.Height() > 0 {
icon := b.scaledIcon(ctx, bounds.Dy())
if icon != nil {
ctx.Renderer().DrawImageOptions(icon, pos, DrawOptions{Tint: textColor})
pos.X += icon.Width() + pad
}
}
if len(b.Text) != 0 {
var fontName = b.FontName(ctx)
var font = ctx.Renderer().Font(fontName)
ctx.Renderer().Text(geom.PtF32(pos.X, pos.Y+.5*(bounds.Dy()-font.Height())), fontName, textColor, b.Text)
}
if b.Type == ButtonTypeOutlined {
ctx.Renderer().Rectangle(b.bounds, palette.TextDisabled, 1)
}
}