Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Add attribute for key used to store MenuItem in Ordered Dict #88

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 22 additions & 7 deletions rumps/rumps.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ class Menu(ListDict):

def __init__(self):
self._separators = 1
self._menu_key = None
if not hasattr(self, '_menu'):
self._menu = NSMenu.alloc().init()
super(Menu, self).__init__()
Expand All @@ -392,7 +393,7 @@ def add(self, menuitem):
"""Adds the object to the menu as a :class:`rumps.MenuItem` using the :attr:`rumps.MenuItem.title` as the
key. `menuitem` will be converted to a `MenuItem` object if not one already.
"""
self.__setitem__(self._choose_key, menuitem)
self.__setitem__(self._choose_or_get_key, menuitem)

def clear(self):
"""Remove all `MenuItem` objects from within the menu of this `MenuItem`."""
Expand Down Expand Up @@ -463,7 +464,7 @@ def insert_after(self, existing_key, menuitem):
:param existing_key: a string key for an existing `MenuItem` value.
:param menuitem: an object to be added. It will be converted to a `MenuItem` if not one already.
"""
key, menuitem = self._process_new_menuitem(self._choose_key, menuitem)
key, menuitem = self._process_new_menuitem(self._choose_or_get_key, menuitem)
self._insert_helper(existing_key, key, menuitem, 1)
super(Menu, self).insert_after(existing_key, (key, menuitem))

Expand All @@ -473,7 +474,7 @@ def insert_before(self, existing_key, menuitem):
:param existing_key: a string key for an existing `MenuItem` value.
:param menuitem: an object to be added. It will be converted to a `MenuItem` if not one already.
"""
key, menuitem = self._process_new_menuitem(self._choose_key, menuitem)
key, menuitem = self._process_new_menuitem(self._choose_or_get_key, menuitem)
self._insert_helper(existing_key, key, menuitem, 0)
super(Menu, self).insert_before(existing_key, (key, menuitem))

Expand All @@ -493,20 +494,23 @@ def _process_new_menuitem(self, key, value):

if value is not separator:
value = MenuItem(value) # safely convert if not already MenuItem
if key is self._choose_key:
if key is self._choose_or_get_key:
key = value.title
if key != value.title:
_log('WARNING: key {0} is not the same as the title of the corresponding MenuItem {1}; while this '
'would occur if the title is dynamically altered, having different names at the time of menu '
'creation may not be desired '.format(repr(key), repr(value.title)))
else:
value = SeparatorMenuItem()
if key is self._choose_key:
if key is self._choose_or_get_key:
key = 'separator_' + str(self._separators)
self._separators += 1

return key, value

def _choose_or_get_key(self):
return self._menu_key if self._menu_key else self._choose_key


class MenuItem(Menu):
"""Represents an item within the application's menu.
Expand All @@ -526,7 +530,7 @@ class MenuItem(Menu):
after other specified ones.

.. note::
When adding a `MenuItem` instance to a menu, the value of :attr:`title` at that time will serve as its key for
When adding a `MenuItem` instance to a menu, the value of :attr:`title`, or :attr:`menu_key` if set, at that time will serve as its key for
lookup performed on menus even if the `title` changes during program execution.

:param title: the name of this menu item. If not a string, will use the string representation of the object.
Expand All @@ -535,6 +539,8 @@ class MenuItem(Menu):
:param icon: a path to an image. If set to ``None``, the current image (if any) is removed.
:param dimensions: a sequence of numbers whose length is two, specifying the dimensions of the icon.
:param template: a boolean, specifying template mode for a given icon (proper b/w display in dark menu bar)
:param menu_key: the key of this menu item in its parent menu. If not a string, will use the string representation
of the object.
"""

# NOTE:
Expand All @@ -551,7 +557,7 @@ def __new__(cls, *args, **kwargs):
return args[0]
return super(MenuItem, cls).__new__(cls, *args, **kwargs)

def __init__(self, title, callback=None, key=None, icon=None, dimensions=None, template=None):
def __init__(self, title, callback=None, key=None, icon=None, dimensions=None, template=None, menu_key=None):
if isinstance(title, MenuItem): # don't initialize already existing instances
return
self._menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(text_type(title), None, '')
Expand All @@ -560,6 +566,7 @@ def __init__(self, title, callback=None, key=None, icon=None, dimensions=None, t
self.set_callback(callback, key)
self._template = template
self.set_icon(icon, dimensions, template)
self._menu_key = menu_key
super(MenuItem, self).__init__()

def __setitem__(self, key, value):
Expand All @@ -584,6 +591,14 @@ def title(self, new_title):
new_title = text_type(new_title)
self._menuitem.setTitle_(new_title)

@property
def menu_key(self):
"""The text used as a key when storing this menu item as a dictionary. If not a string, will use the string representation of the
object.
.. versionadded:: 0.2.1
"""
return self._menu_key

@property
def icon(self):
"""The path to an image displayed next to the text for this menu item. If set to ``None``, the current image
Expand Down