Sander Schobers
0f03760e66
Refactored Size (on Renderer) to return geom.Point instead of geom.PointF32. Refactored Width and Height (on Texture) to return int instead of float32. Refactored texture dimensions to be represented by ints instead of float32s.
233 lines
5.0 KiB
Go
233 lines
5.0 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 = ctx.Style().Dimensions.TextPadding
|
|
var font = ctx.Fonts().Font(b.FontName(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 + iconW + pad
|
|
h = iconH
|
|
}
|
|
} else {
|
|
w += pad + font.WidthOf(b.Text) + pad
|
|
if icon != nil && iconH > 0 {
|
|
if b.IconHeight == 0 {
|
|
iconW = iconW * h / iconH
|
|
// iconH = h
|
|
}
|
|
w += iconW + pad
|
|
}
|
|
}
|
|
if w == 0 {
|
|
return geom.ZeroPtF32
|
|
}
|
|
return geom.PtF32(w, pad+h+pad)
|
|
}
|
|
|
|
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) 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)
|
|
}
|
|
if b.Font.Color != nil {
|
|
return b.Font.Color
|
|
}
|
|
switch b.Type {
|
|
case ButtonTypeContained:
|
|
return p.TextOnPrimary
|
|
case ButtonTypeIcon:
|
|
if b.over {
|
|
if b.HoverColor != nil {
|
|
return b.HoverColor
|
|
}
|
|
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)
|
|
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
|
|
}
|
|
if len(b.Text) != 0 {
|
|
fontName := b.FontName(ctx)
|
|
font := ctx.Fonts().Font(fontName)
|
|
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)
|
|
}
|
|
}
|