Easy menu selection tree

Contrib - Tim Ashley Jenkins 2017

This module allows you to create and initialize an entire branching EvMenu instance with nothing but a multi-line string passed to one function.

EvMenu is incredibly powerful and flexible, but using it for simple menus can often be fairly cumbersome - a simple menu that can branch into five categories would require six nodes, each with options represented as a list of dictionaries.

This module provides a function, init_tree_selection, which acts as a frontend for EvMenu, dynamically sourcing the options from a multi-line string you provide. For example, if you define a string as such:

TEST_MENU = ‘’’Foo Bar Baz Qux’’’

And then use TEST_MENU as the ‘treestr’ source when you call init_tree_selection on a player:

init_tree_selection(TEST_MENU, caller, callback)

The player will be presented with an EvMenu, like so:

Foo Bar Baz Qux

Making a selection will pass the selection’s key to the specified callback as a string along with the caller, as well as the index of the selection (the line number on the source string) along with the source string for the tree itself.

In addition to specifying selections on the menu, you can also specify categories. Categories are indicated by putting options below it preceded with a ‘-‘ character. If a selection is a category, then choosing it will bring up a new menu node, prompting the player to select between those options, or to go back to the previous menu. In addition, categories are marked by default with a ‘[+]’ at the end of their key. Both this marker and the option to go back can be disabled.

Categories can be nested in other categories as well - just go another ‘-‘ deeper. You can do this as many times as you like. There’s no hard limit to the number of categories you can go down.

For example, let’s add some more options to our menu, turning ‘Bar’ into a category.

TEST_MENU = ‘’’Foo Bar -You’ve got to know –When to hold em –When to fold em –When to walk away Baz Qux’’’

Now when we call the menu, we can see that ‘Bar’ has become a category instead of a selectable option.

Foo Bar [+] Baz Qux

Note the [+] next to ‘Bar’. If we select ‘Bar’, it’ll show us the option listed under it.

You’ve got to know [+] << Go Back: Return to the previous menu.

Just the one option, which is a category itself, and the option to go back, which will take us back to the previous menu. Let’s select ‘You’ve got to know’.

When to hold em When to fold em When to walk away << Go Back: Return to the previous menu.

Now we see the three options listed under it, too. We can select one of them or use ‘Go Back’ to return to the ‘Bar’ menu we were just at before. It’s very simple to make a branching tree of selections!

One last thing - you can set the descriptions for the various options simply by adding a ‘:’ character followed by the description to the option’s line. For example, let’s add a description to ‘Baz’ in our menu:

TEST_MENU = ‘’’Foo Bar -You’ve got to know –When to hold em –When to fold em –When to walk away Baz: Look at this one: the best option. Qux’’’

Now we see that the Baz option has a description attached that’s separate from its key:

Foo Bar [+] Baz: Look at this one: the best option. Qux

Once the player makes a selection - let’s say, ‘Foo’ - the menu will terminate and call your specified callback with the selection, like so:

callback(caller, TEST_MENU, 0, “Foo”)

The index of the selection is given along with a string containing the selection’s key. That way, if you have two selections in the menu with the same key, you can still differentiate between them.

And that’s all there is to it! For simple branching-tree selections, using this system is much easier than manually creating EvMenu nodes. It also makes generating menus with dynamic options much easier - since the source of the menu tree is just a string, you could easily generate that string procedurally before passing it to the init_tree_selection function. For example, if a player casts a spell or does an attack without specifying a target, instead of giving them an error, you could present them with a list of valid targets to select by generating a multi-line string of targets and passing it to init_tree_selection, with the callable performing the maneuver once a selection is made.

This selection system only works for simple branching trees - doing anything really complicated like jumping between categories or prompting for arbitrary input would still require a full EvMenu implementation. For simple selections, however, I’m sure you will find using this function to be much easier!

Included in this module is a sample menu and function which will let a player change the color of their name - feel free to mess with it to get a feel for how this system works by importing this module in your game’s default_cmdsets.py module and adding CmdNameColor to your default character’s command set.

evennia.contrib.tree_select.init_tree_selection(treestr, caller, callback, index=None, mark_category=True, go_back=True, cmd_on_exit='look', start_text='Make your selection:')[source]

Prompts a player to select an option from a menu tree given as a multi-line string.

  • treestr (str) – Multi-lne string representing menu options

  • caller (obj) – Player to initialize the menu for

  • callback (callable) – Function to run when a selection is made. Must take 4 args: caller (obj): Caller given above treestr (str): Menu tree string given above index (int): Index of final selection selection (str): Key of final selection


