...

Source file src/code.rocketnine.space/tslocum/cview/contextmenu.go

Documentation: code.rocketnine.space/tslocum/cview

     1  package cview
     2  
     3  import "sync"
     4  
     5  // ContextMenu is a menu that appears upon user interaction, such as right
     6  // clicking or pressing Alt+Enter.
     7  type ContextMenu struct {
     8  	parent   Primitive
     9  	item     int
    10  	open     bool
    11  	drag     bool
    12  	list     *List
    13  	x, y     int
    14  	selected func(int, string, rune)
    15  
    16  	l sync.RWMutex
    17  }
    18  
    19  // NewContextMenu returns a new context menu.
    20  func NewContextMenu(parent Primitive) *ContextMenu {
    21  	return &ContextMenu{
    22  		parent: parent,
    23  	}
    24  }
    25  
    26  func (c *ContextMenu) initializeList() {
    27  	if c.list != nil {
    28  		return
    29  	}
    30  
    31  	c.list = NewList()
    32  	c.list.ShowSecondaryText(false)
    33  	c.list.SetHover(true)
    34  	c.list.SetWrapAround(true)
    35  	c.list.ShowFocus(false)
    36  	c.list.SetBorder(true)
    37  	c.list.SetPadding(
    38  		Styles.ContextMenuPaddingTop,
    39  		Styles.ContextMenuPaddingBottom,
    40  		Styles.ContextMenuPaddingLeft,
    41  		Styles.ContextMenuPaddingRight)
    42  }
    43  
    44  // ContextMenuList returns the underlying List of the context menu.
    45  func (c *ContextMenu) ContextMenuList() *List {
    46  	c.l.Lock()
    47  	defer c.l.Unlock()
    48  
    49  	c.initializeList()
    50  
    51  	return c.list
    52  }
    53  
    54  // AddContextItem adds an item to the context menu. Adding an item with no text
    55  // or shortcut will add a divider.
    56  func (c *ContextMenu) AddContextItem(text string, shortcut rune, selected func(index int)) {
    57  	c.l.Lock()
    58  	defer c.l.Unlock()
    59  
    60  	c.initializeList()
    61  
    62  	item := NewListItem(text)
    63  	item.SetShortcut(shortcut)
    64  	item.SetSelectedFunc(c.wrap(selected))
    65  
    66  	c.list.AddItem(item)
    67  	if text == "" && shortcut == 0 {
    68  		c.list.Lock()
    69  		index := len(c.list.items) - 1
    70  		c.list.items[index].disabled = true
    71  		c.list.Unlock()
    72  	}
    73  }
    74  
    75  func (c *ContextMenu) wrap(f func(index int)) func() {
    76  	return func() {
    77  		f(c.item)
    78  	}
    79  }
    80  
    81  // ClearContextMenu removes all items from the context menu.
    82  func (c *ContextMenu) ClearContextMenu() {
    83  	c.l.Lock()
    84  	defer c.l.Unlock()
    85  
    86  	c.initializeList()
    87  
    88  	c.list.Clear()
    89  }
    90  
    91  // SetContextSelectedFunc sets the function which is called when the user
    92  // selects a context menu item. The function receives the item's index in the
    93  // menu (starting with 0), its text and its shortcut rune. SetSelectedFunc must
    94  // be called before the context menu is shown.
    95  func (c *ContextMenu) SetContextSelectedFunc(handler func(index int, text string, shortcut rune)) {
    96  	c.l.Lock()
    97  	defer c.l.Unlock()
    98  
    99  	c.selected = handler
   100  }
   101  
   102  // ShowContextMenu shows the context menu. Provide -1 for both to position on
   103  // the selected item, or specify a 	position.
   104  func (c *ContextMenu) ShowContextMenu(item int, x int, y int, setFocus func(Primitive)) {
   105  	c.l.Lock()
   106  	defer c.l.Unlock()
   107  
   108  	c.show(item, x, y, setFocus)
   109  }
   110  
   111  // HideContextMenu hides the context menu.
   112  func (c *ContextMenu) HideContextMenu(setFocus func(Primitive)) {
   113  	c.l.Lock()
   114  	defer c.l.Unlock()
   115  
   116  	c.hide(setFocus)
   117  }
   118  
   119  // ContextMenuVisible returns whether or not the context menu is visible.
   120  func (c *ContextMenu) ContextMenuVisible() bool {
   121  	c.l.Lock()
   122  	defer c.l.Unlock()
   123  
   124  	return c.open
   125  }
   126  
   127  func (c *ContextMenu) show(item int, x int, y int, setFocus func(Primitive)) {
   128  	c.initializeList()
   129  
   130  	if len(c.list.items) == 0 {
   131  		return
   132  	}
   133  
   134  	c.open = true
   135  	c.item = item
   136  	c.x, c.y = x, y
   137  
   138  	c.list.Lock()
   139  	for i, item := range c.list.items {
   140  		if !item.disabled {
   141  			c.list.currentItem = i
   142  			break
   143  		}
   144  	}
   145  	c.list.Unlock()
   146  
   147  	c.list.SetSelectedFunc(func(index int, item *ListItem) {
   148  		c.l.Lock()
   149  
   150  		// A context item was selected. Close the menu.
   151  		c.hide(setFocus)
   152  
   153  		if c.selected != nil {
   154  			c.l.Unlock()
   155  			c.selected(index, string(item.mainText), item.shortcut)
   156  		} else {
   157  			c.l.Unlock()
   158  		}
   159  	})
   160  	c.list.SetDoneFunc(func() {
   161  		c.l.Lock()
   162  		defer c.l.Unlock()
   163  
   164  		c.hide(setFocus)
   165  	})
   166  
   167  	setFocus(c.list)
   168  }
   169  
   170  func (c *ContextMenu) hide(setFocus func(Primitive)) {
   171  	c.initializeList()
   172  
   173  	c.open = false
   174  
   175  	if c.list.HasFocus() {
   176  		setFocus(c.parent)
   177  	}
   178  }
   179  

View as plain text