checkradio.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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/gui/assets"
  7. "github.com/g3n/engine/math32"
  8. "github.com/g3n/engine/window"
  9. )
  10. const (
  11. checkON = string(assets.CheckBox)
  12. checkOFF = string(assets.CheckBoxOutlineBlank)
  13. radioON = string(assets.RadioButtonChecked)
  14. radioOFF = string(assets.RadioButtonUnchecked)
  15. )
  16. type CheckRadio struct {
  17. Panel // Embedded panel
  18. Label *Label // Text label
  19. icon *Label
  20. styles *CheckRadioStyles
  21. check bool
  22. group string
  23. cursorOver bool
  24. state bool
  25. codeON string
  26. codeOFF string
  27. }
  28. type CheckRadioStyle struct {
  29. Border BorderSizes
  30. Paddings BorderSizes
  31. BorderColor math32.Color4
  32. BgColor math32.Color4
  33. FgColor math32.Color
  34. }
  35. type CheckRadioStyles struct {
  36. Normal CheckRadioStyle
  37. Over CheckRadioStyle
  38. Focus CheckRadioStyle
  39. Disabled CheckRadioStyle
  40. }
  41. // NewCheckBox creates and returns a pointer to a new CheckBox widget
  42. // with the specified text
  43. func NewCheckBox(text string) *CheckRadio {
  44. return newCheckRadio(true, text)
  45. }
  46. // NewRadioButton creates and returns a pointer to a new RadioButton widget
  47. // with the specified text
  48. func NewRadioButton(text string) *CheckRadio {
  49. return newCheckRadio(false, text)
  50. }
  51. // newCheckRadio creates and returns a pointer to a new CheckRadio widget
  52. // with the specified type and text
  53. func newCheckRadio(check bool, text string) *CheckRadio {
  54. cb := new(CheckRadio)
  55. cb.styles = &StyleDefault.CheckRadio
  56. // Adapts to specified type: CheckBox or RadioButton
  57. cb.check = check
  58. cb.state = false
  59. if cb.check {
  60. cb.codeON = checkON
  61. cb.codeOFF = checkOFF
  62. } else {
  63. cb.codeON = radioON
  64. cb.codeOFF = radioOFF
  65. }
  66. // Initialize panel
  67. cb.Panel.Initialize(0, 0)
  68. // Subscribe to events
  69. cb.Panel.Subscribe(OnKeyDown, cb.onKey)
  70. cb.Panel.Subscribe(OnCursorEnter, cb.onCursor)
  71. cb.Panel.Subscribe(OnCursorLeave, cb.onCursor)
  72. cb.Panel.Subscribe(OnMouseDown, cb.onMouse)
  73. cb.Panel.Subscribe(OnEnable, func(evname string, ev interface{}) { cb.update() })
  74. // Creates label
  75. cb.Label = NewLabel(text)
  76. cb.Label.Subscribe(OnResize, func(evname string, ev interface{}) { cb.recalc() })
  77. cb.Panel.Add(cb.Label)
  78. // Creates icon label
  79. cb.icon = NewIconLabel(" ")
  80. cb.Panel.Add(cb.icon)
  81. cb.recalc()
  82. cb.update()
  83. return cb
  84. }
  85. // SetRoot overrides the IPanel.SetRoot method
  86. func (cb *CheckRadio) SetRoot(root *Root) {
  87. if cb.root == root || root == nil {
  88. return
  89. }
  90. cb.root = root
  91. // Subscribes once to this root panel OnRadioGroup events
  92. root.Subscribe(OnRadioGroup, func(name string, ev interface{}) {
  93. cb.onRadioGroup(ev.(*CheckRadio))
  94. })
  95. }
  96. // Value returns the current state of the checkbox
  97. func (cb *CheckRadio) Value() bool {
  98. return cb.state
  99. }
  100. // SetValue sets the current state of the checkbox
  101. func (cb *CheckRadio) SetValue(state bool) *CheckRadio {
  102. if state == cb.state {
  103. return cb
  104. }
  105. cb.state = state
  106. cb.update()
  107. cb.Dispatch(OnChange, nil)
  108. return cb
  109. }
  110. // Group returns the name of the radio group
  111. func (cb *CheckRadio) Group() string {
  112. return cb.group
  113. }
  114. // SetGroup sets the name of the radio group
  115. func (cb *CheckRadio) SetGroup(group string) {
  116. cb.group = group
  117. }
  118. // SetStyles set the button styles overriding the default style
  119. func (cb *CheckRadio) SetStyles(bs *CheckRadioStyles) {
  120. cb.styles = bs
  121. cb.update()
  122. }
  123. // toggleState toggles the current state of the checkbox/radiobutton
  124. func (cb *CheckRadio) toggleState() {
  125. if cb.check {
  126. cb.state = !cb.state
  127. } else {
  128. if len(cb.group) == 0 {
  129. cb.state = !cb.state
  130. } else {
  131. if cb.state {
  132. return
  133. }
  134. cb.state = !cb.state
  135. }
  136. }
  137. cb.update()
  138. cb.Dispatch(OnChange, nil)
  139. if !cb.check && len(cb.group) > 0 {
  140. cb.root.Dispatch(OnRadioGroup, cb)
  141. }
  142. }
  143. // onMouse process OnMouseDown events
  144. func (cb *CheckRadio) onMouse(evname string, ev interface{}) {
  145. cb.root.SetKeyFocus(cb)
  146. cb.root.StopPropagation(Stop3D)
  147. cb.toggleState()
  148. // Dispatch OnClick for left mouse button down
  149. if evname == OnMouseDown {
  150. mev := ev.(*window.MouseEvent)
  151. if mev.Button == window.MouseButtonLeft {
  152. cb.Dispatch(OnClick, nil)
  153. }
  154. }
  155. cb.root.StopPropagation(StopAll)
  156. }
  157. // onCursor process OnCursor* events
  158. func (cb *CheckRadio) onCursor(evname string, ev interface{}) {
  159. if evname == OnCursorEnter {
  160. cb.cursorOver = true
  161. } else {
  162. cb.cursorOver = false
  163. }
  164. cb.update()
  165. cb.root.StopPropagation(StopAll)
  166. }
  167. // onKey receives subscribed key events
  168. func (cb *CheckRadio) onKey(evname string, ev interface{}) {
  169. kev := ev.(*window.KeyEvent)
  170. if evname == OnKeyDown && kev.Keycode == window.KeyEnter {
  171. cb.toggleState()
  172. cb.update()
  173. cb.Dispatch(OnClick, nil)
  174. cb.root.StopPropagation(Stop3D)
  175. return
  176. }
  177. return
  178. }
  179. // onRadioGroup receives subscriber OnRadioGroup events
  180. func (cb *CheckRadio) onRadioGroup(other *CheckRadio) {
  181. // If event is for this button, ignore
  182. if cb == other {
  183. return
  184. }
  185. // If other radio group is not the group of this button, ignore
  186. if cb.group != other.group {
  187. return
  188. }
  189. // Toggle this button state
  190. cb.SetValue(!other.Value())
  191. }
  192. // update updates the visual appearance of the checkbox
  193. func (cb *CheckRadio) update() {
  194. if cb.state {
  195. cb.icon.SetText(cb.codeON)
  196. } else {
  197. cb.icon.SetText(cb.codeOFF)
  198. }
  199. if !cb.Enabled() {
  200. cb.applyStyle(&cb.styles.Disabled)
  201. return
  202. }
  203. if cb.cursorOver {
  204. cb.applyStyle(&cb.styles.Over)
  205. return
  206. }
  207. cb.applyStyle(&cb.styles.Normal)
  208. }
  209. // setStyle sets the specified checkradio style
  210. func (cb *CheckRadio) applyStyle(s *CheckRadioStyle) {
  211. cb.Panel.SetBordersColor4(&s.BorderColor)
  212. cb.Panel.SetBordersFrom(&s.Border)
  213. cb.Panel.SetPaddingsFrom(&s.Paddings)
  214. cb.Panel.SetColor4(&s.BgColor)
  215. cb.icon.SetColor(&s.FgColor)
  216. cb.Label.SetColor(&s.FgColor)
  217. }
  218. // recalc recalculates dimensions and position from inside out
  219. func (cb *CheckRadio) recalc() {
  220. // Sets icon position
  221. cb.icon.SetFontSize(cb.Label.FontSize() * 1.3)
  222. cb.icon.SetPosition(0, 0)
  223. // Label position
  224. spacing := float32(4)
  225. cb.Label.SetPosition(cb.icon.Width()+spacing, 0)
  226. // Content width
  227. width := cb.icon.Width() + spacing + cb.Label.Width()
  228. cb.SetContentSize(width, cb.Label.Height())
  229. }