package cview import "sync" // ContextMenu is a menu that appears upon user interaction, such as right // clicking or pressing Alt+Enter. type ContextMenu struct { parent Primitive item int open bool drag bool list *List x, y int selected func(int, string, rune) l sync.Mutex } // NewContextMenu returns a new context menu. func NewContextMenu(parent Primitive) *ContextMenu { return &ContextMenu{ parent: parent, } } func (c *ContextMenu) initializeList() { if c.list != nil { return } c.list = NewList(). ShowSecondaryText(false). SetHover(true). SetWrapAround(true) c.list. ShowFocus(false). SetBorder(true). SetBorderPadding( Styles.ContextMenuPaddingTop, Styles.ContextMenuPaddingBottom, Styles.ContextMenuPaddingLeft, Styles.ContextMenuPaddingRight) } // ContextMenuList returns the underlying List of the context menu. func (c *ContextMenu) ContextMenuList() *List { c.l.Lock() defer c.l.Unlock() c.initializeList() return c.list } // AddContextItem adds an item to the context menu. Adding an item with no text // or shortcut will add a divider. func (c *ContextMenu) AddContextItem(text string, shortcut rune, selected func(index int)) *ContextMenu { c.l.Lock() defer c.l.Unlock() c.initializeList() c.list.AddItem(NewListItem(text).SetShortcut(shortcut).SetSelectedFunc(c.wrap(selected))) if text == "" && shortcut == 0 { c.list.Lock() index := len(c.list.items) - 1 c.list.items[index].enabled = false c.list.Unlock() } return c } func (c *ContextMenu) wrap(f func(index int)) func() { return func() { f(c.item) } } // ClearContextMenu removes all items from the context menu. func (c *ContextMenu) ClearContextMenu() *ContextMenu { c.l.Lock() defer c.l.Unlock() c.initializeList() c.list.Clear() return c } // SetContextSelectedFunc sets the function which is called when the user // selects a context menu item. The function receives the item's index in the // menu (starting with 0), its text and its shortcut rune. SetSelectedFunc must // be called before the context menu is shown. func (c *ContextMenu) SetContextSelectedFunc(handler func(index int, text string, shortcut rune)) *ContextMenu { c.l.Lock() defer c.l.Unlock() c.selected = handler return c } // ShowContextMenu shows the context menu. Provide -1 for both to position on // the selected item, or specify a position. func (c *ContextMenu) ShowContextMenu(item int, x int, y int, setFocus func(Primitive)) { c.l.Lock() defer c.l.Unlock() c.show(item, x, y, setFocus) } // HideContextMenu hides the context menu. func (c *ContextMenu) HideContextMenu(setFocus func(Primitive)) { c.l.Lock() defer c.l.Unlock() c.hide(setFocus) } // ContextMenuVisible returns whether or not the context menu is visible. func (c *ContextMenu) ContextMenuVisible() bool { c.l.Lock() defer c.l.Unlock() return c.open } func (c *ContextMenu) show(item int, x int, y int, setFocus func(Primitive)) { c.initializeList() if len(c.list.items) == 0 { return } c.open = true c.item = item c.x, c.y = x, y c.list.Lock() for i, item := range c.list.items { if item.enabled { c.list.currentItem = i break } } c.list.Unlock() c.list.SetSelectedFunc(func(index int, item *ListItem) { c.l.Lock() // A context item was selected. Close the menu. c.hide(setFocus) if c.selected != nil { c.l.Unlock() c.selected(index, item.mainText, item.shortcut) } else { c.l.Unlock() } }).SetDoneFunc(func() { c.hide(setFocus) }) setFocus(c.list) } func (c *ContextMenu) hide(setFocus func(Primitive)) { c.initializeList() c.open = false if c.list.HasFocus() { setFocus(c.parent) } }