AvalonUI/src/scripts/Avalon/MDK/textgauge.lua
2024-06-16 10:59:07 -04:00

336 lines
13 KiB
Lua

--- 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