User interface toolkit for Go with support for SDL2 and HTML Canvas render targets.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

130 lines
2.5 KiB

  1. package ui
  2. import (
  3. "errors"
  4. "fmt"
  5. "git.kirsle.net/go/render"
  6. "git.kirsle.net/go/ui/theme"
  7. )
  8. // Button is a clickable button.
  9. type Button struct {
  10. BaseWidget
  11. child Widget
  12. // Private options.
  13. hovering bool
  14. clicked bool
  15. }
  16. // NewButton creates a new Button.
  17. func NewButton(name string, child Widget) *Button {
  18. w := &Button{
  19. child: child,
  20. }
  21. w.IDFunc(func() string {
  22. return fmt.Sprintf("Button<%s>", name)
  23. })
  24. w.Configure(Config{
  25. BorderSize: 2,
  26. BorderStyle: BorderRaised,
  27. OutlineSize: 1,
  28. OutlineColor: theme.ButtonOutlineColor,
  29. Background: theme.ButtonBackgroundColor,
  30. })
  31. w.Handle(MouseOver, func(e EventData) error {
  32. w.hovering = true
  33. w.SetBackground(theme.ButtonHoverColor)
  34. return nil
  35. })
  36. w.Handle(MouseOut, func(e EventData) error {
  37. w.hovering = false
  38. w.SetBackground(theme.ButtonBackgroundColor)
  39. return nil
  40. })
  41. w.Handle(MouseDown, func(e EventData) error {
  42. w.clicked = true
  43. w.SetBorderStyle(BorderSunken)
  44. return nil
  45. })
  46. w.Handle(MouseUp, func(e EventData) error {
  47. w.clicked = false
  48. w.SetBorderStyle(BorderRaised)
  49. return nil
  50. })
  51. return w
  52. }
  53. // Children returns the button's child widget.
  54. func (w *Button) Children() []Widget {
  55. return []Widget{w.child}
  56. }
  57. // Compute the size of the button.
  58. func (w *Button) Compute(e render.Engine) {
  59. // Compute the size of the inner widget first.
  60. w.child.Compute(e)
  61. // Auto-resize only if we haven't been given a fixed size.
  62. if !w.FixedSize() {
  63. size := w.child.Size()
  64. w.Resize(render.Rect{
  65. W: size.W + w.BoxThickness(2),
  66. H: size.H + w.BoxThickness(2),
  67. })
  68. }
  69. w.BaseWidget.Compute(e)
  70. }
  71. // SetText conveniently sets the button text, for Label children only.
  72. func (w *Button) SetText(text string) error {
  73. if label, ok := w.child.(*Label); ok {
  74. label.Text = text
  75. }
  76. return errors.New("child is not a Label widget")
  77. }
  78. // Present the button.
  79. func (w *Button) Present(e render.Engine, P render.Point) {
  80. if w.Hidden() {
  81. return
  82. }
  83. w.Compute(e)
  84. var (
  85. S = w.Size()
  86. ChildSize = w.child.Size()
  87. )
  88. // Draw the widget's border and everything.
  89. w.DrawBox(e, P)
  90. // Offset further if we are currently sunken.
  91. var clickOffset int
  92. if w.clicked {
  93. clickOffset++
  94. }
  95. // Where to place the child widget.
  96. moveTo := render.Point{
  97. X: P.X + w.BoxThickness(1) + clickOffset,
  98. Y: P.Y + w.BoxThickness(1) + clickOffset,
  99. }
  100. // If we're bigger than we need to be, center the child widget.
  101. if S.Bigger(ChildSize) {
  102. moveTo.X = P.X + (S.W / 2) - (ChildSize.W / 2)
  103. }
  104. // Draw the text label inside.
  105. w.child.Present(e, moveTo)
  106. w.BaseWidget.Present(e, P)
  107. }