2019-03-05 20:52:18 +00:00
|
|
|
package ui
|
|
|
|
|
|
|
|
import (
|
2019-03-13 18:49:00 +00:00
|
|
|
"image/color"
|
|
|
|
|
2019-03-05 20:52:18 +00:00
|
|
|
"opslag.de/schobers/geom"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Button struct {
|
|
|
|
ControlBase
|
|
|
|
|
2019-04-11 21:27:25 +00:00
|
|
|
HoverColor color.Color
|
2020-05-15 12:44:55 +00:00
|
|
|
Icon string
|
2019-04-11 21:27:25 +00:00
|
|
|
Text string
|
|
|
|
Type ButtonType
|
2020-05-16 11:46:07 +00:00
|
|
|
|
|
|
|
clicked ControlClickedEvents
|
2019-03-05 20:52:18 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 18:49:00 +00:00
|
|
|
type ButtonType int
|
|
|
|
|
|
|
|
const (
|
|
|
|
ButtonTypeContained ButtonType = iota
|
|
|
|
ButtonTypeIcon
|
|
|
|
ButtonTypeOutlined
|
|
|
|
ButtonTypeText
|
|
|
|
)
|
|
|
|
|
2020-05-15 12:44:55 +00:00
|
|
|
func BuildButton(text string, fn func(b *Button)) *Button { return BuildIconButton("", text, fn) }
|
2019-03-13 18:49:00 +00:00
|
|
|
|
2020-05-15 12:44:55 +00:00
|
|
|
func BuildIconButton(icon, text string, fn func(b *Button)) *Button {
|
2020-05-12 21:03:43 +00:00
|
|
|
var b = &Button{Text: text, Icon: icon}
|
2019-03-12 20:11:43 +00:00
|
|
|
if fn != nil {
|
|
|
|
fn(b)
|
|
|
|
}
|
2019-03-05 20:52:18 +00:00
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2019-03-13 18:49:00 +00:00
|
|
|
func (b *Button) desiredSize(ctx Context) geom.PointF32 {
|
2019-03-05 20:52:18 +00:00
|
|
|
var pad = ctx.Style().Dimensions.TextPadding
|
2020-05-15 13:42:24 +00:00
|
|
|
var font = ctx.Fonts().Font(b.FontName(ctx))
|
2019-03-13 18:49:00 +00:00
|
|
|
var w, h float32 = 0, font.Height()
|
|
|
|
if len(b.Text) != 0 {
|
2019-03-13 19:16:54 +00:00
|
|
|
w += pad + font.WidthOf(b.Text)
|
2019-03-13 18:49:00 +00:00
|
|
|
}
|
2020-05-15 12:44:55 +00:00
|
|
|
icon := b.icon(ctx)
|
|
|
|
if icon != nil && icon.Height() > 0 {
|
|
|
|
iconW := icon.Width() * h / icon.Height()
|
2019-03-13 19:16:54 +00:00
|
|
|
w += pad + iconW
|
2019-03-13 18:49:00 +00:00
|
|
|
}
|
|
|
|
if w == 0 {
|
|
|
|
return geom.ZeroPtF32
|
|
|
|
}
|
2019-03-13 19:16:54 +00:00
|
|
|
return geom.PtF32(w+pad, pad+h+pad)
|
2019-03-13 18:49:00 +00:00
|
|
|
}
|
|
|
|
|
2020-05-15 12:44:55 +00:00
|
|
|
func (b *Button) icon(ctx Context) Texture {
|
|
|
|
if b.Icon == "" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return ctx.Textures().Texture(b.Icon)
|
|
|
|
}
|
|
|
|
|
2020-05-16 11:46:07 +00:00
|
|
|
func (b *Button) ButtonClicked() ControlClickedEventHandler { return &b.clicked }
|
|
|
|
|
2020-05-16 13:37:53 +00:00
|
|
|
func (b *Button) DesiredSize(ctx Context, _ geom.PointF32) geom.PointF32 {
|
2019-03-13 18:49:00 +00:00
|
|
|
return b.desiredSize(ctx)
|
2019-03-05 20:52:18 +00:00
|
|
|
}
|
|
|
|
|
2020-05-15 17:00:43 +00:00
|
|
|
func (b *Button) Handle(ctx Context, e Event) bool {
|
2020-05-16 11:46:07 +00:00
|
|
|
result := b.ControlBase.HandleNotify(ctx, e, b)
|
2019-03-11 16:30:41 +00:00
|
|
|
if b.over {
|
2020-05-16 11:46:07 +00:00
|
|
|
if b.Disabled {
|
|
|
|
ctx.Renderer().SetMouseCursor(MouseCursorNotAllowed)
|
|
|
|
return true
|
|
|
|
}
|
2019-03-11 16:30:41 +00:00
|
|
|
ctx.Renderer().SetMouseCursor(MouseCursorPointer)
|
|
|
|
}
|
2020-05-15 17:00:43 +00:00
|
|
|
return result
|
2019-03-11 16:30:41 +00:00
|
|
|
}
|
|
|
|
|
2020-05-16 11:46:07 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2019-03-13 18:49:00 +00:00
|
|
|
func (b *Button) fillColor(p *Palette) color.Color {
|
2020-05-16 11:46:07 +00:00
|
|
|
if b.Disabled {
|
|
|
|
if b.Background != nil {
|
|
|
|
return p.Disabled
|
|
|
|
}
|
|
|
|
switch b.Type {
|
|
|
|
case ButtonTypeContained:
|
|
|
|
return p.Disabled
|
|
|
|
default:
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
2019-03-13 18:49:00 +00:00
|
|
|
if b.Background != nil {
|
2019-04-11 21:27:25 +00:00
|
|
|
if b.over && b.HoverColor != nil {
|
|
|
|
return b.HoverColor
|
|
|
|
}
|
2019-03-13 18:49:00 +00:00
|
|
|
return b.Background
|
2019-03-05 20:52:18 +00:00
|
|
|
}
|
|
|
|
if b.over {
|
2019-04-11 21:27:25 +00:00
|
|
|
if b.HoverColor != nil {
|
|
|
|
return b.HoverColor
|
|
|
|
}
|
2019-03-13 18:49:00 +00:00
|
|
|
switch b.Type {
|
|
|
|
case ButtonTypeContained:
|
2019-04-11 18:02:15 +00:00
|
|
|
return p.PrimaryLight
|
2019-03-13 18:49:00 +00:00
|
|
|
case ButtonTypeIcon:
|
|
|
|
default:
|
2019-04-11 18:02:15 +00:00
|
|
|
return p.PrimaryHighlight
|
2019-03-13 18:49:00 +00:00
|
|
|
}
|
2019-03-05 20:52:18 +00:00
|
|
|
}
|
2019-03-13 18:49:00 +00:00
|
|
|
switch b.Type {
|
|
|
|
case ButtonTypeContained:
|
|
|
|
return p.Primary
|
|
|
|
case ButtonTypeIcon:
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Button) textColor(p *Palette) color.Color {
|
2020-05-16 11:46:07 +00:00
|
|
|
if b.Disabled {
|
|
|
|
if b.Background != nil {
|
|
|
|
return p.TextOnDisabled
|
|
|
|
}
|
|
|
|
switch b.Type {
|
|
|
|
case ButtonTypeContained:
|
|
|
|
return p.TextOnDisabled
|
|
|
|
}
|
|
|
|
return p.Disabled
|
|
|
|
}
|
2019-03-13 18:49:00 +00:00
|
|
|
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
|
|
|
|
|
2019-03-05 20:52:18 +00:00
|
|
|
var pad = style.Dimensions.TextPadding
|
2019-03-13 18:49:00 +00:00
|
|
|
bounds = bounds.Inset(pad)
|
2020-05-15 07:20:44 +00:00
|
|
|
boundsH := bounds.Dy()
|
2019-03-13 18:49:00 +00:00
|
|
|
pos := bounds.Min
|
2020-05-15 12:44:55 +00:00
|
|
|
icon := b.icon(ctx)
|
|
|
|
if icon != nil && icon.Height() > 0 {
|
|
|
|
scaled, _ := ctx.Textures().ScaledHeight(icon, boundsH) // try to pre-scale scaled
|
|
|
|
if scaled == nil { // let the renderer scale
|
|
|
|
scaled = icon
|
2019-03-13 18:49:00 +00:00
|
|
|
}
|
2020-05-15 12:44:55 +00:00
|
|
|
scale, iconWidth := ScaleToHeight(SizeOfTexture(scaled), boundsH)
|
|
|
|
ctx.Renderer().DrawTextureOptions(scaled, geom.PtF32(pos.X, pos.Y), DrawOptions{Tint: textColor, Scale: scale})
|
2020-05-15 07:20:44 +00:00
|
|
|
pos.X += iconWidth + pad
|
2019-03-13 18:49:00 +00:00
|
|
|
}
|
|
|
|
if len(b.Text) != 0 {
|
2020-05-15 13:42:24 +00:00
|
|
|
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)
|
2019-03-13 18:49:00 +00:00
|
|
|
}
|
2019-04-11 21:27:25 +00:00
|
|
|
|
2019-03-13 18:49:00 +00:00
|
|
|
if b.Type == ButtonTypeOutlined {
|
2020-05-16 11:46:07 +00:00
|
|
|
b.RenderOutlineDefault(ctx, textColor)
|
2019-03-13 18:49:00 +00:00
|
|
|
}
|
2019-03-05 20:52:18 +00:00
|
|
|
}
|