image_button.go 6.3 KB

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