Generate menu group id automatically.
authorCheng Zhao <zcbenz@gmail.com>
Sun, 25 May 2014 04:32:47 +0000 (12:32 +0800)
committerCheng Zhao <zcbenz@gmail.com>
Sun, 25 May 2014 04:37:00 +0000 (12:37 +0800)
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.

atom/browser/api/lib/menu-item.coffee
atom/browser/api/lib/menu.coffee
docs/api/menu-item.md

index ec38963..834eddf 100644 (file)
@@ -8,7 +8,7 @@ class MenuItem
   constructor: (options) ->
     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?
     throw new Error('Invalid submenu') if @type is 'submenu' and @submenu?.constructor isnt Menu
@@ -20,7 +20,6 @@ class MenuItem
     @enabled = @enabled ? true
     @visible = @visible ? true
     @checked = @checked ? false
-    @groupId = @groupId ? null
     @submenu = @submenu ? null
 
     throw new Error('Unknown menu type') if MenuItem.types.indexOf(@type) is -1
index 01008aa..0c8fec7 100644 (file)
@@ -4,6 +4,24 @@ 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
 
@@ -19,15 +37,7 @@ Menu::append = (item) ->
 Menu::insert = (pos, item) ->
   throw new TypeError('Invalid item') unless item?.constructor is MenuItem
 
-  switch item.type
-    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?
-
+  # Create delegate.
   unless @delegate?
     @commandsMap = {}
     @groupsMap = {}
@@ -39,6 +49,7 @@ Menu::insert = (pos, item) ->
       getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator
       executeCommand: (commandId) =>
         activeItem = @commandsMap[commandId]
+        # Manually flip the checked flags when clicked.
         if activeItem?
           switch activeItem.type
             when 'checkbox'
@@ -48,13 +59,25 @@ Menu::insert = (pos, item) ->
                 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
 
-  if item.groupId?
-    @groupsMap[item.groupId] ?= []
-    @groupsMap[item.groupId].push item
-
 applicationMenu = null
 Menu.setApplicationMenu = (menu) ->
   throw new TypeError('Invalid menu') unless menu?.constructor is Menu
index 85e47e6..ad2e42b 100644 (file)
@@ -17,7 +17,6 @@
   * `enabled` Boolean
   * `visible` Boolean
   * `checked` Boolean
-  * `groupId` Integer - Should be specified for `radio` type menu item
   * `submenu` Menu - Should be specified for `submenu` type menu item, when
      it's specified the `type: 'submenu'` can be omitted for the menu item