menu.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  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. )
  8. type MenuBar struct {
  9. }
  10. type Menu struct {
  11. Panel // embedded panel
  12. styles *MenuStyles // pointer to current styles
  13. }
  14. // MenuBodyStyle describes the style of the menu body
  15. type MenuBodyStyle struct {
  16. Border BorderSizes
  17. Paddings BorderSizes
  18. BorderColor math32.Color4
  19. BgColor math32.Color
  20. FgColor math32.Color
  21. }
  22. // MenuBodyStyles describes all styles of the menu body
  23. type MenuBodyStyles struct {
  24. Normal MenuBodyStyle
  25. Over MenuBodyStyle
  26. Focus MenuBodyStyle
  27. Disabled MenuBodyStyle
  28. }
  29. // MenuStyles describes all styles of the menu body and menu item
  30. type MenuStyles struct {
  31. Body *MenuBodyStyles // Menu body styles
  32. Item *MenuItemStyles // Menu item styles
  33. }
  34. // MenuItem is an option of a Menu
  35. type MenuItem struct {
  36. Panel // embedded panel
  37. styles *MenuItemStyles // pointer to current styles
  38. label *Label // optional internal label (nil for separators)
  39. licon *Label // optional left internal icon label
  40. ricon *Label // optional right internal icon label for submenu
  41. icode int // icon code (if icon is set)
  42. subm *MenuItem // optional pointer to sub menu
  43. shorcut int32 // shortcut code
  44. enabled bool // enabled state
  45. mouseOver bool
  46. }
  47. // MenuItemStyle describes the style of a menu item
  48. type MenuItemStyle struct {
  49. Border BorderSizes
  50. Paddings BorderSizes
  51. BorderColor math32.Color4
  52. BgColor math32.Color
  53. FgColor math32.Color
  54. IconPaddings BorderSizes
  55. }
  56. // MenuItemStyles describes all the menu item styles
  57. type MenuItemStyles struct {
  58. Normal MenuItemStyle
  59. Over MenuItemStyle
  60. Disabled MenuItemStyle
  61. Separator MenuItemStyle
  62. }
  63. // NewMenu creates and returns a pointer to a new empty menu
  64. func NewMenu() *Menu {
  65. m := new(Menu)
  66. m.Panel.Initialize(0, 0)
  67. m.styles = &StyleDefault.Menu
  68. m.update()
  69. return m
  70. }
  71. // AddItem creates and adds a new menu item to this menu and returns the pointer
  72. // to the created item.
  73. func (m *Menu) AddItem(text string) *MenuItem {
  74. mi := newMenuItem(text, m.styles.Item)
  75. m.Panel.Add(mi)
  76. m.recalc()
  77. return mi
  78. }
  79. // AddSeparator creates and adds a new separator to the menu
  80. func (m *Menu) AddSeparator() *MenuItem {
  81. mi := newMenuItem("", m.styles.Item)
  82. m.Panel.Add(mi)
  83. m.recalc()
  84. return mi
  85. }
  86. // RemoveItem removes the specified menu item from this menu
  87. func (m *Menu) RemoveItem(mi *MenuItem) {
  88. }
  89. // update updates the menu visual state
  90. func (m *Menu) update() {
  91. //if s.cursorOver {
  92. // s.applyStyle(&s.styles.Over)
  93. // return
  94. //}
  95. //if s.focus {
  96. // s.applyStyle(&s.styles.Focus)
  97. // return
  98. //}
  99. m.applyStyle(&m.styles.Body.Normal)
  100. }
  101. // applyStyle applies the specified menu body style
  102. func (m *Menu) applyStyle(mbs *MenuBodyStyle) {
  103. m.SetBordersFrom(&mbs.Border)
  104. m.SetBordersColor4(&mbs.BorderColor)
  105. m.SetPaddingsFrom(&mbs.Paddings)
  106. m.SetColor(&mbs.BgColor)
  107. }
  108. // recalc recalculates the positions of this menu internal items
  109. // and the content width and height of the menu
  110. func (m *Menu) recalc() {
  111. // Find the maximum icon and label widths
  112. minWidth := float32(0)
  113. iconWidth := float32(0)
  114. labelWidth := float32(0)
  115. for i := 0; i < len(m.Children()); i++ {
  116. mi := m.Children()[i].(*MenuItem)
  117. minWidth = mi.MinWidth()
  118. // Separator
  119. if mi.label == nil {
  120. continue
  121. }
  122. // Left icon width
  123. if mi.licon != nil && mi.licon.width > iconWidth {
  124. iconWidth = mi.licon.width
  125. }
  126. // Label width
  127. if mi.label.width > labelWidth {
  128. labelWidth = mi.label.width
  129. }
  130. }
  131. width := minWidth + iconWidth + labelWidth
  132. // Sets the position and width of the menu items
  133. // The height is defined by the menu item itself
  134. px := float32(0)
  135. py := float32(0)
  136. for i := 0; i < len(m.Children()); i++ {
  137. mi := m.Children()[i].(*MenuItem)
  138. mi.SetPosition(px, py)
  139. mh := mi.minHeight()
  140. py += mh
  141. mi.SetSize(width, mh)
  142. mi.recalc(iconWidth)
  143. }
  144. m.SetContentSize(width, py)
  145. }
  146. // newMenuItem creates and returns a pointer to a new menu item
  147. // with the specified text.
  148. func newMenuItem(text string, styles *MenuItemStyles) *MenuItem {
  149. mi := new(MenuItem)
  150. mi.Panel.Initialize(0, 0)
  151. mi.styles = styles
  152. if text != "" {
  153. mi.label = NewLabel(text)
  154. //mi.label.SetBorders(1, 1, 1, 1)
  155. mi.Panel.Add(mi.label)
  156. mi.Panel.Subscribe(OnCursorEnter, mi.onCursor)
  157. mi.Panel.Subscribe(OnCursorLeave, mi.onCursor)
  158. }
  159. mi.update()
  160. return mi
  161. }
  162. // SetIcon sets the left icon of this menu item
  163. // If an image was previously set it is replaced by this icon
  164. func (mi *MenuItem) SetIcon(icode int) *MenuItem {
  165. mi.licon = NewIconLabel(string(icode))
  166. mi.Panel.Add(mi.licon)
  167. mi.update()
  168. return mi
  169. }
  170. // SetImage sets the left image of this menu item
  171. // If an icon was previously set it is replaced by this image
  172. func (mi *MenuItem) SetImage(img *Image) *MenuItem {
  173. return mi
  174. }
  175. // SetText sets the text of this menu item
  176. func (mi *MenuItem) SetText(text string) *MenuItem {
  177. return mi
  178. }
  179. // SetShortcut sets the keyboard shortcut of this menu item
  180. func (mi *MenuItem) SetShortcut(text string) *MenuItem {
  181. return mi
  182. }
  183. // SetSubmenu sets an associated sub menu item for this menu item
  184. func (mi *MenuItem) SetSubmenu(smi *MenuItem) *MenuItem {
  185. return mi
  186. }
  187. // SetEnabled sets the enabled state of this menu item
  188. func (mi *MenuItem) SetEnabled(enabled bool) *MenuItem {
  189. return mi
  190. }
  191. func (mi *MenuItem) onCursor(evname string, ev interface{}) {
  192. switch evname {
  193. case OnCursorEnter:
  194. mi.mouseOver = true
  195. mi.update()
  196. case OnCursorLeave:
  197. mi.mouseOver = false
  198. mi.update()
  199. }
  200. }
  201. // update updates the menu item visual state
  202. func (mi *MenuItem) update() {
  203. // Separator
  204. if mi.label == nil {
  205. mi.applyStyle(&mi.styles.Separator)
  206. return
  207. }
  208. if mi.mouseOver {
  209. mi.applyStyle(&mi.styles.Over)
  210. return
  211. }
  212. mi.applyStyle(&mi.styles.Normal)
  213. }
  214. // applyStyle applies the specified menu item style
  215. func (mi *MenuItem) applyStyle(mis *MenuItemStyle) {
  216. mi.SetBordersFrom(&mis.Border)
  217. mi.SetBordersColor4(&mis.BorderColor)
  218. mi.SetPaddingsFrom(&mis.Paddings)
  219. mi.SetColor(&mis.BgColor)
  220. if mi.licon != nil {
  221. mi.licon.SetPaddingsFrom(&mis.IconPaddings)
  222. }
  223. }
  224. // recalc recalculates the positions of this menu item internal panels
  225. func (mi *MenuItem) recalc(iconWidth float32) {
  226. // Separator
  227. if mi.label == nil {
  228. return
  229. }
  230. if mi.licon != nil {
  231. py := (mi.label.height - mi.licon.height) / 2
  232. mi.licon.SetPosition(0, py)
  233. }
  234. mi.label.SetPosition(iconWidth, 0)
  235. }
  236. // minHeight returns the minimum height of this menu item
  237. func (mi *MenuItem) minHeight() float32 {
  238. mh := mi.MinHeight()
  239. if mi.label == nil {
  240. return mh + 4
  241. }
  242. mh += mi.label.height
  243. return mh
  244. }