cleanup, docs

This commit is contained in:
airstruck
2015-11-04 15:08:14 -05:00
parent ad9c954e7b
commit 74fc748e3b
13 changed files with 1949 additions and 189 deletions

7
config.ld Normal file
View File

@@ -0,0 +1,7 @@
project = 'Luigi'
description = 'Lovely User Interfaces for Game Inventors'
full_description = 'A UI library for LÖVE 0.10.0 and 0.9.2'
file = { 'luigi' }
format = 'markdown'
-- sort = true

151
doc/classes/Event.html Normal file
View File

@@ -0,0 +1,151 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Reference</title>
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>Luigi</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Tables">Tables</a></li>
</ul>
<h2>Classes</h2>
<ul class="$(kind=='Topics' and '' or 'nowrap'">
<li><strong>Event</strong></li>
<li><a href="../classes/Layout.html">Layout</a></li>
<li><a href="../classes/Widget.html">Widget</a></li>
</ul>
</div>
<div id="content">
<h1>Class <code>Event</code></h1>
<p>Event class.</p>
<p>
</p>
<h2><a href="#Tables">Tables</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Event.names">Event.names</a></td>
<td class="summary">Event names.</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Tables"></a>Tables</h2>
<dl class="function">
<dt>
<a name = "Event.names"></a>
<strong>Event.names</strong>
</dt>
<dd>
Event names.
<h3>Fields:</h3>
<ul>
<li><span class="parameter">Reshape</span>
A widget is being reshaped.
</li>
<li><span class="parameter">PreDisplay</span>
A widget is about to be drawn.
</li>
<li><span class="parameter">Display</span>
A widget was drawn.
</li>
<li><span class="parameter">KeyPress</span>
A keyboard key was pressed.
</li>
<li><span class="parameter">KeyRelease</span>
A keyboard key was released.
</li>
<li><span class="parameter">TextInput</span>
Text was entered.
</li>
<li><span class="parameter">Move</span>
The cursor moved, and no button was pressed.
</li>
<li><span class="parameter">Enter</span>
The cursor entered a widget, and no button was pressed.
</li>
<li><span class="parameter">Leave</span>
The cursor left a widget, and no button was pressed.
</li>
<li><span class="parameter">PressEnter</span>
The cursor entered a widget, and a button was pressed.
</li>
<li><span class="parameter">PressLeave</span>
The cursor left a widget, and a button was pressed.
</li>
<li><span class="parameter">PressStart</span>
A pointer button or accelerator key was pressed.
</li>
<li><span class="parameter">PressEnd</span>
A pointer button or accelerator key was released.
</li>
<li><span class="parameter">PressDrag</span>
A pressed cursor moved; targets originating widget.
</li>
<li><span class="parameter">PressMove</span>
A pressed cursor moved; targets widget at cursor position.
</li>
<li><span class="parameter">Press</span>
A pointer button was pressed and released on the same widget.
</li>
<li><span class="parameter">Change</span>
A widget's value changed.
</li>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
<i style="float:right;">Last updated 2015-11-04 15:07:53 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

296
doc/classes/Layout.html Normal file
View File

@@ -0,0 +1,296 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Reference</title>
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>Luigi</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Functions">Functions</a></li>
<li><a href="#Methods">Methods</a></li>
</ul>
<h2>Classes</h2>
<ul class="$(kind=='Topics' and '' or 'nowrap'">
<li><a href="../classes/Event.html">Event</a></li>
<li><strong>Layout</strong></li>
<li><a href="../classes/Widget.html">Widget</a></li>
</ul>
</div>
<div id="content">
<h1>Class <code>Layout</code></h1>
<p>Layout class.</p>
<p>
</p>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Luigi.Layout">Luigi.Layout (data)</a></td>
<td class="summary">Layout constructor.</td>
</tr>
</table>
<h2><a href="#Methods">Methods</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Layout:setStyle">Layout:setStyle (rules)</a></td>
<td class="summary">Set the style from a definition table or function.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Layout:setTheme">Layout:setTheme (rules)</a></td>
<td class="summary">Set the theme from a definition table or function.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Layout:show">Layout:show ()</a></td>
<td class="summary">Show the layout.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Layout:hide">Layout:hide ()</a></td>
<td class="summary">Hide the layout.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Layout:focusNextWidget">Layout:focusNextWidget ()</a></td>
<td class="summary">Focus next focusable widget.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Layout:focusPreviousWidget">Layout:focusPreviousWidget ()</a></td>
<td class="summary">Focus previous focusable widget.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Layout:getWidgetAt">Layout:getWidgetAt (x, y[, root])</a></td>
<td class="summary">Get the innermost widget at given coordinates.</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
Methods
<dl class="function">
<dt>
<a name = "Luigi.Layout"></a>
<strong>Luigi.Layout (data)</strong>
</dt>
<dd>
Layout constructor.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">data</span>
<span class="types"><a class="type" href="http://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
A tree of widget data.
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../classes/Layout.html#">Layout</a></span>
A Layout instance.
</ol>
</dd>
</dl>
<h2 class="section-header "><a name="Methods"></a>Methods</h2>
<dl class="function">
<dt>
<a name = "Layout:setStyle"></a>
<strong>Layout:setStyle (rules)</strong>
</dt>
<dd>
Set the style from a definition table or function.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">rules</span>
<span class="types"><a class="type" href="http://www.lua.org/manual/5.1/manual.html#5.5">table</a> or <span class="type">function</span></span>
Style definition.
</li>
</ul>
</dd>
<dt>
<a name = "Layout:setTheme"></a>
<strong>Layout:setTheme (rules)</strong>
</dt>
<dd>
Set the theme from a definition table or function.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">rules</span>
<span class="types"><a class="type" href="http://www.lua.org/manual/5.1/manual.html#5.5">table</a> or <span class="type">function</span></span>
Theme definition.
</li>
</ul>
</dd>
<dt>
<a name = "Layout:show"></a>
<strong>Layout:show ()</strong>
</dt>
<dd>
Show the layout. </p>
<p>Hooks all appropriate Love events and callbacks.
</dd>
<dt>
<a name = "Layout:hide"></a>
<strong>Layout:hide ()</strong>
</dt>
<dd>
Hide the layout. </p>
<p>Unhooks Love events and callbacks.
</dd>
<dt>
<a name = "Layout:focusNextWidget"></a>
<strong>Layout:focusNextWidget ()</strong>
</dt>
<dd>
Focus next focusable widget. </p>
<p>Traverses widgets using Widget:getNextNeighbor until a focusable widget is
found, and focuses that widget.
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../classes/Widget.html#">Widget</a></span>
The widget that was focused, or nil
</ol>
</dd>
<dt>
<a name = "Layout:focusPreviousWidget"></a>
<strong>Layout:focusPreviousWidget ()</strong>
</dt>
<dd>
Focus previous focusable widget. </p>
<p>Traverses widgets using Widget:getPreviousNeighbor until a focusable widget is
found, and focuses that widget.
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../classes/Widget.html#">Widget</a></span>
The widget that was focused, or nil
</ol>
</dd>
<dt>
<a name = "Layout:getWidgetAt"></a>
<strong>Layout:getWidgetAt (x, y[, root])</strong>
</dt>
<dd>
Get the innermost widget at given coordinates.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">x</span>
<span class="types"><span class="type">number</span></span>
Number of pixels from window's left edge.
</li>
<li><span class="parameter">y</span>
<span class="types"><span class="type">number</span></span>
Number of pixels from window's top edge.
</li>
<li><span class="parameter">root</span>
<span class="types"><a class="type" href="../classes/Widget.html#">Widget</a></span>
Widget to search within, defaults to layout root.
(<em>optional</em>)
</li>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
<i style="float:right;">Last updated 2015-11-04 15:07:53 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

