esc
stable

Contents

  • User Manual
  • Developer Manual
    • Operations
    • Menus
      • Creating new menus
      • Adding to existing menus
    • Constants
    • Modes
    • Debugging
    • Class Reference
esc
  • Docs »
  • Developer Manual »
  • Menus
  • Edit on GitHub

Menus¶

Many operations can go on the main menu, but at some point you may want to create additional menus or register new items on existing menus.

Menus can have submenus to an effectively infinite depth.

Creating new menus¶

Menus are defined with the Menu constructor:

esc.commands.Menu(key, description, parent, doc, mode_display=None)[source]¶

Register a new submenu of an existing menu.

Parameters:
  • key – The keyboard key used to select this menu from its parent.
  • description – A short description of this menu to show beside the key.
  • parent – An EscMenu to add this menu to. This may be esc.commands.main_menu or another menu.
  • doc – A string describing the menu, to be used in the help system. This should be something like the docstring of an operation function.
  • mode_display – An optional callable returning a string whose value will be shown beneath the name of the menu when the menu is open. Ordinarily, this is used to show the current value of any modes that apply to the functions on the menu.
Returns:

A new EscMenu.

Example:

from esc.commands import Operation, Menu, main_menu

qdoc = """
This menu contains common operations needed when working with
problems in queueing theory.
"""
qmenu = Menu('Q', 'queueing menu', parent=main_menu, doc=qdoc)

# Here we would define functions whose @Operation decorators
# take 'qmenu' as their menu= argument.

Adding to existing menus¶

Sometimes it’s useful to extend menus defined by other plugins. This poses a challenge: how do we get access to those menu objects? The plugins directory is not a package and we can’t guarantee its contents, so it’s tricky to import from other plugins. The easiest method uses the esc.commands.EscMenu.child() method:

EscMenu.child(access_key)[source]

Return the child defined by access_key. Raises NotInMenuError if it doesn’t exist.

We only need to know the menu access keys to get at any item from the main menu! Let’s suppose we want to add a secant operation to the trig menu installed by the trig plugin bundled with esc. In order to do that, we need to obtain the trig menu. The key of this menu is t. Thus we would do:

from esc.commands import main_menu

trig_menu = main_menu.child('t')

This isn’t very robust, though. We probably want to make sure we’ve actually gotten the trig menu and not some other menu that happened to have the access key t, and we might want our plugin to add its own operations even if we don’t have the trig-menu plugin installed. Let’s add these features:

from esc.commands import main_menu
from esc.oops import NotInMenuError, ProgrammingError

if 't' in main_menu.children:
    trig_menu = main_menu.child('t')
    if trig_menu.description != 'trig menu':
        raise ProgrammingError(
            f"Expected the menu 't' to be the trig menu, but it was "
            f"{trig_menu.description}.")
else:
    trig_doc = """
        Calculate the values of trigonometric functions, treating inputs as
        either degrees or radians depending on the mode.
    """
    trig_menu = Menu('t', 'trig menu', parent=main_menu,
                    doc=trig_doc,
                    mode_display=trig_mode_display)

This is better. If the menu doesn’t exist already, we’ll create it; if it does, we’ll retrieve it and then be sure it’s the right one, throwing an error if it isn’t.

Warning

It’s important to make sure your plugin loads after the plugin you’re extending, or that plugin will crash when it tries to add a menu that already exists (unless it does the same check you did). That’s easy enough to do by changing the filename to be alphabetically later than the plugin you’re targeting; an easy way is to name your file as the target plugin with an additional suffix, like trigextensions.py. (Don’t use an underscore, though – that sorts before the dot!)

Note

A good future addition to esc would be a convenient way to remap the keys added by different plugins, since it’s easy for them to end up colliding if they aren’t designed with each other in mind. As of now, this is a bit hacky still and manual modification is required if you encounter a collision.

Next Previous

© Copyright 2019, Soren Bjornstad Revision 43eb60f4.

Built with Sphinx using a theme provided by Read the Docs.