Generate menu group id automatically.

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.
This commit is contained in:
Cheng Zhao 2014-05-25 12:32:47 +08:00
parent 76d0d3ec19
commit 04fbec5120
3 changed files with 37 additions and 16 deletions

View file

@ -8,7 +8,7 @@ class MenuItem
constructor: (options) -> constructor: (options) ->
Menu = require 'menu' Menu = require 'menu'
{click, @selector, @type, @label, @sublabel, @accelerator, @enabled, @visible, @checked, @groupId, @submenu} = options {click, @selector, @type, @label, @sublabel, @accelerator, @enabled, @visible, @checked, @submenu} = options
@type = 'submenu' if not @type? and @submenu? @type = 'submenu' if not @type? and @submenu?
throw new Error('Invalid submenu') if @type is 'submenu' and @submenu?.constructor isnt Menu throw new Error('Invalid submenu') if @type is 'submenu' and @submenu?.constructor isnt Menu
@ -20,7 +20,6 @@ class MenuItem
@enabled = @enabled ? true @enabled = @enabled ? true
@visible = @visible ? true @visible = @visible ? true
@checked = @checked ? false @checked = @checked ? false
@groupId = @groupId ? null
@submenu = @submenu ? null @submenu = @submenu ? null
throw new Error('Unknown menu type') if MenuItem.types.indexOf(@type) is -1 throw new Error('Unknown menu type') if MenuItem.types.indexOf(@type) is -1

View file

@ -4,6 +4,24 @@ MenuItem = require 'menu-item'
bindings = process.atomBinding 'menu' 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 = bindings.Menu
Menu::__proto__ = EventEmitter.prototype Menu::__proto__ = EventEmitter.prototype
@ -19,15 +37,7 @@ Menu::append = (item) ->
Menu::insert = (pos, item) -> Menu::insert = (pos, item) ->
throw new TypeError('Invalid item') unless item?.constructor is MenuItem throw new TypeError('Invalid item') unless item?.constructor is MenuItem
switch item.type # Create delegate.
when 'normal' then @insertItem pos, item.commandId, item.label
when 'checkbox' then @insertCheckItem pos, item.commandId, item.label
when 'radio' then @insertRadioItem pos, item.commandId, item.label, item.groupId
when 'separator' then @insertSeparator pos
when 'submenu' then @insertSubMenu pos, item.commandId, item.label, item.submenu
@setSublabel pos, item.sublabel if item.sublabel?
unless @delegate? unless @delegate?
@commandsMap = {} @commandsMap = {}
@groupsMap = {} @groupsMap = {}
@ -39,6 +49,7 @@ Menu::insert = (pos, item) ->
getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator
executeCommand: (commandId) => executeCommand: (commandId) =>
activeItem = @commandsMap[commandId] activeItem = @commandsMap[commandId]
# Manually flip the checked flags when clicked.
if activeItem? if activeItem?
switch activeItem.type switch activeItem.type
when 'checkbox' when 'checkbox'
@ -48,13 +59,25 @@ Menu::insert = (pos, item) ->
item.checked = false item.checked = false
activeItem.checked = true activeItem.checked = true
activeItem.click() 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 @items.splice pos, 0, item
@commandsMap[item.commandId] = item @commandsMap[item.commandId] = item
if item.groupId?
@groupsMap[item.groupId] ?= []
@groupsMap[item.groupId].push item
applicationMenu = null applicationMenu = null
Menu.setApplicationMenu = (menu) -> Menu.setApplicationMenu = (menu) ->
throw new TypeError('Invalid menu') unless menu?.constructor is Menu throw new TypeError('Invalid menu') unless menu?.constructor is Menu

View file

@ -17,7 +17,6 @@
* `enabled` Boolean * `enabled` Boolean
* `visible` Boolean * `visible` Boolean
* `checked` Boolean * `checked` Boolean
* `groupId` Integer - Should be specified for `radio` type menu item
* `submenu` Menu - Should be specified for `submenu` type menu item, when * `submenu` Menu - Should be specified for `submenu` type menu item, when
it's specified the `type: 'submenu'` can be omitted for the menu item it's specified the `type: 'submenu'` can be omitted for the menu item