earwax.menus package

Module contents

Provides all menu-related classes.

By default:

  • Menus are lists of items which can be traversed with the arrow keys, or by
    searching.
  • The first item can be focussed with the home key.
  • The last item can be focussed with the end key.
  • The selected item can be activated with the enter key.

Optionally, menus can be dismissed with the escape key.

class earwax.menus.Menu(game: Game, title: Union[str, TitleFunction], dismissible: bool = True, item_select_sound_path: Optional[pathlib.Path] = None, item_activate_sound_path: Optional[pathlib.Path] = None, position: int = -1, search_timeout: float = 0.5, search_time: float = 0.0)

Bases: earwax.level.Level, earwax.mixins.TitleMixin, earwax.mixins.DismissibleMixin

A menu of MenuItem instances.

Menus hold multiple menu items which can be activated using actions.

As menus are simply Level subclasses, they can be pushed, popped, and replaced.

To add items to a menu, you can either use the item() decorator, or the add_item() function.

Here is an example of both methods:

from earwax import Game, Level, Menu
from pyglet.window import key, Window
w = Window(caption='Test Game')
g = Game()
l = Level()
@l.action('Show menu', symbol=key.M)
def menu():
    '''Show a menu with 2 items.'''
    m = Menu(g, 'Menu')
    @m.item(title='First Item')
    def first_item():
        g.output('First menu item.')
        g.pop_level()
    def second_item():
        g.output('Second menu item.')
        g.pop_level()
    m.add_item(second_item, title='Second Item')
    g.push_level(m)

g.push_level(l)
g.run(w)

To override the default actions that are added to a menu, subclass earwax.Menu, and override __attrs_post_init__().

Variables:
  • item_sound_path

    The default sound to play when moving through the menu.

    If the selected item’s sound_path attribute is not None, then that value takes precedence.

  • items – The list of MenuItem instances for this menu.
  • position – The user’s position in this menu.
  • search_timeout – The maximum time between menu searches.
  • search_time – The time the last menu search was performed.
  • search_string – The current menu search search string.
activate() → Optional[Generator[None, None, None]]

Activate the currently focused menu item.

Usually triggered by the enter key.

add_item(func: Callable[[], Optional[Generator[None, None, None]]], **kwargs) → earwax.menus.menu_item.MenuItem

Add an item to this menu.

For example:

m = Menu(game, 'Example Menu')
def f():
    game.output('Menu item activated.')
m.add_item(f, title='Test Item')
m.add_item(f, sound_path=Path('sound.wav'))

If you would rather use decorators, use the item() method instead.

Parameters:
  • func – The function which will be called when the menu item is selected.
  • kwargs – Extra arguments to be passed to the constructor of earwax.MenuItem.
add_submenu(menu: earwax.menus.menu.Menu, replace: bool, **kwargs) → earwax.menus.menu_item.MenuItem

Add a submenu to this menu.

Parameters:
  • menu – The menu to show when the resulting item is activated.
  • replace – If True, then the new menu will replace this one in the levels stack.
  • kwargs – The additional arguments to pass to add_item().
current_item

Return the currently selected menu item.

If position is -1, return None.

end() → None

Move to the end of a menu.

Usually triggered by the end key.

classmethod from_credits(game: Game, credits: List[earwax.credit.Credit], title: str = 'Game Credits') → Menu

Return a menu for showing credits.

Parameters:
  • game – The game to use.
  • credits – The credits to show.
  • title – The title of the new menu.
home() → None

Move to the start of a menu.

Usually triggered by the home key.

item(**kwargs) → Callable[[Callable[[], Optional[Generator[None, None, None]]]], earwax.menus.menu_item.MenuItem]

Decorate a function to be used as a menu item.

For example:

@menu.item(title='Title')
def func():
    pass

@menu.item(sound_path=Path('sound.wav'))
def item_with_sound():
    pass

If you don’t want to use a decorator, you can use the add_item() method instead.

