137 lines
3.0 KiB
Go
137 lines
3.0 KiB
Go
package shell
|
|
|
|
import (
|
|
"hash/fnv"
|
|
|
|
"aego/platform"
|
|
)
|
|
|
|
const appMenuTitle = "Aego Editor"
|
|
|
|
type nativeMenu struct {
|
|
bar platform.MenuBar
|
|
acts []func()
|
|
clicks []int
|
|
sum uint64
|
|
next float64
|
|
}
|
|
|
|
func (a *App) initNativeMenu() {
|
|
if a.eng.Config().Headless {
|
|
return
|
|
}
|
|
if mb, ok := a.eng.Window().(platform.MenuBar); ok {
|
|
a.native = &nativeMenu{bar: mb}
|
|
}
|
|
}
|
|
|
|
func flag(b bool) byte {
|
|
if b {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func hashMenus(menus []platform.Menu) uint64 {
|
|
h := fnv.New64a()
|
|
var walk func([]platform.MenuItem)
|
|
walk = func(items []platform.MenuItem) {
|
|
for _, it := range items {
|
|
h.Write([]byte(it.Label))
|
|
h.Write([]byte{0})
|
|
h.Write([]byte(it.Shortcut))
|
|
h.Write([]byte{flag(it.Enabled), flag(it.Checked), flag(it.Separator), byte(it.Role), 1})
|
|
walk(it.Items)
|
|
h.Write([]byte{2})
|
|
}
|
|
}
|
|
for _, m := range menus {
|
|
h.Write([]byte(m.Title))
|
|
h.Write([]byte{3})
|
|
walk(m.Items)
|
|
}
|
|
return h.Sum64()
|
|
}
|
|
|
|
func (a *App) buildNativeMenu() ([]platform.Menu, []func()) {
|
|
reg := a.ctx.Commands
|
|
var acts []func()
|
|
act := func(fn func()) int {
|
|
acts = append(acts, fn)
|
|
return len(acts) - 1
|
|
}
|
|
menus := []platform.Menu{{Title: appMenuTitle, Items: []platform.MenuItem{
|
|
{Role: platform.RoleHide, Label: "Hide " + appMenuTitle},
|
|
{Role: platform.RoleHideOthers, Label: "Hide Others"},
|
|
{Role: platform.RoleShowAll, Label: "Show All"},
|
|
{Separator: true},
|
|
{ID: act(func() { reg.Run(CommandQuit) }), Label: "Quit " + appMenuTitle, Shortcut: reg.Shortcut(CommandQuit), Enabled: true},
|
|
}}}
|
|
for _, cat := range a.menuCategories() {
|
|
if cat == "Create" {
|
|
continue
|
|
}
|
|
m := platform.Menu{Title: cat}
|
|
last := -1
|
|
for _, d := range reg.Category(cat) {
|
|
if last >= 0 && d.Order/100 != last/100 {
|
|
m.Items = append(m.Items, platform.MenuItem{Separator: true})
|
|
}
|
|
last = d.Order
|
|
label := d.Name
|
|
if d.Label != nil {
|
|
label = d.Label()
|
|
}
|
|
id := d.ID
|
|
m.Items = append(m.Items, platform.MenuItem{
|
|
ID: act(func() { reg.Run(id) }), Label: label, Shortcut: d.Shortcut.String(),
|
|
Enabled: reg.Enabled(d.ID), Checked: d.Checked != nil && d.Checked(),
|
|
})
|
|
}
|
|
if cat == "Scene" {
|
|
docs := a.ctx.Docs.Docs()
|
|
if len(docs) > 0 {
|
|
m.Items = append(m.Items, platform.MenuItem{Separator: true})
|
|
}
|
|
active := a.ctx.Docs.Edit()
|
|
for _, d := range docs {
|
|
name := d.Path
|
|
if d.Dirty() {
|
|
name += " *"
|
|
}
|
|
doc := d.ID
|
|
m.Items = append(m.Items, platform.MenuItem{
|
|
ID: act(func() { a.ctx.Docs.SetActive(doc) }), Label: name, Enabled: true,
|
|
Checked: active != nil && d.ID == active.ID,
|
|
})
|
|
}
|
|
}
|
|
if len(m.Items) > 0 {
|
|
menus = append(menus, m)
|
|
}
|
|
}
|
|
return menus, acts
|
|
}
|
|
|
|
func (a *App) syncNativeMenu(now float64) {
|
|
n := a.native
|
|
if n == nil {
|
|
return
|
|
}
|
|
n.clicks = n.bar.MenuClicks(n.clicks[:0])
|
|
for _, c := range n.clicks {
|
|
if c >= 0 && c < len(n.acts) {
|
|
n.acts[c]()
|
|
}
|
|
}
|
|
if n.sum != 0 && now < n.next {
|
|
return
|
|
}
|
|
n.next = now + 0.25
|
|
menus, acts := a.buildNativeMenu()
|
|
if s := hashMenus(menus); s != n.sum {
|
|
n.sum, n.acts = s, acts
|
|
n.bar.SetMenuBar(appMenuTitle, menus)
|
|
}
|
|
}
|