2019-04-10 00:35:44 +00:00
|
|
|
package ui
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
|
2019-12-23 02:21:58 +00:00
|
|
|
"git.kirsle.net/go/render"
|
2020-06-18 01:04:18 +00:00
|
|
|
"git.kirsle.net/go/ui/style"
|
2019-04-10 00:35:44 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Button is a clickable button.
|
|
|
|
type Button struct {
|
|
|
|
BaseWidget
|
2021-07-26 03:53:09 +00:00
|
|
|
Name string
|
2019-04-10 00:35:44 +00:00
|
|
|
child Widget
|
2020-06-18 01:04:18 +00:00
|
|
|
style *style.Button
|
2019-04-10 00:35:44 +00:00
|
|
|
|
2021-07-26 03:53:09 +00:00
|
|
|
// Set this true to hard-set a color for this button;
|
|
|
|
// it will not adjust on mouse-over or press.
|
|
|
|
FixedColor bool
|
|
|
|
|
2019-04-10 00:35:44 +00:00
|
|
|
// Private options.
|
|
|
|
hovering bool
|
|
|
|
clicked bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewButton creates a new Button.
|
|
|
|
func NewButton(name string, child Widget) *Button {
|
|
|
|
w := &Button{
|
2021-07-26 03:53:09 +00:00
|
|
|
Name: name,
|
2019-04-10 00:35:44 +00:00
|
|
|
child: child,
|
2020-06-18 01:04:18 +00:00
|
|
|
style: &style.DefaultButton,
|
2019-04-10 00:35:44 +00:00
|
|
|
}
|
|
|
|
w.IDFunc(func() string {
|
2021-07-26 03:53:09 +00:00
|
|
|
return fmt.Sprintf("Button<%s>", w.Name)
|
2019-04-10 00:35:44 +00:00
|
|
|
})
|
|
|
|
|
2020-06-18 01:04:18 +00:00
|
|
|
w.SetStyle(Theme.Button)
|
2019-04-10 00:35:44 +00:00
|
|
|
|
2020-04-07 05:57:28 +00:00
|
|
|
w.Handle(MouseOver, func(e EventData) error {
|
2019-04-10 00:35:44 +00:00
|
|
|
w.hovering = true
|
2021-07-26 03:53:09 +00:00
|
|
|
if !w.FixedColor {
|
|
|
|
w.SetBackground(w.style.HoverBackground)
|
|
|
|
if label, ok := w.child.(*Label); ok {
|
|
|
|
label.Font.Color = w.style.HoverForeground
|
|
|
|
}
|
2020-06-18 01:04:18 +00:00
|
|
|
}
|
2020-04-07 05:57:28 +00:00
|
|
|
return nil
|
2019-04-10 00:35:44 +00:00
|
|
|
})
|
2020-04-07 05:57:28 +00:00
|
|
|
w.Handle(MouseOut, func(e EventData) error {
|
2019-04-10 00:35:44 +00:00
|
|
|
w.hovering = false
|
2021-07-26 03:53:09 +00:00
|
|
|
if !w.FixedColor {
|
|
|
|
w.SetBackground(w.style.Background)
|
|
|
|
if label, ok := w.child.(*Label); ok {
|
|
|
|
label.Font.Color = w.style.Foreground
|
|
|
|
}
|
2020-06-18 01:04:18 +00:00
|
|
|
}
|
2020-04-07 05:57:28 +00:00
|
|
|
return nil
|
2019-04-10 00:35:44 +00:00
|
|
|
})
|
|
|
|
|
2020-04-07 05:57:28 +00:00
|
|
|
w.Handle(MouseDown, func(e EventData) error {
|
2019-04-10 00:35:44 +00:00
|
|
|
w.clicked = true
|
|
|
|
w.SetBorderStyle(BorderSunken)
|
2020-04-07 05:57:28 +00:00
|
|
|
return nil
|
2019-04-10 00:35:44 +00:00
|
|
|
})
|
2020-04-07 05:57:28 +00:00
|
|
|
w.Handle(MouseUp, func(e EventData) error {
|
2019-04-10 00:35:44 +00:00
|
|
|
w.clicked = false
|
2020-06-18 01:04:18 +00:00
|
|
|
w.SetBorderStyle(BorderStyle(w.style.BorderStyle))
|
2020-04-07 05:57:28 +00:00
|
|
|
return nil
|
2019-04-10 00:35:44 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
return w
|
|
|
|
}
|
|
|
|
|
2020-06-18 01:04:18 +00:00
|
|
|
// SetStyle sets the button style.
|
|
|
|
func (w *Button) SetStyle(v *style.Button) {
|
|
|
|
if v == nil {
|
|
|
|
v = &style.DefaultButton
|
|
|
|
}
|
|
|
|
|
|
|
|
w.style = v
|
|
|
|
w.Configure(Config{
|
|
|
|
BorderSize: w.style.BorderSize,
|
|
|
|
BorderStyle: BorderStyle(w.style.BorderStyle),
|
|
|
|
OutlineSize: w.style.OutlineSize,
|
|
|
|
OutlineColor: w.style.OutlineColor,
|
|
|
|
Background: w.style.Background,
|
|
|
|
})
|
|
|
|
|
|
|
|
// If the child is a Label, apply the foreground color.
|
|
|
|
if label, ok := w.child.(*Label); ok {
|
|
|
|
label.Font.Color = w.style.Foreground
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-26 03:53:09 +00:00
|
|
|
// GetStyle gets the button style.
|
|
|
|
func (w *Button) GetStyle() *style.Button {
|
|
|
|
return w.style
|
|
|
|
}
|
|
|
|
|
2019-04-10 00:35:44 +00:00
|
|
|
// Children returns the button's child widget.
|
|
|
|
func (w *Button) Children() []Widget {
|
|
|
|
return []Widget{w.child}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute the size of the button.
|
|
|
|
func (w *Button) Compute(e render.Engine) {
|
|
|
|
// Compute the size of the inner widget first.
|
|
|
|
w.child.Compute(e)
|
|
|
|
|
|
|
|
// Auto-resize only if we haven't been given a fixed size.
|
|
|
|
if !w.FixedSize() {
|
|
|
|
size := w.child.Size()
|
|
|
|
w.Resize(render.Rect{
|
|
|
|
W: size.W + w.BoxThickness(2),
|
|
|
|
H: size.H + w.BoxThickness(2),
|
|
|
|
})
|
|
|
|
}
|
2020-03-10 00:13:33 +00:00
|
|
|
|
|
|
|
w.BaseWidget.Compute(e)
|
2019-04-10 00:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetText conveniently sets the button text, for Label children only.
|
|
|
|
func (w *Button) SetText(text string) error {
|
|
|
|
if label, ok := w.child.(*Label); ok {
|
|
|
|
label.Text = text
|
|
|
|
}
|
|
|
|
return errors.New("child is not a Label widget")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Present the button.
|
|
|
|
func (w *Button) Present(e render.Engine, P render.Point) {
|
|
|
|
if w.Hidden() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
w.Compute(e)
|
|
|
|
var (
|
|
|
|
S = w.Size()
|
|
|
|
ChildSize = w.child.Size()
|
|
|
|
)
|
|
|
|
|
|
|
|
// Draw the widget's border and everything.
|
|
|
|
w.DrawBox(e, P)
|
|
|
|
|
|
|
|
// Offset further if we are currently sunken.
|
2019-12-28 03:12:00 +00:00
|
|
|
var clickOffset int
|
2019-04-10 00:35:44 +00:00
|
|
|
if w.clicked {
|
|
|
|
clickOffset++
|
|
|
|
}
|
|
|
|
|
|
|
|
// Where to place the child widget.
|
|
|
|
moveTo := render.Point{
|
|
|
|
X: P.X + w.BoxThickness(1) + clickOffset,
|
|
|
|
Y: P.Y + w.BoxThickness(1) + clickOffset,
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we're bigger than we need to be, center the child widget.
|
|
|
|
if S.Bigger(ChildSize) {
|
|
|
|
moveTo.X = P.X + (S.W / 2) - (ChildSize.W / 2)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw the text label inside.
|
|
|
|
w.child.Present(e, moveTo)
|
2020-03-10 00:13:33 +00:00
|
|
|
|
|
|
|
w.BaseWidget.Present(e, P)
|
2019-04-10 00:35:44 +00:00
|
|
|
}
|