Parameters:kwargs – Extra arguments to be passed to the constructor of earwax.MenuItem.
make_sound(item: earwax.menus.menu_item.MenuItem, path: pathlib.Path) → earwax.sound.Sound

Return a sound object.

Parameters:
  • item

    The menu item to make the sound for.

    This value is probably current_item.

  • path

    The path to load the sound from.

    This value will have been determined by show_selection(), and may have been loaded from the menu item itself, or the main earwax configuration.

move_down() → None

Move down in this menu.

Usually triggered by the down arrow key.

move_up() → None

Move up in this menu.

Usually triggered by the up arrow key.

on_pop() → None

Destroy select_sound if necessary.

on_push() → None

Handle this menu being pushed.

This method is called when this object has been pushed onto a Game instance.

By default, show the current selection. That will be the same as speaking the title, unless self.position has been set to something other than -1..

on_reveal() → None

Show selection again.

on_text(text: str) → None

Handle sent text.

By default, performs a search of this menu.

Parameters:text – The text that has been sent.
show_selection() → None

Speak the menu item at the current position.

If self.position is -1, this method speaks self.title.

This function performs no error checking, so it will happily throw errors if position is something stupid.

classmethod yes_no(game: Game, yes_action: Callable[[], Optional[Generator[None, None, None]]], no_action: Callable[[], Optional[Generator[None, None, None]]], title: str = 'Are you sure?', yes_label: str = 'Yes', no_label: str = 'No', **kwargs) → Menu

Create and return a yes no menu.

Parameters:
  • game – The game to bind the new menu to.
  • yes_action – The function to be called if the yes item is selected.
  • no_action – The action to be performed if no is selected.
  • title – The title of the menu.
  • yes_label – The label of the yes item.
  • no_label – The title of the no label.
  • kwargs – Extra keyword arguments to be passed to the Menu constructor.
class earwax.menus.MenuItem(func: Callable[[], Optional[Generator[None, None, None]]], title: Union[str, TitleFunction, None] = None, select_sound_path: Optional[pathlib.Path] = None, loop_select_sound: bool = False, activate_sound_path: Optional[pathlib.Path] = None)

Bases: earwax.mixins.RegisterEventMixin

An item in a Menu.

This class is rarely used directly, instead earwax.menu.Menu.add_item() or earwax.menu.Menu.item() can be used to return an instance.

Variables:
  • func – The function which will be called when this item is activated.
  • title

    The title of this menu item.

    If this value is a callable, it should return a string which will be used as the title.

  • select_sound_path

    The path to a sound which should play when this menu item is selected.

    If this value is None (the default), then no sound will be heard unless the containing menu has its item_select_sound_path attribute set to something that is not None, or earwax.EarwaxConfig.menus.default_item_select_sound is not None.

  • activate_sound_path

    The path to a sound which should play when this menu item is activated.

    If this value is None (the default), then no sound will be heard unless the containing menu has its item_activate_sound_path attribute set to something that is not None, or earwax.EarwaxConfig.menus.default_item_select_sound is not None.

get_title() → Optional[str]

Return the proper title of this object.

If self.title is a callable, its return value will be returned.

on_selected() → None

Handle this menu item being selected.

class earwax.menus.ActionMenu(game: Game, title: Union[str, TitleFunction], dismissible: bool = True, item_select_sound_path: Optional[pathlib.Path] = None, item_activate_sound_path: Optional[pathlib.Path] = None, position: int = -1, search_timeout: float = 0.5, search_time: float = 0.0, input_mode: Optional[earwax.input_modes.InputModes] = NOTHING, all_triggers_label: Optional[str] = '<< Show all triggers >>')

Bases: earwax.menus.menu.Menu

A menu to show a list of actions and their associated triggers.

You can use this class with any game, like so:

