tabbar.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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 "github.com/g3n/engine/math32"
  6. // TabBar is a panel which can contain other panels arranged in horizontal Tabs.
  7. // Only one panel is visible at a time.
  8. // To show another panel the corresponding Tab must be selected.
  9. type TabBar struct {
  10. Panel // Embedded panel
  11. styles *TabBarStyles // Pointer to current styles
  12. tabs []*Tab // Array of tabs
  13. selected int // Index of the selected tab
  14. cursorOver bool // Cursor over flag
  15. }
  16. // TabBarStyle describes the style of the TabBar
  17. type TabBarStyle struct {
  18. Border BorderSizes // Border sizes
  19. Paddings BorderSizes // Padding sizes
  20. BorderColor math32.Color4 // Border color
  21. BgColor math32.Color4 // Background color
  22. }
  23. // TabBarStyles describes all the TabBarStyles
  24. type TabBarStyles struct {
  25. Normal TabBarStyle // Style for normal exhibition
  26. Over TabBarStyle // Style when cursor is over the TabBar
  27. Focus TabBarStyle // Style when the TabBar has key focus
  28. Disabled TabBarStyle // Style when the TabBar is disabled
  29. Tab TabStyles // Style for Tabs
  30. }
  31. // TabStyle describes the style of the individual Tabs
  32. type TabStyle struct {
  33. Border BorderSizes
  34. Paddings BorderSizes
  35. BorderColor math32.Color4
  36. BgColor math32.Color4
  37. FgColor math32.Color
  38. }
  39. // TabStyles describes all Tab styles
  40. type TabStyles struct {
  41. MinWidth float32 // Minimum Tab header width
  42. Normal TabStyle // Style for normal exhibition
  43. Over TabStyle // Style when cursor is over the Tab
  44. Focus TabStyle // Style when the Tab has key focus
  45. Disabled TabStyle // Style when the Tab is disabled
  46. Selected TabStyle // Style when the Tab is selected
  47. }
  48. // NewTabBar creates and returns a pointer to a new TabBar widget
  49. // with the specified width and height
  50. func NewTabBar(width, height float32) *TabBar {
  51. // Creates new TabBar
  52. tb := new(TabBar)
  53. tb.Initialize(width, height)
  54. tb.styles = &StyleDefault().TabBar
  55. tb.tabs = make([]*Tab, 0)
  56. tb.selected = -1
  57. // Subscribe to panel events
  58. tb.Subscribe(OnCursorEnter, tb.onCursor)
  59. tb.Subscribe(OnCursorLeave, tb.onCursor)
  60. tb.Subscribe(OnEnable, func(name string, ev interface{}) { tb.update() })
  61. tb.Subscribe(OnResize, func(name string, ev interface{}) { tb.recalc() })
  62. tb.recalc()
  63. tb.update()
  64. return tb
  65. }
  66. // AddTab creates and adds a new Tab panel with the specified header text
  67. // at end of this TabBar list of tabs.
  68. // Returns the pointer to thew new Tab.
  69. func (tb *TabBar) AddTab(text string) *Tab {
  70. return tb.InsertTab(text, len(tb.tabs))
  71. }
  72. // InsertTab creates and inserts a new Tab panel with the specified header text
  73. // at the specified position in the TabBar from left to right.
  74. // Returns the pointer to the new Tab or nil if the position is invalid.
  75. func (tb *TabBar) InsertTab(text string, pos int) *Tab {
  76. // Checks position to insert into
  77. if pos < 0 || pos > len(tb.tabs) {
  78. return nil
  79. }
  80. // Inserts created Tab at the specified position
  81. tab := newTab(text, &tb.styles.Tab)
  82. tb.tabs = append(tb.tabs, nil)
  83. copy(tb.tabs[pos+1:], tb.tabs[pos:])
  84. tb.tabs[pos] = tab
  85. tb.Add(&tab.header)
  86. tb.Add(&tab.content)
  87. tb.update()
  88. tb.recalc()
  89. return tab
  90. }
  91. // RemoveTab removes the tab at the specified position in the TabBar.
  92. // Returns the pointer of the removed tab or nil if the position is invalid.
  93. func (tb *TabBar) RemoveTab(pos int) *Tab {
  94. // Check position to remove from
  95. if pos < 0 || pos >= len(tb.tabs) {
  96. return nil
  97. }
  98. // Remove tab from array
  99. tab := tb.tabs[pos]
  100. copy(tb.tabs[pos:], tb.tabs[pos+1:])
  101. tb.tabs[len(tb.tabs)-1] = nil
  102. tb.tabs = tb.tabs[:len(tb.tabs)-1]
  103. // Checks if removed tab was selected
  104. if tb.selected == pos {
  105. }
  106. return tab
  107. }
  108. // TabCount returns the current number of tabs
  109. func (tb *TabBar) TabCount() int {
  110. return len(tb.tabs)
  111. }
  112. // TabAt returns the pointer of the Tab object at the specified index.
  113. // Return nil if the index is invalid
  114. func (tb *TabBar) TabAt(idx int) *Tab {
  115. if idx < 0 || idx >= len(tb.tabs) {
  116. return nil
  117. }
  118. return tb.tabs[idx]
  119. }
  120. // SetSelected sets the selected tab of the TabBar to the tab with the specified position.
  121. // Returns the pointer of the selected tab or nil if the position is invalid.
  122. func (tb *TabBar) SetSelected(pos int) *Tab {
  123. if pos < 0 || pos >= len(tb.tabs) {
  124. return nil
  125. }
  126. tb.selected = pos
  127. return tb.tabs[pos]
  128. }
  129. // Selected returns the position of the selected Tab.
  130. // Returns value < 0 if there is no selected Tab.
  131. func (tb *TabBar) Selected() int {
  132. return tb.selected
  133. }
  134. // onCursor process subscribed cursor events
  135. func (tb *TabBar) onCursor(evname string, ev interface{}) {
  136. switch evname {
  137. case OnCursorEnter:
  138. tb.cursorOver = true
  139. tb.update()
  140. case OnCursorLeave:
  141. tb.cursorOver = false
  142. tb.update()
  143. default:
  144. return
  145. }
  146. tb.root.StopPropagation(StopAll)
  147. }
  148. // applyStyle applies the specified TabBar style
  149. func (tb *TabBar) applyStyle(s *TabBarStyle) {
  150. tb.SetBordersFrom(&s.Border)
  151. tb.SetBordersColor4(&s.BorderColor)
  152. tb.SetPaddingsFrom(&s.Paddings)
  153. tb.SetColor4(&s.BgColor)
  154. }
  155. // recalc recalculates and updates the positions of all tabs
  156. func (tb *TabBar) recalc() {
  157. maxWidth := tb.ContentWidth() / float32(len(tb.tabs))
  158. headerx := float32(0)
  159. for i := 0; i < len(tb.tabs); i++ {
  160. tab := tb.tabs[i]
  161. tab.recalc(maxWidth)
  162. tab.header.SetPosition(headerx, 0)
  163. // Sets size and position of the Tab content panel
  164. contentx := float32(0)
  165. contenty := tab.header.Height()
  166. tab.content.SetWidth(tb.ContentWidth())
  167. tab.content.SetHeight(tb.ContentHeight() - tab.header.Height())
  168. tab.content.SetPosition(contentx, contenty)
  169. headerx += tab.header.Width()
  170. }
  171. }
  172. // update updates the TabBar visual state
  173. func (tb *TabBar) update() {
  174. if !tb.Enabled() {
  175. tb.applyStyle(&tb.styles.Disabled)
  176. return
  177. }
  178. if tb.cursorOver {
  179. tb.applyStyle(&tb.styles.Over)
  180. return
  181. }
  182. tb.applyStyle(&tb.styles.Normal)
  183. }
  184. //
  185. // Tab
  186. //
  187. // Tab describes an individual tab of the TabBar
  188. type Tab struct {
  189. styles *TabStyles // Pointer to Tab current styles
  190. header Panel // Tab header
  191. label *Label // Tab label
  192. icon *Label // Tab optional icon
  193. img *Image // Tab optional image
  194. content Panel // User content panel
  195. cursorOver bool
  196. }
  197. // newTab creates and returns a pointer to a new Tab
  198. func newTab(text string, styles *TabStyles) *Tab {
  199. tab := new(Tab)
  200. tab.styles = styles
  201. tab.header.Initialize(0, 0)
  202. tab.label = NewLabel(text)
  203. tab.header.Add(tab.label)
  204. tab.content.Initialize(0, 0)
  205. // Subscribe to header events
  206. tab.header.Subscribe(OnCursorEnter, tab.onCursor)
  207. tab.header.Subscribe(OnCursorLeave, tab.onCursor)
  208. tab.update()
  209. return tab
  210. }
  211. // onCursor process subscribed cursor events
  212. func (tab *Tab) onCursor(evname string, ev interface{}) {
  213. switch evname {
  214. case OnCursorEnter:
  215. tab.cursorOver = true
  216. tab.update()
  217. case OnCursorLeave:
  218. tab.cursorOver = false
  219. tab.update()
  220. default:
  221. return
  222. }
  223. tab.header.root.StopPropagation(StopAll)
  224. }
  225. // SetText sets the text of the tab header
  226. func (tab *Tab) SetText(text string) *Tab {
  227. return tab
  228. }
  229. // SetIcon sets the icon of the tab header
  230. func (tab *Tab) SetIcon(icon string) *Tab {
  231. return tab
  232. }
  233. // Content returns a pointer to the specified Tab content panel
  234. func (tab *Tab) Content() *Panel {
  235. return &tab.content
  236. }
  237. // applyStyle applies the specified Tab style to the Tab header
  238. func (tab *Tab) applyStyle(s *TabStyle) {
  239. tab.header.SetBordersFrom(&s.Border)
  240. tab.header.SetBordersColor4(&s.BorderColor)
  241. tab.header.SetPaddingsFrom(&s.Paddings)
  242. tab.header.SetColor4(&s.BgColor)
  243. }
  244. func (tab *Tab) update() {
  245. if !tab.header.Enabled() {
  246. tab.applyStyle(&tab.styles.Disabled)
  247. return
  248. }
  249. if tab.cursorOver {
  250. tab.applyStyle(&tab.styles.Over)
  251. return
  252. }
  253. tab.applyStyle(&tab.styles.Normal)
  254. }
  255. // recalc recalculates the size of the Tab header and the size
  256. // and positions of the Taheader internal panels
  257. func (tab *Tab) recalc(maxWidth float32) {
  258. height := tab.label.Height()
  259. //iconWidth := float32(0)
  260. //if tab.icon != nil {
  261. // tab.icon.SetPosition(0, 0)
  262. // iconWidth = tab.icon.Width()
  263. //} else if tab.img != nil {
  264. // tab.img.SetPosition(0, 0)
  265. // iconWidth = tab.img.Width()
  266. //}
  267. width := tab.label.Width()
  268. tab.header.SetContentSize(width, height)
  269. }