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. return nil
  127. }
  128. // Dispose releases resources used by this widget
  129. func (b *ImageButton) Dispose() {
  130. b.Panel.Dispose()
  131. for _, tex := range b.stateImages {
  132. if tex != nil {
  133. tex.Dispose()
  134. }
  135. }
  136. }
  137. // SetStyles set the button styles overriding the default style
  138. func (b *ImageButton) SetStyles(bs *ImageButtonStyles) {
  139. b.styles = bs
  140. b.update()
  141. }
  142. // onCursor process subscribed cursor events
  143. func (b *ImageButton) onCursor(evname string, ev interface{}) {
  144. switch evname {
  145. case OnCursorEnter:
  146. b.mouseOver = true
  147. b.update()
  148. case OnCursorLeave:
  149. b.pressed = false
  150. b.mouseOver = false
  151. b.update()
  152. }
  153. b.root.StopPropagation(StopAll)
  154. }
  155. // onMouseEvent process subscribed mouse events
  156. func (b *ImageButton) onMouse(evname string, ev interface{}) {
  157. switch evname {
  158. case OnMouseDown:
  159. b.root.SetKeyFocus(b)
  160. b.pressed = true
  161. b.update()
  162. b.Dispatch(OnClick, nil)
  163. case OnMouseUp:
  164. b.pressed = false
  165. b.update()
  166. default:
  167. return
  168. }
  169. b.root.StopPropagation(StopAll)
  170. }
  171. // onKey processes subscribed key events
  172. func (b *ImageButton) onKey(evname string, ev interface{}) {
  173. kev := ev.(*window.KeyEvent)
  174. if evname == OnKeyDown && kev.Keycode == window.KeyEnter {
  175. b.pressed = true
  176. b.update()
  177. b.Dispatch(OnClick, nil)
  178. b.root.StopPropagation(Stop3D)
  179. return
  180. }
  181. if evname == OnKeyUp && kev.Keycode == window.KeyEnter {
  182. b.pressed = false
  183. b.update()
  184. b.root.StopPropagation(Stop3D)
  185. return
  186. }
  187. return
  188. }
  189. // update updates the button visual state
  190. func (b *ImageButton) update() {
  191. if !b.Enabled() {
  192. if b.stateImages[ButtonDisabled] != nil {
  193. b.image.SetTexture(b.stateImages[ButtonDisabled])
  194. }
  195. b.applyStyle(&b.styles.Disabled)
  196. return
  197. }
  198. if b.pressed {
  199. if b.stateImages[ButtonPressed] != nil {
  200. b.image.SetTexture(b.stateImages[ButtonPressed])
  201. }
  202. b.applyStyle(&b.styles.Pressed)
  203. return
  204. }
  205. if b.mouseOver {
  206. if b.stateImages[ButtonOver] != nil {
  207. b.image.SetTexture(b.stateImages[ButtonOver])
  208. }
  209. b.applyStyle(&b.styles.Over)
  210. return
  211. }
  212. b.image.SetTexture(b.stateImages[ButtonNormal])
  213. b.applyStyle(&b.styles.Normal)
  214. }
  215. // applyStyle applies the specified button style
  216. func (b *ImageButton) applyStyle(bs *ImageButtonStyle) {
  217. b.SetBordersColor4(&bs.BorderColor)
  218. b.SetBordersFrom(&bs.Border)
  219. b.SetPaddingsFrom(&bs.Paddings)
  220. b.SetColor4(&bs.BgColor)
  221. if b.label != nil {
  222. b.label.SetColor(&bs.FgColor)
  223. }
  224. }
  225. // recalc recalculates all dimensions and position from inside out
  226. func (b *ImageButton) recalc() {
  227. // Only need to recal if there's a label preset
  228. if b.label != nil {
  229. width := b.Panel.ContentWidth()
  230. height := b.Panel.ContentHeight()
  231. x := (width - b.label.Width()) / 2
  232. y := (height - b.label.Height()) / 2
  233. b.label.SetPosition(x, y)
  234. }
  235. }