from earwax import Game, Level, ActionMenu
from pyglet.window import Window, key
w = Window(caption='Test Game')
g = Game()
l = Level()
@l.action('Show actions', symbol=key.SLASH, modifiers=key.MOD_SHIFT)
def actions_menu():
    '''Show an actions menu.'''
    a = ActionMenu(g, 'Actions')
    g.push_level(a)

g.push_level(l)
g.run(w)

Now, if you press shift and slash (a question mark on english keyboards), you will get an action menu.

This code can be shortened to:

@l.action('Show actions', symbol=key.SLASH, modifiers=key.MOD_SHIFT)
def actions_menu():
    '''Show an actions menu.'''
    game.push_action_menu()

If you want to override how triggers appear in the menu, then you can override symbol_to_string() and mouse_to_string().

Variables:
  • input_mode – The input mode this menu will show actions for.
  • all_triggers_label

    The label for the “All triggers” entry.

    If this value is None no such entry will be shown.

action_menu(action: earwax.action.Action) → Callable[[], Optional[Generator[None, None, None]]]

Show a submenu of triggers.

Override this method to change how the submenu for actions is displayed.

Parameters:action – The action to generate the menu for.
action_title(action: earwax.action.Action, triggers: List[str]) → str

Return a suitable title for the given action.

This method is used when building the menu when input_mode is not None.

Parameters:
  • action – The action whose name will be used.
  • triggers – A list of triggers gleaned from the given action.
get_default_input_mode() → earwax.input_modes.InputModes

Get the default input mode.

handle_action(action: earwax.action.Action) → Callable[[], Optional[Generator[None, None, None]]]

Handle an action.

This method is used as the menu handler that is triggered when you select a trigger to activate the current action.

Parameters:action – The action to run.
hat_direction_to_string(direction: Tuple[int, int]) → str

Return the given hat direction as a string.

mouse_to_string(action: earwax.action.Action) → str

Describe how to trigger the given action with the mouse.

Returns a string representing the mouse button and modifiers needed to trigger the provided action.

You must be certain that action.mouse_button is not None.

Override this method to change how mouse triggers appear.

Parameters:action – The action whose mouse_button attribute this method will be working on.
show_all() → None

Show all triggers.

symbol_to_string(action: earwax.action.Action) → str

Describe how to trigger the given action with the keyboard.

Returns a string representing the symbol and modifiers needed to trigger the provided action.

You must be certain that action.symbol is not None.

Override this method to change how symbol triggers appear.

Parameters:action – The action whose symbol attribute this method will be working on.
class earwax.menus.FileMenu(game: Game, title: Union[str, TitleFunction], dismissible: bool = True, item_select_sound_path: Optional[pathlib.Path] = None, item_activate_sound_path: Optional[pathlib.Path] = None, position: int = -1, search_timeout: float = 0.5, search_time: float = 0.0, path: pathlib.Path = NOTHING, func: Callable[[Optional[pathlib.Path]], Optional[Generator[None, None, None]]] = <built-in function print>, root: Optional[pathlib.Path] = None, empty_label: Optional[str] = None, directory_label: Optional[str] = None, show_directories: bool = True, show_files: bool = True, up_label: str = '..')

Bases: earwax.menus.menu.Menu

A menu for selecting a file.

File menus can be used as follows:

from pathlib import Path
from earwax import Game, Level, FileMenu, tts
from pyglet.window import key, Window
w = Window(caption='Test Game')
g = Game()
l = Level(g)
@l.action('Show file menu', symbol=key.F)
def file_menu():
    '''Show a file menu.'''
    def inner(p):
        tts.speak(str(p))
        g.pop_level()
    f = FileMenu(g, 'File Menu', Path.cwd(), inner)
    g.push_level(f)

g.push_level(l)
g.run(w)
Variables:
  • path – The path this menu will start at.
  • func – The function to run with the resulting file or directory.
  • root – The root directory which this menu will be chrooted to.
  • empty_label

    The label given to an entry which will allow this menu to return None as a result.

    If this label is None (the default), then then no such option will be available.

  • directory_label

    The label given to an entry which will allow a directory - in addition to files - to be selected.

    If this argument is None (the default), then no such option will be available.

    If you only want directories to be selected, then pass show_files=False to the constructor.

  • show_directories – Whether or not to show directories in the list.
  • show_files – Whether or not to include files in the list.
  • up_label – The label given to the entry to go up in the directory tree.
