evennia/docs/1.0-dev/_modules/evennia/utils/evform.html
Evennia docbuilder action fd31020c21 Updated HTML docs.
2022-11-15 20:29:38 +00:00

667 lines
No EOL
68 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>evennia.utils.evform &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../../evennia.html" accesskey="U">evennia</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.utils.evform</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../../../index.html">
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="evform.html">1.0-dev (develop branch)</a></li>
<ul>
<li><a href="../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<h1>Source code for evennia.utils.evform</h1><div class="highlight"><pre>
<span></span><span class="c1"># coding=utf-8</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd">EvForm - a way to create advanced ASCII forms</span>
<span class="sd">This is intended for creating advanced ASCII game forms, such as a large pretty character sheet or</span>
<span class="sd">info document.</span>
<span class="sd">The system works on the basis of a readin template that is given in a separate Python file imported</span>
<span class="sd">into the handler. This file contains some optional settings and a string mapping out the form. The</span>
<span class="sd">template has markers in it to denounce fields to fill. The markers map the absolute size of the</span>
<span class="sd">field and will be filled with an `evtable.EvCell` object when displaying the form.</span>
<span class="sd">Example of input file `testform.py`:</span>
<span class="sd">```python</span>
<span class="sd">FORMCHAR = &quot;x&quot;</span>
<span class="sd">TABLECHAR = &quot;c&quot;</span>
<span class="sd">FORM = &#39;&#39;&#39;</span>
<span class="sd">.------------------------------------------------.</span>
<span class="sd">| |</span>
<span class="sd">| Name: xxxxx1xxxxx Player: xxxxxxx2xxxxxxx |</span>
<span class="sd">| xxxxxxxxxxx |</span>
<span class="sd">| |</span>
<span class="sd"> &gt;----------------------------------------------&lt;</span>
<span class="sd">| |</span>
<span class="sd">| Desc: xxxxxxxxxxx STR: x4x DEX: x5x |</span>
<span class="sd">| xxxxx3xxxxx INT: x6x STA: x7x |</span>
<span class="sd">| xxxxxxxxxxx LUC: x8x MAG: x9x |</span>
<span class="sd">| |</span>
<span class="sd"> &gt;----------------------------------------------&lt;</span>
<span class="sd">| | |</span>
<span class="sd">| cccccccc | ccccccccccccccccccccccccccccccccccc |</span>
<span class="sd">| cccccccc | ccccccccccccccccccccccccccccccccccc |</span>
<span class="sd">| cccAcccc | ccccccccccccccccccccccccccccccccccc |</span>
<span class="sd">| cccccccc | ccccccccccccccccccccccccccccccccccc |</span>
<span class="sd">| cccccccc | cccccccccccccccccBccccccccccccccccc |</span>
<span class="sd">| | |</span>
<span class="sd">| v&amp; |</span>
<span class="sd">-------------------------------------------------</span>
<span class="sd">&#39;&#39;&#39;</span>
<span class="sd">```</span>
<span class="sd">The first line of the `FORM` string is ignored if empty. The forms and table markers must mark out</span>
<span class="sd">complete, unbroken rectangles, each containing one embedded single-character identifier (so the</span>
<span class="sd">smallest element possible is a 3-character wide form). The identifier can be any character except</span>
<span class="sd">for the `FORM_CHAR` and `TABLE_CHAR` and some of the common ASCII-art elements, like space, `_` `|`</span>
<span class="sd">`*` etc (see `INVALID_FORMCHARS` in this module). Form Rectangles can have any size, but must be</span>
<span class="sd">separated from each other by at least one other character&#39;s width.</span>
<span class="sd">The form can also replace literal markers not abiding by these rules. For example, the `v&amp;` in the</span>
<span class="sd">bottom right corner could be such literal marker. If a literal-mapping for &#39;v&amp;&#39; is provided, all</span>
<span class="sd">occurrences of this marker will be replaced. This will happen *before* any other parsing, so in</span>
<span class="sd">principle this could be used to inject new fields/tables into the form dynamically. This literal</span>
<span class="sd">mapping does not consider width, but it will affect to total width of the form, so make sure what</span>
<span class="sd">you inject does not break things. Using literal markers is the only way to inject 1 or 2-character</span>
<span class="sd">replacements.</span>
<span class="sd">Usage</span>
<span class="sd">```python</span>
<span class="sd">from evennia import EvForm, EvTable</span>
<span class="sd"># create a new form from the template</span>
<span class="sd">form = EvForm(&quot;path/to/testform.py&quot;)</span>
<span class="sd"># alteratively, you can supply the template as a dict:</span>
<span class="sd">form = EvForm({&quot;FORM&quot;: &quot;....&quot;, &quot;TABLECHAR&quot;: &quot;c&quot;, &quot;FORMCHAR&quot;: &quot;x&quot;})</span>
<span class="sd"># EvForm can also take a dictionary instead of a filepath, as long</span>
<span class="sd"># as the dict contains the keys FORMCHAR, TABLECHAR and FORM</span>
<span class="sd"># form = EvForm(form=form_dict)</span>
<span class="sd"># add data to each tagged form cell</span>
<span class="sd">form.map(cells={1: &quot;Tom the Bouncer&quot;,</span>
<span class="sd"> 2: &quot;Griatch&quot;,</span>
<span class="sd"> 3: &quot;A sturdy fellow&quot;,</span>
<span class="sd"> 4: 12,</span>
<span class="sd"> 5: 10,</span>
<span class="sd"> 6: 5,</span>
<span class="sd"> 7: 18,</span>
<span class="sd"> 8: 10,</span>
<span class="sd"> 9: 3})</span>
<span class="sd"># create the EvTables</span>
<span class="sd">tableA = EvTable(&quot;HP&quot;,&quot;MV&quot;,&quot;MP&quot;,</span>
<span class="sd"> table=[[&quot;**&quot;], [&quot;*****&quot;], [&quot;***&quot;]],</span>
<span class="sd"> border=&quot;incols&quot;)</span>
<span class="sd">tableB = EvTable(&quot;Skill&quot;, &quot;Value&quot;, &quot;Exp&quot;,</span>
<span class="sd"> table=[[&quot;Shooting&quot;, &quot;Herbalism&quot;, &quot;Smithing&quot;],</span>
<span class="sd"> [12,14,9],[&quot;550/1200&quot;, &quot;990/1400&quot;, &quot;205/900&quot;]],</span>
<span class="sd"> border=&quot;incols&quot;)</span>
<span class="sd"># map &#39;literal&#39; replacents (here, a version string)</span>
<span class="sd">custom_mapping = {&quot;v&amp;&quot;, &quot;v2&quot;}</span>
<span class="sd"># add the tables to the proper ids in the form</span>
<span class="sd">form.map(tables={&quot;A&quot;: tableA,</span>
<span class="sd"> &quot;B&quot;: tableB})</span>
<span class="sd">print(form)</span>
<span class="sd">```</span>
<span class="sd">This produces the following result:</span>
<span class="sd">::</span>
<span class="sd"> .------------------------------------------------.</span>
<span class="sd"> | |</span>
<span class="sd"> | Name: Tom the Player: Griatch |</span>
<span class="sd"> | Bouncer |</span>
<span class="sd"> | |</span>
<span class="sd"> &gt;----------------------------------------------&lt;</span>
<span class="sd"> | |</span>
<span class="sd"> | Desc: A sturdy STR: 12 DEX: 10 |</span>
<span class="sd"> | fellow INT: 5 STA: 18 |</span>
<span class="sd"> | LUC: 10 MAG: 3 |</span>
<span class="sd"> | |</span>
<span class="sd"> &gt;----------------------------------------------&lt;</span>
<span class="sd"> | | |</span>
<span class="sd"> | HP|MV|MP | Skill |Value |Exp |</span>
<span class="sd"> | ~~+~~+~~ | ~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~ |</span>
<span class="sd"> | **|**|** | Shooting |12 |550/1200 |</span>
<span class="sd"> | |**|* | Herbalism |14 |990/1400 |</span>
<span class="sd"> | |* | | Smithing |9 |205/900 |</span>
<span class="sd"> | | |</span>
<span class="sd"> | v2 |</span>
<span class="sd"> ------------------------------------------------</span>
<span class="sd">The marked forms have been replaced with EvCells of text and with EvTables. The literal marker `v&amp;`</span>
<span class="sd">was replaced with `v2`.</span>
<span class="sd">If you change the form layout on disk, you can use `form.reload()` to re-read it from disk without</span>
<span class="sd">creating a new form.</span>
<span class="sd">If you want to update the data of an existing form, you can use `form.map()` with the changes - the</span>
<span class="sd">mappings will be updated, keeping the things you want. You can also update the template itself this</span>
<span class="sd">way, by supplying it as a dict.</span>
<span class="sd">Each component (except literal mappings) is restrained to the width and height specified by the</span>
<span class="sd">template, so it will resize to fit (or crop text if the area is too small for it). If you try to fit</span>
<span class="sd">a table into an area it cannot fit into (when including its borders and at least one line of text),</span>
<span class="sd">the form will raise an error.</span>
<span class="sd">----</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="kn">from</span> <span class="nn">copy</span> <span class="kn">import</span> <span class="n">copy</span>
<span class="kn">from</span> <span class="nn">evennia.utils.ansi</span> <span class="kn">import</span> <span class="n">ANSIString</span>
<span class="kn">from</span> <span class="nn">evennia.utils.ansi</span> <span class="kn">import</span> <span class="n">raw</span> <span class="k">as</span> <span class="n">ansi_raw</span>
<span class="kn">from</span> <span class="nn">evennia.utils.evtable</span> <span class="kn">import</span> <span class="n">EvCell</span><span class="p">,</span> <span class="n">EvTable</span>
<span class="kn">from</span> <span class="nn">evennia.utils.utils</span> <span class="kn">import</span> <span class="n">all_from_module</span><span class="p">,</span> <span class="n">is_iter</span><span class="p">,</span> <span class="n">to_str</span>
<span class="c1"># non-valid form-identifying characters (which can thus be</span>
<span class="c1"># used as separators between forms without being detected</span>
<span class="c1"># as an identifier). These should be listed in regex form.</span>
<span class="n">INVALID_FORMCHARS</span> <span class="o">=</span> <span class="sa">r</span><span class="s2">&quot;\s\/\|</span><span class="se">\\</span><span class="s2">\*\_\-\#\&lt;\&gt;\~\^\:\;\.\,&quot;</span>
<span class="c1"># if there is an ansi-escape (||) we have to replace this with ||| to make sure</span>
<span class="c1"># to properly escape down the line</span>
<span class="n">_ANSI_ESCAPE</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;\|\|&quot;</span><span class="p">)</span>
<div class="viewcode-block" id="EvForm"><a class="viewcode-back" href="../../../api/evennia.utils.evform.html#evennia.utils.evform.EvForm">[docs]</a><span class="k">class</span> <span class="nc">EvForm</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This object is instantiated with a text file and parses</span>
<span class="sd"> it for rectangular form fields. It can then be fed a</span>
<span class="sd"> mapping so as to populate the fields with fixed-width</span>
<span class="sd"> EvCell or Tables.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># cell option defaults</span>
<span class="n">cell_options</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;pad_left&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="s2">&quot;pad_right&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="s2">&quot;pad_top&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="s2">&quot;pad_bottom&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="s2">&quot;align&quot;</span><span class="p">:</span> <span class="s2">&quot;l&quot;</span><span class="p">,</span>
<span class="s2">&quot;valign&quot;</span><span class="p">:</span> <span class="s2">&quot;t&quot;</span><span class="p">,</span>
<span class="s2">&quot;enforce_size&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
<span class="p">}</span>
<span class="c1"># table option defaults</span>
<span class="n">table_options</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;pad_left&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="s2">&quot;pad_right&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="s2">&quot;pad_top&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="s2">&quot;pad_bottom&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="s2">&quot;align&quot;</span><span class="p">:</span> <span class="s2">&quot;l&quot;</span><span class="p">,</span>
<span class="s2">&quot;valign&quot;</span><span class="p">:</span> <span class="s2">&quot;t&quot;</span><span class="p">,</span>
<span class="s2">&quot;enforce_size&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
<span class="p">}</span>
<div class="viewcode-block" id="EvForm.__init__"><a class="viewcode-back" href="../../../api/evennia.utils.evform.html#evennia.utils.evform.EvForm.__init__">[docs]</a> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">cells</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">tables</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">literals</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Initiate the form</span>
<span class="sd"> Keyword Args:</span>
<span class="sd"> data (str or dict): Path to template file or a dict with</span>
<span class="sd"> &quot;formchar&quot;, &quot;tablechar&quot; and &quot;form&quot; keys (not case sensitive, so FORM etc</span>
<span class="sd"> also works, to stay compatible with the in-file names). While &quot;form/FORM&quot;</span>
<span class="sd"> is required, if FORMCHAR/TABLECHAR are not given, they will default to</span>
<span class="sd"> &#39;x&#39; and &#39;c&#39; respectively.</span>
<span class="sd"> cells (dict): A dictionary mapping `{id: str}`</span>
<span class="sd"> tables (dict): A dictionary mapping `{id: EvTable}`.</span>
<span class="sd"> literals (dict): A dictionary mapping `{id: str}`. Will be replaced</span>
<span class="sd"> after width of form is calculated, but before cells/tables are mapped.</span>
<span class="sd"> All occurrences of the identifier on the form will be replaced. Note</span>
<span class="sd"> that there is no length-restriction on the remap, you are responsible</span>
<span class="sd"> for not breaking the form.</span>
<span class="sd"> Notes:</span>
<span class="sd"> Other kwargs are fed as options to the EvCells and EvTables</span>
<span class="sd"> (see `evtable.EvCell` and `evtable.EvTable` for more info).</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">indata</span> <span class="o">=</span> <span class="n">data</span> <span class="c1"># storing here so we can reload later in case of a filename</span>
<span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_parse_inkwargs</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cells_mapping</span> <span class="o">=</span> <span class="p">(</span>
<span class="nb">dict</span><span class="p">((</span><span class="n">to_str</span><span class="p">(</span><span class="n">key</span><span class="p">),</span> <span class="n">value</span><span class="p">)</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">cells</span><span class="o">.</span><span class="n">items</span><span class="p">())</span> <span class="k">if</span> <span class="n">cells</span> <span class="k">else</span> <span class="p">{}</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tables_mapping</span> <span class="o">=</span> <span class="p">(</span>
<span class="nb">dict</span><span class="p">((</span><span class="n">to_str</span><span class="p">(</span><span class="n">key</span><span class="p">),</span> <span class="n">value</span><span class="p">)</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">tables</span><span class="o">.</span><span class="n">items</span><span class="p">())</span> <span class="k">if</span> <span class="n">tables</span> <span class="k">else</span> <span class="p">{}</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">literals_mapping</span> <span class="o">=</span> <span class="p">(</span>
<span class="nb">dict</span><span class="p">((</span><span class="n">to_str</span><span class="p">(</span><span class="n">key</span><span class="p">),</span> <span class="n">to_str</span><span class="p">(</span><span class="n">value</span><span class="p">))</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">literals</span><span class="o">.</span><span class="n">items</span><span class="p">())</span>
<span class="k">if</span> <span class="n">literals</span>
<span class="k">else</span> <span class="p">{}</span>
<span class="p">)</span>
<span class="c1"># work arrays</span>
<span class="bp">self</span><span class="o">.</span><span class="n">literal_form</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">mapping</span> <span class="o">=</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">matrix</span> <span class="o">=</span> <span class="p">[]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">form</span> <span class="o">=</span> <span class="p">[]</span>
<span class="c1"># will parse and build the form</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reload</span><span class="p">()</span></div>
<span class="k">def</span> <span class="nf">_parse_indata</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Parse and validate the `self.indata` property. We do this in order to be able to</span>
<span class="sd"> re-load the evform module if indata is a filename and catch any on-file changes.</span>
<span class="sd"> Returns:</span>
<span class="sd"> dict: The data dict parsed/generated from the in-data.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">data</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">indata</span>
<span class="n">default_formchar</span> <span class="o">=</span> <span class="s2">&quot;x&quot;</span>
<span class="n">default_tablechar</span> <span class="o">=</span> <span class="s2">&quot;c&quot;</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="c1"># a module path - read all variables from it</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">all_from_module</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;form&quot;</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;form&quot;</span><span class="p">,</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;FORM&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">))),</span>
<span class="s2">&quot;formchar&quot;</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;formchar&quot;</span><span class="p">,</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;FORMCHAR&quot;</span><span class="p">,</span> <span class="n">default_formchar</span><span class="p">))),</span>
<span class="s2">&quot;tablechar&quot;</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;tablechar&quot;</span><span class="p">,</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;TABLECHAR&quot;</span><span class="p">,</span> <span class="n">default_tablechar</span><span class="p">))),</span>
<span class="p">}</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;EvForm invalid input: </span><span class="si">{</span><span class="n">data</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">data</span> <span class="ow">or</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;form&quot;</span><span class="p">]</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">&quot;Evform data must specify a valid &#39;form&#39; or &#39;FORM&#39;.&quot;</span><span class="p">)</span>
<span class="c1"># handle empty or multi-character form/tablechars (not supported)</span>
<span class="n">data</span><span class="p">[</span><span class="s2">&quot;formchar&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;formchar&quot;</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;formchar&quot;</span><span class="p">]</span> <span class="k">else</span> <span class="n">default_formchar</span>
<span class="n">data</span><span class="p">[</span><span class="s2">&quot;tablechar&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;tablechar&quot;</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;tablechar&quot;</span><span class="p">]</span> <span class="k">else</span> <span class="n">default_tablechar</span>
<span class="k">if</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">rf</span><span class="s2">&quot;[</span><span class="si">{</span><span class="n">INVALID_FORMCHARS</span><span class="si">}</span><span class="s2">]&quot;</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;formchar&quot;</span><span class="p">]):</span>
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid formchar: </span><span class="si">{</span><span class="n">data</span><span class="p">[</span><span class="s1">&#39;formchar&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">rf</span><span class="s2">&quot;[</span><span class="si">{</span><span class="n">INVALID_FORMCHARS</span><span class="si">}</span><span class="s2">]&quot;</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;tablechar&quot;</span><span class="p">]):</span>
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid tablechar: </span><span class="si">{</span><span class="n">data</span><span class="p">[</span><span class="s1">&#39;tablechar&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">data</span>
<span class="k">def</span> <span class="nf">_parse_inkwargs</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Validate incoming kwargs that will be passed on to become cell/table options.</span>
<span class="sd"> Keyword Args:</span>
<span class="sd"> any: Kwargs to process.</span>
<span class="sd"> Returns:</span>
<span class="sd"> dict: A validated/cleaned kwarg to use for options.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="s2">&quot;filename&quot;</span> <span class="ow">in</span> <span class="n">kwargs</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">DeprecationWarning</span><span class="p">(</span>
<span class="s2">&quot;EvForm&#39;s &#39;filename&#39; kwarg was renamed to &#39;data&#39; and can now accept both &quot;</span>
<span class="s2">&quot;a python path and a dict with &#39;FORMCHAR&#39;, &#39;TABLECHAR&#39; and &#39;FORM&#39; keys.&quot;</span>
<span class="p">)</span>
<span class="k">if</span> <span class="s2">&quot;form&quot;</span> <span class="ow">in</span> <span class="n">kwargs</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">DeprecationWarning</span><span class="p">(</span>
<span class="s2">&quot;EvForms&#39;s &#39;form&#39; kwarg was renamed to &#39;data&#39; and can now accept both &quot;</span>
<span class="s2">&quot;a python path and a dict detailing the form.&quot;</span>
<span class="p">)</span>
<span class="c1"># clean cell kwarg options (these cannot be overridden on the cell but must be controlled</span>
<span class="c1"># by the evform itself)</span>
<span class="n">kwargs</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s2">&quot;enforce_size&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="n">kwargs</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s2">&quot;width&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="n">kwargs</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s2">&quot;height&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="k">return</span> <span class="n">kwargs</span>
<span class="k">def</span> <span class="nf">_do_literal_mapping</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Do literal replacement in the EvForm.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">literal_form</span> <span class="o">=</span> <span class="n">copy</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;form&quot;</span><span class="p">])</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">repl</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">literals_mapping</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="n">literal_form</span> <span class="o">=</span> <span class="n">literal_form</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">repl</span><span class="p">)</span>
<span class="k">return</span> <span class="n">literal_form</span>
<span class="k">def</span> <span class="nf">_parse_to_matrix</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Forces all lines to be as long as the longest line, filling with whitespace.</span>
<span class="sd"> Args:</span>
<span class="sd"> lines (list): list of `ANSIString`s</span>
<span class="sd"> Returns:</span>
<span class="sd"> (list): list of `ANSIString`s of</span>
<span class="sd"> same length as the longest input line</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">matrix</span> <span class="o">=</span> <span class="n">EvForm</span><span class="o">.</span><span class="n">_to_ansi</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">literal_form</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">))</span>
<span class="n">maxl</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">line</span><span class="p">)</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">matrix</span><span class="p">)</span>
<span class="n">matrix</span> <span class="o">=</span> <span class="p">[</span><span class="n">line</span> <span class="o">+</span> <span class="s2">&quot; &quot;</span> <span class="o">*</span> <span class="p">(</span><span class="n">maxl</span> <span class="o">-</span> <span class="nb">len</span><span class="p">(</span><span class="n">line</span><span class="p">))</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">matrix</span><span class="p">]</span>
<span class="k">if</span> <span class="n">matrix</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">matrix</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">strip</span><span class="p">():</span>
<span class="c1"># the first line is normally empty, we strip it.</span>
<span class="n">matrix</span> <span class="o">=</span> <span class="n">matrix</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span>
<span class="k">return</span> <span class="n">matrix</span>
<span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="nf">_to_ansi</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">regexable</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="s2">&quot;convert anything to ANSIString&quot;</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">ANSIString</span><span class="p">):</span>
<span class="k">return</span> <span class="n">obj</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="c1"># since ansi will be parsed twice (here and in the normal ansi send), we have to</span>
<span class="c1"># escape ansi twice.</span>
<span class="n">obj</span> <span class="o">=</span> <span class="n">ansi_raw</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">dict</span><span class="p">(</span>
<span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">EvForm</span><span class="o">.</span><span class="n">_to_ansi</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">regexable</span><span class="o">=</span><span class="n">regexable</span><span class="p">))</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">obj</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
<span class="p">)</span>
<span class="c1"># regular _to_ansi (from EvTable)</span>
<span class="k">elif</span> <span class="n">is_iter</span><span class="p">(</span><span class="n">obj</span><span class="p">):</span>
<span class="k">return</span> <span class="p">[</span><span class="n">EvForm</span><span class="o">.</span><span class="n">_to_ansi</span><span class="p">(</span><span class="n">o</span><span class="p">)</span> <span class="k">for</span> <span class="n">o</span> <span class="ow">in</span> <span class="n">obj</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">ANSIString</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">regexable</span><span class="o">=</span><span class="n">regexable</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_rectangles_to_mapping</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Parse a form for rectangular formfields identified by formchar/tablechar enclosing an</span>
<span class="sd"> identifier.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">formchar</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;formchar&quot;</span><span class="p">]</span>
<span class="n">tablechar</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;tablechar&quot;</span><span class="p">]</span>
<span class="n">matrix</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">matrix</span>
<span class="n">cell_options</span> <span class="o">=</span> <span class="n">copy</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">cell_options</span><span class="p">)</span>
<span class="n">cell_options</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="p">)</span>
<span class="n">table_options</span> <span class="o">=</span> <span class="n">copy</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">table_options</span><span class="p">)</span>
<span class="n">table_options</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="p">)</span>
<span class="n">nmatrix</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">matrix</span><span class="p">)</span>
<span class="n">mapping</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">def</span> <span class="nf">_get_rectangles</span><span class="p">(</span><span class="n">char</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Find all identified rectangles marked with given char&quot;&quot;&quot;</span>
<span class="n">rects</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">coords</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">regex</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">rf</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">char</span><span class="si">}</span><span class="s2">+([^</span><span class="si">{</span><span class="n">INVALID_FORMCHARS</span><span class="si">}{</span><span class="n">char</span><span class="si">}</span><span class="s2">]+)</span><span class="si">{</span><span class="n">char</span><span class="si">}</span><span class="s2">+&quot;</span><span class="p">)</span>
<span class="c1"># find the start/width of rectangles for each line</span>
<span class="k">for</span> <span class="n">iy</span><span class="p">,</span> <span class="n">line</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">EvForm</span><span class="o">.</span><span class="n">_to_ansi</span><span class="p">(</span><span class="n">matrix</span><span class="p">,</span> <span class="n">regexable</span><span class="o">=</span><span class="kc">True</span><span class="p">)):</span>
<span class="n">ix0</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="n">match</span> <span class="o">=</span> <span class="n">regex</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">line</span><span class="p">,</span> <span class="n">ix0</span><span class="p">)</span>
<span class="k">if</span> <span class="n">match</span><span class="p">:</span>
<span class="c1"># get the width of the rectangle directly from the match</span>
<span class="n">coords</span><span class="p">[</span><span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)]</span> <span class="o">=</span> <span class="p">[</span><span class="n">iy</span><span class="p">,</span> <span class="n">match</span><span class="o">.</span><span class="n">start</span><span class="p">(),</span> <span class="n">match</span><span class="o">.</span><span class="n">end</span><span class="p">()]</span>
<span class="n">ix0</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">end</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">break</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="p">(</span><span class="n">iy</span><span class="p">,</span> <span class="n">leftix</span><span class="p">,</span> <span class="n">rightix</span><span class="p">)</span> <span class="ow">in</span> <span class="n">coords</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="c1"># scan up to find top of rectangle</span>
<span class="n">dy_up</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">if</span> <span class="n">iy</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">iy</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">all</span><span class="p">(</span><span class="n">matrix</span><span class="p">[</span><span class="n">iy</span> <span class="o">-</span> <span class="n">i</span><span class="p">][</span><span class="n">ix</span><span class="p">]</span> <span class="o">==</span> <span class="n">char</span> <span class="k">for</span> <span class="n">ix</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">leftix</span><span class="p">,</span> <span class="n">rightix</span><span class="p">)):</span>
<span class="n">dy_up</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">break</span>
<span class="c1"># find bottom edge of rectangle</span>
<span class="n">dy_down</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">if</span> <span class="n">iy</span> <span class="o">&lt;</span> <span class="n">nmatrix</span> <span class="o">-</span> <span class="mi">1</span><span class="p">:</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">nmatrix</span> <span class="o">-</span> <span class="n">iy</span> <span class="o">-</span> <span class="mi">1</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">all</span><span class="p">(</span><span class="n">matrix</span><span class="p">[</span><span class="n">iy</span> <span class="o">+</span> <span class="n">i</span><span class="p">][</span><span class="n">ix</span><span class="p">]</span> <span class="o">==</span> <span class="n">char</span> <span class="k">for</span> <span class="n">ix</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">leftix</span><span class="p">,</span> <span class="n">rightix</span><span class="p">)):</span>
<span class="n">dy_down</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">break</span>
<span class="c1"># we have our rectangle. Calculate size</span>
<span class="n">iyup</span> <span class="o">=</span> <span class="n">iy</span> <span class="o">-</span> <span class="n">dy_up</span>
<span class="n">iydown</span> <span class="o">=</span> <span class="n">iy</span> <span class="o">+</span> <span class="n">dy_down</span>
<span class="n">width</span> <span class="o">=</span> <span class="n">rightix</span> <span class="o">-</span> <span class="n">leftix</span>
<span class="n">height</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">iyup</span> <span class="o">-</span> <span class="n">iydown</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span>
<span class="c1"># store (key, y, x, width, height) of triangle</span>
<span class="n">rects</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">key</span><span class="p">,</span> <span class="n">iyup</span><span class="p">,</span> <span class="n">leftix</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">))</span>
<span class="k">return</span> <span class="n">rects</span>
<span class="c1"># Map EvCells into form rectangles</span>
<span class="k">for</span> <span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">)</span> <span class="ow">in</span> <span class="n">_get_rectangles</span><span class="p">(</span><span class="n">formchar</span><span class="p">):</span>
<span class="c1"># get data to populate cell</span>
<span class="n">data</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cells_mapping</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">EvCell</span><span class="p">):</span>
<span class="c1"># mapping already provides the cell. We need to override some</span>
<span class="c1"># of the cell&#39;s options to make it work in the evform rectangle.</span>
<span class="c1"># We retain the align/valign since this may be interesting to</span>
<span class="c1"># play with within the rectangle.</span>
<span class="n">cell</span> <span class="o">=</span> <span class="n">data</span>
<span class="n">custom_align</span> <span class="o">=</span> <span class="n">cell</span><span class="o">.</span><span class="n">align</span>
<span class="n">custom_valign</span> <span class="o">=</span> <span class="n">cell</span><span class="o">.</span><span class="n">valign</span>
<span class="n">cell</span><span class="o">.</span><span class="n">reformat</span><span class="p">(</span>
<span class="n">width</span><span class="o">=</span><span class="n">width</span><span class="p">,</span>
<span class="n">height</span><span class="o">=</span><span class="n">height</span><span class="p">,</span>
<span class="o">**</span><span class="p">{</span><span class="o">**</span><span class="n">cell_options</span><span class="p">,</span> <span class="o">**</span><span class="p">{</span><span class="s2">&quot;align&quot;</span><span class="p">:</span> <span class="n">custom_align</span><span class="p">,</span> <span class="s2">&quot;valign&quot;</span><span class="p">:</span> <span class="n">custom_valign</span><span class="p">}},</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># generating cell on the fly</span>
<span class="n">cell</span> <span class="o">=</span> <span class="n">EvCell</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="o">=</span><span class="n">height</span><span class="p">,</span> <span class="o">**</span><span class="n">cell_options</span><span class="p">)</span>
<span class="n">mapping</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">,</span> <span class="n">cell</span><span class="p">)</span>
<span class="c1"># Map EvTables into form rectangles</span>
<span class="k">for</span> <span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">)</span> <span class="ow">in</span> <span class="n">_get_rectangles</span><span class="p">(</span><span class="n">tablechar</span><span class="p">):</span>
<span class="c1"># get EvTable from mapping</span>
<span class="n">table</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tables_mapping</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="k">if</span> <span class="n">table</span><span class="p">:</span>
<span class="n">table</span><span class="o">.</span><span class="n">reformat</span><span class="p">(</span><span class="n">width</span><span class="o">=</span><span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="o">=</span><span class="n">height</span><span class="p">,</span> <span class="o">**</span><span class="n">table_options</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">table</span> <span class="o">=</span> <span class="n">EvTable</span><span class="p">(</span><span class="n">width</span><span class="o">=</span><span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="o">=</span><span class="n">height</span><span class="p">,</span> <span class="o">**</span><span class="n">table_options</span><span class="p">)</span>
<span class="n">mapping</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">,</span> <span class="n">table</span><span class="p">)</span>
<span class="k">return</span> <span class="n">mapping</span>
<span class="k">def</span> <span class="nf">_build_form</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Insert cell/table contents into form at given locations to create</span>
<span class="sd"> the final result.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">form</span> <span class="o">=</span> <span class="n">copy</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">matrix</span><span class="p">)</span>
<span class="n">mapping</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">mapping</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">,</span> <span class="n">cell_or_table</span><span class="p">)</span> <span class="ow">in</span> <span class="n">mapping</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="c1"># rect is a list of &lt;height&gt; lines, each &lt;width&gt; wide</span>
<span class="n">rect</span> <span class="o">=</span> <span class="n">cell_or_table</span><span class="o">.</span><span class="n">get</span><span class="p">()</span>
<span class="k">for</span> <span class="n">il</span><span class="p">,</span> <span class="n">rectline</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">rect</span><span class="p">):</span>
<span class="n">formline</span> <span class="o">=</span> <span class="n">form</span><span class="p">[</span><span class="n">y</span> <span class="o">+</span> <span class="n">il</span><span class="p">]</span>
<span class="c1"># insert new content, replacing old</span>
<span class="n">form</span><span class="p">[</span><span class="n">y</span> <span class="o">+</span> <span class="n">il</span><span class="p">]</span> <span class="o">=</span> <span class="n">formline</span><span class="p">[:</span><span class="n">x</span><span class="p">]</span> <span class="o">+</span> <span class="n">rectline</span> <span class="o">+</span> <span class="n">formline</span><span class="p">[</span><span class="n">x</span> <span class="o">+</span> <span class="n">width</span> <span class="p">:]</span>
<span class="k">return</span> <span class="n">form</span>
<div class="viewcode-block" id="EvForm.reload"><a class="viewcode-back" href="../../../api/evennia.utils.evform.html#evennia.utils.evform.EvForm.reload">[docs]</a> <span class="k">def</span> <span class="nf">reload</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Creates the form from a filename or data structure.</span>
<span class="sd"> Args:</span>
<span class="sd"> data (str or dict): Can be used to update an existing form using</span>
<span class="sd"> the same cells/tables provided on initialization or using `.map()`.</span>
<span class="sd"> Notes:</span>
<span class="sd"> Kwargs are passed through to Cel creation.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_parse_indata</span><span class="p">()</span>
<span class="c1"># Map any literals into the string</span>
<span class="bp">self</span><span class="o">.</span><span class="n">literal_form</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_do_literal_mapping</span><span class="p">()</span>
<span class="c1"># Create raw form matrix, indexable with (y, x) coords</span>
<span class="bp">self</span><span class="o">.</span><span class="n">matrix</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_parse_to_matrix</span><span class="p">()</span>
<span class="c1"># parse and identify all rectangles in the form</span>
<span class="bp">self</span><span class="o">.</span><span class="n">mapping</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_rectangles_to_mapping</span><span class="p">()</span>
<span class="c1"># combine mapping with form template into a final result</span>
<span class="bp">self</span><span class="o">.</span><span class="n">form</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_build_form</span><span class="p">()</span></div>
<div class="viewcode-block" id="EvForm.map"><a class="viewcode-back" href="../../../api/evennia.utils.evform.html#evennia.utils.evform.EvForm.map">[docs]</a> <span class="k">def</span> <span class="nf">map</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cells</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">tables</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">literals</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Add mapping for form. This allows for updating an existing</span>
<span class="sd"> evform.</span>
<span class="sd"> Args:</span>
<span class="sd"> cells (dict): A dictionary of {identifier:celltext}. These</span>
<span class="sd"> will be appended to the existing mappings.</span>
<span class="sd"> tables (dict): A dictionary of {identifier:table}. Will</span>
<span class="sd"> be appended to the existing mapping.</span>
<span class="sd"> data (str or dict): A path to a evform module or a dict with</span>
<span class="sd"> the needed &quot;FORM&quot;, &quot;TABLE/FORMCHAR&quot; keys. Will replace</span>
<span class="sd"> the originally initialized form.</span>
<span class="sd"> literals</span>
<span class="sd"> Keyword Args:</span>
<span class="sd"> These will be appended to the existing cell/table options.</span>
<span class="sd"> Notes:</span>
<span class="sd"> kwargs will be forwarded to tables/cells. See</span>
<span class="sd"> `evtable.EvCell` and `evtable.EvTable` for info.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">data</span><span class="p">:</span>
<span class="c1"># storing so ._parse_indata will find it during reload</span>
<span class="bp">self</span><span class="o">.</span><span class="n">indata</span> <span class="o">=</span> <span class="n">data</span>
<span class="n">new_cells</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">((</span><span class="n">to_str</span><span class="p">(</span><span class="n">key</span><span class="p">),</span> <span class="n">value</span><span class="p">)</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">cells</span><span class="o">.</span><span class="n">items</span><span class="p">())</span> <span class="k">if</span> <span class="n">cells</span> <span class="k">else</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cells_mapping</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">new_cells</span><span class="p">)</span>
<span class="n">new_tables</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">((</span><span class="n">to_str</span><span class="p">(</span><span class="n">key</span><span class="p">),</span> <span class="n">value</span><span class="p">)</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">tables</span><span class="o">.</span><span class="n">items</span><span class="p">())</span> <span class="k">if</span> <span class="n">tables</span> <span class="k">else</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tables_mapping</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">new_tables</span><span class="p">)</span>
<span class="n">new_literals</span> <span class="o">=</span> <span class="p">(</span>
<span class="nb">dict</span><span class="p">((</span><span class="n">to_str</span><span class="p">(</span><span class="n">key</span><span class="p">),</span> <span class="n">to_str</span><span class="p">(</span><span class="n">value</span><span class="p">))</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">literals</span><span class="o">.</span><span class="n">items</span><span class="p">())</span>
<span class="k">if</span> <span class="n">literals</span>
<span class="k">else</span> <span class="p">{}</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">literals_mapping</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">new_literals</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_parse_inkwargs</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">))</span>
<span class="c1"># parse and build the form</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reload</span><span class="p">()</span></div>
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="s2">&quot;Prints the form&quot;</span>
<span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">ANSIString</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">line</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">form</span><span class="p">]))</span></div>
</pre></div>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../../evennia.html" >evennia</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.utils.evform</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2022, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>