618
doc/classes/Widget.html Normal file
View File

@@ -0,0 +1,618 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Reference</title>
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>Luigi</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Functions">Functions</a></li>
<li><a href="#Methods">Methods</a></li>
</ul>
<h2>Classes</h2>
<ul class="$(kind=='Topics' and '' or 'nowrap'">
<li><a href="../classes/Event.html">Event</a></li>
<li><a href="../classes/Layout.html">Layout</a></li>
<li><strong>Widget</strong></li>
</ul>
</div>
<div id="content">
<h1>Class <code>Widget</code></h1>
<p>Widget class.</p>
<p>
</p>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Luigi.Widget">Luigi.Widget (layout[, data])</a></td>
<td class="summary">Widget pseudo-constructor.</td>
</tr>
</table>
<h2><a href="#Methods">Methods</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Widget:bubbleEvent">Widget:bubbleEvent (eventName[, data])</a></td>
<td class="summary">Fire an event on this widget and each ancestor.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:setValue">Widget:setValue (value)</a></td>
<td class="summary">Set widget's value property and bubble a Change event.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:getPreviousSibling">Widget:getPreviousSibling ()</a></td>
<td class="summary">Get widget's previous sibling.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:getNextSibling">Widget:getNextSibling ()</a></td>
<td class="summary">Get widget's next sibling.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:focus">Widget:focus ()</a></td>
<td class="summary">Attempt to focus the widget.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:getNextNeighbor">Widget:getNextNeighbor ()</a></td>
<td class="summary">Get the next widget, depth-first.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:getPreviousNeighbor">Widget:getPreviousNeighbor ()</a></td>
<td class="summary">Get the previous widget, depth-first.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:addChild">Widget:addChild (data)</a></td>
<td class="summary">Add a child to this widget.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:getX">Widget:getX ()</a></td>
<td class="summary">Get the widget's X coordinate.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:getY">Widget:getY ()</a></td>
<td class="summary">Get the widget's Y coordinate.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:getWidth">Widget:getWidth ()</a></td>
<td class="summary">Get the widget's calculated width.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:getHeight">Widget:getHeight ()</a></td>
<td class="summary">Get the widget's calculated height.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:setWidth">Widget:setWidth (width)</a></td>
<td class="summary">Set the widget's width.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:setHeight">Widget:setHeight (height)</a></td>
<td class="summary">Set the widget's height.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:getRectangle">Widget:getRectangle (useMargin, usePadding)</a></td>
<td class="summary">Get two points describing a rectangle within the widget.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:isAt">Widget:isAt (x, y)</a></td>
<td class="summary">Determine whether a point is within a widget.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:reshape">Widget:reshape ()</a></td>
<td class="summary">Reshape the widget.</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
Methods
<dl class="function">
<dt>
<a name = "Luigi.Widget"></a>
<strong>Luigi.Widget (layout[, data])</strong>
</dt>
<dd>
Widget pseudo-constructor.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">layout</span>
<span class="types"><a class="type" href="../classes/Layout.html#">Layout</a></span>
The layout this widget belongs to.
</li>
<li><span class="parameter">data</span>
<span class="types"><a class="type" href="http://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
The data definition table for this widget.
This table is identical to the constructed widget.
(<em>optional</em>)
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../classes/Widget.html#">Widget</a></span>
A Widget instance.
</ol>
</dd>
</dl>
<h2 class="section-header "><a name="Methods"></a>Methods</h2>
<dl class="function">
<dt>
<a name = "Widget:bubbleEvent"></a>
<strong>Widget:bubbleEvent (eventName[, data])</strong>
</dt>
<dd>
Fire an event on this widget and each ancestor. </p>
<p>If any event handler returns non-nil, stop the event from propagating.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">eventName</span>
<span class="types"><a class="type" href="http://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The name of the Event.
</li>
<li><span class="parameter">data</span>
<span class="types"><a class="type" href="http://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
Information about the event to send to handlers.
(<em>optional</em>)
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">mixed</span></span>
The first value returned by an event handler.
</ol>
</dd>
<dt>
<a name = "Widget:setValue"></a>
<strong>Widget:setValue (value)</strong>
</dt>
<dd>
Set widget's value property and bubble a Change event.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">value</span>
<span class="types"><span class="type">mixed</span></span>
The new value of the widget.
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">mixed</span></span>
The old value of the widget.
</ol>
</dd>
<dt>
<a name = "Widget:getPreviousSibling"></a>
<strong>Widget:getPreviousSibling ()</strong>
</dt>
<dd>
Get widget's previous sibling.
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../classes/Widget.html#">Widget</a> or <span class="type">nil</span></span>
The widget's previous sibling, if any.
</ol>
</dd>
<dt>
<a name = "Widget:getNextSibling"></a>
<strong>Widget:getNextSibling ()</strong>
</dt>
<dd>
Get widget's next sibling.
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../classes/Widget.html#">Widget</a> or <span class="type">nil</span></span>
The widget's next sibling, if any.
</ol>
</dd>
<dt>
<a name = "Widget:focus"></a>
<strong>Widget:focus ()</strong>
</dt>
<dd>
Attempt to focus the widget. </p>
<p>Unfocus currently focused widget, and focus this widget if it's focusable.
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">boolean</span></span>
true if this widget was focused, else false.
</ol>
</dd>
<dt>
<a name = "Widget:getNextNeighbor"></a>
<strong>Widget:getNextNeighbor ()</strong>
</dt>
<dd>
Get the next widget, depth-first. </p>
<p>If the widget has children, returns the first child.
Otherwise, returns the next sibling of the nearest possible ancestor.
Cycles back around to the layout root from the last widget in the tree.
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../classes/Widget.html#">Widget</a></span>
The next widget in the tree.
</ol>
</dd>
<dt>
<a name = "Widget:getPreviousNeighbor"></a>
<strong>Widget:getPreviousNeighbor ()</strong>
</dt>
<dd>
Get the previous widget, depth-first. </p>
<p>Uses the reverse of the traversal order used by <a href="../classes/Widget.html#Widget:getNextNeighbor">getNextNeighbor</a>.
Cycles back around to the last widget in the tree from the layout root.
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../classes/Widget.html#">Widget</a></span>
The previous widget in the tree.
</ol>
</dd>
<dt>
<a name = "Widget:addChild"></a>
<strong>Widget:addChild (data)</strong>
</dt>
<dd>
Add a child to this widget.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">data</span>
<span class="types"><a class="type" href="../classes/Widget.html#">Widget</a> or <a class="type" href="http://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
A widget or definition table representing a widget.
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../classes/Widget.html#">Widget</a></span>
The newly added child widget.
</ol>
</dd>
<dt>
<a name = "Widget:getX"></a>
<strong>Widget:getX ()</strong>
</dt>
<dd>
Get the widget's X coordinate.
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">number</span></span>
The widget's X coordinate.
</ol>
</dd>
<dt>
<a name = "Widget:getY"></a>
<strong>Widget:getY ()</strong>
</dt>
<dd>
Get the widget's Y coordinate.
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">number</span></span>
The widget's Y coordinate.
</ol>
</dd>
<dt>
<a name = "Widget:getWidth"></a>
<strong>Widget:getWidth ()</strong>
</dt>
<dd>
Get the widget's calculated width.
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">number</span></span>
The widget's calculated width.
</ol>
</dd>
<dt>
<a name = "Widget:getHeight"></a>
<strong>Widget:getHeight ()</strong>
</dt>
<dd>
Get the widget's calculated height.
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">number</span></span>
The widget's calculated height.
</ol>
</dd>
<dt>
<a name = "Widget:setWidth"></a>
<strong>Widget:setWidth (width)</strong>
</dt>
<dd>
Set the widget's width. </p>
<p>Limited to space not occupied by siblings.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">width</span>
<span class="types"><span class="type">number</span></span>
The desired width. Actual width may differ.
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">number</span></span>
The actual width of the widget.
</ol>
</dd>
<dt>
<a name = "Widget:setHeight"></a>
<strong>Widget:setHeight (height)</strong>
</dt>
<dd>
Set the widget's height. </p>
<p>Limited to space not occupied by siblings.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">height</span>
<span class="types"><span class="type">number</span></span>
The desired height. Actual height may differ.
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">number</span></span>
The actual height of the widget.
</ol>
</dd>
<dt>
<a name = "Widget:getRectangle"></a>
<strong>Widget:getRectangle (useMargin, usePadding)</strong>
</dt>
<dd>
Get two points describing a rectangle within the widget.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">useMargin</span>
<span class="types"><span class="type">boolean</span></span>
Whether to adjust the rectangle based on the widget's margin.
</li>
<li><span class="parameter">usePadding</span>
<span class="types"><span class="type">boolean</span></span>
Whether to adjust the rectangle based on the widget's padding.
</li>
</ul>
<h3>Returns:</h3>
<ol>
<li>
<span class="types"><span class="type">number</span></span>
The upper left corner's X position.</li>
<li>
<span class="types"><span class="type">number</span></span>
The upper left corner's Y position.</li>
<li>
<span class="types"><span class="type">number</span></span>
The lower right corner's X position.</li>
<li>
<span class="types"><span class="type">number</span></span>
The lower right corner's Y position.</li>
</ol>
</dd>
<dt>
<a name = "Widget:isAt"></a>
<strong>Widget:isAt (x, y)</strong>
</dt>
<dd>
Determine whether a point is within a widget.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">x</span>
<span class="types"><span class="type">number</span></span>
The point's X coordinate.
</li>
<li><span class="parameter">y</span>
<span class="types"><span class="type">number</span></span>
The point's Y coordinate.
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">boolean</span></span>
true if the point is within the widget, else false.
</ol>
</dd>
<dt>
<a name = "Widget:reshape"></a>
<strong>Widget:reshape ()</strong>
</dt>
<dd>
Reshape the widget. </p>
<p>Clears calculated widget dimensions, allowing them to be recalculated, and
fires a Reshape event (does not bubble). Called recursively for each child.</p>
<p>When setting a widget's width or height, this function is automatically called
on the parent widget.
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
<i style="float:right;">Last updated 2015-11-04 15:07:53 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

