04fbec5120
In GTK+ radio menu items are managed automatically, so group id won't have any effect there, in the meanwhile we need to maintain the same behavior on all platforms, so we have to generate group id instead of letting users specifying it.
111 lines
3.5 KiB
CoffeeScript
111 lines
3.5 KiB
CoffeeScript
BrowserWindow = require 'browser-window'
|
|
EventEmitter = require('events').EventEmitter
|
|
MenuItem = require 'menu-item'
|
|
|
|
bindings = process.atomBinding 'menu'
|
|
|
|
# Automatically generated radio menu item's group id.
|
|
nextGroupId = 0
|
|
|
|
# Search between seperators to find a radio menu item and return its group id,
|
|
# otherwise generate a group id.
|
|
generateGroupId = (items, pos) ->
|
|
if pos > 0
|
|
for i in [pos - 1..0]
|
|
item = items[i]
|
|
return item.groupId if item.type is 'radio'
|
|
break if item.type is 'separator'
|
|
else if pos < items.length
|
|
for i in [pos..items.length - 1]
|
|
item = items[i]
|
|
return item.groupId if item.type is 'radio'
|
|
break if item.type is 'separator'
|
|
++nextGroupId
|
|
|
|
Menu = bindings.Menu
|
|
Menu::__proto__ = EventEmitter.prototype
|
|
|
|
popup = Menu::popup
|
|
Menu::popup = (window) ->
|
|
throw new TypeError('Invalid window') unless window?.constructor is BrowserWindow
|
|
|
|
popup.call this, window
|
|
|
|
Menu::append = (item) ->
|
|
@insert @getItemCount(), item
|
|
|
|
Menu::insert = (pos, item) ->
|
|
throw new TypeError('Invalid item') unless item?.constructor is MenuItem
|
|
|
|
# Create delegate.
|
|
unless @delegate?
|
|
@commandsMap = {}
|
|
@groupsMap = {}
|
|
@items = []
|
|
@delegate =
|
|
isCommandIdChecked: (commandId) => @commandsMap[commandId]?.checked
|
|
isCommandIdEnabled: (commandId) => @commandsMap[commandId]?.enabled
|
|
isCommandIdVisible: (commandId) => @commandsMap[commandId]?.visible
|
|
getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator
|
|
executeCommand: (commandId) =>
|
|
activeItem = @commandsMap[commandId]
|
|
# Manually flip the checked flags when clicked.
|
|
if activeItem?
|
|
switch activeItem.type
|
|
when 'checkbox'
|
|
activeItem.checked = !activeItem.checked
|
|
when 'radio'
|
|
for item in @groupsMap[activeItem.groupId]
|
|
item.checked = false
|
|
activeItem.checked = true
|
|
activeItem.click()
|
|
|
|
switch item.type
|
|
when 'normal' then @insertItem pos, item.commandId, item.label
|
|
when 'checkbox' then @insertCheckItem pos, item.commandId, item.label
|
|
when 'separator' then @insertSeparator pos
|
|
when 'submenu' then @insertSubMenu pos, item.commandId, item.label, item.submenu
|
|
when 'radio'
|
|
# Grouping radio menu items.
|
|
item.groupId = generateGroupId(@items, pos)
|
|
@groupsMap[item.groupId] ?= []
|
|
@groupsMap[item.groupId].push item
|
|
@insertRadioItem pos, item.commandId, item.label, item.groupId
|
|
|
|
@setSublabel pos, item.sublabel if item.sublabel?
|
|
|
|
# Remember the items.
|
|
@items.splice pos, 0, item
|
|
@commandsMap[item.commandId] = item
|
|
|
|
applicationMenu = null
|
|
Menu.setApplicationMenu = (menu) ->
|
|
throw new TypeError('Invalid menu') unless menu?.constructor is Menu
|
|
applicationMenu = menu # Keep a reference.
|
|
|
|
if process.platform is 'darwin'
|
|
bindings.setApplicationMenu menu
|
|
else
|
|
windows = BrowserWindow.getAllWindows()
|
|
w.setMenu menu for w in windows
|
|
|
|
Menu.getApplicationMenu = -> applicationMenu
|
|
|
|
Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder
|
|
|
|
Menu.buildFromTemplate = (template) ->
|
|
throw new TypeError('Invalid template for Menu') unless Array.isArray template
|
|
|
|
menu = new Menu
|
|
for item in template
|
|
throw new TypeError('Invalid template for MenuItem') unless typeof item is 'object'
|
|
|
|
item.submenu = Menu.buildFromTemplate item.submenu if item.submenu?
|
|
menuItem = new MenuItem(item)
|
|
menuItem[key] = value for key, value of item when not menuItem[key]?
|
|
|
|
menu.append menuItem
|
|
|
|
menu
|
|
|
|
module.exports = Menu
|