navigate_to(path: pathlib.Path) → Callable[[], None]

Navigate to a different path.

Instead of completely replacing the menu, just change the path, and re- use this instance.

rebuild_menu() → None

Rebuild the menu.

This method will be called once after initialisation, and every time the directory is changed by the navigate_to() method.

select_item(path: Optional[pathlib.Path]) → Callable[[], Optional[Generator[None, None, None]]]

Select an item.

Used as the menu handler in place of a lambda.

Parameters:path – The path that has been selected. Could be a file or a directory.
class earwax.menus.ConfigMenu(game: Game, title: Union[str, TitleFunction], dismissible: bool = True, item_select_sound_path: Optional[pathlib.Path] = None, item_activate_sound_path: Optional[pathlib.Path] = None, position: int = -1, search_timeout: float = 0.5, search_time: float = 0.0, config: earwax.config.Config = NOTHING)

Bases: earwax.menus.menu.Menu

A menu that allows the user to set values on configuration sections.

If an option is present with a type the menu doesn’t know how to handle, earwax.UnknownTypeError will be raised.

Variables:
  • config – The configuration section this menu will configure.
  • type_handlers

    Functions to handle the types this menu knows about.

    New types can be handled with the type_handler() method.

activate_handler(handler: earwax.menus.config_menu.TypeHandler, option: earwax.config.ConfigValue) → Callable[[], Optional[Generator[None, None, None]]]

Activates the given handler with the given configuration value.

Used by the option_menu() method when building menus.

Parameters:
  • handler – The TypeHandler instance that should be activated.
  • option – The ConfigValue instance the handler should work with.
clear_value(option: earwax.config.ConfigValue) → None

Clear the value.

Sets option.value to None.

Used by the default TypeHandler that handles nullable values.

Parameters:option – The ConfigValue instance whose value should be set to None.
earwax_config() → earwax.config.Config

Return the main earwax configuration.

get_option_name(option: earwax.config.ConfigValue, name: str) → str

Get the name for the given option.

The provided name argument will be the attribute name, so should only be used if the option has no __section_name__ attribute.

Parameters:
  • option – The ConfigValue instance whose name should be returned.
  • name – The name of the attribute that holds the option.
get_subsection_name(subsection: earwax.config.Config, name: str) → str

Get the name for the given subsection.

The provided name argument will be the attribute name, so should only be used if the subsection has no __section_name__ attribute.

Parameters:
  • subsection – The Config instance whose name should be returned.
  • name – The name of the attribute that holds the subsection.
handle_bool(option: earwax.config.ConfigValue) → None

Toggle a boolean value.

Used by the default TypeHandler that handles boolean values.

Parameters:option – The ConfigValue instance to work on.
handle_float(option: earwax.config.ConfigValue) → Generator[None, None, None]

Allow editing floats.

Used by the default TypeHandler that handles float values.

Parameters:option – The ConfigValue instance to work on.
handle_int(option: earwax.config.ConfigValue) → Generator[None, None, None]

Allow editing integers.

Used by the default TypeHandler that handles integer values.

Parameters:option – The ConfigValue instance to work on.
handle_path(option: earwax.config.ConfigValue) → Generator[None, None, None]

Allow selecting files and folders.

Used by the default TypeHandler that handles pathlib.Path values.

Parameters:option – The ConfigValue instance to work on.
handle_string(option: earwax.config.ConfigValue) → Generator[None, None, None]

Allow editing strings.

Used by the default TypeHandler that handles string values.

Parameters:option – The ConfigValue instance to work on.
option_menu(option: earwax.config.ConfigValue, name: str) → Callable[[], Generator[None, None, None]]

