image_button.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. // Copyright 2016 The G3N Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package gui
  5. import (
  6. "github.com/g3n/engine/texture"
  7. "github.com/g3n/engine/window"
  8. )
  9. // ImageButton represents an image button GUI element
  10. type ImageButton struct {
  11. *Panel // Embedded Panel
  12. label *Label // Label panel
  13. iconLabel bool // True if icon
  14. image *Image // pointer to button image (may be nil)
  15. styles *ImageButtonStyles // pointer to current button styles
  16. mouseOver bool // true if mouse is over button
  17. pressed bool // true if button is pressed
  18. stateImages [ButtonDisabled + 1]*texture.Texture2D // array of images for each button state
  19. }
  20. // ButtonState specifies a button state.
  21. type ButtonState int
  22. // The possible button states.
  23. const (
  24. ButtonNormal ButtonState = iota
  25. ButtonOver
  26. ButtonPressed
  27. ButtonDisabled
  28. // ButtonFocus
  29. )
  30. // ImageButtonStyle contains the styling of an ImageButton.
  31. type ImageButtonStyle BasicStyle
  32. // ImageButtonStyles contains one ImageButtonStyle for each possible ImageButton state.
  33. type ImageButtonStyles struct {
  34. Normal ImageButtonStyle
  35. Over ImageButtonStyle
  36. Focus ImageButtonStyle
  37. Pressed ImageButtonStyle
  38. Disabled ImageButtonStyle
  39. }
  40. // NewImageButton creates and returns a pointer to a new ImageButton widget
  41. // with the specified image.
  42. func NewImageButton(normalImgPath string) (*ImageButton, error) {
  43. b := new(ImageButton)
  44. b.styles = &StyleDefault().ImageButton
  45. tex, err := texture.NewTexture2DFromImage(normalImgPath)
  46. if err != nil {
  47. return nil, err
  48. }
  49. b.stateImages[ButtonNormal] = tex
  50. b.image = NewImageFromTex(tex)
  51. // Initializes the button panel
  52. b.Panel = NewPanel(0, 0)
  53. b.Panel.SetContentSize(b.image.Width(), b.image.Height())
  54. b.Panel.SetBorders(5, 5, 5, 5)
  55. b.Panel.Add(b.image)
  56. // Subscribe to panel events
  57. b.Panel.Subscribe(OnKeyDown, b.onKey)
  58. b.Panel.Subscribe(OnKeyUp, b.onKey)
  59. b.Panel.Subscribe(OnMouseUp, b.onMouse)
  60. b.Panel.Subscribe(OnMouseDown, b.onMouse)
  61. b.Panel.Subscribe(OnCursor, b.onCursor)
  62. b.Panel.Subscribe(OnCursorEnter, b.onCursor)
  63. b.Panel.Subscribe(OnCursorLeave, b.onCursor)
  64. b.Panel.Subscribe(OnEnable, func(name string, ev interface{}) { b.update() })
  65. b.Panel.Subscribe(OnResize, func(name string, ev interface{}) { b.recalc() })
  66. b.recalc()
  67. b.update()
  68. return b, nil
  69. }
  70. // SetText sets the text of the label
  71. func (b *ImageButton) SetText(text string) {
  72. if b.iconLabel && b.label != nil {
  73. b.Panel.Remove(b.label)
  74. b.label.Dispose()
  75. b.label = nil
  76. }
  77. b.iconLabel = false
  78. if b.label == nil {
  79. // Create label
  80. b.label = NewLabel(text)
  81. b.Panel.Add(b.label)
  82. } else {
  83. b.label.SetText(text)
  84. }
  85. b.recalc()
  86. }
  87. // SetIcon sets the icon
  88. func (b *ImageButton) SetIcon(icode string) {
  89. if b.iconLabel == false && b.label != nil {
  90. b.Panel.Remove(b.label)
  91. b.label.Dispose()
  92. b.label = nil
  93. }
  94. b.iconLabel = true
  95. if b.label == nil {
  96. // Create icon
  97. b.label = NewIcon(icode)
  98. b.Panel.Add(b.label)
  99. } else {
  100. b.label.SetText(icode)
  101. }
  102. b.recalc()
  103. }
  104. // SetFontSize sets the font size of the label/icon
  105. func (b *ImageButton) SetFontSize(size float64) {
  106. if b.label != nil {
  107. b.label.SetFontSize(size)
  108. b.recalc()
  109. }
  110. }
  111. // SetImage sets the button left image from the specified filename
  112. // If there is currently a selected icon, it is removed
  113. func (b *ImageButton) SetImage(state ButtonState, imgfile string) error {
  114. tex, err := texture.NewTexture2DFromImage(imgfile)
  115. if err != nil {
  116. return err
  117. }
  118. if b.stateImages[state] != nil {
  119. b.stateImages[state].Dispose()
  120. }
  121. b.stateImages[state] = tex
  122. b.update()
  123. return nil
  124. }
  125. // Dispose releases resources used by this widget
  126. func (b *ImageButton) Dispose() {
  127. b.Panel.Dispose()
  128. for _, tex := range b.stateImages {
  129. if tex != nil {
  130. tex.Dispose()
  131. }
  132. }
  133. }
  134. // SetStyles set the button styles overriding the default style
  135. func (b *ImageButton) SetStyles(bs *ImageButtonStyles) {
  136. b.styles = bs
  137. b.update()
  138. }
  139. // onCursor process subscribed cursor events
  140. func (b *ImageButton) onCursor(evname string, ev interface{}) {
  141. switch evname {
  142. case OnCursorEnter:
  143. b.mouseOver = true
  144. b.update()
  145. case OnCursorLeave:
  146. b.pressed = false
  147. b.mouseOver = false
  148. b.update()
  149. }
  150. }
  151. // onMouseEvent process subscribed mouse events
  152. func (b *ImageButton) onMouse(evname string, ev interface{}) {
  153. switch evname {
  154. case OnMouseDown:
  155. Manager().SetKeyFocus(b)
  156. b.pressed = true
  157. b.update()
  158. b.Dispatch(OnClick, nil)
  159. case OnMouseUp:
  160. b.pressed = false
  161. b.update()
  162. default:
  163. return
  164. }
  165. }
  166. // onKey processes subscribed key events
  167. func (b *ImageButton) onKey(evname string, ev interface{}) {
  168. kev := ev.(*window.KeyEvent)
  169. if evname == OnKeyDown && kev.Key == window.KeyEnter {
  170. b.pressed = true
  171. b.update()
  172. b.Dispatch(OnClick, nil)
  173. return
  174. }
  175. if evname == OnKeyUp && kev.Key == window.KeyEnter {
  176. b.pressed = false
  177. b.update()
  178. return
  179. }
  180. return
  181. }
  182. // update updates the button visual state
  183. func (b *ImageButton) update() {
  184. if !b.Enabled() {
  185. if b.stateImages[ButtonDisabled] != nil {
  186. b.image.SetTexture(b.stateImages[ButtonDisabled])
  187. }
  188. b.applyStyle(&b.styles.Disabled)
  189. return
  190. }
  191. if b.pressed {
  192. if b.stateImages[ButtonPressed] != nil {
  193. b.image.SetTexture(b.stateImages[ButtonPressed])
  194. }
  195. b.applyStyle(&b.styles.Pressed)
  196. return
  197. }
  198. if b.mouseOver {
  199. if b.stateImages[ButtonOver] != nil {
  200. b.image.SetTexture(b.stateImages[ButtonOver])
  201. }
  202. b.applyStyle(&b.styles.Over)
  203. return
  204. }
  205. b.image.SetTexture(b.stateImages[ButtonNormal])
  206. b.applyStyle(&b.styles.Normal)
  207. }
  208. // applyStyle applies the specified button style
  209. func (b *ImageButton) applyStyle(bs *ImageButtonStyle) {
  210. b.Panel.ApplyStyle(&bs.PanelStyle)
  211. if b.label != nil {
  212. b.label.SetColor4(&bs.FgColor)
  213. }
  214. }
  215. // recalc recalculates all dimensions and position from inside out
  216. func (b *ImageButton) recalc() {
  217. // Only need to recal if there's a label preset
  218. if b.label != nil {
  219. width := b.Panel.ContentWidth()
  220. height := b.Panel.ContentHeight()
  221. x := (width - b.label.Width()) / 2
  222. y := (height - b.label.Height()) / 2
  223. b.label.SetPosition(x, y)
  224. }
  225. }