image_button.go 6.1 KB

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