Add a menu for the given option.

If the type of the provided option is a Union type (like Optional[str]), then an entry for editing each type will be added to the menu. Otherwise, there will be only one entry.

The only special case is when the type is a tuple of values. If this happens, the menu will instead be populated with a list of entries corrisponding to the values of the tuple.

At the end of the menu, there will be an option to restore the default value.

Parameters:
  • option – The ConfigValue instance to generate a menu for.
  • name – The proper name of the given option, as returned by get_option_name().
set_value(option: earwax.config.ConfigValue, value: Any, message: str = 'Done.') → Callable[[], None]

Set a value.

Returns a callable that can be used to set the value of the provided option to the provided value.

This method returns a callable because it is used extensively by option_menu(), and a bunch of lambdas becomes less readable. Plus, Mypy complains about them.

Parameters:
  • option – The ConfigValue instance to work on.
  • value – The value to set option.value to.
  • message – The message to be spoken after setting the value.
subsection_menu(subsection: earwax.config.Config, name: str) → Callable[[], Generator[None, None, None]]

Add a menu for the given subsection.

By default, creates a new earwax.ConfigMenu instance, and returns a function that - when called - will push it onto the stack.

Parameters:
  • subsection – The Config instance to create a menu for.
  • name – The proper name of the subsection, returned by get_subsection_name().
type_handler(type_: object, title: Callable[[earwax.config.ConfigValue, str], str]) → Callable[[Callable[[earwax.config.ConfigValue], Optional[Generator[None, None, None]]]], Callable[[earwax.config.ConfigValue], Optional[Generator[None, None, None]]]]

Add a type handler.

Decorate a function to be used as a type handler:

from datetime import datetime, timedelta
from earwax import ConfigMenu, tts

m = ConfigMenu(pretend_config, 'Options', game)

@m.type_handler(datetime, lambda option, name: 'Add a week')
def add_week(option):
    '''Add a week to the current value.'''
    option.value += timedelta(days=7)
    self.game.output('Added a week.')
    m.game.pop_level()

Handlers can do anything menu item functions can do, including creating more menus, and yielding.

Parameters:
  • type – The type this handler should be registered for.
  • title – A function which will return the title for the menu item for this handler.
class earwax.menus.TypeHandler(title: Callable[[earwax.config.ConfigValue, str], str], func: Callable[[earwax.config.ConfigValue], Optional[Generator[None, None, None]]])

Bases: object

A type handler for use with ConfigMenu instances.

Variables:
  • title – A function that will return a string which can be used as the title for the menu item generated by this handler.
  • func – The function that will be called when this handler is required.
exception earwax.menus.UnknownTypeError

Bases: Exception

An unknown type was encountered.

An exception which will be thrown if a ConfigMenu instance doesn’t know how to handle the given type.

class earwax.menus.ReverbEditor(game: Game, title: Union[str, TitleFunction], dismissible: bool = True, item_select_sound_path: Optional[pathlib.Path] = None, item_activate_sound_path: Optional[pathlib.Path] = None, position: int = -1, search_timeout: float = 0.5, search_time: float = 0.0, reverb: object = NOTHING, settings: earwax.reverb.Reverb = NOTHING, setting_items: List[earwax.menus.menu_item.MenuItem] = NOTHING)

Bases: earwax.menus.menu.Menu

A menu for editing reverbs.

adjust_value(amount: earwax.menus.reverb_editor.ValueAdjustments) → Callable[[], None]

Restore the current menu item to the default.

edit_value(setting: earwax.menus.reverb_editor.ReverbSetting, value: float) → Callable[[], Generator[None, None, None]]

Edit the given value.

get_default_reverb() → object

Raise an error.

get_default_settings() → earwax.reverb.Reverb

Raise an error.

reset() → None

Reload this menu.

set_value(setting: earwax.menus.reverb_editor.ReverbSetting, value: float) → None

Set the value.