Add documentation for the core lua gui library stuff.

develop
Alexander Gavrilov 2012-11-04 17:06:32 +04:00
parent 9598316855
commit bd8c59462c
4 changed files with 1603 additions and 18 deletions

@ -377,12 +377,34 @@ ul.auto-toc {
<li><a class="reference internal" href="#class" id="id35">class</a></li>
</ul>
</li>
<li><a class="reference internal" href="#plugins" id="id36">Plugins</a><ul>
<li><a class="reference internal" href="#burrows" id="id37">burrows</a></li>
<li><a class="reference internal" href="#sort" id="id38">sort</a></li>
<li><a class="reference internal" href="#in-game-ui-library" id="id36">In-game UI Library</a><ul>
<li><a class="reference internal" href="#gui" id="id37">gui</a><ul>
<li><a class="reference internal" href="#misc" id="id38">Misc</a></li>
<li><a class="reference internal" href="#viewrect-class" id="id39">ViewRect class</a></li>
<li><a class="reference internal" href="#painter-class" id="id40">Painter class</a></li>
<li><a class="reference internal" href="#view-class" id="id41">View class</a></li>
<li><a class="reference internal" href="#screen-class" id="id42">Screen class</a></li>
<li><a class="reference internal" href="#framedscreen-class" id="id43">FramedScreen class</a></li>
</ul>
</li>
<li><a class="reference internal" href="#scripts" id="id39">Scripts</a></li>
<li><a class="reference internal" href="#gui-widgets" id="id44">gui.widgets</a><ul>
<li><a class="reference internal" href="#widget-class" id="id45">Widget class</a></li>
<li><a class="reference internal" href="#panel-class" id="id46">Panel class</a></li>
<li><a class="reference internal" href="#pages-class" id="id47">Pages class</a></li>
<li><a class="reference internal" href="#editfield-class" id="id48">EditField class</a></li>
<li><a class="reference internal" href="#label-class" id="id49">Label class</a></li>
<li><a class="reference internal" href="#list-class" id="id50">List class</a></li>
<li><a class="reference internal" href="#filteredlist-class" id="id51">FilteredList class</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#plugins" id="id52">Plugins</a><ul>
<li><a class="reference internal" href="#burrows" id="id53">burrows</a></li>
<li><a class="reference internal" href="#sort" id="id54">sort</a></li>
</ul>
</li>
<li><a class="reference internal" href="#scripts" id="id55">Scripts</a></li>
</ul>
</div>
<p>The current version of DFHack has extensive support for
@ -1584,6 +1606,10 @@ The values can then be used for the <em>tile</em> field of <em>pen</em> structur
<p>Requests repaint of the screen by setting a flag. Unlike other
functions in this section, this may be used at any time.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.screen.getKeyDisplay(key)</tt></p>
<p>Returns the string that should be used to represent the given
logical keybinding on the screen in texts like &quot;press Key to ...&quot;.</p>
</li>
</ul>
<p>The &quot;pen&quot; argument used by functions above may be represented by
a table with the following possible fields:</p>
@ -1889,6 +1915,19 @@ SC_MAP_UNLOADED, SC_VIEWSCREEN_CHANGED, SC_CORE_INITIALIZED</p>
<li><p class="first">Functions already described above</p>
<p>safecall, qerror, mkmodule, reload</p>
</li>
<li><p class="first">Miscellaneous constants</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name" colspan="2">NEWLINE, COMMA, PERIOD:</th></tr>
<tr class="field"><td>&nbsp;</td><td class="field-body">evaluate to the relevant character strings.</td>
</tr>
<tr class="field"><th class="field-name">DEFAULT_NIL:</th><td class="field-body">is an unspecified unique token used by the class module below.</td>
</tr>
</tbody>
</table>
</li>
<li><p class="first"><tt class="docutils literal">printall(obj)</tt></p>
<p>If the argument is a lua table or DF object reference, prints all fields.</p>
</li>
@ -1988,11 +2027,25 @@ are converted to 1-based lua sequences.</p>
as a guide to which values should be skipped as uninteresting.
The <tt class="docutils literal">force</tt> argument makes it always return a non-<em>nil</em> value.</p>
</li>
<li><p class="first"><tt class="docutils literal">utils.parse_bitfield_int(value, type_ref)</tt></p>
<p>Given an int <tt class="docutils literal">value</tt>, and a bitfield type in the <tt class="docutils literal">df</tt> tree,
it returns a lua table mapping the enabled bit keys to <em>true</em>,
unless value is 0, in which case it returns <em>nil</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal">utils.list_bitfield_flags(bitfield[, list])</tt></p>
<p>Adds all enabled bitfield keys to <tt class="docutils literal">list</tt> or a newly-allocated
empty sequence, and returns it. The <tt class="docutils literal">bitfield</tt> argument may
be <em>nil</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal">utils.sort_vector(vector,field,cmpfun)</tt></p>
<p>Sorts a native vector or lua sequence using the comparator function.
If <tt class="docutils literal">field</tt> is not <em>nil</em>, applies the comparator to the field instead
of the whole object.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">utils.linear_index(vector,key[,field])</span></tt></p>
<p>Searches for <tt class="docutils literal">key</tt> in the vector, and returns <em>index, found_value</em>,
or <em>nil</em> if none found.</p>
</li>
<li><p class="first"><tt class="docutils literal">utils.binsearch(vector,key,field,cmpfun,min,max)</tt></p>
<p>Does a binary search in a native vector or lua sequence for
<tt class="docutils literal">key</tt>, using <tt class="docutils literal">cmpfun</tt> and <tt class="docutils literal">field</tt> like sort_vector.
@ -2021,6 +2074,19 @@ utils.insert_or_update(soul.skills, {new=true, id=..., rating=...}, 'id')
<li><p class="first"><tt class="docutils literal">utils.erase_sorted(vector,item,field,cmpfun)</tt></p>
<p>Exactly like <tt class="docutils literal">erase_sorted_key</tt>, but if field is specified, takes the key from <tt class="docutils literal">item[field]</tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">utils.call_with_string(obj,methodname,...)</span></tt></p>
<p>Allocates a temporary string object, calls <tt class="docutils literal"><span class="pre">obj:method(tmp,...)</span></tt>, and
returns the value written into the temporary after deleting it.</p>
</li>
<li><p class="first"><tt class="docutils literal">utils.getBuildingName(building)</tt></p>
<p>Returns the string description of the given building.</p>
</li>
<li><p class="first"><tt class="docutils literal">utils.getBuildingCenter(building)</tt></p>
<p>Returns an x/y/z table pointing at the building center.</p>
</li>
<li><p class="first"><tt class="docutils literal">utils.split_string(string, delimiter)</tt></p>
<p>Splits the string by the given delimiter, and returns a sequence of results.</p>
</li>
<li><p class="first"><tt class="docutils literal">utils.prompt_yes_no(prompt, default)</tt></p>
<p>Presents a yes/no prompt to the user. If <tt class="docutils literal">default</tt> is not <em>nil</em>,
allows just pressing Enter to submit the default choice.
@ -2072,19 +2138,31 @@ calling superclass methods.</p>
from fields in the table used as the constructor argument. If omitted,
they are initialized with the default values specified in this declaration.</p>
<p>If the default value should be <em>nil</em>, use <tt class="docutils literal">ATTRS { foo = DEFAULT_NIL }</tt>.</p>
<p>Declaring an attribute is mostly the same as defining your <tt class="docutils literal">init</tt> method like this:</p>
<pre class="literal-block">
function Class.init(args)
self.attr1 = args.attr1 or default1
self.attr2 = args.attr2 or default2
...
end
</pre>
<p>The main difference is that attributes are processed as a separate
initialization step, before any <tt class="docutils literal">init</tt> methods are called. They
also make the directy relation between instance fields and constructor
arguments more explicit.</p>
</li>
<li><p class="first"><tt class="docutils literal">new_obj = Class{ foo = arg, bar = arg, ... }</tt></p>
<p>Calling the class as a function creates and initializes a new instance.
Initialization happens in this order:</p>
<ol class="arabic simple">
<li>An empty instance table is created, and its metatable set.</li>
<li>The <tt class="docutils literal">preinit</tt> method is called via <tt class="docutils literal">invoke_before</tt> (see below)
with the table used as argument to the class. This method is intended
<li>The <tt class="docutils literal">preinit</tt> methods are called via <tt class="docutils literal">invoke_before</tt> (see below)
with the table used as argument to the class. These methods are intended
for validating and tweaking that argument table.</li>
<li>Declared ATTRS are initialized from the argument table or their default values.</li>
<li>The <tt class="docutils literal">init</tt> method is called via <tt class="docutils literal">invoke_after</tt> with the argument table.
<li>The <tt class="docutils literal">init</tt> methods are called via <tt class="docutils literal">invoke_after</tt> with the argument table.
This is the main constructor method.</li>
<li>The <tt class="docutils literal">postinit</tt> method is called via <tt class="docutils literal">invoke_after</tt> with the argument table.
<li>The <tt class="docutils literal">postinit</tt> methods are called via <tt class="docutils literal">invoke_after</tt> with the argument table.
Place code that should be called after the object is fully constructed here.</li>
</ol>
</li>
@ -2099,6 +2177,12 @@ Place code that should be called after the object is fully constructed here.</li
properly passing in self, and optionally a number of initial arguments too.
The arguments given to the closure are appended to these.</p>
</li>
<li><p class="first"><tt class="docutils literal">instance:cb_getfield(field_name)</tt></p>
<p>Returns a closure that returns the specified field of the object when called.</p>
</li>
<li><p class="first"><tt class="docutils literal">instance:cb_setfield(field_name)</tt></p>
<p>Returns a closure that sets the specified field to its argument when called.</p>
</li>
<li><p class="first"><tt class="docutils literal">instance:invoke_before(method_name, <span class="pre">args...)</span></tt></p>
<p>Navigates the inheritance chain of the instance starting from the most specific
class, and invokes the specified method with the arguments if it is defined in
@ -2123,15 +2207,740 @@ library itself uses them for constructors.</p>
<p>To avoid confusion, these methods cannot be redefined.</p>
</div>
</div>
<div class="section" id="in-game-ui-library">
<h1><a class="toc-backref" href="#id36">In-game UI Library</a></h1>
<p>A number of lua modules with names starting with <tt class="docutils literal">gui</tt> are dedicated
to wrapping the natives of the <tt class="docutils literal">dfhack.screen</tt> module in a way that
is easy to use. This allows relatively easily and naturally creating
dialogs that integrate in the main game UI window.</p>
<p>These modules make extensive use of the <tt class="docutils literal">class</tt> module, and define
things ranging from the basic <tt class="docutils literal">Painter</tt>, <tt class="docutils literal">View</tt> and <tt class="docutils literal">Screen</tt>
classes, to fully functional predefined dialogs.</p>
<div class="section" id="gui">
<h2><a class="toc-backref" href="#id37">gui</a></h2>
<p>This module defines the most important classes and functions for
implementing interfaces. This documents those of them that are
considered stable.</p>
<div class="section" id="misc">
<h3><a class="toc-backref" href="#id38">Misc</a></h3>
<ul>
<li><p class="first"><tt class="docutils literal">USE_GRAPHICS</tt></p>
<p>Contains the value of <tt class="docutils literal">dfhack.screen.inGraphicsMode()</tt>, which cannot be
changed without restarting the game and thus is constant during the session.</p>
</li>
<li><p class="first"><tt class="docutils literal">CLEAR_PEN</tt></p>
<p>The black pen used to clear the screen.</p>
</li>
<li><p class="first"><tt class="docutils literal">simulateInput(screen, <span class="pre">keys...)</span></tt></p>
<p>This function wraps an undocumented native function that passes a set of
keycodes to a screen, and is the official way to do that.</p>
<p>Every argument after the initial screen may be <em>nil</em>, a numeric keycode,
a string keycode, a sequence of numeric or string keycodes, or a mapping
of keycodes to <em>true</em> or <em>false</em>. For instance, it is possible to use the
table passed as argument to <tt class="docutils literal">onInput</tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal">mkdims_xy(x1,y1,x2,y2)</tt></p>
<p>Returns a table containing the arguments as fields, and also <tt class="docutils literal">width</tt> and
<tt class="docutils literal">height</tt> that contains the rectangle dimensions.</p>
</li>
<li><p class="first"><tt class="docutils literal">mkdims_wh(x1,y1,width,height)</tt></p>
<p>Returns the same kind of table as <tt class="docutils literal">mkdims_xy</tt>, only this time it computes
<tt class="docutils literal">x2</tt> and <tt class="docutils literal">y2</tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal">is_in_rect(rect,x,y)</tt></p>
<p>Checks if the given point is within a rectangle, represented by a table produced
by one of the <tt class="docutils literal">mkdims</tt> functions.</p>
</li>
<li><p class="first"><tt class="docutils literal">blink_visible(delay)</tt></p>
<p>Returns <em>true</em> or <em>false</em>, with the value switching to the opposite every <tt class="docutils literal">delay</tt>
msec. This is intended for rendering blinking interface objects.</p>
</li>
<li><p class="first"><tt class="docutils literal">getKeyDisplay(keycode)</tt></p>
<p>Wraps <tt class="docutils literal">dfhack.screen.getKeyDisplay</tt> in order to allow using strings for the keycode argument.</p>
</li>
</ul>
</div>
<div class="section" id="viewrect-class">
<h3><a class="toc-backref" href="#id39">ViewRect class</a></h3>
<p>This class represents an on-screen rectangle with an associated independent
clip area rectangle. It is the base of the <tt class="docutils literal">Painter</tt> class, and is used by
<tt class="docutils literal">Views</tt> to track their client area.</p>
<ul>
<li><p class="first"><tt class="docutils literal">ViewRect{ rect = <span class="pre">...,</span> clip_rect = <span class="pre">...,</span> view_rect = <span class="pre">...,</span> clip_view = ... }</tt></p>
<p>The constructor has the following arguments:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">rect:</th><td class="field-body">The <tt class="docutils literal">mkdims</tt> rectangle in screen coordinates of the logical viewport.
Defaults to the whole screen.</td>
</tr>
<tr class="field"><th class="field-name">clip_rect:</th><td class="field-body">The clip rectangle in screen coordinates. Defaults to <tt class="docutils literal">rect</tt>.</td>
</tr>
<tr class="field"><th class="field-name">view_rect:</th><td class="field-body">A ViewRect object to copy from; overrides both <tt class="docutils literal">rect</tt> and <tt class="docutils literal">clip_rect</tt>.</td>
</tr>
<tr class="field"><th class="field-name">clip_view:</th><td class="field-body">A ViewRect object to intersect the specified clip area with.</td>
</tr>
</tbody>
</table>
</li>
<li><p class="first"><tt class="docutils literal">rect:isDefunct()</tt></p>
<p>Returns <em>true</em> if the clip area is empty, i.e. no painting is possible.</p>
</li>
<li><p class="first"><tt class="docutils literal">rect:inClipGlobalXY(x,y)</tt></p>
<p>Checks if these global coordinates are within the clip rectangle.</p>
</li>
<li><p class="first"><tt class="docutils literal">rect:inClipLocalXY(x,y)</tt></p>
<p>Checks if these coordinates (specified relative to <tt class="docutils literal">x1,y1</tt>) are within the clip rectangle.</p>
</li>
<li><p class="first"><tt class="docutils literal">rect:localXY(x,y)</tt></p>
<p>Converts a pair of global coordinates to local; returns <em>x_local,y_local</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal">rect:globalXY(x,y)</tt></p>
<p>Converts a pair of local coordinates to global; returns <em>x_global,y_global</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal">rect:viewport(x,y,w,h)</tt> or <tt class="docutils literal">rect:viewport(subrect)</tt></p>
<p>Returns a ViewRect representing a sub-rectangle of the current one.
The arguments are specified in local coordinates; the <tt class="docutils literal">subrect</tt>
argument must be a <tt class="docutils literal">mkdims</tt> table. The returned object consists of
the exact specified rectangle, and a clip area produced by intersecting
it with the clip area of the original object.</p>
</li>
</ul>
</div>
<div class="section" id="painter-class">
<h3><a class="toc-backref" href="#id40">Painter class</a></h3>
<p>The painting natives in <tt class="docutils literal">dfhack.screen</tt> apply to the whole screen, are
completely stateless and don't implement clipping.</p>
<p>The Painter class inherits from ViewRect to provide clipping and local
coordinates, and tracks current cursor position and current pen.</p>
<ul>
<li><p class="first"><tt class="docutils literal">Painter{ <span class="pre">...,</span> pen = <span class="pre">...,</span> key_pen = ... }</tt></p>
<p>In addition to ViewRect arguments, Painter accepts a suggestion of
the initial value for the main pen, and the keybinding pen. They
default to COLOR_GREY and COLOR_LIGHTGREEN otherwise.</p>
<p>There are also some convenience functions that wrap this constructor:</p>
<ul class="simple">
<li><tt class="docutils literal">Painter.new(rect,pen)</tt></li>
<li><tt class="docutils literal">Painter.new_view(view_rect,pen)</tt></li>
<li><tt class="docutils literal">Painter.new_xy(x1,y1,x2,y2,pen)</tt></li>
<li><tt class="docutils literal">Painter.new_wh(x1,y1,width,height,pen)</tt></li>
</ul>
</li>
<li><p class="first"><tt class="docutils literal">painter:isValidPos()</tt></p>
<p>Checks if the current cursor position is within the clip area.</p>
</li>
<li><p class="first"><tt class="docutils literal">painter:viewport(x,y,w,h)</tt></p>
<p>Like the superclass method, but returns a Painter object.</p>
</li>
<li><p class="first"><tt class="docutils literal">painter:cursor()</tt></p>
<p>Returns the current cursor <em>x,y</em> in local coordinates.</p>
</li>
<li><p class="first"><tt class="docutils literal">painter:seek(x,y)</tt></p>
<p>Sets the current cursor position, and returns <em>self</em>.
Either of the arguments may be <em>nil</em> to keep the current value.</p>
</li>
<li><p class="first"><tt class="docutils literal">painter:advance(dx,dy)</tt></p>
<p>Adds the given offsets to the cursor position, and returns <em>self</em>.
Either of the arguments may be <em>nil</em> to keep the current value.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">painter:newline([dx])</span></tt></p>
<p>Advances the cursor to the start of the next line plus the given x offset, and returns <em>self</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">painter:pen(...)</span></tt></p>
<p>Sets the current pen to <tt class="docutils literal"><span class="pre">dfhack.pen.parse(old_pen,...)</span></tt>, and returns <em>self</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">painter:key_pen(...)</span></tt></p>
<p>Sets the current keybinding pen to <tt class="docutils literal"><span class="pre">dfhack.pen.parse(old_pen,...)</span></tt>, and returns <em>self</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal">painter:clear()</tt></p>
<p>Fills the whole clip rectangle with <tt class="docutils literal">CLEAR_PEN</tt>, and returns <em>self</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">painter:fill(x1,y1,x2,y2[,...])</span></tt> or <tt class="docutils literal"><span class="pre">painter:fill(rect[,...])</span></tt></p>
<p>Fills the specified local coordinate rectangle with <tt class="docutils literal"><span class="pre">dfhack.pen.parse(cur_pen,...)</span></tt>,
and returns <em>self</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">painter:char([char[,</span> <span class="pre">...]])</span></tt></p>
<p>Paints one character using <tt class="docutils literal">char</tt> and <tt class="docutils literal"><span class="pre">dfhack.pen.parse(cur_pen,...)</span></tt>; returns <em>self</em>.
The <tt class="docutils literal">char</tt> argument, if not nil, is used to override the <tt class="docutils literal">ch</tt> property of the pen.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">painter:tile([char,</span> tile[, <span class="pre">...]])</span></tt></p>
<p>Like above, but also allows overriding the <tt class="docutils literal">tile</tt> property on ad-hoc basis.</p>
</li>
<li><p class="first"><tt class="docutils literal">painter:string(text[, <span class="pre">...])</span></tt></p>
<p>Paints the string with <tt class="docutils literal"><span class="pre">dfhack.pen.parse(cur_pen,...)</span></tt>; returns <em>self</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal">painter:key(keycode[, <span class="pre">...])</span></tt></p>
<p>Paints the description of the keycode using <tt class="docutils literal"><span class="pre">dfhack.pen.parse(cur_key_pen,...)</span></tt>; returns <em>self</em>.</p>
</li>
</ul>
<p>As noted above, all painting methods return <em>self</em>, in order to allow chaining them like this:</p>
<pre class="literal-block">
painter:pen(foo):seek(x,y):char(1):advance(1):string('bar')...
</pre>
</div>
<div class="section" id="view-class">
<h3><a class="toc-backref" href="#id41">View class</a></h3>
<p>This class is the common abstract base of both the stand-alone screens
and common widgets to be used inside them. It defines the basic layout,
rendering and event handling framework.</p>
<p>The class defines the following attributes:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">visible:</th><td class="field-body">Specifies that the view should be painted.</td>
</tr>
<tr class="field"><th class="field-name">active:</th><td class="field-body">Specifies that the view should receive events, if also visible.</td>
</tr>
<tr class="field"><th class="field-name">view_id:</th><td class="field-body">Specifies an identifier to easily identify the view among subviews.
This is reserved for implementation of top-level views, and should
not be used by widgets for their internal subviews.</td>
</tr>
</tbody>
</table>
<p>It also always has the following fields:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">subviews:</th><td class="field-body">Contains a table of all subviews. The sequence part of the
table is used for iteration. In addition, subviews are also
indexed under their <em>view_id</em>, if any; see <tt class="docutils literal">addviews()</tt> below.</td>
</tr>
</tbody>
</table>
<p>These fields are computed by the layout process:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name" colspan="2">frame_parent_rect:</th></tr>
<tr class="field"><td>&nbsp;</td><td class="field-body">The ViewRect represeting the client area of the parent view.</td>
</tr>
<tr class="field"><th class="field-name">frame_rect:</th><td class="field-body">The <tt class="docutils literal">mkdims</tt> rect of the outer frame in parent-local coordinates.</td>
</tr>
<tr class="field"><th class="field-name">frame_body:</th><td class="field-body">The ViewRect representing the body part of the View's own frame.</td>
</tr>
</tbody>
</table>
<p>The class has the following methods:</p>
<ul>
<li><p class="first"><tt class="docutils literal">view:addviews(list)</tt></p>
<p>Adds the views in the list to the <tt class="docutils literal">subviews</tt> sequence. If any of the views
in the list have <tt class="docutils literal">view_id</tt> attributes that don't conflict with existing keys
in <tt class="docutils literal">subviews</tt>, also stores them under the string keys. Finally, copies any
non-conflicting string keys from the <tt class="docutils literal">subviews</tt> tables of the listed views.</p>
<p>Thus, doing something like this:</p>
<pre class="literal-block">
self:addviews{
Panel{
view_id = 'panel',
subviews = {
Label{ view_id = 'label' }
}
}
}
</pre>
<p>Would make the label accessible as both <tt class="docutils literal">self.subviews.label</tt> and
<tt class="docutils literal">self.subviews.panel.subviews.label</tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal">view:getWindowSize()</tt></p>
<p>Returns the dimensions of the <tt class="docutils literal">frame_body</tt> rectangle.</p>
</li>
<li><p class="first"><tt class="docutils literal">view:getMousePos()</tt></p>
<p>Returns the mouse <em>x,y</em> in coordinates local to the <tt class="docutils literal">frame_body</tt>
rectangle if it is within its clip area, or nothing otherwise.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">view:updateLayout([parent_rect])</span></tt></p>
<p>Recomputes layout of the view and its subviews. If no argument is
given, re-uses the previous parent rect. The process goes as follows:</p>
<ol class="arabic simple">
<li>Calls <tt class="docutils literal">preUpdateLayout(parent_rect)</tt> via <tt class="docutils literal">invoke_before</tt>.</li>
<li>Uses <tt class="docutils literal">computeFrame(parent_rect)</tt> to compute the desired frame.</li>
<li>Calls <tt class="docutils literal">postComputeFrame(frame_body)</tt> via <tt class="docutils literal">invoke_after</tt>.</li>
<li>Calls <tt class="docutils literal">updateSubviewLayout(frame_body)</tt> to update children.</li>
<li>Calls <tt class="docutils literal">postUpdateLayout(frame_body)</tt> via <tt class="docutils literal">invoke_after</tt>.</li>
</ol>
</li>
<li><p class="first"><tt class="docutils literal">view:computeFrame(parent_rect)</tt> <em>(for overriding)</em></p>
<p>Called by <tt class="docutils literal">updateLayout</tt> in order to compute the frame rectangle(s).
Should return the <tt class="docutils literal">mkdims</tt> rectangle for the outer frame, and optionally
also for the body frame. If only one rectangle is returned, it is used
for both frames, and the margin becomes zero.</p>
</li>
<li><p class="first"><tt class="docutils literal">view:updateSubviewLayout(frame_body)</tt></p>
<p>Calls <tt class="docutils literal">updateLayout</tt> on all children.</p>
</li>
<li><p class="first"><tt class="docutils literal">view:render(painter)</tt></p>
<p>Given the parent's painter, renders the view via the following process:</p>
<ol class="arabic simple">
<li>Calls <tt class="docutils literal">onRenderFrame(painter, frame_rect)</tt> to paint the outer frame.</li>
<li>Creates a new painter using the <tt class="docutils literal">frame_body</tt> rect.</li>
<li>Calls <tt class="docutils literal">onRenderBody(new_painter)</tt> to paint the client area.</li>
<li>Calls <tt class="docutils literal">renderSubviews(new_painter)</tt> to paint visible children.</li>
</ol>
</li>
<li><p class="first"><tt class="docutils literal">view:renderSubviews(painter)</tt></p>
<p>Calls <tt class="docutils literal">render</tt> on all <tt class="docutils literal">visible</tt> subviews in the order they
appear in the <tt class="docutils literal">subviews</tt> sequence.</p>
</li>
<li><p class="first"><tt class="docutils literal">view:onRenderFrame(painter, rect)</tt> <em>(for overriding)</em></p>
<p>Called by <tt class="docutils literal">render</tt> to paint the outer frame; by default does nothing.</p>
</li>
<li><p class="first"><tt class="docutils literal">view:onRenderBody(painter)</tt> <em>(for overriding)</em></p>
<p>Called by <tt class="docutils literal">render</tt> to paint the client area; by default does nothing.</p>
</li>
<li><p class="first"><tt class="docutils literal">view:onInput(keys)</tt> <em>(for overriding)</em></p>
<p>Override this to handle events. By default directly calls <tt class="docutils literal">inputToSubviews</tt>.
Return a true value from this method to signal that the event has been handled
and should not be passed on to more views.</p>
</li>
<li><p class="first"><tt class="docutils literal">view:inputToSubviews(keys)</tt></p>
<p>Calls <tt class="docutils literal">onInput</tt> on all visible active subviews, iterating the <tt class="docutils literal">subviews</tt>
sequence in <em>reverse order</em>, so that topmost subviews get events first.
Returns <em>true</em> if any of the subviews handled the event.</p>
</li>
</ul>
</div>
<div class="section" id="screen-class">
<h3><a class="toc-backref" href="#id42">Screen class</a></h3>
<p>This is a View subclass intended for use as a stand-alone dialog or screen.
It adds the following methods:</p>
<ul>
<li><p class="first"><tt class="docutils literal">screen:isShown()</tt></p>
<p>Returns <em>true</em> if the screen is currently in the game engine's display stack.</p>
</li>
<li><p class="first"><tt class="docutils literal">screen:isDismissed()</tt></p>
<p>Returns <em>true</em> if the screen is dismissed.</p>
</li>
<li><p class="first"><tt class="docutils literal">screen:isActive()</tt></p>
<p>Returns <em>true</em> if the screen is shown and not dismissed.</p>
</li>
<li><p class="first"><tt class="docutils literal">screen:invalidate()</tt></p>
<p>Requests a repaint. Note that currently using it is not necessary, because
repaints are constantly requested automatically, due to issues with native
screens happening otherwise.</p>
</li>
<li><p class="first"><tt class="docutils literal">screen:renderParent()</tt></p>
<p>Asks the parent native screen to render itself, or clears the screen if impossible.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">screen:sendInputToParent(...)</span></tt></p>
<p>Uses <tt class="docutils literal">simulateInput</tt> to send keypresses to the native parent screen.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">screen:show([parent])</span></tt></p>
<p>Adds the screen to the display stack with the given screen as the parent;
if parent is not specified, places this one one topmost. Before calling
<tt class="docutils literal">dfhack.screen.show</tt>, calls <tt class="docutils literal">self:onAboutToShow(parent)</tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal">screen:onAboutToShow(parent)</tt> <em>(for overriding)</em></p>
<p>Called when <tt class="docutils literal">dfhack.screen.show</tt> is about to be called.</p>
</li>
<li><p class="first"><tt class="docutils literal">screen:onShow()</tt></p>
<p>Called by <tt class="docutils literal">dfhack.screen.show</tt> once the screen is successfully shown.</p>
</li>
<li><p class="first"><tt class="docutils literal">screen:dismiss()</tt></p>
<p>Dismisses the screen. A dismissed screen does not receive any more
events or paint requests, but may remain in the display stack for
a short time until the game removes it.</p>
</li>
<li><p class="first"><tt class="docutils literal">screen:onDismiss()</tt> <em>(for overriding)</em></p>
<p>Called by <tt class="docutils literal">dfhack.screen.dismiss()</tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal">screen:onDestroy()</tt> <em>(for overriding)</em></p>
<p>Called by the native code when the screen is fully destroyed and removed
from the display stack. Place code that absolutely must be called whenever
the screen is removed by any means here.</p>
</li>
<li><p class="first"><tt class="docutils literal">screen:onResize</tt>, <tt class="docutils literal">screen:onRender</tt></p>
<p>Defined as callbacks for native code.</p>
</li>
</ul>
</div>
<div class="section" id="framedscreen-class">
<h3><a class="toc-backref" href="#id43">FramedScreen class</a></h3>
<p>A Screen subclass that paints a visible frame around its body.
Most dialogs should inherit from this class.</p>
<p>A framed screen has the following attributes:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">frame_style:</th><td class="field-body">A table that defines a set of pens to draw various parts of the frame.</td>
</tr>
<tr class="field"><th class="field-name">frame_title:</th><td class="field-body">A string to display in the middle of the top of the frame.</td>
</tr>
<tr class="field"><th class="field-name">frame_width:</th><td class="field-body">Desired width of the client area. If <em>nil</em>, the screen will occupy the whole width.</td>
</tr>
<tr class="field"><th class="field-name">frame_height:</th><td class="field-body">Likewise, for height.</td>
</tr>
<tr class="field"><th class="field-name">frame_inset:</th><td class="field-body">The gap between the frame and the client area. Defaults to 0.</td>
</tr>
<tr class="field"><th class="field-name" colspan="2">frame_background:</th></tr>
<tr class="field"><td>&nbsp;</td><td class="field-body">The pen to fill in the frame with. Defaults to CLEAR_PEN.</td>
</tr>
</tbody>
</table>
<p>There are the following predefined frame style tables:</p>
<ul>
<li><p class="first"><tt class="docutils literal">GREY_FRAME</tt></p>
<p>A plain grey-colored frame.</p>
</li>
<li><p class="first"><tt class="docutils literal">BOUNDARY_FRAME</tt></p>
<p>The same frame as used by the usual full-screen DF views, like dwarfmode.</p>
</li>
<li><p class="first"><tt class="docutils literal">GREY_LINE_FRAME</tt></p>
<p>A frame consisting of grey lines, similar to the one used by titan announcements.</p>
</li>
</ul>
</div>
</div>
<div class="section" id="gui-widgets">
<h2><a class="toc-backref" href="#id44">gui.widgets</a></h2>
<p>This module implements some basic widgets based on the View infrastructure.</p>
<div class="section" id="widget-class">
<h3><a class="toc-backref" href="#id45">Widget class</a></h3>
<p>Base of all the widgets. Inherits from View and has the following attributes:</p>
<ul>
<li><p class="first"><tt class="docutils literal">frame = <span class="pre">{...}</span></tt></p>
<p>Specifies the constraints on the outer frame of the widget.
If omitted, the widget will occupy the whole parent rectangle.</p>
<p>The frame is specified as a table with the following possible fields:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">l:</th><td class="field-body">gap between the left edges of the frame and the parent.</td>
</tr>
<tr class="field"><th class="field-name">t:</th><td class="field-body">gap between the top edges of the frame and the parent.</td>
</tr>
<tr class="field"><th class="field-name">r:</th><td class="field-body">gap between the right edges of the frame and the parent.</td>
</tr>
<tr class="field"><th class="field-name">b:</th><td class="field-body">gap between the bottom edges of the frame and the parent.</td>
</tr>
<tr class="field"><th class="field-name">w:</th><td class="field-body">maximum width of the frame.</td>
</tr>
<tr class="field"><th class="field-name">h:</th><td class="field-body">maximum heigth of the frame.</td>
</tr>
<tr class="field"><th class="field-name">xalign:</th><td class="field-body">X alignment of the frame.</td>
</tr>
<tr class="field"><th class="field-name">yalign:</th><td class="field-body">Y alignment of the frame.</td>
</tr>
</tbody>
</table>
<p>First the <tt class="docutils literal">l,t,r,b</tt> fields restrict the available area for
placing the frame. If <tt class="docutils literal">w</tt> and <tt class="docutils literal">h</tt> are not specified or
larger then the computed area, it becomes the frame. Otherwise
the smaller frame is placed within the are based on the
<tt class="docutils literal">xalign/yalign</tt> fields. If the align hints are omitted, they
are assumed to be 0, 1, or 0.5 based on which of the <tt class="docutils literal">l/r/t/b</tt>
fields are set.</p>
</li>
<li><p class="first"><tt class="docutils literal">frame_inset = <span class="pre">{...}</span></tt></p>
<p>Specifies the gap between the outer frame, and the client area.
The attribute may be a simple integer value to specify a uniform
inset, or a table with the following fields:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">l:</th><td class="field-body">left margin.</td>
</tr>
<tr class="field"><th class="field-name">t:</th><td class="field-body">top margin.</td>
</tr>
<tr class="field"><th class="field-name">r:</th><td class="field-body">right margin.</td>
</tr>
<tr class="field"><th class="field-name">b:</th><td class="field-body">bottom margin.</td>
</tr>
<tr class="field"><th class="field-name">x:</th><td class="field-body">left/right margin, if <tt class="docutils literal">l</tt> and/or <tt class="docutils literal">r</tt> are omitted.</td>
</tr>
<tr class="field"><th class="field-name">y:</th><td class="field-body">top/bottom margin, if <tt class="docutils literal">t</tt> and/or <tt class="docutils literal">b</tt> are omitted.</td>
</tr>
</tbody>
</table>
</li>
<li><p class="first"><tt class="docutils literal">frame_background = pen</tt></p>
<p>The pen to fill the outer frame with. Defaults to no fill.</p>
</li>
</ul>
</div>
<div class="section" id="panel-class">
<h3><a class="toc-backref" href="#id46">Panel class</a></h3>
<p>Inherits from Widget, and intended for grouping a number of subviews.</p>
<p>Has attributes:</p>
<ul>
<li><p class="first"><tt class="docutils literal">subviews = {}</tt></p>
<p>Used to initialize the subview list in the constructor.</p>
</li>
<li><p class="first"><tt class="docutils literal">on_render = function(painter)</tt></p>
<p>Called from <tt class="docutils literal">onRenderBody</tt>.</p>
</li>
</ul>
</div>
<div class="section" id="pages-class">
<h3><a class="toc-backref" href="#id47">Pages class</a></h3>
<p>Subclass of Panel; keeps exactly one child visible.</p>
<ul>
<li><p class="first"><tt class="docutils literal">Pages{ <span class="pre">...,</span> selected = ... }</tt></p>
<p>Specifies which child to select initially; defaults to the first one.</p>
</li>
<li><p class="first"><tt class="docutils literal">pages:getSelected()</tt></p>
<p>Returns the selected <em>index, child</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal">pages:setSelected(index)</tt></p>
<p>Selects the specified child, hiding the previous selected one.
It is permitted to use the subview object, or its <tt class="docutils literal">view_id</tt> as index.</p>
</li>
</ul>
</div>
<div class="section" id="editfield-class">
<h3><a class="toc-backref" href="#id48">EditField class</a></h3>
<p>Subclass of Widget; implements a simple edit field.</p>
<p>Attributes:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">text:</th><td class="field-body">The current contents of the field.</td>
</tr>
<tr class="field"><th class="field-name">text_pen:</th><td class="field-body">The pen to draw the text with.</td>
</tr>
<tr class="field"><th class="field-name">on_char:</th><td class="field-body">Input validation callback; used as <tt class="docutils literal">on_char(new_char,text)</tt>.
If it returns false, the character is ignored.</td>
</tr>
<tr class="field"><th class="field-name">on_change:</th><td class="field-body">Change notification callback; used as <tt class="docutils literal">on_change(new_text,old_text)</tt>.</td>
</tr>
<tr class="field"><th class="field-name">on_submit:</th><td class="field-body">Enter key callback; if set the field will handle the key and call <tt class="docutils literal">on_submit(text)</tt>.</td>
</tr>
</tbody>
</table>
</div>
<div class="section" id="label-class">
<h3><a class="toc-backref" href="#id49">Label class</a></h3>
<p>This Widget subclass implements flowing semi-static text.</p>
<p>It has the following attributes:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">text_pen:</th><td class="field-body">Specifies the pen for active text.</td>
</tr>
<tr class="field"><th class="field-name">text_dpen:</th><td class="field-body">Specifies the pen for disabled text.</td>
</tr>
<tr class="field"><th class="field-name">disabled:</th><td class="field-body">Boolean or a callback; if true, the label is disabled.</td>
</tr>
<tr class="field"><th class="field-name">enabled:</th><td class="field-body">Boolean or a callback; if false, the label is disabled.</td>
</tr>
<tr class="field"><th class="field-name">auto_height:</th><td class="field-body">Sets self.frame.h from the text height.</td>
</tr>
<tr class="field"><th class="field-name">auto_width:</th><td class="field-body">Sets self.frame.w from the text width.</td>
</tr>
</tbody>
</table>
<p>The text itself is represented as a complex structure, and passed
to the object via the <tt class="docutils literal">text</tt> argument of the constructor, or via
the <tt class="docutils literal">setText</tt> method, as one of:</p>
<ul class="simple">
<li>A simple string, possibly containing newlines.</li>
<li>A sequence of tokens.</li>
</ul>
<p>Every token in the sequence in turn may be either a string, possibly
containing newlines, or a table with the following possible fields:</p>
<ul>
<li><p class="first"><tt class="docutils literal">token.text = ...</tt></p>
<p>Specifies the main text content of a token, and may be a string, or
a callback returning a string.</p>
</li>
<li><p class="first"><tt class="docutils literal">token.gap = ...</tt></p>
<p>Specifies the number of character positions to advance on the line
before rendering the token.</p>
</li>
<li><p class="first"><tt class="docutils literal">token.tile = pen</tt></p>
<p>Specifies a pen to paint as one tile before the main part of the token.</p>
</li>
<li><p class="first"><tt class="docutils literal">token.key = <span class="pre">'...'</span></tt></p>
<p>Specifies the keycode associated with the token. The string description
of the key binding is added to the text content of the token.</p>
</li>
<li><p class="first"><tt class="docutils literal">token.key_sep = <span class="pre">'...'</span></tt></p>
<p>Specifies the separator to place between the keybinding label produced
by <tt class="docutils literal">token.key</tt>, and the main text of the token. If the separator is
'()', the token is formatted as <tt class="docutils literal"><span class="pre">text..'</span> <span class="pre">('..binding..')'</span></tt>. Otherwise
it is simply <tt class="docutils literal"><span class="pre">binding..sep..text</span></tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal">token.enabled</tt>, <tt class="docutils literal">token.disabled</tt></p>
<p>Same as the attributes of the label itself, but applies only to the token.</p>
</li>
<li><p class="first"><tt class="docutils literal">token.pen</tt>, <tt class="docutils literal">token.dpen</tt></p>
<p>Specify the pen and disabled pen to be used for the token's text.
The field may be either the pen itself, or a callback that returns it.</p>
</li>
<li><p class="first"><tt class="docutils literal">token.on_activate</tt></p>
<p>If this field is not nil, and <tt class="docutils literal">token.key</tt> is set, the token will actually
respond to that key binding unless disabled, and call this callback. Eventually
this may be extended with mouse click support.</p>
</li>
<li><p class="first"><tt class="docutils literal">token.id</tt></p>
<p>Specifies a unique identifier for the token.</p>
</li>
<li><p class="first"><tt class="docutils literal">token.line</tt>, <tt class="docutils literal">token.x1</tt>, <tt class="docutils literal">token.x2</tt></p>
<p>Reserved for internal use.</p>
</li>
</ul>
<p>The Label widget implements the following methods:</p>
<ul>
<li><p class="first"><tt class="docutils literal">label:setText(new_text)</tt></p>
<p>Replaces the text currently contained in the widget.</p>
</li>
<li><p class="first"><tt class="docutils literal">label:itemById(id)</tt></p>
<p>Finds a token by its <tt class="docutils literal">id</tt> field.</p>
</li>
<li><p class="first"><tt class="docutils literal">label:getTextHeight()</tt></p>
<p>Computes the height of the text.</p>
</li>
<li><p class="first"><tt class="docutils literal">label:getTextWidth()</tt></p>
<p>Computes the width of the text.</p>
</li>
</ul>
</div>
<div class="section" id="list-class">
<h3><a class="toc-backref" href="#id50">List class</a></h3>
<p>The List widget implements a simple list with paging.</p>
<p>It has the following attributes:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">text_pen:</th><td class="field-body">Specifies the pen for deselected list entries.</td>
</tr>
<tr class="field"><th class="field-name">cursor_pen:</th><td class="field-body">Specifies the pen for the selected entry.</td>
</tr>
<tr class="field"><th class="field-name">inactive_pen:</th><td class="field-body">If specified, used for the cursor when the widget is not active.</td>
</tr>
<tr class="field"><th class="field-name">icon_pen:</th><td class="field-body">Default pen for icons.</td>
</tr>
<tr class="field"><th class="field-name">on_select:</th><td class="field-body">Selection change callback; called as <tt class="docutils literal">on_select(index,choice)</tt>.</td>
</tr>
<tr class="field"><th class="field-name">on_submit:</th><td class="field-body">Enter key callback; if specified, the list reacts to the key
and calls it as <tt class="docutils literal">on_submit(index,choice)</tt>.</td>
</tr>
<tr class="field"><th class="field-name">row_height:</th><td class="field-body">Height of every row in text lines.</td>
</tr>
<tr class="field"><th class="field-name">icon_width:</th><td class="field-body">If not <em>nil</em>, the specified number of character columns
are reserved to the left of the list item for the icons.</td>
</tr>
<tr class="field"><th class="field-name">scroll_keys:</th><td class="field-body">Specifies which keys the list should react to as a table.</td>
</tr>
</tbody>
</table>
<p>Every list item may be specified either as a string, or as a lua table
with the following fields:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">text:</th><td class="field-body">Specifies the label text in the same format as the Label text.</td>
</tr>
<tr class="field"><th class="field-name">caption, [1]:</th><td class="field-body">Deprecated legacy aliases for <strong>text</strong>.</td>
</tr>
<tr class="field"><th class="field-name">text_*:</th><td class="field-body">Reserved for internal use.</td>
</tr>
<tr class="field"><th class="field-name">key:</th><td class="field-body">Specifies a keybinding that acts as a shortcut for the specified item.</td>
</tr>
<tr class="field"><th class="field-name">icon:</th><td class="field-body">Specifies an icon string, or a pen to paint a single character. May be a callback.</td>
</tr>
<tr class="field"><th class="field-name">icon_pen:</th><td class="field-body">When the icon is a string, used to paint it.</td>
</tr>
</tbody>
</table>
<p>The list supports the following methods:</p>
<ul>
<li><p class="first"><tt class="docutils literal">List{ <span class="pre">...,</span> choices = <span class="pre">...,</span> selected = ... }</tt></p>
<p>Same as calling <tt class="docutils literal">setChoices</tt> after construction.</p>
</li>
<li><p class="first"><tt class="docutils literal">list:setChoices(choices[, selected])</tt></p>
<p>Replaces the list of choices, possibly also setting the currently selected index.</p>
</li>
<li><p class="first"><tt class="docutils literal">list:setSelected(selected)</tt></p>
<p>Sets the currently selected index. Returns the index after validation.</p>
</li>
<li><p class="first"><tt class="docutils literal">list:getChoices()</tt></p>
<p>Returns the list of choices.</p>
</li>
<li><p class="first"><tt class="docutils literal">list:getSelected()</tt></p>
<p>Returns the selected <em>index, choice</em>, or nothing if the list is empty.</p>
</li>
<li><p class="first"><tt class="docutils literal">list:getContentWidth()</tt></p>
<p>Returns the minimal width to draw all choices without clipping.</p>
</li>
<li><p class="first"><tt class="docutils literal">list:getContentHeight()</tt></p>
<p>Returns the minimal width to draw all choices without scrolling.</p>
</li>
<li><p class="first"><tt class="docutils literal">list:submit()</tt></p>
<p>Call the <tt class="docutils literal">on_submit</tt> callback, as if the Enter key was handled.</p>
</li>
</ul>
</div>
<div class="section" id="filteredlist-class">
<h3><a class="toc-backref" href="#id51">FilteredList class</a></h3>
<p>This widget combines List, EditField and Label into a combo-box like
construction that allows filtering the list by subwords of its items.</p>
<p>In addition to passing through all attributes supported by List, it
supports:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">edit_pen:</th><td class="field-body">If specified, used instead of <tt class="docutils literal">cursor_pen</tt> for the edit field.</td>
</tr>
<tr class="field"><th class="field-name" colspan="2">not_found_label:</th></tr>
<tr class="field"><td>&nbsp;</td><td class="field-body">Specifies the text of the label shown when no items match the filter.</td>
</tr>
</tbody>
</table>
<p>The list choices may include the following attributes:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">search_key:</th><td class="field-body">If specified, used instead of <strong>text</strong> to match against the filter.</td>
</tr>
</tbody>
</table>
<p>The widget implements:</p>
<ul>
<li><p class="first"><tt class="docutils literal">list:setChoices(choices[, selected])</tt></p>
<p>Resets the filter, and passes through to the inner list.</p>
</li>
<li><p class="first"><tt class="docutils literal">list:getChoices()</tt></p>
<p>Returns the list of <em>all</em> choices.</p>
</li>
<li><p class="first"><tt class="docutils literal">list:getFilter()</tt></p>
<p>Returns the current filter string, and the <em>filtered</em> list of choices.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">list:setFilter(filter[,pos])</span></tt></p>
<p>Sets the new filter string, filters the list, and selects the item at
index <tt class="docutils literal">pos</tt> in the <em>unfiltered</em> list if possible.</p>
</li>
<li><p class="first"><tt class="docutils literal">list:canSubmit()</tt></p>
<p>Checks if there are currently any choices in the filtered list.</p>
</li>
<li><p class="first"><tt class="docutils literal">list:getSelected()</tt>, <tt class="docutils literal">list:getContentWidth()</tt>, <tt class="docutils literal">list:getContentHeight()</tt>, <tt class="docutils literal">list:submit()</tt></p>
<p>Same as with an ordinary list.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="section" id="plugins">
<h1><a class="toc-backref" href="#id36">Plugins</a></h1>
<h1><a class="toc-backref" href="#id52">Plugins</a></h1>
<p>DFHack plugins may export native functions and events
to lua contexts. They are automatically imported by
<tt class="docutils literal"><span class="pre">mkmodule('plugins.&lt;name&gt;')</span></tt>; this means that a lua
module file is still necessary for <tt class="docutils literal">require</tt> to read.</p>
<p>The following plugins have lua support.</p>
<div class="section" id="burrows">
<h2><a class="toc-backref" href="#id37">burrows</a></h2>
<h2><a class="toc-backref" href="#id53">burrows</a></h2>
<p>Implements extended burrow manipulations.</p>
<p>Events:</p>
<ul>
@ -2169,13 +2978,13 @@ set is the same as used by the command line.</p>
<p>The lua module file also re-exports functions from <tt class="docutils literal">dfhack.burrows</tt>.</p>
</div>
<div class="section" id="sort">
<h2><a class="toc-backref" href="#id38">sort</a></h2>
<h2><a class="toc-backref" href="#id54">sort</a></h2>
<p>Does not export any native functions as of now. Instead, it
calls lua code to perform the actual ordering of list items.</p>
</div>
</div>
<div class="section" id="scripts">
<h1><a class="toc-backref" href="#id39">Scripts</a></h1>
<h1><a class="toc-backref" href="#id55">Scripts</a></h1>
<p>Any files with the .lua extension placed into hack/scripts/*
are automatically used by the DFHack core as commands. The
matching command name consists of the name of the file sans

@ -1441,6 +1441,11 @@ Basic painting functions:
Requests repaint of the screen by setting a flag. Unlike other
functions in this section, this may be used at any time.
* ``dfhack.screen.getKeyDisplay(key)``
Returns the string that should be used to represent the given
logical keybinding on the screen in texts like "press Key to ...".
The "pen" argument used by functions above may be represented by
a table with the following possible fields:
@ -1796,6 +1801,11 @@ environment by the mandatory init file dfhack.lua:
safecall, qerror, mkmodule, reload
* Miscellaneous constants
:NEWLINE, COMMA, PERIOD: evaluate to the relevant character strings.
:DEFAULT_NIL: is an unspecified unique token used by the class module below.
* ``printall(obj)``
If the argument is a lua table or DF object reference, prints all fields.
@ -1906,12 +1916,29 @@ utils
as a guide to which values should be skipped as uninteresting.
The ``force`` argument makes it always return a non-*nil* value.
* ``utils.parse_bitfield_int(value, type_ref)``
Given an int ``value``, and a bitfield type in the ``df`` tree,
it returns a lua table mapping the enabled bit keys to *true*,
unless value is 0, in which case it returns *nil*.
* ``utils.list_bitfield_flags(bitfield[, list])``
Adds all enabled bitfield keys to ``list`` or a newly-allocated
empty sequence, and returns it. The ``bitfield`` argument may
be *nil*.
* ``utils.sort_vector(vector,field,cmpfun)``
Sorts a native vector or lua sequence using the comparator function.
If ``field`` is not *nil*, applies the comparator to the field instead
of the whole object.
* ``utils.linear_index(vector,key[,field])``
Searches for ``key`` in the vector, and returns *index, found_value*,
or *nil* if none found.
* ``utils.binsearch(vector,key,field,cmpfun,min,max)``
Does a binary search in a native vector or lua sequence for
@ -1947,6 +1974,23 @@ utils
Exactly like ``erase_sorted_key``, but if field is specified, takes the key from ``item[field]``.
* ``utils.call_with_string(obj,methodname,...)``
Allocates a temporary string object, calls ``obj:method(tmp,...)``, and
returns the value written into the temporary after deleting it.
* ``utils.getBuildingName(building)``
Returns the string description of the given building.
* ``utils.getBuildingCenter(building)``
Returns an x/y/z table pointing at the building center.
* ``utils.split_string(string, delimiter)``
Splits the string by the given delimiter, and returns a sequence of results.
* ``utils.prompt_yes_no(prompt, default)``
Presents a yes/no prompt to the user. If ``default`` is not *nil*,
@ -2006,19 +2050,32 @@ Implements a trivial single-inheritance class system.
If the default value should be *nil*, use ``ATTRS { foo = DEFAULT_NIL }``.
Declaring an attribute is mostly the same as defining your ``init`` method like this::
function Class.init(args)
self.attr1 = args.attr1 or default1
self.attr2 = args.attr2 or default2
...
end
The main difference is that attributes are processed as a separate
initialization step, before any ``init`` methods are called. They
also make the directy relation between instance fields and constructor
arguments more explicit.
* ``new_obj = Class{ foo = arg, bar = arg, ... }``
Calling the class as a function creates and initializes a new instance.
Initialization happens in this order:
1. An empty instance table is created, and its metatable set.
2. The ``preinit`` method is called via ``invoke_before`` (see below)
with the table used as argument to the class. This method is intended
2. The ``preinit`` methods are called via ``invoke_before`` (see below)
with the table used as argument to the class. These methods are intended
for validating and tweaking that argument table.
3. Declared ATTRS are initialized from the argument table or their default values.
4. The ``init`` method is called via ``invoke_after`` with the argument table.
4. The ``init`` methods are called via ``invoke_after`` with the argument table.
This is the main constructor method.
5. The ``postinit`` method is called via ``invoke_after`` with the argument table.
5. The ``postinit`` methods are called via ``invoke_after`` with the argument table.
Place code that should be called after the object is fully constructed here.
Predefined instance methods:
@ -2033,6 +2090,14 @@ Predefined instance methods:
properly passing in self, and optionally a number of initial arguments too.
The arguments given to the closure are appended to these.
* ``instance:cb_getfield(field_name)``
Returns a closure that returns the specified field of the object when called.
* ``instance:cb_setfield(field_name)``
Returns a closure that sets the specified field to its argument when called.
* ``instance:invoke_before(method_name, args...)``
Navigates the inheritance chain of the instance starting from the most specific
@ -2057,6 +2122,715 @@ Predefined instance methods:
To avoid confusion, these methods cannot be redefined.
==================
In-game UI Library
==================
A number of lua modules with names starting with ``gui`` are dedicated
to wrapping the natives of the ``dfhack.screen`` module in a way that
is easy to use. This allows relatively easily and naturally creating
dialogs that integrate in the main game UI window.
These modules make extensive use of the ``class`` module, and define
things ranging from the basic ``Painter``, ``View`` and ``Screen``
classes, to fully functional predefined dialogs.
gui
===
This module defines the most important classes and functions for
implementing interfaces. This documents those of them that are
considered stable.
Misc
----
* ``USE_GRAPHICS``
Contains the value of ``dfhack.screen.inGraphicsMode()``, which cannot be
changed without restarting the game and thus is constant during the session.
* ``CLEAR_PEN``
The black pen used to clear the screen.
* ``simulateInput(screen, keys...)``
This function wraps an undocumented native function that passes a set of
keycodes to a screen, and is the official way to do that.
Every argument after the initial screen may be *nil*, a numeric keycode,
a string keycode, a sequence of numeric or string keycodes, or a mapping
of keycodes to *true* or *false*. For instance, it is possible to use the
table passed as argument to ``onInput``.
* ``mkdims_xy(x1,y1,x2,y2)``
Returns a table containing the arguments as fields, and also ``width`` and
``height`` that contains the rectangle dimensions.
* ``mkdims_wh(x1,y1,width,height)``
Returns the same kind of table as ``mkdims_xy``, only this time it computes
``x2`` and ``y2``.
* ``is_in_rect(rect,x,y)``
Checks if the given point is within a rectangle, represented by a table produced
by one of the ``mkdims`` functions.
* ``blink_visible(delay)``
Returns *true* or *false*, with the value switching to the opposite every ``delay``
msec. This is intended for rendering blinking interface objects.
* ``getKeyDisplay(keycode)``
Wraps ``dfhack.screen.getKeyDisplay`` in order to allow using strings for the keycode argument.
ViewRect class
--------------
This class represents an on-screen rectangle with an associated independent
clip area rectangle. It is the base of the ``Painter`` class, and is used by
``Views`` to track their client area.
* ``ViewRect{ rect = ..., clip_rect = ..., view_rect = ..., clip_view = ... }``
The constructor has the following arguments:
:rect: The ``mkdims`` rectangle in screen coordinates of the logical viewport.
Defaults to the whole screen.
:clip_rect: The clip rectangle in screen coordinates. Defaults to ``rect``.
:view_rect: A ViewRect object to copy from; overrides both ``rect`` and ``clip_rect``.
:clip_view: A ViewRect object to intersect the specified clip area with.
* ``rect:isDefunct()``
Returns *true* if the clip area is empty, i.e. no painting is possible.
* ``rect:inClipGlobalXY(x,y)``
Checks if these global coordinates are within the clip rectangle.
* ``rect:inClipLocalXY(x,y)``
Checks if these coordinates (specified relative to ``x1,y1``) are within the clip rectangle.
* ``rect:localXY(x,y)``
Converts a pair of global coordinates to local; returns *x_local,y_local*.
* ``rect:globalXY(x,y)``
Converts a pair of local coordinates to global; returns *x_global,y_global*.
* ``rect:viewport(x,y,w,h)`` or ``rect:viewport(subrect)``
Returns a ViewRect representing a sub-rectangle of the current one.
The arguments are specified in local coordinates; the ``subrect``
argument must be a ``mkdims`` table. The returned object consists of
the exact specified rectangle, and a clip area produced by intersecting
it with the clip area of the original object.
Painter class
-------------
The painting natives in ``dfhack.screen`` apply to the whole screen, are
completely stateless and don't implement clipping.
The Painter class inherits from ViewRect to provide clipping and local
coordinates, and tracks current cursor position and current pen.
* ``Painter{ ..., pen = ..., key_pen = ... }``
In addition to ViewRect arguments, Painter accepts a suggestion of
the initial value for the main pen, and the keybinding pen. They
default to COLOR_GREY and COLOR_LIGHTGREEN otherwise.
There are also some convenience functions that wrap this constructor:
- ``Painter.new(rect,pen)``
- ``Painter.new_view(view_rect,pen)``
- ``Painter.new_xy(x1,y1,x2,y2,pen)``
- ``Painter.new_wh(x1,y1,width,height,pen)``
* ``painter:isValidPos()``
Checks if the current cursor position is within the clip area.
* ``painter:viewport(x,y,w,h)``
Like the superclass method, but returns a Painter object.
* ``painter:cursor()``
Returns the current cursor *x,y* in local coordinates.
* ``painter:seek(x,y)``
Sets the current cursor position, and returns *self*.
Either of the arguments may be *nil* to keep the current value.
* ``painter:advance(dx,dy)``
Adds the given offsets to the cursor position, and returns *self*.
Either of the arguments may be *nil* to keep the current value.
* ``painter:newline([dx])``
Advances the cursor to the start of the next line plus the given x offset, and returns *self*.
* ``painter:pen(...)``
Sets the current pen to ``dfhack.pen.parse(old_pen,...)``, and returns *self*.
* ``painter:key_pen(...)``
Sets the current keybinding pen to ``dfhack.pen.parse(old_pen,...)``, and returns *self*.
* ``painter:clear()``
Fills the whole clip rectangle with ``CLEAR_PEN``, and returns *self*.
* ``painter:fill(x1,y1,x2,y2[,...])`` or ``painter:fill(rect[,...])``
Fills the specified local coordinate rectangle with ``dfhack.pen.parse(cur_pen,...)``,
and returns *self*.
* ``painter:char([char[, ...]])``
Paints one character using ``char`` and ``dfhack.pen.parse(cur_pen,...)``; returns *self*.
The ``char`` argument, if not nil, is used to override the ``ch`` property of the pen.
* ``painter:tile([char, tile[, ...]])``
Like above, but also allows overriding the ``tile`` property on ad-hoc basis.
* ``painter:string(text[, ...])``
Paints the string with ``dfhack.pen.parse(cur_pen,...)``; returns *self*.
* ``painter:key(keycode[, ...])``
Paints the description of the keycode using ``dfhack.pen.parse(cur_key_pen,...)``; returns *self*.
As noted above, all painting methods return *self*, in order to allow chaining them like this::
painter:pen(foo):seek(x,y):char(1):advance(1):string('bar')...
View class
----------
This class is the common abstract base of both the stand-alone screens
and common widgets to be used inside them. It defines the basic layout,
rendering and event handling framework.
The class defines the following attributes:
:visible: Specifies that the view should be painted.
:active: Specifies that the view should receive events, if also visible.
:view_id: Specifies an identifier to easily identify the view among subviews.
This is reserved for implementation of top-level views, and should
not be used by widgets for their internal subviews.
It also always has the following fields:
:subviews: Contains a table of all subviews. The sequence part of the
table is used for iteration. In addition, subviews are also
indexed under their *view_id*, if any; see ``addviews()`` below.
These fields are computed by the layout process:
:frame_parent_rect: The ViewRect represeting the client area of the parent view.
:frame_rect: The ``mkdims`` rect of the outer frame in parent-local coordinates.
:frame_body: The ViewRect representing the body part of the View's own frame.
The class has the following methods:
* ``view:addviews(list)``
Adds the views in the list to the ``subviews`` sequence. If any of the views
in the list have ``view_id`` attributes that don't conflict with existing keys
in ``subviews``, also stores them under the string keys. Finally, copies any
non-conflicting string keys from the ``subviews`` tables of the listed views.
Thus, doing something like this::
self:addviews{
Panel{
view_id = 'panel',
subviews = {
Label{ view_id = 'label' }
}
}
}
Would make the label accessible as both ``self.subviews.label`` and
``self.subviews.panel.subviews.label``.
* ``view:getWindowSize()``
Returns the dimensions of the ``frame_body`` rectangle.
* ``view:getMousePos()``
Returns the mouse *x,y* in coordinates local to the ``frame_body``
rectangle if it is within its clip area, or nothing otherwise.
* ``view:updateLayout([parent_rect])``
Recomputes layout of the view and its subviews. If no argument is
given, re-uses the previous parent rect. The process goes as follows:
1. Calls ``preUpdateLayout(parent_rect)`` via ``invoke_before``.
2. Uses ``computeFrame(parent_rect)`` to compute the desired frame.
3. Calls ``postComputeFrame(frame_body)`` via ``invoke_after``.
4. Calls ``updateSubviewLayout(frame_body)`` to update children.
5. Calls ``postUpdateLayout(frame_body)`` via ``invoke_after``.
* ``view:computeFrame(parent_rect)`` *(for overriding)*
Called by ``updateLayout`` in order to compute the frame rectangle(s).
Should return the ``mkdims`` rectangle for the outer frame, and optionally
also for the body frame. If only one rectangle is returned, it is used
for both frames, and the margin becomes zero.
* ``view:updateSubviewLayout(frame_body)``
Calls ``updateLayout`` on all children.
* ``view:render(painter)``
Given the parent's painter, renders the view via the following process:
1. Calls ``onRenderFrame(painter, frame_rect)`` to paint the outer frame.
2. Creates a new painter using the ``frame_body`` rect.
3. Calls ``onRenderBody(new_painter)`` to paint the client area.
4. Calls ``renderSubviews(new_painter)`` to paint visible children.
* ``view:renderSubviews(painter)``
Calls ``render`` on all ``visible`` subviews in the order they
appear in the ``subviews`` sequence.
* ``view:onRenderFrame(painter, rect)`` *(for overriding)*
Called by ``render`` to paint the outer frame; by default does nothing.
* ``view:onRenderBody(painter)`` *(for overriding)*
Called by ``render`` to paint the client area; by default does nothing.
* ``view:onInput(keys)`` *(for overriding)*
Override this to handle events. By default directly calls ``inputToSubviews``.
Return a true value from this method to signal that the event has been handled
and should not be passed on to more views.
* ``view:inputToSubviews(keys)``
Calls ``onInput`` on all visible active subviews, iterating the ``subviews``
sequence in *reverse order*, so that topmost subviews get events first.
Returns *true* if any of the subviews handled the event.
Screen class
------------
This is a View subclass intended for use as a stand-alone dialog or screen.
It adds the following methods:
* ``screen:isShown()``
Returns *true* if the screen is currently in the game engine's display stack.
* ``screen:isDismissed()``
Returns *true* if the screen is dismissed.
* ``screen:isActive()``
Returns *true* if the screen is shown and not dismissed.
* ``screen:invalidate()``
Requests a repaint. Note that currently using it is not necessary, because
repaints are constantly requested automatically, due to issues with native
screens happening otherwise.
* ``screen:renderParent()``
Asks the parent native screen to render itself, or clears the screen if impossible.
* ``screen:sendInputToParent(...)``
Uses ``simulateInput`` to send keypresses to the native parent screen.
* ``screen:show([parent])``
Adds the screen to the display stack with the given screen as the parent;
if parent is not specified, places this one one topmost. Before calling
``dfhack.screen.show``, calls ``self:onAboutToShow(parent)``.
* ``screen:onAboutToShow(parent)`` *(for overriding)*
Called when ``dfhack.screen.show`` is about to be called.
* ``screen:onShow()``
Called by ``dfhack.screen.show`` once the screen is successfully shown.
* ``screen:dismiss()``
Dismisses the screen. A dismissed screen does not receive any more
events or paint requests, but may remain in the display stack for
a short time until the game removes it.
* ``screen:onDismiss()`` *(for overriding)*
Called by ``dfhack.screen.dismiss()``.
* ``screen:onDestroy()`` *(for overriding)*
Called by the native code when the screen is fully destroyed and removed
from the display stack. Place code that absolutely must be called whenever
the screen is removed by any means here.
* ``screen:onResize``, ``screen:onRender``
Defined as callbacks for native code.
FramedScreen class
------------------
A Screen subclass that paints a visible frame around its body.
Most dialogs should inherit from this class.
A framed screen has the following attributes:
:frame_style: A table that defines a set of pens to draw various parts of the frame.
:frame_title: A string to display in the middle of the top of the frame.
:frame_width: Desired width of the client area. If *nil*, the screen will occupy the whole width.
:frame_height: Likewise, for height.
:frame_inset: The gap between the frame and the client area. Defaults to 0.
:frame_background: The pen to fill in the frame with. Defaults to CLEAR_PEN.
There are the following predefined frame style tables:
* ``GREY_FRAME``
A plain grey-colored frame.
* ``BOUNDARY_FRAME``
The same frame as used by the usual full-screen DF views, like dwarfmode.
* ``GREY_LINE_FRAME``
A frame consisting of grey lines, similar to the one used by titan announcements.
gui.widgets
===========
This module implements some basic widgets based on the View infrastructure.
Widget class
------------
Base of all the widgets. Inherits from View and has the following attributes:
* ``frame = {...}``
Specifies the constraints on the outer frame of the widget.
If omitted, the widget will occupy the whole parent rectangle.
The frame is specified as a table with the following possible fields:
:l: gap between the left edges of the frame and the parent.
:t: gap between the top edges of the frame and the parent.
:r: gap between the right edges of the frame and the parent.
:b: gap between the bottom edges of the frame and the parent.
:w: maximum width of the frame.
:h: maximum heigth of the frame.
:xalign: X alignment of the frame.
:yalign: Y alignment of the frame.
First the ``l,t,r,b`` fields restrict the available area for
placing the frame. If ``w`` and ``h`` are not specified or
larger then the computed area, it becomes the frame. Otherwise
the smaller frame is placed within the are based on the
``xalign/yalign`` fields. If the align hints are omitted, they
are assumed to be 0, 1, or 0.5 based on which of the ``l/r/t/b``
fields are set.
* ``frame_inset = {...}``
Specifies the gap between the outer frame, and the client area.
The attribute may be a simple integer value to specify a uniform
inset, or a table with the following fields:
:l: left margin.
:t: top margin.
:r: right margin.
:b: bottom margin.
:x: left/right margin, if ``l`` and/or ``r`` are omitted.
:y: top/bottom margin, if ``t`` and/or ``b`` are omitted.
* ``frame_background = pen``
The pen to fill the outer frame with. Defaults to no fill.
Panel class
-----------
Inherits from Widget, and intended for grouping a number of subviews.
Has attributes:
* ``subviews = {}``
Used to initialize the subview list in the constructor.
* ``on_render = function(painter)``
Called from ``onRenderBody``.
Pages class
-----------
Subclass of Panel; keeps exactly one child visible.
* ``Pages{ ..., selected = ... }``
Specifies which child to select initially; defaults to the first one.
* ``pages:getSelected()``
Returns the selected *index, child*.
* ``pages:setSelected(index)``
Selects the specified child, hiding the previous selected one.
It is permitted to use the subview object, or its ``view_id`` as index.
EditField class
---------------
Subclass of Widget; implements a simple edit field.
Attributes:
:text: The current contents of the field.
:text_pen: The pen to draw the text with.
:on_char: Input validation callback; used as ``on_char(new_char,text)``.
If it returns false, the character is ignored.
:on_change: Change notification callback; used as ``on_change(new_text,old_text)``.
:on_submit: Enter key callback; if set the field will handle the key and call ``on_submit(text)``.
Label class
-----------
This Widget subclass implements flowing semi-static text.
It has the following attributes:
:text_pen: Specifies the pen for active text.
:text_dpen: Specifies the pen for disabled text.
:disabled: Boolean or a callback; if true, the label is disabled.
:enabled: Boolean or a callback; if false, the label is disabled.
:auto_height: Sets self.frame.h from the text height.
:auto_width: Sets self.frame.w from the text width.
The text itself is represented as a complex structure, and passed
to the object via the ``text`` argument of the constructor, or via
the ``setText`` method, as one of:
* A simple string, possibly containing newlines.
* A sequence of tokens.
Every token in the sequence in turn may be either a string, possibly
containing newlines, or a table with the following possible fields:
* ``token.text = ...``
Specifies the main text content of a token, and may be a string, or
a callback returning a string.
* ``token.gap = ...``
Specifies the number of character positions to advance on the line
before rendering the token.
* ``token.tile = pen``
Specifies a pen to paint as one tile before the main part of the token.
* ``token.key = '...'``
Specifies the keycode associated with the token. The string description
of the key binding is added to the text content of the token.
* ``token.key_sep = '...'``
Specifies the separator to place between the keybinding label produced
by ``token.key``, and the main text of the token. If the separator is
'()', the token is formatted as ``text..' ('..binding..')'``. Otherwise
it is simply ``binding..sep..text``.
* ``token.enabled``, ``token.disabled``
Same as the attributes of the label itself, but applies only to the token.
* ``token.pen``, ``token.dpen``
Specify the pen and disabled pen to be used for the token's text.
The field may be either the pen itself, or a callback that returns it.
* ``token.on_activate``
If this field is not nil, and ``token.key`` is set, the token will actually
respond to that key binding unless disabled, and call this callback. Eventually
this may be extended with mouse click support.
* ``token.id``
Specifies a unique identifier for the token.
* ``token.line``, ``token.x1``, ``token.x2``
Reserved for internal use.
The Label widget implements the following methods:
* ``label:setText(new_text)``
Replaces the text currently contained in the widget.
* ``label:itemById(id)``
Finds a token by its ``id`` field.
* ``label:getTextHeight()``
Computes the height of the text.
* ``label:getTextWidth()``
Computes the width of the text.
List class
----------
The List widget implements a simple list with paging.
It has the following attributes:
:text_pen: Specifies the pen for deselected list entries.
:cursor_pen: Specifies the pen for the selected entry.
:inactive_pen: If specified, used for the cursor when the widget is not active.
:icon_pen: Default pen for icons.
:on_select: Selection change callback; called as ``on_select(index,choice)``.
:on_submit: Enter key callback; if specified, the list reacts to the key
and calls it as ``on_submit(index,choice)``.
:row_height: Height of every row in text lines.
:icon_width: If not *nil*, the specified number of character columns
are reserved to the left of the list item for the icons.
:scroll_keys: Specifies which keys the list should react to as a table.
Every list item may be specified either as a string, or as a lua table
with the following fields:
:text: Specifies the label text in the same format as the Label text.
:caption, [1]: Deprecated legacy aliases for **text**.
:text_*: Reserved for internal use.
:key: Specifies a keybinding that acts as a shortcut for the specified item.
:icon: Specifies an icon string, or a pen to paint a single character. May be a callback.
:icon_pen: When the icon is a string, used to paint it.
The list supports the following methods:
* ``List{ ..., choices = ..., selected = ... }``
Same as calling ``setChoices`` after construction.
* ``list:setChoices(choices[, selected])``
Replaces the list of choices, possibly also setting the currently selected index.
* ``list:setSelected(selected)``
Sets the currently selected index. Returns the index after validation.
* ``list:getChoices()``
Returns the list of choices.
* ``list:getSelected()``
Returns the selected *index, choice*, or nothing if the list is empty.
* ``list:getContentWidth()``
Returns the minimal width to draw all choices without clipping.
* ``list:getContentHeight()``
Returns the minimal width to draw all choices without scrolling.
* ``list:submit()``
Call the ``on_submit`` callback, as if the Enter key was handled.
FilteredList class
------------------
This widget combines List, EditField and Label into a combo-box like
construction that allows filtering the list by subwords of its items.
In addition to passing through all attributes supported by List, it
supports:
:edit_pen: If specified, used instead of ``cursor_pen`` for the edit field.
:not_found_label: Specifies the text of the label shown when no items match the filter.
The list choices may include the following attributes:
:search_key: If specified, used instead of **text** to match against the filter.
The widget implements:
* ``list:setChoices(choices[, selected])``
Resets the filter, and passes through to the inner list.
* ``list:getChoices()``
Returns the list of *all* choices.
* ``list:getFilter()``
Returns the current filter string, and the *filtered* list of choices.
* ``list:setFilter(filter[,pos])``
Sets the new filter string, filters the list, and selects the item at
index ``pos`` in the *unfiltered* list if possible.
* ``list:canSubmit()``
Checks if there are currently any choices in the filtered list.
* ``list:getSelected()``, ``list:getContentWidth()``, ``list:getContentHeight()``, ``list:submit()``
Same as with an ordinary list.
=======
Plugins

@ -504,7 +504,7 @@ function List:onRenderBody(dc)
local icon = getval(obj.icon)
if icon then
dc:seek(0, y)
if type(icon) == 'table' then
if type(icon) ~= 'string' then
dc:char(nil,icon)
else
if current then
@ -573,7 +573,7 @@ FilteredList = defclass(FilteredList, Widget)
function FilteredList:init(info)
self.edit = EditField{
text_pen = info.cursor_pen,
text_pen = info.edit_pen or info.cursor_pen,
frame = { l = info.icon_width, t = 0 },
on_change = self:callback('onFilterChange'),
on_char = self:callback('onFilterChar'),
@ -583,6 +583,7 @@ function FilteredList:init(info)
text_pen = info.text_pen,
cursor_pen = info.cursor_pen,
inactive_pen = info.inactive_pen,
icon_pen = info.icon_pen,
row_height = info.row_height,
scroll_keys = info.scroll_keys,
icon_width = info.icon_width,

@ -457,6 +457,7 @@ function getBuildingCenter(building)
return xyz2pos(building.centerx, building.centery, building.z)
end
-- Split the string by the given delimiter
function split_string(self, delimiter)
local result = { }
local from = 1