EvForm - a way to create advanced ASCII forms

This is intended for creating advanced ASCII game forms, such as a large pretty character sheet or info document.

The system works on the basis of a readin template that is given in a separate Python file imported into the handler. This file contains some optional settings and a string mapping out the form. The template has markers in it to denounce fields to fill. The markers map the absolute size of the field and will be filled with an evtable.EvCell object when displaying the form.

Example of input file testform.py:


FORM = '''
|                                                |
|  Name: xxxxx1xxxxx    Player: xxxxxxx2xxxxxxx  |
|        xxxxxxxxxxx                             |
|                                                |
|                                                |
| Desc:  xxxxxxxxxxx    STR: x4x    DEX: x5x     |
|        xxxxx3xxxxx    INT: x6x    STA: x7x     |
|        xxxxxxxxxxx    LUC: x8x    MAG: x9x     |
|                                                |
|          |                                     |
| cccccccc | ccccccccccccccccccccccccccccccccccc |
| cccccccc | ccccccccccccccccccccccccccccccccccc |
| cccAcccc | ccccccccccccccccccccccccccccccccccc |
| cccccccc | ccccccccccccccccccccccccccccccccccc |
| cccccccc | cccccccccccccccccBccccccccccccccccc |
|          |                                     |
|                                           v&   |

The first line of the FORM string is ignored if empty. The forms and table markers must mark out complete, unbroken rectangles, each containing one embedded single-character identifier (so the smallest element possible is a 3-character wide form). The identifier can be any character except for the FORM_CHAR and TABLE_CHAR and some of the common ASCII-art elements, like space, _ | * etc (see INVALID_FORMCHARS in this module). Form Rectangles can have any size, but must be separated from each other by at least one other character’s width.

The form can also replace literal markers not abiding by these rules. For example, the v& in the bottom right corner could be such literal marker. If a literal-mapping for ‘v&’ is provided, all occurrences of this marker will be replaced. This will happen before any other parsing, so in principle this could be used to inject new fields/tables into the form dynamically. This literal mapping does not consider width, but it will affect to total width of the form, so make sure what you inject does not break things. Using literal markers is the only way to inject 1 or 2-character replacements.


from evennia import EvForm, EvTable

# create a new form from the template
form = EvForm("path/to/testform.py")

# alteratively, you can supply the template as a dict:

form = EvForm({"FORM": "....", "TABLECHAR": "c", "FORMCHAR": "x"})

# EvForm can also take a dictionary instead of a filepath, as long
# as the dict contains the keys FORMCHAR, TABLECHAR and FORM
# form = EvForm(form=form_dict)

# add data to each tagged form cell
form.map(cells={1: "Tom the Bouncer",
                2: "Griatch",
                3: "A sturdy fellow",
                4: 12,
                5: 10,
                6:  5,
                7: 18,
                8: 10,
                9:  3})
# create the EvTables
tableA = EvTable("HP","MV","MP",
                           table=[["**"], ["*****"], ["***"]],
tableB = EvTable("Skill", "Value", "Exp",
                           table=[["Shooting", "Herbalism", "Smithing"],
                                  [12,14,9],["550/1200", "990/1400", "205/900"]],
# map 'literal' replacents (here, a version string)
custom_mapping = {"v&", "v2"}

# add the tables to the proper ids in the form
form.map(tables={"A": tableA,
                 "B": tableB})


This produces the following result:

|                                                |
|  Name: Tom the        Player: Griatch          |
|        Bouncer                                 |
|                                                |
|                                                |
| Desc:  A sturdy       STR: 12     DEX: 10      |
|        fellow         INT: 5      STA: 18      |
|                       LUC: 10     MAG: 3       |
|                                                |
|          |                                     |
| HP|MV|MP | Skill      |Value      |Exp         |
| ~~+~~+~~ | ~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~ |
| **|**|** | Shooting   |12         |550/1200    |
|   |**|*  | Herbalism  |14         |990/1400    |
|   |* |   | Smithing   |9          |205/900     |
|          |                                     |
|                                           v2   |

The marked forms have been replaced with EvCells of text and with EvTables. The literal marker v& was replaced with v2.

If you change the form layout on disk, you can use form.reload() to re-read it from disk without creating a new form.

If you want to update the data of an existing form, you can use form.map() with the changes - the mappings will be updated, keeping the things you want. You can also update the template itself this way, by supplying it as a dict.

Each component (except literal mappings) is restrained to the width and height specified by the template, so it will resize to fit (or crop text if the area is too small for it). If you try to fit a table into an area it cannot fit into (when including its borders and at least one line of text), the form will raise an error.

class evennia.utils.evform.EvForm(data=None, cells=None, tables=None, literals=None, **kwargs)[source]

Bases: object

This object is instantiated with a text file and parses it for rectangular form fields. It can then be fed a mapping so as to populate the fields with fixed-width EvCell or Tables.

cell_options = {'align': 'l', 'enforce_size': True, 'pad_bottom': 0, 'pad_left': 0, 'pad_right': 0, 'pad_top': 0, 'valign': 't'}
table_options = {'align': 'l', 'enforce_size': True, 'pad_bottom': 0, 'pad_left': 0, 'pad_right': 0, 'pad_top': 0, 'valign': 't'}
__init__(data=None, cells=None, tables=None, literals=None, **kwargs)[source]

Initiate the form

Keyword Arguments
  • data (str or dict) – Path to template file or a dict with “formchar”, “tablechar” and “form” keys (not case sensitive, so FORM etc also works, to stay compatible with the in-file names). While “form/FORM” is required, if FORMCHAR/TABLECHAR are not given, they will default to ‘x’ and ‘c’ respectively.

  • cells (dict) – A dictionary mapping {id: str}

  • tables (dict) – A dictionary mapping {id: EvTable}.

  • literals (dict) – A dictionary mapping {id: str}. Will be replaced after width of form is calculated, but before cells/tables are mapped. All occurrences of the identifier on the form will be replaced. Note that there is no length-restriction on the remap, you are responsible for not breaking the form.


Other kwargs are fed as options to the EvCells and EvTables (see evtable.EvCell and evtable.EvTable for more info).


Creates the form from a filename or data structure.


data (str or dict) – Can be used to update an existing form using the same cells/tables provided on initialization or using .map().


Kwargs are passed through to Cel creation.

map(cells=None, tables=None, data=None, literals=None, **kwargs)[source]

Add mapping for form. This allows for updating an existing evform.

  • cells (dict) – A dictionary of {identifier:celltext}. These will be appended to the existing mappings.

  • tables (dict) – A dictionary of {identifier:table}. Will be appended to the existing mapping.

  • data (str or dict) – A path to a evform module or a dict with the needed “FORM”, “TABLE/FORMCHAR” keys. Will replace the originally initialized form.

  • literals

Keyword Arguments

will be appended to the existing cell/table options. (These) –


kwargs will be forwarded to tables/cells. See evtable.EvCell and evtable.EvTable for info.