71
doc/index.html Normal file
View File

@@ -0,0 +1,71 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Reference</title>
<link rel="stylesheet" href="ldoc.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>Luigi</h1>
<h2>Classes</h2>
<ul class="$(kind=='Topics' and '' or 'nowrap'">
<li><a href="classes/Event.html">Event</a></li>
<li><a href="classes/Layout.html">Layout</a></li>
<li><a href="classes/Widget.html">Widget</a></li>
</ul>
</div>
<div id="content">
<h2>Lovely User Interfaces for Game Inventors</h2>
<p>A UI library for LÖVE 0.10.0 and 0.9.2</p>
<h2>Classes</h2>
<table class="module_list">
<tr>
<td class="name" nowrap><a href="classes/Event.html">Event</a></td>
<td class="summary">Event class.</td>
</tr>
<tr>
<td class="name" nowrap><a href="classes/Layout.html">Layout</a></td>
<td class="summary">Layout class.</td>
</tr>
<tr>
<td class="name" nowrap><a href="classes/Widget.html">Widget</a></td>
<td class="summary">Widget class.</td>
</tr>
</table>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
<i style="float:right;">Last updated 2015-11-04 15:07:53 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

304
doc/ldoc.css Normal file
View File

@@ -0,0 +1,304 @@
/* BEGIN RESET
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.com/yui/license.html
version: 2.8.2r1
*/
html {
color: #000;
background: #FFF;
}
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td {
margin: 0;
padding: 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
fieldset,img {
border: 0;
}
address,caption,cite,code,dfn,em,strong,th,var,optgroup {
font-style: inherit;
font-weight: inherit;
}
del,ins {
text-decoration: none;
}
li {
list-style: disc;
margin-left: 20px;
}
caption,th {
text-align: left;
}
h1,h2,h3,h4,h5,h6 {
font-size: 100%;
font-weight: bold;
}
q:before,q:after {
content: '';
}
abbr,acronym {
border: 0;
font-variant: normal;
}
sup {
vertical-align: baseline;
}
sub {
vertical-align: baseline;
}
legend {
color: #000;
}
input,button,textarea,select,optgroup,option {
font-family: inherit;
font-size: inherit;
font-style: inherit;
font-weight: inherit;
}
input,button,textarea,select {*font-size:100%;
}
/* END RESET */
body {
margin-left: 1em;
margin-right: 1em;
font-family: arial, helvetica, geneva, sans-serif;
background-color: #ffffff; margin: 0px;
}
code, tt { font-family: monospace; font-size: 1.1em; }
span.parameter { font-family:monospace; }
span.parameter:after { content:":"; }
span.types:before { content:"("; }
span.types:after { content:")"; }
.type { font-weight: bold; font-style:italic }
body, p, td, th { font-size: .95em; line-height: 1.2em;}
p, ul { margin: 10px 0 0 0px;}
strong { font-weight: bold;}
em { font-style: italic;}
h1 {
font-size: 1.5em;
margin: 0 0 20px 0;
}
h2, h3, h4 { margin: 15px 0 10px 0; }
h2 { font-size: 1.25em; }
h3 { font-size: 1.15em; }
h4 { font-size: 1.06em; }
a:link { font-weight: bold; color: #004080; text-decoration: none; }
a:visited { font-weight: bold; color: #006699; text-decoration: none; }
a:link:hover { text-decoration: underline; }
hr {
color:#cccccc;
background: #00007f;
height: 1px;
}
blockquote { margin-left: 3em; }
ul { list-style-type: disc; }
p.name {
font-family: "Andale Mono", monospace;
padding-top: 1em;
}
pre {
background-color: rgb(245, 245, 245);
border: 1px solid #C0C0C0; /* silver */
padding: 10px;
margin: 10px 0 10px 0;
overflow: auto;
font-family: "Andale Mono", monospace;
}
pre.example {
font-size: .85em;
}
table.index { border: 1px #00007f; }
table.index td { text-align: left; vertical-align: top; }
#container {
margin-left: 1em;
margin-right: 1em;
background-color: #f0f0f0;
}
#product {
text-align: center;
border-bottom: 1px solid #cccccc;
background-color: #ffffff;
}
#product big {
font-size: 2em;
}
#main {
background-color: #f0f0f0;
border-left: 2px solid #cccccc;
}
#navigation {
float: left;
width: 14em;
vertical-align: top;
background-color: #f0f0f0;
overflow: visible;
}
#navigation h2 {
background-color:#e7e7e7;
font-size:1.1em;
color:#000000;
text-align: left;
padding:0.2em;
border-top:1px solid #dddddd;
border-bottom:1px solid #dddddd;
}
#navigation ul
{
font-size:1em;
list-style-type: none;
margin: 1px 1px 10px 1px;
}
#navigation li {
text-indent: -1em;
display: block;
margin: 3px 0px 0px 22px;
}
#navigation li li a {
margin: 0px 3px 0px -1em;
}
#content {
margin-left: 14em;
padding: 1em;
width: 700px;
border-left: 2px solid #cccccc;
border-right: 2px solid #cccccc;
background-color: #ffffff;
}
#about {
clear: both;
padding: 5px;
border-top: 2px solid #cccccc;
background-color: #ffffff;
}
@media print {
body {
font: 12pt "Times New Roman", "TimeNR", Times, serif;
}
a { font-weight: bold; color: #004080; text-decoration: underline; }
#main {
background-color: #ffffff;
border-left: 0px;
}
#container {
margin-left: 2%;
margin-right: 2%;
background-color: #ffffff;
}
#content {
padding: 1em;
background-color: #ffffff;
}
#navigation {
display: none;
}
pre.example {
font-family: "Andale Mono", monospace;
font-size: 10pt;
page-break-inside: avoid;
}
}
table.module_list {
border-width: 1px;
border-style: solid;
border-color: #cccccc;
border-collapse: collapse;
}
table.module_list td {
border-width: 1px;
padding: 3px;
border-style: solid;
border-color: #cccccc;
}
table.module_list td.name { background-color: #f0f0f0; min-width: 200px; }
table.module_list td.summary { width: 100%; }
table.function_list {
border-width: 1px;
border-style: solid;
border-color: #cccccc;
border-collapse: collapse;
}
table.function_list td {
border-width: 1px;
padding: 3px;
border-style: solid;
border-color: #cccccc;
}
table.function_list td.name { background-color: #f0f0f0; min-width: 200px; }
table.function_list td.summary { width: 100%; }
ul.nowrap {
overflow:auto;
white-space:nowrap;
}
dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;}
dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;}
dl.table h3, dl.function h3 {font-size: .95em;}
/* stop sublists from having initial vertical space */
ul ul { margin-top: 0px; }
ol ul { margin-top: 0px; }
ol ol { margin-top: 0px; }
ul ol { margin-top: 0px; }
/* make the target distinct; helps when we're navigating to a function */
a:target + * {
background-color: #FF9;
}
/* styles for prettification of source */
pre .comment { color: #558817; }
pre .constant { color: #a8660d; }
pre .escape { color: #844631; }
pre .keyword { color: #aa5050; font-weight: bold; }
pre .library { color: #0e7c6b; }
pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; }
pre .string { color: #8080ff; }
pre .number { color: #f8660d; }
pre .operator { color: #2239a8; font-weight: bold; }
pre .preprocessor, pre .prepro { color: #a33243; }
pre .global { color: #800080; }
pre .user-keyword { color: #800080; }
pre .prompt { color: #558817; }
pre .url { color: #272fc2; text-decoration: underline; }

View File

@@ -46,7 +46,7 @@ local mainForm = { title = "Test window", id = 'mainWindow', type = 'panel',
icon = 'icon/32px/Harddrive.png' },
},
{ flow = 'x',
{ id = 'leftSideBox', width = 200, minwidth = 64,
{ id = 'leftSideBox', width = 200, minwidth = 64,
{ text = 'Hi, I\'m centered middle. ', style = 'listThing',
align = 'middle center' },
{ text = 'Hi, I\'m centered bottom. ', style = 'listThing',

View File

@@ -1,3 +1,9 @@
--[[--
Event class.
@classmod Event
--]]--
local ROOT = (...):gsub('[^.]*$', '')
local Base = require(ROOT .. 'base')
@@ -17,24 +23,32 @@ function Event:bind (target, callback)
return Hooker.hook(registry, target, callback)
end
local eventNames = {
'Reshape', -- widget's dimensions changed
'PreDisplay', 'Display', -- before/after widget is drawn
'KeyPress', 'KeyRelease', -- keyboard key pressed/released
'TextInput', -- text is entered
'Move', -- cursor moves, no button pressed
'Enter', 'Leave', -- cursor enters/leaves widget, no button pressed
'PressEnter', 'PressLeave', -- cursor enters/leaves widget, button pressed
'PressStart', 'PressEnd', -- cursor or accelerator key press starts/ends
'PressDrag', -- pressed cursor moves, targets originating widget
'PressMove', -- pressed cursor moves, targets widget at cursor position
'Press', -- cursor is pressed and released on same widget
'Change', -- widget's value changed via Widget:setValue
--[[--
Event names.
--]]--
Event.names = {
'Reshape', -- A widget is being reshaped.
'PreDisplay', -- A widget is about to be drawn.
'Display', -- A widget was drawn.
'KeyPress', -- A keyboard key was pressed.
'KeyRelease', -- A keyboard key was released.
'TextInput', -- Text was entered.
'Move', -- The cursor moved, and no button was pressed.
'Enter', -- The cursor entered a widget, and no button was pressed.
'Leave', -- The cursor left a widget, and no button was pressed.
'PressEnter', -- The cursor entered a widget, and a button was pressed.
'PressLeave', -- The cursor left a widget, and a button was pressed.
'PressStart', -- A pointer button or accelerator key was pressed.
'PressEnd', -- A pointer button or accelerator key was released.
'PressDrag', -- A pressed cursor moved; targets originating widget.
'PressMove', -- A pressed cursor moved; targets widget at cursor position.
'Press', -- A pointer button was pressed and released on the same widget.
'Change', -- A widget's value changed.
}
local weakKeyMeta = { __mode = 'k' }
for i, name in ipairs(eventNames) do
for i, name in ipairs(Event.names) do
Event[name] = Event:extend({
name = name,
registry = setmetatable({}, weakKeyMeta),
@@ -42,7 +56,7 @@ for i, name in ipairs(eventNames) do
end
function Event.injectBinders (t)
for i, name in ipairs(eventNames) do
for i, name in ipairs(Event.names) do
t['on' .. name] = function (...) return Event[name]:bind(...) end
end
end

View File

@@ -120,7 +120,7 @@ function Input:handlePressStart (button, x, y, widget, accelerator)
widget.pressed = true
self.pressedWidgets[button] = widget
self.passedWidgets[button] = widget
self.layout:tryFocus(widget)
widget:focus()
widget:bubbleEvent('PressStart', {
button = button,
accelerator = accelerator,

View File

@@ -1,3 +1,9 @@
--[[--
Layout class.
@classmod Layout
--]]--
local ROOT = (...):gsub('[^.]*$', '')
local Base = require(ROOT .. 'base')
@@ -9,6 +15,17 @@ local Hooker = require(ROOT .. 'hooker')
local Layout = Base:extend()
--[[--
Layout constructor.
@function Luigi.Layout
@tparam table data
A tree of widget data.
@treturn Layout
A Layout instance.
--]]--
function Layout:constructor (data)
self.accelerators = {}
self:addDefaultHandlers()
@@ -22,77 +39,144 @@ function Layout:constructor (data)
Widget(self, self.root)
end
-- focus a widget if it's focusable, and return success
function Layout:tryFocus (widget)
if widget.canFocus then
if self.focusedWidget then
self.focusedWidget.focused = false
end
widget.focused = true
self.focusedWidget = widget
return true
--[[--
Set the style from a definition table or function.
@tparam table|function rules
Style definition.
--]]--
function Layout:setStyle (rules)
if type(rules) == 'function' then
rules = rules()
end
self.style = Style(rules or {}, { 'id', 'style' })
end
-- get the next widget, cycling back around to root (depth first)
function Layout:getNextWidget (widget)
if #widget.children > 0 then
return widget.children[1]
--[[--
Set the theme from a definition table or function.
@tparam table|function rules
Theme definition.
--]]--
function Layout:setTheme (rules)
if type(rules) == 'function' then
rules = rules()
end
for ancestor in widget:eachAncestor(true) do
local nextWidget = ancestor:getNext()
if nextWidget then return nextWidget end
end
return self.root
self.theme = Style(rules or {}, { 'type' })
end
-- get the last child of the last child of the last child of the...
local function getGreatestDescendant (widget)
while #widget.children > 0 do
local children = widget.children
widget = children[#children]
--[[--
Show the layout.
Hooks all appropriate Love events and callbacks.
--]]--
function Layout:show ()
local root = self.root
local width = root.width
local height = root.height
local title = root.title
if not self.input then
self.input = Input(self)
end
return widget
local currentWidth, currentHeight, flags = love.window.getMode()
love.window.setMode(width or currentWidth, height or currentHeight, flags)
if title then
love.window.setTitle(title)
end
self:manageInput(self.input)
root:reshape()
end
-- get the previous widget, cycling back around to root (depth first)
function Layout:getPreviousWidget (widget)
if widget == self.root then
return getGreatestDescendant(widget)
--[[--
Hide the layout.
Unhooks Love events and callbacks.
--]]--
function Layout:hide ()
if not self.isManagingInput then
return
end
for ancestor in widget:eachAncestor(true) do
local previousWidget = ancestor:getPrevious()
if previousWidget then
return getGreatestDescendant(previousWidget)
end
if ancestor ~= widget then return ancestor end
end
return self.root
self.isManagingInput = false
self:unhook()
end
-- focus next focusable widget (depth first)
--[[--
Focus next focusable widget.
Traverses widgets using Widget:getNextNeighbor until a focusable widget is
found, and focuses that widget.
@treturn Widget
The widget that was focused, or nil
--]]--
function Layout:focusNextWidget ()
local widget = self.focusedWidget or self.root
local nextWidget = self:getNextWidget(widget)
local nextWidget = widget:getNextNeighbor()
while nextWidget ~= widget do
if self:tryFocus(nextWidget) then return end
nextWidget = self:getNextWidget(nextWidget)
if nextWidget:focus() then return nextWidget end
nextWidget = nextWidget:getNextNeighbor()
end
end
-- focus previous focusable widget (depth first)
--[[--
Focus previous focusable widget.
Traverses widgets using Widget:getPreviousNeighbor until a focusable widget is
found, and focuses that widget.
@treturn Widget
The widget that was focused, or nil
--]]--
function Layout:focusPreviousWidget ()
local widget = self.focusedWidget or self.root
local previousWidget = self:getPreviousWidget(widget)
local previousWidget = widget:getPreviousNeighbor()
while previousWidget ~= widget do
if self:tryFocus(previousWidget) then return end
previousWidget = self:getPreviousWidget(previousWidget)
if previousWidget:focus() then return previousWidget end
previousWidget = previousWidget:getPreviousNeighbor()
end
end
-- handlers for keyboard accelerators and tab focus
--[[--
Get the innermost widget at given coordinates.
@tparam number x
Number of pixels from window's left edge.
@tparam number y
Number of pixels from window's top edge.
@tparam[opt] Widget root
Widget to search within, defaults to layout root.
--]]--
function Layout:getWidgetAt (x, y, root)
local widget = root or self.root
local children = widget.children
local childCount = #children
-- Loop through in reverse, because siblings defined later in the tree
-- will overdraw earlier siblings.
for i = childCount, 1, -1 do
local child = children[i]
local inner = self:getWidgetAt(x, y, child)
if inner then return inner end
end
if widget:isAt(x, y) then return widget end
if widget == self.root then return widget end
end
-- Internal, called from Widget:new
function Layout:addWidget (widget)
if widget.id then
self[widget.id] = widget
end
if widget.key then
self.accelerators[widget.key] = widget
end
end
-- Add handlers for keyboard accelerators and tab focus
function Layout:addDefaultHandlers ()
self:onKeyPress(function (event)
@@ -147,78 +231,6 @@ function Layout:addDefaultHandlers ()
end)
end
-- set the style from a definition table or function
function Layout:setStyle (rules)
if type(rules) == 'function' then
rules = rules()
end
self.style = Style(rules or {}, { 'id', 'style' })
end
-- set the theme from a definition table or function
function Layout:setTheme (rules)
if type(rules) == 'function' then
rules = rules()
end
self.theme = Style(rules or {}, { 'type' })
end
-- show the layout (hooks all appropriate love events and callbacks)
function Layout:show ()
local root = self.root
local width = root.width
local height = root.height
local title = root.title
if not self.input then
self.input = Input(self)
end
local currentWidth, currentHeight, flags = love.window.getMode()
love.window.setMode(width or currentWidth, height or currentHeight, flags)
if title then
love.window.setTitle(title)
end
self:manageInput(self.input)
root:reshape()
end
-- hide the layout (unhooks love events and callbacks)
function Layout:hide ()
if not self.isManagingInput then
return
end
self.isManagingInput = false
self:unhook()
end
-- Get the innermost widget at a position, within a root widget.
-- Should always return a widget since all positions are within
-- the layout's root widget.
function Layout:getWidgetAt (x, y, root)
local widget = root or self.root
local children = widget.children
local childCount = #children
-- Loop through in reverse, because siblings defined later in the tree
-- will overdraw earlier siblings.
for i = childCount, 1, -1 do
local child = children[i]
local inner = self:getWidgetAt(x, y, child)
if inner then return inner end
end
if widget:isAt(x, y) then return widget end
if widget == self.root then return widget end
end
-- Internal, called from Widget:new
function Layout:addWidget (widget)
if widget.id then
self[widget.id] = widget
end
if widget.key then
self.accelerators[widget.key] = widget
end
end
-- event stuff
function Layout:hook (key, method)
@@ -288,4 +300,26 @@ end
Event.injectBinders(Layout)
-- ffi
function Layout:showMessage () end
local _, ffi = pcall(require, 'ffi')
if ffi then
ffi.cdef [[
int SDL_ShowSimpleMessageBox(
uint32_t flags,
const char* title,
const char* message,
void* window
);
]]
function Layout:showMessage (title, message)
ffi.C.SDL_ShowSimpleMessageBox(0, title, message, nil)
end
end
return Layout

View File

@@ -1,3 +1,9 @@
--[[--
Widget class.
@classmod Widget
--]]--
local ROOT = (...):gsub('[^.]*$', '')
local Event = require(ROOT .. 'event')
@@ -22,7 +28,65 @@ function Widget.register (name, decorator)
Widget.typeDecorators[name] = decorator
end
local function new (Widget, layout, self)
-- look for properties in shadow props, Widget, style, and theme
local function metaIndex (self, property)
local value = self.shadowProperties[property]
if value ~= nil then return value end
local value = Widget[property]
if value ~= nil then return value end
local style = self.layout.style
value = style and style:getProperty(self, property)
if value ~= nil and value ~= 'defer' then return value end
local theme = self.layout.theme
return theme and theme:getProperty(self, property)
end
-- setting shadow properties causes special behavior
local function metaNewIndex (self, property, value)
if property == 'font'
or property == 'fontSize'
or property == 'textColor' then
self.shadowProperties[property] = value
self.fontData = Font(self.font, self.fontSize, self.textColor)
return
end
if property == 'width' then
value = math.max(value, self.minwidth or 0)
self.shadowProperties[property] = value
Widget.reshape(self.parent or self)
return
end
if property == 'height' then
value = math.max(value, self.minheight or 0)
self.shadowProperties[property] = value
Widget.reshape(self.parent or self)
return
end
rawset(self, property, value)
end
--[[--
Widget pseudo-constructor.
@function Luigi.Widget
@tparam Layout layout
The layout this widget belongs to.
@tparam[opt] table data
The data definition table for this widget.
This table is identical to the constructed widget.
@treturn Widget
A Widget instance.
--]]--
local function metaCall (Widget, layout, self)
self = self or {}
self.layout = layout
self.children = {}
@@ -30,45 +94,16 @@ local function new (Widget, layout, self)
self.dimensions = { width = nil, height = nil }
self.shadowProperties = {}
setmetatable(self, { __index = metaIndex, __newindex = metaNewIndex })
for _, property
in ipairs { 'font', 'fontSize', 'textColor', 'width', 'height' } do
self.shadowProperties[property] = self[property]
self[property] = nil
end
local meta = setmetatable(self, {
__index = function (self, property)
local value = self.shadowProperties[property]
if value ~= nil then return value end
local value = Widget[property]
if value ~= nil then return value end
local style = self.layout.style
value = style and style:getProperty(self, property)
if value ~= nil and value ~= 'defer' then return value end
local theme = self.layout.theme
return theme and theme:getProperty(self, property)
end,
__newindex = function (self, property, value)
if property == 'font'
or property == 'fontSize'
or property == 'textColor' then
self.shadowProperties[property] = value
self.fontData = Font(self.font, self.fontSize, self.textColor)
return
end
if property == 'width' or property == 'height' then
self.shadowProperties[property] = value
;(self.parent or self):reshape()
return
end
rawset(self, property, value)
local value = rawget(self, property)
rawset(self, property, nil)
if value ~= nil then
self[property] = value
end
})
end
self.type = self.type or 'generic'
self.fontData = Font(self.font, self.fontSize, self.textColor)
@@ -82,13 +117,27 @@ local function new (Widget, layout, self)
end
for k, v in ipairs(self) do
self.children[k] = v.isWidget and v or new(Widget, self.layout, v)
self.children[k] = v.isWidget and v or metaCall(Widget, self.layout, v)
self.children[k].parent = self
end
return self
end
--[[--
Fire an event on this widget and each ancestor.
If any event handler returns non-nil, stop the event from propagating.
@tparam string eventName
The name of the Event.
@tparam[opt] table data
Information about the event to send to handlers.
@treturn mixed
The first value returned by an event handler.
--]]--
function Widget:bubbleEvent (eventName, data)
local event = Event[eventName]
data = data or {}
@@ -100,6 +149,15 @@ function Widget:bubbleEvent (eventName, data)
return event:emit(self.layout, data)
end
--[[--
Set widget's value property and bubble a Change event.
@tparam mixed value
The new value of the widget.
@treturn mixed
The old value of the widget.
--]]--
function Widget:setValue (value)
local oldValue = self.value
self.value = value
@@ -108,9 +166,17 @@ function Widget:setValue (value)
value = value,
oldValue = oldValue,
})
return oldValue
end
function Widget:getPrevious ()
--[[--
Get widget's previous sibling.
@treturn Widget|nil
The widget's previous sibling, if any.
--]]--
function Widget:getPreviousSibling ()
if not self.parent then return end
local siblings = self.parent.children
for i, widget in ipairs(siblings) do
@@ -118,7 +184,13 @@ function Widget:getPrevious ()
end
end
function Widget:getNext ()
--[[--
Get widget's next sibling.
@treturn Widget|nil
The widget's next sibling, if any.
--]]--
function Widget:getNextSibling ()
if not self.parent then return end
local siblings = self.parent.children
for i, widget in ipairs(siblings) do
@@ -126,6 +198,97 @@ function Widget:getNext ()
end
end
--[[--
Attempt to focus the widget.
Unfocus currently focused widget, and focus this widget if it's focusable.
@treturn boolean
true if this widget was focused, else false.
--]]--
function Widget:focus ()
local layout = self.layout
if layout.focusedWidget then
layout.focusedWidget.focused = nil
layout.focusedWidget = nil
end
if self.canFocus then
self.focused = true
layout.focusedWidget = self
return true
end
return false
end
--[[--
Get the next widget, depth-first.
If the widget has children, returns the first child.
Otherwise, returns the next sibling of the nearest possible ancestor.
Cycles back around to the layout root from the last widget in the tree.
@treturn Widget
The next widget in the tree.
--]]--
function Widget:getNextNeighbor ()
if #self.children > 0 then
return self.children[1]
end
for ancestor in self:eachAncestor(true) do
local nextWidget = ancestor:getNextSibling()
if nextWidget then return nextWidget end
end
return self.layout.root
end
-- get the last child of the last child of the last child of the...
local function getGreatestDescendant (widget)
while #widget.children > 0 do
local children = widget.children
widget = children[#children]
end
return widget
end
--[[--
Get the previous widget, depth-first.
Uses the reverse of the traversal order used by `getNextNeighbor`.
Cycles back around to the last widget in the tree from the layout root.
@treturn Widget
The previous widget in the tree.
--]]--
function Widget:getPreviousNeighbor ()
local layout = self.layout
if self == layout.root then
return getGreatestDescendant(self)
end
for ancestor in self:eachAncestor(true) do
local previousWidget = ancestor:getPreviousSibling()
if previousWidget then
return getGreatestDescendant(previousWidget)
end
if ancestor ~= self then return ancestor end
end
return layout.root
end
--[[--
Add a child to this widget.
@tparam Widget|table data
A widget or definition table representing a widget.
@treturn Widget
The newly added child widget.
--]]--
function Widget:addChild (data)
local layout = self.layout
local child = Widget(layout, data or {})
@@ -140,7 +303,17 @@ local function clamp (value, min, max)
return value < min and min or value > max and max or value
end
local function checkReshape (widget)
if widget.needsReshape then
widget.position = {}
widget.dimensions = {}
widget.needsReshape = false
end
end
function Widget:calculateDimension (name)
checkReshape(self)
if self.dimensions[name] then
return self.dimensions[name]
end
@@ -195,6 +368,8 @@ function Widget:calculateDimension (name)
end
function Widget:calculatePosition (axis)
checkReshape(self)
if self.position[axis] then
return self.position[axis]
end
@@ -222,18 +397,42 @@ function Widget:calculatePosition (axis)
return 0
end
--[[--
Get the widget's X coordinate.
@treturn number
The widget's X coordinate.
--]]--
function Widget:getX ()
return self:calculatePosition('x')
end
--[[--
Get the widget's Y coordinate.
@treturn number
The widget's Y coordinate.
--]]--
function Widget:getY ()
return self:calculatePosition('y')
end
--[[--
Get the widget's calculated width.
@treturn number
The widget's calculated width.
--]]--
function Widget:getWidth ()
return self:calculateDimension('width')
end
--[[--
Get the widget's calculated height.
@treturn number
The widget's calculated height.
--]]--
function Widget:getHeight ()
return self:calculateDimension('height')
end
@@ -256,16 +455,40 @@ function Widget:setDimension (name, size)
local min = (name == 'width') and (self.minwidth or 0)
or (self.minheight or 0)
self[name] = math.max(size, min)
return self[name]
end
function Widget:setWidth (size)
return self:setDimension('width', size)
--[[--
Set the widget's width.
Limited to space not occupied by siblings.
@tparam number width
The desired width. Actual width may differ.
@treturn number
The actual width of the widget.
--]]--
function Widget:setWidth (width)
return self:setDimension('width', width)
end
function Widget:setHeight (size)
return self:setDimension('height', size)
--[[--
Set the widget's height.
Limited to space not occupied by siblings.
@tparam number height
The desired height. Actual height may differ.
@treturn number
The actual height of the widget.
--]]--
function Widget:setHeight (height)
return self:setDimension('height', height)
end
function Widget:getOrigin ()
@@ -277,6 +500,27 @@ function Widget:getExtent ()
return x + self:getWidth(), y + self:getHeight()
end
--[[--
Get two points describing a rectangle within the widget.
@tparam boolean useMargin
Whether to adjust the rectangle based on the widget's margin.
@tparam boolean usePadding
Whether to adjust the rectangle based on the widget's padding.
@treturn number
The upper left corner's X position.
@treturn number
The upper left corner's Y position.
@treturn number
The lower right corner's X position.
@treturn number
The lower right corner's Y position.
--]]--
function Widget:getRectangle (useMargin, usePadding)
local x1, y1 = self:getOrigin()
local x2, y2 = self:getExtent()
@@ -295,7 +539,21 @@ function Widget:getRectangle (useMargin, usePadding)
return math.floor(x1), math.floor(y1), math.floor(x2), math.floor(y2)
end
--[[--
Determine whether a point is within a widget.
@tparam number x
The point's X coordinate.
@tparam number y
The point's Y coordinate.
@treturn boolean
true if the point is within the widget, else false.
--]]--
function Widget:isAt (x, y)
checkReshape(self)
local x1, y1, x2, y2 = self:getRectangle()
return (x1 < x) and (x2 > x) and (y1 < y) and (y2 > y)
end
@@ -310,12 +568,19 @@ function Widget:eachAncestor (includeSelf)
end
end
-- reshape the widget. Call this after changing position/dimensions.
--[[--
Reshape the widget.
Clears calculated widget dimensions, allowing them to be recalculated, and
fires a Reshape event (does not bubble). Called recursively for each child.
When setting a widget's width or height, this function is automatically called
on the parent widget.
--]]--
function Widget:reshape ()
if self.isReshaping then return end
self.isReshaping = true
self.position = {}
self.dimensions = {}
self.needsReshape = true
Event.Reshape:emit(self, {
target = self
})
@@ -325,4 +590,4 @@ function Widget:reshape ()
self.isReshaping = nil
end
return setmetatable(Widget, { __call = new })
return setmetatable(Widget, { __call = metaCall })

View File

@@ -17,19 +17,19 @@ return function (self)
axis = 'y'
dimension = 'height'
end
local prevSibling = self:getPrevious()
local nextSibling = self:getNext()
local prevSibling = self:getPreviousSibling()
local nextSibling = self:getNextSibling()
local prevSize = prevSibling and prevSibling[dimension]
local nextSize = nextSibling and nextSibling[dimension]
if prevSize then
prevSibling:setDimension(dimension,
event[axis] - prevSibling:calculatePosition(axis))
event[axis] - prevSibling:calculatePosition(axis))
end
if nextSize then
nextSibling:setDimension(dimension,
nextSibling:calculatePosition(axis) +
nextSibling:calculateDimension(dimension) - event[axis])
nextSibling:calculatePosition(axis) +
nextSibling:calculateDimension(dimension) - event[axis])
end
end)

View File

@@ -39,7 +39,7 @@ return function (self)
local halfThumb = thumb:getWidth() / 2
x1, x2 = x1 + halfThumb, x2 - halfThumb
self:setValue(clamp((event.x - x1) / (x2 - x1)))
self.layout:tryFocus(thumb)
thumb:focus()
end
self:onPressStart(press)