index (int or None): Index to start the menu at, or None for top level mark_category (bool): If True, marks categories with a [+] symbol in the menu go_back (bool): If True, present an option to go back to previous categories start_text (str): Text to display at the top level of the menu cmd_on_exit(str): Command to enter when the menu exits - ‘look’ by default


This function will initialize an instance of EvMenu with options generated dynamically from the source string, and passes the menu user’s selection to a function of your choosing. The EvMenu is made of a single, repeating node, which will call itself over and over at different levels of the menu tree as categories are selected.

Once a non-category selection is made, the user’s selection will be passed to the given callable, both as a string and as an index number. The index is given to ensure every selection has a unique identifier, so that selections with the same key in different categories can be distinguished between.

The menus called by this function are not persistent and cannot perform complicated tasks like prompt for arbitrary input or jump multiple category levels at once - you’ll have to use EvMenu itself if you want to take full advantage of its features.


Counts the number of dashes at the beginning of a string. This is needed to determine the depth of options in categories.


entry (str) – String to count the dashes at the start of


dashes (int) – Number of dashes at the start

evennia.contrib.tree_select.is_category(treestr, index)[source]

Determines whether an option in a tree string is a category by whether or not there are additional options below it.

  • treestr (str) – Multi-line string representing menu options

  • index (int) – Which line of the string to test


is_category (bool) – Whether the option is a category

evennia.contrib.tree_select.parse_opts(treestr, category_index=None)[source]

Parses a tree string and given index into a list of options. If category_index is none, returns all the options at the top level of the menu. If category_index corresponds to a category, returns a list of options under that category. If category_index corresponds to an option that is not a category, it’s a selection and returns True.

  • treestr (str) – Multi-line string representing menu options

  • category_index (int) – Index of category or None for top level


kept_opts (list or True)

Either a list of options in the selected

category or True if a selection was made

evennia.contrib.tree_select.index_to_selection(treestr, index, desc=False)[source]

Given a menu tree string and an index, returns the corresponding selection’s name as a string. If ‘desc’ is set to True, will return the selection’s description as a string instead.

  • treestr (str) – Multi-line string representing menu options

  • index (int) – Index to convert to selection key or description


desc (bool): If true, returns description instead of key


selection (str) – Selection key or description if ‘desc’ is set

evennia.contrib.tree_select.go_up_one_category(treestr, index)[source]

Given a menu tree string and an index, returns the category that the given option belongs to. Used for the ‘go back’ option.

  • treestr (str) – Multi-line string representing menu options

  • index (int) – Index to determine the parent category of


parent_category (int) – Index of parent category

evennia.contrib.tree_select.optlist_to_menuoptions(treestr, optlist, index, mark_category, go_back)[source]

Takes a list of options processed by parse_opts and turns it into a list/dictionary of menu options for use in menunode_treeselect.

  • treestr (str) – Multi-line string representing menu options

  • optlist (list) – List of options to convert to EvMenu’s option format

  • index (int) – Index of current category

  • mark_category (bool) – Whether or not to mark categories with [+]

  • go_back (bool) – Whether or not to add an option to go back in the menu


menuoptions (list of dicts)

List of menu options formatted for use

in EvMenu, each passing a different “newindex” kwarg that changes the menu level or makes a selection

evennia.contrib.tree_select.menunode_treeselect(caller, raw_string, **kwargs)[source]

This is the repeating menu node that handles the tree selection.

class evennia.contrib.tree_select.CmdNameColor(**kwargs)[source]

Bases: evennia.commands.command.Command

Set or remove a special color on your name. Just an example for the easy menu selection tree contrib.

key = 'namecolor'

This is the actual executing part of the command. It is called directly after self.parse(). See the docstring of this module for which object properties are available (beyond those set in self.parse())

aliases = []
help_category = 'general'
lock_storage = 'cmd:all();'
search_index_entry = {'aliases': '', 'category': 'general', 'key': 'namecolor', 'tags': '', 'text': '\n Set or remove a special color on your name. Just an example for the\n easy menu selection tree contrib.\n '}
evennia.contrib.tree_select.change_name_color(caller, treestr, index, selection)[source]

Changes a player’s name color.

  • caller (obj) – Character whose name to color.

  • treestr (str) – String for the color change menu - unused

  • index (int) – Index of menu selection - unused

  • selection (str) – Selection made from the name color menu - used to determine the color the player chose.