Browse Source

gui menu dev

leonsal 8 years ago
parent
commit
17626c07eb
2 changed files with 127 additions and 25 deletions
  1. 123 21
      gui/menu.go
  2. 4 4
      gui/style.go

+ 123 - 21
gui/menu.go

@@ -10,15 +10,14 @@ import (
 	"github.com/g3n/engine/window"
 )
 
-type MenuBar struct {
-}
-
 type Menu struct {
-	Panel              // embedded panel
-	styles *MenuStyles // pointer to current styles
-	items  []*MenuItem // menu items
-	active bool        // menu active state
-	mitem  *MenuItem   // parent menu item for sub menu
+	Panel                // embedded panel
+	styles   *MenuStyles // pointer to current styles
+	bar      bool        // true for menu bar
+	items    []*MenuItem // menu items
+	active   bool        // menu active state
+	autoOpen bool        // open sub menus when mouse over if true
+	mitem    *MenuItem   // parent menu item for sub menu
 }
 
 // MenuBodyStyle describes the style of the menu body
@@ -48,7 +47,7 @@ type MenuStyles struct {
 type MenuItem struct {
 	Panel                          // embedded panel
 	styles      *MenuItemStyles    // pointer to current styles
-	menu        *Menu              // pointer to container menu
+	menu        *Menu              // pointer to parent menu
 	licon       *Label             // optional left icon label
 	label       *Label             // optional text label (nil for separators)
 	shortcut    *Label             // optional shorcut text label
@@ -144,6 +143,13 @@ var mapKeyText = map[window.Key]string{
 	window.KeyF12:        "F12",
 }
 
+func NewMenuBar() *Menu {
+
+	m := NewMenu()
+	m.bar = true
+	return m
+}
+
 // NewMenu creates and returns a pointer to a new empty menu
 func NewMenu() *Menu {
 
@@ -154,6 +160,7 @@ func NewMenu() *Menu {
 	m.Panel.Subscribe(OnCursorEnter, m.onCursor)
 	m.Panel.Subscribe(OnCursorLeave, m.onCursor)
 	m.Panel.Subscribe(OnKeyDown, m.onKey)
+	m.Panel.Subscribe(OnMouseOut, m.onMouse)
 	m.update()
 	return m
 }
@@ -193,6 +200,7 @@ func (m *Menu) AddMenu(text string, subm *Menu) *MenuItem {
 	mi.submenu.SetVisible(false)
 	mi.submenu.SetBounded(false)
 	mi.submenu.mitem = mi
+	mi.submenu.autoOpen = true
 	mi.menu = m
 	mi.ricon = NewIconLabel(string(assets.ChevronRight))
 	mi.Panel.Add(mi.ricon)
@@ -210,7 +218,6 @@ func (m *Menu) RemoveItem(mi *MenuItem) {
 // onCursor process subscribed cursor events
 func (m *Menu) onCursor(evname string, ev interface{}) {
 
-	//log.Error("evname:%s / %v", evname, ev)
 	if evname == OnCursorEnter {
 		m.root.SetKeyFocus(m)
 		m.active = true
@@ -218,9 +225,9 @@ func (m *Menu) onCursor(evname string, ev interface{}) {
 		m.active = false
 		// If this is a sub menu and the parent menu item is not selected
 		// hides this sub menu
-		if m.mitem != nil && !m.mitem.selected {
-			m.SetVisible(false)
-		}
+		//if m.mitem != nil && !m.mitem.selected {
+		//	m.SetVisible(false)
+		//}
 	}
 	m.root.StopPropagation(StopAll)
 }
@@ -262,6 +269,17 @@ func (m *Menu) onKey(evname string, ev interface{}) {
 	}
 }
 
+// onMouse process subscribed mouse events for the menu
+func (m *Menu) onMouse(evname string, ev interface{}) {
+
+	if evname == OnMouseOut {
+		if m.bar {
+			m.autoOpen = false
+			m.setSelectedPos(-1)
+		}
+	}
+}
+
 // setSelectedPos sets the menu item at the specified position as selected
 // and all others as not selected.
 func (m *Menu) setSelectedPos(pos int) {
@@ -364,6 +382,11 @@ func (m *Menu) applyStyle(mbs *MenuBodyStyle) {
 // and the content width and height of the menu
 func (m *Menu) recalc() {
 
+	if m.bar {
+		m.recalcBar()
+		return
+	}
+
 	// Find the maximum icon and label widths
 	minWidth := float32(0)
 	iconWidth := float32(0)
@@ -411,6 +434,30 @@ func (m *Menu) recalc() {
 	m.SetContentSize(width, py)
 }
 
+// recalcBar recalculates the positions of this MenuBar internal items
+// and the content width and height of the menu
+func (m *Menu) recalcBar() {
+
+	height := float32(0)
+	for i := 0; i < len(m.items); i++ {
+		mi := m.items[i]
+		if mi.minHeight() > height {
+			height = mi.minHeight()
+		}
+	}
+
+	px := float32(0)
+	for i := 0; i < len(m.items); i++ {
+		mi := m.items[i]
+		mi.SetPosition(px, 0)
+		width := float32(0)
+		width = mi.minWidth()
+		mi.SetSize(width, height)
+		px += mi.Width()
+	}
+	m.SetContentSize(px, height)
+}
+
 // newMenuItem creates and returns a pointer to a new menu item
 // with the specified text.
 func newMenuItem(text string, styles *MenuItemStyles) *MenuItem {
@@ -423,6 +470,8 @@ func newMenuItem(text string, styles *MenuItemStyles) *MenuItem {
 		mi.Panel.Add(mi.label)
 		mi.Panel.Subscribe(OnCursorEnter, mi.onCursor)
 		mi.Panel.Subscribe(OnCursorLeave, mi.onCursor)
+		mi.Panel.Subscribe(OnMouseUp, mi.onMouse)
+		mi.Panel.Subscribe(OnMouseDown, mi.onMouse)
 	}
 	mi.update()
 	return mi
@@ -440,14 +489,19 @@ func (mi *MenuItem) SetIcon(icode int) *MenuItem {
 
 // SetImage sets the left image of this menu item
 // If an icon was previously set it is replaced by this image
-func (mi *MenuItem) SetImage(img *Image) *MenuItem {
+func (mi *MenuItem) SetImage(img *Image) {
 
-	return mi
 }
 
 // SetText sets the text of this menu item
 func (mi *MenuItem) SetText(text string) *MenuItem {
 
+	if mi.label == nil {
+		return mi
+	}
+	mi.label.SetText(text)
+	mi.update()
+	mi.menu.recalc()
 	return mi
 }
 
@@ -501,16 +555,47 @@ func (mi *MenuItem) SetEnabled(enabled bool) *MenuItem {
 	return mi
 }
 
+// onCursor processes subscribed cursor events over the menu item
 func (mi *MenuItem) onCursor(evname string, ev interface{}) {
 
 	switch evname {
 	case OnCursorEnter:
 		mi.menu.setSelectedItem(mi)
 	case OnCursorLeave:
-		if mi.submenu != nil && mi.submenu.active {
-			return
+		//if mi.submenu != nil && mi.submenu.active {
+		//	return
+		//}
+		//mi.menu.setSelectedItem(nil)
+	}
+}
+
+// onMouse processes subscribed mouse events over the menu item
+func (mi *MenuItem) onMouse(evname string, ev interface{}) {
+
+	switch evname {
+	case OnMouseDown:
+		// MenuBar option
+		if mi.menu.bar {
+			mi.menu.autoOpen = !mi.menu.autoOpen
+			if mi.submenu != nil && mi.submenu.Visible() {
+				mi.submenu.SetVisible(false)
+				return
+			}
+			mi.update()
+			//if mi.submenu != nil {
+			//	if !mi.submenu.Visible() {
+			//		mi.submenu.SetVisible(true)
+			//		mi.submenu.SetPosition(0, mi.Height()-2)
+			//	} else {
+			//		mi.submenu.SetVisible(false)
+			//	}
+			//} else {
+			//	// Dispatch on click
+			//}
+		} else {
+
 		}
-		mi.menu.setSelectedItem(nil)
+	case OnMouseUp:
 	}
 }
 
@@ -522,22 +607,28 @@ func (mi *MenuItem) update() {
 		mi.applyStyle(&mi.styles.Separator)
 		return
 	}
+	// Disabled item
 	if mi.disabled {
 		mi.applyStyle(&mi.styles.Disabled)
 		return
 	}
+	// Selected item
 	if mi.selected {
 		mi.applyStyle(&mi.styles.Over)
-		if mi.submenu != nil {
+		if mi.submenu != nil && mi.menu.autoOpen {
 			mi.menu.SetTopChild(mi)
 			mi.submenu.SetVisible(true)
-			mi.submenu.SetPosition(mi.Width()-4, 0)
+			if mi.menu != nil && mi.menu.bar {
+				mi.submenu.SetPosition(0, mi.Height()-2)
+			} else {
+				mi.submenu.SetPosition(mi.Width()-2, 0)
+			}
 		}
 		return
 	}
 	// If this menu item has a sub menu and the sub menu is not active,
 	// hides the sub menu
-	if mi.submenu != nil && !mi.submenu.active {
+	if mi.submenu != nil {
 		mi.submenu.SetVisible(false)
 	}
 	mi.applyStyle(&mi.styles.Normal)
@@ -594,3 +685,14 @@ func (mi *MenuItem) minHeight() float32 {
 	mh += mi.label.height
 	return mh
 }
+
+// minWidth returns the minimum width of this menu item
+func (mi *MenuItem) minWidth() float32 {
+
+	mw := mi.MinWidth()
+	if mi.label == nil {
+		return mw + 1
+	}
+	mw += mi.label.width
+	return mw
+}

+ 4 - 4
gui/style.go

@@ -705,7 +705,7 @@ func setupDefaultStyle() {
 		Item: &MenuItemStyles{
 			Normal: MenuItemStyle{
 				Border:           BorderSizes{0, 0, 0, 0},
-				Paddings:         BorderSizes{2, 2, 2, 2},
+				Paddings:         BorderSizes{2, 4, 2, 2},
 				BorderColor:      borderColor,
 				BgColor:          bgColor,
 				FgColor:          fgColor,
@@ -715,7 +715,7 @@ func setupDefaultStyle() {
 			},
 			Over: MenuItemStyle{
 				Border:           BorderSizes{0, 0, 0, 0},
-				Paddings:         BorderSizes{2, 2, 2, 2},
+				Paddings:         BorderSizes{2, 4, 2, 2},
 				BorderColor:      borderColor,
 				BgColor:          math32.Color{0.6, 0.6, 0.6},
 				FgColor:          fgColor,
@@ -725,7 +725,7 @@ func setupDefaultStyle() {
 			},
 			Disabled: MenuItemStyle{
 				Border:           BorderSizes{0, 0, 0, 0},
-				Paddings:         BorderSizes{2, 2, 2, 2},
+				Paddings:         BorderSizes{2, 4, 2, 2},
 				BorderColor:      borderColor,
 				BgColor:          bgColor,
 				FgColor:          fgColorDis,
@@ -734,7 +734,7 @@ func setupDefaultStyle() {
 				RiconPaddings:    BorderSizes{2, 0, 0, 4},
 			},
 			Separator: MenuItemStyle{
-				Border:      BorderSizes{2, 0, 2, 0},
+				Border:      BorderSizes{2, 2, 2, 2},
 				Paddings:    BorderSizes{0, 0, 0, 0},
 				BorderColor: math32.Color4{0, 0, 0, 0},
 				BgColor:     math32.Color{0.6, 0.6, 0.6},