image_button.go 6.2 KB

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