image_button.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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. b.root.StopPropagation(StopAll)
  151. }
  152. // onMouseEvent process subscribed mouse events
  153. func (b *ImageButton) onMouse(evname string, ev interface{}) {
  154. switch evname {
  155. case OnMouseDown:
  156. b.root.SetKeyFocus(b)
  157. b.pressed = true
  158. b.update()
  159. b.Dispatch(OnClick, nil)
  160. case OnMouseUp:
  161. b.pressed = false
  162. b.update()
  163. default:
  164. return
  165. }
  166. b.root.StopPropagation(StopAll)
  167. }
  168. // onKey processes subscribed key events
  169. func (b *ImageButton) onKey(evname string, ev interface{}) {
  170. kev := ev.(*window.KeyEvent)
  171. if evname == OnKeyDown && kev.Keycode == window.KeyEnter {
  172. b.pressed = true
  173. b.update()
  174. b.Dispatch(OnClick, nil)
  175. b.root.StopPropagation(Stop3D)
  176. return
  177. }
  178. if evname == OnKeyUp && kev.Keycode == window.KeyEnter {
  179. b.pressed = false
  180. b.update()
  181. b.root.StopPropagation(Stop3D)
  182. return
  183. }
  184. return
  185. }
  186. // update updates the button visual state
  187. func (b *ImageButton) update() {
  188. if !b.Enabled() {
  189. if b.stateImages[ButtonDisabled] != nil {
  190. b.image.SetTexture(b.stateImages[ButtonDisabled])
  191. }
  192. b.applyStyle(&b.styles.Disabled)
  193. return
  194. }
  195. if b.pressed {
  196. if b.stateImages[ButtonPressed] != nil {
  197. b.image.SetTexture(b.stateImages[ButtonPressed])
  198. }
  199. b.applyStyle(&b.styles.Pressed)
  200. return
  201. }
  202. if b.mouseOver {
  203. if b.stateImages[ButtonOver] != nil {
  204. b.image.SetTexture(b.stateImages[ButtonOver])
  205. }
  206. b.applyStyle(&b.styles.Over)
  207. return
  208. }
  209. b.image.SetTexture(b.stateImages[ButtonNormal])
  210. b.applyStyle(&b.styles.Normal)
  211. }
  212. // applyStyle applies the specified button style
  213. func (b *ImageButton) applyStyle(bs *ImageButtonStyle) {
  214. b.Panel.ApplyStyle(&bs.PanelStyle)
  215. if b.label != nil {
  216. b.label.SetColor4(&bs.FgColor)
  217. }
  218. }
  219. // recalc recalculates all dimensions and position from inside out
  220. func (b *ImageButton) recalc() {
  221. // Only need to recal if there's a label preset
  222. if b.label != nil {
  223. width := b.Panel.ContentWidth()
  224. height := b.Panel.ContentHeight()
  225. x := (width - b.label.Width()) / 2
  226. y := (height - b.label.Height()) / 2
  227. b.label.SetPosition(x, y)
  228. }
  229. }