* Add Demonic MDK.

* Inject autostudy plugin into the UI directly.
* Add a TLC automator for study.
[SKIP CI] Do not run CI for this.
This commit is contained in:
Charles Click 2024-10-09 23:11:30 +00:00
parent 0ebb9e6007
commit 954dc3c607
80 changed files with 40838 additions and 2 deletions

View File

@ -0,0 +1,30 @@
[
{
"name": "study.add",
"regex": "^studyadd (.*)$"
},
{
"name": "study.start",
"regex": "^studystart$"
},
{
"name": "study.auto",
"regex": "^studyauto$"
},
{
"name": "study.list",
"regex": "^studylist$"
},
{
"name": "study.clear",
"regex": "^studyclear$"
},
{
"name": "study.resume",
"regex": "^studyresume$"
},
{
"name": "study.help",
"regex": "^studyhelp$"
}
]

View File

@ -0,0 +1,3 @@
studyList = studyList or {}
table.insert(studyList, matches[2])
cecho(matches[2] .. "<dodger_blue> added.")

View File

@ -0,0 +1,25 @@
studyIndex = 1
studyList = {
"camera",
"set",
"construction",
"data",
"sword",
"buffet",
"tome",
"datpad",
"bioplug",
"gloves",
"dna",
"beacon",
"terraform",
"support",
"formation",
"spice",
"models",
"bag"
}
cecho("<dodger_blue>Starting Ithor TLC Automator.")
send("bot start")
send("study " .. studyList[studyIndex])
enableTrigger("autostudy")

View File

@ -0,0 +1,5 @@
studyList = []
studyIndex = 0
disableTrigger("autostudy")
cecho("<dodger_blue>Cleared list of study items.")

View File

View File

@ -0,0 +1,32 @@
local TableMaker = require("lotj-ui.MDK.ftext").TableMaker
if not studyList then
cecho("<dodger_blue>Studylist Empty.")
else
studyTable = TableMaker:new({
title = "Studylist",
printTitle = true,
printHeaders = false,
separateRows = false,
frameColor = "<purple>"
})
studyTable:addColumn({
name = "Index",
width = "5",
textColor = "<orange>"
})
studyTable:addColumn({
name = "Study Item",
width = "25",
textColor = "<>"green
})
for index, value in ipairs(studyList) do
studyTable:addRow({
index,
value
})
end
end
cecho(studyTable:assemble())

View File

@ -0,0 +1,5 @@
if studyList and studyIndex then
send("study " .. studyList[studyIndex])
else
send("<dodger_blue>You need to add items to your study list first. See studyhelp for commands.")
end

View File

@ -0,0 +1,8 @@
if #studyList > 0 then
studyIndex = studyIndex or 1
if studyIndex == 0 then studyIndex = 1 end
send("study " .. studyList[studyIndex])
enableTrigger("autostudy")
else
cecho("<dodger_blue>No study list. See studyhelp for commands.")
end

2204
src/resources/MDK/Big.flf Executable file

File diff suppressed because it is too large Load Diff

48
src/resources/MDK/LICENSE.lua Executable file
View File

@ -0,0 +1,48 @@
--[===[
The MIT License (MIT)
Copyright (c) 2020 Damian Monogue
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]===]
-- schema validation provided by schema.lua, license below
--[[
The MIT License (MIT)
Copyright (c) 2014 Sebastian Schoener
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]

91
src/resources/MDK/README.md Executable file
View File

@ -0,0 +1,91 @@
# the demonnic MDK and You
This is a collection of Lua 'classes' and modules I wrote for Mudlet. It is largely targeted at scripters, and comes packaged in two ways depending on how you intend to use/distribute your work. Please see [Installation](#installation) for more details
## Documentation
The [MDK wiki](https://github.com/demonnic/MDK/wiki) contains an entry for each module or class, as well as examples.
Starting with alpha2 of the MDK, the ldocs generated from code are included in the zipped releases. The current release's ldocs can always be viewed at <https://demonnic.github.io/mdk/current/>
## Installation
How you 'install' the MDK depends on how you intend to use it.
### I just want to install the MDK for my own personal use
You just want to get your hands on the goods, and aren't looking to use any MDK items in an exported package for sharing or anything like that.
Well, you are who the mdk mpackage is for! Download the MDK.mpackage from your desired release on the [Releases](https://github.com/demonnic/MDK/releases) page and install it in the package manager. The examples in the [wiki](https://demonnic.github.io/mdk/current/) are written with this in mind, and you would require the items you need as `local EMCO = require("MDK.emco")`
### I am a package author looking to include/use one of the MDK modules or classes in my package
You should download the `demonnic-MDK-<version>.zip` file for your desired release on the [Releases](https://github.com/demonnic/MDK/releases) page.
Inside are the individual .lua files for the modules and classes described in the [wiki](https://demonnic.github.io/mdk/current/) and [API docs](https://demonnic.github.io/mdk/current/).
You can include all of them if you wish, or only the ones you actually make use of. I ask that you include the LICENSE.lua or LICENSE-MDK.lua file (depending on the release) file in addition.
They should go in the root of your package, so that when your package is installed the files can be found at `getMudletHomeDir() .. "/<packagename>/emco.lua"`. You would then use `local EMCO = require("<mypackagename>.emco")`
So for example if your package name is "MySuperCoolPackage" and it installs to `getMudletHomeDir() .. "/MySuperCoolPackage/"` then you use `local EMCO = require("MySuperCoolPackage.emco")` and the emco.lua file should be at `getMudletHomeDir() .. "/MySuperCoolPackage/emco.lua"`
## Files (Modules/Classes)
These files contain the modules in the MDK. You only need to include those files which you intend to use, except as noted in the descriptions below.
If you include any of the modules from the MDK, you should also include LICENSE.lua or LICENSE-MDK.lua. It contains the licenses for my modules and for luaunit and lua-schema which are not my original works.
You should maybe also include demontools.lua, as it notes below several other of the MDK modules make use of items within it.
* aliasmgr.ua
* Object to manage tempAliases programmatically. <https://github.com/demonnic/MDK/wiki/AliasMgr>
* chyron.lua
* Label which moves a message across its face from right to left, like a stock ticker or the news chyrons. Documentation at <https://github.com/demonnic/MDK/wiki/Chyron>
* demontools.lua
* Collection of miscellaneous useful functions. You should include this file if you use the MDK, as several other modules make use of it. Include functions for converting c/d/hecho, html, and ansi colored strings between each other, mkdir_p, and some others. <https://github.com/demonnic/MDK/wiki/DemonTools>
* emco.lua
* EMCO. Documentation at <https://github.com/demonnic/MDK/wiki/EMCO> Will make use of LoggingConsole if loggingconsole.lua and demontools.lua are included
* figlet.lua
* Creates FIGlets from strings
* Reference package with multiple fonts and color gradients at <https://github.com/demonnic/figinator>
* ftext.lua
* basic fText. Documentation at <https://github.com/demonnic/MDK/wiki/fText>
* now includes TextFormatter and TableMaker as ftext.TextFormatter and ftext.TableMaker
* gradientmaker.lua
* Functions for creating color gradients for use with c/d/hecho. Documentation at <https://github.com/demonnic/MDK/wiki/GradientMaker>
* loggingconsole.lua
* Self logging extension to the mini console. Works just like a Geyser.MiniConsole but adds a templated path and fileName constraint, as well as logFormat so it can log what is echod or appended to it. Requires demontools.lua in order to work.
* loginator.lua
* Creates objects for logging messages to disk. <https://github.com/demonnic/MDK/wiki/Loginator>
* mastermindsolver.lua
* A class which will help you solve Master Mind puzzles. <https://github.com/demonnic/MDK/wiki/MasterMindSolver>
* revisionator.lua
* A class which aims to make upgrading between package versions easier by storing and running patch functions. <https://github.com/demonnic/MDK/wiki/Revisionator>
* sortbox.lua
* SortBox, an alternative to H/VBox which can be either, and also provides options for sorting its contents. Overview at <https://github.com/demonnic/MDK/wiki/SortBox>
* spinbox.lua
* SpinBox, a Geyser element for adjusting numbers with your mouse. Overview at <https://github.com/demonnic/MDK/wiki/SpinBox>
* sug.lua
* Self Updating Gauges, will watch a set of variables and update itself on a timer based on what values those variables hold. Documentation at <https://github.com/demonnic/MDK/wiki/SelfUpdatingGauge>
* textgauge.lua
* TextGauges, what it says on the tin. Documentation at <https://github.com/demonnic/MDK/wiki/TextGauge>
* timergauge.lua
* TimerGauge, an extension of Geyser.Gauge which serves as an animated countdown timer. Overview at <https://github.com/demonnic/MDK/wiki/TimerGauge>
## Others people's work I depend upon
* schema.lua
* lua-schema, for defining table schema. Documentation at <https://github.com/sschoener/lua-schema>
* will be used by Archon for ensuring configuration tables are as they should be.
* LICENSE.lua
* Contains the license information for MDK, as well as lua-schema and luaunit which have been included.

164
src/resources/MDK/aliasmgr.lua Executable file
View File

@ -0,0 +1,164 @@
--- Alias Manager
-- @classmod aliasmgr
-- @author Damian Monogue <demonnic@gmail.com>
-- @copyright 2022 Damian Monogue
-- @license MIT, see LICENSE.lua
local aliasmgr = {}
aliasmgr.__index = aliasmgr
--- Creates a new alias manager
function aliasmgr:new()
local mgr = {
aliases = {}
}
setmetatable(mgr, self)
return mgr
end
local function argError(funcName, argument, expected, actual)
local msg = string.format("%s: %s as %s expected, got %s", funcName, argument, expected, actual)
printError(msg, true, true)
end
--- Registers an alias with the alias manager
-- @param name the name for the alias
-- @param regex the regular expression the alias matches against
-- @param func The code to run when the alias matches. Can wrap code in [[ ]] or pass an actual function
function aliasmgr:register(name, regex, func)
local funcName = "aliasmgr:register(name, regex, func)"
if func == nil then
printError(f"{funcName} takes 3 arguments and you have provided less than that", true, true)
end
local nameType = type(name)
if nameType ~= "string" then
argError(funcName, "name", "string", nameType)
end
local regexType = type(regex)
if regexType ~= "string" then
argError(funcName, "regex", "string", regexType)
end
local funcType = type(func)
if funcType ~= "string" and funcType ~= "function" then
argError(funcName, "func", "string or function", funcType)
end
local object = {
regex = regex,
func = func
}
self:kill(name)
local ok, err = pcall(tempAlias, regex, func)
if not ok then
return nil, err
end
object.handlerID = err
self.aliases[name] = object
return true
end
--- Registers an alias with the alias manager. Alias for register
-- @param name the name for the alias
-- @param regex the regular expression the alias matches against
-- @param func The code to run when the alias matches. Can wrap code in [[ ]] or pass an actual function
-- @see register
function aliasmgr:add(name, regex, func)
self:register(name, regex, func)
end
--- Disables an alias, but does not delete it so it can be enabled later without being redefined
-- @param name the name of the alias to disable
-- @return true if the alias exists and gets disabled, false if it does not exist or is already disabled
function aliasmgr:disable(name)
local funcName = "aliasmgr:disable(name)"
local nameType = type(name)
if nameType ~= "string" then
argError(funcName, "name", "string", nameType)
end
local object = self.aliases[name]
if not object or object.handlerID == -1 then
return false
end
killAlias(object.handlerID)
object.handlerID = -1
return true
end
--- Disables all aliases registered with the manager
function aliasmgr:disableAll()
local aliases = self.aliases
for name, object in pairs(aliases) do
self:disable(name)
end
end
--- Enables an alias by name
-- @param name the name of the alias to enable
-- @return true if the alias exists and was enabled, false if it does not exist.
function aliasmgr:enable(name)
local funcName = "aliasmgr:enable(name)"
local nameType = type(name)
if nameType ~= "string" then
argError(funcName, "name", "string", nameType)
end
local object = self.aliases[name]
if not object then
return false
end
self:register(name, object.regex, object.func)
end
--- Enables all aliases registered with the manager
function aliasmgr:enableAll()
local aliases = self.aliases
for name,_ in pairs(aliases) do
self:enable(name)
end
return true
end
--- Kill an alias, deleting it from the manager
-- @param name the name of the alias to kill
-- @return true if the alias exists and gets deleted, false if the alias does not exist
function aliasmgr:kill(name)
local funcName = "aliasmgr:kill(name)"
local nameType = type(name)
if nameType ~= "string" then
argError(funcName, "name", "string", nameType)
end
local object = self.aliases[name]
if not object then
return false
end
self:disable(name)
self.aliases[name] = nil
return true
end
--- Kills all aliases registered with the manager, clearing it out
function aliasmgr:killAll()
local aliases = self.aliases
for name, _ in pairs(aliases) do
self:kill(name)
end
end
--- Kills an alias, deleting it from the manager
-- @param name the name of the alias to delete
-- @return true if the alias exists and gets deleted, false if the alias does not exist
-- @see kill
function aliasmgr:delete(name)
return self:kill(name)
end
--- Kills all aliases, deleting them from the manager
-- @see killAll
function aliasmgr:deleteAll()
return self:killAll()
end
--- Returns the list of aliases and the information being tracked for them
-- @return the table of alias information, with names as keys and a table of information as the values.
function aliasmgr:getAliases()
return self.aliases
end
return aliasmgr

235
src/resources/MDK/chyron.lua Executable file
View File

@ -0,0 +1,235 @@
--- Creates a label with a scrolling text element. It is highly recommended you use a monospace font for this label.
-- @classmod Chyron
-- @author Delra
-- @copyright 2019
-- @author Damian Monogue
-- @copyright 2020
local Chyron = {
name = "ChyronClass",
text = "",
displayWidth = 28,
updateTime = 200,
font = "Bitstream Vera Sans Mono",
fontSize = "9",
autoWidth = true,
delimiter = "|",
pos = 1,
enabled = true,
alignment = "center",
}
--- Creates a new Chyron label
-- @tparam table cons table of constraints which configures the EMCO.
-- <table class="tg">
-- <thead>
-- <tr>
-- <th>option name</th>
-- <th>description</th>
-- <th>default</th>
-- </tr>
-- </thead>
-- <tbody>
-- <tr>
-- <td class="tg-1">text</td>
-- <td class="tg-1">The text to scroll on the label</td>
-- <td class="tg-1">""</td>
-- </tr>
-- <tr>
-- <td class="tg-2">updateTime</td>
-- <td class="tg-2">Milliseconds between movements (one letter shift)</td>
-- <td class="tg-2">200</td>
-- </tr>
-- <tr>
-- <td class="tg-1">displayWidth</td>
-- <td class="tg-1">How many chars wide to display the text</td>
-- <td class="tg-1">28</td>
-- </tr>
-- <tr>
-- <td class="tg-2">delimiter</td>
-- <td class="tg-2">This character will be inserted with a space either side to mark the stop/start of the message</td>
-- <td class="tg-2">"|"</td>
-- </tr>
-- <tr>
-- <td class="tg-1">enabled</td>
-- <td class="tg-1">Should the chyron scroll?</td>
-- <td class="tg-1">true</td>
-- </tr>
-- <tr>
-- <td class="tg-2">font</td>
-- <td class="tg-2">What font to use for the Chyron? Available in Geyser.Label but we define a default.</td>
-- <td class="tg-2">"Bitstream Vera Sans Mono"</td>
-- </tr>
-- <tr>
-- <td class="tg-1">fontSize</td>
-- <td class="tg-1">What font size to use for the Chyron? Available in Geyser.Label but we define a default.</td>
-- <td class="tg-1">9</td>
-- </tr>
-- <tr>
-- <td class="tg-2">autoWidth</td>
-- <td class="tg-2">Should the Chyron resize to just fit the text?</td>
-- <td class="tg-2">true</td>
-- </tr>
-- <tr>
-- <td class="tg-1">alignment</td>
-- <td class="tg-1">What alignment(left/right/center) to use for the Chyron text? Available in Geyser.Label but we define a default.</td>
-- <td class="tg-1">"center"</td>
-- </tr>
-- </tbody>
-- </table>
-- @tparam GeyserObject container The container to use as the parent for the Chyron
function Chyron:new(cons, container)
cons = cons or {}
cons.type = cons.type or "Chyron"
local me = self.parent:new(cons, container)
setmetatable(me, self)
self.__index = self
me.pos = 0
me:setDisplayWidth(me.displayWidth)
me:setMessage(me.text)
if me.enabled then
me:start()
else
me:stop()
end
return me
end
--- Sets the numver of characters of the text to display at once
-- @tparam number displayWidth number of characters to show at once
function Chyron:setDisplayWidth(displayWidth)
displayWidth = displayWidth or self.displayWidth
self.displayWidth = displayWidth
if self.autoWidth then
local width = calcFontSize(self.fontSize, self.font)
self:resize(width * (displayWidth + 2), self.height)
end
if not self.enabled then
self.pos = self.pos - 1
self:doScroll()
end
end
--- Override setFontSize to call setDisplayWidth in order to resize if necessary
-- @local
function Chyron:setFontSize(fontSize)
Geyser.Label.setFontSize(self, fontSize)
self:setDisplayWidth()
end
--- Override setFont to call setDisplayWidth in order to resize if necessary
-- @local
function Chyron:setFont(font)
Geyser.Label.setFont(self, font)
self:setDisplayWidth()
end
--- Returns the proper section of text
-- @local
-- @param start number the character to start at
-- @param length number the length of the text you want to extract
function Chyron:scrollText(start, length)
local t = self.textTable
local s = ''
local e = start + length
for i = start - 1, e - 2 do
local n = (i % #t) + 1
s = s .. t[n]
end
return s
end
--- scroll the text
-- @local
function Chyron:doScroll()
self.pos = self.pos + 1
local displayString = self:scrollText(self.pos, self.displayWidth)
self:echo('&lt;' .. displayString .. '&gt;')
self.message = self.text
end
--- Sets the Chyron from the first position, without changing enabled status
function Chyron:reset()
self.pos = 0
if not self.enabled then
self:doScroll()
end
end
--- Stops the Chyron with its current display
function Chyron:pause()
self.enabled = false
if self.timer then
killTimer(self.timer)
end
end
--- Start the Chyron back up from wherever it currently is
function Chyron:start()
self.enabled = true
if self.timer then
killTimer(self.timer)
end
self.timer = tempTimer(self.updateTime / 1000, function()
self:doScroll()
end, true)
end
--- Change the update time for the Chyron
-- @param updateTime number new updateTime in milliseconds
function Chyron:setUpdateTime(updateTime)
self.updateTime = updateTime or self.updateTime
if self.timer then
killTimer(self.timer)
end
if self.enabled then
self:start()
end
end
--- Enable autoWidth adjustment
function Chyron:enableAutoWidth()
self.autoWidth = true
self:setDisplayWidth()
end
--- Disable autoWidth adjustment
function Chyron:disableAutoWidth()
self.autoWidth = false
end
--- Stop the Chyron, and reset it to the original position
function Chyron:stop()
if self.timer then
killTimer(self.timer)
end
self.enabled = false
self.pos = 0
self:doScroll()
end
--- Change the text being scrolled on the Chyron
-- @param message string message the text you want to have scroll on the Chyron
function Chyron:setMessage(message)
self.text = message
self.pos = 0
message = string.format("%s %s ", message, self.delimiter)
local t = {}
for i = 1, #message do
t[i] = message:sub(i, i)
end
self.textTable = t
if not self.enabled then
self:doScroll()
end
end
--- Change the delimiter used to show the beginning and end of the message
-- @param delimiter string the new delimiter to use. I recommend using one character.
function Chyron:setDelimiter(delimiter)
self.delimiter = delimiter
end
Chyron.parent = Geyser.Label
setmetatable(Chyron, Geyser.Label)
return Chyron

BIN
src/resources/MDK/computer.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

1486
src/resources/MDK/demontools.lua Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,402 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Methods">Methods</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><strong>Chyron</strong></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
</ul>
</div>
<div id="content">
<h1>Class <code>Chyron</code></h1>
<p>Creates a label with a scrolling text element.</p>
<p> It is highly recommended you use a monospace font for this label.</p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2019,2020</li>
<li><strong>Author</strong>: Delra,Damian Monogue</li>
</ul>
<h2><a href="#Methods">Methods</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#chyron:new">chyron:new(cons, container)</a></td>
<td class="summary">Creates a new Chyron label</td>
</tr>
<tr>
<td class="name" nowrap><a href="#chyron:setDisplayWidth">chyron:setDisplayWidth(displayWidth)</a></td>
<td class="summary">Sets the numver of characters of the text to display at once</td>
</tr>
<tr>
<td class="name" nowrap><a href="#chyron:reset">chyron:reset()</a></td>
<td class="summary">Sets the Chyron from the first position, without changing enabled status</td>
</tr>
<tr>
<td class="name" nowrap><a href="#chyron:pause">chyron:pause()</a></td>
<td class="summary">Stops the Chyron with its current display</td>
</tr>
<tr>
<td class="name" nowrap><a href="#chyron:start">chyron:start()</a></td>
<td class="summary">Start the Chyron back up from wherever it currently is</td>
</tr>
<tr>
<td class="name" nowrap><a href="#chyron:setUpdateTime">chyron:setUpdateTime(updateTime)</a></td>
<td class="summary">Change the update time for the Chyron</td>
</tr>
<tr>
<td class="name" nowrap><a href="#chyron:enableAutoWidth">chyron:enableAutoWidth()</a></td>
<td class="summary">Enable autoWidth adjustment</td>
</tr>
<tr>
<td class="name" nowrap><a href="#chyron:disableAutoWidth">chyron:disableAutoWidth()</a></td>
<td class="summary">Disable autoWidth adjustment</td>
</tr>
<tr>
<td class="name" nowrap><a href="#chyron:stop">chyron:stop()</a></td>
<td class="summary">Stop the Chyron, and reset it to the original position</td>
</tr>
<tr>
<td class="name" nowrap><a href="#chyron:setMessage">chyron:setMessage(message)</a></td>
<td class="summary">Change the text being scrolled on the Chyron</td>
</tr>
<tr>
<td class="name" nowrap><a href="#chyron:setDelimiter">chyron:setDelimiter(delimiter)</a></td>
<td class="summary">Change the delimiter used to show the beginning and end of the message</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Methods"></a>Methods</h2>
<dl class="function">
<dt>
<a name = "chyron:new"></a>
<strong>chyron:new(cons, container)</strong>
<a style="float:right;" href="../source/Chyron.lua.html#80">line 80</a>
</dt>
<dd>
Creates a new Chyron label
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">cons</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
table of constraints which configures the EMCO.
<table class="tg">
<thead>
<tr>
<th>option name</th>
<th>description</th>
<th>default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tg-1">text</td>
<td class="tg-1">The text to scroll on the label</td>
<td class="tg-1">""</td>
</tr>
<tr>
<td class="tg-2">updateTime</td>
<td class="tg-2">Milliseconds between movements (one letter shift)</td>
<td class="tg-2">200</td>
</tr>
<tr>
<td class="tg-1">displayWidth</td>
<td class="tg-1">How many chars wide to display the text</td>
<td class="tg-1">28</td>
</tr>
<tr>
<td class="tg-2">delimiter</td>
<td class="tg-2">This character will be inserted with a space either side to mark the stop/start of the message</td>
<td class="tg-2">"|"</td>
</tr>
<tr>
<td class="tg-1">enabled</td>
<td class="tg-1">Should the chyron scroll?</td>
<td class="tg-1">true</td>
</tr>
<tr>
<td class="tg-2">font</td>
<td class="tg-2">What font to use for the Chyron? Available in Geyser.Label but we define a default.</td>
<td class="tg-2">"Bitstream Vera Sans Mono"</td>
</tr>
<tr>
<td class="tg-1">fontSize</td>
<td class="tg-1">What font size to use for the Chyron? Available in Geyser.Label but we define a default.</td>
<td class="tg-1">9</td>
</tr>
<tr>
<td class="tg-2">autoWidth</td>
<td class="tg-2">Should the Chyron resize to just fit the text?</td>
<td class="tg-2">true</td>
</tr>
<tr>
<td class="tg-1">alignment</td>
<td class="tg-1">What alignment(left/right/center) to use for the Chyron text? Available in Geyser.Label but we define a default.</td>
<td class="tg-1">"center"</td>
</tr>
</tbody>
</table>
</li>
<li><span class="parameter">container</span>
<span class="types"><span class="type">GeyserObject</span></span>
The container to use as the parent for the Chyron
</li>
</ul>
</dd>
<dt>
<a name = "chyron:setDisplayWidth"></a>
<strong>chyron:setDisplayWidth(displayWidth)</strong>
<a style="float:right;" href="../source/Chyron.lua.html#99">line 99</a>
</dt>
<dd>
Sets the numver of characters of the text to display at once
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">displayWidth</span>
<span class="types"><span class="type">number</span></span>
number of characters to show at once
</li>
</ul>
</dd>
<dt>
<a name = "chyron:reset"></a>
<strong>chyron:reset()</strong>
<a style="float:right;" href="../source/Chyron.lua.html#151">line 151</a>
</dt>
<dd>
Sets the Chyron from the first position, without changing enabled status
</dd>
<dt>
<a name = "chyron:pause"></a>
<strong>chyron:pause()</strong>
<a style="float:right;" href="../source/Chyron.lua.html#159">line 159</a>
</dt>
<dd>
Stops the Chyron with its current display
</dd>
<dt>
<a name = "chyron:start"></a>
<strong>chyron:start()</strong>
<a style="float:right;" href="../source/Chyron.lua.html#167">line 167</a>
</dt>
<dd>
Start the Chyron back up from wherever it currently is
</dd>
<dt>
<a name = "chyron:setUpdateTime"></a>
<strong>chyron:setUpdateTime(updateTime)</strong>
<a style="float:right;" href="../source/Chyron.lua.html#179">line 179</a>
</dt>
<dd>
Change the update time for the Chyron
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">updateTime</span>
number new updateTime in milliseconds
</li>
</ul>
</dd>
<dt>
<a name = "chyron:enableAutoWidth"></a>
<strong>chyron:enableAutoWidth()</strong>
<a style="float:right;" href="../source/Chyron.lua.html#190">line 190</a>
</dt>
<dd>
Enable autoWidth adjustment
</dd>
<dt>
<a name = "chyron:disableAutoWidth"></a>
<strong>chyron:disableAutoWidth()</strong>
<a style="float:right;" href="../source/Chyron.lua.html#196">line 196</a>
</dt>
<dd>
Disable autoWidth adjustment
</dd>
<dt>
<a name = "chyron:stop"></a>
<strong>chyron:stop()</strong>
<a style="float:right;" href="../source/Chyron.lua.html#201">line 201</a>
</dt>
<dd>
Stop the Chyron, and reset it to the original position
</dd>
<dt>
<a name = "chyron:setMessage"></a>
<strong>chyron:setMessage(message)</strong>
<a style="float:right;" href="../source/Chyron.lua.html#212">line 212</a>
</dt>
<dd>
Change the text being scrolled on the Chyron
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">message</span>
string message the text you want to have scroll on the Chyron
</li>
</ul>
</dd>
<dt>
<a name = "chyron:setDelimiter"></a>
<strong>chyron:setDelimiter(delimiter)</strong>
<a style="float:right;" href="../source/Chyron.lua.html#228">line 228</a>
</dt>
<dd>
Change the delimiter used to show the beginning and end of the message
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">delimiter</span>
string the new delimiter to use. I recommend using one character.
</li>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,813 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Methods">Methods</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><strong>LoggingConsole</strong></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
</ul>
</div>
<div id="content">
<h1>Class <code>LoggingConsole</code></h1>
<p>MiniConsole with logging capabilities</p>
<p></p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2020 Damian Monogue</li>
<li><strong>License</strong>: MIT, see LICENSE.lua</li>
<li><strong>Author</strong>: Damian Monogue <demonnic@gmail.com></li>
</ul>
<h2><a href="#Methods">Methods</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#loggingconsole:new">loggingconsole:new(cons, container)</a></td>
<td class="summary">Creates and returns a new LoggingConsole.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:getExtension">loggingconsole:getExtension()</a></td>
<td class="summary">Returns the file extension of the logfile this console will log to</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:getPath">loggingconsole:getPath()</a></td>
<td class="summary">Returns the path to the logfile for this console</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:setPath">loggingconsole:setPath(path)</a></td>
<td class="summary">Sets the path to use for the log file.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:getFileName">loggingconsole:getFileName()</a></td>
<td class="summary">Returns the filename for the logfile for this console</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:setFileName">loggingconsole:setFileName(fileName)</a></td>
<td class="summary">Sets the fileName to use for the log file.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:getFullFilename">loggingconsole:getFullFilename()</a></td>
<td class="summary">Returns the pull path and filename for the logfile for this console</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:enableLogging">loggingconsole:enableLogging()</a></td>
<td class="summary">Turns logging for this console on</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:disableLogging">loggingconsole:disableLogging()</a></td>
<td class="summary">Turns logging for this console off</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:cechoLink">loggingconsole:cechoLink(text, command, hint, log)</a></td>
<td class="summary">cechoLink for LoggingConsole</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:dechoLink">loggingconsole:dechoLink(text, command, hint, log)</a></td>
<td class="summary">dechoLink for LoggingConsole</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:hechoLink">loggingconsole:hechoLink(text, command, hint, log)</a></td>
<td class="summary">hechoLink for LoggingConsole</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:echoLink">loggingconsole:echoLink(text, command, hint, useCurrentFormat, log)</a></td>
<td class="summary">echoLink for LoggingConsole</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:cechoPopup">loggingconsole:cechoPopup(text, commands, hints, log)</a></td>
<td class="summary">cechoPopup for LoggingConsole</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:dechoPopup">loggingconsole:dechoPopup(text, commands, hints, log)</a></td>
<td class="summary">dechoPopup for LoggingConsole</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:hechoPopup">loggingconsole:hechoPopup(text, commands, hints, log)</a></td>
<td class="summary">hechoPopup for LoggingConsole</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:echoPopup">loggingconsole:echoPopup(text, commands, hints, useCurrentFormat, log)</a></td>
<td class="summary">echoPopup for LoggingConsole</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:appendBuffer">loggingconsole:appendBuffer(log)</a></td>
<td class="summary">Append copy()ed text to the console</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:append">loggingconsole:append(log)</a></td>
<td class="summary">Append copy()ed text to the console</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:echo">loggingconsole:echo(str, log)</a></td>
<td class="summary">echo's a string to the console.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:hecho">loggingconsole:hecho(str, log)</a></td>
<td class="summary">hecho's a string to the console.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:decho">loggingconsole:decho(str, log)</a></td>
<td class="summary">decho's a string to the console.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:cecho">loggingconsole:cecho(str, log)</a></td>
<td class="summary">cecho's a string to the console.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loggingconsole:replay">loggingconsole:replay(numberOfLines)</a></td>
<td class="summary">Replays the last X lines from the console's log file, if it exists</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Methods"></a>Methods</h2>
<dl class="function">
<dt>
<a name = "loggingconsole:new"></a>
<strong>loggingconsole:new(cons, container)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#56">line 56</a>
</dt>
<dd>
Creates and returns a new LoggingConsole.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">cons</span>
table of constraints. Includes all the valid Geyser.MiniConsole constraints, plus
<table class="tg">
<thead>
<tr>
<th>option name</th>
<th>description</th>
<th>default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tg-1">log</td>
<td class="tg-1">Should the miniconsole be logging?</td>
<td class="tg-1">true</td>
</tr>
<tr>
<td class="tg-2">logFormat</td>
<td class="tg-2">"h" for html, "t" for plaintext, "l" for log (with ansi)</td>
<td class="tg-2">h</td>
</tr>
<tr>
<td class="tg-1">path</td>
<td class="tg-1">The path the file lives in. It is templated.<br>|h is replaced by the profile homedir.<br>|y by 4 digit year.<br>|m by 2 digit month<br>|d by 2 digit day<br>|n by the name constraint<br>|e by the file extension (html for h logType, log for others)</td>
<td class="tg-1">"|h/log/consoleLogs/|y/|m/|d/"</td>
</tr>
<tr>
<td class="tg-2">fileName</td>
<td class="tg-2">The name of the log file. It is templated, same as path above</td>
<td class="tg-2">"|n.|e"</td>
</tr>
</tbody>
</table>
</li>
<li><span class="parameter">container</span>
the container for the console
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> LoggingConsole = <span class="global">require</span>(<span class="string">"MDK.loggingconsole"</span>)
myLoggingConsole = LoggingConsole:<span class="function-name">new</span>({
name = <span class="string">"my logging console"</span>,
x = <span class="number">0</span>,
y = <span class="number">0</span>,
height = <span class="number">200</span>,
width = <span class="number">400</span>,
}) <span class="comment">-- just like making a miniconsole, really</span></pre>
</ul>
</dd>
<dt>
<a name = "loggingconsole:getExtension"></a>
<strong>loggingconsole:getExtension()</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#67">line 67</a>
</dt>
<dd>
Returns the file extension of the logfile this console will log to
</dd>
<dt>
<a name = "loggingconsole:getPath"></a>
<strong>loggingconsole:getPath()</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#95">line 95</a>
</dt>
<dd>
Returns the path to the logfile for this console
</dd>
<dt>
<a name = "loggingconsole:setPath"></a>
<strong>loggingconsole:setPath(path)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#105">line 105</a>
</dt>
<dd>
Sets the path to use for the log file.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">path</span>
the path to put the log file in. It is templated.<br>|h is replaced by the profile homedir.<br>|y by 4 digit year.<br>|m by 2 digit month<br>|d by 2 digit day<br>|n by the name constraint<br>|e by the file extension (html for h logType, log for others)
</li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:getFileName"></a>
<strong>loggingconsole:getFileName()</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#110">line 110</a>
</dt>
<dd>
Returns the filename for the logfile for this console
</dd>
<dt>
<a name = "loggingconsole:setFileName"></a>
<strong>loggingconsole:setFileName(fileName)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#118">line 118</a>
</dt>
<dd>
Sets the fileName to use for the log file.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">fileName</span>
the fileName to use for the logfile. It is templated.<br>|h is replaced by the profile homedir.<br>|y by 4 digit year.<br>|m by 2 digit month<br>|d by 2 digit day<br>|n by the name constraint<br>|e by the file extension (html for h logType, log for others)
</li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:getFullFilename"></a>
<strong>loggingconsole:getFullFilename()</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#123">line 123</a>
</dt>
<dd>
Returns the pull path and filename for the logfile for this console
</dd>
<dt>
<a name = "loggingconsole:enableLogging"></a>
<strong>loggingconsole:enableLogging()</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#132">line 132</a>
</dt>
<dd>
Turns logging for this console on
</dd>
<dt>
<a name = "loggingconsole:disableLogging"></a>
<strong>loggingconsole:disableLogging()</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#137">line 137</a>
</dt>
<dd>
Turns logging for this console off
</dd>
<dt>
<a name = "loggingconsole:cechoLink"></a>
<strong>loggingconsole:cechoLink(text, command, hint, log)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#309">line 309</a>
</dt>
<dd>
cechoLink for LoggingConsole
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text</span>
the text to use for the link
</li>
<li><span class="parameter">command</span>
the command to send when the link is clicked, as text. IE [[send("sleep")]]
</li>
<li><span class="parameter">hint</span>
A tooltip which is displayed when the mouse is over the link
</li>
<li><span class="parameter">log</span>
Should we log this line? Defaults to self.log if not passed.
</li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:dechoLink"></a>
<strong>loggingconsole:dechoLink(text, command, hint, log)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#318">line 318</a>
</dt>
<dd>
dechoLink for LoggingConsole
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text</span>
the text to use for the link
</li>
<li><span class="parameter">command</span>
the command to send when the link is clicked, as text. IE [[send("sleep")]]
</li>
<li><span class="parameter">hint</span>
A tooltip which is displayed when the mouse is over the link
</li>
<li><span class="parameter">log</span>
Should we log this line? Defaults to self.log if not passed.
</li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:hechoLink"></a>
<strong>loggingconsole:hechoLink(text, command, hint, log)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#327">line 327</a>
</dt>
<dd>
hechoLink for LoggingConsole
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text</span>
the text to use for the link
</li>
<li><span class="parameter">command</span>
the command to send when the link is clicked, as text. IE [[send("sleep")]]
</li>
<li><span class="parameter">hint</span>
A tooltip which is displayed when the mouse is over the link
</li>
<li><span class="parameter">log</span>
Should we log this line? Defaults to self.log if not passed.
</li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:echoLink"></a>
<strong>loggingconsole:echoLink(text, command, hint, useCurrentFormat, log)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#340">line 340</a>
</dt>
<dd>
echoLink for LoggingConsole
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text</span>
the text to use for the link
</li>
<li><span class="parameter">command</span>
the command to send when the link is clicked, as text. IE [[send("sleep")]]
</li>
<li><span class="parameter">hint</span>
A tooltip which is displayed when the mouse is over the link
</li>
<li><span class="parameter">useCurrentFormat</span>
If set to true, will look like the text around it. If false it will be blue and underline.
</li>
<li><span class="parameter">log</span>
Should we log this line? Defaults to self.log if not passed. If you want to pass this you must pass in useCurrentFormat
</li>
</ul>
<h3>Usage:</h3>
<ul>
<li><pre class="example">myLoggingConsole:<span class="function-name">echoLink</span>(<span class="string">"This is a link!"</span>, <span class="string">[[send("sleep")]]</span>, <span class="string">"sleep"</span>) <span class="comment">-- text "This is a link" will send("sleep") when clicked and be blue w/ underline. Defaut log behaviour (self.log)</span></pre></li>
<li><pre class="example">myLoggingConsole:<span class="function-name">echoLink</span>(<span class="string">"This is a link!"</span>, <span class="string">[[send("sleep")]]</span>, <span class="string">"sleep"</span>, <span class="keyword">false</span>, <span class="keyword">false</span>) <span class="comment">-- same as above, but forces it not to log regardless of self.log setting</span></pre></li>
<li><pre class="example">myLoggingConsole:<span class="function-name">echoLink</span>(<span class="string">"This is a link!"</span>, <span class="string">[[send("sleep")]]</span>, <span class="string">"sleep"</span>, <span class="keyword">true</span>, <span class="keyword">true</span>) <span class="comment">-- same as above, but forces it to log regardless of self.log setting and the text will look like anything else echoed to the console.</span></pre></li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:cechoPopup"></a>
<strong>loggingconsole:cechoPopup(text, commands, hints, log)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#349">line 349</a>
</dt>
<dd>
cechoPopup for LoggingConsole
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text</span>
the text to use for the link
</li>
<li><span class="parameter">commands</span>
the commands to send when the popup is activated, as table. IE {[[send("sleep")]], [[send("stand")]]}
</li>
<li><span class="parameter">hints</span>
A tooltip which is displayed when the mouse is over the link. IE {{"sleep", "stand"}}
</li>
<li><span class="parameter">log</span>
Should we log this line? Defaults to self.log if not passed.
</li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:dechoPopup"></a>
<strong>loggingconsole:dechoPopup(text, commands, hints, log)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#358">line 358</a>
</dt>
<dd>
dechoPopup for LoggingConsole
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text</span>
the text to use for the link
</li>
<li><span class="parameter">commands</span>
the commands to send when the popup is activated, as table. IE {[[send("sleep")]], [[send("stand")]]}
</li>
<li><span class="parameter">hints</span>
A tooltip which is displayed when the mouse is over the link. IE {{"sleep", "stand"}}
</li>
<li><span class="parameter">log</span>
Should we log this line? Defaults to self.log if not passed.
</li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:hechoPopup"></a>
<strong>loggingconsole:hechoPopup(text, commands, hints, log)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#367">line 367</a>
</dt>
<dd>
hechoPopup for LoggingConsole
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text</span>
the text to use for the link
</li>
<li><span class="parameter">commands</span>
the commands to send when the popup is activated, as table. IE {[[send("sleep")]], [[send("stand")]]}
</li>
<li><span class="parameter">hints</span>
A tooltip which is displayed when the mouse is over the link. IE {{"sleep", "stand"}}
</li>
<li><span class="parameter">log</span>
Should we log this line? Defaults to self.log if not passed.
</li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:echoPopup"></a>
<strong>loggingconsole:echoPopup(text, commands, hints, useCurrentFormat, log)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#380">line 380</a>
</dt>
<dd>
echoPopup for LoggingConsole
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text</span>
the text to use for the link
</li>
<li><span class="parameter">commands</span>
the commands to send when the popup is activated, as table. IE {[[send("sleep")]], [[send("stand")]]}
</li>
<li><span class="parameter">hints</span>
A tooltip which is displayed when the mouse is over the link. IE {{"sleep", "stand"}}
</li>
<li><span class="parameter">useCurrentFormat</span>
If set to true, will look like the text around it. If false it will be blue and underline.
</li>
<li><span class="parameter">log</span>
Should we log this line? Defaults to self.log if not passed. If you want to pass this you must pass in useCurrentFormat
</li>
</ul>
<h3>Usage:</h3>
<ul>
<li><pre class="example">myLoggingConsole:<span class="function-name">echoPopup</span>(<span class="string">"This is a link!"</span>, {<span class="string">[[send("sleep")]]</span>, <span class="string">[[send("stand")]]</span>, {<span class="string">"sleep"</span>, <span class="string">"stand"</span>}) <span class="comment">-- text "This is a link" will send("sleep") when clicked and be blue w/ underline. Defaut log behaviour (self.log)</span></pre></li>
<li><pre class="example">myLoggingConsole:<span class="function-name">echoPopup</span>(<span class="string">"This is a link!"</span>, {<span class="string">[[send("sleep")]]</span>, <span class="string">[[send("stand")]]</span>, {<span class="string">"sleep"</span>, <span class="string">"stand"</span>}, <span class="keyword">false</span>, <span class="keyword">false</span>) <span class="comment">-- same as above, but forces it not to log regardless of self.log setting</span></pre></li>
<li><pre class="example">myLoggingConsole:<span class="function-name">echoPopup</span>(<span class="string">"This is a link!"</span>, {<span class="string">[[send("sleep")]]</span>, <span class="string">[[send("stand")]]</span>, {<span class="string">"sleep"</span>, <span class="string">"stand"</span>}, <span class="keyword">true</span>, <span class="keyword">true</span>) <span class="comment">-- same as above, but forces it to log regardless of self.log setting and the text will look like anything else echoed to the console.</span></pre></li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:appendBuffer"></a>
<strong>loggingconsole:appendBuffer(log)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#386">line 386</a>
</dt>
<dd>
Append copy()ed text to the console
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">log</span>
should we log this?
</li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:append"></a>
<strong>loggingconsole:append(log)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#392">line 392</a>
</dt>
<dd>
Append copy()ed text to the console
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">log</span>
should we log this?
</li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:echo"></a>
<strong>loggingconsole:echo(str, log)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#399">line 399</a>
</dt>
<dd>
echo's a string to the console.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">str</span>
the string to echo
</li>
<li><span class="parameter">log</span>
should this be logged? Used to override the .log constraint
</li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:hecho"></a>
<strong>loggingconsole:hecho(str, log)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#406">line 406</a>
</dt>
<dd>
hecho's a string to the console.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">str</span>
the string to hecho
</li>
<li><span class="parameter">log</span>
should this be logged? Used to override the .log constraint
</li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:decho"></a>
<strong>loggingconsole:decho(str, log)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#413">line 413</a>
</dt>
<dd>
decho's a string to the console.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">str</span>
the string to decho
</li>
<li><span class="parameter">log</span>
should this be logged? Used to override the .log constraint
</li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:cecho"></a>
<strong>loggingconsole:cecho(str, log)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#420">line 420</a>
</dt>
<dd>
cecho's a string to the console.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">str</span>
the string to cecho
</li>
<li><span class="parameter">log</span>
should this be logged? Used to override the .log constraint
</li>
</ul>
</dd>
<dt>
<a name = "loggingconsole:replay"></a>
<strong>loggingconsole:replay(numberOfLines)</strong>
<a style="float:right;" href="../source/LoggingConsole.lua.html#426">line 426</a>
</dt>
<dd>
Replays the last X lines from the console's log file, if it exists
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">numberOfLines</span>
The number of lines to replay from the end of the file
</li>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,546 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Methods">Methods</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><strong>Loginator</strong></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
</ul>
</div>
<div id="content">
<h1>Class <code>Loginator</code></h1>
<p>Loginator creates an object which allows you to log things to file at
various severity levels, with the ability to only log items above a specific
severity to file.</p>
<p></p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2021 Damian Monogue</li>
<li><strong>License</strong>: MIT, see LICENSE.lua</li>
<li><strong>Author</strong>: Damian Monogue <demonnic@gmail.com></li>
</ul>
<h2><a href="#Methods">Methods</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#loginator:new">loginator:new(options)</a></td>
<td class="summary">Creates a new Loginator object</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loginator:setColorForLevel">loginator:setColorForLevel(color, level)</a></td>
<td class="summary">Set the color to associate with a logging level post-creation</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loginator:getFullFilename">loginator:getFullFilename()</a></td>
<td class="summary">Returns the full path and filename to the logfile</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loginator:error">loginator:error(msg)</a></td>
<td class="summary">Write an error level message to the logfile.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loginator:warn">loginator:warn(msg)</a></td>
<td class="summary">Write a warn level message to the logfile.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loginator:info">loginator:info(msg)</a></td>
<td class="summary">Write an info level message to the logfile.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loginator:debug">loginator:debug(msg)</a></td>
<td class="summary">Write a debug level message to the logfile.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loginator:log">loginator:log(msg, level)</a></td>
<td class="summary">Write a message to the log file and optionally specify the level</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loginator:open">loginator:open()</a></td>
<td class="summary">Uses openUrl() to request your OS open the logfile in the appropriate application.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loginator:openDir">loginator:openDir()</a></td>
<td class="summary">Uses openUrl() to request your OS open the directory the logfile resides in.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#loginator:getPath">loginator:getPath(filename)</a></td>
<td class="summary">Returns the path to the log file (directory in which the file resides) as a string</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Methods"></a>Methods</h2>
<dl class="function">
<dt>
<a name = "loginator:new"></a>
<strong>loginator:new(options)</strong>
<a style="float:right;" href="../source/Loginator.lua.html#214">line 214</a>
</dt>
<dd>
Creates a new Loginator object
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">options</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
table of options for the logger
<table class="tg">
<thead>
<tr>
<th>option name</th>
<th>description</th>
<th>default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tg-1">format</td>
<td class="tg-1">What format to log in? "h" for html, "a" for ansi, anything else for plaintext.</td>
<td class="tg-1">"h"</td>
</tr>
<tr>
<td class="tg-2">name</td>
<td class="tg-2">What is the name of the logger? Will replace |n in templates</td>
<td class="tg-2">logname</td>
</tr>
<tr>
<td class="tg-1">level</td>
<td class="tg-1">What level should the logger operate at? This will control what level the log function defaults to, as well as what logs will actually be written<br>
Only items of an equal or higher severity to this will be written to the log file.</td>
<td class="tg-1">"info"</td>
</tr>
<tr>
<td class="tg-2">bgColor</td>
<td class="tg-2">What background color to use for html logs</td>
<td class="tg-2">"black"</td>
</tr>
<tr>
<td class="tg-1">fgColor</td>
<td class="tg-1">What color to use for the main text in html logs</td>
<td class="tg-1">"white"</td>
</tr>
<tr>
<td class="tg-2">fontSize</td>
<td class="tg-2">What font size to use in html logs</td>
<td class="tg-2">12</td>
</tr>
<tr>
<td class="tg-1">levelColors</td>
<td class="tg-1">Table with the log level as the key, and the color which corresponds to it as the value</td>
<td class="tg-1">{ error = "red", warn = "DarkOrange", info = "ForestGreen", debug = "ansi_yellow" }</td>
</tr>
<tr>
<td class="tg-2">fileNameTemplate</td>
<td class="tg-2">A template which will be transformed into the full filename, with path. See template options below for replacements</td>
<td class="tg-2">"|p/log/Loginator/|y-|M-|d-|n.|e"</td>
</tr>
<tr>
<td class="tg-1">entryTemplate</td>
<td class="tg-1">The template which controls the look of each log entry. See template options below for replacements</td>
<td class="tg-1">"|y-|M-|d |h:|m:|s.|x [|c|l|r] |t"</td>
</tr>
</tbody>
</table><br>
Table of template options
<table class="tg">
<thead>
<tr>
<th>template code</th>
<th>what it is replaced with</th>
<th>example</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tg-1">|y</td>
<td class="tg-1">the year in 4 digits</td>
<td class="tg-1">2021</td>
</tr>
<tr>
<td class="tg-2">|p</td>
<td class="tg-2">getMudletHomeDir()</td>
<td class="tg-2">/home/demonnic/.config/mudlet/profiles/testprofile</td>
</tr>
<tr>
<td class="tg-1">|M</td>
<td class="tg-1">Month as 2 digits</td>
<td class="tg-1">05</td>
</tr>
<tr>
<td class="tg-2">|d</td>
<td class="tg-2">day, as 2 digits</td>
<td class="tg-2">23</td>
</tr>
<tr>
<td class="tg-1">|h</td>
<td class="tg-1">hour in 24hr time format, 2 digits</td>
<td class="tg-1">03</td>
</tr>
<tr>
<td class="tg-2">|m</td>
<td class="tg-2">minute as 2 digits</td>
<td class="tg-2">42</td>
</tr>
<tr>
<td class="tg-1">|s</td>
<td class="tg-1">seconds as 2 digits</td>
<td class="tg-1">34</td>
</tr>
<tr>
<td class="tg-2">|x</td>
<td class="tg-2">milliseconds as 3 digits</td>
<td class="tg-2">194</td>
</tr>
<tr>
<td class="tg-1">|e</td>
<td class="tg-1">Filename extension expected. "html" for html format, "log" for everything else</td>
<td class="tg-1">html</td>
</tr>
<tr>
<td class="tg-2">|l</td>
<td class="tg-2">The logging level of the entry, in ALLCAPS</td>
<td class="tg-2">WARN</td>
</tr>
<tr>
<td class="tg-1">|c</td>
<td class="tg-1">The color which corresponds with the logging level. Set via the levelColors table in the options. Example not included.</td>
<td class="tg-1"></td>
</tr>
<tr>
<td class="tg-2">|r</td>
<td class="tg-2">Reset back to standard color. Used to close |c. Example not included</td>
<td class="tg-2"></td>
</tr>
<tr>
<td class="tg-1">|n</td>
<td class="tg-1">The name of the logger, set via the options when you have Loginator create it.</td>
<td class="tg-1">CoolPackageLog</td>
</tr>
</tbody>
</table>
</li>
</ul>
<h3>Returns:</h3>
<ol>
newly created logger object
</ol>
</dd>
<dt>
<a name = "loginator:setColorForLevel"></a>
<strong>loginator:setColorForLevel(color, level)</strong>
<a style="float:right;" href="../source/Loginator.lua.html#288">line 288</a>
</dt>
<dd>
Set the color to associate with a logging level post-creation
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">color</span>
The color to set for the level, as a string. Can be any valid color string for cecho, decho, or hecho.
</li>
<li><span class="parameter">level</span>
The level to set the color for. Must be one of 'error', 'warn', 'info', or 'debug'
</li>
</ul>
<h3>Returns:</h3>
<ol>
true if the color is updated, or nil+error if it could not be updated for some reason.
</ol>
</dd>
<dt>
<a name = "loginator:getFullFilename"></a>
<strong>loginator:getFullFilename()</strong>
<a style="float:right;" href="../source/Loginator.lua.html#332">line 332</a>
</dt>
<dd>
Returns the full path and filename to the logfile
</dd>
<dt>
<a name = "loginator:error"></a>
<strong>loginator:error(msg)</strong>
<a style="float:right;" href="../source/Loginator.lua.html#339">line 339</a>
</dt>
<dd>
Write an error level message to the logfile. Error level messages are always written.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">msg</span>
the message to log
</li>
</ul>
<h3>Returns:</h3>
<ol>
true if msg written, nil+error if error
</ol>
</dd>
<dt>
<a name = "loginator:warn"></a>
<strong>loginator:warn(msg)</strong>
<a style="float:right;" href="../source/Loginator.lua.html#349">line 349</a>
</dt>
<dd>
Write a warn level message to the logfile.
Msg is only written if the logger level is <= warn
From most to least severe the levels are:
error > warn > info > debug
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">msg</span>
the message to log
</li>
</ul>
<h3>Returns:</h3>
<ol>
true if msg written, false if skipped due to level, nil+error if error
</ol>
</dd>
<dt>
<a name = "loginator:info"></a>
<strong>loginator:info(msg)</strong>
<a style="float:right;" href="../source/Loginator.lua.html#359">line 359</a>
</dt>
<dd>
Write an info level message to the logfile.
Msg is only written if the logger level is <= info
From most to least severe the levels are:
error > warn > info > debug
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">msg</span>
the message to log
</li>
</ul>
<h3>Returns:</h3>
<ol>
true if msg written, false if skipped due to level, nil+error if error
</ol>
</dd>
<dt>
<a name = "loginator:debug"></a>
<strong>loginator:debug(msg)</strong>
<a style="float:right;" href="../source/Loginator.lua.html#369">line 369</a>
</dt>
<dd>
Write a debug level message to the logfile.
Msg is only written if the logger level is debug
From most to least severe the levels are:
error > warn > info > debug
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">msg</span>
the message to log
</li>
</ul>
<h3>Returns:</h3>
<ol>
true if msg written, false if skipped due to level, nil+error if error
</ol>
</dd>
<dt>
<a name = "loginator:log"></a>
<strong>loginator:log(msg, level)</strong>
<a style="float:right;" href="../source/Loginator.lua.html#377">line 377</a>
</dt>
<dd>
Write a message to the log file and optionally specify the level
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">msg</span>
the message to log
</li>
<li><span class="parameter">level</span>
the level to log the message at. Defaults to the level of the logger itself if not provided.
</li>
</ul>
<h3>Returns:</h3>
<ol>
true if msg written, false if skipped due to level, nil+error if error
</ol>
</dd>
<dt>
<a name = "loginator:open"></a>
<strong>loginator:open()</strong>
<a style="float:right;" href="../source/Loginator.lua.html#409">line 409</a>
</dt>
<dd>
Uses openUrl() to request your OS open the logfile in the appropriate application. Usually your web browser for html and text editor for all others.
</dd>
<dt>
<a name = "loginator:openDir"></a>
<strong>loginator:openDir()</strong>
<a style="float:right;" href="../source/Loginator.lua.html#414">line 414</a>
</dt>
<dd>
Uses openUrl() to request your OS open the directory the logfile resides in. This allows for easier browsing if you have more than one file.
</dd>
<dt>
<a name = "loginator:getPath"></a>
<strong>loginator:getPath(filename)</strong>
<a style="float:right;" href="../source/Loginator.lua.html#420">line 420</a>
</dt>
<dd>
Returns the path to the log file (directory in which the file resides) as a string
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">filename</span>
optional filename to return the path of. If not supplied, with use the logger's current filename
</li>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,277 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Methods">Methods</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><strong>MasterMindSolver</strong></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
</ul>
</div>
<div id="content">
<h1>Class <code>MasterMindSolver</code></h1>
<p>Interactive object which helps you solve a Master Mind puzzle.</p>
<p></p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2021 Damian Monogue,2008,2009 Konstantinos Asimakis for code used to turn an index number into a guess (indexToGuess method)</li>
<li><strong>Author</strong>: Damian Monogue <demonnic@gmail.com></li>
</ul>
<h2><a href="#Methods">Methods</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#mastermindsolver:new">mastermindsolver:new(options)</a></td>
<td class="summary">Creates a new Master Mind solver</td>
</tr>
<tr>
<td class="name" nowrap><a href="#mastermindsolver:reducePossible">mastermindsolver:reducePossible(guess, coloredPins, whitePins)</a></td>
<td class="summary">Function used to reduce the remaining possible answers, given a guess and the answer to that guess.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#mastermindsolver:checkLastSuggestion">mastermindsolver:checkLastSuggestion(coloredPins, whitePins)</a></td>
<td class="summary">Function which assumes you used the last suggested guess from the solver, and reduces the number of possible correct solutions based on the answer given</td>
</tr>
<tr>
<td class="name" nowrap><a href="#mastermindsolver:getValidGuess">mastermindsolver:getValidGuess(useActions)</a></td>
<td class="summary">Used to get one of the remaining valid possible guesses</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Methods"></a>Methods</h2>
<dl class="function">
<dt>
<a name = "mastermindsolver:new"></a>
<strong>mastermindsolver:new(options)</strong>
<a style="float:right;" href="../source/MasterMindSolver.lua.html#81">line 81</a>
</dt>
<dd>
Creates a new Master Mind solver
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">options</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
table of configuration options for the solver
<table class="tg">
<thead>
<tr>
<th>option name</th>
<th>description</th>
<th>default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tg-1">places</td>
<td class="tg-1">How many spots in the code we're breaking?</td>
<td class="tg-1">4</td>
</tr>
<tr>
<td class="tg-2">items</td>
<td class="tg-2">The table of colors/gemstones/whatever which can be part of the code</td>
<td class="tg-2">{"red", "orange", "yellow", "green", "blue", "purple"}</td>
</tr>
<tr>
<td class="tg-1">template</td>
<td class="tg-1">The string template to use for the guess. Within the template, |t is replaced by the item. Used as the command if autoSend is true</td>
<td class="tg-1">"|t"</td>
</tr>
<tr>
<td class="tg-2">autoSend</td>
<td class="tg-2">Should we send the guess directly to the server?</td>
<td class="tg-2">false</td>
</tr>
<tr>
<td class="tg-1">allowDuplicates</td>
<td class="tg-1">Can the same item be used more than once in a code?</td>
<td class="tg-1">true</td>
</tr>
<tr>
<td class="tg-2">singleCommand</td>
<td class="tg-2">If true, combines the guess into a single command, with each one separated by the separator</td>
<td class="tg-2">false</td>
</tr>
<tr>
<td class="tg-1">separator</td>
<td class="tg-1">If sending the guess as a single command, what should we put between the guesses to separate them?</td>
<td class="tg-1">" "</td>
</tr>
</tbody>
</table>
</li>
</ul>
</dd>
<dt>
<a name = "mastermindsolver:reducePossible"></a>
<strong>mastermindsolver:reducePossible(guess, coloredPins, whitePins)</strong>
<a style="float:right;" href="../source/MasterMindSolver.lua.html#178">line 178</a>
</dt>
<dd>
Function used to reduce the remaining possible answers, given a guess and the answer to that guess. This is not undoable.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">guess</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
guess which the answer belongs to. Uses numbers, rather than item names. IE { 1, 1, 2, 2} rather than { "blue", "blue", "green", "green" }
</li>
<li><span class="parameter">coloredPins</span>
<span class="types"><span class="type">number</span></span>
how many parts of the guess are both the right color and the right place
</li>
<li><span class="parameter">whitePins</span>
<span class="types"><span class="type">number</span></span>
how many parts of the guess are the right color, but in the wrong place
</li>
</ul>
<h3>Returns:</h3>
<ol>
true if you solved the puzzle (coloredPins == number of positions in the code), or false otherwise
</ol>
</dd>
<dt>
<a name = "mastermindsolver:checkLastSuggestion"></a>
<strong>mastermindsolver:checkLastSuggestion(coloredPins, whitePins)</strong>
<a style="float:right;" href="../source/MasterMindSolver.lua.html#202">line 202</a>
</dt>
<dd>
Function which assumes you used the last suggested guess from the solver, and reduces the number of possible correct solutions based on the answer given
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">coloredPins</span>
<span class="types"><span class="type">number</span></span>
how many parts of the guess are both the right color and the right place
</li>
<li><span class="parameter">whitePins</span>
<span class="types"><span class="type">number</span></span>
how many parts of the guess are the right color, but in the wrong place
</li>
</ul>
<h3>Returns:</h3>
<ol>
true if you solved the puzzle (coloredPins == number of positions in the code), or false otherwise
</ol>
<h3>See also:</h3>
<ul>
<a href="../classes/MasterMindSolver.html#mastermindsolver:reducePossible">MasterMindSolver:reducePossible</a>
</ul>
</dd>
<dt>
<a name = "mastermindsolver:getValidGuess"></a>
<strong>mastermindsolver:getValidGuess(useActions)</strong>
<a style="float:right;" href="../source/MasterMindSolver.lua.html#208">line 208</a>
</dt>
<dd>
Used to get one of the remaining valid possible guesses
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">useActions</span>
<span class="types"><span class="type">boolean</span></span>
if true, will return the guess as the commands which would be sent, rather than the numbered items
</li>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,407 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Methods">Methods</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><strong>SUG</strong></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
</ul>
</div>
<div id="content">
<h1>Class <code>SUG</code></h1>
<p>Self Updating Gauge, extends <a href="https://www.mudlet.org/geyser/files/geyser/GeyserGauge.html">Geyser.Gauge</a></p>
<p></p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2020 Damian Monogue</li>
<li><strong>License</strong>: MIT, see LICENSE.lua</li>
<li><strong>Author</strong>: Damian Monogue <demonnic@gmail.com></li>
</ul>
<h2><a href="#Methods">Methods</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#sug:new">sug:new(cons, container)</a></td>
<td class="summary">Creates a new Self Updating Gauge.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sug:setUpdateTime">sug:setUpdateTime(time)</a></td>
<td class="summary">Set how often to update the gauge on a timer</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sug:setUpdateEvent">sug:setUpdateEvent(event)</a></td>
<td class="summary">Set the event to listen for to update the gauge</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sug:setCurrentVariable">sug:setCurrentVariable(variableName)</a></td>
<td class="summary">Set the name of the variable the Self Updating Gauge watches for the 'current' value of the gauge</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sug:setMaxVariable">sug:setMaxVariable(variableName)</a></td>
<td class="summary">Set the name of the variable the Self Updating Gauge watches for the 'max' value of the gauge</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sug:setTextTemplate">sug:setTextTemplate(template)</a></td>
<td class="summary">Set the template for the Self Updating Gauge to set the text with.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sug:setUpdateHook">sug:setUpdateHook(func)</a></td>
<td class="summary">Set the updateHook function which is run just prior to the gauge updating</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sug:stop">sug:stop()</a></td>
<td class="summary">Stops the Self Updating Gauge from updating</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sug:start">sug:start()</a></td>
<td class="summary">Starts the Self Updating Gauge updating.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sug:update">sug:update()</a></td>
<td class="summary">Reads the values from currentVariable and maxVariable, and updates the gauge's value and text.</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Methods"></a>Methods</h2>
<dl class="function">
<dt>
<a name = "sug:new"></a>
<strong>sug:new(cons, container)</strong>
<a style="float:right;" href="../source/SUG.lua.html#91">line 91</a>
</dt>
<dd>
Creates a new Self Updating Gauge.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">cons</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
table of options which control the Gauge's behaviour. In addition to all valid contraints for Geyser.Gauge, SUG adds:
<br>
<table class="tg">
<tr>
<th>name</th>
<th>description</th>
<th>default</th>
</tr>
<tr>
<td class="tg-1">active</td>
<td class="tg-1">boolean, if true starts the timer updating</td>
<td class="tg-1">true</td>
</tr>
<tr>
<td class="tg-2">updateTime</td>
<td class="tg-2">How often should the gauge autoupdate? Milliseconds. 0 to disable the timer but still allow event updates</td>
<td class="tg-2">333</td>
</tr>
<tr>
<td class="tg-1">currentVariable</td>
<td class="tg-1">What variable will hold the 'current' value of the gauge? Pass the name as a string, IE "currentHP" or "gmcp.Char.Vitals.hp"</td>
<td class="tg-1">""</td>
</tr>
<tr>
<td class="tg-2">maxVariable</td>
<td class="tg-2">What variable will hold the 'current' value of the gauge? Pass the name as a string, IE "maxHP" or "gmcp.Char.Vitals.maxhp"</td>
<td class="tg-2">""</td>
</tr>
<tr>
<td class="tg-1">textTemplate</td>
<td class="tg-1">Template to use for the text on the gauge. "|c" replaced with current value, "|m" replaced with max value, "|p" replaced with the % full the gauge should be</td>
<td class="tg-1">" |c/|m |p%"</td>
</tr>
<tr>
<td class="tg-2">defaultCurrent</td>
<td class="tg-2">What value to use if the currentVariable points to nil or something which cannot be made a number?</td>
<td class="tg-2">50</td>
</tr>
<tr>
<td class="tg-1">defaultMax</td>
<td class="tg-1">What value to use if the maxVariable points to nil or something which cannot be made a number?</td>
<td class="tg-1">100</td>
</tr>
<tr>
<td class="tg-2">updateEvent</td>
<td class="tg-2">The name of an event to listen for to perform an update. Can be run alongside or instead of the timer updates. Empty string to turn off</td>
<td class="tg-2">""</td>
</tr>
<tr>
<td class="tg-1">updateHook</td>
<td class="tg-1">A function which is run each time the gauge updates. Should take 3 arguments, the gauge itself, current value, and max value. You can return new current and max values to be used, for example `return 34, 120` would cause the gauge to use 34 for current and 120 for max regardless of what the variables it reads say.</td>
<td class="tg-1"></td>
</tr>
</table>
</li>
<li><span class="parameter">container</span>
The Geyser container for this gauge
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> SUG = <span class="global">require</span>(<span class="string">"MDK.sug"</span>) <span class="comment">--the following will watch "gmcp.Char.Vitals.hp" and "gmcp.Char.Vitals.maxhp" and update itself every 333 milliseconds
</span>myGauge = SUG:<span class="function-name">new</span>({
name = <span class="string">"myGauge"</span>,
currentVariable = <span class="string">"gmcp.Char.Vitals.hp"</span>, <span class="comment">--if this is nil, it will use the defaultCurrent of 50
</span> maxVariable = <span class="string">"gmcp.Char.Vitals.maxhp"</span>, <span class="comment">--if this is nil, it will use the defaultMax of 100.
</span> height = <span class="number">50</span>,
})</pre>
</ul>
</dd>
<dt>
<a name = "sug:setUpdateTime"></a>
<strong>sug:setUpdateTime(time)</strong>
<a style="float:right;" href="../source/SUG.lua.html#115">line 115</a>
</dt>
<dd>
Set how often to update the gauge on a timer
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">time</span>
<span class="types"><span class="type">number</span></span>
time in milliseconds. 0 to disable the timer
</li>
</ul>
</dd>
<dt>
<a name = "sug:setUpdateEvent"></a>
<strong>sug:setUpdateEvent(event)</strong>
<a style="float:right;" href="../source/SUG.lua.html#126">line 126</a>
</dt>
<dd>
Set the event to listen for to update the gauge
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">event</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
the name of the event to listen for, use "" to disable events without stopping any existing timers
</li>
</ul>
</dd>
<dt>
<a name = "sug:setCurrentVariable"></a>
<strong>sug:setCurrentVariable(variableName)</strong>
<a style="float:right;" href="../source/SUG.lua.html#137">line 137</a>
</dt>
<dd>
Set the name of the variable the Self Updating Gauge watches for the 'current' value of the gauge
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">variableName</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The name of the variable to get the current value for the gauge. For instance "currentHP", "gmcp.Char.Vitals.hp" etc
</li>
</ul>
</dd>
<dt>
<a name = "sug:setMaxVariable"></a>
<strong>sug:setMaxVariable(variableName)</strong>
<a style="float:right;" href="../source/SUG.lua.html#152">line 152</a>
</dt>
<dd>
Set the name of the variable the Self Updating Gauge watches for the 'max' value of the gauge
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">variableName</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The name of the variable to get the max value for the gauge. For instance "maxHP", "gmcp.Char.Vitals.maxhp" etc. Set to "" to only check the current value
</li>
</ul>
</dd>
<dt>
<a name = "sug:setTextTemplate"></a>
<strong>sug:setTextTemplate(template)</strong>
<a style="float:right;" href="../source/SUG.lua.html#172">line 172</a>
</dt>
<dd>
Set the template for the Self Updating Gauge to set the text with. "|c" is replaced by the current value, "|m" is replaced by the max value, and "|p" is replaced by the percentage current/max
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">template</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The template to use for the text on the gauge. If the max value is 200 and current is 68, then |c will be replace by 68, |m replaced by 200, and |p replaced by 34.
</li>
</ul>
</dd>
<dt>
<a name = "sug:setUpdateHook"></a>
<strong>sug:setUpdateHook(func)</strong>
<a style="float:right;" href="../source/SUG.lua.html#182">line 182</a>
</dt>
<dd>
Set the updateHook function which is run just prior to the gauge updating
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">func</span>
<span class="types"><span class="type">function</span></span>
The function which will be called when the gauge updates. It should take 3 arguments, the gauge itself, the current value, and the max value. If you wish to override the current or max values used for the gauge, you can return new current and max values, like `return newCurrent newMax`
</li>
</ul>
</dd>
<dt>
<a name = "sug:stop"></a>
<strong>sug:stop()</strong>
<a style="float:right;" href="../source/SUG.lua.html#191">line 191</a>
</dt>
<dd>
Stops the Self Updating Gauge from updating
</dd>
<dt>
<a name = "sug:start"></a>
<strong>sug:start()</strong>
<a style="float:right;" href="../source/SUG.lua.html#204">line 204</a>
</dt>
<dd>
Starts the Self Updating Gauge updating. If it is already updating, it will restart it.
</dd>
<dt>
<a name = "sug:update"></a>
<strong>sug:update()</strong>
<a style="float:right;" href="../source/SUG.lua.html#218">line 218</a>
</dt>
<dd>
Reads the values from currentVariable and maxVariable, and updates the gauge's value and text.
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,593 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Tables">Tables</a></li>
<li><a href="#Methods">Methods</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><strong>SortBox</strong></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
</ul>
</div>
<div id="content">
<h1>Class <code>SortBox</code></h1>
<p>An H/VBox alternative which can be set to either vertical or horizontal, and will autosort the windows</p>
<p></p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2020 Damian Monogue</li>
<li><strong>License</strong>: MIT, see LICENSE.lua</li>
<li><strong>Author</strong>: Damian Monogue <demonnic@gmail.com></li>
</ul>
<h2><a href="#Tables">Tables</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#sortbox.SortFunctions">sortbox.SortFunctions</a></td>
<td class="summary">Sorting functions for spairs, should you wish</td>
</tr>
</table>
<h2><a href="#Methods">Methods</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#sortbox:new">sortbox:new(options[, container])</a></td>
<td class="summary">Creates a new SortBox</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sortbox:organize">sortbox:organize()</a></td>
<td class="summary">Calling this will cause the SortBox to reposition/resize everything</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sortbox:enableElastic">sortbox:enableElastic()</a></td>
<td class="summary">Enables elasticity for the SortBox.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sortbox:disableElastic">sortbox:disableElastic()</a></td>
<td class="summary">Disables elasticity for the SortBox</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sortbox:setElastic">sortbox:setElastic(enabled)</a></td>
<td class="summary">Set elasticity specifically</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sortbox:setMaxWidth">sortbox:setMaxWidth(maxWidth)</a></td>
<td class="summary">Set the max width of the SortBox if it's elastic</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sortbox:setMaxHeight">sortbox:setMaxHeight(maxHeight)</a></td>
<td class="summary">Set the max height of the SortBox if it's elastic</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sortbox:enableTimer">sortbox:enableTimer()</a></td>
<td class="summary">Starts the SortBox sorting and organizing itself on a timer</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sortbox:disableTimer">sortbox:disableTimer()</a></td>
<td class="summary">Stops the SortBox from sorting and organizing itself on a timer</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sortbox:setSortInterval">sortbox:setSortInterval(sortInterval)</a></td>
<td class="summary">Sets the sortInterval, or amount of time in milliseconds between auto sorting on a timer if timerSort is true</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sortbox:enableSort">sortbox:enableSort()</a></td>
<td class="summary">Enables sorting when items are added/removed, or if timerSort is true, every sortInterval milliseconds</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sortbox:disableSort">sortbox:disableSort()</a></td>
<td class="summary">Disables sorting when items are added or removed</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sortbox:setBoxType">sortbox:setBoxType(boxType)</a></td>
<td class="summary">Set whether the SortBox acts as a VBox or HBox.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sortbox:setSortFunction">sortbox:setSortFunction(functionName)</a></td>
<td class="summary">Sets the type of sorting in use by this SortBox.</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Tables"></a>Tables</h2>
<dl class="function">
<dt>
<a name = "sortbox.SortFunctions"></a>
<strong>sortbox.SortFunctions</strong>
<a style="float:right;" href="../source/SortBox.lua.html#29">line 29</a>
</dt>
<dd>
Sorting functions for spairs, should you wish
<h3>Fields:</h3>
<ul>
<li><span class="parameter">gaugeValue</span>
sorts Geyser gauges by value, ascending
</li>
<li><span class="parameter">reverseGaugeValue</span>
sorts Geyser gauges by value, descending
</li>
<li><span class="parameter">timeLeft</span>
sorts TimerGauges by how much time is left, ascending
</li>
<li><span class="parameter">reverseTimeLeft</span>
sorts TimerGauges by how much time is left, descending.
</li>
<li><span class="parameter">name</span>
sorts Geyser objects by name, ascending
</li>
<li><span class="parameter">reverseName</span>
sorts Geyser objects by name, descending
</li>
<li><span class="parameter">message</span>
sorts Geyser labels and gauges by their echoed text, ascending
</li>
<li><span class="parameter">reverseMessage</span>
sorts Geyser labels and gauges by their echoed text, descending
</li>
</ul>
</dd>
</dl>
<h2 class="section-header "><a name="Methods"></a>Methods</h2>
<dl class="function">
<dt>
<a name = "sortbox:new"></a>
<strong>sortbox:new(options[, container])</strong>
<a style="float:right;" href="../source/SortBox.lua.html#144">line 144</a>
</dt>
<dd>
Creates a new SortBox
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">options</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
the options to use for the SortBox. See table below for added options
</li>
<li><span class="parameter">container</span>
the container to add the SortBox into
<br><br>Table of new options
<table class="tg">
<thead>
<tr>
<th>option name</th>
<th>description</th>
<th>default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tg-1">autoSort</td>
<td class="tg-1">should the SortBox perform function based sorting? If false, will behave like a normal H/VBox</td>
<td class="tg-1">true</td>
</tr>
<tr>
<td class="tg-2">timerSort</td>
<td class="tg-2">should the SortBox automatically perform sorting on a timer?</td>
<td class="tg-2">true</td>
</tr>
<tr>
<td class="tg-1">sortInterval</td>
<td class="tg-1">how frequently should we sort on a timer if timerSort is true, in milliseconds</td>
<td class="tg-1">500</td>
</tr>
<tr>
<td class="tg-2">boxType</td>
<td class="tg-2">Should we stack like an HBox or VBox? use 'h' for hbox and 'v' for vbox</td>
<td class="tg-2">v</td>
</tr>
<tr>
<td class="tg-1">sortFunction</td>
<td class="tg-1">how should we sort the items in the SortBox? see setSortFunction for valid options</td>
<td class="tg-1">gaugeValue</td>
</tr>
<tr>
<td class="tg-2">elastic</td>
<td class="tg-2">Should this container stretch to fit its contents? boxType v stretches in height, h stretches in width.</td>
<td class="tg-2">false</td>
</tr>
<tr>
<td class="tg-1">maxHeight</td>
<td class="tg-1">If elastic, what's the biggest a 'v' style box should grow in height? Use 0 for unlimited</td>
<td class="tg-1">0</td>
</tr>
<tr>
<td class="tg-2">maxWidth</td>
<td class="tg-2">If elastic, what's the biggest a 'h' style box should grow in width? Use 0 for unlimited</td>
<td class="tg-2">0</td>
</tr>
</tbody>
</table>
(<em>optional</em>)
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> SortBox = <span class="global">require</span>(<span class="string">"MDK.sortbox"</span>)
mySortBox = SortBox:<span class="function-name">new</span>({
name = <span class="string">"mySortBox"</span>,
x = <span class="number">400</span>,
y = <span class="number">100</span>,
height = <span class="number">150</span>,
width = <span class="number">300</span>,
sortFunction = <span class="string">"timeLeft"</span>
})</pre>
</ul>
</dd>
<dt>
<a name = "sortbox:organize"></a>
<strong>sortbox:organize()</strong>
<a style="float:right;" href="../source/SortBox.lua.html#196">line 196</a>
</dt>
<dd>
Calling this will cause the SortBox to reposition/resize everything
</dd>
<dt>
<a name = "sortbox:enableElastic"></a>
<strong>sortbox:enableElastic()</strong>
<a style="float:right;" href="../source/SortBox.lua.html#372">line 372</a>
</dt>
<dd>
Enables elasticity for the SortBox.
</dd>
<dt>
<a name = "sortbox:disableElastic"></a>
<strong>sortbox:disableElastic()</strong>
<a style="float:right;" href="../source/SortBox.lua.html#377">line 377</a>
</dt>
<dd>
Disables elasticity for the SortBox
</dd>
<dt>
<a name = "sortbox:setElastic"></a>
<strong>sortbox:setElastic(enabled)</strong>
<a style="float:right;" href="../source/SortBox.lua.html#383">line 383</a>
</dt>
<dd>
Set elasticity specifically
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">enabled</span>
<span class="types"><span class="type">boolean</span></span>
if true, enable elasticity. If false, disable it.
</li>
</ul>
</dd>
<dt>
<a name = "sortbox:setMaxWidth"></a>
<strong>sortbox:setMaxWidth(maxWidth)</strong>
<a style="float:right;" href="../source/SortBox.lua.html#389">line 389</a>
</dt>
<dd>
Set the max width of the SortBox if it's elastic
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">maxWidth</span>
<span class="types"><span class="type">number</span></span>
The maximum width in pixels to resize the SortBox to. Use 0 for unlimited.
</li>
</ul>
</dd>
<dt>
<a name = "sortbox:setMaxHeight"></a>
<strong>sortbox:setMaxHeight(maxHeight)</strong>
<a style="float:right;" href="../source/SortBox.lua.html#398">line 398</a>
</dt>
<dd>
Set the max height of the SortBox if it's elastic
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">maxHeight</span>
<span class="types"><span class="type">number</span></span>
The maximum height in pixels to resize the SortBox to. Use 0 for unlimited.
</li>
</ul>
</dd>
<dt>
<a name = "sortbox:enableTimer"></a>
<strong>sortbox:enableTimer()</strong>
<a style="float:right;" href="../source/SortBox.lua.html#406">line 406</a>
</dt>
<dd>
Starts the SortBox sorting and organizing itself on a timer
</dd>
<dt>
<a name = "sortbox:disableTimer"></a>
<strong>sortbox:disableTimer()</strong>
<a style="float:right;" href="../source/SortBox.lua.html#417">line 417</a>
</dt>
<dd>
Stops the SortBox from sorting and organizing itself on a timer
</dd>
<dt>
<a name = "sortbox:setSortInterval"></a>
<strong>sortbox:setSortInterval(sortInterval)</strong>
<a style="float:right;" href="../source/SortBox.lua.html#425">line 425</a>
</dt>
<dd>
Sets the sortInterval, or amount of time in milliseconds between auto sorting on a timer if timerSort is true
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">sortInterval</span>
<span class="types"><span class="type">number</span></span>
time in milliseconds between auto sorting if timerSort is true
</li>
</ul>
</dd>
<dt>
<a name = "sortbox:enableSort"></a>
<strong>sortbox:enableSort()</strong>
<a style="float:right;" href="../source/SortBox.lua.html#436">line 436</a>
</dt>
<dd>
Enables sorting when items are added/removed, or if timerSort is true, every sortInterval milliseconds
</dd>
<dt>
<a name = "sortbox:disableSort"></a>
<strong>sortbox:disableSort()</strong>
<a style="float:right;" href="../source/SortBox.lua.html#442">line 442</a>
</dt>
<dd>
Disables sorting when items are added or removed
</dd>
<dt>
<a name = "sortbox:setBoxType"></a>
<strong>sortbox:setBoxType(boxType)</strong>
<a style="float:right;" href="../source/SortBox.lua.html#451">line 451</a>
</dt>
<dd>
Set whether the SortBox acts as a VBox or HBox.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">boxType</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
If you pass 'h' or 'horizontal' it will act like an HBox. Anything else it will act like a VBox.
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example">mySortBox:<span class="function-name">setBoxType</span>(<span class="string">"v"</span>) <span class="comment">-- behave like a VBox
</span>mySortBox:<span class="function-name">setBoxType</span>(<span class="string">"h"</span>) <span class="comment">-- behave like an HBox
</span>mySortBox:<span class="function-name">setBoxType</span>(<span class="string">"beeblebrox"</span>) <span class="comment">-- why?! Why would you do this? It'll behave like a VBox</span></pre>
</ul>
</dd>
<dt>
<a name = "sortbox:setSortFunction"></a>
<strong>sortbox:setSortFunction(functionName)</strong>
<a style="float:right;" href="../source/SortBox.lua.html#508">line 508</a>
</dt>
<dd>
Sets the type of sorting in use by this SortBox.
<br>If an item in the box does not have the appropriate property or function, then 999999999 is used for sorting except as otherwise noted.
<br>If an invalid option is given, then existing H/VBox behaviour is maintained, just like if autoSort is false.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">functionName</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
what type of sorting should we use? See table below for valid options and their descriptions.
<table class="tg">
<thead>
<tr>
<th>sort type</th>
<th>description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tg-1">gaugeValue</td>
<td class="tg-1">sort gauges based on how full the gauge is, from less full to more</td>
</tr>
<tr>
<td class="tg-2">reverseGaugeValue</td>
<td class="tg-2">sort gauges based on how full the gauge is, from more full to less</td>
</tr>
<tr>
<td class="tg-1">timeLeft</td>
<td class="tg-1">sort TimerGauges based on the total time left in the gauge, from less time to more</td>
</tr>
<tr>
<td class="tg-2">reverseTimeLeft</td>
<td class="tg-2">sort TimerGauges based on the total time left in the gauge, from more time to less</td>
</tr>
<tr>
<td class="tg-1">name</td>
<td class="tg-1">sort any item (and mixed types) by name, alphabetically.</td>
</tr>
<tr>
<td class="tg-2">reverseName</td>
<td class="tg-2">sort any item (and mixed types) by name, reverse alphabetically.</td>
</tr>
<tr>
<td class="tg-1">message</td>
<td class="tg-1">sorts Labels based on their echoed message, alphabetically. If not a label, the empty string will be used</td>
</tr>
<tr>
<td class="tg-2">reverseMessage</td>
<td class="tg-2">sorts Labels based on their echoed message, reverse alphabetically. If not a label, the empty string will be used</td>
</tr>
</tbody>
</table>
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example">mySortBox:<span class="function-name">setSortFunction</span>(<span class="string">"gaugeValue"</span>)</pre>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,622 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Methods">Methods</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><strong>TextGauge</strong></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
</ul>
</div>
<div id="content">
<h1>Class <code>TextGauge</code></h1>
<p>Creates a text based gauge, for use in miniconsoles and the like.</p>
<p></p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2020 Damian Monogue,2021 Damian Monogue</li>
<li><strong>License</strong>: MIT, see LICENSE.lua</li>
<li><strong>Author</strong>: Damian Monogue <demonnic@gmail.com></li>
</ul>
<h2><a href="#Methods">Methods</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#textgauge:new">textgauge:new([options])</a></td>
<td class="summary">Creates a new TextGauge.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:setWidth">textgauge:setWidth(width)</a></td>
<td class="summary">Sets the width in characters of the gauge</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:setFillCharacter">textgauge:setFillCharacter(character)</a></td>
<td class="summary">Sets the character to use for the 'full' part of the gauge</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:setOverflowCharacter">textgauge:setOverflowCharacter(character)</a></td>
<td class="summary">Sets the character to use for the 'overflow' (>100%) part of the gauge</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:setEmptyCharacter">textgauge:setEmptyCharacter(character)</a></td>
<td class="summary">Sets the character to use for the 'full' part of the gauge</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:setFillColor">textgauge:setFillColor(color)</a></td>
<td class="summary">Sets the fill color for the gauge.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:setOverflowColor">textgauge:setOverflowColor(color)</a></td>
<td class="summary">Sets the overflow color for the gauge.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:setEmptyColor">textgauge:setEmptyColor(color)</a></td>
<td class="summary">Sets the empty color for the gauge.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:setPercentColor">textgauge:setPercentColor(color)</a></td>
<td class="summary">Sets the fill color for the gauge.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:setPercentSymbolColor">textgauge:setPercentSymbolColor(color)</a></td>
<td class="summary">Sets the fill color for the gauge.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:enableReverse">textgauge:enableReverse()</a></td>
<td class="summary">Enables reversing the fill direction (right to left instead of the usual left to right)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:disableReverse">textgauge:disableReverse()</a></td>
<td class="summary">Disables reversing the fill direction (go back to the usual left to right)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:enableShowPercent">textgauge:enableShowPercent()</a></td>
<td class="summary">Enables showing the percent value of the gauge</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:disableShowPercent">textgauge:disableShowPercent()</a></td>
<td class="summary">Disables showing the percent value of the gauge</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:enableShowPercentSymbol">textgauge:enableShowPercentSymbol()</a></td>
<td class="summary">Enables showing the percent symbol (appears after the value)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:disableShowPercentSymbol">textgauge:disableShowPercentSymbol()</a></td>
<td class="summary">Enables showing the percent symbol (appears after the value)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:setValue">textgauge:setValue([current[, max]])</a></td>
<td class="summary">Used to set the gauge's value and return the string representation of the gauge</td>
</tr>
<tr>
<td class="name" nowrap><a href="#textgauge:print">textgauge:print(...)</a></td>
<td class="summary">Synonym for setValue</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Methods"></a>Methods</h2>
<dl class="function">
<dt>
<a name = "textgauge:new"></a>
<strong>textgauge:new([options])</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#92">line 92</a>
</dt>
<dd>
Creates a new TextGauge.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">options</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
The table of options you would like the TextGauge to start with.
<br><br>Table of new options
<table class="tg">
<thead>
<tr>
<th>option name</th>
<th>description</th>
<th>default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tg-1">width</td>
<td class="tg-1">How many characters wide to make the gauge</td>
<td class="tg-1">24</td>
</tr>
<tr>
<td class="tg-2">fillCharacter</td>
<td class="tg-2">What character to use for the 'full' part of the gauge</td>
<td class="tg-2">:</td>
</tr>
<tr>
<td class="tg-1">overflowCharacter</td>
<td class="tg-1">What character to use for >100% part of the gauge</td>
<td class="tg-1">if not set, it uses whatever you set fillCharacter to</td>
</tr>
<tr>
<td class="tg-2">emptyCharacter</td>
<td class="tg-2">What character to use for the 'empty' part of the gauge</td>
<td class="tg-2">-</td>
</tr>
<tr>
<td class="tg-1">showPercentSymbol</td>
<td class="tg-1">Should we show the % sign itself?</td>
<td class="tg-1">true</td>
</tr>
<tr>
<td class="tg-2">showPercent</td>
<td class="tg-2">Should we show what % of the gauge is filled?</td>
<td class="tg-2">true</td>
</tr>
<tr>
<td class="tg-1">value</td>
<td class="tg-1">How much of the gauge should be filled</td>
<td class="tg-1">50</td>
</tr>
<tr>
<td class="tg-2">format</td>
<td class="tg-2">What type of color formatting to use? 'c' for cecho, 'd' for decho, 'h' for hecho</td>
<td class="tg-2">c</td>
</tr>
<tr>
<td class="tg-1">fillColor</td>
<td class="tg-1">What color to make the full part of the bar?</td>
<td class="tg-1">"DarkOrange" or equivalent for your format type</td>
</tr>
<tr>
<td class="tg-2">emptyColor</td>
<td class="tg-2">what color to use for the empty part of the bar?</td>
<td class="tg-2">"white" or format appropriate equivalent</td>
</tr>
<tr>
<td class="tg-1">percentColor</td>
<td class="tg-1">What color to print the percentage numvers in, if shown?</td>
<td class="tg-1">"white" or fortmat appropriate equivalent</td>
</tr>
<tr>
<td class="tg-2">percentSymbolColor</td>
<td class="tg-2">What color to make the % if shown?</td>
<td class="tg-2">If not set, uses what percentColor is set to.</td>
</tr>
<tr>
<td class="tg-1">overflowColor</td>
<td class="tg-1">What color to make the >100% portion of the bar?</td>
<td class="tg-1">If not set, will use the same color as fillColor</td>
</tr>
</tbody>
</table>
(<em>optional</em>)
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> TextGauge = <span class="global">require</span>(<span class="string">"MDK.textgauge"</span>)
myTextGauge = TextGauge:<span class="function-name">new</span>()
gaugeText = myTextGauge:<span class="function-name">setValue</span>(<span class="number">382</span>, <span class="number">830</span>)</pre>
</ul>
</dd>
<dt>
<a name = "textgauge:setWidth"></a>
<strong>textgauge:setWidth(width)</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#105">line 105</a>
</dt>
<dd>
Sets the width in characters of the gauge
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">width</span>
<span class="types"><span class="type">number</span></span>
number of characters wide to make the gauge
</li>
</ul>
</dd>
<dt>
<a name = "textgauge:setFillCharacter"></a>
<strong>textgauge:setFillCharacter(character)</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#118">line 118</a>
</dt>
<dd>
Sets the character to use for the 'full' part of the gauge
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">character</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
the character to use.
</li>
</ul>
</dd>
<dt>
<a name = "textgauge:setOverflowCharacter"></a>
<strong>textgauge:setOverflowCharacter(character)</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#126">line 126</a>
</dt>
<dd>
Sets the character to use for the 'overflow' (>100%) part of the gauge
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">character</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
the character to use.
</li>
</ul>
</dd>
<dt>
<a name = "textgauge:setEmptyCharacter"></a>
<strong>textgauge:setEmptyCharacter(character)</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#134">line 134</a>
</dt>
<dd>
Sets the character to use for the 'full' part of the gauge
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">character</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
the character to use.
</li>
</ul>
</dd>
<dt>
<a name = "textgauge:setFillColor"></a>
<strong>textgauge:setFillColor(color)</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#142">line 142</a>
</dt>
<dd>
Sets the fill color for the gauge.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">color</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
the color to use for the full portion of the gauge. Will be run through Geyser.Golor
</li>
</ul>
</dd>
<dt>
<a name = "textgauge:setOverflowColor"></a>
<strong>textgauge:setOverflowColor(color)</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#149">line 149</a>
</dt>
<dd>
Sets the overflow color for the gauge.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">color</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
the color to use for the full portion of the gauge. Will be run through Geyser.Golor
</li>
</ul>
</dd>
<dt>
<a name = "textgauge:setEmptyColor"></a>
<strong>textgauge:setEmptyColor(color)</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#156">line 156</a>
</dt>
<dd>
Sets the empty color for the gauge.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">color</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
the color to use for the empty portion of the gauge. Will be run through Geyser.Golor
</li>
</ul>
</dd>
<dt>
<a name = "textgauge:setPercentColor"></a>
<strong>textgauge:setPercentColor(color)</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#163">line 163</a>
</dt>
<dd>
Sets the fill color for the gauge.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">color</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
the color to use for the numeric value. Will be run through Geyser.Golor
</li>
</ul>
</dd>
<dt>
<a name = "textgauge:setPercentSymbolColor"></a>
<strong>textgauge:setPercentSymbolColor(color)</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#169">line 169</a>
</dt>
<dd>
Sets the fill color for the gauge.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">color</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
the color to use for the numeric value. Will be run through Geyser.Golor
</li>
</ul>
</dd>
<dt>
<a name = "textgauge:enableReverse"></a>
<strong>textgauge:enableReverse()</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#175">line 175</a>
</dt>
<dd>
Enables reversing the fill direction (right to left instead of the usual left to right)
</dd>
<dt>
<a name = "textgauge:disableReverse"></a>
<strong>textgauge:disableReverse()</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#180">line 180</a>
</dt>
<dd>
Disables reversing the fill direction (go back to the usual left to right)
</dd>
<dt>
<a name = "textgauge:enableShowPercent"></a>
<strong>textgauge:enableShowPercent()</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#185">line 185</a>
</dt>
<dd>
Enables showing the percent value of the gauge
</dd>
<dt>
<a name = "textgauge:disableShowPercent"></a>
<strong>textgauge:disableShowPercent()</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#190">line 190</a>
</dt>
<dd>
Disables showing the percent value of the gauge
</dd>
<dt>
<a name = "textgauge:enableShowPercentSymbol"></a>
<strong>textgauge:enableShowPercentSymbol()</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#195">line 195</a>
</dt>
<dd>
Enables showing the percent symbol (appears after the value)
</dd>
<dt>
<a name = "textgauge:disableShowPercentSymbol"></a>
<strong>textgauge:disableShowPercentSymbol()</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#200">line 200</a>
</dt>
<dd>
Enables showing the percent symbol (appears after the value)
</dd>
<dt>
<a name = "textgauge:setValue"></a>
<strong>textgauge:setValue([current[, max]])</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#270">line 270</a>
</dt>
<dd>
Used to set the gauge's value and return the string representation of the gauge
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">current</span>
<span class="types"><span class="type">number</span></span>
current value. If no value is passed it will use the stored value. Defaults to 50 to prevent errors.
(<em>optional</em>)
</li>
<li><span class="parameter">max</span>
<span class="types"><span class="type">number</span></span>
maximum value. If not passed, the internally stored one will be used. Defaults to 100 so that it can be used with single values as a percent
(<em>optional</em>)
</li>
</ul>
<h3>Usage:</h3>
<ul>
<li><pre class="example">myGauge:<span class="function-name">setValue</span>(<span class="number">55</span>) <span class="comment">-- sets the gauge to 55% full</span></pre></li>
<li><pre class="example">myGauge:<span class="function-name">setValue</span>(<span class="number">2345</span>, <span class="number">2780</span>) <span class="comment">-- will figure out what the percentage fill is based on the given current/max values</span></pre></li>
</ul>
</dd>
<dt>
<a name = "textgauge:print"></a>
<strong>textgauge:print(...)</strong>
<a style="float:right;" href="../source/TextGauge.lua.html#331">line 331</a>
</dt>
<dd>
Synonym for setValue
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">...</span>
</li>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,631 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Methods">Methods</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><strong>TimerGauge</strong></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
</ul>
</div>
<div id="content">
<h1>Class <code>TimerGauge</code></h1>
<p>Animated countdown timer, extends <a href="https://www.mudlet.org/geyser/files/geyser/GeyserGauge.html">Geyser.Gauge</a></p>
<p></p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2020 Damian Monogue</li>
<li><strong>License</strong>: MIT, see LICENSE.lua</li>
<li><strong>Author</strong>: Damian Monogue <demonnic@gmail.com></li>
</ul>
<h2><a href="#Methods">Methods</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#timergauge:show2">timergauge:show2()</a></td>
<td class="summary">Shows the TimerGauge.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#timergauge:hide2">timergauge:hide2()</a></td>
<td class="summary">Hides the TimerGauge.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#timergauge:start">timergauge:start([show])</a></td>
<td class="summary">Starts the timergauge.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#timergauge:stop">timergauge:stop([hide])</a></td>
<td class="summary">Stops the timergauge.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#timergauge:pause">timergauge:pause([hide])</a></td>
<td class="summary">Alias for stop.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#timergauge:reset">timergauge:reset()</a></td>
<td class="summary">Resets the time on the timergauge to its original value.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#timergauge:restart">timergauge:restart([show])</a></td>
<td class="summary">Resets and starts the timergauge.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#timergauge:getTime">timergauge:getTime(format)</a></td>
<td class="summary">Get the amount of time remaining on the timer, in seconds</td>
</tr>
<tr>
<td class="name" nowrap><a href="#timergauge:finish">timergauge:finish([skipHook])</a></td>
<td class="summary">Sets the timer's remaining time to 0, stops it, and executes the hook if one exists.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#timergauge:setTime">timergauge:setTime(time)</a></td>
<td class="summary">Sets the amount of time the timer will run for.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#timergauge:setUpdateTime">timergauge:setUpdateTime(updateTime)</a></td>
<td class="summary">Changes the time between gauge updates.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#timergauge:new">timergauge:new(cons, parent)</a></td>
<td class="summary">Creates a new TimerGauge instance.</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Methods"></a>Methods</h2>
<dl class="function">
<dt>
<a name = "timergauge:show2"></a>
<strong>timergauge:show2()</strong>
<a style="float:right;" href="../source/TimerGauge.lua.html#40">line 40</a>
</dt>
<dd>
Shows the TimerGauge. If the manageContainer property is true, then will add it back to its container
</dd>
<dt>
<a name = "timergauge:hide2"></a>
<strong>timergauge:hide2()</strong>
<a style="float:right;" href="../source/TimerGauge.lua.html#49">line 49</a>
</dt>
<dd>
Hides the TimerGauge. If manageContainer property is true, then it will remove it from its container and if the container is an HBox or VBox it will initiate size/position management
</dd>
<dt>
<a name = "timergauge:start"></a>
<strong>timergauge:start([show])</strong>
<a style="float:right;" href="../source/TimerGauge.lua.html#70">line 70</a>
</dt>
<dd>
Starts the timergauge. Works whether the timer is stopped or not. Does not start a timer which is already at 0
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">show</span>
<span class="types"><span class="type">boolean</span></span>
override the autoShow property. True will always show, false will never show.
(<em>optional</em>)
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example">myTimerGauge:<span class="function-name">start</span>() <span class="comment">--starts the timer, will show or not based on autoShow property
</span>myTimerGauge:<span class="function-name">start</span>(<span class="keyword">false</span>) <span class="comment">--starts the timer, will not change hidden status, regardless of autoShow property
</span>myTimerGauge:<span class="function-name">start</span>(<span class="keyword">true</span>) <span class="comment">--starts the timer, will show it regardless of autoShow property</span></pre>
</ul>
</dd>
<dt>
<a name = "timergauge:stop"></a>
<strong>timergauge:stop([hide])</strong>
<a style="float:right;" href="../source/TimerGauge.lua.html#94">line 94</a>
</dt>
<dd>
Stops the timergauge. Works whether the timer is started or not.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">hide</span>
<span class="types"><span class="type">boolean</span></span>
override the autoHide property. True will always hide, false will never hide.
(<em>optional</em>)
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example">myTimerGauge:<span class="function-name">stop</span>() <span class="comment">--stops the timer, will hide or not based on autoHide property
</span>myTimerGauge:<span class="function-name">stop</span>(<span class="keyword">false</span>) <span class="comment">--stops the timer, will not change hidden status, regardless of autoHide property
</span>myTimerGauge:<span class="function-name">stop</span>(<span class="keyword">true</span>) <span class="comment">--stops the timer, will hide it regardless of autoHide property</span></pre>
</ul>
</dd>
<dt>
<a name = "timergauge:pause"></a>
<strong>timergauge:pause([hide])</strong>
<a style="float:right;" href="../source/TimerGauge.lua.html#111">line 111</a>
</dt>
<dd>
Alias for stop.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">hide</span>
<span class="types"><span class="type">boolean</span></span>
override the autoHide property. True will always hide, false will never hide.
(<em>optional</em>)
</li>
</ul>
</dd>
<dt>
<a name = "timergauge:reset"></a>
<strong>timergauge:reset()</strong>
<a style="float:right;" href="../source/TimerGauge.lua.html#116">line 116</a>
</dt>
<dd>
Resets the time on the timergauge to its original value. Does not alter the running state of the timer
</dd>
<dt>
<a name = "timergauge:restart"></a>
<strong>timergauge:restart([show])</strong>
<a style="float:right;" href="../source/TimerGauge.lua.html#127">line 127</a>
</dt>
<dd>
Resets and starts the timergauge.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">show</span>
<span class="types"><span class="type">boolean</span></span>
override the autoShow property. true will always show, false will never show
(<em>optional</em>)
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example">myTimerGauge:<span class="function-name">restart</span>() <span class="comment">--restarts the timer, will show or not based on autoShow property
</span>myTimerGauge:<span class="function-name">restart</span>(<span class="keyword">false</span>) <span class="comment">--restarts the timer, will not change hidden status, regardless of autoShow property
</span>myTimerGauge:<span class="function-name">restart</span>(<span class="keyword">true</span>) <span class="comment">--restarts the timer, will show it regardless of autoShow property</span></pre>
</ul>
</dd>
<dt>
<a name = "timergauge:getTime"></a>
<strong>timergauge:getTime(format)</strong>
<a style="float:right;" href="../source/TimerGauge.lua.html#197">line 197</a>
</dt>
<dd>
Get the amount of time remaining on the timer, in seconds
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">format</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
Format string for how to return the time. If not provided defaults to self.timeFormat(which defaults to "S.t").<br>
If "" is passed will return "" as the time. See below table for formatting codes<br>
<table class="tg">
<tr>
<th>format code</th>
<th>what it is replaced with</th>
</tr>
<tr>
<td class="tg-1">S</td>
<td class="tg-1">Time left in seconds, unbroken down. Does not include milliseconds.<br>
IE a timer with 2 minutes left it would replace S with 120
</td>
</tr>
<tr>
<td class="tg-2">dd</td>
<td class="tg-2">Days, with 1 leading 0 (0, 01, 02-...)</td>
</tr>
<tr>
<td class="tg-1">d</td>
<td class="tg-1">Days, with no leading 0 (1,2,3-...)</td>
</tr>
<tr>
<td class="tg-2">hh</td>
<td class="tg-2">hours, with leading 0 (00-24)</td>
</tr>
<tr>
<td class="tg-1">h</td>
<td class="tg-1">hours, without leading 0 (0-24)</td>
</tr>
<tr>
<td class="tg-2">MM</td>
<td class="tg-2">minutes, with a leading 0 (00-59)</td>
</tr>
<tr>
<td class="tg-1">M</td>
<td class="tg-1">minutes, no leading 0 (0-59)</td>
</tr>
<tr>
<td class="tg-2">ss</td>
<td class="tg-2">seconds, with leading 0 (00-59)</td>
</tr>
<tr>
<td class="tg-1">s</td>
<td class="tg-1">seconds, no leading 0 (0-59)</td>
</tr>
<tr>
<td class="tg-2">t</td>
<td class="tg-2">tenths of a second<br>
timer with 12.345 seconds left, t would<br>
br replaced by 3.
</td>
</tr>
<tr>
<td class="tg-1">mm</td>
<td class="tg-1">milliseconds with leadings 0s (000-999)</td>
</tr>
<tr>
<td class="tg-2">m</td>
<td class="tg-2">milliseconds with no leading 0s (0-999)</td>
</tr>
</table><br>
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example">myTimerGauge:<span class="function-name">getTime</span>() <span class="comment">--returns the time using myTimerGauge.format
</span>myTimerGauge:<span class="function-name">getTime</span>(<span class="string">"hh:MM:ss"</span>) <span class="comment">--returns the time as hours, minutes, and seconds, with leading 0s (01:23:04)
</span>myTimerGauge:<span class="function-name">getTime</span>(<span class="string">"S.mm"</span>) <span class="comment">--returns the time as the total number of seconds, including milliseconds (114.004)</span></pre>
</ul>
</dd>
<dt>
<a name = "timergauge:finish"></a>
<strong>timergauge:finish([skipHook])</strong>
<a style="float:right;" href="../source/TimerGauge.lua.html#263">line 263</a>
</dt>
<dd>
Sets the timer's remaining time to 0, stops it, and executes the hook if one exists.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">skipHook</span>
<span class="types"><span class="type">boolean</span></span>
use true to have it set the timer to 0 and stop, but not execute the hook.
(<em>optional</em>)
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example">myTimerGauge:<span class="function-name">finish</span>() <span class="comment">--executes the hook if it has one
</span> myTimerGauge:<span class="function-name">finish</span>(<span class="keyword">false</span>) <span class="comment">--will not execute the hook</span></pre>
</ul>
</dd>
<dt>
<a name = "timergauge:setTime"></a>
<strong>timergauge:setTime(time)</strong>
<a style="float:right;" href="../source/TimerGauge.lua.html#294">line 294</a>
</dt>
<dd>
Sets the amount of time the timer will run for. Make sure to call :reset() or :restart()
if you want to cause the timer to run for that amount of time. If you set it to a time lower
than the time left on the timer currently, it will reset the current time, otherwise it is left alone
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">time</span>
<span class="types"><span class="type">number</span></span>
how long in seconds the timer should run for
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example">myTimerGauge:<span class="function-name">setTime</span>(<span class="number">50</span>) <span class="comment">-- sets myTimerGauge's max time to 50.</span></pre>
</ul>
</dd>
<dt>
<a name = "timergauge:setUpdateTime"></a>
<strong>timergauge:setUpdateTime(updateTime)</strong>
<a style="float:right;" href="../source/TimerGauge.lua.html#318">line 318</a>
</dt>
<dd>
Changes the time between gauge updates.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">updateTime</span>
<span class="types"><span class="type">number</span></span>
amount of time in milliseconds between gauge updates. Must be a positive number.
</li>
</ul>
</dd>
<dt>
<a name = "timergauge:new"></a>
<strong>timergauge:new(cons, parent)</strong>
<a style="float:right;" href="../source/TimerGauge.lua.html#474">line 474</a>
</dt>
<dd>
Creates a new TimerGauge instance.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">cons</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
a table of options (or constraints) for how the TimerGauge will behave. Valid options include:
<br>
<table class="tg">
<tr>
<th>name</th>
<th>description</th>
<th>default</th>
</tr>
<tr>
<td class="tg-1">time</td>
<td class="tg-1">how long the timer should run for</td>
<td class="tg-1"></td>
</tr>
<tr>
<td class="tg-2">active</td>
<td class="tg-2">whether the timer should run or not</td>
<td class="tg-2">true</td>
</tr>
<tr>
<td class="tg-1">showTime</td>
<td class="tg-1">should we show the time remaining on the gauge?</td>
<td class="tg-1">true</td>
</tr>
<tr>
<td class="tg-2">prefix</td>
<td class="tg-2">text you want shown before the time.</td>
<td class="tg-2">""</td>
</tr>
<tr>
<td class="tg-1">suffix</td>
<td class="tg-1">text you want shown after the time.</td>
<td class="tg-1">""</td>
</tr>
<tr>
<td class="tg-2">timerCaption</td>
<td class="tg-2">Alias for suffix. Deprecated and may be remove in the future</td>
<td class="tg-2"/>
</tr>
<tr>
<td class="tg-1">updateTime</td>
<td class="tg-1">number of milliseconds between gauge updates.</td>
<td class="tg-1">10</td>
</tr>
<tr>
<td class="tg-2">autoHide</td>
<td class="tg-2">should the timer :hide() itself when it runs out/you stop it?</td>
<td class="tg-2">true</td>
</tr>
<tr>
<td class="tg-1">autoShow</td>
<td class="tg-1">should the timer :show() itself when you start it?</td>
<td class="tg-1">true</td>
</tr>
<tr>
<td class="tg-2">manageContainer</td>
<td class="tg-2">should the timer remove itself from its container when you call <br>:hide() and add itself back when you call :show()?</td>
<td class="tg-2">false</td>
</tr>
<tr>
<td class="tg-1">timeFormat</td>
<td class="tg-1">how should the time be displayed/returned if you call :getTime()? <br>See table below for more information</td>
<td class="tg-1">"S.t"</td>
</tr>
</table>
<br>Table of time format options
<table class="tg">
<tr>
<th>format code</th>
<th>what it is replaced with</th>
</tr>
<tr>
<td class="tg-1">S</td>
<td class="tg-1">Time left in seconds, unbroken down. Does not include milliseconds.<br>
IE a timer with 2 minutes left it would replace S with 120
</td>
</tr>
<tr>
<td class="tg-2">dd</td>
<td class="tg-2">Days, with 1 leading 0 (0, 01, 02-...)</td>
</tr>
<tr>
<td class="tg-1">d</td>
<td class="tg-1">Days, with no leading 0 (1,2,3-...)</td>
</tr>
<tr>
<td class="tg-2">hh</td>
<td class="tg-2">hours, with leading 0 (00-24)</td>
</tr>
<tr>
<td class="tg-1">h</td>
<td class="tg-1">hours, without leading 0 (0-24)</td>
</tr>
<tr>
<td class="tg-2">MM</td>
<td class="tg-2">minutes, with a leading 0 (00-59)</td>
</tr>
<tr>
<td class="tg-1">M</td>
<td class="tg-1">minutes, no leading 0 (0-59)</td>
</tr>
<tr>
<td class="tg-2">ss</td>
<td class="tg-2">seconds, with leading 0 (00-59)</td>
</tr>
<tr>
<td class="tg-1">s</td>
<td class="tg-1">seconds, no leading 0 (0-59)</td>
</tr>
<tr>
<td class="tg-2">t</td>
<td class="tg-2">tenths of a second<br>
timer with 12.345 seconds left, t would<br>
br replaced by 3.
</td>
</tr>
<tr>
<td class="tg-1">mm</td>
<td class="tg-1">milliseconds with leadings 0s (000-999)</td>
</tr>
<tr>
<td class="tg-2">m</td>
<td class="tg-2">milliseconds with no leading 0s (0-999)</td>
</tr>
</table><br>
</li>
<li><span class="parameter">parent</span>
The Geyser parent for this TimerGauge
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> TimerGauge = <span class="global">require</span>(<span class="string">"MDK.timergauge"</span>)
myTimerGauge = TimerGauge:<span class="function-name">new</span>({
name = <span class="string">"testGauge"</span>,
x = <span class="number">100</span>,
y = <span class="number">100</span>,
height = <span class="number">40</span>,
width = <span class="number">200</span>,
time = <span class="number">10</span>
})</pre>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,415 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Methods">Methods</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><strong>aliasmgr</strong></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
</ul>
</div>
<div id="content">
<h1>Class <code>aliasmgr</code></h1>
<p>Alias Manager</p>
<p></p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2022 Damian Monogue</li>
<li><strong>License</strong>: MIT, see LICENSE.lua</li>
<li><strong>Author</strong>: Damian Monogue <demonnic@gmail.com></li>
</ul>
<h2><a href="#Methods">Methods</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#aliasmgr:new">aliasmgr:new()</a></td>
<td class="summary">Creates a new alias manager</td>
</tr>
<tr>
<td class="name" nowrap><a href="#aliasmgr:register">aliasmgr:register(name, regex, func)</a></td>
<td class="summary">Registers an alias with the alias manager</td>
</tr>
<tr>
<td class="name" nowrap><a href="#aliasmgr:add">aliasmgr:add(name, regex, func)</a></td>
<td class="summary">Registers an alias with the alias manager.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#aliasmgr:disable">aliasmgr:disable(name)</a></td>
<td class="summary">Disables an alias, but does not delete it so it can be enabled later without being redefined</td>
</tr>
<tr>
<td class="name" nowrap><a href="#aliasmgr:disableAll">aliasmgr:disableAll()</a></td>
<td class="summary">Disables all aliases registered with the manager</td>
</tr>
<tr>
<td class="name" nowrap><a href="#aliasmgr:enable">aliasmgr:enable(name)</a></td>
<td class="summary">Enables an alias by name</td>
</tr>
<tr>
<td class="name" nowrap><a href="#aliasmgr:enableAll">aliasmgr:enableAll()</a></td>
<td class="summary">Enables all aliases registered with the manager</td>
</tr>
<tr>
<td class="name" nowrap><a href="#aliasmgr:kill">aliasmgr:kill(name)</a></td>
<td class="summary">Kill an alias, deleting it from the manager</td>
</tr>
<tr>
<td class="name" nowrap><a href="#aliasmgr:killAll">aliasmgr:killAll()</a></td>
<td class="summary">Kills all aliases registered with the manager, clearing it out</td>
</tr>
<tr>
<td class="name" nowrap><a href="#aliasmgr:delete">aliasmgr:delete(name)</a></td>
<td class="summary">Kills an alias, deleting it from the manager</td>
</tr>
<tr>
<td class="name" nowrap><a href="#aliasmgr:deleteAll">aliasmgr:deleteAll()</a></td>
<td class="summary">Kills all aliases, deleting them from the manager</td>
</tr>
<tr>
<td class="name" nowrap><a href="#aliasmgr:getAliases">aliasmgr:getAliases()</a></td>
<td class="summary">Returns the list of aliases and the information being tracked for them</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Methods"></a>Methods</h2>
<dl class="function">
<dt>
<a name = "aliasmgr:new"></a>
<strong>aliasmgr:new()</strong>
<a style="float:right;" href="../source/aliasmgr.lua.html#10">line 10</a>
</dt>
<dd>
Creates a new alias manager
</dd>
<dt>
<a name = "aliasmgr:register"></a>
<strong>aliasmgr:register(name, regex, func)</strong>
<a style="float:right;" href="../source/aliasmgr.lua.html#27">line 27</a>
</dt>
<dd>
Registers an alias with the alias manager
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">name</span>
the name for the alias
</li>
<li><span class="parameter">regex</span>
the regular expression the alias matches against
</li>
<li><span class="parameter">func</span>
The code to run when the alias matches. Can wrap code in [[ ]] or pass an actual function
</li>
</ul>
</dd>
<dt>
<a name = "aliasmgr:add"></a>
<strong>aliasmgr:add(name, regex, func)</strong>
<a style="float:right;" href="../source/aliasmgr.lua.html#63">line 63</a>
</dt>
<dd>
Registers an alias with the alias manager. Alias for register
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">name</span>
the name for the alias
</li>
<li><span class="parameter">regex</span>
the regular expression the alias matches against
</li>
<li><span class="parameter">func</span>
The code to run when the alias matches. Can wrap code in [[ ]] or pass an actual function
</li>
</ul>
<h3>See also:</h3>
<ul>
<a href="../classes/aliasmgr.html#aliasmgr:register">register</a>
</ul>
</dd>
<dt>
<a name = "aliasmgr:disable"></a>
<strong>aliasmgr:disable(name)</strong>
<a style="float:right;" href="../source/aliasmgr.lua.html#70">line 70</a>
</dt>
<dd>
Disables an alias, but does not delete it so it can be enabled later without being redefined
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">name</span>
the name of the alias to disable
</li>
</ul>
<h3>Returns:</h3>
<ol>
true if the alias exists and gets disabled, false if it does not exist or is already disabled
</ol>
</dd>
<dt>
<a name = "aliasmgr:disableAll"></a>
<strong>aliasmgr:disableAll()</strong>
<a style="float:right;" href="../source/aliasmgr.lua.html#86">line 86</a>
</dt>
<dd>
Disables all aliases registered with the manager
</dd>
<dt>
<a name = "aliasmgr:enable"></a>
<strong>aliasmgr:enable(name)</strong>
<a style="float:right;" href="../source/aliasmgr.lua.html#96">line 96</a>
</dt>
<dd>
Enables an alias by name
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">name</span>
the name of the alias to enable
</li>
</ul>
<h3>Returns:</h3>
<ol>
true if the alias exists and was enabled, false if it does not exist.
</ol>
</dd>
<dt>
<a name = "aliasmgr:enableAll"></a>
<strong>aliasmgr:enableAll()</strong>
<a style="float:right;" href="../source/aliasmgr.lua.html#110">line 110</a>
</dt>
<dd>
Enables all aliases registered with the manager
</dd>
<dt>
<a name = "aliasmgr:kill"></a>
<strong>aliasmgr:kill(name)</strong>
<a style="float:right;" href="../source/aliasmgr.lua.html#121">line 121</a>
</dt>
<dd>
Kill an alias, deleting it from the manager
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">name</span>
the name of the alias to kill
</li>
</ul>
<h3>Returns:</h3>
<ol>
true if the alias exists and gets deleted, false if the alias does not exist
</ol>
</dd>
<dt>
<a name = "aliasmgr:killAll"></a>
<strong>aliasmgr:killAll()</strong>
<a style="float:right;" href="../source/aliasmgr.lua.html#137">line 137</a>
</dt>
<dd>
Kills all aliases registered with the manager, clearing it out
</dd>
<dt>
<a name = "aliasmgr:delete"></a>
<strong>aliasmgr:delete(name)</strong>
<a style="float:right;" href="../source/aliasmgr.lua.html#148">line 148</a>
</dt>
<dd>
Kills an alias, deleting it from the manager
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">name</span>
the name of the alias to delete
</li>
</ul>
<h3>Returns:</h3>
<ol>
true if the alias exists and gets deleted, false if the alias does not exist
</ol>
<h3>See also:</h3>
<ul>
<a href="../classes/aliasmgr.html#aliasmgr:kill">kill</a>
</ul>
</dd>
<dt>
<a name = "aliasmgr:deleteAll"></a>
<strong>aliasmgr:deleteAll()</strong>
<a style="float:right;" href="../source/aliasmgr.lua.html#154">line 154</a>
</dt>
<dd>
Kills all aliases, deleting them from the manager
<h3>See also:</h3>
<ul>
<a href="../classes/aliasmgr.html#aliasmgr:killAll">killAll</a>
</ul>
</dd>
<dt>
<a name = "aliasmgr:getAliases"></a>
<strong>aliasmgr:getAliases()</strong>
<a style="float:right;" href="../source/aliasmgr.lua.html#160">line 160</a>
</dt>
<dd>
Returns the list of aliases and the information being tracked for them
<h3>Returns:</h3>
<ol>
the table of alias information, with names as keys and a table of information as the values.
</ol>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,252 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Methods">Methods</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><strong>revisionator</strong></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
</ul>
</div>
<div id="content">
<h1>Class <code>revisionator</code></h1>
<p>The revisionator provides a standardized way of migrating configurations between revisions
for instance, it will track what the currently applied revision number is, and when you tell
tell it to migrate, it will apply every individual migration between the currently applied
revision and the latest/current revision.</p>
<p> This should allow for more seamlessly moving from
an older version of a package to a new one.</p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2023</li>
<li><strong>License</strong>: MIT, see https://raw.githubusercontent.com/demonnic/MDK/main/src/scripts/LICENSE.lua</li>
<li><strong>Author</strong>: Damian Monogue <demonnic@gmail.com></li>
</ul>
<h2><a href="#Methods">Methods</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#revisionator:new">revisionator:new(options)</a></td>
<td class="summary">Creates a new revisionator</td>
</tr>
<tr>
<td class="name" nowrap><a href="#revisionator:getAppliedPatch">revisionator:getAppliedPatch()</a></td>
<td class="summary">Get the currently applied revision from file</td>
</tr>
<tr>
<td class="name" nowrap><a href="#revisionator:migrate">revisionator:migrate()</a></td>
<td class="summary">go through all the patches in order and apply any which are still necessary</td>
</tr>
<tr>
<td class="name" nowrap><a href="#revisionator:addPatch">revisionator:addPatch(func[, position])</a></td>
<td class="summary">add a patch to the table of patches</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Methods"></a>Methods</h2>
<dl class="function">
<dt>
<a name = "revisionator:new"></a>
<strong>revisionator:new(options)</strong>
<a style="float:right;" href="../source/revisionator.lua.html#47">line 47</a>
</dt>
<dd>
Creates a new revisionator
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">options</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
the options to create the revisionator with.
<table class="tg">
<thead>
<tr>
<th>option name</th>
<th>description</th>
<th>default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tg-1">name</td>
<td class="tg-1">The name of the revisionator. This is absolutely required, as the name is used for tracking the currently applied patch level</td>
<td class="tg-1">raises an error if not provided</td>
</tr>
<tr>
<td class="tg-2">patches</td>
<td class="tg-2">A table of patch functions. It is traversed using ipairs, so must be in the form of {function1, function2, function3} etc. If you do not provide it, you can add the patches by calling :addPatch for each patch in order.</td>
<td class="tg-2">{}</td>
</tr>
</tbody>
</table>
</li>
</ul>
</dd>
<dt>
<a name = "revisionator:getAppliedPatch"></a>
<strong>revisionator:getAppliedPatch()</strong>
<a style="float:right;" href="../source/revisionator.lua.html#65">line 65</a>
</dt>
<dd>
Get the currently applied revision from file
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">number</span></span>
the revision number currently applied, or 0 if it can't read a current version
</ol>
<h3>Or</h3>
<ol>
<li>
<span class="types"><span class="type">nil</span></span>
nil</li>
<li>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
error message</li>
</ol>
</dd>
<dt>
<a name = "revisionator:migrate"></a>
<strong>revisionator:migrate()</strong>
<a style="float:right;" href="../source/revisionator.lua.html#86">line 86</a>
</dt>
<dd>
go through all the patches in order and apply any which are still necessary
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">boolean</span></span>
true if it successfully applied patches, false if it was already at the latest patch level
</ol>
<h3>Or</h3>
<ol>
<li>
<span class="types"><span class="type">nil</span></span>
</li>
<li>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
error message</li>
</ol>
</dd>
<dt>
<a name = "revisionator:addPatch"></a>
<strong>revisionator:addPatch(func[, position])</strong>
<a style="float:right;" href="../source/revisionator.lua.html#111">line 111</a>
</dt>
<dd>
add a patch to the table of patches
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">func</span>
<span class="types"><span class="type">function</span></span>
the function to run as the patch
</li>
<li><span class="parameter">position</span>
<span class="types"><span class="type">number</span></span>
which patch to insert it as? If not supplied, inserts it as the last patch. Which is usually what you want.
(<em>optional</em>)
</li>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,337 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Methods">Methods</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><strong>spinbox</strong></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
</ul>
</div>
<div id="content">
<h1>Class <code>spinbox</code></h1>
<p>A Geyser object to create a spinbox for adjusting a number</p>
<p></p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2023</li>
<li><strong>License</strong>: MIT, see https://raw.githubusercontent.com/demonnic/MDK/main/src/scripts/LICENSE.lua</li>
<li><strong>Author</strong>: Damian Monogue <demonnic@gmail.com></li>
</ul>
<h2><a href="#Methods">Methods</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#spinbox:new">spinbox:new(cons, container)</a></td>
<td class="summary">Creates a new spinbox.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#spinbox:setValue">spinbox:setValue(value)</a></td>
<td class="summary">Used to directly set the value of the spinbox.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#spinbox:generateStyles">spinbox:generateStyles()</a></td>
<td class="summary">(Re)generates the stylesheets for the spinbox
Should not need to call but if you change something and it doesn't take effect
you can try calling this followed by applyStyles</td>
</tr>
<tr>
<td class="name" nowrap><a href="#spinbox:applyStyles">spinbox:applyStyles()</a></td>
<td class="summary">Applies updated stylesheets to the components of the spinbox
Should not need to call this directly</td>
</tr>
<tr>
<td class="name" nowrap><a href="#spinbox:setActiveButtonColor">spinbox:setActiveButtonColor(color)</a></td>
<td class="summary">sets the color for active buttons on the spinbox</td>
</tr>
<tr>
<td class="name" nowrap><a href="#spinbox:setInactiveButtonColor">spinbox:setInactiveButtonColor(color)</a></td>
<td class="summary">sets the color for inactive buttons on the spinbox</td>
</tr>
<tr>
<td class="name" nowrap><a href="#spinbox:setCallBack">spinbox:setCallBack(func)</a></td>
<td class="summary">Set a callback function for the spinbox to call any time the value of the spinbox is changed
the function will be called as func(self.value, self.name)</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Methods"></a>Methods</h2>
<dl class="function">
<dt>
<a name = "spinbox:new"></a>
<strong>spinbox:new(cons, container)</strong>
<a style="float:right;" href="../source/spinbox.lua.html#89">line 89</a>
</dt>
<dd>
Creates a new spinbox.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">cons</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
a table containing the options for this spinbox.
<table class="tg">
<thead>
<tr>
<th>option name</th>
<th>description</th>
<th>default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tg-1">min</td>
<td class="tg-1">The minimum value for this spinbox</td>
<td class="tg-1">0</td>
</tr>
<tr>
<td class="tg-2">max</td>
<td class="tg-2">The maximum value for this spinbox</td>
<td class="tg-2">10</td>
</tr>
<tr>
<td class="tg-1">activeButtonColor</td>
<td class="tg-1">The color the up/down buttons should be when they are active/able to be used</td>
<td class="tg-1">gray</td>
</tr>
<tr>
<td class="tg-2">inactiveButtonColor</td>
<td class="tg-2">The color the up/down buttons should be when they are inactive/unable to be used</td>
<td class="tg-2">dimgray</td>
</tr>
<tr>
<td class="tg-1">integer</td>
<td class="tg-1">Boolean value. When true, values must always be integers (no decimal place)</td>
<td class="tg-1">true</td>
</tr>
<tr>
<td class="tg-2">delta</td>
<td class="tg-2">The amount to change the spinbox's value when the up or down button is pressed.</td>
<td class="tg-2">1</td>
</tr>
<tr>
<td class="tg-1">upArrowLocation</td>
<td class="tg-1">The location of the up arrow image. Either a web URL where it can be downloaded, or the location on disk to read it from</td>
<td class="tg-1">https://demonnic.github.io/image-assets/uparrow.png</td>
</tr>
<tr>
<td class="tg-2">downArrowLocation</td>
<td class="tg-2">The location of the down arrow image. Either a web URL where it can be downloaded, or the location on disk to read it from</td>
<td class="tg-2">https://demonnic.github.io/image-assets/downarrow.png</td>
<tr>
<td class="tg-1">callBack</td>
<td class="tg-1">The function to run when the spinbox's value is updated. Is called with parameters (self.name, value, oldValue)</td>
<td class="tg-1">nil</td>
</tr>
</tr>
</tbody>
</table>
</li>
<li><span class="parameter">container</span>
The Geyser container for this spinbox
</li>
</ul>
</dd>
<dt>
<a name = "spinbox:setValue"></a>
<strong>spinbox:setValue(value)</strong>
<a style="float:right;" href="../source/spinbox.lua.html#270">line 270</a>
</dt>
<dd>
Used to directly set the value of the spinbox.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">value</span>
The new value to set
Rounds the value to an integer if the spinbox is integer only.
Checks if the new value is within the min/max range and clamps it if not.
Updates the display label with the new value.
Applies any styles that depend on the value.
</li>
</ul>
</dd>
<dt>
<a name = "spinbox:generateStyles"></a>
<strong>spinbox:generateStyles()</strong>
<a style="float:right;" href="../source/spinbox.lua.html#387">line 387</a>
</dt>
<dd>
(Re)generates the stylesheets for the spinbox
Should not need to call but if you change something and it doesn't take effect
you can try calling this followed by applyStyles
</dd>
<dt>
<a name = "spinbox:applyStyles"></a>
<strong>spinbox:applyStyles()</strong>
<a style="float:right;" href="../source/spinbox.lua.html#412">line 412</a>
</dt>
<dd>
Applies updated stylesheets to the components of the spinbox
Should not need to call this directly
</dd>
<dt>
<a name = "spinbox:setActiveButtonColor"></a>
<strong>spinbox:setActiveButtonColor(color)</strong>
<a style="float:right;" href="../source/spinbox.lua.html#430">line 430</a>
</dt>
<dd>
sets the color for active buttons on the spinbox
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">color</span>
any valid color formatting string, such a "red" or "#880000" or "<128,0,0>" or a table of colors, like {128, 0,0}. See Geyser.Color.parse at https://www.mudlet.org/geyser/files/geyser/GeyserColor.html#Geyser.Color.parse
</li>
</ul>
</dd>
<dt>
<a name = "spinbox:setInactiveButtonColor"></a>
<strong>spinbox:setInactiveButtonColor(color)</strong>
<a style="float:right;" href="../source/spinbox.lua.html#445">line 445</a>
</dt>
<dd>
sets the color for inactive buttons on the spinbox
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">color</span>
any valid color formatting string, such a "<red>" or "red" or "<128,0,0>" or a table of colors, like {128, 0,0}. See Geyser.Color.parse at https://www.mudlet.org/geyser/files/geyser/GeyserColor.html#Geyser.Color.parse
</li>
</ul>
</dd>
<dt>
<a name = "spinbox:setCallBack"></a>
<strong>spinbox:setCallBack(func)</strong>
<a style="float:right;" href="../source/spinbox.lua.html#472">line 472</a>
</dt>
<dd>
Set a callback function for the spinbox to call any time the value of the spinbox is changed
the function will be called as func(self.value, self.name)
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">func</span>
</li>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

237
src/resources/MDK/doc/index.html Executable file
View File

@ -0,0 +1,237 @@
<!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>MDK</h1>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="modules/demontools.html">demontools</a></li>
<li><a href="modules/echofile.html">echofile</a></li>
<li><a href="modules/figlet.html">figlet</a></li>
<li><a href="modules/ftext.html">ftext</a></li>
<li><a href="modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="classes/Chyron.html">Chyron</a></li>
<li><a href="classes/EMCO.html">EMCO</a></li>
<li><a href="classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="classes/Loginator.html">Loginator</a></li>
<li><a href="classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="classes/revisionator.html">revisionator</a></li>
<li><a href="classes/SortBox.html">SortBox</a></li>
<li><a href="classes/spinbox.html">spinbox</a></li>
<li><a href="classes/SUG.html">SUG</a></li>
<li><a href="classes/TextGauge.html">TextGauge</a></li>
<li><a href="classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</ul>
</div>
<div id="content">
<h2>Modules</h2>
<table class="module_list">
<tr>
<td class="name" nowrap><a href="modules/demontools.html">demontools</a></td>
<td class="summary">Collection of miscellaneous functions and tools which don't necessarily warrant their own module/class</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/echofile.html">echofile</a></td>
<td class="summary">set of functions for echoing files to things.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/figlet.html">figlet</a></td>
<td class="summary">Figlet
A module to read figlet fonts and produce figlet ascii art from text</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/ftext.html">ftext</a></td>
<td class="summary">ftext
functions to format and print text, and the objects which use them</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/GradientMaker.html">GradientMaker</a></td>
<td class="summary">Module which provides for creating color gradients for your text.</td>
</tr>
</table>
<h2>Classes</h2>
<table class="module_list">
<tr>
<td class="name" nowrap><a href="classes/aliasmgr.html">aliasmgr</a></td>
<td class="summary">Alias Manager</td>
</tr>
<tr>
<td class="name" nowrap><a href="classes/Chyron.html">Chyron</a></td>
<td class="summary">Creates a label with a scrolling text element.</td>
</tr>
<tr>
<td class="name" nowrap><a href="classes/EMCO.html">EMCO</a></td>
<td class="summary">Embeddable Multi Console Object.</td>
</tr>
<tr>
<td class="name" nowrap><a href="classes/LoggingConsole.html">LoggingConsole</a></td>
<td class="summary">MiniConsole with logging capabilities</td>
</tr>
<tr>
<td class="name" nowrap><a href="classes/Loginator.html">Loginator</a></td>
<td class="summary">Loginator creates an object which allows you to log things to file at
various severity levels, with the ability to only log items above a specific
severity to file.</td>
</tr>
<tr>
<td class="name" nowrap><a href="classes/MasterMindSolver.html">MasterMindSolver</a></td>
<td class="summary">Interactive object which helps you solve a Master Mind puzzle.</td>
</tr>
<tr>
<td class="name" nowrap><a href="classes/revisionator.html">revisionator</a></td>
<td class="summary">The revisionator provides a standardized way of migrating configurations between revisions
for instance, it will track what the currently applied revision number is, and when you tell
tell it to migrate, it will apply every individual migration between the currently applied
revision and the latest/current revision.</td>
</tr>
<tr>
<td class="name" nowrap><a href="classes/SortBox.html">SortBox</a></td>
<td class="summary">An H/VBox alternative which can be set to either vertical or horizontal, and will autosort the windows</td>
</tr>
<tr>
<td class="name" nowrap><a href="classes/spinbox.html">spinbox</a></td>
<td class="summary">A Geyser object to create a spinbox for adjusting a number</td>
</tr>
<tr>
<td class="name" nowrap><a href="classes/SUG.html">SUG</a></td>
<td class="summary">Self Updating Gauge, extends <a href="https://www.mudlet.org/geyser/files/geyser/GeyserGauge.html">Geyser.Gauge</a></td>
</tr>
<tr>
<td class="name" nowrap><a href="classes/TextGauge.html">TextGauge</a></td>
<td class="summary">Creates a text based gauge, for use in miniconsoles and the like.</td>
</tr>
<tr>
<td class="name" nowrap><a href="classes/TimerGauge.html">TimerGauge</a></td>
<td class="summary">Animated countdown timer, extends <a href="https://www.mudlet.org/geyser/files/geyser/GeyserGauge.html">Geyser.Gauge</a></td>
</tr>
</table>
<h2>Source</h2>
<table class="module_list">
<tr>
<td class="name" nowrap><a href="source/LICENSE.lua.html">LICENSE.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/aliasmgr.lua.html">aliasmgr.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/chyron.lua.html">chyron.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/demontools.lua.html">demontools.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/echofile.lua.html">echofile.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/emco.lua.html">emco.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/figlet.lua.html">figlet.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/ftext.lua.html">ftext.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/gradientmaker.lua.html">gradientmaker.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/loggingconsole.lua.html">loggingconsole.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/loginator.lua.html">loginator.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/mastermindsolver.lua.html">mastermindsolver.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/revisionator.lua.html">revisionator.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/schema.lua.html">schema.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/sortbox.lua.html">sortbox.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/spinbox.lua.html">spinbox.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/sug.lua.html">sug.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/ftext_spec.lua.html">ftext_spec.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/textgauge.lua.html">textgauge.lua</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="source/timergauge.lua.html">timergauge.lua</a></td>
<td class="summary"></td>
</tr>
</table>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

315
src/resources/MDK/doc/ldoc.css Executable file
View File

@ -0,0 +1,315 @@
/* 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: #ccc;
background: #222;
}
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 {
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: #222222; 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: 20px 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: #2266ee; text-decoration: none; }
a:visited { font-weight: bold; color: #0099bb; 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: #000000;
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: #222222;
}
#product {
text-align: center;
border-bottom: 1px solid #cccccc;
background-color: #222222;
}
#product big {
font-size: 2em;
}
#main {
background-color: #222222;
border-left: 2px solid #cccccc;
}
#navigation {
float: left;
width: 14em;
vertical-align: top;
background-color: #222222;
overflow: visible;
}
#navigation h1 {
color: #cccccc;
font-size: 1.5em;
margin: 20px 0 20px 0;
}
#navigation h2 {
background-color:#333333;
font-size:1.1em;
color:#cccccc;
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;
border-left: 2px solid #cccccc;
border-right: 2px solid #cccccc;
background-color: #222222;
}
#about {
clear: both;
padding: 5px;
border-top: 2px solid #cccccc;
background-color: #222222;
}
@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: #222222; 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: #222222; 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: #060;
}
/* 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; }
.tg {border-collapse:collapse;border-color:#ccc;border-spacing:0;}
.tg td{background-color:#8b8b8b;border-color:#ccc;border-style:solid;border-width:1px;color:#000;
font-family:Arial, sans-serif;font-size:14px;overflow:hidden;padding:10px 5px;word-break:normal;}
.tg th{background-color:#000000;border-color:#ccc;border-style:solid;border-width:1px;color:#FFF;
font-family:Arial, sans-serif;font-size:14px;font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}
.tg .tg-2{background-color:#797979;border-color:inherit;text-align:left;vertical-align:top;color:#DDD}
.tg .tg-1{background-color:#8b8b8b;border-color:#ccc;border-style:solid;border-width:1px;color:#000;text-align:left;vertical-align:top}

View File

@ -0,0 +1,422 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Functions">Functions</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><strong>GradientMaker</strong></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</ul>
</div>
<div id="content">
<h1>Module <code>GradientMaker</code></h1>
<p>Module which provides for creating color gradients for your text.</p>
<p>
Original functions found on <a href="https://forums.lusternia.com/discussion/3261/anyone-want-text-gradients">the Lusternia Forums</a>
<br> I added functions to work with hecho.
<br> I also made performance enhancements by storing already calculated gradients after first use for the session and only including the colorcode in the returned string if the color changed.</p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2018 Sylphas,2020 Damian Monogue</li>
<li><strong>Author</strong>: Sylphas on the Lusternia forums,Damian Monogue <demonnic@gmail.com></li>
</ul>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#color_name">color_name(r, g, b)</a></td>
<td class="summary">Returns the closest color name to a given r,g,b color</td>
</tr>
<tr>
<td class="name" nowrap><a href="#dgradient">dgradient(text, first_color, second_color, next_color)</a></td>
<td class="summary">Returns the text, with the defined color gradients applied and formatted for us with decho.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#cgradient">cgradient(text, first_color, second_color, next_color)</a></td>
<td class="summary">Returns the text, with the defined color gradients applied and formatted for us with cecho.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#hgradient">hgradient(text, first_color, second_color, next_color)</a></td>
<td class="summary">Returns the text, with the defined color gradients applied and formatted for us with hecho.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#cgradient_table">cgradient_table(text, first_color, second_color, next_color)</a></td>
<td class="summary">Returns a table, each element of which is a table, the first element of which is the color name to use and the character which should be that color</td>
</tr>
<tr>
<td class="name" nowrap><a href="#dgradient_table">dgradient_table(text, first_color, second_color, next_color)</a></td>
<td class="summary">Returns a table, each element of which is a table, the first element of which is the color({r,g,b} format) to use and the character which should be that color</td>
</tr>
<tr>
<td class="name" nowrap><a href="#hgradient_table">hgradient_table(text, first_color, second_color, next_color)</a></td>
<td class="summary">Returns a table, each element of which is a table, the first element of which is the color(in hex) to use and the second element of which is the character which should be that color</td>
</tr>
<tr>
<td class="name" nowrap><a href="#install_global">install_global()</a></td>
<td class="summary">Creates global copies of the c/d/hgradient(_table) functions and color_name for use without accessing the module table</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
<dl class="function">
<dt>
<a name = "color_name"></a>
<strong>color_name(r, g, b)</strong>
<a style="float:right;" href="../source/GradientMaker.lua.html#228">line 228</a>
</dt>
<dd>
Returns the closest color name to a given r,g,b color
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">r</span>
The red component. Can also pass the full color as a table, IE { 255, 0, 0 }
</li>
<li><span class="parameter">g</span>
The green component. If you pass the color as a table as noted above, this param should be empty
</li>
<li><span class="parameter">b</span>
the blue components. If you pass the color as a table as noted above, this param should be empty
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example">closest_color = GradientMaker.<span class="function-name">color_name</span>(<span class="number">128</span>,<span class="number">200</span>,<span class="number">30</span>) <span class="comment">-- returns "ansi_149"
</span>closest_color = GradientMaker.<span class="function-name">color_name</span>({<span class="number">128</span>, <span class="number">200</span>, <span class="number">30</span>}) <span class="comment">-- this is functionally equivalent to the first one</span></pre>
</ul>
</dd>
<dt>
<a name = "dgradient"></a>
<strong>dgradient(text, first_color, second_color, next_color)</strong>
<a style="float:right;" href="../source/GradientMaker.lua.html#244">line 244</a>
</dt>
<dd>
Returns the text, with the defined color gradients applied and formatted for us with decho. Usage example below produces the following text
<br><img src="https://demonnic.github.io/mdk/images/dechogradient.png" alt="dgradient example">
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The text you want to apply the color gradients to
</li>
<li><span class="parameter">first_color</span>
The color you want it to start at. Table of colors in { r, g, b } format
</li>
<li><span class="parameter">second_color</span>
The color you want the gradient to transition to first. Table of colors in { r, g, b } format
</li>
<li><span class="parameter">next_color</span>
Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
</li>
</ul>
<h3>See also:</h3>
<ul>
<li><a href="../modules/GradientMaker.html#cgradient">cgradient</a></li>
<li><a href="../modules/GradientMaker.html#hgradient">hgradient</a></li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="function-name">decho</span>(GradientMaker.<span class="function-name">dgradient</span>(<span class="string">"a luminescent butterly floats about lazily on brillant blue and lilac wings\n"</span>, {<span class="number">255</span>,<span class="number">0</span>,<span class="number">0</span>}, {<span class="number">255</span>,<span class="number">128</span>,<span class="number">0</span>}, {<span class="number">255</span>,<span class="number">255</span>,<span class="number">0</span>}, {<span class="number">0</span>,<span class="number">255</span>,<span class="number">0</span>}, {<span class="number">0</span>,<span class="number">255</span>,<span class="number">255</span>}, {<span class="number">0</span>,<span class="number">128</span>,<span class="number">255</span>}, {<span class="number">128</span>,<span class="number">0</span>,<span class="number">255</span>}))
<span class="function-name">decho</span>(GradientMaker.<span class="function-name">dgradient</span>(<span class="string">"a luminescent butterly floats about lazily on brillant blue and lilac wings\n"</span>, {<span class="number">255</span>,<span class="number">0</span>,<span class="number">0</span>}, {<span class="number">0</span>,<span class="number">0</span>,<span class="number">255</span>}))
<span class="function-name">decho</span>(GradientMaker.<span class="function-name">dgradient</span>(<span class="string">"a luminescent butterly floats about lazily on brillant blue and lilac wings\n"</span>, {<span class="number">50</span>,<span class="number">50</span>,<span class="number">50</span>}, {<span class="number">0</span>,<span class="number">255</span>,<span class="number">0</span>}, {<span class="number">50</span>,<span class="number">50</span>,<span class="number">50</span>}))</pre>
</ul>
</dd>
<dt>
<a name = "cgradient"></a>
<strong>cgradient(text, first_color, second_color, next_color)</strong>
<a style="float:right;" href="../source/GradientMaker.lua.html#260">line 260</a>
</dt>
<dd>
Returns the text, with the defined color gradients applied and formatted for us with cecho. Usage example below produces the following text
<br><img src="https://demonnic.github.io/mdk/images/cechogradient.png" alt="cgradient example">
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The text you want to apply the color gradients to
</li>
<li><span class="parameter">first_color</span>
The color you want it to start at. Table of colors in { r, g, b } format
</li>
<li><span class="parameter">second_color</span>
The color you want the gradient to transition to first. Table of colors in { r, g, b } format
</li>
<li><span class="parameter">next_color</span>
Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
</li>
</ul>
<h3>See also:</h3>
<ul>
<li><a href="../modules/GradientMaker.html#dgradient">dgradient</a></li>
<li><a href="../modules/GradientMaker.html#hgradient">hgradient</a></li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="function-name">cecho</span>(GradientMaker.<span class="function-name">cgradient</span>(<span class="string">"a luminescent butterly floats about lazily on brillant blue and lilac wings\n"</span>, {<span class="number">255</span>,<span class="number">0</span>,<span class="number">0</span>}, {<span class="number">255</span>,<span class="number">128</span>,<span class="number">0</span>}, {<span class="number">255</span>,<span class="number">255</span>,<span class="number">0</span>}, {<span class="number">0</span>,<span class="number">255</span>,<span class="number">0</span>}, {<span class="number">0</span>,<span class="number">255</span>,<span class="number">255</span>}, {<span class="number">0</span>,<span class="number">128</span>,<span class="number">255</span>}, {<span class="number">128</span>,<span class="number">0</span>,<span class="number">255</span>}))
<span class="function-name">cecho</span>(GradientMaker.<span class="function-name">cgradient</span>(<span class="string">"a luminescent butterly floats about lazily on brillant blue and lilac wings\n"</span>, {<span class="number">255</span>,<span class="number">0</span>,<span class="number">0</span>}, {<span class="number">0</span>,<span class="number">0</span>,<span class="number">255</span>}))
<span class="function-name">cecho</span>(GradientMaker.<span class="function-name">cgradient</span>(<span class="string">"a luminescent butterly floats about lazily on brillant blue and lilac wings\n"</span>, {<span class="number">50</span>,<span class="number">50</span>,<span class="number">50</span>}, {<span class="number">0</span>,<span class="number">255</span>,<span class="number">0</span>}, {<span class="number">50</span>,<span class="number">50</span>,<span class="number">50</span>}))</pre>
</ul>
</dd>
<dt>
<a name = "hgradient"></a>
<strong>hgradient(text, first_color, second_color, next_color)</strong>
<a style="float:right;" href="../source/GradientMaker.lua.html#276">line 276</a>
</dt>
<dd>
Returns the text, with the defined color gradients applied and formatted for us with hecho. Usage example below produces the following text
<br><img src="https://demonnic.github.io/mdk/images/hechogradient.png" alt="hgradient example">
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The text you want to apply the color gradients to
</li>
<li><span class="parameter">first_color</span>
The color you want it to start at. Table of colors in { r, g, b } format
</li>
<li><span class="parameter">second_color</span>
The color you want the gradient to transition to first. Table of colors in { r, g, b } format
</li>
<li><span class="parameter">next_color</span>
Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
</li>
</ul>
<h3>See also:</h3>
<ul>
<li><a href="../modules/GradientMaker.html#cgradient">cgradient</a></li>
<li><a href="../modules/GradientMaker.html#dgradient">dgradient</a></li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="function-name">hecho</span>(GradientMaker.<span class="function-name">hgradient</span>(<span class="string">"a luminescent butterly floats about lazily on brillant blue and lilac wings\n"</span>, {<span class="number">255</span>,<span class="number">0</span>,<span class="number">0</span>}, {<span class="number">255</span>,<span class="number">128</span>,<span class="number">0</span>}, {<span class="number">255</span>,<span class="number">255</span>,<span class="number">0</span>}, {<span class="number">0</span>,<span class="number">255</span>,<span class="number">0</span>}, {<span class="number">0</span>,<span class="number">255</span>,<span class="number">255</span>}, {<span class="number">0</span>,<span class="number">128</span>,<span class="number">255</span>}, {<span class="number">128</span>,<span class="number">0</span>,<span class="number">255</span>}))
<span class="function-name">hecho</span>(GradientMaker.<span class="function-name">hgradient</span>(<span class="string">"a luminescent butterly floats about lazily on brillant blue and lilac wings\n"</span>, {<span class="number">255</span>,<span class="number">0</span>,<span class="number">0</span>}, {<span class="number">0</span>,<span class="number">0</span>,<span class="number">255</span>}))
<span class="function-name">hecho</span>(GradientMaker.<span class="function-name">hgradient</span>(<span class="string">"a luminescent butterly floats about lazily on brillant blue and lilac wings\n"</span>, {<span class="number">50</span>,<span class="number">50</span>,<span class="number">50</span>}, {<span class="number">0</span>,<span class="number">255</span>,<span class="number">0</span>}, {<span class="number">50</span>,<span class="number">50</span>,<span class="number">50</span>}))</pre>
</ul>
</dd>
<dt>
<a name = "cgradient_table"></a>
<strong>cgradient_table(text, first_color, second_color, next_color)</strong>
<a style="float:right;" href="../source/GradientMaker.lua.html#286">line 286</a>
</dt>
<dd>
Returns a table, each element of which is a table, the first element of which is the color name to use and the character which should be that color
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The text you want to apply the color gradients to
</li>
<li><span class="parameter">first_color</span>
The color you want it to start at. Table of colors in { r, g, b } format
</li>
<li><span class="parameter">second_color</span>
The color you want the gradient to transition to first. Table of colors in { r, g, b } format
</li>
<li><span class="parameter">next_color</span>
Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
</li>
</ul>
<h3>See also:</h3>
<ul>
<a href="../modules/GradientMaker.html#cgradient">cgradient</a>
</ul>
</dd>
<dt>
<a name = "dgradient_table"></a>
<strong>dgradient_table(text, first_color, second_color, next_color)</strong>
<a style="float:right;" href="../source/GradientMaker.lua.html#296">line 296</a>
</dt>
<dd>
Returns a table, each element of which is a table, the first element of which is the color({r,g,b} format) to use and the character which should be that color
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The text you want to apply the color gradients to
</li>
<li><span class="parameter">first_color</span>
The color you want it to start at. Table of colors in { r, g, b } format
</li>
<li><span class="parameter">second_color</span>
The color you want the gradient to transition to first. Table of colors in { r, g, b } format
</li>
<li><span class="parameter">next_color</span>
Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
</li>
</ul>
<h3>See also:</h3>
<ul>
<a href="../modules/GradientMaker.html#dgradient">dgradient</a>
</ul>
</dd>
<dt>
<a name = "hgradient_table"></a>
<strong>hgradient_table(text, first_color, second_color, next_color)</strong>
<a style="float:right;" href="../source/GradientMaker.lua.html#306">line 306</a>
</dt>
<dd>
Returns a table, each element of which is a table, the first element of which is the color(in hex) to use and the second element of which is the character which should be that color
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The text you want to apply the color gradients to
</li>
<li><span class="parameter">first_color</span>
The color you want it to start at. Table of colors in { r, g, b } format
</li>
<li><span class="parameter">second_color</span>
The color you want the gradient to transition to first. Table of colors in { r, g, b } format
</li>
<li><span class="parameter">next_color</span>
Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
</li>
</ul>
<h3>See also:</h3>
<ul>
<a href="../modules/GradientMaker.html#hgradient">hgradient</a>
</ul>
</dd>
<dt>
<a name = "install_global"></a>
<strong>install_global()</strong>
<a style="float:right;" href="../source/GradientMaker.lua.html#314">line 314</a>
</dt>
<dd>
Creates global copies of the c/d/hgradient(_table) functions and color_name for use without accessing the module table
<h3>Usage:</h3>
<ul>
<pre class="example">GradientMaker.<span class="function-name">install_global</span>()
<span class="function-name">cecho</span>(<span class="function-name">cgradient</span>(...)) <span class="comment">-- use cgradient directly now</span></pre>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,552 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Functions">Functions</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><strong>echofile</strong></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</ul>
</div>
<div id="content">
<h1>Module <code>echofile</code></h1>
<p>set of functions for echoing files to things.</p>
<p> Uses a slightly hacked up version of f-strings for interpolation/templating</p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2021 Damian Monogue,2016 Hisham Muhammad (https://github.com/hishamhm/f-strings/blob/master/LICENSE)</li>
<li><strong>License</strong>: MIT, see LICENSE.lua</li>
<li><strong>Author</strong>: Damian Monogue <demonnic@gmail.com></li>
</ul>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#f">f(str)</a></td>
<td class="summary">Takes a string and performs interpolation
Uses {} as the delimiter.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#aechoFile">aechoFile(window, filename)</a></td>
<td class="summary">reads the contents of a file, converts it to decho and then dechos it</td>
</tr>
<tr>
<td class="name" nowrap><a href="#aechoFilef">aechoFilef(window, filename)</a></td>
<td class="summary">reads the contents of a file and then cechos it</td>
</tr>
<tr>
<td class="name" nowrap><a href="#cechoFile">cechoFile(window, filename)</a></td>
<td class="summary">reads the contents of a file and then cechos it</td>
</tr>
<tr>
<td class="name" nowrap><a href="#cechoFilef">cechoFilef(window, filename)</a></td>
<td class="summary">reads the contents of a file, interpolates it as per echofile.f and then cechos it</td>
</tr>
<tr>
<td class="name" nowrap><a href="#dechoFile">dechoFile(window, filename)</a></td>
<td class="summary">reads the contents of a file and then dechos it</td>
</tr>
<tr>
<td class="name" nowrap><a href="#dechoFilef">dechoFilef(window, filename)</a></td>
<td class="summary">reads the contents of a file, interpolates it as per echofile.f and then dechos it</td>
</tr>
<tr>
<td class="name" nowrap><a href="#hechoFile">hechoFile(window, filename)</a></td>
<td class="summary">reads the contents of a file and then hechos it</td>
</tr>
<tr>
<td class="name" nowrap><a href="#hechoFilef">hechoFilef(window, filename)</a></td>
<td class="summary">reads the contents of a file, interpolates it as per echofile.f and then hechos it</td>
</tr>
<tr>
<td class="name" nowrap><a href="#echoFile">echoFile(window, filename)</a></td>
<td class="summary">reads the contents of a file, interpolates it as per echofile.f and then echos it</td>
</tr>
<tr>
<td class="name" nowrap><a href="#echoFilef">echoFilef(window, filename)</a></td>
<td class="summary">reads the contents of a file, interpolates it as per echofile.f and then echos it</td>
</tr>
<tr>
<td class="name" nowrap><a href="#patchGeyser">patchGeyser()</a></td>
<td class="summary">Adds c/d/h/echoFile functions to Geyser miniconsole and userwindow objects</td>
</tr>
<tr>
<td class="name" nowrap><a href="#installGlobal">installGlobal()</a></td>
<td class="summary">Installs c/d/h/echoFile and f to the global namespace, and adds functions to Geyser</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
<dl class="function">
<dt>
<a name = "f"></a>
<strong>f(str)</strong>
<a style="float:right;" href="../source/echofile.lua.html#109">line 109</a>
</dt>
<dd>
Takes a string and performs interpolation
Uses {} as the delimiter. Expressions will be evaluated
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">str</span>
string: The string to interpolate
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example">echofile = <span class="global">require</span>(<span class="string">"MDK.echofile"</span>)
echofile.<span class="function-name">f</span>(<span class="string">"{1+1}"</span>) <span class="comment">-- returns "2"
</span><span class="keyword">local</span> x = <span class="number">4</span>
echofile.<span class="function-name">f</span><span class="string">"4+3 = {x+3}"</span> <span class="comment">-- returns "4+3 = 7"</span></pre>
</ul>
</dd>
<dt>
<a name = "aechoFile"></a>
<strong>aechoFile(window, filename)</strong>
<a style="float:right;" href="../source/echofile.lua.html#124">line 124</a>
</dt>
<dd>
reads the contents of a file, converts it to decho and then dechos it
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">window</span>
string: Optional window to cecho to
</li>
<li><span class="parameter">filename</span>
string: Full path to file
</li>
</ul>
<h3>See also:</h3>
<ul>
<li><a href="../modules/echofile.html#f">echofile.f</a></li>
<li><a href="../modules/echofile.html#cechoFile">echofile.cechoFile</a></li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> ec = <span class="global">require</span>(<span class="string">"MDK.echofile"</span>)
<span class="keyword">local</span> cechoFile,f = ec.cechoFile, ec.f
<span class="function-name">cechoFile</span>(<span class="string">"C:/path/to/file"</span>) <span class="comment">-- windows1
</span><span class="function-name">cechoFile</span>(<span class="string">"C:\\path\\to\\file"</span>) <span class="comment">-- windows2
</span><span class="function-name">cechoFile</span>(<span class="string">"/path/to/file"</span>) <span class="comment">-- Linux/MacOS
</span><span class="function-name">cechoFile</span>(<span class="string">"aMiniConsole"</span>, <span class="function-name">f</span><span class="string">"{getMudletHomeDir()}/myPkgName/helpfile"</span>) <span class="comment">-- cecho a file from your pkg to a miniconsole</span></pre>
</ul>
</dd>
<dt>
<a name = "aechoFilef"></a>
<strong>aechoFilef(window, filename)</strong>
<a style="float:right;" href="../source/echofile.lua.html#140">line 140</a>
</dt>
<dd>
reads the contents of a file and then cechos it
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">window</span>
string: Optional window to cecho to
</li>
<li><span class="parameter">filename</span>
string: Full path to file
</li>
</ul>
<h3>See also:</h3>
<ul>
<li><a href="../modules/echofile.html#f">echofile.f</a></li>
<li><a href="../modules/echofile.html#cechoFilef">echofile.cechoFilef</a></li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> ec = <span class="global">require</span>(<span class="string">"MDK.echofile"</span>)
<span class="keyword">local</span> cechoFile,f = ec.cechoFile, ec.f
<span class="function-name">cechoFile</span>(<span class="string">"C:/path/to/file"</span>) <span class="comment">-- windows1
</span><span class="function-name">cechoFile</span>(<span class="string">"C:\\path\\to\\file"</span>) <span class="comment">-- windows2
</span><span class="function-name">cechoFile</span>(<span class="string">"/path/to/file"</span>) <span class="comment">-- Linux/MacOS
</span><span class="function-name">cechoFile</span>(<span class="string">"aMiniConsole"</span>, <span class="function-name">f</span><span class="string">"{getMudletHomeDir()}/myPkgName/helpfile"</span>) <span class="comment">-- cecho a file from your pkg to a miniconsole</span></pre>
</ul>
</dd>
<dt>
<a name = "cechoFile"></a>
<strong>cechoFile(window, filename)</strong>
<a style="float:right;" href="../source/echofile.lua.html#155">line 155</a>
</dt>
<dd>
reads the contents of a file and then cechos it
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">window</span>
string: Optional window to cecho to
</li>
<li><span class="parameter">filename</span>
string: Full path to file
</li>
</ul>
<h3>See also:</h3>
<ul>
<a href="../modules/echofile.html#f">echofile.f</a>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> ec = <span class="global">require</span>(<span class="string">"MDK.echofile"</span>)
<span class="keyword">local</span> cechoFile,f = ec.cechoFile, ec.f
<span class="function-name">cechoFile</span>(<span class="string">"C:/path/to/file"</span>) <span class="comment">-- windows1
</span><span class="function-name">cechoFile</span>(<span class="string">"C:\\path\\to\\file"</span>) <span class="comment">-- windows2
</span><span class="function-name">cechoFile</span>(<span class="string">"/path/to/file"</span>) <span class="comment">-- Linux/MacOS
</span><span class="function-name">cechoFile</span>(<span class="string">"aMiniConsole"</span>, <span class="function-name">f</span><span class="string">"{getMudletHomeDir()}/myPkgName/helpfile"</span>) <span class="comment">-- cecho a file from your pkg to a miniconsole</span></pre>
</ul>
</dd>
<dt>
<a name = "cechoFilef"></a>
<strong>cechoFilef(window, filename)</strong>
<a style="float:right;" href="../source/echofile.lua.html#170">line 170</a>
</dt>
<dd>
reads the contents of a file, interpolates it as per echofile.f and then cechos it
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">window</span>
string: Optional window to cecho to
</li>
<li><span class="parameter">filename</span>
string: Full path to file
</li>
</ul>
<h3>See also:</h3>
<ul>
<a href="../modules/echofile.html#f">echofile.f</a>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> ec = <span class="global">require</span>(<span class="string">"MDK.echofile"</span>)
<span class="keyword">local</span> cechoFile,f = ec.cechoFile, ec.f
<span class="function-name">cechoFile</span>(<span class="string">"C:/path/to/file"</span>) <span class="comment">-- windows1
</span><span class="function-name">cechoFile</span>(<span class="string">"C:\\path\\to\\file"</span>) <span class="comment">-- windows2
</span><span class="function-name">cechoFile</span>(<span class="string">"/path/to/file"</span>) <span class="comment">-- Linux/MacOS
</span><span class="function-name">cechoFile</span>(<span class="string">"aMiniConsole"</span>, <span class="function-name">f</span><span class="string">"{getMudletHomeDir()}/myPkgName/helpfile"</span>) <span class="comment">-- cecho a file from your pkg to a miniconsole</span></pre>
</ul>
</dd>
<dt>
<a name = "dechoFile"></a>
<strong>dechoFile(window, filename)</strong>
<a style="float:right;" href="../source/echofile.lua.html#180">line 180</a>
</dt>
<dd>
reads the contents of a file and then dechos it
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">window</span>
string: Optional window to decho to
</li>
<li><span class="parameter">filename</span>
string: Full path to file
</li>
</ul>
<h3>See also:</h3>
<ul>
<li><a href="../modules/echofile.html#f">echofile.f</a></li>
<li><a href="../modules/echofile.html#cechoFile">echofile.cechoFile</a></li>
</ul>
</dd>
<dt>
<a name = "dechoFilef"></a>
<strong>dechoFilef(window, filename)</strong>
<a style="float:right;" href="../source/echofile.lua.html#190">line 190</a>
</dt>
<dd>
reads the contents of a file, interpolates it as per echofile.f and then dechos it
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">window</span>
string: Optional window to decho to
</li>
<li><span class="parameter">filename</span>
string: Full path to file
</li>
</ul>
<h3>See also:</h3>
<ul>
<li><a href="../modules/echofile.html#f">echofile.f</a></li>
<li><a href="../modules/echofile.html#cechoFile">echofile.cechoFile</a></li>
</ul>
</dd>
<dt>
<a name = "hechoFile"></a>
<strong>hechoFile(window, filename)</strong>
<a style="float:right;" href="../source/echofile.lua.html#200">line 200</a>
</dt>
<dd>
reads the contents of a file and then hechos it
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">window</span>
string: Optional window to hecho to
</li>
<li><span class="parameter">filename</span>
string: Full path to file
</li>
</ul>
<h3>See also:</h3>
<ul>
<li><a href="../modules/echofile.html#f">echofile.f</a></li>
<li><a href="../modules/echofile.html#cechoFile">echofile.cechoFile</a></li>
</ul>
</dd>
<dt>
<a name = "hechoFilef"></a>
<strong>hechoFilef(window, filename)</strong>
<a style="float:right;" href="../source/echofile.lua.html#210">line 210</a>
</dt>
<dd>
reads the contents of a file, interpolates it as per echofile.f and then hechos it
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">window</span>
string: Optional window to hecho to
</li>
<li><span class="parameter">filename</span>
string: Full path to file
</li>
</ul>
<h3>See also:</h3>
<ul>
<li><a href="../modules/echofile.html#f">echofile.f</a></li>
<li><a href="../modules/echofile.html#cechoFile">echofile.cechoFile</a></li>
</ul>
</dd>
<dt>
<a name = "echoFile"></a>
<strong>echoFile(window, filename)</strong>
<a style="float:right;" href="../source/echofile.lua.html#220">line 220</a>
</dt>
<dd>
reads the contents of a file, interpolates it as per echofile.f and then echos it
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">window</span>
string: Optional window to echo to
</li>
<li><span class="parameter">filename</span>
string: Full path to file
</li>
</ul>
<h3>See also:</h3>
<ul>
<li><a href="../modules/echofile.html#f">echofile.f</a></li>
<li><a href="../modules/echofile.html#cechoFile">echofile.cechoFile</a></li>
</ul>
</dd>
<dt>
<a name = "echoFilef"></a>
<strong>echoFilef(window, filename)</strong>
<a style="float:right;" href="../source/echofile.lua.html#230">line 230</a>
</dt>
<dd>
reads the contents of a file, interpolates it as per echofile.f and then echos it
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">window</span>
string: Optional window to echo to
</li>
<li><span class="parameter">filename</span>
string: Full path to file
</li>
</ul>
<h3>See also:</h3>
<ul>
<li><a href="../modules/echofile.html#f">echofile.f</a></li>
<li><a href="../modules/echofile.html#cechoFile">echofile.cechoFile</a></li>
</ul>
</dd>
<dt>
<a name = "patchGeyser"></a>
<strong>patchGeyser()</strong>
<a style="float:right;" href="../source/echofile.lua.html#239">line 239</a>
</dt>
<dd>
Adds c/d/h/echoFile functions to Geyser miniconsole and userwindow objects
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="global">require</span>(<span class="string">"MDK.echofile"</span>).<span class="function-name">patchGeyser</span>()
myMC = Geyser.MiniConsole:<span class="function-name">new</span>({name = <span class="string">"myMC"</span>})
myMC:<span class="function-name">cechoFile</span>(<span class="function-name">f</span><span class="string">"{getMudletHomeDir()}/helpfile"</span>)</pre>
</ul>
</dd>
<dt>
<a name = "installGlobal"></a>
<strong>installGlobal()</strong>
<a style="float:right;" href="../source/echofile.lua.html#281">line 281</a>
</dt>
<dd>
Installs c/d/h/echoFile and f to the global namespace, and adds functions to Geyser
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="global">require</span>(<span class="string">"MDK.echofile"</span>).<span class="function-name">installGlobal</span>()
<span class="function-name">f</span><span class="string">"{1+2}"</span> <span class="comment">-- returns "2"
</span><span class="function-name">dechoFile</span>(<span class="function-name">f</span><span class="string">"{getMudletHomeDir()}/fileWithDechoLines.txt"</span>)
<span class="comment">-- reads contents of fileWithDechoLines.txt from profile directory
</span><span class="comment">-- and dechos them to the main console</span></pre>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,260 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Functions">Functions</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><strong>figlet</strong></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</ul>
</div>
<div id="content">
<h1>Module <code>figlet</code></h1>
<p>Figlet
A module to read figlet fonts and produce figlet ascii art from text</p>
<p></p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2010,2011 Nick Gammon,2022 Damian Monogue</li>
</ul>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Figlet.readfont">Figlet.readfont(filename)</a></td>
<td class="summary">Reads a figlet font file (.flf) into memory and readies it for use by the next figlet
These files are cached in memory so that future calls to load a font just read from there.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Figlet.ascii_art">Figlet.ascii_art(s, kern, smush)</a></td>
<td class="summary">Returns a table of lines representing a string as figlet</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Figlet.getString">Figlet.getString(str, kern, smush)</a></td>
<td class="summary">Returns the figlet as a string, rather than a table</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Figlet.getKern">Figlet.getKern(str)</a></td>
<td class="summary">Returns a figlet as a string, with kern set to true.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Figlet.getSmush">Figlet.getSmush(str)</a></td>
<td class="summary">Returns a figlet as a string, with smush set to true.</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
<dl class="function">
<dt>
<a name = "Figlet.readfont"></a>
<strong>Figlet.readfont(filename)</strong>
<a style="float:right;" href="../source/figlet.lua.html#79">line 79</a>
</dt>
<dd>
Reads a figlet font file (.flf) into memory and readies it for use by the next figlet
These files are cached in memory so that future calls to load a font just read from there.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">filename</span>
the full path to the file to read the font from
</li>
</ul>
</dd>
<dt>
<a name = "Figlet.ascii_art"></a>
<strong>Figlet.ascii_art(s, kern, smush)</strong>
<a style="float:right;" href="../source/figlet.lua.html#214">line 214</a>
</dt>
<dd>
Returns a table of lines representing a string as figlet
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">s</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
the text to make into a figlet
</li>
<li><span class="parameter">kern</span>
<span class="types"><span class="type">boolean</span></span>
should we reduce spacing
</li>
<li><span class="parameter">smush</span>
<span class="types"><span class="type">boolean</span></span>
causes the letters to share edges, condensing it even further
</li>
</ul>
</dd>
<dt>
<a name = "Figlet.getString"></a>
<strong>Figlet.getString(str, kern, smush)</strong>
<a style="float:right;" href="../source/figlet.lua.html#248">line 248</a>
</dt>
<dd>
Returns the figlet as a string, rather than a table
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">str</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
the string the make into a figlet
</li>
<li><span class="parameter">kern</span>
<span class="types"><span class="type">boolean</span></span>
should we reduce the space between letters?
</li>
<li><span class="parameter">smush</span>
<span class="types"><span class="type">boolean</span></span>
should the letters share edges, further condensing the output?
</li>
</ul>
<h3>See also:</h3>
<ul>
<a href="../modules/figlet.html#Figlet.ascii_art">ascii_art</a>
</ul>
</dd>
<dt>
<a name = "Figlet.getKern"></a>
<strong>Figlet.getKern(str)</strong>
<a style="float:right;" href="../source/figlet.lua.html#256">line 256</a>
</dt>
<dd>
Returns a figlet as a string, with kern set to true.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">str</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The string to turn into a figlet
</li>
</ul>
<h3>See also:</h3>
<ul>
<a href="../modules/figlet.html#Figlet.getString">getString</a>
</ul>
</dd>
<dt>
<a name = "Figlet.getSmush"></a>
<strong>Figlet.getSmush(str)</strong>
<a style="float:right;" href="../source/figlet.lua.html#263">line 263</a>
</dt>
<dd>
Returns a figlet as a string, with smush set to true.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">str</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The string to turn into a figlet
</li>
</ul>
<h3>See also:</h3>
<ul>
<a href="../modules/figlet.html#Figlet.getString">getString</a>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,147 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><strong>LICENSE.lua</strong></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>LICENSE.lua</h2>
<pre>
<span class="comment">--[===[
The MIT License (MIT)
Copyright (c) 2020 Damian Monogue
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]===]</span>
<span class="comment">-- schema validation provided by schema.lua, license below
</span><span class="comment">--[[
The MIT License (MIT)
Copyright (c) 2014 Sebastian Schoener
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]</span></pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,263 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><strong>aliasmgr.lua</strong></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>aliasmgr.lua</h2>
<pre>
<span class="comment">--- Alias Manager
</span><span class="comment">-- @classmod aliasmgr
</span><span class="comment">-- @author Damian Monogue &lt;demonnic@gmail.com&gt;
</span><span class="comment">-- @copyright 2022 Damian Monogue
</span><span class="comment">-- @license MIT, see LICENSE.lua
</span><span class="keyword">local</span> aliasmgr = {}
aliasmgr.__index = aliasmgr
<a id="10"></a><span class="comment">--- Creates a new alias manager
</span><span class="keyword">function</span> aliasmgr:<span class="function-name">new</span>()
<span class="keyword">local</span> mgr = {
aliases = {}
}
<span class="global">setmetatable</span>(mgr, self)
<span class="keyword">return</span> mgr
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">argError</span>(funcName, argument, expected, actual)
<span class="keyword">local</span> msg = <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s: %s as %s expected, got %s"</span>, funcName, argument, expected, actual)
<span class="function-name">printError</span>(msg, <span class="keyword">true</span>, <span class="keyword">true</span>)
<span class="keyword">end</span>
<span class="comment">--- Registers an alias with the alias manager
</span><span class="comment">-- @param name the name for the alias
</span><span class="comment">-- @param regex the regular expression the alias matches against
</span><a id="27"></a><span class="comment">-- @param func The code to run when the alias matches. Can wrap code in [[ ]] or pass an actual function
</span><span class="keyword">function</span> aliasmgr:<span class="function-name">register</span>(name, regex, func)
<span class="keyword">local</span> funcName = <span class="string">"aliasmgr:register(name, regex, func)"</span>
<span class="keyword">if</span> func == <span class="keyword">nil</span> <span class="keyword">then</span>
<span class="function-name">printError</span>(<span class="function-name">f</span><span class="string">"{funcName} takes 3 arguments and you have provided less than that"</span>, <span class="keyword">true</span>, <span class="keyword">true</span>)
<span class="keyword">end</span>
<span class="keyword">local</span> nameType = <span class="global">type</span>(name)
<span class="keyword">if</span> nameType ~= <span class="string">"string"</span> <span class="keyword">then</span>
<span class="function-name">argError</span>(funcName, <span class="string">"name"</span>, <span class="string">"string"</span>, nameType)
<span class="keyword">end</span>
<span class="keyword">local</span> regexType = <span class="global">type</span>(regex)
<span class="keyword">if</span> regexType ~= <span class="string">"string"</span> <span class="keyword">then</span>
<span class="function-name">argError</span>(funcName, <span class="string">"regex"</span>, <span class="string">"string"</span>, regexType)
<span class="keyword">end</span>
<span class="keyword">local</span> funcType = <span class="global">type</span>(func)
<span class="keyword">if</span> funcType ~= <span class="string">"string"</span> <span class="keyword">and</span> funcType ~= <span class="string">"function"</span> <span class="keyword">then</span>
<span class="function-name">argError</span>(funcName, <span class="string">"func"</span>, <span class="string">"string or function"</span>, funcType)
<span class="keyword">end</span>
<span class="keyword">local</span> object = {
regex = regex,
func = func
}
self:<span class="function-name">kill</span>(name)
<span class="keyword">local</span> ok, err = <span class="global">pcall</span>(tempAlias, regex, func)
<span class="keyword">if</span> <span class="keyword">not</span> ok <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">nil</span>, err
<span class="keyword">end</span>
object.handlerID = err
self.aliases[name] = object
<span class="keyword">return</span> <span class="keyword">true</span>
<span class="keyword">end</span>
<span class="comment">--- Registers an alias with the alias manager. Alias for register
</span><span class="comment">-- @param name the name for the alias
</span><span class="comment">-- @param regex the regular expression the alias matches against
</span><span class="comment">-- @param func The code to run when the alias matches. Can wrap code in [[ ]] or pass an actual function
</span><a id="63"></a><span class="comment">-- @see register
</span><span class="keyword">function</span> aliasmgr:<span class="function-name">add</span>(name, regex, func)
self:<span class="function-name">register</span>(name, regex, func)
<span class="keyword">end</span>
<span class="comment">--- Disables an alias, but does not delete it so it can be enabled later without being redefined
</span><span class="comment">-- @param name the name of the alias to disable
</span><a id="70"></a><span class="comment">-- @return true if the alias exists and gets disabled, false if it does not exist or is already disabled
</span><span class="keyword">function</span> aliasmgr:<span class="function-name">disable</span>(name)
<span class="keyword">local</span> funcName = <span class="string">"aliasmgr:disable(name)"</span>
<span class="keyword">local</span> nameType = <span class="global">type</span>(name)
<span class="keyword">if</span> nameType ~= <span class="string">"string"</span> <span class="keyword">then</span>
<span class="function-name">argError</span>(funcName, <span class="string">"name"</span>, <span class="string">"string"</span>, nameType)
<span class="keyword">end</span>
<span class="keyword">local</span> object = self.aliases[name]
<span class="keyword">if</span> <span class="keyword">not</span> object <span class="keyword">or</span> object.handlerID == -<span class="number">1</span> <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">false</span>
<span class="keyword">end</span>
<span class="function-name">killAlias</span>(object.handlerID)
object.handlerID = -<span class="number">1</span>
<span class="keyword">return</span> <span class="keyword">true</span>
<span class="keyword">end</span>
<a id="86"></a><span class="comment">--- Disables all aliases registered with the manager
</span><span class="keyword">function</span> aliasmgr:<span class="function-name">disableAll</span>()
<span class="keyword">local</span> aliases = self.aliases
<span class="keyword">for</span> name, object <span class="keyword">in</span> <span class="global">pairs</span>(aliases) <span class="keyword">do</span>
self:<span class="function-name">disable</span>(name)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Enables an alias by name
</span><span class="comment">-- @param name the name of the alias to enable
</span><a id="96"></a><span class="comment">-- @return true if the alias exists and was enabled, false if it does not exist.
</span><span class="keyword">function</span> aliasmgr:<span class="function-name">enable</span>(name)
<span class="keyword">local</span> funcName = <span class="string">"aliasmgr:enable(name)"</span>
<span class="keyword">local</span> nameType = <span class="global">type</span>(name)
<span class="keyword">if</span> nameType ~= <span class="string">"string"</span> <span class="keyword">then</span>
<span class="function-name">argError</span>(funcName, <span class="string">"name"</span>, <span class="string">"string"</span>, nameType)
<span class="keyword">end</span>
<span class="keyword">local</span> object = self.aliases[name]
<span class="keyword">if</span> <span class="keyword">not</span> object <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">false</span>
<span class="keyword">end</span>
self:<span class="function-name">register</span>(name, object.regex, object.func)
<span class="keyword">end</span>
<a id="110"></a><span class="comment">--- Enables all aliases registered with the manager
</span><span class="keyword">function</span> aliasmgr:<span class="function-name">enableAll</span>()
<span class="keyword">local</span> aliases = self.aliases
<span class="keyword">for</span> name,_ <span class="keyword">in</span> <span class="global">pairs</span>(aliases) <span class="keyword">do</span>
self:<span class="function-name">enable</span>(name)
<span class="keyword">end</span>
<span class="keyword">return</span> <span class="keyword">true</span>
<span class="keyword">end</span>
<span class="comment">--- Kill an alias, deleting it from the manager
</span><span class="comment">-- @param name the name of the alias to kill
</span><a id="121"></a><span class="comment">-- @return true if the alias exists and gets deleted, false if the alias does not exist
</span><span class="keyword">function</span> aliasmgr:<span class="function-name">kill</span>(name)
<span class="keyword">local</span> funcName = <span class="string">"aliasmgr:kill(name)"</span>
<span class="keyword">local</span> nameType = <span class="global">type</span>(name)
<span class="keyword">if</span> nameType ~= <span class="string">"string"</span> <span class="keyword">then</span>
<span class="function-name">argError</span>(funcName, <span class="string">"name"</span>, <span class="string">"string"</span>, nameType)
<span class="keyword">end</span>
<span class="keyword">local</span> object = self.aliases[name]
<span class="keyword">if</span> <span class="keyword">not</span> object <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">false</span>
<span class="keyword">end</span>
self:<span class="function-name">disable</span>(name)
self.aliases[name] = <span class="keyword">nil</span>
<span class="keyword">return</span> <span class="keyword">true</span>
<span class="keyword">end</span>
<a id="137"></a><span class="comment">--- Kills all aliases registered with the manager, clearing it out
</span><span class="keyword">function</span> aliasmgr:<span class="function-name">killAll</span>()
<span class="keyword">local</span> aliases = self.aliases
<span class="keyword">for</span> name, _ <span class="keyword">in</span> <span class="global">pairs</span>(aliases) <span class="keyword">do</span>
self:<span class="function-name">kill</span>(name)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Kills an alias, deleting it from the manager
</span><span class="comment">-- @param name the name of the alias to delete
</span><span class="comment">-- @return true if the alias exists and gets deleted, false if the alias does not exist
</span><a id="148"></a><span class="comment">-- @see kill
</span><span class="keyword">function</span> aliasmgr:<span class="function-name">delete</span>(name)
<span class="keyword">return</span> self:<span class="function-name">kill</span>(name)
<span class="keyword">end</span>
<span class="comment">--- Kills all aliases, deleting them from the manager
</span><a id="154"></a><span class="comment">-- @see killAll
</span><span class="keyword">function</span> aliasmgr:<span class="function-name">deleteAll</span>()
<span class="keyword">return</span> self:<span class="function-name">killAll</span>()
<span class="keyword">end</span>
<span class="comment">--- Returns the list of aliases and the information being tracked for them
</span><a id="160"></a><span class="comment">-- @return the table of alias information, with names as keys and a table of information as the values.
</span><span class="keyword">function</span> aliasmgr:<span class="function-name">getAliases</span>()
<span class="keyword">return</span> self.aliases
<span class="keyword">end</span>
<span class="keyword">return</span> aliasmgr</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,334 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><strong>chyron.lua</strong></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>chyron.lua</h2>
<pre>
<span class="comment">--- Creates a label with a scrolling text element. It is highly recommended you use a monospace font for this label.
</span><span class="comment">-- @classmod Chyron
</span><span class="comment">-- @author Delra
</span><span class="comment">-- @copyright 2019
</span><span class="comment">-- @author Damian Monogue
</span><span class="comment">-- @copyright 2020
</span><span class="keyword">local</span> Chyron = {
name = <span class="string">"ChyronClass"</span>,
text = <span class="string">""</span>,
displayWidth = <span class="number">28</span>,
updateTime = <span class="number">200</span>,
font = <span class="string">"Bitstream Vera Sans Mono"</span>,
fontSize = <span class="string">"9"</span>,
autoWidth = <span class="keyword">true</span>,
delimiter = <span class="string">"|"</span>,
pos = <span class="number">1</span>,
enabled = <span class="keyword">true</span>,
alignment = <span class="string">"center"</span>,
}
<span class="comment">--- Creates a new Chyron label
</span><span class="comment">-- @tparam table cons table of constraints which configures the EMCO.
</span><span class="comment">-- &lt;table class="tg"&gt;
</span><span class="comment">-- &lt;thead&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;th&gt;option name&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;description&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;default&lt;/th&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/thead&gt;
</span><span class="comment">-- &lt;tbody&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;text&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;The text to scroll on the label&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;""&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;updateTime&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;Milliseconds between movements (one letter shift)&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;200&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;displayWidth&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;How many chars wide to display the text&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;28&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;delimiter&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;This character will be inserted with a space either side to mark the stop/start of the message&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;"|"&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;enabled&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;Should the chyron scroll?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;true&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;font&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;What font to use for the Chyron? Available in Geyser.Label but we define a default.&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;"Bitstream Vera Sans Mono"&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;fontSize&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;What font size to use for the Chyron? Available in Geyser.Label but we define a default.&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;9&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;autoWidth&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;Should the Chyron resize to just fit the text?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;true&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;alignment&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;What alignment(left/right/center) to use for the Chyron text? Available in Geyser.Label but we define a default.&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;"center"&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/tbody&gt;
</span><span class="comment">-- &lt;/table&gt;
</span><a id="80"></a><span class="comment">-- @tparam GeyserObject container The container to use as the parent for the Chyron
</span><span class="keyword">function</span> Chyron:<span class="function-name">new</span>(cons, container)
cons = cons <span class="keyword">or</span> {}
cons.<span class="global">type</span> = cons.<span class="global">type</span> <span class="keyword">or</span> <span class="string">"Chyron"</span>
<span class="keyword">local</span> me = self.parent:<span class="function-name">new</span>(cons, container)
<span class="global">setmetatable</span>(me, self)
self.__index = self
me.pos = <span class="number">0</span>
me:<span class="function-name">setDisplayWidth</span>(me.displayWidth)
me:<span class="function-name">setMessage</span>(me.text)
<span class="keyword">if</span> me.enabled <span class="keyword">then</span>
me:<span class="function-name">start</span>()
<span class="keyword">else</span>
me:<span class="function-name">stop</span>()
<span class="keyword">end</span>
<span class="keyword">return</span> me
<span class="keyword">end</span>
<span class="comment">--- Sets the numver of characters of the text to display at once
</span><a id="99"></a><span class="comment">-- @tparam number displayWidth number of characters to show at once
</span><span class="keyword">function</span> Chyron:<span class="function-name">setDisplayWidth</span>(displayWidth)
displayWidth = displayWidth <span class="keyword">or</span> self.displayWidth
self.displayWidth = displayWidth
<span class="keyword">if</span> self.autoWidth <span class="keyword">then</span>
<span class="keyword">local</span> width = <span class="function-name">calcFontSize</span>(self.fontSize, self.font)
self:<span class="function-name">resize</span>(width * (displayWidth + <span class="number">2</span>), self.height)
<span class="keyword">end</span>
<span class="keyword">if</span> <span class="keyword">not</span> self.enabled <span class="keyword">then</span>
self.pos = self.pos - <span class="number">1</span>
self:<span class="function-name">doScroll</span>()
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Override setFontSize to call setDisplayWidth in order to resize if necessary
</span><span class="comment">-- @local
</span><span class="keyword">function</span> Chyron:<span class="function-name">setFontSize</span>(fontSize)
Geyser.Label.<span class="function-name">setFontSize</span>(self, fontSize)
self:<span class="function-name">setDisplayWidth</span>()
<span class="keyword">end</span>
<span class="comment">--- Override setFont to call setDisplayWidth in order to resize if necessary
</span><span class="comment">-- @local
</span><span class="keyword">function</span> Chyron:<span class="function-name">setFont</span>(font)
Geyser.Label.<span class="function-name">setFont</span>(self, font)
self:<span class="function-name">setDisplayWidth</span>()
<span class="keyword">end</span>
<span class="comment">--- Returns the proper section of text
</span><span class="comment">-- @local
</span><span class="comment">-- @param start number the character to start at
</span><span class="comment">-- @param length number the length of the text you want to extract
</span><span class="keyword">function</span> Chyron:<span class="function-name">scrollText</span>(start, length)
<span class="keyword">local</span> t = self.textTable
<span class="keyword">local</span> s = <span class="string">''</span>
<span class="keyword">local</span> e = start + length
<span class="keyword">for</span> i = start - <span class="number">1</span>, e - <span class="number">2</span> <span class="keyword">do</span>
<span class="keyword">local</span> n = (i % #t) + <span class="number">1</span>
s = s .. t[n]
<span class="keyword">end</span>
<span class="keyword">return</span> s
<span class="keyword">end</span>
<span class="comment">--- scroll the text
</span><span class="comment">-- @local
</span><span class="keyword">function</span> Chyron:<span class="function-name">doScroll</span>()
self.pos = self.pos + <span class="number">1</span>
<span class="keyword">local</span> displayString = self:<span class="function-name">scrollText</span>(self.pos, self.displayWidth)
self:<span class="function-name">echo</span>(<span class="string">'&amp;lt;'</span> .. displayString .. <span class="string">'&amp;gt;'</span>)
self.message = self.text
<span class="keyword">end</span>
<a id="151"></a><span class="comment">--- Sets the Chyron from the first position, without changing enabled status
</span><span class="keyword">function</span> Chyron:<span class="function-name">reset</span>()
self.pos = <span class="number">0</span>
<span class="keyword">if</span> <span class="keyword">not</span> self.enabled <span class="keyword">then</span>
self:<span class="function-name">doScroll</span>()
<span class="keyword">end</span>
<span class="keyword">end</span>
<a id="159"></a><span class="comment">--- Stops the Chyron with its current display
</span><span class="keyword">function</span> Chyron:<span class="function-name">pause</span>()
self.enabled = <span class="keyword">false</span>
<span class="keyword">if</span> self.timer <span class="keyword">then</span>
<span class="function-name">killTimer</span>(self.timer)
<span class="keyword">end</span>
<span class="keyword">end</span>
<a id="167"></a><span class="comment">--- Start the Chyron back up from wherever it currently is
</span><span class="keyword">function</span> Chyron:<span class="function-name">start</span>()
self.enabled = <span class="keyword">true</span>
<span class="keyword">if</span> self.timer <span class="keyword">then</span>
<span class="function-name">killTimer</span>(self.timer)
<span class="keyword">end</span>
self.timer = <span class="function-name">tempTimer</span>(self.updateTime / <span class="number">1000</span>, <span class="keyword">function</span>()
self:<span class="function-name">doScroll</span>()
<span class="keyword">end</span>, <span class="keyword">true</span>)
<span class="keyword">end</span>
<span class="comment">--- Change the update time for the Chyron
</span><a id="179"></a><span class="comment">-- @param updateTime number new updateTime in milliseconds
</span><span class="keyword">function</span> Chyron:<span class="function-name">setUpdateTime</span>(updateTime)
self.updateTime = updateTime <span class="keyword">or</span> self.updateTime
<span class="keyword">if</span> self.timer <span class="keyword">then</span>
<span class="function-name">killTimer</span>(self.timer)
<span class="keyword">end</span>
<span class="keyword">if</span> self.enabled <span class="keyword">then</span>
self:<span class="function-name">start</span>()
<span class="keyword">end</span>
<span class="keyword">end</span>
<a id="190"></a><span class="comment">--- Enable autoWidth adjustment
</span><span class="keyword">function</span> Chyron:<span class="function-name">enableAutoWidth</span>()
self.autoWidth = <span class="keyword">true</span>
self:<span class="function-name">setDisplayWidth</span>()
<span class="keyword">end</span>
<a id="196"></a><span class="comment">--- Disable autoWidth adjustment
</span><span class="keyword">function</span> Chyron:<span class="function-name">disableAutoWidth</span>()
self.autoWidth = <span class="keyword">false</span>
<span class="keyword">end</span>
<a id="201"></a><span class="comment">--- Stop the Chyron, and reset it to the original position
</span><span class="keyword">function</span> Chyron:<span class="function-name">stop</span>()
<span class="keyword">if</span> self.timer <span class="keyword">then</span>
<span class="function-name">killTimer</span>(self.timer)
<span class="keyword">end</span>
self.enabled = <span class="keyword">false</span>
self.pos = <span class="number">0</span>
self:<span class="function-name">doScroll</span>()
<span class="keyword">end</span>
<span class="comment">--- Change the text being scrolled on the Chyron
</span><a id="212"></a><span class="comment">-- @param message string message the text you want to have scroll on the Chyron
</span><span class="keyword">function</span> Chyron:<span class="function-name">setMessage</span>(message)
self.text = message
self.pos = <span class="number">0</span>
message = <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s %s "</span>, message, self.delimiter)
<span class="keyword">local</span> t = {}
<span class="keyword">for</span> i = <span class="number">1</span>, #message <span class="keyword">do</span>
t[i] = message:<span class="function-name">sub</span>(i, i)
<span class="keyword">end</span>
self.textTable = t
<span class="keyword">if</span> <span class="keyword">not</span> self.enabled <span class="keyword">then</span>
self:<span class="function-name">doScroll</span>()
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Change the delimiter used to show the beginning and end of the message
</span><a id="228"></a><span class="comment">-- @param delimiter string the new delimiter to use. I recommend using one character.
</span><span class="keyword">function</span> Chyron:<span class="function-name">setDelimiter</span>(delimiter)
self.delimiter = delimiter
<span class="keyword">end</span>
Chyron.parent = Geyser.Label
<span class="global">setmetatable</span>(Chyron, Geyser.Label)
<span class="keyword">return</span> Chyron</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,395 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><strong>echofile.lua</strong></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>echofile.lua</h2>
<pre>
<span class="comment">--- set of functions for echoing files to things. Uses a slightly hacked up version of f-strings for interpolation/templating
</span><span class="comment">-- @module echofile
</span><span class="comment">-- @author Damian Monogue &lt;demonnic@gmail.com&gt;
</span><span class="comment">-- @copyright 2021 Damian Monogue
</span><span class="comment">-- @copyright 2016 Hisham Muhammad (https://github.com/hishamhm/f-strings/blob/master/LICENSE)
</span><span class="comment">-- @license MIT, see LICENSE.lua
</span><span class="keyword">local</span> echofile = {}
<span class="comment">-- following functions fiddled with from https://github.com/hishamhm/f-strings/blob/master/F.lua and https://hisham.hm/2016/01/04/string-interpolation-in-lua/
</span><span class="comment">-- it seems to work :shrug:
</span><span class="keyword">local</span> <span class="global">load</span> = <span class="global">load</span>
<span class="keyword">if</span> _VERSION == <span class="string">"Lua 5.1"</span> <span class="keyword">then</span>
<span class="global">load</span> = <span class="keyword">function</span>(code, name, _, env)
<span class="keyword">local</span> fn, err = <span class="global">loadstring</span>(code, name)
<span class="keyword">if</span> fn <span class="keyword">then</span>
<span class="global">setfenv</span>(fn, env)
<span class="keyword">return</span> fn
<span class="keyword">end</span>
<span class="keyword">return</span> <span class="keyword">nil</span>, err
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">f</span>(str)
<span class="keyword">local</span> outer_env = _ENV <span class="keyword">or</span> <span class="global">getfenv</span>(<span class="number">1</span>)
<span class="keyword">return</span> (str:<span class="function-name">gsub</span>(<span class="string">"%b{}"</span>, <span class="keyword">function</span>(block)
<span class="keyword">local</span> code = block:<span class="function-name">match</span>(<span class="string">"{(.*)}"</span>)
<span class="keyword">local</span> exp_env = {}
<span class="global">setmetatable</span>(exp_env, {
__index = <span class="keyword">function</span>(_, k)
<span class="keyword">local</span> stack_level = <span class="number">5</span>
<span class="keyword">while</span> <span class="global">debug</span>.<span class="function-name">getinfo</span>(stack_level, <span class="string">""</span>) ~= <span class="keyword">nil</span> <span class="keyword">do</span>
<span class="keyword">local</span> i = <span class="number">1</span>
<span class="keyword">repeat</span>
<span class="keyword">local</span> name, value = <span class="global">debug</span>.<span class="function-name">getlocal</span>(stack_level, i)
<span class="keyword">if</span> name == k <span class="keyword">then</span>
<span class="keyword">return</span> value
<span class="keyword">end</span>
i = i + <span class="number">1</span>
<span class="keyword">until</span> name == <span class="keyword">nil</span>
stack_level = stack_level + <span class="number">1</span>
<span class="keyword">end</span>
<span class="keyword">return</span> <span class="global">rawget</span>(outer_env, k)
<span class="keyword">end</span>,
})
<span class="keyword">local</span> fn, err = <span class="global">load</span>(<span class="string">"return "</span> .. code, <span class="string">"expression `"</span> .. code .. <span class="string">"`"</span>, <span class="string">"t"</span>, exp_env)
<span class="keyword">if</span> fn <span class="keyword">then</span>
<span class="keyword">return</span> <span class="global">tostring</span>(<span class="function-name">fn</span>())
<span class="keyword">else</span>
<span class="global">error</span>(err, <span class="number">0</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>))
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">xechoFile</span>(options)
<span class="keyword">local</span> filename = options.filename
<span class="keyword">local</span> window = options.window
<span class="keyword">local</span> func = options.func
<span class="keyword">local</span> functionName = options.functionName
<span class="keyword">local</span> fntype = <span class="global">type</span>(filename)
<span class="keyword">if</span> fntype ~= <span class="string">"string"</span> <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">nil</span>, <span class="function-name">f</span>(<span class="string">"{functionName}: filename as string expected, got {fnType}"</span>)
<span class="keyword">end</span>
<span class="keyword">if</span> <span class="keyword">not</span> <span class="global">io</span>.<span class="function-name">exists</span>(filename) <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">nil</span>, <span class="function-name">f</span>(<span class="string">"{functionName}: {filename} not found"</span>)
<span class="keyword">end</span>
<span class="keyword">local</span> file, err = <span class="global">io</span>.<span class="function-name">open</span>(filename, <span class="string">"r"</span>)
<span class="keyword">if</span> <span class="keyword">not</span> file <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">nil</span>, err
<span class="keyword">end</span>
<span class="keyword">local</span> lines = file:<span class="function-name">read</span>(<span class="string">"*a"</span>)
<span class="keyword">if</span> options.ansi <span class="keyword">then</span>
lines = <span class="function-name">ansi2decho</span>(lines)
<span class="keyword">end</span>
<span class="keyword">if</span> options.filter <span class="keyword">then</span>
lines = <span class="function-name">f</span>(lines)
<span class="keyword">end</span>
<span class="keyword">return</span> <span class="function-name">func</span>(window, lines)
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">getOptions</span>(etype, filter, window, filename)
<span class="keyword">if</span> filename == <span class="keyword">nil</span> <span class="keyword">then</span>
filename = window
window = <span class="string">"main"</span>
<span class="keyword">end</span>
<span class="keyword">local</span> ansi = <span class="keyword">false</span>
<span class="keyword">if</span> etype == <span class="string">"a"</span> <span class="keyword">then</span>
etype = <span class="string">'d'</span>
ansi = <span class="keyword">true</span>
<span class="keyword">end</span>
<span class="keyword">local</span> options = {
filename = filename,
window = window,
func = _G[etype .. <span class="string">"echo"</span>],
functionName = etype .. <span class="string">"echoFile([window,] filename)"</span>,
ansi = ansi,
filter = filter,
}
<span class="keyword">return</span> options
<span class="keyword">end</span>
<span class="comment">--- Takes a string and performs interpolation
</span><span class="comment">--- Uses {} as the delimiter. Expressions will be evaluated
</span><span class="comment">---@param str string: The string to interpolate
</span><span class="comment">---@usage echofile = require("MDK.echofile")
</span><span class="comment">--- echofile.f("{1+1}") -- returns "2"
</span><span class="comment">--- local x = 4
</span><a id="109"></a><span class="comment">--- echofile.f"4+3 = {x+3}" -- returns "4+3 = 7"
</span><span class="keyword">function</span> echofile.<span class="function-name">f</span>(str)
<span class="keyword">return</span> <span class="function-name">f</span>(str)
<span class="keyword">end</span>
<span class="comment">--- reads the contents of a file, converts it to decho and then dechos it
</span><span class="comment">---@param window string: Optional window to cecho to
</span><span class="comment">---@param filename string: Full path to file
</span><span class="comment">---@see echofile.f
</span><span class="comment">---@see echofile.cechoFile
</span><span class="comment">---@usage local ec = require("MDK.echofile")
</span><span class="comment">--- local cechoFile,f = ec.cechoFile, ec.f
</span><span class="comment">--- cechoFile("C:/path/to/file") -- windows1
</span><span class="comment">--- cechoFile("C:\\path\\to\\file") -- windows2
</span><span class="comment">--- cechoFile("/path/to/file") -- Linux/MacOS
</span><a id="124"></a><span class="comment">--- cechoFile("aMiniConsole", f"{getMudletHomeDir()}/myPkgName/helpfile") -- cecho a file from your pkg to a miniconsole
</span><span class="keyword">function</span> echofile.<span class="function-name">aechoFile</span>(window, filename)
<span class="keyword">local</span> options = <span class="function-name">getOptions</span>(<span class="string">"a"</span>, <span class="keyword">false</span>, window, filename)
<span class="keyword">return</span> <span class="function-name">xechoFile</span>(options)
<span class="keyword">end</span>
<span class="comment">--- reads the contents of a file and then cechos it
</span><span class="comment">---@param window string: Optional window to cecho to
</span><span class="comment">---@param filename string: Full path to file
</span><span class="comment">---@see echofile.f
</span><span class="comment">---@see echofile.cechoFilef
</span><span class="comment">---@usage local ec = require("MDK.echofile")
</span><span class="comment">--- local cechoFile,f = ec.cechoFile, ec.f
</span><span class="comment">--- cechoFile("C:/path/to/file") -- windows1
</span><span class="comment">--- cechoFile("C:\\path\\to\\file") -- windows2
</span><span class="comment">--- cechoFile("/path/to/file") -- Linux/MacOS
</span><a id="140"></a><span class="comment">--- cechoFile("aMiniConsole", f"{getMudletHomeDir()}/myPkgName/helpfile") -- cecho a file from your pkg to a miniconsole
</span><span class="keyword">function</span> echofile.<span class="function-name">aechoFilef</span>(window, filename)
<span class="keyword">local</span> options = <span class="function-name">getOptions</span>(<span class="string">"a"</span>, <span class="keyword">true</span>, window, filename)
<span class="keyword">return</span> <span class="function-name">xechoFile</span>(options)
<span class="keyword">end</span>
<span class="comment">--- reads the contents of a file and then cechos it
</span><span class="comment">---@param window string: Optional window to cecho to
</span><span class="comment">---@param filename string: Full path to file
</span><span class="comment">---@see echofile.f
</span><span class="comment">---@usage local ec = require("MDK.echofile")
</span><span class="comment">--- local cechoFile,f = ec.cechoFile, ec.f
</span><span class="comment">--- cechoFile("C:/path/to/file") -- windows1
</span><span class="comment">--- cechoFile("C:\\path\\to\\file") -- windows2
</span><span class="comment">--- cechoFile("/path/to/file") -- Linux/MacOS
</span><a id="155"></a><span class="comment">--- cechoFile("aMiniConsole", f"{getMudletHomeDir()}/myPkgName/helpfile") -- cecho a file from your pkg to a miniconsole
</span><span class="keyword">function</span> echofile.<span class="function-name">cechoFile</span>(window, filename)
<span class="keyword">local</span> options = <span class="function-name">getOptions</span>(<span class="string">"c"</span>, <span class="keyword">false</span>, window, filename)
<span class="keyword">return</span> <span class="function-name">xechoFile</span>(options)
<span class="keyword">end</span>
<span class="comment">--- reads the contents of a file, interpolates it as per echofile.f and then cechos it
</span><span class="comment">---@param window string: Optional window to cecho to
</span><span class="comment">---@param filename string: Full path to file
</span><span class="comment">---@see echofile.f
</span><span class="comment">---@usage local ec = require("MDK.echofile")
</span><span class="comment">--- local cechoFile,f = ec.cechoFile, ec.f
</span><span class="comment">--- cechoFile("C:/path/to/file") -- windows1
</span><span class="comment">--- cechoFile("C:\\path\\to\\file") -- windows2
</span><span class="comment">--- cechoFile("/path/to/file") -- Linux/MacOS
</span><a id="170"></a><span class="comment">--- cechoFile("aMiniConsole", f"{getMudletHomeDir()}/myPkgName/helpfile") -- cecho a file from your pkg to a miniconsole
</span><span class="keyword">function</span> echofile.<span class="function-name">cechoFilef</span>(window, filename)
<span class="keyword">local</span> options = <span class="function-name">getOptions</span>(<span class="string">"c"</span>, <span class="keyword">true</span>, window, filename)
<span class="keyword">return</span> <span class="function-name">xechoFile</span>(options)
<span class="keyword">end</span>
<span class="comment">--- reads the contents of a file and then dechos it
</span><span class="comment">---@param window string: Optional window to decho to
</span><span class="comment">---@param filename string: Full path to file
</span><span class="comment">---@see echofile.f
</span><a id="180"></a><span class="comment">---@see echofile.cechoFile
</span><span class="keyword">function</span> echofile.<span class="function-name">dechoFile</span>(window, filename)
<span class="keyword">local</span> options = <span class="function-name">getOptions</span>(<span class="string">"d"</span>, <span class="keyword">false</span>, window, filename)
<span class="keyword">return</span> <span class="function-name">xechoFile</span>(options)
<span class="keyword">end</span>
<span class="comment">--- reads the contents of a file, interpolates it as per echofile.f and then dechos it
</span><span class="comment">---@param window string: Optional window to decho to
</span><span class="comment">---@param filename string: Full path to file
</span><span class="comment">---@see echofile.f
</span><a id="190"></a><span class="comment">---@see echofile.cechoFile
</span><span class="keyword">function</span> echofile.<span class="function-name">dechoFilef</span>(window, filename)
<span class="keyword">local</span> options = <span class="function-name">getOptions</span>(<span class="string">"d"</span>, <span class="keyword">true</span>, window, filename)
<span class="keyword">return</span> <span class="function-name">xechoFile</span>(options)
<span class="keyword">end</span>
<span class="comment">--- reads the contents of a file and then hechos it
</span><span class="comment">---@param window string: Optional window to hecho to
</span><span class="comment">---@param filename string: Full path to file
</span><span class="comment">---@see echofile.f
</span><a id="200"></a><span class="comment">---@see echofile.cechoFile
</span><span class="keyword">function</span> echofile.<span class="function-name">hechoFile</span>(window, filename)
<span class="keyword">local</span> options = <span class="function-name">getOptions</span>(<span class="string">"h"</span>, <span class="keyword">false</span>, window, filename)
<span class="keyword">return</span> <span class="function-name">xechoFile</span>(options)
<span class="keyword">end</span>
<span class="comment">--- reads the contents of a file, interpolates it as per echofile.f and then hechos it
</span><span class="comment">---@param window string: Optional window to hecho to
</span><span class="comment">---@param filename string: Full path to file
</span><span class="comment">---@see echofile.f
</span><a id="210"></a><span class="comment">---@see echofile.cechoFile
</span><span class="keyword">function</span> echofile.<span class="function-name">hechoFilef</span>(window, filename)
<span class="keyword">local</span> options = <span class="function-name">getOptions</span>(<span class="string">"h"</span>, <span class="keyword">true</span>, window, filename)
<span class="keyword">return</span> <span class="function-name">xechoFile</span>(options)
<span class="keyword">end</span>
<span class="comment">--- reads the contents of a file, interpolates it as per echofile.f and then echos it
</span><span class="comment">---@param window string: Optional window to echo to
</span><span class="comment">---@param filename string: Full path to file
</span><span class="comment">---@see echofile.f
</span><a id="220"></a><span class="comment">---@see echofile.cechoFile
</span><span class="keyword">function</span> echofile.<span class="function-name">echoFile</span>(window, filename)
<span class="keyword">local</span> options = <span class="function-name">getOptions</span>(<span class="string">""</span>, <span class="keyword">false</span>, window, filename)
<span class="keyword">return</span> <span class="function-name">xechoFile</span>(options)
<span class="keyword">end</span>
<span class="comment">--- reads the contents of a file, interpolates it as per echofile.f and then echos it
</span><span class="comment">---@param window string: Optional window to echo to
</span><span class="comment">---@param filename string: Full path to file
</span><span class="comment">---@see echofile.f
</span><a id="230"></a><span class="comment">---@see echofile.cechoFile
</span><span class="keyword">function</span> echofile.<span class="function-name">echoFilef</span>(window, filename)
<span class="keyword">local</span> options = <span class="function-name">getOptions</span>(<span class="string">""</span>, <span class="keyword">true</span>, window, filename)
<span class="keyword">return</span> <span class="function-name">xechoFile</span>(options)
<span class="keyword">end</span>
<span class="comment">--- Adds c/d/h/echoFile functions to Geyser miniconsole and userwindow objects
</span><span class="comment">---@usage require("MDK.echofile").patchGeyser()
</span><span class="comment">--- myMC = Geyser.MiniConsole:new({name = "myMC"})
</span><a id="239"></a><span class="comment">--- myMC:cechoFile(f"{getMudletHomeDir()}/helpfile")
</span><span class="keyword">function</span> echofile.<span class="function-name">patchGeyser</span>()
<span class="keyword">if</span> Geyser.MiniConsole.echoFile <span class="keyword">then</span>
<span class="keyword">return</span>
<span class="keyword">end</span>
<span class="keyword">function</span> Geyser.MiniConsole:<span class="function-name">echoFile</span>(filename)
<span class="keyword">return</span> echofile.<span class="function-name">echoFile</span>(self.name, filename)
<span class="keyword">end</span>
<span class="keyword">function</span> Geyser.MiniConsole:<span class="function-name">echoFilef</span>(filename)
<span class="keyword">return</span> echofile.<span class="function-name">echoFilef</span>(self.name, filename)
<span class="keyword">end</span>
<span class="keyword">function</span> Geyser.MiniConsole:<span class="function-name">aechoFile</span>(filename)
<span class="keyword">return</span> echofile.<span class="function-name">aechoFile</span>(self.name, filename)
<span class="keyword">end</span>
<span class="keyword">function</span> Geyser.MiniConsole:<span class="function-name">aechoFilef</span>(filename)
<span class="keyword">return</span> echofile.<span class="function-name">aechoFilef</span>(self.name, filename)
<span class="keyword">end</span>
<span class="keyword">function</span> Geyser.MiniConsole:<span class="function-name">cechoFile</span>(filename)
<span class="keyword">return</span> echofile.<span class="function-name">cechoFile</span>(self.name, filename)
<span class="keyword">end</span>
<span class="keyword">function</span> Geyser.MiniConsole:<span class="function-name">cechoFilef</span>(filename)
<span class="keyword">return</span> echofile.<span class="function-name">cechoFilef</span>(self.name, filename)
<span class="keyword">end</span>
<span class="keyword">function</span> Geyser.MiniConsole:<span class="function-name">dechoFile</span>(filename)
<span class="keyword">return</span> echofile.<span class="function-name">dechoFile</span>(self.name, filename)
<span class="keyword">end</span>
<span class="keyword">function</span> Geyser.MiniConsole:<span class="function-name">dechoFilef</span>(filename)
<span class="keyword">return</span> echofile.<span class="function-name">dechoFilef</span>(self.name, filename)
<span class="keyword">end</span>
<span class="keyword">function</span> Geyser.MiniConsole:<span class="function-name">hechoFile</span>(filename)
<span class="keyword">return</span> echofile.<span class="function-name">hechoFile</span>(self.name, filename)
<span class="keyword">end</span>
<span class="keyword">function</span> Geyser.MiniConsole:<span class="function-name">hechoFilef</span>(filename)
<span class="keyword">return</span> echofile.<span class="function-name">hechoFilef</span>(self.name, filename)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Installs c/d/h/echoFile and f to the global namespace, and adds functions to Geyser
</span><span class="comment">---@usage require("MDK.echofile").installGlobal()
</span><span class="comment">--- f"{1+2}" -- returns "2"
</span><span class="comment">--- dechoFile(f"{getMudletHomeDir()}/fileWithDechoLines.txt")
</span><span class="comment">--- -- reads contents of fileWithDechoLines.txt from profile directory
</span><a id="281"></a><span class="comment">--- -- and dechos them to the main console
</span><span class="keyword">function</span> echofile.<span class="function-name">installGlobal</span>()
_G.f = f
_G.echoFile = echofile.echoFile
_G.echoFilef = echofile.echoFilef
_G.aechoFile = echofile.aechoFile
_G.aechoFilef = echofile.aechoFilef
_G.cechoFile = echofile.cechoFile
_G.cechoFilef = echofile.cechoFilef
_G.dechoFile = echofile.dechoFile
_G.dechoFilef = echofile.dechoFilef
_G.hechoFile = echofile.hechoFile
_G.hechoFilef = echofile.hechoFilef
echofile.<span class="function-name">patchGeyser</span>()
<span class="keyword">end</span>
<span class="keyword">return</span> echofile</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,366 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><strong>figlet.lua</strong></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>figlet.lua</h2>
<pre>
<span class="comment">--- Figlet
</span><span class="comment">-- A module to read figlet fonts and produce figlet ascii art from text
</span><span class="comment">-- @module figlet
</span><span class="comment">-- @copyright 2010,2011 Nick Gammon
</span><span class="comment">-- @copyright 2022 Damian Monogue
</span><span class="keyword">local</span> Figlet = {}
<span class="comment">--[[
Based on figlet.
FIGlet Copyright 1991, 1993, 1994 Glenn Chappell and Ian Chai
FIGlet Copyright 1996, 1997 John Cowan
Portions written by Paul Burton
Internet: &lt;ianchai@usa.net&gt;
FIGlet, along with the various FIGlet fonts and documentation, is
copyrighted under the provisions of the Artistic License (as listed
in the file "artistic.license" which is included in this package.
--]]</span>
<span class="comment">--[[
Latin-1 codes for German letters, respectively:
LATIN CAPITAL LETTER A WITH DIAERESIS = A-umlaut
LATIN CAPITAL LETTER O WITH DIAERESIS = O-umlaut
LATIN CAPITAL LETTER U WITH DIAERESIS = U-umlaut
LATIN SMALL LETTER A WITH DIAERESIS = a-umlaut
LATIN SMALL LETTER O WITH DIAERESIS = o-umlaut
LATIN SMALL LETTER U WITH DIAERESIS = u-umlaut
LATIN SMALL LETTER SHARP S = ess-zed
--]]</span>
<span class="keyword">local</span> deutsch = {<span class="number">196</span>, <span class="number">214</span>, <span class="number">220</span>, <span class="number">228</span>, <span class="number">246</span>, <span class="number">252</span>, <span class="number">223</span>}
<span class="keyword">local</span> fcharlist = {}
<span class="keyword">local</span> magic, hardblank, charheight, maxlen, smush, cmtlines, ffright2left, smush2
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">readfontchar</span>(fontfile, theord)
<span class="keyword">local</span> t = {}
fcharlist[theord] = t
<span class="comment">-- read each character line
</span>
<span class="comment">--[[
eg.
__ __ @
| \/ |@
| \ / |@
| |\/| |@
| | | |@
|_| |_|@
@
@@
--]]</span>
<span class="keyword">for</span> i = <span class="number">1</span>, charheight <span class="keyword">do</span>
<span class="keyword">local</span> line = <span class="global">assert</span>(fontfile:<span class="function-name">read</span>(<span class="string">"*l"</span>), <span class="string">"Not enough character lines for character "</span> .. theord)
<span class="keyword">local</span> line = <span class="global">string</span>.<span class="function-name">gsub</span>(line, <span class="string">"%s+$"</span>, <span class="string">""</span>) <span class="comment">-- remove trailing spaces
</span> <span class="global">assert</span>(line ~= <span class="string">""</span>, <span class="string">"Unexpected empty line"</span>)
<span class="comment">-- find the last character (eg. @)
</span> <span class="keyword">local</span> endchar = line:<span class="function-name">sub</span>(-<span class="number">1</span>) <span class="comment">-- last character
</span>
<span class="comment">-- trim one or more of the last character from the end
</span> <span class="keyword">while</span> line:<span class="function-name">sub</span>(-<span class="number">1</span>) == endchar <span class="keyword">do</span>
line = line:<span class="function-name">sub</span>(<span class="number">1</span>, #line - <span class="number">1</span>)
<span class="keyword">end</span> <span class="comment">-- while line ends with endchar
</span>
<span class="global">table</span>.<span class="function-name">insert</span>(t, line)
<span class="keyword">end</span> <span class="comment">-- for each line
</span>
<span class="keyword">end</span> <span class="comment">-- readfontchar
</span>
<span class="comment">--- Reads a figlet font file (.flf) into memory and readies it for use by the next figlet
</span><span class="comment">-- These files are cached in memory so that future calls to load a font just read from there.
</span><a id="79"></a><span class="comment">-- @param filename the full path to the file to read the font from
</span><span class="keyword">function</span> Figlet.<span class="function-name">readfont</span>(filename)
<span class="keyword">local</span> fontfile = <span class="global">assert</span>(<span class="global">io</span>.<span class="function-name">open</span>(filename, <span class="string">"r"</span>))
<span class="keyword">local</span> s
fcharlist = {}
<span class="comment">-- header line
</span> s = <span class="global">assert</span>(fontfile:<span class="function-name">read</span>(<span class="string">"*l"</span>), <span class="string">"Empty FIGlet file"</span>)
<span class="comment">-- eg. flf2a$ 8 6 59 15 10 0 24463 153
</span> <span class="comment">-- magic charheight maxlen smush cmtlines ffright2left smush2 ??
</span>
<span class="comment">-- configuration line
</span> magic, hardblank, charheight, maxlen, smush, cmtlines, ffright2left, smush2 = <span class="global">string</span>.<span class="function-name">match</span>(s,
<span class="string">"^(flf2).(.) (%d+) %d+ (%d+) (%-?%d+) (%d+) ?(%d*) ?(%d*) ?(%-?%d*)"</span>)
<span class="global">assert</span>(magic, <span class="string">"Not a FIGlet 2 font file"</span>)
<span class="comment">-- convert to numbers
</span> charheight = <span class="global">tonumber</span>(charheight)
maxlen = <span class="global">tonumber</span>(maxlen)
smush = <span class="global">tonumber</span>(smush)
cmtlines = <span class="global">tonumber</span>(cmtlines)
<span class="comment">-- sanity check
</span> <span class="keyword">if</span> charheight &lt; <span class="number">1</span> <span class="keyword">then</span>
charheight = <span class="number">1</span>
<span class="keyword">end</span> <span class="comment">-- if
</span>
<span class="comment">-- skip comment lines
</span> <span class="keyword">for</span> i = <span class="number">1</span>, cmtlines <span class="keyword">do</span>
<span class="global">assert</span>(fontfile:<span class="function-name">read</span>(<span class="string">"*l"</span>), <span class="string">"Not enough comment lines"</span>)
<span class="keyword">end</span> <span class="comment">-- for
</span>
<span class="comment">-- get characters space to tilde
</span> <span class="keyword">for</span> theord = <span class="global">string</span>.<span class="function-name">byte</span>(<span class="string">' '</span>), <span class="global">string</span>.<span class="function-name">byte</span>(<span class="string">'~'</span>) <span class="keyword">do</span>
<span class="function-name">readfontchar</span>(fontfile, theord)
<span class="keyword">end</span> <span class="comment">-- for
</span>
<span class="comment">-- get 7 German characters
</span> <span class="keyword">for</span> theord = <span class="number">1</span>, <span class="number">7</span> <span class="keyword">do</span>
<span class="function-name">readfontchar</span>(fontfile, deutsch[theord])
<span class="keyword">end</span> <span class="comment">-- for
</span>
<span class="comment">-- get extra ones like:
</span> <span class="comment">-- 0x0395 GREEK CAPITAL LETTER EPSILON
</span> <span class="comment">-- 246 LATIN SMALL LETTER O WITH DIAERESIS
</span>
<span class="keyword">repeat</span>
<span class="keyword">local</span> extra = fontfile:<span class="function-name">read</span>(<span class="string">"*l"</span>)
<span class="keyword">if</span> <span class="keyword">not</span> extra <span class="keyword">then</span>
<span class="keyword">break</span>
<span class="keyword">end</span> <span class="comment">-- if eof
</span>
<span class="keyword">local</span> negative, theord = <span class="global">string</span>.<span class="function-name">match</span>(extra, <span class="string">"^(%-?)0[xX](%x+)"</span>)
<span class="keyword">if</span> theord <span class="keyword">then</span>
theord = <span class="global">tonumber</span>(theord, <span class="number">16</span>)
<span class="keyword">if</span> negative == <span class="string">"-"</span> <span class="keyword">then</span>
theord = -theord
<span class="keyword">end</span> <span class="comment">-- if negative
</span> <span class="keyword">else</span>
theord = <span class="global">string</span>.<span class="function-name">match</span>(extra, <span class="string">"^%d+"</span>)
<span class="global">assert</span>(theord, <span class="string">"Unexpected line:"</span> .. extra)
theord = <span class="global">tonumber</span>(theord)
<span class="keyword">end</span> <span class="comment">-- if
</span>
<span class="function-name">readfontchar</span>(fontfile, theord)
<span class="keyword">until</span> <span class="keyword">false</span>
fontfile:<span class="function-name">close</span>()
<span class="comment">-- remove leading/trailing spaces
</span>
<span class="keyword">for</span> k, v <span class="keyword">in</span> <span class="global">pairs</span>(fcharlist) <span class="keyword">do</span>
<span class="comment">-- first see if all lines have a leading space or a trailing space
</span> <span class="keyword">local</span> leading_space = <span class="keyword">true</span>
<span class="keyword">local</span> trailing_space = <span class="keyword">true</span>
<span class="keyword">for</span> _, line <span class="keyword">in</span> <span class="global">ipairs</span>(v) <span class="keyword">do</span>
<span class="keyword">if</span> line:<span class="function-name">sub</span>(<span class="number">1</span>, <span class="number">1</span>) ~= <span class="string">" "</span> <span class="keyword">then</span>
leading_space = <span class="keyword">false</span>
<span class="keyword">end</span> <span class="comment">-- if
</span> <span class="keyword">if</span> line:<span class="function-name">sub</span>(-<span class="number">1</span>, -<span class="number">1</span>) ~= <span class="string">" "</span> <span class="keyword">then</span>
trailing_space = <span class="keyword">false</span>
<span class="keyword">end</span> <span class="comment">-- if
</span> <span class="keyword">end</span> <span class="comment">-- for each line
</span>
<span class="comment">-- now remove them if necessary
</span> <span class="keyword">for</span> i, line <span class="keyword">in</span> <span class="global">ipairs</span>(v) <span class="keyword">do</span>
<span class="keyword">if</span> leading_space <span class="keyword">then</span>
v[i] = line:<span class="function-name">sub</span>(<span class="number">2</span>)
<span class="keyword">end</span> <span class="comment">-- removing leading space
</span> <span class="keyword">if</span> trailing_space <span class="keyword">then</span>
v[i] = line:<span class="function-name">sub</span>(<span class="number">1</span>, -<span class="number">2</span>)
<span class="keyword">end</span> <span class="comment">-- removing trailing space
</span> <span class="keyword">end</span> <span class="comment">-- for each line
</span> <span class="keyword">end</span> <span class="comment">-- for each character
</span><span class="keyword">end</span> <span class="comment">-- readfont
</span>
<span class="comment">-- add one character to output lines
</span><span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">addchar</span>(which, output, kern, smush)
<span class="keyword">local</span> c = fcharlist[<span class="global">string</span>.<span class="function-name">byte</span>(which)]
<span class="keyword">if</span> <span class="keyword">not</span> c <span class="keyword">then</span>
<span class="keyword">return</span>
<span class="keyword">end</span> <span class="comment">-- if doesn't exist
</span>
<span class="keyword">for</span> i = <span class="number">1</span>, charheight <span class="keyword">do</span>
<span class="keyword">if</span> smush <span class="keyword">and</span> output[i] ~= <span class="string">""</span> <span class="keyword">and</span> which ~= <span class="string">" "</span> <span class="keyword">then</span>
<span class="keyword">local</span> lhc = output[i]:<span class="function-name">sub</span>(-<span class="number">1</span>)
<span class="keyword">local</span> rhc = c[i]:<span class="function-name">sub</span>(<span class="number">1</span>, <span class="number">1</span>)
output[i] = output[i]:<span class="function-name">sub</span>(<span class="number">1</span>, -<span class="number">2</span>) <span class="comment">-- remove last character
</span> <span class="keyword">if</span> rhc ~= <span class="string">" "</span> <span class="keyword">then</span>
output[i] = output[i] .. rhc
<span class="keyword">else</span>
output[i] = output[i] .. lhc
<span class="keyword">end</span>
output[i] = output[i] .. c[i]:<span class="function-name">sub</span>(<span class="number">2</span>)
<span class="keyword">else</span>
output[i] = output[i] .. c[i]
<span class="keyword">end</span> <span class="comment">-- if
</span>
<span class="keyword">if</span> <span class="keyword">not</span> (kern <span class="keyword">or</span> smush) <span class="keyword">or</span> which == <span class="string">" "</span> <span class="keyword">then</span>
output[i] = output[i] .. <span class="string">" "</span>
<span class="keyword">end</span> <span class="comment">-- if
</span> <span class="keyword">end</span> <span class="comment">-- for
</span>
<span class="keyword">end</span> <span class="comment">-- addchar
</span>
<span class="comment">--- Returns a table of lines representing a string as figlet
</span><span class="comment">-- @tparam string s the text to make into a figlet
</span><span class="comment">-- @tparam boolean kern should we reduce spacing
</span><a id="214"></a><span class="comment">-- @tparam boolean smush causes the letters to share edges, condensing it even further
</span><span class="keyword">function</span> Figlet.<span class="function-name">ascii_art</span>(s, kern, smush)
<span class="global">assert</span>(fcharlist)
<span class="global">assert</span>(charheight &gt; <span class="number">0</span>)
<span class="comment">-- make table of output lines
</span> <span class="keyword">local</span> output = {}
<span class="keyword">for</span> i = <span class="number">1</span>, charheight <span class="keyword">do</span>
output[i] = <span class="string">""</span>
<span class="keyword">end</span> <span class="comment">-- for
</span>
<span class="keyword">for</span> i = <span class="number">1</span>, #s <span class="keyword">do</span>
<span class="keyword">local</span> c = s:<span class="function-name">sub</span>(i, i)
<span class="keyword">if</span> c &gt;= <span class="string">" "</span> <span class="keyword">and</span> c &lt; <span class="string">"\127"</span> <span class="keyword">then</span>
<span class="function-name">addchar</span>(c, output, kern, smush)
<span class="keyword">end</span> <span class="comment">-- if in range
</span>
<span class="keyword">end</span> <span class="comment">-- for
</span>
<span class="comment">-- fix up blank character so we can do a string.gsub on it
</span> <span class="keyword">local</span> fixedblank = <span class="global">string</span>.<span class="function-name">gsub</span>(hardblank, <span class="string">"[%%%]%^%-$().[*+?]"</span>, <span class="string">"%%%1"</span>)
<span class="keyword">for</span> i, line <span class="keyword">in</span> <span class="global">ipairs</span>(output) <span class="keyword">do</span>
output[i] = <span class="global">string</span>.<span class="function-name">gsub</span>(line, fixedblank, <span class="string">" "</span>)
<span class="keyword">end</span> <span class="comment">-- for
</span>
<span class="keyword">return</span> output
<span class="keyword">end</span> <span class="comment">-- function ascii_art
</span>
<span class="comment">--- Returns the figlet as a string, rather than a table
</span><span class="comment">-- @tparam string str the string the make into a figlet
</span><span class="comment">-- @tparam boolean kern should we reduce the space between letters?
</span><span class="comment">-- @tparam boolean smush should the letters share edges, further condensing the output?
</span><a id="248"></a><span class="comment">-- @see ascii_art
</span><span class="keyword">function</span> Figlet.<span class="function-name">getString</span>(str, kern, smush)
<span class="keyword">local</span> tbl = Figlet.<span class="function-name">ascii_art</span>(str, kern, smush)
<span class="keyword">return</span> <span class="global">table</span>.<span class="function-name">concat</span>(tbl, <span class="string">"\n"</span>)
<span class="keyword">end</span>
<span class="comment">--- Returns a figlet as a string, with kern set to true.
</span><span class="comment">-- @tparam string str The string to turn into a figlet
</span><a id="256"></a><span class="comment">-- @see getString
</span><span class="keyword">function</span> Figlet.<span class="function-name">getKern</span>(str)
<span class="keyword">return</span> Figlet.<span class="function-name">getString</span>(str, <span class="keyword">true</span>)
<span class="keyword">end</span>
<span class="comment">--- Returns a figlet as a string, with smush set to true.
</span><span class="comment">-- @tparam string str The string to turn into a figlet
</span><a id="263"></a><span class="comment">-- @see getString
</span><span class="keyword">function</span> Figlet.<span class="function-name">getSmush</span>(str)
<span class="keyword">return</span> Figlet.<span class="function-name">getString</span>(str, <span class="keyword">true</span>, <span class="keyword">true</span>)
<span class="keyword">end</span>
<span class="keyword">return</span> Figlet</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,546 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><strong>ftext_spec.lua</strong></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>ftext_spec.lua</h2>
<pre>
<span class="keyword">local</span> ftext = <span class="global">require</span>(<span class="string">"MDK.ftext"</span>)
<span class="function-name">describe</span>(<span class="string">"ftext:"</span>, <span class="keyword">function</span>()
<span class="function-name">describe</span>(<span class="string">"ftext.fText:"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> fText = ftext.fText
<span class="function-name">it</span>(<span class="string">"Should properly center text"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expected = <span class="string">" some text "</span>
<span class="keyword">local</span> actual = <span class="function-name">fText</span>(<span class="string">"some text"</span>, {width = <span class="number">20</span>})
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actual:<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should properly pad left aligned text"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expected = <span class="string">"some text "</span>
<span class="keyword">local</span> actual = <span class="function-name">fText</span>(<span class="string">"some text"</span>, {width = <span class="number">20</span>, alignment = <span class="string">"left"</span>})
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actual:<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should properly pad right aligned text"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expected = <span class="string">" some text"</span>
<span class="keyword">local</span> actual = <span class="function-name">fText</span>(<span class="string">"some text"</span>, {width = <span class="number">20</span>, alignment = <span class="string">"right"</span>})
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actual:<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should wrap lines to the correct length"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> str = <span class="string">"This is a test of the emergency broadcast system. This is only a test"</span>
<span class="keyword">local</span> options = {width = <span class="number">10</span>, alignment = <span class="string">"centered"</span>}
<span class="keyword">local</span> actual = <span class="function-name">fText</span>(str, options)
<span class="keyword">for</span> _, line <span class="keyword">in</span> <span class="global">ipairs</span>(actual:<span class="function-name">split</span>(<span class="string">"\n"</span>)) <span class="keyword">do</span>
<span class="global">assert</span>.<span class="function-name">equals</span>(line:<span class="function-name">len</span>(), <span class="number">10</span>)
<span class="keyword">end</span>
options.width = <span class="number">15</span>
actual = <span class="function-name">fText</span>(str, options)
<span class="keyword">for</span> _, line <span class="keyword">in</span> <span class="global">ipairs</span>(actual:<span class="function-name">split</span>(<span class="string">"\n"</span>)) <span class="keyword">do</span>
<span class="global">assert</span>.<span class="function-name">equals</span>(line:<span class="function-name">len</span>(), <span class="number">15</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>)
<span class="function-name">describe</span>(<span class="string">"non-space spacer character:"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> str = <span class="string">"some text"</span>
<span class="keyword">local</span> options = {width = <span class="string">"20"</span>, alignment = <span class="string">"left"</span>, spacer = <span class="string">"="</span>}
<span class="function-name">it</span>(<span class="string">"Should work with left align"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expected = <span class="string">"some text =========="</span>
<span class="keyword">local</span> actual = <span class="function-name">fText</span>(str, options)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actual:<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should work with right align"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expected = <span class="string">"========== some text"</span>
options.alignment = <span class="string">"right"</span>
<span class="keyword">local</span> actual = <span class="function-name">fText</span>(str, options)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actual:<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should work with center align"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expected = (<span class="string">"==== some text ====="</span>)
options.alignment = <span class="string">"center"</span>
<span class="keyword">local</span> actual = <span class="function-name">fText</span>(str, options)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actual:<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="keyword">end</span>)
<span class="function-name">describe</span>(<span class="string">"nogap option:"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> str = <span class="string">"some text"</span>
<span class="keyword">local</span> options = {width = <span class="string">"20"</span>, alignment = <span class="string">"left"</span>, spacer = <span class="string">"="</span>, nogap = <span class="keyword">true</span>}
<span class="function-name">it</span>(<span class="string">"Should work with left align"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expected = <span class="string">"some text==========="</span>
<span class="keyword">local</span> actual = <span class="function-name">fText</span>(str, options)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actual:<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should work with right align"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expected = <span class="string">"===========some text"</span>
options.alignment = <span class="string">"right"</span>
<span class="keyword">local</span> actual = <span class="function-name">fText</span>(str, options)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actual:<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should work with center align"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expected = <span class="string">"=====some text======"</span>
options.alignment = <span class="string">"center"</span>
<span class="keyword">local</span> actual = <span class="function-name">fText</span>(str, options)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actual:<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="keyword">end</span>)
<span class="function-name">describe</span>(<span class="string">"cap functionality"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> str = <span class="string">"some text"</span>
<span class="keyword">local</span> options = {width = <span class="number">20</span>, spacer = <span class="string">"="</span>, cap = <span class="string">"|"</span>}
<span class="function-name">it</span>(<span class="string">"Should place the spacer outside the cap by default"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expected = <span class="string">"===| some text |===="</span>
<span class="keyword">local</span> actual = <span class="function-name">fText</span>(str, options)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actual:<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should place it inside the cap if inside option is true"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expected = <span class="string">"|=== some text ====|"</span>
options.inside = <span class="keyword">true</span>
<span class="keyword">local</span> actual = <span class="function-name">fText</span>(str, options)
options.inside = <span class="keyword">nil</span>
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actual:<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should mirror certain characters with their opposites"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expected = <span class="string">"===[ some text ]===="</span>
options.mirror = <span class="keyword">true</span>
options.cap = <span class="string">"["</span>
<span class="keyword">local</span> actual = <span class="function-name">fText</span>(str, options)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
options.inside = <span class="keyword">true</span>
expected = <span class="string">"[=== some text ====]"</span>
actual = <span class="function-name">fText</span>(str, options)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
options.inside = <span class="keyword">nil</span>
options.cap = <span class="string">"&lt;"</span>
expected = <span class="string">"===&lt; some text &gt;===="</span>
actual = <span class="function-name">fText</span>(str, options)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
options.cap = <span class="string">"{"</span>
expected = <span class="string">"==={ some text }===="</span>
actual = <span class="function-name">fText</span>(str, options)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
options.cap = <span class="string">"("</span>
expected = <span class="string">"===( some text )===="</span>
actual = <span class="function-name">fText</span>(str, options)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
options.cap = <span class="string">"|"</span>
expected = <span class="string">"===| some text |===="</span>
actual = <span class="function-name">fText</span>(str, options)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="keyword">end</span>)
<span class="keyword">end</span>)
<span class="keyword">end</span>)
<span class="function-name">describe</span>(<span class="string">"ftext.cfText"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> cfText = ftext.cfText
<span class="keyword">local</span> str = <span class="string">"some text"</span>
<span class="keyword">local</span> options = {
width = <span class="number">20</span>,
spacer = <span class="string">"="</span>,
cap = <span class="string">"["</span>,
inside = <span class="keyword">true</span>,
mirror = <span class="keyword">true</span>,
capColor = <span class="string">"&lt;purple&gt;"</span>,
spacerColor = <span class="string">"&lt;green&gt;"</span>,
textColor = <span class="string">"&lt;red&gt;"</span>,
}
<span class="function-name">it</span>(<span class="string">"Should handle cecho colored text"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expectedStripped = <span class="string">"[=== some text ====]"</span>
<span class="keyword">local</span> expected = <span class="string">"&lt;purple&gt;[&lt;reset&gt;&lt;green&gt;===&lt;reset&gt;&lt;red&gt; some text &lt;reset&gt;&lt;green&gt;====&lt;reset&gt;&lt;purple&gt;]&lt;reset&gt;"</span>
<span class="keyword">local</span> actual = <span class="function-name">cfText</span>(str, options)
<span class="keyword">local</span> actualStripped = <span class="function-name">cecho2string</span>(actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(expectedStripped, actualStripped)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actualStripped:<span class="function-name">len</span>())
expectedStripped = <span class="string">"===[ some text ]===="</span>
expected = <span class="string">"&lt;green&gt;===&lt;reset&gt;&lt;purple&gt;[&lt;reset&gt;&lt;red&gt; some text &lt;reset&gt;&lt;purple&gt;]&lt;reset&gt;&lt;green&gt;====&lt;reset&gt;"</span>
options.inside = <span class="keyword">false</span>
actual = <span class="function-name">cfText</span>(str, options)
actualStripped = <span class="function-name">cecho2string</span>(actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(expectedStripped, actualStripped)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actualStripped:<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should wrap cecho lines to the correct length"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> str = <span class="string">"This is a test of the emergency broadcast system. This is only a test"</span>
<span class="keyword">local</span> options = {width = <span class="number">10</span>, alignment = <span class="string">"centered"</span>}
<span class="keyword">local</span> actual = <span class="function-name">cfText</span>(str, options)
<span class="keyword">for</span> _, line <span class="keyword">in</span> <span class="global">ipairs</span>(actual:<span class="function-name">split</span>(<span class="string">"\n"</span>)) <span class="keyword">do</span>
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="function-name">cecho2string</span>(line):<span class="function-name">len</span>(), <span class="number">10</span>)
<span class="keyword">end</span>
options.width = <span class="number">15</span>
actual = <span class="function-name">cfText</span>(str, options)
<span class="keyword">for</span> _, line <span class="keyword">in</span> <span class="global">ipairs</span>(actual:<span class="function-name">split</span>(<span class="string">"\n"</span>)) <span class="keyword">do</span>
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="function-name">cecho2string</span>(line):<span class="function-name">len</span>(), <span class="number">15</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>)
<span class="keyword">end</span>)
<span class="function-name">describe</span>(<span class="string">"ftext.dfText"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> dfText = ftext.dfText
<span class="keyword">local</span> str = <span class="string">"some text"</span>
<span class="keyword">local</span> options = {
width = <span class="number">20</span>,
spacer = <span class="string">"="</span>,
cap = <span class="string">"["</span>,
inside = <span class="keyword">true</span>,
mirror = <span class="keyword">true</span>,
capColor = <span class="string">"&lt;160,32,240&gt;"</span>,
spacerColor = <span class="string">"&lt;0,255,0&gt;"</span>,
textColor = <span class="string">"&lt;255,0,0&gt;"</span>,
}
<span class="function-name">it</span>(<span class="string">"Should handle decho colored text"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expectedStripped = <span class="string">"[=== some text ====]"</span>
<span class="keyword">local</span> expected = <span class="string">"&lt;160,32,240&gt;[&lt;r&gt;&lt;0,255,0&gt;===&lt;r&gt;&lt;255,0,0&gt; some text &lt;r&gt;&lt;0,255,0&gt;====&lt;r&gt;&lt;160,32,240&gt;]&lt;r&gt;"</span>
<span class="keyword">local</span> actual = <span class="function-name">dfText</span>(str, options)
<span class="keyword">local</span> actualStripped = <span class="function-name">decho2string</span>(actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(expectedStripped, actualStripped)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actualStripped:<span class="function-name">len</span>())
expectedStripped = <span class="string">"===[ some text ]===="</span>
expected = <span class="string">"&lt;0,255,0&gt;===&lt;r&gt;&lt;160,32,240&gt;[&lt;r&gt;&lt;255,0,0&gt; some text &lt;r&gt;&lt;160,32,240&gt;]&lt;r&gt;&lt;0,255,0&gt;====&lt;r&gt;"</span>
options.inside = <span class="keyword">false</span>
actual = <span class="function-name">dfText</span>(str, options)
actualStripped = <span class="function-name">decho2string</span>(actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(expectedStripped, actualStripped)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actualStripped:<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should wrap decho lines to the correct length"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> str = <span class="string">"This is a test of the emergency broadcast system. This is only a test"</span>
<span class="keyword">local</span> options = {width = <span class="number">10</span>, alignment = <span class="string">"centered"</span>}
<span class="keyword">local</span> actual = <span class="function-name">dfText</span>(str, options)
<span class="keyword">for</span> _, line <span class="keyword">in</span> <span class="global">ipairs</span>(actual:<span class="function-name">split</span>(<span class="string">"\n"</span>)) <span class="keyword">do</span>
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="function-name">decho2string</span>(line):<span class="function-name">len</span>(), <span class="number">10</span>)
<span class="keyword">end</span>
options.width = <span class="number">15</span>
actual = <span class="function-name">dfText</span>(str, options)
<span class="keyword">for</span> _, line <span class="keyword">in</span> <span class="global">ipairs</span>(actual:<span class="function-name">split</span>(<span class="string">"\n"</span>)) <span class="keyword">do</span>
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="function-name">decho2string</span>(line):<span class="function-name">len</span>(), <span class="number">15</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>)
<span class="keyword">end</span>)
<span class="function-name">describe</span>(<span class="string">"ftext.hfText"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> hfText = ftext.hfText
<span class="keyword">local</span> str = <span class="string">"some text"</span>
<span class="keyword">local</span> options = {
width = <span class="number">20</span>,
spacer = <span class="string">"="</span>,
cap = <span class="string">"["</span>,
inside = <span class="keyword">true</span>,
mirror = <span class="keyword">true</span>,
capColor = <span class="string">"#a020f0"</span>,
spacerColor = <span class="string">"#00ff00"</span>,
textColor = <span class="string">"#ff0000"</span>,
}
<span class="function-name">it</span>(<span class="string">"Should handle hecho colored text"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expectedStripped = <span class="string">"[=== some text ====]"</span>
<span class="keyword">local</span> expected = <span class="string">"#a020f0[#r#00ff00===#r#ff0000 some text #r#00ff00====#r#a020f0]#r"</span>
<span class="keyword">local</span> actual = <span class="function-name">hfText</span>(str, options)
<span class="keyword">local</span> actualStripped = <span class="function-name">hecho2string</span>(actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(expectedStripped, actualStripped)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actualStripped:<span class="function-name">len</span>())
expectedStripped = <span class="string">"===[ some text ]===="</span>
expected = <span class="string">"#00ff00===#r#a020f0[#r#ff0000 some text #r#a020f0]#r#00ff00====#r"</span>
options.inside = <span class="keyword">false</span>
actual = <span class="function-name">hfText</span>(str, options)
actualStripped = <span class="function-name">hecho2string</span>(actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(expectedStripped, actualStripped)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actualStripped:<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should wrap hecho lines to the correct length"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> str = <span class="string">"This is a test of the emergency broadcast system. This is only a test"</span>
<span class="keyword">local</span> options = {width = <span class="number">10</span>, alignment = <span class="string">"centered"</span>}
<span class="keyword">local</span> actual = <span class="function-name">hfText</span>(str, options)
<span class="keyword">for</span> _, line <span class="keyword">in</span> <span class="global">ipairs</span>(actual:<span class="function-name">split</span>(<span class="string">"\n"</span>)) <span class="keyword">do</span>
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="function-name">hecho2string</span>(line):<span class="function-name">len</span>(), <span class="number">10</span>)
<span class="keyword">end</span>
options.width = <span class="number">15</span>
actual = <span class="function-name">hfText</span>(str, options)
<span class="keyword">for</span> _, line <span class="keyword">in</span> <span class="global">ipairs</span>(actual:<span class="function-name">split</span>(<span class="string">"\n"</span>)) <span class="keyword">do</span>
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="function-name">hecho2string</span>(line):<span class="function-name">len</span>(), <span class="number">15</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>)
<span class="keyword">end</span>)
<span class="function-name">describe</span>(<span class="string">"ftext.TextFormatter"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> tf = ftext.TextFormatter
<span class="keyword">local</span> str = <span class="string">"some text"</span>
<span class="keyword">local</span> formatter
<span class="function-name">before_each</span>(<span class="keyword">function</span>()
formatter = tf:<span class="function-name">new</span>({width = <span class="number">20</span>})
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should let you change width using :setWidth"</span>, <span class="keyword">function</span>()
formatter:<span class="function-name">setWidth</span>(<span class="number">80</span>)
<span class="keyword">local</span> expected =
<span class="string">"&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt; some text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;"</span>
<span class="keyword">local</span> actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">80</span>, <span class="function-name">cecho2string</span>(actual):<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should format for cecho by default"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expected = <span class="string">"&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt; some text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;"</span>
<span class="keyword">local</span> expectedStripped = <span class="string">" some text "</span>
<span class="keyword">local</span> actual = formatter:<span class="function-name">format</span>(str)
<span class="keyword">local</span> actualStripped = <span class="function-name">cecho2string</span>(actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="global">assert</span>.<span class="function-name">equals</span>(expectedStripped, actualStripped)
<span class="global">assert</span>.<span class="function-name">equals</span>(<span class="number">20</span>, actualStripped:<span class="function-name">len</span>())
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should produce the same line as cfText given the same options"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expected = ftext.<span class="function-name">cfText</span>(str, formatter.options)
<span class="keyword">local</span> actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should let you change type using :setType"</span>, <span class="keyword">function</span>()
formatter:<span class="function-name">setType</span>(<span class="string">"h"</span>)
<span class="keyword">local</span> expected = ftext.<span class="function-name">hfText</span>(str, formatter.options)
<span class="keyword">local</span> actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
formatter:<span class="function-name">setType</span>(<span class="string">"d"</span>)
expected = ftext.<span class="function-name">dfText</span>(str, formatter.options)
actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
formatter:<span class="function-name">setType</span>(<span class="string">""</span>)
expected = ftext.<span class="function-name">fText</span>(str, formatter.options)
actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should default to word wrapping, and let you change it with :setWrap"</span>, <span class="keyword">function</span>()
formatter:<span class="function-name">setWidth</span>(<span class="number">10</span>)
<span class="keyword">local</span> expected =
<span class="string">"&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt; some &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;\n&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt; text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;"</span>
<span class="keyword">local</span> actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
expected = <span class="string">"&lt;white&gt;&lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt; some text &lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt;&lt;reset&gt;"</span>
formatter:<span class="function-name">setWrap</span>(<span class="keyword">false</span>)
actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should allow you to change the cap using :setCap"</span>, <span class="keyword">function</span>()
formatter:<span class="function-name">setCap</span>(<span class="string">'|'</span>)
<span class="keyword">local</span> expected = <span class="string">"&lt;white&gt;|&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt; some text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;|&lt;reset&gt;"</span>
<span class="keyword">local</span> actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should allow you to change the capColor using :setCapColor"</span>, <span class="keyword">function</span>()
formatter:<span class="function-name">setCapColor</span>(<span class="string">'&lt;red&gt;'</span>)
<span class="keyword">local</span> expected = <span class="string">"&lt;red&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt; some text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;red&gt;&lt;reset&gt;"</span>
<span class="keyword">local</span> actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should allow you to change the spacer color using :setSpacerColor"</span>, <span class="keyword">function</span>()
formatter:<span class="function-name">setSpacerColor</span>(<span class="string">"&lt;red&gt;"</span>)
<span class="keyword">local</span> expected = <span class="string">"&lt;white&gt;&lt;reset&gt;&lt;red&gt; &lt;reset&gt;&lt;white&gt; some text &lt;reset&gt;&lt;red&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;"</span>
<span class="keyword">local</span> actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should allow you to change the text color using :setTextColor"</span>, <span class="keyword">function</span>()
formatter:<span class="function-name">setTextColor</span>(<span class="string">"&lt;red&gt;"</span>)
<span class="keyword">local</span> expected = <span class="string">"&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;red&gt; some text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;"</span>
<span class="keyword">local</span> actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should allow you to change the spacer using :setSpacer"</span>, <span class="keyword">function</span>()
formatter:<span class="function-name">setSpacer</span>(<span class="string">"="</span>)
<span class="comment">-- local expected = "&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt; some text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;"
</span> <span class="keyword">local</span> expected = <span class="string">"&lt;white&gt;&lt;reset&gt;&lt;white&gt;====&lt;reset&gt;&lt;white&gt; some text &lt;reset&gt;&lt;white&gt;=====&lt;reset&gt;&lt;white&gt;&lt;reset&gt;"</span>
<span class="keyword">local</span> actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should allow you to set the alignment using :setAlignment"</span>, <span class="keyword">function</span>()
formatter:<span class="function-name">setAlignment</span>(<span class="string">"left"</span>)
<span class="keyword">local</span> expected = <span class="string">"&lt;white&gt;&lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt;some text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;"</span>
<span class="keyword">local</span> actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
formatter:<span class="function-name">setAlignment</span>(<span class="string">"right"</span>)
expected = <span class="string">"&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt; some text&lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt;&lt;reset&gt;"</span>
actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should allow you to change the 'inside' option using :setInside"</span>, <span class="keyword">function</span>()
formatter:<span class="function-name">setInside</span>(<span class="keyword">false</span>)
<span class="keyword">local</span> expected = <span class="string">"&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt; some text &lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;"</span>
<span class="keyword">local</span> actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should allow you to change the mirror option using :setMirror"</span>, <span class="keyword">function</span>()
formatter:<span class="function-name">setCap</span>(<span class="string">'&lt;'</span>)
formatter:<span class="function-name">setMirror</span>(<span class="keyword">true</span>)
<span class="keyword">local</span> expected = <span class="string">"&lt;white&gt;&lt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt; some text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&gt;&lt;reset&gt;"</span>
<span class="keyword">local</span> actual = formatter:<span class="function-name">format</span>(str)
<span class="global">assert</span>.<span class="function-name">equal</span>(expected, actual)
<span class="keyword">end</span>)
<span class="keyword">end</span>)
<span class="function-name">describe</span>(<span class="string">"ftext.TableMaker"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> TableMaker = ftext.TableMaker
<span class="keyword">local</span> tm
<span class="function-name">before_each</span>(<span class="keyword">function</span>()
tm = TableMaker:<span class="function-name">new</span>()
tm:<span class="function-name">addColumn</span>({name = <span class="string">"col1"</span>, width = <span class="number">15</span>, textColor = <span class="string">"&lt;red&gt;"</span>})
tm:<span class="function-name">addColumn</span>({name = <span class="string">"col2"</span>, width = <span class="number">15</span>, textColor = <span class="string">"&lt;blue&gt;"</span>})
tm:<span class="function-name">addColumn</span>({name = <span class="string">"col3"</span>, width = <span class="number">15</span>, textColor = <span class="string">"&lt;green&gt;"</span>})
tm:<span class="function-name">addRow</span>({<span class="string">"some text"</span>, <span class="string">"more text"</span>, <span class="string">"other text"</span>})
tm:<span class="function-name">addRow</span>({<span class="string">"little text"</span>, <span class="string">"bigger text"</span>, <span class="string">"text"</span>})
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"Should assemble a formatted table given default options"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expected = <span class="string">[[&lt;white&gt;*************************************************&lt;reset&gt;
&lt;white&gt;*&lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;red&gt; col1 &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt;|&lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;blue&gt; col2 &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt;|&lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;green&gt; col3 &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt;*&lt;reset&gt;
&lt;white&gt;*&lt;reset&gt;&lt;white&gt;---------------&lt;reset&gt;&lt;white&gt;|&lt;reset&gt;&lt;white&gt;---------------&lt;reset&gt;&lt;white&gt;|&lt;reset&gt;&lt;white&gt;---------------&lt;reset&gt;&lt;white&gt;*&lt;reset&gt;
&lt;white&gt;*&lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;red&gt; some text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt;|&lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;blue&gt; more text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt;|&lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;green&gt; other text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt;*&lt;reset&gt;
&lt;white&gt;*&lt;reset&gt;&lt;white&gt;---------------&lt;reset&gt;&lt;white&gt;|&lt;reset&gt;&lt;white&gt;---------------&lt;reset&gt;&lt;white&gt;|&lt;reset&gt;&lt;white&gt;---------------&lt;reset&gt;&lt;white&gt;*&lt;reset&gt;
&lt;white&gt;*&lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;red&gt; little text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt;|&lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;blue&gt; bigger text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt;|&lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;green&gt; text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;&lt;white&gt;*&lt;reset&gt;
&lt;white&gt;*************************************************&lt;reset&gt;
]]</span>
<span class="keyword">local</span> actual = tm:<span class="function-name">assemble</span>()
<span class="global">assert</span>.<span class="function-name">equals</span>(expected, actual)
<span class="keyword">end</span>)
<span class="function-name">it</span>(<span class="string">"TableMaker:getCell should return the text and formatter for a specific cell"</span>, <span class="keyword">function</span>()
<span class="keyword">local</span> expectedText = <span class="string">"more text"</span>
<span class="keyword">local</span> expectedFormatter = tm.columns[<span class="number">2</span>]
<span class="keyword">local</span> actualText, actualFormatter = tm:<span class="function-name">getCell</span>(<span class="number">1</span>, <span class="number">2</span>)
<span class="global">assert</span>.<span class="function-name">equals</span>(expectedText, actualText)
<span class="global">assert</span>.<span class="function-name">equals</span>(expectedFormatter, actualFormatter)
<span class="keyword">local</span> expectedFormatted = <span class="string">"&lt;white&gt;&lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;blue&gt; more text &lt;reset&gt;&lt;white&gt; &lt;reset&gt;&lt;white&gt;&lt;reset&gt;"</span>
<span class="keyword">local</span> actualFormatted = actualFormatter:<span class="function-name">format</span>(actualText)
<span class="global">assert</span>.<span class="function-name">equals</span>(expectedFormatted, actualFormatted)
<span class="keyword">end</span>)
<span class="keyword">end</span>)
<span class="keyword">end</span>)</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,441 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><strong>gradientmaker.lua</strong></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>gradientmaker.lua</h2>
<pre>
<span class="comment">--- Module which provides for creating color gradients for your text.
</span><span class="comment">-- Original functions found on &lt;a href="https://forums.lusternia.com/discussion/3261/anyone-want-text-gradients"&gt;the Lusternia Forums&lt;/a&gt;
</span><span class="comment">-- &lt;br&gt; I added functions to work with hecho.
</span><span class="comment">-- &lt;br&gt; I also made performance enhancements by storing already calculated gradients after first use for the session and only including the colorcode in the returned string if the color changed.
</span><span class="comment">-- @module GradientMaker
</span><span class="comment">-- @author Sylphas on the Lusternia forums
</span><span class="comment">-- @author Damian Monogue &lt;demonnic@gmail.com&gt;
</span><span class="comment">-- @copyright 2018 Sylphas
</span><span class="comment">-- @copyright 2020 Damian Monogue
</span><span class="keyword">local</span> GradientMaker = {}
<span class="keyword">local</span> gradient_table = {}
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">_clamp</span>(num1, num2, num3)
<span class="keyword">local</span> smaller = <span class="global">math</span>.<span class="function-name">min</span>(num2, num3)
<span class="keyword">local</span> larger = <span class="global">math</span>.<span class="function-name">max</span>(num2, num3)
<span class="keyword">local</span> minimum = <span class="global">math</span>.<span class="function-name">max</span>(<span class="number">0</span>, smaller)
<span class="keyword">local</span> maximum = <span class="global">math</span>.<span class="function-name">min</span>(<span class="number">255</span>, larger)
<span class="keyword">return</span> <span class="global">math</span>.<span class="function-name">min</span>(maximum, <span class="global">math</span>.<span class="function-name">max</span>(minimum, num1))
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">_gradient</span>(length, rgb1, rgb2)
<span class="global">assert</span>(length &gt; <span class="number">0</span>)
<span class="keyword">if</span> length == <span class="number">1</span> <span class="keyword">then</span>
<span class="keyword">return</span> {rgb1}
<span class="keyword">elseif</span> length == <span class="number">2</span> <span class="keyword">then</span>
<span class="keyword">return</span> {rgb1, rgb2}
<span class="keyword">else</span>
<span class="keyword">local</span> step = {}
<span class="keyword">for</span> color = <span class="number">1</span>, <span class="number">3</span> <span class="keyword">do</span>
step[color] = (rgb2[color] - rgb1[color]) / (length - <span class="number">2</span>)
<span class="keyword">end</span>
<span class="keyword">local</span> gradient = {rgb1}
<span class="keyword">for</span> iter = <span class="number">1</span>, length - <span class="number">2</span> <span class="keyword">do</span>
gradient[iter + <span class="number">1</span>] = {}
<span class="keyword">for</span> color = <span class="number">1</span>, <span class="number">3</span> <span class="keyword">do</span>
gradient[iter + <span class="number">1</span>][color] = <span class="global">math</span>.<span class="function-name">ceil</span>(rgb1[color] + (iter * step[color]))
<span class="keyword">end</span>
<span class="keyword">end</span>
gradient[length] = rgb2
<span class="keyword">for</span> index, color <span class="keyword">in</span> <span class="global">ipairs</span>(gradient) <span class="keyword">do</span>
<span class="keyword">for</span> iter = <span class="number">1</span>, <span class="number">3</span> <span class="keyword">do</span>
gradient[index][iter] = <span class="function-name">_clamp</span>(color[iter], rgb1[iter], rgb2[iter])
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> gradient
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">gradient_to_string</span>(gradient)
<span class="keyword">local</span> gradstring = <span class="string">""</span>
<span class="keyword">for</span> _, grad <span class="keyword">in</span> <span class="global">ipairs</span>(gradient) <span class="keyword">do</span>
<span class="keyword">local</span> nodestring = <span class="string">""</span>
<span class="keyword">for</span> _, col <span class="keyword">in</span> <span class="global">ipairs</span>(grad) <span class="keyword">do</span>
nodestring = <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s%03d"</span>, nodestring, col)
<span class="keyword">end</span>
<span class="keyword">if</span> _ == <span class="number">1</span> <span class="keyword">then</span>
gradstring = nodestring
<span class="keyword">else</span>
gradstring = gradstring .. <span class="string">"|"</span> .. nodestring
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> gradstring
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">_gradients</span>(length, ...)
<span class="keyword">local</span> arg = {...}
<span class="keyword">local</span> argkey = <span class="function-name">gradient_to_string</span>(arg)
<span class="keyword">local</span> gradients_for_length = gradient_table[length]
<span class="keyword">if</span> <span class="keyword">not</span> gradients_for_length <span class="keyword">then</span>
gradient_table[length] = {}
gradients_for_length = gradient_table[length]
<span class="keyword">end</span>
<span class="keyword">local</span> grads = gradients_for_length[argkey]
<span class="keyword">if</span> grads <span class="keyword">then</span>
<span class="keyword">return</span> grads
<span class="keyword">end</span>
<span class="keyword">if</span> #arg == <span class="number">0</span> <span class="keyword">then</span>
gradients_for_length[argkey] = {}
<span class="keyword">return</span> {}
<span class="keyword">elseif</span> #arg == <span class="number">1</span> <span class="keyword">then</span>
gradients_for_length[argkey] = arg[<span class="number">1</span>]
<span class="keyword">return</span> arg[<span class="number">1</span>]
<span class="keyword">elseif</span> #arg == <span class="number">2</span> <span class="keyword">then</span>
gradients_for_length[argkey] = <span class="function-name">_gradient</span>(length, arg[<span class="number">1</span>], arg[<span class="number">2</span>])
<span class="keyword">return</span> gradients_for_length[argkey]
<span class="keyword">else</span>
<span class="keyword">local</span> quotient = <span class="global">math</span>.<span class="function-name">floor</span>(length / (#arg - <span class="number">1</span>))
<span class="keyword">local</span> remainder = length % (#arg - <span class="number">1</span>)
<span class="keyword">local</span> gradients = {}
<span class="keyword">for</span> section = <span class="number">1</span>, #arg - <span class="number">1</span> <span class="keyword">do</span>
<span class="keyword">local</span> slength = quotient
<span class="keyword">if</span> section &lt;= remainder <span class="keyword">then</span>
slength = slength + <span class="number">1</span>
<span class="keyword">end</span>
<span class="keyword">local</span> gradient = <span class="function-name">_gradient</span>(slength, arg[section], arg[section + <span class="number">1</span>])
<span class="keyword">for</span> _, rgb <span class="keyword">in</span> <span class="global">ipairs</span>(gradient) <span class="keyword">do</span>
<span class="global">table</span>.<span class="function-name">insert</span>(gradients, rgb)
<span class="keyword">end</span>
<span class="keyword">end</span>
gradients_for_length[argkey] = gradients
<span class="keyword">return</span> gradients
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">_color_name</span>(rgb)
<span class="keyword">local</span> least_distance = <span class="global">math</span>.huge
<span class="keyword">local</span> cname = <span class="string">""</span>
<span class="keyword">for</span> name, color <span class="keyword">in</span> <span class="global">pairs</span>(color_table) <span class="keyword">do</span>
<span class="keyword">local</span> color_distance = <span class="global">math</span>.<span class="function-name">sqrt</span>((color[<span class="number">1</span>] - rgb[<span class="number">1</span>]) ^ <span class="number">2</span> + (color[<span class="number">2</span>] - rgb[<span class="number">2</span>]) ^ <span class="number">2</span> + (color[<span class="number">3</span>] - rgb[<span class="number">3</span>]) ^ <span class="number">2</span>)
<span class="keyword">if</span> color_distance &lt; least_distance <span class="keyword">then</span>
least_distance = color_distance
cname = name
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> cname
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">errorIfEmpty</span>(text, funcName)
<span class="global">assert</span>(#text &gt; <span class="number">0</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s: you passed in an empty string, and I cannot make a gradient out of an empty string"</span>, funcName))
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">dgradient_table</span>(text, ...)
<span class="function-name">errorIfEmpty</span>(text, <span class="string">"dgradient_table"</span>)
<span class="keyword">local</span> gradients = <span class="function-name">_gradients</span>(#text, ...)
<span class="keyword">local</span> dgrads = {}
<span class="keyword">for</span> character = <span class="number">1</span>, #text <span class="keyword">do</span>
<span class="global">table</span>.<span class="function-name">insert</span>(dgrads, {gradients[character], text:<span class="function-name">sub</span>(character, character)})
<span class="keyword">end</span>
<span class="keyword">return</span> dgrads
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">dgradient</span>(text, ...)
<span class="function-name">errorIfEmpty</span>(text, <span class="string">"dgradient"</span>)
<span class="keyword">local</span> gradients = <span class="function-name">_gradients</span>(#text, ...)
<span class="keyword">local</span> dgrad = <span class="string">""</span>
<span class="keyword">local</span> current_color = <span class="string">""</span>
<span class="keyword">for</span> character = <span class="number">1</span>, #text <span class="keyword">do</span>
<span class="keyword">local</span> new_color = <span class="string">"&lt;"</span> .. <span class="global">table</span>.<span class="function-name">concat</span>(gradients[character], <span class="string">","</span>) .. <span class="string">"&gt;"</span>
<span class="keyword">local</span> char = text:<span class="function-name">sub</span>(character, character)
<span class="keyword">if</span> new_color == current_color <span class="keyword">then</span>
dgrad = dgrad .. char
<span class="keyword">else</span>
dgrad = dgrad .. new_color .. char
current_color = new_color
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> dgrad
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">cgradient_table</span>(text, ...)
<span class="function-name">errorIfEmpty</span>(text, <span class="string">"cgradient_table"</span>)
<span class="keyword">local</span> gradients = <span class="function-name">_gradients</span>(#text, ...)
<span class="keyword">local</span> cgrads = {}
<span class="keyword">for</span> character = <span class="number">1</span>, #text <span class="keyword">do</span>
<span class="global">table</span>.<span class="function-name">insert</span>(cgrads, {<span class="function-name">_color_name</span>(gradients[character]), text:<span class="function-name">sub</span>(character, character)})
<span class="keyword">end</span>
<span class="keyword">return</span> cgrads
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">cgradient</span>(text, ...)
<span class="function-name">errorIfEmpty</span>(text, <span class="string">"cgradient"</span>)
<span class="keyword">local</span> gradients = <span class="function-name">_gradients</span>(#text, ...)
<span class="keyword">local</span> cgrad = <span class="string">""</span>
<span class="keyword">local</span> current_color = <span class="string">""</span>
<span class="keyword">for</span> character = <span class="number">1</span>, #text <span class="keyword">do</span>
<span class="keyword">local</span> new_color = <span class="string">"&lt;"</span> .. <span class="function-name">_color_name</span>(gradients[character]) .. <span class="string">"&gt;"</span>
<span class="keyword">local</span> char = text:<span class="function-name">sub</span>(character, character)
<span class="keyword">if</span> new_color == current_color <span class="keyword">then</span>
cgrad = cgrad .. char
<span class="keyword">else</span>
cgrad = cgrad .. new_color .. char
current_color = new_color
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> cgrad
<span class="keyword">end</span>
<span class="keyword">local</span> hex = Geyser.Color.hex
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">hgradient_table</span>(text, ...)
<span class="function-name">errorIfEmpty</span>(text, <span class="string">"hgradient_table"</span>)
<span class="keyword">local</span> grads = <span class="function-name">_gradients</span>(#text, ...)
<span class="keyword">local</span> hgrads = {}
<span class="keyword">for</span> character = <span class="number">1</span>, #text <span class="keyword">do</span>
<span class="global">table</span>.<span class="function-name">insert</span>(hgrads, {<span class="function-name">hex</span>(<span class="global">unpack</span>(grads[character])):<span class="function-name">sub</span>(<span class="number">2</span>, -<span class="number">1</span>), text:<span class="function-name">sub</span>(character, character)})
<span class="keyword">end</span>
<span class="keyword">return</span> hgrads
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">hgradient</span>(text, ...)
<span class="function-name">errorIfEmpty</span>(text, <span class="string">"hgradient"</span>)
<span class="keyword">local</span> grads = <span class="function-name">_gradients</span>(#text, ...)
<span class="keyword">local</span> hgrads = <span class="string">""</span>
<span class="keyword">local</span> current_color = <span class="string">""</span>
<span class="keyword">for</span> character = <span class="number">1</span>, #text <span class="keyword">do</span>
<span class="keyword">local</span> new_color = <span class="function-name">hex</span>(<span class="global">unpack</span>(grads[character]))
<span class="keyword">local</span> char = text:<span class="function-name">sub</span>(character, character)
<span class="keyword">if</span> new_color == current_color <span class="keyword">then</span>
hgrads = hgrads .. char
<span class="keyword">else</span>
hgrads = hgrads .. new_color .. char
current_color = new_color
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> hgrads
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">color_name</span>(...)
<span class="keyword">local</span> arg = {...}
<span class="keyword">if</span> #arg == <span class="number">1</span> <span class="keyword">then</span>
<span class="keyword">return</span> <span class="function-name">_color_name</span>(arg[<span class="number">1</span>])
<span class="keyword">elseif</span> #arg == <span class="number">3</span> <span class="keyword">then</span>
<span class="keyword">return</span> <span class="function-name">_color_name</span>(arg)
<span class="keyword">else</span>
<span class="keyword">local</span> errmsg =
<span class="string">"color_name: You must pass either a table of r,g,b values: color_name({r,g,b})\nor the three r,g,b values separately: color_name(r,g,b)"</span>
<span class="global">error</span>(errmsg)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Returns the closest color name to a given r,g,b color
</span><span class="comment">-- @param r The red component. Can also pass the full color as a table, IE { 255, 0, 0 }
</span><span class="comment">-- @param g The green component. If you pass the color as a table as noted above, this param should be empty
</span><span class="comment">-- @param b the blue components. If you pass the color as a table as noted above, this param should be empty
</span><span class="comment">-- @usage
</span><span class="comment">-- closest_color = GradientMaker.color_name(128,200,30) -- returns "ansi_149"
</span><a id="228"></a><span class="comment">-- closest_color = GradientMaker.color_name({128, 200, 30}) -- this is functionally equivalent to the first one
</span><span class="keyword">function</span> GradientMaker.<span class="function-name">color_name</span>(...)
<span class="keyword">return</span> <span class="function-name">color_name</span>(...)
<span class="keyword">end</span>
<span class="comment">--- Returns the text, with the defined color gradients applied and formatted for us with decho. Usage example below produces the following text
</span><span class="comment">-- &lt;br&gt;&lt;img src="https://demonnic.github.io/mdk/images/dechogradient.png" alt="dgradient example"&gt;
</span><span class="comment">-- @tparam string text The text you want to apply the color gradients to
</span><span class="comment">-- @param first_color The color you want it to start at. Table of colors in { r, g, b } format
</span><span class="comment">-- @param second_color The color you want the gradient to transition to first. Table of colors in { r, g, b } format
</span><span class="comment">-- @param next_color Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
</span><span class="comment">-- @see cgradient
</span><span class="comment">-- @see hgradient
</span><span class="comment">-- @usage
</span><span class="comment">-- decho(GradientMaker.dgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {255,0,0}, {255,128,0}, {255,255,0}, {0,255,0}, {0,255,255}, {0,128,255}, {128,0,255}))
</span><span class="comment">-- decho(GradientMaker.dgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {255,0,0}, {0,0,255}))
</span><a id="244"></a><span class="comment">-- decho(GradientMaker.dgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {50,50,50}, {0,255,0}, {50,50,50}))
</span><span class="keyword">function</span> GradientMaker.<span class="function-name">dgradient</span>(text, ...)
<span class="keyword">return</span> <span class="function-name">dgradient</span>(text, ...)
<span class="keyword">end</span>
<span class="comment">--- Returns the text, with the defined color gradients applied and formatted for us with cecho. Usage example below produces the following text
</span><span class="comment">-- &lt;br&gt;&lt;img src="https://demonnic.github.io/mdk/images/cechogradient.png" alt="cgradient example"&gt;
</span><span class="comment">-- @tparam string text The text you want to apply the color gradients to
</span><span class="comment">-- @param first_color The color you want it to start at. Table of colors in { r, g, b } format
</span><span class="comment">-- @param second_color The color you want the gradient to transition to first. Table of colors in { r, g, b } format
</span><span class="comment">-- @param next_color Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
</span><span class="comment">-- @see dgradient
</span><span class="comment">-- @see hgradient
</span><span class="comment">-- @usage
</span><span class="comment">-- cecho(GradientMaker.cgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {255,0,0}, {255,128,0}, {255,255,0}, {0,255,0}, {0,255,255}, {0,128,255}, {128,0,255}))
</span><span class="comment">-- cecho(GradientMaker.cgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {255,0,0}, {0,0,255}))
</span><a id="260"></a><span class="comment">-- cecho(GradientMaker.cgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {50,50,50}, {0,255,0}, {50,50,50}))
</span><span class="keyword">function</span> GradientMaker.<span class="function-name">cgradient</span>(text, ...)
<span class="keyword">return</span> <span class="function-name">cgradient</span>(text, ...)
<span class="keyword">end</span>
<span class="comment">--- Returns the text, with the defined color gradients applied and formatted for us with hecho. Usage example below produces the following text
</span><span class="comment">-- &lt;br&gt;&lt;img src="https://demonnic.github.io/mdk/images/hechogradient.png" alt="hgradient example"&gt;
</span><span class="comment">-- @tparam string text The text you want to apply the color gradients to
</span><span class="comment">-- @param first_color The color you want it to start at. Table of colors in { r, g, b } format
</span><span class="comment">-- @param second_color The color you want the gradient to transition to first. Table of colors in { r, g, b } format
</span><span class="comment">-- @param next_color Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
</span><span class="comment">-- @see cgradient
</span><span class="comment">-- @see dgradient
</span><span class="comment">-- @usage
</span><span class="comment">-- hecho(GradientMaker.hgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {255,0,0}, {255,128,0}, {255,255,0}, {0,255,0}, {0,255,255}, {0,128,255}, {128,0,255}))
</span><span class="comment">-- hecho(GradientMaker.hgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {255,0,0}, {0,0,255}))
</span><a id="276"></a><span class="comment">-- hecho(GradientMaker.hgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {50,50,50}, {0,255,0}, {50,50,50}))
</span><span class="keyword">function</span> GradientMaker.<span class="function-name">hgradient</span>(text, ...)
<span class="keyword">return</span> <span class="function-name">hgradient</span>(text, ...)
<span class="keyword">end</span>
<span class="comment">--- Returns a table, each element of which is a table, the first element of which is the color name to use and the character which should be that color
</span><span class="comment">-- @tparam string text The text you want to apply the color gradients to
</span><span class="comment">-- @param first_color The color you want it to start at. Table of colors in { r, g, b } format
</span><span class="comment">-- @param second_color The color you want the gradient to transition to first. Table of colors in { r, g, b } format
</span><span class="comment">-- @param next_color Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
</span><a id="286"></a><span class="comment">-- @see cgradient
</span><span class="keyword">function</span> GradientMaker.<span class="function-name">cgradient_table</span>(text, ...)
<span class="keyword">return</span> <span class="function-name">cgradient_table</span>(text, ...)
<span class="keyword">end</span>
<span class="comment">--- Returns a table, each element of which is a table, the first element of which is the color({r,g,b} format) to use and the character which should be that color
</span><span class="comment">-- @tparam string text The text you want to apply the color gradients to
</span><span class="comment">-- @param first_color The color you want it to start at. Table of colors in { r, g, b } format
</span><span class="comment">-- @param second_color The color you want the gradient to transition to first. Table of colors in { r, g, b } format
</span><span class="comment">-- @param next_color Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
</span><a id="296"></a><span class="comment">-- @see dgradient
</span><span class="keyword">function</span> GradientMaker.<span class="function-name">dgradient_table</span>(text, ...)
<span class="keyword">return</span> <span class="function-name">dgradient_table</span>(text, ...)
<span class="keyword">end</span>
<span class="comment">--- Returns a table, each element of which is a table, the first element of which is the color(in hex) to use and the second element of which is the character which should be that color
</span><span class="comment">-- @tparam string text The text you want to apply the color gradients to
</span><span class="comment">-- @param first_color The color you want it to start at. Table of colors in { r, g, b } format
</span><span class="comment">-- @param second_color The color you want the gradient to transition to first. Table of colors in { r, g, b } format
</span><span class="comment">-- @param next_color Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
</span><a id="306"></a><span class="comment">-- @see hgradient
</span><span class="keyword">function</span> GradientMaker.<span class="function-name">hgradient_table</span>(text, ...)
<span class="keyword">return</span> <span class="function-name">hgradient_table</span>(text, ...)
<span class="keyword">end</span>
<span class="comment">--- Creates global copies of the c/d/hgradient(_table) functions and color_name for use without accessing the module table
</span><span class="comment">-- @usage
</span><span class="comment">-- GradientMaker.install_global()
</span><a id="314"></a><span class="comment">-- cecho(cgradient(...)) -- use cgradient directly now
</span><span class="keyword">function</span> GradientMaker.<span class="function-name">install_global</span>()
_G[<span class="string">"hgradient"</span>] = <span class="keyword">function</span>(...)
<span class="keyword">return</span> <span class="function-name">hgradient</span>(...)
<span class="keyword">end</span>
_G[<span class="string">"dgradient"</span>] = <span class="keyword">function</span>(...)
<span class="keyword">return</span> <span class="function-name">dgradient</span>(...)
<span class="keyword">end</span>
_G[<span class="string">"cgradient"</span>] = <span class="keyword">function</span>(...)
<span class="keyword">return</span> <span class="function-name">cgradient</span>(...)
<span class="keyword">end</span>
_G[<span class="string">"hgradient_table"</span>] = <span class="keyword">function</span>(...)
<span class="keyword">return</span> <span class="function-name">hgradient_table</span>(...)
<span class="keyword">end</span>
_G[<span class="string">"dgradient_table"</span>] = <span class="keyword">function</span>(...)
<span class="keyword">return</span> <span class="function-name">dgradient_table</span>(...)
<span class="keyword">end</span>
_G[<span class="string">"cgradient_table"</span>] = <span class="keyword">function</span>(...)
<span class="keyword">return</span> <span class="function-name">cgradient_table</span>(...)
<span class="keyword">end</span>
_G[<span class="string">"color_name"</span>] = <span class="keyword">function</span>(...)
<span class="keyword">return</span> <span class="function-name">color_name</span>(...)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">-- function GradientMaker.getGrads()
</span><span class="comment">-- return gradient_table
</span><span class="comment">-- end
</span>
<span class="keyword">return</span> GradientMaker</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,560 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><strong>loggingconsole.lua</strong></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>loggingconsole.lua</h2>
<pre>
<span class="comment">--- MiniConsole with logging capabilities
</span><span class="comment">-- @classmod LoggingConsole
</span><span class="comment">-- @author Damian Monogue &lt;demonnic@gmail.com&gt;
</span><span class="comment">-- @copyright 2020 Damian Monogue
</span><span class="comment">-- @license MIT, see LICENSE.lua
</span><span class="keyword">local</span> homedir = <span class="function-name">getMudletHomeDir</span>():<span class="function-name">gsub</span>(<span class="string">"\\", "</span>/<span class="string">")
local pathOfThisFile = (...):match("</span>(.-)[^%.]+$<span class="string">")
local dt = require(pathOfThisFile .. "</span><span class="function-name">demontools</span><span class="string">")
local exists, htmlHeader, htmlHeaderPattern = dt.exists, dt.htmlHeader, dt.htmlHeaderPattern
local LoggingConsole = {log = true, logFormat = "</span><span class="function-name">h</span><span class="string">", path = "</span>|h/log/consoleLogs/|y/|m/|d/<span class="string">", fileName = "</span>|n.|<span class="function-name">e</span><span class="string">"}
--- Creates and returns a new LoggingConsole.
-- @param cons table of constraints. Includes all the valid Geyser.MiniConsole constraints, plus
-- &lt;table class="</span><span class="function-name">tg</span><span class="string">"&gt;
-- &lt;thead&gt;
-- &lt;tr&gt;
-- &lt;th&gt;option name&lt;/th&gt;
-- &lt;th&gt;description&lt;/th&gt;
-- &lt;th&gt;default&lt;/th&gt;
-- &lt;/tr&gt;
-- &lt;/thead&gt;
-- &lt;tbody&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;log&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;Should the miniconsole be logging?&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;true&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;logFormat&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;"</span><span class="function-name">h</span><span class="string">" for html, "</span><span class="function-name">t</span><span class="string">" for plaintext, "</span><span class="function-name">l</span><span class="string">" for log (with ansi)&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;h&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;path&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;The path the file lives in. It is templated.&lt;br&gt;|h is replaced by the profile homedir.&lt;br&gt;|y by 4 digit year.&lt;br&gt;|m by 2 digit month&lt;br&gt;|d by 2 digit day&lt;br&gt;|n by the name constraint&lt;br&gt;|e by the file extension (html for h logType, log for others)&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;"</span>|h/log/consoleLogs/|y/|m/|d/<span class="string">"&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;fileName&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;The name of the log file. It is templated, same as path above&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;"</span>|n.|<span class="function-name">e</span><span class="string">"&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;/tbody&gt;
-- &lt;/table&gt;
-- @param container the container for the console
-- @usage
-- local LoggingConsole = require("</span>MDK.<span class="function-name">loggingconsole</span><span class="string">")
-- myLoggingConsole = LoggingConsole:new({
-- name = "</span>my logging <span class="function-name">console</span><span class="string">",
-- x = 0,
-- y = 0,
-- height = 200,
-- width = 400,
-- }) -- just like making a miniconsole, really
function LoggingConsole:new(cons, container)
cons = cons or {}
local consType = type(cons)
assert(consType == "</span><span class="global">table</span><span class="string">", "</span>LoggingConsole:<span class="function-name">new</span>(cons, container): cons must be a valid <span class="global">table</span> of constraints. Got: <span class="string">" .. consType)
local me = Geyser.MiniConsole:new(cons, container)
setmetatable(me, self)
self.__index = self
return me
end
--- Returns the file extension of the logfile this console will log to
function LoggingConsole:getExtension()
local extension = "</span><span class="function-name">log</span><span class="string">"
if table.contains({"</span><span class="function-name">h</span><span class="string">", "</span><span class="function-name">html</span><span class="string">"}, self.logFormat) then
extension = "</span><span class="function-name">html</span><span class="string">"
end
return extension
end
--- Returns a string with all templated items replaced
---@tparam string str The templated string to transform
---@local
function LoggingConsole:transformTemplate(str)
local ttbl = getTime()
local year = ttbl.year
local month = string.format("</span>%<span class="number">02</span><span class="function-name">d</span><span class="string">", ttbl.month)
local day = string.format("</span>%<span class="number">02</span><span class="function-name">d</span><span class="string">", ttbl.day)
local name = self.name
local extension = self:getExtension()
str = str:gsub("</span>|<span class="function-name">h</span><span class="string">", homedir)
str = str:gsub("</span>|<span class="function-name">y</span><span class="string">", year)
str = str:gsub("</span>|<span class="function-name">m</span><span class="string">", month)
str = str:gsub("</span>|<span class="function-name">d</span><span class="string">", day)
str = str:gsub("</span>|<span class="function-name">n</span><span class="string">", name)
str = str:gsub("</span>|<span class="function-name">e</span><span class="string">", extension)
return str
end
--- Returns the path to the logfile for this console
function LoggingConsole:getPath()
local path = self:transformTemplate(self.path)
if not path:ends("</span>/<span class="string">") then
path = path .. "</span>/<span class="string">"
end
return path
end
--- Sets the path to use for the log file.
-- @param path the path to put the log file in. It is templated.&lt;br&gt;|h is replaced by the profile homedir.&lt;br&gt;|y by 4 digit year.&lt;br&gt;|m by 2 digit month&lt;br&gt;|d by 2 digit day&lt;br&gt;|n by the name constraint&lt;br&gt;|e by the file extension (html for h logType, log for others)
function LoggingConsole:setPath(path)
self.path = path
end
--- Returns the filename for the logfile for this console
function LoggingConsole:getFileName()
local fileName = self:transformTemplate(self.fileName)
fileName = fileName:gsub("</span>[&lt;&gt;:<span class="string">'\"/\\?*]", "_")
return fileName
end
--- Sets the fileName to use for the log file.
-- @param fileName the fileName to use for the logfile. It is templated.&lt;br&gt;|h is replaced by the profile homedir.&lt;br&gt;|y by 4 digit year.&lt;br&gt;|m by 2 digit month&lt;br&gt;|d by 2 digit day&lt;br&gt;|n by the name constraint&lt;br&gt;|e by the file extension (html for h logType, log for others)
function LoggingConsole:setFileName(fileName)
self.fileName = fileName
end
--- Returns the pull path and filename for the logfile for this console
function LoggingConsole:getFullFilename()
local path = self:getPath()
local fileName = self:getFileName()
local fullPath = path .. fileName
fullPath = fullPath:gsub("|", "_")
return fullPath
end
--- Turns logging for this console on
function LoggingConsole:enableLogging()
self.log = true
end
--- Turns logging for this console off
function LoggingConsole:disableLogging()
self.log = false
end
--- Creates the path for the logfile for this console if necessary
---@local
function LoggingConsole:createPathIfNotExists()
local path = self:transformTemplate(self.path)
if not path:ends("/") then
path = path .. "/"
end
if not exists(path) then
local ok, err = dt.mkdir_p(path)
if not ok then
assert(false, "Could not create directory for log files:" .. path .. "\n Reason was: " .. err)
end
end
return true
end
--- Handles actually writing to the log file
---@local
function LoggingConsole:writeToLog(str)
local fileName = self:getFullFilename()
self:createPathIfNotExists()
if self:getExtension() == "html" then
if not io.exists(fileName) then
str = htmlHeader .. str
end
str = str
end
local file, err = io.open(fileName, "a")
if not file then
echo(err .. "\n")
return
end
file:write(str)
file:close()
end
local parent = Geyser.MiniConsole
--- Handler function which does the lifting for c/d/h/echo and appendBuffer to provide the logfile writing functionality
---@param str the string to echo. Use "" for appends
---@param etype the type of echo. Valid are "c", "d", "h", "e", and "a"
---@param log Allows you to override the default behaviour defined by the .log property. Pass true to definitely log, false to skip logging.
---@local
function LoggingConsole:xEcho(str, etype, log)
if log == nil then
log = self.log
end
local logStr
local logType = self.logFormat
if logType:find("h") then
logType = "h"
elseif logType ~= "t" then
logType = "l"
end
if etype == "d" then -- decho
if logType == "h" then
logStr = dt.decho2html(str)
elseif logType == "t" then
logStr = dt.decho2string(str)
else
logStr = dt.decho2ansi(str)
end
parent.decho(self, str)
elseif etype == "c" then -- cecho
if logType == "h" then
logStr = dt.cecho2html(str)
elseif logType == "t" then
logStr = dt.cecho2string(str)
else
logStr = dt.cecho2ansi(str)
end
parent.cecho(self, str)
elseif etype == "h" then -- hecho
if logType == "h" then
logStr = dt.hecho2html(str)
elseif logType == "t" then
logStr = dt.hecho2string(str)
else
logStr = dt.hecho2ansi(str)
end
parent.hecho(self, str)
elseif etype == "a" then -- append
str = dt.append2decho()
str = str .. "\n"
if logType == "h" then
logStr = dt.decho2html(str)
elseif logType == "t" then
logStr = dt.decho2string(str)
else
logStr = dt.decho2ansi(str)
end
parent.appendBuffer(self)
elseif etype == "e" then -- echo
if logType == "h" then
logStr = dt.decho2html(str)
else
logStr = str
end
parent.echo(self, str)
end
if log then
self:writeToLog(logStr)
end
end
--- Does the actual lifting of echoing links/popups
-- @local
function LoggingConsole:xEchoLink(text, lType, command, hint, useFormat, log)
if log == nil then
log = self.log
end
local logStr = ""
if lType:starts("c") then
if self.logFormat == "h" then
logStr = dt.cecho2html(text)
elseif self.logFormat == "l" then
logStr = dt.cecho2ansi(text)
elseif self.logFormat == "t" then
logStr = dt.cecho2string(text)
end
if lType:ends("p") then
parent.cechoPopup(self, text, command, hint, useFormat)
else
parent.cechoLink(self, text, command, hint, useFormat)
end
elseif lType:starts("d") then
if self.logFormat == "h" then
logStr = dt.decho2html(text)
elseif self.logFormat == "l" then
logStr = dt.decho2ansi(text)
elseif self.logFormat == "t" then
logStr = dt.decho2string(text)
end
if lType:ends("p") then
parent.dechoPopup(self, text, command, hint, useFormat)
else
parent.dechoLink(self, text, command, hint, useFormat)
end
elseif lType:starts("h") then
if self.logFormat == "h" then
logStr = dt.hecho2html(text)
elseif self.logFormat == "l" then
logStr = dt.hecho2ansi(text)
elseif self.logFormat == "t" then
logStr = dt.hecho2string(text)
end
if lType:ends("p") then
parent.hechoPopup(self, text, command, hint, useFormat)
else
parent.hechoLink(self, text, command, hint, useFormat)
end
elseif lType:starts("e") then
logStr = text
if lType:ends("p") then
parent.echoPopup(self, text, command, hint, useFormat)
else
parent.echoLink(self, text, command, hint, useFormat)
end
end
if log then
self:writeToLog(logStr)
end
end
--- cechoLink for LoggingConsole
-- @param text the text to use for the link
-- @param command the command to send when the link is clicked, as text. IE [[send("sleep")]]
-- @param hint A tooltip which is displayed when the mouse is over the link
-- @param log Should we log this line? Defaults to self.log if not passed.
function LoggingConsole:cechoLink(text, command, hint, log)
self:xEchoLink(text, "c", command, hint, true, log)
end
--- dechoLink for LoggingConsole
-- @param text the text to use for the link
-- @param command the command to send when the link is clicked, as text. IE [[send("sleep")]]
-- @param hint A tooltip which is displayed when the mouse is over the link
-- @param log Should we log this line? Defaults to self.log if not passed.
function LoggingConsole:dechoLink(text, command, hint, log)
self:xEchoLink(text, "d", command, hint, true, log)
end
--- hechoLink for LoggingConsole
-- @param text the text to use for the link
-- @param command the command to send when the link is clicked, as text. IE [[send("sleep")]]
-- @param hint A tooltip which is displayed when the mouse is over the link
-- @param log Should we log this line? Defaults to self.log if not passed.
function LoggingConsole:hechoLink(text, command, hint, log)
self:xEchoLink(text, "h", command, hint, true, log)
end
--- echoLink for LoggingConsole
-- @param text the text to use for the link
-- @param command the command to send when the link is clicked, as text. IE [[send("sleep")]]
-- @param hint A tooltip which is displayed when the mouse is over the link
-- @param useCurrentFormat If set to true, will look like the text around it. If false it will be blue and underline.
-- @param log Should we log this line? Defaults to self.log if not passed. If you want to pass this you must pass in useCurrentFormat
-- @usage myLoggingConsole:echoLink("This is a link!", [[send("sleep")]], "sleep") -- text "This is a link" will send("sleep") when clicked and be blue w/ underline. Defaut log behaviour (self.log)
-- @usage myLoggingConsole:echoLink("This is a link!", [[send("sleep")]], "sleep", false, false) -- same as above, but forces it not to log regardless of self.log setting
-- @usage myLoggingConsole:echoLink("This is a link!", [[send("sleep")]], "sleep", true, true) -- same as above, but forces it to log regardless of self.log setting and the text will look like anything else echoed to the console.
function LoggingConsole:echoLink(text, command, hint, useCurrentFormat, log)
self:xEchoLink(text, "e", command, hint, useCurrentFormat, log)
end
--- cechoPopup for LoggingConsole
-- @param text the text to use for the link
-- @param commands the commands to send when the popup is activated, as table. IE {[[send("sleep")]], [[send("stand")]]}
-- @param hints A tooltip which is displayed when the mouse is over the link. IE {{"sleep", "stand"}}
-- @param log Should we log this line? Defaults to self.log if not passed.
function LoggingConsole:cechoPopup(text, commands, hints, log)
self:xEchoLink(text, "cp", commands, hints, true, log)
end
--- dechoPopup for LoggingConsole
-- @param text the text to use for the link
-- @param commands the commands to send when the popup is activated, as table. IE {[[send("sleep")]], [[send("stand")]]}
-- @param hints A tooltip which is displayed when the mouse is over the link. IE {{"sleep", "stand"}}
-- @param log Should we log this line? Defaults to self.log if not passed.
function LoggingConsole:dechoPopup(text, commands, hints, log)
self:xEchoLink(text, "dp", commands, hints, true, log)
end
--- hechoPopup for LoggingConsole
-- @param text the text to use for the link
-- @param commands the commands to send when the popup is activated, as table. IE {[[send("sleep")]], [[send("stand")]]}
-- @param hints A tooltip which is displayed when the mouse is over the link. IE {{"sleep", "stand"}}
-- @param log Should we log this line? Defaults to self.log if not passed.
function LoggingConsole:hechoPopup(text, commands, hints, log)
self:xEchoLink(text, "hp", commands, hints, true, log)
end
--- echoPopup for LoggingConsole
-- @param text the text to use for the link
-- @param commands the commands to send when the popup is activated, as table. IE {[[send("sleep")]], [[send("stand")]]}
-- @param hints A tooltip which is displayed when the mouse is over the link. IE {{"sleep", "stand"}}
-- @param useCurrentFormat If set to true, will look like the text around it. If false it will be blue and underline.
-- @param log Should we log this line? Defaults to self.log if not passed. If you want to pass this you must pass in useCurrentFormat
-- @usage myLoggingConsole:echoPopup("This is a link!", {[[send("sleep")]], [[send("stand")]], {"sleep", "stand"}) -- text "This is a link" will send("sleep") when clicked and be blue w/ underline. Defaut log behaviour (self.log)
-- @usage myLoggingConsole:echoPopup("This is a link!", {[[send("sleep")]], [[send("stand")]], {"sleep", "stand"}, false, false) -- same as above, but forces it not to log regardless of self.log setting
-- @usage myLoggingConsole:echoPopup("This is a link!", {[[send("sleep")]], [[send("stand")]], {"sleep", "stand"}, true, true) -- same as above, but forces it to log regardless of self.log setting and the text will look like anything else echoed to the console.
function LoggingConsole:echoPopup(text, commands, hints, useCurrentFormat, log)
self:xEchoLink(text, "ep", commands, hints, useCurrentFormat, log)
end
--- Append copy()ed text to the console
-- @param log should we log this?
function LoggingConsole:appendBuffer(log)
self:xEcho("", "a", log)
end
--- Append copy()ed text to the console
-- @param log should we log this?
function LoggingConsole:append(log)
self:xEcho("", "a", log)
end
--- echo'</span>s a <span class="global">string</span> to the console.
<span class="comment">-- @param str the string to echo
</span><span class="comment">-- @param log should this be logged? Used to override the .log constraint
</span><span class="keyword">function</span> LoggingConsole:<span class="function-name">echo</span>(str, log)
self:<span class="function-name">xEcho</span>(str, <span class="string">"e"</span>, log)
<span class="keyword">end</span>
<span class="comment">--- hecho's a string to the console.
</span><span class="comment">-- @param str the string to hecho
</span><span class="comment">-- @param log should this be logged? Used to override the .log constraint
</span><span class="keyword">function</span> LoggingConsole:<span class="function-name">hecho</span>(str, log)
self:<span class="function-name">xEcho</span>(str, <span class="string">"h"</span>, log)
<span class="keyword">end</span>
<span class="comment">--- decho's a string to the console.
</span><span class="comment">-- @param str the string to decho
</span><span class="comment">-- @param log should this be logged? Used to override the .log constraint
</span><span class="keyword">function</span> LoggingConsole:<span class="function-name">decho</span>(str, log)
self:<span class="function-name">xEcho</span>(str, <span class="string">"d"</span>, log)
<span class="keyword">end</span>
<span class="comment">--- cecho's a string to the console.
</span><span class="comment">-- @param str the string to cecho
</span><span class="comment">-- @param log should this be logged? Used to override the .log constraint
</span><span class="keyword">function</span> LoggingConsole:<span class="function-name">cecho</span>(str, log)
self:<span class="function-name">xEcho</span>(str, <span class="string">"c"</span>, log)
<span class="keyword">end</span>
<span class="comment">--- Replays the last X lines from the console's log file, if it exists
</span><span class="comment">-- @param numberOfLines The number of lines to replay from the end of the file
</span><span class="keyword">function</span> LoggingConsole:<span class="function-name">replay</span>(numberOfLines)
<span class="keyword">local</span> fileName = self:<span class="function-name">getFullFilename</span>()
<span class="keyword">if</span> <span class="keyword">not</span> <span class="function-name">exists</span>(fileName) <span class="keyword">then</span>
<span class="keyword">return</span>
<span class="keyword">end</span>
<span class="keyword">local</span> file = <span class="global">io</span>.<span class="function-name">open</span>(fileName, <span class="string">"r"</span>)
<span class="keyword">local</span> lines = file:<span class="function-name">read</span>(<span class="string">"*a"</span>)
<span class="keyword">if</span> self:<span class="function-name">getExtension</span>() == <span class="string">"html"</span> <span class="keyword">then</span>
<span class="keyword">for</span> _, line <span class="keyword">in</span> <span class="global">ipairs</span>(htmlHeaderPattern:<span class="function-name">split</span>(<span class="string">"\n"</span>)) <span class="keyword">do</span>
<span class="keyword">if</span> line ~= <span class="string">""</span> <span class="keyword">then</span>
lines = lines:<span class="function-name">gsub</span>(line .. <span class="string">"\n"</span>, <span class="string">""</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>
lines = dt.<span class="function-name">html2decho</span>(lines)
<span class="keyword">else</span>
lines = <span class="function-name">ansi2decho</span>(lines)
<span class="keyword">end</span>
<span class="keyword">local</span> linesTbl = lines:<span class="function-name">split</span>(<span class="string">"\n"</span>)
<span class="keyword">local</span> result
<span class="keyword">if</span> #linesTbl &lt;= numberOfLines <span class="keyword">then</span><a id="56"></a>
result = lines
<span class="keyword">else</span>
result = <span class="string">""</span>
<span class="keyword">local</span> start = #linesTbl - numberOfLines
<span class="keyword">for</span> index, str <span class="keyword">in</span> <span class="global">ipairs</span>(linesTbl) <span class="keyword">do</span>
<span class="keyword">if</span> index &gt;= start <span class="keyword">then</span>
result = <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s\n%s"</span>, result, str)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
self:<span class="function-name">decho</span>(result, <span class="keyword">false</span>)<a id="67"></a>
<span class="keyword">end</span>
<span class="global">setmetatable</span>(LoggingConsole, parent)
<span class="keyword">return</span> LoggingConsole</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,555 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><strong>loginator.lua</strong></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>loginator.lua</h2>
<pre>
<span class="comment">--- Loginator creates an object which allows you to log things to file at
</span><span class="comment">-- various severity levels, with the ability to only log items above a specific
</span><span class="comment">-- severity to file.
</span><span class="comment">-- @classmod Loginator
</span><span class="comment">-- @author Damian Monogue &lt;demonnic@gmail.com&gt;
</span><span class="comment">-- @copyright 2021 Damian Monogue
</span><span class="comment">-- @license MIT, see LICENSE.lua
</span><span class="keyword">local</span> Loginator = {
format = <span class="string">"h"</span>,
name = <span class="string">"logname"</span>,
fileNameTemplate = <span class="string">"|p/log/Loginator/|y-|M-|d-|n.|e"</span>,
entryTemplate = <span class="string">"|y-|M-|d |h:|m:|s.|x [|c|l|r] |t"</span>,
level = <span class="string">"warn"</span>,
bgColor = <span class="string">"black"</span>,
fontSize = <span class="number">12</span>,
fgColor = <span class="string">"white"</span>,
}
<span class="keyword">local</span> levelColors = {<span class="global">error</span> = <span class="string">"red"</span>, warn = <span class="string">"DarkOrange"</span>, info = <span class="string">"ForestGreen"</span>, <span class="global">debug</span> = <span class="string">"ansi_yellow"</span>}
<span class="keyword">local</span> loggerLevels = {<span class="global">error</span> = <span class="number">1</span>, warn = <span class="number">2</span>, info = <span class="number">3</span>, <span class="global">debug</span> = <span class="number">4</span>}
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">exists</span>(path)
<span class="keyword">local</span> ok, err, code = <span class="global">os</span>.<span class="function-name">rename</span>(path, path)
<span class="keyword">if</span> <span class="keyword">not</span> ok <span class="keyword">and</span> code == <span class="number">13</span> <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">true</span>
<span class="keyword">end</span>
<span class="keyword">return</span> ok, err
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">isWindows</span>()
<span class="keyword">return</span> <span class="global">package</span>.config:<span class="function-name">sub</span>(<span class="number">1</span>, <span class="number">1</span>) == <span class="string">[[\]]</span>
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">mkdir_p</span>(path)
path = path:<span class="function-name">gsub</span>(<span class="string">"\\", "</span>/<span class="string">")
local pathTbl = path:split("</span>/<span class="string">")
local cwd = "</span>/<span class="string">"
if isWindows() then
cwd = "</span><span class="string">"
end
for index, dirName in ipairs(pathTbl) do
if index == 1 then
cwd = cwd .. dirName
else
cwd = cwd .. "</span>/<span class="string">" .. dirName
cwd = cwd:gsub("</span>//<span class="string">", "</span>/<span class="string">")
end
if not table.contains({"</span>/<span class="string">", "</span>C:<span class="string">"}, cwd) and not exists(cwd) then
local ok, err = lfs.mkdir(cwd)
if not ok then
return ok, err
end
end
end
return true
end
local htmlHeaderTemplate = [=[ &lt;!DOCTYPE HTML PUBLIC "</span>-//W3C//DTD HTML <span class="number">4.01</span> Transitional//<span class="function-name">EN</span><span class="string">"
"</span>http://www.w3.org/TR/html4/loose.<span class="function-name">dtd</span><span class="string">"&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="</span>Content-<span class="function-name">Type</span><span class="string">" content="</span>text/html;charset=utf-<span class="number">8</span><span class="string">" &gt;
&lt;link href='http://fonts.googleapis.com/css?family=Droid+Sans+Mono' rel='stylesheet' type='text/css'&gt;
&lt;style type="</span>text/<span class="function-name">css</span><span class="string">"&gt;
body {
background-color: |b;
color: |c;
font-family: 'Droid Sans Mono';
white-space: pre;
font-size: |fpx;
}
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;&lt;span&gt;
]=]
--- Creates a new Loginator object
--@tparam table options table of options for the logger
-- &lt;table class="</span><span class="function-name">tg</span><span class="string">"&gt;
-- &lt;thead&gt;
-- &lt;tr&gt;
-- &lt;th&gt;option name&lt;/th&gt;
-- &lt;th&gt;description&lt;/th&gt;
-- &lt;th&gt;default&lt;/th&gt;
-- &lt;/tr&gt;
-- &lt;/thead&gt;
-- &lt;tbody&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;format&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;What format to log in? "</span><span class="function-name">h</span><span class="string">" for html, "</span><span class="function-name">a</span><span class="string">" for ansi, anything else for plaintext.&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;"</span><span class="function-name">h</span><span class="string">"&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;name&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;What is the name of the logger? Will replace |n in templates&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;logname&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;level&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;What level should the logger operate at? This will control what level the log function defaults to, as well as what logs will actually be written&lt;br&gt;
-- Only items of an equal or higher severity to this will be written to the log file.&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;"</span><span class="function-name">info</span><span class="string">"&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;bgColor&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;What background color to use for html logs&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;"</span><span class="function-name">black</span><span class="string">"&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;fgColor&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;What color to use for the main text in html logs&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;"</span><span class="function-name">white</span><span class="string">"&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;fontSize&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;What font size to use in html logs&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;12&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;levelColors&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;Table with the log level as the key, and the color which corresponds to it as the value&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;{ error = "</span><span class="function-name">red</span><span class="string">", warn = "</span><span class="function-name">DarkOrange</span><span class="string">", info = "</span><span class="function-name">ForestGreen</span><span class="string">", debug = "</span><span class="function-name">ansi_yellow</span><span class="string">" }&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;fileNameTemplate&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;A template which will be transformed into the full filename, with path. See template options below for replacements&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;"</span>|p/log/Loginator/|y-|M-|d-|n.|<span class="function-name">e</span><span class="string">"&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;entryTemplate&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;The template which controls the look of each log entry. See template options below for replacements&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;"</span>|y-|M-|d |h:|m:|s.|x [|c|l|r] |<span class="function-name">t</span><span class="string">"&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;/tbody&gt;
-- &lt;/table&gt;&lt;br&gt;
-- Table of template options
-- &lt;table class="</span><span class="function-name">tg</span><span class="string">"&gt;
-- &lt;thead&gt;
-- &lt;tr&gt;
-- &lt;th&gt;template code&lt;/th&gt;
-- &lt;th&gt;what it is replaced with&lt;/th&gt;
-- &lt;th&gt;example&lt;/th&gt;
-- &lt;/tr&gt;
-- &lt;/thead&gt;
-- &lt;tbody&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;|y&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;the year in 4 digits&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;2021&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;|p&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;getMudletHomeDir()&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;/home/demonnic/.config/mudlet/profiles/testprofile&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;|M&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;Month as 2 digits&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;05&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;|d&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;day, as 2 digits&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;23&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;|h&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;hour in 24hr time format, 2 digits&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;03&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;|m&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;minute as 2 digits&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;42&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;|s&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;seconds as 2 digits&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;34&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;|x&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;milliseconds as 3 digits&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;194&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;|e&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;Filename extension expected. "</span><span class="function-name">html</span><span class="string">" for html format, "</span><span class="function-name">log</span><span class="string">" for everything else&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;html&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;|l&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;The logging level of the entry, in ALLCAPS&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;WARN&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;|c&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;The color which corresponds with the logging level. Set via the levelColors table in the options. Example not included.&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;|r&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;Reset back to standard color. Used to close |c. Example not included&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">2</span><span class="string">"&gt;&lt;/td&gt;
-- &lt;/tr&gt;
-- &lt;tr&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;|n&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;The name of the logger, set via the options when you have Loginator create it.&lt;/td&gt;
-- &lt;td class="</span>tg-<span class="number">1</span><span class="string">"&gt;CoolPackageLog&lt;/td&gt;
-- &lt;/tr&gt;
--&lt;/tbody&gt;
--&lt;/table&gt;
--@return newly created logger object
function Loginator:new(options)
options = options or {}
local optionsType = type(options)
if optionsType ~= "</span><span class="global">table</span><span class="string">" then
return nil, f "</span>Loginator:<span class="function-name">new</span>(options) options as <span class="global">table</span> expected, <span class="function-name">got</span> {optionsType}<span class="string">"
end
local me = table.deepcopy(options)
me.levelColors = me.levelColors or {}
local lcType = type(me.levelColors)
if lcType ~= "</span><span class="global">table</span><span class="string">" then
return nil, f "</span>Loginator:<span class="function-name">new</span>(options) provided options.levelColors must be a <span class="global">table</span>, but you provided <span class="function-name">a</span> {lcType}<span class="string">"
end
for lvl,clr in pairs(levelColors) do
me.levelColors[lvl] = me.levelColors[lvl] or clr
end
setmetatable(me, self)
self.__index = self
return me
end
---@local
function Loginator:processTemplate(str, level)
local lvl = level or self.level
local timeTable = getTime()
for what, with in pairs({
["</span>|<span class="function-name">y</span><span class="string">"] = function()
return timeTable.year
end,
["</span>|<span class="function-name">p</span><span class="string">"] = getMudletHomeDir,
["</span>|<span class="function-name">M</span><span class="string">"] = function()
return string.format("</span>%<span class="number">02</span><span class="function-name">d</span><span class="string">", timeTable.month)
end,
["</span>|<span class="function-name">d</span><span class="string">"] = function()
return string.format("</span>%<span class="number">02</span><span class="function-name">d</span><span class="string">", timeTable.day)
end,
["</span>|<span class="function-name">h</span><span class="string">"] = function()
return string.format("</span>%<span class="number">02</span><span class="function-name">d</span><span class="string">", timeTable.hour)
end,
["</span>|<span class="function-name">m</span><span class="string">"] = function()
return string.format("</span>%<span class="number">02</span><span class="function-name">d</span><span class="string">", timeTable.min)
end,
["</span>|<span class="function-name">s</span><span class="string">"] = function()
return string.format("</span>%<span class="number">02</span><span class="function-name">d</span><span class="string">", timeTable.sec)
end,
["</span>|<span class="function-name">x</span><span class="string">"] = function()
return string.format("</span>%<span class="number">03</span><span class="function-name">d</span><span class="string">", timeTable.msec)
end,
["</span>|<span class="function-name">e</span><span class="string">"] = function()
return (self.format:starts("</span><span class="function-name">h</span><span class="string">") and "</span><span class="function-name">html</span><span class="string">" or "</span><span class="function-name">log</span><span class="string">")
end,
["</span>|<span class="function-name">l</span><span class="string">"] = function()
return lvl:upper()
end,
["</span>|<span class="function-name">c</span><span class="string">"] = function()
return self:getColor(lvl)
end,
["</span>|<span class="function-name">r</span><span class="string">"] = function()
return self:getReset()
end,
["</span>|<span class="function-name">n</span><span class="string">"] = function()
return self.name
end,
}) do
if str:find(what) then
str = str:gsub(what, with())
end
end
return str
end
--- Set the color to associate with a logging level post-creation
--@param color The color to set for the level, as a string. Can be any valid color string for cecho, decho, or hecho.
--@param level The level to set the color for. Must be one of 'error', 'warn', 'info', or 'debug'
--@return true if the color is updated, or nil+error if it could not be updated for some reason.
function Loginator:setColorForLevel(color, level)
if not color then
return nil, "</span>You must provide a color to <span class="function-name">set</span><span class="string">"
end
if not level then
return nil, "</span>You must provide a level to set the color <span class="keyword">for</span><span class="string">"
end
if not loggerLevels[level] then
return nil, "</span>Invalid level. Valid levels <span class="function-name">are</span> <span class="string">'error'</span>, <span class="string">'warn'</span>, <span class="string">'info'</span>, <span class="keyword">or</span> <span class="string">'debug'</span><span class="string">"
end
if not Geyser.Color.parse(color) then
return nil, "</span>You must provide a color which can be parsed by Geyser.Color.parse. Examples <span class="function-name">are</span> <span class="string">'blue'</span> (cecho), <span class="string">'&lt;128,0,0&gt;'</span> (decho), <span class="string">'#aa3388'</span> (hecho), <span class="keyword">or</span> {<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>} (<span class="global">table</span> of r,g,b values)<span class="string">"
end
self.levelColors[level] = color
return true
end
---@local
function Loginator:getColor(level)
if self.format == "</span><span class="function-name">t</span><span class="string">" then
return "</span><span class="string">"
end
local r, g, b = Geyser.Color.parse((self.levelColors[level] or {128, 128, 128}))
if self.format == "</span><span class="function-name">h</span><span class="string">" then
return string.format("</span>&lt;span style=<span class="string">'color: rgb(%d,%d,%d);'</span>&gt;<span class="string">", r, g, b)
elseif self.format == "</span><span class="function-name">a</span><span class="string">" then
return string.format("</span>\<span class="number">27</span>[<span class="number">38</span>:<span class="number">2</span>::%d:%d:%<span class="function-name">dm</span><span class="string">", r, g, b)
end
return "</span><span class="string">"
end
---@local
function Loginator:getReset()
if self.format == "</span><span class="function-name">t</span><span class="string">" then
return "</span><span class="string">"
elseif self.format == "</span><span class="function-name">h</span><span class="string">" then
return "</span>&lt;/span&gt;<span class="string">"
elseif self.format == "</span><span class="function-name">a</span><span class="string">" then
return "</span>\<span class="number">27</span>[<span class="number">39</span>;<span class="number">49</span><span class="function-name">m</span><span class="string">"
end
return "</span><span class="string">"
end
--- Returns the full path and filename to the logfile
function Loginator:getFullFilename()
return self:processTemplate(self.fileNameTemplate)
end
--- Write an error level message to the logfile. Error level messages are always written.
--@param msg the message to log
--@return true if msg written, nil+error if error
function Loginator:error(msg)
return self:log(msg, "</span><span class="global">error</span><span class="string">")
end
--- Write a warn level message to the logfile.
-- Msg is only written if the logger level is &lt;= warn
-- From most to least severe the levels are:
-- error &gt; warn &gt; info &gt; debug
--@param msg the message to log
--@return true if msg written, false if skipped due to level, nil+error if error
function Loginator:warn(msg)
return self:log(msg, "</span><span class="function-name">warn</span><span class="string">")
end
--- Write an info level message to the logfile.
-- Msg is only written if the logger level is &lt;= info
-- From most to least severe the levels are:
-- error &gt; warn &gt; info &gt; debug
--@param msg the message to log
--@return true if msg written, false if skipped due to level, nil+error if error
function Loginator:info(msg)
return self:log(msg, "</span><span class="function-name">info</span><span class="string">")
end
--- Write a debug level message to the logfile.
-- Msg is only written if the logger level is debug
-- From most to least severe the levels are:
-- error &gt; warn &gt; info &gt; debug
--@param msg the message to log
--@return true if msg written, false if skipped due to level, nil+error if error
function Loginator:debug(msg)
return self:log(msg, "</span><span class="global">debug</span><span class="string">")
end
--- Write a message to the log file and optionally specify the level
--@param msg the message to log
--@param level the level to log the message at. Defaults to the level of the logger itself if not provided.
--@return true if msg written, false if skipped due to level, nil+error if error
function Loginator:log(msg, level)
level = level or self.level
local levelNumber = loggerLevels[level]
if not levelNumber then
return nil, f"</span>Unknown logging level: {level}. Valid levels <span class="function-name">are</span> <span class="string">'error'</span>, <span class="string">'warn'</span>, <span class="string">'info'</span>, <span class="keyword">and</span> <span class="string">'debug'</span><span class="string">"
end
local displayLevelNumber = loggerLevels[self.level]
if levelNumber &gt; displayLevelNumber then
return false
end
local filename = self:getFullFilename()
local filteredMsg = self:processTemplate(self.entryTemplate, level):gsub("</span>|<span class="function-name">t</span><span class="string">", msg)
local ok, err = self:createPathIfNotExists(filename)
if err then
debugc(err)
return ok, err
end
if self.format == "</span><span class="function-name">h</span><span class="string">" and not io.exists(filename) then
filteredMsg = self:getHtmlHeader() .. filteredMsg
end
local file, err = io.open(filename, "</span><span class="function-name">a</span><span class="string">")
if not file then
err = string.format("</span>Logger %s failed to open %s because: %s\<span class="function-name">n</span><span class="string">", self.name, filename, err)
debugc(err)
return nil, err
end
file:write(filteredMsg .. "</span>\<span class="function-name">n</span><span class="string">")
file:close()
return true
end
--- Uses openUrl() to request your OS open the logfile in the appropriate application. Usually your web browser for html and text editor for all others.
function Loginator:open()
openUrl(self:getFullFilename())
end
--- Uses openUrl() to request your OS open the directory the logfile resides in. This allows for easier browsing if you have more than one file.
function Loginator:openDir()
openUrl(self:getPath())
end
--- Returns the path to the log file (directory in which the file resides) as a string
--@param filename optional filename to return the path of. If not supplied, with use the logger's current filename
function Loginator:getPath(filename)
filename = filename or self:getFullFilename()
filename = filename:gsub([[\]], "</span>/<span class="string">")
local filenameTable = filename:split("</span>/<span class="string">")
filenameTable[#filenameTable] = nil
local path = table.concat(filenameTable, "</span>/<span class="string">")
return path
end
---@local
function Loginator:createPathIfNotExists(filename)
if exists(filename) then
return false
end
filename = filename:gsub([[\]], "</span>/<span class="string">")
local path = self:getPath(filename)
if exists(path) then
return false
end
local ok, err = mkdir_p(path)
if not ok then
err = string.format("</span>Could <span class="keyword">not</span> create directory <span class="keyword">for</span> log files: %s\n Reason was: %<span class="function-name">s</span><span class="string">", path, err)
return nil, err
end
return true
end
---@local
function Loginator:getHtmlHeader()
local header = htmlHeaderTemplate
header = header:gsub("</span>|<span class="function-name">b</span><span class="string">", self.bgColor)
header = header:gsub("</span>|<span class="function-name">c</span><span class="string">", self.fgColor)
header = header:gsub("</span>|<span class="function-name">f</span>", self.fontSize)
<span class="keyword">return</span> header
<span class="keyword">end</span>
<span class="keyword">return</span> Loginator</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,353 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><strong>mastermindsolver.lua</strong></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>mastermindsolver.lua</h2>
<pre>
<span class="comment">--- Interactive object which helps you solve a Master Mind puzzle.
</span><span class="comment">-- @classmod MasterMindSolver
</span><span class="comment">-- @author Damian Monogue &lt;demonnic@gmail.com&gt;
</span><span class="comment">-- @copyright 2021 Damian Monogue
</span><span class="comment">-- @copyright 2008,2009 Konstantinos Asimakis for code used to turn an index number into a guess (indexToGuess method)
</span><span class="keyword">local</span> MasterMindSolver = {
places = <span class="number">4</span>,
items = {<span class="string">"red"</span>, <span class="string">"orange"</span>, <span class="string">"yellow"</span>, <span class="string">"green"</span>, <span class="string">"blue"</span>, <span class="string">"purple"</span>},
template = <span class="string">"|t"</span>,
autoSend = <span class="keyword">false</span>,
singleCommand = <span class="keyword">false</span>,
separator = <span class="string">" "</span>,
allowDuplicates = <span class="keyword">true</span>,
}
<span class="keyword">local</span> mod, floor, random, randomseed = <span class="global">math</span>.mod, <span class="global">math</span>.floor, <span class="global">math</span>.random, <span class="global">math</span>.randomseed
<span class="keyword">local</span> initialGuess = {{<span class="number">1</span>}, {<span class="number">1</span>, <span class="number">2</span>}, {<span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>}, {<span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">2</span>}, {<span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">2</span>}, {<span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">2</span>}, {<span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">2</span>}, {<span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">2</span>}}
<span class="comment">--- Removes duplicate elements from a list
</span><span class="comment">-- @param tbl the table you want to remove dupes from
</span><span class="comment">-- @local
</span><span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">tableUnique</span>(tbl)
<span class="keyword">local</span> used = {}
<span class="keyword">local</span> result = {}
<span class="keyword">for</span> _, item <span class="keyword">in</span> <span class="global">ipairs</span>(tbl) <span class="keyword">do</span>
<span class="keyword">if</span> <span class="keyword">not</span> used[item] <span class="keyword">then</span>
result[#result + <span class="number">1</span>] = item
used[item] = <span class="keyword">true</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> result
<span class="keyword">end</span>
<span class="comment">--- Creates a new Master Mind solver
</span><span class="comment">-- @tparam table options table of configuration options for the solver
</span><span class="comment">-- &lt;table class="tg"&gt;
</span><span class="comment">-- &lt;thead&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;th&gt;option name&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;description&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;default&lt;/th&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/thead&gt;
</span><span class="comment">-- &lt;tbody&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;places&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;How many spots in the code we're breaking?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;4&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;items&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;The table of colors/gemstones/whatever which can be part of the code&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;{"red", "orange", "yellow", "green", "blue", "purple"}&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;template&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;The string template to use for the guess. Within the template, |t is replaced by the item. Used as the command if autoSend is true&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;"|t"&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;autoSend&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;Should we send the guess directly to the server?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;false&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;allowDuplicates&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;Can the same item be used more than once in a code?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;true&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;singleCommand&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;If true, combines the guess into a single command, with each one separated by the separator&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;false&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;separator&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;If sending the guess as a single command, what should we put between the guesses to separate them?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;" "&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/tbody&gt;
</span><a id="81"></a><span class="comment">-- &lt;/table&gt;
</span><span class="keyword">function</span> MasterMindSolver:<span class="function-name">new</span>(options)
<span class="keyword">if</span> options == <span class="keyword">nil</span> <span class="keyword">then</span>
options = {}
<span class="keyword">end</span>
<span class="keyword">local</span> optionsType = <span class="global">type</span>(options)
<span class="keyword">if</span> optionsType ~= <span class="string">"table"</span> <span class="keyword">then</span>
<span class="global">error</span>(<span class="function-name">f</span> <span class="string">"MasterMindSolver:new(options): options as table expected, got {tostring(options)} of type: {optionsType}"</span>)
<span class="keyword">end</span>
<span class="keyword">local</span> me = options
<span class="global">setmetatable</span>(me, self)
self.__index = self
me:<span class="function-name">populateInitialSet</span>()
<span class="keyword">if</span> <span class="keyword">not</span> me.allowDuplicates <span class="keyword">then</span>
me.initialGuessMade = <span class="keyword">true</span> <span class="comment">-- skip the preset initial guess, they assume duplicates
</span> <span class="keyword">end</span>
<span class="keyword">return</span> me
<span class="keyword">end</span>
<span class="comment">--- Takes a guess number (4, or 1829, or any number from 1 - &lt;total possible combinations&gt;) and returns the
</span><span class="comment">-- actual guess.
</span><span class="comment">-- @tparam number index which guess to generate
</span><span class="comment">-- @local
</span><span class="keyword">function</span> MasterMindSolver:<span class="function-name">indexToGuess</span>(index)
<span class="keyword">local</span> guess = {}
<span class="keyword">local</span> options = #self.items
<span class="keyword">for</span> place = <span class="number">1</span>, self.places <span class="keyword">do</span>
guess[place] = <span class="function-name">mod</span>(<span class="function-name">floor</span>((index - <span class="number">1</span>) / options ^ (place - <span class="number">1</span>)), options) + <span class="number">1</span>
<span class="keyword">end</span>
<span class="keyword">return</span> guess
<span class="keyword">end</span>
<span class="comment">--- Compares a guess with the solution and returns the answer
</span><span class="comment">-- @tparam table guess The guess you are checking, as numbers. { 1 , 1, 2, 2 } as an example
</span><span class="comment">-- @tparam table solution the solution you are checking against, as numbers. { 3, 4, 1, 6 } as an example.
</span><span class="comment">-- @local
</span><span class="keyword">function</span> MasterMindSolver:<span class="function-name">compare</span>(guess, solution)
<span class="keyword">local</span> coloredPins = <span class="number">0</span>
<span class="keyword">local</span> whitePins = <span class="number">0</span>
<span class="keyword">local</span> usedGuessPlace = {}
<span class="keyword">local</span> usedSolutionPlace = {}
<span class="keyword">local</span> places = self.places
<span class="keyword">for</span> place = <span class="number">1</span>, places <span class="keyword">do</span>
<span class="keyword">if</span> guess[place] == solution[place] <span class="keyword">then</span>
coloredPins = coloredPins + <span class="number">1</span>
usedGuessPlace[place] = <span class="keyword">true</span>
usedSolutionPlace[place] = <span class="keyword">true</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">for</span> guessPlace = <span class="number">1</span>, places <span class="keyword">do</span>
<span class="keyword">if</span> <span class="keyword">not</span> usedGuessPlace[guessPlace] <span class="keyword">then</span>
<span class="keyword">for</span> solutionPlace = <span class="number">1</span>, places <span class="keyword">do</span>
<span class="keyword">if</span> <span class="keyword">not</span> usedSolutionPlace[solutionPlace] <span class="keyword">then</span>
<span class="keyword">if</span> guess[guessPlace] == solution[solutionPlace] <span class="keyword">then</span>
whitePins = whitePins + <span class="number">1</span>
usedSolutionPlace[solutionPlace] = <span class="keyword">true</span>
<span class="keyword">break</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> coloredPins, whitePins
<span class="keyword">end</span>
<span class="comment">--- Generates an initial table of all guesses from 1 to &lt;total possible&gt; that are valid.
</span><span class="comment">-- If allowDuplicates is false, will filter out any of the possible combinations which contain duplicates
</span><span class="comment">-- @local
</span><span class="keyword">function</span> MasterMindSolver:<span class="function-name">populateInitialSet</span>()
<span class="keyword">local</span> possible = {}
<span class="keyword">local</span> allowDuplicates = self.allowDuplicates
<span class="keyword">local</span> places = self.places
<span class="keyword">local</span> numberOfItems = #self.items
<span class="keyword">local</span> totalCombos = numberOfItems ^ places
<span class="keyword">local</span> numberRemaining = <span class="number">0</span>
<span class="keyword">for</span> entry = <span class="number">1</span>, totalCombos <span class="keyword">do</span>
<span class="keyword">local</span> useItem = <span class="keyword">true</span>
<span class="keyword">if</span> <span class="keyword">not</span> allowDuplicates <span class="keyword">then</span>
<span class="keyword">local</span> guess = self:<span class="function-name">indexToGuess</span>(entry)
<span class="keyword">local</span> guessUnique = <span class="function-name">tableUnique</span>(guess)
<span class="keyword">if</span> #guessUnique ~= self.places <span class="keyword">then</span>
useItem = <span class="keyword">false</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">if</span> useItem <span class="keyword">then</span>
possible[entry] = <span class="keyword">true</span>
numberRemaining = numberRemaining + <span class="number">1</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
self.possible = possible
self.numberRemaining = numberRemaining
<span class="keyword">end</span>
<span class="comment">--- Function used to reduce the remaining possible answers, given a guess and the answer to that guess. This is not undoable.
</span><span class="comment">-- @tparam table guess guess which the answer belongs to. Uses numbers, rather than item names. IE { 1, 1, 2, 2} rather than { "blue", "blue", "green", "green" }
</span><span class="comment">-- @tparam number coloredPins how many parts of the guess are both the right color and the right place
</span><span class="comment">-- @tparam number whitePins how many parts of the guess are the right color, but in the wrong place
</span><a id="178"></a><span class="comment">-- @return true if you solved the puzzle (coloredPins == number of positions in the code), or false otherwise
</span><span class="keyword">function</span> MasterMindSolver:<span class="function-name">reducePossible</span>(guess, coloredPins, whitePins)
<span class="keyword">if</span> coloredPins == #guess <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">true</span>
<span class="keyword">end</span>
<span class="keyword">local</span> possible = self.possible
<span class="keyword">local</span> numberRemaining = <span class="number">0</span>
<span class="keyword">for</span> entry, _ <span class="keyword">in</span> <span class="global">pairs</span>(possible) <span class="keyword">do</span>
<span class="keyword">local</span> testColor, testWhite = self:<span class="function-name">compare</span>(guess, self:<span class="function-name">indexToGuess</span>(entry))
<span class="keyword">if</span> testColor ~= coloredPins <span class="keyword">or</span> testWhite ~= whitePins <span class="keyword">then</span>
possible[entry] = <span class="keyword">nil</span>
<span class="keyword">else</span>
numberRemaining = numberRemaining + <span class="number">1</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
self.possible = possible
self.numberRemaining = numberRemaining
<span class="keyword">return</span> <span class="keyword">false</span>
<span class="keyword">end</span>
<span class="comment">--- Function which assumes you used the last suggested guess from the solver, and reduces the number of possible correct solutions based on the answer given
</span><span class="comment">-- @see MasterMindSolver:reducePossible
</span><span class="comment">-- @tparam number coloredPins how many parts of the guess are both the right color and the right place
</span><span class="comment">-- @tparam number whitePins how many parts of the guess are the right color, but in the wrong place
</span><a id="202"></a><span class="comment">-- @return true if you solved the puzzle (coloredPins == number of positions in the code), or false otherwise
</span><span class="keyword">function</span> MasterMindSolver:<span class="function-name">checkLastSuggestion</span>(coloredPins, whitePins)
<span class="keyword">return</span> self:<span class="function-name">reducePossible</span>(self.guess, coloredPins, whitePins)
<span class="keyword">end</span>
<span class="comment">--- Used to get one of the remaining valid possible guesses
</span><a id="208"></a><span class="comment">-- @tparam boolean useActions if true, will return the guess as the commands which would be sent, rather than the numbered items
</span><span class="keyword">function</span> MasterMindSolver:<span class="function-name">getValidGuess</span>(useActions)
<span class="keyword">local</span> guess
<span class="keyword">if</span> <span class="keyword">not</span> self.initialGuessMade <span class="keyword">then</span>
self.initialGuessMade = <span class="keyword">true</span>
guess = initialGuess[self.places]
<span class="keyword">end</span>
<span class="keyword">if</span> <span class="keyword">not</span> guess <span class="keyword">then</span>
<span class="keyword">local</span> possible = self.possible
<span class="keyword">local</span> keys = <span class="global">table</span>.<span class="function-name">keys</span>(possible)
<span class="function-name">randomseed</span>(<span class="global">os</span>.<span class="function-name">time</span>())
guess = self:<span class="function-name">indexToGuess</span>(keys[<span class="function-name">random</span>(#keys)])
<span class="keyword">end</span>
self.guess = guess
<span class="keyword">if</span> self.autoSend <span class="keyword">then</span>
self:<span class="function-name">sendGuess</span>(guess)
<span class="keyword">end</span>
<span class="keyword">if</span> useActions <span class="keyword">then</span>
<span class="keyword">return</span> self:<span class="function-name">guessToActions</span>(guess)
<span class="keyword">end</span>
<span class="keyword">return</span> guess
<span class="keyword">end</span>
<span class="comment">--- Takes a guess and converts the numbers to commands/actions. IE guessToActions({1, 1, 2, 2}) might return { "blue", "blue", "green", "green" }
</span><span class="comment">-- @tparam table guess the guess to convert as numbers. IE { 1, 1, 2, 2}
</span><span class="comment">-- @return table of commands/actions correlating to the numbers in the guess.
</span><span class="comment">-- @local
</span><span class="keyword">function</span> MasterMindSolver:<span class="function-name">guessToActions</span>(guess)
<span class="keyword">local</span> actions = {}
<span class="keyword">for</span> index, itemNumber <span class="keyword">in</span> <span class="global">ipairs</span>(guess) <span class="keyword">do</span>
<span class="keyword">local</span> item = self.items[itemNumber]
actions[index] = self.template:<span class="function-name">gsub</span>(<span class="string">"|t"</span>, item)
<span class="keyword">end</span>
<span class="keyword">return</span> actions
<span class="keyword">end</span>
<span class="comment">--- Handles sending the commands to the game for a guess
</span><span class="comment">-- @local
</span><span class="keyword">function</span> MasterMindSolver:<span class="function-name">sendGuess</span>(guess)
<span class="keyword">local</span> actions = self:<span class="function-name">guessToActions</span>(guess)
<span class="keyword">if</span> self.singleCommand <span class="keyword">then</span>
<span class="function-name">send</span>(<span class="global">table</span>.<span class="function-name">concat</span>(actions, self.separator))
<span class="keyword">else</span>
<span class="function-name">sendAll</span>(<span class="global">unpack</span>(actions))
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> MasterMindSolver</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,240 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><strong>revisionator.lua</strong></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>revisionator.lua</h2>
<pre>
<span class="comment">--- The revisionator provides a standardized way of migrating configurations between revisions
</span><span class="comment">-- for instance, it will track what the currently applied revision number is, and when you tell
</span><span class="comment">-- tell it to migrate, it will apply every individual migration between the currently applied
</span><span class="comment">-- revision and the latest/current revision. This should allow for more seamlessly moving from
</span><span class="comment">-- an older version of a package to a new one.
</span><span class="comment">-- @classmod revisionator
</span><span class="comment">-- @author Damian Monogue &lt;demonnic@gmail.com&gt;
</span><span class="comment">-- @copyright 2023
</span><span class="comment">-- @license MIT, see https://raw.githubusercontent.com/demonnic/MDK/main/src/scripts/LICENSE.lua
</span><span class="keyword">local</span> revisionator = {
name = <span class="string">"Revisionator"</span>,
patches = {},
}
revisionator.__index = revisionator
<span class="keyword">local</span> dataDir = <span class="function-name">getMudletHomeDir</span>() .. <span class="string">"/revisionator"</span>
revisionator.dataDir = dataDir
<span class="keyword">if</span> <span class="keyword">not</span> <span class="global">io</span>.<span class="function-name">exists</span>(dataDir) <span class="keyword">then</span>
<span class="keyword">local</span> ok,err = lfs.<span class="function-name">mkdir</span>(dataDir)
<span class="keyword">if</span> <span class="keyword">not</span> ok <span class="keyword">then</span>
<span class="function-name">printDebug</span>(<span class="function-name">f</span><span class="string">"Error creating the directory for storing applied revisions: {err}"</span>, <span class="keyword">true</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Creates a new revisionator
</span><span class="comment">-- @tparam table options the options to create the revisionator with.
</span><span class="comment">-- &lt;table class="tg"&gt;
</span><span class="comment">-- &lt;thead&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;th&gt;option name&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;description&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;default&lt;/th&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/thead&gt;
</span><span class="comment">-- &lt;tbody&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;name&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;The name of the revisionator. This is absolutely required, as the name is used for tracking the currently applied patch level&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;raises an error if not provided&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;patches&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;A table of patch functions. It is traversed using ipairs, so must be in the form of {function1, function2, function3} etc. If you do not provide it, you can add the patches by calling :addPatch for each patch in order.&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;{}&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">--&lt;/tbody&gt;
</span><a id="47"></a><span class="comment">--&lt;/table&gt;
</span><span class="keyword">function</span> revisionator:<span class="function-name">new</span>(options)
options = options <span class="keyword">or</span> {}
<span class="keyword">local</span> optionsType = <span class="global">type</span>(options)
<span class="keyword">if</span> optionsType ~= <span class="string">"table"</span> <span class="keyword">then</span>
<span class="function-name">printError</span>(<span class="function-name">f</span><span class="string">"revisionator:new bad argument #1 type, options as table expected, got {optionsType}"</span>, <span class="keyword">true</span>, <span class="keyword">true</span>)
<span class="keyword">end</span>
<span class="keyword">if</span> <span class="keyword">not</span> options.name <span class="keyword">then</span>
<span class="function-name">printError</span>(<span class="string">"revisionator:new(options) options must include a 'name' key as this is used as part of tracking the applied patch level."</span>, <span class="keyword">true</span>, <span class="keyword">true</span>)
<span class="keyword">end</span>
<span class="keyword">local</span> me = <span class="global">table</span>.<span class="function-name">deepcopy</span>(options)
<span class="global">setmetatable</span>(me, self)
<span class="keyword">return</span> me
<span class="keyword">end</span>
<span class="comment">--- Get the currently applied revision from file
</span><span class="comment">--- @treturn[1] number the revision number currently applied, or 0 if it can't read a current version
</span><span class="comment">--- @treturn[2] nil nil
</span><a id="65"></a><span class="comment">--- @treturn[2] string error message
</span><span class="keyword">function</span> revisionator:<span class="function-name">getAppliedPatch</span>()
<span class="keyword">local</span> fileName = <span class="function-name">f</span><span class="string">"{self.dataDir}/{self.name}.txt"</span>
<span class="function-name">debugc</span>(fileName)
<span class="keyword">local</span> revision = <span class="number">0</span>
<span class="keyword">if</span> <span class="global">io</span>.<span class="function-name">exists</span>(fileName) <span class="keyword">then</span>
<span class="keyword">local</span> file = <span class="global">io</span>.<span class="function-name">open</span>(fileName, <span class="string">"r"</span>)
<span class="keyword">local</span> fileContents = file:<span class="function-name">read</span>(<span class="string">"*a"</span>)
file:<span class="function-name">close</span>()
<span class="keyword">local</span> revNumber = <span class="global">tonumber</span>(fileContents)
<span class="keyword">if</span> revNumber <span class="keyword">then</span>
revision = revNumber
<span class="keyword">else</span>
<span class="keyword">return</span> <span class="keyword">nil</span>, <span class="function-name">f</span><span class="string">"Error while attempting to read current patch version from file: {fileName}\nThe contents of the file are {fileContents} and it was unable to be converted to a revision number"</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> revision
<span class="keyword">end</span>
<span class="comment">--- go through all the patches in order and apply any which are still necessary
</span><span class="comment">--- @treturn boolean true if it successfully applied patches, false if it was already at the latest patch level
</span><a id="86"></a><span class="comment">--- @error error message
</span><span class="keyword">function</span> revisionator:<span class="function-name">migrate</span>()
<span class="keyword">local</span> applied,err = self:<span class="function-name">getAppliedPatch</span>()
<span class="keyword">if</span> <span class="keyword">not</span> applied <span class="keyword">then</span>
<span class="function-name">printError</span>(err, <span class="keyword">true</span>, <span class="keyword">true</span>)
<span class="keyword">end</span>
<span class="keyword">local</span> patches = self.patches
<span class="keyword">if</span> applied &gt;= #patches <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">false</span>
<span class="keyword">end</span>
<span class="keyword">for</span> revision, patch <span class="keyword">in</span> <span class="global">ipairs</span>(patches) <span class="keyword">do</span>
<span class="keyword">if</span> applied &lt; revision <span class="keyword">then</span>
<span class="keyword">local</span> ok, err = <span class="global">pcall</span>(patch)
<span class="keyword">if</span> <span class="keyword">not</span> ok <span class="keyword">then</span>
self:<span class="function-name">setAppliedPatch</span>(revision - <span class="number">1</span>)
<span class="keyword">return</span> <span class="keyword">nil</span>, <span class="function-name">f</span><span class="string">"Error while running patch #{revision}: {err}"</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
self:<span class="function-name">setAppliedPatch</span>(#patches)
<span class="keyword">return</span> <span class="keyword">true</span>
<span class="keyword">end</span>
<span class="comment">--- add a patch to the table of patches
</span><span class="comment">--- @tparam function func the function to run as the patch
</span><a id="111"></a><span class="comment">--- @number[opt] position which patch to insert it as? If not supplied, inserts it as the last patch. Which is usually what you want.
</span><span class="keyword">function</span> revisionator:<span class="function-name">addPatch</span>(func, position)
<span class="keyword">if</span> position <span class="keyword">then</span>
<span class="global">table</span>.<span class="function-name">insert</span>(self.patches, position, func)
<span class="keyword">else</span>
<span class="global">table</span>.<span class="function-name">insert</span>(self.patches, func)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Remove a patch from the table of patches
</span><span class="comment">--- this is primarily used for testing
</span><span class="comment">--- @local
</span><span class="comment">--- @number[opt] patchNumber the patch number to remove. Will remove the last item if not provided.
</span><span class="keyword">function</span> revisionator:<span class="function-name">removePatch</span>(patchNumber)
<span class="global">table</span>.<span class="function-name">remove</span>(self.patches, patchNumber)
<span class="keyword">end</span>
<span class="comment">--- set the currently applied patch number
</span><span class="comment">-- only directly called for testing
</span><span class="comment">--- @local
</span><span class="comment">--- @number patchNumber the patch number to set as the currently applied patch
</span><span class="keyword">function</span> revisionator:<span class="function-name">setAppliedPatch</span>(patchNumber)
<span class="keyword">local</span> fileName = <span class="function-name">f</span><span class="string">"{self.dataDir}/{self.name}.txt"</span>
<span class="keyword">local</span> revFile, err = <span class="global">io</span>.<span class="function-name">open</span>(fileName, <span class="string">"w+"</span>)
<span class="keyword">if</span> <span class="keyword">not</span> revFile <span class="keyword">then</span>
<span class="function-name">printError</span>(err, <span class="keyword">true</span>, <span class="keyword">true</span>)
<span class="keyword">end</span>
revFile:<span class="function-name">write</span>(patchNumber)
revFile:<span class="function-name">close</span>()
<span class="keyword">end</span>
<span class="keyword">return</span> revisionator</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,743 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><strong>schema.lua</strong></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>schema.lua</h2>
<pre>
<span class="comment">--[[
The MIT License (MIT)
Copyright (c) 2014 Sebastian Schoener
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]</span>
<span class="keyword">local</span> schema = {}
<span class="comment">-- Checks an object against a schema.
</span><span class="keyword">function</span> schema.<span class="function-name">CheckSchema</span>(obj, schem, path)
<span class="keyword">if</span> path == <span class="keyword">nil</span> <span class="keyword">then</span>
path = schema.Path.<span class="function-name">new</span>()
path:<span class="function-name">setBase</span>(obj)
<span class="keyword">end</span>
<span class="keyword">if</span> <span class="global">type</span>(schem) == <span class="string">"function"</span> <span class="keyword">then</span>
<span class="keyword">return</span> <span class="function-name">schem</span>(obj, path)
<span class="keyword">else</span> <span class="comment">-- attempt to simply compare the values
</span> <span class="keyword">if</span> schem == obj <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">nil</span>
<span class="keyword">end</span>
<span class="keyword">return</span> schema.<span class="function-name">Error</span>(<span class="string">"Invalid value: "</span>..path..<span class="string">" should be "</span>..<span class="global">tostring</span>(schem), path)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">function</span> schema.<span class="function-name">FormatOutput</span>(output)
<span class="keyword">local</span> format = schema.<span class="function-name">List</span>()
<span class="keyword">for</span> k,v <span class="keyword">in</span> <span class="global">ipairs</span>(output) <span class="keyword">do</span>
format:<span class="function-name">append</span>(v:<span class="function-name">format</span>())
<span class="keyword">end</span>
<span class="keyword">return</span> <span class="global">table</span>.<span class="function-name">concat</span>(format, <span class="string">"\n"</span>)
<span class="keyword">end</span>
<span class="comment">--
</span><span class="comment">-- Infrastructure
</span><span class="comment">--
</span>
<span class="comment">-- Path class. Represents paths to values in a table (the path's *base*).
</span><span class="keyword">local</span> Path = {}
<span class="keyword">function</span> Path.<span class="function-name">new</span>(...)
<span class="keyword">local</span> arg = {...}
<span class="keyword">local</span> self = <span class="global">setmetatable</span>({}, Path)
self.p = {}
<span class="keyword">for</span> k,v <span class="keyword">in</span> <span class="global">ipairs</span>(arg) <span class="keyword">do</span>
self.p[k] = v
<span class="keyword">end</span>
<span class="keyword">return</span> self
<span class="keyword">end</span>
<span class="comment">-- Sets the base of the path, i.e. the table to which the path is relative.
</span><span class="comment">-- Note that this is the actual *table*, not the table's name.
</span><span class="keyword">function</span> Path:<span class="function-name">setBase</span>(base)
self.base = base
<span class="keyword">end</span>
<span class="comment">-- Gets the base of the path.
</span><span class="keyword">function</span> Path:<span class="function-name">getBase</span>()
<span class="keyword">return</span> self.base
<span class="keyword">end</span>
<span class="comment">-- Returns the target of the path or 'nil' if the path is invalid.
</span><span class="keyword">function</span> Path:<span class="function-name">target</span>()
<span class="keyword">if</span> self.base == <span class="keyword">nil</span> <span class="keyword">then</span>
<span class="global">error</span>(<span class="string">"Path:target() called on a path without a base!"</span>)
<span class="keyword">end</span>
<span class="keyword">local</span> current = self.base
<span class="keyword">for</span> k,v <span class="keyword">in</span> <span class="global">ipairs</span>(self.p) <span class="keyword">do</span>
current = current[v]
<span class="keyword">if</span> current == <span class="keyword">nil</span> <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">nil</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> current
<span class="keyword">end</span>
<span class="comment">-- Pushes an entry to the end of the path.
</span><span class="keyword">function</span> Path:<span class="function-name">push</span>(obj)
self.p[#self.p + <span class="number">1</span>] = obj
<span class="keyword">return</span> self
<span class="keyword">end</span>
<span class="comment">-- Pops an entry from the end of the path.
</span><span class="keyword">function</span> Path:<span class="function-name">pop</span>()
<span class="keyword">local</span> tmp = self.p[#self.p]
self.p[#self.p] = <span class="keyword">nil</span>
<span class="keyword">return</span> tmp
<span class="keyword">end</span>
<span class="comment">-- Returns the topmost entry of the end of the path.
</span><span class="keyword">function</span> Path:<span class="function-name">top</span>()
<span class="keyword">return</span> self.p[#self.p]
<span class="keyword">end</span>
<span class="comment">-- Returns the length of the path.
</span><span class="keyword">function</span> Path:<span class="function-name">length</span>()
<span class="keyword">return</span> #self.p
<span class="keyword">end</span>
<span class="comment">-- Returns the element at the specified index.
</span><span class="keyword">function</span> Path:<span class="function-name">get</span>(index)
<span class="keyword">return</span> self.p[index]
<span class="keyword">end</span>
<span class="comment">-- Copies the path.
</span><span class="keyword">function</span> Path:<span class="function-name">copy</span>()
<span class="keyword">local</span> cp = Path.<span class="function-name">new</span>()
cp.base = self.base
<span class="keyword">for</span> k,v <span class="keyword">in</span> <span class="global">ipairs</span>(self) <span class="keyword">do</span>
cp.p[k] = v
<span class="keyword">end</span>
<span class="keyword">return</span> cp
<span class="keyword">end</span>
Path.__index = Path
Path.__tostring = <span class="keyword">function</span>(tbl)
<span class="keyword">if</span> #tbl.p == <span class="number">0</span> <span class="keyword">then</span>
<span class="keyword">return</span> <span class="string">'&lt;val&gt;'</span>
<span class="keyword">end</span>
<span class="keyword">return</span> <span class="global">table</span>.<span class="function-name">concat</span>(tbl.p,<span class="string">"."</span>)
<span class="keyword">end</span>
Path.__concat = <span class="keyword">function</span>(lhs, rhs)
<span class="keyword">if</span> <span class="global">type</span>(lhs) == <span class="string">"table"</span> <span class="keyword">then</span>
<span class="keyword">return</span> <span class="global">tostring</span>(lhs)..rhs
<span class="keyword">elseif</span> <span class="global">type</span>(rhs) == <span class="string">"table"</span> <span class="keyword">then</span>
<span class="keyword">return</span> lhs..<span class="global">tostring</span>(rhs)
<span class="keyword">end</span>
<span class="keyword">end</span>
Path.__len = <span class="keyword">function</span>(self)
<span class="keyword">return</span> #self.p
<span class="keyword">end</span>
<span class="global">setmetatable</span>(Path, {
__call = <span class="keyword">function</span> (cls, ...)
<span class="keyword">return</span> Path.<span class="function-name">new</span>(...)
<span class="keyword">end</span>
})
schema.Path = Path
<span class="comment">-- List class
</span><span class="keyword">local</span> List = {}
<span class="keyword">function</span> List.<span class="function-name">new</span>(...)
<span class="keyword">local</span> self = <span class="global">setmetatable</span>({}, List)
<span class="keyword">local</span> arg = {...}
<span class="keyword">for</span> k,v <span class="keyword">in</span> <span class="global">ipairs</span>(arg) <span class="keyword">do</span>
self[k] = v
<span class="keyword">end</span>
<span class="keyword">return</span> self
<span class="keyword">end</span>
<span class="keyword">function</span> List:<span class="function-name">add</span>(obj)
self[#self+<span class="number">1</span>] = obj
<span class="keyword">return</span> self
<span class="keyword">end</span>
<span class="keyword">function</span> List:<span class="function-name">append</span>(list)
<span class="keyword">for</span> k,v <span class="keyword">in</span> <span class="global">ipairs</span>(list) <span class="keyword">do</span>
self[#self+k] = v
<span class="keyword">end</span>
<span class="keyword">return</span> self
<span class="keyword">end</span>
List.__index = List
List.__tostring = <span class="keyword">function</span>(self)
<span class="keyword">local</span> tmp = {}
<span class="keyword">for</span> k,v <span class="keyword">in</span> <span class="global">ipairs</span>(self) <span class="keyword">do</span>
tmp[k] = <span class="global">tostring</span>(v)
<span class="keyword">end</span>
<span class="keyword">return</span> <span class="global">table</span>.<span class="function-name">concat</span>(tmp, <span class="string">"\n"</span>)
<span class="keyword">end</span>
<span class="global">setmetatable</span>(List, {
__call = <span class="keyword">function</span>(cls, ...)
<span class="keyword">return</span> List.<span class="function-name">new</span>(...)
<span class="keyword">end</span>
})
schema.List = List
<span class="comment">-- Error class. Describes mismatches that occured during the schema-checking.
</span><span class="keyword">local</span> Error = {}
<span class="keyword">function</span> Error.<span class="function-name">new</span>(msg, path, suberrors)
<span class="keyword">local</span> self = <span class="global">setmetatable</span>({}, Error)
self.message = msg
self.path = path:<span class="function-name">copy</span>()
self.suberrors = suberrors
<span class="keyword">return</span> self
<span class="keyword">end</span>
<span class="comment">-- Returns a list of strings which represent the error (with indenttation for
</span><span class="comment">-- suberrors).
</span><span class="keyword">function</span> Error:<span class="function-name">format</span>()
<span class="keyword">local</span> output = List.<span class="function-name">new</span>(self.message)
<span class="keyword">if</span> self.suberrors ~= <span class="keyword">nil</span> <span class="keyword">then</span>
<span class="keyword">for</span> k,sub <span class="keyword">in</span> <span class="global">pairs</span>(self.suberrors) <span class="keyword">do</span>
<span class="keyword">local</span> subout = sub:<span class="function-name">format</span>()
<span class="keyword">for</span> k1,msg <span class="keyword">in</span> <span class="global">pairs</span>(subout) <span class="keyword">do</span>
output = output:<span class="function-name">add</span>(<span class="string">" "</span>..msg)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> output
<span class="keyword">end</span>
Error.__tostring = <span class="keyword">function</span>(self)
<span class="keyword">return</span> <span class="global">table</span>.<span class="function-name">concat</span>(self:<span class="function-name">format</span>(), <span class="string">"\n"</span>)
<span class="keyword">end</span>
Error.__index = Error
<span class="global">setmetatable</span>(Error, {
__call = <span class="keyword">function</span>(cls, ...)
<span class="keyword">return</span> <span class="function-name">List</span>(Error.<span class="function-name">new</span>(...))
<span class="keyword">end</span>
})
schema.Error = Error
<span class="comment">--
</span><span class="comment">-- Schema Building Blocks
</span><span class="comment">-- A schema is a function taking the object to be checked and the path to the
</span><span class="comment">-- current value in the environment.
</span><span class="comment">-- It returns either 'true' if the schema accepted the object or an Error
</span><span class="comment">-- object which describes why it was rejected.
</span><span class="comment">-- The schemata below are just some basic building blocks. Expand them to your
</span><span class="comment">-- liking.
</span><span class="comment">--
</span>
<span class="comment">-- Always accepts.
</span><span class="keyword">function</span> schema.<span class="function-name">Any</span>(obj, path)
<span class="keyword">return</span> <span class="keyword">nil</span>
<span class="keyword">end</span>
<span class="comment">-- Always fails.
</span><span class="keyword">function</span> schema.<span class="function-name">Nothing</span>(obj, path)
<span class="keyword">return</span> schema.<span class="function-name">Error</span>(<span class="string">"Failure: '"</span>..path..<span class="string">"' will always fail."</span>, path)
<span class="keyword">end</span>
<span class="comment">-- Checks a value against a specific type.
</span><span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">TypeSchema</span>(obj, path, typeId)
<span class="keyword">if</span> <span class="global">type</span>(obj) ~= typeId <span class="keyword">then</span>
<span class="keyword">return</span> schema.<span class="function-name">Error</span>(<span class="string">"Type mismatch: '"</span>..path..<span class="string">"' should be "</span>..typeId..<span class="string">", is "</span>..<span class="global">type</span>(obj), path)
<span class="keyword">else</span>
<span class="keyword">return</span> <span class="keyword">nil</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">function</span> schema.<span class="function-name">Boolean</span> (obj, path) <span class="keyword">return</span> <span class="function-name">TypeSchema</span>(obj, path, <span class="string">"boolean"</span>) <span class="keyword">end</span>
<span class="keyword">function</span> schema.<span class="function-name">Function</span>(obj, path) <span class="keyword">return</span> <span class="function-name">TypeSchema</span>(obj, path, <span class="string">"function"</span>) <span class="keyword">end</span>
<span class="keyword">function</span> schema.<span class="function-name">Nil</span> (obj, path) <span class="keyword">return</span> <span class="function-name">TypeSchema</span>(obj, path, <span class="string">"nil"</span>) <span class="keyword">end</span>
<span class="keyword">function</span> schema.<span class="function-name">Number</span> (obj, path) <span class="keyword">return</span> <span class="function-name">TypeSchema</span>(obj, path, <span class="string">"number"</span>) <span class="keyword">end</span>
<span class="keyword">function</span> schema.<span class="function-name">String</span> (obj, path) <span class="keyword">return</span> <span class="function-name">TypeSchema</span>(obj, path, <span class="string">"string"</span>) <span class="keyword">end</span>
<span class="keyword">function</span> schema.<span class="function-name">Table</span> (obj, path) <span class="keyword">return</span> <span class="function-name">TypeSchema</span>(obj, path, <span class="string">"table"</span>) <span class="keyword">end</span>
<span class="keyword">function</span> schema.<span class="function-name">UserData</span>(obj, path) <span class="keyword">return</span> <span class="function-name">TypeSchema</span>(obj, path, <span class="string">"userdata"</span>) <span class="keyword">end</span>
<span class="comment">-- Checks that some value is a string matching a given pattern.
</span><span class="keyword">function</span> schema.<span class="function-name">Pattern</span>(pattern)
<span class="keyword">local</span> userPattern = pattern
<span class="keyword">if</span> <span class="keyword">not</span> pattern:<span class="function-name">match</span>(<span class="string">"^^"</span>) <span class="keyword">then</span>
pattern = <span class="string">"^"</span> .. pattern
<span class="keyword">end</span>
<span class="keyword">if</span> <span class="keyword">not</span> pattern:<span class="function-name">match</span>(<span class="string">"$$"</span>) <span class="keyword">then</span>
pattern = pattern .. <span class="string">"$"</span>
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">CheckPattern</span>(obj, path)
<span class="keyword">local</span> err = schema.<span class="function-name">String</span>(obj, path)
<span class="keyword">if</span> err <span class="keyword">then</span>
<span class="keyword">return</span> err
<span class="keyword">end</span>
<span class="keyword">if</span> <span class="global">string</span>.<span class="function-name">match</span>(obj, pattern) <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">nil</span>
<span class="keyword">else</span>
<span class="keyword">return</span> schema.<span class="function-name">Error</span>(<span class="string">"Invalid value: '"</span>..path..<span class="string">"' must match pattern '"</span>..userPattern..<span class="string">"'"</span>, path)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> CheckPattern
<span class="keyword">end</span>
<span class="comment">-- Checks that some number is an integer.
</span><span class="keyword">function</span> schema.<span class="function-name">Integer</span>(obj, path)
<span class="keyword">local</span> err = schema.<span class="function-name">Number</span>(obj, path)
<span class="keyword">if</span> err <span class="keyword">then</span>
<span class="keyword">return</span> err
<span class="keyword">end</span>
<span class="keyword">if</span> <span class="global">math</span>.<span class="function-name">floor</span>(obj) == obj <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">nil</span>
<span class="keyword">end</span>
<span class="keyword">return</span> schema.<span class="function-name">Error</span>(<span class="string">"Invalid value: '"</span>..path..<span class="string">"' must be an integral number"</span>, path)
<span class="keyword">end</span>
<span class="comment">-- Checks that some number is &gt;= 0.
</span><span class="keyword">function</span> schema.<span class="function-name">NonNegativeNumber</span>(obj, path)
<span class="keyword">local</span> err = schema.<span class="function-name">Number</span>(obj, path)
<span class="keyword">if</span> err <span class="keyword">then</span>
<span class="keyword">return</span> err
<span class="keyword">end</span>
<span class="keyword">if</span> obj &gt;= <span class="number">0</span> <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">nil</span>
<span class="keyword">end</span>
<span class="keyword">return</span> schema.<span class="function-name">Error</span>(<span class="string">"Invalid value: '"</span>..path..<span class="string">"' must be &gt;= 0"</span>, path)
<span class="keyword">end</span>
<span class="comment">-- Checks that some number is &gt; 0.
</span><span class="keyword">function</span> schema.<span class="function-name">PositiveNumber</span>(obj, path)
<span class="keyword">local</span> err = schema.<span class="function-name">Number</span>(obj, path)
<span class="keyword">if</span> err <span class="keyword">then</span>
<span class="keyword">return</span> err
<span class="keyword">end</span>
<span class="keyword">if</span> obj &gt; <span class="number">0</span> <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">nil</span>
<span class="keyword">end</span>
<span class="keyword">return</span> schema.<span class="function-name">Error</span>(<span class="string">"Invalid value: '"</span>..path..<span class="string">"' must be &gt; 0"</span>, path)
<span class="keyword">end</span>
<span class="comment">-- Checks that some value is a number from the interval [lower, upper].
</span><span class="keyword">function</span> schema.<span class="function-name">NumberFrom</span>(lower, upper)
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">CheckNumberFrom</span>(obj, path)
<span class="keyword">local</span> err = schema.<span class="function-name">Number</span>(obj, path)
<span class="keyword">if</span> err <span class="keyword">then</span>
<span class="keyword">return</span> err
<span class="keyword">end</span>
<span class="keyword">if</span> lower &lt;= obj <span class="keyword">and</span> upper &gt;= obj <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">nil</span>
<span class="keyword">else</span>
<span class="keyword">return</span> schema.<span class="function-name">Error</span>(<span class="string">"Invalid value: '"</span>..path..<span class="string">"' must be between "</span>..lower..<span class="string">" and "</span>..upper, path)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> CheckNumberFrom
<span class="keyword">end</span>
<span class="comment">-- Takes schemata and accepts their disjunction.
</span><span class="keyword">function</span> schema.<span class="function-name">OneOf</span>(...)
<span class="keyword">local</span> arg = {...}
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">CheckOneOf</span>(obj, path)
<span class="keyword">for</span> k,v <span class="keyword">in</span> <span class="global">ipairs</span>(arg) <span class="keyword">do</span>
<span class="keyword">local</span> err = schema.<span class="function-name">CheckSchema</span>(obj, v, path)
<span class="keyword">if</span> <span class="keyword">not</span> err <span class="keyword">then</span> <span class="keyword">return</span> <span class="keyword">nil</span> <span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> schema.<span class="function-name">Error</span>(<span class="string">"No suitable alternative: No schema matches '"</span>..path..<span class="string">"'"</span>, path)
<span class="keyword">end</span>
<span class="keyword">return</span> CheckOneOf
<span class="keyword">end</span>
<span class="comment">-- Takes a schema and returns an optional schema.
</span><span class="keyword">function</span> schema.<span class="function-name">Optional</span>(s)
<span class="keyword">return</span> schema.<span class="function-name">OneOf</span>(s, schema.Nil)
<span class="keyword">end</span>
<span class="comment">-- Takes schemata and accepts their conjuction.
</span><span class="keyword">function</span> schema.<span class="function-name">AllOf</span>(...)
<span class="keyword">local</span> arg = {...}
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">CheckAllOf</span>(obj, path)
<span class="keyword">local</span> errmsg = <span class="keyword">nil</span>
<span class="keyword">for</span> k,v <span class="keyword">in</span> <span class="global">ipairs</span>(arg) <span class="keyword">do</span>
<span class="keyword">local</span> err = schema.<span class="function-name">CheckSchema</span>(obj, v, path)
<span class="keyword">if</span> err <span class="keyword">then</span>
<span class="keyword">if</span> errmsg == <span class="keyword">nil</span> <span class="keyword">then</span>
errmsg = err
<span class="keyword">else</span>
errmsg = errmsg:<span class="function-name">append</span>(err)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> errmsg
<span class="keyword">end</span>
<span class="keyword">return</span> CheckAllOf
<span class="keyword">end</span>
<span class="comment">-- Builds a record type schema, i.e. a table with a fixed set of keys (strings)
</span><span class="comment">-- with corresponding values. Use as in
</span><span class="comment">-- Record({
</span><span class="comment">-- name = schema,
</span><span class="comment">-- name2 = schema2
</span><span class="comment">-- })
</span><span class="keyword">function</span> schema.<span class="function-name">Record</span>(recordschema, additionalValues)
<span class="keyword">if</span> additionalValues == <span class="keyword">nil</span> <span class="keyword">then</span>
additionalValues = <span class="keyword">false</span>
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">CheckRecord</span>(obj, path)
<span class="keyword">if</span> <span class="global">type</span>(obj) ~= <span class="string">"table"</span> <span class="keyword">then</span>
<span class="keyword">return</span> schema.<span class="function-name">Error</span>(<span class="string">"Type mismatch: '"</span>..path..<span class="string">"' should be a record (table), is "</span>..<span class="global">type</span>(obj), path)
<span class="keyword">end</span>
<span class="keyword">local</span> errmsg = <span class="keyword">nil</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">AddError</span>(msg)
<span class="keyword">if</span> errmsg == <span class="keyword">nil</span> <span class="keyword">then</span>
errmsg = msg
<span class="keyword">else</span>
errmsg = errmsg:<span class="function-name">append</span>(msg)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">for</span> k,v <span class="keyword">in</span> <span class="global">pairs</span>(recordschema) <span class="keyword">do</span>
path:<span class="function-name">push</span>(k)
<span class="keyword">local</span> err = schema.<span class="function-name">CheckSchema</span>(obj[k], v, path)
<span class="keyword">if</span> err <span class="keyword">then</span>
<span class="function-name">AddError</span>(err)
<span class="keyword">end</span>
path:<span class="function-name">pop</span>()
<span class="keyword">end</span>
<span class="keyword">for</span> k, v <span class="keyword">in</span> <span class="global">pairs</span>(obj) <span class="keyword">do</span>
path:<span class="function-name">push</span>(k)
<span class="keyword">if</span> <span class="global">type</span>(k) ~= <span class="string">"string"</span> <span class="keyword">then</span>
<span class="function-name">AddError</span>(schema.<span class="function-name">Error</span>(<span class="string">"Invalid key: '"</span>..path..<span class="string">"' must be of type 'string'"</span>, path))
<span class="keyword">end</span>
<span class="keyword">if</span> recordschema[k] == <span class="keyword">nil</span> <span class="keyword">and</span> <span class="keyword">not</span> additionalValues <span class="keyword">then</span>
<span class="function-name">AddError</span>(schema.<span class="function-name">Error</span>(<span class="string">"Superfluous value: '"</span>..path..<span class="string">"' does not appear in the record schema"</span>, path))
<span class="keyword">end</span>
path:<span class="function-name">pop</span>()
<span class="keyword">end</span>
<span class="keyword">return</span> errmsg
<span class="keyword">end</span>
<span class="keyword">return</span> CheckRecord
<span class="keyword">end</span>
<span class="keyword">function</span> schema.<span class="function-name">MixedTable</span>(t_schema, additional_values)
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">CheckMixedTable</span>(obj, path)
<span class="keyword">local</span> obj_t = <span class="global">type</span>(obj)
<span class="keyword">if</span> obj_t ~= <span class="string">"table"</span> <span class="keyword">then</span>
<span class="keyword">local</span> msg = (<span class="string">"Type mismatch: '%s' should be a table, is %s"</span>):<span class="function-name">format</span>(path, obj_t)
<span class="keyword">return</span> schema.<span class="function-name">Error</span>(msg, path)
<span class="keyword">end</span>
<span class="keyword">local</span> errmsg = <span class="keyword">nil</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">AddError</span>(msg)
<span class="keyword">if</span> errmsg == <span class="keyword">nil</span> <span class="keyword">then</span>
errmsg = msg
<span class="keyword">else</span>
errmsg = errmsg:<span class="function-name">append</span>(msg)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">local</span> checked_keys = {}
<span class="keyword">for</span> k, v <span class="keyword">in</span> <span class="global">pairs</span>(t_schema) <span class="keyword">do</span>
path:<span class="function-name">push</span>(k)
<span class="keyword">local</span> err = schema.<span class="function-name">CheckSchema</span>(obj[k], v, path)
<span class="keyword">if</span> err <span class="keyword">then</span>
<span class="function-name">AddError</span>(err)
<span class="keyword">end</span>
checked_keys[k] = <span class="keyword">true</span>
path:<span class="function-name">pop</span>()
<span class="keyword">end</span>
<span class="keyword">for</span> k, v <span class="keyword">in</span> <span class="global">pairs</span>(obj) <span class="keyword">do</span>
<span class="keyword">if</span> <span class="keyword">not</span> checked_keys[k] <span class="keyword">then</span>
path:<span class="function-name">push</span>(k)
<span class="keyword">local</span> k_type = <span class="global">type</span>(k)
<span class="keyword">if</span> k_type ~= <span class="string">"string"</span> <span class="keyword">and</span> k_type ~= <span class="string">"number"</span> <span class="keyword">then</span>
<span class="keyword">local</span> msg = (<span class="string">"Invalid key: '%s' must be of type 'string' or 'number'"</span>):<span class="function-name">format</span>(k_type)
<span class="function-name">AddError</span>(schema.<span class="function-name">Error</span>(msg, path))
<span class="keyword">end</span>
<span class="keyword">local</span> t_schema_v = t_schema[k]
<span class="keyword">if</span> t_schema_v <span class="keyword">then</span>
<span class="keyword">local</span> err = schema.<span class="function-name">CheckSchema</span>(v, t_schema_v, path)
<span class="keyword">if</span> err <span class="keyword">then</span>
<span class="function-name">AddError</span>(err)
<span class="keyword">end</span>
<span class="keyword">else</span>
<span class="keyword">if</span> <span class="keyword">not</span> additional_values <span class="keyword">then</span>
<span class="keyword">local</span> msg = (<span class="string">"Superfluous value: '%s' does not appear in the table schema"</span>)
:<span class="function-name">format</span>(path)
<span class="function-name">AddError</span>(schema.<span class="function-name">Error</span>(msg, path))
<span class="keyword">end</span>
<span class="keyword">end</span>
path:<span class="function-name">pop</span>()
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> errmsg
<span class="keyword">end</span>
<span class="keyword">return</span> CheckMixedTable
<span class="keyword">end</span>
<span class="comment">-- Builds a map type schema, i.e. a table with an arbitraty number of
</span><span class="comment">-- entries where both all keys (and all vaules) fit a common schema.
</span><span class="keyword">function</span> schema.<span class="function-name">Map</span>(keyschema, valschema)
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">CheckMap</span>(obj, path)
<span class="keyword">if</span> <span class="global">type</span>(obj) ~= <span class="string">"table"</span> <span class="keyword">then</span>
<span class="keyword">return</span> schema.<span class="function-name">Error</span>(<span class="string">"Type mismatch: '"</span>..path..<span class="string">"' should be a map (table), is "</span>..<span class="global">type</span>(obj), path)
<span class="keyword">end</span>
<span class="keyword">local</span> errmsg = <span class="keyword">nil</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">AddError</span>(msg)
<span class="keyword">if</span> errmsg == <span class="keyword">nil</span> <span class="keyword">then</span>
errmsg = msg
<span class="keyword">else</span>
errmsg = errmsg:<span class="function-name">append</span>(msg)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">-- aggregate error message
</span> <span class="keyword">for</span> k, v <span class="keyword">in</span> <span class="global">pairs</span>(obj) <span class="keyword">do</span>
path:<span class="function-name">push</span>(k)
<span class="keyword">local</span> keyErr = schema.<span class="function-name">CheckSchema</span>(k, keyschema, path)
<span class="keyword">if</span> keyErr <span class="keyword">then</span>
<span class="function-name">AddError</span>(schema.<span class="function-name">Error</span>(<span class="string">"Invalid map key"</span>, path, keyErr))
<span class="keyword">end</span>
<span class="keyword">local</span> valErr = schema.<span class="function-name">CheckSchema</span>(v, valschema, path)
<span class="keyword">if</span> valErr <span class="keyword">then</span>
<span class="function-name">AddError</span>(valErr)
<span class="keyword">end</span>
path:<span class="function-name">pop</span>()
<span class="keyword">end</span>
<span class="keyword">return</span> errmsg
<span class="keyword">end</span>
<span class="keyword">return</span> CheckMap
<span class="keyword">end</span>
<span class="comment">-- Builds a collection type schema, i.e. a table with an arbitrary number of
</span><span class="comment">-- entries where we only care about the type of the values.
</span><span class="keyword">function</span> schema.<span class="function-name">Collection</span>(valschema)
<span class="keyword">return</span> schema.<span class="function-name">Map</span>(schema.Any, valschema)
<span class="keyword">end</span>
<span class="comment">-- Builds a tuple type schema, i.e. a table with a fixed number of entries,
</span><span class="comment">-- each indexed by a number and with a fixed type.
</span><span class="keyword">function</span> schema.<span class="function-name">Tuple</span>(...)
<span class="keyword">local</span> arg = {...}
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">CheckTuple</span>(obj, path)
<span class="keyword">if</span> <span class="global">type</span>(obj) ~= <span class="string">"table"</span> <span class="keyword">then</span>
<span class="keyword">return</span> schema.<span class="function-name">Error</span>(<span class="string">"Type mismatch: '"</span>..path..<span class="string">"' should be a map (tuple), is "</span>..<span class="global">type</span>(obj), path)
<span class="keyword">end</span>
<span class="keyword">if</span> #obj ~= #arg <span class="keyword">then</span>
<span class="keyword">return</span> schema.<span class="function-name">Error</span>(<span class="string">"Invalid length: '"</span>..path..<span class="string">" should have exactly "</span>..#arg..<span class="string">" elements"</span>, path)
<span class="keyword">end</span>
<span class="keyword">local</span> errmsg = <span class="keyword">nil</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">AddError</span>(msg)
<span class="keyword">if</span> errmsg == <span class="keyword">nil</span> <span class="keyword">then</span>
errmsg = msg
<span class="keyword">else</span>
errmsg = errmsg:<span class="function-name">append</span>(msg)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">local</span> min = <span class="number">1</span>
<span class="keyword">local</span> max = #arg
<span class="keyword">for</span> k, v <span class="keyword">in</span> <span class="global">pairs</span>(obj) <span class="keyword">do</span>
path:<span class="function-name">push</span>(k)
<span class="keyword">local</span> err = schema.<span class="function-name">Integer</span>(k, path)
<span class="keyword">if</span> <span class="keyword">not</span> err <span class="keyword">then</span>
err = schema.<span class="function-name">CheckSchema</span>(v, arg[k], path)
<span class="keyword">if</span> err <span class="keyword">then</span>
<span class="function-name">AddError</span>(err)
<span class="keyword">end</span>
<span class="keyword">else</span>
<span class="function-name">AddError</span>(schema.<span class="function-name">Error</span>(<span class="string">"Invalid tuple key"</span>, path, err))
<span class="keyword">end</span>
path:<span class="function-name">pop</span>()
<span class="keyword">end</span>
<span class="keyword">return</span> errmsg
<span class="keyword">end</span>
<span class="keyword">return</span> CheckTuple
<span class="keyword">end</span>
<span class="comment">-- Builds a conditional type schema, i.e. a schema that depends on the value of
</span><span class="comment">-- another value. The dependence must be *local*, i.e. defined in the same
</span><span class="comment">-- table. Use as in
</span><span class="comment">-- Case("name", {"Peter", schema1}, {"Mary", schema2}, {OneOf(...), schema3})
</span><span class="comment">-- This will check the field "name" against every schema in the first component
</span><span class="comment">-- and will return the second component of the first match.
</span><span class="keyword">function</span> schema.<span class="function-name">Case</span>(relativePath, ...)
<span class="keyword">if</span> <span class="global">type</span>(relativePath) ~= <span class="string">"table"</span> <span class="keyword">then</span>
relativePath = schema.<span class="function-name">Path</span>(<span class="string">".."</span>, relativePath)
<span class="keyword">end</span>
<span class="keyword">local</span> cases = {...}
<span class="keyword">for</span> k,v <span class="keyword">in</span> <span class="global">ipairs</span>(cases) <span class="keyword">do</span>
<span class="keyword">if</span> <span class="global">type</span>(v) ~= <span class="string">"table"</span> <span class="keyword">then</span>
<span class="global">error</span>(<span class="string">"Cases expects inputs of the form {conditionSchema, schema}; argument "</span>..v..<span class="string">" is invalid"</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">CheckCase</span>(obj, path)
<span class="keyword">local</span> condPath = path:<span class="function-name">copy</span>()
<span class="keyword">for</span> k=<span class="number">0</span>, #relativePath <span class="keyword">do</span>
<span class="keyword">local</span> s = relativePath:<span class="function-name">get</span>(k)
<span class="keyword">if</span> s == <span class="string">".."</span> <span class="keyword">then</span>
condPath:<span class="function-name">pop</span>()
<span class="keyword">else</span>
condPath:<span class="function-name">push</span>(s)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">local</span> errmsg = <span class="keyword">nil</span>
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">AddError</span>(msg)
<span class="keyword">if</span> errmsg == <span class="keyword">nil</span> <span class="keyword">then</span>
errmsg = msg
<span class="keyword">else</span>
errmsg = errmsg:<span class="function-name">append</span>(msg)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">local</span> anyCond = <span class="keyword">false</span>
<span class="keyword">local</span> condObj = condPath:<span class="function-name">target</span>()
<span class="keyword">for</span> k,v <span class="keyword">in</span> <span class="global">ipairs</span>(cases) <span class="keyword">do</span>
<span class="keyword">local</span> condSchema = v[<span class="number">1</span>]
<span class="keyword">local</span> valSchema = v[<span class="number">2</span>]
<span class="keyword">local</span> condErr = schema.<span class="function-name">CheckSchema</span>(condObj, condSchema, condPath)
<span class="keyword">if</span> <span class="keyword">not</span> condErr <span class="keyword">then</span>
anyCond = <span class="keyword">true</span>
<span class="keyword">local</span> err = schema.<span class="function-name">CheckSchema</span>(obj, valSchema, path)
<span class="keyword">if</span> err <span class="keyword">then</span>
<span class="function-name">AddError</span>(schema.<span class="function-name">Error</span>(<span class="string">"Case failed: Condition "</span>..k..<span class="string">" of '"</span>..path..<span class="string">"' holds but the consequence does not"</span>, path, err))
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">if</span> <span class="keyword">not</span> anyCond <span class="keyword">then</span>
<span class="function-name">AddError</span>(schema.<span class="function-name">Error</span>(<span class="string">"Case failed: No condition on '"</span>..path..<span class="string">"' holds"</span>))
<span class="keyword">end</span>
<span class="keyword">return</span> errmsg
<span class="keyword">end</span>
<span class="keyword">return</span> CheckCase
<span class="keyword">end</span>
<span class="keyword">function</span> schema.<span class="function-name">Test</span>(fn, msg)
<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">CheckTest</span>(obj, path)
<span class="keyword">local</span> pok, ok = <span class="global">pcall</span>(fn, obj)
<span class="keyword">if</span> pok <span class="keyword">and</span> ok <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">nil</span>
<span class="keyword">else</span>
<span class="keyword">return</span> schema.<span class="function-name">Error</span>(<span class="string">"Invalid value: '"</span>..path..(msg <span class="keyword">and</span> <span class="string">"': "</span>..msg <span class="keyword">or</span> <span class="string">""</span>), path)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> CheckTest
<span class="keyword">end</span>
<span class="keyword">return</span> schema</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,613 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><strong>sortbox.lua</strong></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>sortbox.lua</h2>
<pre>
<span class="comment">---An H/VBox alternative which can be set to either vertical or horizontal, and will autosort the windows
</span><span class="comment">-- @classmod SortBox
</span><span class="comment">-- @author Damian Monogue &lt;demonnic@gmail.com&gt;
</span><span class="comment">-- @copyright 2020 Damian Monogue
</span><span class="comment">-- @license MIT, see LICENSE.lua
</span><span class="keyword">local</span> SortBox = Geyser.Container:<span class="function-name">new</span>({
name = <span class="string">"SortBoxClass"</span>,
autoSort = <span class="keyword">true</span>,
timerSort = <span class="keyword">true</span>,
sortInterval = <span class="number">500</span>,
elastic = <span class="keyword">false</span>,
maxHeight = <span class="number">0</span>,
maxWidth = <span class="number">0</span>,
boxType = <span class="string">"v"</span>,
sortFunction = <span class="string">"gaugeValue"</span>,
})
<span class="keyword">local</span> BIGNUMBER = <span class="number">999999999</span>
<span class="comment">--- Sorting functions for spairs, should you wish
</span><span class="comment">-- @table SortFunctions
</span><span class="comment">-- @field gaugeValue sorts Geyser gauges by value, ascending
</span><span class="comment">-- @field reverseGaugeValue sorts Geyser gauges by value, descending
</span><span class="comment">-- @field timeLeft sorts TimerGauges by how much time is left, ascending
</span><span class="comment">-- @field reverseTimeLeft sorts TimerGauges by how much time is left, descending.
</span><span class="comment">-- @field name sorts Geyser objects by name, ascending
</span><span class="comment">-- @field reverseName sorts Geyser objects by name, descending
</span><span class="comment">-- @field message sorts Geyser labels and gauges by their echoed text, ascending
</span><a id="29"></a><span class="comment">-- @field reverseMessage sorts Geyser labels and gauges by their echoed text, descending
</span>SortBox.SortFunctions = {
gaugeValue = <span class="keyword">function</span>(t, a, b)
<span class="keyword">local</span> avalue = t[a].value <span class="keyword">or</span> BIGNUMBER
<span class="keyword">local</span> bvalue = t[b].value <span class="keyword">or</span> BIGNUMBER
<span class="keyword">return</span> avalue &lt; bvalue
<span class="keyword">end</span>,
reverseGaugeValue = <span class="keyword">function</span>(t, a, b)
<span class="keyword">local</span> avalue = t[a].value <span class="keyword">or</span> BIGNUMBER
<span class="keyword">local</span> bvalue = t[b].value <span class="keyword">or</span> BIGNUMBER
<span class="keyword">return</span> avalue &gt; bvalue
<span class="keyword">end</span>,
timeLeft = <span class="keyword">function</span>(t, a, b)
a = t[a]
b = t[b]
<span class="keyword">local</span> avalue = a.getTime <span class="keyword">and</span> <span class="global">tonumber</span>(a:<span class="function-name">getTime</span>(<span class="string">"S.mm"</span>)) <span class="keyword">or</span> BIGNUMBER
<span class="keyword">local</span> bvalue = b.getTime <span class="keyword">and</span> <span class="global">tonumber</span>(b:<span class="function-name">getTime</span>(<span class="string">"S.mm"</span>)) <span class="keyword">or</span> BIGNUMBER
<span class="keyword">return</span> avalue &lt; bvalue
<span class="keyword">end</span>,
reverseTimeLeft = <span class="keyword">function</span>(t, a, b)
a = t[a]
b = t[b]
<span class="keyword">local</span> avalue = a.getTime <span class="keyword">and</span> <span class="global">tonumber</span>(a:<span class="function-name">getTime</span>(<span class="string">"S.mm"</span>)) <span class="keyword">or</span> BIGNUMBER
<span class="keyword">local</span> bvalue = b.getTime <span class="keyword">and</span> <span class="global">tonumber</span>(b:<span class="function-name">getTime</span>(<span class="string">"S.mm"</span>)) <span class="keyword">or</span> BIGNUMBER
<span class="keyword">return</span> avalue &gt; bvalue
<span class="keyword">end</span>,
name = <span class="keyword">function</span>(t, a, b)
<span class="keyword">return</span> t[a].name &lt; t[b].name
<span class="keyword">end</span>,
reverseName = <span class="keyword">function</span>(t, a, b)
<span class="keyword">return</span> t[a].name &gt; t[b].name
<span class="keyword">end</span>,
message = <span class="keyword">function</span>(t, a, b)
a = t[a]
b = t[b]
<span class="keyword">local</span> avalue = a.text <span class="keyword">and</span> a.text.message <span class="keyword">or</span> a.message
<span class="keyword">local</span> bvalue = b.text <span class="keyword">and</span> b.text.message <span class="keyword">or</span> b.message
avalue = avalue <span class="keyword">or</span> <span class="string">""</span>
bvalue = bvalue <span class="keyword">or</span> <span class="string">""</span>
<span class="keyword">return</span> avalue &lt; bvalue
<span class="keyword">end</span>,
reverseMessage = <span class="keyword">function</span>(t, a, b)
a = t[a]
b = t[b]
<span class="keyword">local</span> avalue = a.text <span class="keyword">and</span> a.text.message <span class="keyword">or</span> a.message
<span class="keyword">local</span> bvalue = b.text <span class="keyword">and</span> b.text.message <span class="keyword">or</span> b.message
avalue = avalue <span class="keyword">or</span> <span class="string">""</span>
bvalue = bvalue <span class="keyword">or</span> <span class="string">""</span>
<span class="keyword">return</span> avalue &gt; bvalue
<span class="keyword">end</span>,
}
<span class="comment">--- Creates a new SortBox
</span><span class="comment">-- @usage
</span><span class="comment">-- local SortBox = require("MDK.sortbox")
</span><span class="comment">-- mySortBox = SortBox:new({
</span><span class="comment">-- name = "mySortBox",
</span><span class="comment">-- x = 400,
</span><span class="comment">-- y = 100,
</span><span class="comment">-- height = 150,
</span><span class="comment">-- width = 300,
</span><span class="comment">-- sortFunction = "timeLeft"
</span><span class="comment">-- })
</span><span class="comment">-- @tparam table options the options to use for the SortBox. See table below for added options
</span><span class="comment">-- @param[opt] container the container to add the SortBox into
</span><span class="comment">-- &lt;br&gt;&lt;br&gt;Table of new options
</span><span class="comment">-- &lt;table class="tg"&gt;
</span><span class="comment">-- &lt;thead&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;th&gt;option name&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;description&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;default&lt;/th&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/thead&gt;
</span><span class="comment">-- &lt;tbody&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;autoSort&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;should the SortBox perform function based sorting? If false, will behave like a normal H/VBox&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;true&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;timerSort&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;should the SortBox automatically perform sorting on a timer?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;true&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;sortInterval&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;how frequently should we sort on a timer if timerSort is true, in milliseconds&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;500&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;boxType&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;Should we stack like an HBox or VBox? use 'h' for hbox and 'v' for vbox&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;v&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;sortFunction&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;how should we sort the items in the SortBox? see setSortFunction for valid options&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;gaugeValue&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;elastic&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;Should this container stretch to fit its contents? boxType v stretches in height, h stretches in width.&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;false&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;maxHeight&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;If elastic, what's the biggest a 'v' style box should grow in height? Use 0 for unlimited&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;0&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;maxWidth&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;If elastic, what's the biggest a 'h' style box should grow in width? Use 0 for unlimited&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;0&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/tbody&gt;
</span><a id="144"></a><span class="comment">-- &lt;/table&gt;
</span><span class="keyword">function</span> SortBox:<span class="function-name">new</span>(options, container)
options = options <span class="keyword">or</span> {}
options.<span class="global">type</span> = options.<span class="global">type</span> <span class="keyword">or</span> <span class="string">"SortBox"</span>
<span class="keyword">local</span> me = self.parent:<span class="function-name">new</span>(options, container)
<span class="global">setmetatable</span>(me, self)
self.__index = self
<span class="keyword">if</span> me.timerSort <span class="keyword">then</span>
me:<span class="function-name">enableTimer</span>()
<span class="keyword">end</span>
me:<span class="function-name">setBoxType</span>(me.boxType)
<span class="keyword">return</span> me
<span class="keyword">end</span>
<span class="comment">--- Iterates a key:value pair table in a sorted fashion
</span><span class="comment">-- @local
</span><span class="comment">-- I first found this on https://stackoverflow.com/questions/15706270/sort-a-table-in-lua
</span><span class="comment">-- modified slightly, as Mudlet already has table.keys to collect keys, and I don't want
</span><span class="comment">-- to sort if no function to sort with is given. In this case, I want it to work like pairs.
</span><span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">spairs</span>(t, order)
<span class="keyword">local</span> keys = <span class="global">table</span>.<span class="function-name">keys</span>(t)
<span class="keyword">if</span> order <span class="keyword">then</span>
<span class="global">table</span>.<span class="function-name">sort</span>(keys, <span class="keyword">function</span>(a, b)
<span class="keyword">return</span> <span class="function-name">order</span>(t, a, b)
<span class="keyword">end</span>)
<span class="keyword">end</span>
<span class="keyword">local</span> i = <span class="number">0</span>
<span class="keyword">return</span> <span class="keyword">function</span>()
i = i + <span class="number">1</span>
<span class="keyword">if</span> keys[i] <span class="keyword">then</span>
<span class="keyword">return</span> keys[i], t[keys[i]]
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">function</span> SortBox:<span class="function-name">add</span>(window, cons)
<span class="keyword">if</span> self.useAdd2 <span class="keyword">then</span>
Geyser.<span class="function-name">add2</span>(self, window, cons)
<span class="keyword">else</span>
Geyser.<span class="function-name">add</span>(self, window, cons)
<span class="keyword">end</span>
<span class="keyword">if</span> <span class="keyword">not</span> self.defer_updates <span class="keyword">then</span>
self:<span class="function-name">organize</span>()
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">function</span> SortBox:<span class="function-name">remove</span>(window)
Geyser.<span class="function-name">remove</span>(self, window)
self:<span class="function-name">organize</span>()
<span class="keyword">end</span>
<a id="196"></a><span class="comment">--- Calling this will cause the SortBox to reposition/resize everything
</span><span class="keyword">function</span> SortBox:<span class="function-name">organize</span>()
<span class="comment">-- make sure we don't divide by zero later
</span> <span class="keyword">if</span> self:<span class="function-name">get_width</span>() == <span class="number">0</span> <span class="keyword">then</span>
self:<span class="function-name">resize</span>(<span class="string">"0.9px"</span>, <span class="keyword">nil</span>)
<span class="keyword">end</span>
<span class="keyword">if</span> self:<span class="function-name">get_height</span>() == <span class="number">0</span> <span class="keyword">then</span>
self:<span class="function-name">resize</span>(<span class="keyword">nil</span>, <span class="string">"0.9px"</span>)
<span class="keyword">end</span>
<span class="comment">-- handle the individual boxType organization
</span> <span class="keyword">if</span> self.boxType == <span class="string">"v"</span> <span class="keyword">then</span>
self:<span class="function-name">vorganize</span>()
<span class="keyword">else</span>
self:<span class="function-name">horganize</span>()
<span class="keyword">end</span>
<span class="comment">-- shrink/grow if needed
</span> self:<span class="function-name">handleElastic</span>()
<span class="keyword">end</span>
<span class="comment">--- replicates Geyser.HBox functionality, but with the option of sorting
</span><span class="comment">-- @local
</span><span class="keyword">function</span> SortBox:<span class="function-name">horganize</span>()
<span class="keyword">local</span> window_width = (self:<span class="function-name">calculate_dynamic_window_size</span>().width / self:<span class="function-name">get_width</span>()) * <span class="number">100</span>
<span class="keyword">local</span> start_x = <span class="number">0</span>
<span class="keyword">local</span> sortFunction = (self.autoSort <span class="keyword">and</span> self.sortFunction) <span class="keyword">and</span> SortBox.SortFunctions[self.sortFunction] <span class="keyword">or</span> <span class="keyword">nil</span>
<span class="keyword">if</span> sortFunction <span class="keyword">then</span>
<span class="keyword">for</span> _, window <span class="keyword">in</span> <span class="function-name">spairs</span>(self.windowList, sortFunction) <span class="keyword">do</span>
start_x = start_x + self:<span class="function-name">handleWindow</span>(window, start_x, window_width)
<span class="keyword">end</span>
<span class="keyword">else</span>
<span class="keyword">for</span> _, window_name <span class="keyword">in</span> <span class="global">ipairs</span>(self.windows) <span class="keyword">do</span>
<span class="keyword">local</span> window = self.windowList[window_name]
start_x = start_x + self:<span class="function-name">handleWindow</span>(window, start_x, window_width)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- replicates Geyser.VBox functionality, but with the option of sorting
</span><span class="comment">-- @local
</span><span class="keyword">function</span> SortBox:<span class="function-name">vorganize</span>()
<span class="keyword">local</span> window_height = (self:<span class="function-name">calculate_dynamic_window_size</span>().height / self:<span class="function-name">get_height</span>()) * <span class="number">100</span>
<span class="keyword">local</span> start_y = <span class="number">0</span>
<span class="keyword">local</span> sortFunction = (self.autoSort <span class="keyword">and</span> self.sortFunction) <span class="keyword">and</span> SortBox.SortFunctions[self.sortFunction] <span class="keyword">or</span> <span class="keyword">nil</span>
<span class="keyword">if</span> sortFunction <span class="keyword">then</span>
<span class="keyword">for</span> _, window <span class="keyword">in</span> <span class="function-name">spairs</span>(self.windowList, sortFunction) <span class="keyword">do</span>
start_y = start_y + self:<span class="function-name">handleWindow</span>(window, start_y, window_height)
<span class="keyword">end</span>
<span class="keyword">else</span>
<span class="keyword">for</span> _, window_name <span class="keyword">in</span> <span class="global">ipairs</span>(self.windows) <span class="keyword">do</span>
<span class="keyword">local</span> window = self.windowList[window_name]
start_y = start_y + self:<span class="function-name">handleWindow</span>(window, start_y, window_height)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- handles a single window during the shuffle process
</span><span class="comment">-- @local
</span><span class="keyword">function</span> SortBox:<span class="function-name">handleWindow</span>(window, start, window_dimension)
<span class="keyword">local</span> width = (window:<span class="function-name">get_width</span>() / self:<span class="function-name">get_width</span>()) * <span class="number">100</span>
<span class="keyword">local</span> height = (window:<span class="function-name">get_height</span>() / self:<span class="function-name">get_height</span>()) * <span class="number">100</span>
<span class="keyword">if</span> window.h_policy == Geyser.Fixed <span class="keyword">or</span> window.v_policy == Geyser.Fixed <span class="keyword">then</span>
self.contains_fixed = <span class="keyword">true</span>
<span class="keyword">end</span>
<span class="keyword">if</span> self.boxType == <span class="string">"v"</span> <span class="keyword">then</span>
window:<span class="function-name">move</span>(<span class="string">"0%"</span>, start .. <span class="string">"%"</span>)
<span class="keyword">if</span> window.h_policy == Geyser.Dynamic <span class="keyword">then</span>
width = <span class="number">100</span>
<span class="keyword">if</span> window.width ~= width <span class="keyword">then</span>
window:<span class="function-name">resize</span>(width .. <span class="string">"%"</span>, <span class="keyword">nil</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">if</span> window.v_policy == Geyser.Dynamic <span class="keyword">then</span>
height = window_dimension * window.v_stretch_factor
<span class="keyword">if</span> window.height ~= height <span class="keyword">then</span>
window:<span class="function-name">resize</span>(<span class="keyword">nil</span>, height .. <span class="string">"%"</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> height
<span class="keyword">else</span>
window:<span class="function-name">move</span>(start .. <span class="string">"%"</span>, <span class="string">"0%"</span>)
<span class="keyword">if</span> window.h_policy == Geyser.Dynamic <span class="keyword">then</span>
width = window_dimension * window.h_stretch_factor
<span class="keyword">if</span> window.width ~= width <span class="keyword">then</span>
window:<span class="function-name">resize</span>(width .. <span class="string">"%"</span>, <span class="keyword">nil</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">if</span> window.v_policy == Geyser.Dynamic <span class="keyword">then</span>
height = <span class="number">100</span>
<span class="keyword">if</span> window.height ~= height <span class="keyword">then</span>
window:<span class="function-name">resize</span>(<span class="keyword">nil</span>, height .. <span class="string">"%"</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> width
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">---handles actually resizing the window if elastic
</span><span class="comment">-- @local
</span><span class="keyword">function</span> SortBox:<span class="function-name">handleElastic</span>()
<span class="keyword">if</span> <span class="keyword">not</span> self.elastic <span class="keyword">or</span> <span class="global">table</span>.<span class="function-name">is_empty</span>(self.windows) <span class="keyword">then</span>
<span class="keyword">return</span>
<span class="keyword">end</span>
<span class="keyword">if</span> self.boxType == <span class="string">"v"</span> <span class="keyword">then</span>
<span class="keyword">local</span> contentHeight, canElastic = self:<span class="function-name">getContentHeight</span>()
<span class="keyword">if</span> <span class="keyword">not</span> canElastic <span class="keyword">then</span>
<span class="function-name">debugc</span>(<span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"SortBox named %s cannot properly elasticize, as it contains at least one item with a dynamic v_policy"</span>, self.name))
<span class="keyword">return</span>
<span class="keyword">end</span>
<span class="keyword">local</span> currentHeight = self:<span class="function-name">get_height</span>()
<span class="keyword">local</span> maxHeight = self.maxHeight
<span class="keyword">if</span> maxHeight &gt; <span class="number">0</span> <span class="keyword">and</span> contentHeight &gt; maxHeight <span class="keyword">then</span>
contentHeight = maxHeight
<span class="keyword">end</span>
<span class="keyword">if</span> contentHeight ~= currentHeight <span class="keyword">then</span>
self:<span class="function-name">resize</span>(<span class="keyword">nil</span>, contentHeight)
<span class="keyword">end</span>
<span class="keyword">else</span>
<span class="keyword">local</span> contentWidth, canElastic = self:<span class="function-name">getContentWidth</span>()
<span class="keyword">if</span> <span class="keyword">not</span> canElastic <span class="keyword">then</span>
<span class="function-name">debugc</span>(<span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"SortBox named %s cannot properly elasticize, as it contains at least one item with a dynamic h_policy"</span>, self.name))
<span class="keyword">return</span>
<span class="keyword">end</span>
<span class="keyword">local</span> currentWidth = self:<span class="function-name">get_width</span>()
<span class="keyword">local</span> maxWidth = self.maxWidth
<span class="keyword">if</span> maxWidth &gt; <span class="number">0</span> <span class="keyword">and</span> contentWidth &gt; maxWidth <span class="keyword">then</span>
contentWidth = maxWidth
<span class="keyword">end</span>
<span class="keyword">if</span> contentWidth ~= currentWidth <span class="keyword">then</span>
self:<span class="function-name">resize</span>(contentWidth, <span class="keyword">nil</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">---prevents gaps from forming during resize if it doesn't autoorganize on a timer.
</span><span class="comment">-- @local
</span><span class="keyword">function</span> SortBox:<span class="function-name">reposition</span>()
Geyser.Container.<span class="function-name">reposition</span>(self)
<span class="keyword">if</span> self.contains_fixed <span class="keyword">then</span>
self:<span class="function-name">organize</span>()
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Returns the sum of the heights of the contents, and whether this SortBox can be elastic in height
</span><span class="comment">-- @local
</span><span class="keyword">function</span> SortBox:<span class="function-name">getContentHeight</span>()
<span class="keyword">if</span> self.boxType ~= <span class="string">"v"</span> <span class="keyword">then</span>
<span class="keyword">return</span> self:<span class="function-name">get_height</span>()
<span class="keyword">end</span>
<span class="keyword">local</span> canElastic = <span class="keyword">true</span>
<span class="keyword">local</span> contentHeight = <span class="number">0</span>
<span class="keyword">for</span> _, window <span class="keyword">in</span> <span class="global">pairs</span>(self.windowList) <span class="keyword">do</span>
contentHeight = contentHeight + window:<span class="function-name">get_height</span>()
<span class="keyword">if</span> window.v_policy == Geyser.Dynamic <span class="keyword">then</span>
canElastic = <span class="keyword">false</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> contentHeight, canElastic
<span class="keyword">end</span>
<span class="comment">--- Returns the sum of the widths of the contents, and whether this SortBox can be elastic in width.
</span><span class="comment">-- @local
</span><span class="keyword">function</span> SortBox:<span class="function-name">getContentWidth</span>()
<span class="keyword">if</span> self.boxType == <span class="string">"v"</span> <span class="keyword">then</span>
<span class="keyword">return</span> self:<span class="function-name">get_width</span>()
<span class="keyword">end</span>
<span class="keyword">local</span> canElastic = <span class="keyword">true</span>
<span class="keyword">local</span> contentWidth = <span class="number">0</span>
<span class="keyword">for</span> _, window <span class="keyword">in</span> <span class="global">pairs</span>(self.windowList) <span class="keyword">do</span>
contentWidth = contentWidth + window:<span class="function-name">get_width</span>()
<span class="keyword">if</span> window.h_policy == Geyser.Dynamic <span class="keyword">then</span>
canElastic = <span class="keyword">false</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">return</span> contentWidth, canElastic
<span class="keyword">end</span>
<a id="372"></a><span class="comment">--- Enables elasticity for the SortBox.
</span><span class="keyword">function</span> SortBox:<span class="function-name">enableElastic</span>()
self:<span class="function-name">setElastic</span>(<span class="keyword">true</span>)
<span class="keyword">end</span>
<a id="377"></a><span class="comment">--- Disables elasticity for the SortBox
</span><span class="keyword">function</span> SortBox:<span class="function-name">disableElastic</span>()
self:<span class="function-name">setElastic</span>(<span class="keyword">false</span>)
<span class="keyword">end</span>
<span class="comment">--- Set elasticity specifically
</span><a id="383"></a><span class="comment">-- @tparam boolean enabled if true, enable elasticity. If false, disable it.
</span><span class="keyword">function</span> SortBox:<span class="function-name">setElastic</span>(enabled)
self.elastic = enabled <span class="keyword">and</span> <span class="keyword">true</span> <span class="keyword">or</span> <span class="keyword">false</span>
<span class="keyword">end</span>
<span class="comment">--- Set the max width of the SortBox if it's elastic
</span><a id="389"></a><span class="comment">-- @tparam number maxWidth The maximum width in pixels to resize the SortBox to. Use 0 for unlimited.
</span><span class="keyword">function</span> SortBox:<span class="function-name">setMaxWidth</span>(maxWidth)
<span class="keyword">local</span> mwtype = <span class="global">type</span>(maxWidth)
<span class="global">assert</span>(mwtype == <span class="string">"number"</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"SortBox:setMaxWidth(maxWidth): SortBox: %s maxWidth as number expected, got %s"</span>, self.name, mwtype))
<span class="global">assert</span>(maxWidth &gt;= <span class="number">0</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"SortBox:setMaxWidth(maxWidth): SortBox: %s maxWidth must be &gt;= 0, %d"</span>, self.name, maxWidth))
self.maxWidth = maxWidth
<span class="keyword">end</span>
<span class="comment">--- Set the max height of the SortBox if it's elastic
</span><a id="398"></a><span class="comment">-- @tparam number maxHeight The maximum height in pixels to resize the SortBox to. Use 0 for unlimited.
</span><span class="keyword">function</span> SortBox:<span class="function-name">setMaxHeight</span>(maxHeight)
<span class="keyword">local</span> mhtype = <span class="global">type</span>(maxHeight)
<span class="global">assert</span>(mhtype == <span class="string">"number"</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"SortBox:setMaxHeight(maxHeight): SortBox: %s maxHeight as number expected, got %s"</span>, self.name, mhtype))
<span class="global">assert</span>(maxHeight &gt;= <span class="number">0</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"SortBox:setMaxHeight(maxHeight): SortBox: %s maxHeight must be &gt;= 0, %d"</span>, self.name, maxHeight))
self.maxHeight = maxHeight
<span class="keyword">end</span>
<a id="406"></a><span class="comment">--- Starts the SortBox sorting and organizing itself on a timer
</span><span class="keyword">function</span> SortBox:<span class="function-name">enableTimer</span>()
<span class="keyword">if</span> self.timerID <span class="keyword">then</span>
self:<span class="function-name">disableTimer</span>()
<span class="keyword">end</span>
self.timerSort = <span class="keyword">true</span>
self.timerID = <span class="function-name">tempTimer</span>(self.sortInterval / <span class="number">1000</span>, <span class="keyword">function</span>()
self:<span class="function-name">organize</span>()
<span class="keyword">end</span>, <span class="keyword">true</span>)
<span class="keyword">end</span>
<a id="417"></a><span class="comment">--- Stops the SortBox from sorting and organizing itself on a timer
</span><span class="keyword">function</span> SortBox:<span class="function-name">disableTimer</span>()
<span class="function-name">killTimer</span>(self.timerID)
self.timerID = <span class="keyword">nil</span>
self.timerSort = <span class="keyword">false</span>
<span class="keyword">end</span>
<span class="comment">--- Sets the sortInterval, or amount of time in milliseconds between auto sorting on a timer if timerSort is true
</span><a id="425"></a><span class="comment">-- @tparam number sortInterval time in milliseconds between auto sorting if timerSort is true
</span><span class="keyword">function</span> SortBox:<span class="function-name">setSortInterval</span>(sortInterval)
<span class="keyword">local</span> sitype = <span class="global">type</span>(sortInterval)
<span class="global">assert</span>(sitype == <span class="string">"number"</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"SortBox:setSortInterval(sortInterval): sortInterval as number expected, got %s"</span>, sitype))
<span class="global">assert</span>(sortInterval &gt; <span class="number">0</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"SortBox:setSortInterval(sortInterval): sortInterval must be positive"</span>))
self.sortInterval = sortInterval
<span class="keyword">if</span> self.timerSort <span class="keyword">then</span>
self:<span class="function-name">enableTimer</span>()
<span class="keyword">end</span>
<span class="keyword">end</span>
<a id="436"></a><span class="comment">--- Enables sorting when items are added/removed, or if timerSort is true, every sortInterval milliseconds
</span><span class="keyword">function</span> SortBox:<span class="function-name">enableSort</span>()
self.autoSort = <span class="keyword">true</span>
self:<span class="function-name">organize</span>()
<span class="keyword">end</span>
<a id="442"></a><span class="comment">--- Disables sorting when items are added or removed
</span><span class="keyword">function</span> SortBox:<span class="function-name">disableSort</span>()
self.autoSort = <span class="keyword">false</span>
<span class="keyword">end</span>
<span class="comment">---Set whether the SortBox acts as a VBox or HBox.
</span><span class="comment">-- @tparam string boxType If you pass 'h' or 'horizontal' it will act like an HBox. Anything else it will act like a VBox.
</span><span class="comment">-- @usage mySortBox:setBoxType("v") -- behave like a VBox
</span><span class="comment">-- mySortBox:setBoxType("h") -- behave like an HBox
</span><a id="451"></a><span class="comment">-- mySortBox:setBoxType("beeblebrox") -- why?! Why would you do this? It'll behave like a VBox
</span><span class="keyword">function</span> SortBox:<span class="function-name">setBoxType</span>(boxType)
boxType = boxType:<span class="function-name">lower</span>()
<span class="keyword">if</span> boxType == <span class="string">"h"</span> <span class="keyword">or</span> boxType == <span class="string">"horizontal"</span> <span class="keyword">then</span>
self.boxType = <span class="string">"h"</span>
<span class="keyword">else</span>
self.boxType = <span class="string">"v"</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">---Sets the type of sorting in use by this SortBox.
</span><span class="comment">-- &lt;br&gt;If an item in the box does not have the appropriate property or function, then 999999999 is used for sorting except as otherwise noted.
</span><span class="comment">-- &lt;br&gt;If an invalid option is given, then existing H/VBox behaviour is maintained, just like if autoSort is false.
</span><span class="comment">-- @usage mySortBox:setSortFunction("gaugeValue")
</span><span class="comment">-- @tparam string functionName what type of sorting should we use? See table below for valid options and their descriptions.
</span><span class="comment">-- &lt;table class="tg"&gt;
</span><span class="comment">-- &lt;thead&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;th&gt;sort type&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;description&lt;/th&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/thead&gt;
</span><span class="comment">-- &lt;tbody&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;gaugeValue&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;sort gauges based on how full the gauge is, from less full to more&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;reverseGaugeValue&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;sort gauges based on how full the gauge is, from more full to less&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;timeLeft&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;sort TimerGauges based on the total time left in the gauge, from less time to more&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;reverseTimeLeft&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;sort TimerGauges based on the total time left in the gauge, from more time to less&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;name&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;sort any item (and mixed types) by name, alphabetically.&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;reverseName&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;sort any item (and mixed types) by name, reverse alphabetically.&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;message&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;sorts Labels based on their echoed message, alphabetically. If not a label, the empty string will be used&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;reverseMessage&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;sorts Labels based on their echoed message, reverse alphabetically. If not a label, the empty string will be used&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/tbody&gt;
</span><span class="comment">-- &lt;/table&gt;
</span><a id="508"></a>
<span class="keyword">function</span> SortBox:<span class="function-name">setSortFunction</span>(functionName)
self.sortFunction = functionName
<span class="keyword">end</span>
SortBox.parent = Geyser.Container
<span class="keyword">return</span> SortBox</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,580 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><strong>spinbox.lua</strong></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>spinbox.lua</h2>
<pre>
<span class="comment">--- A Geyser object to create a spinbox for adjusting a number
</span><span class="comment">-- @classmod spinbox
</span><span class="comment">-- @author Damian Monogue &lt;demonnic@gmail.com&gt;
</span><span class="comment">-- @copyright 2023
</span><span class="comment">-- @license MIT, see https://raw.githubusercontent.com/demonnic/MDK/main/src/scripts/LICENSE.lua
</span><span class="keyword">local</span> spinbox = {
parent = Geyser.Container,
name = <span class="string">'SpinboxClass'</span>,
min = <span class="number">0</span>,
max = <span class="number">10</span>,
delta = <span class="number">1</span>,
value = <span class="number">0</span>,
activeButtonColor = <span class="string">"gray"</span>,
inactiveButtonColor = <span class="string">"DimGray"</span>,
integer = <span class="keyword">true</span>,
upArrowLocation = <span class="string">"https://demonnic.github.io/image-assets/uparrow.png"</span>,
downArrowLocation = <span class="string">"https://demonnic.github.io/image-assets/downarrow.png"</span>,
color = <span class="string">"#202020"</span>
}
spinbox.__index = spinbox
<span class="global">setmetatable</span>(spinbox, spinbox.parent)
<span class="keyword">local</span> gss = Geyser.StyleSheet
<span class="keyword">local</span> directory = <span class="function-name">getMudletHomeDir</span>() .. <span class="string">"/spinbox/"</span>
<span class="keyword">local</span> saveFile = directory .. <span class="string">"fileLocations.lua"</span>
<span class="keyword">if</span> <span class="keyword">not</span> <span class="global">io</span>.<span class="function-name">exists</span>(directory) <span class="keyword">then</span>
lfs.<span class="function-name">mkdir</span>(directory)
<span class="keyword">end</span>
<span class="comment">--- Creates a new spinbox.
</span><span class="comment">-- @tparam table cons a table containing the options for this spinbox.
</span><span class="comment">-- &lt;table class="tg"&gt;
</span><span class="comment">-- &lt;thead&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;th&gt;option name&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;description&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;default&lt;/th&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/thead&gt;
</span><span class="comment">-- &lt;tbody&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;min&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;The minimum value for this spinbox&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;0&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;max&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;The maximum value for this spinbox&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;10&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;activeButtonColor&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;The color the up/down buttons should be when they are active/able to be used&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;gray&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;inactiveButtonColor&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;The color the up/down buttons should be when they are inactive/unable to be used&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;dimgray&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;integer&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;Boolean value. When true, values must always be integers (no decimal place)&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;true&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;delta&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;The amount to change the spinbox's value when the up or down button is pressed.&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;1&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;upArrowLocation&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;The location of the up arrow image. Either a web URL where it can be downloaded, or the location on disk to read it from&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;https://demonnic.github.io/image-assets/uparrow.png&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;downArrowLocation&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;The location of the down arrow image. Either a web URL where it can be downloaded, or the location on disk to read it from&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;https://demonnic.github.io/image-assets/downarrow.png&lt;/td&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;callBack&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;The function to run when the spinbox's value is updated. Is called with parameters (self.name, value, oldValue)&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;nil&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">--&lt;/tbody&gt;
</span><span class="comment">--&lt;/table&gt;
</span><a id="89"></a><span class="comment">-- @param container The Geyser container for this spinbox
</span><span class="keyword">function</span> spinbox:<span class="function-name">new</span>(cons, container)
cons = cons <span class="keyword">or</span> {}
<span class="keyword">local</span> consType = <span class="global">type</span>(cons)
<span class="keyword">if</span> consType ~= <span class="string">"table"</span> <span class="keyword">then</span>
<span class="function-name">printError</span>(<span class="function-name">f</span><span class="string">"spinbox:new(cons, container): cons as table of options expected, got {consType}!"</span>, <span class="keyword">true</span>, <span class="keyword">true</span>)
<span class="keyword">end</span>
cons.name = cons.name <span class="keyword">or</span> Geyser.<span class="function-name">nameGen</span>(<span class="string">"spinbox"</span>)
<span class="keyword">local</span> me = self.parent:<span class="function-name">new</span>(cons, container)
<span class="global">setmetatable</span>(me, self)
me:<span class="function-name">createComponents</span>()
<span class="keyword">if</span> me.callBack <span class="keyword">then</span>
me:<span class="function-name">setCallBack</span>(me.callBack)
<span class="keyword">end</span>
me.oldValue = me.value
<span class="keyword">return</span> me
<span class="keyword">end</span>
<span class="comment">--- Creates the components that make up the spinbox UI.
</span><span class="comment">-- @local
</span><span class="comment">-- Obtains the up and down arrow images specified in the spinbox options.
</span><span class="comment">-- Generates styles for the spinbox.
</span><span class="comment">-- Calculates the height of the up/down buttons and any remainder space.
</span><span class="comment">-- Creates:
</span><span class="comment">-- `self.upButton` - A button with an up arrow image for incrementing the value
</span><span class="comment">-- `self.downButton` - A button with a down arrow image for decrementing the value
</span><span class="comment">-- `self.displayLabel` - A label to display the current spinbox value
</span><span class="comment">-- `self.input` - A command line input to allow directly entering a value
</span><span class="comment">-- Hides the input by default.
</span><span class="comment">-- Applies the generated styles.
</span><span class="keyword">function</span> spinbox:<span class="function-name">createComponents</span>()
self:<span class="function-name">obtainImages</span>()
self:<span class="function-name">generateStyles</span>()
self:<span class="function-name">calculateButtonDimensions</span>()
self.upButton = self:<span class="function-name">createButton</span>(<span class="string">"up"</span>)
self.downButton = self:<span class="function-name">createButton</span>(<span class="string">"down"</span>)
self.displayLabel = self:<span class="function-name">createDisplayLabel</span>()
self.input = self:<span class="function-name">createInput</span>()
self.input:<span class="function-name">hide</span>()
self:<span class="function-name">applyStyles</span>()
<span class="keyword">end</span>
<span class="comment">--- Calculates the button height. We use square buttons in this house.
</span><span class="comment">-- @local
</span><span class="comment">-- Calculates the height of the up/down buttons by dividing the spinbox height in half.
</span><span class="comment">-- Stores the remainder (if any) in self.remainder.
</span><span class="comment">-- Stores the calculated button height in self.buttonHeight.
</span><span class="keyword">function</span> spinbox:<span class="function-name">calculateButtonDimensions</span>()
self.buttonHeight = <span class="global">math</span>.<span class="function-name">floor</span>(self.<span class="function-name">get_height</span>() / <span class="number">2</span>)
self.remainder = self.<span class="function-name">get_height</span>() % <span class="number">2</span>
<span class="keyword">end</span>
<span class="comment">--- Creates a button (up or down arrow) for the spinbox.
</span><span class="comment">-- @param type Either "up" or "down" to specify which direction the arrow should point
</span><span class="comment">-- @return The created Geyser.Label button
</span><span class="comment">-- @local
</span><span class="comment">-- Creates a Geyser.Label button with an up or down arrow image.
</span><span class="comment">-- Positions the button at the top or bottom of the spinbox respectively.
</span><span class="comment">-- Sets a click callback on the button to call increment() or decrement() depending on the type.
</span><span class="comment">-- Returns the created button.
</span><span class="keyword">function</span> spinbox:<span class="function-name">createButton</span>(<span class="global">type</span>)
<span class="keyword">local</span> button = Geyser.Label:<span class="function-name">new</span>({
name = self.name .. <span class="string">"spinbox_"</span>..<span class="global">type</span>..<span class="string">"Arrow"</span>,
height = self.buttonHeight,
width = self.buttonHeight,
x = <span class="string">"100%-"</span> .. self.buttonHeight,
y = <span class="global">type</span> == <span class="string">"up"</span> <span class="keyword">and</span> <span class="number">0</span> <span class="keyword">or</span> self.buttonHeight + self.remainder,
}, self)
button:<span class="function-name">setClickCallback</span>(<span class="keyword">function</span>()
<span class="keyword">if</span> <span class="global">type</span> == <span class="string">"up"</span> <span class="keyword">then</span>
self:<span class="function-name">increment</span>()
<span class="keyword">else</span>
self:<span class="function-name">decrement</span>()
<span class="keyword">end</span>
<span class="keyword">end</span>)
<span class="keyword">return</span> button
<span class="keyword">end</span>
<span class="comment">--- Creates the display label for the spinbox value.
</span><span class="comment">-- @return The created Geyser.Label display label
</span><span class="comment">-- @local
</span><span class="comment">-- Creates a Geyser.Label to display the current spinbox value.
</span><span class="comment">-- Centers the text in the label.
</span><span class="comment">-- Sets a double click callback on the label to show the input, put the current
</span><span class="comment">-- value in it, select the text, and hide the label.
</span><span class="comment">-- Returns the created display label.
</span><span class="keyword">function</span> spinbox:<span class="function-name">createDisplayLabel</span>()
<span class="keyword">local</span> displayLabel = Geyser.Label:<span class="function-name">new</span>({
name = self.name .. <span class="string">"spinbox_displayLabel"</span>,
x = <span class="number">0</span>,
y = <span class="number">0</span>,
width = <span class="string">"100%-"</span> .. self.buttonHeight,
height = <span class="string">"100%"</span>,
message = self.value
}, self)
displayLabel:<span class="function-name">setAlignment</span>(<span class="string">"center"</span>)
displayLabel:<span class="function-name">setDoubleClickCallback</span>(<span class="keyword">function</span>()
self.input:<span class="function-name">show</span>()
self.input:<span class="global">print</span>(self.value)
self.input:<span class="function-name">selectText</span>()
displayLabel:<span class="function-name">hide</span>()
<span class="keyword">end</span>)
<span class="keyword">return</span> displayLabel
<span class="keyword">end</span>
<span class="comment">--- Creates the input for directly entering a spinbox value.
</span><span class="comment">-- @return The created Geyser.CommandLine input
</span><span class="comment">-- @local
</span><span class="comment">-- Creates a Geyser.CommandLine input.
</span><span class="comment">-- Sets an action on the input to:
</span><span class="comment">-- - Attempt to convert the input text to a number
</span><span class="comment">-- - If successful, call setValue() with the number to set the spinbox value
</span><span class="comment">-- - Hide the input
</span><span class="comment">-- - Show the display label
</span><span class="comment">-- - Put the new spinbox value in the input
</span><span class="comment">-- Returns the created input.
</span><span class="keyword">function</span> spinbox:<span class="function-name">createInput</span>()
<span class="keyword">local</span> input = Geyser.CommandLine:<span class="function-name">new</span>({
x = <span class="number">0</span>,
y = <span class="number">0</span>,
width = <span class="string">"100%-"</span>.. self.buttonHeight,
height = <span class="string">"100%"</span>,
}, self)
input:<span class="function-name">setAction</span>(<span class="keyword">function</span>(txt)
txt = <span class="global">tonumber</span>(txt)
<span class="keyword">if</span> txt <span class="keyword">then</span>
self:<span class="function-name">setValue</span>(txt)
input:<span class="function-name">hide</span>()
<span class="keyword">end</span>
self.displayLabel:<span class="function-name">show</span>()
input:<span class="global">print</span>(self.value)
<span class="keyword">end</span>)
<span class="keyword">return</span> input
<span class="keyword">end</span>
<span class="comment">--- Used to increment the value by the delta amount
</span><span class="comment">-- @local
</span><span class="comment">-- Increments the spinbox value by the delta amount.
</span><span class="comment">-- Checks if the new value would exceed the max, and if so sets it to the max.
</span><span class="comment">-- Updates the display label with the new value.
</span><span class="comment">-- Applies any styles that depend on the value.
</span><span class="keyword">function</span> spinbox:<span class="function-name">increment</span>()
<span class="keyword">local</span> val = self.value + self.delta
<span class="keyword">if</span> val &gt;= self.max <span class="keyword">then</span>
val = self.max
<span class="keyword">end</span>
self.oldValue = self.value
self.value = val
self.displayLabel:<span class="function-name">echo</span>(val)
self:<span class="function-name">applyStyles</span>()
self:<span class="function-name">handleCallBacks</span>()
<span class="keyword">end</span>
<span class="comment">--- Used to decrement the value by the delta amount
</span><span class="comment">-- @local
</span><span class="comment">-- Decrements the spinbox value by the delta amount.
</span><span class="comment">-- Checks if the new value would be below the min, and if so sets it to the min.
</span><span class="comment">-- Updates the display label with the new value.
</span><span class="comment">-- Applies any styles that depend on the value.
</span><span class="keyword">function</span> spinbox:<span class="function-name">decrement</span>()
<span class="keyword">local</span> val = self.value - self.delta
<span class="keyword">if</span> val &lt;= self.min <span class="keyword">then</span>
val = self.min
<span class="keyword">end</span>
self.oldValue = self.value
self.value = val
self.displayLabel:<span class="function-name">echo</span>(val)
self:<span class="function-name">applyStyles</span>()
self:<span class="function-name">handleCallBacks</span>()
<span class="keyword">end</span>
<span class="comment">--- Used to directly set the value of the spinbox.
</span><span class="comment">-- @param value The new value to set
</span><span class="comment">-- Rounds the value to an integer if the spinbox is integer only.
</span><span class="comment">-- Checks if the new value is within the min/max range and clamps it if not.
</span><span class="comment">-- Updates the display label with the new value.
</span><a id="270"></a><span class="comment">-- Applies any styles that depend on the value.
</span><span class="keyword">function</span> spinbox:<span class="function-name">setValue</span>(value)
<span class="keyword">if</span> self.integer <span class="keyword">then</span>
value = <span class="global">math</span>.<span class="function-name">floor</span>(value)
<span class="keyword">end</span>
<span class="keyword">if</span> value &gt;= self.max <span class="keyword">then</span>
value = self.max
<span class="keyword">elseif</span> value &lt;= self.min <span class="keyword">then</span>
value = self.min
<span class="keyword">end</span>
self.oldValue = self.value
self.value = value
self.displayLabel:<span class="function-name">echo</span>(value)
self:<span class="function-name">applyStyles</span>()
self:<span class="function-name">handleCallBacks</span>()
<span class="keyword">end</span>
<span class="comment">--- Obtains the up and down arrow images for the spinbox.
</span><span class="comment">-- @local
</span><span class="comment">-- Gets the previously saved file locations.
</span><span class="comment">-- Checks if the up arrow image exists at the upArrowLocation.
</span><span class="comment">-- If not, it will download the image from a URL or copy a local file. It saves
</span><span class="comment">-- the new location.
</span><span class="comment">-- Does the same for the down arrow image and downArrowLocation.
</span><span class="comment">-- Saves any new locations to the save file.
</span><span class="comment">-- Sets self.upArrowFile and self.downArrowFile to the locations of the images.
</span><span class="keyword">function</span> spinbox:<span class="function-name">obtainImages</span>()
<span class="keyword">local</span> locations = self:<span class="function-name">getFileLocs</span>()
<span class="keyword">local</span> upURL = self.upArrowLocation
<span class="keyword">local</span> downURL = self.downArrowLocation
<span class="keyword">local</span> upFile = locations[upURL]
<span class="keyword">local</span> downFile = locations[downURL]
<span class="keyword">local</span> locationsChanged = <span class="keyword">false</span>
<span class="keyword">if</span> <span class="keyword">not</span> (upFile <span class="keyword">and</span> <span class="global">io</span>.<span class="function-name">exists</span>(upFile)) <span class="keyword">then</span>
<span class="keyword">if</span> <span class="keyword">not</span> upFile <span class="keyword">then</span>
upFile = directory .. self.name .. <span class="string">"/uparrow.png"</span>
locations[upURL] = upFile
locationsChanged = <span class="keyword">true</span>
<span class="keyword">end</span>
<span class="keyword">if</span> upURL:<span class="function-name">match</span>(<span class="string">"^http"</span>) <span class="keyword">then</span>
self:<span class="function-name">downloadFile</span>(upURL, upFile)
<span class="keyword">elseif</span> <span class="global">io</span>.<span class="function-name">exists</span>(upURL) <span class="keyword">then</span>
upFile = upURL
locations[upURL] = upFile
locationsChanged = <span class="keyword">true</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">if</span> <span class="keyword">not</span> (downFile <span class="keyword">and</span> <span class="global">io</span>.<span class="function-name">exists</span>(downFile)) <span class="keyword">then</span>
<span class="keyword">if</span> <span class="keyword">not</span> downFile <span class="keyword">then</span>
downFile = directory .. self.name .. <span class="string">"/downarrow.png"</span>
locations[downURL] = downFile
locationsChanged = <span class="keyword">true</span>
<span class="keyword">end</span>
<span class="keyword">if</span> downURL:<span class="function-name">match</span>(<span class="string">"^http"</span>) <span class="keyword">then</span>
self:<span class="function-name">downloadFile</span>(downURL, downFile)
<span class="keyword">elseif</span> <span class="global">io</span>.<span class="function-name">exists</span>(downURL) <span class="keyword">then</span>
downFile = downURL
locations[downURL] = downFile
locationsChanged = <span class="keyword">true</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
self.upArrowFile = upFile
self.downArrowFile = downFile
<span class="keyword">if</span> locationsChanged <span class="keyword">then</span>
<span class="global">table</span>.<span class="function-name">save</span>(saveFile, locations)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Handles the actual download of a file from a url
</span><span class="comment">-- @param url The url to download the file from
</span><span class="comment">-- @param fileName The location to save the downloaded file
</span><span class="comment">-- @local
</span><span class="comment">-- Creates any missing directories in the file path.
</span><span class="comment">-- Registers named event handlers to handle the download completing or erroring.
</span><span class="comment">-- The completion handler stops the error handler.
</span><span class="comment">-- The error handler prints an error message and stops the completion handler.
</span><span class="comment">-- Downloads the file from the url to the fileName location.
</span><span class="keyword">function</span> spinbox:<span class="function-name">downloadFile</span>(url, fileName)
<span class="keyword">local</span> parts = fileName:<span class="function-name">split</span>(<span class="string">"/"</span>)
parts[#parts] = <span class="keyword">nil</span>
<span class="keyword">local</span> dirName = <span class="global">table</span>.<span class="function-name">concat</span>(parts, <span class="string">"/"</span>) .. <span class="string">"/"</span>
<span class="keyword">if</span> <span class="keyword">not</span> <span class="global">io</span>.<span class="function-name">exists</span>(dirName) <span class="keyword">then</span>
lfs.<span class="function-name">mkdir</span>(dirName)
<span class="keyword">end</span>
<span class="keyword">local</span> uname = <span class="string">"spinbox"</span>
<span class="keyword">local</span> handlerName = self.name .. url
<span class="keyword">local</span> handler = <span class="keyword">function</span>(event, ...)
<span class="keyword">local</span> args = {...}
<span class="keyword">local</span> file = #args == <span class="number">1</span> <span class="keyword">and</span> args[<span class="number">1</span>] <span class="keyword">or</span> args[<span class="number">2</span>]
<span class="keyword">if</span> file ~= fileName <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">true</span>
<span class="keyword">end</span>
<span class="keyword">if</span> event == <span class="string">"sysDownloadDone"</span> <span class="keyword">then</span>
<span class="function-name">debugc</span>(<span class="function-name">f</span><span class="string">"INFO:Spinbox successfully downloaded {file}"</span>)
<span class="function-name">stopNamedEventHandler</span>(uname, handlerName .. <span class="string">"error"</span>)
<span class="keyword">return</span> <span class="keyword">false</span>
<span class="keyword">end</span>
<span class="function-name">cecho</span>(<span class="function-name">f</span><span class="string">"\n&lt;red&gt;ERROR:&lt;reset&gt;Spinbox had an issue downloading an image file to {file}: {args[1]}\n"</span>)
<span class="function-name">stopNamedEventHandler</span>(uname, handlerName .. <span class="string">"done"</span>)
<span class="keyword">end</span>
<span class="function-name">registerNamedEventHandler</span>(uname, handlerName .. <span class="string">"done"</span>, <span class="string">"sysDownloadDone"</span>, handler, <span class="keyword">true</span>)
<span class="function-name">registerNamedEventHandler</span>(uname, handlerName .. <span class="string">"error"</span>, <span class="string">"sysDownloadError"</span>, handler, <span class="keyword">true</span>)
<span class="function-name">downloadFile</span>(fileName, url)
<span class="keyword">end</span>
<span class="comment">--- Responsible for reading the file locations from disk and returning them
</span><span class="comment">-- @local
</span><span class="keyword">function</span> spinbox:<span class="function-name">getFileLocs</span>()
<span class="keyword">local</span> locations = {}
<span class="keyword">if</span> <span class="global">io</span>.<span class="function-name">exists</span>(saveFile) <span class="keyword">then</span>
<span class="global">table</span>.<span class="global">load</span>(saveFile, locations)
<span class="keyword">end</span>
<span class="keyword">return</span> locations
<span class="keyword">end</span>
<span class="comment">--- (Re)generates the stylesheets for the spinbox
</span><span class="comment">-- Should not need to call but if you change something and it doesn't take effect
</span><a id="387"></a><span class="comment">-- you can try calling this followed by applyStyles
</span><span class="keyword">function</span> spinbox:<span class="function-name">generateStyles</span>()
self.baseStyle = gss:<span class="function-name">new</span>(<span class="string">[[
border-radius: 2px;
border-color: black;
]]</span>)
self.activeStyle = gss:<span class="function-name">new</span>(<span class="function-name">f</span><span class="string">[[
background-color: {self.activeButtonColor};
]]</span>, self.baseStyle)
self.inactiveStyle = gss:<span class="function-name">new</span>(<span class="function-name">f</span><span class="string">[[
background-color: {self.inactiveButtonColor};
]]</span>, self.baseStyle)
self.upStyle = gss:<span class="function-name">new</span>(<span class="function-name">f</span><span class="string">[[
border-image: url("{self.upArrowFile}");
]]</span>)
self.downStyle = gss:<span class="function-name">new</span>(<span class="function-name">f</span><span class="string">[[
border-image: url("{self.downArrowFile}");
]]</span>)
self.displayStyle = gss:<span class="function-name">new</span>(<span class="function-name">f</span><span class="string">[[
background-color: {Geyser.Color.hex(self.color)};
text-align: center;
]]</span>, self.baseStyle)
<span class="keyword">end</span>
<span class="comment">--- Applies updated stylesheets to the components of the spinbox
</span><span class="comment">-- Should not need to call this directly
</span><span class="keyword">function</span> spinbox:<span class="function-name">applyStyles</span>()
<span class="keyword">if</span> self.value &gt;= self.max <span class="keyword">then</span>
self.upStyle:<span class="function-name">setParent</span>(self.inactiveStyle)
<span class="keyword">else</span>
self.upStyle:<span class="function-name">setParent</span>(self.activeStyle)
<span class="keyword">end</span>
<span class="keyword">if</span> self.value &lt;= self.min <span class="keyword">then</span>
self.downStyle:<span class="function-name">setParent</span>(self.inactiveStyle)
<span class="keyword">else</span>
self.downStyle:<span class="function-name">setParent</span>(self.activeStyle)
<span class="keyword">end</span>
self.upButton:<span class="function-name">setStyleSheet</span>(self.upStyle:<span class="function-name">getCSS</span>())
self.downButton:<span class="function-name">setStyleSheet</span>(self.downStyle:<span class="function-name">getCSS</span>())
self.displayLabel:<span class="function-name">setStyleSheet</span>(self.displayStyle:<span class="function-name">getCSS</span>())<a id="412"></a>
<span class="keyword">end</span>
<span class="comment">--- sets the color for active buttons on the spinbox
</span><span class="comment">-- @param color any valid color formatting string, such a "red" or "#880000" or "&lt;128,0,0&gt;" or a table of colors, like {128, 0,0}. See Geyser.Color.parse at https://www.mudlet.org/geyser/files/geyser/GeyserColor.html#Geyser.Color.parse
</span><span class="keyword">function</span> spinbox:<span class="function-name">setActiveButtonColor</span>(color)
<span class="keyword">local</span> colorType = <span class="global">type</span>(color)
<span class="keyword">local</span> hex
<span class="keyword">if</span> colorType == <span class="string">"table"</span> <span class="keyword">then</span>
hex = Geyser.Color.<span class="function-name">hex</span>(<span class="global">unpack</span>(color))
<span class="keyword">else</span>
hex = Geyser.Color.<span class="function-name">hex</span>(color)
<span class="keyword">end</span>
self.activeButtonColor = hex
self.activeStyle:<span class="function-name">set</span>(<span class="string">"background-color"</span>, hex)
self:<span class="function-name">applyStyles</span>()
<span class="keyword">end</span>
<a id="430"></a><span class="comment">--- sets the color for inactive buttons on the spinbox
</span><span class="comment">-- @param color any valid color formatting string, such a "&lt;red&gt;" or "red" or "&lt;128,0,0&gt;" or a table of colors, like {128, 0,0}. See Geyser.Color.parse at https://www.mudlet.org/geyser/files/geyser/GeyserColor.html#Geyser.Color.parse
</span><span class="keyword">function</span> spinbox:<span class="function-name">setInactiveButtonColor</span>(color)
<span class="keyword">local</span> colorType = <span class="global">type</span>(color)
<span class="keyword">local</span> hex
<span class="keyword">if</span> colorType == <span class="string">"table"</span> <span class="keyword">then</span>
hex = Geyser.Color.<span class="function-name">hex</span>(<span class="global">unpack</span>(color))
<span class="keyword">else</span>
hex = Geyser.Color.<span class="function-name">hex</span>(color)
<span class="keyword">end</span>
self.inactiveButtonColor = hex
self.inactiveStyle:<span class="function-name">set</span>(<span class="string">"background-color"</span>, hex)
self:<span class="function-name">applyStyles</span>()
<span class="keyword">end</span>
<a id="445"></a><span class="comment">-- internal function that handles calling a registered callback and raising an event any time the
</span><span class="comment">-- spinbox value is changed, whether using the buttons or the :set function.
</span><span class="keyword">function</span> spinbox:<span class="function-name">handleCallBacks</span>()
<span class="function-name">raiseEvent</span>(<span class="string">"spinbox updated"</span>, self.name, self.value, self.oldValue)
<span class="keyword">if</span> self.callBack <span class="keyword">then</span>
<span class="keyword">local</span> ok, err = <span class="global">pcall</span>(self.callBack, self.name, self.value, self.oldValue)
<span class="keyword">if</span> <span class="keyword">not</span> ok <span class="keyword">then</span>
<span class="function-name">printError</span>(<span class="function-name">f</span><span class="string">"Had an issue running the callback handler for spinbox named {self.name}: {err}"</span>, <span class="keyword">true</span>, <span class="keyword">true</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Set a callback function for the spinbox to call any time the value of the spinbox is changed
</span><span class="comment">-- the function will be called as func(self.value, self.name)
</span><span class="keyword">function</span> spinbox:<span class="function-name">setCallBack</span>(func)
<span class="keyword">local</span> funcType = <span class="global">type</span>(func)
<span class="keyword">if</span> funcType ~= <span class="string">"function"</span> <span class="keyword">then</span>
<span class="function-name">printError</span>(<span class="function-name">f</span><span class="string">"spinbox:setCallBack(func): func as function required, got {funcType}"</span>, <span class="keyword">true</span>, <span class="keyword">true</span>)
<span class="keyword">end</span>
self.callBack = func
<span class="keyword">return</span> <span class="keyword">true</span>
<span class="keyword">end</span>
<span class="keyword">return</span> spinbox</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,354 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><strong>sug.lua</strong></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>sug.lua</h2>
<pre>
<span class="comment">--- Self Updating Gauge, extends &lt;a href="https://www.mudlet.org/geyser/files/geyser/GeyserGauge.html"&gt;Geyser.Gauge&lt;/a&gt;
</span><span class="comment">-- @classmod SUG
</span><span class="comment">-- @author Damian Monogue &lt;demonnic@gmail.com&gt;
</span><span class="comment">-- @copyright 2020 Damian Monogue
</span><span class="comment">-- @license MIT, see LICENSE.lua
</span><span class="keyword">local</span> SUG = {
name = <span class="string">"SelfUpdatingGaugeClass"</span>,
active = <span class="keyword">true</span>,
updateTime = <span class="number">333</span>,
currentVariable = <span class="string">""</span>,
maxVariable = <span class="string">""</span>,
defaultCurrent = <span class="number">50</span>,
defaultMax = <span class="number">100</span>,
textTemplate = <span class="string">" |c/|m |p%"</span>,
strict = <span class="keyword">true</span>,
}
<span class="comment">-- Internal function, used to turn a string variable name into a value
</span><span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">getValueAt</span>(accessString)
<span class="keyword">local</span> ok, err = <span class="global">pcall</span>(<span class="global">loadstring</span>(<span class="string">"return "</span> .. <span class="global">tostring</span>(accessString)))
<span class="keyword">if</span> ok <span class="keyword">then</span> <span class="keyword">return</span> err <span class="keyword">end</span>
<span class="keyword">return</span> <span class="keyword">nil</span>, err
<span class="keyword">end</span>
<span class="comment">-- ========== End section copied from demontools.lua
</span>
<span class="comment">--- Creates a new Self Updating Gauge.
</span><span class="comment">-- @tparam table cons table of options which control the Gauge's behaviour. In addition to all valid contraints for Geyser.Gauge, SUG adds:
</span><span class="comment">-- &lt;br&gt;
</span><span class="comment">-- &lt;table class="tg"&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;th&gt;name&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;description&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;default&lt;/th&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;active&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;boolean, if true starts the timer updating&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;true&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;updateTime&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;How often should the gauge autoupdate? Milliseconds. 0 to disable the timer but still allow event updates&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;333&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;currentVariable&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;What variable will hold the 'current' value of the gauge? Pass the name as a string, IE "currentHP" or "gmcp.Char.Vitals.hp"&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;""&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;maxVariable&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;What variable will hold the 'current' value of the gauge? Pass the name as a string, IE "maxHP" or "gmcp.Char.Vitals.maxhp"&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;""&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;textTemplate&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;Template to use for the text on the gauge. "|c" replaced with current value, "|m" replaced with max value, "|p" replaced with the % full the gauge should be&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;" |c/|m |p%"&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;defaultCurrent&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;What value to use if the currentVariable points to nil or something which cannot be made a number?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;50&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;defaultMax&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;What value to use if the maxVariable points to nil or something which cannot be made a number?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;100&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;updateEvent&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;The name of an event to listen for to perform an update. Can be run alongside or instead of the timer updates. Empty string to turn off&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;""&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;updateHook&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;A function which is run each time the gauge updates. Should take 3 arguments, the gauge itself, current value, and max value. You can return new current and max values to be used, for example `return 34, 120` would cause the gauge to use 34 for current and 120 for max regardless of what the variables it reads say.&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/table&gt;
</span><span class="comment">-- @param container The Geyser container for this gauge
</span><span class="comment">-- @usage
</span><span class="comment">-- local SUG = require("MDK.sug") --the following will watch "gmcp.Char.Vitals.hp" and "gmcp.Char.Vitals.maxhp" and update itself every 333 milliseconds
</span><span class="comment">-- myGauge = SUG:new({
</span><span class="comment">-- name = "myGauge",
</span><span class="comment">-- currentVariable = "gmcp.Char.Vitals.hp", --if this is nil, it will use the defaultCurrent of 50
</span><span class="comment">-- maxVariable = "gmcp.Char.Vitals.maxhp", --if this is nil, it will use the defaultMax of 100.
</span><span class="comment">-- height = 50,
</span><a id="91"></a><span class="comment">-- })
</span><span class="keyword">function</span> SUG:<span class="function-name">new</span>(cons, container)
<span class="keyword">local</span> funcName = <span class="string">"SUG:new(cons, container)"</span>
cons = cons <span class="keyword">or</span> {}
<span class="keyword">local</span> consType = <span class="global">type</span>(cons)
<span class="global">assert</span>(consType == <span class="string">"table"</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s: cons as table expected, got %s"</span>, funcName, consType))
<span class="keyword">local</span> me = SUG.parent:<span class="function-name">new</span>(cons, container)
<span class="global">setmetatable</span>(me, self)
self.__index = self
<span class="comment">-- apply any styling requested
</span> <span class="keyword">if</span> me.cssFront <span class="keyword">then</span>
<span class="keyword">if</span> <span class="keyword">not</span> me.cssBack <span class="keyword">then</span>
me.cssBack = me.cssFront .. <span class="string">"background-color: black;"</span>
<span class="keyword">end</span>
me:<span class="function-name">setStyleSheet</span>(me.cssFront, me.cssBack, me.cssText)
<span class="keyword">end</span>
<span class="keyword">if</span> me.active <span class="keyword">then</span>
me:<span class="function-name">start</span>()
<span class="keyword">end</span>
me:<span class="function-name">update</span>()
<span class="keyword">return</span> me
<span class="keyword">end</span>
<span class="comment">--- Set how often to update the gauge on a timer
</span><a id="115"></a><span class="comment">-- @tparam number time time in milliseconds. 0 to disable the timer
</span><span class="keyword">function</span> SUG:<span class="function-name">setUpdateTime</span>(time)
<span class="keyword">if</span> <span class="global">type</span>(time) ~= <span class="string">"number"</span> <span class="keyword">then</span>
<span class="function-name">debugc</span>(<span class="string">"SUG:setUpdateTime(time) time as number expected, got "</span> .. <span class="global">type</span>(time))
<span class="keyword">return</span>
<span class="keyword">end</span>
self.updateTime = time
<span class="keyword">if</span> self.active <span class="keyword">then</span> self:<span class="function-name">start</span>() <span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Set the event to listen for to update the gauge
</span><a id="126"></a><span class="comment">-- @tparam string event the name of the event to listen for, use "" to disable events without stopping any existing timers
</span><span class="keyword">function</span> SUG:<span class="function-name">setUpdateEvent</span>(event)
<span class="keyword">if</span> <span class="global">type</span>(event) ~= <span class="global">string</span> <span class="keyword">then</span>
<span class="function-name">debugc</span>(<span class="string">"SUG:setUpdateEvent(event) event name as string expected, got "</span> .. <span class="global">type</span>(event))
<span class="keyword">return</span>
<span class="keyword">end</span>
self.updateEvent = event
<span class="keyword">if</span> self.active <span class="keyword">then</span> self:<span class="function-name">start</span>() <span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Set the name of the variable the Self Updating Gauge watches for the 'current' value of the gauge
</span><a id="137"></a><span class="comment">-- @tparam string variableName The name of the variable to get the current value for the gauge. For instance "currentHP", "gmcp.Char.Vitals.hp" etc
</span><span class="keyword">function</span> SUG:<span class="function-name">setCurrentVariable</span>(variableName)
<span class="keyword">local</span> nameType = <span class="global">type</span>(variableName)
<span class="keyword">local</span> funcName = <span class="string">"SUG:setCurrentVariable(variableName)"</span>
<span class="global">assert</span>(nameType == <span class="string">"string"</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s: variableName as string expected, got: %s"</span>, funcName, nameType))
<span class="keyword">local</span> val = <span class="function-name">getValueAt</span>(variableName)
<span class="keyword">local</span> valType = <span class="global">type</span>(<span class="global">tonumber</span>(val))
<span class="global">assert</span>(valType == <span class="string">"number"</span>,
<span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s: variableName must point to a variable which is a number or coercable into one. %s points to a %s"</span>, funcName, variableName,
<span class="global">type</span>(val)))
self.currentVariable = variableName
self:<span class="function-name">update</span>()
<span class="keyword">end</span>
<span class="comment">--- Set the name of the variable the Self Updating Gauge watches for the 'max' value of the gauge
</span><a id="152"></a><span class="comment">-- @tparam string variableName The name of the variable to get the max value for the gauge. For instance "maxHP", "gmcp.Char.Vitals.maxhp" etc. Set to "" to only check the current value
</span><span class="keyword">function</span> SUG:<span class="function-name">setMaxVariable</span>(variableName)
<span class="keyword">if</span> variableName == <span class="string">""</span> <span class="keyword">then</span>
self.maxVariable = variableName
self:<span class="function-name">update</span>()
<span class="keyword">return</span>
<span class="keyword">end</span>
<span class="keyword">local</span> nameType = <span class="global">type</span>(variableName)
<span class="keyword">local</span> funcName = <span class="string">"SUG:setMaxVariable(variableName)"</span>
<span class="global">assert</span>(nameType == <span class="string">"string"</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s: variableName as string expected, got: %s"</span>, funcName, nameType))
<span class="keyword">local</span> val = <span class="function-name">getValueAt</span>(variableName)
<span class="keyword">local</span> valType = <span class="global">type</span>(<span class="global">tonumber</span>(val))
<span class="global">assert</span>(valType == <span class="string">"number"</span>,
<span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s: variableName must point to a variable which is a number or coercable into one. %s points to a %s"</span>, funcName, variableName,
<span class="global">type</span>(val)))
self.maxVariable = variableName
self:<span class="function-name">update</span>()
<span class="keyword">end</span>
<span class="comment">--- Set the template for the Self Updating Gauge to set the text with. "|c" is replaced by the current value, "|m" is replaced by the max value, and "|p" is replaced by the percentage current/max
</span><a id="172"></a><span class="comment">-- @tparam string template The template to use for the text on the gauge. If the max value is 200 and current is 68, then |c will be replace by 68, |m replaced by 200, and |p replaced by 34.
</span><span class="keyword">function</span> SUG:<span class="function-name">setTextTemplate</span>(template)
<span class="keyword">local</span> templateType = <span class="global">type</span>(template)
<span class="keyword">local</span> funcName = <span class="string">"SUG:setTextTemplate(template)"</span>
<span class="global">assert</span>(templateType == <span class="string">"string"</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s: template as string expected, got %s"</span>, funcName, templateType))
self.textTemplate = template
self:<span class="function-name">update</span>()
<span class="keyword">end</span>
<span class="comment">--- Set the updateHook function which is run just prior to the gauge updating
</span><a id="182"></a><span class="comment">-- @tparam function func The function which will be called when the gauge updates. It should take 3 arguments, the gauge itself, the current value, and the max value. If you wish to override the current or max values used for the gauge, you can return new current and max values, like `return newCurrent newMax`
</span><span class="keyword">function</span> SUG:<span class="function-name">setUpdateHook</span>(func)
<span class="keyword">local</span> funcType = <span class="global">type</span>(func)
<span class="keyword">if</span> funcType ~= <span class="string">"function"</span> <span class="keyword">then</span>
<span class="keyword">return</span> <span class="keyword">nil</span>, <span class="string">"setUpdateHook only takes functions, no strings or anything like that. You passed in: "</span> .. funcType
<span class="keyword">end</span>
self.updateHook = func
<span class="keyword">end</span>
<a id="191"></a><span class="comment">--- Stops the Self Updating Gauge from updating
</span><span class="keyword">function</span> SUG:<span class="function-name">stop</span>()
self.active = <span class="keyword">false</span>
<span class="keyword">if</span> self.timer <span class="keyword">then</span>
<span class="function-name">killTimer</span>(self.timer)
self.timer = <span class="keyword">nil</span>
<span class="keyword">end</span>
<span class="keyword">if</span> self.eventHandler <span class="keyword">then</span>
<span class="function-name">killAnonymousEventHandler</span>(self.eventHandler)
self.eventHandler = <span class="keyword">nil</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<a id="204"></a><span class="comment">--- Starts the Self Updating Gauge updating. If it is already updating, it will restart it.
</span><span class="keyword">function</span> SUG:<span class="function-name">start</span>()
self:<span class="function-name">stop</span>()
self.active = <span class="keyword">true</span>
<span class="keyword">local</span> update = <span class="keyword">function</span>() self:<span class="function-name">update</span>() <span class="keyword">end</span>
<span class="keyword">if</span> self.updateTime &gt; <span class="number">0</span> <span class="keyword">then</span>
self.timer = <span class="function-name">tempTimer</span>(self.updateTime / <span class="number">1000</span>, update, <span class="keyword">true</span>)
<span class="keyword">end</span>
<span class="keyword">local</span> updateEvent = self.updateEvent
<span class="keyword">if</span> updateEvent <span class="keyword">and</span> updateEvent ~= <span class="string">""</span> <span class="keyword">and</span> updateEvent ~= <span class="string">"*"</span> <span class="keyword">then</span>
self.eventHandler = <span class="function-name">registerAnonymousEventHandler</span>(self.updateEvent, update)
<span class="keyword">end</span>
<span class="keyword">end</span>
<a id="218"></a><span class="comment">--- Reads the values from currentVariable and maxVariable, and updates the gauge's value and text.
</span><span class="keyword">function</span> SUG:<span class="function-name">update</span>()
<span class="keyword">local</span> current = <span class="function-name">getValueAt</span>(self.currentVariable)
<span class="keyword">local</span> max = <span class="function-name">getValueAt</span>(self.maxVariable)
current = <span class="global">tonumber</span>(current)
max = <span class="global">tonumber</span>(max)
<span class="keyword">if</span> current == <span class="keyword">nil</span> <span class="keyword">then</span>
current = self.defaultCurrent
<span class="function-name">debugc</span>(<span class="global">string</span>.<span class="function-name">format</span>(
<span class="string">"Self Updating Gauge named %s is trying to update with an invalid current value. Using the defaultCurrent instead. currentVariable: '%s' maxVariable: '%s'"</span>,
self.name, self.currentVariable, self.maxVariable))
<span class="keyword">end</span>
<span class="keyword">if</span> max == <span class="keyword">nil</span> <span class="keyword">then</span>
max = self.defaultMax
<span class="keyword">if</span> self.maxVariable ~= <span class="string">""</span> <span class="keyword">then</span>
<span class="function-name">debugc</span>(<span class="global">string</span>.<span class="function-name">format</span>(
<span class="string">"Self Updating Gauge named %s is trying to update with an invalid max value. Using the defaultCurrent instead. currentVariable: '%s' maxVariable: '%s'"</span>,
self.name, self.currentVariable, self.maxVariable))
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">if</span> self.updateHook <span class="keyword">and</span> <span class="global">type</span>(self.updateHook) == <span class="string">"function"</span> <span class="keyword">then</span>
<span class="keyword">local</span> ok, newcur, newmax = <span class="global">pcall</span>(self.updateHook, self, current, max)
<span class="keyword">if</span> ok <span class="keyword">and</span> newcur <span class="keyword">then</span>
current = newcur
max = newmax <span class="keyword">and</span> newmax <span class="keyword">or</span> self.defaultMax
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">local</span> text = self.textTemplate
<span class="keyword">local</span> percent = <span class="global">math</span>.<span class="function-name">floor</span>((current / max * <span class="number">100</span>) + <span class="number">0.5</span>)
text = text:<span class="function-name">gsub</span>(<span class="string">"|c"</span>, current)
text = text:<span class="function-name">gsub</span>(<span class="string">"|m"</span>, max)
text = text:<span class="function-name">gsub</span>(<span class="string">"|p"</span>, percent)
self:<span class="function-name">setValue</span>(current, max, text)
<span class="keyword">end</span>
SUG.parent = Geyser.Gauge
<span class="global">setmetatable</span>(SUG, Geyser.Gauge)
<span class="keyword">return</span> SUG</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,434 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><strong>textgauge.lua</strong></li>
<li><a href="../source/timergauge.lua.html">timergauge.lua</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>textgauge.lua</h2>
<pre>
<span class="comment">--- Creates a text based gauge, for use in miniconsoles and the like.
</span><span class="comment">-- @classmod TextGauge
</span><span class="comment">-- @author Damian Monogue &lt;demonnic@gmail.com&gt;
</span><span class="comment">-- @copyright 2020 Damian Monogue
</span><span class="comment">-- @copyright 2021 Damian Monogue
</span><span class="comment">-- @license MIT, see LICENSE.lua
</span><span class="keyword">local</span> TextGauge = {width = <span class="number">24</span>, fillCharacter = <span class="string">":"</span>, emptyCharacter = <span class="string">"-"</span>, showPercent = <span class="keyword">true</span>, showPercentSymbol = <span class="keyword">true</span>, format = <span class="string">"c"</span>, value = <span class="number">50</span>}
<span class="comment">--- Creates a new TextGauge.
</span><span class="comment">-- @tparam[opt] table options The table of options you would like the TextGauge to start with.
</span><span class="comment">-- &lt;br&gt;&lt;br&gt;Table of new options
</span><span class="comment">-- &lt;table class="tg"&gt;
</span><span class="comment">-- &lt;thead&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;th&gt;option name&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;description&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;default&lt;/th&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/thead&gt;
</span><span class="comment">-- &lt;tbody&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;width&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;How many characters wide to make the gauge&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;24&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;fillCharacter&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;What character to use for the 'full' part of the gauge&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;:&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;overflowCharacter&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;What character to use for &gt;100% part of the gauge&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;if not set, it uses whatever you set fillCharacter to&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;emptyCharacter&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;What character to use for the 'empty' part of the gauge&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;-&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;showPercentSymbol&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;Should we show the % sign itself?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;true&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;showPercent&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;Should we show what % of the gauge is filled?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;true&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;value&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;How much of the gauge should be filled&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;50&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;format&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;What type of color formatting to use? 'c' for cecho, 'd' for decho, 'h' for hecho&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;c&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;fillColor&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;What color to make the full part of the bar?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;"DarkOrange" or equivalent for your format type&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;emptyColor&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;what color to use for the empty part of the bar?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;"white" or format appropriate equivalent&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;percentColor&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;What color to print the percentage numvers in, if shown?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;"white" or fortmat appropriate equivalent&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;percentSymbolColor&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;What color to make the % if shown?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;If not set, uses what percentColor is set to.&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;overflowColor&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;What color to make the &gt;100% portion of the bar?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;If not set, will use the same color as fillColor&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/tbody&gt;
</span><span class="comment">-- &lt;/table&gt;
</span><span class="comment">-- @usage
</span><span class="comment">-- local TextGauge = require("MDK.textgauge")
</span><span class="comment">-- myTextGauge = TextGauge:new()
</span><a id="92"></a><span class="comment">-- gaugeText = myTextGauge:setValue(382, 830)
</span><span class="keyword">function</span> TextGauge:<span class="function-name">new</span>(options)
options = options <span class="keyword">or</span> {}
<span class="keyword">local</span> optionsType = <span class="global">type</span>(options)
<span class="global">assert</span>(optionsType == <span class="string">"table"</span> <span class="keyword">or</span> optionsType == <span class="string">"nil"</span>, <span class="string">"TextGauge:new(options): options expected as table, got "</span> .. optionsType)
<span class="keyword">local</span> me = <span class="global">table</span>.<span class="function-name">deepcopy</span>(options)
<span class="global">setmetatable</span>(me, self)
self.__index = self
me:<span class="function-name">setDefaultColors</span>()
<span class="keyword">return</span> me
<span class="keyword">end</span>
<span class="comment">--- Sets the width in characters of the gauge
</span><a id="105"></a><span class="comment">-- @tparam number width number of characters wide to make the gauge
</span><span class="keyword">function</span> TextGauge:<span class="function-name">setWidth</span>(width)
<span class="keyword">local</span> widthType = <span class="global">type</span>(width)
<span class="global">assert</span>(widthType == <span class="string">"number"</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"TextGauge:setWidth(width): width as number expected, got %s"</span>, widthType))
self.width = width
<span class="keyword">end</span>
<span class="keyword">function</span> TextGauge:<span class="function-name">setFormat</span>(format)
self.format = self:<span class="function-name">getColorType</span>(format)
self:<span class="function-name">setDefaultColors</span>()
<span class="keyword">end</span>
<span class="comment">--- Sets the character to use for the 'full' part of the gauge
</span><a id="118"></a><span class="comment">-- @tparam string character the character to use.
</span><span class="keyword">function</span> TextGauge:<span class="function-name">setFillCharacter</span>(character)
<span class="global">assert</span>(character ~= <span class="keyword">nil</span>, <span class="string">"TextGauge:setFillCharacter(character): character required, got nil"</span>)
<span class="global">assert</span>(utf8.<span class="function-name">len</span>(character) == <span class="number">1</span>, <span class="string">"TextGauge:setFillCharacter(character): character must be a single character"</span>)
self.fillCharacter = character
<span class="keyword">end</span>
<span class="comment">--- Sets the character to use for the 'overflow' (&gt;100%) part of the gauge
</span><a id="126"></a><span class="comment">-- @tparam string character the character to use.
</span><span class="keyword">function</span> TextGauge:<span class="function-name">setOverflowCharacter</span>(character)
<span class="global">assert</span>(character ~= <span class="keyword">nil</span>, <span class="string">"TextGauge:setOverflowCharacter(character): character required, got nil"</span>)
<span class="global">assert</span>(utf8.<span class="function-name">len</span>(character) == <span class="number">1</span>, <span class="string">"TextGauge:setOverflowCharacter(character): character must be a single character"</span>)
self.overflowCharacter = character
<span class="keyword">end</span>
<span class="comment">--- Sets the character to use for the 'full' part of the gauge
</span><a id="134"></a><span class="comment">-- @tparam string character the character to use.
</span><span class="keyword">function</span> TextGauge:<span class="function-name">setEmptyCharacter</span>(character)
<span class="global">assert</span>(character ~= <span class="keyword">nil</span>, <span class="string">"TextGauge:setEmptyCharacter(character): character required, got nil"</span>)
<span class="global">assert</span>(utf8.<span class="function-name">len</span>(character) == <span class="number">1</span>, <span class="string">"TextGauge:setEmptyCharacter(character): character must be a single character"</span>)
self.emptyCharacter = character
<span class="keyword">end</span>
<span class="comment">--- Sets the fill color for the gauge.
</span><a id="142"></a><span class="comment">-- @tparam string color the color to use for the full portion of the gauge. Will be run through Geyser.Golor
</span><span class="keyword">function</span> TextGauge:<span class="function-name">setFillColor</span>(color)
<span class="global">assert</span>(color ~= <span class="keyword">nil</span>, <span class="string">"TextGauge:setFillColor(color): color required, got nil"</span>)
self.fillColor = color
<span class="keyword">end</span>
<span class="comment">--- Sets the overflow color for the gauge.
</span><a id="149"></a><span class="comment">-- @tparam string color the color to use for the full portion of the gauge. Will be run through Geyser.Golor
</span><span class="keyword">function</span> TextGauge:<span class="function-name">setOverflowColor</span>(color)
<span class="global">assert</span>(color ~= <span class="keyword">nil</span>, <span class="string">"TextGauge:setOverflowColor(color): color required, got nil"</span>)
self.overflowColor = color
<span class="keyword">end</span>
<span class="comment">--- Sets the empty color for the gauge.
</span><a id="156"></a><span class="comment">-- @tparam string color the color to use for the empty portion of the gauge. Will be run through Geyser.Golor
</span><span class="keyword">function</span> TextGauge:<span class="function-name">setEmptyColor</span>(color)
<span class="global">assert</span>(color ~= <span class="keyword">nil</span>, <span class="string">"TextGauge:setEmptyColor(color): color required, got nil"</span>)
self.emptyColor = color
<span class="keyword">end</span>
<span class="comment">--- Sets the fill color for the gauge.
</span><a id="163"></a><span class="comment">-- @tparam string color the color to use for the numeric value. Will be run through Geyser.Golor
</span><span class="keyword">function</span> TextGauge:<span class="function-name">setPercentColor</span>(color)
<span class="global">assert</span>(color ~= <span class="keyword">nil</span>, <span class="string">"TextGauge:setPercentColor(color): color required, got nil"</span>)
self.percentColor = color
<span class="keyword">end</span>
<span class="comment">--- Sets the fill color for the gauge.
</span><a id="169"></a><span class="comment">-- @tparam string color the color to use for the numeric value. Will be run through Geyser.Golor
</span><span class="keyword">function</span> TextGauge:<span class="function-name">setPercentSymbolColor</span>(color)
<span class="global">assert</span>(color ~= <span class="keyword">nil</span>, <span class="string">"TextGauge:setPercentSymbolColor(color): color required, got nil"</span>)
self.percentSymbolColor = color
<span class="keyword">end</span>
<a id="175"></a><span class="comment">--- Enables reversing the fill direction (right to left instead of the usual left to right)
</span><span class="keyword">function</span> TextGauge:<span class="function-name">enableReverse</span>()
self.reverse = <span class="keyword">true</span>
<span class="keyword">end</span>
<a id="180"></a><span class="comment">--- Disables reversing the fill direction (go back to the usual left to right)
</span><span class="keyword">function</span> TextGauge:<span class="function-name">disableReverse</span>()
self.reverse = <span class="keyword">false</span>
<span class="keyword">end</span>
<a id="185"></a><span class="comment">--- Enables showing the percent value of the gauge
</span><span class="keyword">function</span> TextGauge:<span class="function-name">enableShowPercent</span>()
self.showPercent = <span class="keyword">true</span>
<span class="keyword">end</span>
<a id="190"></a><span class="comment">--- Disables showing the percent value of the gauge
</span><span class="keyword">function</span> TextGauge:<span class="function-name">disableShowPercent</span>()
self.showPercent = <span class="keyword">false</span>
<span class="keyword">end</span>
<a id="195"></a><span class="comment">--- Enables showing the percent symbol (appears after the value)
</span><span class="keyword">function</span> TextGauge:<span class="function-name">enableShowPercentSymbol</span>()
self.showPercentSymbol = <span class="keyword">true</span>
<span class="keyword">end</span>
<a id="200"></a><span class="comment">--- Enables showing the percent symbol (appears after the value)
</span><span class="keyword">function</span> TextGauge:<span class="function-name">disableShowPercentSymbol</span>()
self.showPercentSymbol = <span class="keyword">false</span>
<span class="keyword">end</span>
<span class="keyword">function</span> TextGauge:<span class="function-name">getColorType</span>(format)
format = format <span class="keyword">or</span> self.format
<span class="keyword">local</span> dec = {<span class="string">"d"</span>, <span class="string">"decimal"</span>, <span class="string">"dec"</span>, <span class="string">"decho"</span>}
<span class="keyword">local</span> hex = {<span class="string">"h"</span>, <span class="string">"hexidecimal"</span>, <span class="string">"hex"</span>, <span class="string">"hecho"</span>}
<span class="keyword">local</span> col = {<span class="string">"c"</span>, <span class="string">"color"</span>, <span class="string">"colour"</span>, <span class="string">"col"</span>, <span class="string">"name"</span>, <span class="string">"cecho"</span>}
<span class="keyword">if</span> <span class="global">table</span>.<span class="function-name">contains</span>(col, format) <span class="keyword">then</span>
<span class="keyword">return</span> <span class="string">"c"</span>
<span class="keyword">elseif</span> <span class="global">table</span>.<span class="function-name">contains</span>(dec, format) <span class="keyword">then</span>
<span class="keyword">return</span> <span class="string">"d"</span>
<span class="keyword">elseif</span> <span class="global">table</span>.<span class="function-name">contains</span>(hex, format) <span class="keyword">then</span>
<span class="keyword">return</span> <span class="string">"h"</span>
<span class="keyword">else</span>
<span class="keyword">return</span> <span class="string">""</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">-- internal function, used at instantiation to ensure some colors are set
</span><span class="keyword">function</span> TextGauge:<span class="function-name">setDefaultColors</span>()
<span class="keyword">local</span> colorType = self:<span class="function-name">getColorType</span>()
<span class="keyword">if</span> colorType == <span class="string">"c"</span> <span class="keyword">then</span>
self.percentColor = self.percentColor <span class="keyword">or</span> <span class="string">"white"</span>
self.percentSymbolColor = self.percentSymbolColor <span class="keyword">or</span> self.percentColor
self.fillColor = self.fillColor <span class="keyword">or</span> <span class="string">"DarkOrange"</span>
self.emptyColor = self.emptyColor <span class="keyword">or</span> <span class="string">"white"</span>
self.resetColor = <span class="string">"&lt;reset&gt;"</span>
<span class="keyword">elseif</span> colorType == <span class="string">"d"</span> <span class="keyword">then</span>
self.percentColor = self.percentColor <span class="keyword">or</span> <span class="string">"&lt;255,255,255&gt;"</span>
self.percentSymbolColor = self.percentSymbolColor <span class="keyword">or</span> self.percentColor
self.fillColor = self.fillColor <span class="keyword">or</span> <span class="string">"&lt;255,140,0&gt;"</span>
self.emptyColor = self.emptyColor <span class="keyword">or</span> <span class="string">"&lt;255,255,255&gt;"</span>
self.resetColor = <span class="string">"&lt;r&gt;"</span>
<span class="keyword">elseif</span> colorType == <span class="string">"h"</span> <span class="keyword">then</span>
self.percentColor = self.percentColor <span class="keyword">or</span> <span class="string">"#ffffff"</span>
self.percentSymbolColor = self.percentSymbolColor <span class="keyword">or</span> self.percentColor
self.fillColor = self.fillColor <span class="keyword">or</span> <span class="string">"#ff8c00"</span>
self.emptyColor = self.emptyColor <span class="keyword">or</span> <span class="string">"#ffffff"</span>
self.resetColor = <span class="string">"#r"</span>
<span class="keyword">else</span>
self.percentColor = self.percentColor <span class="keyword">or</span> <span class="string">""</span>
self.percentSymbolColor = self.percentSymbolColor <span class="keyword">or</span> self.percentColor
self.fillColor = self.fillColor <span class="keyword">or</span> <span class="string">""</span>
self.emptyColor = self.emptyColor <span class="keyword">or</span> <span class="string">""</span>
self.resetColor = <span class="string">""</span>
<span class="keyword">end</span>
self.overflowColor = self.overflowColor <span class="keyword">or</span> self.fillColor
<span class="keyword">end</span>
<span class="comment">-- Internal function used to route Geyser.Color based on internally stored format
</span><span class="keyword">function</span> TextGauge:<span class="function-name">getColor</span>(color)
<span class="keyword">local</span> colorType = self:<span class="function-name">getColorType</span>()
<span class="keyword">if</span> colorType == <span class="string">"c"</span> <span class="keyword">then</span>
<span class="keyword">return</span> <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"&lt;%s&gt;"</span>, color) <span class="comment">-- pass the color back in &lt;&gt; for cecho
</span> <span class="keyword">elseif</span> colorType == <span class="string">"d"</span> <span class="keyword">then</span>
<span class="keyword">return</span> Geyser.Color.<span class="function-name">hdec</span>(color) <span class="comment">-- return it in decho format
</span> <span class="keyword">elseif</span> colorType == <span class="string">"h"</span> <span class="keyword">then</span>
<span class="keyword">return</span> Geyser.Color.<span class="function-name">hex</span>(color) <span class="comment">-- return it in hex format
</span> <span class="keyword">else</span>
<span class="keyword">return</span> <span class="string">""</span> <span class="comment">-- return an empty string for noncolored output
</span> <span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Used to set the gauge's value and return the string representation of the gauge
</span><span class="comment">-- @tparam[opt] number current current value. If no value is passed it will use the stored value. Defaults to 50 to prevent errors.
</span><span class="comment">-- @tparam[opt] number max maximum value. If not passed, the internally stored one will be used. Defaults to 100 so that it can be used with single values as a percent
</span><span class="comment">-- @usage myGauge:setValue(55) -- sets the gauge to 55% full
</span><a id="270"></a><span class="comment">-- @usage myGauge:setValue(2345, 2780) -- will figure out what the percentage fill is based on the given current/max values
</span><span class="keyword">function</span> TextGauge:<span class="function-name">setValue</span>(current, max)
current = current <span class="keyword">or</span> self.value
<span class="global">assert</span>(<span class="global">type</span>(current) == <span class="string">"number"</span>, <span class="string">"TextGauge:setValue(current,max) current as number expected, got "</span> .. <span class="global">type</span>(current))
<span class="global">assert</span>(max == <span class="keyword">nil</span> <span class="keyword">or</span> <span class="global">type</span>(max) == <span class="string">"number"</span>, <span class="string">"TextGauge:setValue(current, max) option max as number expected, got "</span> .. <span class="global">type</span>(max))
<span class="keyword">if</span> current &lt; <span class="number">0</span> <span class="keyword">then</span>
current = <span class="number">0</span>
<span class="keyword">end</span>
max = max <span class="keyword">or</span> <span class="number">100</span>
<span class="keyword">local</span> value = <span class="global">math</span>.<span class="function-name">floor</span>(current / max * <span class="number">100</span>)
self.value = value
<span class="keyword">local</span> width = self.width
<span class="keyword">local</span> percentString = <span class="string">""</span>
<span class="keyword">local</span> percentSymbolString = <span class="string">""</span>
<span class="keyword">local</span> fillCharacter = self.fillCharacter
<span class="keyword">local</span> overflowCharacter = self.overflowCharacter <span class="keyword">or</span> fillCharacter
<span class="keyword">local</span> emptyCharacter = self.emptyCharacter
<span class="keyword">local</span> fillColor = self:<span class="function-name">getColor</span>(self.fillColor)
<span class="keyword">local</span> overflowColor = self:<span class="function-name">getColor</span>(self.overflowColor)
<span class="keyword">local</span> emptyColor = self:<span class="function-name">getColor</span>(self.emptyColor)
<span class="keyword">local</span> percentColor = self:<span class="function-name">getColor</span>(self.percentColor)
<span class="keyword">local</span> percentSymbolColor = self:<span class="function-name">getColor</span>(self.percentSymbolColor)
<span class="keyword">local</span> resetColor = self.resetColor
<span class="keyword">if</span> self.showPercent <span class="keyword">then</span>
percentString = <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s%02d%s"</span>, percentColor, value, resetColor)
width = width - <span class="number">2</span>
<span class="keyword">end</span>
<span class="keyword">if</span> self.showPercentSymbol <span class="keyword">then</span>
percentSymbolString = <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s%s%s"</span>, percentSymbolColor, <span class="string">"%"</span>, resetColor)
width = width - <span class="number">1</span>
<span class="keyword">end</span>
<span class="keyword">local</span> perc = value / <span class="number">100</span>
<span class="keyword">local</span> overflow = perc - <span class="number">1</span>
<span class="keyword">if</span> overflow &lt; <span class="number">0</span> <span class="keyword">then</span>
overflow = <span class="number">0</span>
<span class="keyword">end</span>
<span class="keyword">if</span> overflow &gt; <span class="number">1</span> <span class="keyword">then</span>
perc = <span class="number">2</span>
overflow = <span class="number">1</span>
<span class="keyword">end</span>
<span class="keyword">local</span> overflowWidth = <span class="global">math</span>.<span class="function-name">floor</span>(overflow * width)
<span class="keyword">local</span> fillWidth = <span class="global">math</span>.<span class="function-name">floor</span>((perc - overflow) * width)
<span class="keyword">local</span> emptyWidth = width - fillWidth
fillWidth = fillWidth - overflowWidth
<span class="keyword">if</span> value &gt;= <span class="number">100</span> <span class="keyword">and</span> self.showPercent <span class="keyword">then</span>
fillWidth = fillWidth - <span class="number">1</span>
<span class="keyword">end</span>
<span class="keyword">if</span> value &gt;= <span class="number">200</span> <span class="keyword">and</span> self.showPercent <span class="keyword">then</span>
overflowWidth = overflowWidth - <span class="number">1</span>
<span class="keyword">end</span>
<span class="keyword">local</span> result = <span class="string">""</span>
<span class="keyword">if</span> self.reverse <span class="keyword">then</span>
result = <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s%s%s%s%s%s%s%s%s%s%s"</span>, emptyColor, <span class="global">string</span>.<span class="function-name">rep</span>(emptyCharacter, emptyWidth), resetColor,fillColor, <span class="global">string</span>.<span class="function-name">rep</span>(fillCharacter, fillWidth), resetColor, overflowColor, <span class="global">string</span>.<span class="function-name">rep</span>(overflowCharacter, overflowWidth), resetColor, percentString, percentSymbolString, resetColor)
<span class="keyword">else</span>
result = <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s%s%s%s%s%s%s%s%s%s%s"</span>, overflowColor, <span class="global">string</span>.<span class="function-name">rep</span>(overflowCharacter, overflowWidth), fillColor,
<span class="global">string</span>.<span class="function-name">rep</span>(fillCharacter, fillWidth), resetColor, emptyColor, <span class="global">string</span>.<span class="function-name">rep</span>(emptyCharacter, emptyWidth), resetColor,
percentString, percentSymbolString, resetColor)
<span class="keyword">end</span>
<span class="keyword">return</span> result
<span class="keyword">end</span>
<a id="331"></a><span class="comment">--- Synonym for setValue
</span><span class="keyword">function</span> TextGauge:<span class="global">print</span>(...)
self:<span class="function-name">setValue</span>(...)
<span class="keyword">end</span>
<span class="keyword">return</span> TextGauge</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,628 @@
<!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>MDK</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Source</h2>
<ul class="nowrap">
<li><a href="../source/LICENSE.lua.html">LICENSE.lua</a></li>
<li><a href="../source/aliasmgr.lua.html">aliasmgr.lua</a></li>
<li><a href="../source/chyron.lua.html">chyron.lua</a></li>
<li><a href="../source/demontools.lua.html">demontools.lua</a></li>
<li><a href="../source/echofile.lua.html">echofile.lua</a></li>
<li><a href="../source/emco.lua.html">emco.lua</a></li>
<li><a href="../source/figlet.lua.html">figlet.lua</a></li>
<li><a href="../source/ftext.lua.html">ftext.lua</a></li>
<li><a href="../source/gradientmaker.lua.html">gradientmaker.lua</a></li>
<li><a href="../source/loggingconsole.lua.html">loggingconsole.lua</a></li>
<li><a href="../source/loginator.lua.html">loginator.lua</a></li>
<li><a href="../source/mastermindsolver.lua.html">mastermindsolver.lua</a></li>
<li><a href="../source/revisionator.lua.html">revisionator.lua</a></li>
<li><a href="../source/schema.lua.html">schema.lua</a></li>
<li><a href="../source/sortbox.lua.html">sortbox.lua</a></li>
<li><a href="../source/spinbox.lua.html">spinbox.lua</a></li>
<li><a href="../source/sug.lua.html">sug.lua</a></li>
<li><a href="../source/ftext_spec.lua.html">ftext_spec.lua</a></li>
<li><a href="../source/textgauge.lua.html">textgauge.lua</a></li>
<li><strong>timergauge.lua</strong></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/demontools.html">demontools</a></li>
<li><a href="../modules/echofile.html">echofile</a></li>
<li><a href="../modules/figlet.html">figlet</a></li>
<li><a href="../modules/ftext.html">ftext</a></li>
<li><a href="../modules/GradientMaker.html">GradientMaker</a></li>
</ul>
<h2>Classes</h2>
<ul class="nowrap">
<li><a href="../classes/aliasmgr.html">aliasmgr</a></li>
<li><a href="../classes/Chyron.html">Chyron</a></li>
<li><a href="../classes/EMCO.html">EMCO</a></li>
<li><a href="../classes/LoggingConsole.html">LoggingConsole</a></li>
<li><a href="../classes/Loginator.html">Loginator</a></li>
<li><a href="../classes/MasterMindSolver.html">MasterMindSolver</a></li>
<li><a href="../classes/revisionator.html">revisionator</a></li>
<li><a href="../classes/SortBox.html">SortBox</a></li>
<li><a href="../classes/spinbox.html">spinbox</a></li>
<li><a href="../classes/SUG.html">SUG</a></li>
<li><a href="../classes/TextGauge.html">TextGauge</a></li>
<li><a href="../classes/TimerGauge.html">TimerGauge</a></li>
</ul>
</div>
<div id="content">
<h2>timergauge.lua</h2>
<pre>
<span class="comment">--- Animated countdown timer, extends &lt;a href="https://www.mudlet.org/geyser/files/geyser/GeyserGauge.html"&gt;Geyser.Gauge&lt;/a&gt;
</span><span class="comment">-- @classmod TimerGauge
</span><span class="comment">-- @author Damian Monogue &lt;demonnic@gmail.com&gt;
</span><span class="comment">-- @copyright 2020 Damian Monogue
</span><span class="comment">-- @license MIT, see LICENSE.lua
</span><span class="keyword">local</span> TimerGauge = {
name = <span class="string">"TimerGaugeClass"</span>,
active = <span class="keyword">true</span>,
showTime = <span class="keyword">true</span>,
prefix = <span class="string">""</span>,
timeFormat = <span class="string">"S.t"</span>,
suffix = <span class="string">""</span>,
updateTime = <span class="string">"10"</span>,
autoHide = <span class="keyword">true</span>,
autoShow = <span class="keyword">true</span>,
manageContainer = <span class="keyword">false</span>,
}
<span class="keyword">function</span> TimerGauge:<span class="function-name">setStyleSheet</span>(cssFront, cssBack, cssText)
cssFront = cssFront <span class="keyword">or</span> self.cssFront
cssBack = cssBack <span class="keyword">or</span> self.cssBack
cssBack = cssBack <span class="keyword">or</span> self.cssFront .. <span class="string">"background-color: black;"</span>
cssText = cssText <span class="keyword">or</span> self.cssText
<span class="keyword">if</span> cssFront <span class="keyword">then</span>
self.front:<span class="function-name">setStyleSheet</span>(cssFront)
<span class="keyword">end</span>
<span class="keyword">if</span> cssBack <span class="keyword">then</span>
self.back:<span class="function-name">setStyleSheet</span>(cssBack)
<span class="keyword">end</span>
<span class="keyword">if</span> cssText <span class="keyword">then</span>
self.text:<span class="function-name">setStyleSheet</span>(cssText)
<span class="keyword">end</span>
<span class="comment">-- self.gauge:setStyleSheet(cssFront, cssBack, cssText)
</span> self.cssFront = cssFront
self.cssBack = cssBack
self.cssText = cssText
<span class="keyword">end</span>
<a id="40"></a><span class="comment">--- Shows the TimerGauge. If the manageContainer property is true, then will add it back to its container
</span><span class="keyword">function</span> TimerGauge:<span class="function-name">show2</span>()
<span class="keyword">if</span> self.manageContainer <span class="keyword">and</span> self.savedContainer <span class="keyword">then</span>
self.savedContainer:<span class="function-name">add</span>(self)
self.savedContainer = <span class="keyword">nil</span>
<span class="keyword">end</span>
self:<span class="function-name">show</span>()
<span class="keyword">end</span>
<a id="49"></a><span class="comment">--- Hides the TimerGauge. If manageContainer property is true, then it will remove it from its container and if the container is an HBox or VBox it will initiate size/position management
</span><span class="keyword">function</span> TimerGauge:<span class="function-name">hide2</span>()
<span class="keyword">if</span> self.manageContainer <span class="keyword">and</span> self.container.name ~= Geyser.name <span class="keyword">then</span>
self.savedContainer = self.container
Geyser:<span class="function-name">add</span>(self)
self.savedContainer:<span class="function-name">remove</span>(self)
<span class="keyword">if</span> self.savedContainer.<span class="global">type</span> == <span class="string">"VBox"</span> <span class="keyword">or</span> self.savedContainer.<span class="global">type</span> == <span class="string">"HBox"</span> <span class="keyword">then</span>
<span class="keyword">if</span> self.savedContainer.organize <span class="keyword">then</span>
self.savedContainer:<span class="function-name">organize</span>()
<span class="keyword">else</span>
self.savedContainer:<span class="function-name">reposition</span>()
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
self:<span class="function-name">hide</span>()
<span class="keyword">end</span>
<span class="comment">--- Starts the timergauge. Works whether the timer is stopped or not. Does not start a timer which is already at 0
</span><span class="comment">-- @tparam[opt] boolean show override the autoShow property. True will always show, false will never show.
</span><span class="comment">-- @usage myTimerGauge:start() --starts the timer, will show or not based on autoShow property
</span><span class="comment">-- myTimerGauge:start(false) --starts the timer, will not change hidden status, regardless of autoShow property
</span><a id="70"></a><span class="comment">-- myTimerGauge:start(true) --starts the timer, will show it regardless of autoShow property
</span><span class="keyword">function</span> TimerGauge:<span class="function-name">start</span>(show)
<span class="keyword">if</span> show == <span class="keyword">nil</span> <span class="keyword">then</span>
show = self.autoShow
<span class="keyword">end</span>
self.active = <span class="keyword">true</span>
<span class="keyword">if</span> self.timer <span class="keyword">then</span>
<span class="function-name">killTimer</span>(self.timer)
self.timer = <span class="keyword">nil</span>
<span class="keyword">end</span>
<span class="function-name">startStopWatch</span>(self.stopWatchName)
self:<span class="function-name">update</span>()
self.timer = <span class="function-name">tempTimer</span>(self.updateTime / <span class="number">1000</span>, <span class="keyword">function</span>()
self:<span class="function-name">update</span>()
<span class="keyword">end</span>, <span class="keyword">true</span>)
<span class="keyword">if</span> show <span class="keyword">then</span>
self:<span class="function-name">show2</span>()
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Stops the timergauge. Works whether the timer is started or not.
</span><span class="comment">-- @tparam[opt] boolean hide override the autoHide property. True will always hide, false will never hide.
</span><span class="comment">-- @usage myTimerGauge:stop() --stops the timer, will hide or not based on autoHide property
</span><span class="comment">-- myTimerGauge:stop(false) --stops the timer, will not change hidden status, regardless of autoHide property
</span><a id="94"></a><span class="comment">-- myTimerGauge:stop(true) --stops the timer, will hide it regardless of autoHide property
</span><span class="keyword">function</span> TimerGauge:<span class="function-name">stop</span>(hide)
<span class="keyword">if</span> hide == <span class="keyword">nil</span> <span class="keyword">then</span>
hide = self.autoHide
<span class="keyword">end</span>
self.active = <span class="keyword">false</span>
<span class="keyword">if</span> self.timer <span class="keyword">then</span>
<span class="function-name">killTimer</span>(self.timer)
self.timer = <span class="keyword">nil</span>
<span class="keyword">end</span>
<span class="function-name">stopStopWatch</span>(self.stopWatchName)
<span class="keyword">if</span> hide <span class="keyword">then</span>
self:<span class="function-name">hide2</span>()
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Alias for stop.
</span><a id="111"></a><span class="comment">-- @tparam[opt] boolean hide override the autoHide property. True will always hide, false will never hide.
</span><span class="keyword">function</span> TimerGauge:<span class="function-name">pause</span>(hide)
self:<span class="function-name">stop</span>(hide)
<span class="keyword">end</span>
<a id="116"></a><span class="comment">--- Resets the time on the timergauge to its original value. Does not alter the running state of the timer
</span><span class="keyword">function</span> TimerGauge:<span class="function-name">reset</span>()
<span class="function-name">resetStopWatch</span>(self.stopWatchName)
<span class="function-name">adjustStopWatch</span>(self.stopWatchName, self.time * -<span class="number">1</span>)
self:<span class="function-name">update</span>()
<span class="keyword">end</span>
<span class="comment">--- Resets and starts the timergauge.
</span><span class="comment">-- @tparam[opt] boolean show override the autoShow property. true will always show, false will never show
</span><span class="comment">-- @usage myTimerGauge:restart() --restarts the timer, will show or not based on autoShow property
</span><span class="comment">-- myTimerGauge:restart(false) --restarts the timer, will not change hidden status, regardless of autoShow property
</span><a id="127"></a><span class="comment">-- myTimerGauge:restart(true) --restarts the timer, will show it regardless of autoShow property
</span><span class="keyword">function</span> TimerGauge:<span class="function-name">restart</span>(show)
self:<span class="function-name">reset</span>()
self:<span class="function-name">start</span>(show)
<span class="keyword">end</span>
<span class="comment">--- Get the amount of time remaining on the timer, in seconds
</span><span class="comment">-- @tparam string format Format string for how to return the time. If not provided defaults to self.timeFormat(which defaults to "S.t").&lt;br&gt;
</span><span class="comment">-- If "" is passed will return "" as the time. See below table for formatting codes&lt;br&gt;
</span><span class="comment">-- &lt;table class="tg"&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;th&gt;format code&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;what it is replaced with&lt;/th&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;S&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;Time left in seconds, unbroken down. Does not include milliseconds.&lt;br&gt;
</span><span class="comment">-- IE a timer with 2 minutes left it would replace S with 120
</span><span class="comment">-- &lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;dd&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;Days, with 1 leading 0 (0, 01, 02-...)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;d&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;Days, with no leading 0 (1,2,3-...)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;hh&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;hours, with leading 0 (00-24)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;h&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;hours, without leading 0 (0-24)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;MM&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;minutes, with a leading 0 (00-59)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;M&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;minutes, no leading 0 (0-59)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;ss&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;seconds, with leading 0 (00-59)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;s&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;seconds, no leading 0 (0-59)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;t&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;tenths of a second&lt;br&gt;
</span><span class="comment">-- timer with 12.345 seconds left, t would&lt;br&gt;
</span><span class="comment">-- br replaced by 3.
</span><span class="comment">-- &lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;mm&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;milliseconds with leadings 0s (000-999)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;m&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;milliseconds with no leading 0s (0-999)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/table&gt;&lt;br&gt;
</span><span class="comment">-- @usage myTimerGauge:getTime() --returns the time using myTimerGauge.format
</span><span class="comment">-- myTimerGauge:getTime("hh:MM:ss") --returns the time as hours, minutes, and seconds, with leading 0s (01:23:04)
</span><a id="197"></a><span class="comment">-- myTimerGauge:getTime("S.mm") --returns the time as the total number of seconds, including milliseconds (114.004)
</span><span class="keyword">function</span> TimerGauge:<span class="function-name">getTime</span>(format)
format = format <span class="keyword">or</span> self.timeFormat
<span class="keyword">local</span> time = <span class="function-name">getStopWatchTime</span>(self.stopWatchName)
<span class="keyword">local</span> timerTable = <span class="function-name">getStopWatchBrokenDownTime</span>(self.stopWatchName)
<span class="keyword">if</span> time &gt; <span class="number">0</span> <span class="keyword">then</span>
self:<span class="function-name">stop</span>(self.autoHide)
<span class="function-name">resetStopWatch</span>(self.stopWatchName)
time = <span class="function-name">getStopWatchTime</span>(self.stopWatchName)
timerTable = <span class="function-name">getStopWatchBrokenDownTime</span>(self.stopWatchName)
self.active = <span class="keyword">false</span>
<span class="keyword">end</span>
<span class="keyword">if</span> format == <span class="string">""</span> <span class="keyword">then</span>
<span class="keyword">return</span> format
<span class="keyword">end</span>
<span class="keyword">local</span> totalSeconds = <span class="global">string</span>.<span class="function-name">split</span>(<span class="global">math</span>.<span class="function-name">abs</span>(time), <span class="string">"%."</span>)[<span class="number">1</span>]
<span class="keyword">local</span> tenths = <span class="global">string</span>.<span class="function-name">sub</span>(<span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%03d"</span>, timerTable.milliSeconds), <span class="number">1</span>, <span class="number">1</span>)
format = format:<span class="function-name">gsub</span>(<span class="string">"S"</span>, totalSeconds)
format = format:<span class="function-name">gsub</span>(<span class="string">"t"</span>, tenths)
format = format:<span class="function-name">gsub</span>(<span class="string">"mm"</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%03d"</span>, timerTable.milliSeconds))
format = format:<span class="function-name">gsub</span>(<span class="string">"m"</span>, timerTable.milliSeconds)
format = format:<span class="function-name">gsub</span>(<span class="string">"MM"</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%02d"</span>, timerTable.minutes))
format = format:<span class="function-name">gsub</span>(<span class="string">"M"</span>, timerTable.minutes)
format = format:<span class="function-name">gsub</span>(<span class="string">"dd"</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%02d"</span>, timerTable.days))
format = format:<span class="function-name">gsub</span>(<span class="string">"d"</span>, timerTable.days)
format = format:<span class="function-name">gsub</span>(<span class="string">"ss"</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%02d"</span>, timerTable.seconds))
format = format:<span class="function-name">gsub</span>(<span class="string">"s"</span>, timerTable.seconds)
format = format:<span class="function-name">gsub</span>(<span class="string">"hh"</span>, <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%02d"</span>, timerTable.hours))
format = format:<span class="function-name">gsub</span>(<span class="string">"h"</span>, timerTable.hours)
<span class="keyword">return</span> format
<span class="keyword">end</span>
<span class="comment">-- Execute the timer's hook, if there is one. Internal function
</span><span class="keyword">function</span> TimerGauge:<span class="function-name">executeHook</span>()
<span class="keyword">local</span> hook = self.hook
<span class="keyword">if</span> <span class="keyword">not</span> hook <span class="keyword">then</span>
<span class="keyword">return</span>
<span class="keyword">end</span>
<span class="keyword">local</span> hooktype = <span class="global">type</span>(hook)
<span class="keyword">if</span> hooktype == <span class="string">"string"</span> <span class="keyword">then</span>
<span class="keyword">local</span> f, e = <span class="global">loadstring</span>(<span class="string">"return "</span> .. hook)
<span class="keyword">if</span> <span class="keyword">not</span> f <span class="keyword">then</span>
f, e = <span class="global">loadstring</span>(hook)
<span class="keyword">end</span>
<span class="keyword">if</span> <span class="keyword">not</span> f <span class="keyword">then</span>
<span class="function-name">debugc</span>(<span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"TimerGauge encountered an error while executing the hook for TimerGauge with name: %s error: %s"</span>, self.name, <span class="global">tostring</span>(e)))
<span class="keyword">return</span>
<span class="keyword">end</span>
hook = f
<span class="keyword">end</span>
hooktype = <span class="global">type</span>(hook)
<span class="keyword">if</span> hooktype ~= <span class="string">"function"</span> <span class="keyword">then</span>
<span class="function-name">debugc</span>(<span class="global">string</span>.<span class="function-name">format</span>(
<span class="string">"TimerGauge with name: %s was given a hook which is neither a function nor a string which can be made into one. Provided type was %s"</span>,
self.name, hooktype))
<span class="keyword">return</span>
<span class="keyword">end</span>
<span class="keyword">local</span> worked, err = <span class="global">pcall</span>(hook)
<span class="keyword">if</span> <span class="keyword">not</span> worked <span class="keyword">then</span>
<span class="function-name">debugc</span>(<span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"TimerGauge named %s encountered the following error while executing its hook: %s"</span>, self.name, err))
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Sets the timer's remaining time to 0, stops it, and executes the hook if one exists.
</span><span class="comment">-- @tparam[opt] boolean skipHook use true to have it set the timer to 0 and stop, but not execute the hook.
</span><span class="comment">-- @usage myTimerGauge:finish() --executes the hook if it has one
</span><a id="263"></a><span class="comment">-- myTimerGauge:finish(false) --will not execute the hook
</span><span class="keyword">function</span> TimerGauge:<span class="function-name">finish</span>(skipHook)
<span class="function-name">resetStopWatch</span>(self.stopWatchName)
self:<span class="function-name">update</span>(skipHook)
<span class="keyword">end</span>
<span class="comment">-- Internal function, no ldoc
</span><span class="comment">-- Updates the gauge based on time remaining.
</span><span class="comment">-- @tparam[opt] boolean skipHook use true if you do not want to execute the hook if the timer is at 0.
</span><span class="keyword">function</span> TimerGauge:<span class="function-name">update</span>(skipHook)
<span class="keyword">local</span> time = self.showTime <span class="keyword">and</span> self:<span class="function-name">getTime</span>(self.timeFormat) <span class="keyword">or</span> <span class="string">""</span>
<span class="keyword">local</span> current = <span class="global">tonumber</span>(self:<span class="function-name">getTime</span>(<span class="string">"S.mm"</span>))
<span class="keyword">local</span> suffix = self.suffix <span class="keyword">or</span> <span class="string">""</span>
<span class="keyword">local</span> prefix = self.prefix <span class="keyword">or</span> <span class="string">""</span>
<span class="keyword">local</span> text = <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"%s%s%s"</span>, prefix, time, suffix)
self:<span class="function-name">setValue</span>(current, self.time, text)
<span class="keyword">if</span> current == <span class="number">0</span> <span class="keyword">then</span>
<span class="keyword">if</span> self.timer <span class="keyword">then</span>
<span class="function-name">killTimer</span>(self.timer)
self.timer = <span class="keyword">nil</span>
<span class="keyword">end</span>
<span class="keyword">if</span> <span class="keyword">not</span> skipHook <span class="keyword">then</span>
self:<span class="function-name">executeHook</span>()
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Sets the amount of time the timer will run for. Make sure to call :reset() or :restart()
</span><span class="comment">-- if you want to cause the timer to run for that amount of time. If you set it to a time lower
</span><span class="comment">-- than the time left on the timer currently, it will reset the current time, otherwise it is left alone
</span><span class="comment">-- @tparam number time how long in seconds the timer should run for
</span><a id="294"></a><span class="comment">-- @usage myTimerGauge:setTime(50) -- sets myTimerGauge's max time to 50.
</span><span class="keyword">function</span> TimerGauge:<span class="function-name">setTime</span>(time)
<span class="keyword">local</span> timetype = <span class="global">type</span>(time)
<span class="keyword">if</span> timetype ~= <span class="string">"number"</span> <span class="keyword">then</span>
<span class="keyword">local</span> err = <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"TimerGauge:setTime(time): time as number expected, got %s"</span>, timetype)
<span class="function-name">debugc</span>(err)
<span class="keyword">return</span> <span class="keyword">nil</span>, err
<span class="keyword">end</span>
time = <span class="global">math</span>.<span class="function-name">abs</span>(time)
<span class="keyword">if</span> time == <span class="number">0</span> <span class="keyword">then</span>
<span class="keyword">local</span> err = <span class="string">"TimerGauge:setTime(time): you cannot pass in 0 as the max time for the timer"</span>
<span class="function-name">debugc</span>(err)
<span class="keyword">return</span> <span class="keyword">nil</span>, err
<span class="keyword">end</span>
<span class="keyword">local</span> currentTime = <span class="global">tonumber</span>(self:<span class="function-name">getTime</span>(<span class="string">"S.t"</span>))
self.time = time
<span class="keyword">if</span> time &lt; currentTime <span class="keyword">then</span>
self:<span class="function-name">reset</span>()
<span class="keyword">else</span>
self:<span class="function-name">update</span>(currentTime == <span class="number">0</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="comment">--- Changes the time between gauge updates.
</span><a id="318"></a><span class="comment">-- @tparam number updateTime amount of time in milliseconds between gauge updates. Must be a positive number.
</span><span class="keyword">function</span> TimerGauge:<span class="function-name">setUpdateTime</span>(updateTime)
<span class="keyword">local</span> updateTimeType = <span class="global">type</span>(updateTime)
<span class="global">assert</span>(updateTimeType == <span class="string">"number"</span>,
<span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"TimerGauge:setUpdateTime(updateTime): name: %s updateTime as number expected, got %s"</span>, self.name, updateTimeType))
<span class="global">assert</span>(updateTime &gt; <span class="number">0</span>,
<span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"TimerGauge:setUpdateTime(updateTime): name: %s updateTime must be a positive number. You gave %d"</span>, self.name, updateTime))
self.updateTime = updateTime
<span class="keyword">if</span> self.timer <span class="keyword">then</span>
<span class="function-name">killTimer</span>(self.timer)
self.timer = <span class="keyword">nil</span>
<span class="keyword">end</span>
<span class="keyword">if</span> self.active <span class="keyword">then</span>
self.timer = <span class="function-name">tempTimer</span>(updateTime / <span class="number">1000</span>, <span class="keyword">function</span>()
self:<span class="function-name">update</span>()
<span class="keyword">end</span>, <span class="keyword">true</span>)
<span class="keyword">end</span>
<span class="keyword">end</span>
TimerGauge.parent = Geyser.Gauge
<span class="global">setmetatable</span>(TimerGauge, Geyser.Gauge)
<span class="comment">--- Creates a new TimerGauge instance.
</span><span class="comment">-- @tparam table cons a table of options (or constraints) for how the TimerGauge will behave. Valid options include:
</span><span class="comment">-- &lt;br&gt;
</span><span class="comment">-- &lt;table class="tg"&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;th&gt;name&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;description&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;default&lt;/th&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;time&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;how long the timer should run for&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;active&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;whether the timer should run or not&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;true&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;showTime&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;should we show the time remaining on the gauge?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;true&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;prefix&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;text you want shown before the time.&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;""&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;suffix&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;text you want shown after the time.&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;""&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;timerCaption&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;Alias for suffix. Deprecated and may be remove in the future&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"/&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;updateTime&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;number of milliseconds between gauge updates.&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;10&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;autoHide&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;should the timer :hide() itself when it runs out/you stop it?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;true&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;autoShow&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;should the timer :show() itself when you start it?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;true&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;manageContainer&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;should the timer remove itself from its container when you call &lt;br&gt;:hide() and add itself back when you call :show()?&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;false&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;timeFormat&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;how should the time be displayed/returned if you call :getTime()? &lt;br&gt;See table below for more information&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;"S.t"&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/table&gt;
</span><span class="comment">-- &lt;br&gt;Table of time format options
</span><span class="comment">-- &lt;table class="tg"&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;th&gt;format code&lt;/th&gt;
</span><span class="comment">-- &lt;th&gt;what it is replaced with&lt;/th&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;S&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;Time left in seconds, unbroken down. Does not include milliseconds.&lt;br&gt;
</span><span class="comment">-- IE a timer with 2 minutes left it would replace S with 120
</span><span class="comment">-- &lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;dd&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;Days, with 1 leading 0 (0, 01, 02-...)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;d&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;Days, with no leading 0 (1,2,3-...)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;hh&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;hours, with leading 0 (00-24)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;h&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;hours, without leading 0 (0-24)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;MM&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;minutes, with a leading 0 (00-59)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;M&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;minutes, no leading 0 (0-59)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;ss&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;seconds, with leading 0 (00-59)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;s&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;seconds, no leading 0 (0-59)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;t&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;tenths of a second&lt;br&gt;
</span><span class="comment">-- timer with 12.345 seconds left, t would&lt;br&gt;
</span><span class="comment">-- br replaced by 3.
</span><span class="comment">-- &lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;mm&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-1"&gt;milliseconds with leadings 0s (000-999)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;tr&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;m&lt;/td&gt;
</span><span class="comment">-- &lt;td class="tg-2"&gt;milliseconds with no leading 0s (0-999)&lt;/td&gt;
</span><span class="comment">-- &lt;/tr&gt;
</span><span class="comment">-- &lt;/table&gt;&lt;br&gt;
</span><span class="comment">-- @param parent The Geyser parent for this TimerGauge
</span><span class="comment">-- @usage
</span><span class="comment">-- local TimerGauge = require("MDK.timergauge")
</span><span class="comment">-- myTimerGauge = TimerGauge:new({
</span><span class="comment">-- name = "testGauge",
</span><span class="comment">-- x = 100,
</span><span class="comment">-- y = 100,
</span><span class="comment">-- height = 40,
</span><span class="comment">-- width = 200,
</span><span class="comment">-- time = 10
</span><a id="474"></a><span class="comment">-- })
</span><span class="keyword">function</span> TimerGauge:<span class="function-name">new</span>(cons, parent)
<span class="comment">-- type checking and error handling
</span> <span class="keyword">local</span> consType = <span class="global">type</span>(cons)
<span class="keyword">if</span> consType ~= <span class="string">"table"</span> <span class="keyword">then</span>
<span class="keyword">local</span> err = <span class="global">string</span>.<span class="function-name">format</span>(<span class="string">"TimerGauge:new(options, parent): options must be provided as a table, received: %s"</span>, consType)
<span class="function-name">debugc</span>(err)
<span class="keyword">return</span> <span class="keyword">nil</span>, err
<span class="keyword">end</span>
<span class="keyword">local</span> timetype = <span class="global">type</span>(cons.time)
<span class="keyword">local</span> time = <span class="global">tonumber</span>(cons.time)
<span class="keyword">if</span> <span class="keyword">not</span> time <span class="keyword">then</span>
<span class="keyword">local</span> err = <span class="global">string</span>.<span class="function-name">format</span>(
<span class="string">"TimerGauge:new(options, parent): options table must include a time entry, which must be a number. We received: %s which is type: %s"</span>,
cons.time <span class="keyword">or</span> <span class="global">tostring</span>(cons.time), timetype)
<span class="function-name">debugc</span>(err)
<span class="keyword">return</span> <span class="keyword">nil</span>, err
<span class="keyword">end</span>
cons.time = <span class="global">math</span>.<span class="function-name">abs</span>(time)
<span class="keyword">if</span> cons.time == <span class="number">0</span> <span class="keyword">then</span>
<span class="keyword">local</span> err = <span class="string">"TimerGauge:new(options, parent): time entry in options table must be non-0"</span>
<span class="function-name">debugc</span>(err)
<span class="keyword">return</span> <span class="keyword">nil</span>, err
<span class="keyword">end</span>
<span class="keyword">if</span> cons.timerCaption <span class="keyword">and</span> (<span class="keyword">not</span> cons.suffix) <span class="keyword">then</span>
cons.suffix = cons.timerCaption
<span class="keyword">end</span>
cons.<span class="global">type</span> = cons.<span class="global">type</span> <span class="keyword">or</span> <span class="string">"timergauge"</span>
<span class="comment">-- call parent constructor
</span> <span class="keyword">local</span> me = self.parent:<span class="function-name">new</span>(cons, parent)
<span class="comment">-- add TimerGauge as the metatable/index
</span> <span class="global">setmetatable</span>(me, self)
self.__index = self
<span class="comment">-- apply any styling requested
</span> <span class="keyword">if</span> me.cssFront <span class="keyword">then</span>
<span class="keyword">if</span> <span class="keyword">not</span> me.cssBack <span class="keyword">then</span>
me.cssBack = me.cssFront .. <span class="string">"background-color: black;"</span>
<span class="keyword">end</span>
me:<span class="function-name">setStyleSheet</span>(me.cssFront, me.cssBack, me.cssText)
<span class="keyword">end</span>
<span class="comment">-- create and reset the driving stopwatch
</span> me.stopWatchName = me.name .. <span class="string">"_timergauge"</span>
<span class="function-name">createStopWatch</span>(me.stopWatchName)
me:<span class="function-name">reset</span>()
<span class="comment">-- start it up?
</span> <span class="keyword">if</span> me.active <span class="keyword">then</span>
me:<span class="function-name">start</span>()
<span class="keyword">end</span>
me:<span class="function-name">update</span>()
<span class="keyword">return</span> me
<span class="keyword">end</span>
<span class="keyword">return</span> TimerGauge</pre>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2023-05-29 18:41:27 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

296
src/resources/MDK/echofile.lua Executable file
View File

@ -0,0 +1,296 @@
--- set of functions for echoing files to things. Uses a slightly hacked up version of f-strings for interpolation/templating
-- @module echofile
-- @author Damian Monogue <demonnic@gmail.com>
-- @copyright 2021 Damian Monogue
-- @copyright 2016 Hisham Muhammad (https://github.com/hishamhm/f-strings/blob/master/LICENSE)
-- @license MIT, see LICENSE.lua
local echofile = {}
-- following functions fiddled with from https://github.com/hishamhm/f-strings/blob/master/F.lua and https://hisham.hm/2016/01/04/string-interpolation-in-lua/
-- it seems to work :shrug:
local load = load
if _VERSION == "Lua 5.1" then
load = function(code, name, _, env)
local fn, err = loadstring(code, name)
if fn then
setfenv(fn, env)
return fn
end
return nil, err
end
end
local function f(str)
local outer_env = _ENV or getfenv(1)
return (str:gsub("%b{}", function(block)
local code = block:match("{(.*)}")
local exp_env = {}
setmetatable(exp_env, {
__index = function(_, k)
local stack_level = 5
while debug.getinfo(stack_level, "") ~= nil do
local i = 1
repeat
local name, value = debug.getlocal(stack_level, i)
if name == k then
return value
end
i = i + 1
until name == nil
stack_level = stack_level + 1
end
return rawget(outer_env, k)
end,
})
local fn, err = load("return " .. code, "expression `" .. code .. "`", "t", exp_env)
if fn then
return tostring(fn())
else
error(err, 0)
end
end))
end
local function xechoFile(options)
local filename = options.filename
local window = options.window
local func = options.func
local functionName = options.functionName
local fntype = type(filename)
if fntype ~= "string" then
return nil, f("{functionName}: filename as string expected, got {fnType}")
end
if not io.exists(filename) then
return nil, f("{functionName}: {filename} not found")
end
local file, err = io.open(filename, "r")
if not file then
return nil, err
end
local lines = file:read("*a")
if options.ansi then
lines = ansi2decho(lines)
end
if options.filter then
lines = f(lines)
end
return func(window, lines)
end
local function getOptions(etype, filter, window, filename)
if filename == nil then
filename = window
window = "main"
end
local ansi = false
if etype == "a" then
etype = 'd'
ansi = true
end
local options = {
filename = filename,
window = window,
func = _G[etype .. "echo"],
functionName = etype .. "echoFile([window,] filename)",
ansi = ansi,
filter = filter,
}
return options
end
--- Takes a string and performs interpolation
--- Uses {} as the delimiter. Expressions will be evaluated
---@param str string: The string to interpolate
---@usage echofile = require("MDK.echofile")
--- echofile.f("{1+1}") -- returns "2"
--- local x = 4
--- echofile.f"4+3 = {x+3}" -- returns "4+3 = 7"
function echofile.f(str)
return f(str)
end
--- reads the contents of a file, converts it to decho and then dechos it
---@param window string: Optional window to cecho to
---@param filename string: Full path to file
---@see echofile.f
---@see echofile.cechoFile
---@usage local ec = require("MDK.echofile")
--- local cechoFile,f = ec.cechoFile, ec.f
--- cechoFile("C:/path/to/file") -- windows1
--- cechoFile("C:\\path\\to\\file") -- windows2
--- cechoFile("/path/to/file") -- Linux/MacOS
--- cechoFile("aMiniConsole", f"{getMudletHomeDir()}/myPkgName/helpfile") -- cecho a file from your pkg to a miniconsole
function echofile.aechoFile(window, filename)
local options = getOptions("a", false, window, filename)
return xechoFile(options)
end
--- reads the contents of a file and then cechos it
---@param window string: Optional window to cecho to
---@param filename string: Full path to file
---@see echofile.f
---@see echofile.cechoFilef
---@usage local ec = require("MDK.echofile")
--- local cechoFile,f = ec.cechoFile, ec.f
--- cechoFile("C:/path/to/file") -- windows1
--- cechoFile("C:\\path\\to\\file") -- windows2
--- cechoFile("/path/to/file") -- Linux/MacOS
--- cechoFile("aMiniConsole", f"{getMudletHomeDir()}/myPkgName/helpfile") -- cecho a file from your pkg to a miniconsole
function echofile.aechoFilef(window, filename)
local options = getOptions("a", true, window, filename)
return xechoFile(options)
end
--- reads the contents of a file and then cechos it
---@param window string: Optional window to cecho to
---@param filename string: Full path to file
---@see echofile.f
---@usage local ec = require("MDK.echofile")
--- local cechoFile,f = ec.cechoFile, ec.f
--- cechoFile("C:/path/to/file") -- windows1
--- cechoFile("C:\\path\\to\\file") -- windows2
--- cechoFile("/path/to/file") -- Linux/MacOS
--- cechoFile("aMiniConsole", f"{getMudletHomeDir()}/myPkgName/helpfile") -- cecho a file from your pkg to a miniconsole
function echofile.cechoFile(window, filename)
local options = getOptions("c", false, window, filename)
return xechoFile(options)
end
--- reads the contents of a file, interpolates it as per echofile.f and then cechos it
---@param window string: Optional window to cecho to
---@param filename string: Full path to file
---@see echofile.f
---@usage local ec = require("MDK.echofile")
--- local cechoFile,f = ec.cechoFile, ec.f
--- cechoFile("C:/path/to/file") -- windows1
--- cechoFile("C:\\path\\to\\file") -- windows2
--- cechoFile("/path/to/file") -- Linux/MacOS
--- cechoFile("aMiniConsole", f"{getMudletHomeDir()}/myPkgName/helpfile") -- cecho a file from your pkg to a miniconsole
function echofile.cechoFilef(window, filename)
local options = getOptions("c", true, window, filename)
return xechoFile(options)
end
--- reads the contents of a file and then dechos it
---@param window string: Optional window to decho to
---@param filename string: Full path to file
---@see echofile.f
---@see echofile.cechoFile
function echofile.dechoFile(window, filename)
local options = getOptions("d", false, window, filename)
return xechoFile(options)
end
--- reads the contents of a file, interpolates it as per echofile.f and then dechos it
---@param window string: Optional window to decho to
---@param filename string: Full path to file
---@see echofile.f
---@see echofile.cechoFile
function echofile.dechoFilef(window, filename)
local options = getOptions("d", true, window, filename)
return xechoFile(options)
end
--- reads the contents of a file and then hechos it
---@param window string: Optional window to hecho to
---@param filename string: Full path to file
---@see echofile.f
---@see echofile.cechoFile
function echofile.hechoFile(window, filename)
local options = getOptions("h", false, window, filename)
return xechoFile(options)
end
--- reads the contents of a file, interpolates it as per echofile.f and then hechos it
---@param window string: Optional window to hecho to
---@param filename string: Full path to file
---@see echofile.f
---@see echofile.cechoFile
function echofile.hechoFilef(window, filename)
local options = getOptions("h", true, window, filename)
return xechoFile(options)
end
--- reads the contents of a file, interpolates it as per echofile.f and then echos it
---@param window string: Optional window to echo to
---@param filename string: Full path to file
---@see echofile.f
---@see echofile.cechoFile
function echofile.echoFile(window, filename)
local options = getOptions("", false, window, filename)
return xechoFile(options)
end
--- reads the contents of a file, interpolates it as per echofile.f and then echos it
---@param window string: Optional window to echo to
---@param filename string: Full path to file
---@see echofile.f
---@see echofile.cechoFile
function echofile.echoFilef(window, filename)
local options = getOptions("", true, window, filename)
return xechoFile(options)
end
--- Adds c/d/h/echoFile functions to Geyser miniconsole and userwindow objects
---@usage require("MDK.echofile").patchGeyser()
--- myMC = Geyser.MiniConsole:new({name = "myMC"})
--- myMC:cechoFile(f"{getMudletHomeDir()}/helpfile")
function echofile.patchGeyser()
if Geyser.MiniConsole.echoFile then
return
end
function Geyser.MiniConsole:echoFile(filename)
return echofile.echoFile(self.name, filename)
end
function Geyser.MiniConsole:echoFilef(filename)
return echofile.echoFilef(self.name, filename)
end
function Geyser.MiniConsole:aechoFile(filename)
return echofile.aechoFile(self.name, filename)
end
function Geyser.MiniConsole:aechoFilef(filename)
return echofile.aechoFilef(self.name, filename)
end
function Geyser.MiniConsole:cechoFile(filename)
return echofile.cechoFile(self.name, filename)
end
function Geyser.MiniConsole:cechoFilef(filename)
return echofile.cechoFilef(self.name, filename)
end
function Geyser.MiniConsole:dechoFile(filename)
return echofile.dechoFile(self.name, filename)
end
function Geyser.MiniConsole:dechoFilef(filename)
return echofile.dechoFilef(self.name, filename)
end
function Geyser.MiniConsole:hechoFile(filename)
return echofile.hechoFile(self.name, filename)
end
function Geyser.MiniConsole:hechoFilef(filename)
return echofile.hechoFilef(self.name, filename)
end
end
--- Installs c/d/h/echoFile and f to the global namespace, and adds functions to Geyser
---@usage require("MDK.echofile").installGlobal()
--- f"{1+2}" -- returns "2"
--- dechoFile(f"{getMudletHomeDir()}/fileWithDechoLines.txt")
--- -- reads contents of fileWithDechoLines.txt from profile directory
--- -- and dechos them to the main console
function echofile.installGlobal()
_G.f = f
_G.echoFile = echofile.echoFile
_G.echoFilef = echofile.echoFilef
_G.aechoFile = echofile.aechoFile
_G.aechoFilef = echofile.aechoFilef
_G.cechoFile = echofile.cechoFile
_G.cechoFilef = echofile.cechoFilef
_G.dechoFile = echofile.dechoFile
_G.dechoFilef = echofile.dechoFilef
_G.hechoFile = echofile.hechoFile
_G.hechoFilef = echofile.hechoFilef
echofile.patchGeyser()
end
return echofile

2353
src/resources/MDK/emco.lua Executable file

File diff suppressed because it is too large Load Diff

267
src/resources/MDK/figlet.lua Executable file
View File

@ -0,0 +1,267 @@
--- Figlet
-- A module to read figlet fonts and produce figlet ascii art from text
-- @module figlet
-- @copyright 2010,2011 Nick Gammon
-- @copyright 2022 Damian Monogue
local Figlet = {}
--[[
Based on figlet.
FIGlet Copyright 1991, 1993, 1994 Glenn Chappell and Ian Chai
FIGlet Copyright 1996, 1997 John Cowan
Portions written by Paul Burton
Internet: <ianchai@usa.net>
FIGlet, along with the various FIGlet fonts and documentation, is
copyrighted under the provisions of the Artistic License (as listed
in the file "artistic.license" which is included in this package.
--]]
--[[
Latin-1 codes for German letters, respectively:
LATIN CAPITAL LETTER A WITH DIAERESIS = A-umlaut
LATIN CAPITAL LETTER O WITH DIAERESIS = O-umlaut
LATIN CAPITAL LETTER U WITH DIAERESIS = U-umlaut
LATIN SMALL LETTER A WITH DIAERESIS = a-umlaut
LATIN SMALL LETTER O WITH DIAERESIS = o-umlaut
LATIN SMALL LETTER U WITH DIAERESIS = u-umlaut
LATIN SMALL LETTER SHARP S = ess-zed
--]]
local deutsch = {196, 214, 220, 228, 246, 252, 223}
local fcharlist = {}
local magic, hardblank, charheight, maxlen, smush, cmtlines, ffright2left, smush2
local function readfontchar(fontfile, theord)
local t = {}
fcharlist[theord] = t
-- read each character line
--[[
eg.
__ __ @
| \/ |@
| \ / |@
| |\/| |@
| | | |@
|_| |_|@
@
@@
--]]
for i = 1, charheight do
local line = assert(fontfile:read("*l"), "Not enough character lines for character " .. theord)
local line = string.gsub(line, "%s+$", "") -- remove trailing spaces
assert(line ~= "", "Unexpected empty line")
-- find the last character (eg. @)
local endchar = line:sub(-1) -- last character
-- trim one or more of the last character from the end
while line:sub(-1) == endchar do
line = line:sub(1, #line - 1)
end -- while line ends with endchar
table.insert(t, line)
end -- for each line
end -- readfontchar
--- Reads a figlet font file (.flf) into memory and readies it for use by the next figlet
-- These files are cached in memory so that future calls to load a font just read from there.
-- @param filename the full path to the file to read the font from
function Figlet.readfont(filename)
local fontfile = assert(io.open(filename, "r"))
local s
fcharlist = {}
-- header line
s = assert(fontfile:read("*l"), "Empty FIGlet file")
-- eg. flf2a$ 8 6 59 15 10 0 24463 153
-- magic charheight maxlen smush cmtlines ffright2left smush2 ??
-- configuration line
magic, hardblank, charheight, maxlen, smush, cmtlines, ffright2left, smush2 = string.match(s,
"^(flf2).(.) (%d+) %d+ (%d+) (%-?%d+) (%d+) ?(%d*) ?(%d*) ?(%-?%d*)")
assert(magic, "Not a FIGlet 2 font file")
-- convert to numbers
charheight = tonumber(charheight)
maxlen = tonumber(maxlen)
smush = tonumber(smush)
cmtlines = tonumber(cmtlines)
-- sanity check
if charheight < 1 then
charheight = 1
end -- if
-- skip comment lines
for i = 1, cmtlines do
assert(fontfile:read("*l"), "Not enough comment lines")
end -- for
-- get characters space to tilde
for theord = string.byte(' '), string.byte('~') do
readfontchar(fontfile, theord)
end -- for
-- get 7 German characters
for theord = 1, 7 do
readfontchar(fontfile, deutsch[theord])
end -- for
-- get extra ones like:
-- 0x0395 GREEK CAPITAL LETTER EPSILON
-- 246 LATIN SMALL LETTER O WITH DIAERESIS
repeat
local extra = fontfile:read("*l")
if not extra then
break
end -- if eof
local negative, theord = string.match(extra, "^(%-?)0[xX](%x+)")
if theord then
theord = tonumber(theord, 16)
if negative == "-" then
theord = -theord
end -- if negative
else
theord = string.match(extra, "^%d+")
assert(theord, "Unexpected line:" .. extra)
theord = tonumber(theord)
end -- if
readfontchar(fontfile, theord)
until false
fontfile:close()
-- remove leading/trailing spaces
for k, v in pairs(fcharlist) do
-- first see if all lines have a leading space or a trailing space
local leading_space = true
local trailing_space = true
for _, line in ipairs(v) do
if line:sub(1, 1) ~= " " then
leading_space = false
end -- if
if line:sub(-1, -1) ~= " " then
trailing_space = false
end -- if
end -- for each line
-- now remove them if necessary
for i, line in ipairs(v) do
if leading_space then
v[i] = line:sub(2)
end -- removing leading space
if trailing_space then
v[i] = line:sub(1, -2)
end -- removing trailing space
end -- for each line
end -- for each character
end -- readfont
-- add one character to output lines
local function addchar(which, output, kern, smush)
local c = fcharlist[string.byte(which)]
if not c then
return
end -- if doesn't exist
for i = 1, charheight do
if smush and output[i] ~= "" and which ~= " " then
local lhc = output[i]:sub(-1)
local rhc = c[i]:sub(1, 1)
output[i] = output[i]:sub(1, -2) -- remove last character
if rhc ~= " " then
output[i] = output[i] .. rhc
else
output[i] = output[i] .. lhc
end
output[i] = output[i] .. c[i]:sub(2)
else
output[i] = output[i] .. c[i]
end -- if
if not (kern or smush) or which == " " then
output[i] = output[i] .. " "
end -- if
end -- for
end -- addchar
--- Returns a table of lines representing a string as figlet
-- @tparam string s the text to make into a figlet
-- @tparam boolean kern should we reduce spacing
-- @tparam boolean smush causes the letters to share edges, condensing it even further
function Figlet.ascii_art(s, kern, smush)
assert(fcharlist)
assert(charheight > 0)
-- make table of output lines
local output = {}
for i = 1, charheight do
output[i] = ""
end -- for
for i = 1, #s do
local c = s:sub(i, i)
if c >= " " and c < "\127" then
addchar(c, output, kern, smush)
end -- if in range
end -- for
-- fix up blank character so we can do a string.gsub on it
local fixedblank = string.gsub(hardblank, "[%%%]%^%-$().[*+?]", "%%%1")
for i, line in ipairs(output) do
output[i] = string.gsub(line, fixedblank, " ")
end -- for
return output
end -- function ascii_art
--- Returns the figlet as a string, rather than a table
-- @tparam string str the string the make into a figlet
-- @tparam boolean kern should we reduce the space between letters?
-- @tparam boolean smush should the letters share edges, further condensing the output?
-- @see ascii_art
function Figlet.getString(str, kern, smush)
local tbl = Figlet.ascii_art(str, kern, smush)
return table.concat(tbl, "\n")
end
--- Returns a figlet as a string, with kern set to true.
-- @tparam string str The string to turn into a figlet
-- @see getString
function Figlet.getKern(str)
return Figlet.getString(str, true)
end
--- Returns a figlet as a string, with smush set to true.
-- @tparam string str The string to turn into a figlet
-- @see getString
function Figlet.getSmush(str)
return Figlet.getString(str, true, true)
end
return Figlet

1697
src/resources/MDK/ftext.lua Executable file

File diff suppressed because it is too large Load Diff

447
src/resources/MDK/ftext_spec.lua Executable file
View File

@ -0,0 +1,447 @@
local ftext = require("MDK.ftext")
describe("ftext:", function()
describe("ftext.fText:", function()
local fText = ftext.fText
it("Should properly center text", function()
local expected = " some text "
local actual = fText("some text", {width = 20})
assert.equals(expected, actual)
assert.equals(20, actual:len())
end)
it("Should properly pad left aligned text", function()
local expected = "some text "
local actual = fText("some text", {width = 20, alignment = "left"})
assert.equals(expected, actual)
assert.equals(20, actual:len())
end)
it("Should properly pad right aligned text", function()
local expected = " some text"
local actual = fText("some text", {width = 20, alignment = "right"})
assert.equals(expected, actual)
assert.equals(20, actual:len())
end)
it("Should wrap lines to the correct length", function()
local str = "This is a test of the emergency broadcast system. This is only a test"
local options = {width = 10, alignment = "centered"}
local actual = fText(str, options)
for _, line in ipairs(actual:split("\n")) do
assert.equals(line:len(), 10)
end
options.width = 15
actual = fText(str, options)
for _, line in ipairs(actual:split("\n")) do
assert.equals(line:len(), 15)
end
end)
describe("non-space spacer character:", function()
local str = "some text"
local options = {width = "20", alignment = "left", spacer = "="}
it("Should work with left align", function()
local expected = "some text =========="
local actual = fText(str, options)
assert.equals(expected, actual)
assert.equals(20, actual:len())
end)
it("Should work with right align", function()
local expected = "========== some text"
options.alignment = "right"
local actual = fText(str, options)
assert.equals(expected, actual)
assert.equals(20, actual:len())
end)
it("Should work with center align", function()
local expected = ("==== some text =====")
options.alignment = "center"
local actual = fText(str, options)
assert.equals(expected, actual)
assert.equals(20, actual:len())
end)
end)
describe("nogap option:", function()
local str = "some text"
local options = {width = "20", alignment = "left", spacer = "=", nogap = true}
it("Should work with left align", function()
local expected = "some text==========="
local actual = fText(str, options)
assert.equals(expected, actual)
assert.equals(20, actual:len())
end)
it("Should work with right align", function()
local expected = "===========some text"
options.alignment = "right"
local actual = fText(str, options)
assert.equals(expected, actual)
assert.equals(20, actual:len())
end)
it("Should work with center align", function()
local expected = "=====some text======"
options.alignment = "center"
local actual = fText(str, options)
assert.equals(expected, actual)
assert.equals(20, actual:len())
end)
end)
describe("cap functionality", function()
local str = "some text"
local options = {width = 20, spacer = "=", cap = "|"}
it("Should place the spacer outside the cap by default", function()
local expected = "===| some text |===="
local actual = fText(str, options)
assert.equals(expected, actual)
assert.equals(20, actual:len())
end)
it("Should place it inside the cap if inside option is true", function()
local expected = "|=== some text ====|"
options.inside = true
local actual = fText(str, options)
options.inside = nil
assert.equals(expected, actual)
assert.equals(20, actual:len())
end)
it("Should mirror certain characters with their opposites", function()
local expected = "===[ some text ]===="
options.mirror = true
options.cap = "["
local actual = fText(str, options)
assert.equals(expected, actual)
options.inside = true
expected = "[=== some text ====]"
actual = fText(str, options)
assert.equals(expected, actual)
options.inside = nil
options.cap = "<"
expected = "===< some text >===="
actual = fText(str, options)
assert.equals(expected, actual)
options.cap = "{"
expected = "==={ some text }===="
actual = fText(str, options)
assert.equals(expected, actual)
options.cap = "("
expected = "===( some text )===="
actual = fText(str, options)
assert.equals(expected, actual)
options.cap = "|"
expected = "===| some text |===="
actual = fText(str, options)
assert.equals(expected, actual)
end)
end)
end)
describe("ftext.cfText", function()
local cfText = ftext.cfText
local str = "some text"
local options = {
width = 20,
spacer = "=",
cap = "[",
inside = true,
mirror = true,
capColor = "<purple>",
spacerColor = "<green>",
textColor = "<red>",
}
it("Should handle cecho colored text", function()
local expectedStripped = "[=== some text ====]"
local expected = "<purple>[<reset><green>===<reset><red> some text <reset><green>====<reset><purple>]<reset>"
local actual = cfText(str, options)
local actualStripped = cecho2string(actual)
assert.equals(expected, actual)
assert.equals(expectedStripped, actualStripped)
assert.equals(20, actualStripped:len())
expectedStripped = "===[ some text ]===="
expected = "<green>===<reset><purple>[<reset><red> some text <reset><purple>]<reset><green>====<reset>"
options.inside = false
actual = cfText(str, options)
actualStripped = cecho2string(actual)
assert.equals(expected, actual)
assert.equals(expectedStripped, actualStripped)
assert.equals(20, actualStripped:len())
end)
it("Should wrap cecho lines to the correct length", function()
local str = "This is a test of the emergency broadcast system. This is only a test"
local options = {width = 10, alignment = "centered"}
local actual = cfText(str, options)
for _, line in ipairs(actual:split("\n")) do
assert.equals(cecho2string(line):len(), 10)
end
options.width = 15
actual = cfText(str, options)
for _, line in ipairs(actual:split("\n")) do
assert.equals(cecho2string(line):len(), 15)
end
end)
end)
describe("ftext.dfText", function()
local dfText = ftext.dfText
local str = "some text"
local options = {
width = 20,
spacer = "=",
cap = "[",
inside = true,
mirror = true,
capColor = "<160,32,240>",
spacerColor = "<0,255,0>",
textColor = "<255,0,0>",
}
it("Should handle decho colored text", function()
local expectedStripped = "[=== some text ====]"
local expected = "<160,32,240>[<r><0,255,0>===<r><255,0,0> some text <r><0,255,0>====<r><160,32,240>]<r>"
local actual = dfText(str, options)
local actualStripped = decho2string(actual)
assert.equals(expected, actual)
assert.equals(expectedStripped, actualStripped)
assert.equals(20, actualStripped:len())
expectedStripped = "===[ some text ]===="
expected = "<0,255,0>===<r><160,32,240>[<r><255,0,0> some text <r><160,32,240>]<r><0,255,0>====<r>"
options.inside = false
actual = dfText(str, options)
actualStripped = decho2string(actual)
assert.equals(expected, actual)
assert.equals(expectedStripped, actualStripped)
assert.equals(20, actualStripped:len())
end)
it("Should wrap decho lines to the correct length", function()
local str = "This is a test of the emergency broadcast system. This is only a test"
local options = {width = 10, alignment = "centered"}
local actual = dfText(str, options)
for _, line in ipairs(actual:split("\n")) do
assert.equals(decho2string(line):len(), 10)
end
options.width = 15
actual = dfText(str, options)
for _, line in ipairs(actual:split("\n")) do
assert.equals(decho2string(line):len(), 15)
end
end)
end)
describe("ftext.hfText", function()
local hfText = ftext.hfText
local str = "some text"
local options = {
width = 20,
spacer = "=",
cap = "[",
inside = true,
mirror = true,
capColor = "#a020f0",
spacerColor = "#00ff00",
textColor = "#ff0000",
}
it("Should handle hecho colored text", function()
local expectedStripped = "[=== some text ====]"
local expected = "#a020f0[#r#00ff00===#r#ff0000 some text #r#00ff00====#r#a020f0]#r"
local actual = hfText(str, options)
local actualStripped = hecho2string(actual)
assert.equals(expected, actual)
assert.equals(expectedStripped, actualStripped)
assert.equals(20, actualStripped:len())
expectedStripped = "===[ some text ]===="
expected = "#00ff00===#r#a020f0[#r#ff0000 some text #r#a020f0]#r#00ff00====#r"
options.inside = false
actual = hfText(str, options)
actualStripped = hecho2string(actual)
assert.equals(expected, actual)
assert.equals(expectedStripped, actualStripped)
assert.equals(20, actualStripped:len())
end)
it("Should wrap hecho lines to the correct length", function()
local str = "This is a test of the emergency broadcast system. This is only a test"
local options = {width = 10, alignment = "centered"}
local actual = hfText(str, options)
for _, line in ipairs(actual:split("\n")) do
assert.equals(hecho2string(line):len(), 10)
end
options.width = 15
actual = hfText(str, options)
for _, line in ipairs(actual:split("\n")) do
assert.equals(hecho2string(line):len(), 15)
end
end)
end)
describe("ftext.TextFormatter", function()
local tf = ftext.TextFormatter
local str = "some text"
local formatter
before_each(function()
formatter = tf:new({width = 20})
end)
it("Should let you change width using :setWidth", function()
formatter:setWidth(80)
local expected =
"<white><reset><white> <reset><white> some text <reset><white> <reset><white><reset>"
local actual = formatter:format(str)
assert.equals(expected, actual)
assert.equals(80, cecho2string(actual):len())
end)
it("Should format for cecho by default", function()
local expected = "<white><reset><white> <reset><white> some text <reset><white> <reset><white><reset>"
local expectedStripped = " some text "
local actual = formatter:format(str)
local actualStripped = cecho2string(actual)
assert.equals(expected, actual)
assert.equals(expectedStripped, actualStripped)
assert.equals(20, actualStripped:len())
end)
it("Should produce the same line as cfText given the same options", function()
local expected = ftext.cfText(str, formatter.options)
local actual = formatter:format(str)
assert.equals(expected, actual)
end)
it("Should let you change type using :setType", function()
formatter:setType("h")
local expected = ftext.hfText(str, formatter.options)
local actual = formatter:format(str)
assert.equals(expected, actual)
formatter:setType("d")
expected = ftext.dfText(str, formatter.options)
actual = formatter:format(str)
assert.equals(expected, actual)
formatter:setType("")
expected = ftext.fText(str, formatter.options)
actual = formatter:format(str)
assert.equals(expected, actual)
end)
it("Should default to word wrapping, and let you change it with :setWrap", function()
formatter:setWidth(10)
local expected =
"<white><reset><white> <reset><white> some <reset><white> <reset><white><reset>\n<white><reset><white> <reset><white> text <reset><white> <reset><white><reset>"
local actual = formatter:format(str)
assert.equals(expected, actual)
expected = "<white><reset><white><reset><white> some text <reset><white><reset><white><reset>"
formatter:setWrap(false)
actual = formatter:format(str)
assert.equals(expected, actual)
end)
it("Should allow you to change the cap using :setCap", function()
formatter:setCap('|')
local expected = "<white>|<reset><white> <reset><white> some text <reset><white> <reset><white>|<reset>"
local actual = formatter:format(str)
assert.equals(expected, actual)
end)
it("Should allow you to change the capColor using :setCapColor", function()
formatter:setCapColor('<red>')
local expected = "<red><reset><white> <reset><white> some text <reset><white> <reset><red><reset>"
local actual = formatter:format(str)
assert.equals(expected, actual)
end)
it("Should allow you to change the spacer color using :setSpacerColor", function()
formatter:setSpacerColor("<red>")
local expected = "<white><reset><red> <reset><white> some text <reset><red> <reset><white><reset>"
local actual = formatter:format(str)
assert.equals(expected, actual)
end)
it("Should allow you to change the text color using :setTextColor", function()
formatter:setTextColor("<red>")
local expected = "<white><reset><white> <reset><red> some text <reset><white> <reset><white><reset>"
local actual = formatter:format(str)
assert.equals(expected, actual)
end)
it("Should allow you to change the spacer using :setSpacer", function()
formatter:setSpacer("=")
-- local expected = "<white><reset><white> <reset><white> some text <reset><white> <reset><white><reset>"
local expected = "<white><reset><white>====<reset><white> some text <reset><white>=====<reset><white><reset>"
local actual = formatter:format(str)
assert.equals(expected, actual)
end)
it("Should allow you to set the alignment using :setAlignment", function()
formatter:setAlignment("left")
local expected = "<white><reset><white><reset><white>some text <reset><white> <reset><white><reset>"
local actual = formatter:format(str)
assert.equals(expected, actual)
formatter:setAlignment("right")
expected = "<white><reset><white> <reset><white> some text<reset><white><reset><white><reset>"
actual = formatter:format(str)
assert.equals(expected, actual)
end)
it("Should allow you to change the 'inside' option using :setInside", function()
formatter:setInside(false)
local expected = "<white> <reset><white><reset><white> some text <reset><white><reset><white> <reset>"
local actual = formatter:format(str)
assert.equals(expected, actual)
end)
it("Should allow you to change the mirror option using :setMirror", function()
formatter:setCap('<')
formatter:setMirror(true)
local expected = "<white><<reset><white> <reset><white> some text <reset><white> <reset><white>><reset>"
local actual = formatter:format(str)
assert.equal(expected, actual)
end)
end)
describe("ftext.TableMaker", function()
local TableMaker = ftext.TableMaker
local tm
before_each(function()
tm = TableMaker:new()
tm:addColumn({name = "col1", width = 15, textColor = "<red>"})
tm:addColumn({name = "col2", width = 15, textColor = "<blue>"})
tm:addColumn({name = "col3", width = 15, textColor = "<green>"})
tm:addRow({"some text", "more text", "other text"})
tm:addRow({"little text", "bigger text", "text"})
end)
it("Should assemble a formatted table given default options", function()
local expected = [[<white>*************************************************<reset>
<white>*<reset><white><reset><white> <reset><red> col1 <reset><white> <reset><white><reset><white>|<reset><white><reset><white> <reset><blue> col2 <reset><white> <reset><white><reset><white>|<reset><white><reset><white> <reset><green> col3 <reset><white> <reset><white><reset><white>*<reset>
<white>*<reset><white>---------------<reset><white>|<reset><white>---------------<reset><white>|<reset><white>---------------<reset><white>*<reset>
<white>*<reset><white><reset><white> <reset><red> some text <reset><white> <reset><white><reset><white>|<reset><white><reset><white> <reset><blue> more text <reset><white> <reset><white><reset><white>|<reset><white><reset><white> <reset><green> other text <reset><white> <reset><white><reset><white>*<reset>
<white>*<reset><white>---------------<reset><white>|<reset><white>---------------<reset><white>|<reset><white>---------------<reset><white>*<reset>
<white>*<reset><white><reset><white> <reset><red> little text <reset><white> <reset><white><reset><white>|<reset><white><reset><white> <reset><blue> bigger text <reset><white> <reset><white><reset><white>|<reset><white><reset><white> <reset><green> text <reset><white> <reset><white><reset><white>*<reset>
<white>*************************************************<reset>
]]
local actual = tm:assemble()
assert.equals(expected, actual)
end)
it("TableMaker:getCell should return the text and formatter for a specific cell", function()
local expectedText = "more text"
local expectedFormatter = tm.columns[2]
local actualText, actualFormatter = tm:getCell(1, 2)
assert.equals(expectedText, actualText)
assert.equals(expectedFormatter, actualFormatter)
local expectedFormatted = "<white><reset><white> <reset><blue> more text <reset><white> <reset><white><reset>"
local actualFormatted = actualFormatter:format(actualText)
assert.equals(expectedFormatted, actualFormatted)
end)
end)
end)

View File

@ -0,0 +1,342 @@
--- Module which provides for creating color gradients for your text.
-- Original functions found on <a href="https://forums.lusternia.com/discussion/3261/anyone-want-text-gradients">the Lusternia Forums</a>
-- <br> I added functions to work with hecho.
-- <br> I also made performance enhancements by storing already calculated gradients after first use for the session and only including the colorcode in the returned string if the color changed.
-- @module GradientMaker
-- @author Sylphas on the Lusternia forums
-- @author Damian Monogue <demonnic@gmail.com>
-- @copyright 2018 Sylphas
-- @copyright 2020 Damian Monogue
local GradientMaker = {}
local gradient_table = {}
local function _clamp(num1, num2, num3)
local smaller = math.min(num2, num3)
local larger = math.max(num2, num3)
local minimum = math.max(0, smaller)
local maximum = math.min(255, larger)
return math.min(maximum, math.max(minimum, num1))
end
local function _gradient(length, rgb1, rgb2)
assert(length > 0)
if length == 1 then
return {rgb1}
elseif length == 2 then
return {rgb1, rgb2}
else
local step = {}
for color = 1, 3 do
step[color] = (rgb2[color] - rgb1[color]) / (length - 2)
end
local gradient = {rgb1}
for iter = 1, length - 2 do
gradient[iter + 1] = {}
for color = 1, 3 do
gradient[iter + 1][color] = math.ceil(rgb1[color] + (iter * step[color]))
end
end
gradient[length] = rgb2
for index, color in ipairs(gradient) do
for iter = 1, 3 do
gradient[index][iter] = _clamp(color[iter], rgb1[iter], rgb2[iter])
end
end
return gradient
end
end
local function gradient_to_string(gradient)
local gradstring = ""
for _, grad in ipairs(gradient) do
local nodestring = ""
for _, col in ipairs(grad) do
nodestring = string.format("%s%03d", nodestring, col)
end
if _ == 1 then
gradstring = nodestring
else
gradstring = gradstring .. "|" .. nodestring
end
end
return gradstring
end
local function _gradients(length, ...)
local arg = {...}
local argkey = gradient_to_string(arg)
local gradients_for_length = gradient_table[length]
if not gradients_for_length then
gradient_table[length] = {}
gradients_for_length = gradient_table[length]
end
local grads = gradients_for_length[argkey]
if grads then
return grads
end
if #arg == 0 then
gradients_for_length[argkey] = {}
return {}
elseif #arg == 1 then
gradients_for_length[argkey] = arg[1]
return arg[1]
elseif #arg == 2 then
gradients_for_length[argkey] = _gradient(length, arg[1], arg[2])
return gradients_for_length[argkey]
else
local quotient = math.floor(length / (#arg - 1))
local remainder = length % (#arg - 1)
local gradients = {}
for section = 1, #arg - 1 do
local slength = quotient
if section <= remainder then
slength = slength + 1
end
local gradient = _gradient(slength, arg[section], arg[section + 1])
for _, rgb in ipairs(gradient) do
table.insert(gradients, rgb)
end
end
gradients_for_length[argkey] = gradients
return gradients
end
end
local function _color_name(rgb)
local least_distance = math.huge
local cname = ""
for name, color in pairs(color_table) do
local color_distance = math.sqrt((color[1] - rgb[1]) ^ 2 + (color[2] - rgb[2]) ^ 2 + (color[3] - rgb[3]) ^ 2)
if color_distance < least_distance then
least_distance = color_distance
cname = name
end
end
return cname
end
local function errorIfEmpty(text, funcName)
assert(#text > 0, string.format("%s: you passed in an empty string, and I cannot make a gradient out of an empty string", funcName))
end
local function dgradient_table(text, ...)
errorIfEmpty(text, "dgradient_table")
local gradients = _gradients(#text, ...)
local dgrads = {}
for character = 1, #text do
table.insert(dgrads, {gradients[character], text:sub(character, character)})
end
return dgrads
end
local function dgradient(text, ...)
errorIfEmpty(text, "dgradient")
local gradients = _gradients(#text, ...)
local dgrad = ""
local current_color = ""
for character = 1, #text do
local new_color = "<" .. table.concat(gradients[character], ",") .. ">"
local char = text:sub(character, character)
if new_color == current_color then
dgrad = dgrad .. char
else
dgrad = dgrad .. new_color .. char
current_color = new_color
end
end
return dgrad
end
local function cgradient_table(text, ...)
errorIfEmpty(text, "cgradient_table")
local gradients = _gradients(#text, ...)
local cgrads = {}
for character = 1, #text do
table.insert(cgrads, {_color_name(gradients[character]), text:sub(character, character)})
end
return cgrads
end
local function cgradient(text, ...)
errorIfEmpty(text, "cgradient")
local gradients = _gradients(#text, ...)
local cgrad = ""
local current_color = ""
for character = 1, #text do
local new_color = "<" .. _color_name(gradients[character]) .. ">"
local char = text:sub(character, character)
if new_color == current_color then
cgrad = cgrad .. char
else
cgrad = cgrad .. new_color .. char
current_color = new_color
end
end
return cgrad
end
local hex = Geyser.Color.hex
local function hgradient_table(text, ...)
errorIfEmpty(text, "hgradient_table")
local grads = _gradients(#text, ...)
local hgrads = {}
for character = 1, #text do
table.insert(hgrads, {hex(unpack(grads[character])):sub(2, -1), text:sub(character, character)})
end
return hgrads
end
local function hgradient(text, ...)
errorIfEmpty(text, "hgradient")
local grads = _gradients(#text, ...)
local hgrads = ""
local current_color = ""
for character = 1, #text do
local new_color = hex(unpack(grads[character]))
local char = text:sub(character, character)
if new_color == current_color then
hgrads = hgrads .. char
else
hgrads = hgrads .. new_color .. char
current_color = new_color
end
end
return hgrads
end
local function color_name(...)
local arg = {...}
if #arg == 1 then
return _color_name(arg[1])
elseif #arg == 3 then
return _color_name(arg)
else
local errmsg =
"color_name: You must pass either a table of r,g,b values: color_name({r,g,b})\nor the three r,g,b values separately: color_name(r,g,b)"
error(errmsg)
end
end
--- Returns the closest color name to a given r,g,b color
-- @param r The red component. Can also pass the full color as a table, IE { 255, 0, 0 }
-- @param g The green component. If you pass the color as a table as noted above, this param should be empty
-- @param b the blue components. If you pass the color as a table as noted above, this param should be empty
-- @usage
-- closest_color = GradientMaker.color_name(128,200,30) -- returns "ansi_149"
-- closest_color = GradientMaker.color_name({128, 200, 30}) -- this is functionally equivalent to the first one
function GradientMaker.color_name(...)
return color_name(...)
end
--- Returns the text, with the defined color gradients applied and formatted for us with decho. Usage example below produces the following text
-- <br><img src="https://demonnic.github.io/mdk/images/dechogradient.png" alt="dgradient example">
-- @tparam string text The text you want to apply the color gradients to
-- @param first_color The color you want it to start at. Table of colors in { r, g, b } format
-- @param second_color The color you want the gradient to transition to first. Table of colors in { r, g, b } format
-- @param next_color Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
-- @see cgradient
-- @see hgradient
-- @usage
-- decho(GradientMaker.dgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {255,0,0}, {255,128,0}, {255,255,0}, {0,255,0}, {0,255,255}, {0,128,255}, {128,0,255}))
-- decho(GradientMaker.dgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {255,0,0}, {0,0,255}))
-- decho(GradientMaker.dgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {50,50,50}, {0,255,0}, {50,50,50}))
function GradientMaker.dgradient(text, ...)
return dgradient(text, ...)
end
--- Returns the text, with the defined color gradients applied and formatted for us with cecho. Usage example below produces the following text
-- <br><img src="https://demonnic.github.io/mdk/images/cechogradient.png" alt="cgradient example">
-- @tparam string text The text you want to apply the color gradients to
-- @param first_color The color you want it to start at. Table of colors in { r, g, b } format
-- @param second_color The color you want the gradient to transition to first. Table of colors in { r, g, b } format
-- @param next_color Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
-- @see dgradient
-- @see hgradient
-- @usage
-- cecho(GradientMaker.cgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {255,0,0}, {255,128,0}, {255,255,0}, {0,255,0}, {0,255,255}, {0,128,255}, {128,0,255}))
-- cecho(GradientMaker.cgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {255,0,0}, {0,0,255}))
-- cecho(GradientMaker.cgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {50,50,50}, {0,255,0}, {50,50,50}))
function GradientMaker.cgradient(text, ...)
return cgradient(text, ...)
end
--- Returns the text, with the defined color gradients applied and formatted for us with hecho. Usage example below produces the following text
-- <br><img src="https://demonnic.github.io/mdk/images/hechogradient.png" alt="hgradient example">
-- @tparam string text The text you want to apply the color gradients to
-- @param first_color The color you want it to start at. Table of colors in { r, g, b } format
-- @param second_color The color you want the gradient to transition to first. Table of colors in { r, g, b } format
-- @param next_color Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
-- @see cgradient
-- @see dgradient
-- @usage
-- hecho(GradientMaker.hgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {255,0,0}, {255,128,0}, {255,255,0}, {0,255,0}, {0,255,255}, {0,128,255}, {128,0,255}))
-- hecho(GradientMaker.hgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {255,0,0}, {0,0,255}))
-- hecho(GradientMaker.hgradient("a luminescent butterly floats about lazily on brillant blue and lilac wings\n", {50,50,50}, {0,255,0}, {50,50,50}))
function GradientMaker.hgradient(text, ...)
return hgradient(text, ...)
end
--- Returns a table, each element of which is a table, the first element of which is the color name to use and the character which should be that color
-- @tparam string text The text you want to apply the color gradients to
-- @param first_color The color you want it to start at. Table of colors in { r, g, b } format
-- @param second_color The color you want the gradient to transition to first. Table of colors in { r, g, b } format
-- @param next_color Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
-- @see cgradient
function GradientMaker.cgradient_table(text, ...)
return cgradient_table(text, ...)
end
--- Returns a table, each element of which is a table, the first element of which is the color({r,g,b} format) to use and the character which should be that color
-- @tparam string text The text you want to apply the color gradients to
-- @param first_color The color you want it to start at. Table of colors in { r, g, b } format
-- @param second_color The color you want the gradient to transition to first. Table of colors in { r, g, b } format
-- @param next_color Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
-- @see dgradient
function GradientMaker.dgradient_table(text, ...)
return dgradient_table(text, ...)
end
--- Returns a table, each element of which is a table, the first element of which is the color(in hex) to use and the second element of which is the character which should be that color
-- @tparam string text The text you want to apply the color gradients to
-- @param first_color The color you want it to start at. Table of colors in { r, g, b } format
-- @param second_color The color you want the gradient to transition to first. Table of colors in { r, g, b } format
-- @param next_color Keep repeating if you want it to transition from the second color to a third, then a third to a fourth, etc
-- @see hgradient
function GradientMaker.hgradient_table(text, ...)
return hgradient_table(text, ...)
end
--- Creates global copies of the c/d/hgradient(_table) functions and color_name for use without accessing the module table
-- @usage
-- GradientMaker.install_global()
-- cecho(cgradient(...)) -- use cgradient directly now
function GradientMaker.install_global()
_G["hgradient"] = function(...)
return hgradient(...)
end
_G["dgradient"] = function(...)
return dgradient(...)
end
_G["cgradient"] = function(...)
return cgradient(...)
end
_G["hgradient_table"] = function(...)
return hgradient_table(...)
end
_G["dgradient_table"] = function(...)
return dgradient_table(...)
end
_G["cgradient_table"] = function(...)
return cgradient_table(...)
end
_G["color_name"] = function(...)
return color_name(...)
end
end
-- function GradientMaker.getGrads()
-- return gradient_table
-- end
return GradientMaker

View File

@ -0,0 +1,461 @@
--- MiniConsole with logging capabilities
-- @classmod LoggingConsole
-- @author Damian Monogue <demonnic@gmail.com>
-- @copyright 2020 Damian Monogue
-- @license MIT, see LICENSE.lua
local homedir = getMudletHomeDir():gsub("\\", "/")
local pathOfThisFile = (...):match("(.-)[^%.]+$")
local dt = require(pathOfThisFile .. "demontools")
local exists, htmlHeader, htmlHeaderPattern = dt.exists, dt.htmlHeader, dt.htmlHeaderPattern
local LoggingConsole = {log = true, logFormat = "h", path = "|h/log/consoleLogs/|y/|m/|d/", fileName = "|n.|e"}
--- Creates and returns a new LoggingConsole.
-- @param cons table of constraints. Includes all the valid Geyser.MiniConsole constraints, plus
-- <table class="tg">
-- <thead>
-- <tr>
-- <th>option name</th>
-- <th>description</th>
-- <th>default</th>
-- </tr>
-- </thead>
-- <tbody>
-- <tr>
-- <td class="tg-1">log</td>
-- <td class="tg-1">Should the miniconsole be logging?</td>
-- <td class="tg-1">true</td>
-- </tr>
-- <tr>
-- <td class="tg-2">logFormat</td>
-- <td class="tg-2">"h" for html, "t" for plaintext, "l" for log (with ansi)</td>
-- <td class="tg-2">h</td>
-- </tr>
-- <tr>
-- <td class="tg-1">path</td>
-- <td class="tg-1">The path the file lives in. It is templated.<br>|h is replaced by the profile homedir.<br>|y by 4 digit year.<br>|m by 2 digit month<br>|d by 2 digit day<br>|n by the name constraint<br>|e by the file extension (html for h logType, log for others)</td>
-- <td class="tg-1">"|h/log/consoleLogs/|y/|m/|d/"</td>
-- </tr>
-- <tr>
-- <td class="tg-2">fileName</td>
-- <td class="tg-2">The name of the log file. It is templated, same as path above</td>
-- <td class="tg-2">"|n.|e"</td>
-- </tr>
-- </tbody>
-- </table>
-- @param container the container for the console
-- @usage
-- local LoggingConsole = require("MDK.loggingconsole")
-- myLoggingConsole = LoggingConsole:new({
-- name = "my logging console",
-- x = 0,
-- y = 0,
-- height = 200,
-- width = 400,
-- }) -- just like making a miniconsole, really
function LoggingConsole:new(cons, container)
cons = cons or {}
local consType = type(cons)
assert(consType == "table", "LoggingConsole:new(cons, container): cons must be a valid table of constraints. Got: " .. consType)
local me = Geyser.MiniConsole:new(cons, container)
setmetatable(me, self)
self.__index = self
return me
end
--- Returns the file extension of the logfile this console will log to
function LoggingConsole:getExtension()
local extension = "log"
if table.contains({"h", "html"}, self.logFormat) then
extension = "html"
end
return extension
end
--- Returns a string with all templated items replaced
---@tparam string str The templated string to transform
---@local
function LoggingConsole:transformTemplate(str)
local ttbl = getTime()
local year = ttbl.year
local month = string.format("%02d", ttbl.month)
local day = string.format("%02d", ttbl.day)
local name = self.name
local extension = self:getExtension()
str = str:gsub("|h", homedir)
str = str:gsub("|y", year)
str = str:gsub("|m", month)
str = str:gsub("|d", day)
str = str:gsub("|n", name)
str = str:gsub("|e", extension)
return str
end
--- Returns the path to the logfile for this console
function LoggingConsole:getPath()
local path = self:transformTemplate(self.path)
if not path:ends("/") then
path = path .. "/"
end
return path
end
--- Sets the path to use for the log file.
-- @param path the path to put the log file in. It is templated.<br>|h is replaced by the profile homedir.<br>|y by 4 digit year.<br>|m by 2 digit month<br>|d by 2 digit day<br>|n by the name constraint<br>|e by the file extension (html for h logType, log for others)
function LoggingConsole:setPath(path)
self.path = path
end
--- Returns the filename for the logfile for this console
function LoggingConsole:getFileName()
local fileName = self:transformTemplate(self.fileName)
fileName = fileName:gsub("[<>:'\"/\\?*]", "_")
return fileName
end
--- Sets the fileName to use for the log file.
-- @param fileName the fileName to use for the logfile. It is templated.<br>|h is replaced by the profile homedir.<br>|y by 4 digit year.<br>|m by 2 digit month<br>|d by 2 digit day<br>|n by the name constraint<br>|e by the file extension (html for h logType, log for others)
function LoggingConsole:setFileName(fileName)
self.fileName = fileName
end
--- Returns the pull path and filename for the logfile for this console
function LoggingConsole:getFullFilename()
local path = self:getPath()
local fileName = self:getFileName()
local fullPath = path .. fileName
fullPath = fullPath:gsub("|", "_")
return fullPath
end
--- Turns logging for this console on
function LoggingConsole:enableLogging()
self.log = true
end
--- Turns logging for this console off
function LoggingConsole:disableLogging()
self.log = false
end
--- Creates the path for the logfile for this console if necessary
---@local
function LoggingConsole:createPathIfNotExists()
local path = self:transformTemplate(self.path)
if not path:ends("/") then
path = path .. "/"
end
if not exists(path) then
local ok, err = dt.mkdir_p(path)
if not ok then
assert(false, "Could not create directory for log files:" .. path .. "\n Reason was: " .. err)
end
end
return true
end
--- Handles actually writing to the log file
---@local
function LoggingConsole:writeToLog(str)
local fileName = self:getFullFilename()
self:createPathIfNotExists()
if self:getExtension() == "html" then
if not io.exists(fileName) then
str = htmlHeader .. str
end
str = str
end
local file, err = io.open(fileName, "a")
if not file then
echo(err .. "\n")
return
end
file:write(str)
file:close()
end
local parent = Geyser.MiniConsole
--- Handler function which does the lifting for c/d/h/echo and appendBuffer to provide the logfile writing functionality
---@param str the string to echo. Use "" for appends
---@param etype the type of echo. Valid are "c", "d", "h", "e", and "a"
---@param log Allows you to override the default behaviour defined by the .log property. Pass true to definitely log, false to skip logging.
---@local
function LoggingConsole:xEcho(str, etype, log)
if log == nil then
log = self.log
end
local logStr
local logType = self.logFormat
if logType:find("h") then
logType = "h"
elseif logType ~= "t" then
logType = "l"
end
if etype == "d" then -- decho
if logType == "h" then
logStr = dt.decho2html(str)
elseif logType == "t" then
logStr = dt.decho2string(str)
else
logStr = dt.decho2ansi(str)
end
parent.decho(self, str)
elseif etype == "c" then -- cecho
if logType == "h" then
logStr = dt.cecho2html(str)
elseif logType == "t" then
logStr = dt.cecho2string(str)
else
logStr = dt.cecho2ansi(str)
end
parent.cecho(self, str)
elseif etype == "h" then -- hecho
if logType == "h" then
logStr = dt.hecho2html(str)
elseif logType == "t" then
logStr = dt.hecho2string(str)
else
logStr = dt.hecho2ansi(str)
end
parent.hecho(self, str)
elseif etype == "a" then -- append
str = dt.append2decho()
str = str .. "\n"
if logType == "h" then
logStr = dt.decho2html(str)
elseif logType == "t" then
logStr = dt.decho2string(str)
else
logStr = dt.decho2ansi(str)
end
parent.appendBuffer(self)
elseif etype == "e" then -- echo
if logType == "h" then
logStr = dt.decho2html(str)
else
logStr = str
end
parent.echo(self, str)
end
if log then
self:writeToLog(logStr)
end
end
--- Does the actual lifting of echoing links/popups
-- @local
function LoggingConsole:xEchoLink(text, lType, command, hint, useFormat, log)
if log == nil then
log = self.log
end
local logStr = ""
if lType:starts("c") then
if self.logFormat == "h" then
logStr = dt.cecho2html(text)
elseif self.logFormat == "l" then
logStr = dt.cecho2ansi(text)
elseif self.logFormat == "t" then
logStr = dt.cecho2string(text)
end
if lType:ends("p") then
parent.cechoPopup(self, text, command, hint, useFormat)
else
parent.cechoLink(self, text, command, hint, useFormat)
end
elseif lType:starts("d") then
if self.logFormat == "h" then
logStr = dt.decho2html(text)
elseif self.logFormat == "l" then
logStr = dt.decho2ansi(text)
elseif self.logFormat == "t" then
logStr = dt.decho2string(text)
end
if lType:ends("p") then
parent.dechoPopup(self, text, command, hint, useFormat)
else
parent.dechoLink(self, text, command, hint, useFormat)
end
elseif lType:starts("h") then
if self.logFormat == "h" then
logStr = dt.hecho2html(text)
elseif self.logFormat == "l" then
logStr = dt.hecho2ansi(text)
elseif self.logFormat == "t" then
logStr = dt.hecho2string(text)
end
if lType:ends("p") then
parent.hechoPopup(self, text, command, hint, useFormat)
else
parent.hechoLink(self, text, command, hint, useFormat)
end
elseif lType:starts("e") then
logStr = text
if lType:ends("p") then
parent.echoPopup(self, text, command, hint, useFormat)
else
parent.echoLink(self, text, command, hint, useFormat)
end
end
if log then
self:writeToLog(logStr)
end
end
--- cechoLink for LoggingConsole
-- @param text the text to use for the link
-- @param command the command to send when the link is clicked, as text. IE [[send("sleep")]]
-- @param hint A tooltip which is displayed when the mouse is over the link
-- @param log Should we log this line? Defaults to self.log if not passed.
function LoggingConsole:cechoLink(text, command, hint, log)
self:xEchoLink(text, "c", command, hint, true, log)
end
--- dechoLink for LoggingConsole
-- @param text the text to use for the link
-- @param command the command to send when the link is clicked, as text. IE [[send("sleep")]]
-- @param hint A tooltip which is displayed when the mouse is over the link
-- @param log Should we log this line? Defaults to self.log if not passed.
function LoggingConsole:dechoLink(text, command, hint, log)
self:xEchoLink(text, "d", command, hint, true, log)
end
--- hechoLink for LoggingConsole
-- @param text the text to use for the link
-- @param command the command to send when the link is clicked, as text. IE [[send("sleep")]]
-- @param hint A tooltip which is displayed when the mouse is over the link
-- @param log Should we log this line? Defaults to self.log if not passed.
function LoggingConsole:hechoLink(text, command, hint, log)
self:xEchoLink(text, "h", command, hint, true, log)
end
--- echoLink for LoggingConsole
-- @param text the text to use for the link
-- @param command the command to send when the link is clicked, as text. IE [[send("sleep")]]
-- @param hint A tooltip which is displayed when the mouse is over the link
-- @param useCurrentFormat If set to true, will look like the text around it. If false it will be blue and underline.
-- @param log Should we log this line? Defaults to self.log if not passed. If you want to pass this you must pass in useCurrentFormat
-- @usage myLoggingConsole:echoLink("This is a link!", [[send("sleep")]], "sleep") -- text "This is a link" will send("sleep") when clicked and be blue w/ underline. Defaut log behaviour (self.log)
-- @usage myLoggingConsole:echoLink("This is a link!", [[send("sleep")]], "sleep", false, false) -- same as above, but forces it not to log regardless of self.log setting
-- @usage myLoggingConsole:echoLink("This is a link!", [[send("sleep")]], "sleep", true, true) -- same as above, but forces it to log regardless of self.log setting and the text will look like anything else echoed to the console.
function LoggingConsole:echoLink(text, command, hint, useCurrentFormat, log)
self:xEchoLink(text, "e", command, hint, useCurrentFormat, log)
end
--- cechoPopup for LoggingConsole
-- @param text the text to use for the link
-- @param commands the commands to send when the popup is activated, as table. IE {[[send("sleep")]], [[send("stand")]]}
-- @param hints A tooltip which is displayed when the mouse is over the link. IE {{"sleep", "stand"}}
-- @param log Should we log this line? Defaults to self.log if not passed.
function LoggingConsole:cechoPopup(text, commands, hints, log)
self:xEchoLink(text, "cp", commands, hints, true, log)
end
--- dechoPopup for LoggingConsole
-- @param text the text to use for the link
-- @param commands the commands to send when the popup is activated, as table. IE {[[send("sleep")]], [[send("stand")]]}
-- @param hints A tooltip which is displayed when the mouse is over the link. IE {{"sleep", "stand"}}
-- @param log Should we log this line? Defaults to self.log if not passed.
function LoggingConsole:dechoPopup(text, commands, hints, log)
self:xEchoLink(text, "dp", commands, hints, true, log)
end
--- hechoPopup for LoggingConsole
-- @param text the text to use for the link
-- @param commands the commands to send when the popup is activated, as table. IE {[[send("sleep")]], [[send("stand")]]}
-- @param hints A tooltip which is displayed when the mouse is over the link. IE {{"sleep", "stand"}}
-- @param log Should we log this line? Defaults to self.log if not passed.
function LoggingConsole:hechoPopup(text, commands, hints, log)
self:xEchoLink(text, "hp", commands, hints, true, log)
end
--- echoPopup for LoggingConsole
-- @param text the text to use for the link
-- @param commands the commands to send when the popup is activated, as table. IE {[[send("sleep")]], [[send("stand")]]}
-- @param hints A tooltip which is displayed when the mouse is over the link. IE {{"sleep", "stand"}}
-- @param useCurrentFormat If set to true, will look like the text around it. If false it will be blue and underline.
-- @param log Should we log this line? Defaults to self.log if not passed. If you want to pass this you must pass in useCurrentFormat
-- @usage myLoggingConsole:echoPopup("This is a link!", {[[send("sleep")]], [[send("stand")]], {"sleep", "stand"}) -- text "This is a link" will send("sleep") when clicked and be blue w/ underline. Defaut log behaviour (self.log)
-- @usage myLoggingConsole:echoPopup("This is a link!", {[[send("sleep")]], [[send("stand")]], {"sleep", "stand"}, false, false) -- same as above, but forces it not to log regardless of self.log setting
-- @usage myLoggingConsole:echoPopup("This is a link!", {[[send("sleep")]], [[send("stand")]], {"sleep", "stand"}, true, true) -- same as above, but forces it to log regardless of self.log setting and the text will look like anything else echoed to the console.
function LoggingConsole:echoPopup(text, commands, hints, useCurrentFormat, log)
self:xEchoLink(text, "ep", commands, hints, useCurrentFormat, log)
end
--- Append copy()ed text to the console
-- @param log should we log this?
function LoggingConsole:appendBuffer(log)
self:xEcho("", "a", log)
end
--- Append copy()ed text to the console
-- @param log should we log this?
function LoggingConsole:append(log)
self:xEcho("", "a", log)
end
--- echo's a string to the console.
-- @param str the string to echo
-- @param log should this be logged? Used to override the .log constraint
function LoggingConsole:echo(str, log)
self:xEcho(str, "e", log)
end
--- hecho's a string to the console.
-- @param str the string to hecho
-- @param log should this be logged? Used to override the .log constraint
function LoggingConsole:hecho(str, log)
self:xEcho(str, "h", log)
end
--- decho's a string to the console.
-- @param str the string to decho
-- @param log should this be logged? Used to override the .log constraint
function LoggingConsole:decho(str, log)
self:xEcho(str, "d", log)
end
--- cecho's a string to the console.
-- @param str the string to cecho
-- @param log should this be logged? Used to override the .log constraint
function LoggingConsole:cecho(str, log)
self:xEcho(str, "c", log)
end
--- Replays the last X lines from the console's log file, if it exists
-- @param numberOfLines The number of lines to replay from the end of the file
function LoggingConsole:replay(numberOfLines)
local fileName = self:getFullFilename()
if not exists(fileName) then
return
end
local file = io.open(fileName, "r")
local lines = file:read("*a")
if self:getExtension() == "html" then
for _, line in ipairs(htmlHeaderPattern:split("\n")) do
if line ~= "" then
lines = lines:gsub(line .. "\n", "")
end
end
lines = dt.html2decho(lines)
else
lines = ansi2decho(lines)
end
local linesTbl = lines:split("\n")
local result
if #linesTbl <= numberOfLines then
result = lines
else
result = ""
local start = #linesTbl - numberOfLines
for index, str in ipairs(linesTbl) do
if index >= start then
result = string.format("%s\n%s", result, str)
end
end
end
self:decho(result, false)
end
setmetatable(LoggingConsole, parent)
return LoggingConsole

456
src/resources/MDK/loginator.lua Executable file
View File

@ -0,0 +1,456 @@
--- Loginator creates an object which allows you to log things to file at
-- various severity levels, with the ability to only log items above a specific
-- severity to file.
-- @classmod Loginator
-- @author Damian Monogue <demonnic@gmail.com>
-- @copyright 2021 Damian Monogue
-- @license MIT, see LICENSE.lua
local Loginator = {
format = "h",
name = "logname",
fileNameTemplate = "|p/log/Loginator/|y-|M-|d-|n.|e",
entryTemplate = "|y-|M-|d |h:|m:|s.|x [|c|l|r] |t",
level = "warn",
bgColor = "black",
fontSize = 12,
fgColor = "white",
}
local levelColors = {error = "red", warn = "DarkOrange", info = "ForestGreen", debug = "ansi_yellow"}
local loggerLevels = {error = 1, warn = 2, info = 3, debug = 4}
local function exists(path)
local ok, err, code = os.rename(path, path)
if not ok and code == 13 then
return true
end
return ok, err
end
local function isWindows()
return package.config:sub(1, 1) == [[\]]
end
local function mkdir_p(path)
path = path:gsub("\\", "/")
local pathTbl = path:split("/")
local cwd = "/"
if isWindows() then
cwd = ""
end
for index, dirName in ipairs(pathTbl) do
if index == 1 then
cwd = cwd .. dirName
else
cwd = cwd .. "/" .. dirName
cwd = cwd:gsub("//", "/")
end
if not table.contains({"/", "C:"}, cwd) and not exists(cwd) then
local ok, err = lfs.mkdir(cwd)
if not ok then
return ok, err
end
end
end
return true
end
local htmlHeaderTemplate = [=[ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
<link href='http://fonts.googleapis.com/css?family=Droid+Sans+Mono' rel='stylesheet' type='text/css'>
<style type="text/css">
body {
background-color: |b;
color: |c;
font-family: 'Droid Sans Mono';
white-space: pre;
font-size: |fpx;
}
</style>
</head>
<body><span>
]=]
--- Creates a new Loginator object
--@tparam table options table of options for the logger
-- <table class="tg">
-- <thead>
-- <tr>
-- <th>option name</th>
-- <th>description</th>
-- <th>default</th>
-- </tr>
-- </thead>
-- <tbody>
-- <tr>
-- <td class="tg-1">format</td>
-- <td class="tg-1">What format to log in? "h" for html, "a" for ansi, anything else for plaintext.</td>
-- <td class="tg-1">"h"</td>
-- </tr>
-- <tr>
-- <td class="tg-2">name</td>
-- <td class="tg-2">What is the name of the logger? Will replace |n in templates</td>
-- <td class="tg-2">logname</td>
-- </tr>
-- <tr>
-- <td class="tg-1">level</td>
-- <td class="tg-1">What level should the logger operate at? This will control what level the log function defaults to, as well as what logs will actually be written<br>
-- Only items of an equal or higher severity to this will be written to the log file.</td>
-- <td class="tg-1">"info"</td>
-- </tr>
-- <tr>
-- <td class="tg-2">bgColor</td>
-- <td class="tg-2">What background color to use for html logs</td>
-- <td class="tg-2">"black"</td>
-- </tr>
-- <tr>
-- <td class="tg-1">fgColor</td>
-- <td class="tg-1">What color to use for the main text in html logs</td>
-- <td class="tg-1">"white"</td>
-- </tr>
-- <tr>
-- <td class="tg-2">fontSize</td>
-- <td class="tg-2">What font size to use in html logs</td>
-- <td class="tg-2">12</td>
-- </tr>
-- <tr>
-- <td class="tg-1">levelColors</td>
-- <td class="tg-1">Table with the log level as the key, and the color which corresponds to it as the value</td>
-- <td class="tg-1">{ error = "red", warn = "DarkOrange", info = "ForestGreen", debug = "ansi_yellow" }</td>
-- </tr>
-- <tr>
-- <td class="tg-2">fileNameTemplate</td>
-- <td class="tg-2">A template which will be transformed into the full filename, with path. See template options below for replacements</td>
-- <td class="tg-2">"|p/log/Loginator/|y-|M-|d-|n.|e"</td>
-- </tr>
-- <tr>
-- <td class="tg-1">entryTemplate</td>
-- <td class="tg-1">The template which controls the look of each log entry. See template options below for replacements</td>
-- <td class="tg-1">"|y-|M-|d |h:|m:|s.|x [|c|l|r] |t"</td>
-- </tr>
-- </tbody>
-- </table><br>
-- Table of template options
-- <table class="tg">
-- <thead>
-- <tr>
-- <th>template code</th>
-- <th>what it is replaced with</th>
-- <th>example</th>
-- </tr>
-- </thead>
-- <tbody>
-- <tr>
-- <td class="tg-1">|y</td>
-- <td class="tg-1">the year in 4 digits</td>
-- <td class="tg-1">2021</td>
-- </tr>
-- <tr>
-- <td class="tg-2">|p</td>
-- <td class="tg-2">getMudletHomeDir()</td>
-- <td class="tg-2">/home/demonnic/.config/mudlet/profiles/testprofile</td>
-- </tr>
-- <tr>
-- <td class="tg-1">|M</td>
-- <td class="tg-1">Month as 2 digits</td>
-- <td class="tg-1">05</td>
-- </tr>
-- <tr>
-- <td class="tg-2">|d</td>
-- <td class="tg-2">day, as 2 digits</td>
-- <td class="tg-2">23</td>
-- </tr>
-- <tr>
-- <td class="tg-1">|h</td>
-- <td class="tg-1">hour in 24hr time format, 2 digits</td>
-- <td class="tg-1">03</td>
-- </tr>
-- <tr>
-- <td class="tg-2">|m</td>
-- <td class="tg-2">minute as 2 digits</td>
-- <td class="tg-2">42</td>
-- </tr>
-- <tr>
-- <td class="tg-1">|s</td>
-- <td class="tg-1">seconds as 2 digits</td>
-- <td class="tg-1">34</td>
-- </tr>
-- <tr>
-- <td class="tg-2">|x</td>
-- <td class="tg-2">milliseconds as 3 digits</td>
-- <td class="tg-2">194</td>
-- </tr>
-- <tr>
-- <td class="tg-1">|e</td>
-- <td class="tg-1">Filename extension expected. "html" for html format, "log" for everything else</td>
-- <td class="tg-1">html</td>
-- </tr>
-- <tr>
-- <td class="tg-2">|l</td>
-- <td class="tg-2">The logging level of the entry, in ALLCAPS</td>
-- <td class="tg-2">WARN</td>
-- </tr>
-- <tr>
-- <td class="tg-1">|c</td>
-- <td class="tg-1">The color which corresponds with the logging level. Set via the levelColors table in the options. Example not included.</td>
-- <td class="tg-1"></td>
-- </tr>
-- <tr>
-- <td class="tg-2">|r</td>
-- <td class="tg-2">Reset back to standard color. Used to close |c. Example not included</td>
-- <td class="tg-2"></td>
-- </tr>
-- <tr>
-- <td class="tg-1">|n</td>
-- <td class="tg-1">The name of the logger, set via the options when you have Loginator create it.</td>
-- <td class="tg-1">CoolPackageLog</td>
-- </tr>
--</tbody>
--</table>
--@return newly created logger object
function Loginator:new(options)
options = options or {}
local optionsType = type(options)
if optionsType ~= "table" then
return nil, f "Loginator:new(options) options as table expected, got {optionsType}"
end
local me = table.deepcopy(options)
me.levelColors = me.levelColors or {}
local lcType = type(me.levelColors)
if lcType ~= "table" then
return nil, f "Loginator:new(options) provided options.levelColors must be a table, but you provided a {lcType}"
end
for lvl,clr in pairs(levelColors) do
me.levelColors[lvl] = me.levelColors[lvl] or clr
end
setmetatable(me, self)
self.__index = self
return me
end
---@local
function Loginator:processTemplate(str, level)
local lvl = level or self.level
local timeTable = getTime()
for what, with in pairs({
["|y"] = function()
return timeTable.year
end,
["|p"] = getMudletHomeDir,
["|M"] = function()
return string.format("%02d", timeTable.month)
end,
["|d"] = function()
return string.format("%02d", timeTable.day)
end,
["|h"] = function()
return string.format("%02d", timeTable.hour)
end,
["|m"] = function()
return string.format("%02d", timeTable.min)
end,
["|s"] = function()
return string.format("%02d", timeTable.sec)
end,
["|x"] = function()
return string.format("%03d", timeTable.msec)
end,
["|e"] = function()
return (self.format:starts("h") and "html" or "log")
end,
["|l"] = function()
return lvl:upper()
end,
["|c"] = function()
return self:getColor(lvl)
end,
["|r"] = function()
return self:getReset()
end,
["|n"] = function()
return self.name
end,
}) do
if str:find(what) then
str = str:gsub(what, with())
end
end
return str
end
--- Set the color to associate with a logging level post-creation
--@param color The color to set for the level, as a string. Can be any valid color string for cecho, decho, or hecho.
--@param level The level to set the color for. Must be one of 'error', 'warn', 'info', or 'debug'
--@return true if the color is updated, or nil+error if it could not be updated for some reason.
function Loginator:setColorForLevel(color, level)
if not color then
return nil, "You must provide a color to set"
end
if not level then
return nil, "You must provide a level to set the color for"
end
if not loggerLevels[level] then
return nil, "Invalid level. Valid levels are 'error', 'warn', 'info', or 'debug'"
end
if not Geyser.Color.parse(color) then
return nil, "You must provide a color which can be parsed by Geyser.Color.parse. Examples are 'blue' (cecho), '<128,0,0>' (decho), '#aa3388' (hecho), or {128,0,0} (table of r,g,b values)"
end
self.levelColors[level] = color
return true
end
---@local
function Loginator:getColor(level)
if self.format == "t" then
return ""
end
local r, g, b = Geyser.Color.parse((self.levelColors[level] or {128, 128, 128}))
if self.format == "h" then
return string.format("<span style='color: rgb(%d,%d,%d);'>", r, g, b)
elseif self.format == "a" then
return string.format("\27[38:2::%d:%d:%dm", r, g, b)
end
return ""
end
---@local
function Loginator:getReset()
if self.format == "t" then
return ""
elseif self.format == "h" then
return "</span>"
elseif self.format == "a" then
return "\27[39;49m"
end
return ""
end
--- Returns the full path and filename to the logfile
function Loginator:getFullFilename()
return self:processTemplate(self.fileNameTemplate)
end
--- Write an error level message to the logfile. Error level messages are always written.
--@param msg the message to log
--@return true if msg written, nil+error if error
function Loginator:error(msg)
return self:log(msg, "error")
end
--- Write a warn level message to the logfile.
-- Msg is only written if the logger level is <= warn
-- From most to least severe the levels are:
-- error > warn > info > debug
--@param msg the message to log
--@return true if msg written, false if skipped due to level, nil+error if error
function Loginator:warn(msg)
return self:log(msg, "warn")
end
--- Write an info level message to the logfile.
-- Msg is only written if the logger level is <= info
-- From most to least severe the levels are:
-- error > warn > info > debug
--@param msg the message to log
--@return true if msg written, false if skipped due to level, nil+error if error
function Loginator:info(msg)
return self:log(msg, "info")
end
--- Write a debug level message to the logfile.
-- Msg is only written if the logger level is debug
-- From most to least severe the levels are:
-- error > warn > info > debug
--@param msg the message to log
--@return true if msg written, false if skipped due to level, nil+error if error
function Loginator:debug(msg)
return self:log(msg, "debug")
end
--- Write a message to the log file and optionally specify the level
--@param msg the message to log
--@param level the level to log the message at. Defaults to the level of the logger itself if not provided.
--@return true if msg written, false if skipped due to level, nil+error if error
function Loginator:log(msg, level)
level = level or self.level
local levelNumber = loggerLevels[level]
if not levelNumber then
return nil, f"Unknown logging level: {level}. Valid levels are 'error', 'warn', 'info', and 'debug'"
end
local displayLevelNumber = loggerLevels[self.level]
if levelNumber > displayLevelNumber then
return false
end
local filename = self:getFullFilename()
local filteredMsg = self:processTemplate(self.entryTemplate, level):gsub("|t", msg)
local ok, err = self:createPathIfNotExists(filename)
if err then
debugc(err)
return ok, err
end
if self.format == "h" and not io.exists(filename) then
filteredMsg = self:getHtmlHeader() .. filteredMsg
end
local file, err = io.open(filename, "a")
if not file then
err = string.format("Logger %s failed to open %s because: %s\n", self.name, filename, err)
debugc(err)
return nil, err
end
file:write(filteredMsg .. "\n")
file:close()
return true
end
--- Uses openUrl() to request your OS open the logfile in the appropriate application. Usually your web browser for html and text editor for all others.
function Loginator:open()
openUrl(self:getFullFilename())
end
--- Uses openUrl() to request your OS open the directory the logfile resides in. This allows for easier browsing if you have more than one file.
function Loginator:openDir()
openUrl(self:getPath())
end
--- Returns the path to the log file (directory in which the file resides) as a string
--@param filename optional filename to return the path of. If not supplied, with use the logger's current filename
function Loginator:getPath(filename)
filename = filename or self:getFullFilename()
filename = filename:gsub([[\]], "/")
local filenameTable = filename:split("/")
filenameTable[#filenameTable] = nil
local path = table.concat(filenameTable, "/")
return path
end
---@local
function Loginator:createPathIfNotExists(filename)
if exists(filename) then
return false
end
filename = filename:gsub([[\]], "/")
local path = self:getPath(filename)
if exists(path) then
return false
end
local ok, err = mkdir_p(path)
if not ok then
err = string.format("Could not create directory for log files: %s\n Reason was: %s", path, err)
return nil, err
end
return true
end
---@local
function Loginator:getHtmlHeader()
local header = htmlHeaderTemplate
header = header:gsub("|b", self.bgColor)
header = header:gsub("|c", self.fgColor)
header = header:gsub("|f", self.fontSize)
return header
end
return Loginator

View File

@ -0,0 +1,254 @@
--- Interactive object which helps you solve a Master Mind puzzle.
-- @classmod MasterMindSolver
-- @author Damian Monogue <demonnic@gmail.com>
-- @copyright 2021 Damian Monogue
-- @copyright 2008,2009 Konstantinos Asimakis for code used to turn an index number into a guess (indexToGuess method)
local MasterMindSolver = {
places = 4,
items = {"red", "orange", "yellow", "green", "blue", "purple"},
template = "|t",
autoSend = false,
singleCommand = false,
separator = " ",
allowDuplicates = true,
}
local mod, floor, random, randomseed = math.mod, math.floor, math.random, math.randomseed
local initialGuess = {{1}, {1, 2}, {1, 1, 2}, {1, 1, 2, 2}, {1, 1, 1, 2, 2}, {1, 1, 1, 2, 2, 2}, {1, 1, 1, 1, 2, 2, 2}, {1, 1, 1, 1, 2, 2, 2, 2}}
--- Removes duplicate elements from a list
-- @param tbl the table you want to remove dupes from
-- @local
local function tableUnique(tbl)
local used = {}
local result = {}
for _, item in ipairs(tbl) do
if not used[item] then
result[#result + 1] = item
used[item] = true
end
end
return result
end
--- Creates a new Master Mind solver
-- @tparam table options table of configuration options for the solver
-- <table class="tg">
-- <thead>
-- <tr>
-- <th>option name</th>
-- <th>description</th>
-- <th>default</th>
-- </tr>
-- </thead>
-- <tbody>
-- <tr>
-- <td class="tg-1">places</td>
-- <td class="tg-1">How many spots in the code we're breaking?</td>
-- <td class="tg-1">4</td>
-- </tr>
-- <tr>
-- <td class="tg-2">items</td>
-- <td class="tg-2">The table of colors/gemstones/whatever which can be part of the code</td>
-- <td class="tg-2">{"red", "orange", "yellow", "green", "blue", "purple"}</td>
-- </tr>
-- <tr>
-- <td class="tg-1">template</td>
-- <td class="tg-1">The string template to use for the guess. Within the template, |t is replaced by the item. Used as the command if autoSend is true</td>
-- <td class="tg-1">"|t"</td>
-- </tr>
-- <tr>
-- <td class="tg-2">autoSend</td>
-- <td class="tg-2">Should we send the guess directly to the server?</td>
-- <td class="tg-2">false</td>
-- </tr>
-- <tr>
-- <td class="tg-1">allowDuplicates</td>
-- <td class="tg-1">Can the same item be used more than once in a code?</td>
-- <td class="tg-1">true</td>
-- </tr>
-- <tr>
-- <td class="tg-2">singleCommand</td>
-- <td class="tg-2">If true, combines the guess into a single command, with each one separated by the separator</td>
-- <td class="tg-2">false</td>
-- </tr>
-- <tr>
-- <td class="tg-1">separator</td>
-- <td class="tg-1">If sending the guess as a single command, what should we put between the guesses to separate them?</td>
-- <td class="tg-1">" "</td>
-- </tr>
-- </tbody>
-- </table>
function MasterMindSolver:new(options)
if options == nil then
options = {}
end
local optionsType = type(options)
if optionsType ~= "table" then
error(f "MasterMindSolver:new(options): options as table expected, got {tostring(options)} of type: {optionsType}")
end
local me = options
setmetatable(me, self)
self.__index = self
me:populateInitialSet()
if not me.allowDuplicates then
me.initialGuessMade = true -- skip the preset initial guess, they assume duplicates
end
return me
end
--- Takes a guess number (4, or 1829, or any number from 1 - <total possible combinations>) and returns the
-- actual guess.
-- @tparam number index which guess to generate
-- @local
function MasterMindSolver:indexToGuess(index)
local guess = {}
local options = #self.items
for place = 1, self.places do
guess[place] = mod(floor((index - 1) / options ^ (place - 1)), options) + 1
end
return guess
end
--- Compares a guess with the solution and returns the answer
-- @tparam table guess The guess you are checking, as numbers. { 1 , 1, 2, 2 } as an example
-- @tparam table solution the solution you are checking against, as numbers. { 3, 4, 1, 6 } as an example.
-- @local
function MasterMindSolver:compare(guess, solution)
local coloredPins = 0
local whitePins = 0
local usedGuessPlace = {}
local usedSolutionPlace = {}
local places = self.places
for place = 1, places do
if guess[place] == solution[place] then
coloredPins = coloredPins + 1
usedGuessPlace[place] = true
usedSolutionPlace[place] = true
end
end
for guessPlace = 1, places do
if not usedGuessPlace[guessPlace] then
for solutionPlace = 1, places do
if not usedSolutionPlace[solutionPlace] then
if guess[guessPlace] == solution[solutionPlace] then
whitePins = whitePins + 1
usedSolutionPlace[solutionPlace] = true
break
end
end
end
end
end
return coloredPins, whitePins
end
--- Generates an initial table of all guesses from 1 to <total possible> that are valid.
-- If allowDuplicates is false, will filter out any of the possible combinations which contain duplicates
-- @local
function MasterMindSolver:populateInitialSet()
local possible = {}
local allowDuplicates = self.allowDuplicates
local places = self.places
local numberOfItems = #self.items
local totalCombos = numberOfItems ^ places
local numberRemaining = 0
for entry = 1, totalCombos do
local useItem = true
if not allowDuplicates then
local guess = self:indexToGuess(entry)
local guessUnique = tableUnique(guess)
if #guessUnique ~= self.places then
useItem = false
end
end
if useItem then
possible[entry] = true
numberRemaining = numberRemaining + 1
end
end
self.possible = possible
self.numberRemaining = numberRemaining
end
--- Function used to reduce the remaining possible answers, given a guess and the answer to that guess. This is not undoable.
-- @tparam table guess guess which the answer belongs to. Uses numbers, rather than item names. IE { 1, 1, 2, 2} rather than { "blue", "blue", "green", "green" }
-- @tparam number coloredPins how many parts of the guess are both the right color and the right place
-- @tparam number whitePins how many parts of the guess are the right color, but in the wrong place
-- @return true if you solved the puzzle (coloredPins == number of positions in the code), or false otherwise
function MasterMindSolver:reducePossible(guess, coloredPins, whitePins)
if coloredPins == #guess then
return true
end
local possible = self.possible
local numberRemaining = 0
for entry, _ in pairs(possible) do
local testColor, testWhite = self:compare(guess, self:indexToGuess(entry))
if testColor ~= coloredPins or testWhite ~= whitePins then
possible[entry] = nil
else
numberRemaining = numberRemaining + 1
end
end
self.possible = possible
self.numberRemaining = numberRemaining
return false
end
--- Function which assumes you used the last suggested guess from the solver, and reduces the number of possible correct solutions based on the answer given
-- @see MasterMindSolver:reducePossible
-- @tparam number coloredPins how many parts of the guess are both the right color and the right place
-- @tparam number whitePins how many parts of the guess are the right color, but in the wrong place
-- @return true if you solved the puzzle (coloredPins == number of positions in the code), or false otherwise
function MasterMindSolver:checkLastSuggestion(coloredPins, whitePins)
return self:reducePossible(self.guess, coloredPins, whitePins)
end
--- Used to get one of the remaining valid possible guesses
-- @tparam boolean useActions if true, will return the guess as the commands which would be sent, rather than the numbered items
function MasterMindSolver:getValidGuess(useActions)
local guess
if not self.initialGuessMade then
self.initialGuessMade = true
guess = initialGuess[self.places]
end
if not guess then
local possible = self.possible
local keys = table.keys(possible)
randomseed(os.time())
guess = self:indexToGuess(keys[random(#keys)])
end
self.guess = guess
if self.autoSend then
self:sendGuess(guess)
end
if useActions then
return self:guessToActions(guess)
end
return guess
end
--- Takes a guess and converts the numbers to commands/actions. IE guessToActions({1, 1, 2, 2}) might return { "blue", "blue", "green", "green" }
-- @tparam table guess the guess to convert as numbers. IE { 1, 1, 2, 2}
-- @return table of commands/actions correlating to the numbers in the guess.
-- @local
function MasterMindSolver:guessToActions(guess)
local actions = {}
for index, itemNumber in ipairs(guess) do
local item = self.items[itemNumber]
actions[index] = self.template:gsub("|t", item)
end
return actions
end
--- Handles sending the commands to the game for a guess
-- @local
function MasterMindSolver:sendGuess(guess)
local actions = self:guessToActions(guess)
if self.singleCommand then
send(table.concat(actions, self.separator))
else
sendAll(unpack(actions))
end
end
return MasterMindSolver

View File

@ -0,0 +1 @@
2.10.0

View File

@ -0,0 +1,141 @@
--- The revisionator provides a standardized way of migrating configurations between revisions
-- for instance, it will track what the currently applied revision number is, and when you tell
-- tell it to migrate, it will apply every individual migration between the currently applied
-- revision and the latest/current revision. This should allow for more seamlessly moving from
-- an older version of a package to a new one.
-- @classmod revisionator
-- @author Damian Monogue <demonnic@gmail.com>
-- @copyright 2023
-- @license MIT, see https://raw.githubusercontent.com/demonnic/MDK/main/src/scripts/LICENSE.lua
local revisionator = {
name = "Revisionator",
patches = {},
}
revisionator.__index = revisionator
local dataDir = getMudletHomeDir() .. "/revisionator"
revisionator.dataDir = dataDir
if not io.exists(dataDir) then
local ok,err = lfs.mkdir(dataDir)
if not ok then
printDebug(f"Error creating the directory for storing applied revisions: {err}", true)
end
end
--- Creates a new revisionator
-- @tparam table options the options to create the revisionator with.
-- <table class="tg">
-- <thead>
-- <tr>
-- <th>option name</th>
-- <th>description</th>
-- <th>default</th>
-- </tr>
-- </thead>
-- <tbody>
-- <tr>
-- <td class="tg-1">name</td>
-- <td class="tg-1">The name of the revisionator. This is absolutely required, as the name is used for tracking the currently applied patch level</td>
-- <td class="tg-1">raises an error if not provided</td>
-- </tr>
-- <tr>
-- <td class="tg-2">patches</td>
-- <td class="tg-2">A table of patch functions. It is traversed using ipairs, so must be in the form of {function1, function2, function3} etc. If you do not provide it, you can add the patches by calling :addPatch for each patch in order.</td>
-- <td class="tg-2">{}</td>
-- </tr>
--</tbody>
--</table>
function revisionator:new(options)
options = options or {}
local optionsType = type(options)
if optionsType ~= "table" then
printError(f"revisionator:new bad argument #1 type, options as table expected, got {optionsType}", true, true)
end
if not options.name then
printError("revisionator:new(options) options must include a 'name' key as this is used as part of tracking the applied patch level.", true, true)
end
local me = table.deepcopy(options)
setmetatable(me, self)
return me
end
--- Get the currently applied revision from file
--- @treturn[1] number the revision number currently applied, or 0 if it can't read a current version
--- @treturn[2] nil nil
--- @treturn[2] string error message
function revisionator:getAppliedPatch()
local fileName = f"{self.dataDir}/{self.name}.txt"
debugc(fileName)
local revision = 0
if io.exists(fileName) then
local file = io.open(fileName, "r")
local fileContents = file:read("*a")
file:close()
local revNumber = tonumber(fileContents)
if revNumber then
revision = revNumber
else
return nil, f"Error while attempting to read current patch version from file: {fileName}\nThe contents of the file are {fileContents} and it was unable to be converted to a revision number"
end
end
return revision
end
--- go through all the patches in order and apply any which are still necessary
--- @treturn boolean true if it successfully applied patches, false if it was already at the latest patch level
--- @error error message
function revisionator:migrate()
local applied,err = self:getAppliedPatch()
if not applied then
printError(err, true, true)
end
local patches = self.patches
if applied >= #patches then
return false
end
for revision, patch in ipairs(patches) do
if applied < revision then
local ok, err = pcall(patch)
if not ok then
self:setAppliedPatch(revision - 1)
return nil, f"Error while running patch #{revision}: {err}"
end
end
end
self:setAppliedPatch(#patches)
return true
end
--- add a patch to the table of patches
--- @tparam function func the function to run as the patch
--- @number[opt] position which patch to insert it as? If not supplied, inserts it as the last patch. Which is usually what you want.
function revisionator:addPatch(func, position)
if position then
table.insert(self.patches, position, func)
else
table.insert(self.patches, func)
end
end
--- Remove a patch from the table of patches
--- this is primarily used for testing
--- @local
--- @number[opt] patchNumber the patch number to remove. Will remove the last item if not provided.
function revisionator:removePatch(patchNumber)
table.remove(self.patches, patchNumber)
end
--- set the currently applied patch number
-- only directly called for testing
--- @local
--- @number patchNumber the patch number to set as the currently applied patch
function revisionator:setAppliedPatch(patchNumber)
local fileName = f"{self.dataDir}/{self.name}.txt"
local revFile, err = io.open(fileName, "w+")
if not revFile then
printError(err, true, true)
end
revFile:write(patchNumber)
revFile:close()
end
return revisionator

644
src/resources/MDK/schema.lua Executable file
View File

@ -0,0 +1,644 @@
--[[
The MIT License (MIT)
Copyright (c) 2014 Sebastian Schoener
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
local schema = {}
-- Checks an object against a schema.
function schema.CheckSchema(obj, schem, path)
if path == nil then
path = schema.Path.new()
path:setBase(obj)
end
if type(schem) == "function" then
return schem(obj, path)
else -- attempt to simply compare the values
if schem == obj then
return nil
end
return schema.Error("Invalid value: "..path.." should be "..tostring(schem), path)
end
end
function schema.FormatOutput(output)
local format = schema.List()
for k,v in ipairs(output) do
format:append(v:format())
end
return table.concat(format, "\n")
end
--
-- Infrastructure
--
-- Path class. Represents paths to values in a table (the path's *base*).
local Path = {}
function Path.new(...)
local arg = {...}
local self = setmetatable({}, Path)
self.p = {}
for k,v in ipairs(arg) do
self.p[k] = v
end
return self
end
-- Sets the base of the path, i.e. the table to which the path is relative.
-- Note that this is the actual *table*, not the table's name.
function Path:setBase(base)
self.base = base
end
-- Gets the base of the path.
function Path:getBase()
return self.base
end
-- Returns the target of the path or 'nil' if the path is invalid.
function Path:target()
if self.base == nil then
error("Path:target() called on a path without a base!")
end
local current = self.base
for k,v in ipairs(self.p) do
current = current[v]
if current == nil then
return nil
end
end
return current
end
-- Pushes an entry to the end of the path.
function Path:push(obj)
self.p[#self.p + 1] = obj
return self
end
-- Pops an entry from the end of the path.
function Path:pop()
local tmp = self.p[#self.p]
self.p[#self.p] = nil
return tmp
end
-- Returns the topmost entry of the end of the path.
function Path:top()
return self.p[#self.p]
end
-- Returns the length of the path.
function Path:length()
return #self.p
end
-- Returns the element at the specified index.
function Path:get(index)
return self.p[index]
end
-- Copies the path.
function Path:copy()
local cp = Path.new()
cp.base = self.base
for k,v in ipairs(self) do
cp.p[k] = v
end
return cp
end
Path.__index = Path
Path.__tostring = function(tbl)
if #tbl.p == 0 then
return '<val>'
end
return table.concat(tbl.p,".")
end
Path.__concat = function(lhs, rhs)
if type(lhs) == "table" then
return tostring(lhs)..rhs
elseif type(rhs) == "table" then
return lhs..tostring(rhs)
end
end
Path.__len = function(self)
return #self.p
end
setmetatable(Path, {
__call = function (cls, ...)
return Path.new(...)
end
})
schema.Path = Path
-- List class
local List = {}
function List.new(...)
local self = setmetatable({}, List)
local arg = {...}
for k,v in ipairs(arg) do
self[k] = v
end
return self
end
function List:add(obj)
self[#self+1] = obj
return self
end
function List:append(list)
for k,v in ipairs(list) do
self[#self+k] = v
end
return self
end
List.__index = List
List.__tostring = function(self)
local tmp = {}
for k,v in ipairs(self) do
tmp[k] = tostring(v)
end
return table.concat(tmp, "\n")
end
setmetatable(List, {
__call = function(cls, ...)
return List.new(...)
end
})
schema.List = List
-- Error class. Describes mismatches that occured during the schema-checking.
local Error = {}
function Error.new(msg, path, suberrors)
local self = setmetatable({}, Error)
self.message = msg
self.path = path:copy()
self.suberrors = suberrors
return self
end
-- Returns a list of strings which represent the error (with indenttation for
-- suberrors).
function Error:format()
local output = List.new(self.message)
if self.suberrors ~= nil then
for k,sub in pairs(self.suberrors) do
local subout = sub:format()
for k1,msg in pairs(subout) do
output = output:add(" "..msg)
end
end
end
return output
end
Error.__tostring = function(self)
return table.concat(self:format(), "\n")
end
Error.__index = Error
setmetatable(Error, {
__call = function(cls, ...)
return List(Error.new(...))
end
})
schema.Error = Error
--
-- Schema Building Blocks
-- A schema is a function taking the object to be checked and the path to the
-- current value in the environment.
-- It returns either 'true' if the schema accepted the object or an Error
-- object which describes why it was rejected.
-- The schemata below are just some basic building blocks. Expand them to your
-- liking.
--
-- Always accepts.
function schema.Any(obj, path)
return nil
end
-- Always fails.
function schema.Nothing(obj, path)
return schema.Error("Failure: '"..path.."' will always fail.", path)
end
-- Checks a value against a specific type.
local function TypeSchema(obj, path, typeId)
if type(obj) ~= typeId then
return schema.Error("Type mismatch: '"..path.."' should be "..typeId..", is "..type(obj), path)
else
return nil
end
end
function schema.Boolean (obj, path) return TypeSchema(obj, path, "boolean") end
function schema.Function(obj, path) return TypeSchema(obj, path, "function") end
function schema.Nil (obj, path) return TypeSchema(obj, path, "nil") end
function schema.Number (obj, path) return TypeSchema(obj, path, "number") end
function schema.String (obj, path) return TypeSchema(obj, path, "string") end
function schema.Table (obj, path) return TypeSchema(obj, path, "table") end
function schema.UserData(obj, path) return TypeSchema(obj, path, "userdata") end
-- Checks that some value is a string matching a given pattern.
function schema.Pattern(pattern)
local userPattern = pattern
if not pattern:match("^^") then
pattern = "^" .. pattern
end
if not pattern:match("$$") then
pattern = pattern .. "$"
end
local function CheckPattern(obj, path)
local err = schema.String(obj, path)
if err then
return err
end
if string.match(obj, pattern) then
return nil
else
return schema.Error("Invalid value: '"..path.."' must match pattern '"..userPattern.."'", path)
end
end
return CheckPattern
end
-- Checks that some number is an integer.
function schema.Integer(obj, path)
local err = schema.Number(obj, path)
if err then
return err
end
if math.floor(obj) == obj then
return nil
end
return schema.Error("Invalid value: '"..path.."' must be an integral number", path)
end
-- Checks that some number is >= 0.
function schema.NonNegativeNumber(obj, path)
local err = schema.Number(obj, path)
if err then
return err
end
if obj >= 0 then
return nil
end
return schema.Error("Invalid value: '"..path.."' must be >= 0", path)
end
-- Checks that some number is > 0.
function schema.PositiveNumber(obj, path)
local err = schema.Number(obj, path)
if err then
return err
end
if obj > 0 then
return nil
end
return schema.Error("Invalid value: '"..path.."' must be > 0", path)
end
-- Checks that some value is a number from the interval [lower, upper].
function schema.NumberFrom(lower, upper)
local function CheckNumberFrom(obj, path)
local err = schema.Number(obj, path)
if err then
return err
end
if lower <= obj and upper >= obj then
return nil
else
return schema.Error("Invalid value: '"..path.."' must be between "..lower.." and "..upper, path)
end
end
return CheckNumberFrom
end
-- Takes schemata and accepts their disjunction.
function schema.OneOf(...)
local arg = {...}
local function CheckOneOf(obj, path)
for k,v in ipairs(arg) do
local err = schema.CheckSchema(obj, v, path)
if not err then return nil end
end
return schema.Error("No suitable alternative: No schema matches '"..path.."'", path)
end
return CheckOneOf
end
-- Takes a schema and returns an optional schema.
function schema.Optional(s)
return schema.OneOf(s, schema.Nil)
end
-- Takes schemata and accepts their conjuction.
function schema.AllOf(...)
local arg = {...}
local function CheckAllOf(obj, path)
local errmsg = nil
for k,v in ipairs(arg) do
local err = schema.CheckSchema(obj, v, path)
if err then
if errmsg == nil then
errmsg = err
else
errmsg = errmsg:append(err)
end
end
end
return errmsg
end
return CheckAllOf
end
-- Builds a record type schema, i.e. a table with a fixed set of keys (strings)
-- with corresponding values. Use as in
-- Record({
-- name = schema,
-- name2 = schema2
-- })
function schema.Record(recordschema, additionalValues)
if additionalValues == nil then
additionalValues = false
end
local function CheckRecord(obj, path)
if type(obj) ~= "table" then
return schema.Error("Type mismatch: '"..path.."' should be a record (table), is "..type(obj), path)
end
local errmsg = nil
local function AddError(msg)
if errmsg == nil then
errmsg = msg
else
errmsg = errmsg:append(msg)
end
end
for k,v in pairs(recordschema) do
path:push(k)
local err = schema.CheckSchema(obj[k], v, path)
if err then
AddError(err)
end
path:pop()
end
for k, v in pairs(obj) do
path:push(k)
if type(k) ~= "string" then
AddError(schema.Error("Invalid key: '"..path.."' must be of type 'string'", path))
end
if recordschema[k] == nil and not additionalValues then
AddError(schema.Error("Superfluous value: '"..path.."' does not appear in the record schema", path))
end
path:pop()
end
return errmsg
end
return CheckRecord
end
function schema.MixedTable(t_schema, additional_values)
local function CheckMixedTable(obj, path)
local obj_t = type(obj)
if obj_t ~= "table" then
local msg = ("Type mismatch: '%s' should be a table, is %s"):format(path, obj_t)
return schema.Error(msg, path)
end
local errmsg = nil
local function AddError(msg)
if errmsg == nil then
errmsg = msg
else
errmsg = errmsg:append(msg)
end
end
local checked_keys = {}
for k, v in pairs(t_schema) do
path:push(k)
local err = schema.CheckSchema(obj[k], v, path)
if err then
AddError(err)
end
checked_keys[k] = true
path:pop()
end
for k, v in pairs(obj) do
if not checked_keys[k] then
path:push(k)
local k_type = type(k)
if k_type ~= "string" and k_type ~= "number" then
local msg = ("Invalid key: '%s' must be of type 'string' or 'number'"):format(k_type)
AddError(schema.Error(msg, path))
end
local t_schema_v = t_schema[k]
if t_schema_v then
local err = schema.CheckSchema(v, t_schema_v, path)
if err then
AddError(err)
end
else
if not additional_values then
local msg = ("Superfluous value: '%s' does not appear in the table schema")
:format(path)
AddError(schema.Error(msg, path))
end
end
path:pop()
end
end
return errmsg
end
return CheckMixedTable
end
-- Builds a map type schema, i.e. a table with an arbitraty number of
-- entries where both all keys (and all vaules) fit a common schema.
function schema.Map(keyschema, valschema)
local function CheckMap(obj, path)
if type(obj) ~= "table" then
return schema.Error("Type mismatch: '"..path.."' should be a map (table), is "..type(obj), path)
end
local errmsg = nil
local function AddError(msg)
if errmsg == nil then
errmsg = msg
else
errmsg = errmsg:append(msg)
end
end
-- aggregate error message
for k, v in pairs(obj) do
path:push(k)
local keyErr = schema.CheckSchema(k, keyschema, path)
if keyErr then
AddError(schema.Error("Invalid map key", path, keyErr))
end
local valErr = schema.CheckSchema(v, valschema, path)
if valErr then
AddError(valErr)
end
path:pop()
end
return errmsg
end
return CheckMap
end
-- Builds a collection type schema, i.e. a table with an arbitrary number of
-- entries where we only care about the type of the values.
function schema.Collection(valschema)
return schema.Map(schema.Any, valschema)
end
-- Builds a tuple type schema, i.e. a table with a fixed number of entries,
-- each indexed by a number and with a fixed type.
function schema.Tuple(...)
local arg = {...}
local function CheckTuple(obj, path)
if type(obj) ~= "table" then
return schema.Error("Type mismatch: '"..path.."' should be a map (tuple), is "..type(obj), path)
end
if #obj ~= #arg then
return schema.Error("Invalid length: '"..path.." should have exactly "..#arg.." elements", path)
end
local errmsg = nil
local function AddError(msg)
if errmsg == nil then
errmsg = msg
else
errmsg = errmsg:append(msg)
end
end
local min = 1
local max = #arg
for k, v in pairs(obj) do
path:push(k)
local err = schema.Integer(k, path)
if not err then
err = schema.CheckSchema(v, arg[k], path)
if err then
AddError(err)
end
else
AddError(schema.Error("Invalid tuple key", path, err))
end
path:pop()
end
return errmsg
end
return CheckTuple
end
-- Builds a conditional type schema, i.e. a schema that depends on the value of
-- another value. The dependence must be *local*, i.e. defined in the same
-- table. Use as in
-- Case("name", {"Peter", schema1}, {"Mary", schema2}, {OneOf(...), schema3})
-- This will check the field "name" against every schema in the first component
-- and will return the second component of the first match.
function schema.Case(relativePath, ...)
if type(relativePath) ~= "table" then
relativePath = schema.Path("..", relativePath)
end
local cases = {...}
for k,v in ipairs(cases) do
if type(v) ~= "table" then
error("Cases expects inputs of the form {conditionSchema, schema}; argument "..v.." is invalid")
end
end
local function CheckCase(obj, path)
local condPath = path:copy()
for k=0, #relativePath do
local s = relativePath:get(k)
if s == ".." then
condPath:pop()
else
condPath:push(s)
end
end
local errmsg = nil
local function AddError(msg)
if errmsg == nil then
errmsg = msg
else
errmsg = errmsg:append(msg)
end
end
local anyCond = false
local condObj = condPath:target()
for k,v in ipairs(cases) do
local condSchema = v[1]
local valSchema = v[2]
local condErr = schema.CheckSchema(condObj, condSchema, condPath)
if not condErr then
anyCond = true
local err = schema.CheckSchema(obj, valSchema, path)
if err then
AddError(schema.Error("Case failed: Condition "..k.." of '"..path.."' holds but the consequence does not", path, err))
end
end
end
if not anyCond then
AddError(schema.Error("Case failed: No condition on '"..path.."' holds"))
end
return errmsg
end
return CheckCase
end
function schema.Test(fn, msg)
local function CheckTest(obj, path)
local pok, ok = pcall(fn, obj)
if pok and ok then
return nil
else
return schema.Error("Invalid value: '"..path..(msg and "': "..msg or ""), path)
end
end
return CheckTest
end
return schema

514
src/resources/MDK/sortbox.lua Executable file
View File

@ -0,0 +1,514 @@
---An H/VBox alternative which can be set to either vertical or horizontal, and will autosort the windows
-- @classmod SortBox
-- @author Damian Monogue <demonnic@gmail.com>
-- @copyright 2020 Damian Monogue
-- @license MIT, see LICENSE.lua
local SortBox = Geyser.Container:new({
name = "SortBoxClass",
autoSort = true,
timerSort = true,
sortInterval = 500,
elastic = false,
maxHeight = 0,
maxWidth = 0,
boxType = "v",
sortFunction = "gaugeValue",
})
local BIGNUMBER = 999999999
--- Sorting functions for spairs, should you wish
-- @table SortFunctions
-- @field gaugeValue sorts Geyser gauges by value, ascending
-- @field reverseGaugeValue sorts Geyser gauges by value, descending
-- @field timeLeft sorts TimerGauges by how much time is left, ascending
-- @field reverseTimeLeft sorts TimerGauges by how much time is left, descending.
-- @field name sorts Geyser objects by name, ascending
-- @field reverseName sorts Geyser objects by name, descending
-- @field message sorts Geyser labels and gauges by their echoed text, ascending
-- @field reverseMessage sorts Geyser labels and gauges by their echoed text, descending
SortBox.SortFunctions = {
gaugeValue = function(t, a, b)
local avalue = t[a].value or BIGNUMBER
local bvalue = t[b].value or BIGNUMBER
return avalue < bvalue
end,
reverseGaugeValue = function(t, a, b)
local avalue = t[a].value or BIGNUMBER
local bvalue = t[b].value or BIGNUMBER
return avalue > bvalue
end,
timeLeft = function(t, a, b)
a = t[a]
b = t[b]
local avalue = a.getTime and tonumber(a:getTime("S.mm")) or BIGNUMBER
local bvalue = b.getTime and tonumber(b:getTime("S.mm")) or BIGNUMBER
return avalue < bvalue
end,
reverseTimeLeft = function(t, a, b)
a = t[a]
b = t[b]
local avalue = a.getTime and tonumber(a:getTime("S.mm")) or BIGNUMBER
local bvalue = b.getTime and tonumber(b:getTime("S.mm")) or BIGNUMBER
return avalue > bvalue
end,
name = function(t, a, b)
return t[a].name < t[b].name
end,
reverseName = function(t, a, b)
return t[a].name > t[b].name
end,
message = function(t, a, b)
a = t[a]
b = t[b]
local avalue = a.text and a.text.message or a.message
local bvalue = b.text and b.text.message or b.message
avalue = avalue or ""
bvalue = bvalue or ""
return avalue < bvalue
end,
reverseMessage = function(t, a, b)
a = t[a]
b = t[b]
local avalue = a.text and a.text.message or a.message
local bvalue = b.text and b.text.message or b.message
avalue = avalue or ""
bvalue = bvalue or ""
return avalue > bvalue
end,
}
--- Creates a new SortBox
-- @usage
-- local SortBox = require("MDK.sortbox")
-- mySortBox = SortBox:new({
-- name = "mySortBox",
-- x = 400,
-- y = 100,
-- height = 150,
-- width = 300,
-- sortFunction = "timeLeft"
-- })
-- @tparam table options the options to use for the SortBox. See table below for added options
-- @param[opt] container the container to add the SortBox into
-- <br><br>Table of new options
-- <table class="tg">
-- <thead>
-- <tr>
-- <th>option name</th>
-- <th>description</th>
-- <th>default</th>
-- </tr>
-- </thead>
-- <tbody>
-- <tr>
-- <td class="tg-1">autoSort</td>
-- <td class="tg-1">should the SortBox perform function based sorting? If false, will behave like a normal H/VBox</td>
-- <td class="tg-1">true</td>
-- </tr>
-- <tr>
-- <td class="tg-2">timerSort</td>
-- <td class="tg-2">should the SortBox automatically perform sorting on a timer?</td>
-- <td class="tg-2">true</td>
-- </tr>
-- <tr>
-- <td class="tg-1">sortInterval</td>
-- <td class="tg-1">how frequently should we sort on a timer if timerSort is true, in milliseconds</td>
-- <td class="tg-1">500</td>
-- </tr>
-- <tr>
-- <td class="tg-2">boxType</td>
-- <td class="tg-2">Should we stack like an HBox or VBox? use 'h' for hbox and 'v' for vbox</td>
-- <td class="tg-2">v</td>
-- </tr>
-- <tr>
-- <td class="tg-1">sortFunction</td>
-- <td class="tg-1">how should we sort the items in the SortBox? see setSortFunction for valid options</td>
-- <td class="tg-1">gaugeValue</td>
-- </tr>
-- <tr>
-- <td class="tg-2">elastic</td>
-- <td class="tg-2">Should this container stretch to fit its contents? boxType v stretches in height, h stretches in width.</td>
-- <td class="tg-2">false</td>
-- </tr>
-- <tr>
-- <td class="tg-1">maxHeight</td>
-- <td class="tg-1">If elastic, what's the biggest a 'v' style box should grow in height? Use 0 for unlimited</td>
-- <td class="tg-1">0</td>
-- </tr>
-- <tr>
-- <td class="tg-2">maxWidth</td>
-- <td class="tg-2">If elastic, what's the biggest a 'h' style box should grow in width? Use 0 for unlimited</td>
-- <td class="tg-2">0</td>
-- </tr>
-- </tbody>
-- </table>
function SortBox:new(options, container)
options = options or {}
options.type = options.type or "SortBox"
local me = self.parent:new(options, container)
setmetatable(me, self)
self.__index = self
if me.timerSort then
me:enableTimer()
end
me:setBoxType(me.boxType)
return me
end
--- Iterates a key:value pair table in a sorted fashion
-- @local
-- I first found this on https://stackoverflow.com/questions/15706270/sort-a-table-in-lua
-- modified slightly, as Mudlet already has table.keys to collect keys, and I don't want
-- to sort if no function to sort with is given. In this case, I want it to work like pairs.
local function spairs(t, order)
local keys = table.keys(t)
if order then
table.sort(keys, function(a, b)
return order(t, a, b)
end)
end
local i = 0
return function()
i = i + 1
if keys[i] then
return keys[i], t[keys[i]]
end
end
end
function SortBox:add(window, cons)
if self.useAdd2 then
Geyser.add2(self, window, cons)
else
Geyser.add(self, window, cons)
end
if not self.defer_updates then
self:organize()
end
end
function SortBox:remove(window)
Geyser.remove(self, window)
self:organize()
end
--- Calling this will cause the SortBox to reposition/resize everything
function SortBox:organize()
-- make sure we don't divide by zero later
if self:get_width() == 0 then
self:resize("0.9px", nil)
end
if self:get_height() == 0 then
self:resize(nil, "0.9px")
end
-- handle the individual boxType organization
if self.boxType == "v" then
self:vorganize()
else
self:horganize()
end
-- shrink/grow if needed
self:handleElastic()
end
--- replicates Geyser.HBox functionality, but with the option of sorting
-- @local
function SortBox:horganize()
local window_width = (self:calculate_dynamic_window_size().width / self:get_width()) * 100
local start_x = 0
local sortFunction = (self.autoSort and self.sortFunction) and SortBox.SortFunctions[self.sortFunction] or nil
if sortFunction then
for _, window in spairs(self.windowList, sortFunction) do
start_x = start_x + self:handleWindow(window, start_x, window_width)
end
else
for _, window_name in ipairs(self.windows) do
local window = self.windowList[window_name]
start_x = start_x + self:handleWindow(window, start_x, window_width)
end
end
end
--- replicates Geyser.VBox functionality, but with the option of sorting
-- @local
function SortBox:vorganize()
local window_height = (self:calculate_dynamic_window_size().height / self:get_height()) * 100
local start_y = 0
local sortFunction = (self.autoSort and self.sortFunction) and SortBox.SortFunctions[self.sortFunction] or nil
if sortFunction then
for _, window in spairs(self.windowList, sortFunction) do
start_y = start_y + self:handleWindow(window, start_y, window_height)
end
else
for _, window_name in ipairs(self.windows) do
local window = self.windowList[window_name]
start_y = start_y + self:handleWindow(window, start_y, window_height)
end
end
end
--- handles a single window during the shuffle process
-- @local
function SortBox:handleWindow(window, start, window_dimension)
local width = (window:get_width() / self:get_width()) * 100
local height = (window:get_height() / self:get_height()) * 100
if window.h_policy == Geyser.Fixed or window.v_policy == Geyser.Fixed then
self.contains_fixed = true
end
if self.boxType == "v" then
window:move("0%", start .. "%")
if window.h_policy == Geyser.Dynamic then
width = 100
if window.width ~= width then
window:resize(width .. "%", nil)
end
end
if window.v_policy == Geyser.Dynamic then
height = window_dimension * window.v_stretch_factor
if window.height ~= height then
window:resize(nil, height .. "%")
end
end
return height
else
window:move(start .. "%", "0%")
if window.h_policy == Geyser.Dynamic then
width = window_dimension * window.h_stretch_factor
if window.width ~= width then
window:resize(width .. "%", nil)
end
end
if window.v_policy == Geyser.Dynamic then
height = 100
if window.height ~= height then
window:resize(nil, height .. "%")
end
end
return width
end
end
---handles actually resizing the window if elastic
-- @local
function SortBox:handleElastic()
if not self.elastic or table.is_empty(self.windows) then
return
end
if self.boxType == "v" then
local contentHeight, canElastic = self:getContentHeight()
if not canElastic then
debugc(string.format("SortBox named %s cannot properly elasticize, as it contains at least one item with a dynamic v_policy", self.name))
return
end
local currentHeight = self:get_height()
local maxHeight = self.maxHeight
if maxHeight > 0 and contentHeight > maxHeight then
contentHeight = maxHeight
end
if contentHeight ~= currentHeight then
self:resize(nil, contentHeight)
end
else
local contentWidth, canElastic = self:getContentWidth()
if not canElastic then
debugc(string.format("SortBox named %s cannot properly elasticize, as it contains at least one item with a dynamic h_policy", self.name))
return
end
local currentWidth = self:get_width()
local maxWidth = self.maxWidth
if maxWidth > 0 and contentWidth > maxWidth then
contentWidth = maxWidth
end
if contentWidth ~= currentWidth then
self:resize(contentWidth, nil)
end
end
end
---prevents gaps from forming during resize if it doesn't autoorganize on a timer.
-- @local
function SortBox:reposition()
Geyser.Container.reposition(self)
if self.contains_fixed then
self:organize()
end
end
--- Returns the sum of the heights of the contents, and whether this SortBox can be elastic in height
-- @local
function SortBox:getContentHeight()
if self.boxType ~= "v" then
return self:get_height()
end
local canElastic = true
local contentHeight = 0
for _, window in pairs(self.windowList) do
contentHeight = contentHeight + window:get_height()
if window.v_policy == Geyser.Dynamic then
canElastic = false
end
end
return contentHeight, canElastic
end
--- Returns the sum of the widths of the contents, and whether this SortBox can be elastic in width.
-- @local
function SortBox:getContentWidth()
if self.boxType == "v" then
return self:get_width()
end
local canElastic = true
local contentWidth = 0
for _, window in pairs(self.windowList) do
contentWidth = contentWidth + window:get_width()
if window.h_policy == Geyser.Dynamic then
canElastic = false
end
end
return contentWidth, canElastic
end
--- Enables elasticity for the SortBox.
function SortBox:enableElastic()
self:setElastic(true)
end
--- Disables elasticity for the SortBox
function SortBox:disableElastic()
self:setElastic(false)
end
--- Set elasticity specifically
-- @tparam boolean enabled if true, enable elasticity. If false, disable it.
function SortBox:setElastic(enabled)
self.elastic = enabled and true or false
end
--- Set the max width of the SortBox if it's elastic
-- @tparam number maxWidth The maximum width in pixels to resize the SortBox to. Use 0 for unlimited.
function SortBox:setMaxWidth(maxWidth)
local mwtype = type(maxWidth)
assert(mwtype == "number", string.format("SortBox:setMaxWidth(maxWidth): SortBox: %s maxWidth as number expected, got %s", self.name, mwtype))
assert(maxWidth >= 0, string.format("SortBox:setMaxWidth(maxWidth): SortBox: %s maxWidth must be >= 0, %d", self.name, maxWidth))
self.maxWidth = maxWidth
end
--- Set the max height of the SortBox if it's elastic
-- @tparam number maxHeight The maximum height in pixels to resize the SortBox to. Use 0 for unlimited.
function SortBox:setMaxHeight(maxHeight)
local mhtype = type(maxHeight)
assert(mhtype == "number", string.format("SortBox:setMaxHeight(maxHeight): SortBox: %s maxHeight as number expected, got %s", self.name, mhtype))
assert(maxHeight >= 0, string.format("SortBox:setMaxHeight(maxHeight): SortBox: %s maxHeight must be >= 0, %d", self.name, maxHeight))
self.maxHeight = maxHeight
end
--- Starts the SortBox sorting and organizing itself on a timer
function SortBox:enableTimer()
if self.timerID then
self:disableTimer()
end
self.timerSort = true
self.timerID = tempTimer(self.sortInterval / 1000, function()
self:organize()
end, true)
end
--- Stops the SortBox from sorting and organizing itself on a timer
function SortBox:disableTimer()
killTimer(self.timerID)
self.timerID = nil
self.timerSort = false
end
--- Sets the sortInterval, or amount of time in milliseconds between auto sorting on a timer if timerSort is true
-- @tparam number sortInterval time in milliseconds between auto sorting if timerSort is true
function SortBox:setSortInterval(sortInterval)
local sitype = type(sortInterval)
assert(sitype == "number", string.format("SortBox:setSortInterval(sortInterval): sortInterval as number expected, got %s", sitype))
assert(sortInterval > 0, string.format("SortBox:setSortInterval(sortInterval): sortInterval must be positive"))
self.sortInterval = sortInterval
if self.timerSort then
self:enableTimer()
end
end
--- Enables sorting when items are added/removed, or if timerSort is true, every sortInterval milliseconds
function SortBox:enableSort()
self.autoSort = true
self:organize()
end
--- Disables sorting when items are added or removed
function SortBox:disableSort()
self.autoSort = false
end
---Set whether the SortBox acts as a VBox or HBox.
-- @tparam string boxType If you pass 'h' or 'horizontal' it will act like an HBox. Anything else it will act like a VBox.
-- @usage mySortBox:setBoxType("v") -- behave like a VBox
-- mySortBox:setBoxType("h") -- behave like an HBox
-- mySortBox:setBoxType("beeblebrox") -- why?! Why would you do this? It'll behave like a VBox
function SortBox:setBoxType(boxType)
boxType = boxType:lower()
if boxType == "h" or boxType == "horizontal" then
self.boxType = "h"
else
self.boxType = "v"
end
end
---Sets the type of sorting in use by this SortBox.
-- <br>If an item in the box does not have the appropriate property or function, then 999999999 is used for sorting except as otherwise noted.
-- <br>If an invalid option is given, then existing H/VBox behaviour is maintained, just like if autoSort is false.
-- @usage mySortBox:setSortFunction("gaugeValue")
-- @tparam string functionName what type of sorting should we use? See table below for valid options and their descriptions.
-- <table class="tg">
-- <thead>
-- <tr>
-- <th>sort type</th>
-- <th>description</th>
-- </tr>
-- </thead>
-- <tbody>
-- <tr>
-- <td class="tg-1">gaugeValue</td>
-- <td class="tg-1">sort gauges based on how full the gauge is, from less full to more</td>
-- </tr>
-- <tr>
-- <td class="tg-2">reverseGaugeValue</td>
-- <td class="tg-2">sort gauges based on how full the gauge is, from more full to less</td>
-- </tr>
-- <tr>
-- <td class="tg-1">timeLeft</td>
-- <td class="tg-1">sort TimerGauges based on the total time left in the gauge, from less time to more</td>
-- </tr>
-- <tr>
-- <td class="tg-2">reverseTimeLeft</td>
-- <td class="tg-2">sort TimerGauges based on the total time left in the gauge, from more time to less</td>
-- </tr>
-- <tr>
-- <td class="tg-1">name</td>
-- <td class="tg-1">sort any item (and mixed types) by name, alphabetically.</td>
-- </tr>
-- <tr>
-- <td class="tg-2">reverseName</td>
-- <td class="tg-2">sort any item (and mixed types) by name, reverse alphabetically.</td>
-- </tr>
-- <tr>
-- <td class="tg-1">message</td>
-- <td class="tg-1">sorts Labels based on their echoed message, alphabetically. If not a label, the empty string will be used</td>
-- </tr>
-- <tr>
-- <td class="tg-2">reverseMessage</td>
-- <td class="tg-2">sorts Labels based on their echoed message, reverse alphabetically. If not a label, the empty string will be used</td>
-- </tr>
-- </tbody>
-- </table>
function SortBox:setSortFunction(functionName)
self.sortFunction = functionName
end
SortBox.parent = Geyser.Container
return SortBox

481
src/resources/MDK/spinbox.lua Executable file
View File

@ -0,0 +1,481 @@
--- A Geyser object to create a spinbox for adjusting a number
-- @classmod spinbox
-- @author Damian Monogue <demonnic@gmail.com>
-- @copyright 2023
-- @license MIT, see https://raw.githubusercontent.com/demonnic/MDK/main/src/scripts/LICENSE.lua
local spinbox = {
parent = Geyser.Container,
name = 'SpinboxClass',
min = 0,
max = 10,
delta = 1,
value = 0,
activeButtonColor = "gray",
inactiveButtonColor = "DimGray",
integer = true,
upArrowLocation = "https://demonnic.github.io/image-assets/uparrow.png",
downArrowLocation = "https://demonnic.github.io/image-assets/downarrow.png",
color = "#202020"
}
spinbox.__index = spinbox
setmetatable(spinbox, spinbox.parent)
local gss = Geyser.StyleSheet
local directory = getMudletHomeDir() .. "/spinbox/"
local saveFile = directory .. "fileLocations.lua"
if not io.exists(directory) then
lfs.mkdir(directory)
end
--- Creates a new spinbox.
-- @tparam table cons a table containing the options for this spinbox.
-- <table class="tg">
-- <thead>
-- <tr>
-- <th>option name</th>
-- <th>description</th>
-- <th>default</th>
-- </tr>
-- </thead>
-- <tbody>
-- <tr>
-- <td class="tg-1">min</td>
-- <td class="tg-1">The minimum value for this spinbox</td>
-- <td class="tg-1">0</td>
-- </tr>
-- <tr>
-- <td class="tg-2">max</td>
-- <td class="tg-2">The maximum value for this spinbox</td>
-- <td class="tg-2">10</td>
-- </tr>
-- <tr>
-- <td class="tg-1">activeButtonColor</td>
-- <td class="tg-1">The color the up/down buttons should be when they are active/able to be used</td>
-- <td class="tg-1">gray</td>
-- </tr>
-- <tr>
-- <td class="tg-2">inactiveButtonColor</td>
-- <td class="tg-2">The color the up/down buttons should be when they are inactive/unable to be used</td>
-- <td class="tg-2">dimgray</td>
-- </tr>
-- <tr>
-- <td class="tg-1">integer</td>
-- <td class="tg-1">Boolean value. When true, values must always be integers (no decimal place)</td>
-- <td class="tg-1">true</td>
-- </tr>
-- <tr>
-- <td class="tg-2">delta</td>
-- <td class="tg-2">The amount to change the spinbox's value when the up or down button is pressed.</td>
-- <td class="tg-2">1</td>
-- </tr>
-- <tr>
-- <td class="tg-1">upArrowLocation</td>
-- <td class="tg-1">The location of the up arrow image. Either a web URL where it can be downloaded, or the location on disk to read it from</td>
-- <td class="tg-1">https://demonnic.github.io/image-assets/uparrow.png</td>
-- </tr>
-- <tr>
-- <td class="tg-2">downArrowLocation</td>
-- <td class="tg-2">The location of the down arrow image. Either a web URL where it can be downloaded, or the location on disk to read it from</td>
-- <td class="tg-2">https://demonnic.github.io/image-assets/downarrow.png</td>
-- <tr>
-- <td class="tg-1">callBack</td>
-- <td class="tg-1">The function to run when the spinbox's value is updated. Is called with parameters (self.name, value, oldValue)</td>
-- <td class="tg-1">nil</td>
-- </tr>
-- </tr>
--</tbody>
--</table>
-- @param container The Geyser container for this spinbox
function spinbox:new(cons, container)
cons = cons or {}
local consType = type(cons)
if consType ~= "table" then
printError(f"spinbox:new(cons, container): cons as table of options expected, got {consType}!", true, true)
end
cons.name = cons.name or Geyser.nameGen("spinbox")
local me = self.parent:new(cons, container)
setmetatable(me, self)
me:createComponents()
if me.callBack then
me:setCallBack(me.callBack)
end
me.oldValue = me.value
return me
end
--- Creates the components that make up the spinbox UI.
-- @local
-- Obtains the up and down arrow images specified in the spinbox options.
-- Generates styles for the spinbox.
-- Calculates the height of the up/down buttons and any remainder space.
-- Creates:
-- `self.upButton` - A button with an up arrow image for incrementing the value
-- `self.downButton` - A button with a down arrow image for decrementing the value
-- `self.displayLabel` - A label to display the current spinbox value
-- `self.input` - A command line input to allow directly entering a value
-- Hides the input by default.
-- Applies the generated styles.
function spinbox:createComponents()
self:obtainImages()
self:generateStyles()
self:calculateButtonDimensions()
self.upButton = self:createButton("up")
self.downButton = self:createButton("down")
self.displayLabel = self:createDisplayLabel()
self.input = self:createInput()
self.input:hide()
self:applyStyles()
end
--- Calculates the button height. We use square buttons in this house.
-- @local
-- Calculates the height of the up/down buttons by dividing the spinbox height in half.
-- Stores the remainder (if any) in self.remainder.
-- Stores the calculated button height in self.buttonHeight.
function spinbox:calculateButtonDimensions()
self.buttonHeight = math.floor(self.get_height() / 2)
self.remainder = self.get_height() % 2
end
--- Creates a button (up or down arrow) for the spinbox.
-- @param type Either "up" or "down" to specify which direction the arrow should point
-- @return The created Geyser.Label button
-- @local
-- Creates a Geyser.Label button with an up or down arrow image.
-- Positions the button at the top or bottom of the spinbox respectively.
-- Sets a click callback on the button to call increment() or decrement() depending on the type.
-- Returns the created button.
function spinbox:createButton(type)
local button = Geyser.Label:new({
name = self.name .. "spinbox_"..type.."Arrow",
height = self.buttonHeight,
width = self.buttonHeight,
x = "100%-" .. self.buttonHeight,
y = type == "up" and 0 or self.buttonHeight + self.remainder,
}, self)
button:setClickCallback(function()
if type == "up" then
self:increment()
else
self:decrement()
end
end)
return button
end
--- Creates the display label for the spinbox value.
-- @return The created Geyser.Label display label
-- @local
-- Creates a Geyser.Label to display the current spinbox value.
-- Centers the text in the label.
-- Sets a double click callback on the label to show the input, put the current
-- value in it, select the text, and hide the label.
-- Returns the created display label.
function spinbox:createDisplayLabel()
local displayLabel = Geyser.Label:new({
name = self.name .. "spinbox_displayLabel",
x = 0,
y = 0,
width = "100%-" .. self.buttonHeight,
height = "100%",
message = self.value
}, self)
displayLabel:setAlignment("center")
displayLabel:setDoubleClickCallback(function()
self.input:show()
self.input:print(self.value)
self.input:selectText()
displayLabel:hide()
end)
return displayLabel
end
--- Creates the input for directly entering a spinbox value.
-- @return The created Geyser.CommandLine input
-- @local
-- Creates a Geyser.CommandLine input.
-- Sets an action on the input to:
-- - Attempt to convert the input text to a number
-- - If successful, call setValue() with the number to set the spinbox value
-- - Hide the input
-- - Show the display label
-- - Put the new spinbox value in the input
-- Returns the created input.
function spinbox:createInput()
local input = Geyser.CommandLine:new({
x = 0,
y = 0,
width = "100%-".. self.buttonHeight,
height = "100%",
}, self)
input:setAction(function(txt)
txt = tonumber(txt)
if txt then
self:setValue(txt)
input:hide()
end
self.displayLabel:show()
input:print(self.value)
end)
return input
end
--- Used to increment the value by the delta amount
-- @local
-- Increments the spinbox value by the delta amount.
-- Checks if the new value would exceed the max, and if so sets it to the max.
-- Updates the display label with the new value.
-- Applies any styles that depend on the value.
function spinbox:increment()
local val = self.value + self.delta
if val >= self.max then
val = self.max
end
self.oldValue = self.value
self.value = val
self.displayLabel:echo(val)
self:applyStyles()
self:handleCallBacks()
end
--- Used to decrement the value by the delta amount
-- @local
-- Decrements the spinbox value by the delta amount.
-- Checks if the new value would be below the min, and if so sets it to the min.
-- Updates the display label with the new value.
-- Applies any styles that depend on the value.
function spinbox:decrement()
local val = self.value - self.delta
if val <= self.min then
val = self.min
end
self.oldValue = self.value
self.value = val
self.displayLabel:echo(val)
self:applyStyles()
self:handleCallBacks()
end
--- Used to directly set the value of the spinbox.
-- @param value The new value to set
-- Rounds the value to an integer if the spinbox is integer only.
-- Checks if the new value is within the min/max range and clamps it if not.
-- Updates the display label with the new value.
-- Applies any styles that depend on the value.
function spinbox:setValue(value)
if self.integer then
value = math.floor(value)
end
if value >= self.max then
value = self.max
elseif value <= self.min then
value = self.min
end
self.oldValue = self.value
self.value = value
self.displayLabel:echo(value)
self:applyStyles()
self:handleCallBacks()
end
--- Obtains the up and down arrow images for the spinbox.
-- @local
-- Gets the previously saved file locations.
-- Checks if the up arrow image exists at the upArrowLocation.
-- If not, it will download the image from a URL or copy a local file. It saves
-- the new location.
-- Does the same for the down arrow image and downArrowLocation.
-- Saves any new locations to the save file.
-- Sets self.upArrowFile and self.downArrowFile to the locations of the images.
function spinbox:obtainImages()
local locations = self:getFileLocs()
local upURL = self.upArrowLocation
local downURL = self.downArrowLocation
local upFile = locations[upURL]
local downFile = locations[downURL]
local locationsChanged = false
if not (upFile and io.exists(upFile)) then
if not upFile then
upFile = directory .. self.name .. "/uparrow.png"
locations[upURL] = upFile
locationsChanged = true
end
if upURL:match("^http") then
self:downloadFile(upURL, upFile)
elseif io.exists(upURL) then
upFile = upURL
locations[upURL] = upFile
locationsChanged = true
end
end
if not (downFile and io.exists(downFile)) then
if not downFile then
downFile = directory .. self.name .. "/downarrow.png"
locations[downURL] = downFile
locationsChanged = true
end
if downURL:match("^http") then
self:downloadFile(downURL, downFile)
elseif io.exists(downURL) then
downFile = downURL
locations[downURL] = downFile
locationsChanged = true
end
end
self.upArrowFile = upFile
self.downArrowFile = downFile
if locationsChanged then
table.save(saveFile, locations)
end
end
--- Handles the actual download of a file from a url
-- @param url The url to download the file from
-- @param fileName The location to save the downloaded file
-- @local
-- Creates any missing directories in the file path.
-- Registers named event handlers to handle the download completing or erroring.
-- The completion handler stops the error handler.
-- The error handler prints an error message and stops the completion handler.
-- Downloads the file from the url to the fileName location.
function spinbox:downloadFile(url, fileName)
local parts = fileName:split("/")
parts[#parts] = nil
local dirName = table.concat(parts, "/") .. "/"
if not io.exists(dirName) then
lfs.mkdir(dirName)
end
local uname = "spinbox"
local handlerName = self.name .. url
local handler = function(event, ...)
local args = {...}
local file = #args == 1 and args[1] or args[2]
if file ~= fileName then
return true
end
if event == "sysDownloadDone" then
debugc(f"INFO:Spinbox successfully downloaded {file}")
stopNamedEventHandler(uname, handlerName .. "error")
return false
end
cecho(f"\n<red>ERROR:<reset>Spinbox had an issue downloading an image file to {file}: {args[1]}\n")
stopNamedEventHandler(uname, handlerName .. "done")
end
registerNamedEventHandler(uname, handlerName .. "done", "sysDownloadDone", handler, true)
registerNamedEventHandler(uname, handlerName .. "error", "sysDownloadError", handler, true)
downloadFile(fileName, url)
end
--- Responsible for reading the file locations from disk and returning them
-- @local
function spinbox:getFileLocs()
local locations = {}
if io.exists(saveFile) then
table.load(saveFile, locations)
end
return locations
end
--- (Re)generates the stylesheets for the spinbox
-- Should not need to call but if you change something and it doesn't take effect
-- you can try calling this followed by applyStyles
function spinbox:generateStyles()
self.baseStyle = gss:new([[
border-radius: 2px;
border-color: black;
]])
self.activeStyle = gss:new(f[[
background-color: {self.activeButtonColor};
]], self.baseStyle)
self.inactiveStyle = gss:new(f[[
background-color: {self.inactiveButtonColor};
]], self.baseStyle)
self.upStyle = gss:new(f[[
border-image: url("{self.upArrowFile}");
]])
self.downStyle = gss:new(f[[
border-image: url("{self.downArrowFile}");
]])
self.displayStyle = gss:new(f[[
background-color: {Geyser.Color.hex(self.color)};
text-align: center;
]], self.baseStyle)
end
--- Applies updated stylesheets to the components of the spinbox
-- Should not need to call this directly
function spinbox:applyStyles()
if self.value >= self.max then
self.upStyle:setParent(self.inactiveStyle)
else
self.upStyle:setParent(self.activeStyle)
end
if self.value <= self.min then
self.downStyle:setParent(self.inactiveStyle)
else
self.downStyle:setParent(self.activeStyle)
end
self.upButton:setStyleSheet(self.upStyle:getCSS())
self.downButton:setStyleSheet(self.downStyle:getCSS())
self.displayLabel:setStyleSheet(self.displayStyle:getCSS())
end
--- sets the color for active buttons on the spinbox
-- @param color any valid color formatting string, such a "red" or "#880000" or "<128,0,0>" or a table of colors, like {128, 0,0}. See Geyser.Color.parse at https://www.mudlet.org/geyser/files/geyser/GeyserColor.html#Geyser.Color.parse
function spinbox:setActiveButtonColor(color)
local colorType = type(color)
local hex
if colorType == "table" then
hex = Geyser.Color.hex(unpack(color))
else
hex = Geyser.Color.hex(color)
end
self.activeButtonColor = hex
self.activeStyle:set("background-color", hex)
self:applyStyles()
end
--- sets the color for inactive buttons on the spinbox
-- @param color any valid color formatting string, such a "<red>" or "red" or "<128,0,0>" or a table of colors, like {128, 0,0}. See Geyser.Color.parse at https://www.mudlet.org/geyser/files/geyser/GeyserColor.html#Geyser.Color.parse
function spinbox:setInactiveButtonColor(color)
local colorType = type(color)
local hex
if colorType == "table" then
hex = Geyser.Color.hex(unpack(color))
else
hex = Geyser.Color.hex(color)
end
self.inactiveButtonColor = hex
self.inactiveStyle:set("background-color", hex)
self:applyStyles()
end
-- internal function that handles calling a registered callback and raising an event any time the
-- spinbox value is changed, whether using the buttons or the :set function.
function spinbox:handleCallBacks()
raiseEvent("spinbox updated", self.name, self.value, self.oldValue)
if self.callBack then
local ok, err = pcall(self.callBack, self.name, self.value, self.oldValue)
if not ok then
printError(f"Had an issue running the callback handler for spinbox named {self.name}: {err}", true, true)
end
end
end
--- Set a callback function for the spinbox to call any time the value of the spinbox is changed
-- the function will be called as func(self.value, self.name)
function spinbox:setCallBack(func)
local funcType = type(func)
if funcType ~= "function" then
printError(f"spinbox:setCallBack(func): func as function required, got {funcType}", true, true)
end
self.callBack = func
return true
end
return spinbox

255
src/resources/MDK/sug.lua Executable file
View File

@ -0,0 +1,255 @@
--- Self Updating Gauge, extends <a href="https://www.mudlet.org/geyser/files/geyser/GeyserGauge.html">Geyser.Gauge</a>
-- @classmod SUG
-- @author Damian Monogue <demonnic@gmail.com>
-- @copyright 2020 Damian Monogue
-- @license MIT, see LICENSE.lua
local SUG = {
name = "SelfUpdatingGaugeClass",
active = true,
updateTime = 333,
currentVariable = "",
maxVariable = "",
defaultCurrent = 50,
defaultMax = 100,
textTemplate = " |c/|m |p%",
strict = true,
}
-- Internal function, used to turn a string variable name into a value
local function getValueAt(accessString)
local ok, err = pcall(loadstring("return " .. tostring(accessString)))
if ok then return err end
return nil, err
end
-- ========== End section copied from demontools.lua
--- Creates a new Self Updating Gauge.
-- @tparam table cons table of options which control the Gauge's behaviour. In addition to all valid contraints for Geyser.Gauge, SUG adds:
-- <br>
-- <table class="tg">
-- <tr>
-- <th>name</th>
-- <th>description</th>
-- <th>default</th>
-- </tr>
-- <tr>
-- <td class="tg-1">active</td>
-- <td class="tg-1">boolean, if true starts the timer updating</td>
-- <td class="tg-1">true</td>
-- </tr>
-- <tr>
-- <td class="tg-2">updateTime</td>
-- <td class="tg-2">How often should the gauge autoupdate? Milliseconds. 0 to disable the timer but still allow event updates</td>
-- <td class="tg-2">333</td>
-- </tr>
-- <tr>
-- <td class="tg-1">currentVariable</td>
-- <td class="tg-1">What variable will hold the 'current' value of the gauge? Pass the name as a string, IE "currentHP" or "gmcp.Char.Vitals.hp"</td>
-- <td class="tg-1">""</td>
-- </tr>
-- <tr>
-- <td class="tg-2">maxVariable</td>
-- <td class="tg-2">What variable will hold the 'current' value of the gauge? Pass the name as a string, IE "maxHP" or "gmcp.Char.Vitals.maxhp"</td>
-- <td class="tg-2">""</td>
-- </tr>
-- <tr>
-- <td class="tg-1">textTemplate</td>
-- <td class="tg-1">Template to use for the text on the gauge. "|c" replaced with current value, "|m" replaced with max value, "|p" replaced with the % full the gauge should be</td>
-- <td class="tg-1">" |c/|m |p%"</td>
-- </tr>
-- <tr>
-- <td class="tg-2">defaultCurrent</td>
-- <td class="tg-2">What value to use if the currentVariable points to nil or something which cannot be made a number?</td>
-- <td class="tg-2">50</td>
-- </tr>
-- <tr>
-- <td class="tg-1">defaultMax</td>
-- <td class="tg-1">What value to use if the maxVariable points to nil or something which cannot be made a number?</td>
-- <td class="tg-1">100</td>
-- </tr>
-- <tr>
-- <td class="tg-2">updateEvent</td>
-- <td class="tg-2">The name of an event to listen for to perform an update. Can be run alongside or instead of the timer updates. Empty string to turn off</td>
-- <td class="tg-2">""</td>
-- </tr>
-- <tr>
-- <td class="tg-1">updateHook</td>
-- <td class="tg-1">A function which is run each time the gauge updates. Should take 3 arguments, the gauge itself, current value, and max value. You can return new current and max values to be used, for example `return 34, 120` would cause the gauge to use 34 for current and 120 for max regardless of what the variables it reads say.</td>
-- <td class="tg-1"></td>
-- </tr>
-- </table>
-- @param container The Geyser container for this gauge
-- @usage
-- local SUG = require("MDK.sug") --the following will watch "gmcp.Char.Vitals.hp" and "gmcp.Char.Vitals.maxhp" and update itself every 333 milliseconds
-- myGauge = SUG:new({
-- name = "myGauge",
-- currentVariable = "gmcp.Char.Vitals.hp", --if this is nil, it will use the defaultCurrent of 50
-- maxVariable = "gmcp.Char.Vitals.maxhp", --if this is nil, it will use the defaultMax of 100.
-- height = 50,
-- })
function SUG:new(cons, container)
local funcName = "SUG:new(cons, container)"
cons = cons or {}
local consType = type(cons)
assert(consType == "table", string.format("%s: cons as table expected, got %s", funcName, consType))
local me = SUG.parent:new(cons, container)
setmetatable(me, self)
self.__index = self
-- apply any styling requested
if me.cssFront then
if not me.cssBack then
me.cssBack = me.cssFront .. "background-color: black;"
end
me:setStyleSheet(me.cssFront, me.cssBack, me.cssText)
end
if me.active then
me:start()
end
me:update()
return me
end
--- Set how often to update the gauge on a timer
-- @tparam number time time in milliseconds. 0 to disable the timer
function SUG:setUpdateTime(time)
if type(time) ~= "number" then
debugc("SUG:setUpdateTime(time) time as number expected, got " .. type(time))
return
end
self.updateTime = time
if self.active then self:start() end
end
--- Set the event to listen for to update the gauge
-- @tparam string event the name of the event to listen for, use "" to disable events without stopping any existing timers
function SUG:setUpdateEvent(event)
if type(event) ~= string then
debugc("SUG:setUpdateEvent(event) event name as string expected, got " .. type(event))
return
end
self.updateEvent = event
if self.active then self:start() end
end
--- Set the name of the variable the Self Updating Gauge watches for the 'current' value of the gauge
-- @tparam string variableName The name of the variable to get the current value for the gauge. For instance "currentHP", "gmcp.Char.Vitals.hp" etc
function SUG:setCurrentVariable(variableName)
local nameType = type(variableName)
local funcName = "SUG:setCurrentVariable(variableName)"
assert(nameType == "string", string.format("%s: variableName as string expected, got: %s", funcName, nameType))
local val = getValueAt(variableName)
local valType = type(tonumber(val))
assert(valType == "number",
string.format("%s: variableName must point to a variable which is a number or coercable into one. %s points to a %s", funcName, variableName,
type(val)))
self.currentVariable = variableName
self:update()
end
--- Set the name of the variable the Self Updating Gauge watches for the 'max' value of the gauge
-- @tparam string variableName The name of the variable to get the max value for the gauge. For instance "maxHP", "gmcp.Char.Vitals.maxhp" etc. Set to "" to only check the current value
function SUG:setMaxVariable(variableName)
if variableName == "" then
self.maxVariable = variableName
self:update()
return
end
local nameType = type(variableName)
local funcName = "SUG:setMaxVariable(variableName)"
assert(nameType == "string", string.format("%s: variableName as string expected, got: %s", funcName, nameType))
local val = getValueAt(variableName)
local valType = type(tonumber(val))
assert(valType == "number",
string.format("%s: variableName must point to a variable which is a number or coercable into one. %s points to a %s", funcName, variableName,
type(val)))
self.maxVariable = variableName
self:update()
end
--- Set the template for the Self Updating Gauge to set the text with. "|c" is replaced by the current value, "|m" is replaced by the max value, and "|p" is replaced by the percentage current/max
-- @tparam string template The template to use for the text on the gauge. If the max value is 200 and current is 68, then |c will be replace by 68, |m replaced by 200, and |p replaced by 34.
function SUG:setTextTemplate(template)
local templateType = type(template)
local funcName = "SUG:setTextTemplate(template)"
assert(templateType == "string", string.format("%s: template as string expected, got %s", funcName, templateType))
self.textTemplate = template
self:update()
end
--- Set the updateHook function which is run just prior to the gauge updating
-- @tparam function func The function which will be called when the gauge updates. It should take 3 arguments, the gauge itself, the current value, and the max value. If you wish to override the current or max values used for the gauge, you can return new current and max values, like `return newCurrent newMax`
function SUG:setUpdateHook(func)
local funcType = type(func)
if funcType ~= "function" then
return nil, "setUpdateHook only takes functions, no strings or anything like that. You passed in: " .. funcType
end
self.updateHook = func
end
--- Stops the Self Updating Gauge from updating
function SUG:stop()
self.active = false
if self.timer then
killTimer(self.timer)
self.timer = nil
end
if self.eventHandler then
killAnonymousEventHandler(self.eventHandler)
self.eventHandler = nil
end
end
--- Starts the Self Updating Gauge updating. If it is already updating, it will restart it.
function SUG:start()
self:stop()
self.active = true
local update = function() self:update() end
if self.updateTime > 0 then
self.timer = tempTimer(self.updateTime / 1000, update, true)
end
local updateEvent = self.updateEvent
if updateEvent and updateEvent ~= "" and updateEvent ~= "*" then
self.eventHandler = registerAnonymousEventHandler(self.updateEvent, update)
end
end
--- Reads the values from currentVariable and maxVariable, and updates the gauge's value and text.
function SUG:update()
local current = getValueAt(self.currentVariable)
local max = getValueAt(self.maxVariable)
current = tonumber(current)
max = tonumber(max)
if current == nil then
current = self.defaultCurrent
debugc(string.format(
"Self Updating Gauge named %s is trying to update with an invalid current value. Using the defaultCurrent instead. currentVariable: '%s' maxVariable: '%s'",
self.name, self.currentVariable, self.maxVariable))
end
if max == nil then
max = self.defaultMax
if self.maxVariable ~= "" then
debugc(string.format(
"Self Updating Gauge named %s is trying to update with an invalid max value. Using the defaultCurrent instead. currentVariable: '%s' maxVariable: '%s'",
self.name, self.currentVariable, self.maxVariable))
end
end
if self.updateHook and type(self.updateHook) == "function" then
local ok, newcur, newmax = pcall(self.updateHook, self, current, max)
if ok and newcur then
current = newcur
max = newmax and newmax or self.defaultMax
end
end
local text = self.textTemplate
local percent = math.floor((current / max * 100) + 0.5)
text = text:gsub("|c", current)
text = text:gsub("|m", max)
text = text:gsub("|p", percent)
self:setValue(current, max, text)
end
SUG.parent = Geyser.Gauge
setmetatable(SUG, Geyser.Gauge)
return SUG

335
src/resources/MDK/textgauge.lua Executable file
View File

@ -0,0 +1,335 @@
--- Creates a text based gauge, for use in miniconsoles and the like.
-- @classmod TextGauge
-- @author Damian Monogue <demonnic@gmail.com>
-- @copyright 2020 Damian Monogue
-- @copyright 2021 Damian Monogue
-- @license MIT, see LICENSE.lua
local TextGauge = {width = 24, fillCharacter = ":", emptyCharacter = "-", showPercent = true, showPercentSymbol = true, format = "c", value = 50}
--- Creates a new TextGauge.
-- @tparam[opt] table options The table of options you would like the TextGauge to start with.
-- <br><br>Table of new options
-- <table class="tg">
-- <thead>
-- <tr>
-- <th>option name</th>
-- <th>description</th>
-- <th>default</th>
-- </tr>
-- </thead>
-- <tbody>
-- <tr>
-- <td class="tg-1">width</td>
-- <td class="tg-1">How many characters wide to make the gauge</td>
-- <td class="tg-1">24</td>
-- </tr>
-- <tr>
-- <td class="tg-2">fillCharacter</td>
-- <td class="tg-2">What character to use for the 'full' part of the gauge</td>
-- <td class="tg-2">:</td>
-- </tr>
-- <tr>
-- <td class="tg-1">overflowCharacter</td>
-- <td class="tg-1">What character to use for >100% part of the gauge</td>
-- <td class="tg-1">if not set, it uses whatever you set fillCharacter to</td>
-- </tr>
-- <tr>
-- <td class="tg-2">emptyCharacter</td>
-- <td class="tg-2">What character to use for the 'empty' part of the gauge</td>
-- <td class="tg-2">-</td>
-- </tr>
-- <tr>
-- <td class="tg-1">showPercentSymbol</td>
-- <td class="tg-1">Should we show the % sign itself?</td>
-- <td class="tg-1">true</td>
-- </tr>
-- <tr>
-- <td class="tg-2">showPercent</td>
-- <td class="tg-2">Should we show what % of the gauge is filled?</td>
-- <td class="tg-2">true</td>
-- </tr>
-- <tr>
-- <td class="tg-1">value</td>
-- <td class="tg-1">How much of the gauge should be filled</td>
-- <td class="tg-1">50</td>
-- </tr>
-- <tr>
-- <td class="tg-2">format</td>
-- <td class="tg-2">What type of color formatting to use? 'c' for cecho, 'd' for decho, 'h' for hecho</td>
-- <td class="tg-2">c</td>
-- </tr>
-- <tr>
-- <td class="tg-1">fillColor</td>
-- <td class="tg-1">What color to make the full part of the bar?</td>
-- <td class="tg-1">"DarkOrange" or equivalent for your format type</td>
-- </tr>
-- <tr>
-- <td class="tg-2">emptyColor</td>
-- <td class="tg-2">what color to use for the empty part of the bar?</td>
-- <td class="tg-2">"white" or format appropriate equivalent</td>
-- </tr>
-- <tr>
-- <td class="tg-1">percentColor</td>
-- <td class="tg-1">What color to print the percentage numvers in, if shown?</td>
-- <td class="tg-1">"white" or fortmat appropriate equivalent</td>
-- </tr>
-- <tr>
-- <td class="tg-2">percentSymbolColor</td>
-- <td class="tg-2">What color to make the % if shown?</td>
-- <td class="tg-2">If not set, uses what percentColor is set to.</td>
-- </tr>
-- <tr>
-- <td class="tg-1">overflowColor</td>
-- <td class="tg-1">What color to make the >100% portion of the bar?</td>
-- <td class="tg-1">If not set, will use the same color as fillColor</td>
-- </tr>
-- </tbody>
-- </table>
-- @usage
-- local TextGauge = require("MDK.textgauge")
-- myTextGauge = TextGauge:new()
-- gaugeText = myTextGauge:setValue(382, 830)
function TextGauge:new(options)
options = options or {}
local optionsType = type(options)
assert(optionsType == "table" or optionsType == "nil", "TextGauge:new(options): options expected as table, got " .. optionsType)
local me = table.deepcopy(options)
setmetatable(me, self)
self.__index = self
me:setDefaultColors()
return me
end
--- Sets the width in characters of the gauge
-- @tparam number width number of characters wide to make the gauge
function TextGauge:setWidth(width)
local widthType = type(width)
assert(widthType == "number", string.format("TextGauge:setWidth(width): width as number expected, got %s", widthType))
self.width = width
end
function TextGauge:setFormat(format)
self.format = self:getColorType(format)
self:setDefaultColors()
end
--- Sets the character to use for the 'full' part of the gauge
-- @tparam string character the character to use.
function TextGauge:setFillCharacter(character)
assert(character ~= nil, "TextGauge:setFillCharacter(character): character required, got nil")
assert(utf8.len(character) == 1, "TextGauge:setFillCharacter(character): character must be a single character")
self.fillCharacter = character
end
--- Sets the character to use for the 'overflow' (>100%) part of the gauge
-- @tparam string character the character to use.
function TextGauge:setOverflowCharacter(character)
assert(character ~= nil, "TextGauge:setOverflowCharacter(character): character required, got nil")
assert(utf8.len(character) == 1, "TextGauge:setOverflowCharacter(character): character must be a single character")
self.overflowCharacter = character
end
--- Sets the character to use for the 'full' part of the gauge
-- @tparam string character the character to use.
function TextGauge:setEmptyCharacter(character)
assert(character ~= nil, "TextGauge:setEmptyCharacter(character): character required, got nil")
assert(utf8.len(character) == 1, "TextGauge:setEmptyCharacter(character): character must be a single character")
self.emptyCharacter = character
end
--- Sets the fill color for the gauge.
-- @tparam string color the color to use for the full portion of the gauge. Will be run through Geyser.Golor
function TextGauge:setFillColor(color)
assert(color ~= nil, "TextGauge:setFillColor(color): color required, got nil")
self.fillColor = color
end
--- Sets the overflow color for the gauge.
-- @tparam string color the color to use for the full portion of the gauge. Will be run through Geyser.Golor
function TextGauge:setOverflowColor(color)
assert(color ~= nil, "TextGauge:setOverflowColor(color): color required, got nil")
self.overflowColor = color
end
--- Sets the empty color for the gauge.
-- @tparam string color the color to use for the empty portion of the gauge. Will be run through Geyser.Golor
function TextGauge:setEmptyColor(color)
assert(color ~= nil, "TextGauge:setEmptyColor(color): color required, got nil")
self.emptyColor = color
end
--- Sets the fill color for the gauge.
-- @tparam string color the color to use for the numeric value. Will be run through Geyser.Golor
function TextGauge:setPercentColor(color)
assert(color ~= nil, "TextGauge:setPercentColor(color): color required, got nil")
self.percentColor = color
end
--- Sets the fill color for the gauge.
-- @tparam string color the color to use for the numeric value. Will be run through Geyser.Golor
function TextGauge:setPercentSymbolColor(color)
assert(color ~= nil, "TextGauge:setPercentSymbolColor(color): color required, got nil")
self.percentSymbolColor = color
end
--- Enables reversing the fill direction (right to left instead of the usual left to right)
function TextGauge:enableReverse()
self.reverse = true
end
--- Disables reversing the fill direction (go back to the usual left to right)
function TextGauge:disableReverse()
self.reverse = false
end
--- Enables showing the percent value of the gauge
function TextGauge:enableShowPercent()
self.showPercent = true
end
--- Disables showing the percent value of the gauge
function TextGauge:disableShowPercent()
self.showPercent = false
end
--- Enables showing the percent symbol (appears after the value)
function TextGauge:enableShowPercentSymbol()
self.showPercentSymbol = true
end
--- Enables showing the percent symbol (appears after the value)
function TextGauge:disableShowPercentSymbol()
self.showPercentSymbol = false
end
function TextGauge:getColorType(format)
format = format or self.format
local dec = {"d", "decimal", "dec", "decho"}
local hex = {"h", "hexidecimal", "hex", "hecho"}
local col = {"c", "color", "colour", "col", "name", "cecho"}
if table.contains(col, format) then
return "c"
elseif table.contains(dec, format) then
return "d"
elseif table.contains(hex, format) then
return "h"
else
return ""
end
end
-- internal function, used at instantiation to ensure some colors are set
function TextGauge:setDefaultColors()
local colorType = self:getColorType()
if colorType == "c" then
self.percentColor = self.percentColor or "white"
self.percentSymbolColor = self.percentSymbolColor or self.percentColor
self.fillColor = self.fillColor or "DarkOrange"
self.emptyColor = self.emptyColor or "white"
self.resetColor = "<reset>"
elseif colorType == "d" then
self.percentColor = self.percentColor or "<255,255,255>"
self.percentSymbolColor = self.percentSymbolColor or self.percentColor
self.fillColor = self.fillColor or "<255,140,0>"
self.emptyColor = self.emptyColor or "<255,255,255>"
self.resetColor = "<r>"
elseif colorType == "h" then
self.percentColor = self.percentColor or "#ffffff"
self.percentSymbolColor = self.percentSymbolColor or self.percentColor
self.fillColor = self.fillColor or "#ff8c00"
self.emptyColor = self.emptyColor or "#ffffff"
self.resetColor = "#r"
else
self.percentColor = self.percentColor or ""
self.percentSymbolColor = self.percentSymbolColor or self.percentColor
self.fillColor = self.fillColor or ""
self.emptyColor = self.emptyColor or ""
self.resetColor = ""
end
self.overflowColor = self.overflowColor or self.fillColor
end
-- Internal function used to route Geyser.Color based on internally stored format
function TextGauge:getColor(color)
local colorType = self:getColorType()
if colorType == "c" then
return string.format("<%s>", color) -- pass the color back in <> for cecho
elseif colorType == "d" then
return Geyser.Color.hdec(color) -- return it in decho format
elseif colorType == "h" then
return Geyser.Color.hex(color) -- return it in hex format
else
return "" -- return an empty string for noncolored output
end
end
--- Used to set the gauge's value and return the string representation of the gauge
-- @tparam[opt] number current current value. If no value is passed it will use the stored value. Defaults to 50 to prevent errors.
-- @tparam[opt] number max maximum value. If not passed, the internally stored one will be used. Defaults to 100 so that it can be used with single values as a percent
-- @usage myGauge:setValue(55) -- sets the gauge to 55% full
-- @usage myGauge:setValue(2345, 2780) -- will figure out what the percentage fill is based on the given current/max values
function TextGauge:setValue(current, max)
current = current or self.value
assert(type(current) == "number", "TextGauge:setValue(current,max) current as number expected, got " .. type(current))
assert(max == nil or type(max) == "number", "TextGauge:setValue(current, max) option max as number expected, got " .. type(max))
if current < 0 then
current = 0
end
max = max or 100
local value = math.floor(current / max * 100)
self.value = value
local width = self.width
local percentString = ""
local percentSymbolString = ""
local fillCharacter = self.fillCharacter
local overflowCharacter = self.overflowCharacter or fillCharacter
local emptyCharacter = self.emptyCharacter
local fillColor = self:getColor(self.fillColor)
local overflowColor = self:getColor(self.overflowColor)
local emptyColor = self:getColor(self.emptyColor)
local percentColor = self:getColor(self.percentColor)
local percentSymbolColor = self:getColor(self.percentSymbolColor)
local resetColor = self.resetColor
if self.showPercent then
percentString = string.format("%s%02d%s", percentColor, value, resetColor)
width = width - 2
end
if self.showPercentSymbol then
percentSymbolString = string.format("%s%s%s", percentSymbolColor, "%", resetColor)
width = width - 1
end
local perc = value / 100
local overflow = perc - 1
if overflow < 0 then
overflow = 0
end
if overflow > 1 then
perc = 2
overflow = 1
end
local overflowWidth = math.floor(overflow * width)
local fillWidth = math.floor((perc - overflow) * width)
local emptyWidth = width - fillWidth
fillWidth = fillWidth - overflowWidth
if value >= 100 and self.showPercent then
fillWidth = fillWidth - 1
end
if value >= 200 and self.showPercent then
overflowWidth = overflowWidth - 1
end
local result = ""
if self.reverse then
result = string.format("%s%s%s%s%s%s%s%s%s%s%s", emptyColor, string.rep(emptyCharacter, emptyWidth), resetColor,fillColor, string.rep(fillCharacter, fillWidth), resetColor, overflowColor, string.rep(overflowCharacter, overflowWidth), resetColor, percentString, percentSymbolString, resetColor)
else
result = string.format("%s%s%s%s%s%s%s%s%s%s%s", overflowColor, string.rep(overflowCharacter, overflowWidth), fillColor,
string.rep(fillCharacter, fillWidth), resetColor, emptyColor, string.rep(emptyCharacter, emptyWidth), resetColor,
percentString, percentSymbolString, resetColor)
end
return result
end
--- Synonym for setValue
function TextGauge:print(...)
self:setValue(...)
end
return TextGauge

529
src/resources/MDK/timergauge.lua Executable file
View File

@ -0,0 +1,529 @@
--- Animated countdown timer, extends <a href="https://www.mudlet.org/geyser/files/geyser/GeyserGauge.html">Geyser.Gauge</a>
-- @classmod TimerGauge
-- @author Damian Monogue <demonnic@gmail.com>
-- @copyright 2020 Damian Monogue
-- @license MIT, see LICENSE.lua
local TimerGauge = {
name = "TimerGaugeClass",
active = true,
showTime = true,
prefix = "",
timeFormat = "S.t",
suffix = "",
updateTime = "10",
autoHide = true,
autoShow = true,
manageContainer = false,
}
function TimerGauge:setStyleSheet(cssFront, cssBack, cssText)
cssFront = cssFront or self.cssFront
cssBack = cssBack or self.cssBack
cssBack = cssBack or self.cssFront .. "background-color: black;"
cssText = cssText or self.cssText
if cssFront then
self.front:setStyleSheet(cssFront)
end
if cssBack then
self.back:setStyleSheet(cssBack)
end
if cssText then
self.text:setStyleSheet(cssText)
end
-- self.gauge:setStyleSheet(cssFront, cssBack, cssText)
self.cssFront = cssFront
self.cssBack = cssBack
self.cssText = cssText
end
--- Shows the TimerGauge. If the manageContainer property is true, then will add it back to its container
function TimerGauge:show2()
if self.manageContainer and self.savedContainer then
self.savedContainer:add(self)
self.savedContainer = nil
end
self:show()
end
--- Hides the TimerGauge. If manageContainer property is true, then it will remove it from its container and if the container is an HBox or VBox it will initiate size/position management
function TimerGauge:hide2()
if self.manageContainer and self.container.name ~= Geyser.name then
self.savedContainer = self.container
Geyser:add(self)
self.savedContainer:remove(self)
if self.savedContainer.type == "VBox" or self.savedContainer.type == "HBox" then
if self.savedContainer.organize then
self.savedContainer:organize()
else
self.savedContainer:reposition()
end
end
end
self:hide()
end
--- Starts the timergauge. Works whether the timer is stopped or not. Does not start a timer which is already at 0
-- @tparam[opt] boolean show override the autoShow property. True will always show, false will never show.
-- @usage myTimerGauge:start() --starts the timer, will show or not based on autoShow property
-- myTimerGauge:start(false) --starts the timer, will not change hidden status, regardless of autoShow property
-- myTimerGauge:start(true) --starts the timer, will show it regardless of autoShow property
function TimerGauge:start(show)
if show == nil then
show = self.autoShow
end
self.active = true
if self.timer then
killTimer(self.timer)
self.timer = nil
end
startStopWatch(self.stopWatchName)
self:update()
self.timer = tempTimer(self.updateTime / 1000, function()
self:update()
end, true)
if show then
self:show2()
end
end
--- Stops the timergauge. Works whether the timer is started or not.
-- @tparam[opt] boolean hide override the autoHide property. True will always hide, false will never hide.
-- @usage myTimerGauge:stop() --stops the timer, will hide or not based on autoHide property
-- myTimerGauge:stop(false) --stops the timer, will not change hidden status, regardless of autoHide property
-- myTimerGauge:stop(true) --stops the timer, will hide it regardless of autoHide property
function TimerGauge:stop(hide)
if hide == nil then
hide = self.autoHide
end
self.active = false
if self.timer then
killTimer(self.timer)
self.timer = nil
end
stopStopWatch(self.stopWatchName)
if hide then
self:hide2()
end
end
--- Alias for stop.
-- @tparam[opt] boolean hide override the autoHide property. True will always hide, false will never hide.
function TimerGauge:pause(hide)
self:stop(hide)
end
--- Resets the time on the timergauge to its original value. Does not alter the running state of the timer
function TimerGauge:reset()
resetStopWatch(self.stopWatchName)
adjustStopWatch(self.stopWatchName, self.time * -1)
self:update()
end
--- Resets and starts the timergauge.
-- @tparam[opt] boolean show override the autoShow property. true will always show, false will never show
-- @usage myTimerGauge:restart() --restarts the timer, will show or not based on autoShow property
-- myTimerGauge:restart(false) --restarts the timer, will not change hidden status, regardless of autoShow property
-- myTimerGauge:restart(true) --restarts the timer, will show it regardless of autoShow property
function TimerGauge:restart(show)
self:reset()
self:start(show)
end
--- Get the amount of time remaining on the timer, in seconds
-- @tparam string format Format string for how to return the time. If not provided defaults to self.timeFormat(which defaults to "S.t").<br>
-- If "" is passed will return "" as the time. See below table for formatting codes<br>
-- <table class="tg">
-- <tr>
-- <th>format code</th>
-- <th>what it is replaced with</th>
-- </tr>
-- <tr>
-- <td class="tg-1">S</td>
-- <td class="tg-1">Time left in seconds, unbroken down. Does not include milliseconds.<br>
-- IE a timer with 2 minutes left it would replace S with 120
-- </td>
-- </tr>
-- <tr>
-- <td class="tg-2">dd</td>
-- <td class="tg-2">Days, with 1 leading 0 (0, 01, 02-...)</td>
-- </tr>
-- <tr>
-- <td class="tg-1">d</td>
-- <td class="tg-1">Days, with no leading 0 (1,2,3-...)</td>
-- </tr>
-- <tr>
-- <td class="tg-2">hh</td>
-- <td class="tg-2">hours, with leading 0 (00-24)</td>
-- </tr>
-- <tr>
-- <td class="tg-1">h</td>
-- <td class="tg-1">hours, without leading 0 (0-24)</td>
-- </tr>
-- <tr>
-- <td class="tg-2">MM</td>
-- <td class="tg-2">minutes, with a leading 0 (00-59)</td>
-- </tr>
-- <tr>
-- <td class="tg-1">M</td>
-- <td class="tg-1">minutes, no leading 0 (0-59)</td>
-- </tr>
-- <tr>
-- <td class="tg-2">ss</td>
-- <td class="tg-2">seconds, with leading 0 (00-59)</td>
-- </tr>
-- <tr>
-- <td class="tg-1">s</td>
-- <td class="tg-1">seconds, no leading 0 (0-59)</td>
-- </tr>
-- <tr>
-- <td class="tg-2">t</td>
-- <td class="tg-2">tenths of a second<br>
-- timer with 12.345 seconds left, t would<br>
-- br replaced by 3.
-- </td>
-- </tr>
-- <tr>
-- <td class="tg-1">mm</td>
-- <td class="tg-1">milliseconds with leadings 0s (000-999)</td>
-- </tr>
-- <tr>
-- <td class="tg-2">m</td>
-- <td class="tg-2">milliseconds with no leading 0s (0-999)</td>
-- </tr>
-- </table><br>
-- @usage myTimerGauge:getTime() --returns the time using myTimerGauge.format
-- myTimerGauge:getTime("hh:MM:ss") --returns the time as hours, minutes, and seconds, with leading 0s (01:23:04)
-- myTimerGauge:getTime("S.mm") --returns the time as the total number of seconds, including milliseconds (114.004)
function TimerGauge:getTime(format)
format = format or self.timeFormat
local time = getStopWatchTime(self.stopWatchName)
local timerTable = getStopWatchBrokenDownTime(self.stopWatchName)
if time > 0 then
self:stop(self.autoHide)
resetStopWatch(self.stopWatchName)
time = getStopWatchTime(self.stopWatchName)
timerTable = getStopWatchBrokenDownTime(self.stopWatchName)
self.active = false
end
if format == "" then
return format
end
local totalSeconds = string.split(math.abs(time), "%.")[1]
local tenths = string.sub(string.format("%03d", timerTable.milliSeconds), 1, 1)
format = format:gsub("S", totalSeconds)
format = format:gsub("t", tenths)
format = format:gsub("mm", string.format("%03d", timerTable.milliSeconds))
format = format:gsub("m", timerTable.milliSeconds)
format = format:gsub("MM", string.format("%02d", timerTable.minutes))
format = format:gsub("M", timerTable.minutes)
format = format:gsub("dd", string.format("%02d", timerTable.days))
format = format:gsub("d", timerTable.days)
format = format:gsub("ss", string.format("%02d", timerTable.seconds))
format = format:gsub("s", timerTable.seconds)
format = format:gsub("hh", string.format("%02d", timerTable.hours))
format = format:gsub("h", timerTable.hours)
return format
end
-- Execute the timer's hook, if there is one. Internal function
function TimerGauge:executeHook()
local hook = self.hook
if not hook then
return
end
local hooktype = type(hook)
if hooktype == "string" then
local f, e = loadstring("return " .. hook)
if not f then
f, e = loadstring(hook)
end
if not f then
debugc(string.format("TimerGauge encountered an error while executing the hook for TimerGauge with name: %s error: %s", self.name, tostring(e)))
return
end
hook = f
end
hooktype = type(hook)
if hooktype ~= "function" then
debugc(string.format(
"TimerGauge with name: %s was given a hook which is neither a function nor a string which can be made into one. Provided type was %s",
self.name, hooktype))
return
end
local worked, err = pcall(hook)
if not worked then
debugc(string.format("TimerGauge named %s encountered the following error while executing its hook: %s", self.name, err))
end
end
--- Sets the timer's remaining time to 0, stops it, and executes the hook if one exists.
-- @tparam[opt] boolean skipHook use true to have it set the timer to 0 and stop, but not execute the hook.
-- @usage myTimerGauge:finish() --executes the hook if it has one
-- myTimerGauge:finish(false) --will not execute the hook
function TimerGauge:finish(skipHook)
resetStopWatch(self.stopWatchName)
self:update(skipHook)
end
-- Internal function, no ldoc
-- Updates the gauge based on time remaining.
-- @tparam[opt] boolean skipHook use true if you do not want to execute the hook if the timer is at 0.
function TimerGauge:update(skipHook)
local time = self.showTime and self:getTime(self.timeFormat) or ""
local current = tonumber(self:getTime("S.mm"))
local suffix = self.suffix or ""
local prefix = self.prefix or ""
local text = string.format("%s%s%s", prefix, time, suffix)
self:setValue(current, self.time, text)
if current == 0 then
if self.timer then
killTimer(self.timer)
self.timer = nil
end
if not skipHook then
self:executeHook()
end
end
end
--- Sets the amount of time the timer will run for. Make sure to call :reset() or :restart()
-- if you want to cause the timer to run for that amount of time. If you set it to a time lower
-- than the time left on the timer currently, it will reset the current time, otherwise it is left alone
-- @tparam number time how long in seconds the timer should run for
-- @usage myTimerGauge:setTime(50) -- sets myTimerGauge's max time to 50.
function TimerGauge:setTime(time)
local timetype = type(time)
if timetype ~= "number" then
local err = string.format("TimerGauge:setTime(time): time as number expected, got %s", timetype)
debugc(err)
return nil, err
end
time = math.abs(time)
if time == 0 then
local err = "TimerGauge:setTime(time): you cannot pass in 0 as the max time for the timer"
debugc(err)
return nil, err
end
local currentTime = tonumber(self:getTime("S.t"))
self.time = time
if time < currentTime then
self:reset()
else
self:update(currentTime == 0)
end
end
--- Changes the time between gauge updates.
-- @tparam number updateTime amount of time in milliseconds between gauge updates. Must be a positive number.
function TimerGauge:setUpdateTime(updateTime)
local updateTimeType = type(updateTime)
assert(updateTimeType == "number",
string.format("TimerGauge:setUpdateTime(updateTime): name: %s updateTime as number expected, got %s", self.name, updateTimeType))
assert(updateTime > 0,
string.format("TimerGauge:setUpdateTime(updateTime): name: %s updateTime must be a positive number. You gave %d", self.name, updateTime))
self.updateTime = updateTime
if self.timer then
killTimer(self.timer)
self.timer = nil
end
if self.active then
self.timer = tempTimer(updateTime / 1000, function()
self:update()
end, true)
end
end
TimerGauge.parent = Geyser.Gauge
setmetatable(TimerGauge, Geyser.Gauge)
--- Creates a new TimerGauge instance.
-- @tparam table cons a table of options (or constraints) for how the TimerGauge will behave. Valid options include:
-- <br>
-- <table class="tg">
-- <tr>
-- <th>name</th>
-- <th>description</th>
-- <th>default</th>
-- </tr>
-- <tr>
-- <td class="tg-1">time</td>
-- <td class="tg-1">how long the timer should run for</td>
-- <td class="tg-1"></td>
-- </tr>
-- <tr>
-- <td class="tg-2">active</td>
-- <td class="tg-2">whether the timer should run or not</td>
-- <td class="tg-2">true</td>
-- </tr>
-- <tr>
-- <td class="tg-1">showTime</td>
-- <td class="tg-1">should we show the time remaining on the gauge?</td>
-- <td class="tg-1">true</td>
-- </tr>
-- <tr>
-- <td class="tg-2">prefix</td>
-- <td class="tg-2">text you want shown before the time.</td>
-- <td class="tg-2">""</td>
-- </tr>
-- <tr>
-- <td class="tg-1">suffix</td>
-- <td class="tg-1">text you want shown after the time.</td>
-- <td class="tg-1">""</td>
-- </tr>
-- <tr>
-- <td class="tg-2">timerCaption</td>
-- <td class="tg-2">Alias for suffix. Deprecated and may be remove in the future</td>
-- <td class="tg-2"/>
-- </tr>
-- <tr>
-- <td class="tg-1">updateTime</td>
-- <td class="tg-1">number of milliseconds between gauge updates.</td>
-- <td class="tg-1">10</td>
-- </tr>
-- <tr>
-- <td class="tg-2">autoHide</td>
-- <td class="tg-2">should the timer :hide() itself when it runs out/you stop it?</td>
-- <td class="tg-2">true</td>
-- </tr>
-- <tr>
-- <td class="tg-1">autoShow</td>
-- <td class="tg-1">should the timer :show() itself when you start it?</td>
-- <td class="tg-1">true</td>
-- </tr>
-- <tr>
-- <td class="tg-2">manageContainer</td>
-- <td class="tg-2">should the timer remove itself from its container when you call <br>:hide() and add itself back when you call :show()?</td>
-- <td class="tg-2">false</td>
-- </tr>
-- <tr>
-- <td class="tg-1">timeFormat</td>
-- <td class="tg-1">how should the time be displayed/returned if you call :getTime()? <br>See table below for more information</td>
-- <td class="tg-1">"S.t"</td>
-- </tr>
-- </table>
-- <br>Table of time format options
-- <table class="tg">
-- <tr>
-- <th>format code</th>
-- <th>what it is replaced with</th>
-- </tr>
-- <tr>
-- <td class="tg-1">S</td>
-- <td class="tg-1">Time left in seconds, unbroken down. Does not include milliseconds.<br>
-- IE a timer with 2 minutes left it would replace S with 120
-- </td>
-- </tr>
-- <tr>
-- <td class="tg-2">dd</td>
-- <td class="tg-2">Days, with 1 leading 0 (0, 01, 02-...)</td>
-- </tr>
-- <tr>
-- <td class="tg-1">d</td>
-- <td class="tg-1">Days, with no leading 0 (1,2,3-...)</td>
-- </tr>
-- <tr>
-- <td class="tg-2">hh</td>
-- <td class="tg-2">hours, with leading 0 (00-24)</td>
-- </tr>
-- <tr>
-- <td class="tg-1">h</td>
-- <td class="tg-1">hours, without leading 0 (0-24)</td>
-- </tr>
-- <tr>
-- <td class="tg-2">MM</td>
-- <td class="tg-2">minutes, with a leading 0 (00-59)</td>
-- </tr>
-- <tr>
-- <td class="tg-1">M</td>
-- <td class="tg-1">minutes, no leading 0 (0-59)</td>
-- </tr>
-- <tr>
-- <td class="tg-2">ss</td>
-- <td class="tg-2">seconds, with leading 0 (00-59)</td>
-- </tr>
-- <tr>
-- <td class="tg-1">s</td>
-- <td class="tg-1">seconds, no leading 0 (0-59)</td>
-- </tr>
-- <tr>
-- <td class="tg-2">t</td>
-- <td class="tg-2">tenths of a second<br>
-- timer with 12.345 seconds left, t would<br>
-- br replaced by 3.
-- </td>
-- </tr>
-- <tr>
-- <td class="tg-1">mm</td>
-- <td class="tg-1">milliseconds with leadings 0s (000-999)</td>
-- </tr>
-- <tr>
-- <td class="tg-2">m</td>
-- <td class="tg-2">milliseconds with no leading 0s (0-999)</td>
-- </tr>
-- </table><br>
-- @param parent The Geyser parent for this TimerGauge
-- @usage
-- local TimerGauge = require("MDK.timergauge")
-- myTimerGauge = TimerGauge:new({
-- name = "testGauge",
-- x = 100,
-- y = 100,
-- height = 40,
-- width = 200,
-- time = 10
-- })
function TimerGauge:new(cons, parent)
-- type checking and error handling
local consType = type(cons)
if consType ~= "table" then
local err = string.format("TimerGauge:new(options, parent): options must be provided as a table, received: %s", consType)
debugc(err)
return nil, err
end
local timetype = type(cons.time)
local time = tonumber(cons.time)
if not time then
local err = string.format(
"TimerGauge:new(options, parent): options table must include a time entry, which must be a number. We received: %s which is type: %s",
cons.time or tostring(cons.time), timetype)
debugc(err)
return nil, err
end
cons.time = math.abs(time)
if cons.time == 0 then
local err = "TimerGauge:new(options, parent): time entry in options table must be non-0"
debugc(err)
return nil, err
end
if cons.timerCaption and (not cons.suffix) then
cons.suffix = cons.timerCaption
end
cons.type = cons.type or "timergauge"
-- call parent constructor
local me = self.parent:new(cons, parent)
-- add TimerGauge as the metatable/index
setmetatable(me, self)
self.__index = self
-- apply any styling requested
if me.cssFront then
if not me.cssBack then
me.cssBack = me.cssFront .. "background-color: black;"
end
me:setStyleSheet(me.cssFront, me.cssBack, me.cssText)
end
-- create and reset the driving stopwatch
me.stopWatchName = me.name .. "_timergauge"
createStopWatch(me.stopWatchName)
me:reset()
-- start it up?
if me.active then
me:start()
end
me:update()
return me
end
return TimerGauge

View File

@ -0,0 +1,33 @@
function autoStudyStartup()
cecho("\n<dodger_blue>Autostudy loaded. 'studyhelp' for more info.")
end
function autostudy.checkNextMove(index)
if studyIndex <= 4 then
return "w"
elseif studyIndex == 5 then
return "s"
elseif studyIndex <= 7 then
return "se"
elseif studyIndex == 8 then
return "e"
elseif studyIndex == 9 then
return "n"
elseif studyIndex == 10 then
return "ne"
elseif studyIndex == 11 then
return "se"
elseif studyIndex == 12 then
return "s"
elseif studyIndex == 13 then
return "e"
elseif studyIndex <= 15 then
return "ne"
elseif studyIndex == 16 then
return "n"
else
return "w"
end
end
registerAnonymousEventHandler("sysLoadEvent", "autoStudyStartup")

View File

@ -0,0 +1,5 @@
[
{
"name": "autostudy"
}
]

View File

@ -33,8 +33,8 @@
"name": "autoresearch.grabSkills.featsLine",
"patterns": [
{
"pattern": "^-+ Feats -+$",
"type": "regex"
"pattern": "To see a shorter practice list, type PRACTICE <class name>.",
"type": "startOfLine"
}
],
"script": "lotj.autoResearch.startOnPracticeEnd = true; disableTrigger(\"autoresearch.grabSkills\")"

View File

@ -0,0 +1,3 @@
send("afk")
send("bot start")
send("study " .. studyList[studyIndex])

View File

@ -0,0 +1 @@
send("study " .. studyList[studyIndex])

View File

@ -0,0 +1 @@
send("study " .. studyList[studyIndex])

View File

@ -0,0 +1,4 @@
studyIndex = studyIndex + 1
send(autostudy.checkNextMove(studyIndex))
send("study " .. studyList[studyIndex])

View File

@ -0,0 +1 @@
send(autostudy.checkNextMove(studyIndex))

View File

@ -0,0 +1,56 @@
[
{
"name": "study",
"isActive": "yes",
"patterns": [
{
"pattern": "You study it for some time,",
"type": "startOfLine"
},
{
"pattern": "After some time studying",
"type": "startOfLine"
}
]
},
{
"name": "study.next",
"isActive": "yes",
"patterns": [
{
"pattern": "^You are now an adept of (?!study)",
"type": "regex"
}
]
},
{
"name": "study.botStart",
"isActive": "yes",
"patterns": [
{
"pattern": "You may now bot again.",
"type": "exactMatch"
}
]
},
{
"name": "study.nextMove",
"isActive": "yes",
"patterns": [
{
"pattern": "You don't see anything like that nearby to study.",
"type": "exactMatch"
}
]
},
{
"name": "study.copyOver",
"isActive": "yes",
"patterns": [
{
"pattern": "Copyover recovery complete.",
"type": "exactMatch"
}
]
}
]